Token purchase for Ether
Generally token purchase for ether are provided by a contract external from the main storage token, a so-called "crowdsale" contract.
This sale contract would have tokens transferred to it from the main ECR20 token's contract and will have a payable function that accepts payment of Ether in exchange for the tokens.
There's more details about this in the main ethereum documentation https://www.ethereum.org/crowdsale.
A simple example:
There are many fully featured crowdsales contracts out there, but this example neatly demonstrates the basics:
pragma solidity ^0.4.19;
interface iERC20 {
function totalSupply() public constant returns (uint256 supply);
function balanceOf(address owner) public constant returns (uint256 balance);
function allowance(address owner, address spender) public view returns (uint remaining);
function transfer(address to, uint tokens) public returns (bool success);
function approve(address spender, uint tokens) public returns (bool success);
function transferFrom(address from, address to, uint tokens) public returns (bool success);
}
/// @title An example contract that demonstrates buying tokens with eth.
/// @dev This contract must be created with the address of the token to sell.
/// This contract must also own some quantity of the token it's selling.
/// Note: This is an example only and is not meant to be feature complete.
contract Crowdsale {
iERC20 token;
address owner;
uint rateMillionths;
modifier ownerOnly() {
require(msg.sender == owner);
_;
}
// @notice Initialises the contract.
// @param _main The address of an ERC20 compatible token to sell.
function Crowdsale(address _main) public {
token = iERC20(_main);
owner = msg.sender;
rateMillionths = 1000000;
}
/// @notice Will transfer all ether in this account to the contract owner.
function withdraw() public ownerOnly {
owner.transfer(this.balance);
}
/// @notice This function will set the conversion rate (in millionths).
/// @dev To set a rate of 1.5token / eth, you would make the rate 1,500,000 and so forth.
/// @param _rateMillionths The conversion rate in millionths.
function setRate(uint _rateMillionths) public ownerOnly {
rateMillionths = _rateMillionths;
}
/// @notice Any funds sent to this contract will be converted to the linked contract's tokens
/// @dev This function receives funds, and transfers tokens based on the current conversion rate
function () public payable {
uint value = msg.value * rateMillionths;
// Overflow detection/protection:
require(value/msg.value == rateMillionths);
value = value / 1000000;
token.transfer(msg.sender, value);
}
}
Whenever someone transfers ether to this contract, it will take the amount of wei sent, multiply it by rateMillionths
and divide by one million to calculate the number of quintillionths (smallest unit at 18 decimal places) of the token contract to issue to the sender.
It then transfers that number of tokens from it's balance to the sender.
Thus this contract ends up with ether and a smaller token balance, and the sender ends up with a smaller ether balance and the appropriate number of the token.
The owner (creator) of the crowdsale can subsequently call withdraw()
to have the current ether balance transferred to them.
As this is a simple example, there are other features that you generally want with a crowdsale, such as:
- the ability for the owner to recover unsold tokens
- recovery of any accidentally sent ERC20 tokens of other types
- to transfer ownership to a new owner
- to pause and resume the sale etc.
All these features can be found in more comprehensive contract examples out there.
Stopping accidental ether transfers
In order to stop people accidentally sending ether to the main contract and expecting themselves to be getting tokens, you will need to add a rejecting fallback function to it:
/// @notice Payments to this contract will not get tokens.
/// @dev Please send payments to the crowdsale contract instead.
function () public payable {
revert();
}