23

教程: 利用Gelato搭建自动Uniswap交易

 3 years ago
source link: https://learnblockchain.cn/article/1682
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

如何使用 Gelato 来执行定时交易

Gelato 用来帮助开发人员自动执行智能合约的工具。

我们都知道,以太坊上的智能合约无法定时执行任务,但是经常有这样的需求场景,例如 DEFI 合约需要定时给合约喂价。

实现定时任务常用的做法是编写一个执行合约交易脚本,然后使用外部定时任务去运行脚本,使用 Gelato 一个显而易见的优势是可以避免单点失败以及节约开发时间。

本教程以每2分钟自动在Uniswap上将DAI交换为ETH为示例, 学习悉如何使用Gelato构建自动执行的交易。

2分钟知识方便开发验证的时间,如果你看开发一个以太坊定投,可以按修改为一周或二周。

rUZRZzq.gif!mobile

项目创建

环境准备

项目是基于node.js开发,因此需要我们先安装:

  • node.js
  • yarn (或 npm )

克隆项目代码

Gelato 提供了教程的源码,把代码克隆到本地,并安装好相应的依赖库:

git clone https://github.com/gelatodigital/gelato-uniswap.git

cd gelato-uniswap

yarn install  # or npm install

有些版本的 node 可能会提示一些 gyp-error 错误,没关系。

配置Infura Key及私钥

自动任务需要和进行链上的 Uniswap 交易,我们使用Infura和节点通信,另外还需要用到用户私钥(用来支付),通常这类的私密信息放在不被代码管理的 .env 文件中( .env 加到 .g​​itignore ):

在项目根目录下添加一个.env文件:

touch .env

将以下变量添加到.env文件中。

DEMO_INFURA_ID="输入你的在 Infura 申请的 Project ID"
DEMO_USER_PK="填入地址私钥,0x 先开头"
DEMO_PROVIDER_PK="填入提供者私钥(用来代替用户付费,本文暂时不需要)"

从这里 你可以免费获得 DEMO_INFURA_ID ,如果遇到问题,可查看 教程

获取DEMO_USER_PK和DEMO_PROVIDER_PK 私钥的一种方法是安装Metamask并按照此 教程 导出所选地址的私钥,注意填入的的私钥需要以 0x 前缀。

此外,还需要为帐户存入一下ETH以便发起交易, 用户 钱包还需要存入一些 DAI 。 因为Demo 是基于 Rinkeby 进行开发的, ETH 可以从 水龙头 获取到,为了防止交易失败,最好将至少2 ETH存入与DEMO_USER_PK关联的帐户:

在用户钱包中包含ETH之后,运行以下命令可以获取100 个 Rinkeby DAI:

yarn get-dai

Gelato 是如何运作的

在使用Gelato之前,先简单介绍一下 Gelato 的运作原理。 Gelato 由一个 中继服务器网络 组成,这些网络的执行者(Executors)被激励为Dapp用户 执行 某些 任务(Task)

“我们”需要为这些 执行者(Executors) 付费,以便运行自动化基础架构,并代表你的用户提交将来的交易。

在Gelato上,付费的主体(上一句话的我们)称为 Gelato Providers(提供者) ,需要预先存入ETH,以在满足预定条件时通过提交交易来支付 执行者 以执行 任务

有两种 Gelato Providers

  1. 自我提供者(Self-Providers) 是最终用户或Dapps自己,他们直接向 执行者 支付费用,因此必须先将ETH存入Gelato再使用。他们自己为将来的交易付费,前面 .env 中的 DEMO_USER_PK 就是用来作为自我提供者,

  2. 外部提供者(External Providers) ,可以代Dapp用户向 执行者 付款。例如,这些是dapp开发人员或DAO,他们希望为用户提供出色的UX,而代替用户在Gelato上存款。前面 .env 中的 DEMO_PROVIDER_PK 就是用来作为外部提供者。

在本教程中,如果作为 自助提供者 ,自行支付 执行者 费用。在之后的文章,将介绍切换成为外部提供者角色。

Gelato 使用详解

现在到有趣的部分,在实践中体验 Gelato,体验使用gelato作为自动执行交易。

我们的 Demo 会 每2分钟在Uniswap上自动用DAI购买WETH,总共进行3笔交易

在 Demo 中与Gelato的交易是通过Buidler 任务来执行的。 Buidler 任务会使用到.env提供的 DEMO_USER_PK 作为钱包,再次确保账号下有Rinkeby ETH和DAI。

