├── .gitignore ├── Auction.sol ├── BOLT.sol ├── ERC20.sol ├── ERC621.sol ├── GRID.sol ├── README.md ├── Registry.sol └── TokenChannels.sol /.gitignore: -------------------------------------------------------------------------------- 1 | Migrations.sol 2 | -------------------------------------------------------------------------------- /Auction.sol: -------------------------------------------------------------------------------- 1 | // An auction for bidding on BOLTs that have been sent to the contract. 2 | pragma solidity ^0.4.8; 3 | import "./ERC621.sol"; 4 | 5 | contract Auction { 6 | address private admin; 7 | address public BOLT; 8 | address public GRID; 9 | 10 | struct Period { 11 | mapping (address => uint) bids; 12 | uint bid_period_end; // Time at which the bidding period ends 13 | uint reveal_period_end; // Time at which the reveal period ends 14 | uint high_bid; // Highest currently revealed bid 15 | address high_bidder; // Current highest bidder 16 | } 17 | 18 | mapping (uint => Period) public periods; 19 | uint n; // Current bid number 20 | 21 | 22 | //============================================================================ 23 | // AUCTION FUNCTIONS 24 | //============================================================================ 25 | 26 | // Submit a bid during the bidding window. 27 | function SubmitBid(uint value) { 28 | if (periods[n].bid_period_end < now) { throw; } 29 | ERC621 grid = ERC621(GRID); 30 | if (!grid.transferFrom(msg.sender, address(this), value)) { throw; } 31 | else { 32 | periods[n].bids[msg.sender] = safeAdd(periods[n].bids[msg.sender], value); 33 | } 34 | } 35 | 36 | // Once the reveal period begins, each participant should reveal their bid. 37 | // If the bid is above the current highest, it displaces the 38 | function RevealBid() { 39 | if (periods[n].reveal_period_end < now) { throw; } 40 | else if (periods[n].bids[msg.sender] == 0) { throw; } 41 | else { 42 | // Capture the bid amount 43 | uint bid = periods[n].bids[msg.sender]; 44 | // Zero out the bid 45 | periods[n].bids[msg.sender] = 0; 46 | 47 | if (periods[n].bids[msg.sender] < periods[n].high_bid) { 48 | // If the bid didn't win, refund it 49 | ERC621 grid = ERC621(GRID); 50 | if (!grid.transfer(msg.sender, bid)) { throw; } 51 | } else { 52 | // If the bid can displace the current leader, refund that participant 53 | if (!grid.transfer(periods[n].high_bidder, periods[n].high_bid)) { throw; } 54 | // Replace the bid 55 | periods[n].high_bid = bid; 56 | periods[n].high_bidder = msg.sender; 57 | } 58 | } 59 | } 60 | 61 | // Once the reveal period expires, the winner (publically viewable) 62 | // may claim the reward. 63 | function ClaimReward() { 64 | if (periods[n].reveal_period_end > now) { throw; } 65 | else if (msg.sender != periods[n].high_bidder) { throw; } 66 | else { 67 | // Get the total number of BOLTs held by this contract 68 | ERC621 bolt = ERC621(BOLT); 69 | ERC621 grid = ERC621(GRID); 70 | uint reward = bolt.balanceOf(address(this)); 71 | 72 | // Transfer reward, decrease supply, and reset high bid params. 73 | if (!bolt.transfer(msg.sender, reward)) { throw; } 74 | else if (!grid.decreaseSupply(periods[n].high_bid, periods[n].high_bidder)) { throw; } 75 | else { 76 | periods[n].high_bid = 0; 77 | periods[n].high_bidder = address(0); 78 | } 79 | } 80 | } 81 | 82 | // If the reveal period has elapsed and a participant still has GRID locked up, 83 | // they can still withdraw until the next auction period (and incur a small 84 | // penalty) 85 | function PostRevealWithdraw() { 86 | if (periods[n].reveal_period_end > now) { throw; } 87 | else if (periods[n].bids[msg.sender] == 0) { throw; } 88 | else { 89 | // Capture the bid amount 90 | uint bid = periods[n].bids[msg.sender]; 91 | // Zero out the bid 92 | periods[n].bids[msg.sender] = 0; 93 | ERC621 grid = ERC621(GRID); 94 | 95 | // Penalty of 5% 96 | uint penalty = bid/20; 97 | uint remainder = bid - penalty; 98 | if (!grid.transfer(msg.sender, remainder)) { throw; } 99 | else if (!grid.decreaseSupply(penalty, msg.sender)) { throw; } 100 | } 101 | } 102 | 103 | //============================================================================ 104 | // UTIL 105 | //============================================================================ 106 | 107 | // Get how many seconds are left in the bidding period 108 | function biddingRemaining() public constant returns (uint) { 109 | if (periods[n].bid_period_end <= now) { return 0; } 110 | else { return periods[n].bid_period_end - now; } 111 | } 112 | 113 | // Get how many seconds are left in the reveal period 114 | function revealRemaining() public constant returns (uint) { 115 | if (periods[n].reveal_period_end <= now) { return 0; } 116 | else { return periods[n].reveal_period_end - now; } 117 | } 118 | 119 | // Avoid numerical overflow 120 | function safeAdd(uint a, uint b) internal returns (uint) { 121 | if (a + b < a) throw; 122 | return a + b; 123 | } 124 | 125 | //============================================================================ 126 | // ADMIN FUNCTIONS 127 | //============================================================================ 128 | 129 | // Set a new period to start now. 130 | function NewPeriod(uint bid_end, uint reveal_end) onlyAdmin() { 131 | Period memory period; 132 | period.bid_period_end = bid_end; 133 | period.reveal_period_end = reveal_end; 134 | uint new_n = n + 1; 135 | periods[new_n] = period; 136 | n = new_n; 137 | } 138 | 139 | // Instantiate the Auction contract with GRID and BOLT addresses. 140 | function Auction(address _BOLT, address _GRID) { 141 | admin = msg.sender; 142 | BOLT = _BOLT; 143 | GRID = _GRID; 144 | } 145 | 146 | 147 | modifier onlyAdmin() { 148 | if (msg.sender != admin) { throw; } 149 | _; 150 | } 151 | 152 | function() { throw; } 153 | 154 | 155 | } 156 | -------------------------------------------------------------------------------- /BOLT.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.8; 2 | 3 | import "./ERC621.sol"; 4 | 5 | contract BOLT is ERC621 { 6 | 7 | mapping (address => bool) admins; // Mapping of who is an admin 8 | 9 | 10 | //============================================================================ 11 | // ERC20 12 | //============================================================================ 13 | 14 | mapping( address => uint ) balances; 15 | mapping( address => mapping( address => uint ) ) approvals; 16 | uint public supply; 17 | string public name; 18 | uint8 public decimals; 19 | string public symbol; 20 | string public version; 21 | 22 | function BOLT( uint _supply, string _name, uint8 _decimals, string _symbol, string _version ) { 23 | balances[msg.sender] = _supply; 24 | supply = _supply; 25 | name = _name; 26 | decimals = _decimals; 27 | symbol = _symbol; 28 | version = _version; 29 | admins[msg.sender] = true; 30 | } 31 | 32 | function totalSupply() constant returns (uint) { 33 | return supply; 34 | } 35 | 36 | function balanceOf( address who ) constant returns (uint) { 37 | return balances[who]; 38 | } 39 | 40 | function transfer( address to, uint value) returns (bool) { 41 | balances[msg.sender] = safeSub(balances[msg.sender], value); 42 | balances[to] = safeAdd(balances[to], value); 43 | Transfer( msg.sender, to, value ); 44 | return true; 45 | } 46 | 47 | function transferFrom( address from, address to, uint value) returns (bool) { 48 | approvals[from][msg.sender] = safeSub(approvals[from][msg.sender], value); 49 | balances[from] = safeSub(balances[from], value); 50 | balances[to] = safeAdd(balances[to], value); 51 | Transfer( from, to, value ); 52 | return true; 53 | } 54 | 55 | function approve(address spender, uint value) returns (bool) { 56 | approvals[msg.sender][spender] = value; 57 | Approval( msg.sender, spender, value ); 58 | return true; 59 | } 60 | 61 | function allowance(address owner, address spender) constant returns (uint) { 62 | return approvals[owner][spender]; 63 | } 64 | 65 | //============================================================================ 66 | // ADMIN + SUPPLY FUNCTIONS 67 | //============================================================================ 68 | 69 | function addAdmin(address new_admin) onlyAdmins() { 70 | admins[new_admin] = true; 71 | } 72 | 73 | function removeAdmin(address old_admin) onlyAdmins() { 74 | admins[old_admin] = false; 75 | } 76 | 77 | function increaseSupply(uint value, address to) onlyAdmins() returns (bool) { 78 | supply = safeAdd(supply, value); 79 | balances[to] = safeAdd(balances[to], value); 80 | Transfer(0, to, value); 81 | } 82 | 83 | function decreaseSupply(uint value, address from) onlyAdmins() returns (bool) { 84 | balances[from] = safeSub(balances[from], value); 85 | supply = safeSub(supply, value); 86 | Transfer(from, 0, value); 87 | } 88 | 89 | 90 | //============================================================================ 91 | // SAFE MATH FUNCTIONS 92 | //============================================================================ 93 | 94 | function safeToAdd(uint a, uint b) internal returns (bool) { 95 | return (a + b >= a); 96 | } 97 | 98 | function safeAdd(uint a, uint b) internal returns (uint) { 99 | if (!safeToAdd(a, b)) throw; 100 | return a + b; 101 | } 102 | 103 | function safeToSubtract(uint a, uint b) internal returns (bool) { 104 | return (b <= a); 105 | } 106 | 107 | function safeSub(uint a, uint b) internal returns (uint) { 108 | if (!safeToSubtract(a, b)) throw; 109 | return a - b; 110 | } 111 | 112 | 113 | modifier onlyAdmins() { 114 | if (admins[msg.sender] != true) { throw; } 115 | _; 116 | } 117 | 118 | function() { throw; } 119 | } 120 | -------------------------------------------------------------------------------- /ERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.8; 2 | 3 | contract ERC20 { 4 | 5 | // Events 6 | event Transfer(address indexed from, address indexed to, uint value); 7 | event Approval( address indexed owner, address indexed spender, uint value); 8 | 9 | // Stateless functions 10 | function totalSupply() constant returns (uint supply); 11 | function balanceOf( address who ) constant returns (uint value); 12 | function allowance(address owner, address spender) constant returns (uint value); 13 | 14 | // Stateful functions 15 | function transfer( address to, uint value) returns (bool ok); 16 | function transferFrom( address from, address to, uint value) returns (bool ok); 17 | function approve(address spender, uint value) returns (bool ok); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /ERC621.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.8; 2 | 3 | contract ERC621 { 4 | 5 | // Events 6 | event Transfer(address indexed from, address indexed to, uint value); 7 | event Approval( address indexed owner, address indexed spender, uint value); 8 | 9 | // Stateless functions 10 | function totalSupply() constant returns (uint supply); 11 | function balanceOf( address who ) constant returns (uint value); 12 | function allowance(address owner, address spender) constant returns (uint value); 13 | 14 | // Stateful functions 15 | function transfer( address to, uint value) returns (bool ok); 16 | function transferFrom( address from, address to, uint value) returns (bool ok); 17 | function approve(address spender, uint value) returns (bool ok); 18 | 19 | // Admin only functions 20 | function increaseSupply(uint value, address to) returns (bool ok); 21 | function decreaseSupply(uint value, address from) returns (bool ok); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /GRID.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.8; 2 | 3 | import "./ERC621.sol"; 4 | 5 | contract GRID is ERC621 { 6 | 7 | mapping (address => bool) admins; // Mapping of who is an admin 8 | 9 | 10 | //============================================================================ 11 | // ERC20 12 | //============================================================================ 13 | 14 | mapping( address => uint ) balances; 15 | mapping( address => mapping( address => uint ) ) approvals; 16 | uint public supply; 17 | string public name; 18 | uint8 public decimals; 19 | string public symbol; 20 | string public version; 21 | 22 | function GRID( uint _supply, string _name, uint8 _decimals, string _symbol, string _version ) { 23 | balances[msg.sender] = _supply; 24 | supply = _supply; 25 | name = _name; 26 | decimals = _decimals; 27 | symbol = _symbol; 28 | version = _version; 29 | admins[msg.sender] = true; 30 | } 31 | 32 | function totalSupply() constant returns (uint) { 33 | return supply; 34 | } 35 | 36 | function balanceOf( address who ) constant returns (uint) { 37 | return balances[who]; 38 | } 39 | 40 | function transfer( address to, uint value) returns (bool) { 41 | balances[msg.sender] = safeSub(balances[msg.sender], value); 42 | balances[to] = safeAdd(balances[to], value); 43 | Transfer( msg.sender, to, value ); 44 | return true; 45 | } 46 | 47 | function transferFrom( address from, address to, uint value) returns (bool) { 48 | approvals[from][msg.sender] = safeSub(approvals[from][msg.sender], value); 49 | balances[from] = safeSub(balances[from], value); 50 | balances[to] = safeAdd(balances[to], value); 51 | Transfer( from, to, value ); 52 | return true; 53 | } 54 | 55 | function approve(address spender, uint value) returns (bool) { 56 | approvals[msg.sender][spender] = value; 57 | Approval( msg.sender, spender, value ); 58 | return true; 59 | } 60 | 61 | function allowance(address owner, address spender) constant returns (uint) { 62 | return approvals[owner][spender]; 63 | } 64 | 65 | //============================================================================ 66 | // ADMIN + SUPPLY FUNCTIONS 67 | //============================================================================ 68 | 69 | function addAdmin(address new_admin) onlyAdmins() { 70 | admins[new_admin] = true; 71 | } 72 | 73 | function removeAdmin(address old_admin) onlyAdmins() { 74 | admins[old_admin] = false; 75 | } 76 | 77 | function increaseSupply(uint value, address to) onlyAdmins() returns(bool) { 78 | supply = safeAdd(supply, value); 79 | balances[to] = safeAdd(balances[to], value); 80 | Transfer(0, to, value); 81 | return true; 82 | } 83 | 84 | function decreaseSupply(uint value, address from) onlyAdmins() returns(bool) { 85 | balances[from] = safeSub(balances[from], value); 86 | supply = safeSub(supply, value); 87 | Transfer(from, 0, value); 88 | return true; 89 | } 90 | 91 | 92 | //============================================================================ 93 | // SAFE MATH FUNCTIONS 94 | //============================================================================ 95 | 96 | function safeToAdd(uint a, uint b) internal returns (bool) { 97 | return (a + b >= a); 98 | } 99 | 100 | function safeAdd(uint a, uint b) internal returns (uint) { 101 | if (!safeToAdd(a, b)) throw; 102 | return a + b; 103 | } 104 | 105 | function safeToSubtract(uint a, uint b) internal returns (bool) { 106 | return (b <= a); 107 | } 108 | 109 | function safeSub(uint a, uint b) internal returns (uint) { 110 | if (!safeToSubtract(a, b)) throw; 111 | return a - b; 112 | } 113 | 114 | 115 | modifier onlyAdmins() { 116 | if (admins[msg.sender] != true) { throw; } 117 | _; 118 | } 119 | 120 | function() { throw; } 121 | } 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Contracts 2 | Smart contracts for the Grid+ Platform. 3 | 4 | ## Registry.sol 5 | The registry contract. Grid+ holds administrator privilege and whitelists 6 | agent setup keys by mapping them to hashed serial numbers (generated by Grid+). 7 | Upon setup, the client [generates](https://github.com/GridPlus/client/blob/master/init/main.go#L71) a new wallet key and [replaces](https://github.com/GridPlus/client/blob/master/src/rpc/eth.go#L98) the setup key 8 | on this registry. 9 | The owner also claims ownership of this new wallet key by querying the agent over 10 | a local area network. 11 | 12 | ## USDX.sol 13 | A standard ERC20 token that is used to pay bills. This will be backed by USD. 14 | 15 | ## ERC20.sol 16 | A representation of the ERC20 standard used as a base class for all tokens. 17 | -------------------------------------------------------------------------------- /Registry.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.8; 2 | 3 | contract Registry { 4 | address private admin; 5 | mapping (bytes32 => address) private registry; // Maps a serial number hash to its setup address (later wallet) 6 | mapping (bytes32 => address) private owners; // Maps the serial hash to the owner 7 | /*event Register(bytes32 indexed serial_hash, uint timestamp); 8 | event Wallet(address indexed agent, address indexed wallet, uint timestamp); 9 | event Claim(bytes32 indexed serial_hash, address indexed owner, uint timestamp);*/ 10 | 11 | function Registry() { 12 | admin = msg.sender; 13 | } 14 | 15 | // OWNER only 16 | // ========================= 17 | 18 | function transferAdmin(address new_admin) isAdmin() returns (bool) { 19 | admin = new_admin; 20 | return true; 21 | } 22 | 23 | // Register a agent address. This can only be called by the admin. 24 | // This must be called before a agent is turned online. 25 | // The serial hash is a keccak_256 hash of the serial number. 26 | function register(address agent, bytes32 serial_hash) isAdmin() returns (bool) { 27 | if (registry[serial_hash] != address(0)) { throw; } 28 | registry[serial_hash] = agent; 29 | /*Register(serial_hash, now);*/ 30 | return true; 31 | } 32 | 33 | // SETTERS 34 | // ========================= 35 | 36 | // Set a wallet for a given agent. Must be called by the setup key. 37 | // 38 | // This will overwrite all functionality for the setup key and essentially transfer 39 | // all agency to the new wallet key. 40 | function setWallet(address wallet, bytes32 serial_hash) public returns (bool) { 41 | if (registry[serial_hash] == address(0)) { throw; } 42 | else if (registry[serial_hash] != msg.sender) { throw;} 43 | // Transfer registration to the new wallet 44 | registry[serial_hash] = wallet; 45 | /*Wallet(msg.sender, wallet, now);*/ 46 | return true; 47 | } 48 | 49 | // Claim ownership of an agent with a verifiable keccak_256 hash of the serial number. 50 | // The agent must be registered and may not have been claimed by anyone else. 51 | // 52 | // A wallet key must also have been set. That wallet key is what is being claimed. 53 | function claim(bytes32 serial_hash) public returns (bool) { 54 | if (registry[serial_hash] == address(0)) { throw; } 55 | else if (owners[serial_hash] != address(0)) { throw; } 56 | owners[serial_hash] = msg.sender; 57 | /*Claim(serial_hash, msg.sender, now);*/ 58 | return true; 59 | } 60 | 61 | // PUBLIC constant functions 62 | // ========================= 63 | 64 | // Check if the agent is registered. 65 | function registered(bytes32 serial_hash) public constant returns (bool) { 66 | if (registry[serial_hash] == address(0)) { return false; } 67 | return true; 68 | } 69 | 70 | // Check if the agent has been claimed 71 | function claimed(bytes32 serial_hash) public constant returns (bool) { 72 | if (registry[serial_hash] == address(0)) { return false; } 73 | else if (owners[serial_hash] == address(0)) { return false; } 74 | else { return true; } 75 | } 76 | 77 | // Check if a specific address is mapped to the serial hash 78 | function check_registry(bytes32 serial_hash, address registrant) public constant returns (bool) { 79 | if (registry[serial_hash] == registrant) { return true; } 80 | return false; 81 | } 82 | 83 | // Check if a specific owner is mapped to the serial hash 84 | function check_owner(bytes32 serial_hash, address owner) public constant returns (bool) { 85 | if (owners[serial_hash] == owner) { return true; } 86 | return false; 87 | } 88 | 89 | // Given an owner and a serial_hash, get the wallet address 90 | function get_owner_wallet(bytes32 serial_hash, address owner) public constant returns (address) { 91 | if (owners[serial_hash] != owner) { throw; } 92 | return registry[serial_hash]; 93 | } 94 | 95 | // Check if an address is the admin 96 | function checkAdmin(address addr) public constant returns (bool) { 97 | if (admin == addr) { return true; } 98 | else { return false; } 99 | } 100 | 101 | 102 | // MODIFIERS 103 | // ========================== 104 | modifier isAdmin() { 105 | if (msg.sender != admin) { throw; } 106 | _; 107 | } 108 | 109 | function() { throw; } 110 | } 111 | -------------------------------------------------------------------------------- /TokenChannels.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.8; 2 | import "./ERC20.sol"; 3 | 4 | contract TokenChannels { 5 | 6 | //============================================================================ 7 | // GLOBAL VARIABLES 8 | //============================================================================ 9 | 10 | struct Channel { 11 | address sender; 12 | address recipient; 13 | address token; 14 | uint deposit; 15 | } 16 | mapping (address => uint) balances; 17 | 18 | mapping (bytes32 => Channel) channels; 19 | mapping (address => mapping(address => bytes32)) active_ids; 20 | 21 | 22 | //============================================================================ 23 | // STATE TRANSITION FUNCTIONS 24 | //============================================================================ 25 | 26 | /** 27 | * Open a channel with a recipient. A non-zero message value must be included. 28 | * 29 | * address token Address of token contract 30 | * address to Address of recipient 31 | * uint amount Number of token quanta to send 32 | */ 33 | function OpenChannel(address token, address to, uint amount) { 34 | // Sanity checks 35 | if (amount == 0) { throw; } 36 | if (to == msg.sender) { throw; } 37 | if (active_ids[msg.sender][to] != bytes32(0)) { throw; } 38 | 39 | // Create a channel 40 | bytes32 id = sha3(msg.sender, to, now); 41 | 42 | // Initialize the channel 43 | Channel memory _channel; 44 | _channel.deposit = amount; 45 | _channel.sender = msg.sender; 46 | _channel.recipient = to; 47 | _channel.token = token; 48 | 49 | // Make the deposit 50 | ERC20 t = ERC20(token); 51 | if (!t.transferFrom(msg.sender, address(this), amount)) { throw; } 52 | 53 | channels[id] = _channel; 54 | 55 | // Add it to the lookup table 56 | active_ids[msg.sender][to] = id; 57 | } 58 | 59 | 60 | /** 61 | * Close a channel at any time. May only be called by sender or recipient. 62 | * The "value" is sent to the recipient and the remainder is refunded to the sender. 63 | * 64 | * bytes32 id Identifier of "channels" mapping 65 | * bytes32 h [ id, msg_hash, r, s ] 66 | * uint8 v Component of signature of "h" coming from sender 67 | * bytes32 r Component of signature of "h" coming from sender 68 | * bytes32 s Component of signature of "h" coming from sender 69 | * uint value Amount of wei sent 70 | */ 71 | function CloseChannel(bytes32[4] h, uint8 v, uint256 value) { 72 | // h[0] Channel id 73 | // h[1] Hash of (id, value) 74 | // h[2] r of signature 75 | // h[3] s of signature 76 | 77 | // Grab the channel in question 78 | if (channels[h[0]].deposit == 0) { throw; } 79 | Channel memory _channel; 80 | _channel = channels[h[0]]; 81 | 82 | if (msg.sender != _channel.sender && msg.sender != _channel.recipient) { throw; } 83 | 84 | address signer = ecrecover(h[1], v, h[2], h[3]); 85 | if (signer != _channel.sender) { throw; } 86 | 87 | // Make sure the hash provided is of the channel id and the amount sent 88 | bytes32 proof = sha3(h[0], value); 89 | // Ensure the proof matches, send the value, send the remainder, and delete the channel 90 | if (proof != h[1]) { throw; } 91 | else if (value > _channel.deposit) { throw; } 92 | 93 | // Pay recipient and refund sender the remainder 94 | ERC20 t = ERC20(_channel.token); 95 | if (!t.transfer(_channel.recipient, value)) { throw; } 96 | else if (!t.transfer(_channel.sender, _channel.deposit-value)) { throw; } 97 | 98 | // Close the channel 99 | delete channels[h[0]]; 100 | delete active_ids[_channel.sender][_channel.recipient]; 101 | 102 | } 103 | 104 | //============================================================================ 105 | // CONSTANT FUNCTIONS 106 | //============================================================================ 107 | 108 | /** 109 | * Verify that a message sent will allow the channel to close. 110 | * Parameters are the same as for CloseChannel 111 | */ 112 | function VerifyMsg(bytes32[4] h, uint8 v, uint256 value) public constant returns (bool) { 113 | // h[0] Channel id 114 | // h[1] Hash of (id, value) 115 | // h[2] r of signature 116 | // h[3] s of signature 117 | 118 | // Grab the channel in question 119 | if (channels[h[0]].deposit == 0) { return false; } 120 | Channel memory _channel; 121 | _channel = channels[h[0]]; 122 | 123 | // https://ethereum.stackexchange.com/a/15911/1391 124 | // TODO put this logic into JS 125 | address signer = ecrecover(h[1], v, h[2], h[3]); 126 | if (signer != _channel.sender) { return false; } 127 | 128 | // Make sure the hash provided is of the channel id and the amount sent 129 | bytes32 proof = sha3(h[0], value); 130 | // Ensure the proof matches, send the value, send the remainder, and delete the channel 131 | if (proof != h[1]) { return false; } 132 | else if (value > _channel.deposit) { return false; } 133 | 134 | return true; 135 | } 136 | 137 | // GETTERS 138 | 139 | function GetChannelId(address from, address to) public constant returns (bytes32) { 140 | return active_ids[from][to]; 141 | } 142 | 143 | function GetDeposit(bytes32 id) public constant returns (uint) { 144 | return channels[id].deposit; 145 | } 146 | 147 | function GetSender(bytes32 id) public constant returns (address) { 148 | return channels[id].sender; 149 | } 150 | 151 | function GetRecipient(bytes32 id) public constant returns (address) { 152 | return channels[id].recipient; 153 | } 154 | 155 | function GetToken(bytes32 id) public constant returns (address) { 156 | return channels[id].token; 157 | } 158 | 159 | function() { throw; } 160 | 161 | } 162 | --------------------------------------------------------------------------------