UNPKG

0xweb

Version:

Contract package manager and other web3 tools

115 lines (92 loc) 4.17 kB
import di from 'a-di'; import { BlockchainExplorerFactory } from '@dequanto/explorer/BlockchainExplorerFactory'; import { EoAccount } from "@dequanto/models/TAccount"; import { Web3ClientFactory } from '@dequanto/clients/Web3ClientFactory'; import { IToken } from '@dequanto/models/IToken'; import { TAddress } from '@dequanto/models/TAddress'; import { TPlatform } from '@dequanto/models/TPlatform'; import { class_Uri } from 'atma-utils'; import { TokensService } from '../TokensService'; import { TxWriter } from '@dequanto/txs/TxWriter'; import { TxDataBuilder } from '@dequanto/txs/TxDataBuilder'; import { Web3Client } from '@dequanto/clients/Web3Client'; import { IBlockchainExplorer } from '@dequanto/explorer/IBlockchainExplorer'; import { ERC20 } from '@dequanto/prebuilt/openzeppelin/ERC20'; import { $http } from '@dequanto/utils/$http'; const PLATFORMS = { eth: 1, bsc: 56, polygon: 137, } export class OneInchExchange { client: Web3Client explorer: IBlockchainExplorer constructor(public platform: TPlatform) { this.client = Web3ClientFactory.get(this.platform); this.explorer = BlockchainExplorerFactory.get(this.platform); } async approve (account: EoAccount, from: string | IToken, fromAmount?: number, spender?: TAddress) { let tokens = di.resolve(TokensService, this.platform, this.explorer); let $from = typeof from === 'string' ? await tokens.getToken(from) : from; let erc20 = new ERC20($from.address, this.client, this.explorer); if (spender != null) { let current = await erc20.allowance(account.address, spender); if (current > 10n**25n) { return; } } let query = [ `infinity=true`, `tokenAddress=${$from.address}`, ]; let callURL = this.getUrl(`/approve/calldata?${query.join('&')}`); let { data: tx } = await $http.get(callURL); let txWriter = await this.sendTx(account, tx); let receipt = await txWriter.onCompleted; return txWriter; } async swap (account: EoAccount, from: string | IToken, to: string | IToken, fromAmount: number) { let tokens = di.resolve(TokensService, this.platform, this.explorer); let $owner = account.address; let $from = typeof from === 'string' ? await tokens.getToken(from) : from; let $to = typeof to === 'string' ? await tokens.getToken(to) : to; let $amount = await this.getAmount($owner, $from, fromAmount); let query = [ `fromTokenAddress=${$from.address}`, `toTokenAddress=${$to.address}`, `amount=${$amount}`, `fromAddress=${$owner}`, `slippage=3` ]; let callURL = this.getUrl(`/swap?${query.join('&')}`); let { data } = await $http.get(callURL); await this.approve(account, from, Infinity, data.tx.to); return this.sendTx(account, data.tx); } private getUrl(path: string) { let chainId = PLATFORMS[this.platform]; return class_Uri.combine(`https://api.1inch.exchange/v3.0/${chainId}/`, path); } private async getAmount (owner: TAddress, token: IToken, amount: number): Promise<bigint> { if (amount === Infinity) { let erc20 = new ERC20(token.address, this.client, this.explorer); let balance = await erc20.balanceOf(owner); return balance; } let decimals = Number(token.decimals); if (isNaN(decimals)) { throw new Error(`Decimals are not defined for ${token.symbol} in ${this.platform}`); } return BigInt(amount) * 10n ** BigInt(decimals); } private async sendTx (account: EoAccount, calldata) { let txData = TxDataBuilder.normalize(calldata); let $txData = txData as any; let gas = $txData.gas; delete $txData.gas; $txData.gas = BigInt(gas) * 2n; let txBuilder = new TxDataBuilder(this.client, account, txData ); await txBuilder.setNonce(); return TxWriter.write(this.client, txBuilder, account); } }