forked from onflow/kitty-items
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathFungibleToken.cdc
199 lines (167 loc) · 6.82 KB
/
FungibleToken.cdc
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/**
# The Flow Fungible Token standard
## `FungibleToken` contract interface
The interface that all fungible token contracts would have to conform to.
If a users wants to deploy a new token contract, their contract
would need to implement the FungibleToken interface.
Their contract would have to follow all the rules and naming
that the interface specifies.
## `Vault` resource
Each account that owns tokens would need to have an instance
of the Vault resource stored in their account storage.
The Vault resource has methods that the owner and other users can call.
## `Provider`, `Receiver`, and `Balance` resource interfaces
These interfaces declare pre-conditions and post-conditions that restrict
the execution of the functions in the Vault.
They are separate because it gives the user the ability to share
a reference to their Vault that only exposes the fields functions
in one or more of the interfaces.
It also gives users the ability to make custom resources that implement
these interfaces to do various things with the tokens.
For example, a faucet can be implemented by conforming
to the Provider interface.
By using resources and interfaces, users of FungibleToken contracts
can send and receive tokens peer-to-peer, without having to interact
with a central ledger smart contract. To send tokens to another user,
a user would simply withdraw the tokens from their Vault, then call
the deposit function on another user's Vault to complete the transfer.
*/
/// FungibleToken
///
/// The interface that fungible token contracts implement.
///
pub contract interface FungibleToken {
/// The total number of tokens in existence.
/// It is up to the implementer to ensure that the total supply
/// stays accurate and up to date
///
pub var totalSupply: UFix64
/// TokensInitialized
///
/// The event that is emitted when the contract is created
///
pub event TokensInitialized(initialSupply: UFix64)
/// TokensWithdrawn
///
/// The event that is emitted when tokens are withdrawn from a Vault
///
pub event TokensWithdrawn(amount: UFix64, from: Address?)
/// TokensDeposited
///
/// The event that is emitted when tokens are deposited into a Vault
///
pub event TokensDeposited(amount: UFix64, to: Address?)
/// Provider
///
/// The interface that enforces the requirements for withdrawing
/// tokens from the implementing type.
///
/// It does not enforce requirements on `balance` here,
/// because it leaves open the possibility of creating custom providers
/// that do not necessarily need their own balance.
///
pub resource interface Provider {
/// withdraw subtracts tokens from the owner's Vault
/// and returns a Vault with the removed tokens.
///
/// The function's access level is public, but this is not a problem
/// because only the owner storing the resource in their account
/// can initially call this function.
///
/// The owner may grant other accounts access by creating a private
/// capability that allows specific other users to access
/// the provider resource through a reference.
///
/// The owner may also grant all accounts access by creating a public
/// capability that allows all users to access the provider
/// resource through a reference.
///
pub fun withdraw(amount: UFix64): @Vault {
post {
// `result` refers to the return value
result.balance == amount:
"Withdrawal amount must be the same as the balance of the withdrawn Vault"
}
}
}
/// Receiver
///
/// The interface that enforces the requirements for depositing
/// tokens into the implementing type.
///
/// We do not include a condition that checks the balance because
/// we want to give users the ability to make custom receivers that
/// can do custom things with the tokens, like split them up and
/// send them to different places.
///
pub resource interface Receiver {
/// deposit takes a Vault and deposits it into the implementing resource type
///
pub fun deposit(from: @Vault)
}
/// Balance
///
/// The interface that contains the `balance` field of the Vault
/// and enforces that when new Vaults are created, the balance
/// is initialized correctly.
///
pub resource interface Balance {
/// The total balance of a vault
///
pub var balance: UFix64
init(balance: UFix64) {
post {
self.balance == balance:
"Balance must be initialized to the initial balance"
}
}
}
/// Vault
///
/// The resource that contains the functions to send and receive tokens.
///
pub resource Vault: Provider, Receiver, Balance {
// The declaration of a concrete type in a contract interface means that
// every Fungible Token contract that implements the FungibleToken interface
// must define a concrete `Vault` resource that conforms to the `Provider`, `Receiver`,
// and `Balance` interfaces, and declares their required fields and functions
/// The total balance of the vault
///
pub var balance: UFix64
// The conforming type must declare an initializer
// that allows prioviding the initial balance of the Vault
//
init(balance: UFix64)
/// withdraw subtracts `amount` from the Vault's balance
/// and returns a new Vault with the subtracted balance
///
pub fun withdraw(amount: UFix64): @Vault {
pre {
self.balance >= amount:
"Amount withdrawn must be less than or equal than the balance of the Vault"
}
post {
// use the special function `before` to get the value of the `balance` field
// at the beginning of the function execution
//
self.balance == before(self.balance) - amount:
"New Vault balance must be the difference of the previous balance and the withdrawn Vault"
}
}
/// deposit takes a Vault and adds its balance to the balance of this Vault
///
pub fun deposit(from: @Vault) {
post {
self.balance == before(self.balance) + before(from.balance):
"New Vault balance must be the sum of the previous balance and the deposited Vault"
}
}
}
/// createEmptyVault allows any user to create a new Vault that has a zero balance
///
pub fun createEmptyVault(): @Vault {
post {
result.balance == 0.0: "The newly created Vault must have zero balance"
}
}
}