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
103 changes: 55 additions & 48 deletions channel.sol
Original file line number Diff line number Diff line change
@@ -1,51 +1,58 @@
pragma solidity ^0.4.0;
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Channel {

address public channelSender;
address public channelRecipient;
uint public startDate;
uint public channelTimeout;
mapping (bytes32 => address) signatures;

function Channel(address to, uint timeout) payable {
channelRecipient = to;
channelSender = msg.sender;
startDate = now;
channelTimeout = timeout;
}

function CloseChannel(bytes32 h, uint8 v, bytes32 r, bytes32 s, uint value){

address signer;
bytes32 proof;

// get signer from signature
signer = ecrecover(h, v, r, s);

// signature is invalid, throw
if (signer != channelSender && signer != channelRecipient) throw;

proof = sha3(this, value);

// signature is valid but doesn't match the data provided
if (proof != h) throw;

if (signatures[proof] == 0)
signatures[proof] = signer;
else if (signatures[proof] != signer){
// channel completed, both signatures provided
if (!channelRecipient.send(value)) throw;
selfdestruct(channelSender);
}

}

function ChannelTimeout(){
if (startDate + channelTimeout > now)
throw;

selfdestruct(channelSender);
}

address public channelSender;
address public channelRecipient;
uint public startDate;
uint public channelDuration;
uint public channelMargin;
bytes32 public channelTip;
bool public isActive;

constructor(address to, uint timeout, uint margin, bytes32 tip) payable {
channelRecipient = to;
channelSender = msg.sender;
startDate = block.timestamp;
channelDuration = timeout;
channelMargin = margin;
channelTip = tip;
isActive = true;
}

modifier onlyActive() {
require(isActive, "Channel is not active.");
_;
}

function closeChannel(bytes32 _word, uint8 _wordCount) public onlyActive {
require(msg.sender == channelRecipient, "Only the recipient can close the channel.");
bytes32 wordScratch = _word;
for (uint i = 1; i <= _wordCount; i++) {
wordScratch = keccak256(abi.encodePacked(wordScratch));
}

require(wordScratch == channelTip, "Invalid word or word count.");
(bool sent, ) = channelRecipient.call{value: _wordCount * channelMargin}("");
require(sent, "Failed to send Ether");
deactivate();
}

function expireChannel() public onlyActive {
require(block.timestamp >= startDate + channelDuration, "Channel timeout has not been reached.");
deactivate();
}

function deactivate() private {
isActive = false;
uint balance = address(this).balance;
if (balance > 0) {
(bool sent, ) = channelSender.call{value: balance}("");
require(sent, "Failed to return remaining Ether to sender");
}
}

receive() external payable {}

fallback() external payable {}
}