κ°κ΅¬λ¦¬μ½μΈ, κΉμ μμ½μΈ λ± μ¨κ° μ‘μ½μΈμ΄ λ²λνλ μ΄ μκΈ°,
λ¬Έλ κ°μΈ μ½μΈμ ν λ² λ§λ€μ΄ λ³΄κ³ μΆμ΄μ‘μ΅λλ€.
κ·Έλμ μλ ν¬μ€ν
μ λ°λΌ μ΄λ리μ κΈ°λ°μ ERC20 ν ν°μ λ§λ€μ΄ 보μμ΅λλ€.
λ° λ
μ΄ λμ κΈμ΄λΌ μ μλλ λ΄μ©μ΄ μμλλ°,
λ©λ΄μΌμ΄λ λ€λ₯Έ μλ£λ₯Ό μ‘°κΈ μ°Έκ³ νμ¬ μμ νμμ΅λλ€.
How to create token and initial coin offering
(μ°Έκ³ λ‘ μ λ μ λ¬Έ κ°λ°μλ μλλ©° κ°μΈμ μΈ μ 리 μ°¨μμμ λ¨κΈ°λ κ±°λΌ,
μ‘°κΈ μ΄μ€νκ±°λ νλ¦° λ΄μ©μ΄ μμ μ μμ΅λλ€.
μλͺ»λ λ΄μ©μ΄λ λΆκ° μ€λͺ
μ λκΈλ‘ λ¨κ²¨μ£Όμλ©΄ κ³ λ§κ² μ΅λλ€^^ )
μ°Έκ³ λ‘ μ λ ubuntu μμ μ§ννμμ΅λλ€.
λ ΈνΈλΆμ μ°μ μ΄λ리μ μ€λ§νΈ 컨νΈλνΈλ₯Ό κ°λ°μ μν κ°λ°νκ²½μ μΈν ν΄μΌ ν©λλ€.
λ©μΈλ·μ λΆμ΄λ €λ©΄ μ΄λκ° νμν΄μ, κ°λ° νκ²½μμλ§ λ§λ€μμ΅λλ€.
μλ¬Έμμλ ethereumjs-testrpc λ₯Ό μΆκ°λ‘ μ€μΉνμΌλ, truffle 4.0.x λΆν° μ체 ν
μ€νΈ νκ²½μ΄ μμ΄μ μ μΈνμμ΅λλ€.
$ npm install -g truffle
$ mkdir my-ico && cd my-ico
$ truffle init
$ npm install zeppelin-solidity
μ°μ κ° μ νκ²½μ λ§λ nodejsλ₯Ό μ€μΉν©λλ€.
κ·Έ λ€μ truffle μ€μΉνκ³ μμ
곡κ°(my-ico)μ μμ±ν ν,
truffle init λ₯Ό μ€ννλ©΄ κΈ°λ³Έ ν΄λμ κ°μ’
ν
νλ¦Ώμ΄ μμ± λ©λλ€.
$ npm install -g truffle
$ mkdir my-ico && cd my-ico
$ truffle init
contracts, migrations, test ν΄λ μμ±μ νμΈν μ μμ΅λλ€.
μ΄μ νμ€ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ 곡νλ zeppelin-solidity μ€μΉν©λλ€.
npm install zeppelin-solidity
μλ zeppelin μ κΈ°λ³Έ λΌμ΄λΈλ¬λ¦¬ λ€μ΄ μ€μΉλ©λλ€.
ν λ² νμ΄λ³΄λ©΄, ERC20 κ°μ κΈ°λ³Έ ν ν°λ₯Ό νννλ 리μ΄λΈλ¬λ¦¬λ€λ 보μ΄λ€μ.
μ΄λ리μμ μμ±νλ smart contractλ νΉμ μ£Όμμ λ°°ν¬μ΄νμ μμ λ μλλ©°, μμ λ²κ·Έλ λ§€μ° μΉλͺ μ μΌ μ μμ΅λλ€. νΉν μλͺ»λ κ³μ½ μ½λλ μ€λν κΈμ μ μν΄λ₯Ό λΌμΉ μ μμ΅λλ€. μ΄λ₯Ό λ°©μ§νκΈ° μν΄μ zepplin-solidityλ νμ€ κ³μ½μ μ 곡νκ³ μμ΅λλ€.
my-ico/contracts ν΄λμ JHPCoin.sol νμΌ νλλ₯Ό λ§λ€κ³ μλ μ½λλ₯Ό 볡μ¬ν©λλ€.
νμ€ MintableTokenμ νλ μμλ°μμ contract λ₯Ό μμ±νκ³ ,
Coinμ μ΄λ¦κ³Ό μ¬λ³Όμ μ€μ νλ μ½λ μ
λλ€. ( κ°λ¨νμ£ ?)
mintableμ λ» : νν λ°νμ΄ κ°λ₯ν
MintableToken : crowdsaleμμ μ΄λλ₯Ό λ°μμ κ·Έμ λμλλ μμ μ½μΈμ λ°ννλ ννμ ν ν° κ³μ½
my-ico/contracts/JHPCoin.sol
pragma solidity ^0.4.17;
import 'zeppelin-solidity/contracts/token/ERC20/MintableToken.sol';
contract JHPCoin is MintableToken {
string public name = "JHP PERSONAL COIN"; // μ€λͺ
string public symbol = "JHP"; // μ½μΈ μ¬λ²
uint8 public decimals = 18; // μ리μ
} // end of contract -------------------------------------------
μ½μΈμ λ§λ€μμΌλ, μ΄μ ICOνλ μ½λλ₯Ό λ§λ€μ΄ λ΄μΌκ² λ€μ.
contracts ν΄λμ JHPCoinCrowdSale.sol νμΌμ λ§λ€κ³ μλ μ½λλ₯Ό 볡μ¬ν©λλ€.
μ½λ λ΄μ©μ λ¨μν©λλ€.
μμ zeppelinμμ λ§λ νμ€μ μΈ crowdsaleμ μμλ°λ λ΄μ©μ
λλ€.
my-ico/contracts/JHPCoinCrowdSale.sol
pragma solidity ^0.4.17;
import './JHPCoin.sol';
import 'zeppelin-solidity/contracts/crowdsale/Crowdsale.sol';
contract JHPCoinCrowdsale is Crowdsale {
// startTime : crowdSale μμμΌ
// endTime : μ’
λ£μΌ
// rate : μ΄λ-μ½μΈ κ΅νλΉ. ν ν° λ°νλ = μ΄λ x rate
// wallet : crowdSaleμ μ§κΈλλ μ΄λλ₯Ό λ°μ μ§κ°
function JHPCoinCrowdsale(uint256 _startTime, uint256 _endTime, uint256 _rate, address _wallet)
Crowdsale(_startTime, _endTime, _rate, _wallet) {
}
// creates the token to be sold.
// override this method to have crowdsale of a specific MintableToken token.
function createTokenContract() internal returns (MintableToken) {
return new JHPCoin();
}
}
crowdSale κ΄λ ¨ κ³μ½μ λͺ¨λ μμ±νμμ΅λλ€.
μ΄μ truffle νκ²½μμ λ°°ν¬λ₯Ό μν μ½λλ₯Ό μμ±ν΄ λ³΄κ² μ΅λλ€.
μ°μ migrations ν΄λμ 2_deploy_contracts.js νμΌμ λ§λ€μ΄μ μλ μ½λλ₯Ό 볡μ¬ν©λλ€.
my-ico/migrations/2_deploy_contracts.js
const JHPCoinCrowdsale = artifacts.require("./JHPCoinCrowdsale.sol")
module.exports = function(deployer, network, accounts) {
const startTime = web3.eth.getBlock(web3.eth.blockNumber).timestamp + 5 // κ³μ½ μμ± ν 5μ΄λ€μ μμ!
const endTime = startTime + (86400 * 20) // 20 days
const rate = new web3.BigNumber(1000) // μ΄λ νλμ 1000κ°μ ν ν°μ 보λ
λλ€.
const wallet = accounts[0] // ν
μ€νΈλ·μ κ³μ 0 μ§κ° ν λΉ. μ€μ ICOλ©΄ μκΈ° μ§κ°μ λ£μ΄μΌ κ² μ£ ?,,
deployer.deploy(JHPCoinCrowdsale, startTime, endTime, rate, wallet)
};
μ°λ¦¬λ μλ¬Έμ solidity-testrpc λμ truffle develop λ‘ κ°λ°λ·μ λ§λλλ€.
localhost ν¬νΈ(9545)κ° λ¬λΌμ Έμ my-ico/truffle.jsμ μλμ κ°μ΄ μ€μ μ λ³κ²½νμ¬ μ€λλ€.
μ΄λ μ μνκ²½ μ€μ μΈ networks > development μ€μ μ localhost:9545λ‘ νκ² λ€λ μλ―Έμ λλ€.
my-ico/truffle.js
module.exports = {
// See <http://truffleframework.com/docs/advanced/configuration>
// to customize your Truffle configuration!
networks: {
development: {
host: "localhost",
port: 9545,
network_id: "*" // Match any network id
}
}
};
μ μ΄μ λ€μμ΅λλ€. μ»΄νμΌ νκ³ μ€νν΄ λ³΄κ² μ΅λλ€.
$ truffle compile
μ λ§ μ»΄νμΌμ΄ λλκ΅°μ γ
γ
λͺ κ° κ²½κ³ κ° λ΄μ§λ§, κ°λ³κ² 무μνκ² μ΅λλ€.
μ½μμ κ²°κ³Ό νλ©΄μ 보λ μ κ° λ§λ JHPCoinκ³Ό CrowdSale,
truffleμμ κΈ°λ³Έμ μΌλ‘ μ 곡νλ Migration.sol,
κ·Έλ¦¬κ³ zepplinμ ERC20 κ΄λ ¨ ν ν° μ½λλ€μ΄ μ»΄νμΌ λ©λλ€.
λ³λμ μ½μμ μ€ννκ³ , κ°μμ μ΄λ리μ λ€νΈμν¬λ₯Ό ꡬλν©λλ€.
$truffle develop
localhost:9545λ‘ κ°λ°λ·μ΄ μ€νλκ³ , λͺ κ°μ accountκ° μμ±μ΄ λμμμ μ μ μμ΅λλ€.
λ§μ μμ±νκ³ λ³΄λ κΈΈκ΅°μ... μ΄μ λ§μ§λ§μ
λλ€.
μ΄λ²μ£Ό ν μμΌ λ°λμ μ μλΉν κ² κ°κ΅°μ. λμ΄ λ³΄μ
λλ€.
truffle migrate λ₯Ό μ€νν©λλ€. λ°°ν¬λμ΄λ! μ΄μ!
$truffle migrate --reset
migrate λͺ
λ Ήμ΄λ μ»΄νμΌλ contractλ₯Ό λͺ©νν μ΄λ리μ λ€νΈμν¬μ λ°°ν¬νλ μν μ ν©λλ€.
μλ¬Έμμλ testrpc μ νμμΌλ, truffle 4.0.xλ‘ λμ΄μ€λ©΄μ μ체 develop networkλ₯Ό μ 곡νμ¬ μ¬κΈ°μ λ°°ν¬νμμ΅λλ€.
μ λ λ€νΈμν¬λ₯Ό μΈμ§νμ§ λͺ»νλ μ€λ₯κ° λ°μνμμΌλ, reset μ΅μ μ λΆμ¬μ£Όλ μ μμ μΌλ‘ λ©λλ€. μ€λ₯ μμΈμ μ’ λ μ°Ύμλ΄μΌ λ κ² κ°κ΅°μ
κ·ΈλΌ development λ€νΈμν¬μ κ³μ½μ΄ μ μ¬λΌκ°λμ§ νμΈν΄ λ³΄κ² μ΅λλ€.
truffle console λ‘ networkμ μ μμ΄ κ°λ₯ν©λλ€.
$truffle console
첫λ²μ§Έ ꡬ맀μλ₯Ό 1λ² κ³μ μΌλ‘ μ€μ ν©λλ€.
μ°Έκ³ λ‘ web3λ μ΄λ리μ λ€νΈμν¬μ μ μνκΈ° μν μΈν°νμ΄μ€ μ λλ€.
truffle(development)> first_buyer = web3.eth.accounts[1]
'0xf17f52151ebef6c7334fad080c5704d77216b732'
CrowdSale μ½λκ° λ°°ν¬λμ§ νμΈνκ³ , λ°°ν¬λ κ³μ½μ μ£Όμλ₯Ό λ°μ μ΅λλ€.
truffle(development)> JHPCoinCrowdsale.deployed().then(inst => { crowdsale = inst } )
undefined
CrowdSale κ³μ½μ΄ μμ±λλ©΄, JHPCoin κ³μ½λ κ°μ΄ μμ±μ΄ λ©λλ€.
CrowdSaleμ κ³μ½μ£Όμλ₯Ό μ½μ΄μ, ν ν°κ³μ½μ μ£Όμλ₯Ό λ°μμ΅λλ€.
truffle(development)> crowdsale.token().then(addr => { tokenAddress = addr } )
undefined
μλλ ν ν° κ³μ½ μ£Όμμ
λλ€.
λͺ¨λ κ³μ½μ μ§κ°κ³Ό λμΌνκ² μ£Όμ νλκ° ν λΉμ΄ λ©λλ€.
truffle(development)> tokenAddress
'0x6b5f2b72ed649a5018701eb2b71c4fd8f472595c'
μ°λ¦¬μ 첫λ²μ§Έ ν ν° κ΅¬λ§€μμΈ first_buyerμ νμ¬ balanceλ₯Ό νμΈν©λλ€.
μμ§ μ무κ²λ ꡬ맀νμ§ μμμΌλ―λ‘, balanceκ° '0' μμ νμΈν μ μμ΅λλ€.
truffle(development)> JHPCoin.at(tokenAddress).balanceOf(first_buyer).then( balance => balance.toString(10) )
'0'
crowdsaleμμ transaction νλλ₯Ό λ°μμν΅λλ€.
first_buyerλ‘ λΆν° 1 μ΄λλ₯Ό crowdsale κ³μ½μΌλ‘ μ μ‘νλ transaction μ
λλ€.
truffle(development)> crowdsale.sendTransaction({ from: first_buyer, value: web3.toWei(1, "ether")})
{ tx: '0xca48615349f295b9b61d5c02651f0801e083bdbf205bda5ee8925543cf877988',
receipt:
{ transactionHash: '0xca48615349f295b9b61d5c02651f0801e083bdbf205bda5ee8925543cf877988',
transactionIndex: 0,
blockHash: '0x5309fdd94e2b4cf7a73efd3ef1431977bf677d5abb79ac26fd8ffa7b7adb1bf4',
blockNumber: 10,
gasUsed: 99279,
cumulativeGasUsed: 99279,
contractAddress: null,
logs: [ [Object], [Object], [Object] ],
status: 1 },
logs:
[ { logIndex: 2,
transactionIndex: 0,
transactionHash: '0xca48615349f295b9b61d5c02651f0801e083bdbf205bda5ee8925543cf877988',
blockHash: '0x5309fdd94e2b4cf7a73efd3ef1431977bf677d5abb79ac26fd8ffa7b7adb1bf4',
blockNumber: 10,
address: '0x30753e4a8aad7f8597332e813735def5dd395028',
type: 'mined',
event: 'TokenPurchase',
args: [Object] } ] }
transaction μ΄νμ μ°λ¦¬μ 첫λ²μ§Έ ꡬ맀μμ balanceκ° μ¦κ°νλμ§ νμΈν΄ λ³΄κ² μ΅λλ€.
1eth * 1000 rate λ§νΌμ ν ν°μ΄ λ°νμ΄ λμλ€μ!!
μ°Έκ³ λ‘ JHPToken ν ν° μ€μ μ decimalμ 18λ‘ μ€μ νμ¬μ, 10^18 * 1000 μΌλ‘ νμλ©λλ€.
truffle(development)> JHPCoin.at(tokenAddress).balanceOf(first_buyer).then( balance => balance.toString(10) )
'1000000000000000000000'
ν΄~ μκ°λ³΄λ€ μ€λκ±Έλ Έλ€μ.
λ€μ λ²μλ νμ€ ν ν°μ νΉμ±μ λν΄μ μ’ λ νλ³΄κ³ , μ€μ κ±°λλλ ICO μ½λλ₯Ό λΆμν΄ λ³΄κ² μ΅λλ€.
μ½μΈ λ‘κ³ λ₯Ό λ§λ€κ³ , μ‘ κ±°λμλΌλ ν λ² λ±λ‘μ ν΄λ΄μΌ λκ² λ€μ.
λλ§μ μ½μΈμ λ§λ€μ΄ λ΄
μλ€. #1 - κ°λ°νκ²½ μΈν
λ° ERC20 μ½μΈ μμ±
λλ§μ μ½μΈμ λ§λ€μ΄ λ΄
μλ€. #2 - ERCxx νμ€ ν ν° νΉμ± λΆμ λ° μ€μ ICO μ½λ λΆμ
λλ§μ μ½μΈμ λ§λ€μ΄ λ΄
μλ€. #3 - λ‘κ³ μ ICO νμ΄μ§ λ§λ€μ΄ 보기
λλ§μ μ½μΈμ λ§λ€μ΄ λ΄
μλ€. #4 - 리μΌλ·μ λΆμ¬μ μ‘κ±°λμμ μμ₯ν΄λ³΄κΈ°