🔍

How to Interpret Diamond Cut Data

Tags

The diamondCut function updates any number of functions from any number of facets in a single transaction. Executing all changes within a single transaction prevents data corruption which could occur in upgrades done over multiple transactions.

BIP Runbooks will include a JSON file of the diamondCut data, and this data can be verified to be the same diamondCut data in the BIP on Safe.

A diamondCut has 3 inputs:

  1. _diamondCut: An array of FacetCuts (see below). This input can be empty.
  2. _init: The address of the contract to execute _calldata. Essentially, if there is code that needs to be executed before each of the FacetCuts (such as changing data in storage, minting Beans, etc.), an init contract will be deployed with that code and _init will be that contract’s address. This input can be the null address.
  3. _calldata: A function call executed with delegatecall on _init.

A FacetCut is a tuple with 3 items:

  1. facetAddress: The facet address being added, changed or removed.
  2. action: 0 if the facet is being added, 1 if it is being replaced and 2 if it is being removed.
  3. functionSelectors: The function selectors in facetAddress that are having action done on them.

Louper, the Ethereum Diamond Inspector, is a way to verify which facets and function selectors are currently part of Beanstalk: https://louper.dev/diamond/0xc1e088fc1323b20bcbee9bd1b9fc9546db5624c5

Here’s an example of diamondCut data from BIP-24 (Safe transaction):

bip24.json8.1KB
{
    "diamondCut": [
        [
            "0xc2E90aCbA1DC5ec1B852592390f479012eB304C2", // ConvertFacet address
            1, // Replace the following function selectors
            [
                "0x3b2a1b28", // convert
                "0x4aa06652", // getAmountOut
                "0x24dd285c" // getMaxAmountIn
            ]
        ],
        [
            "0x6530A76c77F11731Bf7F1C799AA97E0C15d3FB26", // SiloFacet address
            0,  // Add the following functions
            [
                "0x1302afc2", // approveDeposit
                "0x45947ba9", // claimPlenty
                "0xd9ee1269", // decreaseDepositAllowance
                "0x2a6a8ef5", // depositAllowance
                "0x5793e485", // increaseDepositAllowance
                "0x9e32d261", // transferDeposit
                "0x0d2615b1" // transferDeposits
            ]
        ],
        [
            "0x6530A76c77F11731Bf7F1C799AA97E0C15d3FB26", // SiloFacet address
            1, // Replace the following function selectors
            [
                "0x3e465a2e", // balanceOfEarnedBeans
                "0x602aa123", // balanceOfEarnedSeeds
                "0x341b94d5", // balanceOfEarnedStalk
                "0x249564aa", // balanceOfGrownStalk
                "0x896651e8", // balanceOfPlenty
                "0x69fbad94", // balanceOfRainRoots
                "0xba39dc02", // balanceOfRoots
                "0x4916bc72", // balanceOfSeeds
                "0xa7bf680f", // balanceOfSop
                "0x8eeae310", // balanceOfStalk
                "0x488e94dc", // claimWithdrawal
                "0x764a9874", // claimWithdrawals
                "0xf19ed6be", // deposit
                "0xd5d2ea8c", // enrootDeposit
                "0x83b9e85d", // enrootDeposits
                "0x8a6a7eb4", // getDeposit
                "0x0c9c31bd", // getTotalDeposited
                "0xb1c7a20f", // getTotalWithdrawn
                "0xe23c96a4", // getWithdrawal
                "0xbe6547d2", // lastSeasonOfPlenty
                "0xcb03fb1e", // lastUpdate
                "0x779b3c5c", // plant
                "0xe923e8d4", // tokenSettings
                "0xfd9de166", // totalEarnedBeans
                "0x46544166", // totalRoots
                "0xd8bd0d9d", // totalSeeds
                "0x7b52fadf", // totalStalk
                "0x1c1b8772", // update
                "0x7af9a0ce", // withdrawDeposit
                "0xb189d9c8", // withdrawDeposits
                "0x55926690" // withdrawFreeze
            ]
        ],
        [
            "0x261b3aE660504537FbFe15b6C1c664976344eb0a", // UnripeFacet address
            0, // Add the following function selectors
            [
                "0xa84643e4", // _getPenalizedUnderlying
                "0x9a516cad" // chop
            ]
        ],
        [
            "0x261b3aE660504537FbFe15b6C1c664976344eb0a", // UnripeFacet address
            1, // Replace the following function selectors
            [
                "0xfa345569", // addUnripeToken
                "0x1acc0a47", // balanceOfPenalizedUnderlying
                "0x1be655e8", // balanceOfUnderlying
                "0x6de45df2", // getPenalizedUnderlying
                "0x014a8a49", // getPenalty
                "0xbb7de478", // getPercentPenalty
                "0x43cc4ee0", // getRecapFundedPercent
                "0xab434eb7", // getRecapPaidPercent
                "0xadef4533", // getTotalUnderlying
                "0x9f06b3fa", // getUnderlying
                "0xb8a04d1b", // getUnderlyingPerUnripeToken
                "0x691bcc88", // getUnderlyingToken
                "0xfc6a19df", // isUnripe
                "0x13ed3cea", // pick
                "0xd3c73ec8" // picked
            ]
        ]
    ],
    "initFacetAddress": "0xF95389567B222Ec36e509B874E8aD4452ea05654", // _init address
    "functionCall": "0xe1c7392a" // _calldata to execute function on _init address
}