Skip to content
This repository has been archived by the owner on May 28, 2021. It is now read-only.

Commit

Permalink
🔀 Merge branch '1038-integrate-watcher' into staging
Browse files Browse the repository at this point in the history
  • Loading branch information
bohendo committed Aug 27, 2020
2 parents f127430 + 31daedf commit ea23957
Show file tree
Hide file tree
Showing 117 changed files with 2,304 additions and 1,659 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/cd-staging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -147,5 +147,5 @@ jobs:
export INDRA_DOMAINNAME="$STAGING_DOMAINNAME";
make restart-prod;
docker container prune -f;
docker image ls -q | xargs docker image rm || true;
docker image ls -q | xargs docker image rm -f || true;
'
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,10 @@ test-watcher: watcher
bash ops/test/watcher.sh

test-node: node
bash ops/test/node.sh
bash ops/test/node.sh test

watch-node:
bash ops/test/node.sh watch

test-tps: bot
bash ops/test/tps.sh 5 0 10
Expand Down
4 changes: 2 additions & 2 deletions docs/src/reference/watcher.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ type WatcherInitOptions = {
signer: IChannelSigner | string; // wallet or pk
provider: providers.JsonRpcProvider | string;
context: ContractAddresses;
store: IWatcherStoreService;
store: IStoreService;
logger?: ILoggerService | ILogger;
logLevel?: number;
};
Expand All @@ -130,7 +130,7 @@ The options object contains the following fields:
A json containing all the addresses across the relevant network (should be derived from your `address-book.json`). This will be shared with an internal instance of the ChainListener class.

