-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathNftlyToken.cdc
177 lines (158 loc) · 6.61 KB
/
NftlyToken.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
// NftlyToken.cdc
//
// The NftlyToken contract is a sample implementation of a fungible token on Flow.
//
// Fungible tokens behave like everyday currencies -- they can be minted, transferred or
// traded for digital goods.
pub contract NftlyToken {
// Total supply of all tokens in existence.
pub var totalSupply: UFix64
// Provider
//
// Interface that enforces the requirements for withdrawing
// tokens from the implementing type.
//
// We don't enforce requirements on self.balance here because
// it leaves open the possibility of creating custom providers
// that don't necessarily need their own balance.
//
pub resource interface Provider {
// withdraw
//
// Function that subtracts tokens from the owner's Vault
// and returns a Vault resource (@Vault) with the removed tokens.
//
// The function's access level is public, but this isn't a problem
// because even the public functions are not fully public at first.
// anyone in the network can call them, but only if the owner grants
// them access by publishing a resource that exposes the withdraw
// function.
//
pub fun withdraw(amount: UFix64): @Vault {
post {
// `result` refers to the return value of the function
result.balance == UFix64(amount):
"Withdrawal amount must be the same as the balance of the withdrawn Vault"
}
}
}
// Receiver
//
// Interface that enforces the requirements for depositing
// tokens into the implementing type.
//
// We don't 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
//
// Function that can be called to deposit tokens
// into the implementing resource type
//
pub fun deposit(from: @Vault)
}
// Balance
//
// Interface that specifies a public `balance` field for the vault
//
pub resource interface Balance {
pub var balance: UFix64
}
// Vault
//
// Each user stores an instance of only the Vault in their storage
// The functions in the Vault and governed by the pre and post conditions
// in the interfaces when they are called.
// The checks happen at runtime whenever a function is called.
//
// Resources can only be created in the context of the contract that they
// are defined in, so there is no way for a malicious user to create Vaults
// out of thin air. A special Minter resource needs to be defined to mint
// new tokens.
//
pub resource Vault: Provider, Receiver, Balance {
// keeps track of the total balance of the account's tokens
pub var balance: UFix64
// initialize the balance at resource creation time
init(balance: UFix64) {
self.balance = balance
}
// withdraw
//
// Function that takes an integer amount as an argument
// and withdraws that amount from the Vault.
//
// It creates a new temporary Vault that is used to hold
// the money that is being transferred. It returns the newly
// created Vault to the context that called so it can be deposited
// elsewhere.
//
pub fun withdraw(amount: UFix64): @Vault {
self.balance = self.balance - amount
return <-create Vault(balance: amount)
}
// deposit
//
// Function that takes a Vault object as an argument and adds
// its balance to the balance of the owners Vault.
//
// It is allowed to destroy the sent Vault because the Vault
// was a temporary holder of the tokens. The Vault's balance has
// been consumed and therefore can be destroyed.
pub fun deposit(from: @Vault) {
self.balance = self.balance + from.balance
destroy from
}
}
// createEmptyVault
//
// Function that creates a new Vault with a balance of zero
// and returns it to the calling context. A user must call this function
// and store the returned Vault in their storage in order to allow their
// account to be able to receive deposits of this token type.
//
pub fun createEmptyVault(): @Vault {
return <-create Vault(balance: 0.0)
}
// VaultMinter
//
// Resource object that an admin can control to mint new tokens
pub resource VaultMinter {
// Function that mints new tokens and deposits into an account's vault
// using their `Receiver` reference.
// We say `&AnyResource{Receiver}` to say that the recipient can be any resource
// as long as it implements the Receiver interface
pub fun mintTokens(amount: UFix64, recipient: Capability<&AnyResource{Receiver}>) {
let recipientRef = recipient.borrow()
?? panic("Could not borrow a receiver reference to the vault")
NftlyToken.totalSupply = NftlyToken.totalSupply + UFix64(amount)
recipientRef.deposit(from: <-create Vault(balance: amount))
}
}
// The init function for the contract. All fields in the contract must
// be initialized at deployment. This is just an example of what
// an implementation could do in the init function. The numbers are arbitrary.
init() {
self.totalSupply = 10000.0
// create the Vault with the initial balance and put it in storage
// account.save saves an object to the specified `to` path
// The path is a literal path that consists of a domain and identifier
// The domain must be `storage`, `private`, or `public`
// the identifier can be any name
let vault <- create Vault(balance: self.totalSupply)
self.account.save(<-vault, to: /storage/MainVault)
// Create a new MintAndBurn resource and store it in account storage
self.account.save(<-create VaultMinter(), to: /storage/MainMinter)
// Create a private capability link for the Minter
// Capabilities can be used to create temporary references to an object
// so that callers can use the reference to access fields and functions
// of the objet.
//
// The capability is stored in the /private/ domain, which is only
// accesible by the owner of the account
self.account.link<&VaultMinter>(/private/Minter, target: /storage/MainMinter)
}
}