Last active
February 13, 2025 13:47
-
-
Save zengzengzenghuy/c53aec325e8e701b4f902a029c90290b to your computer and use it in GitHub Desktop.
Rebalance logic for intent solver
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { | |
| createClient, | |
| getClient, | |
| convertViemChainToRelayChain, | |
| MAINNET_RELAY_API, | |
| adaptViemWallet, | |
| } from "@reservoir0x/relay-sdk"; | |
| import { createWalletClient, http, parseUnits, publicActions } from "viem"; | |
| import { arbitrum, base } from "viem/chains"; | |
| import { privateKeyToAccount } from "viem/accounts"; | |
| const SOLVER_ADDRESS = "0xab6395320249174313457713e46d01528dd959ab"; | |
| const PRIVATE_KEY = ""; | |
| const USDC_ADDRESSES = { | |
| arbitrum: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", | |
| base: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", | |
| }; | |
| const CHECK_INTERVAL = 30000; // 5 seconds | |
| const THRESHOLD = parseUnits("200", 6); // 200 USDC with 6 decimals | |
| const REFILLED_BALANCE = parseUnits("500", 6); | |
| // Viem clients for both chains | |
| const account = privateKeyToAccount(PRIVATE_KEY); | |
| const clients = { | |
| arbitrum: createWalletClient({ | |
| chain: arbitrum, | |
| transport: http(), | |
| account, | |
| }).extend(publicActions), | |
| base: createWalletClient({ | |
| chain: base, | |
| transport: http(), | |
| account, | |
| }).extend(publicActions), | |
| }; | |
| // Initialize Relay SDK client | |
| createClient({ | |
| baseApiUrl: "https://api.reservoir.tools", // MAINNET_RELAY_API | |
| chains: [ | |
| convertViemChainToRelayChain(arbitrum), | |
| convertViemChainToRelayChain(base), | |
| ], | |
| }); | |
| process.on("unhandledRejection", (reason, promise) => { | |
| // TODO: fix APIError | |
| console.error("Unhandled Rejection at:", promise, "reason:", reason); | |
| }); | |
| async function getUsdcBalance(chain, address) { | |
| const client = clients[chain]; | |
| const usdcAddress = USDC_ADDRESSES[chain]; | |
| return await client.readContract({ | |
| address: usdcAddress, | |
| abi: [ | |
| { | |
| type: "function", | |
| name: "balanceOf", | |
| inputs: [{ name: "account", type: "address" }], | |
| outputs: [{ type: "uint256" }], | |
| stateMutability: "view", | |
| }, | |
| ], | |
| functionName: "balanceOf", | |
| args: [address], | |
| }); | |
| } | |
| function convertRelayChainToViemChain(chainName) { | |
| switch (chainName) { | |
| case "Arbitrum One": | |
| return "arbitrum"; | |
| case "Base": | |
| return "base"; | |
| default: | |
| return "arbitrum"; | |
| } | |
| } | |
| async function rebalance(fromChain, toChain, amount) { | |
| try { | |
| // const quote = await getClient()?.actions.getQuote({ | |
| // chainId: fromChain.id, | |
| // toChainId: toChain.id, | |
| // currency: USDC_ADDRESSES[convertRelayChainToViemChain(fromChain.name)], | |
| // toCurrency: USDC_ADDRESSES[convertRelayChainToViemChain(toChain.name)], | |
| // amount: amount.toString(), | |
| // }); | |
| const options = { | |
| method: "POST", | |
| headers: { "Content-Type": "application/json" }, | |
| body: `{"user": "${SOLVER_ADDRESS}","recipient":"${SOLVER_ADDRESS}","originChainId":${ | |
| fromChain.id | |
| },"destinationChainId":${toChain.id},"originCurrency":"${ | |
| USDC_ADDRESSES[convertRelayChainToViemChain(fromChain.name)] | |
| }","destinationCurrency": "${ | |
| USDC_ADDRESSES[convertRelayChainToViemChain(toChain.name)] | |
| }","amount": "${amount.toString()}","tradeType":"EXACT_INPUT", "refundTo":"${SOLVER_ADDRESS}"}`, | |
| }; | |
| const response = await fetch("https://api.relay.link/quote", options); | |
| if (!response.ok) { | |
| throw new Error(`Failed to get quote: ${response.statusText}`); | |
| } | |
| const responseData = await response.json(); | |
| console.log(responseData); | |
| console.log("Executing swap..."); | |
| await getClient().actions.execute({ | |
| quote: responseData, | |
| wallet: adaptViemWallet( | |
| clients[convertRelayChainToViemChain(fromChain.name)] | |
| ), | |
| onProgress: ({ currentStep, txHashes }) => { | |
| try { | |
| console.log(`Step: ${currentStep?.action}, TxHashes: ${txHashes}`); | |
| } catch (err) { | |
| console.error(`Progress callback error: ${err.message}`); | |
| } | |
| }, | |
| }); | |
| } catch (error) { | |
| console.error(`Rebalance failed: ${error.message}`); | |
| } | |
| } | |
| async function monitorBalances() { | |
| try { | |
| const [arbitrumBalance, baseBalance] = await Promise.all([ | |
| getUsdcBalance("arbitrum", SOLVER_ADDRESS), | |
| getUsdcBalance("base", SOLVER_ADDRESS), | |
| ]); | |
| console.log( | |
| `Balances - Arbitrum: ${arbitrumBalance / BigInt(1e6)} USDC, Base: ${ | |
| baseBalance / BigInt(1e6) | |
| } USDC` | |
| ); | |
| const balances = { arbitrum: arbitrumBalance, base: baseBalance }; | |
| for (const chain of ["arbitrum", "base"]) { | |
| if (balances[chain] < THRESHOLD) { | |
| console.log( | |
| `Solver ${SOLVER_ADDRESS} balance on ${chain} is ${ | |
| balances[chain] / BigInt(1e6) | |
| } USDC, below threshold ${THRESHOLD / BigInt(1e6)}, rebalancing...` | |
| ); | |
| const otherChain = chain === "arbitrum" ? "base" : "arbitrum"; | |
| const deficit = THRESHOLD - balances[chain]; | |
| console.log("Deficit ", deficit); | |
| if (balances[otherChain] - deficit > THRESHOLD) { | |
| await rebalance( | |
| clients[otherChain].chain, | |
| clients[chain].chain, | |
| deficit | |
| ); | |
| } else { | |
| console.warn( | |
| `Not enough funds on ${otherChain} to rebalance ${chain}` | |
| ); | |
| } | |
| } | |
| } | |
| } catch (error) { | |
| console.error(`Monitor error: ${error.message}`); | |
| } | |
| } | |
| setInterval(async () => { | |
| try { | |
| await monitorBalances(); | |
| } catch (error) { | |
| console.error(`Interval Monitor Error: ${error.message}`); | |
| } | |
| }, CHECK_INTERVAL); | |
| console.log("Monitoring USDC balances..."); |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
yarn add @reservoir0x/relay-sdk viem