UNPKG

@saberhq/stableswap-sdk

Version:
139 lines 5.11 kB
import { deserializeAccount, deserializeMint, parseBigintIsh, Token, TokenAmount, } from "@saberhq/token-utils"; import BN from "bn.js"; import { default as invariant } from "tiny-invariant"; import { SWAP_PROGRAM_ID } from "../constants.js"; import { StableSwap } from "../stable-swap.js"; import { loadProgramAccount } from "../util/account.js"; /** * Calculates the amp factor of a swap. * @param state * @param now * @returns */ export const calculateAmpFactor = (state, now = Date.now() / 1_000) => { const { initialAmpFactor, targetAmpFactor, startRampTimestamp, stopRampTimestamp, } = state; // The most common case is that there is no ramp in progress. if (now >= stopRampTimestamp) { return parseBigintIsh(targetAmpFactor); } // If the ramp is about to start, use the initial amp. if (now <= startRampTimestamp) { return parseBigintIsh(initialAmpFactor); } invariant(stopRampTimestamp >= startRampTimestamp, "stop must be after start"); // Calculate how far we are along the ramp curve. const percent = now >= stopRampTimestamp ? 1 : now <= startRampTimestamp ? 0 : (now - startRampTimestamp) / (stopRampTimestamp - startRampTimestamp); const diff = Math.floor(parseFloat(targetAmpFactor.sub(initialAmpFactor).toString()) * percent); return parseBigintIsh(initialAmpFactor.add(new BN(diff))); }; /** * Creates an IExchangeInfo from parameters. * @returns */ export const makeExchangeInfo = ({ exchange, swap, accounts, }) => { const swapAmountA = deserializeAccount(accounts.reserveA).amount; const swapAmountB = deserializeAccount(accounts.reserveB).amount; const poolMintSupply = accounts.poolMint ? deserializeMint(accounts.poolMint).supply : undefined; const ampFactor = calculateAmpFactor(swap.state); return { ampFactor, fees: swap.state.fees, lpTotalSupply: new TokenAmount(exchange.lpToken, poolMintSupply ?? 0), reserves: [ { reserveAccount: swap.state.tokenA.reserve, adminFeeAccount: swap.state.tokenA.adminFeeAccount, amount: new TokenAmount(exchange.tokens[0], swapAmountA), }, { reserveAccount: swap.state.tokenB.reserve, adminFeeAccount: swap.state.tokenB.adminFeeAccount, amount: new TokenAmount(exchange.tokens[1], swapAmountB), }, ], }; }; /** * Loads exchange info. * @param exchange * @param swap * @returns */ export const loadExchangeInfo = async (connection, exchange, swap) => { if (!exchange.programID.equals(swap.config.swapProgramID)) { throw new Error("Swap program id mismatch"); } const reserveA = await loadProgramAccount(connection, swap.state.tokenA.reserve, swap.config.tokenProgramID); const reserveB = await loadProgramAccount(connection, swap.state.tokenB.reserve, swap.config.tokenProgramID); const poolMint = await loadProgramAccount(connection, swap.state.poolTokenMint, swap.config.tokenProgramID); return makeExchangeInfo({ swap, exchange, accounts: { reserveA, reserveB, poolMint, }, }); }; /** * Creates an IExchange from an ExchangeBasic. * @param tokenMap * @param param1 * @returns */ export const makeExchange = ({ swapAccount, lpToken, tokenA, tokenB, }) => { const exchange = { swapAccount, programID: SWAP_PROGRAM_ID, lpToken: new Token({ symbol: "SLP", name: `${tokenA.symbol}-${tokenB.symbol} Saber LP`, logoURI: "https://app.saber.so/tokens/slp.png", decimals: tokenA.decimals, address: lpToken.toString(), chainId: tokenA.chainId, tags: ["saber-stableswap-lp"], }), tokens: [new Token(tokenA), new Token(tokenB)], }; return exchange; }; /** * Get exchange info from just the swap account. * @param connection * @param swapAccount * @param tokenA * @param tokenB * @returns */ export const loadExchangeInfoFromSwapAccount = async (connection, swapAccount, tokenA = undefined, tokenB = undefined) => { const stableSwap = await StableSwap.load(connection, swapAccount); const theTokenA = tokenA ?? (await Token.load(connection, stableSwap.state.tokenA.mint))?.info; if (!theTokenA) { throw new Error(`Token ${stableSwap.state.tokenA.mint.toString()} not found`); } const theTokenB = tokenB ?? (await Token.load(connection, stableSwap.state.tokenB.mint))?.info; if (!theTokenB) { throw new Error(`Token ${stableSwap.state.tokenB.mint.toString()} not found`); } const exchange = makeExchange({ swapAccount, lpToken: stableSwap.state.poolTokenMint, tokenA: theTokenA, tokenB: theTokenB, }); if (exchange === null) { return null; } return await loadExchangeInfo(connection, exchange, stableSwap); }; //# sourceMappingURL=exchange.js.map