import { context } from '../context' ; import { MultisigBuilder , MultisigConfig , readSavedMultisig } from '../multisig' ; import { ExecuteOptions } from '../execute/execute' ; import { SavedMultisigEntry , saveMultisig } from '../multisig/multisigState' ; import { log } from '../logging' ; /***
 * Designates a wrapping block of syntax statements that are to be executed as a single multisig transaction batch.
 * Use 'propose()' to terminate the block.
 */ export interface MultisigBlock { name : string ; propose ( ) : void ; } param name export function multisig ( name ) { context . ensureEnabled ( ) ; const multisig = context . multisig ; if ( ! multisig ) throw new Error ( 'Multisig context does not exist. Ensure you configured it for the deployment.' ) ; multisig . defineStart ( name ) ; context . actions . push ( { type : 'MULTISIG_START' , } ) ; return { name , propose ( ) { context . ensureEnabled ( ) ; multisig . defineEnd ( ) ; context . actions . push ( { type : 'MULTISIG_END' , } ) ; } , } ; } /***
 * Multisig context of deployment process.
 *
 * A global overview of all the multisigs in the deployment. Manages them globally.
 */ export class MultisigContext { private _all : MultisigBuilder [ ] = [ ] ; private _config : MultisigConfig ; private _current ? : MultisigBuilder ; constructor ( config ) { this . _config = config ; } public defineStart ( name ) { if ( this . isActive ( ) ) throw new Error ( "Multisig block already opened. Make sure you proposed the previous multisig with 'propose'." ) ; if ( this . contains ( multisig . name ) ) throw new Error ( `Multisig name ${ multisig . name } already defined.` ) ; const builder = new MultisigBuilder ( name , this . _config . networkChainId ) ; this . _current = builder ; this . _all . push ( builder ) ; } public defineEnd ( ) { if ( ! this . isActive ( ) ) throw new Error ( 'Multisig block has not been opened. Ensure you created a multisig block first.' ) ; this . _current = undefined ; } public async executeStart ( ) { if ( this . _all . length == 0 ) throw new Error ( 'There are no multisig elements to process. This indicates a bug in code.' ) ; this . _current = this . _all [ 0 ] ; this . _all = this . _all . slice ( 1 ) ; } public async executeEnd ( options ) { const current = this . ensureCurrent ( ) ; const executable = current . buildExecutable ( options . signer , this . _config ) ; const multisigData = readSavedMultisig ( options . deploymentsFile , options . networkName , executable . name ) ; let state ; if ( ! multisigData || multisigData . state == 'UNKNOWN' ) { if ( current . txBatch . length == 0 ) { log ( `Skipping multisig '${ executable . name }' due to empty tx set.'` ) ; return { continue : true } ; } const multisigId = await executable . propose ( current . txBatch ) ; await executable . approve ( multisigId ) ; state = { id : multisigId , state : 'PROPOSED' , } ; saveMultisig ( options . deploymentsFile , options . networkName , executable . name , state ) ; return { continue : false } ; } else if ( multisigData . state == 'PROPOSED' ) { const checkedState = await executable . checkState ( multisigData . id ) ; if ( checkedState . kind == 'EXECUTED' ) { state = { id : multisigData . id , state : 'EXECUTED' , txHash : checkedState . txHash , } ; saveMultisig ( options . deploymentsFile , options . networkName , executable . name , state ) ; return { continue : true } ; } return { continue : false } ; } this . _current = undefined ; return { continue : true } ; } public isActive ( ) { return this . _current !== undefined ; } public current ( ) { return this . _current ; } private contains ( name ) { return this . _all . map ( ( m ) => m . name ) . indexOf ( name ) >= 0 ; } private ensureCurrent ( ) { if ( ! this . _current ) throw new Error ( 'Current builder is undefined. You are outside the multisig block trying to do multisig' ) ; return this . _current ; } }