zkUsePaymaster

Signature

function zkUsePaymaster(address paymaster, bytes calldata input) external pure;

Description

This cheatcode enables the use of a paymaster for the next transaction in the contract. The parameters specify the address of the paymaster and the pre-encoded data to be passed to the paymaster. The paymaster should be deployed before using this cheatcode.

Examples

import {TestExt} from "forge-zksync-std/TestExt.sol";

contract Test is TestExt {
    function test_zkUsePaymaster() public {
        MyPaymaster paymaster = new MyPaymaster();
        // Encode paymaster input
        bytes memory paymaster_encoded_input = abi.encodeWithSelector(
            bytes4(keccak256("general(bytes)")),
            bytes("0x")
        );
        vmExt.zkUsePaymaster(address(paymaster), paymaster_encoded_input);
    }
}

The paymaster flow depends on the type of paymaster used. Here’s an example of the simplest usage of a ‘general’ paymaster in Foundry:

  1. Write a custom paymaster:
contract MyPaymaster is IPaymaster {
    modifier onlyBootloader() {
        require(msg.sender == BOOTLOADER_FORMAL_ADDRESS, "Only bootloader can call this method");
        _;
    }

    constructor() payable {}

    function validateAndPayForPaymasterTransaction(bytes32, bytes32, Transaction calldata _transaction)
        external
        payable
        onlyBootloader
        returns (bytes4 magic, bytes memory context)
    {
        // Always accept the transaction
        magic = PAYMASTER_VALIDATION_SUCCESS_MAGIC;

        // Pay for the transaction fee
        uint256 requiredETH = _transaction.gasLimit * _transaction.maxFeePerGas;
        (bool success,) = payable(BOOTLOADER_FORMAL_ADDRESS).call{value: requiredETH}("");
        require(success, "Failed to transfer tx fee to the bootloader");
    }

    function postTransaction( 
        bytes calldata _context,
        Transaction calldata _transaction,
        bytes32,
        bytes32,
        ExecutionResult _txResult,
        uint256 _maxRefundedGas
    ) external payable override onlyBootloader {}

    receive() external payable {}
}
  1. Deploy the paymaster:

You can deploy the paymaster either in a test or script:

MyPaymaster paymaster = new MyPaymaster();

Or using the forge create command:

forge create ./src/MyPaymaster.sol:MyPaymaster --rpc-url {RPC_URL} --private-key {PRIVATE_KEY} --zksync
  1. Use the cheatcode to set the paymaster for the next transaction:
vmExt.zkUsePaymaster(address(paymaster), abi.encodeWithSelector(
    bytes4(keccak256("general(bytes)")),
    bytes("0x")
));

For more examples, see the Foundry ZkSync Paymaster Tests.

Also, see the ZKsync Paymaster Documentation for more information.