UNPKG

@tatumio/erc20-connector

Version:

ERC20 Connector for Tatum API

348 lines (329 loc) 16.8 kB
import Web3 from 'web3'; import {PinoLogger} from 'nestjs-pino'; import {Erc20Error} from './Erc20Error'; import { ChainBurnCeloErc20, ChainBurnErc20, ChainBurnKcsErc20, ChainDeployCeloErc20, ChainDeployErc20, ChainDeployKcsErc20, ChainEgldEsdtTransaction, ChainMintCeloErc20, ChainMintErc20, ChainMintKcsErc20, ChainTransferAlgoErc20, ChainTransferBscBep20, ChainTransferCeloErc20Token, ChainTransferErc20, ChainTransferEthErc20, ChainTransferHrm20, ChainTransferKcsErc20, ChainTransferPolygonErc20 } from './Erc20Base'; import {HarmonyAddress} from '@harmony-js/crypto'; import { ApproveErc20, BurnCeloErc20, BurnErc20, Currency, DeployCeloErc20, DeployErc20, EgldEsdtTransaction, egldGetAccountErc20Balance, fromXdcAddress, getAlgoClient, MintCeloErc20, MintErc20, OneBurn20, OneMint20, OneTransfer20, prepareAlgoBurnFTSignedTransaction, prepareAlgoCreateFTSignedTransaction, prepareAlgoTransferFTSignedTransaction, prepareAuctionApproveErc20Transfer, prepareBurnBep20SignedTransaction, prepareCeloBurnErc20SignedTransaction, prepareCeloDeployErc20SignedTransaction, prepareCeloMintErc20SignedTransaction, prepareCeloTransferErc20SignedTransaction, prepareCustomBep20SignedTransaction, prepareCustomErc20SignedTransaction, prepareDeployBep20SignedTransaction, prepareDeployErc20SignedTransaction, prepareEgldBurnEsdtSignedTransaction, prepareEgldDeployEsdtSignedTransaction, prepareEgldFreezeOrWipeOrOwvershipEsdtSignedTransaction, prepareEgldMintEsdtSignedTransaction, prepareEgldTransferEsdtSignedTransaction, prepareEthBurnErc20SignedTransaction, prepareEthMintErc20SignedTransaction, prepareEthOrErc20SignedTransaction, prepareMintBep20SignedTransaction, prepareOneBurn20SignedTransaction, prepareOneDeploy20SignedTransaction, prepareOneMint20SignedTransaction, prepareOneTransfer20SignedTransaction, preparePolygonBurnErc20SignedTransaction, preparePolygonDeployErc20SignedTransaction, preparePolygonMintErc20SignedTransaction, preparePolygonTransferErc20SignedTransaction, prepareXdcBurnErc20SignedTransaction, prepareXdcCustomErc20SignedTransaction, prepareXdcDeployErc20SignedTransaction, prepareXdcMintErc20SignedTransaction, TransactionHash, TransferCeloOrCeloErc20Token, TransferErc20 } from '@tatumio/tatum'; import erc20_abi from '@tatumio/tatum/dist/src/contracts/erc20/token_abi'; import { BurnErc20 as CoreBurnErc20, DeployErc20 as CoreDeployErc20, MintErc20 as CoreMintErc20, TransferErc20 as CoreTransferErc20 } from '@tatumio/tatum-core' import { prepareBurnErc20SignedTransaction as prepareKcsBurnErc20SignedTransaction, prepareDeployErc20SignedTransaction as prepareKcsDeployErc20SignedTransaction, prepareMintErc20SignedTransaction as prepareKcsMintErc20SignedTransaction, prepareTransferErc20SignedTransaction as prepareKcsTransferErc20SignedTransaction } from '@tatumio/tatum-kcs' export abstract class Erc20Service { protected constructor(protected readonly logger: PinoLogger) { } protected abstract storeKMSTransaction(txData: string, currency: string, signatureId: string[], index?: number): Promise<string>; protected abstract isTestnet(): Promise<boolean>; protected abstract getNodesUrl(chain: Currency, testnet: boolean): Promise<string[]>; protected abstract broadcast(chain: Currency, txData: string, signatureId?: string): Promise<TransactionHash>; private async getFirstNodeUrl(chain: Currency, testnet: boolean): Promise<string> { const nodes = await this.getNodesUrl(chain, testnet); if (nodes.length === 0) { new Erc20Error('Nodes url array must have at least one element.', 'erc20.nodes.url'); } return nodes[0]; } private async getClient(chain: Currency, testnet: boolean) { if ([Currency.ETH, Currency.BSC, Currency.CELO, Currency.XDC, Currency.ONE, Currency.MATIC, Currency.KCS].includes(chain)) { return new Web3((await this.getFirstNodeUrl(chain, testnet))); } else if (chain === Currency.ALGO) { return await getAlgoClient(await this.isTestnet(), await this.getFirstNodeUrl(chain, testnet)); } throw new Erc20Error(`Unsupported chain ${chain}.`, 'unsupported.chain'); } public async getErc20Balance(chain: Currency, address: string, contractAddress: string): Promise<{ balance: string }> { let contractOrAddress; switch (chain) { case Currency.ETH: case Currency.BSC: case Currency.CELO: case Currency.MATIC: case Currency.KCS: contractOrAddress = contractAddress; break; case Currency.ONE: contractOrAddress = new HarmonyAddress(contractAddress).basicHex; break; case Currency.EGLD: return { balance: `${await egldGetAccountErc20Balance(address, contractAddress)}` }; case Currency.XDC: contractOrAddress = fromXdcAddress(contractAddress); break; default: throw new Erc20Error(`Unsupported chain ${chain}.`, 'unsupported.chain'); } const _address = chain === Currency.XDC ? fromXdcAddress(address) : address; const client = await this.getClient(chain, await this.isTestnet()); // @ts-ignore const contract = new client.eth.Contract(erc20_abi, contractOrAddress); return {balance: await contract.methods.balanceOf(_address).call()}; } public async transferErc20(body: ChainTransferEthErc20 | ChainTransferBscBep20 | ChainTransferCeloErc20Token | ChainTransferErc20 | ChainTransferHrm20 | ChainTransferPolygonErc20 | ChainEgldEsdtTransaction | ChainTransferAlgoErc20 | ChainTransferKcsErc20): Promise<TransactionHash | { signatureId: string }> { const testnet = await this.isTestnet(); const {chain, ..._body} = body; let txData; switch (chain) { case Currency.ETH: if ((_body as TransferErc20).currency) { txData = await prepareEthOrErc20SignedTransaction(_body as TransferErc20, (await this.getFirstNodeUrl(chain, testnet))); } else { txData = await prepareCustomErc20SignedTransaction(_body as TransferErc20, (await this.getFirstNodeUrl(chain, testnet))); } break; case Currency.ONE: txData = await prepareOneTransfer20SignedTransaction(testnet, _body as OneTransfer20, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.MATIC: txData = await preparePolygonTransferErc20SignedTransaction(testnet, _body as TransferErc20, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.KCS: txData = await prepareKcsTransferErc20SignedTransaction(_body as CoreTransferErc20, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.BSC: txData = await prepareCustomBep20SignedTransaction(_body as TransferErc20, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.CELO: txData = await prepareCeloTransferErc20SignedTransaction(testnet, _body as TransferCeloOrCeloErc20Token, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.EGLD: txData = await prepareEgldTransferEsdtSignedTransaction(_body as EgldEsdtTransaction, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.XDC: txData = await prepareXdcCustomErc20SignedTransaction(_body as TransferErc20, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.ALGO: txData = await prepareAlgoTransferFTSignedTransaction(testnet, _body as TransferErc20, (await this.getFirstNodeUrl(chain, testnet))); break; default: throw new Erc20Error(`Unsupported chain ${chain}.`, 'unsupported.chain'); } if (body.signatureId) { return {signatureId: await this.storeKMSTransaction(txData, chain, [body.signatureId], body.index)}; } else { return this.broadcast(chain, txData); } } public async burnErc20(body: ChainBurnErc20 | ChainBurnCeloErc20 | ChainEgldEsdtTransaction | ChainBurnKcsErc20): Promise<TransactionHash | { signatureId: string }> { const testnet = await this.isTestnet(); const {chain, ..._body} = body; let txData; switch (chain) { case Currency.ETH: txData = await prepareEthBurnErc20SignedTransaction(_body as BurnErc20, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.ONE: txData = await prepareOneBurn20SignedTransaction(testnet, _body as OneBurn20, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.MATIC: txData = await preparePolygonBurnErc20SignedTransaction(testnet, _body as BurnErc20, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.KCS: txData = await prepareKcsBurnErc20SignedTransaction(_body as CoreBurnErc20, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.BSC: txData = await prepareBurnBep20SignedTransaction(_body as BurnErc20, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.CELO: txData = await prepareCeloBurnErc20SignedTransaction(testnet, _body as BurnCeloErc20, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.EGLD: txData = await prepareEgldBurnEsdtSignedTransaction(_body as EgldEsdtTransaction, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.XDC: txData = await prepareXdcBurnErc20SignedTransaction(_body as BurnErc20, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.ALGO: txData = await prepareAlgoBurnFTSignedTransaction(testnet, _body as BurnErc20, (await this.getFirstNodeUrl(chain, testnet))); break; default: throw new Erc20Error(`Unsupported chain ${chain}.`, 'unsupported.chain'); } if (body.signatureId) { return {signatureId: await this.storeKMSTransaction(txData, chain, [body.signatureId], body.index)}; } else { return this.broadcast(chain, txData); } } public async mintErc20(body: ChainMintErc20 | ChainMintCeloErc20 | ChainEgldEsdtTransaction | ChainMintKcsErc20): Promise<TransactionHash | { signatureId: string }> { const testnet = await this.isTestnet(); const {chain, ..._body} = body; let txData; switch (chain) { case Currency.ETH: txData = await prepareEthMintErc20SignedTransaction(_body as MintErc20, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.ONE: txData = await prepareOneMint20SignedTransaction(testnet, _body as OneMint20, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.MATIC: txData = await preparePolygonMintErc20SignedTransaction(testnet, _body as MintErc20, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.KCS: txData = await prepareKcsMintErc20SignedTransaction(_body as CoreMintErc20, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.BSC: txData = await prepareMintBep20SignedTransaction(_body as MintErc20, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.CELO: txData = await prepareCeloMintErc20SignedTransaction(testnet, _body as MintCeloErc20, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.EGLD: txData = await prepareEgldMintEsdtSignedTransaction(_body as EgldEsdtTransaction, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.XDC: txData = await prepareXdcMintErc20SignedTransaction(_body as MintErc20, (await this.getFirstNodeUrl(chain, testnet))); break; default: throw new Erc20Error(`Unsupported chain ${chain}.`, 'unsupported.chain'); } if (body.signatureId) { return {signatureId: await this.storeKMSTransaction(txData, chain, [body.signatureId], body.index)}; } else { return this.broadcast(chain, txData); } } public async deployErc20(body: ChainDeployErc20 | ChainDeployCeloErc20 | ChainEgldEsdtTransaction | ChainDeployKcsErc20): Promise<TransactionHash | { signatureId: string }> { const testnet = await this.isTestnet(); const {chain, ..._body} = body; let txData; switch (chain) { case Currency.ETH: txData = await prepareDeployErc20SignedTransaction(_body as DeployErc20, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.ONE: txData = await prepareOneDeploy20SignedTransaction(testnet, _body as DeployErc20, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.MATIC: txData = await preparePolygonDeployErc20SignedTransaction(testnet, _body as DeployErc20, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.KCS: txData = await prepareKcsDeployErc20SignedTransaction(_body as CoreDeployErc20, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.BSC: txData = await prepareDeployBep20SignedTransaction(_body as DeployErc20, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.CELO: txData = await prepareCeloDeployErc20SignedTransaction(testnet, _body as DeployCeloErc20, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.EGLD: txData = await prepareEgldDeployEsdtSignedTransaction(_body as EgldEsdtTransaction, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.XDC: const tx = { ..._body, address: fromXdcAddress((_body as DeployErc20).address), }; txData = await prepareXdcDeployErc20SignedTransaction(tx as DeployErc20, (await this.getFirstNodeUrl(chain, testnet))); break; case Currency.ALGO: txData = await prepareAlgoCreateFTSignedTransaction(testnet, _body as DeployErc20, (await this.getFirstNodeUrl(chain, testnet))); break; default: throw new Erc20Error(`Unsupported chain ${chain}.`, 'unsupported.chain'); } if (body.signatureId) { return {signatureId: await this.storeKMSTransaction(txData, chain, [body.signatureId], body.index)}; } else { return this.broadcast(chain, txData); } } public async approveErc20(body: ApproveErc20 | ChainEgldEsdtTransaction): Promise<TransactionHash | { signatureId: string }> { const testnet = await this.isTestnet(); const {chain, ..._body} = body; let txData; switch (chain) { case Currency.EGLD: txData = await prepareEgldFreezeOrWipeOrOwvershipEsdtSignedTransaction(_body as EgldEsdtTransaction, (await this.getFirstNodeUrl(chain, testnet))); break; default: txData = await prepareAuctionApproveErc20Transfer(testnet, body as ApproveErc20, await this.getFirstNodeUrl(body.chain, testnet)); } if (body.signatureId) { return {signatureId: await this.storeKMSTransaction(txData, body.chain, [body.signatureId], body.index)}; } else { return this.broadcast(body.chain, txData); } } }