import {Portfolio} from '@yoroi/types' import {freeze} from 'immer' function negate( amounts: Readonly, ): Readonly { return freeze( Object.fromEntries( Object.entries(amounts).map(([tokenId, amount]) => [ tokenId, { ...amount, quantity: -amount.quantity, }, ]), ), true, ) } function drop( amounts: Readonly, removeTokenIds: ReadonlyArray, ): Portfolio.Token.AmountRecords { return freeze( Object.fromEntries( Object.entries(amounts).filter( ([tokenId]) => !removeTokenIds.includes(tokenId as Portfolio.Token.Id), ), ), true, ) } function plus( amounts: ReadonlyArray, ): Readonly { const entries = amounts.map((amount) => Object.entries(amount)).flat() return freeze( entries.reduce((result, [id, {info, quantity}]) => { const tokenId = id as Portfolio.Token.Id result[tokenId] = { info, quantity: (result[tokenId]?.quantity ?? 0n) + quantity, } return result }, {} as Portfolio.Token.AmountRecords), true, ) } function minus( amounts1: Readonly, amounts2: Readonly, ): Readonly { const negatedAmounts2 = negate(amounts2) return freeze(plus([amounts1, negatedAmounts2]), true) } export const AmountsCalcultor = ( initialAmounts: Readonly = {}, ) => { let amounts = {...initialAmounts} const builder = { negate: () => { amounts = negate(amounts) return builder }, drop: (removeTokenIds: ReadonlyArray) => { amounts = drop(amounts, removeTokenIds) return builder }, plus: (newAmounts: Readonly) => { amounts = plus([amounts, newAmounts]) return builder }, minus: (newAmounts: Readonly) => { amounts = minus(amounts, newAmounts) return builder }, build: () => amounts, } return builder }