mirror of
https://github.com/orionprotocol/sdk.git
synced 2026-03-14 06:02:36 +03:00
fix: swapMarket and swapLimit
This commit is contained in:
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@orionprotocol/sdk",
|
||||
"version": "0.20.38",
|
||||
"version": "0.20.39",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@orionprotocol/sdk",
|
||||
"version": "0.20.38",
|
||||
"version": "0.20.39",
|
||||
"hasInstallScript": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
|
||||
@@ -12,6 +12,10 @@ import { signOrder } from '../../crypt/index.js';
|
||||
import type orderSchema from '../../services/Aggregator/schemas/orderSchema.js';
|
||||
import type { z } from 'zod';
|
||||
import { simpleFetch } from 'simple-typed-fetch';
|
||||
import { generateSwapCalldata } from './generateSwapCalldata.js';
|
||||
import isValidFactory from '../../utils/isValidFactory.js';
|
||||
import type { SingleSwap } from '../../types.js';
|
||||
import { must, safeGet } from '../../utils/safeGetters.js';
|
||||
|
||||
export type SwapLimitParams = {
|
||||
type: 'exactSpend' | 'exactReceive'
|
||||
@@ -49,6 +53,10 @@ type PoolSwap = {
|
||||
|
||||
export type Swap = AggregatorOrder | PoolSwap;
|
||||
|
||||
const isValidSingleSwap = (singleSwap: Omit<SingleSwap, 'factory'> & { factory: string }): singleSwap is SingleSwap => {
|
||||
return isValidFactory(singleSwap.factory);
|
||||
}
|
||||
|
||||
export default async function swapLimit({
|
||||
type,
|
||||
assetIn,
|
||||
@@ -85,6 +93,7 @@ export default async function swapLimit({
|
||||
exchangeContractAddress,
|
||||
matcherAddress,
|
||||
assetToAddress,
|
||||
swapExecutorContractAddress,
|
||||
} = await simpleFetch(blockchainService.getInfo)();
|
||||
const nativeCryptocurrency = getNativeCryptocurrencyName(assetToAddress);
|
||||
|
||||
@@ -92,7 +101,8 @@ export default async function swapLimit({
|
||||
const feeAssets = await simpleFetch(blockchainService.getPlatformFees)({ walletAddress, assetIn, assetOut });
|
||||
const allPrices = await simpleFetch(blockchainService.getPricesWithQuoteAsset)();
|
||||
const gasPriceWei = await simpleFetch(blockchainService.getGasPriceWei)();
|
||||
const { factories } = await simpleFetch(blockchainService.getPoolsConfig)();
|
||||
const { factories, WETHAddress } = await simpleFetch(blockchainService.getPoolsConfig)();
|
||||
must(WETHAddress, 'WETHAddress is not defined');
|
||||
const poolExchangesList = factories !== undefined ? Object.keys(factories) : [];
|
||||
|
||||
const gasPriceGwei = ethers.formatUnits(gasPriceWei, 'gwei').toString();
|
||||
@@ -138,7 +148,7 @@ export default async function swapLimit({
|
||||
: undefined,
|
||||
);
|
||||
|
||||
const { exchanges: swapExchanges } = swapInfo;
|
||||
const { exchanges: swapExchanges, exchangeContractPath } = swapInfo;
|
||||
|
||||
const [firstSwapExchange] = swapExchanges;
|
||||
|
||||
@@ -236,12 +246,6 @@ export default async function swapLimit({
|
||||
if (factoryAddress !== undefined) options?.logger?.(`Factory address is ${factoryAddress}. Exchange is ${firstSwapExchange}`);
|
||||
}
|
||||
|
||||
const pathAddresses = swapInfo.path.map((name) => {
|
||||
const assetAddress = assetToAddress[name];
|
||||
if (assetAddress === undefined) throw new Error(`No asset address for ${name}`);
|
||||
return assetAddress;
|
||||
});
|
||||
|
||||
const amountSpend = swapInfo.type === 'exactSpend'
|
||||
? swapInfo.amountIn
|
||||
: new BigNumber(swapInfo.orderInfo.amount).multipliedBy(swapInfo.orderInfo.safePrice)
|
||||
@@ -271,33 +275,52 @@ export default async function swapLimit({
|
||||
BigNumber.ROUND_FLOOR,
|
||||
);
|
||||
|
||||
const unsignedSwapThroughOrionPoolTx = await exchangeContract.swapThroughOrionPool.populateTransaction(
|
||||
amountSpendBlockchainParam,
|
||||
amountReceiveBlockchainParam,
|
||||
factoryAddress !== undefined
|
||||
? [factoryAddress, ...pathAddresses]
|
||||
: pathAddresses,
|
||||
type === 'exactSpend',
|
||||
const { calldata, swapDescription, value } = await generateSwapCalldata({
|
||||
amount: amountSpendBlockchainParam,
|
||||
minReturnAmount: amountReceiveBlockchainParam,
|
||||
path: exchangeContractPath.filter(isValidSingleSwap),
|
||||
initiatorAddress: walletAddress,
|
||||
receiverAddress: walletAddress,
|
||||
provider,
|
||||
|
||||
matcher: matcherAddress,
|
||||
feeToken: feeAssetAddress,
|
||||
fee: 0,
|
||||
exchangeContractAddress,
|
||||
swapExecutorContractAddress,
|
||||
wethAddress: WETHAddress,
|
||||
|
||||
curveRegistryAddress: safeGet(unit.contracts, 'curveRegistry'),
|
||||
})
|
||||
|
||||
const unsignedSwapThroughPoolsTx = await exchangeContract.swap.populateTransaction(
|
||||
swapExecutorContractAddress,
|
||||
swapDescription,
|
||||
new Uint8Array(0),
|
||||
calldata,
|
||||
{
|
||||
value
|
||||
}
|
||||
);
|
||||
|
||||
unsignedSwapThroughOrionPoolTx.chainId = BigInt(parseInt(chainId, 10));
|
||||
unsignedSwapThroughOrionPoolTx.gasPrice = BigInt(gasPriceWei);
|
||||
unsignedSwapThroughPoolsTx.chainId = BigInt(parseInt(chainId, 10));
|
||||
unsignedSwapThroughPoolsTx.gasPrice = BigInt(gasPriceWei);
|
||||
|
||||
unsignedSwapThroughOrionPoolTx.from = walletAddress;
|
||||
unsignedSwapThroughPoolsTx.from = walletAddress;
|
||||
const amountSpendBN = new BigNumber(amountSpend);
|
||||
|
||||
let value = new BigNumber(0);
|
||||
let txValue = new BigNumber(0);
|
||||
const denormalizedAssetInExchangeBalance = balances[assetIn]?.exchange;
|
||||
if (denormalizedAssetInExchangeBalance === undefined) throw new Error(`Asset '${assetIn}' exchange balance is not found`);
|
||||
if (assetIn === nativeCryptocurrency && amountSpendBN.gt(denormalizedAssetInExchangeBalance)) {
|
||||
value = amountSpendBN.minus(denormalizedAssetInExchangeBalance);
|
||||
txValue = amountSpendBN.minus(denormalizedAssetInExchangeBalance);
|
||||
}
|
||||
unsignedSwapThroughOrionPoolTx.value = normalizeNumber(
|
||||
value.dp(INTERNAL_PROTOCOL_PRECISION, BigNumber.ROUND_CEIL),
|
||||
unsignedSwapThroughPoolsTx.value = normalizeNumber(
|
||||
txValue.dp(INTERNAL_PROTOCOL_PRECISION, BigNumber.ROUND_CEIL),
|
||||
NATIVE_CURRENCY_PRECISION,
|
||||
BigNumber.ROUND_CEIL,
|
||||
);
|
||||
unsignedSwapThroughOrionPoolTx.gasLimit = BigInt(SWAP_THROUGH_ORION_POOL_GAS_LIMIT);
|
||||
unsignedSwapThroughPoolsTx.gasLimit = BigInt(SWAP_THROUGH_ORION_POOL_GAS_LIMIT);
|
||||
|
||||
const transactionCost = BigInt(SWAP_THROUGH_ORION_POOL_GAS_LIMIT) * BigInt(gasPriceWei);
|
||||
const denormalizedTransactionCost = denormalizeNumber(transactionCost, BigInt(NATIVE_CURRENCY_PRECISION));
|
||||
@@ -327,10 +350,10 @@ export default async function swapLimit({
|
||||
await balanceGuard.check(options?.autoApprove);
|
||||
|
||||
const nonce = await provider.getTransactionCount(walletAddress, 'pending');
|
||||
unsignedSwapThroughOrionPoolTx.nonce = nonce;
|
||||
unsignedSwapThroughPoolsTx.nonce = nonce;
|
||||
|
||||
options?.logger?.('Signing transaction...');
|
||||
const swapThroughOrionPoolTxResponse = await signer.sendTransaction(unsignedSwapThroughOrionPoolTx);
|
||||
const swapThroughOrionPoolTxResponse = await signer.sendTransaction(unsignedSwapThroughPoolsTx);
|
||||
options?.logger?.(`Transaction sent. Tx hash: ${swapThroughOrionPoolTxResponse.hash}`);
|
||||
return {
|
||||
amountOut: swapInfo.amountOut,
|
||||
|
||||
@@ -12,6 +12,10 @@ import type orderSchema from '../../services/Aggregator/schemas/orderSchema.js';
|
||||
import type { z } from 'zod';
|
||||
import type { SwapLimitParams } from './swapLimit.js';
|
||||
import { simpleFetch } from 'simple-typed-fetch';
|
||||
import { generateSwapCalldata } from './generateSwapCalldata.js';
|
||||
import isValidFactory from '../../utils/isValidFactory.js';
|
||||
import type { SingleSwap } from '../../types.js';
|
||||
import { must, safeGet } from '../../utils/safeGetters.js';
|
||||
|
||||
export type SwapMarketParams = Omit<SwapLimitParams, 'price'> & {
|
||||
slippagePercent: BigNumber.Value
|
||||
@@ -33,6 +37,11 @@ type PoolSwap = {
|
||||
|
||||
export type Swap = AggregatorOrder | PoolSwap;
|
||||
|
||||
|
||||
const isValidSingleSwap = (singleSwap: Omit<SingleSwap, 'factory'> & { factory: string }): singleSwap is SingleSwap => {
|
||||
return isValidFactory(singleSwap.factory);
|
||||
}
|
||||
|
||||
export default async function swapMarket({
|
||||
type,
|
||||
assetIn,
|
||||
@@ -71,6 +80,7 @@ export default async function swapMarket({
|
||||
exchangeContractAddress,
|
||||
matcherAddress,
|
||||
assetToAddress,
|
||||
swapExecutorContractAddress,
|
||||
} = await simpleFetch(blockchainService.getInfo)();
|
||||
const nativeCryptocurrency = getNativeCryptocurrencyName(assetToAddress);
|
||||
|
||||
@@ -78,7 +88,8 @@ export default async function swapMarket({
|
||||
const feeAssets = await simpleFetch(blockchainService.getPlatformFees)({ walletAddress, assetIn, assetOut });
|
||||
const allPrices = await simpleFetch(blockchainService.getPricesWithQuoteAsset)();
|
||||
const gasPriceWei = await simpleFetch(blockchainService.getGasPriceWei)();
|
||||
const { factories } = await simpleFetch(blockchainService.getPoolsConfig)();
|
||||
const { factories, WETHAddress } = await simpleFetch(blockchainService.getPoolsConfig)();
|
||||
must(WETHAddress, 'WETHAddress is not defined');
|
||||
const poolExchangesList = factories !== undefined ? Object.keys(factories) : [];
|
||||
|
||||
const gasPriceGwei = ethers.formatUnits(gasPriceWei, 'gwei').toString();
|
||||
@@ -124,7 +135,7 @@ export default async function swapMarket({
|
||||
: undefined,
|
||||
);
|
||||
|
||||
const { exchanges: swapExchanges } = swapInfo;
|
||||
const { exchanges: swapExchanges, exchangeContractPath } = swapInfo;
|
||||
|
||||
const [firstSwapExchange] = swapExchanges;
|
||||
|
||||
@@ -185,12 +196,6 @@ export default async function swapMarket({
|
||||
if (factoryAddress !== undefined) options?.logger?.(`Factory address is ${factoryAddress}. Exchange is ${firstSwapExchange}`);
|
||||
}
|
||||
|
||||
const pathAddresses = swapInfo.path.map((name) => {
|
||||
const assetAddress = assetToAddress[name];
|
||||
if (assetAddress === undefined) throw new Error(`No asset address for ${name}`);
|
||||
return assetAddress;
|
||||
});
|
||||
|
||||
const amountOutWithSlippage = new BigNumber(swapInfo.amountOut)
|
||||
.multipliedBy(new BigNumber(1).minus(percent))
|
||||
.toString();
|
||||
@@ -222,33 +227,52 @@ export default async function swapMarket({
|
||||
INTERNAL_PROTOCOL_PRECISION,
|
||||
BigNumber.ROUND_FLOOR,
|
||||
);
|
||||
const unsignedSwapThroughOrionPoolTx = await exchangeContract.swapThroughOrionPool.populateTransaction(
|
||||
amountSpendBlockchainParam.toString(),
|
||||
amountReceiveBlockchainParam.toString(),
|
||||
factoryAddress !== undefined
|
||||
? [factoryAddress, ...pathAddresses]
|
||||
: pathAddresses,
|
||||
type === 'exactSpend',
|
||||
const { calldata, swapDescription, value } = await generateSwapCalldata({
|
||||
amount: amountSpendBlockchainParam,
|
||||
minReturnAmount: amountReceiveBlockchainParam,
|
||||
path: exchangeContractPath.filter(isValidSingleSwap),
|
||||
initiatorAddress: walletAddress,
|
||||
receiverAddress: walletAddress,
|
||||
provider,
|
||||
|
||||
matcher: matcherAddress,
|
||||
feeToken: feeAssetAddress,
|
||||
fee: 0,
|
||||
exchangeContractAddress,
|
||||
swapExecutorContractAddress,
|
||||
wethAddress: WETHAddress,
|
||||
|
||||
curveRegistryAddress: safeGet(unit.contracts, 'curveRegistry'),
|
||||
})
|
||||
|
||||
const unsignedSwapThroughPoolsTx = await exchangeContract.swap.populateTransaction(
|
||||
swapExecutorContractAddress,
|
||||
swapDescription,
|
||||
new Uint8Array(0),
|
||||
calldata,
|
||||
{
|
||||
value
|
||||
}
|
||||
);
|
||||
|
||||
unsignedSwapThroughOrionPoolTx.chainId = BigInt(chainId);
|
||||
unsignedSwapThroughOrionPoolTx.gasPrice = BigInt(gasPriceWei);
|
||||
unsignedSwapThroughPoolsTx.chainId = BigInt(parseInt(chainId, 10));
|
||||
unsignedSwapThroughPoolsTx.gasPrice = BigInt(gasPriceWei);
|
||||
|
||||
unsignedSwapThroughOrionPoolTx.from = walletAddress;
|
||||
unsignedSwapThroughPoolsTx.from = walletAddress;
|
||||
const amountSpendBN = new BigNumber(amountSpend);
|
||||
|
||||
let value = new BigNumber(0);
|
||||
let txValue = new BigNumber(0);
|
||||
const denormalizedAssetInExchangeBalance = balances[assetIn]?.exchange;
|
||||
if (denormalizedAssetInExchangeBalance === undefined) throw new Error(`Asset '${assetIn}' exchange balance is not found`);
|
||||
if (assetIn === nativeCryptocurrency && amountSpendBN.gt(denormalizedAssetInExchangeBalance)) {
|
||||
value = amountSpendBN.minus(denormalizedAssetInExchangeBalance);
|
||||
txValue = amountSpendBN.minus(denormalizedAssetInExchangeBalance);
|
||||
}
|
||||
unsignedSwapThroughOrionPoolTx.value = normalizeNumber(
|
||||
value.dp(INTERNAL_PROTOCOL_PRECISION, BigNumber.ROUND_CEIL),
|
||||
unsignedSwapThroughPoolsTx.value = normalizeNumber(
|
||||
txValue.dp(INTERNAL_PROTOCOL_PRECISION, BigNumber.ROUND_CEIL),
|
||||
NATIVE_CURRENCY_PRECISION,
|
||||
BigNumber.ROUND_CEIL,
|
||||
);
|
||||
unsignedSwapThroughOrionPoolTx.gasLimit = BigInt(SWAP_THROUGH_ORION_POOL_GAS_LIMIT);
|
||||
unsignedSwapThroughPoolsTx.gasLimit = BigInt(SWAP_THROUGH_ORION_POOL_GAS_LIMIT);
|
||||
|
||||
const transactionCost = BigInt(SWAP_THROUGH_ORION_POOL_GAS_LIMIT) * BigInt(gasPriceWei);
|
||||
const denormalizedTransactionCost = denormalizeNumber(transactionCost, BigInt(NATIVE_CURRENCY_PRECISION));
|
||||
@@ -278,10 +302,10 @@ export default async function swapMarket({
|
||||
await balanceGuard.check(options?.autoApprove);
|
||||
|
||||
const nonce = await provider.getTransactionCount(walletAddress, 'pending');
|
||||
unsignedSwapThroughOrionPoolTx.nonce = nonce;
|
||||
unsignedSwapThroughPoolsTx.nonce = nonce;
|
||||
|
||||
options?.logger?.('Signing transaction...');
|
||||
const swapThroughOrionPoolTxResponse = await signer.sendTransaction(unsignedSwapThroughOrionPoolTx);
|
||||
const swapThroughOrionPoolTxResponse = await signer.sendTransaction(unsignedSwapThroughPoolsTx);
|
||||
options?.logger?.(`Transaction sent. Tx hash: ${swapThroughOrionPoolTxResponse.hash}`);
|
||||
return {
|
||||
amountOut: swapInfo.amountOut,
|
||||
|
||||
@@ -7,6 +7,13 @@ const orderInfoSchema = z.object({
|
||||
safePrice: z.number(),
|
||||
}).nullable();
|
||||
|
||||
const exchangeContractStep = z.object({
|
||||
pool: z.string(),
|
||||
assetIn: z.string(),
|
||||
assetOut: z.string(),
|
||||
factory: z.string(),
|
||||
});
|
||||
|
||||
const swapInfoBase = z.object({
|
||||
id: z.string(),
|
||||
amountIn: z.number(),
|
||||
@@ -22,12 +29,7 @@ const swapInfoBase = z.object({
|
||||
minAmountOut: z.number(),
|
||||
minAmountIn: z.number(),
|
||||
marketPrice: z.number().nullable(), // spending asset market price
|
||||
exchangeContractPath: z.array(z.object({
|
||||
pool: z.string(),
|
||||
assetIn: z.string(),
|
||||
assetOut: z.string(),
|
||||
factory: z.string(),
|
||||
})),
|
||||
exchangeContractPath: z.array(exchangeContractStep),
|
||||
alternatives: z.object({ // execution alternatives
|
||||
exchanges: z.array(z.string()),
|
||||
path: z.array(z.string()),
|
||||
|
||||
8
src/utils/isValidFactory.ts
Normal file
8
src/utils/isValidFactory.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { type Factory } from '../types.js';
|
||||
import { factories } from '../index.js';
|
||||
|
||||
const isValidFactory = (factory: string): factory is Factory => {
|
||||
return factories.some((f) => f === factory);
|
||||
};
|
||||
|
||||
export default isValidFactory;
|
||||
Reference in New Issue
Block a user