일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- cookie-parser 만들어보기
- node.js path
- express.static
- mysql wsl
- 시퀄라이즈 기본설정
- express session
- useContext
- javascript기초
- JWT 하드코딩
- express router
- 아이디 중복체크기능
- next 매개변수
- OAuth 카카오
- 블록 만들기
- express실행
- FormData()
- Uncaught Error: could not find react-redux context value; please ensure the component is wrapped in a <Provider>
- 세션으로 로그인 구현
- nodejs파일업로드
- 라우터와 미들웨어
- JWT 로그인 기능 구현
- ws 라이브러리
- 라우터 분리
- css기초
- JWT 만들어보기
- 라우터미들웨어 분리
- buffer.from
- 라우트 매개변수
- 비동기파일업로드
- useEffect clean up
- Today
- Total
즐코
ERC20 interface / ERC20 본문
오늘은 ERC20 규격을 표현하는 IERC20 과 그에 따른 ERC20, 또 이걸 상속하는 ERC20 토큰을 만드는 걸 배웠다.
우선 ERC-20을 다루기 전에 솔리디티의 인터페이스에 대해 정리해보려고 한다.
이전에 크립토 좀비 레슨2를 하면서 잠깐 마주쳤던 거 같은데 ( https://yjleekr.tistory.com/99?category=1284408 ) 살짝 개념이 모호해서 다시 정리해 본다.
interface 인터페이스
다른 컨트랙트와 상호작용하기 위해서 인터페이스가 존재한다고 하는데...
사실 이 말 자체가 애매해서 잘 이해가 안되므로 아래의 세부적인 특징으로 이해하고 넘어가려고 한다.
1. 상속받는 컨트랙트들을 위한 하나의 규격이라고 생각하면 될 듯하다. (자식 컨트랙트들을 위한 가이드라인)
2. 함수이름, 매개변수, 반환값만 선언하고 함수의 바디 내용은 없는 추상 함수로 interface를 구성해야한다.
=> 따라서, 함수의 내용부분은 이를 상속하는 컨트랙트들에서 구현한다
3. 다른 컨트랙트들과 상호작용할 때 이 인터페이스를 가진 컨트랙트는 이런 함수들을 포함한다고 미리 정보를 주는 역할을 한다.
4. 밑에서 ERC20의 인터페이스를 보면 알겠지만, 인터페이스를 구성하는 함수들은 전부 external 접근 제한자를 붙여줘야한다.
5. 함수 내용을 생략하는 것처럼 constructor 생성자 함수 또한 선언할 수 없다.
6. 상태변수를 선언할 수 없다. 따라서, 상태변수 대신 매개변수 값을 받지 않는 view 함수로서 선언해주는 것 같다.
이를 바탕으로 ERC20 과 ERC20 인터페이스를 정리해보자..
ERC20 과 ERC20 인터페이스
우선, ERC20 토큰은 아래와 같은 기능을 제공한다.
- transfer tokens : 토큰 전송
- allow others to transfer tokens on behalf of the token holder
: 토큰 보유자를 대신해서 다른 누군가가 토큰을 전송할 수 있다. (대리인의 역할)
토큰 전송까진 알겠으나 대리인의 역할은 오늘 처음 만난 개념이었다. 그건 좀이따 밑에서 정리해보려고 한다.
우선, ERC20 인터페이스 코드는 아래와 같다!
IERC20 : ERC20 인터페이스
// contracts/IERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
interface IERC20 {
function totalSupply() external view returns (uint);
function balanceOf(address account) external view returns(uint);
function transfer(address recipient, uint amount) external returns (bool);
function allowance(address owner, address spender) external returns (uint);
function approve(address spender, uint amount) external returns (bool);
function transferFrom(address spender, address recipient, uint amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint amount);
event Approval(address indexed owner, address indexed spender, uint value);
}
저번에 정리했던 아주 간단한 ERC-20 토큰 규격에 대한 포스팅 (https://yjleekr.tistory.com/100?category=1284408 )에서 totalSupply와 balanceOf, transfer는 간단하게 다루었기 때문에 설명은 생략한다.
오늘 추가적으로 배운 새로운 함수들에 대해서 정리해본다.
- function allowance
계정의 소유자가 특정 계정 혹은 CA 계정들에 얼마씩을 위임하고 있는지 그 기록을 보여주는 함수이다.
실제로 IERC를 상속하는 컨트랙트 상에선 mapping으로 표현할 것이다.
- function approve
계정의 소유자가 특정 계정 혹은 CA 계정에 얼마를 위임할지 정해주는 함수라고 본다.
- function transferFrom
위임받은 계정이 수취 계정으로 일부 토큰을 전송할 때 사용하는 함수이다.
이벤트도 있다!!
- event Transfer
토큰 전송이 일어났을 때 발동되는 이벤트이다. value 0 전송 시에도 이벤트는 발생된다.
- event Approval
approve 즉, 일정량의 토큰을 특정 계정에게 위임했을 때 이 Approval 이벤트를 호출한다.
이 IERC20 인터페이스를 틀로 잡고 ERC20을 작성해보자!
ERC20
IERC20 를 상속받아 작성한다. 전체코드는 맨 밑에 두었고, 세부적으로 하나하나 살펴보고자 한다.
상태 변수들
string public name;
string public symbol;
uint8 public decimals = 18;
uint public override totalSupply;
mapping(address => uint) public balances;
mapping(address => mapping(address => uint)) public override allowance;
- IERC20 인터페이스로부터 상속받은 함수들 앞에는 override 키워드를 붙였다.
*override 속성
상속받은 함수를 덮어 쓰기하겠다라는 뜻이다. override를 붙여주지 않으면 컴파일러가 경고를 준다.
알고보니 상속해주는 부모 컨트랙트가 가지고 있는 함수가 virtual 속성을 가지고 있으면, 상속받은 자식 컨트랙트는 상속받은 함수 앞에 override 속성을 달아줘야한다. 그런데 우린 IERC20을 만들 때 virtual을 붙여주지 않았는데도 override를 붙여줘야 warning 메시지를 지울 수 있었는데, 이는 interface 컨트랙트 내의 모든 함수들은 virtual 함수이기 때문에 해당 인터페이스를 상속하는 모든 함수들은 이 override 키워드를 붙여줘야하고 그로 인해 함수의 세부 내용을 변경할 수 있다고 한다!
allowance 상태변수
mapping이 이중으로 되있어서 헷갈리는데 아래와 같이 객체로 풀어서 생각해보면 이해하기 어렵지 않다.
메인 계좌를 key값으로 생각하고 속성값으로 대리 계좌가 여러 개 있다고 치면 이중으로 들어갈 수 밖에 없다.
const allowance = {
/*
메인 계좌: {
대리계좌1: 일부 amount,
대리계좌2: 일부 amount,
}
*/
"0xDDF59456E1881513f4b12CCF4527985cD7adeCc6": {
"0xb76c8f5896541b92f3Eb0c69f5764fE42e256611": 1000,
"0xb76c8f5896541b92f3Eb0c69f5764fE42e256611": 2000,
"0xb76c8f5896541b92f3Eb0c69f5764fE42e256611": 4000,
},
"0x0B4a937E2304F0D0877a035c32E7F84676ca97bc": {
"0xb76c8f5896541b92f3Eb0c69f5764fE42e256611": 50000,
},
};
approve
해당 함수를 통해 계정의 소유자가 특정 계정 혹은 CA 계정에 얼마를 위임할지 정해줘야한다.
allowance[계정소유자][대리 계정] = 대리계정에 줄 돈
위임이 성공한다면 IERC20에서 정의한 이벤트인 Approval 이벤트를 호출할 것이며 true를 리턴한다.
function approve(address spender, uint amount) external override returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
transferFrom
해당 함수에서는 sender, msg.sender가 누구를 가리키는지 인지할 필요가 있다.
- sender : 전송할 토큰을 소유한 주인, 메인 계정
- msg.sender / 해당 함수의 호출자: 메인 계정으로부터 일정량의 토큰을 위임받은 계정
=> 즉, 송금의 주체 (함수실행의 주체)가 주인 계정이 아니라 위임받은 계정인 것이다.
allowance[sender][msg.sender] 즉, 메인계정이 위임계정한테 위임한 토큰양이 amount보다 커야 함수가 실행될 것이다.
그리고 마지막에는 컨트랙트 실행 공유를 위해 Transfer 이벤트를 호출한다.
function transferFrom(address sender, address recipient, uint amount) external override returns (bool) {
require(allowance[sender][msg.sender]) > amount, "Error - lack of allowance on this caller");
allowance[sender][msg.sender] -= amount;
balances[sender] -= amount;
balances[recipient] += amount;
emit Transfer(sender, recipient, amount);
return true;
}
mint 와 burn
사실 이 두 함수는 배울 때 이해가 잘 안되서 그냥 내가 이해하기론 시장 즉, 이더리움 플랫폼 상에 풀려 있는 토큰의 총 발행량을 조절해서 토큰의 가격을 일정선에서 안정적으로 유지하기 위해 쓰이는 것 같다..
mint == 토큰 발행 및 양적완화 같은 개념?
우선, IERC20에서 상속받은 함수가 아니기에 override 속성을 붙여주지 않아도 된다.
토큰 발행에 있어 엔트리포인트 함수라고 한다. 토큰을 만들 때 ERC20 규격에 맞춰서 발행하겠다라는 뜻이며, 특정 계정에 얼마만큼의 토큰을 발행해줄지 정한다. 여기서의 msg.sender는 토큰을 발행받는 계정이며 그만큼 이더리움 플랫폼 상에 풀린 토큰의 총 발행량도 증가시켜줘야한다. 또한, 해당 함수는 특정 계정에서 토큰이 빠져나가는게 아니라, 중앙은행에서 화폐를 발행해서 시중에 돈을 푸는 거처럼 이더리움 플랫폼 상에서 토큰을 푸는 개념이므로 from에는 아무 계정도 들어가지 않는다. 따라서 null값을 의미하는 address(0)을 넣어준 것이다.
function mint(uint amount) internal {
balances[msg.sender] += amount;
totalSupply += amount;
emit Transfer(address(0), msg.sender, amount);
}
burn == 테이퍼링 같은 개념?
이 또한 IERC20에서 상속받은 함수가 아니기에 override 속성을 붙여주지 않아도 된다.
시중에 너무 많은 돈이 풀려있으면 양적완화 축소에 들어간다. 뭔가 그런걸 의미하는 것 같다. 이더리움 플랫폼 상에 너무 많은 토큰이 풀려 있으면 그 토큰의 가치는 떨어질 것이니 시중에 풀려있는 토큰을 거둬들여야한다. 근데, 이때 토큰의 총 발행량인 totalSupply를 줄인다 쳐도 msg.sender는 누구일까,, 누구의 돈을 뺏아오는걸까 아직도 의문이다. 이 부분은 나중에 물어보고 수정해야겠다..
결국 ERC20 전체코드는 아래와 같다
// contracts/ERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import "./IERC20.sol";
contract ERC20 is IERC20{
string public name;
string public symbol;
uint8 public decimals = 18;
uint public override totalSupply;
mapping(address => uint) public balances;
mapping(address => mapping(address=>uint)) public override allowance;
// 왜 이중으로 넣는가..?
function balanceOf(address account) view external override returns (uint){
return balances[account];
}
function transfer(address recipient, uint amount) external override returns (bool){
require(balances[msg.sender] >= amount, "Error - lack of sender's balance" );
balances[msg.sender] -= amount;
balances[recipient] += amount;
return true;
}
function approve(address spender, uint amount) external override returns (bool){
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transferFrom(address sender, address recipient, uint amount) external override returns (bool){
require(allowance[sender][msg.sender] > amount, "Error - lack of allowance on this caller");
allowance[sender][msg.sender] -= amount;
balances[sender] -= amount;
balances[recipient] += amount;
emit Transfer(sender, recipient, amount);
return true;
}
function mint(uint amount) internal {
balances[msg.sender] += amount;
totalSupply += amount;
emit Transfer(address(0), msg.sender, amount);
}
function burn(uint amount) external {
balances[msg.sender] -= amount;
totalSupply -= amount;
emit Transfer(msg.sender, address(0), amount);
}
}
이 ERC20 컨트랙트 기준으로 다음 포스팅에선 나만의 토큰을 위한 컨트랙트 작성을 해볼거다.
'BlockChain' 카테고리의 다른 글
ether-token 스왑 / 토큰발행 컨트랙트+스왑전용 컨트랙트 (0) | 2022.07.25 |
---|---|
ERC-20 나만의 토큰 작성 / fallback, receive? / 이더로 토큰 사기 (0) | 2022.07.22 |
ETHER 전송을 위한 스마트 컨트랙트 작성 (payable) (0) | 2022.07.21 |
스마트 컨트랙트로 초간단 투표 dApp 만들기 (0) | 2022.07.20 |
스마트 컨트랙트로 토큰 발행 및 전송해보기 (0) | 2022.07.19 |