import Subscription from "../subscription" ; import TasitProviderHelpers from "@tasit/provider-helpers" ; const { ProviderFactory } = TasitProviderHelpers ; import { Network , Receipt , RawAction } from "./types" ; class Action extends Subscription { private provider : { getTransactionCount : ( arg0 : any ) => void ; getNetwork : ( ) => Promise < Network > ; sendTransaction : ( arg0 : any ) => void ; getTransactionReceipt : ( arg0 : any ) => Promise < Receipt > ; waitForTransaction : ( arg0 : any ) => void ; } ; private signer : { address : any ; sign : ( arg0 : any ) => void ; } ; private rawAction : any ; private tx : any ; private txConfirmations = 0 ; constructor ( rawAction , provider , signer ) { super ( provider ) ; this . rawAction = rawAction ; this . signer = signer ; this . provider = provider ; this . txConfirmations = 0 ; } _toRaw = ( ) => { return this . rawAction ; } ; private fillRawAction = async ( rawTx ) => { const nonce = this . provider . getTransactionCount ( this . signer . address ) ; const network = await this . provider . getNetwork ( ) ; const { chainId } = network ; let { value } = rawTx ; value = ! value ? 0 : value ; const gasPrice = 1e9 ; const gasLimit = 7e6 ; const rawTxOutput = { ... rawTx , nonce , chainId , value , gasPrice , gasLimit } ; return rawTxOutput ; } ; private signAndSend = async ( ) => { try { const rawAction = await this . rawAction ; this . rawAction = await this . fillRawAction ( rawAction ) ; const signedTx = this . signer . sign ( this . rawAction ) ; this . tx = this . provider . sendTransaction ( signedTx ) ; } catch ( error ) { this . _emitErrorEvent ( new Error ( `Action with error: ${ error . message }` ) ) ; } } ; send = async ( ) => { await this . signAndSend ( ) ; } ; on = ( eventName , listener ) => { this . addListener ( eventName , listener , false ) ; } ; once = ( eventName , listener ) => { this . addListener ( eventName , listener , true ) ; } ; private addListener = ( eventName , listener , once ) => { const events = [ "confirmation" , "error" ] ; if ( ! events . includes ( eventName ) ) throw new Error ( `Invalid event, use: [${ events }]` ) ; if ( eventName === "error" && once ) throw new Error ( `Use on() function to subscribe to an error event.` ) ; if ( ! listener || typeof listener !== "function" ) throw new Error ( `Cannot listen without a function` ) ; if ( eventName !== "error" && eventName !== "confirmation" ) { throw new Error ( `Invalid event '${ event }'.` ) ; } else if ( eventName === "error" ) { this . _addErrorListener ( listener ) ; } else if ( eventName === "confirmation" ) { this . addConfirmationListener ( listener , once ) ; } } ; private addConfirmationListener = ( listener , once ) => { const eventName = "confirmation" ; const ethersListener = async ( ) => { try { const tx = await this . tx ; if ( ! tx ) { console . info ( `The action wasn't sent yet.` ) ; return ; } const receipt = this . provider . getTransactionReceipt ( tx . hash ) ; const { confirmations , status } = await receipt ; const blockReorgOccurred = ( receipt === null && this . txConfirmations > 0 ) || ( receipt !== null && confirmations <= this . txConfirmations ) ; if ( blockReorgOccurred ) { this . _emitErrorEventFromEventListener ( new Error ( `Your action's position in the chain has changed in a surprising way.` ) , eventName ) ; } if ( ! receipt ) return ; const txFailed = status === 0 ; if ( txFailed ) { this . _emitErrorEventFromEventListener ( new Error ( `Action failed.` ) , eventName ) ; return ; } this . txConfirmations = confirmations ; const message = { data : { confirmations , } , } ; listener ( message ) ; if ( once ) this . off ( eventName ) ; } catch ( error ) { this . _emitErrorEventFromEventListener ( new Error ( `Listener function with error: ${ error . message }` ) , eventName ) ; } } ; this . _addEventListener ( eventName , ethersListener ) ; } ; getTransaction = ( ) => { return this . tx ; } ; getId = async ( ) => { const tx = await this . tx ; const { hash : id } = tx ; return id ; } ; waitForOneConfirmation = async ( ) => { const tx = await this . tx ; if ( tx ) this . provider . waitForTransaction ( tx . hash ) ; } ; _refreshProvider = ( ) => { const provider = ProviderFactory . getProvider ( ) ; if ( provider ) { this . provider = provider ; } } ; } export default Action ;