Hummingbot 和 Gateway-api 交互

Gateway 和 Uniswap

gateway通过用ethers(https://github.com/ethers-io/ethers.js)与ETH网络交互
使用@uniswap/sdk(https://github.com/Uniswap/uniswap-v2-sdk)来实现与uninswap的交互

EthereumService 组件(ethereumService)

ethereum.ts 封装了调用 ether 库针对 eth 网络的操作


getETHBalance从钱包中检查 ETH 余额
getERC20Balance从合约中检查 ERC20 的余额
getERC20Allowance检查 spender 允许从钱包转移的数目
approveERC20授权spender从钱包转移ERC20代币
deposit给 ERC20 地址转币,暂时没人用这个 api
getERC20TokenAddress获取 ERC20 代币地址
getERC20TokenByAddress通过地址获取 ERC20 代币
getWallet获取钱包信息
getTransactionReceipt通过 txHash 获得交易信息

Uniswap 组件(uni)

uniswap.js 封装了针对 uniswap 的操作,比如下单,获取交易对等操作


fetch_route: 获取交易路径,主要在获取兑换价格priceSwapIn时候使用,因为有的币可能需要经过>1次兑换才能换到目标币种,这种情况下就需要获取交易路径。
extend_update_pairs: 在获取兑换价格priceSwapIn的时候会使用,用来更新交换币对的扩展的属性。
update_pairs: 定时执行更新维护币对列表,主要只维护币对,扩展信息交由获取价格时候调用 extend_update_pairs实现。
priceSwapIn:获取换入币种的价格,卖出币种时候使用。
priceSwapOut:获取换出币种的价格,买入币种的时候使用。
两个函数结构相似,区分的是 base 和 quote 币种要互换位置。买入quote数目->预计付出base数目->成交->实际付出和预计数量不一定一样,卖出quote数目->预计获得base数目->成交->实际获得和预计数量不一定一样
swapExactIn:在这个函数里面会实际调用 eth 合约实现交易,如果要卖出币种调用的是这个函数
swapExactOut:在这个函数里面会实际调用 eth 合约实现交易,如果要买入币种调用的是这个函数
其实两个函数并没有什么本质区别站在不同的角度上 swapIn 也是一种 swapOut,代码也是一样的只是变量交换了位置。

授权

授权币种

[email protected]
const wallet = ethereumService.getWallet(req.body.privateKey);

    // Getting token info
const tokenContractInfo = ethereumService.getERC20TokenAddress(
  req.body.token
);

const tokenAddress = tokenContractInfo.address;

      const gasPrice = req.body.gasPrice || ethereumGasService.getGasPrice();

      let amount = ethers.constants.MaxUint256;
      if (req.body.amount) {
        amount = ethers.utils.parseUnits(
          req.body.amount,
          tokenContractInfo.decimals
        );
      }
      // call approve function
      let approval;
      try {
        approval = await ethereumService.approveERC20(
          wallet,
          spender,
          tokenAddress,
          amount,
          gasPrice
        );
      } catch (err) {
        approval = err;
      }

......
[email protected]
const contract = new Contract(tokenAddress, abi.ERC20Abi, wallet);
contract.approve(spender, amount, {
        gasPrice: gasPrice * 1e9,
        // fixate gas limit to prevent overwriting
        gasLimit: this.config.approvalGasLimit,
      });

获取钱包授权的数量

//[email protected]
const wallet = ethereumService.getWallet(req.body.privateKey);
approvals[symbol] = await ethereumService.getERC20Allowance(
            wallet,
            spender,
            address,
            decimals
          );

const contract = new Contract(tokenAddress, abi.ERC20Abi, this.provider);
const allowance = await contract.allowance(wallet.address, spender);

获取 swap 价格

//[email protected]
//还有一个priceSwapIn 类似

  async priceSwapOut(tokenIn, tokenOut, tokenOutAmount) {
    await this.extend_update_pairs([tokenIn, tokenOut]);
    const tOut = this.tokenList[tokenOut];
    const tIn = this.tokenList[tokenIn];
    const tokenAmountOut = new uni.TokenAmount(
      tOut,
      ethers.utils.parseUnits(tokenOutAmount, tOut.decimals)
    );
    //先查询本地缓存
    if (this.pairs.length === 0) {
      const route = await this.fetch_route(tIn, tOut);
      const trade = uni.Trade.exactOut(route, tokenAmountOut);
      if (trade !== undefined) {
        const expectedAmount = trade.maximumAmountIn(this.allowedSlippage);
        this.cachedRoutes[tIn.symbol + tOut.Symbol] = trade;
        return { trade, expectedAmount };
      }
      return;
    }
    // 最大可以换出的数目
    let trade = uni.Trade.bestTradeExactOut(
      this.pairs,
      this.tokenList[tokenIn],
      tokenAmountOut,
      { maxHops: 5 }
    )[0];
    if (trade === undefined) {
      trade = this.cachedRoutes[tIn.symbol + tOut.Symbol];
    } else {
      this.cachedRoutes[tIn.symbol + tOut.Symbol] = trade;
    }
    const expectedAmount = trade.maximumAmountIn(this.allowedSlippage);
    return { trade, expectedAmount };
  }


SWAP

// [email protected]
//还有一个swapExactIn 类似
async swapExactOut(wallet, trade, tokenAddress, gasPrice) {
    const result = uni.Router.swapCallParameters(trade, {
      ttl: TTL,
      recipient: wallet.address,
      allowedSlippage: this.allowedSlippage,
    });

    const contract = new ethers.Contract(
      this.router,
      proxyArtifact.abi,
      wallet
    );
    //真正调用合约的地方
    const tx = await contract[result.methodName](...result.args, {
      gasPrice: gasPrice * 1e9,
      gasLimit: GAS_LIMIT,
      value: result.value,
    });

    debug(`Tx Hash: ${tx.hash}`);
    return tx;
}

交易记录

//202@ethereum.
//json-rpc-provider
    async perform(method: string, params: any): Promise {
        const args = this.prepareRequest(method,  params);

        if (args == null) {
            logger.throwError(method + " not implemented", Logger.errors.NOT_IMPLEMENTED, { operation: method });
        }
        try {
            return await this.send(args[0], args[1])
        } catch (error) {
            return checkError(method, error, params);
        }
    }

    ...

    send(method: string, params: Array): Promise {
    

        this.emit("debug", {
            action: "request",
            request: deepCopy(request),
            provider: this
        });
    }

    emit(eventName: EventType, ...args: Array): boolean {
        let result = false;

        let stopped: Array = [ ];

        let eventTag = getEventTag(eventName);
        this._events = this._events.filter((event) => {
            if (event.tag !== eventTag) { return true; }

            setTimeout(() => {
                event.listener.apply(this, args);
            }, 0);

            result = true;

            if (event.once) {
                stopped.push(event);
                return false;
            }

            return true;
        });

        stopped.forEach((event) => { this._stopEvent(event); });

        return result;
    }


eth 钱包余额

//[email protected]

const wallet: ethers.Wallet = ethereumService.getWallet(
      req.body.privateKey || ''
    );

for (const symbol of JSON.parse(req.body.tokenList)) {
      const tokenContractInfo = ethereumService.getERC20TokenAddress(symbol);
      if (!tokenContractInfo) {
        continue;
      }

      tokenContractList[symbol] = tokenContractInfo;
    }

 // Getting user balancers
    const balances: Record = {};
    balances.ETH = await ethereumService.getETHBalance(wallet);
    await Promise.all(
      Object.keys(tokenContractList).map(async (symbol) => {
        if (tokenContractList[symbol] !== undefined) {
          const address = tokenContractList[symbol].address;
          const decimals = tokenContractList[symbol].decimals;
          balances[symbol] = await ethereumService.getERC20Balance(
            wallet,
            address,
            decimals
          );
        } else {
          logger.error(`Token contract info for ${symbol} not found`);
        }
      })
    );

你可能感兴趣的:(Hummingbot 和 Gateway-api 交互)