import { TransactionObject } from '@arianee/arianee-abi/types/types' ; import { injectable } from 'tsyringe' ; import { Transaction } from 'web3-core' ; import { Contract } from 'web3-eth-contract' ; import { POAAndAriaService } from '../wallet/services/POAAndAriaFaucet/POAAndAriaService' ; import { UtilsService } from '../wallet/services/utilService/utilsService' ; import { WalletService } from '../wallet/services/walletService/walletService' ; import { Web3Service } from '../wallet/services/web3Service/web3Service' ; import { flatPromise } from './flat-promise' ; import { TransactionMapper } from '../etherjsWeb3Transaction/TransactionMapper' ; declare global { interface Window { ethereum : any ; } } @ injectable ( ) export class ArianeeContract < ContractImplementation extends Contract > { public key : ContractImplementation ; public constructor ( private contract , private walletService , private web3Service , private poaAndAriaService , private utilsService ) { if ( contract === undefined ) { throw new Error ( 'contract is undefined' ) ; } this . key = < ContractImplementation > contract ; Object . keys ( this . key . methods ) . forEach ( method => { const b = contract . methods [ method ] ; if ( ! method . startsWith ( '0' ) ) { this . key . methods [ method ] = ( ... args ) => { return { ... b . bind ( b ) ( ... args ) , send : ( transaction ) => this . overideSend ( transaction , b . bind ( b ) ( ... args ) ) , call : ( transaction ) => this . overideCall ( transaction , b . bind ( b ) ( ... args ) ) } ; } ; } } ) ; } public makeArianee ( ) { return this . key ; } param nonce param contractAddress param data public arianeeSignMetamask ( transaction ) { const { resolve , promise , reject } = flatPromise ( ) ; this . web3Service . web3 . eth . sendTransaction ( transaction , function ( err , result ) { if ( err ) { reject ( err ) ; } else { resolve ( ) ; } } ) ; return promise ; } private overideCall = async ( transaction , data ) => { const defaultTransaction = { from : this . walletService . address } ; const mergedTransaction = { ... defaultTransaction , ... transaction } ; return data . call ( mergedTransaction ) ; } ; private overideSend = async ( transaction , data ) : Promise < any > => { const encodeABI = data . encodeABI ( ) ; const preparedTransaction = await this . utilsService . prepareTransaction ( encodeABI , this . contract . options . address , false , transaction ) ; if ( this . walletService . isCustomSendTransaction ( ) ) { return this . walletService . customSendTransaction ( preparedTransaction ) ; } else { if ( this . walletService . isRemoteAccount ( ) ) { return this . web3Service . web3 . eth . sendTransaction ( preparedTransaction ) . then ( ( txHash ) => { this . web3Service . web3 . eth . getTransactionReceipt ( txHash ) . then ( ( receipt ) => { return { undefined , receipt } ; } ) ; } ) . catch ( ( e ) => { return { receipt : e . message , error : e } ; } ) ; } if ( this . walletService . metamask ) { const metamaskTransaction = new TransactionMapper ( preparedTransaction ) . toMetamaskTransaction ( ) ; const txHash = await window . ethereum . request ( { method : 'eth_sendTransaction' , params : [ metamaskTransaction ] } ) ; if ( txHash === '0x0000000000000000000000000000000000000000000000000000000000000000' ) { throw new Error ( 'An error occurred while sending the transaction' ) ; } const watchReceipt = async ( ) => { const receipt = await window . ethereum . request ( { method : 'eth_getTransactionReceipt' , params : [ txHash ] } ) ; if ( receipt === null ) { return watchReceipt ( ) ; } else { return receipt ; } } ; const receipt = await watchReceipt ( ) ; return { receipt } ; } else { const signTransaction = this . walletService . signTransaction ( preparedTransaction ) ; const [ { rawTransaction } ] = await Promise . all ( [ signTransaction , this . poaAndAriaService . requestPoa ( ) . catch ( ) ] ) ; return new Promise ( ( resolve , reject ) => { this . web3Service . web3 . eth . sendSignedTransaction ( rawTransaction ) . once ( 'error' , async ( error , receipt ) => { console . error ( error ) ; reject ( { receipt , error } ) ; } ) . once ( 'receipt' , ( receipt ) => { resolve ( { receipt } ) ; } ) ; } ) ; } } } ; }