import Web3 from 'web3'; import BigNumber from 'bignumber.js'; import { formatFixed, parseFixed } from '@ethersproject/bignumber'; import { getBody, getFullUrl, formatPairAddress } from './utils' import { DODO_SDK_DATA } from './data/constants'; import { TOKENLIST, KOVANLIST, BSCLIST } from './data/tokenList'; import { DODORoute } from './dodoRoute'; import { MixRoute } from './mixRoute'; import * as ERC20_ABI from './abi/erc20.json'; import * as DODO_PROXY_ABI from './abi/dodoProxy.json'; import * as DODO_PROXY_OLD_1 from './abi/dodoProxy_old_1.json'; import * as WETH_ABI from './abi/weth.json'; export class Route { public ZERO_ADDRESS: string = '0x0000000000000000000000000000000000000000' public ETH_ADDRESS: string = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE' public PRICE_IMPACT_HACK_SYMBOL = ['WBTC', 'YFI', 'RENBTC']; public WETH_TOKEN: { symbol: string; address: string; decimals: number, name: string, source: string } public ZEROX_SWAP_URL: string = DODO_SDK_DATA.ZEROX_SWAP_URL public ZEROX_TARGET_APPROVE: string = DODO_SDK_DATA.ZEROX_TARGET_APPROVE public ZEROX_QUOTE_URL: string = DODO_SDK_DATA.ZEROX_QUOTE_URL public ONEINCH_SWAP_URL: string = DODO_SDK_DATA.ONEINCH_SWAP_URL public ONEINCH_TARGET_APPROVE: string = DODO_SDK_DATA.ONEINCH_TARGET_APPROVE public ONEINCH_QUOTE_URL_V2: string = DODO_SDK_DATA.ONEINCH_QUOTE_URL_V2 public ONEINCH_TARGET_APPROVE_V2: string = DODO_SDK_DATA.ONEINCH_TARGET_APPROVE_V2 public ONEINCH_SWAP_URL_V2: string = DODO_SDK_DATA.ONEINCH_SWAP_URL_V2 public NETWORK_ID: number public WEB3_URL: string public DODO_PROXY: string public DODO_APPROVE: string public DODO_SWAP_CALC_HELPER: string public DODO_PROXY_HISTORY: { version: number, address: string }[] private DEFAULT_ROUTE_DETAIL: { resAmount: number, resPricePerToToken: number, resPricePerFromToken: number, priceImpact: number, useSource: string, targetDecimals: number, targetApproveAddr: string, to?: string, data?: string, resCostGas?: number } = { resAmount: 0, resPricePerToToken: 0, resPricePerFromToken: 0, priceImpact: 0, useSource: "", targetDecimals: 0, targetApproveAddr: "", to: "", data: "", resCostGas: 0 } public DIRECTLY_DODO: {} = {} public constructor( _NETWORK_ID: number, _WEB3_URL?: string, _DODO_PROXY?: string, _DODO_APPROVE?: string ) { this.NETWORK_ID = _NETWORK_ID switch (_NETWORK_ID) { case 1: this.WEB3_URL = _WEB3_URL || DODO_SDK_DATA.WEB3_URL this.DODO_SWAP_CALC_HELPER = DODO_SDK_DATA.DODO_SWAP_CALC_HELPER this.DODO_APPROVE = _DODO_APPROVE || DODO_SDK_DATA.DODO_APPROVE this.DODO_PROXY = _DODO_PROXY || DODO_SDK_DATA.DODO_PROXY this.DODO_PROXY_HISTORY = DODO_SDK_DATA.DODO_PORXY_HISTORY this.WETH_TOKEN = DODO_SDK_DATA.WETH this.DIRECTLY_DODO = DODO_SDK_DATA.DIRECTLY_DODO break; case 42: this.WEB3_URL = _WEB3_URL || DODO_SDK_DATA.WEB3_URL_KOVAN this.DODO_SWAP_CALC_HELPER = DODO_SDK_DATA.DODO_SWAP_CALC_HELPER_KOVAN this.DODO_APPROVE = _DODO_APPROVE || DODO_SDK_DATA.DODO_APPROVE_KOVAN this.DODO_PROXY = _DODO_PROXY || DODO_SDK_DATA.DODO_PROXY_KOVAN this.DODO_PROXY_HISTORY = DODO_SDK_DATA.DODO_PORXY_HISTORY_KOVAN this.WETH_TOKEN = DODO_SDK_DATA.WETH_KOVAN break; case 56: this.WEB3_URL = _WEB3_URL || DODO_SDK_DATA.WEB3_URL_BSC this.DODO_SWAP_CALC_HELPER = DODO_SDK_DATA.DODO_SWAP_CALC_HELPER_BSC this.DODO_APPROVE = _DODO_APPROVE || DODO_SDK_DATA.DODO_APPROVE_BSC this.DODO_PROXY = _DODO_PROXY || DODO_SDK_DATA.DODO_PROXY_BSC this.DODO_PROXY_HISTORY = DODO_SDK_DATA.DODO_PORXY_HISTORY_BSC this.WETH_TOKEN = DODO_SDK_DATA.WETH_BSC break; } } /** * @notice 根据地址获取Token * @param tokenAddr token地址 */ public async GetTokenByAddr( tokenSearch: string, web3Provider: any = null ) { const web3 = new Web3(web3Provider || new Web3.providers.HttpProvider(this.WEB3_URL)); try { const erc20Token = new web3.eth.Contract(ERC20_ABI['default'], tokenSearch); let symbolFunc = erc20Token.methods.symbol().call(); let nameFunc = erc20Token.methods.name().call(); let decimalsFunc = erc20Token.methods.decimals().call(); let tokenDetail = await Promise.all([symbolFunc, nameFunc, decimalsFunc]); let obj = { symbol: tokenDetail[0], address: tokenSearch, name: tokenDetail[1], decimals: parseInt(tokenDetail[2]), source: 'other' } return obj; } catch (error) { return null; } } /** * @notice 获取默认tokenList */ public async GetTokenList() { if (this.NETWORK_ID == 1) { let list: any = await getBody("https://config.dodoex.io/tokens/mainnet.json", "{}") let resList = JSON.parse(list) if (list == "{}" || resList['ETH'] == undefined) { return TOKENLIST } else { return resList; } } else if (this.NETWORK_ID == 42) { let list: any = await getBody("https://config.dodoex.io/tokens/kovan.json", "{}") let resList = JSON.parse(list) if (list == "{}" || resList['ETH'] == undefined) { return KOVANLIST } else { return resList; } } else { let list: any = await getBody("https://config.dodoex.io/tokens/bsc.json", "{}") let resList = JSON.parse(list) if (list == "{}" || resList['BNB'] == undefined) { return BSCLIST } else { return resList; } } } /** * @notice 获取订单历史 * @param userAddr 默认空 * @param fromTokenAddress 默认空 * @param toTokenAddress 默认空 * @param fromBlock 默认6000 * 30 */ public async GetUserOrderHistory( userAddr: string = "", fromTokenAddress: string = "", toTokenAddress: string = "", gapBlock: number = 30 * 6000, web3Provider: any = null ) { // const web3 = new Web3(web3Provider || new Web3.providers.HttpProvider(this.WEB3_URL)); const web3 = new Web3(web3Provider || new Web3.providers.HttpProvider("https://mainnet.infura.io/v3/22d4a3b2df0e47b78d458f43fe50a199")); let blockNum = await web3.eth.getBlockNumber(); let block = await web3.eth.getBlock(blockNum); let timeStamp: number = +block.timestamp; let res: { fromToken: string, toToken: string, sender: string, fromAmount: string, returnAmount: string }[] = [] for (let i = 0; i < this.DODO_PROXY_HISTORY.length; i++) { let abi: any; switch (this.DODO_PROXY_HISTORY[i].version) { case 0: abi = DODO_PROXY_ABI['default'] break; case 1: abi = DODO_PROXY_OLD_1['default'] break; } const proxyInstance = new web3.eth.Contract(abi, this.DODO_PROXY_HISTORY[i].address); let filter = { sender: userAddr !== "" ? [userAddr] : [], fromToken: fromTokenAddress !== "" ? [fromTokenAddress] : [], toToken: toTokenAddress !== "" ? [toTokenAddress] : [] } let events = await proxyInstance.getPastEvents('OrderHistory', { filter: filter, fromBlock: blockNum - gapBlock, toBlock: 'latest' }) for (var j = 0; j < events.length; j++) { let curBlockNumber = events[j].blockNumber; let cur = { fromToken: events[j].returnValues['fromToken'], toToken: events[j].returnValues['toToken'], sender: events[j].returnValues['sender'], fromAmount: events[j].returnValues['fromAmount'], returnAmount: events[j].returnValues['returnAmount'], timeStamp: (timeStamp - (blockNum - curBlockNumber) * 13) + "", txHash: events[j].transactionHash } res.push(cur) } } return res } /** * @notice 查询dodoAndUni路由,仅支持主网 */ public async GetAndMakeDODOAndUniRoute( fromToken: { decimals: number; symbol: string; address: string; source: string; name?: string; }, toToken: { symbol: string; address: string; name: string; decimals: number; source: string }, fromAmount: string, slippage: number = 0, assetTo: string, deadline: number = 0, marginAmount: string = '0', web3Provider: any = null ) { let routeDetail = Object.assign({}, this.DEFAULT_ROUTE_DETAIL); routeDetail.to = this.DODO_PROXY routeDetail.useSource = "dodoAndUni"; routeDetail.targetDecimals = toToken.decimals; if (this.DIRECTLY_DODO[formatPairAddress(fromToken.address, toToken.address)]) return routeDetail; //hacked protection if (toToken.address == this.ETH_ADDRESS) return routeDetail; if (this.NETWORK_ID != 1) return routeDetail; try { if (this.WethAndETHWrapJudge(fromToken, toToken, fromAmount, routeDetail)) { return routeDetail } const mixRoute = new MixRoute(this.NETWORK_ID, this.WEB3_URL) let timeoutId; const delay = new Promise(function (resolve, reject) { timeoutId = setTimeout(function () { reject(console.log("backUp route calc timeout")); }, 3000); }); return Promise.race([delay, mixRoute.GetAndMakeDODOAndUniRoute(fromToken, toToken, fromAmount, assetTo, deadline, slippage, routeDetail)]) .then(() => { clearTimeout(timeoutId); return routeDetail; }); } catch (error) { console.log("Mixroute calc error"); routeDetail.resAmount = 0 return routeDetail } } /** * @notice 查询dodo路由 * @param fromToken {"symbol","name","decimals","address"} * @param toToken {"symbol","name","decimals","address"} * @param swapAmount (不考虑decimals) */ public async GetDODORoute( fromToken: { decimals: number; symbol: string; address: string; source: string; name?: string; }, toToken: { symbol: string; address: string; name: string; decimals: number; source: string }, fromAmount: string, marginAmount: string = '0' ) { let routeDetail = Object.assign({}, this.DEFAULT_ROUTE_DETAIL); routeDetail.useSource = "dodo"; routeDetail.targetDecimals = toToken.decimals; try { if (this.WethAndETHWrapJudge(fromToken, toToken, fromAmount, routeDetail)) { return routeDetail } const dodoRoute = new DODORoute(this.NETWORK_ID, this.WEB3_URL) routeDetail = await dodoRoute.GetDODORoute(fromToken, toToken, fromAmount, routeDetail) return routeDetail } catch (error) { console.log("dodoRoute calc error"); routeDetail.resAmount = 0 return routeDetail } } /** * @notice 查询0x路由,仅支持主网 * @param fromToken {"symbol","name","decimals","address"} * @param toToken {"symbol","name","decimals","address"} * @param swapAmount (不考虑decimals) */ public async GetZeroXRoute( fromToken: { decimals: number; symbol: string; address: string; source: string; name?: string; }, toToken: { symbol: string; address: string; name: string; decimals: number; source: string }, fromAmount: string, marginAmount: string = '0' ) { let routeDetail = Object.assign({}, this.DEFAULT_ROUTE_DETAIL); routeDetail.useSource = "0x"; routeDetail.targetDecimals = toToken.decimals; if (this.DIRECTLY_DODO[formatPairAddress(fromToken.address, toToken.address)]) return routeDetail; if (this.NETWORK_ID != 1) return routeDetail; if (fromToken.address != this.ETH_ADDRESS) { routeDetail.targetApproveAddr = this.DODO_APPROVE; } try { if (this.WethAndETHWrapJudge(fromToken, toToken, fromAmount, routeDetail)) { return routeDetail } let zeroXOptions = { sellToken: fromToken.address, buyToken: toToken.address, sellAmount: fromAmount } console.log("0x Quote Url", getFullUrl(this.ZEROX_QUOTE_URL, zeroXOptions)); let zeroXBodyFunc: any = getBody(getFullUrl(this.ZEROX_QUOTE_URL, zeroXOptions), `{"message":"Error"}`); if (marginAmount != '0') { zeroXOptions.sellAmount = marginAmount; } else if (this.PRICE_IMPACT_HACK_SYMBOL.includes(fromToken.symbol)) { zeroXOptions.sellAmount = parseFixed("1", fromToken.decimals - 3).toString(); } else { zeroXOptions.sellAmount = parseFixed("1", fromToken.decimals - 2).toString(); } let zeroXBody2Func: any = getBody(getFullUrl(this.ZEROX_QUOTE_URL, zeroXOptions), `{"message":"Error"}`); let bodys: any[] = await Promise.all([zeroXBodyFunc, zeroXBody2Func]); let zeroXRes = JSON.parse(bodys[0]); let zeroResAmount = zeroXRes.buyAmount || '0'; let res0xAmount = formatFixed(zeroResAmount, toToken.decimals) let _priceImpact: number = 0; if (res0xAmount !== '0.0') { routeDetail.resAmount = parseFloat(res0xAmount) routeDetail.resPricePerFromToken = parseFloat(zeroXRes.price); routeDetail.resPricePerToToken = 1 / routeDetail.resPricePerFromToken; let zeroXRes2 = JSON.parse(bodys[1]); let zeroOriginResAmount = zeroXRes2.buyAmount || '0'; if (zeroOriginResAmount !== '0') _priceImpact = 1 - new BigNumber(zeroResAmount).div(new BigNumber(zeroOriginResAmount).multipliedBy(new BigNumber(fromAmount).div(zeroXOptions.sellAmount))).toNumber() else { routeDetail.resAmount = 0 return routeDetail } } else { routeDetail.resAmount = 0 return routeDetail } routeDetail.priceImpact = _priceImpact < 0 ? 0 : _priceImpact return routeDetail } catch (error) { console.log("0xRoute calc error"); routeDetail.resAmount = 0 return routeDetail } } /** * @notice 查询1inch路由,仅支持主网 * @param fromToken {"symbol","name","decimals","address"} * @param toToken {"symbol","name","decimals","address"} * @param swapAmount (不考虑decimals) */ public async GetOneInchRoute( fromToken: { decimals: number; symbol: string; address: string; source: string; name?: string; }, toToken: { symbol: string; address: string; name: string; decimals: number; source: string }, fromAmount: string, marginAmount: string = '0' ) { let routeDetail = Object.assign({}, this.DEFAULT_ROUTE_DETAIL); routeDetail.useSource = "1inch"; routeDetail.targetDecimals = toToken.decimals; if (this.DIRECTLY_DODO[formatPairAddress(fromToken.address, toToken.address)]) return routeDetail; if (this.NETWORK_ID != 1) return routeDetail; if (fromToken.address != this.ETH_ADDRESS) { routeDetail.targetApproveAddr = this.DODO_APPROVE; } try { if (this.WethAndETHWrapJudge(fromToken, toToken, fromAmount, routeDetail)) { return routeDetail } let oneInchOptions = { fromTokenAddress: fromToken.address, toTokenAddress: toToken.address, amount: fromAmount } console.log("1inch Quote Url", getFullUrl(this.ONEINCH_QUOTE_URL_V2, oneInchOptions)); let oneInchBodyFunc: any = getBody(getFullUrl(this.ONEINCH_QUOTE_URL_V2, oneInchOptions), `{"message":"Error"}`); if (marginAmount != '0') { oneInchOptions.amount = marginAmount; } else if (this.PRICE_IMPACT_HACK_SYMBOL.includes(fromToken.symbol)) { oneInchOptions.amount = parseFixed("1", fromToken.decimals - 3).toString(); } else { oneInchOptions.amount = parseFixed("1", fromToken.decimals - 2).toString(); } let oneInchBody2Func: any = getBody(getFullUrl(this.ONEINCH_QUOTE_URL_V2, oneInchOptions), `{"message":"Error"}`) let bodys: any[] = await Promise.all([oneInchBodyFunc, oneInchBody2Func]); let oneInchRes = JSON.parse(bodys[0]); let oneInchResAmount = oneInchRes.toTokenAmount || '0'; let res1inchAmount = formatFixed(oneInchResAmount, toToken.decimals) let _priceImpact: number = 0; if (res1inchAmount !== '0.0') { routeDetail.resAmount = parseFloat(res1inchAmount) routeDetail.resPricePerToToken = (parseInt(oneInchRes.fromTokenAmount) / 10 ** fromToken.decimals) / (parseInt(oneInchResAmount) / 10 ** toToken.decimals); routeDetail.resPricePerFromToken = 1 / routeDetail.resPricePerToToken; let oneInchRes2 = JSON.parse(bodys[1]); let oneInchOriginResAmount = oneInchRes2.toTokenAmount || '0'; if (oneInchOriginResAmount !== '0') _priceImpact = 1 - new BigNumber(oneInchResAmount).div(new BigNumber(oneInchOriginResAmount).multipliedBy(new BigNumber(fromAmount).div(oneInchOptions.amount))).toNumber() else { routeDetail.resAmount = 0 return routeDetail } } else { routeDetail.resAmount = 0 return routeDetail } routeDetail.priceImpact = _priceImpact < 0 ? 0 : _priceImpact return routeDetail } catch (error) { console.log("1inchRoute calc error"); routeDetail.resAmount = 0 return routeDetail } } /** * @notice 构造路由请求至合约 * @param fromToken {"symbol","name","decimals","address"} * @param toToken {"symbol","name","decimals","address"} * @param swapAmount (不考虑decimals) * @param slippage % * @param addr 账户地址 * @param deadline 截止时间戳 单位 秒 */ public async MakeRoute( fromToken: { decimals: number; symbol: string; address: string; source: string; name?: string; }, toToken: { symbol: string; address: string; name: string; decimals: number; source: string }, swapAmount: string, minAmount: string, slippage: number, addr: string, deadline: number, source: string, web3Provider: any = null ) { const web3 = new Web3(web3Provider || new Web3.providers.HttpProvider(this.WEB3_URL)); let to: string = this.DODO_PROXY; let data: string = ""; let resCostGas: number = 0; try { let dodoSwapInstance = new web3.eth.Contract(DODO_PROXY_ABI['default'], this.DODO_PROXY) if (fromToken.address == this.ETH_ADDRESS && toToken.address == this.WETH_TOKEN.address) { to = this.WETH_TOKEN.address; data = await this.wrapAndUnWrapETH(true); } else if (fromToken.address == this.WETH_TOKEN.address && toToken.address == this.ETH_ADDRESS) { to = this.WETH_TOKEN.address; data = await this.wrapAndUnWrapETH(false, swapAmount); } else if (source == 'dodo') { const dodoRoute = new DODORoute(this.NETWORK_ID, this.WEB3_URL) const [_data, _resCostGas] = await dodoRoute.MakeDODORoute(fromToken, toToken, swapAmount, minAmount, slippage / 100, deadline); data = _data resCostGas = _resCostGas } else if (source == 'dodoAndUni') { var uniDodoDetail = await this.GetAndMakeDODOAndUniRoute(fromToken, toToken, swapAmount, slippage, addr, deadline); var resAmount = uniDodoDetail.resAmount; if (new BigNumber(resAmount).multipliedBy(1 - slippage / 100).gte(new BigNumber(minAmount))) data = uniDodoDetail.data; } else if (source == '1inch') { //1inch let oneInchOptions = { fromTokenAddress: fromToken.address, toTokenAddress: toToken.address, amount: swapAmount, fromAddress: this.DODO_PROXY, slippage: slippage, //0-50 disableEstimate: true } console.log("1inch Swap Url", getFullUrl(this.ONEINCH_SWAP_URL_V2, oneInchOptions)); let oneInchBody: any = await getBody(getFullUrl(this.ONEINCH_SWAP_URL_V2, oneInchOptions), `{"message":"Error"}`); let oneInchRes = JSON.parse(oneInchBody); let oneInchResAmount = oneInchRes.toTokenAmount || '0'; if (oneInchResAmount !== '0') { let resData = oneInchRes.tx.data if (new BigNumber(oneInchResAmount).gte(new BigNumber(minAmount))) { data = await dodoSwapInstance.methods.externalSwap( fromToken.address, toToken.address, this.ONEINCH_TARGET_APPROVE_V2, oneInchRes.tx.to, new BigNumber(oneInchRes.fromTokenAmount).toFixed(0, BigNumber.ROUND_DOWN), minAmount, resData, deadline ).encodeABI() } } } else if (source == '0x') { //0x let zeroXOptions = { sellToken: fromToken.address, buyToken: toToken.address, sellAmount: swapAmount, slippagePercentage: slippage / 100, affiliateAddress: DODO_SDK_DATA.ZEROX_AFFILIATE_ADDR } let zeroXBody: any = await getBody(getFullUrl(this.ZEROX_SWAP_URL, zeroXOptions), `{"message":"Error"}`); console.log("0x Swap Url", getFullUrl(this.ZEROX_SWAP_URL, zeroXOptions)); let zeroXRes = JSON.parse(zeroXBody); let zeroResAmount = zeroXRes.buyAmount || '0'; if (zeroResAmount !== '0') { if (new BigNumber(zeroResAmount).gte(new BigNumber(minAmount))) data = dodoSwapInstance.methods.externalSwap( fromToken.address, toToken.address, zeroXRes.allowanceTarget, zeroXRes.to, new BigNumber(zeroXRes.sellAmount).toFixed(0, BigNumber.ROUND_DOWN), minAmount, zeroXRes.data, deadline ).encodeABI(); } } let routeDetail = { to, data, resCostGas } return routeDetail; } catch (error) { let routeDetail = { to: "", data: "", resCostGas: 0 } return routeDetail; } } private async wrapAndUnWrapETH( isDeposit: Boolean, amount: string = "", web3Provider: any = null ): Promise { const web3 = new Web3(web3Provider || new Web3.providers.HttpProvider(this.WEB3_URL)) let wethInstance = new web3.eth.Contract(WETH_ABI['default'], this.WETH_TOKEN.address) let dataAbi: string = "" if (isDeposit) { dataAbi = await wethInstance.methods.deposit().encodeABI() } else { dataAbi = await wethInstance.methods.withdraw(amount).encodeABI() } return dataAbi } private WethAndETHWrapJudge( fromToken: { decimals: number; symbol: string; address: string; source: string; name?: string; }, toToken: { symbol: string; address: string; name: string; decimals: number; source: string }, swapAmount: string, routeDetail: { resAmount: number, resPricePerToToken: number, resPricePerFromToken: number, priceImpact: number, useSource: string, targetDecimals: number, targetApproveAddr: string } ): boolean { if ((fromToken.address == this.ETH_ADDRESS && toToken.address == this.WETH_TOKEN.address) || (fromToken.address == this.WETH_TOKEN.address && toToken.address == this.ETH_ADDRESS)) { routeDetail.resAmount = parseFloat(formatFixed(swapAmount, fromToken.decimals)) routeDetail.resPricePerToToken = 1 routeDetail.resPricePerFromToken = 1 routeDetail.useSource = 'dodo' return true } else { return false } } /** * @notice 获取Proxy Gas补贴参数 */ public async GasParam( web3Provider: any = null ) { const web3 = new Web3(web3Provider || new Web3.providers.HttpProvider(this.WEB3_URL)); let dodoSwapInstance = new web3.eth.Contract(DODO_PROXY_ABI['default'], this.DODO_PROXY) let dodoGasFunc = dodoSwapInstance.methods._GAS_DODO_MAX_RETURN_().call(); let externalGasFunc = dodoSwapInstance.methods._GAS_EXTERNAL_RETURN_().call(); let params: any[] = await Promise.all([dodoGasFunc, externalGasFunc]); let obj = { "dodoGasMaxReturn": parseInt(params[0]), "externalGasReturn": parseInt(params[1]) } return obj; } /** * @legacy * @notice 判断Swap的token是否需要授权 * @param fromToken {"symbol","name","decimals","address"} * @param addr 用户地址 */ public async ApproveJudge( fromToken: { symbol: string; address: string; }, addr: string, targetAddr: string, web3Provider: any = null ) { const web3 = new Web3(web3Provider || new Web3.providers.HttpProvider(this.WEB3_URL)); if (fromToken.address == this.ETH_ADDRESS) return -1; const erc20Token = new web3.eth.Contract(ERC20_ABI['default'], fromToken.address); let allowanceAmount = await erc20Token.methods.allowance(addr, targetAddr).call(); return allowanceAmount; } /** * @legacy * @notice ERC20 Token 交易前授权 * @param fromToken {"symbol","name","decimals","address"} * @param targetAddr 授权合约地址 * @param approveAmount hex 16进制字符串数值 */ public async ApproveHandle( fromToken: { address: string; }, targetAddr: string, approveAmount: string, web3Provider: any = null ) { const web3 = new Web3(web3Provider || new Web3.providers.HttpProvider(this.WEB3_URL)); const erc20Token = new web3.eth.Contract(ERC20_ABI['default'], fromToken.address); let data = await erc20Token.methods.approve(targetAddr, approveAmount).encodeABI(); return data; } }