UNPKG

@robertprp/intents-sdk

Version:

Shogun Network Intent-based cross-chain swaps SDK

185 lines 6.95 kB
import { ChainID, chainIdToChainTypeMap, isEvmChain } from '../../chains.js'; import { ValidationError } from '../../errors/index.js'; import { SingleChainOrderValidator } from '../../utils/order-validator.js'; import { QuoteProvider } from '../../utils/quote/aggregator.js'; import { getEVMSingleChainOrderTypedData } from '../evm/order-signature.js'; import { BaseSDK } from '../sdk.js'; import { getSolanaSingleChainOrderInstructions } from '../solana/order-instructions.js'; import {} from './common.js'; export class SingleChainOrder { constructor(params) { Object.defineProperty(this, "user", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "chainId", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "amountIn", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "tokenIn", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "tokenOut", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "amountOutMin", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "destinationAddress", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "extraTransfers", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "deadline", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "stopLossMaxOut", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "takeProfitMinOut", { enumerable: true, configurable: true, writable: true, value: void 0 }); this.user = params.user; this.chainId = params.chainId; this.amountIn = params.amountIn; this.tokenIn = params.tokenIn; this.tokenOut = params.tokenOut; this.amountOutMin = params.amountOutMin ?? 1n; this.destinationAddress = params.destinationAddress; this.extraTransfers = params.extraTransfers; this.deadline = params.deadline; this.stopLossMaxOut = params.stopLossMaxOut; this.takeProfitMinOut = params.takeProfitMinOut; } static async create(input) { new SingleChainOrderValidator().validateOrder(input); const amountOutMin = await this.calculateAmountOutMin(input); const order = new SingleChainOrder({ ...input, amountOutMin, user: input.user, }); const preparedRandomData = order.getRandomPreparedData(); const intentRequest = order.toIntentRequest(preparedRandomData); await BaseSDK.validateSingleChainOrder(intentRequest); return order; } /// This is needed because API requires the prepared data to be send /// In the cases of Solana and Sui, if we want the real data, we must send the order on-chain before validating. /// And that is something we cannot do before validating the order on the API side. getRandomPreparedData() { const chainId = this.chainId; const chainType = chainIdToChainTypeMap[chainId]; const randomNumber = String(Math.floor(Math.random() * 10000000)); switch (chainType) { case 'EVM': { return { nonce: randomNumber, signature: '0x0000000000000000000000000000000000000000000000000000000000000000' }; } case 'Solana': { return { secretNumber: randomNumber, orderPubkey: 'DFNAjFAvS4GF98Tp1kiyLvEHM3wjGXibCfF86nnmhuVc' }; } case 'Sui': { const digest = 'FQWndwYJhNQUoHyvR8UuhGURC2EKx9eWErFm9Tc2DggF'; return { transactionHash: digest }; } default: { throw new Error('Chain type not supported'); } } } static async calculateAmountOutMin(input) { const { amountOutMin, stopLossMaxOut } = input; const scenario = this.getSingleChainOrderScenario({ hasAmountOutMin: !!amountOutMin, hasStopLoss: !!stopLossMaxOut, }); switch (scenario) { case 'QUOTE_REQUIRED': const quote = await QuoteProvider.getSingleChainQuote({ tokenIn: input.tokenIn, amount: input.amountIn, chainId: input.chainId, tokenOut: input.tokenOut, }); return (quote.amountOut * 93n) / 100n; // Add 7% reduced to cover fees case 'USE_PROVIDED_AMOUNT': return amountOutMin; case 'STOP_LOSS_ONLY': case 'BOTH_PROVIDED': // When stop loss is involved, amountOutMin should be 1 return 1n; } } static getSingleChainOrderScenario({ hasAmountOutMin, hasStopLoss, }) { if (!hasAmountOutMin && !hasStopLoss) return 'QUOTE_REQUIRED'; if (hasAmountOutMin && !hasStopLoss) return 'USE_PROVIDED_AMOUNT'; if (!hasAmountOutMin && hasStopLoss) return 'STOP_LOSS_ONLY'; return 'BOTH_PROVIDED'; } toIntentRequest(preparedData) { const sourceChainType = chainIdToChainTypeMap[this.chainId]; return { genericData: this, chainSpecificData: { [sourceChainType]: preparedData, }, }; } sendToAuctioneer(preparedData) { return BaseSDK.sendSingleChainOrder({ order: this, preparedData, }); } async toEVMTypedData() { if (!isEvmChain(this.chainId)) { throw new ValidationError('Chain id is not an Ethereum compatible chain'); } return getEVMSingleChainOrderTypedData(this); } async toSolanaInstructionsByteArray() { if (this.chainId !== ChainID.Solana) { throw new ValidationError('Chain id is not Solana'); } return getSolanaSingleChainOrderInstructions(this); } } //# sourceMappingURL=single-chain.js.map