Created
September 14, 2017 17:02
-
-
Save kidwai/0f980cfcf4ab8f8febc6419532ef12b1 to your computer and use it in GitHub Desktop.
A rough sketch of a token library. There are probably problems.
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
/** | |
* A simple example of a token sale that makes use of a library with | |
* a simple transfer function and a token struct. This is a biased implementation | |
* that mimics the types of operations found in most current token implementations. | |
* The purpose is only to illustrate the idea. This is nothing novel and turns out | |
* to be very similar to work by Open Zeppelin (https://blog.aragon.one/library-driven-development-in-solidity-2bebcaf88736). | |
* | |
* This can be generalized to support multiple sales or auctions. Questions surrounding issuance | |
* structure and governance are imperative, no different from ERC20 tokens. | |
* | |
* Elements of approval are omitted for the moment for simplicity. | |
**/ | |
pragma solidity ^0.4.11; | |
library TokenLib { | |
// Some basic properties found in token contracts. | |
// The debatable "admin" property is made only to reflect current | |
// implementation. This is not necessarily the most trustless design. | |
struct Token { | |
address admin; | |
uint256 total_supply; | |
mapping (address => uint256) balances; | |
Sale sale; | |
} | |
struct Sale { | |
uint256 start_block; | |
uint256 end_block; | |
uint256 price; | |
} | |
/** | |
* @dev Initializes a token struct's properties. | |
* @param self A token struct - passed as first argument by default when called through a token struct [e.g. tokenInstance.init(..) ] | |
* @param admin The 'admin', the address responsible for issuing administrative transactions. This is explicitly provided to allow for the use of a multisignature contract. | |
* @param total_supply The total supply of tokens. | |
* @param founders The addresses of the founders. | |
* @param allocations The allocations to the respective founders. | |
* @param sale_start The block at which to commence the token sale. | |
* @param sale_end The block at which to end the sale. | |
* @param sale_price The price at which to sell the token. | |
**/ | |
function init ( | |
Token storage self, | |
address admin, | |
uint256 total_supply, | |
address[] founders, | |
uint256[] allocations, | |
uint256 sale_start, | |
uint256 sale_end, | |
uint256 sale_price | |
) onlyUninitialized (self) { | |
self.admin = admin; // set the token's admin address | |
// a sample of basic properties of a token | |
self.total_supply = total_supply; | |
self.sale.start_block = sale_start; | |
self.sale.end_block = sale_end; | |
self.sale.price = sale_price; | |
// give founders their hard-earned money | |
for (uint8 i = 0 ; i < founders.length; i++) { | |
self.balances[founders[i]] = allocations[i]; | |
} | |
} | |
/** | |
* @dev Buy a quantity of tokens when on sale based on the transaction value. | |
* @param self The token struct on which to operate. | |
**/ | |
function buy ( | |
Token storage self | |
) onSale(self) { | |
self.balances[msg.sender] += msg.value/self.sale.price; | |
} | |
// Transfer '_value' tokens to the address '_to'. | |
function transfer ( | |
Token storage self, | |
address _to, | |
uint256 _value | |
) onlyInitialized (self) | |
{ | |
require(self.balances[msg.sender] >= _value); | |
self.balances[msg.sender] -= _value; | |
self.balances[_to] += _value; | |
Transfer(msg.sender, _to, _value); | |
} | |
function balanceOf (Token storage self, address _addr) constant returns (uint256) { | |
return self.balances[_addr]; | |
} | |
// checks if a token is on sale | |
modifier onSale (Token token) { | |
require (token.sale.start_block <= block.number && block.number < token.sale.end_block); | |
_; | |
} | |
modifier onlyUninitialized (Token token) { | |
require (token.admin == 0); | |
_; | |
} | |
modifier onlyInitialized (Token token) { | |
require (token.admin != 0); | |
_; | |
} | |
event Transfer (address indexed from, address to, uint256 value); | |
} | |
// A simple example of a sale of 100 coins at 1000 Wei / coin | |
contract FooCoin { | |
using TokenLib for TokenLib.Token; | |
TokenLib.Token token; | |
function FooCoin ( | |
address[] founders, | |
uint256[] allocations | |
) { | |
token.init(msg.sender, | |
100, | |
founders, | |
allocations, | |
block.number + 10, | |
block.number + 20, | |
1000); | |
} | |
function balanceOf (address _addr) constant returns (uint256) { | |
// use the library implementation | |
return token.balanceOf(_addr); | |
} | |
function transfer (address _to, uint256 _value) | |
{ | |
return token.transfer(_to, _value); | |
} | |
function () payable { | |
// use the library implementation | |
token.buy(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I like it a lot and agree that it's non-ideal that so much "standard" logic is being duplicated on chain.
A few questions/observations:
approve()
are missing, but given this is just meant a proof of concept it's great.