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,代码也是一样的只是变量交换了位置。

授权

授权币种

141@ethereum.ts
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;
      }

......
175@ethereums.ts
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,
      });

获取钱包授权的数量

//88@ethereums.ts
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 价格

//166@uniswap.js
//还有一个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

// 254@uniswap.js
//还有一个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<any> {
        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<any>): Promise<any> {
    

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

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

        let stopped: Array<Event> = [ ];

        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 钱包余额

//34@ethereum.ts

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<string, string> = {};
    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`);
        }
      })
    );

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1. 以太坊堆栈介绍 Like any software stack, the complete "Ethereu...
    龙小治阅读 1,363评论 0 1
  • 前一段时间,朋友圈刮起了一阵妖风。这股妖风很怪,时而让人欢喜,时而让人悲伤。 这到底是为什么呢?原来是有人在Uni...
    百家社话阅读 658评论 0 0
  • 我是黑夜里大雨纷飞的人啊 1 “又到一年六月,有人笑有人哭,有人欢乐有人忧愁,有人惊喜有人失落,有的觉得收获满满有...
    陌忘宇阅读 8,605评论 28 53
  • 人工智能是什么?什么是人工智能?人工智能是未来发展的必然趋势吗?以后人工智能技术真的能达到电影里机器人的智能水平吗...
    ZLLZ阅读 3,893评论 0 5
  • 首先介绍下自己的背景: 我11年左右入市到现在,也差不多有4年时间,看过一些关于股票投资的书籍,对于巴菲特等股神的...
    瞎投资阅读 5,785评论 3 8