ERC20 Token
ERC20 is one of the first token standards created in the Ethereum ecosystem. It was proposed by Fabian Vogelsteller in 2015 and to date it remains on of the most widely used token standards.
Further information on the standard can be found here:

Implementation in Vyper

erc20.vy
1
# Author: Sören Steiger, twitter.com/ssteiger_
2
# License: MIT
3
4
# ERC20 Token Standard
5
# https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
6
7
8
from vyper.interfaces import ERC20
9
10
implements: ERC20
11
12
# EVENTS:
13
14
# ----- Transfer -----
15
# MUST trigger when tokens are transferred, including zero value transfers.
16
# A token contract which creates new tokens SHOULD trigger a Transfer event
17
# with the _from address set to 0x0 when tokens are created.
18
Transfer: event({_from: indexed(address), _to: indexed(address), _value: uint256})
19
20
# ----- Approval -----
21
# MUST trigger on any successful call to approve(address _spender, uint256 _value).
22
Approval: event({_owner: indexed(address), _spender: indexed(address), _value: uint256})
23
24
25
# STATE VARIABLES:
26
# values which are permanently stored in contract storage
27
28
# ----- name -----
29
# Returns the name of the token - e.g. "MyToken".
30
# OPTIONAL - This method can be used to improve usability, but interfaces and
31
# other contracts MUST NOT expect these values to be present.
32
name: public(string[64]) # TODO: is this an acceptable size?
33
34
# ----- symbol -----
35
# Returns the symbol of the token. E.g. "HIX".
36
# OPTIONAL - This method can be used to improve usability, but interfaces and
37
# other contracts MUST NOT expect these values to be present.
38
symbol: public(string[32]) # TODO: is this an acceptable size?
39
40
# ----- decimals -----
41
# Returns the number of decimals the token uses - e.g. 8, means to divide
42
# the token amount by 100000000 to get its user representation.
43
# OPTIONAL - This method can be used to improve usability, but interfaces and
44
# other contracts MUST NOT expect these values to be present.
45
decimals: public(uint256)
46
47
# ----- totalSupply -----
48
# Returns the total token supply.
49
totalSupply: public(uint256)
50
51
# mappings
52
balanceOf: public(map(address, uint256))
53
approvedFunds: map(address, map(address, uint256))
54
55
56
@public
57
def __init__(_name: string[64], _symbol: string[32], _decimals: uint256, _totalSupply: uint256):
58
self.name = _name
59
self.symbol = _symbol
60
self.decimals = _decimals
61
self.totalSupply = _totalSupply * 10 ** _decimals
62
# mint all tokens to the contract creator
63
self.balanceOf[msg.sender] = self.totalSupply
64
# fire transfer event
65
log.Transfer(ZERO_ADDRESS, msg.sender, self.totalSupply)
66
67
68
# METHODS:
69
70
# NOTES:
71
# Callers MUST handle false from returns (bool success).
72
# Callers MUST NOT assume that false is never returned!
73
74
75
# ----- balanceOf -----
76
# Returns the account balance of another account with address _owner.
77
# See: https://github.com/ethereum/vyper/issues/1241
78
# And: https://vyper.readthedocs.io/en/v0.1.0-beta.8/types.html?highlight=getter#mappings
79
80
81
# ----- transfer -----
82
# Transfers _value amount of tokens to address _to, and MUST fire the Transfer
83
# event. The function SHOULD throw if the _from account balance does not have
84
# enough tokens to spend.
85
86
# NOTE: Transfers of 0 values MUST be treated as normal transfers and fire the
87
# Transfer event.
88
@public
89
def transfer(_to: address, _value: uint256) -> bool:
90
# NOTE: vyper does not allow unterflows
91
# so checks for sufficient funds are done implicitly
92
# see https://github.com/ethereum/vyper/issues/1237#issuecomment-461957413
93
# substract balance from sender
94
self.balanceOf[msg.sender] -= _value
95
# add balance to recipient
96
self.balanceOf[_to] += _value
97
# fire transfer event
98
log.Transfer(msg.sender, _to, _value)
99
return True
100
101
102
# ----- transferFrom -----
103
# Transfers _value amount of tokens from address _from to address _to,
104
# and MUST fire the Transfer event.
105
106
# The transferFrom method is used for a withdraw workflow, allowing contracts
107
# to transfer tokens on your behalf. This can be used for example to allow a
108
# contract to transfer tokens on your behalf and/or to charge fees in
109
# sub-currencies. The function SHOULD throw unless the _from account has
110
# deliberately authorized the sender of the message via some mechanism.
111
112
# NOTE: Transfers of 0 values MUST be treated as normal transfers and fire the
113
# Transfer event.
114
@public
115
def transferFrom(_from: address, _to: address, _value: uint256) -> bool:
116
# NOTE: vyper does not allow unterflows
117
# so checks for sufficient funds are done implicitly
118
# see https://github.com/ethereum/vyper/issues/1237#issuecomment-461957413
119
# update sender balance
120
self.balanceOf[_from] -= _value
121
# update recipient balance
122
self.balanceOf[_to] += _value
123
# update approved funds
124
self.approvedFunds[_from][msg.sender] -= _value
125
# fire transfer event
126
log.Transfer(_from, _to, _value)
127
return True
128
129
130
# ----- approve -----
131
# Allows _spender to withdraw from your account multiple times, up to the _value
132
# amount. If this function is called again it overwrites the current allowance
133
# with _value.
134
135
# NOTE: To prevent attack vectors like the one described here and discussed here,
136
# clients SHOULD make sure to create user interfaces in such a way that they set
137
# the allowance first to 0 before setting it to another value for the same
138
# spender. THOUGH The contract itself shouldn't enforce it, to allow backwards
139
# compatibility with contracts deployed before.
140
@public
141
def approve(_spender: address, _value: uint256) -> bool:
142
# overwrites the current allowance
143
self.approvedFunds[msg.sender][_spender] = _value
144
# fire approval event
145
log.Approval(msg.sender, _spender, _value)
146
return True
147
148
149
# ----- allowance -----
150
# Returns the amount which _spender is still allowed to withdraw from _owner.
151
@public
152
@constant
153
def allowance(_owner: address, _spender: address) -> uint256:
154
return self.approvedFunds[_owner][_spender]
Copied!
Last modified 2yr ago
Copy link