Skip to content

Commit 1fbc7af

Browse files
committed
add LifChannels tests
1 parent 288fe8b commit 1fbc7af

File tree

2 files changed

+161
-1
lines changed

2 files changed

+161
-1
lines changed

contracts/LifChannels.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import "zeppelin-solidity/contracts/math/SafeMath.sol";
55
import "zeppelin-solidity/contracts/ECRecovery.sol";
66

77
/**
8-
@title LifChannels, Statw channels for ERC20 Lif Token
8+
@title LifChannels, State channels for ERC20 Lif Token
99
1010
Contract that provides holders of a ERC20 compatible token the creation of
1111
channels between two users, once a channel is open the users can exchange

test/LifChannels.js

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
var help = require('./helpers');
2+
var ethUtils = require('ethereumjs-util');
3+
4+
var BigNumber = web3.BigNumber;
5+
6+
require('chai')
7+
.use(require('chai-bignumber')(BigNumber))
8+
.should();
9+
10+
var LifTokenTest = artifacts.require('./LifTokenTest.sol');
11+
var LifChannels = artifacts.require('./LifChannels.sol');
12+
var ECRecovery = artifacts.require('./ECRecovery.sol');
13+
14+
var {increaseTimeTestRPC} = require('./helpers/increaseTime');
15+
16+
const LOG_EVENTS = true;
17+
18+
contract('LifToken', function(accounts) {
19+
20+
var token;
21+
var lifChannels;
22+
var eventsWatcher;
23+
24+
// This private keys should match the ones used by testrpc
25+
const privateKeys = {};
26+
privateKeys[accounts[0]]= '0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501200';
27+
privateKeys[accounts[1]]= '0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501201';
28+
privateKeys[accounts[2]]= '0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501202';
29+
privateKeys[accounts[3]]= '0x2bdd21761a483f71054e14f5b827213567971c676928d9a1808cbfa4b7501203';
30+
31+
// Sign a message with a private key, it returns the signature in rpc format
32+
function signMsg(msg, pvKey){
33+
const sig = ethUtils.ecsign(ethUtils.toBuffer(msg), ethUtils.toBuffer(pvKey));
34+
return ethUtils.toRpcSig(sig.v, sig.r, sig.s);
35+
}
36+
37+
beforeEach(async function() {
38+
const ecrecovery = await ECRecovery.new();
39+
LifChannels.link('ECRecovery', ecrecovery.address);
40+
token = await LifTokenTest.new();
41+
await token.faucetLif({from: accounts[1]});
42+
await token.faucetLif({from: accounts[2]});
43+
await token.faucetLif({from: accounts[3]});
44+
lifChannels = await LifChannels.new(token.address, 60);
45+
eventsWatcher = lifChannels.allEvents();
46+
eventsWatcher.watch(function(error, log){
47+
if (LOG_EVENTS)
48+
help.debug('Event:', log.event, ':',log.args);
49+
});
50+
});
51+
52+
afterEach(function(done) {
53+
eventsWatcher.stopWatching();
54+
done();
55+
});
56+
57+
it('create channel', async function() {
58+
await token.approve(lifChannels.address, help.lif2LifWei(30), {from: accounts[2]});
59+
const nonce = 66;
60+
help.debug('Creating channel between '+accounts[1]+' and'+accounts[2]);
61+
await lifChannels.openChannel(accounts[1], help.lif2LifWei(30), nonce, {from: accounts[2]});
62+
const channelInfo = await lifChannels.getChannelInfo(accounts[2], accounts[1], nonce);
63+
assert.equal(channelInfo[1], help.lif2LifWei(30));
64+
assert.equal(channelInfo[2], 0);
65+
assert.equal(channelInfo[3], 0);
66+
});
67+
68+
it('create channel and close it with a mutual agreement from sender', async function() {
69+
await token.approve(lifChannels.address, help.lif2LifWei(30), {from: accounts[2]});
70+
const nonce = 33;
71+
await lifChannels.openChannel(accounts[1], help.lif2LifWei(30), nonce, {from: accounts[2]});
72+
help.debug('Sharing sig to send 20 Lif to '+accounts[1]+' from '+accounts[2]);
73+
const hash = await lifChannels.generateBalanceHash(accounts[1], nonce, help.lif2LifWei(20));
74+
const senderSig = signMsg(hash, privateKeys[accounts[2]]);
75+
assert.equal(accounts[2],
76+
await lifChannels.getSignerOfBalanceHash(accounts[1], nonce, help.lif2LifWei(20), senderSig)
77+
);
78+
help.debug('Sharing sig to accept 20 Lif from '+accounts[2]+' to '+accounts[1]);
79+
const senderHash = await lifChannels.generateKeccak256(senderSig);
80+
const closingSig = signMsg(senderHash, privateKeys[accounts[1]]);
81+
help.debug('Closing channel from '+accounts[2]);
82+
await lifChannels.cooperativeClose(accounts[1], nonce, help.lif2LifWei(20), senderSig, closingSig, {from: accounts[1]});
83+
(await token.balanceOf(accounts[2])).should.be.bignumber
84+
.equal(help.lif2LifWei(30));
85+
(await token.balanceOf(accounts[1])).should.be.bignumber
86+
.equal(help.lif2LifWei(70));
87+
});
88+
89+
it('create channel and close it with a mutual agreement from receiver', async function() {
90+
await token.approve(lifChannels.address, help.lif2LifWei(30), {from: accounts[2]});
91+
const nonce = 33;
92+
await lifChannels.openChannel(accounts[1], help.lif2LifWei(30), nonce, {from: accounts[2]});
93+
help.debug('Sharing sig to send 20 Lif to '+accounts[1]+' from '+accounts[2]);
94+
const hash = await lifChannels.generateBalanceHash(accounts[1], nonce, help.lif2LifWei(20));
95+
const senderSig = signMsg(hash, privateKeys[accounts[2]]);
96+
assert.equal(accounts[2],
97+
await lifChannels.getSignerOfBalanceHash(accounts[1], nonce, help.lif2LifWei(20), senderSig)
98+
);
99+
help.debug('Sharing sig to accept 20 Lif from '+accounts[2]+' to '+accounts[1]);
100+
const senderHash = await lifChannels.generateKeccak256(senderSig);
101+
const closingSig = signMsg(senderHash, privateKeys[accounts[1]]);
102+
help.debug('Closing channel from '+accounts[2]);
103+
await lifChannels.cooperativeClose(accounts[1], nonce, help.lif2LifWei(20), senderSig, closingSig, {from: accounts[2]});
104+
(await token.balanceOf(accounts[2])).should.be.bignumber
105+
.equal(help.lif2LifWei(30));
106+
(await token.balanceOf(accounts[1])).should.be.bignumber
107+
.equal(help.lif2LifWei(70));
108+
});
109+
110+
it('create channel and close it from sender with uncooperativeClose', async function() {
111+
await token.approve(lifChannels.address, help.lif2LifWei(30), {from: accounts[2]});
112+
const nonce = 33;
113+
await lifChannels.openChannel(accounts[1], help.lif2LifWei(30), nonce, {from: accounts[2]});
114+
help.debug('Sharing sig to send 10 Lif to '+accounts[1]+' from '+accounts[2]);
115+
const hash = await lifChannels.generateBalanceHash(accounts[1], nonce, help.lif2LifWei(10));
116+
const senderSig = signMsg(hash, privateKeys[accounts[2]]);
117+
assert.equal(accounts[2],
118+
await lifChannels.getSignerOfBalanceHash(accounts[1], nonce, help.lif2LifWei(10), senderSig)
119+
);
120+
help.debug('Closing channel from '+accounts[2]);
121+
await lifChannels.uncooperativeClose(accounts[1], nonce, help.lif2LifWei(10), {from: accounts[2]});
122+
try {
123+
await lifChannels.closeChannel(accounts[1], nonce, {from: accounts[2]});
124+
assert(false, 'close should have thrown');
125+
} catch (error) {
126+
if (!help.isInvalidOpcodeEx(error)) throw error;
127+
}
128+
await increaseTimeTestRPC(61);
129+
await lifChannels.closeChannel(accounts[1], nonce, {from: accounts[2]});
130+
(await token.balanceOf(accounts[2])).should.be.bignumber
131+
.equal(help.lif2LifWei(40));
132+
(await token.balanceOf(accounts[1])).should.be.bignumber
133+
.equal(help.lif2LifWei(60));
134+
});
135+
136+
it('create channel and close it from receiver after sender chanllenge with different balance', async function() {
137+
await token.approve(lifChannels.address, help.lif2LifWei(30), {from: accounts[2]});
138+
const nonce = 33;
139+
await lifChannels.openChannel(accounts[1], help.lif2LifWei(30), nonce, {from: accounts[2]});
140+
help.debug('Sharing sig to send 20 Lif to '+accounts[1]+' from '+accounts[2]);
141+
const hash = await lifChannels.generateBalanceHash(accounts[1], nonce, help.lif2LifWei(20));
142+
const senderSig = signMsg(hash, privateKeys[accounts[2]]);
143+
assert.equal(accounts[2],
144+
await lifChannels.getSignerOfBalanceHash(accounts[1], nonce, help.lif2LifWei(20), senderSig)
145+
);
146+
help.debug('Sharing sig to accept 20 Lif from '+accounts[2]+' to '+accounts[1]);
147+
const senderHash = await lifChannels.generateKeccak256(senderSig);
148+
const closingSig = signMsg(senderHash, privateKeys[accounts[1]]);
149+
help.debug('Start close channel request from '+accounts[2]+' with 10 lif');
150+
await lifChannels.uncooperativeClose(accounts[1], nonce, help.lif2LifWei(10), {from: accounts[2]});
151+
await increaseTimeTestRPC(10);
152+
help.debug('Claim the 20 agreed before from '+accounts[1]);
153+
await lifChannels.cooperativeClose(accounts[1], nonce, help.lif2LifWei(20), senderSig, closingSig, {from: accounts[1]});
154+
(await token.balanceOf(accounts[2])).should.be.bignumber
155+
.equal(help.lif2LifWei(30));
156+
(await token.balanceOf(accounts[1])).should.be.bignumber
157+
.equal(help.lif2LifWei(70));
158+
});
159+
160+
});

0 commit comments

Comments
 (0)