/**
 * File notes:
 *
 * FIXME: This file over-uses the xkeyKthAddress function which
 *        is quite computationally expensive. Refactor to use it less.
 */ import { MultiAssetMultiPartyCoinTransferInterpreterParams , NetworkContext , OutcomeType , SingleAssetTwoPartyCoinTransferInterpreterParams , TwoPartyFixedOutcomeInterpreterParams , virtualAppAgreementEncoding } from "@counterfactual/types" ; import { MaxUint256 } from "ethers/constants" ; import { Provider } from "ethers/providers" ; import { BigNumber , bigNumberify , defaultAbiCoder } from "ethers/utils" ; import { UNASSIGNED_SEQ_NO } from "../constants" ; import { ConditionalTransaction , SetStateCommitment } from "../ethereum" ; import { AppInstance , StateChannel , StateChannelJSON } from "../models" ; import { getCreate2MultisigAddress } from "../utils" ; import { Opcode , Protocol } from "./enums" ; import { Context , InstallVirtualAppParams , ProtocolExecutionFlow , ProtocolMessage } from "./types" ; import { assertIsValidSignature } from "./utils/signature-validator" ; import { sortAddresses , xkeyKthAddress } from "./xkeys" ; export const encodeSingleAssetTwoPartyIntermediaryAgreementParams = params => defaultAbiCoder . encode ( [ virtualAppAgreementEncoding ] , [ params ] ) ; const protocol = Protocol . InstallVirtualApp ; const { OP_SIGN , IO_SEND , IO_SEND_AND_WAIT } = Opcode ; /**
 * This exchange is described at the following URL:
 *
 * https://specs.counterfactual.com/en/latest/protocols/install-virtual-app.html
 */ export const INSTALL_VIRTUAL_APP_PROTOCOL = { 0 : async function * ( context ) { const { message : { params , processID } , store , network , provider } = context ; const { sharedData : { stateChannelsMap } } = store ; const { intermediaryXpub , responderXpub } = params as InstallVirtualAppParams ; const [ stateChannelWithInitiatingAndIntermediary , stateChannelWithResponding , stateChannelWithIntermediary , virtualAppInstance , timeLockedPassThroughAppInstance ] = await getUpdatedStateChannelAndVirtualAppObjectsForInitiating ( params as InstallVirtualAppParams , stateChannelsMap , network , provider ) ; const intermediaryAddress = stateChannelWithIntermediary . getMultisigOwnerAddrOf ( intermediaryXpub ) ; const responderAddress = stateChannelWithResponding . getMultisigOwnerAddrOf ( responderXpub ) ; const presignedMultisigTxForAliceIngridVirtualAppAgreement = new ConditionalTransaction ( network , stateChannelWithIntermediary . multisigAddress , stateChannelWithIntermediary . multisigOwners , timeLockedPassThroughAppInstance . identityHash , stateChannelWithIntermediary . freeBalance . identityHash , network . TwoPartyFixedOutcomeFromVirtualAppInterpreter , encodeSingleAssetTwoPartyIntermediaryAgreementParams ( stateChannelWithIntermediary . getSingleAssetTwoPartyIntermediaryAgreementFromVirtualApp ( virtualAppInstance . identityHash ) ) ) ; const initiatorSignatureOnAliceIngridVirtualAppAgreement = yield [ OP_SIGN , presignedMultisigTxForAliceIngridVirtualAppAgreement ] ; const m1 = { params , protocol , processID , toXpub : intermediaryXpub , seq : 1 , customData : { signature : initiatorSignatureOnAliceIngridVirtualAppAgreement , signature2 : virtualAppInstance . identityHash , signature3 : timeLockedPassThroughAppInstance . state [ "defaultOutcome" ] } } as ProtocolMessage ; const m4 = ( yield [ IO_SEND_AND_WAIT , m1 ] ) as ProtocolMessage ; const { customData : { signature : intermediarySignatureOnAliceIngridVirtualAppAgreement , signature2 : intermediarySignatureOnAliceIngridFreeBalanceAppActivation } } = m4 ; assertIsValidSignature ( intermediaryAddress , presignedMultisigTxForAliceIngridVirtualAppAgreement , intermediarySignatureOnAliceIngridVirtualAppAgreement ) ; await store . setCommitment ( [ Protocol . InstallVirtualApp , virtualAppInstance . identityHash ] , presignedMultisigTxForAliceIngridVirtualAppAgreement . getSignedTransaction ( [ initiatorSignatureOnAliceIngridVirtualAppAgreement , intermediarySignatureOnAliceIngridVirtualAppAgreement ] ) ) ; const freeBalanceAliceIngridVirtualAppAgreementActivationCommitment = new SetStateCommitment ( network , stateChannelWithIntermediary . freeBalance . identity , stateChannelWithIntermediary . freeBalance . hashOfLatestState , stateChannelWithIntermediary . freeBalance . versionNumber , stateChannelWithIntermediary . freeBalance . timeout ) ; assertIsValidSignature ( intermediaryAddress , freeBalanceAliceIngridVirtualAppAgreementActivationCommitment , intermediarySignatureOnAliceIngridFreeBalanceAppActivation ) ; const initiatorSignatureOnAliceIngridFreeBalanceAppActivation = yield [ OP_SIGN , freeBalanceAliceIngridVirtualAppAgreementActivationCommitment ] ; await store . setCommitment ( [ Protocol . Update , stateChannelWithIntermediary . freeBalance . identityHash ] , freeBalanceAliceIngridVirtualAppAgreementActivationCommitment . getSignedTransaction ( [ initiatorSignatureOnAliceIngridFreeBalanceAppActivation , intermediarySignatureOnAliceIngridFreeBalanceAppActivation ] ) ) ; const virtualAppSetStateCommitment = new SetStateCommitment ( network , virtualAppInstance . identity , virtualAppInstance . hashOfLatestState , virtualAppInstance . versionNumber , virtualAppInstance . defaultTimeout ) ; const timeLockedPassThroughSetStateCommitment = new SetStateCommitment ( network , timeLockedPassThroughAppInstance . identity , timeLockedPassThroughAppInstance . hashOfLatestState , timeLockedPassThroughAppInstance . versionNumber , timeLockedPassThroughAppInstance . defaultTimeout ) ; const initiatorSignatureOnTimeLockedPassThroughSetStateCommitment = yield [ OP_SIGN , timeLockedPassThroughSetStateCommitment ] ; const initiatorSignatureOnVirtualAppSetStateCommitment = yield [ OP_SIGN , virtualAppSetStateCommitment ] ; const m5 = { protocol , processID , toXpub : intermediaryXpub , seq : UNASSIGNED_SEQ_NO , customData : { signature : initiatorSignatureOnAliceIngridFreeBalanceAppActivation , signature2 : initiatorSignatureOnTimeLockedPassThroughSetStateCommitment , signature3 : initiatorSignatureOnVirtualAppSetStateCommitment } } as ProtocolMessage ; const m8 = ( yield [ IO_SEND_AND_WAIT , m5 ] ) as ProtocolMessage ; const { customData : { signature : intermediarySignatureOnTimeLockedPassThroughSetStateCommitment , signature2 : responderSignatureOnTimeLockedPassThroughSetStateCommitment , signature3 : responderSignatureOnVirtualAppSetStateCommitment } } = m8 ; assertIsValidSignature ( intermediaryAddress , timeLockedPassThroughSetStateCommitment , intermediarySignatureOnTimeLockedPassThroughSetStateCommitment ) ; assertIsValidSignature ( responderAddress , timeLockedPassThroughSetStateCommitment , responderSignatureOnTimeLockedPassThroughSetStateCommitment ) ; assertIsValidSignature ( responderAddress , virtualAppSetStateCommitment , responderSignatureOnVirtualAppSetStateCommitment ) ; await store . setCommitment ( [ Protocol . Update , timeLockedPassThroughAppInstance . identityHash ] , timeLockedPassThroughSetStateCommitment . getSignedTransaction ( [ initiatorSignatureOnTimeLockedPassThroughSetStateCommitment , responderSignatureOnTimeLockedPassThroughSetStateCommitment , intermediarySignatureOnTimeLockedPassThroughSetStateCommitment ] ) ) ; await store . setCommitment ( [ Protocol . Update , virtualAppInstance . identityHash ] , virtualAppSetStateCommitment . getSignedTransaction ( [ initiatorSignatureOnVirtualAppSetStateCommitment , responderSignatureOnVirtualAppSetStateCommitment ] ) ) ; await store . saveStateChannel ( stateChannelWithIntermediary ) ; await store . saveStateChannel ( stateChannelWithResponding ) ; await store . saveStateChannel ( stateChannelWithInitiatingAndIntermediary ) ; } , 1 : async function * ( context ) { const { message : m1 , store , network } = context ; const { sharedData : { stateChannelsMap } } = store ; const { params , processID , customData : { signature : initiatorSignatureOnAliceIngridVirtualAppAgreement , signature2 : virtualAppInstanceIdentityHash , signature3 : virtualAppInstanceDefaultOutcome } } = m1 ; const { initiatorXpub , responderXpub } = params as InstallVirtualAppParams ; const [ stateChannelBetweenVirtualAppUsers , stateChannelWithInitiating , stateChannelWithResponding , timeLockedPassThroughAppInstance ] = await getUpdatedStateChannelAndVirtualAppObjectsForIntermediary ( params as InstallVirtualAppParams , stateChannelsMap , ( virtualAppInstanceIdentityHash as unknown ) as string , ( virtualAppInstanceDefaultOutcome as unknown ) as string , network ) ; const initiatorAddress = stateChannelWithInitiating . getMultisigOwnerAddrOf ( initiatorXpub ) ; const responderAddress = stateChannelWithResponding . getMultisigOwnerAddrOf ( responderXpub ) ; const presignedMultisigTxForAliceIngridVirtualAppAgreement = new ConditionalTransaction ( network , stateChannelWithInitiating . multisigAddress , stateChannelWithInitiating . multisigOwners , timeLockedPassThroughAppInstance . identityHash , stateChannelWithInitiating . freeBalance . identityHash , network . TwoPartyFixedOutcomeFromVirtualAppInterpreter , encodeSingleAssetTwoPartyIntermediaryAgreementParams ( stateChannelWithInitiating . getSingleAssetTwoPartyIntermediaryAgreementFromVirtualApp ( timeLockedPassThroughAppInstance . state [ "targetAppIdentityHash" ] ) ) ) ; assertIsValidSignature ( initiatorAddress , presignedMultisigTxForAliceIngridVirtualAppAgreement , initiatorSignatureOnAliceIngridVirtualAppAgreement ) ; const presignedMultisigTxForIngridBobVirtualAppAgreement = new ConditionalTransaction ( network , stateChannelWithResponding . multisigAddress , stateChannelWithResponding . multisigOwners , timeLockedPassThroughAppInstance . identityHash , stateChannelWithResponding . freeBalance . identityHash , network . TwoPartyFixedOutcomeFromVirtualAppInterpreter , encodeSingleAssetTwoPartyIntermediaryAgreementParams ( stateChannelWithResponding . getSingleAssetTwoPartyIntermediaryAgreementFromVirtualApp ( timeLockedPassThroughAppInstance . state [ "targetAppIdentityHash" ] ) ) ) ; const intermediarySignatureOnIngridBobVirtualAppAgreement = yield [ OP_SIGN , presignedMultisigTxForIngridBobVirtualAppAgreement ] ; const m2 = { params , protocol , processID , seq : 2 , toXpub : responderXpub , customData : { signature : intermediarySignatureOnIngridBobVirtualAppAgreement } } as ProtocolMessage ; const m3 = ( yield [ IO_SEND_AND_WAIT , m2 ] ) as ProtocolMessage ; const { customData : { signature : responderSignatureOnIngridBobVirtualAppAgreement , signature2 : responderSignatureOnIngridBobFreeBalanceAppActivation } } = m3 ; assertIsValidSignature ( responderAddress , presignedMultisigTxForIngridBobVirtualAppAgreement , responderSignatureOnIngridBobVirtualAppAgreement ) ; const freeBalanceIngridBobVirtualAppAgreementActivationCommitment = new SetStateCommitment ( network , stateChannelWithResponding . freeBalance . identity , stateChannelWithResponding . freeBalance . hashOfLatestState , stateChannelWithResponding . freeBalance . versionNumber , stateChannelWithResponding . freeBalance . timeout ) ; assertIsValidSignature ( responderAddress , freeBalanceIngridBobVirtualAppAgreementActivationCommitment , responderSignatureOnIngridBobFreeBalanceAppActivation ) ; const freeBalanceAliceIngridVirtualAppAgreementActivationCommitment = new SetStateCommitment ( network , stateChannelWithInitiating . freeBalance . identity , stateChannelWithInitiating . freeBalance . hashOfLatestState , stateChannelWithInitiating . freeBalance . versionNumber , stateChannelWithInitiating . freeBalance . timeout ) ; const intermediarySignatureOnAliceIngridFreeBalanceAppActivation = yield [ OP_SIGN , freeBalanceAliceIngridVirtualAppAgreementActivationCommitment ] ; const intermediarySignatureOnAliceIngridVirtualAppAgreement = yield [ OP_SIGN , presignedMultisigTxForAliceIngridVirtualAppAgreement ] ; await store . setCommitment ( [ Protocol . InstallVirtualApp , timeLockedPassThroughAppInstance . identityHash ] , presignedMultisigTxForAliceIngridVirtualAppAgreement . getSignedTransaction ( [ initiatorSignatureOnAliceIngridVirtualAppAgreement , intermediarySignatureOnAliceIngridVirtualAppAgreement ] ) ) ; const m4 = { protocol , processID , seq : UNASSIGNED_SEQ_NO , toXpub : initiatorXpub , customData : { signature : intermediarySignatureOnAliceIngridVirtualAppAgreement , signature2 : intermediarySignatureOnAliceIngridFreeBalanceAppActivation } } as ProtocolMessage ; const m5 = ( yield [ IO_SEND_AND_WAIT , m4 ] ) as ProtocolMessage ; const { customData : { signature : initiatorSignatureOnAliceIngridFreeBalanceAppActivation , signature2 : initiatorSignatureOnTimeLockedPassThroughSetStateCommitment , signature3 : initiatorSignatureOnVirtualAppSetStateCommitment } } = m5 ; assertIsValidSignature ( initiatorAddress , freeBalanceAliceIngridVirtualAppAgreementActivationCommitment , initiatorSignatureOnAliceIngridFreeBalanceAppActivation ) ; await store . setCommitment ( [ Protocol . Update , stateChannelWithResponding . freeBalance . identityHash ] , freeBalanceIngridBobVirtualAppAgreementActivationCommitment . getSignedTransaction ( [ initiatorSignatureOnAliceIngridFreeBalanceAppActivation , intermediarySignatureOnAliceIngridFreeBalanceAppActivation ] ) ) ; const timeLockedPassThroughSetStateCommitment = new SetStateCommitment ( network , timeLockedPassThroughAppInstance . identity , timeLockedPassThroughAppInstance . hashOfLatestState , timeLockedPassThroughAppInstance . versionNumber , timeLockedPassThroughAppInstance . defaultTimeout ) ; assertIsValidSignature ( initiatorAddress , timeLockedPassThroughSetStateCommitment , initiatorSignatureOnTimeLockedPassThroughSetStateCommitment ) ; const intermediarySignatureOnIngridBobFreeBalanceAppActivation = yield [ OP_SIGN , freeBalanceIngridBobVirtualAppAgreementActivationCommitment ] ; await store . setCommitment ( [ Protocol . Update , stateChannelWithResponding . freeBalance . identityHash ] , freeBalanceIngridBobVirtualAppAgreementActivationCommitment . getSignedTransaction ( [ responderSignatureOnIngridBobFreeBalanceAppActivation , intermediarySignatureOnIngridBobFreeBalanceAppActivation ] ) ) ; const intermediarySignatureOnTimeLockedPassThroughSetStateCommitment = yield [ OP_SIGN , timeLockedPassThroughSetStateCommitment ] ; const m6 = { protocol , processID , toXpub : responderXpub , seq : UNASSIGNED_SEQ_NO , customData : { signature : intermediarySignatureOnIngridBobFreeBalanceAppActivation , signature2 : intermediarySignatureOnTimeLockedPassThroughSetStateCommitment , signature3 : initiatorSignatureOnTimeLockedPassThroughSetStateCommitment , signature4 : initiatorSignatureOnVirtualAppSetStateCommitment } } as ProtocolMessage ; const m7 = ( yield [ IO_SEND_AND_WAIT , m6 ] ) as ProtocolMessage ; const { customData : { signature : responderSignatureOnTimeLockedPassThroughSetStateCommitment , signature2 : responderSignatureOnVirtualAppSetStateCommitment } } = m7 ; assertIsValidSignature ( responderAddress , timeLockedPassThroughSetStateCommitment , responderSignatureOnTimeLockedPassThroughSetStateCommitment ) ; await store . setCommitment ( [ Protocol . Update , timeLockedPassThroughAppInstance . identityHash ] , timeLockedPassThroughSetStateCommitment . getSignedTransaction ( [ initiatorSignatureOnTimeLockedPassThroughSetStateCommitment , responderSignatureOnTimeLockedPassThroughSetStateCommitment , intermediarySignatureOnTimeLockedPassThroughSetStateCommitment ] ) ) ; const m8 = { protocol , processID , toXpub : initiatorXpub , seq : UNASSIGNED_SEQ_NO , customData : { signature : intermediarySignatureOnTimeLockedPassThroughSetStateCommitment , signature2 : responderSignatureOnTimeLockedPassThroughSetStateCommitment , signature3 : responderSignatureOnVirtualAppSetStateCommitment } } as ProtocolMessage ; yield [ IO_SEND , m8 ] ; await store . saveStateChannel ( stateChannelBetweenVirtualAppUsers ) ; await store . saveStateChannel ( stateChannelWithResponding ) ; await store . saveStateChannel ( stateChannelWithInitiating ) ; } , 2 : async function * ( context ) { const { message : m2 , store , network , provider } = context ; const { sharedData : { stateChannelsMap } } = store ; const { params , processID , customData : { signature : intermediarySignatureOnIngridBobVirtualAppAgreement } } = m2 ; const { intermediaryXpub , initiatorXpub } = params as InstallVirtualAppParams ; const [ stateChannelWithRespondingAndIntermediary , stateChannelWithInitiating , stateChannelWithIntermediary , virtualAppInstance , timeLockedPassThroughAppInstance ] = await getUpdatedStateChannelAndVirtualAppObjectsForResponding ( params as InstallVirtualAppParams , stateChannelsMap , network , provider ) ; const intermediaryAddress = stateChannelWithIntermediary . getMultisigOwnerAddrOf ( intermediaryXpub ) ; const initiatorAddress = stateChannelWithInitiating . getMultisigOwnerAddrOf ( initiatorXpub ) ; const presignedMultisigTxForIngridBobVirtualAppAgreement = new ConditionalTransaction ( network , stateChannelWithIntermediary . multisigAddress , stateChannelWithIntermediary . multisigOwners , timeLockedPassThroughAppInstance . identityHash , stateChannelWithIntermediary . freeBalance . identityHash , network . TwoPartyFixedOutcomeFromVirtualAppInterpreter , encodeSingleAssetTwoPartyIntermediaryAgreementParams ( stateChannelWithIntermediary . getSingleAssetTwoPartyIntermediaryAgreementFromVirtualApp ( virtualAppInstance . identityHash ) ) ) ; assertIsValidSignature ( intermediaryAddress , presignedMultisigTxForIngridBobVirtualAppAgreement , intermediarySignatureOnIngridBobVirtualAppAgreement ) ; const responderSignatureOnIngridBobVirtualAppAgreement = yield [ OP_SIGN , presignedMultisigTxForIngridBobVirtualAppAgreement ] ; await store . setCommitment ( [ Protocol . InstallVirtualApp , virtualAppInstance . identityHash ] , presignedMultisigTxForIngridBobVirtualAppAgreement . getSignedTransaction ( [ responderSignatureOnIngridBobVirtualAppAgreement , intermediarySignatureOnIngridBobVirtualAppAgreement ] ) ) ; const freeBalanceIngridBobVirtualAppAgreementActivationCommitment = new SetStateCommitment ( network , stateChannelWithIntermediary . freeBalance . identity , stateChannelWithIntermediary . freeBalance . hashOfLatestState , stateChannelWithIntermediary . freeBalance . versionNumber , stateChannelWithIntermediary . freeBalance . timeout ) ; const responderSignatureOnIngridBobFreeBalanceAppActivation = yield [ OP_SIGN , freeBalanceIngridBobVirtualAppAgreementActivationCommitment ] ; const m3 = { protocol , processID , toXpub : intermediaryXpub , seq : UNASSIGNED_SEQ_NO , customData : { signature : responderSignatureOnIngridBobVirtualAppAgreement , signature2 : responderSignatureOnIngridBobFreeBalanceAppActivation } } as ProtocolMessage ; const m6 = ( yield [ IO_SEND_AND_WAIT , m3 ] ) as ProtocolMessage ; const { customData : { signature : intermediarySignatureOnIngridBobFreeBalanceAppActivation , signature2 : intermediarySignatureOnTimeLockedPassThroughSetStateCommitment , signature3 : initiatorSignatureOnTimeLockedPassThroughSetStateCommitment , signature4 : initiatorSignatureOnVirtualAppSetStateCommitment } } = m6 ; assertIsValidSignature ( intermediaryAddress , freeBalanceIngridBobVirtualAppAgreementActivationCommitment , intermediarySignatureOnIngridBobFreeBalanceAppActivation ) ; await store . setCommitment ( [ Protocol . Update , stateChannelWithIntermediary . freeBalance . identityHash ] , freeBalanceIngridBobVirtualAppAgreementActivationCommitment . getSignedTransaction ( [ intermediarySignatureOnIngridBobFreeBalanceAppActivation , responderSignatureOnIngridBobFreeBalanceAppActivation ] ) ) ; const virtualAppSetStateCommitment = new SetStateCommitment ( network , virtualAppInstance . identity , virtualAppInstance . hashOfLatestState , virtualAppInstance . versionNumber , virtualAppInstance . defaultTimeout ) ; const timeLockedPassThroughSetStateCommitment = new SetStateCommitment ( network , timeLockedPassThroughAppInstance . identity , timeLockedPassThroughAppInstance . hashOfLatestState , timeLockedPassThroughAppInstance . versionNumber , timeLockedPassThroughAppInstance . defaultTimeout ) ; assertIsValidSignature ( intermediaryAddress , timeLockedPassThroughSetStateCommitment , intermediarySignatureOnTimeLockedPassThroughSetStateCommitment ) ; assertIsValidSignature ( initiatorAddress , timeLockedPassThroughSetStateCommitment , initiatorSignatureOnTimeLockedPassThroughSetStateCommitment ) ; assertIsValidSignature ( initiatorAddress , virtualAppSetStateCommitment , initiatorSignatureOnVirtualAppSetStateCommitment ) ; const responderSignatureOnTimeLockedPassThroughSetStateCommitment = yield [ OP_SIGN , timeLockedPassThroughSetStateCommitment ] ; const responderSignatureOnVirtualAppSetStateCommitment = yield [ OP_SIGN , virtualAppSetStateCommitment ] ; await store . setCommitment ( [ Protocol . Update , timeLockedPassThroughAppInstance . identityHash ] , timeLockedPassThroughSetStateCommitment . getSignedTransaction ( [ initiatorSignatureOnTimeLockedPassThroughSetStateCommitment , responderSignatureOnTimeLockedPassThroughSetStateCommitment , intermediarySignatureOnTimeLockedPassThroughSetStateCommitment ] ) ) ; await store . setCommitment ( [ Protocol . Update , virtualAppInstance . identityHash ] , virtualAppSetStateCommitment . getSignedTransaction ( [ initiatorSignatureOnVirtualAppSetStateCommitment , responderSignatureOnVirtualAppSetStateCommitment ] ) ) ; const m7 = { protocol , processID , toXpub : intermediaryXpub , seq : UNASSIGNED_SEQ_NO , customData : { signature : responderSignatureOnTimeLockedPassThroughSetStateCommitment , signature2 : responderSignatureOnVirtualAppSetStateCommitment } } as ProtocolMessage ; yield [ IO_SEND , m7 ] ; await store . saveStateChannel ( stateChannelWithIntermediary ) ; await store . saveStateChannel ( stateChannelWithRespondingAndIntermediary ) ; await store . saveStateChannel ( stateChannelWithInitiating ) ; } } ; function computeInterpreterParameters ( outcomeType , initiatingAddress , respondingAddress , initiatingBalanceDecrement , respondingBalanceDecrement , tokenAddress ) { const multiAssetMultiPartyCoinTransferInterpreterParams = undefined ; let twoPartyOutcomeInterpreterParams = undefined ; let singleAssetTwoPartyCoinTransferInterpreterParams = undefined ; if ( outcomeType === undefined ) { throw Error ( "This really should have been caught earlier" ) ; } switch ( outcomeType ) { case OutcomeType . TWO_PARTY_FIXED_OUTCOME : { twoPartyOutcomeInterpreterParams = { tokenAddress , playerAddrs : [ initiatingAddress , respondingAddress ] , amount : initiatingBalanceDecrement . add ( respondingBalanceDecrement ) . toHexString ( ) } ; break ; } case OutcomeType . SINGLE_ASSET_TWO_PARTY_COIN_TRANSFER : { singleAssetTwoPartyCoinTransferInterpreterParams = { tokenAddress , limit : initiatingBalanceDecrement . add ( respondingBalanceDecrement ) . toHexString ( ) } ; break ; } default : { throw Error ( `Not supported, and weird outcome type: ${ outcomeType }` ) ; } } return { multiAssetMultiPartyCoinTransferInterpreterParams , twoPartyOutcomeInterpreterParams , singleAssetTwoPartyCoinTransferInterpreterParams } ; } param { StateChannel } stateChannelBetweenEndpoints param { InstallVirtualAppParams } params returns { AppInstance } function constructVirtualAppInstance ( params ) { const { initiatorXpub , responderXpub , defaultTimeout , appInterface , initialState , outcomeType , initiatorBalanceDecrement , responderBalanceDecrement , tokenAddress , appSeqNo } = params ; const initiatorAddress = xkeyKthAddress ( initiatorXpub , appSeqNo ) ; const responderAddress = xkeyKthAddress ( responderXpub , appSeqNo ) ; const { multiAssetMultiPartyCoinTransferInterpreterParams , twoPartyOutcomeInterpreterParams , singleAssetTwoPartyCoinTransferInterpreterParams } = computeInterpreterParameters ( outcomeType , initiatorAddress , responderAddress , initiatorBalanceDecrement , responderBalanceDecrement , tokenAddress ) ; return new AppInstance ( sortAddresses ( [ initiatorAddress , responderAddress ] ) , defaultTimeout , appInterface , true , appSeqNo , initialState , 0 , defaultTimeout , outcomeType , twoPartyOutcomeInterpreterParams , multiAssetMultiPartyCoinTransferInterpreterParams , singleAssetTwoPartyCoinTransferInterpreterParams ) ; } param { StateChannel } threePartyStateChannel param { InstallVirtualAppParams } params returns { AppInstance } function constructTimeLockedPassThroughAppInstance ( threePartyStateChannel , virtualAppInstanceIdentityHash , virtualAppDefaultOutcome , network , params ) { const { intermediaryXpub , initiatorXpub , responderXpub , initiatorBalanceDecrement , responderBalanceDecrement , outcomeType , tokenAddress } = params ; const seqNo = threePartyStateChannel . numProposedApps ; const intermediaryAddress = xkeyKthAddress ( intermediaryXpub , seqNo ) ; const initiatorAddress = xkeyKthAddress ( initiatorXpub , seqNo ) ; const responderAddress = xkeyKthAddress ( responderXpub , seqNo ) ; const HARD_CODED_CHALLENGE_TIMEOUT = 100 ; const { multiAssetMultiPartyCoinTransferInterpreterParams , twoPartyOutcomeInterpreterParams , singleAssetTwoPartyCoinTransferInterpreterParams } = computeInterpreterParameters ( outcomeType , initiatorAddress , responderAddress , initiatorBalanceDecrement , responderBalanceDecrement , tokenAddress ) ; return new AppInstance ( sortAddresses ( [ initiatorAddress , responderAddress , intermediaryAddress ] ) , HARD_CODED_CHALLENGE_TIMEOUT , { stateEncoding : `
        tuple(
          address challengeRegistryAddress,
          bytes32 targetAppIdentityHash,
          uint256 switchesOutcomeAt,
          bytes defaultOutcome
        )
      ` , actionEncoding : undefined , addr : network . TimeLockedPassThrough } , true , seqNo , { challengeRegistryAddress : network . ChallengeRegistry , targetAppIdentityHash : virtualAppInstanceIdentityHash , switchesOutcomeAt : MaxUint256 , defaultOutcome : virtualAppDefaultOutcome } , 0 , HARD_CODED_CHALLENGE_TIMEOUT , outcomeType , twoPartyOutcomeInterpreterParams , multiAssetMultiPartyCoinTransferInterpreterParams , singleAssetTwoPartyCoinTransferInterpreterParams ) ; } param { { [ multisigAddress : string ] : StateChannelJSON } } stateChannelsMap param { [ string , string ] } userXpubs param { NetworkContext } network returns { StateChannel } function getOrCreateStateChannelWithUsers ( stateChannelsMap , userXpubs , network ) { const multisigAddress = getCreate2MultisigAddress ( userXpubs , network . ProxyFactory , network . MinimumViableMultisig ) ; return stateChannelsMap [ multisigAddress ] ? StateChannel . fromJson ( stateChannelsMap [ multisigAddress ] ) : StateChannel . createEmptyChannel ( multisigAddress , userXpubs ) ; } async function getUpdatedStateChannelAndVirtualAppObjectsForInitiating ( params , stateChannelsMap , network , provider ) { const { initiatorBalanceDecrement , responderBalanceDecrement , tokenAddress , initiatorXpub , intermediaryXpub , responderXpub } = params as InstallVirtualAppParams ; const stateChannelWithAllThreeParties = getOrCreateStateChannelWithUsers ( stateChannelsMap , [ initiatorXpub , responderXpub , intermediaryXpub ] , network ) ; const stateChannelWithResponding = getOrCreateStateChannelWithUsers ( stateChannelsMap , [ initiatorXpub , responderXpub ] , network ) ; const virtualAppInstance = constructVirtualAppInstance ( params ) ; const timeLockedPassThroughAppInstance = await constructTimeLockedPassThroughAppInstance ( stateChannelWithAllThreeParties , virtualAppInstance . identityHash , await virtualAppInstance . computeOutcomeWithCurrentState ( provider ) , network , params ) ; const initiatorAddress = xkeyKthAddress ( initiatorXpub , 0 ) ; const intermediaryAddress = xkeyKthAddress ( intermediaryXpub , 0 ) ; const stateChannelWithIntermediary = StateChannel . fromJson ( stateChannelsMap [ getCreate2MultisigAddress ( [ initiatorXpub , intermediaryXpub ] , network . ProxyFactory , network . MinimumViableMultisig ) ] ) ; if ( ! stateChannelWithIntermediary ) { throw Error ( "Cannot run InstallVirtualAppProtocol without existing channel with intermediary" ) ; } const newStateChannelWithIntermediary = stateChannelWithIntermediary . addSingleAssetTwoPartyIntermediaryAgreement ( virtualAppInstance . identityHash , { tokenAddress , timeLockedPassThroughIdentityHash : timeLockedPassThroughAppInstance . identityHash , capitalProvided : bigNumberify ( initiatorBalanceDecrement ) . add ( responderBalanceDecrement ) . toHexString ( ) , capitalProvider : intermediaryAddress , virtualAppUser : initiatorAddress } , { [ initiatorAddress ] : initiatorBalanceDecrement , [ intermediaryAddress ] : responderBalanceDecrement } , tokenAddress ) ; return [ stateChannelWithAllThreeParties . addAppInstance ( timeLockedPassThroughAppInstance ) , stateChannelWithResponding . addAppInstance ( virtualAppInstance ) , newStateChannelWithIntermediary , virtualAppInstance , timeLockedPassThroughAppInstance ] ; } async function getUpdatedStateChannelAndVirtualAppObjectsForIntermediary ( params , stateChannelsMap , virtualAppInstanceIdentityHash , virtualAppInstanceDefaultOutcome , network ) { const { initiatorBalanceDecrement , responderBalanceDecrement , initiatorXpub , intermediaryXpub , responderXpub , tokenAddress } = params as InstallVirtualAppParams ; const stateChannelWithAllThreeParties = getOrCreateStateChannelWithUsers ( stateChannelsMap , [ initiatorXpub , responderXpub , intermediaryXpub ] , network ) ; const timeLockedPassThroughAppInstance = await constructTimeLockedPassThroughAppInstance ( stateChannelWithAllThreeParties , virtualAppInstanceIdentityHash , virtualAppInstanceDefaultOutcome , network , params ) ; const channelWithInitiating = StateChannel . fromJson ( stateChannelsMap [ getCreate2MultisigAddress ( [ initiatorXpub , intermediaryXpub ] , network . ProxyFactory , network . MinimumViableMultisig ) ] ) ; if ( ! channelWithInitiating ) { throw Error ( "Cannot mediate InstallVirtualAppProtocol without mediation channel to initiator" ) ; } const channelWithResponding = StateChannel . fromJson ( stateChannelsMap [ getCreate2MultisigAddress ( [ responderXpub , intermediaryXpub ] , network . ProxyFactory , network . MinimumViableMultisig ) ] ) ; if ( ! channelWithResponding ) { throw Error ( "Cannot mediate InstallVirtualAppProtocol without mediation channel to responder" ) ; } const initiatorAddress = xkeyKthAddress ( initiatorXpub , 0 ) ; const intermediaryAddress = xkeyKthAddress ( intermediaryXpub , 0 ) ; const responderAddress = xkeyKthAddress ( responderXpub , 0 ) ; return [ stateChannelWithAllThreeParties . addAppInstance ( timeLockedPassThroughAppInstance ) , channelWithInitiating . addSingleAssetTwoPartyIntermediaryAgreement ( virtualAppInstanceIdentityHash , { tokenAddress , timeLockedPassThroughIdentityHash : timeLockedPassThroughAppInstance . identityHash , capitalProvided : bigNumberify ( initiatorBalanceDecrement ) . add ( responderBalanceDecrement ) . toHexString ( ) , capitalProvider : intermediaryAddress , virtualAppUser : initiatorAddress } , { [ initiatorAddress ] : initiatorBalanceDecrement , [ intermediaryAddress ] : responderBalanceDecrement } , tokenAddress ) , channelWithResponding . addSingleAssetTwoPartyIntermediaryAgreement ( virtualAppInstanceIdentityHash , { tokenAddress , timeLockedPassThroughIdentityHash : timeLockedPassThroughAppInstance . identityHash , capitalProvided : bigNumberify ( initiatorBalanceDecrement ) . add ( responderBalanceDecrement ) . toHexString ( ) , capitalProvider : intermediaryAddress , virtualAppUser : responderAddress } , { [ intermediaryAddress ] : initiatorBalanceDecrement , [ responderAddress ] : responderBalanceDecrement } , tokenAddress ) , timeLockedPassThroughAppInstance ] ; } async function getUpdatedStateChannelAndVirtualAppObjectsForResponding ( params , stateChannelsMap , network , provider ) { const { initiatorBalanceDecrement , responderBalanceDecrement , initiatorXpub , intermediaryXpub , responderXpub , tokenAddress } = params as InstallVirtualAppParams ; const stateChannelWithAllThreeParties = getOrCreateStateChannelWithUsers ( stateChannelsMap , [ initiatorXpub , responderXpub , intermediaryXpub ] , network ) ; const stateChannelWithInitiating = getOrCreateStateChannelWithUsers ( stateChannelsMap , [ initiatorXpub , responderXpub ] , network ) ; const virtualAppInstance = constructVirtualAppInstance ( params ) ; const timeLockedPassThroughAppInstance = await constructTimeLockedPassThroughAppInstance ( stateChannelWithAllThreeParties , virtualAppInstance . identityHash , await virtualAppInstance . computeOutcomeWithCurrentState ( provider ) , network , params ) ; const stateChannelWithIntermediary = StateChannel . fromJson ( stateChannelsMap [ getCreate2MultisigAddress ( [ responderXpub , intermediaryXpub ] , network . ProxyFactory , network . MinimumViableMultisig ) ] ) ; if ( ! stateChannelWithIntermediary ) { throw Error ( "Cannot run InstallVirtualAppProtocol without existing channel with intermediary" ) ; } const intermediaryAddress = xkeyKthAddress ( intermediaryXpub , 0 ) ; const responderAddress = xkeyKthAddress ( responderXpub , 0 ) ; return [ stateChannelWithAllThreeParties . addAppInstance ( timeLockedPassThroughAppInstance ) , stateChannelWithInitiating . addAppInstance ( virtualAppInstance ) , stateChannelWithIntermediary . addSingleAssetTwoPartyIntermediaryAgreement ( virtualAppInstance . identityHash , { tokenAddress , timeLockedPassThroughIdentityHash : timeLockedPassThroughAppInstance . identityHash , capitalProvided : bigNumberify ( initiatorBalanceDecrement ) . add ( responderBalanceDecrement ) . toHexString ( ) , capitalProvider : intermediaryAddress , virtualAppUser : responderAddress } , { [ intermediaryAddress ] : initiatorBalanceDecrement , [ responderAddress ] : responderBalanceDecrement } , tokenAddress ) , virtualAppInstance , timeLockedPassThroughAppInstance ] ; }