import { NetworkContextForTestSuite } from "@counterfactual/local-ganache-server" ; import { Address , AppInstanceJson } from "@counterfactual/types" ; import { One , Zero } from "ethers/constants" ; import { BigNumber , bigNumberify } from "ethers/utils" ; import { Node } from "../../src" ; import { initialSimpleTransferState } from "./simple-transfer" ; import { getAppInstance , getApps , installApp , installVirtualApp , takeAppAction , uninstallApp , uninstallVirtualApp } from "./utils" ; type UnidirectionalLinkedTransferAppAction = { amount : BigNumber ; assetId : Address ; paymentId : string ; preImage : string ; } ; type UnidirectionalLinkedTransferAppState = { linkedHash : string ; stage : number ; finalized : boolean ; turnNum : BigNumber ; transfers : CoinTransfer [ ] ; } ; type CoinTransfer = { to : Address ; amount : BigNumber ; } ; const { SimpleTransferApp , UnidirectionalLinkedTransferApp } = global [ "networkContext" ] as NetworkContextForTestSuite ; /**
 * This file contains any utils functions that are useful when testing
 * Connext specific applications and errors.
 *
 * Note: this does nothing to assert that the transfer exchanges the intended
 * amount. That is assumed to be tested in unit tests.
 */ export async function makeSimpleTransfer ( sender , intermediary , receiver , amount = One ) { const initialState = initialSimpleTransferState ( sender . freeBalanceAddress , receiver . freeBalanceAddress , amount ) ; const appId = await installVirtualApp ( sender , intermediary , receiver , SimpleTransferApp , initialState ) ; const senderApp = await getAppInstance ( sender , appId ) ; const receiverApp = await getAppInstance ( receiver , appId ) ; expect ( senderApp ) . toEqual ( receiverApp ) ; await uninstallVirtualApp ( sender , receiver , intermediary . publicIdentifier , appId ) ; } export async function installLink ( funder , redeemer , state , action ) { const linkDef = UnidirectionalLinkedTransferApp ; const res = await installApp ( funder , redeemer , linkDef , state , bigNumberify ( action . amount ) , action . assetId , Zero , action . assetId ) ; return res [ 0 ] ; } function assertLinkRedemption ( app , amount ) { expect ( ( app . latestState as UnidirectionalLinkedTransferAppState ) . finalized ) . toEqual ( true ) ; expect ( ( app . latestState as UnidirectionalLinkedTransferAppState ) . transfers [ 1 ] [ 1 ] ) . toBeEq ( amount ) ; expect ( ( app . latestState as UnidirectionalLinkedTransferAppState ) . transfers [ 0 ] [ 1 ] ) . toBeEq ( Zero ) ; } /**
 * Takes an action on an already installed link app to redeem the locked value
 * and uninstalls the app
 */ export async function redeemLink ( redeemer , funder , appId , action ) { await takeAppAction ( redeemer , appId , action ) ; const redeemerApp = await getAppInstance ( redeemer , appId ) ; assertLinkRedemption ( redeemerApp , action . amount ) ; return await uninstallApp ( redeemer , funder , appId ) ; } /**
 * Completes the "redeem flow":
 * 1. Matching app with intermediary and link funder found
 * 2. Redeemer and intermediary install a link app
 * 3. Redeemer takes action on the app to claim funds
 * 4. Intermediary takes action on matched app to reclaim funds
 */ export async function installAndRedeemLink ( funder , intermediary , redeemer , stateAndAction ) { const linkDef = UnidirectionalLinkedTransferApp ; const hubApps = await getApps ( intermediary ) ; const { state , action } = stateAndAction ; const hasAddressInTransfers = ( app , addr ) : boolean => { return ( ( app . latestState as UnidirectionalLinkedTransferAppState ) . transfers [ 0 ] . to === addr || ( app . latestState as UnidirectionalLinkedTransferAppState ) . transfers [ 1 ] . to === addr ) ; } ; const getMatchingHubApp = ( apps ) => { return apps . find ( app => app . appInterface . addr === linkDef && hasAddressInTransfers ( app , funder . freeBalanceAddress ) && ( app . latestState as UnidirectionalLinkedTransferAppState ) . linkedHash === state . linkedHash ) ; } ; const matchedApp = getMatchingHubApp ( hubApps ) ; expect ( matchedApp ) . toBeDefined ( ) ; const redeemerAppId = await installLink ( intermediary , redeemer , state , action ) ; await redeemLink ( redeemer , intermediary , redeemerAppId , action ) ; await redeemLink ( intermediary , funder , matchedApp ! . identityHash , action ) ; }