以太坊 - 使用JavaScript与0x API进行交互 - Quicknode

  • QuickNode
  • 发布于 2024-05-11 21:37
  • 阅读 29

本文详细介绍了去中心化交易所(DEX)的定义及其技术原理,重点阐述了0x协议如何通过API提供最佳价格报价,从而简化加密货币的交易过程。文章还包含了代码示例,展示如何使用0x的API获取不同DEX的交易报价,适合希望深入理解DEX及其应用的开发者和爱好者。

概述

我们已经看到去中心化交易所(DEX)交易量的迅猛增长。随着越来越多的 DEX 进入市场,在想要将一种代币兑换为另一种代币时,选择哪个 DEX 变得困难。这就是 0x 及其 API 的作用。它帮助我们获取最佳价格报价。这将为我们想要交换的代币数量提供更好的结果,你最终会在最后看到。因此,请确保跟随我们直到最后。

前提条件:

1. 终端

2. Node

3. 代码编辑器

4. 求知欲

什么是 DEX?

一个 D ecentralised EX changes,通俗称为 DEX,是区块链生态系统中的关键部分。它是一个去中心化的市场,以点对点的方式连接加密货币买卖双方,不涉及任何控制或中心权威。在这一领域,一些流行的 DEX 包括 UniSwap、SushiSwap 和 PancakeSwap。每个 DEX 都由智能合约驱动,以确定性和不可阻止的方式运行。由于 DEX 是无许可的,它们的受欢迎程度迅速增长,数量也大幅增加。在任何中心化交易所,你都需要通过 KYC 验证身份,而交易所控制着你的私钥。因此,如果组织被黑客攻击或冻结了你的账户,你的资金将永久丢失。但是在 DEX 中,用户控制着私钥。唯一的限制因素是合约中的安全漏洞。任何一个优秀的 DEX 都会从多个机构进行审计,以确保它们不易受到攻击。因此,如果你想把 ETH 兑换成一些 DAI,你可以轻松地使用 DEX 完成。

DEX 的核心 → AMM

自动化市场制造商(Automated Market Maker)或 AMM 驱动着 DEX。AMM 在其核心使用一个数学公式来决定一对代币的价格,并促进代币的交易。它帮助报价两个资产的兑换率,并允许任何人通过提供流动性来构建双边市场,即成为市场制造商。例如,Uniswap 使用 x*y=k 作为 AMM。这里 x 是一种代币的数量,y 是另一种代币的数量。现在,这两个代币的乘积应该是恒定的,由 k 表示。理想情况下,无论添加或移除多少代币,它将会平衡以保持乘积稳定。其他功能包括交换、流动性挖矿等等。

关于 0X

根据 官方文档

0x 是一个促进基于以太坊资产的点对点交换的协议。该协议作为开放标准和任何需要交换功能的开发者的通用构件。

0x 是一种独一无二的协议,它允许以传统的委托订单方法进行点对点交易。委托订单是一种标准的交易方法,根据买家和卖家报价的价格进行匹配。虽然对于中心化交易所来说,这是一种可行且时尚的选择,但对于 DEX 来说,它会变得非常昂贵且耗时。每笔交易和智能合约的交互都会消耗 gas,即金钱。0x 承诺通过将某些程序移到链外来消除这一痛点。这将为参与者节省大量资金,并使过程更快。简而言之,交易启动是在链外进行的,而结算是在链上完成的,这使得无摩擦的去中心化订单簿的梦想成为现实。

该协议的关键参与者有 MakersTakersRelayers。Makers 是发起交易的市场实体,而 Takers 是满足交易的实体。介于二者之间的是 Relayers,连接 Makers 和 Takers,并记录所有链外结算。假设 Maker 想要交换代币 A 和代币 B,则过程如下:

1. Maker 批准 0x 合同以访问其代币 A 的余额,并发起将其兑换为代币 B 的订单。Maker 使用私钥签署交易,将订单转换为 **消息格式**,准备传输到链外通道。

2. Maker 通过 Relayer 广播该订单。0x 有一个浏览器页面列出了 Relayers。

3. 想要填补该订单的 Taker 批准 0x 合同以访问其代币 B 的余额。

4. Taker 通过提交订单到以太坊区块链上的 0x 合同来填补该订单。

