import _ from 'lodash' ; import { AllocationItem , BN , makeDestination , SimpleAllocation , Destination , } from '@statechannels/wallet-core' ; import { Uint256 } from '../../type-aliases' ; export class SimpleAllocationOutcome { private outcome : SimpleAllocation ; constructor ( outcome ) { this . outcome = outcome ; } public get destinations ( ) : Destination [ ] { return this . outcome . allocationItems . map ( i => i . destination ) ; } public balanceFor ( destination ) { return this . itemFor ( destination ) ?. amount ; } public get toLegacyAllocation ( ) : SimpleAllocation { return this . outcome ; } public get items ( ) : SimpleAllocation [ 'allocationItems' ] { return this . outcome . allocationItems ; } public dup ( ) { const newOutcome = _ . cloneDeep ( this . outcome ) ; return new SimpleAllocationOutcome ( newOutcome ) ; } public isEqualTo ( otherOutcome ) { return ( ! ! otherOutcome && this . outcome . type === otherOutcome . toLegacyAllocation . type && this . outcome . asset === otherOutcome . toLegacyAllocation . asset && _ . every ( _ . zip ( this . items , otherOutcome . items ) . map ( ( [ a , b ] ) => allocationItemsEqual ( a , b ) ) ) ) ; } public remove ( channelId , refundDestinations , refundAmounts ) { if ( refundDestinations . length !== refundAmounts . length ) throw new Error ( 'Destinations and amounts have different lengths' ) ; const itemToRemove = this . itemFor ( channelId ) ; const refundItems = refundDestinations . map ( d => this . itemFor ( d ) ) ; if ( ! itemToRemove || _ . some ( refundItems , _ . isUndefined ) ) return undefined ; if ( ! BN . eq ( itemToRemove . amount , refundAmounts . reduce ( BN . add ) ) ) return undefined ; _ . remove ( this . outcome . allocationItems , itemToRemove ) ; for ( const [ item , amt ] of _ . zip ( refundItems , refundAmounts ) ) { if ( item && amt ) { item . amount = BN . add ( item . amount , amt ) ; } } return this ; } private itemFor ( destination ) { return this . outcome . allocationItems . find ( i => i . destination === destination ) ; } public add ( channelId , fundingSources , fundingAmounts ) { if ( fundingSources . length !== fundingAmounts . length ) throw new Error ( 'Sources and amounts have different lengths' ) ; const sourceItems = fundingSources . map ( d => this . itemFor ( d ) ) ; for ( const [ item , amt ] of _ . zip ( sourceItems , fundingAmounts ) ) { if ( ! item ) return undefined ; if ( ! amt ) throw new Error ( 'More sources that amounts' ) ; if ( ! BN . gte ( item . amount , amt ) ) return undefined ; } this . outcome . allocationItems . push ( { destination : makeDestination ( channelId ) , amount : BN . from ( fundingAmounts . reduce ( BN . add ) ) , } ) ; for ( const [ item , amt ] of _ . zip ( sourceItems , fundingAmounts ) ) { if ( item && amt ) { item . amount = BN . sub ( item . amount , amt ) ; } } return this ; } } function allocationItemsEqual ( a , b ) { if ( a && b ) { return a . destination === b . destination && BN . eq ( a . amount , b . amount ) ; } else { return false ; } }