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 ) { } protected abstract storeKMSTransaction ( txData , currency , signatureId , index ? ) ; protected abstract isTestnet ( ) ; protected abstract getNodesUrl ( chain , testnet ) ; protected abstract broadcast ( chain , txData , signatureId ? ) ; private async getFirstNodeUrl ( chain , testnet ) { 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 , testnet ) { 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 , address , contractAddress ) { 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 ( ) ) ; const contract = new client . eth . Contract ( erc20_abi , contractOrAddress ) ; return { balance : await contract . methods . balanceOf ( _address ) . call ( ) } ; } public async transferErc20 ( body ) { 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 ) { 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 ) { 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 ) { 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 ) { 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 ) ; } } }