5. Relayer 接收以 XRZ 的形式支付的费用,XRZ 是 0x 的原生代币。

0x 是下一代 DEX,允许开发者利用其开放的软件构建 Dapps 和相关项目。0x 提供开发者友好的资源并支持在 0x 上开发项目。通过这种方式,0x 成为商人和开发者的诱人选择。0x 相信,任何可以拥有的资产都可以被代币化,即在区块链上表示为代币。这意味着,你的房子很快就可以被定义为区块链上的代币,并且可以以去中心化的方式进行交易,而无需律师或经纪公司等中介。0x 正在发展,并计划满足这样的需求。

代码

现在,我们将利用 0x 提供的 API 来构建一个应用程序,以帮助我们找到最佳 DEX 来交换我们的代币。

安装

1. 为此,创建一个名为 ZRX_Swap 的文件夹。进入该文件夹,在终端中输入:

npm init -y

2. 现在在你喜欢的编辑器中打开该文件夹。对于本文,我们将使用 VS Code 编辑器。现在,运行以下命令在 VS 编辑器中打开该文件夹:

code .

3. 我们需要安装一个名为 qs 的包。为此:

npm install qs --save

4. 现在,我们还需要安装一个名为 axios 的包。它将帮助我们调用 0x API。为此:

npm install axios --save

编写代码

创建一个名为 index.js 的文件来存放我们的主要代码。在此文件中,我们将获取 0x 发送的最佳报价,并尝试单独从 UniSwapV3 获取相同的报价。这突显了我们可以选择特定的交易所,也可以让 0x 决定对我们来说最佳的交易所。将以下代码复制并粘贴到该文件中:

const { default: axios } = require('axios')
const qs = require('qs')
const params = {
  buyToken: 'DAI',
  sellToken: 'ETH',
  sellAmount: 0.05 * Math.pow(10, 18).toString(), // 始终以 wei 计
}
const URL = 'https://api.0x.org/swap/v1/quote?'

// 获取默认报价
const getDefaultQuote = async () => {
  let response
  try {
    response = await axios.get(`${URL}${qs.stringify(params)}`)
  } catch (err) {
    console.error(err)
  }
  console.log("默认报价")
  console.log("%O",response.data)
  console.log("%O",response.data.sources)

}

// 从特定 DEX 获取报价
const getUniSwapV3Quote = async (inputToken, outputToken, value) => {
  const exchangeList = 'Uniswap_V3'
  const params = {
    buyToken: 'DAI',
    sellToken: 'ETH',
    sellAmount: 0.05 * Math.pow(10, 18).toString(), // 始终以 wei 计
    includedSources: exchangeList,
  }
  let response
  try {
    response = await axios.get(
      `${URL}${qs.stringify(params)}`,
    )
  } catch (err) {
    console.error(err)
  }
  console.log("Uniswap 报价",)
  console.log("%O",response.data)
  console.log("%O",response.data.sources)
}

getDefaultQuote()
getUniSwapV3Quote()

第 1 行:我们正在导入 axios,这是一个流行的 Node 模块,用于进行 HTTPS 请求。

第 2 行:接下来,我们正在导入 qs,它主要用于格式化我们的查询字符串,以便我们的 API 正常工作。

第 3-7 行:我们正在创建一个对象,包含以下信息:

1. 我们想要出售的代币。在本例中,是以太(即 ETH)。

2. 我们想要购买的代币。因此,我们将购买一些 DAI。

3. 你想要出售的代币数量。在本例中,我们出售 0.005 以太或 0.005 * 10^18 Wei。

第 8 行:我们将基本 URL 存储在一个变量中。

第 11 行:我们定义一个可以为给定的代币对获取最佳价格报价的函数。

第 12 行:我们定义一个变量来存储从 API 获得的响应。

第 13 行: try 块的开始。

第 14 行:我们使用 axios 调用 API。在 get 参数中,我们传递基本 URL 和格式化的查询对象。我们将输出存储在 response 变量中。

第 15-17 行: try 块的结束。我们有一个 catch 块,用于记录从 API 返回的错误。

第 18-21 行:我们展示代币对的报价和我们获取它们的来源。

