Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions contracts/LedgerChannel.sol
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,19 @@ contract LedgerChannel {
uint256 updateLCtimeout
);

event DidLCWithdrawal(
bytes32 indexed lcID,
address withdrawalAddress,
uint256 sequence,
uint256 ethBalanceA,
uint256 ethBalanceI,
uint256 tokenBalanceA,
uint256 tokenBalanceI,
uint256 ethWithdrawalAmount,
uint256 tokenWithdrawalAmount
);


event DidLCClose (
bytes32 indexed channelId,
uint256 sequence,
Expand Down Expand Up @@ -234,6 +247,88 @@ contract LedgerChannel {
emit DidLCDeposit(_lcID, recipient, _balance, isToken);
}

// A consensus withdraw is essentially doing a consensus close for a partial amount and then opening a new channel with the remaining balances
// we are doing it while keeping the same channel by changing initialDeposit

// We may want to change initialDeposit to a different variable name like lastCheckedInBalances
// multiple consensusWithdraws can happen offchain before submitting to chain as long as both parties remain smart about what the balances truly are.

// if multiple consensus withdraws happen off chain before getting submitted to chain some issues happen when trying to batch them.
// for example: partyA withdraws, partyI then wishes to batch their own withdraw with patyA. But now partyI can submit their first withdrawal to chain and invalidate the 2nd one whenever they wish
// this would also invalidate all state updates after the first withdrawal.
function consensusWithdraw(
bytes32 _lcID,
uint256[7] withdrawParams, // [sequence, ethBalanceA, ethBalanceI, tokenBalanceA, tokenBalanceI, ethWithdrawal, tokenWithdrawal]
address _withdrawalAddress,
string _sigA,
string _sigI
)
public
{
// first we make sure the channel is open and the balances all add up. This means that the consensusWithdraw must be submitted to chain before trying to closeChannel or
// both parties can ignore the consensusWithdraw and submit a consensusClose for the correct balances (batching together the withdraw and the close)
require(Channels[_lcID].isOpen == true);
require(Channels[_lcID].initialDeposit[0] + Channels[_lcID].ethBalances[2] + Channels[_lcID].ethBalances[3] == withdrawParams[1] + withdrawParams[2] + withdrawParams[5]);
require(Channels[_lcID].initialDeposit[1] + Channels[_lcID].erc20Balances[2] + Channels[_lcID].erc20Balances[3] == withdrawParams[3] + withdrawParams[4] + withdrawParams[6]);

// prevent replay attacks
require(withdrawParams[0] > Channels[_lcID].sequence);

// verify sigs
bytes32 _state = keccak256(
abi.encodePacked(
_lcID,
true,
withdrawParams[0],
// what are these 2?
uint256(0),
bytes32(0x0),
Channels[_lcID].partyAddresses[0],
Channels[_lcID].partyAddresses[1],
// withdrawParams[1], // commenting this out because it's determinstic still (balances must add up to total) and getting a stack too deep error
withdrawParams[2],
withdrawParams[3],
withdrawParams[4],
withdrawParams[5],
withdrawParams[6]
)
);

require(Channels[_lcID].partyAddresses[0] == ECTools.recoverSigner(_state, _sigA));
require(Channels[_lcID].partyAddresses[1] == ECTools.recoverSigner(_state, _sigI));

// transfer eth
if(withdrawParams[5] != 0) {
_withdrawalAddress.transfer(withdrawParams[5]);
}

// transfer Tokens
if(withdrawParams[6] != 0) {
require(Channels[_lcID].token.transfer(_withdrawalAddress, withdrawParams[6]), "happyWithdrawlChannel: token transfer failure");
}

// update the new channel as if it just now got created with the current sequence
Channels[_lcID].sequence = withdrawParams[0];
Channels[_lcID].initialDeposit = [withdrawParams[1] + withdrawParams[2], withdrawParams[3] + withdrawParams[4]];



Channels[_lcID].ethBalances = [withdrawParams[1], withdrawParams[2]];
Channels[_lcID].erc20Balances = [withdrawParams[3], withdrawParams[4]];

emit DidLCWithdrawal(
_lcID,
_withdrawalAddress,
withdrawParams[0],
withdrawParams[1],
withdrawParams[2],
withdrawParams[3],
withdrawParams[4],
withdrawParams[5],
withdrawParams[6]
);
}

// 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,
Expand Down