UNPKG

@robertprp/intents-sdk

Version:

Shogun Network Intent-based cross-chain swaps SDK

82 lines (67 loc) 2.82 kB
import { Transaction } from '@mysten/sui/transactions'; import { normalizeSuiObjectId } from '@mysten/sui/utils'; import { ChainID } from '../../chains.js'; import { CROSS_CHAIN_GUARD_ADDRESSES, NATIVE_SUI_TOKEN_ADDRESS, SUI_GUARD_COLLATERAL_TYPE, SUI_GUARD_STABLECOIN_TYPE, SUI_PACKAGE_ID, } from '../../constants.js'; import { ValidationError } from '../../errors/index.js'; import { createSuiClient } from './client.js'; import type { CrossChainOrder } from '../orders/cross-chain.js'; /** * Generates Sui order transaction for creating an order * @param order The order to generate transaction for * @returns Object containing the transaction */ export async function getSuiOrderTransaction(order: CrossChainOrder): Promise<Transaction> { const userAddress = order.user; const client = createSuiClient(); const coins = await client.getCoins({ owner: userAddress, coinType: order.sourceTokenAddress, }); const guardAddress = CROSS_CHAIN_GUARD_ADDRESSES[ChainID.Sui]; const sourceTokenInCoins = coins.data.sort((a, b) => Number(b.balance) - Number(a.balance)); if (sourceTokenInCoins.length === 0) { throw new ValidationError(`No token (${order.sourceTokenAddress}) to create order`); } const coinsInSum = sourceTokenInCoins.reduce((acc, coin) => acc + BigInt(coin.balance), 0n); if (coinsInSum < order.sourceTokenAmount) { throw new ValidationError( `Insufficient balance to create order. Total coins is ${coinsInSum}, but order requires ${order.sourceTokenAmount}`, ); } const spendingGasCoin = normalizeSuiObjectId(order.sourceTokenAddress) === normalizeSuiObjectId(NATIVE_SUI_TOKEN_ADDRESS); const tx = new Transaction(); const coinInArg = spendingGasCoin ? tx.gas : sourceTokenInCoins[0]!.coinObjectId; if (sourceTokenInCoins.length > 1) { // Merging coins IN into a single object just in case tx.mergeCoins( // merge into 1st coin object coinInArg, // merge the rest of coins sourceTokenInCoins.slice(1).map((coin) => coin.coinObjectId), ); } const [coinIn] = tx.splitCoins(coinInArg, [order.sourceTokenAmount]); tx.moveCall({ package: SUI_PACKAGE_ID, module: 'source_chain_guard', function: 'create_order', arguments: [ tx.object(guardAddress), // arg0: &Guard<T0, T2> coinIn, // arg1: Coin<T1> tx.pure.u64(order.minStablecoinAmount), // arg2: min_stablecoins_amount tx.pure.u64(order.deadline * 1000), // arg3: deadline (converted to milliseconds) tx.pure.vector('u8', order.executionDetailsHashToBytes()), // arg4: execution_details_hash tx.object.clock(), // arg5: &Clock ], typeArguments: [SUI_GUARD_COLLATERAL_TYPE, order.sourceTokenAddress, SUI_GUARD_STABLECOIN_TYPE], }); tx.setSender(userAddress); return tx; }