UNPKG

ndtr-dexter

Version:

Customizable Typescript SDK for interacting with Cardano DEXs

113 lines (112 loc) 5.12 kB
import { BaseDex } from './base-dex'; import { DefinitionBuilder } from '../definition-builder'; import { correspondingReserves } from '../utils'; import { AddressType, DatumParameterKey } from '../constants'; import order from './definitions/vyfinance/order'; import { VyfinanceApi } from './api/vyfinance-api'; /** * VyFinance constants. */ const SWAP_ACTION_EXPECT_ASSET = 3; const SWAP_ACTION_EXPECT_ADA = 4; export class VyFinance extends BaseDex { constructor(requestConfig = {}) { super(); this.name = 'VyFinance'; this.api = new VyfinanceApi(this, requestConfig); } async liquidityPoolAddresses(provider) { return Promise.reject('Not implemented as VyFinance pools are not easily identifiable on-chain.'); } async liquidityPools(provider) { return Promise.reject('Not implemented as VyFinance pools are not easily identifiable on-chain.'); } liquidityPoolFromUtxo(provider, utxo) { return Promise.reject('Not implemented until pools are identifiable on-chain'); } estimatedGive(liquidityPool, swapOutToken, swapOutAmount) { const poolFeeMultiplier = 1000n; const poolFeeModifier = poolFeeMultiplier - BigInt(Math.round((liquidityPool.poolFeePercent / 100) * Number(poolFeeMultiplier))); const [reserveOut, reserveIn] = correspondingReserves(liquidityPool, swapOutToken); const swapInNumerator = swapOutAmount * reserveIn * poolFeeMultiplier; const swapInDenominator = (reserveOut - swapOutAmount) * poolFeeModifier; return swapInNumerator / swapInDenominator + 1n; } estimatedReceive(liquidityPool, swapInToken, swapInAmount) { const poolFeeMultiplier = 1000n; const poolFeeModifier = poolFeeMultiplier - BigInt(Math.round((liquidityPool.poolFeePercent / 100) * Number(poolFeeMultiplier))); const [reserveIn, reserveOut] = correspondingReserves(liquidityPool, swapInToken); const swapOutNumerator = swapInAmount * reserveOut * poolFeeModifier; const swapOutDenominator = swapInAmount * poolFeeModifier + reserveIn * poolFeeMultiplier; return swapOutNumerator / swapOutDenominator; } priceImpactPercent(liquidityPool, swapInToken, swapInAmount) { const [reserveIn, reserveOut] = correspondingReserves(liquidityPool, swapInToken).map((x) => Number(x)); const estimatedReceive = Number(this.estimatedReceive(liquidityPool, swapInToken, swapInAmount)); const swapFee = Number(swapInAmount) * liquidityPool.poolFeePercent / 100; return (1 - estimatedReceive / ((Number(swapInAmount) - swapFee) * (reserveOut / reserveIn))) * 100; } async buildSwapOrder(liquidityPool, swapParameters) { const isDoubleSidedSwap = swapParameters.SwapInTokenPolicyId !== '' && swapParameters.SwapOutTokenPolicyId !== ''; const swapDirection = swapParameters.SwapInTokenPolicyId === '' || isDoubleSidedSwap ? SWAP_ACTION_EXPECT_ASSET : SWAP_ACTION_EXPECT_ADA; swapParameters = { ...swapParameters, [DatumParameterKey.Action]: swapDirection, [DatumParameterKey.SenderKeyHashes]: swapParameters.SenderPubKeyHash + swapParameters.SenderStakingKeyHash, }; const datumBuilder = new DefinitionBuilder(); await datumBuilder.loadDefinition(order) .then((builder) => { builder.pushParameters(swapParameters); }); return [ this.buildSwapOrderPayment(swapParameters, { address: liquidityPool.marketOrderAddress, addressType: AddressType.Contract, assetBalances: [ { asset: 'lovelace', quantity: this.swapOrderFees().reduce((feeAmount, fee) => feeAmount + fee.value, 0n), }, ], datum: datumBuilder.getCbor(), }) ]; } async buildCancelSwapOrder(txOutputs, returnAddress) { const relevantUtxo = txOutputs.find((utxo) => { return utxo.address !== returnAddress; }); if (!relevantUtxo) { return Promise.reject('Unable to find relevant UTxO for cancelling the swap order.'); } return [ { address: returnAddress, addressType: AddressType.Base, assetBalances: relevantUtxo.assetBalances, spendUtxos: [relevantUtxo], } ]; } swapOrderFees() { return [ { id: 'processFee', title: 'Process Fee', description: 'Fee paid to the off-chain processor fulfilling order.', value: 1900000n, isReturned: false, }, { id: 'minAda', title: 'MinADA', description: 'MinADA will be held in the UTxO and returned when the order is processed.', value: 2000000n, isReturned: true, }, ]; } }