[BlockChain] ERC20
- -
안뇽안뇽~~ 오랜만이야 나는 rhenus라고 해!!
다들 반갑구 ㅎㅎ 요즘 나는 blockchain에 푹 빠져 있어서 공부하면서 여러 가지 지식을 블로그를 통해 정리하려고 해
그래서 오늘!!!! 주제는 무엇이냐 바로바로 ERC-20이라는 말씀
ERC-20
ERC-20이 뭘까??
Ethereum Request for Comment 20의 약자이며 Ethereum 공식 문서에 따르면 대체 가능 토큰에 대한 표준을 도입한다고 나와있어.
즉, 이더리움 네트워크 상에서 유통할 수 있는 토큰의 호환성을 보장하기 위한 표준 사양인데 왜 이런 표준이 생겼을까?? 궁금하지??
http://wiki.hash.kr/index.php/ERC-20
해시넷에 설명이 정말 잘되어 있어서 내용을 정리해 보자면
이더리움은 블록체인을 기반으로 다양한 탈중앙화 된 애플리케이션들이 작동할 수 있도록 고안된 하나의 플랫폼 네트워크야. 조금 쉽게 설명하면
안드로이드 나 iOS처럼 app들이 존재하는 하나의 플랫폼이라는 뜻이지. 그리고 이런 플랫폼 위에 있는 app이 Dapp이고
이해했어?? 여기까진 쉽지??
Dapp은 이러한 이더리움 플랫폼에서 smart contract를 이용하여 쉽고 빠르게 토큰을 발행할 수 있어. 그래서 Dapp은 app의 특성에 맞게 사용할 수 있는 토큰을 발행할 수 있어. 그러면 각각의 Dapp에서 발행한 토큰은 독자적인 토큰인 듯 하지만 이더리움 플랫폼 특징 중 하나는 각각의 Dapp이 발행한 토큰을 통합하는 것이 가능해
신기하지?? 그런데 토큰을 통합하기 위해서는 기준이 있어야 하잖아?? 그래서 나온 표준이 ERC-20이라는 거야
ERC-20은 이더리움 토큰에 대한 통합 규격 목록을 정의하여 개발자가 토큰 간 상호 작용을 예측할 수 있으며 주소 간 토큰을 전송하는 방법과 토큰 내의 데이터에 접근하는 방법도 포함되어 있어.
또한 ERC-20은 Dapp에서 발행된 토큰이 ETH와 호환성을 충족하기 위해 규정하고 있는 프로그래밍 기준이야. 그래서 이러한 기준에 맞게 Dapp을 설계한 후 토큰을 발행하면 ETH와 쉽게 교환할 수 있고 표준 이더리움 지갑에 자유롭게 전송할 수 있찌 ㅎㅎ
여기까지 이해했으면 다 같이 기능에 대해 살펴볼까??
Method
기본 Method는 name, symbol, decimals가 있다.
/* token 이름 */
function name() public view virtual override returns (string memory) {
return _name;
}
/* token symbol */
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/* ether는 10^18이므로 18을 return */
function decimals() public view virtual override returns (uint8) {
return 18;
}
기능을 하는 Method는 totalSupply(), balanceOf(), transfer(), transferFrom(), approve(), allowance()가 있다.
/* 전체 token의 수 */
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/* account의 잔액 */
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/* to에 amount의 token을 송금 */
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
/* spender가 owner의 계좌에서 몇개의 token을 가져갈 수 있는지 확인 */
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/* spender에게 최대 amount의 token을 가져갈 수 있다는 것을 승인 */
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
/* from에서 to로 amount의 token을 송금 */
function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
/* maximum으로 가져갈 수 있는 token을 증가 */
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
/* maximum으로 가져갈 수 있는 token을 감소 */
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
// owner -> spender로 amount를 승인해준다.
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
// 사용한 amount를 기준으로 owner -> spender를 update함
function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
// fromBalance에서 amount를 출금 -> toBalance에서 송금
function _transfer(address from, address to, uint256 amount) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
// Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
// decrementing then incrementing.
_balances[to] += amount;
}
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
Event
/* token이 _from에서 _to로 옮겨지면 발생 */
event Transfer(address indexed _from, address indexed _to, uint256 _value)
/* _owner에 의해 _spender가 최대 _value만큼 출금할 수 있다고 승인 될때 발생 */
event Approval(address indexed _owner, address indexed _spender, uint256 _value)
ERC-20의 기능들을 살펴보았는데 Method 중 approve()랑 굳이 transfer()이 있는데 transferFrom()은 왜 있지??라는 생각이 들지 않아??
이 부분에 대해서 설명 해주께!! 걱정 마~~
자 여기 사슴과 곰이 있는데 둘이 친구야 신용도 좋아 ㅎㅎ
사슴이 아마존으로 유학을 가서 한몇 년간 못 보게 되었지... 사슴은 돈을 저금하고 싶어서 은행을 찾던 중 마침 아마존에 자기 지역에 있는 은행이 보이는 거야
그래서 사슴은 은행에 1000 token을 저금했어.
어느 날 곰이 급전이 필요하다고 50 token만 빌려달래. 사슴은 곰과 친구이기도 하고 신용도 좋아서 빌려주기로 했어. 그런데 사슴은 유학을 가서 직접 곰에게 줄 수도 없고 심지어 계좌도 몰라.....
이러한 상태에서 token을 줄 수 있는 방법이 approve()와 transferFrom() 함수야
어떻게 하냐!! 아까 사슴이 자기 지역에 있는 은행을 봤다고 했지?? 그래서 그 은행에 내 친구 곰이 내 계좌에서 token을 인출할 것이다. 그러니 최대 100 token까지 인출할 수 있게 허용할 것이다.라고 은행에 말하고 승인을 받았어
그러면 곰은 똑같은 은행에 가서 자기 이름을 대고 인출을 하면 살제로 사슴의 계좌에서 token이 빠져나가잖아.
이러한 프로세스를 가지는 게 approve() 랑 transferFrom() 메서드인 거야!! 이해했쥥??
나도 아직 블록체인 초보라서... 많이 틀릴 수도 있고 이상할 수도 있는데... 우리 같이 성장해 나가 보자!!
긴 글 읽느라 고생해또
'Web3 > BlockChain' 카테고리의 다른 글
[BlockChain] DeFiVulnLabs - Integer overflow (0) | 2023.02.05 |
---|---|
[BlockChain] DeFiHackLabs - 3. Write Your Own PoC (0) | 2023.02.05 |
[BlockChain] DeFiHackLabs - 2. Warmup (0) | 2023.02.05 |
[BlockChain] Contract & Assembly (0) | 2023.02.02 |
[BlockChain] DelegateCall (0) | 2023.02.02 |
소중한 공감 감사합니다