搭建跨链应用#
在本指南中,我们将通过欧易 DEX 提供的一个示例来展示如何进行跨链兑换,使用 Ethereum 链上的 USDT 兑换 Arbitrum 链上的 USDC。这个过程包括:
- 设置你的环境
- 检查授权额度
- 检查授权交易参数并发起授权交易
- 通过 fromChainId 拿到可以交易的 toChainId 列表,并选择其中一条链作为目标链
- 通过 toChainId 拿到该链的币种列表,并且选择其中一个代币作为目标链币种
- 请求询价接口,拿到询价数据,主要目的是为了获取跨链桥 ID
- 请求跨链兑换接口,发起交易
- 查询交易状态
1. 设置你的环境#
导入必要的 Node.js 库并设置你的环境变量以及定义辅助函数和组装参数 Node.js 环境设置
2. 检查授权额度#
以 ETH chain 举例#
Demo 为 JavaScript 语言
连接到以太坊节点
:您需要确保您已经连接到一个可用的以太坊节点。您可以使用 web3.js 或其他以太坊开发库来连接到节点。在代码中,您需要指定节点的 HTTP 或 WebSocket 端点。获取代币合约实例
:使用代币的合约地址和 ABI,您需要创建一个代币合约的实例。您可以使用 web3.js 的 web3.eth.Contract 方法来实现这一点,将合约地址和 ABI 作为参数传递给合约实例。查询授权额度
:通过调用合约实例的 allowance 函数来查询授权额度。该函数需要两个参数:拥有者的地址和被授权者的地址。您可以通过在调用时提供这两个地址来查询授权额度。- spenderAddress 地址可以参考 此处 接口 Response 中的 dexTokenApproveAddress。
const { Web3 } = require('web3');
// Connect to an Ethereum node
const web3 = new Web3('https://xxxxx');
// token address and ABI
const tokenAddress = '0xxxxxxxxx';
// user address
const ownerAddress = '0xxxxxxxx';
// ETH dex token approval address
const spenderAddress = '0x40aa958dd87fc8305b97f2ba922cddca374bcd7f';
const tokenABI = [
{
"constant": true,
"inputs": [
{
"name": "_owner",
"type": "address"
},
{
"name": "_spender",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
}
];
// Create token contract instance
const tokenContract = new web3.eth.Contract(tokenABI, tokenAddress);
// Query token approve allowance function
async function getAllowance(ownerAddress, spenderAddress) {
try {
const allowance = await tokenContract.methods.allowance(ownerAddress, spenderAddress).call();
console.log(`Allowance for ${ownerAddress} to ${spenderAddress}: ${allowance}`);
} catch (error) {
console.error('Failed to query allowance:', error);
}
}
getAllowance(ownerAddress, spenderAddress).then(r => console.log(r));
- 下文的 allowanceAmount 代表真实的链上授权额度
2.2 获取授权数量#
提示
获取授权数量。如果 allowanceAmount < fromTokenAmount,请查看步骤 3,如果 allowanceAmount >= fromTokenAmount,你可以选择使用步骤 3 增加授权数量,或者直接进行步骤 4。
const { data: allowanceData } = await getAllowanceData();
const allowanceAmount = allowanceData?.[0]?.allowanceAmount;
3. 检查授权交易参数并发起授权交易#
提示
由于 allowanceAmount < fromTokenAmount,我们需要对该币种进行授权。
3.1 定义授权交易参数#
接下来,定义你要执行授权交易的参数。
const getApproveTransactionParams = {
chainId: fromChainId,
tokenContractAddress: fromTokenAddress,
userWalletAddress,
approveAmount: fromTokenAmount,
};
3.2 定义辅助函数#
定义一个辅助函数,用于与 DEX API 进行交互。
const approveTransaction = async () => {
const { apiRequestUrl, path } = getAggregatorRequestUrl(
'/approve-transaction',
getApproveTransactionParams
);
return fetch(apiRequestUrl, {
method: 'get',
headers: headersParams,
})
.then((res) => res.json())
.then((res) => {
return res;
});
};
3.3 获取授权交易 tx 并且发送授权交易#
if (parseFloat(allowanceAmount) < parseFloat(fromTokenAmount)) {
const { data } = await approveTransaction(allowanceAmount);
let allowanceParams = {
...{ data: data[0].data }, // You can modify the data content you want according to the web3 official website
};
const { rawTransaction } = await web3.eth.accounts.signTransaction(
allowanceParams,
privateKey
);
await web3.eth.sendSignedTransaction(rawTransaction);
}
4. 通过 fromChainId 拿到可以交易的 toChainId 列表,并选择其中一条链作为目标链#
4.1 定义获取支持的目标链参数#
接下来,定义参数,并通过 fromChainId 拿到对应的 toChainId 列表。
const toChainListParams = {
chainId: fromChainId,
};
4.2 定义辅助函数#
定义一个辅助函数,用于与 DEX API 进行交互。
const getSupportedChain = async () => {
const { apiRequestUrl, path } = getCrossChainBaseUrl(
'/supported/chain',
toChainListParams
);
return fetch(apiRequestUrl, {
method: 'get',
headers: headersParams,
})
.then((res) => res.json())
.then((res) => {
return res;
});
};
4.3 获取支持的目标链列表并选择 Arbitrum 链,你也可以根据列表选择其他链作为目标链#
const { data: supportedChainList } = await getSupportedChain();
const selectChainItem = supportedChainList.find((item) => {
return item.chainName === 'Arbitrum';
});
toChainId = selectChainItem?.chainId;
5. 通过 toChainId 拿到该链的币种列表,并且选择其中一个代币作为目标链币种#
5.1 定义获取可交易币种参数#
接下来,定义参数,并通过 toChainId 拿到可交易的币种列表。
const toChainTokenListParams = {
chainId: toChainId,
};
5.2 定义辅助函数#
定义一个辅助函数,用于与 DEX API 进行交互。
const getToChainTokenList = async () => {
const { apiRequestUrl, path } = getAggregatorRequestUrl(
'/all-tokens'',
toChainTokenListParams
);
return fetch(apiRequestUrl, {
method: 'get',
headers: headersParams,
})
.then((res) => res.json())
.then((res) => {
return res;
});
};
5.3 获取币种列表并选择 USDC 币种,你也可以根据列表选择其他币种作为目标链币种#
const { data: toChainTokenList } = await getToChainTokenList();
const selectToChainToken = toChainTokenList.find((item) => {
return item.tokenSymbol === 'USDC';
});
toTokenAddress = selectToChainToken?.tokenContractAddress;
6. 请求询价接口,拿到询价数据,主要目的是为了获取跨链桥 ID#
6.1 定义询价参数#
接下来,定义参数,用来拿到询价的基础信息和路径列表信息。
const quoteParams = {
fromChainId,
toChainId,
fromTokenAddress,
toTokenAddress,
amount: fromTokenAmount,
slippage,
};
6.2 定义辅助函数#
定义一个辅助函数,用于与 DEX API 进行交互。
const getQuote = async () => {
const { apiRequestUrl, path } = getCrossChainBaseUrl('/quote', quoteParams);
return fetch(apiRequestUrl, {
method: 'get',
headers: headersParams,
})
.then((res) => res.json())
.then((res) => {
return res;
});
};
6.3 获取询价信息,并选择一条路径作为交易路径#
const { data: quoteData } = await getQuote();
bridgeId = quoteData[0]?.routerList[0]?.router?.bridgeId;
7. 请求跨链兑换接口,发起交易#
7.1 定义跨链兑换参数#
接下来,定义参数,并获取跨链兑换的 tx 信息。
const swapParams = {
fromChainId: fromChainId,
toChainId: toChainId,
fromTokenAddress,
toTokenAddress,
amount: fromTokenAmount,
slippage,
userWalletAddress,
bridgeId,
};
7.2 定义辅助函数#
定义一个辅助函数,用于与 DEX API 进行交互。
const getSwapData = async () => {
const { apiRequestUrl, path } = getCrossChainBaseUrl('/build-tx', swapParams);
return fetch(apiRequestUrl, {
method: 'get',
headers: headersParams,
})
.then((res) => res.json())
.then((res) => {
return res;
});
};
7.3 请求跨链兑换接口拿到 tx 信息,发起上链交易#
const { data: swapData } = await getSwapData();
const swapDataTxInfo = swapData[0].tx;
const nonce = await web3.eth.getTransactionCount(userWalletAddress, 'latest');
// You can obtain the latest nonce and process the hexadecimal numbers starting with 0x according to your needs
let signTransactionParams = {
data: swapDataTxInfo.data,
gasPrice: swapDataTxInfo.gasPrice,
to: swapDataTxInfo.to,
value: swapDataTxInfo.value,
nonce,
};
const { rawTransaction } = await web3.eth.accounts.signTransaction(
signTransactionParams,
privateKey
);
const chainTxInfo = await web3.eth.sendSignedTransaction(rawTransaction);
transactionTx = chainTxInfo;
8. 查询交易状态#
8.1 定义查询参数#
接下来,定义参数,主要为源链 Hash 地址信息。
const getCheckStatusParams = {
hash: transactionTx,
};
8.2 定义辅助函数#
定义一个辅助函数,用于与 DEX API 进行交互。
const checkTransactionStatus = async () => {
const { apiRequestUrl, path } = getCrossChainBaseUrl(
'/status',
getCheckStatusParams
);
return fetch(apiRequestUrl, {
method: 'get',
headers: headersParams,
})
.then((res) => res.json())
.then((res) => {
return res;
});
};
8.3 获取交易状态#
提示
你也可以增加轮询的方式获取实时订单状态,这里为单次查询的例子。
const { data: statusInfo } = await checkTransactionStatus();
console.log(statusInfo?.data[0]?.detailStatus);