import * as blakejs from 'blakejs' ; import { JSONPath } from 'jsonpath-plus' ; import { TezosLanguageUtil } from '../TezosLanguageUtil' ; import { TezosNodeReader } from '../TezosNodeReader' ; import { TezosNodeWriter } from '../TezosNodeWriter' ; import { KeyStore , Signer } from '../../../types/ExternalInterfaces' ; import * as TezosTypes from '../../../types/tezos/TezosChainTypes' ; export namespace MurbardMultisigHelper { param server param address export async function verifyDestination ( server , address ) { const contract = await TezosNodeReader . getAccountForBlock ( server , 'head' , address ) ; if ( ! ! ! contract . script ) { throw new Error ( `No code found at ${ address }` ) ; } const k = Buffer . from ( blakejs . blake2s ( JSON . stringify ( contract . script . code ) , null , 16 ) ) . toString ( 'hex' ) ; if ( k !== '914629850cfdad7b54a8c5a661d10bd0' ) { throw new Error ( `Contract does not match the expected code hash: ${ k }, '914629850cfdad7b54a8c5a661d10bd0'` ) ; } return true ; } param script export function verifyScript ( script ) { const k = Buffer . from ( blakejs . blake2s ( TezosLanguageUtil . preProcessMichelsonScript ( script ) . join ( '\n' ) , null , 16 ) ) . toString ( 'hex' ) ; if ( k !== 'ffcad1e376a6c8915780fe6676aceec6' ) { throw new Error ( `Contract does not match the expected code hash: ${ k }, 'ffcad1e376a6c8915780fe6676aceec6'` ) ; } return true ; } export async function getSimpleStorage ( server , address ) { const storageResult = await TezosNodeReader . getContractStorage ( server , address ) ; return { counter : Number ( JSONPath ( { path : '$.args[0].int' , json : storageResult } ) [ 0 ] ) , threshold : Number ( JSONPath ( { path : '$.args[1].args[0].int' , json : storageResult } ) [ 0 ] ) , keys : JSONPath ( { path : '$.args[1].args[1]..string' , json : storageResult } ) } ; } /**
     * Sample multi-sig contract retrieved in April 2020.
     * https://github.com/murbard/smart-contracts/blob/master/multisig/michelson/multisig.tzip
     */ export async function deployContract ( server , signer , keyStore , delegate , fee , amount , counter , threshold , keys ) { if ( threshold > keys . length ) { throw new Error ( 'Number of keys provided is lower than the threshold' ) ; } const code = `parameter (pair (pair :payload (nat %counter) (or :action (pair :transfer (mutez %amount) (contract %dest unit)) (or (option %delegate key_hash) (pair %change_keys (nat %threshold) (list %keys key))))) (list %sigs (option signature)));
        storage (pair (nat %stored_counter) (pair (nat %threshold) (list %keys key)));
        code
          {
            UNPAIR ; SWAP ; DUP ; DIP { SWAP } ;
            DIP
              {
                UNPAIR ;
                DUP ; SELF ; ADDRESS ; CHAIN_ID ; PAIR ; PAIR ;
                PACK ;
                DIP { UNPAIR @counter ; DIP { SWAP } } ; SWAP
              } ;
            UNPAIR @stored_counter; DIP { SWAP };
            ASSERT_CMPEQ ;
            DIP { SWAP } ; UNPAIR @threshold @keys;
            DIP
              {
                PUSH @valid nat 0; SWAP ;
                ITER
                  {
                    DIP { SWAP } ; SWAP ;
                    IF_CONS
                      {
                        IF_SOME
                          { SWAP ;
                            DIP
                              {
                                SWAP ; DIIP { DUUP } ;
                                CHECK_SIGNATURE ; ASSERT ;
                                PUSH nat 1 ; ADD @valid } }
                          { SWAP ; DROP }
                      }
                      {
                        FAIL
                      } ;
                    SWAP
                  }
              } ;
            ASSERT_CMPLE ;
            DROP ; DROP ;
            DIP { UNPAIR ; PUSH nat 1 ; ADD @new_counter ; PAIR} ;
            NIL operation ; SWAP ;
            IF_LEFT
              {
                UNPAIR ; UNIT ; TRANSFER_TOKENS ; CONS }
              { IF_LEFT {
                          SET_DELEGATE ; CONS }
                        {
                          DIP { SWAP ; CAR } ; SWAP ; PAIR ; SWAP }} ;
            PAIR }` ; const storage = `(Pair ${ counter } (Pair ${ threshold } { "${ keys . join ( '" ; "' ) }" } ) )` ; const nodeResult = await TezosNodeWriter . sendContractOriginationOperation ( server , signer , keyStore , amount , delegate , fee , 5000 , 120000 , code , storage , TezosTypes . TezosParameterFormat . Michelson ) ; return clearRPCOperationGroupHash ( nodeResult [ 'operationGroupID' ] ) ; } function clearRPCOperationGroupHash ( hash ) { return hash . replace ( /\"/g , '' ) . replace ( /\n/ , '' ) ; } }