import { SignedStateWithHash , serializeAllocation , checkThat , isAllocation , Participant , Address , Destination , SignedStateVarsWithHash , isSimpleAllocation , BN , } from '@statechannels/wallet-core' ; import { ChannelResult , ChannelStatus , FundingStatus , FundingStrategy , } from '@statechannels/client-api-schema' ; import _ from 'lodash' ; import { Bytes32 , Uint256 } from '../type-aliases' ; import { ChainServiceRequest } from '../models/chain-service-request' ; import { AdjudicatorStatus } from '../models/adjudicator-status' ; export type ChannelStateFunding = { amount : Uint256 ; transferredOut : { toAddress : Destination ; amount : Uint256 ; } [ ] ; } ; export type ChannelState = { channelId : string ; myIndex : 0 | 1 ; participants : Participant [ ] ; support ? : SignedStateWithHash [ ] ; supported ? : SignedStateWithHash ; latest : SignedStateWithHash ; latestSignedByMe ? : SignedStateWithHash ; funding : ( address : Address ) => ChannelStateFunding | undefined ; chainServiceRequests : ChainServiceRequest [ ] ; fundingStrategy : FundingStrategy ; fundingLedgerChannelId ? : Bytes32 ; directFundingStatus ? : FundingStatus ; adjudicatorStatus : AdjudicatorStatus [ 'channelMode' ] ; } ; type WithSupported = { supported : SignedStateWithHash ; } ; type SignedByMe = { latestSignedByMe : SignedStateWithHash ; } ; export type ChannelStateWithMe = ChannelState & SignedByMe ; export type ChannelStateWithSupported = ChannelState & SignedByMe & WithSupported ; /**
 * The definition of a ChannelStatus is still under debate, but for now
 * this is what we have settled on. Future changes should include 'funding',
 * 'defunding', and state related to challenging, probably. See this issue
 * for more: https://github.com/statechannels/statechannels/issues/2509
 */ export const status = ( channelState ) : ChannelStatus => { const { supported , latest , latestSignedByMe , support } = channelState ; const { participants } = latest ; if ( ! supported ) { if ( ! latestSignedByMe ) return 'proposed' ; return 'opening' ; } if ( supported . isFinal ) { if ( _ . every ( support , 'isFinal' ) ) return 'closed' ; return 'closing' ; } if ( supported . turnNum < 2 * participants . length - 1 ) return 'opening' ; return 'running' ; } ; export const toChannelResult = ( channelState ) : ChannelResult => { const { channelId , supported , latest , directFundingStatus , adjudicatorStatus } = channelState ; const { outcome , appData , turnNum , participants , appDefinition } = supported ?? latest ; return { appData , appDefinition , channelId , participants , turnNum , allocations : serializeAllocation ( checkThat ( outcome , isAllocation ) ) , status : status ( channelState ) , fundingStatus : directFundingStatus , adjudicatorStatus , } ; } ; export function directFundingStatus ( supported , fundingFn , myParticipant , fundingStrategy ) { if ( fundingStrategy === 'Fake' ) { if ( ! supported ) return 'Uncategorized' ; if ( supported . turnNum < 3 ) return 'ReadyToFund' ; return 'Funded' ; } if ( fundingStrategy !== 'Direct' ) { return 'Uncategorized' ; } const outcome = supported ?. outcome ; if ( ! supported || ! outcome ) { return 'Uncategorized' ; } const { allocationItems , asset } = checkThat ( outcome , isSimpleAllocation ) ; const myDestination = myParticipant . destination ; const myAmount = allocationItems . filter ( ai => ai . destination === myDestination ) . map ( ai => ai . amount ) . reduce ( BN . add , BN . from ( 0 ) ) ; const funding = fundingFn ( asset ) ; if ( ! funding ) return undefined ; const amountTransferredToMe = funding . transferredOut . filter ( tf => tf . toAddress === myDestination ) . map ( ai => ai . amount ) . reduce ( BN . add , BN . from ( 0 ) ) ; const amountTransferredToAll = funding . transferredOut . map ( ai => ai . amount ) . reduce ( BN . add , BN . from ( 0 ) ) ; if ( supported . isFinal && BN . gte ( amountTransferredToMe , myAmount ) ) { return 'Defunded' ; } const fullFunding = allocationItems . map ( a => a . amount ) . reduce ( BN . add , BN . from ( 0 ) ) ; if ( BN . eq ( amountTransferredToMe , 0 ) && BN . gte ( funding . amount , fullFunding ) ) { return 'Funded' ; } const myAllocationIndex = _ . findIndex ( allocationItems , ai => ai . destination === myDestination ) ; const allocationsBeforeMe = allocationItems . slice ( 0 , myAllocationIndex ) ; const allocationsWithMe = allocationItems . slice ( 0 , myAllocationIndex + 1 ) ; const fundingBeforeMe = allocationsBeforeMe . map ( a => a . amount ) . reduce ( BN . add , BN . from ( 0 ) ) ; const fundingWithMe = allocationsWithMe . map ( a => a . amount ) . reduce ( BN . add , BN . from ( 0 ) ) ; if ( BN . eq ( amountTransferredToAll , 0 ) && BN . gte ( funding . amount , fundingBeforeMe ) && BN . lt ( funding . amount , fundingWithMe ) ) { return 'ReadyToFund' ; } return 'Uncategorized' ; }