在我们的 Demo 为了可以更清楚地了解每一步发生了什么,才拆分为一个个步骤,在实际开发中,很多步骤可以合并在一起。

1. 创建代理合约钱包

为了能够使用Gelato在Uniswap上执行交易,我们需要一个代理合约钱包,来代理用户与Gelato协议进行交互。可以将Gelato视作为一个模块,可以集成到任何智能合约里(包括智能合约钱包: 例如Gnosis Safe,dsProxy等),从而使这些合约可以在将来某个时候(满足指定条件,例如从现在开始的一天)执行交易。

在Demo中,为简单起见,使用Gelato 官方案例提供的 GelatoUserProxy 作为代理合约钱包。从理论上讲,可以使用任何智能合约代理,例如 GnosisSafeMakerDSProxy

运行以下命令部署 GelatoUserProxy 合约:

yarn create-userproxy

该命令会执行 demo/Part-1_Gelato_User/step1-create-user-proxy.js 部署任务脚本,在部署脚本中, 是通过Gelato已经部署好的 GelatoUserProxyFactory 来部署 GelatoUserProxy 合约。

2. 在gelato上预存ETH,选择gelato执行者,并告诉gelato用户拥有哪种代理

为了使新创建的用户代理与Gelato交互,还需要做一些配置:

  1. 需要在Gelato上存入一些ETH,以支付执行者费用;
  2. 选择默认的Gelato执行者网络;
  3. 告诉Gelato需要与哪种智能合约(在本例中为Proxy)交互。 Gelato可以与任何智能合约一起使用,它与代理标准无关,可以与任何智能合约代理标准(例如Gnosis Safe,dsProxy,GelatoUser Proxy等)一起使用。

确保用户帐户中有足够的ETH(1 ETH 以上)。

为了完成上面的 3 件事,运行以下脚本:

yarn userproxy-setup

该命令会执行 demo/Part-1_Gelato_User/step2-user-proxy-setup.js 脚本,脚本里通过 GelatoUserProxy 合约向 GelatoCore 发起一个初始化 Action(动作 - 下面介绍) 完成配置,可以查看源码,探究细节。

3. 通过代理合约钱包将任务提交给Gelato

在Demo中,想要让Gelato代表我们执行3笔交易(称为Task),每笔交易每2分钟用1个DAI去兑换ETH。

Gelato Task(任务) 只是 Conditions (条件 - 什么时候执行交易) 和 Actions (动作 - 交易应执行什么)的组合。

在本 Demo,只有一个用于跟踪时间的 条件 和一个在Uniswap上进行交易的 动作 。但是,也可以根据需要将多个 条件 与多个 动作 组合为一个 任务

在这里,定义 Task(任务) 为:

  • Condition(条件)每2分钟 (或每次在以太坊上达到某个时间戳记时)

  • Action(动作)在Uniswap上用1 DAI兑换WETH (调用uniswap智能合约上的交易函数)

  • Task(任务)每2分钟,在Uniswap上用1 DAI兑换WETH

Condition 条件会由GelatoCore智能合约检查,并在满足条件的区块上执行任务。

动作是其他智能合约要运行的某些逻辑,将由用户GelatoUserProxy检查或执行。你可以编写自己的 ConditionAction 合约,并将其与gelato一起使用,也可以像本教程中一样,使用现有的合约。

看看我们 Demo 的任务:

new Task({
      conditions: [conditionEvery2minutes],  // 条件
      // 包含的动作,所有动作在一个交易完成(要么都失败)
      actions: [
        actionTransferFrom,
        actionApproveUniswapRouter,
        actionSwapTokensUniswap,
        actionUpdateConditionTime,
      ],
      selfProviderGasLimit: estimatedGasPerExecution, // gas Limit 
      selfProviderGasPriceCeil: 0, //  gas 价格上限,0表示不在意价格
    });

任务包含的4 个动作:转账、授权、Uniswap交易、更新时间,我们看一下核心的Uniswap交易动作:

const actionSwapTokensUniswap = new Action({
      addr: UNISWAP_V2_Router_02,
      data: await bre.run("abi-encode-withselector", {
        contractname: "IUniswapV2Router02",
        functionname: "swapExactTokensForTokens",
        inputs: [DAI_AMOUNT_PER_TRADE, 0, tokenPath, myUserAddress, 4102448461],
      }),
      operation: Operation.Call, // This Action must be executed via the UserProxy
    });

完整的任务和动作定义,可以查看代码: demo/Part-1_Gelato_User/step3-submit-task-uniswap.js

如果你有兴趣的话,还可以看看对应条件合约及执行动作合约: Condition合约: contracts/gelato_conditions/ConditionTimeStateful.sol Action合约: 动作由 Uniswap V2 Router2 合约执行

执行以下命令提交任务:

yarn submit-task-uniswap-self-provider-and-monitor

执行这个脚本会发送2个交易:

  1. approve(授权) 代理合约 GelatoUserProxy 可以转移3 DAI,因为之后代理合约要使用 Dai在uniswap上交易。

  2. 任务 提交 GelatoCore.sol ,它定义了从现在开始每2分钟在uniswap上进行交易。

我们可以在Metmask或Etherscan上查看你的 USER 帐户余额中的 DAIWETH 来确认交易是否执行,记得是在Rinkeby网络上哦。

我们也可以使用demo 提供的 demo/Part-1_Gelato_User/monitorBalanceChanges.js 来监听余额的变化:

yarn monitor-balances

这样在定义任务交易执行时,可以在控制台看到打印出交易日志,类似下面:

___:moneybag: Current Token BALANCES! ____:moneybag:

 myUserWallet ETH Balance: 0.97978682 ETH

 myUserWallet DAI Balance:   99.0 DAI

 myUserWallet DAI Allowance:   2.0 DAI

全部交易大概要7分钟完成。

4. (可选) 将剩余的ETH取回“用户钱包”

要将用户的剩余ETH余额撤回其钱包,运行以下脚本:

yarn withdraw-remaining-eth

对应的脚本为: demo/Part-1_Gelato_User/step4-withdraw-remaining-eth.js ,有兴趣可以查看。

到这里,这部分教程就完成了,你应该了解了如何使用 Gelato 来执行定时交易。

接下来

在一些场景下,上述用户体验可能不够友好,因为它要求用户提前将ETH存入Gelato上,然后Gelato才能执行其任务。前面描述了另一种Gelato提供者: 外部提供者 ,可以代表用户为交易付费,因此用户不必存款,从而创造出了更好的用户体验,我们在之后的文章再介绍。

本文由 Cell Network 赞助支持。

Gelato 用来帮助开发人员自动执行智能合约的工具。

我们都知道,以太坊上的智能合约无法定时执行任务,但是经常有这样的需求场景,例如 DEFI 合约需要定时给合约喂价。

实现定时任务常用的做法是编写一个执行合约交易脚本,然后使用外部定时任务去运行脚本,使用 Gelato 一个显而易见的优势是可以避免单点失败以及节约开发时间。

本教程以每2分钟自动在Uniswap上将DAI交换为ETH为示例, 学习悉如何使用Gelato构建自动执行的交易。

2分钟知识方便开发验证的时间,如果你看开发一个以太坊定投,可以按修改为一周或二周。

rUZRZzq.gif!mobile

项目创建

环境准备

项目是基于node.js开发,因此需要我们先安装:

  • node.js
  • yarn (或 npm )

克隆项目代码

Gelato 提供了教程的源码,把代码克隆到本地,并安装好相应的依赖库:

git clone https://github.com/gelatodigital/gelato-uniswap.git

cd gelato-uniswap

yarn install  # or npm install

有些版本的 node 可能会提示一些 gyp-error 错误,没关系。

配置Infura Key及私钥

自动任务需要和进行链上的 Uniswap 交易,我们使用Infura和节点通信,另外还需要用到用户私钥(用来支付),通常这类的私密信息放在不被代码管理的 .env 文件中( .env 加到 .g​​itignore ):

在项目根目录下添加一个.env文件:

touch .env

将以下变量添加到.env文件中。

DEMO_INFURA_ID="输入你的在 Infura 申请的 Project ID"
DEMO_USER_PK="填入地址私钥,0x 先开头"
DEMO_PROVIDER_PK="填入提供者私钥(用来代替用户付费,本文暂时不需要)"

从这里 你可以免费获得 DEMO_INFURA_ID ,如果遇到问题,可查看 教程

获取DEMO_USER_PK和DEMO_PROVIDER_PK 私钥的一种方法是安装Metamask并按照此 教程 导出所选地址的私钥,注意填入的的私钥需要以 0x 前缀。

