import { providers } from 'ethers'; import BaseService from '../commons/BaseService'; import { eEthereumTxType, EthereumTransactionTypeExtended, tEthereumAddress, transactionType, } from '../commons/types'; import { ERC721Validator } from '../commons/validators/methodValidators'; import { isEthAddress, isValidTokenId, } from '../commons/validators/paramValidators'; import { IERC721 } from './typechain/IERC721'; import { IERC721Factory } from './typechain/IERC721Factory'; type ApproveType = { user: tEthereumAddress; token: tEthereumAddress; spender: tEthereumAddress; token_id: string; }; type ApproveAllType = { user: tEthereumAddress; token: tEthereumAddress; spender: tEthereumAddress; token_ids: string[]; }; type SetApproveAllType = { user: tEthereumAddress; token: tEthereumAddress; spender: tEthereumAddress; }; export interface IERC721ServiceInterface { isApproved: (args: ApproveType) => Promise; isApprovedForAll: (args: ApproveAllType) => Promise; approve: (args: ApproveType) => EthereumTransactionTypeExtended; setApprovalForAll: ( args: SetApproveAllType, ) => EthereumTransactionTypeExtended; } export class ERC721Service extends BaseService implements IERC721ServiceInterface { constructor(provider: providers.Provider) { super(provider, IERC721Factory); this.isApproved = this.isApproved.bind(this); this.isApprovedForAll = this.isApprovedForAll.bind(this); this.approve = this.approve.bind(this); this.setApprovalForAll = this.setApprovalForAll.bind(this); } @ERC721Validator public approve( @isEthAddress('user') @isEthAddress('token') @isEthAddress('spender') @isValidTokenId('token_id') { user, token, spender, token_id }: ApproveType, ): EthereumTransactionTypeExtended { const erc721Contract: IERC721 = this.getContractInstance(token); const txCallback: () => Promise = this.generateTxCallback({ rawTxMethod: async () => erc721Contract.populateTransaction.approve(spender, token_id), from: user, }); return { tx: txCallback, txType: eEthereumTxType.ERC721_APPROVAL, gas: this.generateTxPriceEstimation([], txCallback), }; } @ERC721Validator public async isApproved( @isEthAddress('user') @isEthAddress('token') @isEthAddress('spender') @isValidTokenId('token_id') { user, token, spender, token_id }: ApproveType, ): Promise { const erc721Contract: IERC721 = this.getContractInstance(token); const approved: tEthereumAddress = await erc721Contract.getApproved( token_id, ); if (approved === spender) { return true; } return erc721Contract.isApprovedForAll(user, spender); } @ERC721Validator public setApprovalForAll( @isEthAddress('user') @isEthAddress('token') @isEthAddress('spender') { user, token, spender }: SetApproveAllType, ): EthereumTransactionTypeExtended { const erc721Contract: IERC721 = this.getContractInstance(token); const txCallback: () => Promise = this.generateTxCallback({ rawTxMethod: async () => erc721Contract.populateTransaction.setApprovalForAll(spender, true), from: user, }); return { tx: txCallback, txType: eEthereumTxType.ERC721_APPROVAL, gas: this.generateTxPriceEstimation([], txCallback), }; } @ERC721Validator public async isApprovedForAll( @isEthAddress('user') @isEthAddress('token') @isEthAddress('spender') { user, token, spender, token_ids }: ApproveAllType, ): Promise { const erc721Contract: IERC721 = this.getContractInstance(token); let allApproved: boolean = await erc721Contract.isApprovedForAll( user, spender, ); if (!allApproved) { for (const token_id of token_ids) { // eslint-disable-next-line no-await-in-loop const approved: tEthereumAddress = await erc721Contract.getApproved( token_id, ); if (approved !== spender) { allApproved = false; break; } } } return allApproved; } public async balanceOf(token: string, owner: string) { const erc721Contract: IERC721 = this.getContractInstance(token); return erc721Contract.balanceOf(owner); } }