在 Sui 链上搭建兑换应用#
在Sui上使用OKX DEX构建兑换应用程序有两种方法:
- API 方法 - 直接调用 OKX DEX API
- SDK方法 - 使用
@okx-dex/okx-dex-sdk
,简化了开发人员的体验
本指南涵盖了这两种方法,以帮助你选择最适合你需求的方法。
方法1:API方法#
在本指南中,我们将提供通过OKX DEX进行Sui代币兑换的用例。
1. 设置环境#
导入必要的Node. js库并设置环境变量:
// Required libraries
import { SuiWallet } from "@okxweb3/coin-sui";
import { getFullnodeUrl, SuiClient } from '@mysten/sui/client';
import { Transaction } from '@mysten/sui/transactions';
import cryptoJS from "crypto-js";
// Install dependencies
// npm i @okxweb3/coin-sui
// npm i @mysten/sui
// npm i crypto-js
// Set up environment variables
const apiKey = 'your_api_key';
const secretKey = 'your_secret_key';
const apiPassphrase = 'your_passphrase';
const projectId = 'your_project_id';
const userAddress = 'your_sui_wallet_address';
const userPrivateKey = 'your_sui_wallet_private_key';
// Constants
const SUI_CHAIN_ID = "784";
const DEFAULT_GAS_BUDGET = 50000000;
const MAX_RETRIES = 3;
// Initialize Sui client
const wallet = new SuiWallet();
const client = new SuiClient({
url: getFullnodeUrl('mainnet')
});
// For Sui, you need to use the hexWithoutFlag format of your private key
// You can convert your key using sui keytool:
// sui keytool convert <your_sui_private_key>
2. 获取代币信息和兑换报价#
首先,创建一个实用函数来处理API身份验证标头:
function getHeaders(timestamp, method, requestPath, queryString = "") {
if (!apiKey || !secretKey || !apiPassphrase || !projectId) {
throw new Error("Missing required environment variables");
}
const stringToSign = timestamp + method + requestPath + queryString;
return {
"Content-Type": "application/json",
"OK-ACCESS-KEY": apiKey,
"OK-ACCESS-SIGN": cryptoJS.enc.Base64.stringify(
cryptoJS.HmacSHA256(stringToSign, secretKey)
),
"OK-ACCESS-TIMESTAMP": timestamp,
"OK-ACCESS-PASSPHRASE": apiPassphrase,
"OK-ACCESS-PROJECT": projectId,
};
}
然后,创建一个函数来获取令牌信息:
async function getTokenInfo(fromTokenAddress, toTokenAddress) {
const timestamp = new Date().toISOString();
const requestPath = "/api/v5/dex/aggregator/quote";
const params = {
chainId: SUI_CHAIN_ID,
fromTokenAddress,
toTokenAddress,
amount: "1000000",
slippage: "0.005",// 0.5% slippage
};
const queryString = "?" + new URLSearchParams(params).toString();
const headers = getHeaders(timestamp, "GET", requestPath, queryString);
const response = await fetch(
`https://web3.okx.com${requestPath}${queryString}`,
{ method: "GET", headers }
);
if (!response.ok) {
throw new Error(`Failed to get quote: ${await response.text()}`);
}
const data = await response.json();
if (data.code !== "0" || !data.data?.[0]) {
throw new Error("Failed to get token information");
}
const quoteData = data.data[0];
return {
fromToken: {
symbol: quoteData.fromToken.tokenSymbol,
decimals: parseInt(quoteData.fromToken.decimal),
price: quoteData.fromToken.tokenUnitPrice
},
toToken: {
symbol: quoteData.toToken.tokenSymbol,
decimals: parseInt(quoteData.toToken.decimal),
price: quoteData.toToken.tokenUnitPrice
}
};
}
创建一个函数将人类可读的数量转换为基本单位:
function convertAmount(amount, decimals) {
try {
if (!amount || isNaN(parseFloat(amount))) {
throw new Error("Invalid amount");
}
const value = parseFloat(amount);
if (value <= 0) {
throw new Error("Amount must be greater than 0");
}
return (BigInt(Math.floor(value * Math.pow(10, decimals)))).toString();
} catch (err) {
console.error("Amount conversion error:", err);
throw new Error("Invalid amount format");
}
}
3. 处理和签署交易#
3.1 Define swap parameters
const swapParams = {
chainId: chainId,
fromTokenAddress,
toTokenAddress,
amount,
userWalletAddress: userAddress,
slippage
};
3.2 Request swap transaction data
/**
* Get swap transaction data from DEX API
* @param fromTokenAddress - Source token address
* @param toTokenAddress - Destination token address
* @param amount - Amount to swap
* @param userAddress - User wallet address
* @param slippage - Maximum slippage (e.g., "0.5" for 0.5%)
* @returns Swap transaction data
*/
async function getSwapTransaction(
fromTokenAddress: string,
toTokenAddress: string,
amount: string,
userAddress: string,
slippage: string = '0.5'
): Promise<any> {
try {
const path = 'dex/aggregator/swap';
const url = `${baseUrl}${path}`;
const params = {
chainId: chainId,
fromTokenAddress,
toTokenAddress,
amount,
userWalletAddress: userAddress,
slippage
};
// Prepare authentication
const timestamp = new Date().toISOString();
const requestPath = `/api/v5/${path}`;
const queryString = "?" + new URLSearchParams(params).toString();
const headers = getHeaders(timestamp, 'GET', requestPath, queryString);
const response = await axios.get(url, { params, headers });
if (response.data.code === '0') {
return response.data.data[0];
} else {
throw new Error(`API Error: ${response.data.msg || 'Unknown error'}`);
}
} catch (error) {
console.error('Failed to get swap transaction data:', (error as Error).message);
throw error;
}
}
4. 模拟交易#
在执行实际兑换之前,务必模拟交易以确保其成功并识别任何潜在问题:
此功能使用 交易上链 API
。此 API 仅供我们的白名单客户使用。如您感兴趣,请联系我们 dexapi@okx.com。
async function simulateTransaction(txData) {
try {
if (!txData) {
throw new Error('Invalid transaction data format');
}
const params = {
chainIndex: SUI_CHAIN_ID,
txData: txData,
includeDebug: true
};
const timestamp = new Date().toISOString();
const requestPath = "/api/v5/dex/pre-transaction/simulate";
const requestBody = JSON.stringify(params);
const headers = getHeaders(timestamp, "POST", requestPath, "", requestBody);
console.log('Simulating transaction...');
const response = await fetch(
`https://web3.okx.com${requestPath}`,
{
method: 'POST',
headers,
body: requestBody
}
);
const data = await response.json();
if (data.code !== "0") {
throw new Error(`Simulation failed: ${data.msg || "Unknown simulation error"}`);
}
const simulationResult = data.data[0];
// Check simulation success
if (simulationResult.success === false) {
console.error('Transaction simulation failed:', simulationResult.error);
throw new Error(`Transaction would fail: ${simulationResult.error}`);
}
console.log('Transaction simulation successful');
console.log(`Estimated gas used: ${simulationResult.gasUsed || 'N/A'}`);
if (simulationResult.logs) {
console.log('Simulation logs:', simulationResult.logs);
}
return simulationResult;
} catch (error) {
console.error("Error simulating transaction:", error);
throw error;
}
}
5. 执行交易#
最后,执行签名交易:
async function executeSwap(txData, privateKey) {
// Create transaction block
const txBlock = Transaction.from(txData);
txBlock.setSender(normalizedWalletAddress);
// Set gas parameters
const referenceGasPrice = await client.getReferenceGasPrice();
txBlock.setGasPrice(BigInt(referenceGasPrice));
txBlock.setGasBudget(BigInt(DEFAULT_GAS_BUDGET));
// Build and sign transaction
const builtTx = await txBlock.build({ client });
const txBytes = Buffer.from(builtTx).toString('base64');
const signedTx = await wallet.signTransaction({
privateKey,
data: {
type: 'raw',
data: txBytes
}
});
if (!signedTx?.signature) {
throw new Error("Failed to sign transaction");
}
return { builtTx, signature: signedTx.signature };
}
然后,使用 RPC 方法调用发送交易
使用 RPC:
async function sendTransaction(builtTx, signature) {
// Execute transaction
const result = await client.executeTransactionBlock({
transactionBlock: builtTx,
signature: [signature],
options: {
showEffects: true,
showEvents: true,
}
});
// Wait for confirmation
const confirmation = await client.waitForTransaction({
digest: result.digest,
options: {
showEffects: true,
showEvents: true,
}
});
console.log("\nSwap completed successfully!");
console.log("Transaction ID:", result.digest);
console.log("Explorer URL:", `https://suiscan.xyz/mainnet/tx/${result.digest}`);
return result.digest;
}
6. 跟踪交易#
使用 SWAP API 跟踪交易:
SWAP API 交易跟踪使用 /dex/aggregator/history
端点提供全面的交换执行详情。它提供特定于代币的信息(符号、金额)、已支付的费用以及详细的区块链数据。当您需要获取包含代币级详细信息的完整交换洞察时,请使用此功能。
async function trackTransactionWithSwapAPI(txHash) {
try {
const path = 'dex/aggregator/history';
const url = `${baseUrl}${path}`;
const params = {
chainId: SUI_CHAIN_ID,
txHash: txHash,
isFromMyProject: 'false'
};
const timestamp = new Date().toISOString();
const requestPath = `/api/v5/${path}`;
const queryString = "?" + new URLSearchParams(params).toString();
const headers = getHeaders(timestamp, 'GET', requestPath, queryString);
console.log('Fetching transaction status...');
const response = await fetch(`${url}${queryString}`, { headers });
const data = await response.json();
if (!data) {
throw new Error('No response data received from API');
}
if (data.code !== '0') {
throw new Error(`API Error: ${data.msg || 'Unknown error'}`);
}
if (!data.data || !Array.isArray(data.data) || data.data.length === 0) {
console.log('Transaction not found in history yet, might be too recent');
return { status: 'pending', details: null };
}
const txData = data.data[0];
if (!txData) {
console.log('Transaction data not available yet');
return { status: 'pending', details: null };
}
const status = txData.status;
console.log(`Transaction status: ${status}`);
if (status === 'pending') {
console.log(`Transaction is still pending: ${txHash}`);
return { status: 'pending', details: txData };
} else if (status === 'success') {
console.log(`Transaction successful!`);
console.log(`From: ${txData.fromTokenDetails.symbol} - Amount: ${txData.fromTokenDetails.amount}`);
console.log(`To: ${txData.toTokenDetails.symbol} - Amount: ${txData.toTokenDetails.amount}`);
console.log(`Transaction Fee: ${txData.txFee}`);
console.log(`Explorer URL: https://suiscan.xyz/mainnet/tx/${txHash}`);
return { status: 'success', details: txData };
} else if (status === 'fail') {
const errorMsg = txData.errorMsg || 'Unknown reason';
console.error(`Transaction failed: ${errorMsg}`);
return { status: 'failure', details: txData, error: errorMsg };
}
return { status: 'unknown', details: txData };
} catch (error) {
console.error('Failed to track transaction status:', error.message);
return { status: 'pending', details: null, error: error.message };
}
}
7. 完整实现#
这是一个完整的实现示例:
// swap.ts
import { SuiWallet } from "@okxweb3/coin-sui";
import { getFullnodeUrl, SuiClient } from '@mysten/sui/client';
import { Transaction } from '@mysten/sui/transactions';
import cryptoJS from "crypto-js";
import dotenv from 'dotenv';
dotenv.config();
// Environment variables
const apiKey = process.env.OKX_API_KEY;
const secretKey = process.env.OKX_SECRET_KEY;
const apiPassphrase = process.env.OKX_API_PASSPHRASE;
const projectId = process.env.OKX_PROJECT_ID;
const userAddress = process.env.WALLET_ADDRESS;
const userPrivateKey = process.env.PRIVATE_KEY;
// Constants
const SUI_CHAIN_ID = "784";
const DEFAULT_GAS_BUDGET = 50000000;
const MAX_RETRIES = 3;
// Initialize clients
const wallet = new SuiWallet();
const client = new SuiClient({
url: getFullnodeUrl('mainnet')
});
// Normalize wallet address
const normalizedWalletAddress = userAddress;
function getHeaders(timestamp: string, method: string, requestPath: string, queryString: string = "", requestBody: string = "") {
if (!apiKey || !secretKey || !apiPassphrase || !projectId) {
throw new Error("Missing required environment variables");
}
const stringToSign = timestamp + method + requestPath + queryString + requestBody;
return {
"Content-Type": "application/json",
"OK-ACCESS-KEY": apiKey,
"OK-ACCESS-SIGN": cryptoJS.enc.Base64.stringify(
cryptoJS.HmacSHA256(stringToSign, secretKey)
),
"OK-ACCESS-TIMESTAMP": timestamp,
"OK-ACCESS-PASSPHRASE": apiPassphrase,
"OK-ACCESS-PROJECT": projectId,
};
}
async function getTokenInfo(fromTokenAddress: string, toTokenAddress: string) {
const timestamp = new Date().toISOString();
const requestPath = "/api/v5/dex/aggregator/quote";
const params = {
chainId: SUI_CHAIN_ID,
fromTokenAddress,
toTokenAddress,
amount: "1000000",
slippage: "0.005",// 0.5% slippage
};
const queryString = "?" + new URLSearchParams(params).toString();
const headers = getHeaders(timestamp, "GET", requestPath, queryString);
const response = await fetch(
`https://web3.okx.com${requestPath}${queryString}`,
{ method: "GET", headers }
);
if (!response.ok) {
throw new Error(`Failed to get quote: ${await response.text()}`);
}
const data = await response.json();
if (data.code !== "0" || !data.data?.[0]) {
throw new Error("Failed to get token information");
}
const quoteData = data.data[0];
return {
fromToken: {
symbol: quoteData.fromToken.tokenSymbol,
decimals: parseInt(quoteData.fromToken.decimal),
price: quoteData.fromToken.tokenUnitPrice
},
toToken: {
symbol: quoteData.toToken.tokenSymbol,
decimals: parseInt(quoteData.toToken.decimal),
price: quoteData.toToken.tokenUnitPrice
}
};
}
function convertAmount(amount: string | number, decimals: number) {
try {
if (!amount || isNaN(parseFloat(amount.toString()))) {
throw new Error("Invalid amount");
}
const value = parseFloat(amount.toString());
if (value <= 0) {
throw new Error("Amount must be greater than 0");
}
return (BigInt(Math.floor(value * Math.pow(10, decimals)))).toString();
} catch (err) {
console.error("Amount conversion error:", err);
throw new Error("Invalid amount format");
}
}
async function trackTransactionWithSwapAPI(txHash: string) {
try {
const path = 'dex/aggregator/history';
const url = `https://web3.okx.com/api/v5/${path}`;
const params = {
chainId: SUI_CHAIN_ID,
txHash: txHash,
isFromMyProject: 'false'
};
const timestamp = new Date().toISOString();
const requestPath = `/api/v5/${path}`;
const queryString = "?" + new URLSearchParams(params).toString();
const headers = getHeaders(timestamp, 'GET', requestPath, queryString);
const response = await fetch(`${url}${queryString}`, { headers });
const data = await response.json();
if (data.code !== '0') {
throw new Error(`API Error: ${data.msg || 'Unknown error'}`);
}
return data.data?.[0] || { status: 'pending' };
} catch (error) {
console.error('Failed to track transaction:', error);
return { status: 'error', error: error instanceof Error ? error.message : 'Unknown error' };
}
}
async function main() {
try {
const args = process.argv.slice(2);
if (args.length < 3) {
console.log("Usage: ts-node swap.ts <amount> <fromTokenAddress> <toTokenAddress>");
console.log("Example: ts-node swap.ts 1.5 0x2::sui::SUI 0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC");
process.exit(1);
}
const [amount, fromTokenAddress, toTokenAddress] = args;
if (!userPrivateKey || !userAddress) {
throw new Error("Private key or user address not found");
}
// Get token information
console.log("Getting token information...");
const tokenInfo = await getTokenInfo(fromTokenAddress, toTokenAddress);
console.log(`From: ${tokenInfo.fromToken.symbol} (${tokenInfo.fromToken.decimals} decimals)`);
console.log(`To: ${tokenInfo.toToken.symbol} (${tokenInfo.toToken.decimals} decimals)`);
// Convert amount using fetched decimals
const rawAmount = convertAmount(amount, tokenInfo.fromToken.decimals);
console.log(`Amount in ${tokenInfo.fromToken.symbol} base units:`, rawAmount);
// Get swap quote
const quoteParams = {
chainId: SUI_CHAIN_ID,
amount: rawAmount,
fromTokenAddress,
toTokenAddress,
slippage: "0.005",// 0.5% slippage
userWalletAddress: normalizedWalletAddress || "",
};
// Get swap data
const timestamp = new Date().toISOString();
const requestPath = "/api/v5/dex/aggregator/swap";
const queryString = "?" + new URLSearchParams(quoteParams).toString();
const headers = getHeaders(timestamp, "GET", requestPath, queryString);
console.log("Requesting swap quote...");
const response = await fetch(
`https://web3.okx.com${requestPath}${queryString}`,
{ method: "GET", headers }
);
const data = await response.json();
if (data.code !== "0") {
throw new Error(`API Error: ${data.msg}`);
}
const swapData = data.data[0];
// Show estimated output and price impact
const outputAmount = parseFloat(swapData.routerResult.toTokenAmount) / Math.pow(10, tokenInfo.toToken.decimals);
console.log("\nSwap Quote:");
console.log(`Input: ${amount} ${tokenInfo.fromToken.symbol} ($${(parseFloat(amount) * parseFloat(tokenInfo.fromToken.price)).toFixed(2)})`);
console.log(`Output: ${outputAmount.toFixed(tokenInfo.toToken.decimals)} ${tokenInfo.toToken.symbol} ($${(outputAmount * parseFloat(tokenInfo.toToken.price)).toFixed(2)})`);
if (swapData.priceImpactPercentage) {
console.log(`Price Impact: ${swapData.priceImpactPercentage}%`);
}
console.log("\nExecuting swap transaction...");
let retryCount = 0;
while (retryCount < MAX_RETRIES) {
try {
// Create transaction block
const txBlock = Transaction.from(swapData.tx.data);
if (!normalizedWalletAddress) {
throw new Error("Wallet address is not defined");
}
txBlock.setSender(normalizedWalletAddress);
// Set gas parameters
const referenceGasPrice = await client.getReferenceGasPrice();
txBlock.setGasPrice(BigInt(referenceGasPrice));
txBlock.setGasBudget(BigInt(DEFAULT_GAS_BUDGET));
// Build and sign transaction
const builtTx = await txBlock.build({ client });
const txBytes = Buffer.from(builtTx).toString('base64');
const signedTx = await wallet.signTransaction({
privateKey: userPrivateKey,
data: {
type: 'raw',
data: txBytes
}
});
if (!signedTx?.signature) {
throw new Error("Failed to sign transaction");
}
// Execute transaction
const result = await client.executeTransactionBlock({
transactionBlock: builtTx,
signature: [signedTx.signature],
options: {
showEffects: true,
showEvents: true,
}
});
// Wait for confirmation
const confirmation = await client.waitForTransaction({
digest: result.digest,
options: {
showEffects: true,
showEvents: true,
}
});
console.log("\nSwap completed successfully!");
console.log("Transaction ID:", result.digest);
console.log("Explorer URL:", `https://suiscan.xyz/mainnet/tx/${result.digest}`);
// Track transaction
const txStatus = await trackTransactionWithSwapAPI(result.digest);
console.log("Transaction Status:", txStatus);
process.exit(0);
} catch (error) {
console.error(`Attempt ${retryCount + 1} failed:`, error);
retryCount++;
if (retryCount === MAX_RETRIES) {
throw error;
}
await new Promise(resolve => setTimeout(resolve, 2000 * retryCount));
}
}
} catch (error) {
console.error("Error:", error instanceof Error ? error.message : "Unknown error");
process.exit(1);
}
}
if (require.main === module) {
main();
}
方法2:SDK方法#
OKX DEX SDK 提供了更简单的开发人员体验,同时保留了API方法的所有功能。SDK为你处理许多实现细节,包括重试逻辑、错误处理和交易管理。
1. 安装SDK#
npm install @okx-dex/okx-dex-sdk
# or
yarn add @okx-dex/okx-dex-sdk
# or
pnpm add @okx-dex/okx-dex-sdk
2. 设置环境#
使用你的API凭据和钱包信息创建一个. env文件:
# OKX API Credentials
OKX_API_KEY=your_api_key
OKX_SECRET_KEY=your_secret_key
OKX_API_PASSPHRASE=your_passphrase
OKX_PROJECT_ID=your_project_id
# Sui Configuration
SUI_WALLET_ADDRESS=your_sui_wallet_address
SUI_PRIVATE_KEY=your_sui_private_key
请记住,您需要使用 SUI 私钥的 hexWithoutFlag 格式,您可以使用 SUI CLI 获取该格式:
sui keytool convert <your_sui_private_key>
3. 初始化客户端#
为你的DEX客户端创建一个文件(例如,DexClient. ts):
// DexClient.ts
import { OKXDexClient } from '@okx-dex/okx-dex-sdk';
import 'dotenv/config';
// Validate environment variables
const requiredEnvVars = [
'OKX_API_KEY',
'OKX_SECRET_KEY',
'OKX_API_PASSPHRASE',
'OKX_PROJECT_ID',
'SUI_WALLET_ADDRESS',
'SUI_PRIVATE_KEY'
];
for (const envVar of requiredEnvVars) {
if (!process.env[envVar]) {
throw new Error(`Missing required environment variable: ${envVar}`);
}
}
// Initialize the client
export const client = new OKXDexClient({
apiKey: process.env.OKX_API_KEY!,
secretKey: process.env.OKX_SECRET_KEY!,
apiPassphrase: process.env.OKX_API_PASSPHRASE!,
projectId: process.env.OKX_PROJECT_ID!,
sui: {
privateKey: process.env.SUI_PRIVATE_KEY!,
walletAddress: process.env.SUI_WALLET_ADDRESS!,
connection: {
rpcUrl: 'https://sui-mainnet.blockvision.org'
}
}
});
4. 创建代币助手(可选)#
你可以创建一个代币列表助手以便于参考:
// Common tokens on Sui mainnet
export const TOKENS = {
SUI: "0x2::sui::SUI",
USDC: "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC"
} as const;
5. 调用SDK执行兑换#
创建兑换执行的文件:
// swap.ts
import { client } from './DexClient';
import { TOKENS } from './Tokens'; // Optional, if you created the token helper
/**
* Example: Execute a swap from SUI to USDC
*/
async function executeSwap() {
try {
if (!process.env.SUI_PRIVATE_KEY) {
throw new Error('Missing SUI_PRIVATE_KEY in .env file');
}
// First, get token information using a quote
console.log("Getting token information...");
const fromTokenAddress = TOKENS.SUI; // Or use directly: "0x2::sui::SUI"
const toTokenAddress = TOKENS.USDC; // Or use directly: "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC"
const quote = await client.dex.getQuote({
chainId: '784', // Sui chain ID
fromTokenAddress,
toTokenAddress,
amount: '1000000', // Small amount for quote
slippage: '0.005' // 0.5% slippage
});
const tokenInfo = {
fromToken: {
symbol: quote.data[0].fromToken.tokenSymbol,
decimals: parseInt(quote.data[0].fromToken.decimal),
price: quote.data[0].fromToken.tokenUnitPrice
},
toToken: {
symbol: quote.data[0].toToken.tokenSymbol,
decimals: parseInt(quote.data[0].toToken.decimal),
price: quote.data[0].toToken.tokenUnitPrice
}
};
// Convert amount to base units
const humanReadableAmount = 1.5; // 1.5 SUI
const rawAmount = (humanReadableAmount * Math.pow(10, tokenInfo.fromToken.decimals)).toString();
console.log("\nSwap Details:");
console.log("--------------------");
console.log(`From: ${tokenInfo.fromToken.symbol}`);
console.log(`To: ${tokenInfo.toToken.symbol}`);
console.log(`Amount: ${humanReadableAmount} ${tokenInfo.fromToken.symbol}`);
console.log(`Amount in base units: ${rawAmount}`);
console.log(`Approximate USD value: $${(humanReadableAmount * parseFloat(tokenInfo.fromToken.price)).toFixed(2)}`);
// Execute the swap
console.log("\nExecuting swap...");
const swapResult = await client.dex.executeSwap({
chainId: '784', // Sui chain ID
fromTokenAddress,
toTokenAddress,
amount: rawAmount,
slippage: '0.005', // 0.5% slippage
userWalletAddress: process.env.SUI_WALLET_ADDRESS!
});
console.log('Swap executed successfully:');
console.log("\nTransaction ID:", swapResult.transactionId);
console.log("Explorer URL:", swapResult.explorerUrl);
if (swapResult.details) {
console.log("\nDetails:");
console.log(`Input: ${swapResult.details.fromToken.amount} ${swapResult.details.fromToken.symbol}`);
console.log(`Output: ${swapResult.details.toToken.amount} ${swapResult.details.toToken.symbol}`);
if (swapResult.details.priceImpact) {
console.log(`Price Impact: ${swapResult.details.priceImpact}%`);
}
}
return swapResult;
} catch (error) {
if (error instanceof Error) {
console.error('Error executing swap:', error.message);
// API errors include details in the message
if (error.message.includes('API Error:')) {
const match = error.message.match(/API Error: (.*)/);
if (match) console.error('API Error Details:', match[1]);
}
}
throw error;
}
}
// Run if this file is executed directly
if (require.main === module) {
executeSwap()
.then(() => process.exit(0))
.catch((error) => {
console.error('Error:', error);
process.exit(1);
});
}
export { executeSwap };
6. 附加SDK功能#
SDK提供了简化开发的附加方法: 获取代币对的报价
const quote = await client.dex.getQuote({
chainId: '784', // Sui
fromTokenAddress: '0x2::sui::SUI', // SUI
toTokenAddress: '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC', // USDC
amount: '100000000', // In base units
slippage: '0.005' // 0.5% slippage
});