import { Either , left , right , chain , map } from 'fp-ts/lib/Either' ; import { StateVariables , Outcome } from '@statechannels/wallet-core' ; import { pipe } from 'fp-ts/lib/function' ; import { ChannelId } from '@statechannels/client-api-schema' ; import { SignState , signState } from '../protocols/actions' ; import { ChannelState , ChannelStateWithSupported } from '../protocols/state' ; import { EngineError , Values } from '../errors/engine-error' ; import { hasSupportedState , isMyTurn } from './helpers' ; type StepResult = Either < UpdateChannelError , ChannelStateWithSupported > ; type UpdateChannelResult = Either < UpdateChannelError , SignState > ; export interface UpdateChannelHandlerParams { channelId : ChannelId ; outcome : Outcome ; appData : string ; } export class UpdateChannelError extends EngineError { readonly type = EngineError . errors . UpdateChannelError ; static readonly reasons = { channelNotFound : 'channel not found' , invalidLatestState : 'must have latest state' , notInRunningStage : 'channel must be in running state' , notMyTurn : 'it is not my turn' , } as const ; constructor ( reason , public readonly data = undefined ) { super ( reason ) ; } } const ensureSupportedStateExists = ( cs ) : Either < UpdateChannelError , ChannelStateWithSupported > => hasSupportedState ( cs ) ? right ( cs ) : left ( new UpdateChannelError ( UpdateChannelError . reasons . invalidLatestState ) ) ; function ensureItIsMyTurn ( cs ) { if ( isMyTurn ( cs ) ) return right ( cs ) ; return left ( new UpdateChannelError ( UpdateChannelError . reasons . notMyTurn ) ) ; } function hasRunningTurnNumber ( cs ) { if ( cs . supported . turnNum < 3 ) return left ( new UpdateChannelError ( UpdateChannelError . reasons . notInRunningStage ) ) ; return right ( cs ) ; } const incrementTurnNumber = ( args ) => ( cs ) : StateVariables => ( { ... args , turnNum : cs . supported . turnNum + 1 , isFinal : false , } ) ; export function updateChannel ( args , channelState ) { const signStateVars = ( sv ) : SignState => signState ( { ... sv , channelId : args . channelId } ) ; return pipe ( channelState , ensureSupportedStateExists , chain ( hasRunningTurnNumber ) , chain ( ensureItIsMyTurn ) , map ( incrementTurnNumber ( args ) ) , map ( signStateVars ) ) ; }