Mobile work-around

To use paymaster transactions on ZKsync, the Viem implementation requires you to import {eip712WalletActions} from 'viem/zksync'and extend a WalletClient with it.

However, this modifies the WalletClient.SendTransaction() function by replacing the eth_sendTransaction JSON RPC API method by the eth_sendRawTransaction method, which is not supported on several mobile wallets.

The current work-around for making paymaster transactions work with all wallets is to sign the transaction using a WalletClient, and then send the signed transaction using a PublicClient supporting the eth_sendRawTransaction. The simplest way is to use a public JSON RPC endpoint, such as https://mainnet.era.zksync.io.

Classic Paymaster implementation (not compatible with all wallets):

  // Paymaster Data received from Zyfi's API
  const pmData = await submitTxDataToAPI(API_URL, dataTxRequest)

  // Extend wallet client to support paymaster transactions
  const wClient = walletClient.extend(eip712WalletActions())

    // Prepare transaction request
    const txReq = await wClient.prepareTransactionRequest({
      account: address,
      to: toAddress,
      value: ETH_AMOUNT,
      chain: zkSync,
      gas: BigInt(pmData.gasLimit),
      gasPerPubdata: BigInt(pmData.txData.customData.gasPerPubdata),
      maxFeePerGas: BigInt(pmData.txData.maxFeePerGas),
      maxPriorityFeePerGas: 0n,
      data: pmData.txData.data,
      paymaster: pmData.txData.customData.paymasterParams.paymaster,
      paymasterInput: pmData.txData.customData.paymasterParams.paymasterInput,
    })

    //  Signs and sends to an endpoint that might be incompatible with eth_sendRawTransaction 
    const hash = await wClient.sendTransaction(txReq)

Work-around Paymaster Implementation (Works with all wallets)

  // Paymaster Data received from Zyfi's API
  const pmData = await submitTxDataToAPI(API_URL, dataTxRequest)

  // Extend wallet client to support paymaster transactions
  const wClient = walletClient.extend(eip712WalletActions())
  
  // Create custom public client with an endpoint that suports eth_sendRawTransaction
  const publicClient = createPublicClient({
    chain: zkSync,
    transport: http('https://mainnet.era.zksync.io')
  })
  
  
  const txReq = await wClient.prepareTransactionRequest({
      account: address,
      to: toAddress,
      value: ETH_AMOUNT,
      chain: zkSync,
      gas: BigInt(pmData.gasLimit),
      gasPerPubdata: BigInt(pmData.txData.customData.gasPerPubdata),
      maxFeePerGas: BigInt(pmData.txData.maxFeePerGas),
      maxPriorityFeePerGas: 0n,
      data: pmData.txData.data,
      paymaster: pmData.txData.customData.paymasterParams.paymaster,
      paymasterInput: pmData.txData.customData.paymasterParams.paymasterInput,
    })
    
    // Sign with Wallet and send signed transaction directly to a compatible endpoint
    const signature = await wClient.signTransaction(txReq)
    const hash = await publicClient.sendRawTransaction({ serializedTransaction: signature })

It's a workaround that works perfectly for Dapps wanting to support paymaster functionality on mobile within ZKsync chains.

Last updated