@@ -620,4 +620,52 @@ Safe Remote Purchase
620
620
Micropayment Channel
621
621
********************
622
622
623
- To be written.
623
+ ::
624
+
625
+ pragma solidity ^0.4.11;
626
+ contract Channel {
627
+ address[2] users;
628
+ uint deposit;
629
+ uint timeout;
630
+ uint closeTimestamp;
631
+ uint closeSequenceNumber;
632
+ uint closeBalanceUser0;
633
+ enum State { Opened, Accepted, Closing, Closed }
634
+ State state;
635
+ function Channel(address _other, uint _timeout) payable {
636
+ users[0] = msg.sender;
637
+ users[1] = _other;
638
+ deposit = msg.value;
639
+ require(deposit < 2**250);
640
+ require(_timeout < 2 days);
641
+ timeout = _timeout;
642
+ }
643
+ function accept() payable {
644
+ require(msg.sender == users[1]);
645
+ require(msg.value == deposit);
646
+ require(state == State.Opened);
647
+ state = State.Accepted;
648
+ }
649
+ function requestClose(uint _balanceUser0, uint _sequenceNumber, uint8 v, bytes32 r, bytes32 s) {
650
+ require(state == State.Accepted || state == State.Closing);
651
+ require(_sequenceNumber > closeSequenceNumber);
652
+ require(_balanceUser0 <= 2 * deposit);
653
+ require(closeTimestamp == 0 || now <= closeTimestamp + timeout);
654
+ require(ecrecover(sha3(_balanceUser0, _sequenceNumber), v, r, s) == users[_sequenceNumber % 2]);
655
+ closeTimestamp = now;
656
+ closeSequenceNumber = _sequenceNumber;
657
+ closeBalanceUser0 = _balanceUser0;
658
+ state = State.Closing;
659
+ }
660
+ function close()
661
+ {
662
+ // TODO Can we actually include this second condition?
663
+ require(now >= closeTimestamp + timeout || msg.sender == users[(closeSequenceNumber + 1) % 2]);
664
+ require(state == State.Closing || state == State.Closed);
665
+ state = State.Closed;
666
+ if (users[0].send(closeBalanceUser0))
667
+ closeBalanceUser0 = 0;
668
+ if (users[1].send(2 * deposit - closeBalanceUser0))
669
+ deposit = 0;
670
+ }
671
+ }
0 commit comments