This repository has been archived by the owner on May 28, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 38
/
Copy pathasyncTransfer.test.ts
172 lines (148 loc) · 5.97 KB
/
asyncTransfer.test.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
import { xkeyKthAddress } from "@connext/cf-core";
import { IConnextClient } from "@connext/types";
import { ContractFactory, Wallet } from "ethers";
import { AddressZero } from "ethers/constants";
import { HDNode, hexlify, randomBytes } from "ethers/utils";
const tokenArtifacts = require("openzeppelin-solidity/build/contracts/ERC20Mintable.json");
import { expect } from "../util";
import {
asyncTransferAsset,
createClient,
ETH_AMOUNT_LG,
ETH_AMOUNT_MD,
ETH_AMOUNT_SM,
ethProvider,
fundChannel,
FUNDED_MNEMONICS,
TOKEN_AMOUNT,
} from "../util";
describe.only("Async Transfers", () => {
let clientA: IConnextClient;
let clientB: IConnextClient;
let tokenAddress: string;
let nodeFreeBalanceAddress: string;
let nodePublicIdentifier: string;
beforeEach(async () => {
clientA = await createClient();
clientB = await createClient();
tokenAddress = clientA.config.contractAddresses.Token;
nodePublicIdentifier = clientA.config.nodePublicIdentifier;
nodeFreeBalanceAddress = xkeyKthAddress(nodePublicIdentifier);
}, 90_000);
test("happy case: client A transfers eth to client B through node", async () => {
await fundChannel(clientA, ETH_AMOUNT_SM, AddressZero);
await clientB.requestCollateral(AddressZero);
await asyncTransferAsset(clientA, clientB, ETH_AMOUNT_SM, AddressZero, nodeFreeBalanceAddress);
});
test("happy case: client A transfers tokens to client B through node", async () => {
await fundChannel(clientA, ETH_AMOUNT_LG, tokenAddress);
await clientB.requestCollateral(tokenAddress);
await asyncTransferAsset(clientA, clientB, ETH_AMOUNT_LG, tokenAddress, nodeFreeBalanceAddress);
});
test("Bot A tries to transfer a negative amount", async () => {
await fundChannel(clientA, ETH_AMOUNT_MD, tokenAddress);
// verify collateral
await clientB.requestCollateral(tokenAddress);
await expect(
clientA.transfer({
amount: ETH_AMOUNT_SM.mul(-1).toString(),
assetId: tokenAddress,
recipient: clientB.publicIdentifier,
}),
).rejects.toThrowError("Value -10000000000000000 is negative");
});
test("Bot A tries to transfer with an invalid token address", async () => {
await fundChannel(clientA, ETH_AMOUNT_SM, tokenAddress);
await expect(
clientA.transfer({
amount: ETH_AMOUNT_SM.toString(),
assetId: "0xabc",
recipient: clientB.publicIdentifier,
}),
).rejects.toThrowError(
`Value "0xabc" is not a valid eth address, Value (${ETH_AMOUNT_SM.toString()}) is not less than or equal to 0`,
);
// NOTE: will also include a `Value (..) is not less than or equal to 0
// because it will not be able to fetch the free balance of the assetId
});
test.only("Bot A tries to transfer with an unsupported (but not invalid) token address", async () => {
// deploy a token
const factory = ContractFactory.fromSolidity(tokenArtifacts);
const token = await factory
.connect(Wallet.fromMnemonic(FUNDED_MNEMONICS[0]).connect(ethProvider))
.deploy();
const deployHash = token.deployTransaction.hash;
expect(deployHash).toBeDefined();
await ethProvider.waitForTransaction(token.deployTransaction.hash!);
// mint token to client
await token.mint(clientA.signerAddress, TOKEN_AMOUNT);
// assert sender balance
const senderBal = await token.balanceOf(clientA.signerAddress);
expect(senderBal).toBeBigNumberEq(TOKEN_AMOUNT);
// fund channel
await fundChannel(clientA, ETH_AMOUNT_LG, token.address);
await expect(
clientA.transfer({
amount: ETH_AMOUNT_LG.toString(),
assetId: token.address,
recipient: clientB.publicIdentifier,
}),
).rejects.toThrowError(`test`);
});
test("Bot A tries to transfer with invalid recipient xpub", async () => {
await fundChannel(clientA, ETH_AMOUNT_SM, tokenAddress);
await expect(
clientA.transfer({
amount: ETH_AMOUNT_SM.toString(),
assetId: tokenAddress,
recipient: `nope`,
}),
).rejects.toThrowError(`Value \"nope\" must start with \"xpub\"`);
});
// tslint:disable-next-line: max-line-length
test("Bot A tries to transfer an amount greater than they have in their free balance", async () => {
await expect(
clientA.transfer({
amount: ETH_AMOUNT_SM.toString(),
assetId: tokenAddress,
recipient: clientB.publicIdentifier,
}),
).rejects.toThrowError(`Value (${ETH_AMOUNT_SM.toString()}) is not less than or equal to 0`);
});
test("Bot A tries to transfer with a paymentId that is not 32 bytes", async () => {
await fundChannel(clientA, ETH_AMOUNT_SM, tokenAddress);
await expect(
clientA.conditionalTransfer({
amount: ETH_AMOUNT_SM.toString(),
assetId: tokenAddress,
conditionType: "LINKED_TRANSFER_TO_RECIPIENT",
paymentId: "nope",
preImage: hexlify(randomBytes(32)),
recipient: clientB.publicIdentifier,
}),
).rejects.toThrowError(`Value \"nope\" is not a valid hex string`);
});
test("Bot A tries to transfer with a preimage that is not 32 bytes", async () => {
await fundChannel(clientA, ETH_AMOUNT_SM, tokenAddress);
await expect(
clientA.conditionalTransfer({
amount: ETH_AMOUNT_SM.toString(),
assetId: tokenAddress,
conditionType: "LINKED_TRANSFER_TO_RECIPIENT",
paymentId: hexlify(randomBytes(32)),
preImage: "nope",
recipient: clientB.publicIdentifier,
}),
).rejects.toThrowError(`Value \"nope\" is not a valid hex string`);
});
test("Bot A proposes a transfer to an xpub that doesn’t have a channel", async () => {
await fundChannel(clientA, ETH_AMOUNT_SM, tokenAddress);
await expect(
clientA.transfer({
amount: ETH_AMOUNT_SM.toString(),
assetId: tokenAddress,
recipient: HDNode.fromMnemonic(Wallet.createRandom().mnemonic).neuter().extendedKey,
}),
).rejects.toThrowError(`No channel exists for recipientPublicIdentifier`);
});
});