ndtr-dexter
Version:
Customizable Typescript SDK for interacting with Cardano DEXs
113 lines (112 loc) • 5.12 kB
JavaScript
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,
},
];
}
}