此外,还需要为帐户存入一下ETH以便发起交易, 用户 钱包还需要存入一些 DAI 。 因为Demo 是基于 Rinkeby 进行开发的, ETH 可以从 水龙头 获取到,为了防止交易失败,最好将至少2 ETH存入与DEMO_USER_PK关联的帐户:

在用户钱包中包含ETH之后,运行以下命令可以获取100 个 Rinkeby DAI:

yarn get-dai

Gelato 是如何运作的

在使用Gelato之前,先简单介绍一下 Gelato 的运作原理。 Gelato 由一个 中继服务器网络 组成,这些网络的执行者(Executors)被激励为Dapp用户 执行 某些 任务(Task)

“我们”需要为这些 执行者(Executors) 付费,以便运行自动化基础架构,并代表你的用户提交将来的交易。

在Gelato上,付费的主体(上一句话的我们)称为 Gelato Providers(提供者) ,需要预先存入ETH,以在满足预定条件时通过提交交易来支付 执行者 以执行 任务

有两种 Gelato Providers

  1. 自我提供者(Self-Providers) 是最终用户或Dapps自己,他们直接向 执行者 支付费用,因此必须先将ETH存入Gelato再使用。他们自己为将来的交易付费,前面 .env 中的 DEMO_USER_PK 就是用来作为自我提供者,

  2. 外部提供者(External Providers) ,可以代Dapp用户向 执行者 付款。例如,这些是dapp开发人员或DAO,他们希望为用户提供出色的UX,而代替用户在Gelato上存款。前面 .env 中的 DEMO_PROVIDER_PK 就是用来作为外部提供者。

在本教程中,如果作为 自助提供者 ,自行支付 执行者 费用。在之后的文章,将介绍切换成为外部提供者角色。

Gelato 使用详解

现在到有趣的部分,在实践中体验 Gelato,体验使用gelato作为自动执行交易。

我们的 Demo 会 每2分钟在Uniswap上自动用DAI购买WETH,总共进行3笔交易

在 Demo 中与Gelato的交易是通过Buidler 任务来执行的。 Buidler 任务会使用到.env提供的 DEMO_USER_PK 作为钱包,再次确保账号下有Rinkeby ETH和DAI。

在我们的 Demo 为了可以更清楚地了解每一步发生了什么,才拆分为一个个步骤,在实际开发中,很多步骤可以合并在一起。

1. 创建代理合约钱包

为了能够使用Gelato在Uniswap上执行交易,我们需要一个代理合约钱包,来代理用户与Gelato协议进行交互。可以将Gelato视作为一个模块,可以集成到任何智能合约里(包括智能合约钱包: 例如Gnosis Safe,dsProxy等),从而使这些合约可以在将来某个时候(满足指定条件,例如从现在开始的一天)执行交易。

在Demo中,为简单起见,使用Gelato 官方案例提供的 GelatoUserProxy 作为代理合约钱包。从理论上讲,可以使用任何智能合约代理,例如 GnosisSafeMakerDSProxy

运行以下命令部署 GelatoUserProxy 合约:

yarn create-userproxy

该命令会执行 demo/Part-1_Gelato_User/step1-create-user-proxy.js 部署任务脚本,在部署脚本中, 是通过Gelato已经部署好的 GelatoUserProxyFactory 来部署 GelatoUserProxy 合约。

2. 在gelato上预存ETH,选择gelato执行者,并告诉gelato用户拥有哪种代理

为了使新创建的用户代理与Gelato交互,还需要做一些配置:

  1. 需要在Gelato上存入一些ETH,以支付执行者费用;
  2. 选择默认的Gelato执行者网络;
  3. 告诉Gelato需要与哪种智能合约(在本例中为Proxy)交互。 Gelato可以与任何智能合约一起使用,它与代理标准无关,可以与任何智能合约代理标准(例如Gnosis Safe,dsProxy,GelatoUser Proxy等)一起使用。

确保用户帐户中有足够的ETH(1 ETH 以上)。

为了完成上面的 3 件事,运行以下脚本:

yarn userproxy-setup

该命令会执行 demo/Part-1_Gelato_User/step2-user-proxy-setup.js 脚本,脚本里通过 GelatoUserProxy 合约向 GelatoCore 发起一个初始化 Action(动作 - 下面介绍) 完成配置,可以查看源码,探究细节。

3. 通过代理合约钱包将任务提交给Gelato

在Demo中,想要让Gelato代表我们执行3笔交易(称为Task),每笔交易每2分钟用1个DAI去兑换ETH。

