diff --git a/packages/local-ganache-server/src/contract-deployments.jest.ts b/packages/local-ganache-server/src/contract-deployments.jest.ts index 4ccbbf109..cc9d9a097 100644 --- a/packages/local-ganache-server/src/contract-deployments.jest.ts +++ b/packages/local-ganache-server/src/contract-deployments.jest.ts @@ -25,102 +25,67 @@ export type NetworkContextForTestSuite = NetworkContext & { SimpleTransferApp: string; }; -export async function deployTestArtifactsToChain(wallet: Wallet) { - const coinBalanceRefundContract = await new ContractFactory( - CoinBalanceRefundApp.abi, - CoinBalanceRefundApp.evm.bytecode, +export async function deployed(artifacts: any, wallet: Wallet) { + const contract = await new ContractFactory( + artifacts.abi, + artifacts.evm.bytecode, wallet ).deploy(); - const dolphinCoin = await new ContractFactory( - DolphinCoin.abi, - DolphinCoin.evm.bytecode, - wallet - ).deploy(); + await contract.deployed(); + return contract; +} - const identityApp = await new ContractFactory( - IdentityApp.abi, - IdentityApp.evm.bytecode, +export async function deployTestArtifactsToChain(wallet: Wallet) { + const coinBalanceRefundContract = await deployed( + CoinBalanceRefundApp, wallet - ).deploy(); + ); - const mvmContract = await new ContractFactory( - MinimumViableMultisig.abi, - MinimumViableMultisig.evm.bytecode, - wallet - ).deploy(); + const dolphinCoin = await deployed(DolphinCoin, wallet); - const proxyFactoryContract = await new ContractFactory( - ProxyFactory.abi, - ProxyFactory.evm.bytecode, - wallet - ).deploy(); + const identityApp = await deployed(IdentityApp, wallet); - const coinTransferETHInterpreter = await new ContractFactory( - MultiAssetMultiPartyCoinTransferInterpreter.abi, - MultiAssetMultiPartyCoinTransferInterpreter.evm.bytecode, - wallet - ).deploy(); + const mvmContract = await deployed(MinimumViableMultisig, wallet); - const twoPartyFixedOutcomeInterpreter = await new ContractFactory( - TwoPartyFixedOutcomeInterpreter.abi, - TwoPartyFixedOutcomeInterpreter.evm.bytecode, - wallet - ).deploy(); + const proxyFactoryContract = await deployed(ProxyFactory, wallet); - const challengeRegistry = await new ContractFactory( - ChallengeRegistry.abi, - ChallengeRegistry.evm.bytecode, + const coinTransferETHInterpreter = await deployed( + MultiAssetMultiPartyCoinTransferInterpreter, wallet - ).deploy(); + ); - const conditionalTransactionDelegateTarget = await new ContractFactory( - ConditionalTransactionDelegateTarget.abi, - ConditionalTransactionDelegateTarget.evm.bytecode, + const twoPartyFixedOutcomeInterpreter = await deployed( + TwoPartyFixedOutcomeInterpreter, wallet - ).deploy(); + ); - const twoPartyFixedOutcomeFromVirtualAppETHInterpreter = await new ContractFactory( - TwoPartyFixedOutcomeFromVirtualAppInterpreter.abi, - TwoPartyFixedOutcomeFromVirtualAppInterpreter.evm.bytecode, - wallet - ).deploy(); + const challengeRegistry = await deployed(ChallengeRegistry, wallet); - const tttContract = await new ContractFactory( - TicTacToeApp.abi, - TicTacToeApp.evm.bytecode, + const conditionalTransactionDelegateTarget = await deployed( + ConditionalTransactionDelegateTarget, wallet - ).deploy(); + ); - const transferContract = await new ContractFactory( - UnidirectionalTransferApp.abi, - UnidirectionalTransferApp.evm.bytecode, + const twoPartyFixedOutcomeFromVirtualAppETHInterpreter = await deployed( + TwoPartyFixedOutcomeFromVirtualAppInterpreter, wallet - ).deploy(); + ); - const simpleTransferContract = await new ContractFactory( - SimpleTransferApp.abi, - SimpleTransferApp.evm.bytecode, - wallet - ).deploy(); + const tttContract = await deployed(TicTacToeApp, wallet); - const linkContract = await new ContractFactory( - UnidirectionalLinkedTransferApp.abi, - UnidirectionalLinkedTransferApp.evm.bytecode, - wallet - ).deploy(); + const transferContract = await deployed(UnidirectionalTransferApp, wallet); - const timeLockedPassThrough = await new ContractFactory( - TimeLockedPassThrough.abi, - TimeLockedPassThrough.evm.bytecode, - wallet - ).deploy(); + const simpleTransferContract = await deployed(SimpleTransferApp, wallet); - const singleAssetTwoPartyCoinTransferInterpreter = await new ContractFactory( - SingleAssetTwoPartyCoinTransferInterpreter.abi, - SingleAssetTwoPartyCoinTransferInterpreter.evm.bytecode, + const linkContract = await deployed(UnidirectionalLinkedTransferApp, wallet); + + const timeLockedPassThrough = await deployed(TimeLockedPassThrough, wallet); + + const singleAssetTwoPartyCoinTransferInterpreter = await deployed( + SingleAssetTwoPartyCoinTransferInterpreter, wallet - ).deploy(); + ); return { ChallengeRegistry: challengeRegistry.address, diff --git a/packages/local-ganache-server/src/index.ts b/packages/local-ganache-server/src/index.ts index 1dfe13cea..af63d2ae4 100644 --- a/packages/local-ganache-server/src/index.ts +++ b/packages/local-ganache-server/src/index.ts @@ -59,7 +59,10 @@ export class LocalGanacheServer { this.server = ganache.server({ accounts, gasLimit: 17592186044415, // 0xfffffffffff - gasPrice: "0x01" + gasPrice: "0x01", + blockTime: process.env.GANACHE_BLOCK_TIME + ? parseInt(process.env.GANACHE_BLOCK_TIME!, 10) + : undefined }); this.server.listen(parseInt(process.env.GANACHE_PORT!, 10)); diff --git a/packages/node/.env.defaults b/packages/node/.env.defaults index 9f2524198..07accb0ed 100644 --- a/packages/node/.env.defaults +++ b/packages/node/.env.defaults @@ -4,6 +4,7 @@ FIREBASE_MESSAGING_SERVER_KEY="messageKey" FIREBASE_STORE_SERVER_KEY="storeKey" FIREBASE_STORE_PREFIX_KEY="dev-store" GANACHE_PORT="8545" +GANACHE_BLOCK_TIME="" POSTGRES_USER="postgres" POSTGRES_HOST="localhost" POSTGRES_DATABASE="postgres" diff --git a/packages/node/.env.schema b/packages/node/.env.schema index 21df052e3..53b594718 100644 --- a/packages/node/.env.schema +++ b/packages/node/.env.schema @@ -4,3 +4,4 @@ FIREBASE_MESSAGING_SERVER_KEY= FIREBASE_STORE_SERVER_KEY= FIREBASE_STORE_PREFIX_KEY= GANACHE_PORT= +GANACHE_BLOCK_TIME= \ No newline at end of file diff --git a/packages/node/test/integration/unobtrusive-collateralize.spec.ts b/packages/node/test/integration/unobtrusive-collateralize.spec.ts new file mode 100644 index 000000000..bc3e03f0e --- /dev/null +++ b/packages/node/test/integration/unobtrusive-collateralize.spec.ts @@ -0,0 +1,101 @@ +import { NetworkContextForTestSuite } from "@counterfactual/local-ganache-server"; +import { One } from "ethers/constants"; +import { parseEther } from "ethers/utils"; + +import { Node } from "../../src"; +import { CONVENTION_FOR_ETH_TOKEN_ADDRESS } from "../../src/constants"; +import { NODE_EVENTS, ProposeMessage, InstallMessage } from "../../src/types"; +import { toBeLt } from "../machine/integration/bignumber-jest-matcher"; + +import { setup, SetupContext } from "./setup"; +import { + collateralizeChannel, + createChannel, + deposit, + makeInstallCall, + makeProposeCall +} from "./utils"; + +expect.extend({ toBeLt }); + +jest.setTimeout(45000); + +const { TicTacToeApp } = global["networkContext"] as NetworkContextForTestSuite; + +/** + * This should be tested without using automine! GANACHE_BLOCK_TIME variable + * should be defined and >= 1 + */ +describe("Should be able to update the free balance app (deposit/withdraw) without interrupting flow of other apps (install/uninstall)", () => { + let multisigAddress: string; + let nodeA: Node; + let nodeB: Node; + beforeEach(async () => { + // create channel + const context: SetupContext = await setup(global); + console.log(`setup complete`); + nodeA = context["A"].node; + nodeB = context["B"].node; + + multisigAddress = await createChannel(nodeA, nodeB); + + // add some initial balance + await collateralizeChannel(multisigAddress, nodeA, nodeB, parseEther("2")); + }); + + it("should be able to deposit additional collateral into channel while installing an app", async done => { + let completedEvents = 0; + let nonDepositAppId; + + const verifyAndExit = () => { + completedEvents += 1; + if (completedEvents === 2) { + done(); + } + }; + + nodeB.on(NODE_EVENTS.PROPOSE_INSTALL, async (msg: ProposeMessage) => { + console.log(`installing non-deposit app`); + nonDepositAppId = msg.data.appInstanceId; + await makeInstallCall(nodeB, msg.data.appInstanceId); + }); + + nodeA.on(NODE_EVENTS.INSTALL, (msg: InstallMessage) => { + if (msg.data.params.appInstanceId !== nonDepositAppId) { + // is the deposit app, dont count in the completed + console.log(`installed deposit app`); + return; + } + console.log(`installed non-deposit app`); + verifyAndExit(); + }); + + nodeB.on(NODE_EVENTS.DEPOSIT_STARTED, () => { + console.log(`deposit started`); + }); + + nodeA.on(NODE_EVENTS.DEPOSIT_CONFIRMED, () => { + console.log(`deposit finished`); + if (!nonDepositAppId) { + // still hasnt tried installing channel app, + // force test failure + expect(`Could not install app with deposit in progress`).toBeNull(); + } + verifyAndExit(); + }); + + const installRpc = makeProposeCall( + nodeB, + TicTacToeApp, + undefined, + One, + CONVENTION_FOR_ETH_TOKEN_ADDRESS, + One, + CONVENTION_FOR_ETH_TOKEN_ADDRESS + ); + + // wait for deposit to progress + await deposit(nodeB, multisigAddress); + nodeA.rpcRouter.dispatch(installRpc); + }); +});