Pay gas in ERC-20 tokens

Pay for wallet deployments, transfers, or NFT mints in ERC-20 tokens.


For a FunWallet to pay gas in an ERC-20 token, 2 assets must be staked in a Token Paymaster contract:

  • The native gas token (ETH if on Ethereum, MATIC if on Polygon, etc). This token must be transferred to the Token Paymaster contract.

  • The ERC-20 token to pay gas in. This token can be staked in 2 ways:




Quick start

1

Configure environment

Configure the options.gasSponsor environment variable to contain both the address of the gas sponsor & the name of the ERC-20 token to pay gas in. To learn more about gas sponsors for paying gas in ERC-20 tokens, visit the token sponsor section.

await configureEnvironment({
gasSponsor: {
sponsorAddress: "0x07Ac5A221e5b3263ad0E04aBa6076B795A91aef9" // Our test sponsor address on Göerli
token: "usdc"
}
})

Fun offers a publicly-available token sponsor on the Göerli testnet for developer testing purposes. Once Fun has completed smart contract audits, a production-ready token paymaster will be available for use on all supported networks.

,
erc20-gas.js
const ethers = require("ethers")
const { FunWallet, configureEnvironment } = require("fun-wallet")
const { Eoa } = require("fun-wallet/auth")
const { fundWallet } = require("fun-wallet/utils")
const fetch = require('node-fetch')
const API_KEY = "MYny3w7xJh6PRlRgkJ9604sHouY2MTke6lCPpSHq"
const PRIVATE_KEY = "0x98e9cfb323863bc4bfc094482703f3d4ac0cd407e3af2351c00dde1a6732756a"
const DEST_ADDR = "0xd8da6bf26964af9d7eed9e03e53415d37aa96045"
const main = async () => {
// Configure environment
await configureEnvironment({
gasSponsor: {
sponsorAddress: "0x07Ac5A221e5b3263ad0E04aBa6076B795A91aef9" // Our paymaster address
token: "usdc"
}
})
const provider = new ethers.providers.JsonRpcProvider("https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161")
const eoa = new ethers.Wallet(PRIVATE_KEY, provider)
const auth = new Eoa({ signer: eoa })
const uniqueId = await auth.getUniqueId()
const funWallet = new FunWallet( { uniqueId } )
const receipt = await funWallet.transfer(auth, {
to: DEST_ADDR,
amount: 10,
token: "USDC"
})
}
main()

This code will fail without step 2.

2

Give paymaster approval to spend ERC-20s from your wallet

When a FunWallet executes a transaction paying for gas in ERC-20s, the paymaster contract first calculates the amount of gas the transaction will take, then checks an oracle price feed to get the exchange rate between the native gas token & the ERC-20 token intended to pay gas in. Finally, the paymaster contract transfers the necessary ERC-20s to from the FunWallet to itself. I order for the paymaster contract to be able to do this, the FunWallet must give token spend approval to the paymaster contract.

const { TokenSponsor } = require("fun-wallet/sponsors/TokenSponsor")
// Get token sponsor object
const tokenSponsor = new TokenSponsor()
// Approve paymaster address to access predefined set of wallet funds
await funWallet.approve(auth, {
spender: tokenSponsor.getPaymasterAddress(),
token: "usdc",
amount: 10000
})
,
erc20-gas.js
const ethers = require("ethers")
const { TokenSponsor } = require("fun-wallet/sponsors/TokenSponsor")
const { FunWallet, configureEnvironment } = require("fun-wallet")
const { Eoa } = require("fun-wallet/auth")
const fetch = require('node-fetch')
const API_KEY = "MYny3w7xJh6PRlRgkJ9604sHouY2MTke6lCPpSHq"
const PRIVATE_KEY = "0x98e9cfb323863bc4bfc094482703f3d4ac0cd407e3af2351c00dde1a6732756a"
const DEST_ADDR = "0xd8da6bf26964af9d7eed9e03e53415d37aa96045"
const main = async () => {
await configureEnvironment({
gasSponsor: {
sponsorAddress: "0x07Ac5A221e5b3263ad0E04aBa6076B795A91aef9"
token: "usdc"
}
})
const provider = new ethers.providers.JsonRpcProvider("https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161")
const eoa = new ethers.Wallet(PRIVATE_KEY, provider)
const auth = new Eoa({ signer: eoa })
const uniqueId = auth.getUniqueId()
const funWallet = new FunWallet( { uniqueId } )
// Get token sponsor object
const tokenSponsor = new TokenSponsor()
// Approve paymaster address to spend ERC-20s from funWallet
await funWallet.approve(auth, {
spender: tokenSponsor.getPaymasterAddress(),
token: "usdc",
amount: 10000
})
const receipt = await funWallet.transfer(auth, {
to: DEST_ADDR,
amount: 10,
token: "USDC"
})
}
main()