When implementing an Embedded Wallet, one will need to be able to pay for the gas fees on a non-testnet network to send a transaction.

Fee options provide a quote to cover the gas fees only useable for a certain period of time (which is unique to the Sequence stack).

To send a transaction successfully, you have a few directions you can take:

  • Testnets: Using a testnet, transactions with Sequence are free, not requiring a fee option inputted into the SDK call.
  • Sponsored Contract or Wallet: Having the smart contract or wallet sponsored, not requiring a fee option inputted into the SDK call. You can learn about sponsoring a contract or wallet here.
  • Fee Options: Using a Sequence API to get a custom fee quote and fee options object, pass both into the waas sdk call. See below.

You will know if you need to either sponsor your contract or wallet, or, implement fee options if you receive the following response from the WaaS API:

{

    "error": "WebrpcEndpoint",

    "code": 0,

    "msg": "endpoint error",

    "cause": "sending transaction: WebrpcEndpoint 0: endpoint error: failed to send transaction: Aborted 1005: Request aborted: failed to relay transaction: Aborted 1005: Request aborted: refusing to dispatch: missing required fee payment",

    "status": 400

}

Implementing Fee Options

Before implementing the following “Fee Options” flow, you will need to ensure that your wallet has sufficienct funds to pay for your transaction on the specific network in the native currency.

You can either transfer tokens to your wallet, or, use the on-ramp feature using the Sequence Kit solution.

And ensure that the following packages are installed:

pnpm install @0xsequence/waas ethers
1

Generalized API for Fee Options & Fee Quote

To implement fee options passed into the request, a first call to sequence.feeOptions({...}) is required, which is wrapped in the following function checkTransactionFeeOptions:

In the following examples, the sequence variable is an Embbeded Wallet object intialized from the @0xsequence/waas npm package with the WaasConfigKey and ProjectAccessKey. Learn how to do this here

import { FeeOption, Network, Transaction } from "@0xsequence/waas"



....



async function checkTransactionFeeOptions({transactions, network}: {transactions: Transaction[], network: string | number }): Promise<{feeQuote: string | undefined, feeOptions: FeeOption[] | undefined, isSponsored: boolean}> {

  const resp = await sequence.feeOptions({

    transactions: transactions,

    network: network,

  })



  if (resp.data.feeQuote && resp.data.feeOptions) {

    return {feeQuote: resp.data.feeQuote, feeOptions: resp.data.feeOptions, isSponsored: false}

  }

  return {feeQuote: resp.data.feeQuote, feeOptions: resp.data.feeOptions, isSponsored: true}

}
2

Crafting Fee Options & Fee Quote with Transaction

Implementing an ERC20 Transaction

import { ethers } from 'ethers'

import { erc20 } from '@0xsequence/waas'



...



const response = await checkTransactionFeeOptions({

    transactions: [erc20({

        token: customTokenAddress,

        to: destinationAddress,

        value: ethers.parseUnits(amount, decimals).toString()

    })],

    network: 'arbitrum-nova' // i.e. network or chainID e.g. 42170 

})



const tx = await sequence.sendERC20({

    token: customTokenAddress,

    to: destinationAddress,

    value: ethers.parseUnits(amount, decimals),

    network: 'arbitrum-nova',

    transactionsFeeOption: response.feeOptions,

    transactionsFeeQuote: response.feeQuote

})

Implementing an ERC1155 / ERC721 Transaction

For ERC721 just replace erc1155({...}) with erc721({...}) and call sequence.sendERC721({...})

import { ethers } from 'ethers'

import { erc1155, erc721 } from '@0xsequence/waas'



...



const response = await checkTransactionFeeOptions({

    transactions: [erc1155({

        token: customTokenAddress,

        to: destinationAddress,

        values: [{

          id: tokenID,

          amount: ethers.parseUnits(amount, 0)

        }]

    })],

    network: 'arbitrum-nova' // i.e. network or chainID e.g. 42170 

})



const tx = await sequence.sendERC1155({

    token: customTokenAddress,

    to: destinationAddress,

    values: [{

        id: tokenID,

        amount: ethers.parseUnits(amount, 0)

    }],

    network: 'arbitrum-nova',

    transactionsFeeOption: response.feeOptions,

    transactionsFeeQuote: response.feeQuote

})

Implementing an Native Currency Transaction

import { ethers } from 'ethers'



const to = '0x...'



const response = await checkTransactionFeeOptions({

    transactions: [{

        to, value: ethers.parseEther(amount),

    }],

    network: 'arbitrum-nova'

})



const tx = await sequence.sendTransaction({

    transactions: [{

        to, value: ethers.parseEther(amount),

    }],

    network: 'arbitrum-nova',

    transactionsFeeOption: feeOption,

    transactionsFeeQuote: feeQuote

})

Implementing a Custom Contract Transaction

import { delayedEncode } from '@0xsequence/waas'



...



const response = await checkTransactionFeeOptions({

    transactions: [delayedEncode({

        to: contractAddress,

        abi: contractAbi,

        func: contractMethod, // e.g. "transfer"

        args: JSON.parse(contractMethodArgs), // e.g. [0x..., 1000] or named { "to": "0x...", "amount": "1000" }

        value: "0"

    })],

    network: 'arbitrum-nova'

})



const tx = await sequence.callContract({

    network: 'arbitrum-nova',

    to: contractAddress,

    abi: contractAbi,

    func: contractMethod, // e.g. "transfer"

    args: JSON.parse(contractMethodArgs),

    value: 0,

    transactionsFeeOption: response.feeOption,

    transactionsFeeQuote: response.feeQuote

})