이타인클럽 도움 주고 받기를 위한 ERC 토큰을 만들어 보려고 합니다.
이전글 - [Reboot 이타인클럽] #2 컨트랙트 빌드 with Truffle
ERC777토큰 컨트랙트 빌드는 매우 순조롭게 진행됐습니다.
그런데!
ERC777 토큰은 openzeppelin에서 solidity 0.6.0 이상 버전을 사용하는데, 이게 문제가 좀 됩니다. 인터넷에 널린 자료들로 deploy하면 에러가 발생합니다.
$ truffle migrate --network ganache
...
2_deploy_contract.js
====================
Replacing 'EtainClubToken'
--------------------------
Error: *** Deployment Failed ***
"EtainClubToken" hit a require or revert statement somewhere in its constructor. Try:
* Verifying that your constructor params satisfy all require conditions.
* Adding reason strings to your require statements.
at /home/etain/.config/yarn/global/node_modules/truffle/build/webpack:/packages/deployer/src/deployment.js:364:1
solidity 0.6으로 넘어오면서 에러가 발생하는 것입니다.
EtainClubToken (ERC777) Deploy 과정
컨트랙트 컴파일부터 다시 알아보겠습니다. 컨트랙트 코드가 살짝 바뀌었습니다.
1. 컨트랙트 컴파일
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import "../node_modules/@openzeppelin/contracts/token/ERC777/ERC777.sol";
contract EtainClubToken is ERC777 {
// constructor
constructor(
string memory name,
string memory symbol,
uint256 initialSupply
)
ERC777(name, symbol, new address[](0))
public
{
_mint(msg.sender, initialSupply, "", "");
}
}
컨트랙트 소스를 보면, solidity ^0.6.0이 보입니다. 주의하시고요.
ERC777 constructor는 세 개의 인자를 받습니다. 토큰 이름, 심볼, defaultOperators.
세번째 인자에 new address[](0)
을 넣은 것을 주의하셔서 보세요.
이렇게 하고 컴파일 합니다.
$ truffle compile
컴파일은 이전처럼 문제없이 진행됩니다.
2. ganache
컨트랙트를 배포하기 위해서는 블록체인 네트워크가 필요합니다. 로컬 PC에서만 돌아가는 ganache 블록체인 네트워크를 실행합니다.
!주의: 이 때, truffle.config.js에 ganache라는 네트워크에 설정된 port와 networkId와 일치시켜야 합니다.
$ ganache-cli -p 7545 -i 5777
Ganache CLI v6.10.0-beta.2 (ganache-core: 2.11.0-beta.0)
Available Accounts
==================
(0) 0xF1908bF83e54898E58B75067e57Db4FcB444a2B1 (100 ETH)
(1) 0x65a3D4A3a740bf0c9CB28755f1287ADF20568CfA (100 ETH)
...
ganache 실행도 문제 없습니다.
3. 컨트랙트 Migrate
컨트랙트를 블록체인에 배포(deploy)하기 위해서는 migration (이관) 코드가 필요합니다. 순전히 배포를 위한 코드라고 보시면 됩니다.
문제는 여기서 발생합니다. 책이나 truffle 공식 사이트에도 다음과 같이 하라고 나옵니다.
var EtainToken = artifacts.require('EtainClubToken');
module.exports = function(deployer) {
deployer.deploy(EtainToken, 'EtainClubToken', 'ECT', 1000);
}
이러면 위에서 보는 것과 같은 에러가 발생합니다
migration 코드가 조금 복잡해졌습니다. 다음과 같이 해야 합니다.
참고. https://forum.openzeppelin.com/t/error-deploying-simple-erc777-contract-with-truffle-and-ganache/1588/13
var EtainToken = artifacts.require('EtainClubToken');
require('../node_modules/@openzeppelin/test-helpers/configure')({
provider: web3.currentProvider,
environment: 'truffle'
});
const { singletons } = require('../node_modules/@openzeppelin/test-helpers');
module.exports = async function(deployer, network, accounts) {
const registry = await singletons.ERC1820Registry(accounts[0]);
await deployer.deploy(EtainToken, 'EtainClubToken', 'ECT', 1000);
};
코드를 보면 openzeppelin의 helpers 모듈을 사용해야 하고, ERC1829Registry 부분도 꼭 필요합니다. 아직 정확한 의미를 모르지만 이것때문에 고생을 좀 많이 했네요. ERC777의 세 번째 인자인 operation 계정(defaultOperators)과 관련 있는거 같습니다.
자 이제 됩니다! ganache가 실행되는 것을 확인하고 다음과 같이 합니다.
$ truffle migrate --network ganache
...
Starting migrations...
======================
> Network name: 'ganache'
> Network id: 5777
> Block gas limit: 6721975 (0x6691b7)
...
2_deploy_contract.js
====================
Deploying 'EtainClubToken'
--------------------------
> transaction hash: 0x0ae4f38b2d2edfcd1116d17ca22bf18f512ef02fbc1333a0063fe19ea7b85b3f
> Blocks: 0 Seconds: 0
> contract address: 0x7B33313345d952767D737D43B11Ac1B681107e26
> block number: 5
> block timestamp: 1593549791
> account: 0xF1908bF83e54898E58B75067e57Db4FcB444a2B1
> balance: 99.86041118
> gas used: 2772709 (0x2a4ee5)
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.05545418 ETH
> Saving migration to chain.
> Saving artifacts
-------------------------------------
> Total cost: 0.05545418 ETH
Summary
=======
> Total deployments: 2
> Final cost: 0.058742 ETH
짜잔! migration코드에 의해 컨트랙트가 블록체인에 배포되었습니다!
4. 확인
배포가 잘 되었는지 확인을 해야 겠죠. 이것도 truffle을 이용합니다. 다음과 같이 truffle console을 이용합니다.
$ truffle console --network ganache
// truffle console에서 배포한 컨트랙트를 쳐봅니다.
truffle(ganache)> EtainClubToken
[Function: TruffleContract] {
_constructorMethods: {
configureNetwork: [Function: configureNetwork],
setProvider: [Function: setProvider],
...
컨트랙트 관련 어마어마한 내용이 출력됩니다. 컨트랙트 주소값을 읽어 봅니다.
truffle(ganache)> EtainClubToken.address
초기 토큰 갯수값을 읽어 봅니다.
truffle(ganache)> EtainClubToken.deployed().then(instance => instance.totalSupply())
BN {
negative: 0,
words: [ 1000, <1 empty item> ],
length: 1,
red: null
}
이제 배포된 컨트랙트에서 값을 읽거나 상태를 바꿀 수가 있게 됐습니다!
예전에는 쉽게 된거 같은데 solidity 0.6으로 바뀌면서 좀 헤맸습니다.
이제 ERC777 토큰 배포까지 되었으니, 다음에는 EtainClubToken에 필요한 기능을 추가해서 배포해 보겠습니다.