Uniswap对接PHP开发包

Uniswap.php 开发包适用于为PHP应用快速增加对Uniswap协议的支持能力。即支持使用自有部署以太坊区块链节点的应用场景,也支持使用第三方节点的轻量级部署场景。官方下载地址:Uniswap.php对接开发包

1、开发包概述

Uniswap.php开发包主要包含以下特性:

  • 一键部署Uniswap协议,便于快速开发与测试
  • 支持Uniswap协议的全部接口,并提供开发人员友好的API
  • 支持ERC20/ERC20、ETH/ERC20等各种交易对的流动性添加、移除与兑换交易
  • 支持自动做市价格计算与滑点计算
  • 支持以太坊交易gas用量与gas价格的自动估算与手动设定
  • 支持EIP712签名授权,单一交易内完成流动性维护

Uniswap.php开发包运行在 Php 7.1+ 环境下,当前版本1.0.0,主要类/接口及关系如下图所示:

在这里插入图片描述

Uniswap.php开发包的主要代码文件清单如下:

代码文件 说明
uniswap.php/src/SwapKit.php Uniswap.php开发包入口类
uniswap.php/src/OrderBuilder.php 流动性维护订单构造器
uniswap.php/src/Order.php 流动性维护订单类
uniswap.php/src/TradeBuilder.php 兑换交易构造器
uniswap.php/src/Trade.php 兑换交易类
uniswap.php/src/PermitSigner.php EIP712签名实现类
uniswap.php/src/SmartContract.php 智能合约封装类
uniswap.php/src/Transactor.php 以太坊交易执行器
uniswap.php/src/Credential.php 以太坊身份标识类
uniswap.php/src/Callback.php 回调执行辅助类
uniswap.php/src/helper.php 其他辅助函数
demo/config.php 演示程序参数配置文件
deploy-contracts.php Uniswap及测试Token合约部署工具,可用于快速开发与测试
demo/add-liquidity.php ERC20/ERC20交易对流动性添加演示
demo/add-liquidity.php ERC20/ERC20交易对流动性添加演示
demo/add-liquidity-eth.php ERC20/ETH交易对流动性添加演示
demo/remove-liquidity.php ERC20/ERC20交易对流动性移除演示
demo/remove-liquidity-eth.php ERC20/ETH交易对流动性移除演示
demo/swap-exact-tokens-for-tokens.php ERC20/ERC20兑换演示,以输入token数量为基准
demo/swap-tokens-for-exact-tokens.php ERC20/ERC20兑换演示,以输出token数量为基准
demo/swap-exact-eth-for-tokens.php ETH/ERC20兑换演示,以输入eth数量为基准
demo/swap-eth-for-exact-tokens.php ETH/ERC20兑换演示,以输出token数量为基准
demo/swap-exact-tokens-for-eth.php ERC20/ETH兑换演示,以输入token数量为基准
demo/swap-tokens-for-exact-eth.php ERC20/ETH兑换演示,以输出eth数量为基准
contract/HappyToken.sol 标准ERC20 token实现,开发测试用
contract/TetherToken.sol Tether/USDT实现,开发测试用
contract/UniswapV2Factory.sol Uniswap V2工厂合约实现
contract/UniswapV2Router02.sol Uniswap V2路由合约实现
contract/WETH9.sol WETH9合约实现
bin/ solc编译器目录
build-contract.sh 合约编译脚本
vendor 第三方依赖包目录
composer.json composer配置文件

2、使用示例代码

2.1 编译合约

在终端进入项目目录,执行如下命令编译Uniswap及开发包提供的测试Token合约:

~$ cd ~/uniswap.php
~/uniswap.php$ ./build-contract.sh

执行结果如下:

在这里插入图片描述

2.2 部署合约

首先在另一个终端启动开发私链:

~$ ganache-cli -d

然后进入项目demo目录,执行如下命令部署合约:

~$ cd ~/uniswap.php/demo
~/uniswap.php/demo$ php deploy-contracts.php

执行结果如下:

在这里插入图片描述

注意 :如果需要在以太坊测试链,例如Ropsten、Rinkeby等,或者在主链 部署上述合约,或者使用其他参数启动ganache-cli,需要修改demo/config.php 中的账号配置。

2.3 Token授权

代码token-approve.php演示了如何授权Uniswap路由合约代理操作当前账号的HAPY token和USDT token。

在终端进入项目demo目录,执行如下命令:

~$ cd ~/uniswap.php/demo
~/uniswap.php/demo$ php token-approve.php

执行结果如下:

在这里插入图片描述

2.4 ERC20/ERC20交易对添加流动性

代码add-liquidity.php演示了如何为ERC20/ERC20交易对添加流动性。

在终端进入项目demo目录,执行如下命令:

~$ cd ~/uniswap.php/demo
~/uniswap.php/demo$ php add-liquidity.php

执行结果如下:

在这里插入图片描述

Uniswap协议约定,第一次添加流动性将自动创建交易对 ,之后再次添加流动性时,演示代码将首先显示当前的仓位信息。例如再次执行如下命令:

~/uniswap.php/demo$ php add-liquidity.php

执行结果如下:

在这里插入图片描述

2.5 ERC20/ERC20交易对移除流动性

代码remove-liquidity.php演示了如何移除指定的ERC20/ERC20交易对的流动性。

在终端进入项目demo目录,执行如下命令:

~$ cd ~/uniswap.php/demo
~/uniswap.php/demo$ php remove-liquidity.php

执行结果如下:

在这里插入图片描述

2.6 ERC20/ERC20兑换:以输入token数量为基准

代码swap-exact-tokens-for-tokens.php演示了如何实现以输入token数量为基准的ERC20/ERC20兑换。

在终端进入项目demo目录,执行如下命令:

~$ cd ~/uniswap.php/demo
~/uniswap.php/demo$ php swap-exact-tokens-for-tokens.php

执行结果如下:

在这里插入图片描述

2.7 ERC20/ERC20兑换:以输出token数量为基准

代码swap-tokens-for-exact-tokens.php演示了如何实现以输出
token数量为基准的ERC20/ERC20兑换。

在终端进入项目demo目录,执行如下命令:

~$ cd ~/uniswap.php/demo
~/uniswap.php/demo$ php swap-tokens-for-exact-tokens.php

执行结果如下:

在这里插入图片描述

2.8 ETH/ERC20交易对添加流动性

代码add-liquidty-eth.php演示了如何为ETH/ERC20或ERC20/ETH交易对添加流动性。

在终端进入项目demo目录,执行如下命令:

~$ cd ~/uniswap.php/demo
~/uniswap.php/demo$ php add-liquidity-eth.php

执行结果如下:

在这里插入图片描述

第一次添加流动性将自动创建交易对,之后再次添加将首先显示
当前的持仓信息。例如再次执行如下命令:

~/uniswap.php/demo$ php add-liquidity-eth.php

执行结果如下:
在这里插入图片描述

2.9 ETH/ERC20交易对移除流动性

代码remove-liquidity-eth.php演示了如何移除ETH/ERC20或ERC20/ETH
交易对的流动性。

在终端进入项目demo目录,执行如下命令:

~$ cd ~/uniswap.php/demo
~/uniswap.php/demo$ php remove-liquidity-eth.php

执行结果如下:

在这里插入图片描述

2.10 ETH/ERC20兑换:以输入ETH数量为基准

代码swap-exact-eth-for-tokens.php演示和如何将指定数量的ETH
兑换为ERC20 token。

在终端进入项目demo目录,执行如下命令:

~$ cd ~/uniswap.php/demo
~/uniswap.php/demo$ php swap-exact-eth-for-tokens.php

执行结果如下:

在这里插入图片描述

2.11 ETH/ERC20兑换:以输出token数量为基准

代码swap-eth-for-exact-tokens.php演示了如何将ETH兑换为指定
数量的ERC20 token。

在终端进入项目demo目录,执行如下命令:

~$ cd ~/uniswap.php/demo
~/uniswap.php/demo$ php swap-eth-for-exact-tokens.php

执行结果如下:

在这里插入图片描述

2.12 ERC20/ETH兑换:以输入token数量为基准

代码swap-exact-tokens-for-eth.php演示了如何将指定数量的
ERC20 token兑换为ETH。

在终端进入项目demo目录,执行如下命令:

~$ cd ~/uniswap.php/demo
~/uniswap.php/demo$ php swap-exact-tokens-for-eth.php

执行结果如下:

在这里插入图片描述

2.13 ERC20/ETH兑换:以输出ETH数量为基准

代码swap-tokens-for-exact-eth.php演示了如何将ERC20
token兑换为指定数量的ETH。

在终端进入项目demo目录,执行如下命令:

~$ cd ~/uniswap.php/demo
~/uniswap.php/demo$ php swap-tokens-for-exact-eth.php

执行结果如下:

在这里插入图片描述

3、使用Uniswap.php开发包

SwapKit 是开发包的入口,使用这个类可以快速实现如下功能:

  • 流动性添加与移除:支持ERC20/ERC20、ERC20/ETH、ETH/ERC20等各种交易对
  • 兑换交易的创建与执行:支持ERC20/ERC20、ERC20/ETH、ETH/ERC20等各种交易对,支持以输入或输出价格为准
  • 用户仓位查询:查询指定账号在指定交易对的持仓情况,例如持仓数量、占比等。

3.1 实例化SwapKit

SwapKit实例化需要传入三个参数:

  • 以太坊节点URL
  • Uniswap路由合约地址
  • 用于执行合约交互的以太坊账号,即一个Credential对象。

例如,下面的代码创建一个接入以太坊主网Uniswap协议的SwapKit实例:

//use Uniswap\SwapKit;
//use Uniswap\Credential;

$kit = new SwapKit(
  'http://localhost:8545',                          //以太坊节点URL
  '0x7a250d5630B4...b4c659F2488D',                  //Uniswap路由合约地址
  Credential::fromKey('0x4f3e...3b1d')              //默认执行账号,指定私钥                                 
);

有关Credential的使用说明,详见本文第3.3部分。

3.2 使用ProtocolMeta(可选)

为了避免混淆各网络的Uniswap路由地址,Uniswap.php 提供了ProtocolMeta类的静态方法getPresetAddress()来获取Uniswap官方在以太坊主网和测试网部署的Uniswap协议合约地址。例如
获取主网的路由合约:

//use Uniswap\SwapKit;
//use Uniswap\ProtocolMeta;

$routerAddr = ProtocolMeta::getPresetAddress(
  SwapKit::MAINNET,                                  //以太坊网络  
  SwapKit::ROUTER                                    //Uniswap合约
);
echo $routerAddr . PHP_EOL                           //0x7a250d5630B4...

ProtocolMeta 目前支持的以太坊网络及标识如下:

网络标识(SwapKit::*) 合约标识(SwapKit::*) 地址 说明
MAINNET FACTORY 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f 以太坊主网工厂合约
ROUTER 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D 以太坊主网路由合约
WETH 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 以太坊主网WETH9合约
ROPSTEN FACTORY 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f Ropsten测试网工厂合约
ROUTER 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D Ropsten测试网路由合约
WETH 0xc778417E063141139Fce010982780140Aa0cD5Ab Ropsten测试网WETH9合约
RINKEBY FACTORY 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f Rinkeby测试网工厂合约
ROUTER 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D Rinkeby测试网路由合约
WETH 0xc778417E063141139Fce010982780140Aa0cD5Ab Rinkeby测试网WETH9合约
GORLI FACTORY 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f Gorli测试网工厂合约
ROUTER 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D Gorli测试网路由合约
WETH 0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6 Gorli测试网WETH9合约
KOVAN FACTORY 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f Kovan测试网工厂合约
ROUTER 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D Kovan测试网路由合约
WETH 0xd0A1E359811322d97991E03f863a0C30C2cF029C Kovan测试网WETH9合约

3.3 Credential:以太坊身份与地址表示

在Uniswap.php开发包中,使用 Credential 表征以太坊区块链中的一个用户身份,与以太坊地址相比,Credential对象中包含了用户的私钥信息,可以用来签名交易,因此需要保护其不会泄露。

使用Credential类的静态方法new()创建新账户。例如,下面的代码创建一个新的账户并显示其私钥、公钥和地址:

//use Uniswap\Credential;

$alice = Credential::new();                                  //创建新账号
echo 'private key => ' . $alice->getPrivateKey() . PHP_EOL;  //显示私钥
echo 'public key => ' . $alice->getPublicKey() . PHP_EOL;    //显示公钥
echo 'address => ' . $alice->getAddress() . PHP_EOL;         //显示地址

可以使用静态方法fromKey()导入已有的私钥来实例化Credential。例如下面的代码导入已有私钥并显示地址:

//use Uniswap\Credential;

