Todo :
1. Mint 함수 구현
2. 이벤트 구현
3. modifier 기능 구현
describe("Mint", () => {
// 1MT = 1*(10^18) = 1n*10n**18n = BigInt(1*10**18)
it("should retrun initial supply + 1MT balance for signer 0", async () => {
const signer0 = signers[0];
const oneMt = hre.ethers.parseUnits("1", DECIMALS);
await myTokenC.mint(oneMt, signer0.address);
expect(await myTokenC.balanceOf(signer0.address)).equal(
MINTING_AMOUNT * 10n ** DECIMALS + oneMt,
);
});
...
});
기존의 "should retrun 100 totalSupply"와 동일하던 테스트코드를
"should retrun initial supply + 1MT balance for signer 0"로 변경하여 mint함수의 작동을 확인하는 테스트코드 작성
@internal
def _mint(_amount: uint256, _to: address):
self.balanceOf[_to] += _amount
self.totalSupply += _amount
@external
def mint(_amount: uint256, _to: address):
self._mint(_amount, _to)
mint함수 추가.
vyper는 typechain이 자동으로 생기지 않음
❯ npx hardhat compile
// → artifacts 생성됨
❯ npx hardhat typechain
// → typechain-types 생성됨
# @version ^0.3.0
# @license MIT
event Transfer:
owner: indexed(address) #from은 예약어
to: indexed(address)
amount: uint256
event Approval:
# 원래는 owner: address 까지 적어주는 것 권장 (msg.sender로 사용할 수 있지만)
spender: indexed(address)
amount: uint256
name: public(String[64])
symbol: public(String[32])
decimals: public(uint256)
totalSupply: public(uint256)
#바이퍼만 스네이크 대신 낙타 사용..
balanceOf: public(HashMap[address, uint256])
allowances: public(HashMap[address, HashMap[address, uint256]])
@external
def __init__(_name: String[64], _symbol: String[32], _decimals: uint256, _initialSupply: uint256):
self.name = _name
self.symbol = _symbol
self.decimals = _decimals
self.totalSupply = _initialSupply * 10 ** 18
self.balanceOf[msg.sender] += _initialSupply * 10 ** 18
@external
def transfer(_amount:uint256, _to:address):
assert self.balanceOf[msg.sender] >= _amount, "insufficient balance" #require 역할
self.balanceOf[msg.sender] -= _amount
self.balanceOf[_to] += _amount
#emit이던게 log로 변함
log Transfer(msg.sender, _to, _amount)
@external
def approve( _spender:address, _amount:uint256):
# assert self.balanceOf[_owner] >= _amount, "insuffient balance"
self.allowances[msg.sender][_spender] += _amount
log Approval(_spender, _amount)
@external
def transferFrom(_owner:address, _to:address, _amount:uint256):
assert self.allowances[_owner][msg.sender] >= _amount, "insufficient allowance"
assert self.balanceOf[_owner] >= _amount, "insufficient balance"
self.balanceOf[_owner] -= _amount
self.balanceOf[_to] += _amount
self.allowances[_owner][msg.sender] -= _amount
log Transfer(_owner, _to, _amount)
@internal
def _mint(_amount: uint256, _to: address):
self.balanceOf[_to] += _amount
self.totalSupply += _amount
#zero address in solidity : address(0)
log Transfer(ZERO_ADDRESS, _to, _amount)
@external
def mint(_amount: uint256, _to: address):
self._mint(_amount, _to)
event 정의
event EventName: name: type name: indexed(type) //인덱스를 할 경우형태로 사용한다.
+ from이 import할 때 사용되는 예약어라서 owner로 바꿔서 사용했다.
event 발생
solidity 에서 사용하던
emit대신
vyper에서는log를 사용하여log Transfer(ZERO_ADDRESS, _to, _amount)형태로 사용한다.
+ "zero address" 사용은
solidity에서 address(0)로 사용한 것과 달리
vyper에서는 ZERO_ADDRESS를 사용한다.zero address란? 참고 :
- stackoverflow - What is address(0) in Solidity
- metaschool - What is Address(0) in Solidity
>> vyper에는 modifier가 없다....! <<
그래서 직접 함수로 구현해줘야 한다...!
# @version ^0.3.0
# @license MIT
event Transfer:
owner: indexed(address) #from은 예약어
to: indexed(address)
amount: uint256
event Approval:
# 원래는 owner: address 까지 적어주는 것 권장 (msg.sender로 사용할 수 있지만)
spender: indexed(address)
amount: uint256
#추가
owner: address
manager: address
name: public(String[64])
symbol: public(String[32])
decimals: public(uint256)
totalSupply: public(uint256)
#바이퍼만 스네이크 대신 낙타 사용..
balanceOf: public(HashMap[address, uint256])
allowances: public(HashMap[address, HashMap[address, uint256]])
@external
def __init__(_name: String[64], _symbol: String[32], _decimals: uint256, _initialSupply: uint256):
self.name = _name
self.symbol = _symbol
self.decimals = _decimals
self.totalSupply = _initialSupply * 10 ** 18
self.balanceOf[msg.sender] += _initialSupply * 10 ** 18
#추가
self.owner = msg.sender
self.manager = msg.sender
# 함수 호출 시 함수 정의 순서 중요
@internal
def onlyOwner(_owner: address):
assert self.owner == _owner, "You are not authorized"
@internal
def onlyManager(_manager: address):
assert self.manager == _manager, "You are not authorized to manage this contract"
@external
def transfer(_amount:uint256, _to:address):
assert self.balanceOf[msg.sender] >= _amount, "insufficient balance" #require 역할
self.balanceOf[msg.sender] -= _amount
self.balanceOf[_to] += _amount
#emit이던게 log로 변함
log Transfer(msg.sender, _to, _amount)
@external
def approve( _spender:address, _amount:uint256):
# assert self.balanceOf[_owner] >= _amount, "insuffient balance"
self.allowances[msg.sender][_spender] += _amount
log Approval(_spender, _amount)
@external
def transferFrom(_owner:address, _to:address, _amount:uint256):
assert self.allowances[_owner][msg.sender] >= _amount, "insufficient allowance"
assert self.balanceOf[_owner] >= _amount, "insufficient balance"
self.balanceOf[_owner] -= _amount
self.balanceOf[_to] += _amount
self.allowances[_owner][msg.sender] -= _amount
log Transfer(_owner, _to, _amount)
@internal
def _mint(_amount: uint256, _to: address):
self.balanceOf[_to] += _amount
self.totalSupply += _amount
#zero address in solidity : address(0)
log Transfer(ZERO_ADDRESS, _to, _amount)
@external
def mint(_amount: uint256, _to: address):
self.onlyManager(msg.sender)
self._mint(_amount, _to)
@external
def setManager(_manager: address):
self.onlyOwner(msg.sender)
self.manager = _manager
# msg.sender is not allowed in internal functions
# Function does not exist or has not been declared
일단 owner와 manager 주소를 선언하고, 생성자에서 msg.sender로 할당해준다.
onlyOwner, onlyManager 함수를 만들어준다
내부에는 assert (require)로 호출자가 owner인지 확인해준다.
* 이 때,
assert self.owner == msg.sender, "~~"와 같이
msg.sender를 바로 함수 내부에 사용하면
msg.sender is not allowed in internal functions
오류가 난다.
internal 함수에서는msg.sender에 접근할 수 없기에 (vyper 특성)
msg.sender를 매개변수로 받는다.
( 이후 사용 시self.onlyManager(msg.sender)처럼 사용)
* 또한, vyper는 함수의 선언 위치에 따라 사용에 제한이 있다.
함수가 사용되는 곳보다 나중에 함수가 선언되면 사용이 불가능하다.
(아래와 같은 오류가 남)
Function does not exist or has not been declared
따라서onlyOwner,onlyManager함수를 생성자 밑으로 가져와줬다.
self.onlyManager(msg.sender)와 self.onlyOwner(msg.sender)를 추가해준다.이렇게 수정을 마치면
MyToken.ts의 테스트는 모두 통과하는 것을 볼 수 있다.

TinyBank를 vyper로 만들어본다.