3

Here is a basic example, where I'm calling a method on myContract and using a Paymaster:

await myContract.myMethod(
  myArgs,
  {
    customData: {
      paymasterParams: paymasterParams,
      gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT,
    }
  }
);

To ensure that the Paymaster can only be used for myContract and only to call myMethod I need get the calling contract and method from within the paymaster smart contract code. Getting the contract is straight forward it is available from the transaction.to object.

It appears that the transaction.data holds the encoded method call. So in order to access the data I have tried:

if (paymasterInputSelector == IPaymasterFlow.general.selector) {
  address userAddress = address(uint160(_transaction.from));
  address callerAddress = address(uint160(_transaction.to));
  require(userAddress == allowedUser, "Must be an Approved User");
  require(callerAddress == tokenAddr, "Invalid token address");
  bytes4 funcSlct = bytes4(keccak256(bytes(_transaction.data)));  //Trying to extract function selector from data
  if (funcSlct == bytes4(keccak256(bytes("0x1234abcd")))) {  
    // compare function selector from data to the expected value.
    // do something
    // But this always fails!
  } else {
    //don't do anything, revert! 
    // it always reverts here.
  }
  // rest of the paymaster code
}

The problem is that the condition is never met and it always reverts.

I'm not sure if this an issue with the transaction object in the paymaster, or whether there is a problem with how I'm decoding and comparing the function signature/selector. Note that when it reverts it prints the transaction object to screen and data appears with the matching function selector.

1 Answer 1

1

You are extracting the function selector from the transaction data, but it contains the function selector followed by the ABI-encoded arguments, just Replace myMethod() with the correct method signature that you want to match.

if (paymasterInputSelector == IPaymasterFlow.general.selector) {
    address userAddress = address(uint160(_transaction.from));
    address callerAddress = address(uint160(_transaction.to));
    require(userAddress == allowedUser, "Must be an Approved User");
    require(callerAddress == tokenAddr, "Invalid token address");
    
    bytes4 funcSlct = bytes4(_transaction.data[0] | (_transaction.data[1] << 8) | (_transaction.data[2] << 16) | (_transaction.data[3] << 24));
    bytes4 expectedFuncSlct = bytes4(keccak256("myMethod()"));

    if (funcSlct == expectedFuncSlct) {
        // Do something
    } else {
        // Revert
    }
    // Rest of the paymaster code
}
2
  • Unfortunately it still gives the same result. Can you explain the line bytes functSlct = ...? My guess is that problem is with how _transaction.data is being decoded. Commented Apr 8, 2023 at 4:30
  • 1
    I got it to work by simply using bytes4 funcSlct = bytes4(_transaction.data); Commented Apr 8, 2023 at 19:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.