The Intent API lets you trade gasless, MEV-protected and at optimal rates.
Overview
This guide provides an overview of how to interact with the Intent API: Query for swap rates, construct a swap order, and submit an order for execution.
Prerequisites
Before you start, ensure you have:
Familiarity with HTTP requests and responses.
An Ethereum Mainnet wallet address with enough balance for the swap.
Ensure that the tokens you intend to swap are approved for use by the Permit2 contract with at least the amount the user intends to swap.
Uniswap Labs developed the Permit2 contract and acts as an intermediary, allowing each swap operation to be approved via signatures, saving the user gas cost and increasing security. We recommend that the token is approved with the max uint256 amount, to avoid having to approve multiple times. -> Read more about what is Permit2.
Example
// Assuming you have a connected wallet and the token's contract instanceconsttokenContract=newethers.Contract(tokenAddress, tokenABI, wallet);constamountToApprove=ethers.constants.MaxUint256; // Approve maximum for convenienceconstspenderAddress='0x000000000022d473030f116ddee9f6b43ac78ba3'; // Permit2 contract addressawaittokenContract.approve(spenderAddress, amountToApprove);
2. Get a swap quote
To initiate a swap, you first need to query the current swap rate between two tokens. This involves sending a request to our solver API with the details of your intended swap, including the input token, output token, and the amount you wish to swap. Check the solver API reference guide for in-depth details.
Understanding Gas Fees in Transactions
When using intents, it's important to note that a transaction's executor (in this case, the filler) pays for the gas fees. As a result, the gas cost is deducted from the calculated output amount of your transaction. This ensures the network fees are covered, allowing your transaction to be processed smoothly on the blockchain.
To assist the user, we've included the `deduct_gas_cost` parameter. We will automatically convert and deduct the gas cost from the output quote amount when active.
To ensure the uniqueness and sequence of your transactions, you must first fetch a nonce for your swap order. The nonce is a number that represents the current transaction count for your wallet address, ensuring that each transaction is processed exactly once. The nonce is saved in the execution contract, so it's different than the wallet's nonce.
This is the nonce value you should use in your order.
4. Construct the Order
After obtaining the nonce and the price, construct your swap order. This payload outlines the specifics of the swap, including the tokens involved, the amounts, and the timing parameters.
To maintain consistency with other Intent APIs, the order follows the same interface as Uniswap X's Signed Order. To build the order, you can either use UniswapX's SDK - if you're using JavaScript / Typescript or encode the ABI in any other way you'd like.
We are developing our own SDK to allow for quick order creation in several languages.
// ABI["tuple(address,address,uint256,uint256,address,bytes)","uint256","uint256","address","uint256","tuple(address,uint256,uint256)","tuple(address,uint256,uint256,address)[]",]// Schema{"reactor": "Address of the reactor","swapper": "Your wallet address","nonce": "Incremented nonce value","deadline": "UNIX timestamp of the deadline","additionalValidationContract": "Address for additional validation, if any","additionalValidationData": "Data for additional validation, if any","decayStartTime": "UNIX timestamp for decay start","decayEndTime": "UNIX timestamp for decay end","exclusiveFiller": "Address of the exclusive filler, if any","exclusivityOverrideBps": "Basis points for exclusivity override","input": {"token":"Contract address of the input token","startAmount":"Initial amount of the input token","endAmount":"Final amount of the input token" },"outputs": [ {"token":"Contract address of the output token","startAmount":"Initial amount of the output token","endAmount":"Final amount of the output token","recipient":"Recipient's address" } ]}// Example code:constorderData= {// Fill in with the structured order data as per the JSON structure above};constserializedOrder=serialize(orderData);functionserialize(orderData) {constabiCoder=newethers.utils.AbiCoder();returnabiCoder.encode( ["tuple(address,address,uint256,uint256,address,bytes)","uint256","uint256","address","uint256","tuple(address,uint256,uint256)","tuple(address,uint256,uint256,address)[]" ], [ [orderData.reactor,orderData.swapper,orderData.nonce,orderData.deadline,orderData.additionalValidationContract,orderData.additionalValidationData ],orderData.decayStartTime,orderData.decayEndTime,orderData.exclusiveFiller,orderData.exclusivityOverrideBps, [orderData.input.token,orderData.input.startAmount,orderData.input.endAmount ],orderData.outputs.map((output) => [output.token,output.startAmount,output.endAmount,output.recipient ]) ] );}
5. Sign the order
All orders must be signed with your private key.
To sign the provided data for the transaction, users must prepare the data according to the Ethereum EIP-712 standard, which enables typed structured data signing. This process involves specifying a domain, types for the data being signed, and the values of the transaction.
Once the order is signed, submit it to the Propellerswap Helix API for execution. This involves sending a POST request to our order submission endpoint with the order details and signature.