一、简单代币合约(上)
pragma solidity >0.4.22 <0.6.0;
contract Coin {
//铸币者
address public minter;
//地址到代币余额的映射
mapping (address => uint) balances;
event Sent(address from, address to, uint amount);
//构造函数,把自己定义为铸币者
constructor() public { minter = msg.sender; }
//凭空发币以及数量
function mint(address receiver, uint amount) public {
require(msg.sender == minter);
balances[receiver] += amount;
}
//转币以及数量
function send(address receiver, uint amount) public {
require(amount <= balances[msg.sender]);
balances[msg.sender] -= amount;
balances[receiver] += amount;
//便于外部监听的时候获取数据
emit Sent(msg.sender, receiver, amount);
}
}
二、简单代币合约(下)
1、限制铸币人权利,代币固定不会无限发
ragma solidity >0.4.22;
contract Coin {
mapping (address => uint ) public balances;
constructor(uint initalSupply) public {
balances[msg.sender] = initalSupply;
}
function send(address receiver, uint amount) public returns(bool succese) {
require(balances[msg.sender] >= amount);
require(balances[msg.sender]+amount >= balances[receiver]);
balances[msg.sender] -= amount;
balances[receiver] += amount;
return true;
}
}
(1)合约的解读
- event Sent(address from, address to, uint amount);
声明了一个“事件”(event),它会在 send 函数的最后一行触发 - 用户可以监听区块链上正在发送的事件,而不会花费太多成本。一旦它被发出,监听该事件的listener都将收到通知
- 所有的事件都包含了 from , to 和 amount 三个参数,可方便追踪事务
emit Sent(msg.sender, receiver, amount); - 触发Sent事件,并将参数传入
(2)事件的监听(部分代码)
Coin.Sent().watch({}, '', function(error, result) {
if (!error) {
console.log("Coin transfer: " + result.args.amount +
"coins were sent from " + result.args.from +
" to " + result.args.to + ".");
console.log("Balances now:\n" +
"Sender: " + Coin.balances.call(result.args.from) +
"Receiver: " + Coin.balances.call(result.args.to));
}
});
2、ERC20 代币合约
pragma solidity ^0.4.16;
interface tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) external; }
contract TokenERC20 {
// Public variables of the token币名和币的简称
string public name;
string public symbol;
uint8 public decimals = 18;
// 18 decimals is the strongly suggested default, avoid changing it(18是最强赋值,不可更改的)
uint256 public totalSupply;
// This creates an array with all balances
mapping (address => uint256) public balanceOf;
//允许别人用自己的名义转币,给别人的授权额度
mapping (address => mapping (address => uint256)) public allowance;
// This generates a public event on the blockchain that will notify clients(谁授权,授权给谁,额度是多少)
event Transfer(address indexed from, address indexed to, uint256 value);
// This generates a public event on the blockchain that will notify clients
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
// This notifies clients about the amount burnt(代币的销毁机制,需要销毁的地址和数量)
event Burn(address indexed from, uint256 value);
/**
* Constructor function
*
* Initializes contract with initial supply tokens to the creator of the contract
*/
function TokenERC20(
uint256 initialSupply,
string tokenName,
string tokenSymbol
) public {
totalSupply = initialSupply * 10 ** uint256(decimals); /*Update total supply with the
decimal amount(10 ** uint256(decimals)表示10的18次方)*/
balanceOf[msg.sender] = totalSupply; // Give the creator all initial tokens
name = tokenName; // Set the name for display purposes
symbol = tokenSymbol; // Set the symbol for display purposes
}
/**
* Internal transfer, only can be called by this contract(内部方法只能在内部可见)
*/
function _transfer(address _from, address _to, uint _value) internal {
// Prevent transfer to 0x0 address. Use burn() instead(不能往0地址转币,0地址用于销毁币)
require(_to != 0x0);
// Check if the sender has enough
require(balanceOf[_from] >= _value);
// Check for overflows(防止溢出)
require(balanceOf[_to] + _value >= balanceOf[_to]);
// Save this for an assertion in the future
uint previousBalances = balanceOf[_from] + balanceOf[_to];
// Subtract from the sender
balanceOf[_from] -= _value;
// Add the same to the recipient
balanceOf[_to] += _value;
emit Transfer(_from, _to, _value);
// Asserts are used to use static analysis to find bugs in your code. They should never fail(assert后面一定要为真,转出和转入的总和要一定)
assert(balanceOf[_from] + balanceOf[_to] == previousBalances);
}
/**
* Transfer tokens
*
* Send `_value` tokens to `_to` from your account
*
* @param _to The address of the recipient
* @param _value the amount to send
*/
function transfer(address _to, uint256 _value) public returns (bool success) {
_transfer(msg.sender, _to, _value);
return true;
}
/**
* Transfer tokens from other address
*
* Send `_value` tokens to `_to` on behalf of `_from`
*
* @param _from The address of the sender
* @param _to The address of the recipient
* @param _value the amount to send
* (外部可见的transfer)
*/
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
require(_value <= allowance[_from][msg.sender]); // Check allowance
allowance[_from][msg.sender] -= _value;
_transfer(_from, _to, _value);
return true;
}
/**
* Set allowance for other address
*
* Allows `_spender` to spend no more than `_value` tokens on your behalf
*
* @param _spender The address authorized to spend
* @param _value the max amount they can spend
*/
function approve(address _spender, uint256 _value) public
returns (bool success) {
allowance[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
/**
* Set allowance for other address and notify
*
* Allows `_spender` to spend no more than `_value` tokens on your behalf, and then ping the contract about it
*
* @param _spender The address authorized to spend
* @param _value the max amount they can spend
* @param _extraData some extra information to send to the approved contract
*/
function approveAndCall(address _spender, uint256 _value, bytes _extraData)
public
returns (bool success) {
tokenRecipient spender = tokenRecipient(_spender);
if (approve(_spender, _value)) {
spender.receiveApproval(msg.sender, _value, this, _extraData);
return true;
}
}
/**
* Destroy tokens
*
* Remove `_value` tokens from the system irreversibly
*
* @param _value the amount of money to burn
*/
function burn(uint256 _value) public returns (bool success) {
require(balanceOf[msg.sender] >= _value); // Check if the sender has enough
balanceOf[msg.sender] -= _value; // Subtract from the sender
totalSupply -= _value; // Updates totalSupply
emit Burn(msg.sender, _value);
return true;
}
/**
* Destroy tokens from other account
*
* Remove `_value` tokens from the system irreversibly on behalf of `_from`.
*
* @param _from the address of the sender
* @param _value the amount of money to burn
* 代替别人销毁币
*/
function burnFrom(address _from, uint256 _value) public returns (bool success) {
require(balanceOf[_from] >= _value); // Check if the targeted balance is enough
require(_value <= allowance[_from][msg.sender]); // Check allowance
balanceOf[_from] -= _value; // Subtract from the targeted balance
allowance[_from][msg.sender] -= _value; // Subtract from the sender's allowance
totalSupply -= _value; // Update totalSupply
emit Burn(_from, _value);
return true;
}
}
三、Ballot – 一个简单的投票合约
- 电子投票的主要问题是如何将投票权分配给正确的人员以及如何防止被操纵。 这个合约展示了如何进行委托投票,同时,计票又是 自动和完全透明的
- 为每个(投票)表决创建一份合约,然后作为合约的创造者——即主席,将给予每个独立的地址以投票权
- 地址后面的人可以选择自己投票,或者委托给他们信任的人来投票
- 在投票时间结束时,winningProposal() 将返回获得最多投票的提案
pragma solidity >=0.4.22 <0.6.0;
contract Ballot {
struct Voter {
//权重
uint weight;
//是否已投票
bool voted;
//每个提案用数字编号
uint8 vote;
//投票的代理
address delegate;
}
//提案获得多少票
struct Proposal {
uint voteCount;
}
//主席
address chairperson;
//地址到voter结构体的映射
mapping(address => Voter) voters;
//定义变长数组
Proposal[] proposals;
/// Create a new ballot with $(_numProposals) different proposals.
constructor(uint8 _numProposals) public {
//给创建者赋予主席身份
chairperson = msg.sender;
//主席的权重
voters[chairperson].weight = 1;
proposals.length = _numProposals;
}
/// Give $(toVoter) the right to vote on this ballot.
/// May only be called by $(chairperson).主席给权利去投票
function giveRightToVote(address toVoter) public {
//调用方法的人必须要是主席并且没有投过票
if (msg.sender != chairperson || voters[toVoter].voted) return;
voters[toVoter].weight = 1;
}
/// Delegate your vote to the voter $(to).授权给其他人代理投票
function delegate(address to) public {
//将地址中的结构体拿出
Voter storage sender = voters[msg.sender]; // assigns reference
//已经投过则return
if (sender.voted) return;
//不能委托给0地址和自己
while (voters[to].delegate != address(0) && voters[to].delegate != msg.sender)
//委托人委托给其他人
to = voters[to].delegate;
//递归后找到最终委托人
if (to == msg.sender) return;
sender.voted = true;
sender.delegate = to;
Voter storage delegateTo = voters[to];
//如果委托人已经投了票,则把自己的票加到上面,没有则增加委托人的投票权重
if (delegateTo.voted)
proposals[delegateTo.vote].voteCount += sender.weight;
else
delegateTo.weight += sender.weight;
}
/// Give a single vote to proposal $(toProposal).
//发起投票
function vote(uint8 toProposal) public {
Voter storage sender = voters[msg.sender];
//判断调用者是否投过票,提案是否存在
if (sender.voted || toProposal >= proposals.length) return;
sender.voted = true;
sender.vote = toProposal;
proposals[toProposal].voteCount += sender.weight;
}
//选取最终提案
function winningProposal() public view returns (uint8 _winningProposal) {
uint256 winningVoteCount = 0;
for (uint8 prop = 0; prop < proposals.length; prop++)
if (proposals[prop].voteCount > winningVoteCount) {
winningVoteCount = proposals[prop].voteCount;
_winningProposal = prop;
}
}
}
四、总结
简单的发币和投票合约,ICO代码的解读,不过版本较老。