UNPKG

0xweb

Version:

Contract package manager and other web3 tools

143 lines (125 loc) 5.17 kB
import di from 'a-di'; import { EoAccount } from "@dequanto/models/TAccount"; import { Web3Client } from '@dequanto/clients/Web3Client'; import { IToken } from '@dequanto/models/IToken'; import { TAddress } from '@dequanto/models/TAddress'; import { TxWriter } from '@dequanto/txs/TxWriter'; import { $bigint } from '@dequanto/utils/$bigint'; import { TokensServiceFactory } from './TokensServiceFactory'; import { $require } from '@dequanto/utils/$require'; import { TokensService } from './TokensService'; import { WETH } from '@dequanto/prebuilt/weth/WETH/WETH'; import { BlockDateResolver } from '@dequanto/blocks/BlockDateResolver'; export class TokenService { private tokensProvider: TokensService; constructor(public client: Web3Client) { this.tokensProvider = TokensServiceFactory.get(this.client.platform); } async balanceOf(address: TAddress, token: string | IToken, params?: { forBlock?: number | bigint | Date }): Promise<bigint> { token = await this.getToken(token); let forBlock = await this.getBlock(params?.forBlock); let isNative = this.tokensProvider.isNative(token.address); if (isNative) { return this.client.getBalance(address, forBlock); } let erc20 = await this.tokensProvider.erc20(token); if (forBlock != null) { erc20 = erc20.forBlock(forBlock); } let balance = await erc20.balanceOf(address); return balance; } async hasToken(address: TAddress, token: string | IToken, amount: number): Promise<boolean> { let t = await this.getToken(token); let balance = await this.balanceOf(address, t); let wei = $bigint.toWei(amount, t.decimals); return wei <= balance; } async ensureApproved (account: EoAccount, tokenMix: string | IToken, spender: TAddress, amount: bigint | number): Promise<TxWriter | null> { let token = await this.getToken(tokenMix); let erc20 = await this.tokensProvider.erc20(token.address); let approved = await erc20.allowance(account.address, spender); let desiredApproval = typeof amount === 'bigint' ? amount : $bigint.toWei(amount, token.decimals); if (approved < desiredApproval) { return await erc20.approve(account, spender, desiredApproval); } return null; } /** * @param amount Can be negative (wraps all with rest) */ async wrapNativeToERC20 (account: EoAccount, amount: number): Promise<TxWriter> { let amountWei = $bigint.toWei(amount, 18); if (amountWei < 0n) { let balance = await this.client.getBalance(account.address); amountWei = balance + amountWei; } $require.gt(amountWei, 0n); let depositor: { deposit: WETH['deposit'] }; switch (this.client.platform) { case 'xdai': depositor = di.resolve(WETH, '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d'); break; } if (depositor == null) { throw new Error(`Wrapping depositor not found for platform ${this.client?.platform}`); } return await depositor.deposit({ ...account, value: amountWei }); } /** * */ async unwrapNative (account: EoAccount, amount?: number | bigint): Promise<TxWriter> { let depositor: { balanceOf: WETH['balanceOf'], withdraw: WETH['withdraw'] }; switch (this.client.platform) { case 'xdai': depositor = di.resolve(WETH, '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d'); break; } if (depositor == null) { throw new Error(`Wrapping depositor not found for platform ${this.client?.platform}`); } if (amount == null || amount === Infinity) { amount = await depositor.balanceOf(account.address); } let amountWei = typeof amount === 'number' ? $bigint.toWei(amount, 18) : amount; console.log(amount, amountWei); $require.gt(amountWei, 0n); return await depositor.withdraw(account, amountWei); } protected async getToken(mix: string | IToken): Promise<IToken> { let token = typeof mix === 'string' ? await this.tokensProvider.getKnownToken(mix) : mix; if (this.tokensProvider.isNative(token.address)) { token = { ...token, address: '0x0000000000000000000000000000000000000000', } } if (token == null || token.address == null) { throw new Error(`Address undefined: ${token}`); } return token; } protected async getBlock (block: undefined | number | bigint | Date): Promise<number | bigint> { if (block == null) { // default return null; } if (block instanceof Date) { let resolver = di.resolve(BlockDateResolver, this.client); return await resolver.getBlockNumberFor(block); } return block; } }