import { simpleEthAllocation , makeDestination , calculateChannelId , createSignatureEntry , State , Objective , BN , makeAddress } from '@statechannels/wallet-core' ; import { Wallet } from 'ethers' ; import { ChannelStoreEntry } from '../channel-store-entry' ; import { MemoryBackend as Backend } from '../memory-backend' ; import { CHAIN_NETWORK_ID , CHALLENGE_DURATION , WALLET_VERSION } from '../../config' ; import { Errors } from '..' ; import { Store } from './../store' ; const { address : aAddress , privateKey : aPrivateKey } = new Wallet ( '0x95942b296854c97024ca3145abef8930bf329501b718c0f66d57dba596ff1318' ) ; const { address : bAddress , privateKey : bPrivateKey } = new Wallet ( '0xb3ab7b031311fe1764b657a6ae7133f19bac97acd1d7edca9409daa35892e727' ) ; const [ aDestination , bDestination ] = [ aAddress , bAddress ] . map ( makeDestination ) ; const outcome = simpleEthAllocation ( [ { destination : aDestination , amount : BN . from ( 5 ) } , { destination : bDestination , amount : BN . from ( 6 ) } ] ) ; const turnNum = 4 ; const appData = '0x0abc' ; const isFinal = false ; const chainId = CHAIN_NETWORK_ID ; const participants = [ { participantId : 'a' , destination : aDestination , signingAddress : makeAddress ( aAddress ) } , { participantId : 'b' , destination : bDestination , signingAddress : makeAddress ( bAddress ) } ] ; const stateVars = { outcome , turnNum , appData , isFinal } ; const channelNonce = 0 ; const appDefinition = makeAddress ( '0x5409ED021D9299bf6814279A6A1411A7e866A631' ) ; const challengeDuration = CHALLENGE_DURATION ; const channelConstants = { chainId , participants , channelNonce , appDefinition , challengeDuration } ; const state = { ... stateVars , ... channelConstants } ; const channelId = calculateChannelId ( channelConstants ) ; const signature = createSignatureEntry ( state , aPrivateKey ) ; const signedState = { ... state , signatures : [ signature ] } ; const signedStates = [ signedState ] ; const aStore = async ( noPrivateKeys = false ) => { const store = new Store ( undefined , new Backend ( ) ) ; const privateKeys = noPrivateKeys ? undefined : [ aPrivateKey ] ; await store . initialize ( privateKeys , true ) ; return store ; } ; describe ( 'getAddress' , ( ) => { it ( 'returns an address' , async ( ) => { const store = await aStore ( ) ; const address = await store . getAddress ( ) ; expect ( address ) . toEqual ( aAddress ) ; } ) ; } ) ; describe ( 'channelUpdatedFeed' , ( ) => { test ( 'it fires when a state with the correct channel id is received' , async ( ) => { const store = await aStore ( ) ; const outputs = [ ] ; store . channelUpdatedFeed ( channelId ) . subscribe ( x => { outputs . push ( x ) ; } ) ; await store . pushMessage ( { walletVersion : WALLET_VERSION , signedStates } ) ; expect ( outputs [ 0 ] . latest ) . toMatchObject ( state ) ; } ) ; test ( "it doesn't fire if the channelId doesn't match" , async ( ) => { const store = await aStore ( ) ; const outputs = [ ] ; store . channelUpdatedFeed ( 'a-different-channel-id' ) . subscribe ( x => outputs . push ( x ) ) ; await store . pushMessage ( { walletVersion : WALLET_VERSION , signedStates } ) ; expect ( outputs ) . toEqual ( [ ] ) ; } ) ; } ) ; test . skip ( 'newObjectiveFeed' , async ( ) => { const objective = { type : 'OpenChannel' , participants : [ ] , data : { targetChannelId : 'foo' , fundingStrategy : 'Direct' } } ; const store = await aStore ( ) ; const outputs = [ ] ; store . objectiveFeed . subscribe ( x => outputs . push ( x ) ) ; await store . pushMessage ( { walletVersion : WALLET_VERSION , objectives : [ objective ] } ) ; expect ( outputs ) . toEqual ( [ objective ] ) ; await store . pushMessage ( { walletVersion : WALLET_VERSION , objectives : [ objective ] } ) ; expect ( outputs ) . toEqual ( [ objective ] ) ; } ) ; describe ( 'createChannel' , ( ) => { it ( 'returns a channel-store-entry' , async ( ) => { const store = await aStore ( ) ; const firstEntry = await store . createChannel ( participants , challengeDuration , stateVars , appDefinition ) ; expect ( firstEntry . channelId ) . toMatch ( /0x/ ) ; const secondEntry = await store . createChannel ( participants , challengeDuration , stateVars , appDefinition ) ; expect ( firstEntry . channelId ) . not . toEqual ( secondEntry . channelId ) ; } ) ; it ( "fails if the wallet doesn't hold the private key for any participant" , async ( ) => { const store = await aStore ( true ) ; await expect ( store . createChannel ( participants , challengeDuration , stateVars , appDefinition ) ) . rejects . toMatchObject ( { message : Errors . notInChannel } ) ; } ) ; } ) ; describe ( 'pushMessage' , ( ) => { it ( 'stores states' , async ( ) => { const store = await aStore ( ) ; await store . createChannel ( signedState . participants , signedState . challengeDuration , { ... signedState , turnNum : 0 } , signedState . appDefinition ) ; const nextState = { ... state , turnNum : state . turnNum + 2 } ; await store . pushMessage ( { walletVersion : WALLET_VERSION , signedStates : [ { ... nextState , signatures : [ createSignatureEntry ( nextState , bPrivateKey ) ] } ] } ) ; expect ( ( await store . getEntry ( channelId ) ) . latest ) . toMatchObject ( nextState ) ; } ) ; it ( 'creates a channel if it receives states for a new channel' , async ( ) => { const store = await aStore ( ) ; await store . pushMessage ( { walletVersion : WALLET_VERSION , signedStates } ) ; expect ( await store . getEntry ( channelId ) ) . not . toBeUndefined ( ) ; } ) ; } ) ;