ERC20 Token¶
Warning
This is example code for learning purposes. Do not use in production without thorough review and testing.
A standard ERC20 fungible token implementation.
1#pragma version >0.3.10
2
3###########################################################################
4## THIS IS EXAMPLE CODE, NOT MEANT TO BE USED IN PRODUCTION! CAVEAT EMPTOR!
5###########################################################################
6
7# @dev example implementation of an ERC20 token
8# @author Takayuki Jimba (@yudetamago)
9# https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
10
11from ethereum.ercs import IERC20
12from ethereum.ercs import IERC20Detailed
13
14implements: IERC20
15implements: IERC20Detailed
16
17name: public(String[32])
18symbol: public(String[32])
19decimals: public(uint8)
20
21# NOTE: By declaring `balanceOf` as public, vyper automatically generates a 'balanceOf()' getter
22# method to allow access to account balances.
23# The _KeyType will become a required parameter for the getter and it will return _ValueType.
24# See: https://docs.vyperlang.org/en/v0.1.0-beta.8/types.html?highlight=getter#mappings
25balanceOf: public(HashMap[address, uint256])
26# By declaring `allowance` as public, vyper automatically generates the `allowance()` getter
27allowance: public(HashMap[address, HashMap[address, uint256]])
28# By declaring `totalSupply` as public, we automatically create the `totalSupply()` getter
29totalSupply: public(uint256)
30minter: address
31
32
33@deploy
34def __init__(_name: String[32], _symbol: String[32], _decimals: uint8, _supply: uint256):
35 init_supply: uint256 = _supply * 10 ** convert(_decimals, uint256)
36 self.name = _name
37 self.symbol = _symbol
38 self.decimals = _decimals
39 self.balanceOf[msg.sender] = init_supply
40 self.totalSupply = init_supply
41 self.minter = msg.sender
42 log IERC20.Transfer(sender=empty(address), receiver=msg.sender, value=init_supply)
43
44
45@external
46def transfer(_to : address, _value : uint256) -> bool:
47 """
48 @dev Transfer token for a specified address
49 @param _to The address to transfer to.
50 @param _value The amount to be transferred.
51 """
52 # NOTE: vyper does not allow underflows
53 # so the following subtraction would revert on insufficient balance
54 self.balanceOf[msg.sender] -= _value
55 self.balanceOf[_to] += _value
56 log IERC20.Transfer(sender=msg.sender, receiver=_to, value=_value)
57 return True
58
59
60@external
61def transferFrom(_from : address, _to : address, _value : uint256) -> bool:
62 """
63 @dev Transfer tokens from one address to another.
64 @param _from address The address which you want to send tokens from
65 @param _to address The address which you want to transfer to
66 @param _value uint256 the amount of tokens to be transferred
67 """
68 # NOTE: vyper does not allow underflows
69 # so the following subtraction would revert on insufficient balance
70 self.balanceOf[_from] -= _value
71 self.balanceOf[_to] += _value
72 # NOTE: vyper does not allow underflows
73 # so the following subtraction would revert on insufficient allowance
74 self.allowance[_from][msg.sender] -= _value
75 log IERC20.Transfer(sender=_from, receiver=_to, value=_value)
76 return True
77
78
79@external
80def approve(_spender : address, _value : uint256) -> bool:
81 """
82 @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
83 Beware that changing an allowance with this method brings the risk that someone may use both the old
84 and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
85 race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
86 https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
87 @param _spender The address which will spend the funds.
88 @param _value The amount of tokens to be spent.
89 """
90 self.allowance[msg.sender][_spender] = _value
91 log IERC20.Approval(owner=msg.sender, spender=_spender, value=_value)
92 return True
93
94
95@external
96def mint(_to: address, _value: uint256):
97 """
98 @dev Mint an amount of the token and assigns it to an account.
99 This encapsulates the modification of balances such that the
100 proper events are emitted.
101 @param _to The account that will receive the created tokens.
102 @param _value The amount that will be created.
103 """
104 assert msg.sender == self.minter
105 assert _to != empty(address)
106 self.totalSupply += _value
107 self.balanceOf[_to] += _value
108 log IERC20.Transfer(sender=empty(address), receiver=_to, value=_value)
109
110
111@internal
112def _burn(_to: address, _value: uint256):
113 """
114 @dev Internal function that burns an amount of the token of a given
115 account.
116 @param _to The account whose tokens will be burned.
117 @param _value The amount that will be burned.
118 """
119 assert _to != empty(address)
120 self.totalSupply -= _value
121 self.balanceOf[_to] -= _value
122 log IERC20.Transfer(sender=_to, receiver=empty(address), value=_value)
123
124
125@external
126def burn(_value: uint256):
127 """
128 @dev Burn an amount of the token of msg.sender.
129 @param _value The amount that will be burned.
130 """
131 self._burn(msg.sender, _value)
132
133
134@external
135def burnFrom(_to: address, _value: uint256):
136 """
137 @dev Burn an amount of the token from a given account.
138 @param _to The account whose tokens will be burned.
139 @param _value The amount that will be burned.
140 """
141 self.allowance[_to][msg.sender] -= _value
142 self._burn(_to, _value)
Key features:
Implements the
IERC20andIERC20Detailedinterfaces fromethereum.ercsStandard
transfer,transferFrom, andapprovefunctionsmintandburnfunctions for supply managementUses
HashMapfor balances and allowances
Note
This is example code. Production tokens require additional security review.
Notice how Vyper’s overflow/underflow protection is built-in: the comment “vyper does not allow underflows” explains why no explicit check is needed when subtracting from balances.