Simple HOT Swap Example
A simple Typescript example to make a HOT swap on the Arbitrum pool, also available here: https://github.com/ValantisLabs/valantis-hot/tree/main/scripts/hot-example Note:
Make sure that there are enough WETH funds in the account that is set as
authorized_sender
. Currently this value is 0.0001 WETH, and the authorized sender is automatically set as the public key of the account whos private key is provided as the environment variable.Make sure that appropriate approvals are given to the sovereign pool address, before this request is sent. All deployment addresses can be found here.
main.ts
import { privateKeyToAccount } from 'viem/accounts';
import { gnosis, arbitrum } from 'viem/chains';
import { Address, createWalletClient, http, publicActions } from 'viem';
import { SignTypedDataReturnType } from 'viem';
import { fetchAmountOut } from './utils/price-api';
async function swap() {
const headers = {
'Content-Type': 'application/json',
'X-API-Key': `${process.env.API_KEY}`,
};
const account = privateKeyToAccount(`0x${process.env.PK}`);
// 0.0001 * 1e18 ether
const AMOUNT_IN = BigInt('100000000000000');
// Fetch latest price from Binance API.
// Liquidity Manager will attempt to match or improve it
// Optionally: Set to 0 and it works as a standard RFQ API
const AMOUNT_OUT = await fetchAmountOut(AMOUNT_IN);
const requestParams = JSON.stringify({
authorized_recipient: account.address, // address which receives token out
authorized_sender: account.address, // should be same address which calls pool contract
chain_id: 42161, // 1 for mainnet, 42161 for arbitrum
token_in: '0x82af49447d8a07e3bd95bd0d56f35241523fbab1', // weth on arbitrum (0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 for mainnet)
token_out: '0xaf88d065e77c8cc2239327c5edb3a432268e5831', // USDC on arbitrum (0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 for mainnet)
expected_gas_price: '0',
expected_gas_units: '0',
amount_in: AMOUNT_IN.toString(),
amount_out_requested: AMOUNT_OUT.toString(),
request_expiry: Math.ceil(Date.now() / 1000) + 30, // Expiry in 30 seconds,
quote_expiry: Math.ceil(Date.now() / 1000) + 120, // Quote valid for 120 seconds
});
const requestOptions: RequestInit = {
body: requestParams,
method: 'POST',
headers,
};
const response = await fetch('https://hot.valantis.xyz/solver/order', requestOptions);
const data = await response.json();
console.log(data);
const quote = data as {
pool_address: Address;
signed_payload: SignTypedDataReturnType;
};
const walletClient = createWalletClient({
name: 'Main',
account,
chain: arbitrum, // set to `mainnet` for mainnet
transport: http(`${process.env.ARBITRUM_RPC}`), //Set to MAINNET_RPC for mainnet
}).extend(publicActions);
if (!quote.signed_payload) {
console.log('Could not get signed payload');
return;
}
const txHash = await walletClient.sendTransaction({
account,
chain: arbitrum,
to: quote.pool_address,
value: 0n,
data: quote.signed_payload,
gas: 1_000_000n,
});
console.log(txHash);
}
swap();
main.ts
import { AddressLike, Wallet, ethers } from 'ethers';
import { fetchAmountOut } from './utils/price-api';
async function swap() {
const headers = {
'Content-Type': 'application/json',
'X-API-Key': `${process.env.API_KEY}`,
};
const chainId = 42161; // Set to 100 for arbitrum, 1 for mainnet
const provider = new ethers.JsonRpcProvider(`${process.env.ARBITRUM_RPC}`); // Set to MAINNET_RPC for mainnet
const account = new Wallet(`0x${process.env.PK}`, provider);
// 0.0001 * 1e18 ether
const AMOUNT_IN = BigInt('100000000000000');
// Fetch latest price from Binance API.
// Liquidity Manager will attempt to match or improve it
// Optionally: Set to 0 and it works as a standard RFQ API
const AMOUNT_OUT = await fetchAmountOut(AMOUNT_IN);
const requestParams = JSON.stringify({
authorized_recipient: account.address, // address which receives token out
authorized_sender: account.address, // should be same address which calls pool contract
chain_id: chainId, // 1 for mainnet, 100 for arbitrum
token_in: '0x82af49447d8a07e3bd95bd0d56f35241523fbab1', // weth on arbitrum (0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 for mainnet)
token_out: '0xaf88d065e77c8cc2239327c5edb3a432268e5831', // USDC on arbitrum (0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 for mainnet)
expected_gas_price: '0',
expected_gas_units: '0',
amount_in: AMOUNT_IN.toString(), // 0.0001 * 1e18 ether
amount_out_requested: AMOUNT_OUT.toString(), // 0.29 * 1e6 USDC
request_expiry: Math.ceil(Date.now() / 1000) + 30, // Expiry in 30 seconds
quote_expiry: Math.ceil(Date.now() / 1000) + 120, // Quote valid for 120 seconds
});
const requestOptions = {
body: requestParams,
method: 'POST',
headers,
};
const response = await fetch('https://hot.valantis.xyz/solver/order', requestOptions);
const data = await response.json();
console.log(data);
const quote = data as {
pool_address: AddressLike;
signed_payload: string;
volume_token_out: string;
amount_out_min_payload_offset: number;
amount_payload_offset: number;
gas_price: number;
};
if (!quote.signed_payload) {
console.log('Could not get signed payload');
return;
}
const tx = await account.sendTransaction({
to: quote.pool_address,
data: quote.signed_payload,
gasLimit: 1_000_000n,
});
const receipt = await tx.wait();
console.log(receipt?.hash);
}
swap();
Last updated