a) I should be able to create the token conveniently without too much programming involved
You could try using the source code from the MiniMe token contract, my TestERC20Token or one of the main tokens one issue Supported-ERC20-Tokens that is supported by the https://cryptoderivatives.market/ decentralised exchange.
For the easiest deployment, run Ethereum Wallet, select the Contracts tab, click on Deploy New Contract, paste your source code into the Solidity Contract Source Code box, click Deploy and confirm the transaction with your password.
Then ideally, find the newly deployed contract using https://etherscan.io/ and source code verify the deployed bytecode - see
Problem verifying source code on Etherscan
for the steps to do this.
Here's a simple token with the owner's + 10 addresses pre-allocated:
pragma solidity ^0.4.8;
// ----------------------------------------------------------------------------------------------
// Basic ERC20 Token Contract. Don't use for any high value contracts without a lot more
// security testing
//
// Enjoy. (c) BokkyPooBah 2017. The MIT Licence.
// ----------------------------------------------------------------------------------------------
// ERC Token Standard #20 Interface
// https://github.com/ethereum/EIPs/issues/20
contract ERC20Interface {
// Get the total token supply
function totalSupply() constant returns (uint256 totalSupply);
// Get the account balance of another account with address _owner
function balanceOf(address _owner) constant returns (uint256 balance);
// Send _value amount of tokens to address _to
function transfer(address _to, uint256 _value) returns (bool success);
// Send _value amount of tokens from address _from to address _to
// The transferFrom method is used for a withdraw workflow, allowing contracts to send
// tokens on your behalf, for example to "deposit" to a contract address and/or to charge
// fees in sub-currencies; the command should fail unless the _from account has
// deliberately authorized the sender of the message via some mechanism; we propose
// these standardized APIs for approval:
function transferFrom(address _from, address _to, uint256 _value) returns (bool success);
// Allow _spender to withdraw from your account, multiple times, up to the _value amount.
// If this function is called again it overwrites the current allowance with _value.
function approve(address _spender, uint256 _value) returns (bool success);
// Returns the amount which _spender is still allowed to withdraw from _owner
function allowance(address _owner, address _spender) constant returns (uint256 remaining);
// Triggered when tokens are transferred.
event Transfer(address indexed _from, address indexed _to, uint256 _value);
// Triggered whenever approve(address _spender, uint256 _value) is called.
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
contract BokkyPooBahTestToken is ERC20Interface {
string public name;
string public symbol;
uint8 public decimals;
// Owner of this contract
address public owner;
// Balances for each account
mapping(address => uint256) balances;
// Owner of account approves the transfer of an amount to another account
mapping(address => mapping (address => uint256)) allowed;
// Total supply
uint256 _totalSupply;
// Functions with this modifier can only be executed by the owner
modifier onlyOwner() {
if (msg.sender != owner) {
throw;
}
_;
}
// Constructor
function BokkyPooBahTestToken() {
owner = msg.sender;
name = "BokkyPooBahTest";
symbol = "BPBT☺";
decimals = 18;
// 1 million with 18 decimal places
_totalSupply = 1000000000000000000000000;
balances[owner] = _totalSupply * 50 / 100;
balances[0x00001009bd8f0b1301cc5edc28ed1222a3ce671e] = _totalSupply * 5 / 100;
balances[0x00011009bd8f0b1301cc5edc28ed1222a3ce671e] = _totalSupply * 5 / 100;
balances[0x00021009bd8f0b1301cc5edc28ed1222a3ce671e] = _totalSupply * 5 / 100;
balances[0x00031009bd8f0b1301cc5edc28ed1222a3ce671e] = _totalSupply * 5 / 100;
balances[0x00041009bd8f0b1301cc5edc28ed1222a3ce671e] = _totalSupply * 5 / 100;
balances[0x00051009bd8f0b1301cc5edc28ed1222a3ce671e] = _totalSupply * 5 / 100;
balances[0x00061009bd8f0b1301cc5edc28ed1222a3ce671e] = _totalSupply * 5 / 100;
balances[0x00071009bd8f0b1301cc5edc28ed1222a3ce671e] = _totalSupply * 5 / 100;
balances[0x00081009bd8f0b1301cc5edc28ed1222a3ce671e] = _totalSupply * 5 / 100;
balances[0x00091009bd8f0b1301cc5edc28ed1222a3ce671e] = _totalSupply * 5 / 100;
}
function totalSupply() constant returns (uint256 totalSupply) {
totalSupply = _totalSupply;
}
// What is the balance of a particular account?
function balanceOf(address _owner) constant returns (uint256 balance) {
return balances[_owner];
}
// Transfer the balance from owner's account to another account
function transfer(address _to, uint256 _amount) returns (bool success) {
if (balances[msg.sender] >= _amount && _amount > 0) {
balances[msg.sender] -= _amount;
balances[_to] += _amount;
Transfer(msg.sender, _to, _amount);
return true;
} else {
return false;
}
}
// Send _value amount of tokens from address _from to address _to
// The transferFrom method is used for a withdraw workflow, allowing contracts to send
// tokens on your behalf, for example to "deposit" to a contract address and/or to charge
// fees in sub-currencies; the command should fail unless the _from account has
// deliberately authorized the sender of the message via some mechanism; we propose
// these standardized APIs for approval:
function transferFrom(
address _from,
address _to,
uint256 _amount
) returns (bool success) {
if (balances[_from] >= _amount
&& allowed[_from][msg.sender] >= _amount
&& _amount > 0) {
balances[_to] += _amount;
balances[_from] -= _amount;
allowed[_from][msg.sender] -= _amount;
Transfer(_from, _to, _amount);
return true;
} else {
return false;
}
}
// Allow _spender to withdraw from your account, multiple times, up to the _value amount.
// If this function is called again it overwrites the current allowance with _value.
function approve(address _spender, uint256 _amount) returns (bool success) {
allowed[msg.sender][_spender] = _amount;
Approval(msg.sender, _spender, _amount);
return true;
}
function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
return allowed[_owner][_spender];
}
// Don't want any ethers leaking into this contract
function () {
throw;
}
}
b) I should be able to list the token on a decentralized exchange
You can list any ERC20-compliant token on https://cryptoderivatives.market/ . Read the manuals (I'm in the process of writing it up) on how to do this.
c) I should be able to distribute the token to a list of 100 Ethereum addresses at once without paying more than about 0.01 USD in transaction fees
When you deploy your token contract, you could set the totalSupply
to your total supply and assign it to your owner account - for an example see 0x2c875e5ea4706b1978a41b59edf2d3af31d60e70
// Constructor
function IncentCoffeeToken() {
_totalSupply = 824;
owner = msg.sender;
balances[owner] = _totalSupply;
}
It will cost about USD 0.01 to distribute tokens to each Ethereum address, for example Tx 0x404f03c9... costs 0.00112580763312 Ether ($0.01).
There are ways to bulk upload the initial token distribution, but it gets complicated. For an example, see @ledgerwatch's The DAO ExtraBalance refund contract - search for ExtraBalToken Contract in How do I get a refund for the amount I paid in excess of 1 ether to 100 The DAO tokens where he added the fill(...)
and seal(...)
functions:
bool public sealed;
// The 160 LSB is the address of the balance
// The 96 MSB is the balance of that address.
function fill(uint[] data) {
if ((msg.sender != owner)||(sealed))
throw;
for (uint i=0; i<data.length; i++) {
address a = address( data[i] & (D160-1) );
uint amount = data[i] / D160;
if (balanceOf[a] == 0) { // In case it's filled two times, it only increments once
balanceOf[a] = amount;
totalSupply += amount;
}
}
}
function seal() {
if ((msg.sender != owner)||(sealed))
throw;
sealed= true;
}
The idea here is that you deploy the contract, then call fill(...)
with an array of uint256
data where the 160 least-significant-bits is the address of the balance and the 96 most-significant-bits is the balance of that address.