How to set your token allowances
To allow a third party to move funds on your behalf, you need to set up a token allowance. This means giving permission for someone else to move your tokens.
Depending on whether you use swap/permit2
or /swap/allowance-holder
, you want to allow either the Permit2 contract or AllowanceHolder, respectively to trade our ERC20 tokens. To do this, we need to approve an allowance on the ERC20 contract, allowing these contracts to move a specific amount of our tokens.
To do so, we will need to give an allowance to the issues.allowance.spender
parameter if it is returned by the Swap API /price
and /quote
endpoints. The issues.allowance.spender
is the the address to set the allowance to.
Example response from /swap/permit2/quote
will return back the contract address if an allowance needs to be set:
"issues": {
"allowance": {
"actual": "0",
"spender": "0x000000000022d473030f116ddee9f6b43ac78ba3"
},
For instances of wrapping and unwrapping ETH (i.e. swapping WETH <-> ETH and ETH <-> WETH), no allowance is needed. In these cases, allowance is null
.
Setting Allowances for 0x API quotes​
There are several ways to set a token allowance, both programmatically and through a UI. We will cover options for both methods below.
Using wagmi​
wagmi has a number of hooks that can help us read and write to contracts.
- First, we need to check if the spender (Permit2) has an allowance already. We can use wagmi's
useReadContract
hook to read from the sellToken's "allowance" function. - If thre is no allowance, then we can write an approval to the sellToken's smart contract using wagmi's
useSimulateContract
anduseWriteContract
- Lastly, use wagmi's
useWaitForTransactionReceipt
to wait for the approval transaction to complete
Here is an example snippet demonstrating how to approve a USDC token allowance for the Permit2 contract using wagmi. See the full code implementation in the Swap v2 Demo App and accompanying guide.
// Setup wallet client, contract addresses and ABIs
// Fetch price
...
// Once price has been fetched, check and approve allowance
function ApproveOrReviewButton({
taker,
onClick,
sellTokenAddress,
disabled,
}: {
taker: Address;
onClick: () => void;
sellTokenAddress: Address;
disabled?: boolean;
}) {
// 1. Read from erc20, check approval for permit2 to spend sellToken
const { data: allowance, refetch } = useReadContract({
address: sellTokenAddress,
abi: erc20Abi,
functionName: "allowance",
args: [taker, PERMIT2_ADDRESS],
});
console.log("checked permit2 approval");
// 2. (only if no allowance): write to erc20, approve token allowance for permit2
const { data } = useSimulateContract({
address: sellTokenAddress,
abi: erc20Abi,
functionName: "approve",
args: [PERMIT2_ADDRESS, MAX_ALLOWANCE],
});
// Define useWriteContract for the 'approve' operation
const {
data: writeContractResult,
writeContractAsync: writeContract,
error,
} = useWriteContract();
// useWaitForTransactionReceipt to wait for the approval transaction to complete
const { data: approvalReceiptData, isLoading: isApproving } =
useWaitForTransactionReceipt({
hash: writeContractResult,
});
...
Using web3.js​
Here is an example snippet demonstrating how to approve a USDC token allowance for the Permit2 contract using web3.js:
(async () => {
const Web3 = require('web3');
const web3 = new Web3('https://eth-mainnet.alchemyapi.io/v2/YOUR_ALCHEMY_API_KEY'); // Replace with your Alchemy API key
// Setup ERC20 ABI in a separate file and import
const erc20Abi = require('./erc20Abi.json');
// Get a quote from 0x API which contains `issues.allowance.spender`
// `spender` is the address that the user needs to set an ERC20 allowance for
const res = await fetch(`https://api.0x.org/swap/permit2/quote?${qs.stringify(params)}`);
const quote = await res.json();
// Set up approval
const usdcAddress = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'; // USDC on Ethereum
// Initialize the USDC contract
const usdcContract = new web3.eth.Contract(erc20Abi, usdcAddress);
const maxApproval = new BigNumber(2).pow(256).minus(1); // This example sets the allowance amount to a large number, but you can adjust it to only the amount required for trading
// Write to the ERC20 token contract address and approve the allowanceTarget to spend maxApproval
const chainId = 1;
const approvalTxData = usdcContract.approve(quote.issues.allowance.spender, maxApproval).encodeABI();
await web3.eth.sendTransaction(approvalTxData);
})();
Using Etherscan​
There are a lot of apps that let you set your allowances such as Metamask, but for this example we will be using Etherscan.
Let's look at an example of how to approve an allowance for WETH from the Etherscan website. Navigate to the WETH ERC20 Contract > Contracts > Write Contract tab > approve method here.
From here, you can call the approve
method to approve the Permit2 Address (what's returned in issues.allowance.spender
) for the max uint256 amount which is 115792089237316195423570985008687907853269984665640564039457584007913129639935
.
You can give a WETH allowance to any smart contract this way. To set your allowance for a different token, you'll have to navigate to the smart contract interface for that token.
Revoking Allowances​
To revoke an allowance, you will need to set the allowance to 0. This can be done programmatically or through a UI such as https://revoke.cash/ .
Common Issues​
When setting the token allowance, make sure to provide enough allowance for the buy or sell amount as well as the gas; otherwise, you may receive a 'Gas estimation failed' error.