Created
December 21, 2018 17:09
-
-
Save cwhinfrey/a700474f647ffed51c74ec5d6b76300b to your computer and use it in GitHub Desktop.
PaymentChannelPOC.sol
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.24; | |
library ECDSA { | |
/** | |
* @dev Recover signer address from a message by using their signature | |
* @param hash bytes32 message, the hash is the signed message. What is recovered is the signer address. | |
* @param signature bytes signature, the signature is generated using web3.eth.sign() | |
*/ | |
function recover(bytes32 hash, bytes signature) internal pure returns (address) { | |
bytes32 r; | |
bytes32 s; | |
uint8 v; | |
// Check the signature length | |
if (signature.length != 65) { | |
return (address(0)); | |
} | |
// Divide the signature in r, s and v variables | |
// ecrecover takes the signature parameters, and the only way to get them | |
// currently is to use assembly. | |
// solium-disable-next-line security/no-inline-assembly | |
assembly { | |
r := mload(add(signature, 0x20)) | |
s := mload(add(signature, 0x40)) | |
v := byte(0, mload(add(signature, 0x60))) | |
} | |
// Version of signature should be 27 or 28, but 0 and 1 are also possible versions | |
if (v < 27) { | |
v += 27; | |
} | |
// If the version is correct return the signer address | |
if (v != 27 && v != 28) { | |
return (address(0)); | |
} else { | |
// solium-disable-next-line arg-overflow | |
return ecrecover(hash, v, r, s); | |
} | |
} | |
/** | |
* toEthSignedMessageHash | |
* @dev prefix a bytes32 value with "\x19Ethereum Signed Message:" | |
* and hash the result | |
*/ | |
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { | |
// 32 is the length in bytes of hash, | |
// enforced by the type signature above | |
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); | |
} | |
} | |
contract PaymentChannel { | |
using ECDSA for bytes32; | |
uint256 public constant disputePeriod = 1 hours; | |
address public party1; | |
address public party2; | |
mapping(address => uint256) public balances; | |
uint256 public nonce; | |
int256 public delta; | |
bool public isClosed; | |
uint256 public disputePeriodEnd; | |
function() public payable { | |
// Only participants can send ETH | |
require(msg.sender == party1 || msg.sender == party2); | |
require(!isClosed); | |
// Add to balance | |
balances[msg.sender] += msg.value; | |
} | |
function openChannel(address _party1, address _party2) public payable { | |
require(party1 == address(0) && party2 == address(0)); | |
// Set the two participants | |
party1 = _party1; | |
party2 = _party2; | |
// Add to balance is ETH was sent | |
balances[msg.sender] += msg.value; | |
} | |
function resolveChannel(uint256 _nonce, int256 _delta, bytes signature1, bytes signature2) public { | |
// TODO: Check signatures | |
// bytes32 messageHash = keccak256(abi.encodePacked(party1, party2, _nonce, _delta)).toEthSignedMessageHash(); | |
// require(party1 == messageHash.recover(signature1)); | |
// require(party2 == messageHash.recover(signature2)); | |
require(_nonce >= nonce); | |
require(!isClosed); | |
//Start the dispute period if not started | |
if(disputePeriodEnd == 0) { | |
disputePeriodEnd = now + disputePeriod; | |
} else { | |
// Dispute period must not be over | |
require(disputePeriodEnd >= now); | |
} | |
// If nonce is the same, cooperatively close channel | |
if (_nonce == nonce) { | |
isClosed = true; | |
return; | |
} | |
// If nonce is greater, update the nonce and delta | |
nonce = _nonce; | |
delta = _delta; | |
} | |
function withdraw() public { | |
require(disputePeriodEnd != 0); | |
require(isClosed || now > disputePeriodEnd); | |
uint256 value; | |
if (msg.sender == party1) { | |
// Handle positive and negative deltas | |
if (delta >= 0) { | |
value = balances[party1] + uint256(delta); | |
} else { | |
value = balances[party1] - uint256(delta * -1); | |
} | |
party1.transfer(value); | |
} else if (msg.sender == party2) { | |
// Handle positive and negative deltas | |
// A more positive delta means less value for party 2 | |
if (delta >= 0) { | |
value = balances[party2] - uint256(delta); | |
} else { | |
value = balances[party2] + uint256(delta * -1); | |
} | |
party2.transfer(value); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment