UNPKG

@jovanvuleta/test-dex-sdk

Version:

Utilities to query Stacks AMMs

195 lines (192 loc) 6.06 kB
// src/velar.ts import { callReadOnlyFunction, Cl, cvToJSON } from "@stacks/transactions"; async function getVelarPoolData(velarContractAddress, tokenInName, tokenInAddress, tokenOutName, tokenOutAddress, network, sender = "ST2F4BK4GZH6YFBNHYDDGN4T1RKBA7DA1BJZPJEJJ") { const contractName = "univ2-core"; const functionName = "get-pool-id"; const options = { contractAddress: velarContractAddress, contractName, functionName, functionArgs: [ Cl.contractPrincipal(tokenInAddress, tokenInName), Cl.contractPrincipal(tokenOutAddress, tokenOutName) ], network, senderAddress: sender }; const poolId = await callReadOnlyFunction(options); if (poolId.type == 8 || poolId.type == 9) throw "Pool does not exist"; options.functionName = "lookup-pool"; const poolData = await callReadOnlyFunction(options); if (poolData.type == 8) throw "Quoter contract error"; return { poolId: poolId.value.value, flipped: poolData.value.data.flipped.type == 4 ? false : true, lpToken: cvToJSON(poolData.value.data.pool.data["lp-token"]).value, token0: cvToJSON(poolData.value.data.pool.data.token0).value, token1: cvToJSON(poolData.value.data.pool.data.token1).value, reserve0: poolData.value.data.pool.data.reserve0.value, reserve1: poolData.value.data.pool.data.reserve1.value, swapFee: { num: poolData.value.data.pool.data["swap-fee"].data.num.value, den: poolData.value.data.pool.data["swap-fee"].data.den.value }, shareFee: { num: poolData.value.data.pool.data["share-fee"].data.num.value, den: poolData.value.data.pool.data["share-fee"].data.den.value }, protocolFee: { num: poolData.value.data.pool.data["protocol-fee"].data.num.value, den: poolData.value.data.pool.data["protocol-fee"].data.den.value } }; } async function velarQuoter(velarContractAddress, amtIn, tokenInName, tokenInAddress, tokenOutName, tokenOutAddress, network, sender = "ST2F4BK4GZH6YFBNHYDDGN4T1RKBA7DA1BJZPJEJJ") { const result = await getVelarPoolData( velarContractAddress, tokenInName, tokenInAddress, tokenOutName, tokenOutAddress, "mainnet" ); const contractName = "univ2-library"; const functionName = "get-amount-out"; const options = { contractAddress: velarContractAddress, contractName, functionName, functionArgs: [ Cl.uint(amtIn), Cl.uint(result.reserve0), Cl.uint(result.reserve1), Cl.tuple({ num: Cl.uint(result.swapFee.num), den: Cl.uint(result.swapFee.den) }) ], network, senderAddress: sender }; const amtOut = await callReadOnlyFunction(options); if (amtOut.type == 8) throw "Quoter contract error"; return amtOut.value.value; } // src/alex.ts import { callReadOnlyFunction as callReadOnlyFunction2, Cl as Cl2 } from "@stacks/transactions"; async function getAlexPoolData(alexContractAddress, tokenInName, tokenInAddress, tokenOutName, tokenOutAddress, factor, network, sender = "ST2F4BK4GZH6YFBNHYDDGN4T1RKBA7DA1BJZPJEJJ") { const contractName = "amm-registry-v2-01"; const functionName = "get-pool-details"; const options = { contractAddress: alexContractAddress, contractName, functionName, functionArgs: [ Cl2.contractPrincipal(tokenInAddress, tokenInName), Cl2.contractPrincipal(tokenOutAddress, tokenOutName), Cl2.uint(factor) ], network, senderAddress: sender }; const poolData = await callReadOnlyFunction2(options); if (poolData.type == 8) throw "Pool does not exist"; return { poolId: poolData.value.data["pool-id"].value, balanceX: poolData.value.data["balance-x"].value, balanceY: poolData.value.data["balance-y"].value }; } async function alexQuoter(alexContractAddress, amtIn, tokenInName, tokenInAddress, tokenOutName, tokenOutAddress, network, sender = "ST2F4BK4GZH6YFBNHYDDGN4T1RKBA7DA1BJZPJEJJ") { const alexFactor0 = 1e8; const alexFactor1 = 5e6; const contractName = "amm-pool-v2-01"; const functionName = "get-helper"; const options = { contractAddress: alexContractAddress, contractName, functionName, functionArgs: [ Cl2.contractPrincipal(tokenInAddress, tokenInName), Cl2.contractPrincipal(tokenOutAddress, tokenOutName), Cl2.uint(alexFactor0), Cl2.uint(amtIn) // dx ], network, senderAddress: sender }; let amtOut = await callReadOnlyFunction2(options); if (amtOut.type == 8) { options.functionArgs[2] = Cl2.uint(alexFactor1); amtOut = await callReadOnlyFunction2(options); if (amtOut.type == 8) throw "Quoter contract error"; } return { amtOut: amtOut.value.value, factor: options.functionArgs[2] }; } // src/aggregator.ts async function getBestPath(velar, alex, amtIn, tokenInName, tokenInAddress, tokenOutName, tokenOutAddress, network) { let velarAmtOut; try { velarAmtOut = await velarQuoter( velar, amtIn, tokenInName, tokenInAddress, tokenOutName, tokenOutAddress, network ); } catch { velarAmtOut = 0n; } let alexAmtOut; let alexPoolData = {}; try { alexPoolData = await alexQuoter( alex, amtIn, tokenInName, tokenInAddress, tokenOutName, tokenOutAddress, network ); alexAmtOut = alexPoolData.amtOut; } catch { alexAmtOut = 0n; } const dex = alexAmtOut > velarAmtOut ? "alex" : "velar"; let data = {}; let poolData = {}; if (dex == "velar") { poolData = await getVelarPoolData( velar, tokenInName, tokenInAddress, tokenOutName, tokenOutAddress, network ); data = { ...poolData, shareFeeTo: "SP1Y5YSTAHZ88XYK1VPDH24GY0HPX5J4JECTMY4A1.univ2-share-fee-to" }; } else { data = { factor: alexPoolData.factor }; } return { dex, amtOut: alexAmtOut > velarAmtOut ? alexAmtOut : velarAmtOut, data }; } export { alexQuoter, getAlexPoolData, getBestPath, getVelarPoolData, velarQuoter };