@yoroi/swap
Version:
The Swap package of Yoroi SDK
375 lines (373 loc) • 12.6 kB
JavaScript
"use strict";
import { Portfolio, Swap } from '@yoroi/types';
import { Dex } from './types';
import { isDex } from './validators';
export const ptIdDh = '000000000000000000000000000000000000000000000000000000006c6f76656c616365';
export const toSwapSplit = ({
amount_in = 0,
batcher_fee = 0,
deposits = 0,
dex,
expected_output = 0,
expected_output_without_slippage = 0,
fee = 0,
final_price = 0,
initial_price = 0,
pool_fee = 0,
pool_id = '',
price_distortion = 0,
price_impact = 0
}) => ({
amountIn: amount_in,
batcherFee: batcher_fee,
deposits,
protocol: toSwapProtocol(dex),
expectedOutput: expected_output,
expectedOutputWithoutSlippage: expected_output_without_slippage,
fee,
finalPrice: final_price,
initialPrice: initial_price,
poolFee: pool_fee,
poolId: pool_id,
priceDistortion: price_distortion,
priceImpact: price_impact
});
export const toPriceImpact = splits => {
const totalAmountIn = splits.reduce((sum, split) => sum + (split.amount_in ?? 0), 0);
if (totalAmountIn === 0) return 0; // Avoid division by zero
const weightedPriceImpact = splits.reduce((sum, split) => sum + (split.price_impact ?? 0) * (split.amount_in ?? 0), 0);
return weightedPriceImpact / totalAmountIn;
};
export const transformersMaker = ({
primaryTokenInfo,
address,
isPrimaryToken
}) => {
const fromTokenId = tokenId => tokenId === ptIdDh ? primaryTokenInfo.id : `${tokenId.slice(0, 56)}.${tokenId.slice(56)}`;
const toTokenId = tokenId => isPrimaryToken(tokenId) ? 'ADA' : tokenId.replace('.', '');
return {
tokens: {
fromId: fromTokenId,
toId: toTokenId,
response: res => res.map(({
token_id,
is_verified,
token_decimals = 0,
token_ascii = '',
ticker = ''
}) => {
if (token_id === ptIdDh) return primaryTokenInfo;
return {
id: fromTokenId(token_id),
decimals: token_decimals,
ticker: ticker,
name: token_ascii,
status: is_verified ? Portfolio.Token.Status.Valid : Portfolio.Token.Status.Invalid,
type: Portfolio.Token.Type.FT,
nature: Portfolio.Token.Nature.Secondary,
application: Portfolio.Token.Application.General,
symbol: '',
tag: '',
reference: '',
fingerprint: '',
description: '',
website: '',
originalImage: ''
};
})
},
orders: {
response: res => res.map(({
_id,
dex,
last_update,
submission_time,
output_index,
actual_out_amount = 0,
expected_out_amount = 0,
amount_in = 0,
is_dexhunter = false,
status,
token_id_in = '',
token_id_out = '',
tx_hash = '',
update_tx_hash = ''
}) => ({
status: {
COMPLETE: 'matched',
CANCELLED: 'canceled',
PENDING: 'open'
}[status],
amountIn: amount_in,
actualAmountOut: actual_out_amount,
expectedAmountOut: expected_out_amount,
txHash: tx_hash,
outputIndex: output_index,
updateTxHash: update_tx_hash,
customId: _id,
placedAt: submission_time ? new Date(submission_time).getTime() : undefined,
lastUpdate: last_update ? new Date(last_update).getTime() : undefined,
aggregator: is_dexhunter ? Swap.Aggregator.Dexhunter : Swap.Aggregator.Muesliswap,
protocol: toSwapProtocol(dex),
tokenIn: fromTokenId(token_id_in),
tokenOut: fromTokenId(token_id_out)
}))
},
cancel: {
request: ({
order
}) => ({
address,
order_id: order.customId
}),
response: ({
additional_cancellation_fee,
cbor = ''
}) => ({
cbor,
additionalCancellationFee: additional_cancellation_fee
})
},
estimate: {
request: ({
amountIn,
blockedProtocols,
slippage,
tokenIn,
tokenOut
}) => ({
slippage,
amount_in: amountIn,
blacklisted_dexes: blockedProtocols?.map(fromSwapProtocol).filter(isDex),
token_in: toTokenId(tokenIn),
token_out: toTokenId(tokenOut)
}),
response: ({
splits,
batcher_fee = 0,
deposits = 0,
dexhunter_fee = 0,
net_price = 0,
net_price_reverse = 0,
partner_fee = 0,
total_output = 0,
total_output_without_slippage = 0
}, reversed) => ({
deposits,
splits: splits?.map(toSwapSplit) ?? [],
totalOutputWithoutSlippage: total_output_without_slippage,
totalInput: splits?.reduce((acc, cur) => acc + (cur.amount_in ?? 0), 0) ?? undefined,
batcherFee: batcher_fee,
aggregatorFee: dexhunter_fee,
frontendFee: partner_fee,
netPrice: reversed ? net_price_reverse : net_price,
priceImpact: toPriceImpact(splits ?? []),
totalFee: Number((batcher_fee + dexhunter_fee + partner_fee).toFixed(primaryTokenInfo.decimals)),
totalOutput: total_output
})
},
reverseEstimate: {
request: ({
amountOut,
blockedProtocols,
slippage,
tokenIn,
tokenOut
}) => ({
slippage,
amount_out: amountOut,
blacklisted_dexes: blockedProtocols?.map(fromSwapProtocol).filter(isDex),
token_in: toTokenId(tokenIn),
token_out: toTokenId(tokenOut)
}),
response: ({
batcher_fee = 0,
deposits = 0,
dexhunter_fee = 0,
net_price = 0,
net_price_reverse = 0,
partner_fee = 0,
splits,
total_input = 0,
total_output = 0
}, reversed) => ({
deposits,
batcherFee: batcher_fee,
aggregatorFee: dexhunter_fee,
frontendFee: partner_fee,
netPrice: reversed ? net_price_reverse : net_price,
priceImpact: toPriceImpact(splits ?? []),
totalFee: Number((batcher_fee + dexhunter_fee + partner_fee).toFixed(primaryTokenInfo.decimals)),
totalOutput: total_output,
totalOutputWithoutSlippage: total_output,
splits: splits?.map(toSwapSplit) ?? [],
totalInput: (total_input || splits?.reduce((acc, cur) => acc + (cur.amount_in ?? 0), 0)) ?? undefined
})
},
limitEstimate: {
request: ({
protocol = Swap.Protocol.Unsupported,
multiples = 1,
amountIn,
blockedProtocols,
tokenIn,
tokenOut,
wantedPrice
}) => ({
multiples,
amount_in: amountIn,
wanted_price: isPrimaryToken(tokenIn) && wantedPrice !== undefined && wantedPrice !== 0 ? 1 / wantedPrice : wantedPrice,
blacklisted_dexes: blockedProtocols?.map(fromSwapProtocol).filter(isDex),
dex: fromSwapProtocol(protocol),
token_in: toTokenId(tokenIn),
token_out: toTokenId(tokenOut)
}),
response: ({
splits,
batcher_fee = 0,
deposits = 0,
dexhunter_fee = 0,
net_price = 0,
partner_fee = 0,
total_input = 0,
total_output = 0
}, reversed) => ({
deposits,
batcherFee: batcher_fee,
aggregatorFee: dexhunter_fee,
frontendFee: partner_fee,
netPrice: reverse(reversed, net_price),
priceImpact: toPriceImpact(splits ?? []),
totalFee: Number((batcher_fee + dexhunter_fee + partner_fee).toFixed(primaryTokenInfo.decimals)),
totalOutput: total_output,
totalOutputWithoutSlippage: total_output,
splits: splits?.map(toSwapSplit) ?? [],
totalInput: (total_input || splits?.reduce((acc, cur) => acc + (cur.amount_in ?? 0), 0)) ?? undefined
})
},
limitBuild: {
request: ({
amountIn,
blockedProtocols,
protocol,
multiples,
tokenIn,
tokenOut,
wantedPrice
}) => ({
multiples,
buyer_address: address,
amount_in: amountIn,
wanted_price: isPrimaryToken(tokenIn) && wantedPrice !== undefined && wantedPrice !== 0 ? 1 / wantedPrice : wantedPrice,
token_in: toTokenId(tokenIn),
token_out: toTokenId(tokenOut),
blacklisted_dexes: blockedProtocols?.map(fromSwapProtocol).filter(isDex),
dex: protocol ? fromSwapProtocol(protocol) : undefined
}),
response: ({
cbor = '',
batcher_fee = 0,
deposits = 0,
dexhunter_fee = 0,
partner_fee = 0,
splits,
total_input = 0,
total_output = 0
}, reversed) => ({
cbor,
deposits,
aggregator: Swap.Aggregator.Dexhunter,
batcherFee: batcher_fee,
aggregatorFee: dexhunter_fee,
frontendFee: partner_fee / 10 ** primaryTokenInfo.decimals,
netPrice: reverse(reversed, splits?.[0]?.initial_price ?? 0),
totalOutput: total_output,
totalOutputWithoutSlippage: total_output,
priceImpact: toPriceImpact(splits ?? []),
totalFee: Number((batcher_fee + dexhunter_fee + partner_fee / 10 ** primaryTokenInfo.decimals).toFixed(primaryTokenInfo.decimals)),
splits: splits?.map(toSwapSplit) ?? [],
totalInput: (total_input || splits?.reduce((acc, cur) => acc + (cur.amount_in ?? 0), 0)) ?? 0
})
},
build: {
request: ({
slippage = 0,
amountIn,
blockedProtocols,
tokenIn,
tokenOut,
inputs
}) => ({
slippage,
amount_in: amountIn,
buyer_address: address,
blacklisted_dexes: blockedProtocols?.map(fromSwapProtocol).filter(isDex),
token_in: toTokenId(tokenIn),
token_out: toTokenId(tokenOut),
inputs
}),
response: ({
splits,
cbor = '',
batcher_fee = 0,
deposits = 0,
dexhunter_fee = 0,
net_price = 0,
net_price_reverse = 0,
partner_fee = 0,
total_input = 0,
total_output = 0,
total_output_without_slippage = 0
}, reversed) => ({
aggregator: Swap.Aggregator.Dexhunter,
cbor,
deposits,
batcherFee: batcher_fee,
aggregatorFee: dexhunter_fee,
frontendFee: partner_fee,
netPrice: (reversed ? net_price_reverse || reverse(true, splits?.[0]?.initial_price ?? 0) : net_price || splits?.[0]?.initial_price) ?? 0,
// main net_price is coming as 0 :(
priceImpact: toPriceImpact(splits ?? []),
totalOutput: total_output,
totalFee: Number((batcher_fee + dexhunter_fee + partner_fee).toFixed(primaryTokenInfo.decimals)),
totalOutputWithoutSlippage: total_output_without_slippage,
totalInput: (total_input || splits?.reduce((acc, cur) => acc + (cur.amount_in ?? 0), 0)) ?? 0,
splits: splits?.map(toSwapSplit) ?? []
})
}
};
};
export const toSwapProtocol = dex => ({
[Dex.Cswap]: Swap.Protocol.Cswap,
[Dex.Minswap_v1]: Swap.Protocol.Minswap_v1,
[Dex.Minswap_v2]: Swap.Protocol.Minswap_v2,
[Dex.Wingriders_v1]: Swap.Protocol.Wingriders_v1,
[Dex.Wingriders_v2]: Swap.Protocol.Wingriders_v2,
[Dex.Vyfi_v1]: Swap.Protocol.Vyfi_v1,
[Dex.Sundaeswap_v1]: Swap.Protocol.Sundaeswap_v1,
[Dex.Sundaeswap_v3]: Swap.Protocol.Sundaeswap_v3,
[Dex.Splash_v1]: Swap.Protocol.Splash_v1,
[Dex.Muesliswap_clp]: Swap.Protocol.Muesliswap_clp,
[Dex.Muesliswap_v2]: Swap.Protocol.Muesliswap_v2,
[Dex.Unsupported]: Swap.Protocol.Unsupported
})[dex] ?? Swap.Protocol.Unsupported;
export const fromSwapProtocol = dex => ({
[Swap.Protocol.Cswap]: Dex.Cswap,
[Swap.Protocol.Minswap_v1]: Dex.Minswap_v1,
[Swap.Protocol.Minswap_v2]: Dex.Minswap_v2,
[Swap.Protocol.Minswap_stable]: Dex.Unsupported,
[Swap.Protocol.Wingriders_v1]: Dex.Wingriders_v1,
[Swap.Protocol.Wingriders_v2]: Dex.Wingriders_v2,
[Swap.Protocol.Vyfi_v1]: Dex.Vyfi_v1,
[Swap.Protocol.Sundaeswap_v1]: Dex.Sundaeswap_v1,
[Swap.Protocol.Sundaeswap_v3]: Dex.Sundaeswap_v3,
[Swap.Protocol.Splash_v1]: Dex.Splash_v1,
[Swap.Protocol.Teddy_v1]: Dex.Unsupported,
[Swap.Protocol.Muesliswap_v2]: Dex.Muesliswap_v2,
[Swap.Protocol.Muesliswap_clp]: Dex.Muesliswap_clp,
[Swap.Protocol.Spectrum_v1]: Dex.Unsupported,
[Swap.Protocol.Unsupported]: Dex.Unsupported
})[dex] ?? Dex.Unsupported;
export const DexhunterProtocols = Object.values(Dex).filter(p => p !== Dex.Unsupported).map(toSwapProtocol);
export const reverse = (reversed, price) => !reversed || price === 0 || price === undefined ? price : 1 / price;
//# sourceMappingURL=transformers.js.map