Gelato Task(任务) 只是 Conditions (条件 - 什么时候执行交易) 和 Actions (动作 - 交易应执行什么)的组合。

在本 Demo,只有一个用于跟踪时间的 条件 和一个在Uniswap上进行交易的 动作 。但是,也可以根据需要将多个 条件 与多个 动作 组合为一个 任务

在这里,定义 Task(任务) 为:

  • Condition(条件)每2分钟 (或每次在以太坊上达到某个时间戳记时)

  • Action(动作)在Uniswap上用1 DAI兑换WETH (调用uniswap智能合约上的交易函数)

  • Task(任务)每2分钟,在Uniswap上用1 DAI兑换WETH

Condition 条件会由GelatoCore智能合约检查,并在满足条件的区块上执行任务。

动作是其他智能合约要运行的某些逻辑,将由用户GelatoUserProxy检查或执行。你可以编写自己的 ConditionAction 合约,并将其与gelato一起使用,也可以像本教程中一样,使用现有的合约。

看看我们 Demo 的任务:

new Task({
      conditions: [conditionEvery2minutes],  // 条件
      // 包含的动作,所有动作在一个交易完成(要么都失败)
      actions: [
        actionTransferFrom,
        actionApproveUniswapRouter,
        actionSwapTokensUniswap,
        actionUpdateConditionTime,
      ],
      selfProviderGasLimit: estimatedGasPerExecution, // gas Limit 
      selfProviderGasPriceCeil: 0, //  gas 价格上限,0表示不在意价格
    });

任务包含的4 个动作:转账、授权、Uniswap交易、更新时间,我们看一下核心的Uniswap交易动作:

const actionSwapTokensUniswap = new Action({
      addr: UNISWAP_V2_Router_02,
      data: await bre.run("abi-encode-withselector", {
        contractname: "IUniswapV2Router02",
        functionname: "swapExactTokensForTokens",
        inputs: [DAI_AMOUNT_PER_TRADE, 0, tokenPath, myUserAddress, 4102448461],
      }),
      operation: Operation.Call, // This Action must be executed via the UserProxy
    });

完整的任务和动作定义,可以查看代码: demo/Part-1_Gelato_User/step3-submit-task-uniswap.js

如果你有兴趣的话,还可以看看对应条件合约及执行动作合约: Condition合约: contracts/gelato_conditions/ConditionTimeStateful.sol Action合约: 动作由 Uniswap V2 Router2 合约执行

执行以下命令提交任务:

yarn submit-task-uniswap-self-provider-and-monitor

执行这个脚本会发送2个交易:

  1. approve(授权) 代理合约 GelatoUserProxy 可以转移3 DAI,因为之后代理合约要使用 Dai在uniswap上交易。

  2. 任务 提交 GelatoCore.sol ,它定义了从现在开始每2分钟在uniswap上进行交易。

我们可以在Metmask或Etherscan上查看你的 USER 帐户余额中的 DAIWETH 来确认交易是否执行,记得是在Rinkeby网络上哦。

我们也可以使用demo 提供的 demo/Part-1_Gelato_User/monitorBalanceChanges.js 来监听余额的变化:

yarn monitor-balances

这样在定义任务交易执行时,可以在控制台看到打印出交易日志,类似下面:

___:moneybag: Current Token BALANCES! ____:moneybag:

 myUserWallet ETH Balance: 0.97978682 ETH

 myUserWallet DAI Balance:   99.0 DAI

 myUserWallet DAI Allowance:   2.0 DAI

全部交易大概要7分钟完成。

4. (可选) 将剩余的ETH取回“用户钱包”

要将用户的剩余ETH余额撤回其钱包,运行以下脚本:

yarn withdraw-remaining-eth

对应的脚本为: demo/Part-1_Gelato_User/step4-withdraw-remaining-eth.js ,有兴趣可以查看。

到这里,这部分教程就完成了,你应该了解了如何使用 Gelato 来执行定时交易。

接下来

在一些场景下,上述用户体验可能不够友好,因为它要求用户提前将ETH存入Gelato上,然后Gelato才能执行其任务。前面描述了另一种Gelato提供者: 外部提供者 ,可以代表用户为交易付费,因此用户不必存款,从而创造出了更好的用户体验,我们在之后的文章再介绍。

本文由 Cell Network 赞助支持。

本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

  • 发表于 17分钟前
  • 阅读 ( 31 )
  • 学分 ( 0 )
  • 分类:以太坊

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK