import { BigNumber } from "@ethersproject/bignumber" import { Overrides } from "@ethersproject/contracts" import ERC20TokenArtifact from "@sakeperp/artifact/src/ERC20Token.json" import Big from "big.js" import { ethers, Wallet } from "ethers" import { Service } from "typedi" import { ERC20Token } from "../types/ethers/ERC20Token" import { EthService } from "./EthService" import { Log } from "./Log" import { SystemMetadataFactory } from "./SystemMetadataFactory" @Service() export class ERC20Service { private readonly log = Log.getLogger(ERC20Service.name) constructor(readonly ethService: EthService, readonly systemMetadataFactory: SystemMetadataFactory) {} private createErc20Contract(tokenAddr: string, from?: Wallet): ERC20Token { return this.ethService.createContract<ERC20Token>(tokenAddr, ERC20TokenArtifact, from) } async allowance(tokenAddr: string, ownerAddr: string, spenderAddr: string): Promise<Big> { const token = this.createErc20Contract(tokenAddr) const scaledAmount = await token.functions.allowance(ownerAddr, spenderAddr) return this.fromScaled(tokenAddr, scaledAmount[0]) } async approve( tokenAddr: string, spenderAddr: string, amount: Big, from: Wallet, overrides?: Overrides, ): Promise<void> { const token = this.createErc20Contract(tokenAddr, from) const scaledAmount = await this.toScaled(tokenAddr, amount) const tx = await token.functions.approve(spenderAddr, scaledAmount, { ...overrides, }) const receipt = await tx.wait() if (receipt.status !== 1) throw new Error(`transferError:${tx.hash}`) } async balanceOf(tokenAddr: string, accountAddr: string): Promise<Big> { const token = this.createErc20Contract(tokenAddr) const scaledAmount = await token.functions.balanceOf(accountAddr) return this.fromScaled(tokenAddr, scaledAmount[0]) } async transfer(tokenAddr: string, recipientAddr: string, amount: Big, from: Wallet): Promise<void> { const token = this.createErc20Contract(tokenAddr, from) const scaledAmount = await this.toScaled(tokenAddr, amount) const tx = await token.functions.transfer(recipientAddr, scaledAmount) const receipt = await tx.wait() if (receipt.status !== 1) throw new Error(`transferError:${tx.hash}`) } // noinspection JSMethodCanBeStatic async fromScaled(tokenAddr: string, val: BigNumber): Promise<Big> { const token = this.createErc20Contract(tokenAddr) const decimals = await token.functions.decimals() return new Big(ethers.utils.formatUnits(val, decimals[0])) } // noinspection JSMethodCanBeStatic async toScaled(tokenAddr: string, val: Big): Promise<ethers.BigNumber> { const token = this.createErc20Contract(tokenAddr) const decimals = await token.functions.decimals() return ethers.utils.parseUnits(val.toFixed(decimals[0]), decimals[0]) } }