diff --git a/contracts/ChannelManager.sol b/contracts/ChannelManager.sol new file mode 100644 index 0000000..767d672 --- /dev/null +++ b/contracts/ChannelManager.sol @@ -0,0 +1,641 @@ +pragma solidity ^0.4.23; + +import "./lib/ECTools.sol"; +import "./lib/token/HumanStandardToken.sol"; + +/// @title Set Virtual Channels - A layer2 hub and spoke payment network +/// @author Nathan Ginnever + +contract ChannelManager { + + string public constant NAME = "ChannelManager"; + string public constant VERSION = "0.0.1"; + + uint256 public numChannels = 0; + + event DidChannelOpen ( + bytes32 indexed channelId, + address indexed partyA, + address indexed partyI, + uint256 ethBalanceA, + address token, + uint256 tokenBalanceA, + uint256 openTimeout + ); + + event DidChannelJoin ( + bytes32 indexed channelId, + uint256 ethBalanceI, + uint256 tokenBalanceI + ); + + event DidChannelDeposit ( + bytes32 indexed channelId, + address indexed recipient, + uint256 deposit, + bool isToken + ); + + event DidChannelUpdateState ( + bytes32 indexed channelId, + uint256 sequence, + uint256 numOpenThread, + uint256 ethBalanceA, + uint256 tokenBalanceA, + uint256 ethBalanceI, + uint256 tokenBalanceI, + bytes32 threadRoot, + uint256 updateChannelTimeout + ); + + event DidChannelClose ( + bytes32 indexed channelId, + uint256 sequence, + uint256 ethBalanceA, + uint256 tokenBalanceA, + uint256 ethBalanceI, + uint256 tokenBalanceI + ); + + event DidThreadInit ( + bytes32 indexed lcId, + bytes32 indexed vcId, + bytes proof, + uint256 sequence, + address partyA, + address partyB, + uint256 balanceA, + uint256 balanceB + ); + + event DidThreadSettle ( + bytes32 indexed lcId, + bytes32 indexed vcId, + uint256 updateSeq, + uint256 updateBalA, + uint256 updateBalB, + address challenger, + uint256 updateThreadTimeout + ); + + event DidThreadClose( + bytes32 indexed lcId, + bytes32 indexed vcId, + uint256 balanceA, + uint256 balanceB + ); + + struct Channel { + //TODO: figure out if it's better just to split arrays by balances/deposits instead of eth/erc20 + address[2] partyAddresses; // 0: partyA 1: partyI + uint256[4] ethBalances; // 0: balanceA 1:balanceI 2:depositedA 3:depositedI + uint256[4] erc20Balances; // 0: balanceA 1:balanceI 2:depositedA 3:depositedI + uint256[2] initialDeposit; // 0: eth 1: tokens + uint256 sequence; + uint256 confirmTime; + bytes32 threadRootHash; + uint256 openTimeout; + uint256 updateChannelTimeout; // when update channel times out + bool isOpen; // true when both parties have joined + bool isUpdateChannelSettling; + uint256 numOpenThread; + HumanStandardToken token; + } + + // thread state + struct Thread { + bool isClose; + bool isInSettlementState; + uint256 sequence; + address challenger; // Initiator of challenge + uint256 updateThreadTimeout; // when update thread times out + // channel state + address partyA; // thread participant A + address partyB; // thread participant B + address partyI; // channel hub + uint256[2] ethBalances; + uint256[2] erc20Balances; + uint256[2] bond; + HumanStandardToken token; + } + + mapping(bytes32 => Thread) public Threads; + mapping(bytes32 => Channel) public Channels; + + function createChannel( + bytes32 _channelId, + address _partyI, + uint256 _confirmTime, + address _token, + uint256[2] _balances // [eth, token] + ) + public + payable + { + require(Channels[_channelId].partyAddresses[0] == address(0), "Channel has already been created."); + require(_partyI != 0x0, "No partyI address provided to channel creation"); + require(_balances[0] >= 0 && _balances[1] >= 0, "Balances cannot be negative"); + // Set initial channel state + // Alice must execute this and we assume the initial state + // to be signed from this requirement + // Alternative is to check a sig as in joinChannel + Channels[_channelId].partyAddresses[0] = msg.sender; + Channels[_channelId].partyAddresses[1] = _partyI; + + if(_balances[0] != 0) { + require(msg.value == _balances[0], "Eth balance does not match sent value"); + Channels[_channelId].ethBalances[0] = msg.value; + } + if(_balances[1] != 0) { + Channels[_channelId].token = HumanStandardToken(_token); + require(Channels[_channelId].token.transferFrom(msg.sender, this, _balances[1]),"CreateChannel: token transfer failure"); + Channels[_channelId].erc20Balances[0] = _balances[1]; + } + + Channels[_channelId].sequence = 0; + Channels[_channelId].confirmTime = _confirmTime; + // is close flag, channel state sequence, number open vc, thread root hash, partyA... + //Channels[_channelId].stateHash = keccak256(uint256(0), uint256(0), uint256(0), bytes32(0x0), bytes32(msg.sender), bytes32(_partyI), balanceA, balanceI); + Channels[_channelId].openTimeout = now + _confirmTime; + Channels[_channelId].initialDeposit = _balances; + + emit DidChannelOpen(_channelId, msg.sender, _partyI, _balances[0], _token, _balances[1], Channels[_channelId].openTimeout); + } + + function channelOpenTimeout(bytes32 _channelId) public { + require(msg.sender == Channels[_channelId].partyAddresses[0] && Channels[_channelId].isOpen == false); + require(now > Channels[_channelId].openTimeout); + + if(Channels[_channelId].initialDeposit[0] != 0) { + //TODO: what happens if eth transfer fails? + Channels[_channelId].partyAddresses[0].transfer(Channels[_channelId].ethBalances[0]); + } + if(Channels[_channelId].initialDeposit[1] != 0) { + require(Channels[_channelId].token.transfer(Channels[_channelId].partyAddresses[0], Channels[_channelId].erc20Balances[0]),"CreateChannel: token transfer failure"); + } + + emit DidChannelClose(_channelId, 0, Channels[_channelId].ethBalances[0], Channels[_channelId].erc20Balances[0], 0, 0); + + // only safe to delete since no action was taken on this channel + delete Channels[_channelId]; + } + + function joinChannel(bytes32 _channelId, uint256[2] _balances) public payable { + // require the channel is not open yet + require(Channels[_channelId].isOpen == false); + require(msg.sender == Channels[_channelId].partyAddresses[1]); + //TODO check if balances are negative? + + if(_balances[0] != 0) { + require(msg.value == _balances[0], "state balance does not match sent value"); + Channels[_channelId].ethBalances[1] = msg.value; + } + if(_balances[1] != 0) { + require(Channels[_channelId].token.transferFrom(msg.sender, this, _balances[1]),"joinChannel: token transfer failure"); + Channels[_channelId].erc20Balances[1] = _balances[1]; + } + + Channels[_channelId].initialDeposit[0]+=_balances[0]; + Channels[_channelId].initialDeposit[1]+=_balances[1]; + // no longer allow joining functions to be called + Channels[_channelId].isOpen = true; + numChannels++; + + emit DidChannelJoin(_channelId, _balances[0], _balances[1]); + } + + + // additive updates of monetary state + // TODO check this for attack vectors + function deposit(bytes32 _channelId, address recipient, uint256 _balance, bool isToken) public payable { + require(Channels[_channelId].isOpen == true, "Tried adding funds to a closed channel"); + require(recipient == Channels[_channelId].partyAddresses[0] || recipient == Channels[_channelId].partyAddresses[1]); + + //if(Channels[_channelId].token) + + if (Channels[_channelId].partyAddresses[0] == recipient) { + if(isToken) { + require(Channels[_channelId].token.transferFrom(msg.sender, this, _balance),"deposit: token transfer failure"); + Channels[_channelId].erc20Balances[2] += _balance; + } else { + require(msg.value == _balance, "state balance does not match sent value"); + Channels[_channelId].ethBalances[2] += msg.value; + } + } + + if (Channels[_channelId].partyAddresses[1] == recipient) { + if(isToken) { + require(Channels[_channelId].token.transferFrom(msg.sender, this, _balance),"deposit: token transfer failure"); + Channels[_channelId].erc20Balances[3] += _balance; + } else { + require(msg.value == _balance, "state balance does not match sent value"); + Channels[_channelId].ethBalances[3] += msg.value; + } + } + + emit DidChannelDeposit(_channelId, recipient, _balance, isToken); + } + + // TODO: Check there are no open virtual channels, the client should have cought this before signing a close channel state update + function consensusCloseChannel( + bytes32 _channelId, + uint256 _sequence, + uint256[4] _balances, // 0: ethBalanceA 1:ethBalanceI 2:tokenBalanceA 3:tokenBalanceI + string _sigA, + string _sigI + ) + public + { + // assume num open thread is 0 and root hash is 0x0 + //require(Channels[_channelId].sequence < _sequence); + require(Channels[_channelId].isOpen == true); + uint256 totalEthDeposit = Channels[_channelId].initialDeposit[0] + Channels[_channelId].ethBalances[2] + Channels[_channelId].ethBalances[3]; + uint256 totalTokenDeposit = Channels[_channelId].initialDeposit[1] + Channels[_channelId].erc20Balances[2] + Channels[_channelId].erc20Balances[3]; + require(totalEthDeposit == _balances[0] + _balances[1]); + require(totalTokenDeposit == _balances[2] + _balances[3]); + + bytes32 _state = keccak256( + abi.encodePacked( + _channelId, + true, + _sequence, + uint256(0), + bytes32(0x0), + Channels[_channelId].partyAddresses[0], + Channels[_channelId].partyAddresses[1], + _balances[0], + _balances[1], + _balances[2], + _balances[3] + ) + ); + + require(Channels[_channelId].partyAddresses[0] == ECTools.recoverSigner(_state, _sigA)); + require(Channels[_channelId].partyAddresses[1] == ECTools.recoverSigner(_state, _sigI)); + + Channels[_channelId].isOpen = false; + + if(_balances[0] != 0 || _balances[1] != 0) { + Channels[_channelId].partyAddresses[0].transfer(_balances[0]); + Channels[_channelId].partyAddresses[1].transfer(_balances[1]); + } + + if(_balances[2] != 0 || _balances[3] != 0) { + require(Channels[_channelId].token.transfer(Channels[_channelId].partyAddresses[0], _balances[2]),"happyCloseChannel: token transfer failure"); + require(Channels[_channelId].token.transfer(Channels[_channelId].partyAddresses[1], _balances[3]),"happyCloseChannel: token transfer failure"); + } + + numChannels--; + + emit DidChannelClose(_channelId, _sequence, _balances[0], _balances[1], _balances[2], _balances[3]); + } + + // Byzantine functions + + function updateChannelState( + bytes32 _channelId, + uint256[6] updateParams, // [sequence, numOpenThread, ethbalanceA, ethbalanceI, tokenbalanceA, tokenbalanceI] + bytes32 _threadRoot, + string _sigA, + string _sigI + ) + public + { + Channel storage channel = Channels[_channelId]; + require(channel.isOpen); + require(channel.sequence < updateParams[0]); // do same as thread sequence check + require(channel.ethBalances[0] + channel.ethBalances[1] >= updateParams[2] + updateParams[3]); + require(channel.erc20Balances[0] + channel.erc20Balances[1] >= updateParams[4] + updateParams[5]); + + if(channel.isUpdateChannelSettling == true) { + require(channel.updateChannelTimeout > now); + } + + bytes32 _state = keccak256( + abi.encodePacked( + _channelId, + false, + updateParams[0], + updateParams[1], + _threadRoot, + channel.partyAddresses[0], + channel.partyAddresses[1], + updateParams[2], + updateParams[3], + updateParams[4], + updateParams[5] + ) + ); + + require(channel.partyAddresses[0] == ECTools.recoverSigner(_state, _sigA)); + require(channel.partyAddresses[1] == ECTools.recoverSigner(_state, _sigI)); + + // update channel state + channel.sequence = updateParams[0]; + channel.numOpenThread = updateParams[1]; + channel.ethBalances[0] = updateParams[2]; + channel.ethBalances[1] = updateParams[3]; + channel.erc20Balances[0] = updateParams[4]; + channel.erc20Balances[1] = updateParams[5]; + channel.threadRootHash = _threadRoot; + channel.isUpdateChannelSettling = true; + channel.updateChannelTimeout = now + channel.confirmTime; + + // make settlement flag + + emit DidChannelUpdateState ( + _channelId, + updateParams[0], + updateParams[1], + updateParams[2], + updateParams[3], + updateParams[4], + updateParams[5], + _threadRoot, + channel.updateChannelTimeout + ); + } + + // supply initial state of thread to "prime" the force push game + function initThreadState( + bytes32 _channelId, + bytes32 _threadId, + bytes _proof, + address _partyA, + address _partyB, + uint256[2] _bond, + uint256[4] _balances, // 0: ethBalanceA 1:ethBalanceI 2:tokenBalanceA 3:tokenBalanceI + string sigA + ) + public + { + require(Channels[_channelId].isOpen, "channel is closed."); + // sub-channel must be open + require(!Threads[_threadId].isClose, "thread is closed."); + // Check time has passed on updateChannelTimeout and has not passed the time to store a thread state + require(Channels[_channelId].updateChannelTimeout < now, "channel timeout not over."); + // prevent rentry of initializing thread state + require(Threads[_threadId].updateThreadTimeout == 0); + // partyB is now Ingrid + bytes32 _initState = keccak256( + abi.encodePacked(_threadId, uint256(0), _partyA, _partyB, _bond[0], _bond[1], _balances[0], _balances[1], _balances[2], _balances[3]) + ); + + // Make sure Alice has signed initial thread state (A/B in oldState) + require(_partyA == ECTools.recoverSigner(_initState, sigA)); + + // Check the oldState is in the root hash + require(_isContained(_initState, _proof, Channels[_channelId].threadRootHash) == true); + + Threads[_threadId].partyA = _partyA; // thread participant A + Threads[_threadId].partyB = _partyB; // thread participant B + Threads[_threadId].sequence = uint256(0); + Threads[_threadId].ethBalances[0] = _balances[0]; + Threads[_threadId].ethBalances[1] = _balances[1]; + Threads[_threadId].erc20Balances[0] = _balances[2]; + Threads[_threadId].erc20Balances[1] = _balances[3]; + Threads[_threadId].bond = _bond; + Threads[_threadId].updateThreadTimeout = now + Channels[_channelId].confirmTime; + Threads[_threadId].isInSettlementState = true; + + emit DidThreadInit(_channelId, _threadId, _proof, uint256(0), _partyA, _partyB, _balances[0], _balances[1]); + } + + //TODO: verify state transition since the hub did not agree to this state + // make sure the A/B balances are not beyond ingrids bonds + // Params: thread init state, thread final balance, vcID + function settleThread( + bytes32 _channelId, + bytes32 _threadId, + uint256 updateSeq, + address _partyA, + address _partyB, + uint256[4] updateBal, // [ethupdateBalA, ethupdateBalB, tokenupdateBalA, tokenupdateBalB] + string sigA + ) + public + { + require(Channels[_channelId].isOpen, "channel is closed."); + // sub-channel must be open + require(!Threads[_threadId].isClose, "thread is closed."); + require(Threads[_threadId].sequence < updateSeq, "thread sequence is higher than update sequence."); + require( + Threads[_threadId].ethBalances[1] < updateBal[1] && Threads[_threadId].erc20Balances[1] < updateBal[3], + "State updates may only increase recipient balance." + ); + require( + Threads[_threadId].bond[0] == updateBal[0] + updateBal[1] && + Threads[_threadId].bond[1] == updateBal[2] + updateBal[3], + "Incorrect balances for bonded amount"); + // Check time has passed on updateChannelTimeout and has not passed the time to store a thread state + // Threads[_threadId].updateThreadTimeout should be 0 on uninitialized thread state, and this should + // fail if initVC() isn't called first + // require(Channels[_channelId].updateChannelTimeout < now && now < Threads[_threadId].updateThreadTimeout); + require(Channels[_channelId].updateChannelTimeout < now); // for testing! + + bytes32 _updateState = keccak256( + abi.encodePacked( + _threadId, + updateSeq, + _partyA, + _partyB, + Threads[_threadId].bond[0], + Threads[_threadId].bond[1], + updateBal[0], + updateBal[1], + updateBal[2], + updateBal[3] + ) + ); + + // Make sure Alice has signed a higher sequence new state + require(Threads[_threadId].partyA == ECTools.recoverSigner(_updateState, sigA)); + + // store thread data + // we may want to record who is initiating on-chain settles + Threads[_threadId].challenger = msg.sender; + Threads[_threadId].sequence = updateSeq; + + // channel state + Threads[_threadId].ethBalances[0] = updateBal[0]; + Threads[_threadId].ethBalances[1] = updateBal[1]; + Threads[_threadId].erc20Balances[0] = updateBal[2]; + Threads[_threadId].erc20Balances[1] = updateBal[3]; + + Threads[_threadId].updateThreadTimeout = now + Channels[_channelId].confirmTime; + + emit DidThreadSettle(_channelId, _threadId, updateSeq, updateBal[0], updateBal[1], msg.sender, Threads[_threadId].updateThreadTimeout); + } + + function closeThread(bytes32 _channelId, bytes32 _threadId) public { + // require(updateChannelTimeout > now) + require(Channels[_channelId].isOpen, "channel is closed."); + require(Threads[_threadId].isInSettlementState, "thread is not in settlement state."); + require(Threads[_threadId].updateThreadTimeout < now, "Update thread timeout has not elapsed."); + require(!Threads[_threadId].isClose, "thread is already closed"); + // reduce the number of open virtual channels stored on LC + Channels[_channelId].numOpenThread--; + // close thread flags + Threads[_threadId].isClose = true; + // re-introduce the balances back into the channel state from the settled VC + // decide if this channel is alice or bob in the vc + if(Threads[_threadId].partyA == Channels[_channelId].partyAddresses[0]) { + Channels[_channelId].ethBalances[0] += Threads[_threadId].ethBalances[0]; + Channels[_channelId].ethBalances[1] += Threads[_threadId].ethBalances[1]; + + Channels[_channelId].erc20Balances[0] += Threads[_threadId].erc20Balances[0]; + Channels[_channelId].erc20Balances[1] += Threads[_threadId].erc20Balances[1]; + } else if (Threads[_threadId].partyB == Channels[_channelId].partyAddresses[0]) { + Channels[_channelId].ethBalances[0] += Threads[_threadId].ethBalances[1]; + Channels[_channelId].ethBalances[1] += Threads[_threadId].ethBalances[0]; + + Channels[_channelId].erc20Balances[0] += Threads[_threadId].erc20Balances[1]; + Channels[_channelId].erc20Balances[1] += Threads[_threadId].erc20Balances[0]; + } + + emit DidThreadClose(_channelId, _threadId, Threads[_threadId].erc20Balances[0], Threads[_threadId].erc20Balances[1]); + } + + + // todo: allow ethier lc.end-user to nullify the settled channel state and return to off-chain + function byzantineCloseChannel(bytes32 _channelId) public { + Channel storage channel = Channels[_channelId]; + + // check settlement flag + require(channel.isOpen, "Channel is not open"); + require(channel.isUpdateChannelSettling == true); + require(channel.numOpenThread == 0); + require(channel.updateChannelTimeout < now, "channel timeout over."); + + // if off chain state update didnt reblance deposits, just return to deposit owner + uint256 totalEthDeposit = channel.initialDeposit[0] + channel.ethBalances[2] + channel.ethBalances[3]; + uint256 totalTokenDeposit = channel.initialDeposit[1] + channel.erc20Balances[2] + channel.erc20Balances[3]; + + uint256 possibleTotalEthBeforeDeposit = channel.ethBalances[0] + channel.ethBalances[1]; + uint256 possibleTotalTokenBeforeDeposit = channel.erc20Balances[0] + channel.erc20Balances[1]; + + if(possibleTotalEthBeforeDeposit < totalEthDeposit) { + channel.ethBalances[0]+=channel.ethBalances[2]; + channel.ethBalances[1]+=channel.ethBalances[3]; + } else { + require(possibleTotalEthBeforeDeposit == totalEthDeposit); + } + + if(possibleTotalTokenBeforeDeposit < totalTokenDeposit) { + channel.erc20Balances[0]+=channel.erc20Balances[2]; + channel.erc20Balances[1]+=channel.erc20Balances[3]; + } else { + require(possibleTotalTokenBeforeDeposit == totalTokenDeposit); + } + + // reentrancy + uint256 ethbalanceA = channel.ethBalances[0]; + uint256 ethbalanceI = channel.ethBalances[1]; + uint256 tokenbalanceA = channel.erc20Balances[0]; + uint256 tokenbalanceI = channel.erc20Balances[1]; + + channel.ethBalances[0] = 0; + channel.ethBalances[1] = 0; + channel.erc20Balances[0] = 0; + channel.erc20Balances[1] = 0; + + if(ethbalanceA != 0 || ethbalanceI != 0) { + channel.partyAddresses[0].transfer(ethbalanceA); + channel.partyAddresses[1].transfer(ethbalanceI); + } + + if(tokenbalanceA != 0 || tokenbalanceI != 0) { + require( + channel.token.transfer(channel.partyAddresses[0], tokenbalanceA), + "byzantineCloseChannel: token transfer failure" + ); + require( + channel.token.transfer(channel.partyAddresses[1], tokenbalanceI), + "byzantineCloseChannel: token transfer failure" + ); + } + + channel.isOpen = false; + numChannels--; + + emit DidChannelClose(_channelId, channel.sequence, ethbalanceA, ethbalanceI, tokenbalanceA, tokenbalanceI); + } + + function _isContained(bytes32 _hash, bytes _proof, bytes32 _root) internal pure returns (bool) { + bytes32 cursor = _hash; + bytes32 proofElem; + + for (uint256 i = 64; i <= _proof.length; i += 32) { + assembly { proofElem := mload(add(_proof, i)) } + + if (cursor < proofElem) { + cursor = keccak256(abi.encodePacked(cursor, proofElem)); + } else { + cursor = keccak256(abi.encodePacked(proofElem, cursor)); + } + } + + return cursor == _root; + } + + //Struct Getters + function getChannel(bytes32 id) public view returns ( + address[2], + uint256[4], + uint256[4], + uint256[2], + uint256, + uint256, + bytes32, + uint256, + uint256, + bool, + bool, + uint256 + ) { + Channel memory channel = Channels[id]; + return ( + channel.partyAddresses, + channel.ethBalances, + channel.erc20Balances, + channel.initialDeposit, + channel.sequence, + channel.confirmTime, + channel.threadRootHash, + channel.openTimeout, + channel.updateChannelTimeout, + channel.isOpen, + channel.isUpdateChannelSettling, + channel.numOpenThread + ); + } + + function getThread(bytes32 id) public view returns( + bool, + bool, + uint256, + address, + uint256, + address, + address, + address, + uint256[2], + uint256[2], + uint256[2] + ) { + Thread memory thread = Threads[id]; + return( + thread.isClose, + thread.isInSettlementState, + thread.sequence, + thread.challenger, + thread.updateThreadTimeout, + thread.partyA, + thread.partyB, + thread.partyI, + thread.ethBalances, + thread.erc20Balances, + thread.bond + ); + } +} diff --git a/contracts/LedgerChannel.sol b/contracts/LedgerChannel.sol deleted file mode 100644 index 6850d17..0000000 --- a/contracts/LedgerChannel.sol +++ /dev/null @@ -1,637 +0,0 @@ -pragma solidity ^0.4.23; - -import "./lib/ECTools.sol"; -import "./lib/token/HumanStandardToken.sol"; - -/// @title Set Virtual Channels - A layer2 hub and spoke payment network -/// @author Nathan Ginnever - -contract LedgerChannel { - - string public constant NAME = "Ledger Channel"; - string public constant VERSION = "0.0.1"; - - uint256 public numChannels = 0; - - event DidLCOpen ( - bytes32 indexed channelId, - address indexed partyA, - address indexed partyI, - uint256 ethBalanceA, - address token, - uint256 tokenBalanceA, - uint256 LCopenTimeout - ); - - event DidLCJoin ( - bytes32 indexed channelId, - uint256 ethBalanceI, - uint256 tokenBalanceI - ); - - event DidLCDeposit ( - bytes32 indexed channelId, - address indexed recipient, - uint256 deposit, - bool isToken - ); - - event DidLCUpdateState ( - bytes32 indexed channelId, - uint256 sequence, - uint256 numOpenVc, - uint256 ethBalanceA, - uint256 tokenBalanceA, - uint256 ethBalanceI, - uint256 tokenBalanceI, - bytes32 vcRoot, - uint256 updateLCtimeout - ); - - event DidLCClose ( - bytes32 indexed channelId, - uint256 sequence, - uint256 ethBalanceA, - uint256 tokenBalanceA, - uint256 ethBalanceI, - uint256 tokenBalanceI - ); - - event DidVCInit ( - bytes32 indexed lcId, - bytes32 indexed vcId, - bytes proof, - uint256 sequence, - address partyA, - address partyB, - uint256 balanceA, - uint256 balanceB - ); - - event DidVCSettle ( - bytes32 indexed lcId, - bytes32 indexed vcId, - uint256 updateSeq, - uint256 updateBalA, - uint256 updateBalB, - address challenger, - uint256 updateVCtimeout - ); - - event DidVCClose( - bytes32 indexed lcId, - bytes32 indexed vcId, - uint256 balanceA, - uint256 balanceB - ); - - struct Channel { - //TODO: figure out if it's better just to split arrays by balances/deposits instead of eth/erc20 - address[2] partyAddresses; // 0: partyA 1: partyI - uint256[4] ethBalances; // 0: balanceA 1:balanceI 2:depositedA 3:depositedI - uint256[4] erc20Balances; // 0: balanceA 1:balanceI 2:depositedA 3:depositedI - uint256[2] initialDeposit; // 0: eth 1: tokens - uint256 sequence; - uint256 confirmTime; - bytes32 VCrootHash; - uint256 LCopenTimeout; - uint256 updateLCtimeout; // when update LC times out - bool isOpen; // true when both parties have joined - bool isUpdateLCSettling; - uint256 numOpenVC; - HumanStandardToken token; - } - - // virtual-channel state - struct VirtualChannel { - bool isClose; - bool isInSettlementState; - uint256 sequence; - address challenger; // Initiator of challenge - uint256 updateVCtimeout; // when update VC times out - // channel state - address partyA; // VC participant A - address partyB; // VC participant B - address partyI; // LC hub - uint256[2] ethBalances; - uint256[2] erc20Balances; - uint256[2] bond; - HumanStandardToken token; - } - - mapping(bytes32 => VirtualChannel) public virtualChannels; - mapping(bytes32 => Channel) public Channels; - - function createChannel( - bytes32 _lcID, - address _partyI, - uint256 _confirmTime, - address _token, - uint256[2] _balances // [eth, token] - ) - public - payable - { - require(Channels[_lcID].partyAddresses[0] == address(0), "Channel has already been created."); - require(_partyI != 0x0, "No partyI address provided to LC creation"); - require(_balances[0] >= 0 && _balances[1] >= 0, "Balances cannot be negative"); - // Set initial ledger channel state - // Alice must execute this and we assume the initial state - // to be signed from this requirement - // Alternative is to check a sig as in joinChannel - Channels[_lcID].partyAddresses[0] = msg.sender; - Channels[_lcID].partyAddresses[1] = _partyI; - - if(_balances[0] != 0) { - require(msg.value == _balances[0], "Eth balance does not match sent value"); - Channels[_lcID].ethBalances[0] = msg.value; - } - if(_balances[1] != 0) { - Channels[_lcID].token = HumanStandardToken(_token); - require(Channels[_lcID].token.transferFrom(msg.sender, this, _balances[1]),"CreateChannel: token transfer failure"); - Channels[_lcID].erc20Balances[0] = _balances[1]; - } - - Channels[_lcID].sequence = 0; - Channels[_lcID].confirmTime = _confirmTime; - // is close flag, lc state sequence, number open vc, vc root hash, partyA... - //Channels[_lcID].stateHash = keccak256(uint256(0), uint256(0), uint256(0), bytes32(0x0), bytes32(msg.sender), bytes32(_partyI), balanceA, balanceI); - Channels[_lcID].LCopenTimeout = now + _confirmTime; - Channels[_lcID].initialDeposit = _balances; - - emit DidLCOpen(_lcID, msg.sender, _partyI, _balances[0], _token, _balances[1], Channels[_lcID].LCopenTimeout); - } - - function LCOpenTimeout(bytes32 _lcID) public { - require(msg.sender == Channels[_lcID].partyAddresses[0] && Channels[_lcID].isOpen == false); - require(now > Channels[_lcID].LCopenTimeout); - - if(Channels[_lcID].initialDeposit[0] != 0) { - Channels[_lcID].partyAddresses[0].transfer(Channels[_lcID].ethBalances[0]); - } - if(Channels[_lcID].initialDeposit[1] != 0) { - require(Channels[_lcID].token.transfer(Channels[_lcID].partyAddresses[0], Channels[_lcID].erc20Balances[0]),"CreateChannel: token transfer failure"); - } - - emit DidLCClose(_lcID, 0, Channels[_lcID].ethBalances[0], Channels[_lcID].erc20Balances[0], 0, 0); - - // only safe to delete since no action was taken on this channel - delete Channels[_lcID]; - } - - function joinChannel(bytes32 _lcID, uint256[2] _balances) public payable { - // require the channel is not open yet - require(Channels[_lcID].isOpen == false); - require(msg.sender == Channels[_lcID].partyAddresses[1]); - - if(_balances[0] != 0) { - require(msg.value == _balances[0], "state balance does not match sent value"); - Channels[_lcID].ethBalances[1] = msg.value; - } - if(_balances[1] != 0) { - require(Channels[_lcID].token.transferFrom(msg.sender, this, _balances[1]),"joinChannel: token transfer failure"); - Channels[_lcID].erc20Balances[1] = _balances[1]; - } - - Channels[_lcID].initialDeposit[0]+=_balances[0]; - Channels[_lcID].initialDeposit[1]+=_balances[1]; - // no longer allow joining functions to be called - Channels[_lcID].isOpen = true; - numChannels++; - - emit DidLCJoin(_lcID, _balances[0], _balances[1]); - } - - - // additive updates of monetary state - // TODO check this for attack vectors - function deposit(bytes32 _lcID, address recipient, uint256 _balance, bool isToken) public payable { - require(Channels[_lcID].isOpen == true, "Tried adding funds to a closed channel"); - require(recipient == Channels[_lcID].partyAddresses[0] || recipient == Channels[_lcID].partyAddresses[1]); - - //if(Channels[_lcID].token) - - if (Channels[_lcID].partyAddresses[0] == recipient) { - if(isToken) { - require(Channels[_lcID].token.transferFrom(msg.sender, this, _balance),"deposit: token transfer failure"); - Channels[_lcID].erc20Balances[2] += _balance; - } else { - require(msg.value == _balance, "state balance does not match sent value"); - Channels[_lcID].ethBalances[2] += msg.value; - } - } - - if (Channels[_lcID].partyAddresses[1] == recipient) { - if(isToken) { - require(Channels[_lcID].token.transferFrom(msg.sender, this, _balance),"deposit: token transfer failure"); - Channels[_lcID].erc20Balances[3] += _balance; - } else { - require(msg.value == _balance, "state balance does not match sent value"); - Channels[_lcID].ethBalances[3] += msg.value; - } - } - - emit DidLCDeposit(_lcID, recipient, _balance, isToken); - } - - // TODO: Check there are no open virtual channels, the client should have cought this before signing a close LC state update - function consensusCloseChannel( - bytes32 _lcID, - uint256 _sequence, - uint256[4] _balances, // 0: ethBalanceA 1:ethBalanceI 2:tokenBalanceA 3:tokenBalanceI - string _sigA, - string _sigI - ) - public - { - // assume num open vc is 0 and root hash is 0x0 - //require(Channels[_lcID].sequence < _sequence); - require(Channels[_lcID].isOpen == true); - uint256 totalEthDeposit = Channels[_lcID].initialDeposit[0] + Channels[_lcID].ethBalances[2] + Channels[_lcID].ethBalances[3]; - uint256 totalTokenDeposit = Channels[_lcID].initialDeposit[1] + Channels[_lcID].erc20Balances[2] + Channels[_lcID].erc20Balances[3]; - require(totalEthDeposit == _balances[0] + _balances[1]); - require(totalTokenDeposit == _balances[2] + _balances[3]); - - bytes32 _state = keccak256( - abi.encodePacked( - _lcID, - true, - _sequence, - uint256(0), - bytes32(0x0), - Channels[_lcID].partyAddresses[0], - Channels[_lcID].partyAddresses[1], - _balances[0], - _balances[1], - _balances[2], - _balances[3] - ) - ); - - require(Channels[_lcID].partyAddresses[0] == ECTools.recoverSigner(_state, _sigA)); - require(Channels[_lcID].partyAddresses[1] == ECTools.recoverSigner(_state, _sigI)); - - Channels[_lcID].isOpen = false; - - if(_balances[0] != 0 || _balances[1] != 0) { - Channels[_lcID].partyAddresses[0].transfer(_balances[0]); - Channels[_lcID].partyAddresses[1].transfer(_balances[1]); - } - - if(_balances[2] != 0 || _balances[3] != 0) { - require(Channels[_lcID].token.transfer(Channels[_lcID].partyAddresses[0], _balances[2]),"happyCloseChannel: token transfer failure"); - require(Channels[_lcID].token.transfer(Channels[_lcID].partyAddresses[1], _balances[3]),"happyCloseChannel: token transfer failure"); - } - - numChannels--; - - emit DidLCClose(_lcID, _sequence, _balances[0], _balances[1], _balances[2], _balances[3]); - } - - // Byzantine functions - - function updateLCstate( - bytes32 _lcID, - uint256[6] updateParams, // [sequence, numOpenVc, ethbalanceA, ethbalanceI, tokenbalanceA, tokenbalanceI] - bytes32 _VCroot, - string _sigA, - string _sigI - ) - public - { - Channel storage channel = Channels[_lcID]; - require(channel.isOpen); - require(channel.sequence < updateParams[0]); // do same as vc sequence check - require(channel.ethBalances[0] + channel.ethBalances[1] >= updateParams[2] + updateParams[3]); - require(channel.erc20Balances[0] + channel.erc20Balances[1] >= updateParams[4] + updateParams[5]); - - if(channel.isUpdateLCSettling == true) { - require(channel.updateLCtimeout > now); - } - - bytes32 _state = keccak256( - abi.encodePacked( - _lcID, - false, - updateParams[0], - updateParams[1], - _VCroot, - channel.partyAddresses[0], - channel.partyAddresses[1], - updateParams[2], - updateParams[3], - updateParams[4], - updateParams[5] - ) - ); - - require(channel.partyAddresses[0] == ECTools.recoverSigner(_state, _sigA)); - require(channel.partyAddresses[1] == ECTools.recoverSigner(_state, _sigI)); - - // update LC state - channel.sequence = updateParams[0]; - channel.numOpenVC = updateParams[1]; - channel.ethBalances[0] = updateParams[2]; - channel.ethBalances[1] = updateParams[3]; - channel.erc20Balances[0] = updateParams[4]; - channel.erc20Balances[1] = updateParams[5]; - channel.VCrootHash = _VCroot; - channel.isUpdateLCSettling = true; - channel.updateLCtimeout = now + channel.confirmTime; - - // make settlement flag - - emit DidLCUpdateState ( - _lcID, - updateParams[0], - updateParams[1], - updateParams[2], - updateParams[3], - updateParams[4], - updateParams[5], - _VCroot, - channel.updateLCtimeout - ); - } - - // supply initial state of VC to "prime" the force push game - function initVCstate( - bytes32 _lcID, - bytes32 _vcID, - bytes _proof, - address _partyA, - address _partyB, - uint256[2] _bond, - uint256[4] _balances, // 0: ethBalanceA 1:ethBalanceI 2:tokenBalanceA 3:tokenBalanceI - string sigA - ) - public - { - require(Channels[_lcID].isOpen, "LC is closed."); - // sub-channel must be open - require(!virtualChannels[_vcID].isClose, "VC is closed."); - // Check time has passed on updateLCtimeout and has not passed the time to store a vc state - require(Channels[_lcID].updateLCtimeout < now, "LC timeout over."); - // prevent rentry of initializing vc state - require(virtualChannels[_vcID].updateVCtimeout == 0); - // partyB is now Ingrid - bytes32 _initState = keccak256( - abi.encodePacked(_vcID, uint256(0), _partyA, _partyB, _bond[0], _bond[1], _balances[0], _balances[1], _balances[2], _balances[3]) - ); - - // Make sure Alice has signed initial vc state (A/B in oldState) - require(_partyA == ECTools.recoverSigner(_initState, sigA)); - - // Check the oldState is in the root hash - require(_isContained(_initState, _proof, Channels[_lcID].VCrootHash) == true); - - virtualChannels[_vcID].partyA = _partyA; // VC participant A - virtualChannels[_vcID].partyB = _partyB; // VC participant B - virtualChannels[_vcID].sequence = uint256(0); - virtualChannels[_vcID].ethBalances[0] = _balances[0]; - virtualChannels[_vcID].ethBalances[1] = _balances[1]; - virtualChannels[_vcID].erc20Balances[0] = _balances[2]; - virtualChannels[_vcID].erc20Balances[1] = _balances[3]; - virtualChannels[_vcID].bond = _bond; - virtualChannels[_vcID].updateVCtimeout = now + Channels[_lcID].confirmTime; - - emit DidVCInit(_lcID, _vcID, _proof, uint256(0), _partyA, _partyB, _balances[0], _balances[1]); - } - - //TODO: verify state transition since the hub did not agree to this state - // make sure the A/B balances are not beyond ingrids bonds - // Params: vc init state, vc final balance, vcID - function settleVC( - bytes32 _lcID, - bytes32 _vcID, - uint256 updateSeq, - address _partyA, - address _partyB, - uint256[4] updateBal, // [ethupdateBalA, ethupdateBalB, tokenupdateBalA, tokenupdateBalB] - string sigA - ) - public - { - require(Channels[_lcID].isOpen, "LC is closed."); - // sub-channel must be open - require(!virtualChannels[_vcID].isClose, "VC is closed."); - require(virtualChannels[_vcID].sequence < updateSeq, "VC sequence is higher than update sequence."); - require( - virtualChannels[_vcID].ethBalances[1] < updateBal[1] && virtualChannels[_vcID].erc20Balances[1] < updateBal[3], - "State updates may only increase recipient balance." - ); - require( - virtualChannels[_vcID].bond[0] == updateBal[0] + updateBal[1] && - virtualChannels[_vcID].bond[1] == updateBal[2] + updateBal[3], - "Incorrect balances for bonded amount"); - // Check time has passed on updateLCtimeout and has not passed the time to store a vc state - // virtualChannels[_vcID].updateVCtimeout should be 0 on uninitialized vc state, and this should - // fail if initVC() isn't called first - //require(Channels[_lcID].updateLCtimeout < now && now < virtualChannels[_vcID].updateVCtimeout); - require(Channels[_lcID].updateLCtimeout < now); // for testing! - - bytes32 _updateState = keccak256( - abi.encodePacked( - _vcID, - updateSeq, - _partyA, - _partyB, - virtualChannels[_vcID].bond[0], - virtualChannels[_vcID].bond[1], - updateBal[0], - updateBal[1], - updateBal[2], - updateBal[3] - ) - ); - - // Make sure Alice has signed a higher sequence new state - require(virtualChannels[_vcID].partyA == ECTools.recoverSigner(_updateState, sigA)); - - // store VC data - // we may want to record who is initiating on-chain settles - virtualChannels[_vcID].challenger = msg.sender; - virtualChannels[_vcID].sequence = updateSeq; - - // channel state - virtualChannels[_vcID].ethBalances[0] = updateBal[0]; - virtualChannels[_vcID].ethBalances[1] = updateBal[1]; - virtualChannels[_vcID].erc20Balances[0] = updateBal[2]; - virtualChannels[_vcID].erc20Balances[1] = updateBal[3]; - - virtualChannels[_vcID].updateVCtimeout = now + Channels[_lcID].confirmTime; - virtualChannels[_vcID].isInSettlementState = true; - - emit DidVCSettle(_lcID, _vcID, updateSeq, updateBal[0], updateBal[1], msg.sender, virtualChannels[_vcID].updateVCtimeout); - } - - function closeVirtualChannel(bytes32 _lcID, bytes32 _vcID) public { - // require(updateLCtimeout > now) - require(Channels[_lcID].isOpen, "LC is closed."); - require(virtualChannels[_vcID].isInSettlementState, "VC is not in settlement state."); - require(virtualChannels[_vcID].updateVCtimeout < now, "Update vc timeout has not elapsed."); - // reduce the number of open virtual channels stored on LC - Channels[_lcID].numOpenVC--; - // close vc flags - virtualChannels[_vcID].isClose = true; - // re-introduce the balances back into the LC state from the settled VC - // decide if this lc is alice or bob in the vc - if(virtualChannels[_vcID].partyA == Channels[_lcID].partyAddresses[0]) { - Channels[_lcID].ethBalances[0] += virtualChannels[_vcID].ethBalances[0]; - Channels[_lcID].ethBalances[1] += virtualChannels[_vcID].ethBalances[1]; - - Channels[_lcID].erc20Balances[0] += virtualChannels[_vcID].erc20Balances[0]; - Channels[_lcID].erc20Balances[1] += virtualChannels[_vcID].erc20Balances[1]; - } else if (virtualChannels[_vcID].partyB == Channels[_lcID].partyAddresses[0]) { - Channels[_lcID].ethBalances[0] += virtualChannels[_vcID].ethBalances[1]; - Channels[_lcID].ethBalances[1] += virtualChannels[_vcID].ethBalances[0]; - - Channels[_lcID].erc20Balances[0] += virtualChannels[_vcID].erc20Balances[1]; - Channels[_lcID].erc20Balances[1] += virtualChannels[_vcID].erc20Balances[0]; - } - - emit DidVCClose(_lcID, _vcID, virtualChannels[_vcID].erc20Balances[0], virtualChannels[_vcID].erc20Balances[1]); - } - - - // todo: allow ethier lc.end-user to nullify the settled LC state and return to off-chain - function byzantineCloseChannel(bytes32 _lcID) public { - Channel storage channel = Channels[_lcID]; - - // check settlement flag - require(channel.isUpdateLCSettling == true); - require(channel.numOpenVC == 0); - require(channel.updateLCtimeout < now, "LC timeout over."); - - // if off chain state update didnt reblance deposits, just return to deposit owner - uint256 totalEthDeposit = channel.initialDeposit[0] + channel.ethBalances[2] + channel.ethBalances[3]; - uint256 totalTokenDeposit = channel.initialDeposit[1] + channel.erc20Balances[2] + channel.erc20Balances[3]; - - uint256 possibleTotalEthBeforeDeposit = channel.ethBalances[0] + channel.ethBalances[1]; - uint256 possibleTotalTokenBeforeDeposit = channel.erc20Balances[0] + channel.erc20Balances[1]; - - if(possibleTotalEthBeforeDeposit < totalEthDeposit) { - channel.ethBalances[0]+=channel.ethBalances[2]; - channel.ethBalances[1]+=channel.ethBalances[3]; - } else { - require(possibleTotalEthBeforeDeposit == totalEthDeposit); - } - - if(possibleTotalTokenBeforeDeposit < totalTokenDeposit) { - channel.erc20Balances[0]+=channel.erc20Balances[2]; - channel.erc20Balances[1]+=channel.erc20Balances[3]; - } else { - require(possibleTotalTokenBeforeDeposit == totalTokenDeposit); - } - - // reentrancy - uint256 ethbalanceA = channel.ethBalances[0]; - uint256 ethbalanceI = channel.ethBalances[1]; - uint256 tokenbalanceA = channel.erc20Balances[0]; - uint256 tokenbalanceI = channel.erc20Balances[1]; - - channel.ethBalances[0] = 0; - channel.ethBalances[1] = 0; - channel.erc20Balances[0] = 0; - channel.erc20Balances[1] = 0; - - if(ethbalanceA != 0 || ethbalanceI != 0) { - channel.partyAddresses[0].transfer(ethbalanceA); - channel.partyAddresses[1].transfer(ethbalanceI); - } - - if(tokenbalanceA != 0 || tokenbalanceI != 0) { - require( - channel.token.transfer(channel.partyAddresses[0], tokenbalanceA), - "byzantineCloseChannel: token transfer failure" - ); - require( - channel.token.transfer(channel.partyAddresses[1], tokenbalanceI), - "byzantineCloseChannel: token transfer failure" - ); - } - - channel.isOpen = false; - numChannels--; - - emit DidLCClose(_lcID, channel.sequence, ethbalanceA, ethbalanceI, tokenbalanceA, tokenbalanceI); - } - - function _isContained(bytes32 _hash, bytes _proof, bytes32 _root) internal pure returns (bool) { - bytes32 cursor = _hash; - bytes32 proofElem; - - for (uint256 i = 64; i <= _proof.length; i += 32) { - assembly { proofElem := mload(add(_proof, i)) } - - if (cursor < proofElem) { - cursor = keccak256(abi.encodePacked(cursor, proofElem)); - } else { - cursor = keccak256(abi.encodePacked(proofElem, cursor)); - } - } - - return cursor == _root; - } - - //Struct Getters - function getChannel(bytes32 id) public view returns ( - address[2], - uint256[4], - uint256[4], - uint256[2], - uint256, - uint256, - bytes32, - uint256, - uint256, - bool, - bool, - uint256 - ) { - Channel memory channel = Channels[id]; - return ( - channel.partyAddresses, - channel.ethBalances, - channel.erc20Balances, - channel.initialDeposit, - channel.sequence, - channel.confirmTime, - channel.VCrootHash, - channel.LCopenTimeout, - channel.updateLCtimeout, - channel.isOpen, - channel.isUpdateLCSettling, - channel.numOpenVC - ); - } - - function getVirtualChannel(bytes32 id) public view returns( - bool, - bool, - uint256, - address, - uint256, - address, - address, - address, - uint256[2], - uint256[2], - uint256[2] - ) { - VirtualChannel memory virtualChannel = virtualChannels[id]; - return( - virtualChannel.isClose, - virtualChannel.isInSettlementState, - virtualChannel.sequence, - virtualChannel.challenger, - virtualChannel.updateVCtimeout, - virtualChannel.partyA, - virtualChannel.partyB, - virtualChannel.partyI, - virtualChannel.ethBalances, - virtualChannel.erc20Balances, - virtualChannel.bond - ); - } -} diff --git a/migrations/2_deploy_contracts.js b/migrations/2_deploy_contracts.js index a543b32..af7b0bb 100644 --- a/migrations/2_deploy_contracts.js +++ b/migrations/2_deploy_contracts.js @@ -1,8 +1,8 @@ var EC = artifacts.require("./ECTools.sol"); -var LC = artifacts.require("./LedgerChannel.sol"); +var CM = artifacts.require("./ChannelManager.sol"); module.exports = async function(deployer) { deployer.deploy(EC); - deployer.link(EC, LC); - deployer.deploy(LC); + deployer.link(EC, CM); + deployer.deploy(CM); }; diff --git a/package.json b/package.json index e1212cf..bc3b265 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,9 @@ }, "dependencies": { "buffer": "^5.0.7", + "chai": "^4.1.2", + "chai-as-promised": "^7.1.1", + "chai-bignumber": "^2.0.2", "ethereumjs-abi": "^0.6.5", "ethereumjs-util": "^5.1.5", "truffle-hdwallet-provider-privkey": "^0.2.0", diff --git a/test/scenarios/CoopEthTokenTest.js b/test/scenarios/CoopEthTokenTest.js index feb3f47..86d702e 100644 --- a/test/scenarios/CoopEthTokenTest.js +++ b/test/scenarios/CoopEthTokenTest.js @@ -1,466 +1,466 @@ -'use strict' - -import MerkleTree from '../helpers/MerkleTree' -const Utils = require('../helpers/utils') -const Ledger = artifacts.require('./LedgerChannel.sol') -const EC = artifacts.require('./ECTools.sol') -const Token = artifacts.require('./token/HumanStandardToken.sol') - -const Web3latest = require('web3') -const web3latest = new Web3latest(new Web3latest.providers.HttpProvider("http://localhost:8545")) //ganache port - - -let lc -let token - -// state - -let partyA -let partyB -let partyI - -let lcid_AI -let lcid_BI - -let vcRootHash - -// is close flag, lc state sequence, number open vc, vc root hash, partyA/B, partyI, balA/B, balI - -let AI_lcS0 -let AI_lcS1 -let AI_lcS2 -let AI_lcS3 - -let BI_lcS0 -let BI_lcS1 -let BI_lcS2 - -let AB_vcS0 -let AB_vcS1 - -let AB_vc2_S0 -let AB_vc2_S1 - -// signature storage -let AI_lcS0_sigA -let AI_lcS1_sigA -let AI_lcS2_sigA -let AI_lcS3_sigA - -let AI_lcS0_sigI -let AI_lcS1_sigI -let AI_lcS2_sigI -let AI_lcS3_sigI - -let BI_lcS0_sigB -let BI_lcS1_sigB -let BI_lcS2_sigB - -let BI_lcS0_sigI -let BI_lcS1_sigI -let BI_lcS2_sigI - -let AB_vcS0_sigA -let AB_vcS1_sigA - -let AB_vcS0_sigB -let AB_vcS1_sigB - -contract('Test Cooperative Token and Eth Payments', function(accounts) { - - before(async () => { - partyA = accounts[0] - partyB = accounts[1] - partyI = accounts[2] - - let ec = await EC.new() - token = await Token.new(web3latest.utils.toWei('1000'), 'Test', 1, 'TST') - Ledger.link('HumanStandardToken', token.address) - Ledger.link('ECTools', ec.address) - lc = await Ledger.new() - await token.transfer(partyB, web3latest.utils.toWei('100')) - await token.transfer(partyI, web3latest.utils.toWei('100')) - }) - - it("Create initial ledger channel state lcS0 for AI channel", async () => { - lcid_AI = web3latest.utils.sha3('1111', {encoding: 'hex'}) - AI_lcS0 = web3latest.utils.soliditySha3( - { type: 'uint256', value: lcid_AI }, // ID - { type: 'bool', value: false }, // isclose - //{ type: 'bytes32', value: web3.sha3('lc2', {encoding: 'hex'}) }, // lcid - { type: 'uint256', value: 0 }, // sequence - { type: 'uint256', value: 0 }, // open VCs - { type: 'string', value: '0x0' }, // VC root hash - { type: 'address', value: partyA }, // partyA - { type: 'address', value: partyI }, // hub - { type: 'uint256', value: web3latest.utils.toWei('10') }, // eth - { type: 'uint256', value: web3latest.utils.toWei('20') }, // eth - { type: 'uint256', value: web3latest.utils.toWei('10') }, // token - { type: 'uint256', value: web3latest.utils.toWei('20') } // token - ) - }) - - it("Alice signs initial lcS0 state", async () => { - AI_lcS0_sigA = await web3latest.eth.sign(AI_lcS0, partyA) - }) - - // address[2] partyAdresses; // 0: partyA 1: partyI - // uint256[2] ethBalances; // 0: balanceA 1:balanceI - // uint256[2] erc20Balances; // 0: balanceA 1:balanceI - // uint256[2] deposited; - // uint256 initialDeposit; - // uint256 sequence; - // uint256 confirmTime; - // bytes32 VCrootHash; - // uint256 LCopenTimeout; - // uint256 updateLCtimeout; // when update LC times out - // bool isOpen; // true when both parties have joined - // bool isUpdateLCSettling; - // uint256 numOpenVC; - - - it("Alice initiates ledger channel with lcS0", async () => { - let approval = await token.approve(lc.address, web3latest.utils.toWei('10')) - let res = await lc.createChannel(lcid_AI, partyI, '0', token.address, [web3latest.utils.toWei('10'), web3latest.utils.toWei('10')], {from:partyA, value: web3latest.utils.toWei('10')}) - var gasUsed = res.receipt.gasUsed - //console.log('createChan: '+ gasUsed) - let openChans = await lc.numChannels() - let chan = await lc.getChannel(lcid_AI) - assert.equal(chan[0].toString(), [partyA,partyI]) //check partyAddresses - assert.equal(chan[1].toString(), [web3latest.utils.toWei('10'), '0', '0', '0']) //check ethBalances - assert.equal(chan[2].toString(), [web3latest.utils.toWei('10'), '0', '0', '0']) //check erc20Balances - assert.equal(chan[3].toString(), [web3latest.utils.toWei('10'), web3latest.utils.toWei('10')]) //check initalDeposit - assert.equal(chan[4].toString(), '0') //check sequence - assert.equal(chan[5].toString(), '0') //check confirmTime - assert.equal(chan[6], '0x0000000000000000000000000000000000000000000000000000000000000000') //check VCrootHash - //check if chan[7] is equal to now + confirmtime - assert.equal(chan[8].toString(), '0') //check updateLCTimeout - assert.equal(chan[9], false) //check isOpen - assert.equal(chan[10], false) //check isUpdateLCSettling - assert.equal(chan[11], '0') //check numOpenVC - }) - - it("Hub signs initial lcS0 state", async () => { - AI_lcS0_sigI = await web3latest.eth.sign(AI_lcS0, partyI) - }) - - it("Ingrid joins ledger channel", async () => { - let approval = await token.approve(lc.address, web3latest.utils.toWei('20'), {from: partyI}) - let res = await lc.joinChannel(lcid_AI, [web3latest.utils.toWei('20'), web3latest.utils.toWei('20')], {from: partyI, value: web3latest.utils.toWei('20')}) - var gasUsed = res.receipt.gasUsed - //console.log('joinChan: '+ gasUsed) - let openChans = await lc.numChannels() - let chan = await lc.getChannel(lcid_AI) - assert.equal(chan[0].toString(), [partyA,partyI]) //check partyAddresses - assert.equal(chan[1].toString(), [web3latest.utils.toWei('10'), web3latest.utils.toWei('20'), '0', '0']) //check ethBalances - assert.equal(chan[2].toString(), [web3latest.utils.toWei('10'), web3latest.utils.toWei('20'), '0', '0']) //check erc20Balances - assert.equal(chan[3].toString(), [web3latest.utils.toWei('30'), web3latest.utils.toWei('30')]) //check initalDeposit - assert.equal(chan[4].toString(), '0') //check sequence - assert.equal(chan[5].toString(), '0') //check confirmTime - assert.equal(chan[6], '0x0000000000000000000000000000000000000000000000000000000000000000') //check VCrootHash - //check if chan[7] is equal to now + confirmtime - assert.equal(chan[8].toString(), '0') //check updateLCTimeout - assert.equal(chan[9], true) //check isOpen - assert.equal(chan[10], false) //check isUpdateLCSettling - assert.equal(chan[11], '0') //check numOpenVC - }) - - // Bob creates ledger channel - it("Create Bob's ledger channel state lcS0 for BI channel", async () => { - lcid_BI = web3latest.utils.sha3('2222', {encoding: 'hex'}) - - BI_lcS0 = web3latest.utils.soliditySha3( - { type: 'uint256', value: lcid_BI }, // ID - { type: 'bool', value: false }, // isclose - //{ type: 'bytes32', value: web3.sha3('lc4', {encoding: 'hex'}) }, // lcid - { type: 'uint256', value: 0 }, // sequence - { type: 'uint256', value: 0 }, // open VCs - { type: 'string', value: '0x0' }, // VC root hash - { type: 'address', value: partyB }, // partyA - { type: 'address', value: partyI }, // hub - { type: 'uint256', value: web3latest.utils.toWei('10') }, - { type: 'uint256', value: web3latest.utils.toWei('20') }, - { type: 'uint256', value: web3latest.utils.toWei('10') }, // token - { type: 'uint256', value: web3latest.utils.toWei('20') } // token - ) - }) - - it("Bob signs initial lcS0 state", async () => { - BI_lcS0_sigB = await web3latest.eth.sign(BI_lcS0, partyB) - }) - - - it("Bob initiates ledger channel with lcS0", async () => { - let approval = await token.approve(lc.address, web3latest.utils.toWei('10'), {from: partyB}) - await lc.createChannel(lcid_BI, partyI, '0', token.address, [web3latest.utils.toWei('10'), web3latest.utils.toWei('10')], {from:partyB, value: web3latest.utils.toWei('10')}) - let openChans = await lc.numChannels() - let chan = await lc.getChannel(lcid_BI) - assert.equal(chan[0].toString(), [partyB,partyI]) //check partyAddresses - assert.equal(chan[1].toString(), [web3latest.utils.toWei('10'), '0', '0', '0']) //check ethBalances - assert.equal(chan[2].toString(), [web3latest.utils.toWei('10'), '0', '0', '0']) //check erc20Balances - assert.equal(chan[3].toString(), [web3latest.utils.toWei('10'),web3latest.utils.toWei('10')]) //check initalDeposit - assert.equal(chan[4].toString(), '0') //check sequence - assert.equal(chan[5].toString(), '0') //check confirmTime - assert.equal(chan[6], '0x0000000000000000000000000000000000000000000000000000000000000000') //check VCrootHash - //check if chan[7] is equal to now + confirmtime - assert.equal(chan[8].toString(), '0') //check updateLCTimeout - assert.equal(chan[9], false) //check isOpen - assert.equal(chan[10], false) //check isUpdateLCSettling - assert.equal(chan[11], '0') //check numOpenVC - }) - - it("Hub signs initial lcS0 state", async () => { - BI_lcS0_sigI = await web3latest.eth.sign(BI_lcS0, partyI) - }) - - it("Ingrid joins ledger channel", async () => { - let approval = await token.approve(lc.address, web3latest.utils.toWei('20'), {from: partyI}) - await lc.joinChannel(lcid_BI, [web3latest.utils.toWei('20'), web3latest.utils.toWei('20')], {from: partyI, value: web3latest.utils.toWei('20')}) - let openChans = await lc.numChannels() - let chan = await lc.getChannel(lcid_BI) - assert.equal(chan[0].toString(), [partyB,partyI]) //check partyAddresses - assert.equal(chan[1].toString(), [web3latest.utils.toWei('10'), web3latest.utils.toWei('20'), '0', '0']) //check ethBalances - assert.equal(chan[2].toString(), [web3latest.utils.toWei('10'), web3latest.utils.toWei('20'), '0', '0']) //check erc20Balances - assert.equal(chan[3].toString(), [web3latest.utils.toWei('30'), web3latest.utils.toWei('30')]) //check initalDeposit - assert.equal(chan[4].toString(), '0') //check sequence - assert.equal(chan[5].toString(), '0') //check confirmTime - assert.equal(chan[6], '0x0000000000000000000000000000000000000000000000000000000000000000') //check VCrootHash - //check if chan[7] is equal to now + confirmtime - assert.equal(chan[8].toString(), '0') //check updateLCTimeout - assert.equal(chan[9], true) //check isOpen - assert.equal(chan[10], false) //check isUpdateLCSettling - assert.equal(chan[11], '0') //check numOpenVC - }) - - - it("Alice creates vc state vcSO with Bob", async () => { - AB_vcS0 = web3latest.utils.soliditySha3( - { type: 'bytes32', value: web3latest.utils.sha3('1337', {encoding: 'hex'}) }, // vc id - { type: 'uint256', value: 0 }, // sequence - { type: 'address', value: partyA }, // partyA - { type: 'address', value: partyB }, // partyB, - { type: 'uint256', value: web3latest.utils.toWei('12') }, // hub eth bond - { type: 'uint256', value: web3latest.utils.toWei('12')}, //hub token bond - { type: 'uint256', value: web3latest.utils.toWei('5') }, - { type: 'uint256', value: web3latest.utils.toWei('7') }, - { type: 'uint256', value: web3latest.utils.toWei('5') }, // token - { type: 'uint256', value: web3latest.utils.toWei('7') } // token - ) - - }) - - it("Alice and Bob sign vcSO", async () => { - AB_vcS0_sigA = await web3latest.eth.sign(AB_vcS0, partyA) - AB_vcS0_sigB = await web3latest.eth.sign(AB_vcS0, partyB) - }) - - it("Alice creates lc state lcS1 containing vcSO with Ingrid", async () => { - var hash = web3latest.utils.sha3(AB_vcS0, {encoding: 'hex'}) - var buf = Utils.hexToBuffer(hash) - var elems = [] - elems.push(buf) - elems.push(Utils.hexToBuffer('0x0000000000000000000000000000000000000000000000000000000000000000')) - var merkle = new MerkleTree(elems) - - vcRootHash = Utils.bufferToHex(merkle.getRoot()) - - AI_lcS1 = web3latest.utils.soliditySha3( - { type: 'uint256', value: lcid_AI }, - { type: 'bool', value: false }, // isclose - //{ type: 'bytes32', value: web3.sha3('lc2', {encoding: 'hex'}) }, // lcid - { type: 'uint256', value: 1 }, // sequence - { type: 'uint256', value: 1 }, // open VCs - { type: 'string', value: vcRootHash }, // VC root hash - { type: 'address', value: partyA }, // partyA - { type: 'address', value: partyI }, // hub - { type: 'uint256', value: web3latest.utils.toWei('5') }, //eth - { type: 'uint256', value: web3latest.utils.toWei('13') }, //eth - { type: 'uint256', value: web3latest.utils.toWei('5') }, // token - { type: 'uint256', value: web3latest.utils.toWei('13') } // token - ) - }) - - it("Alice signs lcS1 state and sends to Hub", async () => { - AI_lcS1_sigA = await web3latest.eth.sign(AI_lcS1, partyA) - }) - - it("Bob creates lc state lcS1 containing vcSO with Ingrid", async () => { - var hash = web3latest.utils.sha3(AB_vcS0, {encoding: 'hex'}) - var buf = Utils.hexToBuffer(hash) - var elems = [] - elems.push(buf) - elems.push(Utils.hexToBuffer('0x0000000000000000000000000000000000000000000000000000000000000000')) - var merkle = new MerkleTree(elems) - - vcRootHash = Utils.bufferToHex(merkle.getRoot()) - - BI_lcS1 = web3latest.utils.soliditySha3( - { type: 'uint256', value: lcid_BI }, - { type: 'bool', value: false }, // isclose - //{ type: 'bytes32', value: web3.sha3('lc4', {encoding: 'hex'}) }, // lcid - { type: 'uint256', value: 1 }, // sequence - { type: 'uint256', value: 1 }, // open VCs - { type: 'string', value: vcRootHash }, // VC root hash - { type: 'address', value: partyB }, // partyB - { type: 'address', value: partyI }, // hub - { type: 'uint256', value: web3latest.utils.toWei('3') }, //eth - { type: 'uint256', value: web3latest.utils.toWei('15') }, //eth - { type: 'uint256', value: web3latest.utils.toWei('3') }, // token - { type: 'uint256', value: web3latest.utils.toWei('15') } // token - ) - }) - - it("Bob signs lcS1 state and sends to hub", async () => { - BI_lcS1_sigB = await web3latest.eth.sign(BI_lcS1, partyB) - }) - - it("Hub signs both Alice and Bob's lcS1 state to open VC", async () => { - AI_lcS1_sigI = await web3latest.eth.sign(AI_lcS1, partyI) - BI_lcS1_sigI = await web3latest.eth.sign(BI_lcS1, partyI) - }) - - it("Alice generates virtual channel payment with Bob (vcS1)", async () => { - AB_vcS1 = web3latest.utils.soliditySha3( - { type: 'bytes32', value: web3latest.utils.sha3('1337', {encoding: 'hex'}) }, // vc id - { type: 'uint256', value: 1 }, // sequence - { type: 'address', value: partyA }, // partyA - { type: 'address', value: partyB }, // partyB - { type: 'uint256', value: web3latest.utils.toWei('12') }, // hub eth bond - { type: 'uint256', value: web3latest.utils.toWei('12') }, //hub token bond - { type: 'uint256', value: web3latest.utils.toWei('0') }, - { type: 'uint256', value: web3latest.utils.toWei('12') }, - { type: 'uint256', value: web3latest.utils.toWei('0') }, // token - { type: 'uint256', value: web3latest.utils.toWei('12') } // token - ) - - }) - - it("Alice and Bob sign vcS1", async () => { - AB_vcS1_sigA = await web3latest.eth.sign(AB_vcS1, partyA) - AB_vcS1_sigB = await web3latest.eth.sign(AB_vcS1, partyB) - }) - - it("Alice generates lc state to close vc", async () => { - AI_lcS2 = web3latest.utils.soliditySha3( - { type: 'uint256', value: lcid_AI }, - { type: 'bool', value: false }, // isclose - //{ type: 'bytes32', value: web3.sha3('lc2', {encoding: 'hex'}) }, // lcid - { type: 'uint256', value: 2 }, // sequence - { type: 'uint256', value: 0 }, // open VCs - { type: 'string', value: '0x0' }, // VC root hash - { type: 'address', value: partyA }, // partyA - { type: 'address', value: partyI }, // hub - { type: 'uint256', value: web3latest.utils.toWei('5') }, //eth - { type: 'uint256', value: web3latest.utils.toWei('25') }, //eth - { type: 'uint256', value: web3latest.utils.toWei('5') }, // token - { type: 'uint256', value: web3latest.utils.toWei('25') } // token - ) - - }) - - it("Bob generates lc state to close vc", async () => { - BI_lcS2 = web3latest.utils.soliditySha3( - { type: 'uint256', value: lcid_BI }, - { type: 'bool', value: false }, // isclose - //{ type: 'bytes32', value: web3.sha3('lc4', {encoding: 'hex'}) }, // lcid - { type: 'uint256', value: 2 }, // sequence - { type: 'uint256', value: 0 }, // open VCs - { type: 'string', value: '0x0' }, // VC root hash - { type: 'address', value: partyB }, // partyB - { type: 'address', value: partyI }, // hub - { type: 'uint256', value: web3latest.utils.toWei('15') }, //eth - { type: 'uint256', value: web3latest.utils.toWei('15') }, //eth - { type: 'uint256', value: web3latest.utils.toWei('15') }, // token - { type: 'uint256', value: web3latest.utils.toWei('15') } // token - ) - }) - - it("Alice signs lcS2 state and sends to Hub", async () => { - AI_lcS2_sigA = await web3latest.eth.sign(AI_lcS2, partyA) - }) - - it("Bob signs lcS2 state and sends to hub", async () => { - BI_lcS2_sigB = await web3latest.eth.sign(BI_lcS2, partyB) - }) - - it("Hub signs both Alice and Bob's lcS2 state to close VC", async () => { - AI_lcS2_sigI = await web3latest.eth.sign(AI_lcS2, partyI) - BI_lcS2_sigI = await web3latest.eth.sign(BI_lcS2, partyI) - }) - - it("Alice creates lc update to close vc", async () => { - AI_lcS3 = web3latest.utils.soliditySha3( - { type: 'uint256', value: lcid_AI }, - { type: 'bool', value: true }, // isclose - //{ type: 'bytes32', value: web3.sha3('lc2', {encoding: 'hex'}) }, // lcid - { type: 'uint256', value: '3' }, // sequence - { type: 'uint256', value: '0' }, // open VCs - { type: 'bytes32', value: '0x0' }, // VC root hash - { type: 'address', value: partyA }, // partyA - { type: 'address', value: partyI }, // hub - { type: 'uint256', value: web3latest.utils.toWei('5') }, - { type: 'uint256', value: web3latest.utils.toWei('25') }, - { type: 'uint256', value: web3latest.utils.toWei('5') }, // token - { type: 'uint256', value: web3latest.utils.toWei('25') } // token - ) - }) - - it("Alice signs lcS3 state and sends to Hub", async () => { - AI_lcS3_sigA = await web3latest.eth.sign(AI_lcS3, partyA) - }) - - it("Hub signs closing lcS3 state", async () => { - AI_lcS3_sigI = await web3latest.eth.sign(AI_lcS3, partyI) - }) - - it("Close Alice ledger channel", async () => { - var balA1e = await web3latest.eth.getBalance(partyA) - var balI1e = await web3latest.eth.getBalance(partyI) - var balA1t = await token.balanceOf(partyA) - var balI1t = await token.balanceOf(partyI) - let receipt = await lc.consensusCloseChannel(lcid_AI, '3', [web3latest.utils.toWei('5'), web3latest.utils.toWei('25'), web3latest.utils.toWei('5'), web3latest.utils.toWei('25')], AI_lcS3_sigA, AI_lcS3_sigI) - var gasUsed = receipt.receipt.gasUsed - //console.log('Close Channel: ' + gasUsed) - var balA2e = await web3latest.eth.getBalance(partyA) - var balI2e = await web3latest.eth.getBalance(partyI) - var balA2t = await token.balanceOf(partyA) - var balI2t = await token.balanceOf(partyI) - // TODO calculate gas, this may very based on testrpc - assert.equal(balI2e - balI1e, '25000000000000000000') - assert.equal(balI2t - balI1t, '25000000000000000000') - // assert.equal(balA2 - balA1, '7926958099999998000') - }) - - /******TO DO******/ - it("Hub deposits into Bob's lc", async () => { - await lc.deposit(lcid_BI, partyI, web3latest.utils.toWei('10'), false, {from:partyI, value:web3latest.utils.toWei('10')}) - let chan = await lc.getChannel(lcid_BI) - }) - - it("Hub creates lc state lcS2 containing new deposit", async () => { - var hash = web3latest.utils.sha3(AB_vcS0, {encoding: 'hex'}) - var buf = Utils.hexToBuffer(hash) - var elems = [] - elems.push(buf) - elems.push(Utils.hexToBuffer('0x0000000000000000000000000000000000000000000000000000000000000000')) - var merkle = new MerkleTree(elems) - - vcRootHash = Utils.bufferToHex(merkle.getRoot()) - - BI_lcS1 = web3latest.utils.soliditySha3( - { type: 'uint256', value: lcid_BI }, - { type: 'bool', value: false }, // isclose - //{ type: 'bytes32', value: web3.sha3('lc4', {encoding: 'hex'}) }, // lcid - { type: 'uint256', value: 2 }, // sequence - { type: 'uint256', value: 1 }, // open VCs - { type: 'string', value: vcRootHash }, // VC root hash - { type: 'address', value: partyB }, // partyA - { type: 'address', value: partyI }, // hub - { type: 'uint256', value: web3latest.utils.toWei('3') }, - { type: 'uint256', value: web3latest.utils.toWei('25') }, - { type: 'uint256', value: web3latest.utils.toWei('0') }, // token - { type: 'uint256', value: web3latest.utils.toWei('0') } // token - ) - }) - -}) \ No newline at end of file +// 'use strict' + +// import MerkleTree from '../helpers/MerkleTree' +// const Utils = require('../helpers/utils') +// const Ledger = artifacts.require('./LedgerChannel.sol') +// const EC = artifacts.require('./ECTools.sol') +// const Token = artifacts.require('./token/HumanStandardToken.sol') + +// const Web3latest = require('web3') +// const web3latest = new Web3latest(new Web3latest.providers.HttpProvider("http://localhost:8545")) //ganache port + + +// let lc +// let token + +// // state + +// let partyA +// let partyB +// let partyI + +// let lcid_AI +// let lcid_BI + +// let vcRootHash + +// // is close flag, lc state sequence, number open vc, vc root hash, partyA/B, partyI, balA/B, balI + +// let AI_lcS0 +// let AI_lcS1 +// let AI_lcS2 +// let AI_lcS3 + +// let BI_lcS0 +// let BI_lcS1 +// let BI_lcS2 + +// let AB_vcS0 +// let AB_vcS1 + +// let AB_vc2_S0 +// let AB_vc2_S1 + +// // signature storage +// let AI_lcS0_sigA +// let AI_lcS1_sigA +// let AI_lcS2_sigA +// let AI_lcS3_sigA + +// let AI_lcS0_sigI +// let AI_lcS1_sigI +// let AI_lcS2_sigI +// let AI_lcS3_sigI + +// let BI_lcS0_sigB +// let BI_lcS1_sigB +// let BI_lcS2_sigB + +// let BI_lcS0_sigI +// let BI_lcS1_sigI +// let BI_lcS2_sigI + +// let AB_vcS0_sigA +// let AB_vcS1_sigA + +// let AB_vcS0_sigB +// let AB_vcS1_sigB + +// contract('Test Cooperative Token and Eth Payments', function(accounts) { + +// before(async () => { +// partyA = accounts[0] +// partyB = accounts[1] +// partyI = accounts[2] + +// let ec = await EC.new() +// token = await Token.new(web3latest.utils.toWei('1000'), 'Test', 1, 'TST') +// Ledger.link('HumanStandardToken', token.address) +// Ledger.link('ECTools', ec.address) +// lc = await Ledger.new() +// await token.transfer(partyB, web3latest.utils.toWei('100')) +// await token.transfer(partyI, web3latest.utils.toWei('100')) +// }) + +// it("Create initial ledger channel state lcS0 for AI channel", async () => { +// lcid_AI = web3latest.utils.sha3('1111', {encoding: 'hex'}) +// AI_lcS0 = web3latest.utils.soliditySha3( +// { type: 'uint256', value: lcid_AI }, // ID +// { type: 'bool', value: false }, // isclose +// //{ type: 'bytes32', value: web3.sha3('lc2', {encoding: 'hex'}) }, // lcid +// { type: 'uint256', value: 0 }, // sequence +// { type: 'uint256', value: 0 }, // open VCs +// { type: 'string', value: '0x0' }, // VC root hash +// { type: 'address', value: partyA }, // partyA +// { type: 'address', value: partyI }, // hub +// { type: 'uint256', value: web3latest.utils.toWei('10') }, // eth +// { type: 'uint256', value: web3latest.utils.toWei('20') }, // eth +// { type: 'uint256', value: web3latest.utils.toWei('10') }, // token +// { type: 'uint256', value: web3latest.utils.toWei('20') } // token +// ) +// }) + +// it("Alice signs initial lcS0 state", async () => { +// AI_lcS0_sigA = await web3latest.eth.sign(AI_lcS0, partyA) +// }) + +// // address[2] partyAdresses; // 0: partyA 1: partyI +// // uint256[2] ethBalances; // 0: balanceA 1:balanceI +// // uint256[2] erc20Balances; // 0: balanceA 1:balanceI +// // uint256[2] deposited; +// // uint256 initialDeposit; +// // uint256 sequence; +// // uint256 confirmTime; +// // bytes32 VCrootHash; +// // uint256 LCopenTimeout; +// // uint256 updateLCtimeout; // when update LC times out +// // bool isOpen; // true when both parties have joined +// // bool isUpdateLCSettling; +// // uint256 numOpenVC; + + +// it("Alice initiates ledger channel with lcS0", async () => { +// let approval = await token.approve(lc.address, web3latest.utils.toWei('10')) +// let res = await lc.createChannel(lcid_AI, partyI, '0', token.address, [web3latest.utils.toWei('10'), web3latest.utils.toWei('10')], {from:partyA, value: web3latest.utils.toWei('10')}) +// var gasUsed = res.receipt.gasUsed +// //console.log('createChan: '+ gasUsed) +// let openChans = await lc.numChannels() +// let chan = await lc.getChannel(lcid_AI) +// assert.equal(chan[0].toString(), [partyA,partyI]) //check partyAddresses +// assert.equal(chan[1].toString(), [web3latest.utils.toWei('10'), '0', '0', '0']) //check ethBalances +// assert.equal(chan[2].toString(), [web3latest.utils.toWei('10'), '0', '0', '0']) //check erc20Balances +// assert.equal(chan[3].toString(), [web3latest.utils.toWei('10'), web3latest.utils.toWei('10')]) //check initalDeposit +// assert.equal(chan[4].toString(), '0') //check sequence +// assert.equal(chan[5].toString(), '0') //check confirmTime +// assert.equal(chan[6], '0x0000000000000000000000000000000000000000000000000000000000000000') //check VCrootHash +// //check if chan[7] is equal to now + confirmtime +// assert.equal(chan[8].toString(), '0') //check updateLCTimeout +// assert.equal(chan[9], false) //check isOpen +// assert.equal(chan[10], false) //check isUpdateLCSettling +// assert.equal(chan[11], '0') //check numOpenVC +// }) + +// it("Hub signs initial lcS0 state", async () => { +// AI_lcS0_sigI = await web3latest.eth.sign(AI_lcS0, partyI) +// }) + +// it("Ingrid joins ledger channel", async () => { +// let approval = await token.approve(lc.address, web3latest.utils.toWei('20'), {from: partyI}) +// let res = await lc.joinChannel(lcid_AI, [web3latest.utils.toWei('20'), web3latest.utils.toWei('20')], {from: partyI, value: web3latest.utils.toWei('20')}) +// var gasUsed = res.receipt.gasUsed +// //console.log('joinChan: '+ gasUsed) +// let openChans = await lc.numChannels() +// let chan = await lc.getChannel(lcid_AI) +// assert.equal(chan[0].toString(), [partyA,partyI]) //check partyAddresses +// assert.equal(chan[1].toString(), [web3latest.utils.toWei('10'), web3latest.utils.toWei('20'), '0', '0']) //check ethBalances +// assert.equal(chan[2].toString(), [web3latest.utils.toWei('10'), web3latest.utils.toWei('20'), '0', '0']) //check erc20Balances +// assert.equal(chan[3].toString(), [web3latest.utils.toWei('30'), web3latest.utils.toWei('30')]) //check initalDeposit +// assert.equal(chan[4].toString(), '0') //check sequence +// assert.equal(chan[5].toString(), '0') //check confirmTime +// assert.equal(chan[6], '0x0000000000000000000000000000000000000000000000000000000000000000') //check VCrootHash +// //check if chan[7] is equal to now + confirmtime +// assert.equal(chan[8].toString(), '0') //check updateLCTimeout +// assert.equal(chan[9], true) //check isOpen +// assert.equal(chan[10], false) //check isUpdateLCSettling +// assert.equal(chan[11], '0') //check numOpenVC +// }) + +// // Bob creates ledger channel +// it("Create Bob's ledger channel state lcS0 for BI channel", async () => { +// lcid_BI = web3latest.utils.sha3('2222', {encoding: 'hex'}) + +// BI_lcS0 = web3latest.utils.soliditySha3( +// { type: 'uint256', value: lcid_BI }, // ID +// { type: 'bool', value: false }, // isclose +// //{ type: 'bytes32', value: web3.sha3('lc4', {encoding: 'hex'}) }, // lcid +// { type: 'uint256', value: 0 }, // sequence +// { type: 'uint256', value: 0 }, // open VCs +// { type: 'string', value: '0x0' }, // VC root hash +// { type: 'address', value: partyB }, // partyA +// { type: 'address', value: partyI }, // hub +// { type: 'uint256', value: web3latest.utils.toWei('10') }, +// { type: 'uint256', value: web3latest.utils.toWei('20') }, +// { type: 'uint256', value: web3latest.utils.toWei('10') }, // token +// { type: 'uint256', value: web3latest.utils.toWei('20') } // token +// ) +// }) + +// it("Bob signs initial lcS0 state", async () => { +// BI_lcS0_sigB = await web3latest.eth.sign(BI_lcS0, partyB) +// }) + + +// it("Bob initiates ledger channel with lcS0", async () => { +// let approval = await token.approve(lc.address, web3latest.utils.toWei('10'), {from: partyB}) +// await lc.createChannel(lcid_BI, partyI, '0', token.address, [web3latest.utils.toWei('10'), web3latest.utils.toWei('10')], {from:partyB, value: web3latest.utils.toWei('10')}) +// let openChans = await lc.numChannels() +// let chan = await lc.getChannel(lcid_BI) +// assert.equal(chan[0].toString(), [partyB,partyI]) //check partyAddresses +// assert.equal(chan[1].toString(), [web3latest.utils.toWei('10'), '0', '0', '0']) //check ethBalances +// assert.equal(chan[2].toString(), [web3latest.utils.toWei('10'), '0', '0', '0']) //check erc20Balances +// assert.equal(chan[3].toString(), [web3latest.utils.toWei('10'),web3latest.utils.toWei('10')]) //check initalDeposit +// assert.equal(chan[4].toString(), '0') //check sequence +// assert.equal(chan[5].toString(), '0') //check confirmTime +// assert.equal(chan[6], '0x0000000000000000000000000000000000000000000000000000000000000000') //check VCrootHash +// //check if chan[7] is equal to now + confirmtime +// assert.equal(chan[8].toString(), '0') //check updateLCTimeout +// assert.equal(chan[9], false) //check isOpen +// assert.equal(chan[10], false) //check isUpdateLCSettling +// assert.equal(chan[11], '0') //check numOpenVC +// }) + +// it("Hub signs initial lcS0 state", async () => { +// BI_lcS0_sigI = await web3latest.eth.sign(BI_lcS0, partyI) +// }) + +// it("Ingrid joins ledger channel", async () => { +// let approval = await token.approve(lc.address, web3latest.utils.toWei('20'), {from: partyI}) +// await lc.joinChannel(lcid_BI, [web3latest.utils.toWei('20'), web3latest.utils.toWei('20')], {from: partyI, value: web3latest.utils.toWei('20')}) +// let openChans = await lc.numChannels() +// let chan = await lc.getChannel(lcid_BI) +// assert.equal(chan[0].toString(), [partyB,partyI]) //check partyAddresses +// assert.equal(chan[1].toString(), [web3latest.utils.toWei('10'), web3latest.utils.toWei('20'), '0', '0']) //check ethBalances +// assert.equal(chan[2].toString(), [web3latest.utils.toWei('10'), web3latest.utils.toWei('20'), '0', '0']) //check erc20Balances +// assert.equal(chan[3].toString(), [web3latest.utils.toWei('30'), web3latest.utils.toWei('30')]) //check initalDeposit +// assert.equal(chan[4].toString(), '0') //check sequence +// assert.equal(chan[5].toString(), '0') //check confirmTime +// assert.equal(chan[6], '0x0000000000000000000000000000000000000000000000000000000000000000') //check VCrootHash +// //check if chan[7] is equal to now + confirmtime +// assert.equal(chan[8].toString(), '0') //check updateLCTimeout +// assert.equal(chan[9], true) //check isOpen +// assert.equal(chan[10], false) //check isUpdateLCSettling +// assert.equal(chan[11], '0') //check numOpenVC +// }) + + +// it("Alice creates vc state vcSO with Bob", async () => { +// AB_vcS0 = web3latest.utils.soliditySha3( +// { type: 'bytes32', value: web3latest.utils.sha3('1337', {encoding: 'hex'}) }, // vc id +// { type: 'uint256', value: 0 }, // sequence +// { type: 'address', value: partyA }, // partyA +// { type: 'address', value: partyB }, // partyB, +// { type: 'uint256', value: web3latest.utils.toWei('12') }, // hub eth bond +// { type: 'uint256', value: web3latest.utils.toWei('12')}, //hub token bond +// { type: 'uint256', value: web3latest.utils.toWei('5') }, +// { type: 'uint256', value: web3latest.utils.toWei('7') }, +// { type: 'uint256', value: web3latest.utils.toWei('5') }, // token +// { type: 'uint256', value: web3latest.utils.toWei('7') } // token +// ) + +// }) + +// it("Alice and Bob sign vcSO", async () => { +// AB_vcS0_sigA = await web3latest.eth.sign(AB_vcS0, partyA) +// AB_vcS0_sigB = await web3latest.eth.sign(AB_vcS0, partyB) +// }) + +// it("Alice creates lc state lcS1 containing vcSO with Ingrid", async () => { +// var hash = web3latest.utils.sha3(AB_vcS0, {encoding: 'hex'}) +// var buf = Utils.hexToBuffer(hash) +// var elems = [] +// elems.push(buf) +// elems.push(Utils.hexToBuffer('0x0000000000000000000000000000000000000000000000000000000000000000')) +// var merkle = new MerkleTree(elems) + +// vcRootHash = Utils.bufferToHex(merkle.getRoot()) + +// AI_lcS1 = web3latest.utils.soliditySha3( +// { type: 'uint256', value: lcid_AI }, +// { type: 'bool', value: false }, // isclose +// //{ type: 'bytes32', value: web3.sha3('lc2', {encoding: 'hex'}) }, // lcid +// { type: 'uint256', value: 1 }, // sequence +// { type: 'uint256', value: 1 }, // open VCs +// { type: 'string', value: vcRootHash }, // VC root hash +// { type: 'address', value: partyA }, // partyA +// { type: 'address', value: partyI }, // hub +// { type: 'uint256', value: web3latest.utils.toWei('5') }, //eth +// { type: 'uint256', value: web3latest.utils.toWei('13') }, //eth +// { type: 'uint256', value: web3latest.utils.toWei('5') }, // token +// { type: 'uint256', value: web3latest.utils.toWei('13') } // token +// ) +// }) + +// it("Alice signs lcS1 state and sends to Hub", async () => { +// AI_lcS1_sigA = await web3latest.eth.sign(AI_lcS1, partyA) +// }) + +// it("Bob creates lc state lcS1 containing vcSO with Ingrid", async () => { +// var hash = web3latest.utils.sha3(AB_vcS0, {encoding: 'hex'}) +// var buf = Utils.hexToBuffer(hash) +// var elems = [] +// elems.push(buf) +// elems.push(Utils.hexToBuffer('0x0000000000000000000000000000000000000000000000000000000000000000')) +// var merkle = new MerkleTree(elems) + +// vcRootHash = Utils.bufferToHex(merkle.getRoot()) + +// BI_lcS1 = web3latest.utils.soliditySha3( +// { type: 'uint256', value: lcid_BI }, +// { type: 'bool', value: false }, // isclose +// //{ type: 'bytes32', value: web3.sha3('lc4', {encoding: 'hex'}) }, // lcid +// { type: 'uint256', value: 1 }, // sequence +// { type: 'uint256', value: 1 }, // open VCs +// { type: 'string', value: vcRootHash }, // VC root hash +// { type: 'address', value: partyB }, // partyB +// { type: 'address', value: partyI }, // hub +// { type: 'uint256', value: web3latest.utils.toWei('3') }, //eth +// { type: 'uint256', value: web3latest.utils.toWei('15') }, //eth +// { type: 'uint256', value: web3latest.utils.toWei('3') }, // token +// { type: 'uint256', value: web3latest.utils.toWei('15') } // token +// ) +// }) + +// it("Bob signs lcS1 state and sends to hub", async () => { +// BI_lcS1_sigB = await web3latest.eth.sign(BI_lcS1, partyB) +// }) + +// it("Hub signs both Alice and Bob's lcS1 state to open VC", async () => { +// AI_lcS1_sigI = await web3latest.eth.sign(AI_lcS1, partyI) +// BI_lcS1_sigI = await web3latest.eth.sign(BI_lcS1, partyI) +// }) + +// it("Alice generates virtual channel payment with Bob (vcS1)", async () => { +// AB_vcS1 = web3latest.utils.soliditySha3( +// { type: 'bytes32', value: web3latest.utils.sha3('1337', {encoding: 'hex'}) }, // vc id +// { type: 'uint256', value: 1 }, // sequence +// { type: 'address', value: partyA }, // partyA +// { type: 'address', value: partyB }, // partyB +// { type: 'uint256', value: web3latest.utils.toWei('12') }, // hub eth bond +// { type: 'uint256', value: web3latest.utils.toWei('12') }, //hub token bond +// { type: 'uint256', value: web3latest.utils.toWei('0') }, +// { type: 'uint256', value: web3latest.utils.toWei('12') }, +// { type: 'uint256', value: web3latest.utils.toWei('0') }, // token +// { type: 'uint256', value: web3latest.utils.toWei('12') } // token +// ) + +// }) + +// it("Alice and Bob sign vcS1", async () => { +// AB_vcS1_sigA = await web3latest.eth.sign(AB_vcS1, partyA) +// AB_vcS1_sigB = await web3latest.eth.sign(AB_vcS1, partyB) +// }) + +// it("Alice generates lc state to close vc", async () => { +// AI_lcS2 = web3latest.utils.soliditySha3( +// { type: 'uint256', value: lcid_AI }, +// { type: 'bool', value: false }, // isclose +// //{ type: 'bytes32', value: web3.sha3('lc2', {encoding: 'hex'}) }, // lcid +// { type: 'uint256', value: 2 }, // sequence +// { type: 'uint256', value: 0 }, // open VCs +// { type: 'string', value: '0x0' }, // VC root hash +// { type: 'address', value: partyA }, // partyA +// { type: 'address', value: partyI }, // hub +// { type: 'uint256', value: web3latest.utils.toWei('5') }, //eth +// { type: 'uint256', value: web3latest.utils.toWei('25') }, //eth +// { type: 'uint256', value: web3latest.utils.toWei('5') }, // token +// { type: 'uint256', value: web3latest.utils.toWei('25') } // token +// ) + +// }) + +// it("Bob generates lc state to close vc", async () => { +// BI_lcS2 = web3latest.utils.soliditySha3( +// { type: 'uint256', value: lcid_BI }, +// { type: 'bool', value: false }, // isclose +// //{ type: 'bytes32', value: web3.sha3('lc4', {encoding: 'hex'}) }, // lcid +// { type: 'uint256', value: 2 }, // sequence +// { type: 'uint256', value: 0 }, // open VCs +// { type: 'string', value: '0x0' }, // VC root hash +// { type: 'address', value: partyB }, // partyB +// { type: 'address', value: partyI }, // hub +// { type: 'uint256', value: web3latest.utils.toWei('15') }, //eth +// { type: 'uint256', value: web3latest.utils.toWei('15') }, //eth +// { type: 'uint256', value: web3latest.utils.toWei('15') }, // token +// { type: 'uint256', value: web3latest.utils.toWei('15') } // token +// ) +// }) + +// it("Alice signs lcS2 state and sends to Hub", async () => { +// AI_lcS2_sigA = await web3latest.eth.sign(AI_lcS2, partyA) +// }) + +// it("Bob signs lcS2 state and sends to hub", async () => { +// BI_lcS2_sigB = await web3latest.eth.sign(BI_lcS2, partyB) +// }) + +// it("Hub signs both Alice and Bob's lcS2 state to close VC", async () => { +// AI_lcS2_sigI = await web3latest.eth.sign(AI_lcS2, partyI) +// BI_lcS2_sigI = await web3latest.eth.sign(BI_lcS2, partyI) +// }) + +// it("Alice creates lc update to close vc", async () => { +// AI_lcS3 = web3latest.utils.soliditySha3( +// { type: 'uint256', value: lcid_AI }, +// { type: 'bool', value: true }, // isclose +// //{ type: 'bytes32', value: web3.sha3('lc2', {encoding: 'hex'}) }, // lcid +// { type: 'uint256', value: '3' }, // sequence +// { type: 'uint256', value: '0' }, // open VCs +// { type: 'bytes32', value: '0x0' }, // VC root hash +// { type: 'address', value: partyA }, // partyA +// { type: 'address', value: partyI }, // hub +// { type: 'uint256', value: web3latest.utils.toWei('5') }, +// { type: 'uint256', value: web3latest.utils.toWei('25') }, +// { type: 'uint256', value: web3latest.utils.toWei('5') }, // token +// { type: 'uint256', value: web3latest.utils.toWei('25') } // token +// ) +// }) + +// it("Alice signs lcS3 state and sends to Hub", async () => { +// AI_lcS3_sigA = await web3latest.eth.sign(AI_lcS3, partyA) +// }) + +// it("Hub signs closing lcS3 state", async () => { +// AI_lcS3_sigI = await web3latest.eth.sign(AI_lcS3, partyI) +// }) + +// it("Close Alice ledger channel", async () => { +// var balA1e = await web3latest.eth.getBalance(partyA) +// var balI1e = await web3latest.eth.getBalance(partyI) +// var balA1t = await token.balanceOf(partyA) +// var balI1t = await token.balanceOf(partyI) +// let receipt = await lc.consensusCloseChannel(lcid_AI, '3', [web3latest.utils.toWei('5'), web3latest.utils.toWei('25'), web3latest.utils.toWei('5'), web3latest.utils.toWei('25')], AI_lcS3_sigA, AI_lcS3_sigI) +// var gasUsed = receipt.receipt.gasUsed +// //console.log('Close Channel: ' + gasUsed) +// var balA2e = await web3latest.eth.getBalance(partyA) +// var balI2e = await web3latest.eth.getBalance(partyI) +// var balA2t = await token.balanceOf(partyA) +// var balI2t = await token.balanceOf(partyI) +// // TODO calculate gas, this may very based on testrpc +// assert.equal(balI2e - balI1e, '25000000000000000000') +// assert.equal(balI2t - balI1t, '25000000000000000000') +// // assert.equal(balA2 - balA1, '7926958099999998000') +// }) + +// /******TO DO******/ +// it("Hub deposits into Bob's lc", async () => { +// await lc.deposit(lcid_BI, partyI, web3latest.utils.toWei('10'), false, {from:partyI, value:web3latest.utils.toWei('10')}) +// let chan = await lc.getChannel(lcid_BI) +// }) + +// it("Hub creates lc state lcS2 containing new deposit", async () => { +// var hash = web3latest.utils.sha3(AB_vcS0, {encoding: 'hex'}) +// var buf = Utils.hexToBuffer(hash) +// var elems = [] +// elems.push(buf) +// elems.push(Utils.hexToBuffer('0x0000000000000000000000000000000000000000000000000000000000000000')) +// var merkle = new MerkleTree(elems) + +// vcRootHash = Utils.bufferToHex(merkle.getRoot()) + +// BI_lcS1 = web3latest.utils.soliditySha3( +// { type: 'uint256', value: lcid_BI }, +// { type: 'bool', value: false }, // isclose +// //{ type: 'bytes32', value: web3.sha3('lc4', {encoding: 'hex'}) }, // lcid +// { type: 'uint256', value: 2 }, // sequence +// { type: 'uint256', value: 1 }, // open VCs +// { type: 'string', value: vcRootHash }, // VC root hash +// { type: 'address', value: partyB }, // partyA +// { type: 'address', value: partyI }, // hub +// { type: 'uint256', value: web3latest.utils.toWei('3') }, +// { type: 'uint256', value: web3latest.utils.toWei('25') }, +// { type: 'uint256', value: web3latest.utils.toWei('0') }, // token +// { type: 'uint256', value: web3latest.utils.toWei('0') } // token +// ) +// }) + +// }) diff --git a/test/scenarios/CoopTokenTest.js b/test/scenarios/CoopTokenTest.js index d69344c..0b9908c 100644 --- a/test/scenarios/CoopTokenTest.js +++ b/test/scenarios/CoopTokenTest.js @@ -1,465 +1,465 @@ -'use strict' - -import MerkleTree from '../helpers/MerkleTree' -const Utils = require('../helpers/utils') -const Ledger = artifacts.require('./LedgerChannel.sol') -const EC = artifacts.require('./ECTools.sol') -const Token = artifacts.require('./token/HumanStandardToken.sol') - -const Web3latest = require('web3') -const web3latest = new Web3latest(new Web3latest.providers.HttpProvider("http://localhost:8545")) //ganache port - - -let lc -let token - -// state - -let partyA -let partyB -let partyI - -let lcid_AI -let lcid_BI - -let vcRootHash - -// is close flag, lc state sequence, number open vc, vc root hash, partyA/B, partyI, balA/B, balI - -let AI_lcS0 -let AI_lcS1 -let AI_lcS2 -let AI_lcS3 - -let BI_lcS0 -let BI_lcS1 -let BI_lcS2 - -let AB_vcS0 -let AB_vcS1 - -let AB_vc2_S0 -let AB_vc2_S1 - -// signature storage -let AI_lcS0_sigA -let AI_lcS1_sigA -let AI_lcS2_sigA -let AI_lcS3_sigA - -let AI_lcS0_sigI -let AI_lcS1_sigI -let AI_lcS2_sigI -let AI_lcS3_sigI - -let BI_lcS0_sigB -let BI_lcS1_sigB -let BI_lcS2_sigB - -let BI_lcS0_sigI -let BI_lcS1_sigI -let BI_lcS2_sigI - -let AB_vcS0_sigA -let AB_vcS1_sigA - -let AB_vcS0_sigB -let AB_vcS1_sigB - -contract('Test Cooperative Token Payments', function(accounts) { - - before(async () => { - partyA = accounts[0] - partyB = accounts[1] - partyI = accounts[2] - - let ec = await EC.new() - token = await Token.new(1000, 'Test', 1, 'TST') - Ledger.link('HumanStandardToken', token.address) - Ledger.link('ECTools', ec.address) - lc = await Ledger.new() - await token.transfer(partyB, 100) - await token.transfer(partyI, 100) - }) - - it("Create initial ledger channel state lcS0 for AI channel", async () => { - lcid_AI = web3latest.utils.sha3('1111', {encoding: 'hex'}) - AI_lcS0 = web3latest.utils.soliditySha3( - { type: 'uint256', value: lcid_AI }, // ID - { type: 'bool', value: false }, // isclose - //{ type: 'bytes32', value: web3.sha3('lc2', {encoding: 'hex'}) }, // lcid - { type: 'uint256', value: 0 }, // sequence - { type: 'uint256', value: 0 }, // open VCs - { type: 'string', value: '0x0' }, // VC root hash - { type: 'address', value: partyA }, // partyA - { type: 'address', value: partyI }, // hub - { type: 'uint256', value: web3latest.utils.toWei('0') }, // eth - { type: 'uint256', value: web3latest.utils.toWei('0') }, // eth - { type: 'uint256', value: web3latest.utils.toWei('20') }, // token - { type: 'uint256', value: web3latest.utils.toWei('0') } // token - ) - }) - - it("Alice signs initial lcS0 state", async () => { - AI_lcS0_sigA = await web3latest.eth.sign(AI_lcS0, partyA) - }) - - // address[2] partyAdresses; // 0: partyA 1: partyI - // uint256[2] ethBalances; // 0: balanceA 1:balanceI - // uint256[2] erc20Balances; // 0: balanceA 1:balanceI - // uint256[2] deposited; - // uint256 initialDeposit; - // uint256 sequence; - // uint256 confirmTime; - // bytes32 VCrootHash; - // uint256 LCopenTimeout; - // uint256 updateLCtimeout; // when update LC times out - // bool isOpen; // true when both parties have joined - // bool isUpdateLCSettling; - // uint256 numOpenVC; - - - it("Alice initiates ledger channel with lcS0", async () => { - let approval = await token.approve(lc.address, 10) - let res = await lc.createChannel(lcid_AI, partyI, '0', token.address, [0, 10]) - var gasUsed = res.receipt.gasUsed - //console.log('createChan: '+ gasUsed) - let openChans = await lc.numChannels() - let chan = await lc.getChannel(lcid_AI) - assert.equal(chan[0].toString(), [partyA,partyI]) //check partyAddresses - assert.equal(chan[1].toString(), ['0', '0', '0', '0']) //check ethBalances - assert.equal(chan[2].toString(), ['10', '0', '0', '0']) //check erc20Balances - assert.equal(chan[3].toString(), [0,'10']) //check initalDeposit - assert.equal(chan[4].toString(), '0') //check sequence - assert.equal(chan[5].toString(), '0') //check confirmTime - assert.equal(chan[6], '0x0000000000000000000000000000000000000000000000000000000000000000') //check VCrootHash - //check if chan[7] is equal to now + confirmtime - assert.equal(chan[8].toString(), '0') //check updateLCTimeout - assert.equal(chan[9], false) //check isOpen - assert.equal(chan[10], false) //check isUpdateLCSettling - assert.equal(chan[11], '0') //check numOpenVC - }) - - it("Hub signs initial lcS0 state", async () => { - AI_lcS0_sigI = await web3latest.eth.sign(AI_lcS0, partyI) - }) - - it("Ingrid joins ledger channel", async () => { - let approval = await token.approve(lc.address, 20, {from: partyI}) - let res = await lc.joinChannel(lcid_AI, [0,20], {from: partyI}) - var gasUsed = res.receipt.gasUsed - //console.log('joinChan: '+ gasUsed) - let openChans = await lc.numChannels() - let chan = await lc.getChannel(lcid_AI) - assert.equal(chan[0].toString(), [partyA,partyI]) //check partyAddresses - assert.equal(chan[1].toString(), ['0', '0', '0', '0']) //check ethBalances - assert.equal(chan[2].toString(), ['10', '20', '0', '0']) //check erc20Balances - assert.equal(chan[3].toString(), [0,'30']) //check initalDeposit - assert.equal(chan[4].toString(), '0') //check sequence - assert.equal(chan[5].toString(), '0') //check confirmTime - assert.equal(chan[6], '0x0000000000000000000000000000000000000000000000000000000000000000') //check VCrootHash - //check if chan[7] is equal to now + confirmtime - assert.equal(chan[8].toString(), '0') //check updateLCTimeout - assert.equal(chan[9], true) //check isOpen - assert.equal(chan[10], false) //check isUpdateLCSettling - assert.equal(chan[11], '0') //check numOpenVC - }) - - // Bob creates ledger channel - it("Create Bob's ledger channel state lcS0 for BI channel", async () => { - lcid_BI = web3latest.utils.sha3('2222', {encoding: 'hex'}) - - BI_lcS0 = web3latest.utils.soliditySha3( - { type: 'uint256', value: lcid_BI }, // ID - { type: 'bool', value: false }, // isclose - //{ type: 'bytes32', value: web3.sha3('lc4', {encoding: 'hex'}) }, // lcid - { type: 'uint256', value: 0 }, // sequence - { type: 'uint256', value: 0 }, // open VCs - { type: 'string', value: '0x0' }, // VC root hash - { type: 'address', value: partyB }, // partyA - { type: 'address', value: partyI }, // hub - { type: 'uint256', value: web3latest.utils.toWei('10') }, - { type: 'uint256', value: web3latest.utils.toWei('20') }, - { type: 'uint256', value: web3latest.utils.toWei('0') }, // token - { type: 'uint256', value: web3latest.utils.toWei('0') } // token - ) - }) - - it("Bob signs initial lcS0 state", async () => { - BI_lcS0_sigB = await web3latest.eth.sign(BI_lcS0, partyB) - }) - - - it("Bob initiates ledger channel with lcS0", async () => { - let approval = await token.approve(lc.address, 10, {from: partyB}) - let res = await lc.createChannel(lcid_BI, partyI, '0', token.address, [0,10], {from: partyB}) - var gasUsed = res.receipt.gasUsed - //console.log('createChan: '+ gasUsed) - let openChans = await lc.numChannels() - let chan = await lc.getChannel(lcid_BI) - assert.equal(chan[0].toString(), [partyB,partyI]) //check partyAddresses - assert.equal(chan[1].toString(), ['0', '0', '0', '0']) //check ethBalances - assert.equal(chan[2].toString(), ['10', '0', '0', '0']) //check erc20Balances - assert.equal(chan[3].toString(), [0,'10']) //check initalDeposit - assert.equal(chan[4].toString(), '0') //check sequence - assert.equal(chan[5].toString(), '0') //check confirmTime - assert.equal(chan[6], '0x0000000000000000000000000000000000000000000000000000000000000000') //check VCrootHash - //check if chan[7] is equal to now + confirmtime - assert.equal(chan[8].toString(), '0') //check updateLCTimeout - assert.equal(chan[9], false) //check isOpen - assert.equal(chan[10], false) //check isUpdateLCSettling - assert.equal(chan[11], '0') //check numOpenVC - }) - - it("Hub signs initial lcS0 state", async () => { - BI_lcS0_sigI = await web3latest.eth.sign(BI_lcS0, partyI) - }) - - it("Ingrid joins ledger channel", async () => { - let approval = await token.approve(lc.address, 20, {from: partyI}) - let res = await lc.joinChannel(lcid_BI, [0,20], {from: partyI}) - var gasUsed = res.receipt.gasUsed - //console.log('joinChan: '+ gasUsed) - let openChans = await lc.numChannels() - let chan = await lc.getChannel(lcid_BI) - assert.equal(chan[0].toString(), [partyB,partyI]) //check partyAddresses - assert.equal(chan[1].toString(), ['0', '0', '0', '0']) //check ethBalances - assert.equal(chan[2].toString(), ['10', '20', '0', '0']) //check erc20Balances - assert.equal(chan[3].toString(), [0,'30']) //check initalDeposit - assert.equal(chan[4].toString(), '0') //check sequence - assert.equal(chan[5].toString(), '0') //check confirmTime - assert.equal(chan[6], '0x0000000000000000000000000000000000000000000000000000000000000000') //check VCrootHash - //check if chan[7] is equal to now + confirmtime - assert.equal(chan[8].toString(), '0') //check updateLCTimeout - assert.equal(chan[9], true) //check isOpen - assert.equal(chan[10], false) //check isUpdateLCSettling - assert.equal(chan[11], '0') //check numOpenVC - }) - - - it("Alice creates vc state vcSO with Bob", async () => { - AB_vcS0 = web3latest.utils.soliditySha3( - { type: 'bytes32', value: web3latest.utils.sha3('1337', {encoding: 'hex'}) }, // vc id - { type: 'uint256', value: 0 }, // sequence - { type: 'address', value: partyA }, // partyA - { type: 'address', value: partyB }, // partyB, - { type: 'uint256', value: 0 }, //hub eth bond - { type: 'uint256', value: 12 }, // hub token bond - { type: 'uint256', value: 0 }, - { type: 'uint256', value: 0 }, - { type: 'uint256', value: 5 }, // token - { type: 'uint256', value: 7 } // token - ) - - }) - - it("Alice and Bob sign vcSO", async () => { - AB_vcS0_sigA = await web3latest.eth.sign(AB_vcS0, partyA) - AB_vcS0_sigB = await web3latest.eth.sign(AB_vcS0, partyB) - }) - - it("Alice creates lc state lcS1 containing vcSO with Ingrid", async () => { - var hash = web3latest.utils.sha3(AB_vcS0, {encoding: 'hex'}) - var buf = Utils.hexToBuffer(hash) - var elems = [] - elems.push(buf) - elems.push(Utils.hexToBuffer('0x0000000000000000000000000000000000000000000000000000000000000000')) - var merkle = new MerkleTree(elems) - - vcRootHash = Utils.bufferToHex(merkle.getRoot()) - - AI_lcS1 = web3latest.utils.soliditySha3( - { type: 'uint256', value: lcid_AI }, - { type: 'bool', value: false }, // isclose - //{ type: 'bytes32', value: web3.sha3('lc2', {encoding: 'hex'}) }, // lcid - { type: 'uint256', value: 1 }, // sequence - { type: 'uint256', value: 1 }, // open VCs - { type: 'string', value: vcRootHash }, // VC root hash - { type: 'address', value: partyA }, // partyA - { type: 'address', value: partyI }, // hub - { type: 'uint256', value: 0 }, //eth - { type: 'uint256', value: 0 }, //eth - { type: 'uint256', value: 5 }, // token - { type: 'uint256', value: 13 } // token - ) - }) - - it("Alice signs lcS1 state and sends to Hub", async () => { - AI_lcS1_sigA = await web3latest.eth.sign(AI_lcS1, partyA) - }) - - it("Bob creates lc state lcS1 containing vcSO with Ingrid", async () => { - var hash = web3latest.utils.sha3(AB_vcS0, {encoding: 'hex'}) - var buf = Utils.hexToBuffer(hash) - var elems = [] - elems.push(buf) - elems.push(Utils.hexToBuffer('0x0000000000000000000000000000000000000000000000000000000000000000')) - var merkle = new MerkleTree(elems) - - vcRootHash = Utils.bufferToHex(merkle.getRoot()) - - BI_lcS1 = web3latest.utils.soliditySha3( - { type: 'uint256', value: lcid_BI }, - { type: 'bool', value: false }, // isclose - //{ type: 'bytes32', value: web3.sha3('lc4', {encoding: 'hex'}) }, // lcid - { type: 'uint256', value: 1 }, // sequence - { type: 'uint256', value: 1 }, // open VCs - { type: 'string', value: vcRootHash }, // VC root hash - { type: 'address', value: partyB }, // partyB - { type: 'address', value: partyI }, // hub - { type: 'uint256', value: 0 }, //eth - { type: 'uint256', value: 0 }, //eth - { type: 'uint256', value: 3 }, // token - { type: 'uint256', value: 15 } // token - ) - }) - - it("Bob signs lcS1 state and sends to hub", async () => { - BI_lcS1_sigB = await web3latest.eth.sign(BI_lcS1, partyB) - }) - - it("Hub signs both Alice and Bob's lcS1 state to open VC", async () => { - AI_lcS1_sigI = await web3latest.eth.sign(AI_lcS1, partyI) - BI_lcS1_sigI = await web3latest.eth.sign(BI_lcS1, partyI) - }) - - it("Alice generates virtual channel payment with Bob (vcS1)", async () => { - AB_vcS1 = web3latest.utils.soliditySha3( - { type: 'bytes32', value: web3latest.utils.sha3('1337', {encoding: 'hex'}) }, // vc id - { type: 'uint256', value: 1 }, // sequence - { type: 'address', value: partyA }, // partyA - { type: 'address', value: partyB }, // partyB - { type: 'uint256', value: 0 }, // hub eth bond - { type: 'uint256', value: 12}, //hub token bond - { type: 'uint256', value: 0 }, - { type: 'uint256', value: 0 }, - { type: 'uint256', value: 0 }, // token - { type: 'uint256', value: 12 } // token - ) - - }) - - it("Alice and Bob sign vcS1", async () => { - AB_vcS1_sigA = await web3latest.eth.sign(AB_vcS1, partyA) - AB_vcS1_sigB = await web3latest.eth.sign(AB_vcS1, partyB) - }) - - it("Alice generates lc state to close vc", async () => { - AI_lcS2 = web3latest.utils.soliditySha3( - { type: 'uint256', value: lcid_AI }, - { type: 'bool', value: false }, // isclose - //{ type: 'bytes32', value: web3.sha3('lc2', {encoding: 'hex'}) }, // lcid - { type: 'uint256', value: 2 }, // sequence - { type: 'uint256', value: 0 }, // open VCs - { type: 'string', value: '0x0' }, // VC root hash - { type: 'address', value: partyA }, // partyA - { type: 'address', value: partyI }, // hub - { type: 'uint256', value: 0 }, //eth - { type: 'uint256', value: 0 }, //eth - { type: 'uint256', value: 5 }, // token - { type: 'uint256', value: 25 } // token - ) - - }) - - it("Bob generates lc state to close vc", async () => { - BI_lcS2 = web3latest.utils.soliditySha3( - { type: 'uint256', value: lcid_BI }, - { type: 'bool', value: false }, // isclose - //{ type: 'bytes32', value: web3.sha3('lc4', {encoding: 'hex'}) }, // lcid - { type: 'uint256', value: 2 }, // sequence - { type: 'uint256', value: 0 }, // open VCs - { type: 'string', value: '0x0' }, // VC root hash - { type: 'address', value: partyB }, // partyB - { type: 'address', value: partyI }, // hub - { type: 'uint256', value: 0 }, //eth - { type: 'uint256', value: 0 }, //eth - { type: 'uint256', value: 15 }, // token - { type: 'uint256', value: 15 } // token - ) - }) - - it("Alice signs lcS2 state and sends to Hub", async () => { - AI_lcS2_sigA = await web3latest.eth.sign(AI_lcS2, partyA) - }) - - it("Bob signs lcS2 state and sends to hub", async () => { - BI_lcS2_sigB = await web3latest.eth.sign(BI_lcS2, partyB) - }) - - it("Hub signs both Alice and Bob's lcS2 state to close VC", async () => { - AI_lcS2_sigI = await web3latest.eth.sign(AI_lcS2, partyI) - BI_lcS2_sigI = await web3latest.eth.sign(BI_lcS2, partyI) - }) - - it("Alice creates lc update to close vc", async () => { - AI_lcS3 = web3latest.utils.soliditySha3( - { type: 'uint256', value: lcid_AI }, - { type: 'bool', value: true }, // isclose - //{ type: 'bytes32', value: web3.sha3('lc2', {encoding: 'hex'}) }, // lcid - { type: 'uint256', value: '3' }, // sequence - { type: 'uint256', value: '0' }, // open VCs - { type: 'bytes32', value: '0x0' }, // VC root hash - { type: 'address', value: partyA }, // partyA - { type: 'address', value: partyI }, // hub - { type: 'uint256', value: 0 }, //eth - { type: 'uint256', value: 0 }, //eth - { type: 'uint256', value: 5 }, // token - { type: 'uint256', value: 25 } // token - ) - }) - - it("Alice signs lcS3 state and sends to Hub", async () => { - AI_lcS3_sigA = await web3latest.eth.sign(AI_lcS3, partyA) - }) - - it("Hub signs closing lcS3 state", async () => { - AI_lcS3_sigI = await web3latest.eth.sign(AI_lcS3, partyI) - }) - - it("Close Alice ledger channel", async () => { - var balA1 = await token.balanceOf(partyA) - var balI1 = await token.balanceOf(partyI) - let receipt = await lc.consensusCloseChannel(lcid_AI, '3', [0, 0, 5, 25], AI_lcS3_sigA, AI_lcS3_sigI) - var gasUsed = receipt.receipt.gasUsed - //console.log('Close Channel: ' + gasUsed) - var balA2 = await token.balanceOf(partyA) - var balI2 = await token.balanceOf(partyI) - // TODO calculate gas, this may very based on testrpc - assert.equal(balI2 - balI1, '25') - // assert.equal(balA2 - balA1, '7926958099999998000') - }) - - /******TO DO******/ - it("Hub deposits into Bob's lc", async () => { - await lc.deposit(lcid_BI, partyI, web3latest.utils.toWei('10'), false, {from:partyI, value:web3latest.utils.toWei('10')}) - let chan = await lc.getChannel(lcid_BI) - }) - - it("Hub creates lc state lcS2 containing new deposit", async () => { - var hash = web3latest.utils.sha3(AB_vcS0, {encoding: 'hex'}) - var buf = Utils.hexToBuffer(hash) - var elems = [] - elems.push(buf) - elems.push(Utils.hexToBuffer('0x0000000000000000000000000000000000000000000000000000000000000000')) - var merkle = new MerkleTree(elems) - - vcRootHash = Utils.bufferToHex(merkle.getRoot()) - - BI_lcS1 = web3latest.utils.soliditySha3( - { type: 'uint256', value: lcid_BI }, - { type: 'bool', value: false }, // isclose - //{ type: 'bytes32', value: web3.sha3('lc4', {encoding: 'hex'}) }, // lcid - { type: 'uint256', value: 2 }, // sequence - { type: 'uint256', value: 1 }, // open VCs - { type: 'string', value: vcRootHash }, // VC root hash - { type: 'address', value: partyB }, // partyA - { type: 'address', value: partyI }, // hub - { type: 'uint256', value: web3latest.utils.toWei('3') }, - { type: 'uint256', value: web3latest.utils.toWei('25') }, - { type: 'uint256', value: web3latest.utils.toWei('0') }, // token - { type: 'uint256', value: web3latest.utils.toWei('0') } // token - ) - }) - -}) \ No newline at end of file +// 'use strict' + +// import MerkleTree from '../helpers/MerkleTree' +// const Utils = require('../helpers/utils') +// const Ledger = artifacts.require('./LedgerChannel.sol') +// const EC = artifacts.require('./ECTools.sol') +// const Token = artifacts.require('./token/HumanStandardToken.sol') + +// const Web3latest = require('web3') +// const web3latest = new Web3latest(new Web3latest.providers.HttpProvider("http://localhost:8545")) //ganache port + + +// let lc +// let token + +// // state + +// let partyA +// let partyB +// let partyI + +// let lcid_AI +// let lcid_BI + +// let vcRootHash + +// // is close flag, lc state sequence, number open vc, vc root hash, partyA/B, partyI, balA/B, balI + +// let AI_lcS0 +// let AI_lcS1 +// let AI_lcS2 +// let AI_lcS3 + +// let BI_lcS0 +// let BI_lcS1 +// let BI_lcS2 + +// let AB_vcS0 +// let AB_vcS1 + +// let AB_vc2_S0 +// let AB_vc2_S1 + +// // signature storage +// let AI_lcS0_sigA +// let AI_lcS1_sigA +// let AI_lcS2_sigA +// let AI_lcS3_sigA + +// let AI_lcS0_sigI +// let AI_lcS1_sigI +// let AI_lcS2_sigI +// let AI_lcS3_sigI + +// let BI_lcS0_sigB +// let BI_lcS1_sigB +// let BI_lcS2_sigB + +// let BI_lcS0_sigI +// let BI_lcS1_sigI +// let BI_lcS2_sigI + +// let AB_vcS0_sigA +// let AB_vcS1_sigA + +// let AB_vcS0_sigB +// let AB_vcS1_sigB + +// contract('Test Cooperative Token Payments', function(accounts) { + +// before(async () => { +// partyA = accounts[0] +// partyB = accounts[1] +// partyI = accounts[2] + +// let ec = await EC.new() +// token = await Token.new(1000, 'Test', 1, 'TST') +// Ledger.link('HumanStandardToken', token.address) +// Ledger.link('ECTools', ec.address) +// lc = await Ledger.new() +// await token.transfer(partyB, 100) +// await token.transfer(partyI, 100) +// }) + +// it("Create initial ledger channel state lcS0 for AI channel", async () => { +// lcid_AI = web3latest.utils.sha3('1111', {encoding: 'hex'}) +// AI_lcS0 = web3latest.utils.soliditySha3( +// { type: 'uint256', value: lcid_AI }, // ID +// { type: 'bool', value: false }, // isclose +// //{ type: 'bytes32', value: web3.sha3('lc2', {encoding: 'hex'}) }, // lcid +// { type: 'uint256', value: 0 }, // sequence +// { type: 'uint256', value: 0 }, // open VCs +// { type: 'string', value: '0x0' }, // VC root hash +// { type: 'address', value: partyA }, // partyA +// { type: 'address', value: partyI }, // hub +// { type: 'uint256', value: web3latest.utils.toWei('0') }, // eth +// { type: 'uint256', value: web3latest.utils.toWei('0') }, // eth +// { type: 'uint256', value: web3latest.utils.toWei('20') }, // token +// { type: 'uint256', value: web3latest.utils.toWei('0') } // token +// ) +// }) + +// it("Alice signs initial lcS0 state", async () => { +// AI_lcS0_sigA = await web3latest.eth.sign(AI_lcS0, partyA) +// }) + +// // address[2] partyAdresses; // 0: partyA 1: partyI +// // uint256[2] ethBalances; // 0: balanceA 1:balanceI +// // uint256[2] erc20Balances; // 0: balanceA 1:balanceI +// // uint256[2] deposited; +// // uint256 initialDeposit; +// // uint256 sequence; +// // uint256 confirmTime; +// // bytes32 VCrootHash; +// // uint256 LCopenTimeout; +// // uint256 updateLCtimeout; // when update LC times out +// // bool isOpen; // true when both parties have joined +// // bool isUpdateLCSettling; +// // uint256 numOpenVC; + + +// it("Alice initiates ledger channel with lcS0", async () => { +// let approval = await token.approve(lc.address, 10) +// let res = await lc.createChannel(lcid_AI, partyI, '0', token.address, [0, 10]) +// var gasUsed = res.receipt.gasUsed +// //console.log('createChan: '+ gasUsed) +// let openChans = await lc.numChannels() +// let chan = await lc.getChannel(lcid_AI) +// assert.equal(chan[0].toString(), [partyA,partyI]) //check partyAddresses +// assert.equal(chan[1].toString(), ['0', '0', '0', '0']) //check ethBalances +// assert.equal(chan[2].toString(), ['10', '0', '0', '0']) //check erc20Balances +// assert.equal(chan[3].toString(), [0,'10']) //check initalDeposit +// assert.equal(chan[4].toString(), '0') //check sequence +// assert.equal(chan[5].toString(), '0') //check confirmTime +// assert.equal(chan[6], '0x0000000000000000000000000000000000000000000000000000000000000000') //check VCrootHash +// //check if chan[7] is equal to now + confirmtime +// assert.equal(chan[8].toString(), '0') //check updateLCTimeout +// assert.equal(chan[9], false) //check isOpen +// assert.equal(chan[10], false) //check isUpdateLCSettling +// assert.equal(chan[11], '0') //check numOpenVC +// }) + +// it("Hub signs initial lcS0 state", async () => { +// AI_lcS0_sigI = await web3latest.eth.sign(AI_lcS0, partyI) +// }) + +// it("Ingrid joins ledger channel", async () => { +// let approval = await token.approve(lc.address, 20, {from: partyI}) +// let res = await lc.joinChannel(lcid_AI, [0,20], {from: partyI}) +// var gasUsed = res.receipt.gasUsed +// //console.log('joinChan: '+ gasUsed) +// let openChans = await lc.numChannels() +// let chan = await lc.getChannel(lcid_AI) +// assert.equal(chan[0].toString(), [partyA,partyI]) //check partyAddresses +// assert.equal(chan[1].toString(), ['0', '0', '0', '0']) //check ethBalances +// assert.equal(chan[2].toString(), ['10', '20', '0', '0']) //check erc20Balances +// assert.equal(chan[3].toString(), [0,'30']) //check initalDeposit +// assert.equal(chan[4].toString(), '0') //check sequence +// assert.equal(chan[5].toString(), '0') //check confirmTime +// assert.equal(chan[6], '0x0000000000000000000000000000000000000000000000000000000000000000') //check VCrootHash +// //check if chan[7] is equal to now + confirmtime +// assert.equal(chan[8].toString(), '0') //check updateLCTimeout +// assert.equal(chan[9], true) //check isOpen +// assert.equal(chan[10], false) //check isUpdateLCSettling +// assert.equal(chan[11], '0') //check numOpenVC +// }) + +// // Bob creates ledger channel +// it("Create Bob's ledger channel state lcS0 for BI channel", async () => { +// lcid_BI = web3latest.utils.sha3('2222', {encoding: 'hex'}) + +// BI_lcS0 = web3latest.utils.soliditySha3( +// { type: 'uint256', value: lcid_BI }, // ID +// { type: 'bool', value: false }, // isclose +// //{ type: 'bytes32', value: web3.sha3('lc4', {encoding: 'hex'}) }, // lcid +// { type: 'uint256', value: 0 }, // sequence +// { type: 'uint256', value: 0 }, // open VCs +// { type: 'string', value: '0x0' }, // VC root hash +// { type: 'address', value: partyB }, // partyA +// { type: 'address', value: partyI }, // hub +// { type: 'uint256', value: web3latest.utils.toWei('10') }, +// { type: 'uint256', value: web3latest.utils.toWei('20') }, +// { type: 'uint256', value: web3latest.utils.toWei('0') }, // token +// { type: 'uint256', value: web3latest.utils.toWei('0') } // token +// ) +// }) + +// it("Bob signs initial lcS0 state", async () => { +// BI_lcS0_sigB = await web3latest.eth.sign(BI_lcS0, partyB) +// }) + + +// it("Bob initiates ledger channel with lcS0", async () => { +// let approval = await token.approve(lc.address, 10, {from: partyB}) +// let res = await lc.createChannel(lcid_BI, partyI, '0', token.address, [0,10], {from: partyB}) +// var gasUsed = res.receipt.gasUsed +// //console.log('createChan: '+ gasUsed) +// let openChans = await lc.numChannels() +// let chan = await lc.getChannel(lcid_BI) +// assert.equal(chan[0].toString(), [partyB,partyI]) //check partyAddresses +// assert.equal(chan[1].toString(), ['0', '0', '0', '0']) //check ethBalances +// assert.equal(chan[2].toString(), ['10', '0', '0', '0']) //check erc20Balances +// assert.equal(chan[3].toString(), [0,'10']) //check initalDeposit +// assert.equal(chan[4].toString(), '0') //check sequence +// assert.equal(chan[5].toString(), '0') //check confirmTime +// assert.equal(chan[6], '0x0000000000000000000000000000000000000000000000000000000000000000') //check VCrootHash +// //check if chan[7] is equal to now + confirmtime +// assert.equal(chan[8].toString(), '0') //check updateLCTimeout +// assert.equal(chan[9], false) //check isOpen +// assert.equal(chan[10], false) //check isUpdateLCSettling +// assert.equal(chan[11], '0') //check numOpenVC +// }) + +// it("Hub signs initial lcS0 state", async () => { +// BI_lcS0_sigI = await web3latest.eth.sign(BI_lcS0, partyI) +// }) + +// it("Ingrid joins ledger channel", async () => { +// let approval = await token.approve(lc.address, 20, {from: partyI}) +// let res = await lc.joinChannel(lcid_BI, [0,20], {from: partyI}) +// var gasUsed = res.receipt.gasUsed +// //console.log('joinChan: '+ gasUsed) +// let openChans = await lc.numChannels() +// let chan = await lc.getChannel(lcid_BI) +// assert.equal(chan[0].toString(), [partyB,partyI]) //check partyAddresses +// assert.equal(chan[1].toString(), ['0', '0', '0', '0']) //check ethBalances +// assert.equal(chan[2].toString(), ['10', '20', '0', '0']) //check erc20Balances +// assert.equal(chan[3].toString(), [0,'30']) //check initalDeposit +// assert.equal(chan[4].toString(), '0') //check sequence +// assert.equal(chan[5].toString(), '0') //check confirmTime +// assert.equal(chan[6], '0x0000000000000000000000000000000000000000000000000000000000000000') //check VCrootHash +// //check if chan[7] is equal to now + confirmtime +// assert.equal(chan[8].toString(), '0') //check updateLCTimeout +// assert.equal(chan[9], true) //check isOpen +// assert.equal(chan[10], false) //check isUpdateLCSettling +// assert.equal(chan[11], '0') //check numOpenVC +// }) + + +// it("Alice creates vc state vcSO with Bob", async () => { +// AB_vcS0 = web3latest.utils.soliditySha3( +// { type: 'bytes32', value: web3latest.utils.sha3('1337', {encoding: 'hex'}) }, // vc id +// { type: 'uint256', value: 0 }, // sequence +// { type: 'address', value: partyA }, // partyA +// { type: 'address', value: partyB }, // partyB, +// { type: 'uint256', value: 0 }, //hub eth bond +// { type: 'uint256', value: 12 }, // hub token bond +// { type: 'uint256', value: 0 }, +// { type: 'uint256', value: 0 }, +// { type: 'uint256', value: 5 }, // token +// { type: 'uint256', value: 7 } // token +// ) + +// }) + +// it("Alice and Bob sign vcSO", async () => { +// AB_vcS0_sigA = await web3latest.eth.sign(AB_vcS0, partyA) +// AB_vcS0_sigB = await web3latest.eth.sign(AB_vcS0, partyB) +// }) + +// it("Alice creates lc state lcS1 containing vcSO with Ingrid", async () => { +// var hash = web3latest.utils.sha3(AB_vcS0, {encoding: 'hex'}) +// var buf = Utils.hexToBuffer(hash) +// var elems = [] +// elems.push(buf) +// elems.push(Utils.hexToBuffer('0x0000000000000000000000000000000000000000000000000000000000000000')) +// var merkle = new MerkleTree(elems) + +// vcRootHash = Utils.bufferToHex(merkle.getRoot()) + +// AI_lcS1 = web3latest.utils.soliditySha3( +// { type: 'uint256', value: lcid_AI }, +// { type: 'bool', value: false }, // isclose +// //{ type: 'bytes32', value: web3.sha3('lc2', {encoding: 'hex'}) }, // lcid +// { type: 'uint256', value: 1 }, // sequence +// { type: 'uint256', value: 1 }, // open VCs +// { type: 'string', value: vcRootHash }, // VC root hash +// { type: 'address', value: partyA }, // partyA +// { type: 'address', value: partyI }, // hub +// { type: 'uint256', value: 0 }, //eth +// { type: 'uint256', value: 0 }, //eth +// { type: 'uint256', value: 5 }, // token +// { type: 'uint256', value: 13 } // token +// ) +// }) + +// it("Alice signs lcS1 state and sends to Hub", async () => { +// AI_lcS1_sigA = await web3latest.eth.sign(AI_lcS1, partyA) +// }) + +// it("Bob creates lc state lcS1 containing vcSO with Ingrid", async () => { +// var hash = web3latest.utils.sha3(AB_vcS0, {encoding: 'hex'}) +// var buf = Utils.hexToBuffer(hash) +// var elems = [] +// elems.push(buf) +// elems.push(Utils.hexToBuffer('0x0000000000000000000000000000000000000000000000000000000000000000')) +// var merkle = new MerkleTree(elems) + +// vcRootHash = Utils.bufferToHex(merkle.getRoot()) + +// BI_lcS1 = web3latest.utils.soliditySha3( +// { type: 'uint256', value: lcid_BI }, +// { type: 'bool', value: false }, // isclose +// //{ type: 'bytes32', value: web3.sha3('lc4', {encoding: 'hex'}) }, // lcid +// { type: 'uint256', value: 1 }, // sequence +// { type: 'uint256', value: 1 }, // open VCs +// { type: 'string', value: vcRootHash }, // VC root hash +// { type: 'address', value: partyB }, // partyB +// { type: 'address', value: partyI }, // hub +// { type: 'uint256', value: 0 }, //eth +// { type: 'uint256', value: 0 }, //eth +// { type: 'uint256', value: 3 }, // token +// { type: 'uint256', value: 15 } // token +// ) +// }) + +// it("Bob signs lcS1 state and sends to hub", async () => { +// BI_lcS1_sigB = await web3latest.eth.sign(BI_lcS1, partyB) +// }) + +// it("Hub signs both Alice and Bob's lcS1 state to open VC", async () => { +// AI_lcS1_sigI = await web3latest.eth.sign(AI_lcS1, partyI) +// BI_lcS1_sigI = await web3latest.eth.sign(BI_lcS1, partyI) +// }) + +// it("Alice generates virtual channel payment with Bob (vcS1)", async () => { +// AB_vcS1 = web3latest.utils.soliditySha3( +// { type: 'bytes32', value: web3latest.utils.sha3('1337', {encoding: 'hex'}) }, // vc id +// { type: 'uint256', value: 1 }, // sequence +// { type: 'address', value: partyA }, // partyA +// { type: 'address', value: partyB }, // partyB +// { type: 'uint256', value: 0 }, // hub eth bond +// { type: 'uint256', value: 12}, //hub token bond +// { type: 'uint256', value: 0 }, +// { type: 'uint256', value: 0 }, +// { type: 'uint256', value: 0 }, // token +// { type: 'uint256', value: 12 } // token +// ) + +// }) + +// it("Alice and Bob sign vcS1", async () => { +// AB_vcS1_sigA = await web3latest.eth.sign(AB_vcS1, partyA) +// AB_vcS1_sigB = await web3latest.eth.sign(AB_vcS1, partyB) +// }) + +// it("Alice generates lc state to close vc", async () => { +// AI_lcS2 = web3latest.utils.soliditySha3( +// { type: 'uint256', value: lcid_AI }, +// { type: 'bool', value: false }, // isclose +// //{ type: 'bytes32', value: web3.sha3('lc2', {encoding: 'hex'}) }, // lcid +// { type: 'uint256', value: 2 }, // sequence +// { type: 'uint256', value: 0 }, // open VCs +// { type: 'string', value: '0x0' }, // VC root hash +// { type: 'address', value: partyA }, // partyA +// { type: 'address', value: partyI }, // hub +// { type: 'uint256', value: 0 }, //eth +// { type: 'uint256', value: 0 }, //eth +// { type: 'uint256', value: 5 }, // token +// { type: 'uint256', value: 25 } // token +// ) + +// }) + +// it("Bob generates lc state to close vc", async () => { +// BI_lcS2 = web3latest.utils.soliditySha3( +// { type: 'uint256', value: lcid_BI }, +// { type: 'bool', value: false }, // isclose +// //{ type: 'bytes32', value: web3.sha3('lc4', {encoding: 'hex'}) }, // lcid +// { type: 'uint256', value: 2 }, // sequence +// { type: 'uint256', value: 0 }, // open VCs +// { type: 'string', value: '0x0' }, // VC root hash +// { type: 'address', value: partyB }, // partyB +// { type: 'address', value: partyI }, // hub +// { type: 'uint256', value: 0 }, //eth +// { type: 'uint256', value: 0 }, //eth +// { type: 'uint256', value: 15 }, // token +// { type: 'uint256', value: 15 } // token +// ) +// }) + +// it("Alice signs lcS2 state and sends to Hub", async () => { +// AI_lcS2_sigA = await web3latest.eth.sign(AI_lcS2, partyA) +// }) + +// it("Bob signs lcS2 state and sends to hub", async () => { +// BI_lcS2_sigB = await web3latest.eth.sign(BI_lcS2, partyB) +// }) + +// it("Hub signs both Alice and Bob's lcS2 state to close VC", async () => { +// AI_lcS2_sigI = await web3latest.eth.sign(AI_lcS2, partyI) +// BI_lcS2_sigI = await web3latest.eth.sign(BI_lcS2, partyI) +// }) + +// it("Alice creates lc update to close vc", async () => { +// AI_lcS3 = web3latest.utils.soliditySha3( +// { type: 'uint256', value: lcid_AI }, +// { type: 'bool', value: true }, // isclose +// //{ type: 'bytes32', value: web3.sha3('lc2', {encoding: 'hex'}) }, // lcid +// { type: 'uint256', value: '3' }, // sequence +// { type: 'uint256', value: '0' }, // open VCs +// { type: 'bytes32', value: '0x0' }, // VC root hash +// { type: 'address', value: partyA }, // partyA +// { type: 'address', value: partyI }, // hub +// { type: 'uint256', value: 0 }, //eth +// { type: 'uint256', value: 0 }, //eth +// { type: 'uint256', value: 5 }, // token +// { type: 'uint256', value: 25 } // token +// ) +// }) + +// it("Alice signs lcS3 state and sends to Hub", async () => { +// AI_lcS3_sigA = await web3latest.eth.sign(AI_lcS3, partyA) +// }) + +// it("Hub signs closing lcS3 state", async () => { +// AI_lcS3_sigI = await web3latest.eth.sign(AI_lcS3, partyI) +// }) + +// it("Close Alice ledger channel", async () => { +// var balA1 = await token.balanceOf(partyA) +// var balI1 = await token.balanceOf(partyI) +// let receipt = await lc.consensusCloseChannel(lcid_AI, '3', [0, 0, 5, 25], AI_lcS3_sigA, AI_lcS3_sigI) +// var gasUsed = receipt.receipt.gasUsed +// //console.log('Close Channel: ' + gasUsed) +// var balA2 = await token.balanceOf(partyA) +// var balI2 = await token.balanceOf(partyI) +// // TODO calculate gas, this may very based on testrpc +// assert.equal(balI2 - balI1, '25') +// // assert.equal(balA2 - balA1, '7926958099999998000') +// }) + +// /******TO DO******/ +// it("Hub deposits into Bob's lc", async () => { +// await lc.deposit(lcid_BI, partyI, web3latest.utils.toWei('10'), false, {from:partyI, value:web3latest.utils.toWei('10')}) +// let chan = await lc.getChannel(lcid_BI) +// }) + +// it("Hub creates lc state lcS2 containing new deposit", async () => { +// var hash = web3latest.utils.sha3(AB_vcS0, {encoding: 'hex'}) +// var buf = Utils.hexToBuffer(hash) +// var elems = [] +// elems.push(buf) +// elems.push(Utils.hexToBuffer('0x0000000000000000000000000000000000000000000000000000000000000000')) +// var merkle = new MerkleTree(elems) + +// vcRootHash = Utils.bufferToHex(merkle.getRoot()) + +// BI_lcS1 = web3latest.utils.soliditySha3( +// { type: 'uint256', value: lcid_BI }, +// { type: 'bool', value: false }, // isclose +// //{ type: 'bytes32', value: web3.sha3('lc4', {encoding: 'hex'}) }, // lcid +// { type: 'uint256', value: 2 }, // sequence +// { type: 'uint256', value: 1 }, // open VCs +// { type: 'string', value: vcRootHash }, // VC root hash +// { type: 'address', value: partyB }, // partyA +// { type: 'address', value: partyI }, // hub +// { type: 'uint256', value: web3latest.utils.toWei('3') }, +// { type: 'uint256', value: web3latest.utils.toWei('25') }, +// { type: 'uint256', value: web3latest.utils.toWei('0') }, // token +// { type: 'uint256', value: web3latest.utils.toWei('0') } // token +// ) +// }) + +// }) diff --git a/test/scenarios/coopEtherTest.js b/test/scenarios/coopEtherTest.js index ae400b9..978c578 100644 --- a/test/scenarios/coopEtherTest.js +++ b/test/scenarios/coopEtherTest.js @@ -1,451 +1,451 @@ -'use strict' +// 'use strict' -import MerkleTree from '../helpers/MerkleTree' -const Utils = require('../helpers/utils') -const Ledger = artifacts.require('./LedgerChannel.sol') -const EC = artifacts.require('./ECTools.sol') - -const Web3latest = require('web3') -const web3latest = new Web3latest(new Web3latest.providers.HttpProvider("http://localhost:8545")) //ganache port - - -let lc - -// state - -let partyA -let partyB -let partyI - -let lcid_AI -let lcid_BI - -let vcRootHash - -// is close flag, lc state sequence, number open vc, vc root hash, partyA/B, partyI, balA/B, balI - -let AI_lcS0 -let AI_lcS1 -let AI_lcS2 -let AI_lcS3 - -let BI_lcS0 -let BI_lcS1 -let BI_lcS2 - -let AB_vcS0 -let AB_vcS1 - -let AB_vc2_S0 -let AB_vc2_S1 - -// signature storage -let AI_lcS0_sigA -let AI_lcS1_sigA -let AI_lcS2_sigA -let AI_lcS3_sigA - -let AI_lcS0_sigI -let AI_lcS1_sigI -let AI_lcS2_sigI -let AI_lcS3_sigI - -let BI_lcS0_sigB -let BI_lcS1_sigB -let BI_lcS2_sigB - -let BI_lcS0_sigI -let BI_lcS1_sigI -let BI_lcS2_sigI - -let AB_vcS0_sigA -let AB_vcS1_sigA - -let AB_vcS0_sigB -let AB_vcS1_sigB - -contract('Test Cooperative Ether Payments', function(accounts) { - - before(async () => { - partyA = accounts[0] - partyB = accounts[1] - partyI = accounts[2] - - let ec = await EC.new() - Ledger.link('ECTools', ec.address) - lc = await Ledger.new() - }) - - it("Create initial ledger channel state lcS0 for AI channel", async () => { - lcid_AI = web3latest.utils.sha3('1111', {encoding: 'hex'}) - AI_lcS0 = web3latest.utils.soliditySha3( - { type: 'uint256', value: lcid_AI }, // ID - { type: 'bool', value: false }, // isclose - //{ type: 'bytes32', value: web3.sha3('lc2', {encoding: 'hex'}) }, // lcid - { type: 'uint256', value: 0 }, // sequence - { type: 'uint256', value: 0 }, // open VCs - { type: 'string', value: '0x0' }, // VC root hash - { type: 'address', value: partyA }, // partyA - { type: 'address', value: partyI }, // hub - { type: 'uint256', value: web3latest.utils.toWei('10') }, // eth - { type: 'uint256', value: web3latest.utils.toWei('20') }, // eth - { type: 'uint256', value: web3latest.utils.toWei('0') }, // token - { type: 'uint256', value: web3latest.utils.toWei('0') } // token - ) - }) - - it("Alice signs initial lcS0 state", async () => { - AI_lcS0_sigA = await web3latest.eth.sign(AI_lcS0, partyA) - }) - - // address[2] partyAdresses; // 0: partyA 1: partyI - // uint256[2] ethBalances; // 0: balanceA 1:balanceI - // uint256[2] erc20Balances; // 0: balanceA 1:balanceI - // uint256[2] deposited; - // uint256 initialDeposit; - // uint256 sequence; - // uint256 confirmTime; - // bytes32 VCrootHash; - // uint256 LCopenTimeout; - // uint256 updateLCtimeout; // when update LC times out - // bool isOpen; // true when both parties have joined - // bool isUpdateLCSettling; - // uint256 numOpenVC; - - - it("Alice initiates ledger channel with lcS0", async () => { - let res = await lc.createChannel(lcid_AI, partyI, '0', '0x0', [web3latest.utils.toWei('10'), 0], {from:partyA, value: web3latest.utils.toWei('10')}) - var gasUsed = res.receipt.gasUsed - //console.log('createChan: '+ gasUsed) - let openChans = await lc.numChannels() - let chan = await lc.getChannel(lcid_AI) - assert.equal(chan[0].toString(), [partyA,partyI]) //check partyAddresses - assert.equal(chan[1].toString(), [web3latest.utils.toWei('10'), '0', '0', '0']) //check ethBalances - assert.equal(chan[2].toString(), ['0', '0', '0', '0']) //check erc20Balances - assert.equal(chan[3].toString(), [web3latest.utils.toWei('10'), 0]) //check initalDeposit - assert.equal(chan[4].toString(), '0') //check sequence - assert.equal(chan[5].toString(), '0') //check confirmTime - assert.equal(chan[6], '0x0000000000000000000000000000000000000000000000000000000000000000') //check VCrootHash - //check if chan[7] is equal to now + confirmtime - assert.equal(chan[8].toString(), '0') //check updateLCTimeout - assert.equal(chan[9], false) //check isOpen - assert.equal(chan[10], false) //check isUpdateLCSettling - assert.equal(chan[11], '0') //check numOpenVC - }) - - it("Hub signs initial lcS0 state", async () => { - AI_lcS0_sigI = await web3latest.eth.sign(AI_lcS0, partyI) - }) - - it("Ingrid joins ledger channel", async () => { - let res = await lc.joinChannel(lcid_AI, [web3latest.utils.toWei('20'), 0], {from: partyI, value: web3latest.utils.toWei('20')}) - var gasUsed = res.receipt.gasUsed - //console.log('joinChan: '+ gasUsed) - let openChans = await lc.numChannels() - let chan = await lc.getChannel(lcid_AI) - assert.equal(chan[0].toString(), [partyA,partyI]) //check partyAddresses - assert.equal(chan[1].toString(), [web3latest.utils.toWei('10'), web3latest.utils.toWei('20'), '0', '0']) //check ethBalances - assert.equal(chan[2].toString(), ['0', '0', '0', '0']) //check erc20Balances - assert.equal(chan[3].toString(), [web3latest.utils.toWei('30'), 0]) //check initalDeposit - assert.equal(chan[4].toString(), '0') //check sequence - assert.equal(chan[5].toString(), '0') //check confirmTime - assert.equal(chan[6], '0x0000000000000000000000000000000000000000000000000000000000000000') //check VCrootHash - //check if chan[7] is equal to now + confirmtime - assert.equal(chan[8].toString(), '0') //check updateLCTimeout - assert.equal(chan[9], true) //check isOpen - assert.equal(chan[10], false) //check isUpdateLCSettling - assert.equal(chan[11], '0') //check numOpenVC - }) - - // Bob creates ledger channel - it("Create Bob's ledger channel state lcS0 for BI channel", async () => { - lcid_BI = web3latest.utils.sha3('2222', {encoding: 'hex'}) - - BI_lcS0 = web3latest.utils.soliditySha3( - { type: 'uint256', value: lcid_BI }, // ID - { type: 'bool', value: false }, // isclose - //{ type: 'bytes32', value: web3.sha3('lc4', {encoding: 'hex'}) }, // lcid - { type: 'uint256', value: 0 }, // sequence - { type: 'uint256', value: 0 }, // open VCs - { type: 'string', value: '0x0' }, // VC root hash - { type: 'address', value: partyB }, // partyA - { type: 'address', value: partyI }, // hub - { type: 'uint256', value: web3latest.utils.toWei('10') }, - { type: 'uint256', value: web3latest.utils.toWei('20') }, - { type: 'uint256', value: web3latest.utils.toWei('0') }, // token - { type: 'uint256', value: web3latest.utils.toWei('0') } // token - ) - }) - - it("Bob signs initial lcS0 state", async () => { - BI_lcS0_sigB = await web3latest.eth.sign(BI_lcS0, partyB) - }) - - - it("Bob initiates ledger channel with lcS0", async () => { - await lc.createChannel(lcid_BI, partyI, '0', '0x0', [web3latest.utils.toWei('10'), 0], {from:partyB, value: web3latest.utils.toWei('10')}) - let openChans = await lc.numChannels() - let chan = await lc.getChannel(lcid_BI) - assert.equal(chan[0].toString(), [partyB,partyI]) //check partyAddresses - assert.equal(chan[1].toString(), [web3latest.utils.toWei('10'), '0', '0', '0']) //check ethBalances - assert.equal(chan[2].toString(), ['0', '0', '0', '0']) //check erc20Balances - assert.equal(chan[3].toString(), [web3latest.utils.toWei('10'),0]) //check initalDeposit - assert.equal(chan[4].toString(), '0') //check sequence - assert.equal(chan[5].toString(), '0') //check confirmTime - assert.equal(chan[6], '0x0000000000000000000000000000000000000000000000000000000000000000') //check VCrootHash - //check if chan[7] is equal to now + confirmtime - assert.equal(chan[8].toString(), '0') //check updateLCTimeout - assert.equal(chan[9], false) //check isOpen - assert.equal(chan[10], false) //check isUpdateLCSettling - assert.equal(chan[11], '0') //check numOpenVC - }) - - it("Hub signs initial lcS0 state", async () => { - BI_lcS0_sigI = await web3latest.eth.sign(BI_lcS0, partyI) - }) - - it("Ingrid joins ledger channel", async () => { - await lc.joinChannel(lcid_BI, [web3latest.utils.toWei('20'), 0], {from: partyI, value: web3latest.utils.toWei('20')}) - let openChans = await lc.numChannels() - let chan = await lc.getChannel(lcid_BI) - assert.equal(chan[0].toString(), [partyB,partyI]) //check partyAddresses - assert.equal(chan[1].toString(), [web3latest.utils.toWei('10'), web3latest.utils.toWei('20'), '0', '0']) //check ethBalances - assert.equal(chan[2].toString(), ['0', '0', '0', '0']) //check erc20Balances - assert.equal(chan[3].toString(), [web3latest.utils.toWei('30'),0]) //check initalDeposit - assert.equal(chan[4].toString(), '0') //check sequence - assert.equal(chan[5].toString(), '0') //check confirmTime - assert.equal(chan[6], '0x0000000000000000000000000000000000000000000000000000000000000000') //check VCrootHash - //check if chan[7] is equal to now + confirmtime - assert.equal(chan[8].toString(), '0') //check updateLCTimeout - assert.equal(chan[9], true) //check isOpen - assert.equal(chan[10], false) //check isUpdateLCSettling - assert.equal(chan[11], '0') //check numOpenVC - }) - - - it("Alice creates vc state vcSO with Bob", async () => { - AB_vcS0 = web3latest.utils.soliditySha3( - { type: 'bytes32', value: web3latest.utils.sha3('1337', {encoding: 'hex'}) }, // vc id - { type: 'uint256', value: 0 }, // sequence - { type: 'address', value: partyA }, // partyA - { type: 'address', value: partyB }, // partyB, - { type: 'uint256', value: web3latest.utils.toWei('12') }, // hub eth bond - { type: 'uint256', value: 0}, //hub token bond - { type: 'uint256', value: web3latest.utils.toWei('5') }, - { type: 'uint256', value: web3latest.utils.toWei('7') }, - { type: 'uint256', value: web3latest.utils.toWei('0') }, // token - { type: 'uint256', value: web3latest.utils.toWei('0') } // token - ) - - }) - - it("Alice and Bob sign vcSO", async () => { - AB_vcS0_sigA = await web3latest.eth.sign(AB_vcS0, partyA) - AB_vcS0_sigB = await web3latest.eth.sign(AB_vcS0, partyB) - }) - - it("Alice creates lc state lcS1 containing vcSO with Ingrid", async () => { - var hash = web3latest.utils.sha3(AB_vcS0, {encoding: 'hex'}) - var buf = Utils.hexToBuffer(hash) - var elems = [] - elems.push(buf) - elems.push(Utils.hexToBuffer('0x0000000000000000000000000000000000000000000000000000000000000000')) - var merkle = new MerkleTree(elems) - - vcRootHash = Utils.bufferToHex(merkle.getRoot()) - - AI_lcS1 = web3latest.utils.soliditySha3( - { type: 'uint256', value: lcid_AI }, - { type: 'bool', value: false }, // isclose - //{ type: 'bytes32', value: web3.sha3('lc2', {encoding: 'hex'}) }, // lcid - { type: 'uint256', value: 1 }, // sequence - { type: 'uint256', value: 1 }, // open VCs - { type: 'string', value: vcRootHash }, // VC root hash - { type: 'address', value: partyA }, // partyA - { type: 'address', value: partyI }, // hub - { type: 'uint256', value: web3latest.utils.toWei('5') }, //eth - { type: 'uint256', value: web3latest.utils.toWei('13') }, //eth - { type: 'uint256', value: web3latest.utils.toWei('0') }, // token - { type: 'uint256', value: web3latest.utils.toWei('0') } // token - ) - }) - - it("Alice signs lcS1 state and sends to Hub", async () => { - AI_lcS1_sigA = await web3latest.eth.sign(AI_lcS1, partyA) - }) - - it("Bob creates lc state lcS1 containing vcSO with Ingrid", async () => { - var hash = web3latest.utils.sha3(AB_vcS0, {encoding: 'hex'}) - var buf = Utils.hexToBuffer(hash) - var elems = [] - elems.push(buf) - elems.push(Utils.hexToBuffer('0x0000000000000000000000000000000000000000000000000000000000000000')) - var merkle = new MerkleTree(elems) - - vcRootHash = Utils.bufferToHex(merkle.getRoot()) - - BI_lcS1 = web3latest.utils.soliditySha3( - { type: 'uint256', value: lcid_BI }, - { type: 'bool', value: false }, // isclose - //{ type: 'bytes32', value: web3.sha3('lc4', {encoding: 'hex'}) }, // lcid - { type: 'uint256', value: 1 }, // sequence - { type: 'uint256', value: 1 }, // open VCs - { type: 'string', value: vcRootHash }, // VC root hash - { type: 'address', value: partyB }, // partyB - { type: 'address', value: partyI }, // hub - { type: 'uint256', value: web3latest.utils.toWei('3') }, //eth - { type: 'uint256', value: web3latest.utils.toWei('15') }, //eth - { type: 'uint256', value: web3latest.utils.toWei('0') }, // token - { type: 'uint256', value: web3latest.utils.toWei('0') } // token - ) - }) - - it("Bob signs lcS1 state and sends to hub", async () => { - BI_lcS1_sigB = await web3latest.eth.sign(BI_lcS1, partyB) - }) - - it("Hub signs both Alice and Bob's lcS1 state to open VC", async () => { - AI_lcS1_sigI = await web3latest.eth.sign(AI_lcS1, partyI) - BI_lcS1_sigI = await web3latest.eth.sign(BI_lcS1, partyI) - }) - - it("Alice generates virtual channel payment with Bob (vcS1)", async () => { - AB_vcS1 = web3latest.utils.soliditySha3( - { type: 'bytes32', value: web3latest.utils.sha3('1337', {encoding: 'hex'}) }, // vc id - { type: 'uint256', value: 1 }, // sequence - { type: 'address', value: partyA }, // partyA - { type: 'address', value: partyB }, // partyB - { type: 'uint256', value: web3latest.utils.toWei('12') }, // hub eth bond - { type: 'uint256', value: 0}, //hub token bond - { type: 'uint256', value: web3latest.utils.toWei('0') }, - { type: 'uint256', value: web3latest.utils.toWei('12') }, - { type: 'uint256', value: web3latest.utils.toWei('0') }, // token - { type: 'uint256', value: web3latest.utils.toWei('0') } // token - ) - - }) - - it("Alice and Bob sign vcS1", async () => { - AB_vcS1_sigA = await web3latest.eth.sign(AB_vcS1, partyA) - AB_vcS1_sigB = await web3latest.eth.sign(AB_vcS1, partyB) - }) - - it("Alice generates lc state to close vc", async () => { - AI_lcS2 = web3latest.utils.soliditySha3( - { type: 'uint256', value: lcid_AI }, - { type: 'bool', value: false }, // isclose - //{ type: 'bytes32', value: web3.sha3('lc2', {encoding: 'hex'}) }, // lcid - { type: 'uint256', value: 2 }, // sequence - { type: 'uint256', value: 0 }, // open VCs - { type: 'string', value: '0x0' }, // VC root hash - { type: 'address', value: partyA }, // partyA - { type: 'address', value: partyI }, // hub - { type: 'uint256', value: web3latest.utils.toWei('5') }, //eth - { type: 'uint256', value: web3latest.utils.toWei('25') }, //eth - { type: 'uint256', value: web3latest.utils.toWei('0') }, // token - { type: 'uint256', value: web3latest.utils.toWei('0') } // token - ) - - }) - - it("Bob generates lc state to close vc", async () => { - BI_lcS2 = web3latest.utils.soliditySha3( - { type: 'uint256', value: lcid_BI }, - { type: 'bool', value: false }, // isclose - //{ type: 'bytes32', value: web3.sha3('lc4', {encoding: 'hex'}) }, // lcid - { type: 'uint256', value: 2 }, // sequence - { type: 'uint256', value: 0 }, // open VCs - { type: 'string', value: '0x0' }, // VC root hash - { type: 'address', value: partyB }, // partyB - { type: 'address', value: partyI }, // hub - { type: 'uint256', value: web3latest.utils.toWei('15') }, //eth - { type: 'uint256', value: web3latest.utils.toWei('15') }, //eth - { type: 'uint256', value: web3latest.utils.toWei('0') }, // token - { type: 'uint256', value: web3latest.utils.toWei('0') } // token - ) - }) - - it("Alice signs lcS2 state and sends to Hub", async () => { - AI_lcS2_sigA = await web3latest.eth.sign(AI_lcS2, partyA) - }) - - it("Bob signs lcS2 state and sends to hub", async () => { - BI_lcS2_sigB = await web3latest.eth.sign(BI_lcS2, partyB) - }) - - it("Hub signs both Alice and Bob's lcS2 state to close VC", async () => { - AI_lcS2_sigI = await web3latest.eth.sign(AI_lcS2, partyI) - BI_lcS2_sigI = await web3latest.eth.sign(BI_lcS2, partyI) - }) - - it("Alice creates lc update to close vc", async () => { - AI_lcS3 = web3latest.utils.soliditySha3( - { type: 'uint256', value: lcid_AI }, - { type: 'bool', value: true }, // isclose - //{ type: 'bytes32', value: web3.sha3('lc2', {encoding: 'hex'}) }, // lcid - { type: 'uint256', value: '3' }, // sequence - { type: 'uint256', value: '0' }, // open VCs - { type: 'bytes32', value: '0x0' }, // VC root hash - { type: 'address', value: partyA }, // partyA - { type: 'address', value: partyI }, // hub - { type: 'uint256', value: web3latest.utils.toWei('5') }, - { type: 'uint256', value: web3latest.utils.toWei('25') }, - { type: 'uint256', value: web3latest.utils.toWei('0') }, // token - { type: 'uint256', value: web3latest.utils.toWei('0') } // token - ) - }) - - it("Alice signs lcS3 state and sends to Hub", async () => { - AI_lcS3_sigA = await web3latest.eth.sign(AI_lcS3, partyA) - }) - - it("Hub signs closing lcS3 state", async () => { - AI_lcS3_sigI = await web3latest.eth.sign(AI_lcS3, partyI) - }) - - it("Close Alice ledger channel", async () => { - var balA1 = await web3latest.eth.getBalance(partyA) - var balI1 = await web3latest.eth.getBalance(partyI) - let receipt = await lc.consensusCloseChannel(lcid_AI, '3', [web3latest.utils.toWei('5'), web3latest.utils.toWei('25'), 0, 0], AI_lcS3_sigA, AI_lcS3_sigI) - var gasUsed = receipt.receipt.gasUsed - //console.log('Close Channel: ' + gasUsed) - var balA2 = await web3latest.eth.getBalance(partyA) - var balI2 = await web3latest.eth.getBalance(partyI) - // TODO calculate gas, this may very based on testrpc - assert.equal(balI2 - balI1, '25000000000000000000') - // assert.equal(balA2 - balA1, '7926958099999998000') - }) - - /******TO DO******/ - it("Hub deposits into Bob's lc", async () => { - await lc.deposit(lcid_BI, partyI, web3latest.utils.toWei('10'), false, {from:partyI, value:web3latest.utils.toWei('10')}) - let chan = await lc.getChannel(lcid_BI) - }) - - it("Hub creates lc state lcS2 containing new deposit", async () => { - var hash = web3latest.utils.sha3(AB_vcS0, {encoding: 'hex'}) - var buf = Utils.hexToBuffer(hash) - var elems = [] - elems.push(buf) - elems.push(Utils.hexToBuffer('0x0000000000000000000000000000000000000000000000000000000000000000')) - var merkle = new MerkleTree(elems) - - vcRootHash = Utils.bufferToHex(merkle.getRoot()) - - BI_lcS1 = web3latest.utils.soliditySha3( - { type: 'uint256', value: lcid_BI }, - { type: 'bool', value: false }, // isclose - //{ type: 'bytes32', value: web3.sha3('lc4', {encoding: 'hex'}) }, // lcid - { type: 'uint256', value: 2 }, // sequence - { type: 'uint256', value: 1 }, // open VCs - { type: 'string', value: vcRootHash }, // VC root hash - { type: 'address', value: partyB }, // partyA - { type: 'address', value: partyI }, // hub - { type: 'uint256', value: web3latest.utils.toWei('3') }, - { type: 'uint256', value: web3latest.utils.toWei('25') }, - { type: 'uint256', value: web3latest.utils.toWei('0') }, // token - { type: 'uint256', value: web3latest.utils.toWei('0') } // token - ) - }) - -}) \ No newline at end of file +// import MerkleTree from '../helpers/MerkleTree' +// const Utils = require('../helpers/utils') +// const Ledger = artifacts.require('./LedgerChannel.sol') +// const EC = artifacts.require('./ECTools.sol') + +// const Web3latest = require('web3') +// const web3latest = new Web3latest(new Web3latest.providers.HttpProvider("http://localhost:8545")) //ganache port + + +// let lc + +// // state + +// let partyA +// let partyB +// let partyI + +// let lcid_AI +// let lcid_BI + +// let vcRootHash + +// // is close flag, lc state sequence, number open vc, vc root hash, partyA/B, partyI, balA/B, balI + +// let AI_lcS0 +// let AI_lcS1 +// let AI_lcS2 +// let AI_lcS3 + +// let BI_lcS0 +// let BI_lcS1 +// let BI_lcS2 + +// let AB_vcS0 +// let AB_vcS1 + +// let AB_vc2_S0 +// let AB_vc2_S1 + +// // signature storage +// let AI_lcS0_sigA +// let AI_lcS1_sigA +// let AI_lcS2_sigA +// let AI_lcS3_sigA + +// let AI_lcS0_sigI +// let AI_lcS1_sigI +// let AI_lcS2_sigI +// let AI_lcS3_sigI + +// let BI_lcS0_sigB +// let BI_lcS1_sigB +// let BI_lcS2_sigB + +// let BI_lcS0_sigI +// let BI_lcS1_sigI +// let BI_lcS2_sigI + +// let AB_vcS0_sigA +// let AB_vcS1_sigA + +// let AB_vcS0_sigB +// let AB_vcS1_sigB + +// contract('Test Cooperative Ether Payments', function(accounts) { + +// before(async () => { +// partyA = accounts[0] +// partyB = accounts[1] +// partyI = accounts[2] + +// let ec = await EC.new() +// Ledger.link('ECTools', ec.address) +// lc = await Ledger.new() +// }) + +// it("Create initial ledger channel state lcS0 for AI channel", async () => { +// lcid_AI = web3latest.utils.sha3('1111', {encoding: 'hex'}) +// AI_lcS0 = web3latest.utils.soliditySha3( +// { type: 'uint256', value: lcid_AI }, // ID +// { type: 'bool', value: false }, // isclose +// //{ type: 'bytes32', value: web3.sha3('lc2', {encoding: 'hex'}) }, // lcid +// { type: 'uint256', value: 0 }, // sequence +// { type: 'uint256', value: 0 }, // open VCs +// { type: 'string', value: '0x0' }, // VC root hash +// { type: 'address', value: partyA }, // partyA +// { type: 'address', value: partyI }, // hub +// { type: 'uint256', value: web3latest.utils.toWei('10') }, // eth +// { type: 'uint256', value: web3latest.utils.toWei('20') }, // eth +// { type: 'uint256', value: web3latest.utils.toWei('0') }, // token +// { type: 'uint256', value: web3latest.utils.toWei('0') } // token +// ) +// }) + +// it("Alice signs initial lcS0 state", async () => { +// AI_lcS0_sigA = await web3latest.eth.sign(AI_lcS0, partyA) +// }) + +// // address[2] partyAdresses; // 0: partyA 1: partyI +// // uint256[2] ethBalances; // 0: balanceA 1:balanceI +// // uint256[2] erc20Balances; // 0: balanceA 1:balanceI +// // uint256[2] deposited; +// // uint256 initialDeposit; +// // uint256 sequence; +// // uint256 confirmTime; +// // bytes32 VCrootHash; +// // uint256 LCopenTimeout; +// // uint256 updateLCtimeout; // when update LC times out +// // bool isOpen; // true when both parties have joined +// // bool isUpdateLCSettling; +// // uint256 numOpenVC; + + +// it("Alice initiates ledger channel with lcS0", async () => { +// let res = await lc.createChannel(lcid_AI, partyI, '0', '0x0', [web3latest.utils.toWei('10'), 0], {from:partyA, value: web3latest.utils.toWei('10')}) +// var gasUsed = res.receipt.gasUsed +// //console.log('createChan: '+ gasUsed) +// let openChans = await lc.numChannels() +// let chan = await lc.getChannel(lcid_AI) +// assert.equal(chan[0].toString(), [partyA,partyI]) //check partyAddresses +// assert.equal(chan[1].toString(), [web3latest.utils.toWei('10'), '0', '0', '0']) //check ethBalances +// assert.equal(chan[2].toString(), ['0', '0', '0', '0']) //check erc20Balances +// assert.equal(chan[3].toString(), [web3latest.utils.toWei('10'), 0]) //check initalDeposit +// assert.equal(chan[4].toString(), '0') //check sequence +// assert.equal(chan[5].toString(), '0') //check confirmTime +// assert.equal(chan[6], '0x0000000000000000000000000000000000000000000000000000000000000000') //check VCrootHash +// //check if chan[7] is equal to now + confirmtime +// assert.equal(chan[8].toString(), '0') //check updateLCTimeout +// assert.equal(chan[9], false) //check isOpen +// assert.equal(chan[10], false) //check isUpdateLCSettling +// assert.equal(chan[11], '0') //check numOpenVC +// }) + +// it("Hub signs initial lcS0 state", async () => { +// AI_lcS0_sigI = await web3latest.eth.sign(AI_lcS0, partyI) +// }) + +// it("Ingrid joins ledger channel", async () => { +// let res = await lc.joinChannel(lcid_AI, [web3latest.utils.toWei('20'), 0], {from: partyI, value: web3latest.utils.toWei('20')}) +// var gasUsed = res.receipt.gasUsed +// //console.log('joinChan: '+ gasUsed) +// let openChans = await lc.numChannels() +// let chan = await lc.getChannel(lcid_AI) +// assert.equal(chan[0].toString(), [partyA,partyI]) //check partyAddresses +// assert.equal(chan[1].toString(), [web3latest.utils.toWei('10'), web3latest.utils.toWei('20'), '0', '0']) //check ethBalances +// assert.equal(chan[2].toString(), ['0', '0', '0', '0']) //check erc20Balances +// assert.equal(chan[3].toString(), [web3latest.utils.toWei('30'), 0]) //check initalDeposit +// assert.equal(chan[4].toString(), '0') //check sequence +// assert.equal(chan[5].toString(), '0') //check confirmTime +// assert.equal(chan[6], '0x0000000000000000000000000000000000000000000000000000000000000000') //check VCrootHash +// //check if chan[7] is equal to now + confirmtime +// assert.equal(chan[8].toString(), '0') //check updateLCTimeout +// assert.equal(chan[9], true) //check isOpen +// assert.equal(chan[10], false) //check isUpdateLCSettling +// assert.equal(chan[11], '0') //check numOpenVC +// }) + +// // Bob creates ledger channel +// it("Create Bob's ledger channel state lcS0 for BI channel", async () => { +// lcid_BI = web3latest.utils.sha3('2222', {encoding: 'hex'}) + +// BI_lcS0 = web3latest.utils.soliditySha3( +// { type: 'uint256', value: lcid_BI }, // ID +// { type: 'bool', value: false }, // isclose +// //{ type: 'bytes32', value: web3.sha3('lc4', {encoding: 'hex'}) }, // lcid +// { type: 'uint256', value: 0 }, // sequence +// { type: 'uint256', value: 0 }, // open VCs +// { type: 'string', value: '0x0' }, // VC root hash +// { type: 'address', value: partyB }, // partyA +// { type: 'address', value: partyI }, // hub +// { type: 'uint256', value: web3latest.utils.toWei('10') }, +// { type: 'uint256', value: web3latest.utils.toWei('20') }, +// { type: 'uint256', value: web3latest.utils.toWei('0') }, // token +// { type: 'uint256', value: web3latest.utils.toWei('0') } // token +// ) +// }) + +// it("Bob signs initial lcS0 state", async () => { +// BI_lcS0_sigB = await web3latest.eth.sign(BI_lcS0, partyB) +// }) + + +// it("Bob initiates ledger channel with lcS0", async () => { +// await lc.createChannel(lcid_BI, partyI, '0', '0x0', [web3latest.utils.toWei('10'), 0], {from:partyB, value: web3latest.utils.toWei('10')}) +// let openChans = await lc.numChannels() +// let chan = await lc.getChannel(lcid_BI) +// assert.equal(chan[0].toString(), [partyB,partyI]) //check partyAddresses +// assert.equal(chan[1].toString(), [web3latest.utils.toWei('10'), '0', '0', '0']) //check ethBalances +// assert.equal(chan[2].toString(), ['0', '0', '0', '0']) //check erc20Balances +// assert.equal(chan[3].toString(), [web3latest.utils.toWei('10'),0]) //check initalDeposit +// assert.equal(chan[4].toString(), '0') //check sequence +// assert.equal(chan[5].toString(), '0') //check confirmTime +// assert.equal(chan[6], '0x0000000000000000000000000000000000000000000000000000000000000000') //check VCrootHash +// //check if chan[7] is equal to now + confirmtime +// assert.equal(chan[8].toString(), '0') //check updateLCTimeout +// assert.equal(chan[9], false) //check isOpen +// assert.equal(chan[10], false) //check isUpdateLCSettling +// assert.equal(chan[11], '0') //check numOpenVC +// }) + +// it("Hub signs initial lcS0 state", async () => { +// BI_lcS0_sigI = await web3latest.eth.sign(BI_lcS0, partyI) +// }) + +// it("Ingrid joins ledger channel", async () => { +// await lc.joinChannel(lcid_BI, [web3latest.utils.toWei('20'), 0], {from: partyI, value: web3latest.utils.toWei('20')}) +// let openChans = await lc.numChannels() +// let chan = await lc.getChannel(lcid_BI) +// assert.equal(chan[0].toString(), [partyB,partyI]) //check partyAddresses +// assert.equal(chan[1].toString(), [web3latest.utils.toWei('10'), web3latest.utils.toWei('20'), '0', '0']) //check ethBalances +// assert.equal(chan[2].toString(), ['0', '0', '0', '0']) //check erc20Balances +// assert.equal(chan[3].toString(), [web3latest.utils.toWei('30'),0]) //check initalDeposit +// assert.equal(chan[4].toString(), '0') //check sequence +// assert.equal(chan[5].toString(), '0') //check confirmTime +// assert.equal(chan[6], '0x0000000000000000000000000000000000000000000000000000000000000000') //check VCrootHash +// //check if chan[7] is equal to now + confirmtime +// assert.equal(chan[8].toString(), '0') //check updateLCTimeout +// assert.equal(chan[9], true) //check isOpen +// assert.equal(chan[10], false) //check isUpdateLCSettling +// assert.equal(chan[11], '0') //check numOpenVC +// }) + + +// it("Alice creates vc state vcSO with Bob", async () => { +// AB_vcS0 = web3latest.utils.soliditySha3( +// { type: 'bytes32', value: web3latest.utils.sha3('1337', {encoding: 'hex'}) }, // vc id +// { type: 'uint256', value: 0 }, // sequence +// { type: 'address', value: partyA }, // partyA +// { type: 'address', value: partyB }, // partyB, +// { type: 'uint256', value: web3latest.utils.toWei('12') }, // hub eth bond +// { type: 'uint256', value: 0}, //hub token bond +// { type: 'uint256', value: web3latest.utils.toWei('5') }, +// { type: 'uint256', value: web3latest.utils.toWei('7') }, +// { type: 'uint256', value: web3latest.utils.toWei('0') }, // token +// { type: 'uint256', value: web3latest.utils.toWei('0') } // token +// ) + +// }) + +// it("Alice and Bob sign vcSO", async () => { +// AB_vcS0_sigA = await web3latest.eth.sign(AB_vcS0, partyA) +// AB_vcS0_sigB = await web3latest.eth.sign(AB_vcS0, partyB) +// }) + +// it("Alice creates lc state lcS1 containing vcSO with Ingrid", async () => { +// var hash = web3latest.utils.sha3(AB_vcS0, {encoding: 'hex'}) +// var buf = Utils.hexToBuffer(hash) +// var elems = [] +// elems.push(buf) +// elems.push(Utils.hexToBuffer('0x0000000000000000000000000000000000000000000000000000000000000000')) +// var merkle = new MerkleTree(elems) + +// vcRootHash = Utils.bufferToHex(merkle.getRoot()) + +// AI_lcS1 = web3latest.utils.soliditySha3( +// { type: 'uint256', value: lcid_AI }, +// { type: 'bool', value: false }, // isclose +// //{ type: 'bytes32', value: web3.sha3('lc2', {encoding: 'hex'}) }, // lcid +// { type: 'uint256', value: 1 }, // sequence +// { type: 'uint256', value: 1 }, // open VCs +// { type: 'string', value: vcRootHash }, // VC root hash +// { type: 'address', value: partyA }, // partyA +// { type: 'address', value: partyI }, // hub +// { type: 'uint256', value: web3latest.utils.toWei('5') }, //eth +// { type: 'uint256', value: web3latest.utils.toWei('13') }, //eth +// { type: 'uint256', value: web3latest.utils.toWei('0') }, // token +// { type: 'uint256', value: web3latest.utils.toWei('0') } // token +// ) +// }) + +// it("Alice signs lcS1 state and sends to Hub", async () => { +// AI_lcS1_sigA = await web3latest.eth.sign(AI_lcS1, partyA) +// }) + +// it("Bob creates lc state lcS1 containing vcSO with Ingrid", async () => { +// var hash = web3latest.utils.sha3(AB_vcS0, {encoding: 'hex'}) +// var buf = Utils.hexToBuffer(hash) +// var elems = [] +// elems.push(buf) +// elems.push(Utils.hexToBuffer('0x0000000000000000000000000000000000000000000000000000000000000000')) +// var merkle = new MerkleTree(elems) + +// vcRootHash = Utils.bufferToHex(merkle.getRoot()) + +// BI_lcS1 = web3latest.utils.soliditySha3( +// { type: 'uint256', value: lcid_BI }, +// { type: 'bool', value: false }, // isclose +// //{ type: 'bytes32', value: web3.sha3('lc4', {encoding: 'hex'}) }, // lcid +// { type: 'uint256', value: 1 }, // sequence +// { type: 'uint256', value: 1 }, // open VCs +// { type: 'string', value: vcRootHash }, // VC root hash +// { type: 'address', value: partyB }, // partyB +// { type: 'address', value: partyI }, // hub +// { type: 'uint256', value: web3latest.utils.toWei('3') }, //eth +// { type: 'uint256', value: web3latest.utils.toWei('15') }, //eth +// { type: 'uint256', value: web3latest.utils.toWei('0') }, // token +// { type: 'uint256', value: web3latest.utils.toWei('0') } // token +// ) +// }) + +// it("Bob signs lcS1 state and sends to hub", async () => { +// BI_lcS1_sigB = await web3latest.eth.sign(BI_lcS1, partyB) +// }) + +// it("Hub signs both Alice and Bob's lcS1 state to open VC", async () => { +// AI_lcS1_sigI = await web3latest.eth.sign(AI_lcS1, partyI) +// BI_lcS1_sigI = await web3latest.eth.sign(BI_lcS1, partyI) +// }) + +// it("Alice generates virtual channel payment with Bob (vcS1)", async () => { +// AB_vcS1 = web3latest.utils.soliditySha3( +// { type: 'bytes32', value: web3latest.utils.sha3('1337', {encoding: 'hex'}) }, // vc id +// { type: 'uint256', value: 1 }, // sequence +// { type: 'address', value: partyA }, // partyA +// { type: 'address', value: partyB }, // partyB +// { type: 'uint256', value: web3latest.utils.toWei('12') }, // hub eth bond +// { type: 'uint256', value: 0}, //hub token bond +// { type: 'uint256', value: web3latest.utils.toWei('0') }, +// { type: 'uint256', value: web3latest.utils.toWei('12') }, +// { type: 'uint256', value: web3latest.utils.toWei('0') }, // token +// { type: 'uint256', value: web3latest.utils.toWei('0') } // token +// ) + +// }) + +// it("Alice and Bob sign vcS1", async () => { +// AB_vcS1_sigA = await web3latest.eth.sign(AB_vcS1, partyA) +// AB_vcS1_sigB = await web3latest.eth.sign(AB_vcS1, partyB) +// }) + +// it("Alice generates lc state to close vc", async () => { +// AI_lcS2 = web3latest.utils.soliditySha3( +// { type: 'uint256', value: lcid_AI }, +// { type: 'bool', value: false }, // isclose +// //{ type: 'bytes32', value: web3.sha3('lc2', {encoding: 'hex'}) }, // lcid +// { type: 'uint256', value: 2 }, // sequence +// { type: 'uint256', value: 0 }, // open VCs +// { type: 'string', value: '0x0' }, // VC root hash +// { type: 'address', value: partyA }, // partyA +// { type: 'address', value: partyI }, // hub +// { type: 'uint256', value: web3latest.utils.toWei('5') }, //eth +// { type: 'uint256', value: web3latest.utils.toWei('25') }, //eth +// { type: 'uint256', value: web3latest.utils.toWei('0') }, // token +// { type: 'uint256', value: web3latest.utils.toWei('0') } // token +// ) + +// }) + +// it("Bob generates lc state to close vc", async () => { +// BI_lcS2 = web3latest.utils.soliditySha3( +// { type: 'uint256', value: lcid_BI }, +// { type: 'bool', value: false }, // isclose +// //{ type: 'bytes32', value: web3.sha3('lc4', {encoding: 'hex'}) }, // lcid +// { type: 'uint256', value: 2 }, // sequence +// { type: 'uint256', value: 0 }, // open VCs +// { type: 'string', value: '0x0' }, // VC root hash +// { type: 'address', value: partyB }, // partyB +// { type: 'address', value: partyI }, // hub +// { type: 'uint256', value: web3latest.utils.toWei('15') }, //eth +// { type: 'uint256', value: web3latest.utils.toWei('15') }, //eth +// { type: 'uint256', value: web3latest.utils.toWei('0') }, // token +// { type: 'uint256', value: web3latest.utils.toWei('0') } // token +// ) +// }) + +// it("Alice signs lcS2 state and sends to Hub", async () => { +// AI_lcS2_sigA = await web3latest.eth.sign(AI_lcS2, partyA) +// }) + +// it("Bob signs lcS2 state and sends to hub", async () => { +// BI_lcS2_sigB = await web3latest.eth.sign(BI_lcS2, partyB) +// }) + +// it("Hub signs both Alice and Bob's lcS2 state to close VC", async () => { +// AI_lcS2_sigI = await web3latest.eth.sign(AI_lcS2, partyI) +// BI_lcS2_sigI = await web3latest.eth.sign(BI_lcS2, partyI) +// }) + +// it("Alice creates lc update to close vc", async () => { +// AI_lcS3 = web3latest.utils.soliditySha3( +// { type: 'uint256', value: lcid_AI }, +// { type: 'bool', value: true }, // isclose +// //{ type: 'bytes32', value: web3.sha3('lc2', {encoding: 'hex'}) }, // lcid +// { type: 'uint256', value: '3' }, // sequence +// { type: 'uint256', value: '0' }, // open VCs +// { type: 'bytes32', value: '0x0' }, // VC root hash +// { type: 'address', value: partyA }, // partyA +// { type: 'address', value: partyI }, // hub +// { type: 'uint256', value: web3latest.utils.toWei('5') }, +// { type: 'uint256', value: web3latest.utils.toWei('25') }, +// { type: 'uint256', value: web3latest.utils.toWei('0') }, // token +// { type: 'uint256', value: web3latest.utils.toWei('0') } // token +// ) +// }) + +// it("Alice signs lcS3 state and sends to Hub", async () => { +// AI_lcS3_sigA = await web3latest.eth.sign(AI_lcS3, partyA) +// }) + +// it("Hub signs closing lcS3 state", async () => { +// AI_lcS3_sigI = await web3latest.eth.sign(AI_lcS3, partyI) +// }) + +// it("Close Alice ledger channel", async () => { +// var balA1 = await web3latest.eth.getBalance(partyA) +// var balI1 = await web3latest.eth.getBalance(partyI) +// let receipt = await lc.consensusCloseChannel(lcid_AI, '3', [web3latest.utils.toWei('5'), web3latest.utils.toWei('25'), 0, 0], AI_lcS3_sigA, AI_lcS3_sigI) +// var gasUsed = receipt.receipt.gasUsed +// //console.log('Close Channel: ' + gasUsed) +// var balA2 = await web3latest.eth.getBalance(partyA) +// var balI2 = await web3latest.eth.getBalance(partyI) +// // TODO calculate gas, this may very based on testrpc +// assert.equal(balI2 - balI1, '25000000000000000000') +// // assert.equal(balA2 - balA1, '7926958099999998000') +// }) + +// /******TO DO******/ +// it("Hub deposits into Bob's lc", async () => { +// await lc.deposit(lcid_BI, partyI, web3latest.utils.toWei('10'), false, {from:partyI, value:web3latest.utils.toWei('10')}) +// let chan = await lc.getChannel(lcid_BI) +// }) + +// it("Hub creates lc state lcS2 containing new deposit", async () => { +// var hash = web3latest.utils.sha3(AB_vcS0, {encoding: 'hex'}) +// var buf = Utils.hexToBuffer(hash) +// var elems = [] +// elems.push(buf) +// elems.push(Utils.hexToBuffer('0x0000000000000000000000000000000000000000000000000000000000000000')) +// var merkle = new MerkleTree(elems) + +// vcRootHash = Utils.bufferToHex(merkle.getRoot()) + +// BI_lcS1 = web3latest.utils.soliditySha3( +// { type: 'uint256', value: lcid_BI }, +// { type: 'bool', value: false }, // isclose +// //{ type: 'bytes32', value: web3.sha3('lc4', {encoding: 'hex'}) }, // lcid +// { type: 'uint256', value: 2 }, // sequence +// { type: 'uint256', value: 1 }, // open VCs +// { type: 'string', value: vcRootHash }, // VC root hash +// { type: 'address', value: partyB }, // partyA +// { type: 'address', value: partyI }, // hub +// { type: 'uint256', value: web3latest.utils.toWei('3') }, +// { type: 'uint256', value: web3latest.utils.toWei('25') }, +// { type: 'uint256', value: web3latest.utils.toWei('0') }, // token +// { type: 'uint256', value: web3latest.utils.toWei('0') } // token +// ) +// }) + +// }) diff --git a/test/unit/ledgerChannelNotes.txt b/test/unit/ChannelManageNotes.txt similarity index 51% rename from test/unit/ledgerChannelNotes.txt rename to test/unit/ChannelManageNotes.txt index 32b0ec0..3fd72b3 100644 --- a/test/unit/ledgerChannelNotes.txt +++ b/test/unit/ChannelManageNotes.txt @@ -145,4 +145,126 @@ Test case infrastructure: - local web3 instance talking to testrpc - local database - assertions will be made using connext-client methods -- when test cases complete, shut down all infra \ No newline at end of file +- when test cases complete, shut down all infra + +====================================================================================================== +Questions + 1) Why is LC_S0 needed before opening the channel? + + +============ +Unit test full + +createChannel: 7 cases + - 1. Error: Channel with lcID has already been created + - 2. Error: No partyI address provided + - 3. Error: Token _balance is negative + - 4. Error: Eth balance doesn't match paid value + - 5. Error: Token transfer failure + - 6. Success + +LCOpenTimeout: 5 (6?) cases + - 1. Error: Msg.sender is not partyA of Channels[_lcID] + - 2. Error: Channel does not exist + - 3. Error: Channel is already open + - 4. Error: Function called before LCopenTimeout time has expired + - (5?. Error: Token transfer failed) How do we check this?? + - 6. Success + +joinChannel: 6 cases + - 1. Error: Channel with that lcID has already been opened + - 2. Error: Msg.sender is not partyI of Channels[_lcID] + - 3. Error: Token _balance is negative + - 4. Error: Eth balance does not match paid value + - 5. Error: Token transfer failure + - 6. Success + + Add more case: channel with that ID does not exist + +deposit: 7 cases + - 1. Error: Tried depositing to a closed channel (what happens with payable eth here? Fallback function?) + - 2. Error: Recipient is not either partyA or partyI + - 3. Error: Token transfer failure partyA + - 4. Error: deposit doesn't match payable Eth partyA + - 5. Error: Token transfer failure partyI + - 6. Error: deposit doesn't match payable Eth partyI + - 7. Success + + Questions: + Why do we need separate deposit fields for parties and initial deposit? + How does a deposit get reflected in a new LC update? Should depositing just create an update and checkpoint the channel? + +consensusClose: 7 cases + - 1. Error: Channel with that ID doesn't exist + - 2. Error: Channel with that ID is not open + - 3. Error: Total Eth deposit not equal to LC eth balance + - 4. Error: Total token deposit not equal to LC token balance + - 5. Error: Incorrect signature for party A (either wrong state update or wrong address) + - 6. Error: Incorrect signature for party I (either wrong state update or wrong address) + - 7. Success + + Add more case: sequence number needs to be greater than channel.sequence + +updateLC: + - 1. Error: Channel with that ID doesn't exist + - 2. Error: Channel with that ID is not open + - 4. Error: Total Eth deposit not equal to LC eth balance + - 5. Error: Total token deposit not equal to LC token balance + - 7. Error: Incorrect signature for party A (either wrong state update or wrong address) + - 8. Error: Incorrect signature for party I (either wrong state update or wrong address) + - 9. Success 1: updateLCstate called and updateLCtimeout initiated + - 3. Error: Channel sequence is not less than state number + - 6. Error: updateLCtimeout has already timed out (channel is updateLCSettling but updateLCtimeout > now) + - 10. Success 2: updateLCstate called after timer started + +initVCstate: + - 1. Error: Channel with that ID doesn't exist + - 2. Error: Channel with that ID is not open + - 3. Error: VC with that ID is closed already + - 4. Error: LC update timer has not yet expired + - 5. Error: Update VC timer is not 0 (reentry, i.e. initVCstate was already called) + - 6. Error: Alice has not signed initial state or wrong state + - 7. Error: Old state is not contained in root hash + - 8. Success (check that updateVCtimer != 0) + + Questions: + 1) Make sure bob does not need to be checked here in any way + 2) Does hub sig need to be checked? What happens if alice submits a "fake" VC (i.e. one that was never ratified by hub) + +settleVC: + - 1. Error: Channel with that ID doesn't exist + - 2. Error: Channel with that ID is not open + - 3. Error: VC with that ID is already closed + - 4. Error: Onchain VC sequence is higher than submitted sequence + - 5. Error: State update decreases Eth balance + - 6. Error: State update decreases Token balance + - 7. Error: Eth balances do not match Eth bonded amount + - 8. Error: Token balances do not match token bonded amount + - 9. Error: InitVC was not called first + - 10. Error: updateLCtimeout has not yet expired (i.e. updateLCtimeout > now) + - 11. Error: Incorrect partyA signature or payload + - 12. Error: updateVCtimeout has expired + - 13. Success 1: called first time (check isInSettlementState flag) + - 14. Success 2: called with another higher sequence update before updateVCtimeout expires (check sequence number of onchain vc state) + +closeVirtualChannel: + - 1. Error: Channel with that ID doesn't exist + - 2. Error: Channel with that ID is not open + - 3. Error: VC with that ID is already closed + - 4. Error: VC is not in settlement state + - 5. Error: updateVCtimeout has not expired + - 6. Success (check that correct amounts were transferred to all parties) + + Questions: + VC with that ID is already closed doesnt seem to be checked but should be? + you can't call closeVC without first calling settleVC (which means you HAVE to prep a sequence 1 state) + +byzantineCloseChannel: + - 1. Error: Channel with that ID doesnt exist + - 2. Error: Channel with that ID is not open + - 3. Error: Channel is not updateSettling (i.e. not in dispute) + - 4. Error: VCs are still open + - 5. Error: LC timeout has not yet expired + - 6. Error: onchain Eth balances are greater than deposit (how would this happen?) + - 7. Error: onchain token balances are greater than deposit (how would this happen?) + - 8. Success: channel byzantine closed! (check numchannels) \ No newline at end of file diff --git a/test/unit/ChannelManagerTest.js b/test/unit/ChannelManagerTest.js new file mode 100644 index 0000000..990cf9b --- /dev/null +++ b/test/unit/ChannelManagerTest.js @@ -0,0 +1,2281 @@ +'use strict' + +import MerkleTree from '../helpers/MerkleTree' +const Utils = require('../helpers/utils') +const Ledger = artifacts.require('./ChannelManager.sol') +const EC = artifacts.require('./ECTools.sol') +const Token = artifacts.require('./token/HumanStandardToken.sol') + +const Web3latest = require('web3') +const web3latest = new Web3latest(new Web3latest.providers.HttpProvider("http://localhost:8545")) //ganache port +const BigNumber = web3.BigNumber + +const should = require('chai').use(require('chai-as-promised')).use(require('chai-bignumber')(BigNumber)).should() +const SolRevert = 'VM Exception while processing transaction: revert' + +let channelManager +let ec +let token +let bond + +// state +let partyA +let partyB +let partyI +let partyN + +let threadRootHash +let initialThreadState + +let payload +let sigA +let sigI +let sigB +let fakeSig + +//is close flag, channel state sequence, number open thread, thread root hash, partyA/B, partyI, balA/B, balI + +contract('ChannelManager :: createChannel()', function(accounts) { + + before(async () => { + partyA = accounts[0] + partyB = accounts[1] + partyI = accounts[2] + partyN = accounts[3] + + ec = await EC.new() + token = await Token.new(web3latest.utils.toWei('1000'), 'Test', 1, 'TST') + Ledger.link('HumanStandardToken', token.address) + Ledger.link('ECTools', ec.address) + channelManager = await Ledger.new() + + await token.transfer(partyB, web3latest.utils.toWei('100')) + await token.transfer(partyI, web3latest.utils.toWei('100')) + + let channel_id_fail = web3latest.utils.sha3('fail', {encoding: 'hex'}) + await channelManager.createChannel(channel_id_fail, partyI, '1000000000000000000', token.address, [0, 0], {from:partyA, value: 0}) + }) + + describe('Creating a channel has 6 possible cases:', () => { + it("1. Fail: Channel with that ID has already been created", async () => { + let channel_id = web3latest.utils.sha3('fail', {encoding: 'hex'}) + let sentBalance = [web3latest.utils.toWei('10'), web3latest.utils.toWei('10')] + let approval = await token.approve(channelManager.address, sentBalance[1]) + let channel = await channelManager.getChannel(channel_id) + expect(channel[0][0]).to.not.be.equal('0x0000000000000000000000000000000000000000') //fail + expect(partyI).to.not.be.equal('0x0000000000000000000000000000000000000000') //pass + expect(sentBalance[0]).to.be.above(0) //pass + expect(sentBalance[1]).to.be.above(0) //pass + expect(sentBalance[0]).to.be.equal(web3latest.utils.toWei('10')) //pass + expect(sentBalance[1]).to.be.equal(web3latest.utils.toWei('10')) //pass + + await channelManager.createChannel(channel_id, partyI, '0', token.address, sentBalance, {from:partyA, value: sentBalance[0]}).should.be.rejectedWith(SolRevert) + }) + it("2. Fail: No Hub address was provided.", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let sentBalance = [web3latest.utils.toWei('10'), web3latest.utils.toWei('10')] + let approval = await token.approve(channelManager.address, sentBalance[1]) + let channel = await channelManager.getChannel(channel_id) + let partyI_fail = ('0x0000000000000000000000000000000000000000') + expect(channel[0][0]).to.be.equal('0x0000000000000000000000000000000000000000') //pass + expect(partyI_fail).to.be.equal('0x0000000000000000000000000000000000000000') //fail + expect(sentBalance[0]).to.be.above(0) //pass + expect(sentBalance[1]).to.be.above(0) //pass + expect(sentBalance[0]).to.be.equal(web3latest.utils.toWei('10')) //pass + expect(sentBalance[1]).to.be.equal(web3latest.utils.toWei('10')) //pass + + await channelManager.createChannel(channel_id, partyI_fail, '0', token.address, sentBalance, {from:partyA, value: sentBalance[0]}).should.be.rejectedWith(SolRevert) + }) + it("3. Fail: Token balance input is negative.", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let sentBalance = [web3latest.utils.toWei('10'), web3latest.utils.toWei('-10')] + let approval = await token.approve(channelManager.address, sentBalance[1]) + let channel = await channelManager.getChannel(channel_id) + expect(channel[0][0]).to.be.equal('0x0000000000000000000000000000000000000000') //pass + expect(partyI).to.not.be.equal('0x0000000000000000000000000000000000000000') //pass + expect(sentBalance[0]).to.be.above(0) //fail + expect(sentBalance[1]).to.not.be.above(0) //pass + expect(sentBalance[0]).to.be.equal(web3latest.utils.toWei('10')) //pass + expect(sentBalance[1]).to.be.equal(web3latest.utils.toWei('-10')) //pass + + await channelManager.createChannel(channel_id, partyI, '0', token.address, sentBalance, {from:partyA, value: sentBalance[0]}).should.be.rejectedWith(SolRevert) + }) + it("4. Fail: Eth balance doesn't match paid value.", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let sentBalance = [web3latest.utils.toWei('10'), web3latest.utils.toWei('10')] + let approval = await token.approve(channelManager.address, sentBalance[1]) + let channel = await channelManager.getChannel(channel_id) + expect(channel[0][0]).to.be.equal('0x0000000000000000000000000000000000000000') //pass + expect(partyI).to.not.be.equal('0x0000000000000000000000000000000000000000') //pass + expect(sentBalance[0]).to.be.above(0) //pass + expect(sentBalance[1]).to.be.above(0) //pass + expect(sentBalance[0]).to.not.be.equal(web3latest.utils.toWei('1')) //fail + expect(sentBalance[1]).to.be.equal(web3latest.utils.toWei('10')) //pass + + await channelManager.createChannel(channel_id, partyI, '0', token.address, sentBalance, {from:partyA, value: web3latest.utils.toWei('1')}).should.be.rejectedWith(SolRevert) + }) + it("5. Fail: Token transferFrom failed.", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let sentBalance = [web3latest.utils.toWei('10'), web3latest.utils.toWei('10')] + let approval = await token.approve(channelManager.address, web3latest.utils.toWei('1')) + let channel = await channelManager.getChannel(channel_id) + expect(channel[0][0]).to.be.equal('0x0000000000000000000000000000000000000000') //pass + expect(partyI).to.not.be.equal('0x0000000000000000000000000000000000000000') //pass + expect(sentBalance[0]).to.be.above(0) //pass + expect(sentBalance[1]).to.be.above(0) //pass + expect(sentBalance[0]).to.be.equal(web3latest.utils.toWei('10')) //pass + expect(sentBalance[1]).to.not.be.equal(web3latest.utils.toWei('1')) //fail + + await channelManager.createChannel(channel_id, partyI, '0', token.address, sentBalance, {from:partyA, value: sentBalance[0]}).should.be.rejectedWith(SolRevert) + }) + it("6. Success: Channel created!", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let sentBalance = [web3latest.utils.toWei('10'), web3latest.utils.toWei('10')] + let approval = await token.approve(channelManager.address, web3latest.utils.toWei('10')) + let channel = await channelManager.getChannel(channel_id) + expect(channel[0][0]).to.be.equal('0x0000000000000000000000000000000000000000') //pass + expect(partyI).to.not.be.equal('0x0000000000000000000000000000000000000000') //pass + expect(sentBalance[0]).to.be.above(0) //pass + expect(sentBalance[1]).to.be.above(0) //pass + expect(sentBalance[0]).to.be.equal(web3latest.utils.toWei('10')) //pass + expect(sentBalance[1]).to.be.equal(web3latest.utils.toWei('10')) //pass + + await channelManager.createChannel(channel_id, partyI, '0', token.address, sentBalance, {from:partyA, value: sentBalance[0]}) + }) + }) +}) + +contract('ChannelManager :: channelOpenTimeout()', function(accounts) { + + before(async () => { + partyA = accounts[0] + partyB = accounts[1] + partyI = accounts[2] + partyN = accounts[3] + + ec = await EC.new() + token = await Token.new(web3latest.utils.toWei('1000'), 'Test', 1, 'TST') + Ledger.link('HumanStandardToken', token.address) + Ledger.link('ECTools', ec.address) + channelManager = await Ledger.new() + + await token.transfer(partyB, web3latest.utils.toWei('100')) + await token.transfer(partyI, web3latest.utils.toWei('100')) + + let sentBalance = [web3latest.utils.toWei('10'), web3latest.utils.toWei('10')] + let approval = await token.approve(channelManager.address, sentBalance[1]) + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + await channelManager.createChannel(channel_id, partyI, '0', token.address, sentBalance, {from:partyA, value: sentBalance[0]}) + + let channel_id_fail = web3latest.utils.sha3('fail', {encoding: 'hex'}) + await channelManager.createChannel(channel_id_fail, partyI, '1000000000000000000', token.address, [0, 0], {from:partyA, value: 0}) + }) + + + describe('channelopenTimeout() has 5 possible cases:', () => { + it("1. Fail: Sender is not PartyA of channel", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let channel = await channelManager.getChannel(channel_id) + expect(channel[0][0]).to.not.be.equal(partyB) //fail + expect(channel[0][0]).to.not.be.equal(null) //pass + expect(channel[9]).to.be.equal(false) //pass + expect(channel[7]*1000).to.be.below(Date.now()) //pass + + await channelManager.channelOpenTimeout(channel_id, {from:partyB}).should.be.rejectedWith(SolRevert) + }) + it("2. Fail: Channel does not exist", async () => { + let channel_id = web3latest.utils.sha3('0000', {encoding: 'hex'}) + let channel = await channelManager.getChannel(channel_id) + expect(channel[0][0]).to.not.be.equal(partyB) //pass + expect(channel[0][0]).to.be.equal(null || '0x0000000000000000000000000000000000000000') //fail + expect(channel[9]).to.be.equal(false) //pass + expect(channel[7]*1000).to.be.below(Date.now()) //pass + + await channelManager.channelOpenTimeout(channel_id, {from:partyA}).should.be.rejectedWith(SolRevert) + }) + it("3. Fail: Channel is already open", async () => { + let channel_id = web3latest.utils.sha3('0000', {encoding: 'hex'}) + await channelManager.createChannel(channel_id, partyI, '0', token.address, ['0', '0'], {from:partyA}) + await channelManager.joinChannel(channel_id, ['0', '0'], {from: partyI}) + let channel = await channelManager.getChannel(channel_id) + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[0][0]).to.not.be.equal(null) //pass + expect(channel[9]).to.be.equal(true) //fail + expect(channel[7]*1000).to.be.below(Date.now()) //pass + + await channelManager.channelOpenTimeout(channel_id, {from:partyA}).should.be.rejectedWith(SolRevert) + }) + it("4. Fail: channelopenTimeout has not expired", async () => { + let channel_id = web3latest.utils.sha3('fail', {encoding: 'hex'}) + let channel = await channelManager.getChannel(channel_id) + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[0][0]).to.not.be.equal(null) //pass + expect(channel[9]).to.be.equal(false) //pass + expect(channel[7]*1000).to.be.above(Date.now()) //fail + + await channelManager.channelOpenTimeout(channel_id, {from:partyA}).should.be.rejectedWith(SolRevert) + }) + //****** + //NOTE: there's one more require in the contract for a failed token transfer. Unfortunately we can't recreate that here. + //****** + it("5. Success!", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let channel = await channelManager.getChannel(channel_id) + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[0][0]).to.not.be.equal(null) //pass + expect(channel[9]).to.be.equal(false) //pass + expect(channel[7]*1000).to.be.below(Date.now()) //pass + + let oldBalanceEth = await web3latest.eth.getBalance(partyA) + let oldBalanceToken = await token.balanceOf(partyA) + + await channelManager.channelOpenTimeout(channel_id, {from:partyA}) + + let newBalanceEth = await web3latest.eth.getBalance(partyA) + let newBalanceToken = await token.balanceOf(partyA) + newBalanceToken = newBalanceToken - oldBalanceToken + let balanceToken = await (newBalanceToken).toString() + //TODO gas estimate for this test + // expect(newBalanceEth - oldBalanceEth).to.be.equal(web3latest.utils.toWei('10')) + expect(balanceToken).to.be.equal(web3latest.utils.toWei('10')) + }) + }) +}) + +contract('ChannelManager :: joinChannel()', function(accounts) { + + before(async () => { + partyA = accounts[0] + partyB = accounts[1] + partyI = accounts[2] + partyN = accounts[3] + + ec = await EC.new() + token = await Token.new(web3latest.utils.toWei('1000'), 'Test', 1, 'TST') + Ledger.link('HumanStandardToken', token.address) + Ledger.link('ECTools', ec.address) + channelManager = await Ledger.new() + + await token.transfer(partyB, web3latest.utils.toWei('100')) + await token.transfer(partyI, web3latest.utils.toWei('100')) + + let sentBalance = [web3latest.utils.toWei('10'), web3latest.utils.toWei('10')] + let approval = await token.approve(channelManager.address, sentBalance[1]) + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + await channelManager.createChannel(channel_id, partyI, '0', token.address, sentBalance, {from:partyA, value: sentBalance[0]}) + + let channel_id_fail = web3latest.utils.sha3('fail', {encoding: 'hex'}) + await channelManager.createChannel(channel_id_fail, partyI, '0', token.address, [0, 0], {from:partyA, value: 0}) + await channelManager.joinChannel(channel_id_fail, [0,0], {from: partyI, value: 0}) + }) + + + describe('joinChannel() has 6 possible cases:', () => { + it("1. Fail: Channel with that ID has already been opened", async () => { + let channel_id = web3latest.utils.sha3('fail', {encoding: 'hex'}) + let sentBalance = [web3latest.utils.toWei('10'), web3latest.utils.toWei('10')] + let approval = await token.approve(channelManager.address, sentBalance[1], {from: partyI}) + let channel = await channelManager.getChannel(channel_id) + expect(channel[9]).to.be.equal(true) //fail + expect(channel[0][1]).to.be.equal(partyI) //pass + expect(sentBalance[1]).to.be.at.least(0) //pass + expect(sentBalance[0]).to.be.equal(web3latest.utils.toWei('10')) //pass + expect(sentBalance[1]).to.be.equal(web3latest.utils.toWei('10')) //pass + + await channelManager.joinChannel(channel_id, sentBalance, {from: partyI, value: sentBalance[0]}).should.be.rejectedWith(SolRevert) + }) + it("2. Fail: Msg.sender is not PartyI of this channel", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let sentBalance = [web3latest.utils.toWei('10'), web3latest.utils.toWei('10')] + let approval = await token.approve(channelManager.address, sentBalance[1], {from: partyI}) + let channel = await channelManager.getChannel(channel_id) + expect(channel[9]).to.be.equal(false) //pass + expect(channel[0][1]).to.not.be.equal(partyB) //fail + expect(sentBalance[1]).to.be.at.least(0) //pass + expect(sentBalance[0]).to.be.equal(web3latest.utils.toWei('10')) //pass + expect(sentBalance[1]).to.be.equal(web3latest.utils.toWei('10')) //pass + + await channelManager.joinChannel(channel_id, sentBalance, {from: partyB, value: sentBalance[0]}).should.be.rejectedWith(SolRevert) + }) + it("3. Fail: Token balance is negative", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let sentBalance = [web3latest.utils.toWei('10'), web3latest.utils.toWei('-10')] + let approval = await token.approve(channelManager.address, sentBalance[1], {from: partyI}) + let channel = await channelManager.getChannel(channel_id) + expect(channel[9]).to.be.equal(false) //pass + expect(channel[0][1]).to.be.equal(partyI) //pass + expect(sentBalance[1]).to.be.below(0) //fail + expect(sentBalance[0]).to.be.equal(web3latest.utils.toWei('10')) //pass + expect(sentBalance[1]).to.be.equal(web3latest.utils.toWei('-10')) //pass + + await channelManager.joinChannel(channel_id, sentBalance, {from: partyI, value: sentBalance[0]}).should.be.rejectedWith(SolRevert) + }) + it("4. Fail: Eth balance does not match paid value", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let sentBalance = [web3latest.utils.toWei('1'), web3latest.utils.toWei('10')] + let approval = await token.approve(channelManager.address, sentBalance[1], {from: partyI}) + let channel = await channelManager.getChannel(channel_id) + expect(channel[9]).to.be.equal(false) //pass + expect(channel[0][1]).to.be.equal(partyI) //pass + expect(sentBalance[1]).to.be.at.least(0) //pass + expect(sentBalance[0]).to.not.be.equal(web3latest.utils.toWei('10')) //fail + expect(sentBalance[1]).to.be.equal(web3latest.utils.toWei('10')) //pass + + await channelManager.joinChannel(channel_id, sentBalance, {from: partyI, value: web3latest.utils.toWei('10')}).should.be.rejectedWith(SolRevert) + }) + it("5. Fail: Token transferFrom failed", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let sentBalance = [web3latest.utils.toWei('10'), web3latest.utils.toWei('1')] + let approval = await token.approve(channelManager.address, sentBalance[1], {from: partyI}) + let channel = await channelManager.getChannel(channel_id) + expect(channel[9]).to.be.equal(false) //pass + expect(channel[0][1]).to.be.equal(partyI) //pass + expect(sentBalance[1]).to.be.at.least(0) //pass + expect(sentBalance[0]).to.be.equal(web3latest.utils.toWei('10')) //pass + expect(sentBalance[1]).to.not.be.equal(web3latest.utils.toWei('10')) //fail + + await channelManager.joinChannel(channel_id, [sentBalance[0], web3latest.utils.toWei('10')], {from: partyI, value: sentBalance[0]}).should.be.rejectedWith(SolRevert) + }) + it("6. Success: channel Joined!", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let sentBalance = [web3latest.utils.toWei('10'), web3latest.utils.toWei('10')] + let approval = await token.approve(channelManager.address, sentBalance[1], {from: partyI}) + let channel = await channelManager.getChannel(channel_id) + expect(channel[9]).to.be.equal(false) //pass + expect(channel[0][1]).to.be.equal(partyI) //pass + expect(sentBalance[1]).to.be.at.least(0) //pass + expect(sentBalance[0]).to.be.equal(web3latest.utils.toWei('10')) //pass + expect(sentBalance[1]).to.be.equal(web3latest.utils.toWei('10')) //pass + + await channelManager.joinChannel(channel_id, sentBalance, {from: partyI, value: sentBalance[0]}) + + }) + }) +}) + +// // //TODO deposit unit tests + +contract('ChannelManager :: consensusCloseChannel()', function(accounts) { + + before(async () => { + partyA = accounts[0] + partyB = accounts[1] + partyI = accounts[2] + partyN = accounts[3] + + ec = await EC.new() + token = await Token.new(web3latest.utils.toWei('1000'), 'Test', 1, 'TST') + Ledger.link('HumanStandardToken', token.address) + Ledger.link('ECTools', ec.address) + channelManager = await Ledger.new() + + await token.transfer(partyB, web3latest.utils.toWei('100')) + await token.transfer(partyI, web3latest.utils.toWei('100')) + + let sentBalance = [web3latest.utils.toWei('10'), web3latest.utils.toWei('10')] + await token.approve(channelManager.address, sentBalance[1]) + await token.approve(channelManager.address, sentBalance[1], {from: partyI}) + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + await channelManager.createChannel(channel_id, partyI, '0', token.address, sentBalance, {from:partyA, value: sentBalance[0]}) + await channelManager.joinChannel(channel_id, sentBalance, {from: partyI, value: sentBalance[0]}) + + payload = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id }, + { type: 'bool', value: true }, // isclose + { type: 'uint256', value: '1' }, // sequence + { type: 'uint256', value: '0' }, // open threads + { type: 'bytes32', value: '0x0' }, // thread root hash + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyI }, // hub + { type: 'uint256', value: web3latest.utils.toWei('5') }, + { type: 'uint256', value: web3latest.utils.toWei('15') }, + { type: 'uint256', value: web3latest.utils.toWei('5') }, // token + { type: 'uint256', value: web3latest.utils.toWei('15') } // token + ) + + fakeSig = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id }, // ID + { type: 'bool', value: true }, // isclose + { type: 'uint256', value: '1' }, // sequence + { type: 'uint256', value: '0' }, // open threads + { type: 'string', value: '0x0' }, // thread root hash + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyI }, // hub + { type: 'uint256', value: web3latest.utils.toWei('15') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('15') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('15') }, // token + { type: 'uint256', value: web3latest.utils.toWei('15') } // token + ) + + sigA = await web3latest.eth.sign(payload, partyA) + sigI = await web3latest.eth.sign(payload, partyI) + fakeSig = await web3latest.eth.sign(fakeSig, partyA) + + let channel_id_fail = web3latest.utils.sha3('fail', {encoding: 'hex'}) + await token.approve(channelManager.address, sentBalance[1]) + await channelManager.createChannel(channel_id_fail, partyI, '0', token.address, sentBalance, {from:partyA, value: sentBalance[0]}) + }) + + + describe('consensusCloseChannel() has 7 possible cases:', () => { + it("1. Fail: Channel with that ID does not exist", async () => { + let channel_id = web3latest.utils.sha3('2222', {encoding: 'hex'}) + let balances = [web3latest.utils.toWei('5'), web3latest.utils.toWei('15'), web3latest.utils.toWei('5'), web3latest.utils.toWei('15')] + let channel = await channelManager.getChannel(channel_id) + let totalEthDeposit = channel[3][0].add(channel[1][2]).add(channel[1][3]).toString(); + let totalTokenDeposit = channel[3][1].add(channel[2][2]).add(channel[2][3]).toString(); + let verificationA = await web3latest.eth.sign(payload, partyA) + let verificationI = await web3latest.eth.sign(payload, partyI) + + expect(channel[0][0]).to.be.equal('0x0000000000000000000000000000000000000000') //fail + expect(channel[9]).to.not.be.equal(true) //pass + expect(totalEthDeposit).to.not.be.equal(web3latest.utils.toWei('20')) //pass + expect(totalTokenDeposit).to.not.be.equal(web3latest.utils.toWei('20')) //pass + expect(sigA).to.be.equal(verificationA) //pass + expect(sigI).to.be.equal(verificationI) //pass + + await channelManager.consensusCloseChannel(channel_id, '1', balances, sigA, sigI).should.be.rejectedWith(SolRevert) + }) + it("2. Fail: Channel with that ID is not open", async () => { + let channel_id = web3latest.utils.sha3('fail', {encoding: 'hex'}) + let balances = [web3latest.utils.toWei('5'), web3latest.utils.toWei('15'), web3latest.utils.toWei('5'), web3latest.utils.toWei('15')] + let channel = await channelManager.getChannel(channel_id) + let totalEthDeposit = channel[3][0].add(channel[1][2]).add(channel[1][3]).toString(); + let totalTokenDeposit = channel[3][1].add(channel[2][2]).add(channel[2][3]).toString(); + let verificationA = await web3latest.eth.sign(payload, partyA) + let verificationI = await web3latest.eth.sign(payload, partyI) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(false) //fail + expect(totalEthDeposit).to.be.equal(web3latest.utils.toWei('10')) //pass + expect(totalTokenDeposit).to.be.equal(web3latest.utils.toWei('10')) //pass + expect(sigA).to.be.equal(verificationA) //pass + expect(sigI).to.be.equal(verificationI) //pass + + await channelManager.consensusCloseChannel(channel_id, '1', balances, sigA, sigI).should.be.rejectedWith(SolRevert) + }) + it("3. Fail: Total Eth deposit is not equal to submitted Eth balances", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let balances = [web3latest.utils.toWei('5'), web3latest.utils.toWei('5'), web3latest.utils.toWei('5'), web3latest.utils.toWei('15')] + let channel = await channelManager.getChannel(channel_id) + let totalEthDeposit = channel[3][0].add(channel[1][2]).add(channel[1][3]).toString(); + let totalTokenDeposit = channel[3][1].add(channel[2][2]).add(channel[2][3]).toString(); + let verificationA = await web3latest.eth.sign(payload, partyA) + let verificationI = await web3latest.eth.sign(payload, partyI) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(totalEthDeposit).to.not.be.equal(web3latest.utils.toWei('10')) //fail + expect(totalTokenDeposit).to.be.equal(web3latest.utils.toWei('20')) //pass + expect(sigA).to.be.equal(verificationA) //pass + expect(sigI).to.be.equal(verificationI) //pass + + await channelManager.consensusCloseChannel(channel_id, '1', balances, sigA, sigI).should.be.rejectedWith(SolRevert) + }) + it("4. Fail: Total token deposit is not equal to submitted token balances", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let balances = [web3latest.utils.toWei('5'), web3latest.utils.toWei('15'), web3latest.utils.toWei('5'), web3latest.utils.toWei('5')] + let channel = await channelManager.getChannel(channel_id) + let totalEthDeposit = channel[3][0].add(channel[1][2]).add(channel[1][3]).toString(); + let totalTokenDeposit = channel[3][1].add(channel[2][2]).add(channel[2][3]).toString(); + let verificationA = await web3latest.eth.sign(payload, partyA) + let verificationI = await web3latest.eth.sign(payload, partyI) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(totalEthDeposit).to.be.equal(web3latest.utils.toWei('20')) //pass + expect(totalTokenDeposit).to.not.be.equal(web3latest.utils.toWei('10')) //fail + expect(sigA).to.be.equal(verificationA) //pass + expect(sigI).to.be.equal(verificationI) //pass + + await channelManager.consensusCloseChannel(channel_id, '1', balances, sigA, sigI).should.be.rejectedWith(SolRevert) + }) + it("5. Fail: Incorrect sig for partyA", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let balances = [web3latest.utils.toWei('5'), web3latest.utils.toWei('15'), web3latest.utils.toWei('5'), web3latest.utils.toWei('15')] + let channel = await channelManager.getChannel(channel_id) + let totalEthDeposit = channel[3][0].add(channel[1][2]).add(channel[1][3]).toString(); + let totalTokenDeposit = channel[3][1].add(channel[2][2]).add(channel[2][3]).toString(); + let verificationA = await web3latest.eth.sign(payload, partyA) + let verificationI = await web3latest.eth.sign(payload, partyI) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(totalEthDeposit).to.be.equal(web3latest.utils.toWei('20')) //pass + expect(totalTokenDeposit).to.be.equal(web3latest.utils.toWei('20')) //pass + expect(fakeSig).to.not.be.equal(verificationA) //fail + expect(sigI).to.be.equal(verificationI) //pass + + await channelManager.consensusCloseChannel(channel_id, '1', balances, fakeSig, sigI).should.be.rejectedWith(SolRevert) + }) + it("6. Fail: Incorrect sig for partyI", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let balances = [web3latest.utils.toWei('5'), web3latest.utils.toWei('15'), web3latest.utils.toWei('5'), web3latest.utils.toWei('15')] + let channel = await channelManager.getChannel(channel_id) + let totalEthDeposit = channel[3][0].add(channel[1][2]).add(channel[1][3]).toString(); + let totalTokenDeposit = channel[3][1].add(channel[2][2]).add(channel[2][3]).toString(); + let verificationA = await web3latest.eth.sign(payload, partyA) + let verificationI = await web3latest.eth.sign(payload, partyI) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(totalEthDeposit).to.be.equal(web3latest.utils.toWei('20')) //pass + expect(totalTokenDeposit).to.be.equal(web3latest.utils.toWei('20')) //pass + expect(sigA).to.be.equal(verificationA) //pass + expect(fakeSig).to.not.be.equal(verificationI) //fail + + await channelManager.consensusCloseChannel(channel_id, '1', balances, sigA, fakeSig).should.be.rejectedWith(SolRevert) + }) + it("7. Success: Channel Closed", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let balances = [web3latest.utils.toWei('5'), web3latest.utils.toWei('15'), web3latest.utils.toWei('5'), web3latest.utils.toWei('15')] + let channel = await channelManager.getChannel(channel_id) + let openChansInit = await channelManager.numChannels(); + let totalEthDeposit = channel[3][0].add(channel[1][2]).add(channel[1][3]).toString(); + let totalTokenDeposit = channel[3][1].add(channel[2][2]).add(channel[2][3]).toString(); + let verificationA = await web3latest.eth.sign(payload, partyA) + let verificationI = await web3latest.eth.sign(payload, partyI) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(totalEthDeposit).to.be.equal(web3latest.utils.toWei('20')) //pass + expect(totalTokenDeposit).to.be.equal(web3latest.utils.toWei('20')) //pass + expect(sigA).to.be.equal(verificationA) //pass + expect(sigI).to.be.equal(verificationI) //pass + + await channelManager.consensusCloseChannel(channel_id, '1', balances, sigA, sigI) + let openChansFinal = await channelManager.numChannels(); + expect(openChansInit - openChansFinal).to.be.equal(1); + }) + }) +}) + +contract('ChannelManager :: updateChannelState()', function(accounts) { + + before(async () => { + partyA = accounts[0] + partyB = accounts[1] + partyI = accounts[2] + partyN = accounts[3] + + ec = await EC.new() + token = await Token.new(web3latest.utils.toWei('1000'), 'Test', 1, 'TST') + Ledger.link('HumanStandardToken', token.address) + Ledger.link('ECTools', ec.address) + channelManager = await Ledger.new() + + await token.transfer(partyB, web3latest.utils.toWei('100')) + await token.transfer(partyI, web3latest.utils.toWei('100')) + + let sentBalance = [web3latest.utils.toWei('10'), web3latest.utils.toWei('10')] + await token.approve(channelManager.address, sentBalance[1]) + await token.approve(channelManager.address, sentBalance[1], {from: partyI}) + + let channel_id_1 = web3latest.utils.sha3('1111', {encoding: 'hex'}) + await channelManager.createChannel(channel_id_1, partyI, '0', token.address, sentBalance, {from:partyA, value: sentBalance[0]}) + await channelManager.joinChannel(channel_id_1, sentBalance, {from: partyI, value: sentBalance[0]}) + + await token.approve(channelManager.address, sentBalance[1]) + await token.approve(channelManager.address, sentBalance[1], {from: partyI}) + let channel_id_2 = web3latest.utils.sha3('2222', {encoding: 'hex'}) + await channelManager.createChannel(channel_id_2, partyI, '100000', token.address, sentBalance, {from:partyA, value: sentBalance[0]}) + await channelManager.joinChannel(channel_id_2, sentBalance, {from: partyI, value: sentBalance[0]}) + + threadRootHash = web3latest.utils.soliditySha3({type: 'bytes32', value: '0x1'}) + payload = web3latest.utils.soliditySha3( + { type: 'bytes32', value: channel_id_1 }, + { type: 'bool', value: false }, // isclose + { type: 'uint256', value: '2' }, // sequence + { type: 'uint256', value: '1' }, // open threads + { type: 'bytes32', value: threadRootHash }, // thread root hash + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyI }, // hub + { type: 'uint256', value: web3latest.utils.toWei('5') }, + { type: 'uint256', value: web3latest.utils.toWei('15') }, + { type: 'uint256', value: web3latest.utils.toWei('5') }, // token + { type: 'uint256', value: web3latest.utils.toWei('15') } // token + ) + + fakeSig = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id_1 }, // ID + { type: 'bool', value: false }, // isclose + { type: 'uint256', value: '2' }, // sequence + { type: 'uint256', value: '1' }, // open threads + { type: 'bytes32', value: '0x1' }, // thread root hash + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyI }, // hub + { type: 'uint256', value: web3latest.utils.toWei('15') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('15') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('15') }, // token + { type: 'uint256', value: web3latest.utils.toWei('15') } // token + ) + + sigA = await web3latest.eth.sign(payload, partyA) + sigI = await web3latest.eth.sign(payload, partyI) + fakeSig = await web3latest.eth.sign(fakeSig, partyA) + + let channel_id_fail = web3latest.utils.sha3('fail', {encoding: 'hex'}) + await token.approve(channelManager.address, sentBalance[1]) + await channelManager.createChannel(channel_id_fail, partyI, '0', token.address, sentBalance, {from:partyA, value: sentBalance[0]}) + }) + + + describe('updateChannelState() has 10 possible cases:', () => { + it("1. Fail: Channel with that ID does not exist", async () => { + let channel_id = web3latest.utils.sha3('nochannel', {encoding: 'hex'}) + let sequence = '2'; + let threadRootHash = web3latest.utils.soliditySha3({type: 'bytes32', value: '0x1'}) + let updateParams = [sequence, '1', web3latest.utils.toWei('5'), web3latest.utils.toWei('15'), web3latest.utils.toWei('5'), web3latest.utils.toWei('15')] + let channel = await channelManager.getChannel(channel_id) + let totalEthDeposit = channel[3][0].add(channel[1][2]).add(channel[1][3]).toString(); + let totalTokenDeposit = channel[3][1].add(channel[2][2]).add(channel[2][3]).toString(); + let verificationA = await web3latest.eth.sign(payload, partyA) + let verificationI = await web3latest.eth.sign(payload, partyI) + + expect(channel[0][0]).to.be.equal('0x0000000000000000000000000000000000000000') //fail + expect(channel[9]).to.not.be.equal(true) //pass + expect(totalEthDeposit).to.not.be.equal(web3latest.utils.toWei('20')) //pass + expect(totalTokenDeposit).to.not.be.equal(web3latest.utils.toWei('20')) //pass + expect(sigA).to.be.equal(verificationA) //pass + expect(sigI).to.be.equal(verificationI) //pass + expect(channel[4]).to.be.below(sequence) //pass + if(channel[10] == true) expect(channel[8]*1000).to.be.above(Date.now()) //pass + + await channelManager.updateChannelState(channel_id, updateParams, threadRootHash, sigA, sigI).should.be.rejectedWith(SolRevert) + }) + it("2. Fail: Channel with that ID is not open", async () => { + let channel_id = web3latest.utils.sha3('fail', {encoding: 'hex'}) + let sequence = '2'; + let threadRootHash = web3latest.utils.soliditySha3({type: 'bytes32', value: '0x1'}) + let updateParams = [sequence, '1', web3latest.utils.toWei('5'), web3latest.utils.toWei('15'), web3latest.utils.toWei('5'), web3latest.utils.toWei('15')] + let channel = await channelManager.getChannel(channel_id) + let totalEthDeposit = channel[3][0].add(channel[1][2]).add(channel[1][3]).toString(); + let totalTokenDeposit = channel[3][1].add(channel[2][2]).add(channel[2][3]).toString(); + let verificationA = await web3latest.eth.sign(payload, partyA) + let verificationI = await web3latest.eth.sign(payload, partyI) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(false) //fail + expect(totalEthDeposit).to.be.equal(web3latest.utils.toWei('10')) //pass + expect(totalTokenDeposit).to.be.equal(web3latest.utils.toWei('10')) //pass + expect(sigA).to.be.equal(verificationA) //pass + expect(sigI).to.be.equal(verificationI) //pass + expect(channel[4]).to.be.below(sequence) //pass + if(channel[10] == true) expect(channel[8]*1000).to.be.above(Date.now()) //pass + + await channelManager.updateChannelState(channel_id, updateParams, threadRootHash, sigA, sigI).should.be.rejectedWith(SolRevert) + }) + it("3. Fail: Total Eth deposit is not equal to submitted Eth balances", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let sequence = '2'; + let threadRootHash = web3latest.utils.soliditySha3({type: 'bytes32', value: '0x1'}) + let updateParams = [sequence, '1', web3latest.utils.toWei('5'), web3latest.utils.toWei('5'), web3latest.utils.toWei('5'), web3latest.utils.toWei('15')] + let channel = await channelManager.getChannel(channel_id) + let totalEthDeposit = channel[3][0].add(channel[1][2]).add(channel[1][3]).toString(); + let totalTokenDeposit = channel[3][1].add(channel[2][2]).add(channel[2][3]).toString(); + let verificationA = await web3latest.eth.sign(payload, partyA) + let verificationI = await web3latest.eth.sign(payload, partyI) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(totalEthDeposit).to.not.be.equal(web3latest.utils.toWei('10')) //fail + expect(totalTokenDeposit).to.be.equal(web3latest.utils.toWei('20')) //pass + expect(sigA).to.be.equal(verificationA) //pass + expect(sigI).to.be.equal(verificationI) //pass + expect(channel[4]).to.be.below(sequence) //pass + if(channel[10] == true) expect(channel[8]*1000).to.be.above(Date.now()) //pass + + await channelManager.updateChannelState(channel_id, updateParams, threadRootHash, sigA, sigI).should.be.rejectedWith(SolRevert) + }) + it("4. Fail: Total token deposit is not equal to submitted Eth balances", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let sequence = '2'; + let threadRootHash = web3latest.utils.soliditySha3({type: 'bytes32', value: '0x1'}) + let updateParams = [sequence, '1', web3latest.utils.toWei('5'), web3latest.utils.toWei('15'), web3latest.utils.toWei('5'), web3latest.utils.toWei('5')] + let channel = await channelManager.getChannel(channel_id) + let totalEthDeposit = channel[3][0].add(channel[1][2]).add(channel[1][3]).toString(); + let totalTokenDeposit = channel[3][1].add(channel[2][2]).add(channel[2][3]).toString(); + let verificationA = await web3latest.eth.sign(payload, partyA) + let verificationI = await web3latest.eth.sign(payload, partyI) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(totalEthDeposit).to.be.equal(web3latest.utils.toWei('20')) //pass + expect(totalTokenDeposit).to.not.be.equal(web3latest.utils.toWei('10')) //fail + expect(sigA).to.be.equal(verificationA) //pass + expect(sigI).to.be.equal(verificationI) //pass + expect(channel[4]).to.be.below(sequence) //pass + if(channel[10] == true) expect(channel[8]*1000).to.be.above(Date.now()) //pass + + await channelManager.updateChannelState(channel_id, updateParams, threadRootHash, sigA, sigI).should.be.rejectedWith(SolRevert) + }) + it("5. Fail: Incorrect sig for partyA", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let sequence = '2'; + let threadRootHash = web3latest.utils.soliditySha3({type: 'bytes32', value: '0x1'}) + let updateParams = [sequence, '1', web3latest.utils.toWei('5'), web3latest.utils.toWei('15'), web3latest.utils.toWei('5'), web3latest.utils.toWei('5')] + let channel = await channelManager.getChannel(channel_id) + let totalEthDeposit = channel[3][0].add(channel[1][2]).add(channel[1][3]).toString(); + let totalTokenDeposit = channel[3][1].add(channel[2][2]).add(channel[2][3]).toString(); + let verificationA = await web3latest.eth.sign(payload, partyA) + let verificationI = await web3latest.eth.sign(payload, partyI) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(totalEthDeposit).to.be.equal(web3latest.utils.toWei('20')) //pass + expect(totalTokenDeposit).to.be.equal(web3latest.utils.toWei('20')) //pass + expect(fakeSig).to.not.be.equal(verificationA) //fail + expect(sigI).to.be.equal(verificationI) //pass + expect(channel[4]).to.be.below(sequence) //pass + if(channel[10] == true) expect(channel[8]*1000).to.be.above(Date.now()) //pass + + await channelManager.updateChannelState(channel_id, updateParams, threadRootHash, fakeSig, sigI).should.be.rejectedWith(SolRevert) + }) + it("6. Fail: Incorrect sig for partyI", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let sequence = '2'; + let threadRootHash = web3latest.utils.soliditySha3({type: 'bytes32', value: '0x1'}) + let updateParams = [sequence, '1', web3latest.utils.toWei('5'), web3latest.utils.toWei('15'), web3latest.utils.toWei('5'), web3latest.utils.toWei('5')] + let channel = await channelManager.getChannel(channel_id) + let totalEthDeposit = channel[3][0].add(channel[1][2]).add(channel[1][3]).toString(); + let totalTokenDeposit = channel[3][1].add(channel[2][2]).add(channel[2][3]).toString(); + let verificationA = await web3latest.eth.sign(payload, partyA) + let verificationI = await web3latest.eth.sign(payload, partyI) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(totalEthDeposit).to.be.equal(web3latest.utils.toWei('20')) //pass + expect(totalTokenDeposit).to.be.equal(web3latest.utils.toWei('20')) //pass + expect(sigA).to.be.equal(verificationA) //pass + expect(fakeSig).to.not.be.equal(verificationI) //fail + expect(channel[4]).to.be.below(sequence) //pass + if(channel[10] == true) expect(channel[8]*1000).to.be.above(Date.now()) //pass + + await channelManager.updateChannelState(channel_id, updateParams, threadRootHash, sigA, fakeSig).should.be.rejectedWith(SolRevert) + }) + it("7. Success 1: updateChannelState called first time and timeout started", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let sequence = '2'; + // let threadRootHash = web3latest.utils.soliditySha3({type: 'bytes32', value: '0x1'}) + let updateParams = [sequence, '1', web3latest.utils.toWei('5'), web3latest.utils.toWei('15'), web3latest.utils.toWei('5'), web3latest.utils.toWei('15')] + let channel = await channelManager.getChannel(channel_id) + let totalEthDeposit = channel[3][0].add(channel[1][2]).add(channel[1][3]).toString(); + let totalTokenDeposit = channel[3][1].add(channel[2][2]).add(channel[2][3]).toString(); + let verificationA = await web3latest.eth.sign(payload, partyA) + let verificationI = await web3latest.eth.sign(payload, partyI) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(totalEthDeposit).to.be.equal(web3latest.utils.toWei('20')) //pass + expect(totalTokenDeposit).to.be.equal(web3latest.utils.toWei('20')) //pass + expect(sigA).to.be.equal(verificationA) //pass + expect(sigI).to.be.equal(verificationI) //pass + expect(channel[4]).to.be.below(sequence) //pass + if(channel[10] == true) expect(channel[8]*1000).to.be.above(Date.now()) //pass + + await channelManager.updateChannelState(channel_id, updateParams, threadRootHash, sigA, sigI) + + channel = await channelManager.getChannel(channel_id) + expect(channel[10]).to.be.equal(true) + }) + it("8. Error: State none below onchain latest sequence", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let sequence = '1'; + // let threadRootHash = web3latest.utils.soliditySha3({type: 'bytes32', value: '0x1'}) + let updateParams = [sequence, '1', web3latest.utils.toWei('5'), web3latest.utils.toWei('15'), web3latest.utils.toWei('5'), web3latest.utils.toWei('15')] + let channel = await channelManager.getChannel(channel_id) + let totalEthDeposit = channel[3][0].add(channel[1][2]).add(channel[1][3]).toString(); + let totalTokenDeposit = channel[3][1].add(channel[2][2]).add(channel[2][3]).toString(); + + payload = web3latest.utils.soliditySha3( + { type: 'bytes32', value: channel_id }, + { type: 'bool', value: false }, // isclose + { type: 'uint256', value: '1' }, // sequence + { type: 'uint256', value: '1' }, // open threads + { type: 'bytes32', value: threadRootHash }, // thread root hash + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyI }, // hub + { type: 'uint256', value: web3latest.utils.toWei('5') }, + { type: 'uint256', value: web3latest.utils.toWei('15') }, + { type: 'uint256', value: web3latest.utils.toWei('5') }, // token + { type: 'uint256', value: web3latest.utils.toWei('15') } // token + ) + + let verificationA = await web3latest.eth.sign(payload, partyA) + let verificationI = await web3latest.eth.sign(payload, partyI) + + sigA = await web3latest.eth.sign(payload, partyA) + sigI = await web3latest.eth.sign(payload, partyI) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(totalEthDeposit).to.be.equal(web3latest.utils.toWei('20')) //pass + expect(totalTokenDeposit).to.be.equal(web3latest.utils.toWei('20')) //pass + expect(sigA).to.be.equal(verificationA) //pass + expect(sigI).to.be.equal(verificationI) //pass + expect(channel[4]).to.not.be.below(sequence) //fail + if(channel[10] == true) expect(channel[8]*1000).to.not.be.above(Date.now()) //pass ==== Technically this is a fail right now, but sequence is checked earlier. Needs to be fixed later + + await channelManager.updateChannelState(channel_id, updateParams, threadRootHash, sigA, sigI).should.be.rejectedWith(SolRevert) + }) + it("9. Error: Updatechannel timed out", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let sequence = '3'; + // let threadRootHash = web3latest.utils.soliditySha3({type: 'bytes32', value: '0x1'}) + let updateParams = [sequence, '1', web3latest.utils.toWei('5'), web3latest.utils.toWei('15'), web3latest.utils.toWei('5'), web3latest.utils.toWei('15')] + let channel = await channelManager.getChannel(channel_id) + let totalEthDeposit = channel[3][0].add(channel[1][2]).add(channel[1][3]).toString(); + let totalTokenDeposit = channel[3][1].add(channel[2][2]).add(channel[2][3]).toString(); + + payload = web3latest.utils.soliditySha3( + { type: 'bytes32', value: channel_id }, + { type: 'bool', value: false }, // isclose + { type: 'uint256', value: '3' }, // sequence + { type: 'uint256', value: '1' }, // open threads + { type: 'bytes32', value: threadRootHash }, // thread root hash + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyI }, // hub + { type: 'uint256', value: web3latest.utils.toWei('5') }, + { type: 'uint256', value: web3latest.utils.toWei('15') }, + { type: 'uint256', value: web3latest.utils.toWei('5') }, // token + { type: 'uint256', value: web3latest.utils.toWei('15') } // token + ) + + let verificationA = await web3latest.eth.sign(payload, partyA) + let verificationI = await web3latest.eth.sign(payload, partyI) + + sigA = await web3latest.eth.sign(payload, partyA) + sigI = await web3latest.eth.sign(payload, partyI) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(totalEthDeposit).to.be.equal(web3latest.utils.toWei('20')) //pass + expect(totalTokenDeposit).to.be.equal(web3latest.utils.toWei('20')) //pass + expect(sigA).to.be.equal(verificationA) //pass + expect(sigI).to.be.equal(verificationI) //pass + expect(channel[4]).to.be.below(sequence) //pass + if(channel[10] == true) expect(channel[8]*1000).to.not.be.above(Date.now()) //fail + + await channelManager.updateChannelState(channel_id, updateParams, threadRootHash, sigA, sigI).should.be.rejectedWith(SolRevert) + }) + it("10. Success 2: new state submitted to updatechannel", async () => { + let channel_id = web3latest.utils.sha3('2222', {encoding: 'hex'}) + let sequence = '3'; + // let threadRootHash = web3latest.utils.soliditySha3({type: 'bytes32', value: '0x1'}) + let updateParams = [sequence, '1', web3latest.utils.toWei('5'), web3latest.utils.toWei('15'), web3latest.utils.toWei('5'), web3latest.utils.toWei('15')] + let channel = await channelManager.getChannel(channel_id) + let totalEthDeposit = channel[3][0].add(channel[1][2]).add(channel[1][3]).toString(); + let totalTokenDeposit = channel[3][1].add(channel[2][2]).add(channel[2][3]).toString(); + + payload = web3latest.utils.soliditySha3( + { type: 'bytes32', value: channel_id }, + { type: 'bool', value: false }, // isclose + { type: 'uint256', value: '3' }, // sequence + { type: 'uint256', value: '1' }, // open threads + { type: 'bytes32', value: threadRootHash }, // thread root hash + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyI }, // hub + { type: 'uint256', value: web3latest.utils.toWei('5') }, + { type: 'uint256', value: web3latest.utils.toWei('15') }, + { type: 'uint256', value: web3latest.utils.toWei('5') }, // token + { type: 'uint256', value: web3latest.utils.toWei('15') } // token + ) + + let verificationA = await web3latest.eth.sign(payload, partyA) + let verificationI = await web3latest.eth.sign(payload, partyI) + + sigA = await web3latest.eth.sign(payload, partyA) + sigI = await web3latest.eth.sign(payload, partyI) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(totalEthDeposit).to.be.equal(web3latest.utils.toWei('20')) //pass + expect(totalTokenDeposit).to.be.equal(web3latest.utils.toWei('20')) //pass + expect(sigA).to.be.equal(verificationA) //pass + expect(sigI).to.be.equal(verificationI) //pass + expect(channel[4]).to.be.below(sequence) //pass + if(channel[10] == true) expect(channel[8]*1000).to.not.be.above(Date.now()) //pass + + await channelManager.updateChannelState(channel_id, updateParams, threadRootHash, sigA, sigI) + + sequence = '4'; + updateParams = [sequence, '1', web3latest.utils.toWei('10'), web3latest.utils.toWei('10'), web3latest.utils.toWei('5'), web3latest.utils.toWei('15')] + + payload = web3latest.utils.soliditySha3( + { type: 'bytes32', value: channel_id }, + { type: 'bool', value: false }, // isclose + { type: 'uint256', value: '4' }, // sequence + { type: 'uint256', value: '1' }, // open threads + { type: 'bytes32', value: threadRootHash }, // thread root hash + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyI }, // hub + { type: 'uint256', value: web3latest.utils.toWei('10') }, + { type: 'uint256', value: web3latest.utils.toWei('10') }, + { type: 'uint256', value: web3latest.utils.toWei('5') }, // token + { type: 'uint256', value: web3latest.utils.toWei('15') } // token + ) + + sigA = await web3latest.eth.sign(payload, partyA) + sigI = await web3latest.eth.sign(payload, partyI) + + await channelManager.updateChannelState(channel_id, updateParams, threadRootHash, sigA, sigI) + + channel = await channelManager.getChannel(channel_id) + expect(channel[4].toString()).to.be.equal(sequence); //new state updated successfully! + }) + }) +}) + +contract('ChannelManager :: initThreadState()', function(accounts) { + + before(async () => { + partyA = accounts[0] + partyB = accounts[1] + partyI = accounts[2] + partyN = accounts[3] + + ec = await EC.new() + token = await Token.new(web3latest.utils.toWei('1000'), 'Test', 1, 'TST') + Ledger.link('HumanStandardToken', token.address) + Ledger.link('ECTools', ec.address) + channelManager = await Ledger.new() + + await token.transfer(partyB, web3latest.utils.toWei('100')) + await token.transfer(partyI, web3latest.utils.toWei('100')) + + let sentBalance = [web3latest.utils.toWei('10'), web3latest.utils.toWei('10')] + await token.approve(channelManager.address, sentBalance[1]) + await token.approve(channelManager.address, sentBalance[1], {from: partyI}) + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + await channelManager.createChannel(channel_id, partyI, '1', token.address, sentBalance, {from:partyA, value: sentBalance[0]}) + await channelManager.joinChannel(channel_id, sentBalance, {from: partyI, value: sentBalance[0]}) + + initialThreadState = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id }, // thread ID + { type: 'uint256', value: 0 }, // sequence + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyB }, // partyB + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond token + { type: 'uint256', value: web3latest.utils.toWei('0') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('0') }, // token + { type: 'uint256', value: web3latest.utils.toWei('1') } // token + ) + + payload = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id }, + { type: 'bool', value: false }, // isclose + { type: 'uint256', value: '1' }, // sequence + { type: 'uint256', value: '1' }, // open threads + { type: 'bytes32', value: initialThreadState }, // thread root hash + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyI }, // hub + { type: 'uint256', value: web3latest.utils.toWei('5') }, + { type: 'uint256', value: web3latest.utils.toWei('15') }, + { type: 'uint256', value: web3latest.utils.toWei('5') }, // token + { type: 'uint256', value: web3latest.utils.toWei('15') } // token + ) + + fakeSig = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id }, // ID + { type: 'bool', value: false }, // isclose + { type: 'uint256', value: '1' }, // sequence + { type: 'uint256', value: '0' }, // open threads + { type: 'string', value: '0x0' }, // thread root hash + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyI }, // hub + { type: 'uint256', value: web3latest.utils.toWei('15') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('15') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('15') }, // token + { type: 'uint256', value: web3latest.utils.toWei('15') } // token + ) + + sigA = await web3latest.eth.sign(payload, partyA) + sigI = await web3latest.eth.sign(payload, partyI) + fakeSig = await web3latest.eth.sign(fakeSig, partyA) + + threadRootHash = initialThreadState + bond = [web3latest.utils.toWei('1'), web3latest.utils.toWei('1')] + let updateParams = ['1', '1', web3latest.utils.toWei('5'), web3latest.utils.toWei('15'), web3latest.utils.toWei('5'), web3latest.utils.toWei('15')] + await channelManager.updateChannelState(channel_id, updateParams, threadRootHash, sigA, sigI) + + let channel_id_fail = web3latest.utils.sha3('fail', {encoding: 'hex'}) + await token.approve(channelManager.address, sentBalance[1]) + await channelManager.createChannel(channel_id_fail, partyI, '0', token.address, sentBalance, {from:partyA, value: sentBalance[0]}) + }) + + + describe('initThreadState() has 8 possible cases:', () => { + it("1. Fail: Channel with that ID does not exist", async () => { + let channel_id = web3latest.utils.sha3('nochannel', {encoding: 'hex'}) + let balances = [web3latest.utils.toWei('0'), web3latest.utils.toWei('1'), web3latest.utils.toWei('0'), web3latest.utils.toWei('1')] + let channel = await channelManager.getChannel(channel_id) + let thread = await channelManager.getThread(channel_id) + let verificationA = await web3latest.eth.sign(initialThreadState, partyA) + sigA = await web3latest.eth.sign(initialThreadState, partyA) + + expect(channel[0][0]).to.be.equal('0x0000000000000000000000000000000000000000') //fail + expect(channel[9]).to.not.be.equal(true) //pass + expect(thread[0]).to.not.be.equal(true) //pass + expect(channel[8]*1000).to.be.below(Date.now()) //pass (inverted because channel[8] is 0 for nonexistent channel) + expect(thread[4].toString()).to.be.equal('0') //pass + expect(sigA).to.be.equal(verificationA) //pass + expect(threadRootHash).to.be.equal(initialThreadState) //pass (this is a way of checking isContained() if there is only one thread open) + + + await channelManager.initThreadState(channel_id, channel_id, 0, partyA, partyB, bond, balances, sigA).should.be.rejectedWith(SolRevert) + }) + it("2. Fail: Channel with that ID is not open", async () => { + let channel_id = web3latest.utils.sha3('fail', {encoding: 'hex'}) + let balances = [web3latest.utils.toWei('0'), web3latest.utils.toWei('1'), web3latest.utils.toWei('0'), web3latest.utils.toWei('1')] + let channel = await channelManager.getChannel(channel_id) + let thread = await channelManager.getThread(channel_id) + let verificationA = await web3latest.eth.sign(initialThreadState, partyA) + sigA = await web3latest.eth.sign(initialThreadState, partyA) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.not.be.equal(true) //fail + expect(thread[0]).to.not.be.equal(true) //pass + expect(channel[8]*1000).to.be.below(Date.now()) //pass (inverted because channel[8] is 0 for non open channel) + expect(thread[4].toString()).to.be.equal('0') //pass + expect(sigA).to.be.equal(verificationA) //pass + expect(threadRootHash).to.be.equal(initialThreadState) //pass (this is a way of checking isContained() if there is only one thread open) + + + await channelManager.initThreadState(channel_id, channel_id, 0, partyA, partyB, bond, balances, sigA).should.be.rejectedWith(SolRevert) + }) + it("TODO Fail: 3. Fail: thread with that ID is closed already", async () => { + //Sometimes reverts on initial close, unclear why. :( + + // let channel_id = web3latest.utils.sha3('closed', {encoding: 'hex'}) + // let sentBalance = [web3latest.utils.toWei('10'), web3latest.utils.toWei('10')] + // await token.approve(channelManager.address, sentBalance[1]) + // await token.approve(channelManager.address, sentBalance[1], {from: partyI}) + // await channelManager.createChannel(channel_id, partyI, 0, token.address, sentBalance, {from:partyA, value: sentBalance[0]}) + // await channelManager.joinChannel(channel_id, sentBalance, {from: partyI, value: sentBalance[0]}) + + // let threadRootHash_temp = web3latest.utils.soliditySha3( + // { type: 'uint256', value: channel_id }, // thread ID + // { type: 'uint256', value: 0 }, // sequence + // { type: 'address', value: partyA }, // partyA + // { type: 'address', value: partyB }, // partyB + // { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond eth + // { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond token + // { type: 'uint256', value: web3latest.utils.toWei('1') }, // eth + // { type: 'uint256', value: web3latest.utils.toWei('0') }, // eth + // { type: 'uint256', value: web3latest.utils.toWei('1') }, // token + // { type: 'uint256', value: web3latest.utils.toWei('0') } // token + // ) + + // let payload_temp = web3latest.utils.soliditySha3( + // { type: 'uint256', value: channel_id }, + // { type: 'bool', value: false }, // isclose + // { type: 'uint256', value: 1 }, // sequence + // { type: 'uint256', value: 1 }, // open threads + // { type: 'bytes32', value: threadRootHash_temp }, // thread root hash + // { type: 'address', value: partyA }, // partyA + // { type: 'address', value: partyI }, // hub + // { type: 'uint256', value: web3latest.utils.toWei('5') }, + // { type: 'uint256', value: web3latest.utils.toWei('15') }, + // { type: 'uint256', value: web3latest.utils.toWei('5') }, // token + // { type: 'uint256', value: web3latest.utils.toWei('15') } // token + // ) + + // sigA = await web3latest.eth.sign(payload_temp, partyA) + // sigI = await web3latest.eth.sign(payload_temp, partyI) + // let updateParams = [1, 1, web3latest.utils.toWei('5'), web3latest.utils.toWei('15'), web3latest.utils.toWei('5'), web3latest.utils.toWei('15')] + // await channelManager.updateChannelState(channel_id, updateParams, threadRootHash_temp, sigA, sigI) + + // let balances = [web3latest.utils.toWei('1'), web3latest.utils.toWei('0'), web3latest.utils.toWei('1'), web3latest.utils.toWei('0')] + // sigA = await web3latest.eth.sign(threadRootHash_temp, partyA) + // await channelManager.initThreadState(channel_id, channel_id, 0, partyA, partyB, bond, balances, sigA) + + // await channelManager.closeThread(channel_id, channel_id) + + // let channel = await channelManager.getChannel(channel_id) + // let thread = await channelManager.getThread(channel_id) + // let verificationA = await web3latest.eth.sign(threadRootHash_temp, partyA) + // sigA = await web3latest.eth.sign(threadRootHash_temp, partyA) + + // expect(channel[0][0]).to.be.equal(partyA) //pass + // expect(channel[9]).to.be.equal(true) //pass + // expect(thread[0]).to.not.be.equal(true) //fail + // expect(channel[8]*1000).to.not.be.below(Date.now()) //pass + // expect(thread[4].toString()).to.not.be.equal('0') //pass (inverted because thread was already closed) + // expect(sigA).to.be.equal(verificationA) //pass + // expect(threadRootHash_temp).to.be.equal(threadRootHash_temp) //pass (this is a way of checking isContained() if there is only one thread open) + + // await channelManager.initThreadState(channel_id, channel_id, 0, partyA, partyB, bond, balances, sigA).should.be.rejectedWith(SolRevert) + }) + it("4. Fail: channel update timer has not yet expired", async () => { + let sentBalance = [web3latest.utils.toWei('10'), web3latest.utils.toWei('10')] + await token.approve(channelManager.address, sentBalance[1]) + await token.approve(channelManager.address, sentBalance[1], {from: partyI}) + let channel_id = web3latest.utils.sha3('2222', {encoding: 'hex'}) + await channelManager.createChannel(channel_id, partyI, '100000000', token.address, sentBalance, {from:partyA, value: sentBalance[0]}) + await channelManager.joinChannel(channel_id, sentBalance, {from: partyI, value: sentBalance[0]}) + + let threadRootHash_temp = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id }, // thread ID + { type: 'uint256', value: 0 }, // sequence + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyB }, // partyB + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond token + { type: 'uint256', value: web3latest.utils.toWei('0') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('0') }, // token + { type: 'uint256', value: web3latest.utils.toWei('1') } // token + ) + + let payload_temp = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id }, + { type: 'bool', value: false }, // isclose + { type: 'uint256', value: '1' }, // sequence + { type: 'uint256', value: '1' }, // open threads + { type: 'bytes32', value: threadRootHash_temp }, // thread root hash + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyI }, // hub + { type: 'uint256', value: web3latest.utils.toWei('5') }, + { type: 'uint256', value: web3latest.utils.toWei('15') }, + { type: 'uint256', value: web3latest.utils.toWei('5') }, // token + { type: 'uint256', value: web3latest.utils.toWei('15') } // token + ) + let channel = await channelManager.getChannel(channel_id) + + let sigA_temp = await web3latest.eth.sign(payload_temp, partyA) + let sigI_temp = await web3latest.eth.sign(payload_temp, partyI) + let updateParams = ['1', '1', web3latest.utils.toWei('5'), web3latest.utils.toWei('15'), web3latest.utils.toWei('5'), web3latest.utils.toWei('15')] + await channelManager.updateChannelState(channel_id, updateParams, threadRootHash_temp, sigA_temp, sigI_temp) + + let balances = [web3latest.utils.toWei('0'), web3latest.utils.toWei('1'), web3latest.utils.toWei('0'), web3latest.utils.toWei('1')] + channel = await channelManager.getChannel(channel_id) + let thread = await channelManager.getThread(channel_id) + let verificationA = await web3latest.eth.sign(threadRootHash_temp, partyA) + sigA = await web3latest.eth.sign(threadRootHash_temp, partyA) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(thread[0]).to.not.be.equal(true) //pass + expect(channel[8]*1000).to.not.be.below(Date.now()) //fail + expect(thread[4].toString()).to.be.equal('0') //pass + expect(sigA).to.be.equal(verificationA) //pass + expect(threadRootHash_temp).to.be.equal(threadRootHash_temp) //pass (this is a way of checking isContained() if there is only one thread open) + + await channelManager.initThreadState(channel_id, channel_id, 0, partyA, partyB, bond, balances, sigA).should.be.rejectedWith(SolRevert) + }) + it("5. Fail: Alice has not signed initial state (or wrong state)", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let balances = [web3latest.utils.toWei('0'), web3latest.utils.toWei('1'), web3latest.utils.toWei('0'), web3latest.utils.toWei('1')] + let channel = await channelManager.getChannel(channel_id) + let verificationA = await web3latest.eth.sign(initialThreadState, partyA) + sigA = await web3latest.eth.sign(initialThreadState, partyA) + let thread = await channelManager.getThread(channel_id) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(thread[0]).to.not.be.equal(true) //pass + expect(channel[8]*1000).to.be.below(Date.now()) //pass (inverted because channel[8] is 0 for non open channel) + expect(thread[4].toString()).to.be.equal('0') //pass + expect(fakeSig).to.not.be.equal(verificationA) //fail + expect(threadRootHash).to.be.equal(initialThreadState) //pass (this is a way of checking isContained() if there is only one thread open) + + await channelManager.initThreadState(channel_id, channel_id, 0, partyA, partyB, bond, balances, fakeSig).should.be.rejectedWith(SolRevert) + }) + it("6. Fail: Old state not contained in root hash", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let balances = [web3latest.utils.toWei('1'), web3latest.utils.toWei('0'), web3latest.utils.toWei('1'), web3latest.utils.toWei('0')] + let channel = await channelManager.getChannel(channel_id) + let thread = await channelManager.getThread(channel_id) + + let threadRootHash_temp = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id }, // thread ID + { type: 'uint256', value: 0 }, // sequence + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyB }, // partyB + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond token + { type: 'uint256', value: web3latest.utils.toWei('1') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('0') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // token + { type: 'uint256', value: web3latest.utils.toWei('0') } // token + ) + + let verificationA = await web3latest.eth.sign(threadRootHash_temp, partyA) + sigA = verificationA + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(thread[0]).to.not.be.equal(true) //pass + expect(channel[8]*1000).to.be.below(Date.now()) //pass (inverted because channel[8] is 0 for non open channel) + expect(thread[4].toString()).to.be.equal('0') //pass + expect(sigA).to.be.equal(verificationA) //pass + expect(threadRootHash_temp).to.not.be.equal(initialThreadState) //fail (this is a way of checking isContained() if there is only one thread open) + + await channelManager.initThreadState(channel_id, channel_id, 0, partyA, partyB, bond, balances, sigA).should.be.rejectedWith(SolRevert) + }) + it("7. Success: thread inited successfully", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let balances = [web3latest.utils.toWei('0'), web3latest.utils.toWei('1'), web3latest.utils.toWei('0'), web3latest.utils.toWei('1')] + let channel = await channelManager.getChannel(channel_id) + let verificationA = await web3latest.eth.sign(initialThreadState, partyA) + sigA = await web3latest.eth.sign(initialThreadState, partyA) + let thread = await channelManager.getThread(channel_id) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(thread[0]).to.not.be.equal(true) //pass + expect(channel[8]*1000).to.be.below(Date.now()) //pass (inverted because channel[8] is 0 for non open channel) + expect(thread[4].toString()).to.be.equal('0') //pass + expect(sigA).to.be.equal(verificationA) //pass + expect(threadRootHash).to.be.equal(initialThreadState) //pass (this is a way of checking isContained() if there is only one thread open) + + await channelManager.initThreadState(channel_id, channel_id, 0, partyA, partyB, bond, balances, sigA) + }) + it("8. Fail: Update thread timer is not 0 (initThreadState has already been called before)", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let balances = [web3latest.utils.toWei('0'), web3latest.utils.toWei('1'), web3latest.utils.toWei('0'), web3latest.utils.toWei('1')] + let channel = await channelManager.getChannel(channel_id) + let verificationA = await web3latest.eth.sign(initialThreadState, partyA) + sigA = await web3latest.eth.sign(initialThreadState, partyA) + let thread = await channelManager.getThread(channel_id) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(thread[0]).to.not.be.equal(true) //pass + expect(channel[8]*1000).to.be.below(Date.now()) //pass (inverted because channel[8] is 0 for non open channel) + expect(thread[4].toString()).to.not.be.equal('0') //fail + expect(sigA).to.be.equal(verificationA) //pass + expect(threadRootHash).to.be.equal(initialThreadState) //pass (this is a way of checking isContained() if there is only one thread open) + + await channelManager.initThreadState(channel_id, channel_id, 0, partyA, partyB, bond, balances, sigA).should.be.rejectedWith(SolRevert) + }) + }) +}) + +contract('ChannelManager :: settleThread()', function(accounts) { + + before(async () => { + partyA = accounts[0] + partyB = accounts[1] + partyI = accounts[2] + partyN = accounts[3] + + ec = await EC.new() + token = await Token.new(web3latest.utils.toWei('1000'), 'Test', 1, 'TST') + Ledger.link('HumanStandardToken', token.address) + Ledger.link('ECTools', ec.address) + channelManager = await Ledger.new() + + await token.transfer(partyB, web3latest.utils.toWei('100')) + await token.transfer(partyI, web3latest.utils.toWei('100')) + + let sentBalance = [web3latest.utils.toWei('10'), web3latest.utils.toWei('10')] + await token.approve(channelManager.address, sentBalance[1]) + await token.approve(channelManager.address, sentBalance[1], {from: partyI}) + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + await channelManager.createChannel(channel_id, partyI, 0, token.address, sentBalance, {from:partyA, value: sentBalance[0]}) + await channelManager.joinChannel(channel_id, sentBalance, {from: partyI, value: sentBalance[0]}) + + initialThreadState = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id }, // thread ID + { type: 'uint256', value: 0 }, // sequence + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyB }, // partyB + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond token + { type: 'uint256', value: web3latest.utils.toWei('1') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('0') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // token + { type: 'uint256', value: web3latest.utils.toWei('0') } // token + ) + + payload = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id }, + { type: 'bool', value: false }, // isclose + { type: 'uint256', value: '1' }, // sequence + { type: 'uint256', value: '1' }, // open threads + { type: 'bytes32', value: initialThreadState }, // thread root hash + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyI }, // hub + { type: 'uint256', value: web3latest.utils.toWei('5') }, + { type: 'uint256', value: web3latest.utils.toWei('15') }, + { type: 'uint256', value: web3latest.utils.toWei('5') }, // token + { type: 'uint256', value: web3latest.utils.toWei('15') } // token + ) + + fakeSig = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id }, // ID + { type: 'bool', value: false }, // isclose + { type: 'uint256', value: '1' }, // sequence + { type: 'uint256', value: '0' }, // open threads + { type: 'string', value: '0x0' }, // thread root hash + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyI }, // hub + { type: 'uint256', value: web3latest.utils.toWei('15') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('15') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('15') }, // token + { type: 'uint256', value: web3latest.utils.toWei('15') } // token + ) + + sigA = await web3latest.eth.sign(payload, partyA) + sigI = await web3latest.eth.sign(payload, partyI) + fakeSig = await web3latest.eth.sign(fakeSig, partyA) + + threadRootHash = initialThreadState + bond = [web3latest.utils.toWei('1'), web3latest.utils.toWei('1')] + let updateParams = ['1', '1', web3latest.utils.toWei('5'), web3latest.utils.toWei('15'), web3latest.utils.toWei('5'), web3latest.utils.toWei('15')] + await channelManager.updateChannelState(channel_id, updateParams, threadRootHash, sigA, sigI) + + let balances = [web3latest.utils.toWei('1'), web3latest.utils.toWei('0'), web3latest.utils.toWei('1'), web3latest.utils.toWei('0')] + sigA = await web3latest.eth.sign(initialThreadState, partyA) + await channelManager.initThreadState(channel_id, channel_id, 0, partyA, partyB, bond, balances, sigA) + + let channel_id_fail = web3latest.utils.sha3('fail', {encoding: 'hex'}) + await token.approve(channelManager.address, sentBalance[1]) + await channelManager.createChannel(channel_id_fail, partyI, '0', token.address, sentBalance, {from:partyA, value: sentBalance[0]}) + + payload = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id }, // thread ID + { type: 'uint256', value: 1 }, // sequence + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyB }, // partyB + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond token + { type: 'uint256', value: web3latest.utils.toWei('0') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('0') }, // token + { type: 'uint256', value: web3latest.utils.toWei('1') } // token + ) + + }) + + + describe('settleThread() has 14 possible cases:', () => { + it("1. Fail: Channel with that ID does not exist", async () => { + let channel_id = web3latest.utils.sha3('nochannel', {encoding: 'hex'}) + let balances = [web3latest.utils.toWei('0'), web3latest.utils.toWei('1'), web3latest.utils.toWei('0'), web3latest.utils.toWei('1')] + let sequence = 1 + let channel = await channelManager.getChannel(channel_id) + let thread = await channelManager.getThread(channel_id) + let verificationA = await web3latest.eth.sign(payload, partyA) + sigA = await web3latest.eth.sign(payload, partyA) + + expect(channel[0][0]).to.be.equal('0x0000000000000000000000000000000000000000') //fail + expect(channel[9]).to.not.be.equal(true) //pass (inverted for nonexistent channel) + expect(thread[0]).to.not.be.equal(true) //pass + expect(thread[2]).to.be.below(sequence) //pass + expect(thread[8][1].toString()).to.be.below(balances[1]) //pass + expect(thread[9][1].toString()).to.be.below(balances[3]) //pass + expect(thread[10][0].toString()).to.not.be.equal(web3latest.utils.toWei('1')) //pass (inverted because thread state not inited yet) + expect(thread[10][1].toString()).to.not.be.equal(web3latest.utils.toWei('1')) //pass (inverted because thread state not inited yet) + expect(thread[4].toString()).to.be.equal('0') //pass (inverted because thread state not inited yet) + expect(channel[8]*1000).to.be.below(Date.now()) //pass + expect(sigA).to.be.equal(verificationA) //pass + //expect(thread[4]*1000).to.be.above(Date.now()) //pass + + await channelManager.settleThread(channel_id, channel_id, sequence, partyA, partyB, balances, sigA).should.be.rejectedWith(SolRevert) + }) + it("2. Fail: Channel with that ID is not open", async () => { + let channel_id = web3latest.utils.sha3('fail', {encoding: 'hex'}) + let balances = [web3latest.utils.toWei('0'), web3latest.utils.toWei('1'), web3latest.utils.toWei('0'), web3latest.utils.toWei('1')] + let sequence = 1 + let channel = await channelManager.getChannel(channel_id) + let thread = await channelManager.getThread(channel_id) + let verificationA = await web3latest.eth.sign(payload, partyA) + sigA = await web3latest.eth.sign(payload, partyA) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.not.be.equal(true) //fail + expect(thread[0]).to.not.be.equal(true) //pass + expect(thread[2]).to.be.below(sequence) //pass + expect(thread[8][1].toString()).to.be.below(balances[1]) //pass + expect(thread[9][1].toString()).to.be.below(balances[3]) //pass + expect(thread[10][0].toString()).to.not.be.equal(web3latest.utils.toWei('1')) //pass (inverted because thread state not inited yet) + expect(thread[10][1].toString()).to.not.be.equal(web3latest.utils.toWei('1')) //pass (inverted because thread state not inited yet) + expect(thread[4].toString()).to.be.equal('0') //pass (inverted because thread state not inited yet) + expect(channel[8]*1000).to.be.below(Date.now()) //pass + expect(sigA).to.be.equal(verificationA) //pass + //expect(thread[4]*1000).to.be.above(Date.now()) //pass + + await channelManager.settleThread(channel_id, channel_id, sequence, partyA, partyB, balances, sigA).should.be.rejectedWith(SolRevert) + }) + it("3. Fail: thread with that ID is already closed", async () => { + //Sometimes reverts on initial close, unclear why. :( + + // let channel_id = web3latest.utils.sha3('closed', {encoding: 'hex'}) + // let sentBalance = [web3latest.utils.toWei('10'), web3latest.utils.toWei('10')] + // await token.approve(channelManager.address, sentBalance[1]) + // await token.approve(channelManager.address, sentBalance[1], {from: partyI}) + // await channelManager.createChannel(channel_id, partyI, 0, token.address, sentBalance, {from:partyA, value: sentBalance[0]}) + // await channelManager.joinChannel(channel_id, sentBalance, {from: partyI, value: sentBalance[0]}) + + // initialThreadState = web3latest.utils.soliditySha3( + // { type: 'uint256', value: channel_id }, // thread ID + // { type: 'uint256', value: 0 }, // sequence + // { type: 'address', value: partyA }, // partyA + // { type: 'address', value: partyB }, // partyB + // { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond eth + // { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond token + // { type: 'uint256', value: web3latest.utils.toWei('1') }, // eth + // { type: 'uint256', value: web3latest.utils.toWei('0') }, // eth + // { type: 'uint256', value: web3latest.utils.toWei('1') }, // token + // { type: 'uint256', value: web3latest.utils.toWei('0') } // token + // ) + + // let payload_temp = web3latest.utils.soliditySha3( + // { type: 'uint256', value: channel_id }, + // { type: 'bool', value: false }, // isclose + // { type: 'uint256', value: 1 }, // sequence + // { type: 'uint256', value: 1 }, // open threads + // { type: 'bytes32', value: initialThreadState }, // thread root hash + // { type: 'address', value: partyA }, // partyA + // { type: 'address', value: partyI }, // hub + // { type: 'uint256', value: web3latest.utils.toWei('5') }, + // { type: 'uint256', value: web3latest.utils.toWei('15') }, + // { type: 'uint256', value: web3latest.utils.toWei('5') }, // token + // { type: 'uint256', value: web3latest.utils.toWei('15') } // token + // ) + + // sigA = await web3latest.eth.sign(payload_temp, partyA) + // sigI = await web3latest.eth.sign(payload_temp, partyI) + // let updateParams = [1, 1, web3latest.utils.toWei('5'), web3latest.utils.toWei('15'), web3latest.utils.toWei('5'), web3latest.utils.toWei('15')] + // await channelManager.updateChannelState(channel_id, updateParams, initialThreadState, sigA, sigI) + + // let balances = [web3latest.utils.toWei('1'), web3latest.utils.toWei('0'), web3latest.utils.toWei('1'), web3latest.utils.toWei('0')] + // sigA = await web3latest.eth.sign(initialThreadState, partyA) + // await channelManager.initThreadState(channel_id, channel_id, 0, partyA, partyB, bond, balances, sigA) + + // await channelManager.closeThread(channel_id, channel_id) + + // let channel = await channelManager.getChannel(channel_id) + // let thread = await channelManager.getThread(channel_id) + + // balances = [web3latest.utils.toWei('0'), web3latest.utils.toWei('1'), web3latest.utils.toWei('0'), web3latest.utils.toWei('1')] + + // payload_temp = web3latest.utils.soliditySha3( + // { type: 'uint256', value: channel_id }, // thread ID + // { type: 'uint256', value: 2 }, // sequence + // { type: 'address', value: partyA }, // partyA + // { type: 'address', value: partyB }, // partyB + // { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond eth + // { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond token + // { type: 'uint256', value: web3latest.utils.toWei('0') }, // eth + // { type: 'uint256', value: web3latest.utils.toWei('1') }, // eth + // { type: 'uint256', value: web3latest.utils.toWei('0') }, // token + // { type: 'uint256', value: web3latest.utils.toWei('1') } // token + // ) + // sigA = await web3latest.eth.sign(payload_temp, partyA) + // let verificationA = sigA + + // expect(channel[0][0]).to.be.equal(partyA) //pass + // expect(channel[9]).to.be.equal(true) //pass + // expect(thread[0]).to.be.equal(true) //fail + // expect(thread[2]).to.be.below(2) //pass + // expect(thread[8][1].toString()).to.be.below(balances[1]) //pass + // expect(thread[9][1].toString()).to.be.below(balances[3]) //pass + // expect(thread[10][0].toString()).to.be.equal(web3latest.utils.toWei('1')) //pass + // expect(thread[10][1].toString()).to.be.equal(web3latest.utils.toWei('1')) //pass + // expect(thread[4].toString()).to.not.be.equal('0') //pass + // expect(channel[8]*1000).to.be.below(Date.now()) //pass + // expect(sigA).to.be.equal(verificationA) //pass + // // expect(thread[4]*1000).to.be.above(Date.now()) //pass + + // await channelManager.settleThread(channel_id, channel_id, 2, partyA, partyB, balances, sigA).should.be.rejectedWith(SolRevert) + }) + it("4. Fail: Onchain thread sequence is higher than submitted sequence", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let balances = [web3latest.utils.toWei('0'), web3latest.utils.toWei('1'), web3latest.utils.toWei('0'), web3latest.utils.toWei('1')] + let sequence = 0 + let channel = await channelManager.getChannel(channel_id) + let thread = await channelManager.getThread(channel_id) + let verificationA = await web3latest.eth.sign(payload, partyA) + sigA = await web3latest.eth.sign(payload, partyA) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(thread[0]).to.not.be.equal(true) //pass + expect(thread[2]).to.not.be.below(sequence) //fail + expect(thread[8][1].toString()).to.be.below(balances[1]) //pass + expect(thread[9][1].toString()).to.be.below(balances[3]) //pass + expect(thread[10][0].toString()).to.be.equal(web3latest.utils.toWei('1')) //pass + expect(thread[10][1].toString()).to.be.equal(web3latest.utils.toWei('1')) //pass + expect(thread[4].toString()).to.not.be.equal('0') //pass + expect(channel[8]*1000).to.be.below(Date.now()) //pass + expect(sigA).to.be.equal(verificationA) //pass + //expect(thread[4]*1000).to.be.above(Date.now()) //pass + + await channelManager.settleThread(channel_id, channel_id, sequence, partyA, partyB, balances, sigA).should.be.rejectedWith(SolRevert) + }) + it("5. Fail: State update decreases recipient balance", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let balances = [web3latest.utils.toWei('1'), web3latest.utils.toWei('0'), web3latest.utils.toWei('0'), web3latest.utils.toWei('1')] + let sequence = 1 + let channel = await channelManager.getChannel(channel_id) + let thread = await channelManager.getThread(channel_id) + + let payload_temp = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id }, // thread ID + { type: 'uint256', value: 1 }, // sequence + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyB }, // partyB + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond token + { type: 'uint256', value: web3latest.utils.toWei('1') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('0') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('0') }, // token + { type: 'uint256', value: web3latest.utils.toWei('1') } // token + ) + + let verificationA = await web3latest.eth.sign(payload_temp, partyA) + sigA = await web3latest.eth.sign(payload_temp, partyA) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(thread[0]).to.not.be.equal(true) //pass + expect(thread[2]).to.be.below(sequence) //pass + expect(thread[8][1].toString()).to.not.be.below(balances[1]) //fail + expect(thread[9][1].toString()).to.be.below(balances[3]) //pass + expect(thread[10][0].toString()).to.be.equal(web3latest.utils.toWei('1')) //pass + expect(thread[10][1].toString()).to.be.equal(web3latest.utils.toWei('1')) //pass + expect(thread[4].toString()).to.not.be.equal('0') //pass + expect(channel[8]*1000).to.be.below(Date.now()) //pass + expect(sigA).to.be.equal(verificationA) //pass + //expect(thread[4]*1000).to.be.above(Date.now()) //pass + + await channelManager.settleThread(channel_id, channel_id, sequence, partyA, partyB, balances, sigA).should.be.rejectedWith(SolRevert) + }) + it("6. Fail: State update decreases recipient balance", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let balances = [web3latest.utils.toWei('0'), web3latest.utils.toWei('1'), web3latest.utils.toWei('1'), web3latest.utils.toWei('0')] + let sequence = 1 + let channel = await channelManager.getChannel(channel_id) + let thread = await channelManager.getThread(channel_id) + + let payload_temp = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id }, // thread ID + { type: 'uint256', value: 1 }, // sequence + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyB }, // partyB + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond token + { type: 'uint256', value: web3latest.utils.toWei('0') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // token + { type: 'uint256', value: web3latest.utils.toWei('0') } // token + ) + + let verificationA = await web3latest.eth.sign(payload_temp, partyA) + sigA = await web3latest.eth.sign(payload_temp, partyA) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(thread[0]).to.not.be.equal(true) //pass + expect(thread[2]).to.be.below(sequence) //pass + expect(thread[8][1].toString()).to.be.below(balances[1]) //pass + expect(thread[9][1].toString()).to.not.be.below(balances[3]) //fail + expect(thread[10][0].toString()).to.be.equal(web3latest.utils.toWei('1')) //pass + expect(thread[10][1].toString()).to.be.equal(web3latest.utils.toWei('1')) //pass + expect(thread[4].toString()).to.not.be.equal('0') //pass + expect(channel[8]*1000).to.be.below(Date.now()) //pass + expect(sigA).to.be.equal(verificationA) //pass + //expect(thread[4]*1000).to.be.above(Date.now()) //pass + + await channelManager.settleThread(channel_id, channel_id, sequence, partyA, partyB, balances, sigA).should.be.rejectedWith(SolRevert) + }) + it("7. Fail: Eth balances do not match bonded amount", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let balances = [web3latest.utils.toWei('1'), web3latest.utils.toWei('1'), web3latest.utils.toWei('0'), web3latest.utils.toWei('1')] + let sequence = 1 + let channel = await channelManager.getChannel(channel_id) + let thread = await channelManager.getThread(channel_id) + + let payload_temp = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id }, // thread ID + { type: 'uint256', value: 1 }, // sequence + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyB }, // partyB + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond token + { type: 'uint256', value: web3latest.utils.toWei('1') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('0') }, // token + { type: 'uint256', value: web3latest.utils.toWei('1') } // token + ) + + let verificationA = await web3latest.eth.sign(payload_temp, partyA) + sigA = await web3latest.eth.sign(payload_temp, partyA) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(thread[0]).to.not.be.equal(true) //pass + expect(thread[2]).to.be.below(sequence) //pass + expect(thread[8][1].toString()).to.be.below(balances[1]) //pass + expect(thread[9][1].toString()).to.be.below(balances[3]) //pass + expect(thread[10][0].toString()).to.not.be.equal(web3latest.utils.toWei('2')) //fail + expect(thread[10][1].toString()).to.be.equal(web3latest.utils.toWei('1')) //pass + expect(thread[4].toString()).to.not.be.equal('0') //pass + expect(channel[8]*1000).to.be.below(Date.now()) //pass + expect(sigA).to.be.equal(verificationA) //pass + //expect(thread[4]*1000).to.be.above(Date.now()) //pass + + await channelManager.settleThread(channel_id, channel_id, sequence, partyA, partyB, balances, sigA).should.be.rejectedWith(SolRevert) + }) + it("8. Fail: Eth balances do not match bonded amount", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let balances = [web3latest.utils.toWei('0'), web3latest.utils.toWei('1'), web3latest.utils.toWei('1'), web3latest.utils.toWei('1')] + let sequence = 1 + let channel = await channelManager.getChannel(channel_id) + let thread = await channelManager.getThread(channel_id) + + let payload_temp = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id }, // thread ID + { type: 'uint256', value: 1 }, // sequence + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyB }, // partyB + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond token + { type: 'uint256', value: web3latest.utils.toWei('0') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // token + { type: 'uint256', value: web3latest.utils.toWei('1') } // token + ) + + let verificationA = await web3latest.eth.sign(payload_temp, partyA) + sigA = await web3latest.eth.sign(payload_temp, partyA) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(thread[0]).to.not.be.equal(true) //pass + expect(thread[2]).to.be.below(sequence) //pass + expect(thread[8][1].toString()).to.be.below(balances[1]) //pass + expect(thread[9][1].toString()).to.be.below(balances[3]) //pass + expect(thread[10][0].toString()).to.be.equal(web3latest.utils.toWei('1')) //pass + expect(thread[10][1].toString()).to.not.be.equal(web3latest.utils.toWei('2')) //fail + expect(thread[4].toString()).to.not.be.equal('0') //pass + expect(channel[8]*1000).to.be.below(Date.now()) //pass + expect(sigA).to.be.equal(verificationA) //pass + //expect(thread[4]*1000).to.be.above(Date.now()) //pass + + await channelManager.settleThread(channel_id, channel_id, sequence, partyA, partyB, balances, sigA).should.be.rejectedWith(SolRevert) + }) + it("9. Fail: Initthread was not called first", async () => { + let channel_id = web3latest.utils.sha3('2222', {encoding: 'hex'}) + let balances = [web3latest.utils.toWei('0'), web3latest.utils.toWei('1'), web3latest.utils.toWei('0'), web3latest.utils.toWei('1')] + let sequence = 1 + + let initial_temp = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id }, // thread ID + { type: 'uint256', value: 0 }, // sequence + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyB }, // partyB + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond token + { type: 'uint256', value: web3latest.utils.toWei('0') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('0') }, // token + { type: 'uint256', value: web3latest.utils.toWei('1') } // token + ) + + let payload_temp = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id }, + { type: 'bool', value: false }, // isclose + { type: 'uint256', value: '1' }, // sequence + { type: 'uint256', value: '1' }, // open threads + { type: 'bytes32', value: initial_temp }, // thread root hash + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyI }, // hub + { type: 'uint256', value: web3latest.utils.toWei('5') }, + { type: 'uint256', value: web3latest.utils.toWei('15') }, + { type: 'uint256', value: web3latest.utils.toWei('5') }, // token + { type: 'uint256', value: web3latest.utils.toWei('15') } // token + ) + + let sentBalance = [web3latest.utils.toWei('10'), web3latest.utils.toWei('10')] + await token.approve(channelManager.address, sentBalance[1]) + await token.approve(channelManager.address, sentBalance[1], {from: partyI}) + await channelManager.createChannel(channel_id, partyI, '1', token.address, sentBalance, {from:partyA, value: sentBalance[0]}) + await channelManager.joinChannel(channel_id, sentBalance, {from: partyI, value: sentBalance[0]}) + + sigA = await web3latest.eth.sign(payload_temp, partyA) + sigI = await web3latest.eth.sign(payload_temp, partyI) + + let updateParams = ['1', '1', web3latest.utils.toWei('5'), web3latest.utils.toWei('15'), web3latest.utils.toWei('5'), web3latest.utils.toWei('15')] + await channelManager.updateChannelState(channel_id, updateParams, initial_temp, sigA, sigI) + + let verificationA = await web3latest.eth.sign(initial_temp, partyA) + sigA = await web3latest.eth.sign(initial_temp, partyA) + + let channel = await channelManager.getChannel(channel_id) + let thread = await channelManager.getThread(channel_id) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(thread[0]).to.not.be.equal(true) //pass + expect(thread[2]).to.be.below(sequence) //pass + expect(thread[8][1].toString()).to.be.below(balances[1]) //pass + expect(thread[9][1].toString()).to.be.below(balances[3]) //pass + expect(thread[10][0].toString()).to.not.be.equal(web3latest.utils.toWei('1')) //pass (inverted because initthread not called) + expect(thread[10][1].toString()).to.not.be.equal(web3latest.utils.toWei('1')) //pass (inverted because initthread not called) + expect(thread[4].toString()).to.be.equal('0') //fail + expect(channel[8]*1000).to.be.below(Date.now()) //pass + expect(sigA).to.be.equal(verificationA) //pass + //expect(thread[4]*1000).to.be.above(Date.now()) //pass + + await channelManager.settleThread(channel_id, channel_id, sequence, partyA, partyB, balances, sigA).should.be.rejectedWith(SolRevert) + }) + it("TODO 10. Fail: updatechannel timeout has not expired", async () => { + //Not sure how to test this since Initthread can only be called after timeout expires. + }) + it("11. Fail: Incorrect partyA signature or payload", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let balances = [web3latest.utils.toWei('0'), web3latest.utils.toWei('1'), web3latest.utils.toWei('0'), web3latest.utils.toWei('1')] + let sequence = 1 + let channel = await channelManager.getChannel(channel_id) + let thread = await channelManager.getThread(channel_id) + + let verificationA = await web3latest.eth.sign(payload, partyA) + sigA = await web3latest.eth.sign(payload, partyA) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(thread[0]).to.not.be.equal(true) //pass + expect(thread[2]).to.be.below(sequence) //pass + expect(thread[8][1].toString()).to.be.below(balances[1]) //pass + expect(thread[9][1].toString()).to.be.below(balances[3]) //pass + expect(thread[10][0].toString()).to.be.equal(web3latest.utils.toWei('1')) //pass + expect(thread[10][1].toString()).to.be.equal(web3latest.utils.toWei('1')) //pass + expect(thread[4].toString()).to.not.be.equal('0') //pass + expect(channel[8]*1000).to.be.below(Date.now()) //pass + expect(fakeSig).to.not.be.equal(verificationA) //fail + //expect(thread[4]*1000).to.be.above(Date.now()) //pass + + await channelManager.settleThread(channel_id, channel_id, sequence, partyA, partyB, balances, fakeSig).should.be.rejectedWith(SolRevert) + }) + it("TODO 12. Fail: Updatethread timer has expired", async () => { + //also unclear how best to unit test + }) + it("13. Success 1: First state added!", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let balances = [web3latest.utils.toWei('0.5'), web3latest.utils.toWei('0.5'), web3latest.utils.toWei('0.5'), web3latest.utils.toWei('0.5')] + let sequence = 1 + let channel = await channelManager.getChannel(channel_id) + let thread = await channelManager.getThread(channel_id) + + let payload_temp = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id }, // thread ID + { type: 'uint256', value: 1 }, // sequence + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyB }, // partyB + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond token + { type: 'uint256', value: web3latest.utils.toWei('0.5') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('0.5') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('0.5') }, // token + { type: 'uint256', value: web3latest.utils.toWei('0.5') } // token + ) + + let verificationA = await web3latest.eth.sign(payload_temp, partyA) + sigA = await web3latest.eth.sign(payload_temp, partyA) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(thread[0]).to.not.be.equal(true) //pass + expect(thread[2]).to.be.below(sequence) //pass + expect(thread[8][1].toString()).to.be.below(balances[1]) //pass + expect(thread[9][1].toString()).to.be.below(balances[3]) //pass + expect(thread[10][0].toString()).to.be.equal(web3latest.utils.toWei('1')) //pass + expect(thread[10][1].toString()).to.be.equal(web3latest.utils.toWei('1')) //pass + expect(thread[4].toString()).to.not.be.equal('0') //pass + expect(channel[8]*1000).to.be.below(Date.now()) //pass + expect(sigA).to.be.equal(verificationA) //pass + //expect(thread[4]*1000).to.be.above(Date.now()) //pass + + await channelManager.settleThread(channel_id, channel_id, sequence, partyA, partyB, balances, sigA) + + thread = await channelManager.getThread(channel_id) + expect(thread[1]).to.be.equal(true) //pass + }) + it("14. Success 2: Disputed with higher sequence state!", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let balances = [web3latest.utils.toWei('0'), web3latest.utils.toWei('1'), web3latest.utils.toWei('0'), web3latest.utils.toWei('1')] + let sequence = 2 + let channel = await channelManager.getChannel(channel_id) + let thread = await channelManager.getThread(channel_id) + + let payload_temp = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id }, // thread ID + { type: 'uint256', value: 2 }, // sequence + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyB }, // partyB + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond token + { type: 'uint256', value: web3latest.utils.toWei('0') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('0') }, // token + { type: 'uint256', value: web3latest.utils.toWei('1') } // token + ) + + let verificationA = await web3latest.eth.sign(payload_temp, partyA) + sigA = await web3latest.eth.sign(payload_temp, partyA) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(thread[0]).to.not.be.equal(true) //pass + expect(thread[2]).to.be.below(sequence) //pass + expect(parseInt(thread[8][1])).to.be.below(balances[1]) //pass + expect(parseInt(thread[9][1])).to.be.below(balances[3]) //pass + expect(thread[10][0].toString()).to.be.equal(web3latest.utils.toWei('1')) //pass + expect(thread[10][1].toString()).to.be.equal(web3latest.utils.toWei('1')) //pass + expect(thread[4].toString()).to.not.be.equal('0') //pass + expect(channel[8]*1000).to.be.below(Date.now()) //pass + expect(sigA).to.be.equal(verificationA) //pass + //expect(thread[4]*1000).to.be.above(Date.now()) //pass + + await channelManager.settleThread(channel_id, channel_id, sequence, partyA, partyB, balances, sigA) + + thread = await channelManager.getThread(channel_id) + expect(parseInt(thread[2])).to.be.equal(sequence) //pass + }) + }) +}) + +contract('ChannelManager :: closeThread()', function(accounts) { + + before(async () => { + partyA = accounts[0] + partyB = accounts[1] + partyI = accounts[2] + partyN = accounts[3] + + ec = await EC.new() + token = await Token.new(web3latest.utils.toWei('1000'), 'Test', 1, 'TST') + Ledger.link('HumanStandardToken', token.address) + Ledger.link('ECTools', ec.address) + channelManager = await Ledger.new() + + await token.transfer(partyB, web3latest.utils.toWei('100')) + await token.transfer(partyI, web3latest.utils.toWei('100')) + + let sentBalance = [web3latest.utils.toWei('10'), web3latest.utils.toWei('10')] + await token.approve(channelManager.address, sentBalance[1]) + await token.approve(channelManager.address, sentBalance[1], {from: partyI}) + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + await channelManager.createChannel(channel_id, partyI, 0, token.address, sentBalance, {from:partyA, value: sentBalance[0]}) + await channelManager.joinChannel(channel_id, sentBalance, {from: partyI, value: sentBalance[0]}) + + initialThreadState = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id }, // thread ID + { type: 'uint256', value: 0 }, // sequence + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyB }, // partyB + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond token + { type: 'uint256', value: web3latest.utils.toWei('1') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('0') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // token + { type: 'uint256', value: web3latest.utils.toWei('0') } // token + ) + + payload = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id }, + { type: 'bool', value: false }, // isclose + { type: 'uint256', value: '1' }, // sequence + { type: 'uint256', value: '1' }, // open threads + { type: 'bytes32', value: initialThreadState }, // thread root hash + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyI }, // hub + { type: 'uint256', value: web3latest.utils.toWei('5') }, + { type: 'uint256', value: web3latest.utils.toWei('15') }, + { type: 'uint256', value: web3latest.utils.toWei('5') }, // token + { type: 'uint256', value: web3latest.utils.toWei('15') } // token + ) + + fakeSig = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id }, // ID + { type: 'bool', value: false }, // isclose + { type: 'uint256', value: '1' }, // sequence + { type: 'uint256', value: '0' }, // open threads + { type: 'string', value: '0x0' }, // thread root hash + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyI }, // hub + { type: 'uint256', value: web3latest.utils.toWei('15') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('15') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('15') }, // token + { type: 'uint256', value: web3latest.utils.toWei('15') } // token + ) + + sigA = await web3latest.eth.sign(payload, partyA) + sigI = await web3latest.eth.sign(payload, partyI) + fakeSig = await web3latest.eth.sign(fakeSig, partyA) + + threadRootHash = initialThreadState + bond = [web3latest.utils.toWei('1'), web3latest.utils.toWei('1')] + let updateParams = ['1', '1', web3latest.utils.toWei('5'), web3latest.utils.toWei('15'), web3latest.utils.toWei('5'), web3latest.utils.toWei('15')] + await channelManager.updateChannelState(channel_id, updateParams, threadRootHash, sigA, sigI) + + let balances = [web3latest.utils.toWei('1'), web3latest.utils.toWei('0'), web3latest.utils.toWei('1'), web3latest.utils.toWei('0')] + sigA = await web3latest.eth.sign(initialThreadState, partyA) + await channelManager.initThreadState(channel_id, channel_id, 0, partyA, partyB, bond, balances, sigA) + + + let channel_id_fail = web3latest.utils.sha3('fail', {encoding: 'hex'}) + await token.approve(channelManager.address, sentBalance[1]) + await channelManager.createChannel(channel_id_fail, partyI, 0, token.address, sentBalance, {from:partyA, value: sentBalance[0]}) + + payload = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id }, // thread ID + { type: 'uint256', value: 1 }, // sequence + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyB }, // partyB + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond token + { type: 'uint256', value: web3latest.utils.toWei('0') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('0') }, // token + { type: 'uint256', value: web3latest.utils.toWei('1') } // token + ) + + balances = [web3latest.utils.toWei('0'), web3latest.utils.toWei('1'), web3latest.utils.toWei('0'), web3latest.utils.toWei('1')] + sigA = await web3latest.eth.sign(payload, partyA) + await channelManager.settleThread(channel_id, channel_id, 1, partyA, partyB, balances, sigA) + }) + + describe('closeThread() has 6 possible cases:', () => { + it("1. Fail: Channel with that ID does not exist", async () => { + let channel_id = web3latest.utils.sha3('nochannel', {encoding: 'hex'}) + let channel = await channelManager.getChannel(channel_id) + let thread = await channelManager.getThread(channel_id) + + expect(channel[0][0]).to.be.equal('0x0000000000000000000000000000000000000000') //fail + expect(channel[9]).to.not.be.equal(true) //pass (inverted for nonexistent channel) + expect(thread[0]).to.not.be.equal(true) //pass + expect(thread[1]).to.not.be.equal(true) //pass (inverted for nonexistent thread) + expect(thread[4]*1000).to.be.below(Date.now()) //pass + + await channelManager.closeThread(channel_id, channel_id).should.be.rejectedWith(SolRevert) + }) + it("2. Fail: Channel with that ID is not open", async () => { + let channel_id = web3latest.utils.sha3('fail', {encoding: 'hex'}) + let channel = await channelManager.getChannel(channel_id) + let thread = await channelManager.getThread(channel_id) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.not.be.equal(true) //fail + expect(thread[0]).to.not.be.equal(true) //pass + expect(thread[1]).to.not.be.equal(true) //pass (inverted for nonexistent thread) + expect(thread[4]*1000).to.be.below(Date.now()) //pass + + await channelManager.closeThread(channel_id, channel_id).should.be.rejectedWith(SolRevert) + }) + it("3. Fail: thread with that ID already closed", async () => { + // let channel_id = web3latest.utils.sha3('closed', {encoding: 'hex'}) + // let sentBalance = [web3latest.utils.toWei('10'), web3latest.utils.toWei('10')] + // await token.approve(channelManager.address, sentBalance[1]) + // await token.approve(channelManager.address, sentBalance[1], {from: partyI}) + // await channelManager.createChannel(channel_id, partyI, 0, token.address, sentBalance, {from:partyA, value: sentBalance[0]}) + // await channelManager.joinChannel(channel_id, sentBalance, {from: partyI, value: sentBalance[0]}) + + // initialThreadState = web3latest.utils.soliditySha3( + // { type: 'uint256', value: channel_id }, // thread ID + // { type: 'uint256', value: 0 }, // sequence + // { type: 'address', value: partyA }, // partyA + // { type: 'address', value: partyB }, // partyB + // { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond eth + // { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond token + // { type: 'uint256', value: web3latest.utils.toWei('1') }, // eth + // { type: 'uint256', value: web3latest.utils.toWei('0') }, // eth + // { type: 'uint256', value: web3latest.utils.toWei('1') }, // token + // { type: 'uint256', value: web3latest.utils.toWei('0') } // token + // ) + + // let payload_temp = web3latest.utils.soliditySha3( + // { type: 'uint256', value: channel_id }, + // { type: 'bool', value: false }, // isclose + // { type: 'uint256', value: '1' }, // sequence + // { type: 'uint256', value: '1' }, // open threads + // { type: 'bytes32', value: initialThreadState }, // thread root hash + // { type: 'address', value: partyA }, // partyA + // { type: 'address', value: partyI }, // hub + // { type: 'uint256', value: web3latest.utils.toWei('5') }, + // { type: 'uint256', value: web3latest.utils.toWei('15') }, + // { type: 'uint256', value: web3latest.utils.toWei('5') }, // token + // { type: 'uint256', value: web3latest.utils.toWei('15') } // token + // ) + + // sigA = await web3latest.eth.sign(payload_temp, partyA) + // sigI = await web3latest.eth.sign(payload_temp, partyI) + // let updateParams = ['1', '1', web3latest.utils.toWei('5'), web3latest.utils.toWei('15'), web3latest.utils.toWei('5'), web3latest.utils.toWei('15')] + // await channelManager.updateChannelState(channel_id, updateParams, initialThreadState, sigA, sigI) + + // let balances = [web3latest.utils.toWei('1'), web3latest.utils.toWei('0'), web3latest.utils.toWei('1'), web3latest.utils.toWei('0')] + // sigA = await web3latest.eth.sign(initialThreadState, partyA) + // await channelManager.initThreadState(channel_id, channel_id, 0, partyA, partyB, bond, balances, sigA) + + // await channelManager.closeThread(channel_id, channel_id) + + // let channel = await channelManager.getChannel(channel_id) + // let thread = await channelManager.getThread(channel_id) + + // expect(channel[0][0]).to.be.equal(partyA) //pass + // expect(channel[9]).to.be.equal(true) //pass + // expect(thread[0]).to.be.equal(true) //fail + // expect(thread[1]).to.be.equal(true) //pass + // expect(thread[4]*1000).to.be.below(Date.now()) //pass + + // await channelManager.closeThread(channel_id, channel_id).should.be.rejectedWith(SolRevert) + }) + it("4. Fail: thread is not in settlement state", async () => { + // no point testing this since threads cannot exist unless they're in settlement state. We probably don't need this flag too, since its + // only checked in closethread() + }) + it("TO DO 5. Fail: updatethreadtimeout has not expired", async () => { + // figure out how to test this (need to wait for time to pass) + }) + it("6. Fail: Channel with that ID is not open", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let channel = await channelManager.getChannel(channel_id) + let thread = await channelManager.getThread(channel_id) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(thread[0]).to.not.be.equal(true) //pass + expect(thread[1]).to.be.equal(true) //pass + expect(thread[4]*1000).to.be.below(Date.now()) //pass + + await channelManager.closeThread(channel_id, channel_id) + }) + }) +}) + +contract('ChannelManager :: byzantineCloseChannel()', function(accounts) { + + before(async () => { + partyA = accounts[0] + partyB = accounts[1] + partyI = accounts[2] + partyN = accounts[3] + + ec = await EC.new() + token = await Token.new(web3latest.utils.toWei('1000'), 'Test', 1, 'TST') + Ledger.link('HumanStandardToken', token.address) + Ledger.link('ECTools', ec.address) + channelManager = await Ledger.new() + + await token.transfer(partyB, web3latest.utils.toWei('100')) + await token.transfer(partyI, web3latest.utils.toWei('100')) + + let sentBalance = [web3latest.utils.toWei('10'), web3latest.utils.toWei('10')] + await token.approve(channelManager.address, sentBalance[1]) + await token.approve(channelManager.address, sentBalance[1], {from: partyI}) + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + await channelManager.createChannel(channel_id, partyI, '0', token.address, sentBalance, {from:partyA, value: sentBalance[0]}) + await channelManager.joinChannel(channel_id, sentBalance, {from: partyI, value: sentBalance[0]}) + + initialThreadState = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id }, // thread ID + { type: 'uint256', value: '0' }, // sequence + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyB }, // partyB + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond token + { type: 'uint256', value: web3latest.utils.toWei('1') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('0') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // token + { type: 'uint256', value: web3latest.utils.toWei('0') } // token + ) + + payload = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id }, + { type: 'bool', value: false }, // isclose + { type: 'uint256', value: '1' }, // sequence + { type: 'uint256', value: '1' }, // open threads + { type: 'bytes32', value: initialThreadState }, // thread root hash + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyI }, // hub + { type: 'uint256', value: web3latest.utils.toWei('4') }, + { type: 'uint256', value: web3latest.utils.toWei('15') }, + { type: 'uint256', value: web3latest.utils.toWei('4') }, // token + { type: 'uint256', value: web3latest.utils.toWei('15') } // token + ) + + fakeSig = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id }, // ID + { type: 'bool', value: false }, // isclose + { type: 'uint256', value: '1' }, // sequence + { type: 'uint256', value: '0' }, // open threads + { type: 'string', value: '0x0' }, // thread root hash + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyI }, // hub + { type: 'uint256', value: web3latest.utils.toWei('15') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('15') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('15') }, // token + { type: 'uint256', value: web3latest.utils.toWei('15') } // token + ) + + sigA = await web3latest.eth.sign(payload, partyA) + sigI = await web3latest.eth.sign(payload, partyI) + fakeSig = await web3latest.eth.sign(fakeSig, partyA) + + threadRootHash = initialThreadState + bond = [web3latest.utils.toWei('1'), web3latest.utils.toWei('1')] + let updateParams = ['1', '1', web3latest.utils.toWei('4'), web3latest.utils.toWei('15'), web3latest.utils.toWei('4'), web3latest.utils.toWei('15')] + await channelManager.updateChannelState(channel_id, updateParams, threadRootHash, sigA, sigI) + + let balances = [web3latest.utils.toWei('1'), web3latest.utils.toWei('0'), web3latest.utils.toWei('1'), web3latest.utils.toWei('0')] + sigA = await web3latest.eth.sign(initialThreadState, partyA) + await channelManager.initThreadState(channel_id, channel_id, '0', partyA, partyB, bond, balances, sigA) + + let channel_id_fail = web3latest.utils.sha3('fail', {encoding: 'hex'}) + await token.approve(channelManager.address, sentBalance[1]) + await channelManager.createChannel(channel_id_fail, partyI, '100', token.address, sentBalance, {from:partyA, value: sentBalance[0]}) + + payload = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id }, // thread ID + { type: 'uint256', value: 1 }, // sequence + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyB }, // partyB + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // bond token + { type: 'uint256', value: web3latest.utils.toWei('0') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('1') }, // eth + { type: 'uint256', value: web3latest.utils.toWei('0') }, // token + { type: 'uint256', value: web3latest.utils.toWei('1') } // token + ) + + balances = [web3latest.utils.toWei('0'), web3latest.utils.toWei('1'), web3latest.utils.toWei('0'), web3latest.utils.toWei('1')] + sigA = await web3latest.eth.sign(payload, partyA) + + }) + + + describe('byzantineCloseChannel() has 6 possible cases:', () => { + it("1. Fail: Channel with that ID does not exist", async () => { + let channel_id = web3latest.utils.sha3('nochannel', {encoding: 'hex'}) + let channel = await channelManager.getChannel(channel_id) + let thread = await channelManager.getThread(channel_id) + + expect(channel[0][0]).to.be.equal('0x0000000000000000000000000000000000000000') //fail + expect(channel[9]).to.not.be.equal(true) //pass (inverted for nonexistent channel) + expect(channel[10]).to.not.be.equal(true) //pass (inverted for nonexistent channel) + expect(channel[8]*1000).to.not.be.above(Date.now()) //pass (inverted for nonexistent thread) + expect(parseInt(channel[11])).to.be.equal(0) //pass + expect(parseInt(channel[3][0])).to.be.at.least(parseInt(channel[1][0]) + parseInt(channel[1][1])) //pass + expect(parseInt(channel[3][1])).to.be.at.least(parseInt(channel[2][0]) + parseInt(channel[2][1])) //pass + + await channelManager.byzantineCloseChannel(channel_id).should.be.rejectedWith(SolRevert) + }) + it("2. Fail: Channel with that ID is not open", async () => { + let channel_id = web3latest.utils.sha3('fail', {encoding: 'hex'}) + let channel = await channelManager.getChannel(channel_id) + let thread = await channelManager.getThread(channel_id) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.not.be.equal(true) //fail + expect(channel[10]).to.not.be.equal(true) //pass (inverted for nonexistent channel) + expect(channel[8]*1000).to.be.below(Date.now()) //pass + expect(parseInt(channel[11])).to.be.equal(0) //pass + expect(parseInt(channel[3][0])).to.be.at.least(parseInt(channel[1][0]) + parseInt(channel[1][1])) //pass + expect(parseInt(channel[3][1])).to.be.at.least(parseInt(channel[2][0]) + parseInt(channel[2][1])) //pass + + await channelManager.byzantineCloseChannel(channel_id).should.be.rejectedWith(SolRevert) + }) + it("3. Fail: Channel is not in dispute", async () => { + let channel_id = web3latest.utils.sha3('fail', {encoding: 'hex'}) + + let sentBalance = [web3latest.utils.toWei('10'), web3latest.utils.toWei('10')] + await token.approve(channelManager.address, sentBalance[1], {from: partyI}) + await channelManager.joinChannel(channel_id, sentBalance, {from: partyI, value: sentBalance[0]}) + + let channel = await channelManager.getChannel(channel_id) + let thread = await channelManager.getThread(channel_id) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(channel[10]).to.be.equal(false) //fail + expect(channel[8]*1000).to.be.below(Date.now()) //pass + expect(parseInt(channel[11])).to.be.equal(0) //pass + expect(parseInt(channel[3][0])).to.be.at.least(parseInt(channel[1][0]) + parseInt(channel[1][1])) //pass + expect(parseInt(channel[3][1])).to.be.at.least(parseInt(channel[2][0]) + parseInt(channel[2][1])) //pass + + await channelManager.byzantineCloseChannel(channel_id).should.be.rejectedWith(SolRevert) + }) + it("4. Fail: UpdatechannelTimeout has not yet expired", async () => { + let channel_id = web3latest.utils.sha3('fail', {encoding: 'hex'}) + + payload = web3latest.utils.soliditySha3( + { type: 'uint256', value: channel_id }, + { type: 'bool', value: false }, // isclose + { type: 'uint256', value: '1' }, // sequence + { type: 'uint256', value: '0' }, // open threads + { type: 'bytes32', value: '0x0' }, // thread root hash + { type: 'address', value: partyA }, // partyA + { type: 'address', value: partyI }, // hub + { type: 'uint256', value: web3latest.utils.toWei('5') }, + { type: 'uint256', value: web3latest.utils.toWei('15') }, + { type: 'uint256', value: web3latest.utils.toWei('5') }, // token + { type: 'uint256', value: web3latest.utils.toWei('15') } // token + ) + let sigA_temp = await web3latest.eth.sign(payload, partyA) + let sigI_temp = await web3latest.eth.sign(payload, partyI) + + let updateParams = ['1', '0', web3latest.utils.toWei('5'), web3latest.utils.toWei('15'), web3latest.utils.toWei('5'), web3latest.utils.toWei('15')] + await channelManager.updateChannelState(channel_id, updateParams, '0x0', sigA_temp, sigI_temp) + + let channel = await channelManager.getChannel(channel_id) + let thread = await channelManager.getThread(channel_id) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(channel[10]).to.be.equal(true) //pass + expect(channel[8]*1000).to.be.above(Date.now()) //fail + expect(parseInt(channel[11])).to.be.equal(0) //pass + expect(parseInt(channel[3][0])).to.be.at.least(parseInt(channel[1][0]) + parseInt(channel[1][1])) //pass + expect(parseInt(channel[3][1])).to.be.at.least(parseInt(channel[2][0]) + parseInt(channel[2][1])) //pass + + await channelManager.byzantineCloseChannel(channel_id).should.be.rejectedWith(SolRevert) + }) + it("5. Fail: threads are still open", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + let channel = await channelManager.getChannel(channel_id) + let thread = await channelManager.getThread(channel_id) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(channel[10]).to.be.equal(true) //pass + expect(channel[8]*1000).to.be.below(Date.now()) //pass + expect(parseInt(channel[11])).to.be.equal(1) //fail + expect(parseInt(channel[3][0])).to.be.at.least(parseInt(channel[1][0]) + parseInt(channel[1][1])) //pass + expect(parseInt(channel[3][1])).to.be.at.least(parseInt(channel[2][0]) + parseInt(channel[2][1])) //pass + + await channelManager.byzantineCloseChannel(channel_id).should.be.rejectedWith(SolRevert) + }) + it("6. Fail: Onchain Eth balances are greater than deposit", async () => { + // can't test this until deposits are complete + }) + it("7. Fail: Onchain token balances are greater than deposit", async () => { + // can't test this until deposits are complete + }) + it("8. Success: Channel byzantine closed!", async () => { + let channel_id = web3latest.utils.sha3('1111', {encoding: 'hex'}) + await channelManager.closeThread(channel_id, channel_id) + + let channel = await channelManager.getChannel(channel_id) + let thread = await channelManager.getThread(channel_id) + + expect(channel[0][0]).to.be.equal(partyA) //pass + expect(channel[9]).to.be.equal(true) //pass + expect(channel[10]).to.be.equal(true) //pass + expect(channel[8]*1000).to.be.below(Date.now()) //pass + expect(parseInt(channel[11])).to.be.equal(0) //pass + expect(parseInt(channel[3][0])).to.be.at.least(parseInt(channel[1][0]) + parseInt(channel[1][1])) //pass + expect(parseInt(channel[3][1])).to.be.at.least(parseInt(channel[2][0]) + parseInt(channel[2][1])) //pass + + await channelManager.byzantineCloseChannel(channel_id) + + channel = await channelManager.getChannel(channel_id) + expect(channel[9]).to.be.equal(false) + }) + }) +}) \ No newline at end of file diff --git a/test/unit/ledgerChannelTest.js b/test/unit/ledgerChannelTest.js deleted file mode 100644 index e69de29..0000000