Aaron Bloomfield (aaron@virginia.edu) @github | ↑ |
pragma solidity ^0.4.24; import "zeppelin-solidity/contracts/math/SafeMath.sol"; import "zeppelin-solidity/contracts/ECRecovery.sol"; /** * @title SimplePaymentChannel * @author Eric Olszewski (eolszewski@gmail.com) * * @dev Ethereum payment channels allow for off-chain transactions with an on-chain * settlement. In this implementation, a party (sender) can open a channel with a * deposit, expiration, and recipient. The sender can then sign transactions off-chain * and send them to the recipient, who can submit one of these signed transactions to * chain to close and settle the channel. */ contract SimplePaymentChannel { using SafeMath for uint256; using ECRecovery for bytes32; event ChannelOpened(address sender, address recipient, uint expiration, uint256 deposit); event ChannelClosed(uint256 senderBalance, uint256 recipientBalance); address public sender; address public recipient; uint256 public expiration; constructor(address _recipient, uint256 _duration) public payable { require(msg.value > 0); require(msg.sender != _recipient); sender = msg.sender; recipient = _recipient; expiration = now + _duration; emit ChannelOpened(sender, recipient, expiration, msg.value); } function closeChannel(uint256 _balance, bytes _signedMessage) public { require(msg.sender == recipient); require(isValidSignature(_balance, _signedMessage)); uint256 balance = _balance; uint256 remainder = 0; if (_balance > address(this).balance) { balance = address(this).balance; } else { remainder = address(this).balance.sub(balance); } recipient.transfer(balance); emit ChannelClosed(remainder, balance); selfdestruct(sender); } function extendExpiration(uint256 _expiration) public { require(msg.sender == sender); require(_expiration > expiration); expiration = _expiration; } function claimTimeout() public { require(now >= expiration); selfdestruct(sender); } function isValidSignature(uint256 _balance, bytes _signedMessage) internal view returns (bool) { bytes32 message = prefixed(keccak256(abi.encodePacked(address(this), _balance))); return message.recover(_signedMessage) == sender; } function prefixed(bytes32 _hash) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _hash)); } }
/** * @brief C-based Helloworld BPF program */ #include <solana_sdk.h> uint64_t helloworld(SolParameters *params) { if (params->ka_num < 1) { sol_log("Greeted account not included in the instruction"); return ERROR_NOT_ENOUGH_ACCOUNT_KEYS; } // Get the account to say hello to SolAccountInfo *greeted_account = & params->ka[0]; // The account must be owned by the program in order to modify its data if (!SolPubkey_same(greeted_account->owner, params->program_id)) { sol_log("Greeted account does not have the correct program id"); return ERROR_INCORRECT_PROGRAM_ID; } // The data must be large enough to hold an uint32_t value if (greeted_account->data_len < sizeof(uint32_t)) { sol_log("Greeted account data length too small to hold uint32_t value"); return ERROR_INVALID_ACCOUNT_DATA; } // Increment and store the number of times the account has been greeted uint32_t *num_greets = (uint32_t *)greeted_account->data; *num_greets += 1; sol_log("Hello!"); return SUCCESS; } extern uint64_t entrypoint(const uint8_t *input) { sol_log("Helloworld C program entrypoint"); SolAccountInfo accounts[1]; SolParameters params = (SolParameters){.ka = accounts}; if (!sol_deserialize(input, & params, SOL_ARRAY_SIZE(accounts))) { return ERROR_INVALID_ARGUMENT; } return helloworld(& params); } //