第 24-41 行:我们遵循与上述相同的过程,只是我们在 params 对象中传递了一个额外字段,即 includedSources ,其中包含我们希望获取报价的 DEX 的名称。在本例中,我们希望从 UniSwapV3 获取报价。

第 43-44 行:我们调用上述函数以查看其输出。

现在,在终端中运行:

node index

输出

你应该看到类似以下内容的输出:

1. 对于默认报价

默认报价
{
  chainId: 1,
  price: '1813.2127887520304968',
  guaranteedPrice: '1795.0806608645101918',
  to: '0xdef1c0ded9bec7f1a1670819833240f027b25eff',
  data: '0xd9627aa400000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000007c8f09c066034caf00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f869584cd0000000000000000000000001000000000000000000000000000000000000011000000000000000000000000000000000000000000000083951146f160f5b444',
  value: '5000000000000000',
  gas: '136000',
  estimatedGas: '136000',
  gasPrice: '59000000000',
  protocolFee: '0',
  minimumProtocolFee: '0',
  buyTokenAddress: '0x6b175474e89094c44da98b954eedeac495271d0f',
  sellTokenAddress: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
  buyAmount: '9066063943760152484',
  sellAmount: '5000000000000000',
  sources: [\
    { name: '0x', proportion: '0' },\
    { name: 'Uniswap', proportion: '0' },\
    { name: 'Uniswap_V2', proportion: '0' },\
    { name: 'Eth2Dai', proportion: '0' },\
    { name: 'Kyber', proportion: '0' },\
    { name: 'Curve', proportion: '0' },\
    { name: 'Balancer', proportion: '0' },\
    { name: 'Balancer_V2', proportion: '0' },\
    { name: 'Bancor', proportion: '0' },\
    { name: 'mStable', proportion: '0' },\
    { name: 'Mooniswap', proportion: '0' },\
    { name: 'Swerve', proportion: '0' },\
    { name: 'SnowSwap', proportion: '0' },\
    { name: 'SuiSwap', proportion: '1' },\
    { name: 'Shell', proportion: '0' },\
    { name: 'MultiHop', proportion: '0' },\
    { name: 'DODO', proportion: '0' },\
    { name: 'DODO_V2', proportion: '0' },\
    { name: 'CREAM', proportion: '0' },\
    { name: 'LiquidityProvider', proportion: '0' },\
    { name: 'CryptoCom', proportion: '0' },\
    { name: 'Linkswap', proportion: '0' },\
    { name: 'Lido', proportion: '0' },\
    { name: 'MakerPsm', proportion: '0' },\
    { name: 'KyberDMM', proportion: '0' },\
    { name: 'Smoothy', proportion: '0' },\
    { name: 'Component', proportion: '0' },\
    { name: 'Saddle', proportion: '0' },\
    { name: 'xSigma', proportion: '0' },\
    { name: 'Uniswap_V3', proportion: '0' },\
    { name: 'Curve_V2', proportion: '0' },\
    { name: 'ShibaSwap', proportion: '0' }\
  ],
  orders: [\
    {\
      makerToken: '0x6b175474e89094c44da98b954eedeac495271d0f',\
      takerToken: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',\
      makerAmount: '9066063943760152484',\
      takerAmount: '5000000000000000',\
      fillData: [Object],\
      source: 'SuiSwap',\
      sourcePathId: '0x2ea41c4f046aa0e743deb854fb95d19a4c011243a12d190f8a22cf14e974c86b',\
      type: 0\
    }\
  ],
  allowanceTarget: '0x0000000000000000000000000000000000000000',
  sellTokenToEthRate: '1',
  buyTokenToEthRate: '1813.2096453862199738'
}
[\
  { name: '0x', proportion: '0' },\
  { name: 'Uniswap', proportion: '0' },\
  { name: 'Uniswap_V2', proportion: '0' },\
  { name: 'Eth2Dai', proportion: '0' },\
  { name: 'Kyber', proportion: '0' },\
  { name: 'Curve', proportion: '0' },\
  { name: 'Balancer', proportion: '0' },\
  { name: 'Balancer_V2', proportion: '0' },\
  { name: 'Bancor', proportion: '0' },\
  { name: 'mStable', proportion: '0' },\
  { name: 'Mooniswap', proportion: '0' },\
  { name: 'Swerve', proportion: '0' },\
  { name: 'SnowSwap', proportion: '0' },\
  { name: 'SuiSwap', proportion: '1' },\
  { name: 'Shell', proportion: '0' },\
  { name: 'MultiHop', proportion: '0' },\
  { name: 'DODO', proportion: '0' },\
  { name: 'DODO_V2', proportion: '0' },\
  { name: 'CREAM', proportion: '0' },\
  { name: 'LiquidityProvider', proportion: '0' },\
  { name: 'CryptoCom', proportion: '0' },\
  { name: 'Linkswap', proportion: '0' },\
  { name: 'Lido', proportion: '0' },\
  { name: 'MakerPsm', proportion: '0' },\
  { name: 'KyberDMM', proportion: '0' },\
  { name: 'Smoothy', proportion: '0' },\
  { name: 'Component', proportion: '0' },\
  { name: 'Saddle', proportion: '0' },\
  { name: 'xSigma', proportion: '0' },\
  { name: 'Uniswap_V3', proportion: '0' },\
  { name: 'Curve_V2', proportion: '0' },\
  { name: 'ShibaSwap', proportion: '0' }\
]

2. 对于 UniSwapV3 报价

UniswapV3 报价
{
  chainId: 1,
  price: '1819.24780097598123892',
  guaranteedPrice: '1801.05532296622142652',
  to: '0xdef1c0ded9bec7f1a1670819833240f027b25eff',
  data: '0x3598d8ab0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000004e1bbb1b11f673a5e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002bc02aaa39b223fe8d0a0e5c4f27ead9083c756cc20001f46b175474e89094c44da98b954eedeac495271d0f000000000000000000000000000000000000000000869584cd00000000000000000000000010000000000000000000000000000000000000110000000000000000000000000000000000000000000000c2bfe11f3560f5b443',
  value: '50000000000000000',
  gas: '151000',
  estimatedGas: '151000',
  gasPrice: '59000000000',
  protocolFee: '0',
  minimumProtocolFee: '0',
  buyTokenAddress: '0x6b175474e89094c44da98b954eedeac495271d0f',
  sellTokenAddress: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
  buyAmount: '90962390048799061946',
  sellAmount: '50000000000000000',
  sources: [\
    { name: '0x', proportion: '0' },\
    { name: 'Uniswap', proportion: '0' },\
    { name: 'Uniswap_V2', proportion: '0' },\
    { name: 'Eth2Dai', proportion: '0' },\
    { name: 'Kyber', proportion: '0' },\
    { name: 'Curve', proportion: '0' },\
    { name: 'Balancer', proportion: '0' },\
    { name: 'Balancer_V2', proportion: '0' },\
    { name: 'Bancor', proportion: '0' },\
    { name: 'mStable', proportion: '0' },\
    { name: 'Mooniswap', proportion: '0' },\
    { name: 'Swerve', proportion: '0' },\
    { name: 'SnowSwap', proportion: '0' },\
    { name: 'SuiSwap', proportion: '0' },\
    { name: 'Shell', proportion: '0' },\
    { name: 'MultiHop', proportion: '0' },\
    { name: 'DODO', proportion: '0' },\
    { name: 'DODO_V2', proportion: '0' },\
    { name: 'CREAM', proportion: '0' },\
    { name: 'LiquidityProvider', proportion: '0' },\
    { name: 'CryptoCom', proportion: '0' },\
    { name: 'Linkswap', proportion: '0' },\
    { name: 'Lido', proportion: '0' },\
    { name: 'MakerPsm', proportion: '0' },\
    { name: 'KyberDMM', proportion: '0' },\
    { name: 'Smoothy', proportion: '0' },\
    { name: 'Component', proportion: '0' },\
    { name: 'Saddle', proportion: '0' },\
    { name: 'xSigma', proportion: '0' },\
    { name: 'Uniswap_V3', proportion: '1' },\
    { name: 'Curve_V2', proportion: '0' },\
    { name: 'ShibaSwap', proportion: '0' }\
  ],
  orders: [\
    {\
      makerToken: '0x6b175474e89094c44da98b954eedeac495271d0f',\
      takerToken: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',\
      makerAmount: '90962390048799061946',\
      takerAmount: '50000000000000000',\
      fillData: [Object],\
      source: 'Uniswap_V3',\
      sourcePathId: '0xfe215f0d81d8367ed86f2044b4b354d556f564f8bcb5bfec85fa07c54f31015c',\
      type: 0\
    }\
  ],
  allowanceTarget: '0x0000000000000000000000000000000000000000',
  sellTokenToEthRate: '1',
  buyTokenToEthRate: '1813.2096453862199738'
}
[\
  { name: '0x', proportion: '0' },\
  { name: 'Uniswap', proportion: '0' },\
  { name: 'Uniswap_V2', proportion: '0' },\
  { name: 'Eth2Dai', proportion: '0' },\
  { name: 'Kyber', proportion: '0' },\
  { name: 'Curve', proportion: '0' },\
  { name: 'Balancer', proportion: '0' },\
  { name: 'Balancer_V2', proportion: '0' },\
  { name: 'Bancor', proportion: '0' },\
  { name: 'mStable', proportion: '0' },\
  { name: 'Mooniswap', proportion: '0' },\
  { name: 'Swerve', proportion: '0' },\
  { name: 'SnowSwap', proportion: '0' },\
  { name: 'SuiSwap', proportion: '0' },\
  { name: 'Shell', proportion: '0' },\
  { name: 'MultiHop', proportion: '0' },\
  { name: 'DODO', proportion: '0' },\
  { name: 'DODO_V2', proportion: '0' },\
  { name: 'CREAM', proportion: '0' },\
  { name: 'LiquidityProvider', proportion: '0' },\
  { name: 'CryptoCom', proportion: '0' },\
  { name: 'Linkswap', proportion: '0' },\
  { name: 'Lido', proportion: '0' },\
  { name: 'MakerPsm', proportion: '0' },\
  { name: 'KyberDMM', proportion: '0' },\
  { name: 'Smoothy', proportion: '0' },\
  { name: 'Component', proportion: '0' },\
  { name: 'Saddle', proportion: '0' },\
  { name: 'xSigma', proportion: '0' },\
  { name: 'Uniswap_V3', proportion: '1' },\
  { name: 'Curve_V2', proportion: '0' },\
  { name: 'ShibaSwap', proportion: '0' }\
]

以下是你要注意的一些事项:

1. price:它为代币对提供最佳价格,该价格不涉及 滑点率.

2. guaranteedPrice:如果存在较大的滑点率,它为代币对提供价格。如果未达到此价格,API 将撤回比赛。

3. buyAmount:以 Wei 计的代币数量。

4. sellAmount:以 Wei 计的我们出售的代币数量。

5. sources:它显示资金在不同 DEX 之间分配的比例。我们从单个 DEX 获取全部金额,因此在这两种情况下我们都有 1 的比例。

如果你仔细观察,你会发现从 SushiSwap 获取的 buyAmount 比从 UniSwapV3 获取的要高。现在,你可以在 SushiSwap 将我们的 ETH 兑换成更多的 DAI。建议你尝试不同的代币对,并将默认报价与你最喜欢的 DEX 进行比较。以下是你可以在 params: 中传递的 DEX 列表:

如果你想从多个 DEX 获取报价,可以通过逗号分隔指定它们在 includedSources 中。因此,如果你想从 SushiSwap 和 UniSwapV3 获取报价,你可以这样指定:

const exchangeList = 'Uniswap_V3,SushiSwap'
  const params = {
    buyToken: 'DAI',
    sellToken: 'ETH',
    sellAmount: 0.05 * Math.pow(10, 18).toString(), // 始终以 wei 计
    includedSources: exchangeList,
  }

结论

我们能够使用 0x API 获取代币对的最佳价格报价。我们不需要遍历所有 DEX,比较报价以获取最佳报价并进行交易。相反,我们利用 API 获取最佳价格报价。这可以成为你构建套利机器人(arbitrage bot)的基础。你可以查阅 官方文档 来构建你下一个创新项目。

请订阅我们的 新闻通讯,获取有关以太坊的更多文章和指南。如果你有任何反馈,欢迎通过 Twitter 联系我们。你也可以在 Discord 社区服务器上与我们聊天,那里聚集了一些你见过的最酷的开发者 :)

  • 原文链接: quicknode.com/guides/def...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
QuickNode
QuickNode
江湖只有他的大名,没有他的介绍。