@flowtyio/flow-contracts 0.0.11 → 0.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/add.js +44 -4
- package/contracts/FlowStorageFees.cdc +193 -0
- package/contracts/FlowToken.cdc +274 -0
- package/contracts/FungibleTokenMetadataViews.cdc +183 -0
- package/contracts/TokenForwarding.cdc +82 -0
- package/contracts/dapper/DapperUtilityCoin.cdc +199 -0
- package/contracts/dapper/FlowUtilityToken.cdc +199 -0
- package/contracts/lost-and-found/FeeEstimator.cdc +62 -0
- package/contracts/lost-and-found/LostAndFound.cdc +758 -0
- package/contracts/lost-and-found/LostAndFoundHelper.cdc +42 -0
- package/contracts/nft-catalog/NFTCatalog.cdc +422 -0
- package/contracts/nft-catalog/NFTCatalogAdmin.cdc +175 -0
- package/flow.json +107 -2
- package/index.js +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import "FungibleToken"
|
|
2
|
+
import "MetadataViews"
|
|
3
|
+
|
|
4
|
+
/// This contract implements the metadata standard proposed
|
|
5
|
+
/// in FLIP-1087.
|
|
6
|
+
///
|
|
7
|
+
/// Ref: https://github.com/onflow/flow/blob/master/flips/20220811-fungible-tokens-metadata.md
|
|
8
|
+
///
|
|
9
|
+
/// Structs and resources can implement one or more
|
|
10
|
+
/// metadata types, called views. Each view type represents
|
|
11
|
+
/// a different kind of metadata.
|
|
12
|
+
///
|
|
13
|
+
pub contract FungibleTokenMetadataViews {
|
|
14
|
+
/// FTView wraps FTDisplay and FTVaultData, and is used to give a complete
|
|
15
|
+
/// picture of a Fungible Token. Most Fungible Token contracts should
|
|
16
|
+
/// implement this view.
|
|
17
|
+
///
|
|
18
|
+
pub struct FTView {
|
|
19
|
+
pub let ftDisplay: FTDisplay?
|
|
20
|
+
pub let ftVaultData: FTVaultData?
|
|
21
|
+
init(
|
|
22
|
+
ftDisplay: FTDisplay?,
|
|
23
|
+
ftVaultData: FTVaultData?
|
|
24
|
+
) {
|
|
25
|
+
self.ftDisplay = ftDisplay
|
|
26
|
+
self.ftVaultData = ftVaultData
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/// Helper to get a FT view.
|
|
31
|
+
///
|
|
32
|
+
/// @param viewResolver: A reference to the resolver resource
|
|
33
|
+
/// @return A FTView struct
|
|
34
|
+
///
|
|
35
|
+
pub fun getFTView(viewResolver: &{MetadataViews.Resolver}): FTView {
|
|
36
|
+
let maybeFTView = viewResolver.resolveView(Type<FTView>())
|
|
37
|
+
if let ftView = maybeFTView {
|
|
38
|
+
return ftView as! FTView
|
|
39
|
+
}
|
|
40
|
+
return FTView(
|
|
41
|
+
ftDisplay: self.getFTDisplay(viewResolver),
|
|
42
|
+
ftVaultData: self.getFTVaultData(viewResolver)
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/// View to expose the information needed to showcase this FT.
|
|
47
|
+
/// This can be used by applications to give an overview and
|
|
48
|
+
/// graphics of the FT.
|
|
49
|
+
///
|
|
50
|
+
pub struct FTDisplay {
|
|
51
|
+
/// The display name for this token.
|
|
52
|
+
///
|
|
53
|
+
/// Example: "Flow"
|
|
54
|
+
///
|
|
55
|
+
pub let name: String
|
|
56
|
+
|
|
57
|
+
/// The abbreviated symbol for this token.
|
|
58
|
+
///
|
|
59
|
+
/// Example: "FLOW"
|
|
60
|
+
pub let symbol: String
|
|
61
|
+
|
|
62
|
+
/// A description the provides an overview of this token.
|
|
63
|
+
///
|
|
64
|
+
/// Example: "The FLOW token is the native currency of the Flow network."
|
|
65
|
+
pub let description: String
|
|
66
|
+
|
|
67
|
+
/// External link to a URL to view more information about the fungible token.
|
|
68
|
+
pub let externalURL: MetadataViews.ExternalURL
|
|
69
|
+
|
|
70
|
+
/// One or more versions of the fungible token logo.
|
|
71
|
+
pub let logos: MetadataViews.Medias
|
|
72
|
+
|
|
73
|
+
/// Social links to reach the fungible token's social homepages.
|
|
74
|
+
/// Possible keys may be "instagram", "twitter", "discord", etc.
|
|
75
|
+
pub let socials: {String: MetadataViews.ExternalURL}
|
|
76
|
+
|
|
77
|
+
init(
|
|
78
|
+
name: String,
|
|
79
|
+
symbol: String,
|
|
80
|
+
description: String,
|
|
81
|
+
externalURL: MetadataViews.ExternalURL,
|
|
82
|
+
logos: MetadataViews.Medias,
|
|
83
|
+
socials: {String: MetadataViews.ExternalURL}
|
|
84
|
+
) {
|
|
85
|
+
self.name = name
|
|
86
|
+
self.symbol = symbol
|
|
87
|
+
self.description = description
|
|
88
|
+
self.externalURL = externalURL
|
|
89
|
+
self.logos = logos
|
|
90
|
+
self.socials = socials
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/// Helper to get FTDisplay in a way that will return a typed optional.
|
|
95
|
+
///
|
|
96
|
+
/// @param viewResolver: A reference to the resolver resource
|
|
97
|
+
/// @return An optional FTDisplay struct
|
|
98
|
+
///
|
|
99
|
+
pub fun getFTDisplay(_ viewResolver: &{MetadataViews.Resolver}): FTDisplay? {
|
|
100
|
+
if let maybeDisplayView = viewResolver.resolveView(Type<FTDisplay>()) {
|
|
101
|
+
if let displayView = maybeDisplayView as? FTDisplay {
|
|
102
|
+
return displayView
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return nil
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/// View to expose the information needed store and interact with a FT vault.
|
|
109
|
+
/// This can be used by applications to setup a FT vault with proper
|
|
110
|
+
/// storage and public capabilities.
|
|
111
|
+
///
|
|
112
|
+
pub struct FTVaultData {
|
|
113
|
+
/// Path in storage where this FT vault is recommended to be stored.
|
|
114
|
+
pub let storagePath: StoragePath
|
|
115
|
+
|
|
116
|
+
/// Public path which must be linked to expose the public receiver capability.
|
|
117
|
+
pub let receiverPath: PublicPath
|
|
118
|
+
|
|
119
|
+
/// Public path which must be linked to expose the balance and resolver public capabilities.
|
|
120
|
+
pub let metadataPath: PublicPath
|
|
121
|
+
|
|
122
|
+
/// Private path which should be linked to expose the provider capability to withdraw funds
|
|
123
|
+
/// from the vault.
|
|
124
|
+
pub let providerPath: PrivatePath
|
|
125
|
+
|
|
126
|
+
/// Type that should be linked at the `receiverPath`. This is a restricted type requiring
|
|
127
|
+
/// the `FungibleToken.Receiver` interface.
|
|
128
|
+
pub let receiverLinkedType: Type
|
|
129
|
+
|
|
130
|
+
/// Type that should be linked at the `receiverPath`. This is a restricted type requiring
|
|
131
|
+
/// the `FungibleToken.Balance` and `MetadataViews.Resolver` interfaces.
|
|
132
|
+
pub let metadataLinkedType: Type
|
|
133
|
+
|
|
134
|
+
/// Type that should be linked at the aforementioned private path. This
|
|
135
|
+
/// is normally a restricted type with at a minimum the `FungibleToken.Provider` interface.
|
|
136
|
+
pub let providerLinkedType: Type
|
|
137
|
+
|
|
138
|
+
/// Function that allows creation of an empty FT vault that is intended
|
|
139
|
+
/// to store the funds.
|
|
140
|
+
pub let createEmptyVault: ((): @FungibleToken.Vault)
|
|
141
|
+
|
|
142
|
+
init(
|
|
143
|
+
storagePath: StoragePath,
|
|
144
|
+
receiverPath: PublicPath,
|
|
145
|
+
metadataPath: PublicPath,
|
|
146
|
+
providerPath: PrivatePath,
|
|
147
|
+
receiverLinkedType: Type,
|
|
148
|
+
metadataLinkedType: Type,
|
|
149
|
+
providerLinkedType: Type,
|
|
150
|
+
createEmptyVaultFunction: ((): @FungibleToken.Vault)
|
|
151
|
+
) {
|
|
152
|
+
pre {
|
|
153
|
+
receiverLinkedType.isSubtype(of: Type<&{FungibleToken.Receiver}>()): "Receiver public type must include FungibleToken.Receiver."
|
|
154
|
+
metadataLinkedType.isSubtype(of: Type<&{FungibleToken.Balance, MetadataViews.Resolver}>()): "Metadata public type must include FungibleToken.Balance and MetadataViews.Resolver interfaces."
|
|
155
|
+
providerLinkedType.isSubtype(of: Type<&{FungibleToken.Provider}>()): "Provider type must include FungibleToken.Provider interface."
|
|
156
|
+
}
|
|
157
|
+
self.storagePath = storagePath
|
|
158
|
+
self.receiverPath = receiverPath
|
|
159
|
+
self.metadataPath = metadataPath
|
|
160
|
+
self.providerPath = providerPath
|
|
161
|
+
self.receiverLinkedType = receiverLinkedType
|
|
162
|
+
self.metadataLinkedType = metadataLinkedType
|
|
163
|
+
self.providerLinkedType = providerLinkedType
|
|
164
|
+
self.createEmptyVault = createEmptyVaultFunction
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/// Helper to get FTVaultData in a way that will return a typed Optional.
|
|
169
|
+
///
|
|
170
|
+
/// @param viewResolver: A reference to the resolver resource
|
|
171
|
+
/// @return A optional FTVaultData struct
|
|
172
|
+
///
|
|
173
|
+
pub fun getFTVaultData(_ viewResolver: &{MetadataViews.Resolver}): FTVaultData? {
|
|
174
|
+
if let view = viewResolver.resolveView(Type<FTVaultData>()) {
|
|
175
|
+
if let v = view as? FTVaultData {
|
|
176
|
+
return v
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return nil
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
}
|
|
183
|
+
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
|
|
3
|
+
# Fungible Token Forwarding Contract
|
|
4
|
+
|
|
5
|
+
This contract shows how an account could set up a custom FungibleToken Receiver
|
|
6
|
+
to allow them to forward tokens to a different account whenever they receive tokens.
|
|
7
|
+
|
|
8
|
+
They can publish this Forwarder resource as a Receiver capability just like a Vault,
|
|
9
|
+
and the sender doesn't even need to know it is different.
|
|
10
|
+
|
|
11
|
+
When an account wants to create a Forwarder, they call the createNewForwarder
|
|
12
|
+
function and provide it with the Receiver reference that they want to forward
|
|
13
|
+
their tokens to.
|
|
14
|
+
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import "FungibleToken"
|
|
18
|
+
|
|
19
|
+
pub contract TokenForwarding {
|
|
20
|
+
|
|
21
|
+
// Event that is emitted when tokens are deposited to the target receiver
|
|
22
|
+
pub event ForwardedDeposit(amount: UFix64, from: Address?)
|
|
23
|
+
|
|
24
|
+
pub resource interface ForwarderPublic {
|
|
25
|
+
pub fun check(): Bool
|
|
26
|
+
pub fun safeBorrow(): &{FungibleToken.Receiver}?
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
pub resource Forwarder: FungibleToken.Receiver, ForwarderPublic {
|
|
30
|
+
|
|
31
|
+
// This is where the deposited tokens will be sent.
|
|
32
|
+
// The type indicates that it is a reference to a receiver
|
|
33
|
+
//
|
|
34
|
+
access(self) var recipient: Capability
|
|
35
|
+
|
|
36
|
+
// deposit
|
|
37
|
+
//
|
|
38
|
+
// Function that takes a Vault object as an argument and forwards
|
|
39
|
+
// it to the recipient's Vault using the stored reference
|
|
40
|
+
//
|
|
41
|
+
pub fun deposit(from: @FungibleToken.Vault) {
|
|
42
|
+
let receiverRef = self.recipient.borrow<&{FungibleToken.Receiver}>()!
|
|
43
|
+
|
|
44
|
+
let balance = from.balance
|
|
45
|
+
|
|
46
|
+
receiverRef.deposit(from: <-from)
|
|
47
|
+
|
|
48
|
+
emit ForwardedDeposit(amount: balance, from: self.owner?.address)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
pub fun check(): Bool {
|
|
52
|
+
return self.recipient.check<&{FungibleToken.Receiver}>()
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
pub fun safeBorrow(): &{FungibleToken.Receiver}? {
|
|
56
|
+
return self.recipient.borrow<&{FungibleToken.Receiver}>()
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// changeRecipient changes the recipient of the forwarder to the provided recipient
|
|
60
|
+
//
|
|
61
|
+
pub fun changeRecipient(_ newRecipient: Capability) {
|
|
62
|
+
pre {
|
|
63
|
+
newRecipient.borrow<&{FungibleToken.Receiver}>() != nil: "Could not borrow Receiver reference from the Capability"
|
|
64
|
+
}
|
|
65
|
+
self.recipient = newRecipient
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
init(recipient: Capability) {
|
|
69
|
+
pre {
|
|
70
|
+
recipient.borrow<&{FungibleToken.Receiver}>() != nil: "Could not borrow Receiver reference from the Capability"
|
|
71
|
+
}
|
|
72
|
+
self.recipient = recipient
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// createNewForwarder creates a new Forwarder reference with the provided recipient
|
|
77
|
+
//
|
|
78
|
+
pub fun createNewForwarder(recipient: Capability): @Forwarder {
|
|
79
|
+
return <-create Forwarder(recipient: recipient)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import "FungibleToken"
|
|
2
|
+
|
|
3
|
+
pub contract DapperUtilityCoin: FungibleToken {
|
|
4
|
+
|
|
5
|
+
// Total supply of DapperUtilityCoins in existence
|
|
6
|
+
pub var totalSupply: UFix64
|
|
7
|
+
|
|
8
|
+
// Event that is emitted when the contract is created
|
|
9
|
+
pub event TokensInitialized(initialSupply: UFix64)
|
|
10
|
+
|
|
11
|
+
// Event that is emitted when tokens are withdrawn from a Vault
|
|
12
|
+
pub event TokensWithdrawn(amount: UFix64, from: Address?)
|
|
13
|
+
|
|
14
|
+
// Event that is emitted when tokens are deposited to a Vault
|
|
15
|
+
pub event TokensDeposited(amount: UFix64, to: Address?)
|
|
16
|
+
|
|
17
|
+
// Event that is emitted when new tokens are minted
|
|
18
|
+
pub event TokensMinted(amount: UFix64)
|
|
19
|
+
|
|
20
|
+
// Event that is emitted when tokens are destroyed
|
|
21
|
+
pub event TokensBurned(amount: UFix64)
|
|
22
|
+
|
|
23
|
+
// Event that is emitted when a new minter resource is created
|
|
24
|
+
pub event MinterCreated(allowedAmount: UFix64)
|
|
25
|
+
|
|
26
|
+
// Event that is emitted when a new burner resource is created
|
|
27
|
+
pub event BurnerCreated()
|
|
28
|
+
|
|
29
|
+
// Vault
|
|
30
|
+
//
|
|
31
|
+
// Each user stores an instance of only the Vault in their storage
|
|
32
|
+
// The functions in the Vault and governed by the pre and post conditions
|
|
33
|
+
// in FungibleToken when they are called.
|
|
34
|
+
// The checks happen at runtime whenever a function is called.
|
|
35
|
+
//
|
|
36
|
+
// Resources can only be created in the context of the contract that they
|
|
37
|
+
// are defined in, so there is no way for a malicious user to create Vaults
|
|
38
|
+
// out of thin air. A special Minter resource needs to be defined to mint
|
|
39
|
+
// new tokens.
|
|
40
|
+
//
|
|
41
|
+
pub resource Vault: FungibleToken.Provider, FungibleToken.Receiver, FungibleToken.Balance {
|
|
42
|
+
|
|
43
|
+
// holds the balance of a users tokens
|
|
44
|
+
pub var balance: UFix64
|
|
45
|
+
|
|
46
|
+
// initialize the balance at resource creation time
|
|
47
|
+
init(balance: UFix64) {
|
|
48
|
+
self.balance = balance
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// withdraw
|
|
52
|
+
//
|
|
53
|
+
// Function that takes an integer amount as an argument
|
|
54
|
+
// and withdraws that amount from the Vault.
|
|
55
|
+
// It creates a new temporary Vault that is used to hold
|
|
56
|
+
// the money that is being transferred. It returns the newly
|
|
57
|
+
// created Vault to the context that called so it can be deposited
|
|
58
|
+
// elsewhere.
|
|
59
|
+
//
|
|
60
|
+
pub fun withdraw(amount: UFix64): @FungibleToken.Vault {
|
|
61
|
+
self.balance = self.balance - amount
|
|
62
|
+
emit TokensWithdrawn(amount: amount, from: self.owner?.address)
|
|
63
|
+
return <-create Vault(balance: amount)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// deposit
|
|
67
|
+
//
|
|
68
|
+
// Function that takes a Vault object as an argument and adds
|
|
69
|
+
// its balance to the balance of the owners Vault.
|
|
70
|
+
// It is allowed to destroy the sent Vault because the Vault
|
|
71
|
+
// was a temporary holder of the tokens. The Vault's balance has
|
|
72
|
+
// been consumed and therefore can be destroyed.
|
|
73
|
+
pub fun deposit(from: @FungibleToken.Vault) {
|
|
74
|
+
let vault <- from as! @DapperUtilityCoin.Vault
|
|
75
|
+
self.balance = self.balance + vault.balance
|
|
76
|
+
emit TokensDeposited(amount: vault.balance, to: self.owner?.address)
|
|
77
|
+
vault.balance = 0.0
|
|
78
|
+
destroy vault
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
destroy() {
|
|
82
|
+
DapperUtilityCoin.totalSupply = DapperUtilityCoin.totalSupply - self.balance
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// createEmptyVault
|
|
87
|
+
//
|
|
88
|
+
// Function that creates a new Vault with a balance of zero
|
|
89
|
+
// and returns it to the calling context. A user must call this function
|
|
90
|
+
// and store the returned Vault in their storage in order to allow their
|
|
91
|
+
// account to be able to receive deposits of this token type.
|
|
92
|
+
//
|
|
93
|
+
pub fun createEmptyVault(): @FungibleToken.Vault {
|
|
94
|
+
return <-create Vault(balance: 0.0)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
pub resource Administrator {
|
|
98
|
+
// createNewMinter
|
|
99
|
+
//
|
|
100
|
+
// Function that creates and returns a new minter resource
|
|
101
|
+
//
|
|
102
|
+
pub fun createNewMinter(allowedAmount: UFix64): @Minter {
|
|
103
|
+
emit MinterCreated(allowedAmount: allowedAmount)
|
|
104
|
+
return <-create Minter(allowedAmount: allowedAmount)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// createNewBurner
|
|
108
|
+
//
|
|
109
|
+
// Function that creates and returns a new burner resource
|
|
110
|
+
//
|
|
111
|
+
pub fun createNewBurner(): @Burner {
|
|
112
|
+
emit BurnerCreated()
|
|
113
|
+
return <-create Burner()
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Minter
|
|
118
|
+
//
|
|
119
|
+
// Resource object that token admin accounts can hold to mint new tokens.
|
|
120
|
+
//
|
|
121
|
+
pub resource Minter {
|
|
122
|
+
|
|
123
|
+
// the amount of tokens that the minter is allowed to mint
|
|
124
|
+
pub var allowedAmount: UFix64
|
|
125
|
+
|
|
126
|
+
// mintTokens
|
|
127
|
+
//
|
|
128
|
+
// Function that mints new tokens, adds them to the total supply,
|
|
129
|
+
// and returns them to the calling context.
|
|
130
|
+
//
|
|
131
|
+
pub fun mintTokens(amount: UFix64): @DapperUtilityCoin.Vault {
|
|
132
|
+
pre {
|
|
133
|
+
amount > UFix64(0): "Amount minted must be greater than zero"
|
|
134
|
+
amount <= self.allowedAmount: "Amount minted must be less than the allowed amount"
|
|
135
|
+
}
|
|
136
|
+
DapperUtilityCoin.totalSupply = DapperUtilityCoin.totalSupply + amount
|
|
137
|
+
self.allowedAmount = self.allowedAmount - amount
|
|
138
|
+
emit TokensMinted(amount: amount)
|
|
139
|
+
return <-create Vault(balance: amount)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
init(allowedAmount: UFix64) {
|
|
143
|
+
self.allowedAmount = allowedAmount
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Burner
|
|
148
|
+
//
|
|
149
|
+
// Resource object that token admin accounts can hold to burn tokens.
|
|
150
|
+
//
|
|
151
|
+
pub resource Burner {
|
|
152
|
+
|
|
153
|
+
// burnTokens
|
|
154
|
+
//
|
|
155
|
+
// Function that destroys a Vault instance, effectively burning the tokens.
|
|
156
|
+
//
|
|
157
|
+
// Note: the burned tokens are automatically subtracted from the
|
|
158
|
+
// total supply in the Vault destructor.
|
|
159
|
+
//
|
|
160
|
+
pub fun burnTokens(from: @FungibleToken.Vault) {
|
|
161
|
+
let vault <- from as! @DapperUtilityCoin.Vault
|
|
162
|
+
let amount = vault.balance
|
|
163
|
+
destroy vault
|
|
164
|
+
emit TokensBurned(amount: amount)
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
init() {
|
|
169
|
+
// we're using a high value as the balance here to make it look like we've got a ton of money,
|
|
170
|
+
// just in case some contract manually checks that our balance is sufficient to pay for stuff
|
|
171
|
+
self.totalSupply = 999999999.0
|
|
172
|
+
|
|
173
|
+
let admin <- create Administrator()
|
|
174
|
+
let minter <- admin.createNewMinter(allowedAmount: self.totalSupply)
|
|
175
|
+
self.account.save(<-admin, to: /storage/dapperUtilityCoinAdmin)
|
|
176
|
+
|
|
177
|
+
// mint tokens
|
|
178
|
+
let tokenVault <- minter.mintTokens(amount: self.totalSupply)
|
|
179
|
+
self.account.save(<-tokenVault, to: /storage/dapperUtilityCoinVault)
|
|
180
|
+
destroy minter
|
|
181
|
+
|
|
182
|
+
// Create a public capability to the stored Vault that only exposes
|
|
183
|
+
// the balance field through the Balance interface
|
|
184
|
+
self.account.link<&DapperUtilityCoin.Vault{FungibleToken.Balance}>(
|
|
185
|
+
/public/dapperUtilityCoinBalance,
|
|
186
|
+
target: /storage/dapperUtilityCoinVault
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
// Create a public capability to the stored Vault that only exposes
|
|
190
|
+
// the deposit method through the Receiver interface
|
|
191
|
+
self.account.link<&{FungibleToken.Receiver}>(
|
|
192
|
+
/public/dapperUtilityCoinReceiver,
|
|
193
|
+
target: /storage/dapperUtilityCoinVault
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
// Emit an event that shows that the contract was initialized
|
|
197
|
+
emit TokensInitialized(initialSupply: self.totalSupply)
|
|
198
|
+
}
|
|
199
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import "FungibleToken"
|
|
2
|
+
|
|
3
|
+
pub contract FlowUtilityToken: FungibleToken {
|
|
4
|
+
|
|
5
|
+
// Total supply of DapperUtilityCoins in existence
|
|
6
|
+
pub var totalSupply: UFix64
|
|
7
|
+
|
|
8
|
+
// Event that is emitted when the contract is created
|
|
9
|
+
pub event TokensInitialized(initialSupply: UFix64)
|
|
10
|
+
|
|
11
|
+
// Event that is emitted when tokens are withdrawn from a Vault
|
|
12
|
+
pub event TokensWithdrawn(amount: UFix64, from: Address?)
|
|
13
|
+
|
|
14
|
+
// Event that is emitted when tokens are deposited to a Vault
|
|
15
|
+
pub event TokensDeposited(amount: UFix64, to: Address?)
|
|
16
|
+
|
|
17
|
+
// Event that is emitted when new tokens are minted
|
|
18
|
+
pub event TokensMinted(amount: UFix64)
|
|
19
|
+
|
|
20
|
+
// Event that is emitted when tokens are destroyed
|
|
21
|
+
pub event TokensBurned(amount: UFix64)
|
|
22
|
+
|
|
23
|
+
// Event that is emitted when a new minter resource is created
|
|
24
|
+
pub event MinterCreated(allowedAmount: UFix64)
|
|
25
|
+
|
|
26
|
+
// Event that is emitted when a new burner resource is created
|
|
27
|
+
pub event BurnerCreated()
|
|
28
|
+
|
|
29
|
+
// Vault
|
|
30
|
+
//
|
|
31
|
+
// Each user stores an instance of only the Vault in their storage
|
|
32
|
+
// The functions in the Vault and governed by the pre and post conditions
|
|
33
|
+
// in FungibleToken when they are called.
|
|
34
|
+
// The checks happen at runtime whenever a function is called.
|
|
35
|
+
//
|
|
36
|
+
// Resources can only be created in the context of the contract that they
|
|
37
|
+
// are defined in, so there is no way for a malicious user to create Vaults
|
|
38
|
+
// out of thin air. A special Minter resource needs to be defined to mint
|
|
39
|
+
// new tokens.
|
|
40
|
+
//
|
|
41
|
+
pub resource Vault: FungibleToken.Provider, FungibleToken.Receiver, FungibleToken.Balance {
|
|
42
|
+
|
|
43
|
+
// holds the balance of a users tokens
|
|
44
|
+
pub var balance: UFix64
|
|
45
|
+
|
|
46
|
+
// initialize the balance at resource creation time
|
|
47
|
+
init(balance: UFix64) {
|
|
48
|
+
self.balance = balance
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// withdraw
|
|
52
|
+
//
|
|
53
|
+
// Function that takes an integer amount as an argument
|
|
54
|
+
// and withdraws that amount from the Vault.
|
|
55
|
+
// It creates a new temporary Vault that is used to hold
|
|
56
|
+
// the money that is being transferred. It returns the newly
|
|
57
|
+
// created Vault to the context that called so it can be deposited
|
|
58
|
+
// elsewhere.
|
|
59
|
+
//
|
|
60
|
+
pub fun withdraw(amount: UFix64): @FungibleToken.Vault {
|
|
61
|
+
self.balance = self.balance - amount
|
|
62
|
+
emit TokensWithdrawn(amount: amount, from: self.owner?.address)
|
|
63
|
+
return <-create Vault(balance: amount)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// deposit
|
|
67
|
+
//
|
|
68
|
+
// Function that takes a Vault object as an argument and adds
|
|
69
|
+
// its balance to the balance of the owners Vault.
|
|
70
|
+
// It is allowed to destroy the sent Vault because the Vault
|
|
71
|
+
// was a temporary holder of the tokens. The Vault's balance has
|
|
72
|
+
// been consumed and therefore can be destroyed.
|
|
73
|
+
pub fun deposit(from: @FungibleToken.Vault) {
|
|
74
|
+
let vault <- from as! @FlowUtilityToken.Vault
|
|
75
|
+
self.balance = self.balance + vault.balance
|
|
76
|
+
emit TokensDeposited(amount: vault.balance, to: self.owner?.address)
|
|
77
|
+
vault.balance = 0.0
|
|
78
|
+
destroy vault
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
destroy() {
|
|
82
|
+
FlowUtilityToken.totalSupply = FlowUtilityToken.totalSupply - self.balance
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// createEmptyVault
|
|
87
|
+
//
|
|
88
|
+
// Function that creates a new Vault with a balance of zero
|
|
89
|
+
// and returns it to the calling context. A user must call this function
|
|
90
|
+
// and store the returned Vault in their storage in order to allow their
|
|
91
|
+
// account to be able to receive deposits of this token type.
|
|
92
|
+
//
|
|
93
|
+
pub fun createEmptyVault(): @FungibleToken.Vault {
|
|
94
|
+
return <-create Vault(balance: 0.0)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
pub resource Administrator {
|
|
98
|
+
// createNewMinter
|
|
99
|
+
//
|
|
100
|
+
// Function that creates and returns a new minter resource
|
|
101
|
+
//
|
|
102
|
+
pub fun createNewMinter(allowedAmount: UFix64): @Minter {
|
|
103
|
+
emit MinterCreated(allowedAmount: allowedAmount)
|
|
104
|
+
return <-create Minter(allowedAmount: allowedAmount)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// createNewBurner
|
|
108
|
+
//
|
|
109
|
+
// Function that creates and returns a new burner resource
|
|
110
|
+
//
|
|
111
|
+
pub fun createNewBurner(): @Burner {
|
|
112
|
+
emit BurnerCreated()
|
|
113
|
+
return <-create Burner()
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Minter
|
|
118
|
+
//
|
|
119
|
+
// Resource object that token admin accounts can hold to mint new tokens.
|
|
120
|
+
//
|
|
121
|
+
pub resource Minter {
|
|
122
|
+
|
|
123
|
+
// the amount of tokens that the minter is allowed to mint
|
|
124
|
+
pub var allowedAmount: UFix64
|
|
125
|
+
|
|
126
|
+
// mintTokens
|
|
127
|
+
//
|
|
128
|
+
// Function that mints new tokens, adds them to the total supply,
|
|
129
|
+
// and returns them to the calling context.
|
|
130
|
+
//
|
|
131
|
+
pub fun mintTokens(amount: UFix64): @FlowUtilityToken.Vault {
|
|
132
|
+
pre {
|
|
133
|
+
amount > UFix64(0): "Amount minted must be greater than zero"
|
|
134
|
+
amount <= self.allowedAmount: "Amount minted must be less than the allowed amount"
|
|
135
|
+
}
|
|
136
|
+
FlowUtilityToken.totalSupply = FlowUtilityToken.totalSupply + amount
|
|
137
|
+
self.allowedAmount = self.allowedAmount - amount
|
|
138
|
+
emit TokensMinted(amount: amount)
|
|
139
|
+
return <-create Vault(balance: amount)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
init(allowedAmount: UFix64) {
|
|
143
|
+
self.allowedAmount = allowedAmount
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Burner
|
|
148
|
+
//
|
|
149
|
+
// Resource object that token admin accounts can hold to burn tokens.
|
|
150
|
+
//
|
|
151
|
+
pub resource Burner {
|
|
152
|
+
|
|
153
|
+
// burnTokens
|
|
154
|
+
//
|
|
155
|
+
// Function that destroys a Vault instance, effectively burning the tokens.
|
|
156
|
+
//
|
|
157
|
+
// Note: the burned tokens are automatically subtracted from the
|
|
158
|
+
// total supply in the Vault destructor.
|
|
159
|
+
//
|
|
160
|
+
pub fun burnTokens(from: @FungibleToken.Vault) {
|
|
161
|
+
let vault <- from as! @FlowUtilityToken.Vault
|
|
162
|
+
let amount = vault.balance
|
|
163
|
+
destroy vault
|
|
164
|
+
emit TokensBurned(amount: amount)
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
init() {
|
|
169
|
+
// we're using a high value as the balance here to make it look like we've got a ton of money,
|
|
170
|
+
// just in case some contract manually checks that our balance is sufficient to pay for stuff
|
|
171
|
+
self.totalSupply = 999999999.0
|
|
172
|
+
|
|
173
|
+
let admin <- create Administrator()
|
|
174
|
+
let minter <- admin.createNewMinter(allowedAmount: self.totalSupply)
|
|
175
|
+
self.account.save(<-admin, to: /storage/flowUtilityTokenAdmin)
|
|
176
|
+
|
|
177
|
+
// mint tokens
|
|
178
|
+
let tokenVault <- minter.mintTokens(amount: self.totalSupply)
|
|
179
|
+
self.account.save(<-tokenVault, to: /storage/flowUtilityTokenVault)
|
|
180
|
+
destroy minter
|
|
181
|
+
|
|
182
|
+
// Create a public capability to the stored Vault that only exposes
|
|
183
|
+
// the balance field through the Balance interface
|
|
184
|
+
self.account.link<&FlowUtilityToken.Vault{FungibleToken.Balance}>(
|
|
185
|
+
/public/flowUtilityTokenBalance,
|
|
186
|
+
target: /storage/flowUtilityTokenVault
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
// Create a public capability to the stored Vault that only exposes
|
|
190
|
+
// the deposit method through the Receiver interface
|
|
191
|
+
self.account.link<&{FungibleToken.Receiver}>(
|
|
192
|
+
/public/flowUtilityTokenReceiver,
|
|
193
|
+
target: /storage/flowUtilityTokenVault
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
// Emit an event that shows that the contract was initialized
|
|
197
|
+
emit TokensInitialized(initialSupply: self.totalSupply)
|
|
198
|
+
}
|
|
199
|
+
}
|