Created
June 25, 2017 09:23
-
-
Save Arachnid/34b2d6458aed15cdddad3ba112b97c85 to your computer and use it in GitHub Desktop.
This file contains 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.10; | |
import "IERC20Token.sol"; | |
/** | |
* The problem: Handing out tokens is problematic, because the receiving account | |
* also needs enough ether to send a transaction transferring the tokens to the | |
* user's account. | |
* | |
* The solution: Send the tokens to a 'checking account'. The recipient of the | |
* tokens can claim them from the account by writing a 'cheque' - a signed | |
* message authorising transfer of the tokens to a different account. | |
* | |
* Issuing: | |
* 1. Generate a series of accounts (eg, using a mnemonic generator) | |
* 2. Add an ERC20 authorisation for the TokenCheckingAccount contract | |
* sufficient to cover the number of tokens being distributed. | |
* 4. Call TokenCheckingAccount.deposit() with the list of account addresses, | |
* the ERC20 token address, and the number of tokens to allocate to each address. | |
* | |
* Redeeming: | |
* 1. Have the user sign a message consisting of | |
* (checking_account_address, token_address, recipient). | |
* 2. From any account, call `TokenCheckingAccount.redeemFor` or | |
* `TokenCodeRedeemer.redeem` with the ERC20 token address, the recipient | |
* (optional), and the signature from step 1. | |
*/ | |
contract TokenCheckingAccount { | |
event TokensDeposited(address indexed token, address indexed owner, uint quantity); | |
event TokensRedeemed(address indexed token, address indexed owner, address indexed recipient, uint quantity); | |
// (erc20 address => (owner => balance)) | |
mapping(address=>mapping (address=>uint)) public balances; | |
/** | |
* @dev Credits tokens to a list of checking accounts. The caller must first | |
* provide this contract with an allowance equal to the required | |
* number of tokens. | |
* @param token The address of the token contract. | |
* @param addresses The list of addresses to credit tokens to. | |
* @param quantity The number of tokens to issue to each address. | |
*/ | |
function deposit(IERC20Token token, address[] addresses, uint quantity) { | |
// Transfer the required number of tokens to us | |
require(token.transferFrom(msg.sender, this, quantity * addresses.length)); | |
for(var i = 0; i < addresses.length; i++) { | |
var addr = addresses[i]; | |
balances[token][addr] += quantity; | |
TokensDeposited(token, addr, quantity); | |
} | |
} | |
/** | |
* @dev Redeems a 'cheque', transferring the tokens owned by an account to | |
* a new address. | |
* @param recipient The address to send the tokens to. | |
* @param token The address of the token being redeemed. | |
* @param v (r, s) The ECDSA signature from a valid account address authorising | |
* the transfer. | |
*/ | |
function redeemFor(IERC20Token token, address recipient, uint8 v, bytes32 r, bytes32 s) { | |
var addr = ecrecover(sha3(address(this), recipient, token), v, r, s); | |
var quantity = balances[token][addr]; | |
require(quantity > 0); | |
delete balances[token][addr]; | |
TokensRedeemed(token, addr, recipient, quantity); | |
require(token.transfer(recipient, quantity)); | |
} | |
/** | |
* @dev Redeems a 'cheque', sending the tokens to the caller. | |
* @param token The address of the token being redeemed. | |
* @param v (r, s) The ECDSA signature from a valid account address authorising | |
* the transfer. | |
*/ | |
function redeem(IERC20Token token, uint8 v, bytes32 r, bytes32 s) { | |
redeemFor(token, msg.sender, v, r, s); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment