Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[POC] Experiment paymaster contract (EIP 4337) #29

Open
thomas-nguy opened this issue Jul 26, 2023 · 7 comments
Open

[POC] Experiment paymaster contract (EIP 4337) #29

thomas-nguy opened this issue Jul 26, 2023 · 7 comments
Assignees

Comments

@thomas-nguy
Copy link
Member

thomas-nguy commented Jul 26, 2023

Zksync has implemented account abstraction (EIP 4337)
https://eips.ethereum.org/EIPS/eip-4337
https://era.zksync.io/docs/reference/concepts/account-abstraction.html

We would like to experiment this feature by creating a paymaster that would accept a custom token to pay the gas fee on transactions

  • Experiment the paymaster functionality
  • See if the paymaster can be limited to specific applications

Ideally we should come up with a prototype contract and deliver a demo

@thomas-nguy thomas-nguy changed the title [Core] Create Paymaster contract [Core] Experiment and create paymaster contract (EIP 4337) Jul 26, 2023
@thomas-nguy thomas-nguy changed the title [Core] Experiment and create paymaster contract (EIP 4337) [Core] Experiment paymaster contract (EIP 4337) Jul 26, 2023
@thomas-nguy thomas-nguy changed the title [Core] Experiment paymaster contract (EIP 4337) [POC] Experiment paymaster contract (EIP 4337) Jul 26, 2023
@crypto-matto crypto-matto self-assigned this Jul 31, 2023
@crypto-matto
Copy link

crypto-matto commented Aug 1, 2023

Followed this tutorial: Custom Paymaster Tutorial
https://github.com/matter-labs/custom-paymaster-tutorial
The code works smoothly.

Only BootLoader (a system contract) can call this method. It is a never deployed contract and cannot be called. It does, however, have a formal address that is used by msg.sender when calling other contracts.

Procedure

  1. Deploy an ERC20 Token Contract
  2. Deploy the PayMaster contract, specified with an approved ERC20 address
  3. Calls a mint() function with paymasterParams from any other empty balance wallet address
  4. ERC20 token will be transferred to the empty balance wallet address, without paying any gas fee from the wallet POV

Result

ETH balance of the empty wallet before mint: 0 ETH
ERC20 token balance of the empty wallet before mint: 0
Paymaster ETH balance is 0.06 ETH
Transaction fee estimation is :>>  0.0000572715 ETH
Minting 5 tokens for empty wallet via paymaster...
Paymaster ERC20 token balance is now 1
Paymaster ETH balance is now 0.05995183625 ETH
ETH balance of the empty wallet after mint: 0 ETH
ERC20 token balance of the wallet after mint: 4
  • Empty Wallet is always having 0 ETH balance
  • Empty Wallet initiates a mint transaction for 5 ERC20 Token
  • PayMaster pays the gas fee, roughly ~0.00006 ETH
  • PayMaster collected 1 ERC20 token
  • Empty Wallet gets 4 ERC20 Token in the end

The magic lies on passing a paymasterParams in customData when calling mint() of the ERC20 token:

  const paymasterParams = utils.getPaymasterParams(PAYMASTER_ADDRESS, {
    type: "ApprovalBased",
    token: TOKEN_ADDRESS,
    // set minimalAllowance as we defined in the paymaster contract
    minimalAllowance: ethers.BigNumber.from(1),
    // empty bytes as testnet paymaster does not use innerInput
    innerInput: new Uint8Array(),
  });
  ...
    await erc20.mint(emptyWallet.address, 5, {
      // paymaster info
      customData: {
        paymasterParams: paymasterParams,
        gasPerPubdata: utils.DEFAULT_GAS_PER_PUBDATA_LIMIT,
      },
    })

There are 2 types:

  • general: Any input data without any requirements
  • approvalBased: token & minimalAllowance fields are required

The input data is not needed for this paymaster on testnet. It's uncertain what's its role on mainnet, or any other potential usage. But this could be the entry point of limiting the usage to specific applications.

@thomas-nguy
Copy link
Member Author

thomas-nguy commented Aug 2, 2023

For the next time, could we try to deploy a uniswap contract pool on testnet and try to deploy a paymaster that authorize a swap on a specific pool?

@crypto-matto
Copy link

crypto-matto commented Aug 2, 2023

Follow up

  • See how this can relates to L1 tx

@crypto-matto
Copy link

crypto-matto commented Aug 8, 2023

For the next time, could we try to deploy a uniswap contract pool on testnet and try to deploy a paymaster that authorize a swap on a specific pool?

In regard to paying the fee for uniswap transaction, the test was unsuccessful on local.

Steps

  1. Deploy all necessary uniswap contracts
  2. Create a trading pair & add liquidity
    • e.g. Token A - Token B
  3. Deploy a paymaster contract, specified with Token A
  4. Call a swap tx from Token A to Token B, specified with paymasterParams

The swap transaction swapExactTokensForETH() always fail with a general error:

TransferHelper::transferFrom: transferFrom failed

Another attempt on NFT ERC721

While for another experiment on ERC721 contract, the paymaster contract works fine with transactions like mint() & setBaseURI(). The general usage is pretty similar as ERC20.

Steps

  1. Deploy ERC721 contract
  2. Deploy Paymaster contract. Compare to the Paymaster used with ERC20
    • This NFT Paymaster contract is using General type selector, instead of ApprovalBased
    • This Paymaster contract doesn't ask for any fee from the caller
  3. Calls any functions with paymasterParams from any other empty balance wallet address

Result

Empty wallet's address: 0x52F43E59A6e5c645a7a9C23a6c22a0f82378bed9
ETH balance of the empty wallet before mint: 0
Paymaster ETH balance is 0.00492076 ETH
ERC721 token balance of the recipient: 1
Transaction setBaseURI() fee estimation is :>>  0.0000468345 ETH
Initiate ERC721 token transaction from empty wallet via paymaster...
New baseURI is: https://ipfs.io/ipfs/QmPtDtJEJDzxthbKmdgvYcLa9oNUUUkh7vvz5imJFPQdKa
Paymaster ERC721 token balance is now 0
Empty Wallet ERC721 token balance is now 1
Paymaster ETH balance is now 0.004881412 ETH
ETH balance of the empty wallet after mint: 0

Experiment on Loop Contracts

Infinite Loop

pragma solidity ^0.8.0;

contract TestInfiniteLoop {
      function loop() public pure returns(string memory){
        uint i = 1;
        uint c = 0;
        while(i == 1){
            c = c + 1;
        }
        return "good";
    }
}

On normal remix, calling loop() will result in VM error: out of gas.

On zkSync, calling loop() with the aid of paymaster, will result in CALL_EXCEPTION error instead, with errorName: null. Paymaster balance is not decreased.

Finite Loop

For initiating a finite loop transaction, a bunch of execute_in_sandbox actions, predicting things like execution time. While the ETH balance in paymaster is definitely enough to pay for the gas:

When it’s a loop 5000+ transaction, in the end the send_raw_transaction_impl function will return failed to validate the transaction.
failed_validation

When the loop is set to 4000, the procedure is the same, but the transaction will go through.
success_tx

@crypto-matto
Copy link

crypto-matto commented Aug 8, 2023

Paymaster Properties

  • *Anyone can deploy a Paymaster Contract
  • Call restrictions / validation logics can be implemented, like normal Smart Contracts
  • The Paymaster must be filled with enough ETH to pay for Gas
  • When Paymaster balance drained, it will not work anymore
  • If any part of the validation fails, the account is not charged a fee, and such transaction can not be included in a block.
  • The Paymaster is not necessarily ask for a fee from the caller. It is configurable.
  • *As long as a transaction provides a Paymaster Address with a paymasterParams, it will locate the paymaster and do the work for the Caller
  • *There is paymaster validation rules to avoid abuse of use. Yet it is unknown what sort of rules & implementation has applied for the moment.
  • *What if someone spam the validation rules, as the validation process seems not costing any gas
  • *Unlike Ethereum, where they have authorized EntryPoint & whitelisted addresses, zkSync is open to everyone for callling.

For points marked as *, we might need to clarify from zkSync team. I suppose this will work for all types of transactions, but uncertain at this point if there are some OPCODE doesn't support yet.

@crypto-matto
Copy link

crypto-matto commented Aug 10, 2023

@XinyuCRO
Copy link

Paying the fee for Uniswap transaction is doable, check out this PR: crypto-matto/custom-paymaster-tutorial#1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants