Calculating bytes length for structs

Hi. I have few questions regarding permit2

  1. When I'm manually checking the length of parmitData its length is coming 32 * 12. Shouldnt it be 32 * 8 ? Can someone tell me correctly way for calculating bytes length when structs are involved.
  2. How can we encode parameters of permitTransferFrom function using ethers.js.
// My call
PERMIT2.call(abi.encodePacked(IPermit2.permitTransferFrom.selector, permitData));

------------------------------
// permit2

struct TokenPermissions {
    address token;
    uint256 amount;
}

struct PermitTransferFrom {
    TokenPermissions permitted;
    uint256 nonce;
    uint256 deadline;
}

struct SignatureTransferDetails {
    address to;
    uint256 requestedAmount;
}

function permitTransferFrom(
    PermitTransferFrom memory permit,
    SignatureTransferDetails calldata transferDetails,
    address owner,
    bytes calldata signature
) external;

Hi Dante,

  1. Each function value takes up 32 bytes, not like the state variable declare. There is no difference value and struct bytes. and also bytes takes slot 32 * 3.

    function permitTransferFrom(
    PermitTransferFrom memory permit,
    SignatureTransferDetails calldata transferDetails,
    address owner,
    bytes calldata signature
    ) external pure returns (uint256 result) {
    assembly {
    result := calldatasize()
    }
    }

If you want to encode the function parameter.
Try this npm package - https://www.npmjs.com/package/@ethersproject/abi

1 Like

Encoding using web3

  web3.eth.abi.encodeParameters(
    [
      {
        PermitTransferFrom: {
          permitted: {
            token: 'address',
            amount: 'uint256',
          },
          nonce: 'uint256',
          deadline: 'uint256',
        },
      },
      {
        SignatureTransferDetails: {
          to: 'address',
          requestedAmount: 'uint256',
        },
      },
      'address',
      'bytes',
    ],
    [permitDetails, transferDetails, wallet.address, signature]
  )

Encoding using etherjs

  ethers.utils.defaultAbiCoder.encode(
    [
      'tuple(address token, uint256 amount) permitted',
      'uint256 nonce',
      'uint256 deadline',
      'tuple(address to, uint256 requestedAmount) transferDetails',
      'address owner',
      'bytes signature',
    ],
    [
      {
        token,
        amount,
      },
      nonce,
      deadline,
      transferDetails,
      wallet.address,
      signature,
    ]
  )

The thing I was doing wrong was

ethers.utils.defaultAbiCoder.encode(
    [
      'tuple(address token, uint256 amount) permitted, uint256 nonce, uint256 deadline) permit',
      'tuple(address to, uint256 requestedAmount) transferDetails',
      'address owner',
      'bytes signature',
    ],
    [
      {
        permitted: {
            token,
            amount,
        }, 
        nonce,
        deadline,
      },
      transferDetails,
      wallet.address,
      signature,
    ]
  )

Signature will take

  • 5 slots if it is calculated using wallet._signedTypeData
  • 4 slots if it is calculated using ethers.utils.splitSignature("signature").compact

so the break down in permitTransferFrom will be like this :
permit : 32 * 4 (2 for permitted(token, amount), 1 for nonce, 1 for deadline)
transferDetails : 32 * 2 (1 for to and and 1 for requestedAmount)
owner : 32 * 1
signature : 32 * 3.

the total comes to be 10, but the total slots being used are 12.
Can you please give a break down for the this.

How did you find the use of the slot?

I have found out what i was doing wrong, signature will be for 5 or 4 slots (if it is compact).