- `store`:
`IWatcherStoreService` is an interface containing all the store methods for saving challenge records. You can use any connext store, or implement your own. See [challenge storage](#challengestorage) for more detail.
`IStoreService` is an interface containing all the store methods for saving challenge records. You can use any connext store, or implement your own. See [challenge storage](#challengestorage) for more detail.

- `logger (optional)`:
Optional logger, can use the exported logger from the `@connext/utils` package
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ import {
MinimalTransaction,
TransactionReceipt,
} from "@connext/types";
import { delay, getGasPrice, getSignerAddressFromPublicIdentifier, stringify } from "@connext/utils";
import {
delay,
getGasPrice,
getSignerAddressFromPublicIdentifier,
stringify,
} from "@connext/utils";
import { Contract, Signer, utils, constants, providers } from "ethers";

import {
Expand Down Expand Up @@ -150,7 +155,12 @@ export class DeployStateDepositController extends MethodController {
let error: any;
if (transactionService) {
log.info("Sending multisig deployment transaction using transaction service");
receipt = await transactionService.sendTransaction(minTx, preProtocolStateChannel.toJson());
const response = await transactionService.sendTransaction(
minTx,
preProtocolStateChannel.chainId,
preProtocolStateChannel.multisigAddress,
);
receipt = await response.wait();
} else {
// try with nonce retry logic
for (let tryCount = 1; tryCount <= retryCount; tryCount += 1) {
Expand Down
1 change: 1 addition & 0 deletions modules/cf-core/src/rpc-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export class RpcRouter {
}

unsubscribeAll() {
this.requestHandler.incoming.removeAllListeners();
this.requestHandler.outgoing.removeAllListeners();
}

Expand Down
5 changes: 3 additions & 2 deletions modules/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,16 @@
"lint": "../../node_modules/.bin/eslint -c '../../.eslintrc.js' --fix 'src/**/*'"
},
"dependencies": {
"axios": "0.19.2",
"@connext/apps": "7.3.8",
"@connext/cf-core": "7.3.8",
"@connext/channel-provider": "7.3.8",
"@connext/utils": "7.3.8",
"@connext/contracts": "3.5.0",
"@connext/messaging": "7.3.8",
"@connext/store": "7.3.8",
"@connext/types": "7.3.8",
"@connext/utils": "7.3.8",
"@connext/watcher": "7.3.8",
"axios": "0.19.2",
"core-js": "3.6.5",
"ethers": "5.0.8",
"evt": "1.8.4",
Expand Down
7 changes: 1 addition & 6 deletions modules/client/src/channelProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,6 @@ import {
ValidationMiddleware,
ProtocolName,
MiddlewareContext,
ProtocolNames,
ProposeMiddlewareContext,
UninstallMiddlewareContext,
InstallMiddlewareContext,
} from "@connext/types";
import {
deBigNumberifyJson,
Expand Down Expand Up @@ -224,8 +220,7 @@ export class CFCoreRpcConnection extends ConnextEventEmitter implements IRpcConn
};

public removeAllListeners = (): any => {
this.cfCore.removeAllListeners();
return this.cfCore;
return this.cfCore.removeAllListeners();
};

public once = (
Expand Down
14 changes: 14 additions & 0 deletions modules/client/src/connect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
delay,
getChainId,
} from "@connext/utils";
import { Watcher } from "@connext/watcher";

import { Contract, providers } from "ethers";

Expand Down Expand Up @@ -45,6 +46,7 @@ export const connect = async (
nodeUrl,
middlewareMap,
skipInitStore,
watcherEnabled,
skipSync,
} = opts;
let { ethProvider, messaging } = opts;
Expand Down Expand Up @@ -142,6 +144,17 @@ export const connect = async (
throw new Error("Must provide channelProvider or signer");
}

// create watcher, which is enabled by default
const watcher = await Watcher.init({
signer,
providers: {},
context: node.config.contractAddresses,
store,
});
if (!watcherEnabled) {
await watcher.disable();
}

// create a token contract based on the provided token
const token = new Contract(config.contractAddresses[chainId].Token, ERC20.abi, ethProvider);

Expand All @@ -162,6 +175,7 @@ export const connect = async (
store,
token,
chainId,
watcher,
});

logger.info(`Done creating connext client`);
Expand Down
74 changes: 64 additions & 10 deletions modules/client/src/connext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,16 @@ import {
SupportedApplicationNames,
WithdrawalMonitorObject,
WithdrawAppName,
IWatcher,
StoredAppChallengeStatus,
} from "@connext/types";
import {
delay,
getRandomBytes32,
getAddressFromAssetId,
getSignerAddressFromPublicIdentifier,
stringify,
computeCancelDisputeHash,
} from "@connext/utils";
import { BigNumber, Contract, providers, constants, utils } from "ethers";

Expand Down Expand Up @@ -78,6 +81,7 @@ export class ConnextClient implements IConnextClient {
public signerAddress: string;
public store: IStoreService;
public token: Contract;
public watcher: IWatcher;

private opts: InternalClientOptions;

Expand All @@ -101,6 +105,7 @@ export class ConnextClient implements IConnextClient {
this.node = opts.node;
this.store = opts.store;
this.token = opts.token;
this.watcher = opts.watcher;

this.signerAddress = this.channelProvider.config.signerAddress;
this.publicIdentifier = this.channelProvider.config.userIdentifier;
Expand Down Expand Up @@ -274,22 +279,48 @@ export class ConnextClient implements IConnextClient {
return this.node.getTransferHistory();
};

///////////////////////////////////
// DISPUTE METHODS
public initiateChallenge = (
params: PublicParams.InitiateChallenge,
): Promise<PublicResults.InitiateChallenge> => {
return this.watcher.initiate(params.appIdentityHash);
};

public cancelChallenge = async (
params: PublicParams.CancelChallenge,
): Promise<PublicResults.CancelChallenge> => {
const { appInstance } = (await this.getAppInstance(params.appIdentityHash)) || {};
if (!appInstance) {
throw new Error(`Could not find record of app with hash ${params.appIdentityHash}`);
}
const cancelHash = computeCancelDisputeHash(
appInstance.identityHash,
appInstance.latestVersionNumber,
);
const signature = await this.channelProvider.signMessage(cancelHash);
return this.node.cancelChallenge(params.appIdentityHash, signature);
};

///////////////////////////////////
// CORE CHANNEL METHODS

public deposit = async (params: PublicParams.Deposit): Promise<PublicResults.Deposit> => {
await this.assertFreeBalanceNotDisputed();
return this.depositController.deposit(params);
};

public requestDepositRights = async (
params: PublicParams.RequestDepositRights,
): Promise<MethodResults.RequestDepositRights> => {
await this.assertFreeBalanceNotDisputed();
return this.depositController.requestDepositRights(params);
};

public rescindDepositRights = async (
params: PublicParams.RescindDepositRights,
): Promise<PublicResults.RescindDepositRights> => {
await this.assertFreeBalanceNotDisputed();
return this.depositController.rescindDepositRights(params);
};

Expand All @@ -304,8 +335,8 @@ export class ConnextClient implements IConnextClient {
};

public swap = async (params: PublicParams.Swap): Promise<PublicResults.Swap> => {
const res = await this.swapController.swap(params);
return res;
await this.assertFreeBalanceNotDisputed();
return this.swapController.swap(params);
};

/**
Expand All @@ -315,6 +346,7 @@ export class ConnextClient implements IConnextClient {
public transfer = async (
params: PublicParams.Transfer,
): Promise<PublicResults.ConditionalTransfer> => {
await this.assertFreeBalanceNotDisputed();
return this.createTransferController.createTransfer({
amount: params.amount,
assetId: params.assetId || CONVENTION_FOR_ETH_ASSET_ID,
Expand All @@ -326,11 +358,13 @@ export class ConnextClient implements IConnextClient {
}) as Promise<PublicResults.ConditionalTransfer>;
};

public withdraw = (params: PublicParams.Withdraw): Promise<PublicResults.Withdraw> => {
public withdraw = async (params: PublicParams.Withdraw): Promise<PublicResults.Withdraw> => {
await this.assertFreeBalanceNotDisputed();
return this.withdrawalController.withdraw(params);
};

public respondToNodeWithdraw = (appInstance: AppInstanceJson): Promise<void> => {
public respondToNodeWithdraw = async (appInstance: AppInstanceJson): Promise<void> => {
await this.assertFreeBalanceNotDisputed();
return this.withdrawalController.respondToNodeWithdraw(appInstance);
};

Expand All @@ -346,6 +380,7 @@ export class ConnextClient implements IConnextClient {
params: PublicParams.ResolveCondition,
): Promise<PublicResults.ResolveCondition> => {
// paymentId is generated for hashlock transfer
await this.assertFreeBalanceNotDisputed();
if (params.conditionType === ConditionalTransferTypes.HashLockTransfer && !params.paymentId) {
const lockHash = soliditySha256(["bytes32"], [params.preImage]);
const paymentId = soliditySha256(["address", "bytes32"], [params.assetId, lockHash]);
Expand All @@ -357,6 +392,7 @@ export class ConnextClient implements IConnextClient {
public conditionalTransfer = async (
params: PublicParams.ConditionalTransfer,
): Promise<PublicResults.ConditionalTransfer> => {
await this.assertFreeBalanceNotDisputed();
params.assetId = params.assetId || CONVENTION_FOR_ETH_ASSET_ID;
return this.createTransferController.createTransfer(params);
};
Expand Down Expand Up @@ -468,12 +504,11 @@ export class ConnextClient implements IConnextClient {
return this.listener.waitFor(event, timeout, filter);
}

// TODO: allow for removing listeners attached via a specific event
// by manipulating the context of the events

public off = () => {
this.listener.detach();
this.channelProvider.removeAllListeners();
public off = async () => {
await this.messaging.disconnect();
await this.listener.detach();
await this.channelProvider.removeAllListeners();
await delay(500); // give messaging a bit more time to finish disconnecting
};

public emit = <T extends EventName>(event: T, payload: EventPayload[T]): boolean => {
Expand Down Expand Up @@ -572,6 +607,7 @@ export class ConnextClient implements IConnextClient {
action: AppAction,
stateTimeout?: BigNumber,
): Promise<MethodResults.TakeAction> => {
await this.assertFreeBalanceNotDisputed();
// check the app is actually installed
const err = await this.appNotInstalled(appIdentityHash);
if (err) {
Expand Down Expand Up @@ -602,6 +638,7 @@ export class ConnextClient implements IConnextClient {
};

public installApp = async (appIdentityHash: string): Promise<MethodResults.Install> => {
await this.assertFreeBalanceNotDisputed();
// check the app isnt actually installed
const alreadyInstalled = await this.appInstalled(appIdentityHash);
if (alreadyInstalled) {
Expand All @@ -617,6 +654,7 @@ export class ConnextClient implements IConnextClient {
appIdentityHash: string,
action?: AppAction,
): Promise<MethodResults.Uninstall> => {
await this.assertFreeBalanceNotDisputed();
// check the app is actually installed
const err = await this.appNotInstalled(appIdentityHash);
if (err) {
Expand Down Expand Up @@ -946,4 +984,20 @@ export class ConnextClient implements IConnextClient {
}
return undefined;
};

private assertFreeBalanceNotDisputed = async () => {
const channel = await this.store.getStateChannel(this.multisigAddress);
if (!channel || !channel.freeBalanceAppInstance) {
return;
}
const freeBalanceChallenge = await this.store.getAppChallenge(
channel.freeBalanceAppInstance.identityHash,
);
if (
freeBalanceChallenge &&
freeBalanceChallenge.status !== StoredAppChallengeStatus.NO_CHALLENGE
) {
throw new Error(`Free balance app has been disputed, cannot use channel.`);
}
};
}
Loading

0 comments on commit ea23957

Please sign in to comment.