Hummingbot 和 Gateway-api 交互

Gateway 和 Uniswap

gateway通過用ethers(https://github.com/ethers-io/ethers.js)與ETH網絡交互
使用@uniswap/sdk(https://github.com/Uniswap/uniswap-v2-sdk)來實現(xiàn)與uninswap的交互

EthereumService 組件(ethereumService)

ethereum.ts 封裝了調用 ether 庫針對 eth 網絡的操作


getETHBalance從錢包中檢查 ETH 余額
getERC20Balance從合約中檢查 ERC20 的余額
getERC20Allowance檢查 spender 允許從錢包轉移的數(shù)目
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: 定時執(zhí)行更新維護幣對列表,主要只維護幣對蛾找,擴展信息交由獲取價格時候調用 extend_update_pairs實現(xiàn)娩脾。
priceSwapIn:獲取換入幣種的價格,賣出幣種時候使用腋粥。
priceSwapOut:獲取換出幣種的價格晦雨,買入幣種的時候使用架曹。
兩個函數(shù)結構相似隘冲,區(qū)分的是 base 和 quote 幣種要互換位置。買入quote數(shù)目->預計付出base數(shù)目->成交->實際付出和預計數(shù)量不一定一樣绑雄,賣出quote數(shù)目->預計獲得base數(shù)目->成交->實際獲得和預計數(shù)量不一定一樣
swapExactIn:在這個函數(shù)里面會實際調用 eth 合約實現(xiàn)交易展辞,如果要賣出幣種調用的是這個函數(shù)
swapExactOut:在這個函數(shù)里面會實際調用 eth 合約實現(xiàn)交易,如果要買入幣種調用的是這個函數(shù)
其實兩個函數(shù)并沒有什么本質區(qū)別站在不同的角度上 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,
      });

獲取錢包授權的數(shù)量

//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;
    }
    // 最大可以換出的數(shù)目
    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`);
        }
      })
    );

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末洽腺,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子覆旱,更是在濱河造成了極大的恐慌蘸朋,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扣唱,死亡現(xiàn)場離奇詭異藕坯,居然都是意外死亡,警方通過查閱死者的電腦和手機噪沙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進店門炼彪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人正歼,你說我怎么就攤上這事辐马。” “怎么了局义?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵喜爷,是天一觀的道長。 經常有香客問我萄唇,道長贞奋,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任穷绵,我火速辦了婚禮轿塔,結果婚禮上,老公的妹妹穿的比我還像新娘仲墨。我一直安慰自己勾缭,他們只是感情好,可當我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布目养。 她就那樣靜靜地躺著俩由,像睡著了一般。 火紅的嫁衣襯著肌膚如雪癌蚁。 梳的紋絲不亂的頭發(fā)上幻梯,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天,我揣著相機與錄音努释,去河邊找鬼碘梢。 笑死,一個胖子當著我的面吹牛伐蒂,可吹牛的內容都是我干的煞躬。 我是一名探鬼主播,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼恩沛!你這毒婦竟也來了在扰?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤雷客,失蹤者是張志新(化名)和其女友劉穎芒珠,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體搅裙,經...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡妓局,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了呈宇。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片好爬。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖甥啄,靈堂內的尸體忽然破棺而出存炮,到底是詐尸還是另有隱情,我是刑警寧澤蜈漓,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布穆桂,位于F島的核電站,受9級特大地震影響融虽,放射性物質發(fā)生泄漏享完。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一有额、第九天 我趴在偏房一處隱蔽的房頂上張望般又。 院中可真熱鬧,春花似錦巍佑、人聲如沸茴迁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽堕义。三九已至,卻和暖如春脆栋,著一層夾襖步出監(jiān)牢的瞬間倦卖,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工椿争, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留怕膛,地道東北人。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓丘薛,卻偏偏與公主長得像嘉竟,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子洋侨,可洞房花燭夜當晚...
    茶點故事閱讀 45,055評論 2 355

推薦閱讀更多精彩內容

  • 1. 以太坊堆棧介紹 Like any software stack, the complete "Ethereu...
    龍小治閱讀 1,257評論 0 1
  • 前一段時間,朋友圈刮起了一陣妖風裁僧。這股妖風很怪个束,時而讓人歡喜,時而讓人悲傷聊疲。 這到底是為什么呢茬底?原來是有人在Uni...
    百家社話閱讀 596評論 0 0
  • 我是黑夜里大雨紛飛的人啊 1 “又到一年六月,有人笑有人哭获洲,有人歡樂有人憂愁阱表,有人驚喜有人失落,有的覺得收獲滿滿有...
    陌忘宇閱讀 8,536評論 28 53
  • 人工智能是什么贡珊?什么是人工智能最爬?人工智能是未來發(fā)展的必然趨勢嗎?以后人工智能技術真的能達到電影里機器人的智能水平嗎...
    ZLLZ閱讀 3,781評論 0 5
  • 首先介紹下自己的背景: 我11年左右入市到現(xiàn)在,也差不多有4年時間寒随,看過一些關于股票投資的書籍糠悯,對于巴菲特等股神的...
    瞎投資閱讀 5,731評論 3 8