$alice = Credential::fromKey('0x7889...023a');              //导入已有私钥
echo 'address => ' . $alice->getAddress() . PHP_EOL;        //显示相应地址

3.4 生成流动性添加/移除委托单

由于Uniswap协议中涉及到交易滑点处理以及价格预计算,因此Uniswap.php提供了一个专门的类 OrderBuilder 用于生成流动性添加/移除委托单。OrderBuilder的实现内置了自动价格计算与
滑点计算,因此调用者只需要指定基本的数据即可生成可提交给Uniswap合约的流动性添加/移除委托单。

使用SwapKit对象的getOrderBuilder()方法获取预创建的OrderBuilder对象,并调用OrderBuilder的build()方法生成委托单。例如:

$order = $kit->getOrderBuilder()           //返回OrderBuilder对象 
             ->....                        //参数设置
             ->build();                    //生成并返回委托单

OrderBuilder对象提供了以下方法用于调整生成器的行为:

  • orderType($type) :设置委托单类型,目前支持两种:
    • Order::LIQUIDITY_ADD - 流动性添加委托单
    • Order::LIQUIDITY_REMOVE - 流动性移除委托单
  • tokenA($addr) / tokenB($addr) :交易对的两个Token地址
    表示交易对之一为以太币
  • amountA($bn) / amountB($bn) :两个token的添加数量,仅在添加流动时需要设置
  • liquidity($bn) :LP token数量,仅在移除流动性时需要设置
  • slippage($bn) :交易滑点设置,默认值为5, 表示0.5%的滑点容忍区间
  • to($addr) :委托单执行结果接收地址

例如,下面的代码生成一个流动性添加委托单:

use Uniswap\Order;

$order = $kit->getOrderBuilder()                         //获取委托单生成器对象
             ->orderType(Order::LIQUIDITY_ADD)           //添加流动性
             ->tokenA('0x...')                           //交易对TokenA
             ->tokenB('0x...')                           //交易对TokenB
             ->amountA(bn('100000000000000000000'))      //以TokenA数量为基准按市价自动计算TokenB数量
             ->slippage(bn('10'))                        //滑点容忍范围1%
             ->to($kit->getCredential())                 //设置LP Token的接收地址
             ->build();                                  //生成委托单 
             
echo 'amountA => ' . $order->amountA . PHP_EOL;          //TokenA设置数量  
echo 'amountB => ' . $order->amountB . PHP_EOL;          //TokenB计算数量 
echo 'amountAMin => ' . $order->amountAMin . PHP_EOL;    //滑点处理后的TokenA最小可接受数量 
echo 'amountBMin => ' . $order->amountAMin . PHP_EOL;    //滑点处理后的TokenB最小可接受数量

注意:

  • 使用特殊的 SwapKit::ETH_TOKEN 表示交易对中的ETH,值为:0x00000000000000000000000000000000000eeeee
  • bn($numstr) 是Uniswap提供的一个创建 BigInteger 对象 的快捷函数,其参数为10进制字符串。
  • token数量均按最小单位指定

类似的,下面的代码生成一个流动性移除委托单:

$order = $kit->getOrderBuilder()                         //获取委托单生成器对象
             ->orderType(Order::LIQUIDITY_REMOVE)        //移除流动性  
             ->tokenA('0x...')                           //交易对TokenA地址 
             ->tokenB('0x...')                           //交易对TokenB地址 
             ->liquidity(bn('10000000000000000000'))     //要移除的流动性数量
             ->slippage(bn('10'))                        //滑点容忍范围1%
             ->to($kit->getCredential())                 //token接收地址
             ->build();                                  //生成委托单 

echo 'amountAMin => ' . $order->amountAMin . PHP_EOL;    //滑点处理后最少应收到的TokenA数量 
echo 'amountBMin => ' . $order->amountAMin . PHP_EOL;    //滑点处理后最少应收到的TokenB数量

Order对象提供的以下值,有助于在执行委托单之前向用户提供更好的反馈信息:

  • amountA/amountB :市价计算的tokenA或tokenB理想值
  • amountAMin/amountAMax :滑点处理后的tokenA最小值/最大值
  • amountBMin/amountBMax :滑点处理后的tokenB最小值/最大值

3.5 执行流动性委托单

