DEX API
构建跨链应用

构建跨链应用#

在本指南中,我们将通过欧易 DEX 提供的一个示例来展示如何进行跨链兑换,使用 Ethereum 链上的 USDT 兑换 Arbitrum 链上的 USDC。这个过程包括:

  • 设置你的环境
  • 检查授权额度
  • 检查授权交易参数并发起授权交易
  • 通过 fromChainId 拿到可以交易的 toChainId 列表,并选择其中一条链作为目标链
  • 通过 toChainId 拿到该链的币种列表,并且选择其中一个代币作为目标链币种
  • 请求询价接口,拿到询价数据,主要目的是为了获取跨链桥 ID
  • 请求跨链兑换接口,发起交易
  • 查询交易状态
提示
这个例子使用的是 Ethereum 链;但该方法同时也支持水平扩展,可以通过添加节点来增加链的容量和吞吐量。同时,它还支持智能合约的编写和执行,提供更多应用开发的可能性。

1. 设置你的环境#

导入必要的 Node.js 库并设置你的环境变量以及定义辅助函数和组装参数 Node.js 环境设置

2. 检查授权额度#

2.1 请参考查询授权额度教程#

查询授权额度

  • 下文的 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);