講了那麼多的 ERC20 Token 的實作,怎麼可以最後沒提到 ICO Contract 要怎麼做呢XD 今天就讓我們來談談 ICO Contract 要怎麼寫吧!
本日合約:
ICOToken.sol
pragma solidity ^0.4.25;
import "browser/SafeMath.sol";
import "browser/IERC20.sol";
contract ICOToken is IERC20 {
//=== Library =============================================================
using SafeMath for uint256;
//=========================================================================
//=== State Variables =====================================================
string mName = "ICOToken";
uint8 mDecimals = 18;
string mSymbol = "ICO";
uint256 mTotalSupply = 0;
mapping(address => uint256) mBalances;
mapping(address => mapping(address => uint256)) mApprove;
//=========================================================================
//=== Constructor =========================================================
constructor(
string pName,
uint8 pDecimals,
string pSymbol,
uint256 pTotalSupply)
public
{
mName = pName;
mDecimals = pDecimals;
mSymbol = pSymbol;
mTotalSupply = pTotalSupply;
mBalances[msg.sender] = mBalances[msg.sender].add(mTotalSupply);
emit Transfer(address(this), msg.sender, mTotalSupply);
}
//=========================================================================
//=== ERC20 Functions =====================================================
// 所有存在的 Token 數量
function totalSupply() external view returns (uint256) {
return mTotalSupply;
}
// 讀取 tokenOwner 這個 address 所持有的 Token 數量
// address => uint256
function balanceOf(address tokenOwner) external view returns (uint256 balance) {
return mBalances[tokenOwner];
}
// 從 msg.sender 轉 tokens 個 Token 給 to 這個 address
// msg.sender ---tokens---> to
function transfer(address to, uint256 tokens) external returns (bool success) {
return _transfer(msg.sender, to, tokens);
}
// 得到 tokenOwner 授權給 spender 使用的 Token 剩餘數量
function allowance(address tokenOwner, address spender) external view returns (uint256 remaining) {
return mApprove[tokenOwner][spender];
}
// tokenOwner -> spender -> tokens
// address => address => uint256
// msg.sender 授權給 spender 可使用自己的 tokens 個 Token
function approve(address spender, uint256 tokens) external returns (bool success) {
mApprove[msg.sender][spender] = tokens;
emit Approval(msg.sender, spender, tokens);
return true;
}
// 將 tokens 個 Token 從 from 轉到 to
function transferFrom(address from, address to, uint256 tokens) external returns (bool success) {
mApprove[from][msg.sender] = mApprove[from][msg.sender].sub(tokens);
return _transfer(from, to, tokens);
}
function _transfer(address from, address to, uint256 tokens) internal returns (bool success) {
mBalances[from] = mBalances[from].sub(tokens);
mBalances[to] = mBalances[to].add(tokens);
emit Transfer(from, to, tokens);
return true;
}
//=========================================================================
//=== ERC20 Detail information ============================================
function name() public constant returns (string) {
return mName;
}
function decimals() public constant returns (uint8) {
return mDecimals;
}
function symbol() public constant returns (string) {
return mSymbol;
}
//=========================================================================
}
ICOContract.sol
pragma solidity ^0.4.25;
import "browser/ICOToken.sol";
contract ICO {
//=== Library =============================================================
using SafeMath for uint;
//=========================================================================
//=== Enum ================================================================
enum ICOState {INITIAL, START, END}
//=========================================================================
//=== State Variables =====================================================
address private owner = 0x0;
address public mTokenAddress = 0x0;
uint256 mCaps = 0;
uint256 mCurrentFund = 0;
ICOState mICOState = ICOState.INITIAL;
//=========================================================================
//=== Modifiers ===========================================================
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
modifier beforICOStart() {
require(mICOState == ICOState.INITIAL);
_;
}
modifier whenICOStart() {
require(mICOState == ICOState.START);
_;
}
modifier whenICOEnd() {
require(mICOState == ICOState.END);
_;
}
//=========================================================================
//=== Constructor =========================================================
constructor() public {
owner = msg.sender;
string memory name = "HYDAIToken";
uint8 decimals = 18;
string memory symbol = "HYT";
uint256 totalSupply = 1000*(10**18);
mCaps = totalSupply;
mTokenAddress = new ICOToken(name, decimals, symbol, totalSupply);
mICOState = ICOState.INITIAL;
}
//=========================================================================
//=== Functions ===========================================================
function startICO() public onlyOwner beforICOStart {
mICOState = ICOState.START;
}
function endICO() public onlyOwner whenICOStart {
mICOState = ICOState.END;
owner.transfer(address(this).balance);
IERC20(mTokenAddress).transfer(owner, mCaps.sub(mCurrentFund));
}
//=========================================================================
//=== Fallback Function ===================================================
function() public payable whenICOStart {
require(msg.value > 0);
require(mCaps >= mCurrentFund + msg.value);
mCurrentFund = mCurrentFund.add(msg.value);
IERC20(mTokenAddress).transfer(msg.sender, msg.value);
}
//=========================================================================
}
本日影片:
https://youtu.be/a51xrVIT--Q
Smart Contract 實戰教學播放清單:
https://www.youtube.com/playlist?list=PLHmOMPRfmOxSJcrlwyandWYiuP9ZAMYoF