使用SwapKit的 executeOrder() 方法即可执行生成的流动性委托单,最终完成流动性添加/移除交易。例如:

$txid = $kit->executeOrder($trade);                      //执行委托单
echo 'txid => ' . $txid . PHP_EOL;                       //显示交易ID 

默认情况下,executeOrder()方法自动估算交易所需的gas限额与gas价格,但可以传入额外的参数手动设置这两个值。

例如,下面的代码以指定的gas参数执行流动性维护单:

$opts = [
  'gasLimit' => bn('4000000'),                          //4 million
  'gasPrice' => bn('200000000000')                      //200 gwei
];
$txid = $kit->executeOrder($order, $opts);              //执行委托单

3.6 查询仓位信息

使用SwapKit的 getLiquidityInfo() 方法可以查询指定账号在指定交易对的仓位信息。例如查询某地址的持仓情况:

$info = $kit->getLiquidityInfo('0x90F8...c9C1');       //查询持仓信息

echo 'total => ' . $info->totalSupply . PHP_EOL;       //LP总量 
echo 'balance => ' . $info->balance . PHP_EOL;         //持仓数量
echo 'share % => ' . $info->share . PHP_EOL;           //持仓比例

3.7 生成兑换交易对象

类似于流动性的添加与移除,在Uniswap中的交易对兑换也存在价格自动计算与滑点处理问题。为此,Uniswap.php开发包提供了一个专门的类 TradeBuilder用来简化这一操作。TradeBuilder内置了价格自动计算与滑点处理,因此调用者只需要设置基本的参数即可。

使用SwapKit对象的getTradeBuilder()方法获取预创建的TradeBuilder对象,例如:

$tb = $kit->getTradeBuilder()              //获取预创建的兑换交易生成器
          ->...                            //参数设置
          ->build();                       //生成兑换交易对象

TradeBuilder提供了以下方法用于调整生成器的行为:

  • tradeType($type) :兑换类型,可选值为:
    • Trade::EXACT_INPUT - 以tokenIn的数量为基准
    • Trade::EXACT_OUTPUT - 以tokenOut的数量为基准
  • tokenIn($addr) - 输入Token的地址
  • tokenOut($addr) - 输出Token的地址
  • amountIn($bn) - 输入数量,仅在兑换类型为EXACT_INPUT时需要设置
  • amountOut($bn) - 输出数量,仅在兑换类型为EXACT_OUTPUT时需要设置
  • slippage($bn) - 交易滑点设置,默认值5, 表示允许0.5%的滑点
  • to($addr) - 输出token接收地址

例如,下面的代码以输入token数量为基准生成一个兑换交易对象:

$trade = $kit->getTradeBuilder()                     //获取兑换交易生成器
             ->tradeType(Trade::EXACT_INPUT)         //以输入token数量为基准
             ->tokenIn('0x...')                      //输入token
             ->tokenOut('0x...')                     //输出token
             ->amountIn(bn('10000000000000000000'))  //输入token的数量
             ->slippage(bn('10'))                    //滑点容忍范围1%
             ->to($kit->getCredential())             //输出token的接收地址
             ->build();                              //生成兑换交易对象
             
echo 'amountIn => ' . $trade->amountIn . PHP_EOL;          //输入token的设置数量
echo 'amountOut => ' . $trade->amountOut . PHP_EOL;        //自动做市算法得到的输出token的数量
echo 'amountOutMin => ' . $trade->amountOutMin . PHP_EOL;  //滑点处理后的应收到的输出token最少数量

3.8 执行兑换交易

使用SwapKit对象的 executeTrade() 方法执行指定的兑换交易对象。例如:

$txid = $kit->executeTrade($trade);                       //执行兑换交易
echo 'txid => ' . $txid . PHP_EOL;                        //显示交易ID

默认情况下,executeTrade()方法自动估算交易所需的gas限额与gas价格,但可以传入额外的参数手动设置这两个值。

例如,下面的代码使用设定的gas参数执行兑换交易:

$opts = [
  'gasLimit' => bn('4000000'),                            //4 million
  'gasPrice' => bn('200000000000')                        //200 gwei
];
$txid = $kit->executeTrade($trade, $opts);                //执行交易

Uniswap.php官方下载地址:http://sc.hubwiz.com/codebag/uniswap-php/

猜你喜欢

转载自blog.csdn.net/shebao3333/article/details/109345542