@flowtyio/flow-contracts 0.0.17 → 0.1.0-beta.1

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.
@@ -2,21 +2,18 @@
2
2
 
3
3
  # The Flow Fungible Token standard
4
4
 
5
- ## `FungibleToken` contract interface
5
+ ## `FungibleToken` contract
6
6
 
7
- The interface that all Fungible Token contracts would have to conform to.
8
- If a users wants to deploy a new token contract, their contract
9
- would need to implement the FungibleToken interface.
10
-
11
- Their contract would have to follow all the rules and naming
12
- that the interface specifies.
7
+ The Fungible Token standard is no longer an interface
8
+ that all fungible token contracts would have to conform to.
13
9
 
14
- ## `Vault` resource
10
+ If a users wants to deploy a new token contract, their contract
11
+ does not need to implement the FungibleToken interface, but their tokens
12
+ do need to implement the interfaces defined in this contract.
15
13
 
16
- Each account that owns tokens would need to have an instance
17
- of the Vault resource stored in their account storage.
14
+ ## `Vault` resource interface
18
15
 
19
- The Vault resource has methods that the owner and other users can call.
16
+ Each fungible token resource type needs to implement the `Vault` resource interface.
20
17
 
21
18
  ## `Provider`, `Receiver`, and `Balance` resource interfaces
22
19
 
@@ -32,32 +29,30 @@ these interfaces to do various things with the tokens.
32
29
  For example, a faucet can be implemented by conforming
33
30
  to the Provider interface.
34
31
 
35
- By using resources and interfaces, users of Fungible Token contracts
36
- can send and receive tokens peer-to-peer, without having to interact
37
- with a central ledger smart contract. To send tokens to another user,
38
- a user would simply withdraw the tokens from their Vault, then call
39
- the deposit function on another user's Vault to complete the transfer.
40
-
41
32
  */
42
33
 
43
- /// The interface that Fungible Token contracts implement.
44
- ///
45
- pub contract interface FungibleToken {
34
+ import "ViewResolver"
46
35
 
47
- /// The total number of tokens in existence.
48
- /// It is up to the implementer to ensure that the total supply
49
- /// stays accurate and up to date
50
- pub var totalSupply: UFix64
36
+ /// FungibleToken
37
+ ///
38
+ /// Fungible Token implementations are no longer required to implement the fungible token
39
+ /// interface. We still have it as an interface here because there are some useful
40
+ /// utility methods that many projects will still want to have on their contracts,
41
+ /// but they are by no means required. all that is required is that the token
42
+ /// implements the `Vault` interface
43
+ access(all) contract FungibleToken {
51
44
 
52
- /// The event that is emitted when the contract is created
53
- pub event TokensInitialized(initialSupply: UFix64)
45
+ // An entitlement for allowing the withdrawal of tokens from a Vault
46
+ access(all) entitlement Withdrawable
54
47
 
55
48
  /// The event that is emitted when tokens are withdrawn from a Vault
56
- pub event TokensWithdrawn(amount: UFix64, from: Address?)
49
+ access(all) event Withdraw(amount: UFix64, from: Address?, type: String)
57
50
 
58
- /// The event that is emitted when tokens are deposited into a Vault
59
- pub event TokensDeposited(amount: UFix64, to: Address?)
51
+ /// The event that is emitted when tokens are deposited to a Vault
52
+ access(all) event Deposit(amount: UFix64, to: Address?, type: String)
60
53
 
54
+ /// Provider
55
+ ///
61
56
  /// The interface that enforces the requirements for withdrawing
62
57
  /// tokens from the implementing type.
63
58
  ///
@@ -65,9 +60,9 @@ pub contract interface FungibleToken {
65
60
  /// because it leaves open the possibility of creating custom providers
66
61
  /// that do not necessarily need their own balance.
67
62
  ///
68
- pub resource interface Provider {
63
+ access(all) resource interface Provider {
69
64
 
70
- /// Subtracts tokens from the owner's Vault
65
+ /// withdraw subtracts tokens from the owner's Vault
71
66
  /// and returns a Vault with the removed tokens.
72
67
  ///
73
68
  /// The function's access level is public, but this is not a problem
@@ -82,18 +77,18 @@ pub contract interface FungibleToken {
82
77
  /// capability that allows all users to access the provider
83
78
  /// resource through a reference.
84
79
  ///
85
- /// @param amount: The amount of tokens to be withdrawn from the vault
86
- /// @return The Vault resource containing the withdrawn funds
87
- ///
88
- pub fun withdraw(amount: UFix64): @Vault {
80
+ access(Withdrawable) fun withdraw(amount: UFix64): @{Vault} {
89
81
  post {
90
82
  // `result` refers to the return value
91
- result.balance == amount:
83
+ result.getBalance() == amount:
92
84
  "Withdrawal amount must be the same as the balance of the withdrawn Vault"
85
+ emit Withdraw(amount: amount, from: self.owner?.address, type: self.getType().identifier)
93
86
  }
94
87
  }
95
88
  }
96
89
 
90
+ /// Receiver
91
+ ///
97
92
  /// The interface that enforces the requirements for depositing
98
93
  /// tokens into the implementing type.
99
94
  ///
@@ -102,30 +97,41 @@ pub contract interface FungibleToken {
102
97
  /// can do custom things with the tokens, like split them up and
103
98
  /// send them to different places.
104
99
  ///
105
- pub resource interface Receiver {
100
+ access(all) resource interface Receiver {
106
101
 
107
- /// Takes a Vault and deposits it into the implementing resource type
108
- ///
109
- /// @param from: The Vault resource containing the funds that will be deposited
102
+ /// deposit takes a Vault and deposits it into the implementing resource type
110
103
  ///
111
- pub fun deposit(from: @Vault)
112
-
113
- /// Below is referenced from the FLIP #69 https://github.com/onflow/flips/blob/main/flips/20230206-fungible-token-vault-type-discovery.md
114
- ///
115
- /// Returns the dictionary of Vault types that the the receiver is able to accept in its `deposit` method
116
- /// this then it would return `{Type<@FlowToken.Vault>(): true}` and if any custom receiver
117
- /// uses the default implementation then it would return empty dictionary as its parent
118
- /// resource doesn't conform with the `FungibleToken.Vault` resource.
119
- ///
120
- /// Custom receiver implementations are expected to upgrade their contracts to add an implementation
121
- /// that supports this method because it is very valuable for various applications to have.
122
- ///
123
- /// @return dictionary of supported deposit vault types by the implementing resource.
124
- ///
125
- pub fun getSupportedVaultTypes(): {Type: Bool} {
104
+ access(all) fun deposit(from: @{Vault})
105
+
106
+ /// getSupportedVaultTypes optionally returns a list of vault types that this receiver accepts
107
+ access(all) view fun getSupportedVaultTypes(): {Type: Bool} {
108
+ pre { true: "dummy" }
109
+ }
110
+
111
+ /// Returns whether or not the given type is accepted by the Receiver
112
+ /// A vault that can accept any type should just return true by default
113
+ access(all) view fun isSupportedVaultType(type: Type): Bool {
114
+ pre { true: "dummy" }
115
+ }
116
+ }
117
+
118
+ /// Vault
119
+ ///
120
+ /// Ideally, this interface would also conform to Receiver, Balance, Transferor, Provider, and Resolver
121
+ /// but that is not supported yet
122
+ ///
123
+ access(all) resource interface Vault: Receiver, Provider, ViewResolver.Resolver {
124
+
125
+ //access(all) event ResourceDestroyed(balance: UFix64 = self.getBalance())
126
+
127
+ /// Get the balance of the vault
128
+ access(all) view fun getBalance(): UFix64
129
+
130
+ /// getSupportedVaultTypes optionally returns a list of vault types that this receiver accepts
131
+ access(all) view fun getSupportedVaultTypes(): {Type: Bool} {
126
132
  // Below check is implemented to make sure that run-time type would
127
- // only get returned when the parent resource conforms with `FungibleToken.Vault`.
128
- if self.getType().isSubtype(of: Type<@FungibleToken.Vault>()) {
133
+ // only get returned when the parent resource conforms with `FungibleToken.Vault`.
134
+ if self.getType().isSubtype(of: Type<@{FungibleToken.Vault}>()) {
129
135
  return {self.getType(): true}
130
136
  } else {
131
137
  // Return an empty dictionary as the default value for resource who don't
@@ -133,105 +139,63 @@ pub contract interface FungibleToken {
133
139
  return {}
134
140
  }
135
141
  }
136
- }
137
-
138
- /// The interface that contains the `balance` field of the Vault
139
- /// and enforces that when new Vaults are created, the balance
140
- /// is initialized correctly.
141
- ///
142
- pub resource interface Balance {
143
-
144
- /// The total balance of a vault
145
- ///
146
- pub var balance: UFix64
147
142
 
148
- init(balance: UFix64) {
149
- post {
150
- self.balance == balance:
151
- "Balance must be initialized to the initial balance"
152
- }
143
+ access(all) view fun isSupportedVaultType(type: Type): Bool {
144
+ return self.getSupportedVaultTypes()[type] ?? false
153
145
  }
154
146
 
155
- /// Function that returns all the Metadata Views implemented by a Fungible Token
156
- ///
157
- /// @return An array of Types defining the implemented views. This value will be used by
158
- /// developers to know which parameter to pass to the resolveView() method.
159
- ///
160
- pub fun getViews(): [Type] {
161
- return []
162
- }
147
+ /// Returns the storage path where the vault should typically be stored
148
+ access(all) view fun getDefaultStoragePath(): StoragePath?
163
149
 
164
- /// Function that resolves a metadata view for this fungible token by type.
165
- ///
166
- /// @param view: The Type of the desired view.
167
- /// @return A structure representing the requested view.
168
- ///
169
- pub fun resolveView(_ view: Type): AnyStruct? {
150
+ /// Returns the public path where this vault should have a public capability
151
+ access(all) view fun getDefaultPublicPath(): PublicPath?
152
+
153
+ /// Returns the public path where this vault's Receiver should have a public capability
154
+ /// Publishing a Receiver Capability at a different path enables alternate Receiver implementations to be used
155
+ /// in the same canonical namespace as the underlying Vault.
156
+ access(all) view fun getDefaultReceiverPath(): PublicPath? {
170
157
  return nil
171
158
  }
172
- }
173
159
 
174
- /// The resource that contains the functions to send and receive tokens.
175
- /// The declaration of a concrete type in a contract interface means that
176
- /// every Fungible Token contract that implements the FungibleToken interface
177
- /// must define a concrete `Vault` resource that conforms to the `Provider`, `Receiver`,
178
- /// and `Balance` interfaces, and declares their required fields and functions
179
- ///
180
- pub resource Vault: Provider, Receiver, Balance {
181
-
182
- /// The total balance of the vault
183
- pub var balance: UFix64
184
-
185
- // The conforming type must declare an initializer
186
- // that allows providing the initial balance of the Vault
187
- //
188
- init(balance: UFix64)
189
-
190
- /// Subtracts `amount` from the Vault's balance
160
+ /// withdraw subtracts `amount` from the Vault's balance
191
161
  /// and returns a new Vault with the subtracted balance
192
162
  ///
193
- /// @param amount: The amount of tokens to be withdrawn from the vault
194
- /// @return The Vault resource containing the withdrawn funds
195
- ///
196
- pub fun withdraw(amount: UFix64): @Vault {
163
+ access(Withdrawable) fun withdraw(amount: UFix64): @{Vault} {
197
164
  pre {
198
- self.balance >= amount:
165
+ self.getBalance() >= amount:
199
166
  "Amount withdrawn must be less than or equal than the balance of the Vault"
200
167
  }
201
168
  post {
202
169
  // use the special function `before` to get the value of the `balance` field
203
170
  // at the beginning of the function execution
204
171
  //
205
- self.balance == before(self.balance) - amount:
206
- "New Vault balance must be the difference of the previous balance and the withdrawn Vault"
172
+ self.getBalance() == before(self.getBalance()) - amount:
173
+ "New Vault balance must be the difference of the previous balance and the withdrawn Vault balance"
207
174
  }
208
175
  }
209
176
 
210
- /// Takes a Vault and deposits it into the implementing resource type
211
- ///
212
- /// @param from: The Vault resource containing the funds that will be deposited
177
+ /// deposit takes a Vault and adds its balance to the balance of this Vault
213
178
  ///
214
- pub fun deposit(from: @Vault) {
179
+ access(all) fun deposit(from: @{FungibleToken.Vault}) {
215
180
  // Assert that the concrete type of the deposited vault is the same
216
181
  // as the vault that is accepting the deposit
217
182
  pre {
218
- from.isInstance(self.getType()):
183
+ from.isInstance(self.getType()):
219
184
  "Cannot deposit an incompatible token type"
185
+ emit Deposit(amount: from.getBalance(), to: self.owner?.address, type: from.getType().identifier)
220
186
  }
221
187
  post {
222
- self.balance == before(self.balance) + before(from.balance):
188
+ self.getBalance() == before(self.getBalance()) + before(from.getBalance()):
223
189
  "New Vault balance must be the sum of the previous balance and the deposited Vault"
224
190
  }
225
191
  }
226
- }
227
192
 
228
- /// Allows any user to create a new Vault that has a zero balance
229
- ///
230
- /// @return The new Vault resource
231
- ///
232
- pub fun createEmptyVault(): @Vault {
233
- post {
234
- result.balance == 0.0: "The newly created Vault must have zero balance"
193
+ /// createEmptyVault allows any user to create a new Vault that has a zero balance
194
+ ///
195
+ access(all) fun createEmptyVault(): @{Vault} {
196
+ post {
197
+ result.getBalance() == 0.0: "The newly created Vault must have zero balance"
198
+ }
235
199
  }
236
200
  }
237
- }
201
+ }
@@ -1,24 +1,26 @@
1
1
  import "FungibleToken"
2
2
  import "MetadataViews"
3
+ import "ViewResolver"
3
4
 
4
5
  /// This contract implements the metadata standard proposed
5
6
  /// in FLIP-1087.
6
- ///
7
- /// Ref: https://github.com/onflow/flow/blob/master/flips/20220811-fungible-tokens-metadata.md
8
- ///
7
+ ///
8
+ /// Ref: https://github.com/onflow/flips/blob/main/application/20220811-fungible-tokens-metadata.md
9
+ ///
9
10
  /// Structs and resources can implement one or more
10
11
  /// metadata types, called views. Each view type represents
11
12
  /// a different kind of metadata.
12
13
  ///
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
14
+ access(all) contract FungibleTokenMetadataViews {
15
+
16
+ /// FTView wraps FTDisplay and FTVaultData, and is used to give a complete
17
+ /// picture of a Fungible Token. Most Fungible Token contracts should
16
18
  /// implement this view.
17
19
  ///
18
- pub struct FTView {
19
- pub let ftDisplay: FTDisplay?
20
- pub let ftVaultData: FTVaultData?
21
- init(
20
+ access(all) struct FTView {
21
+ access(all) let ftDisplay: FTDisplay?
22
+ access(all) let ftVaultData: FTVaultData?
23
+ view init(
22
24
  ftDisplay: FTDisplay?,
23
25
  ftVaultData: FTVaultData?
24
26
  ) {
@@ -32,7 +34,7 @@ pub contract FungibleTokenMetadataViews {
32
34
  /// @param viewResolver: A reference to the resolver resource
33
35
  /// @return A FTView struct
34
36
  ///
35
- pub fun getFTView(viewResolver: &{MetadataViews.Resolver}): FTView {
37
+ access(all) fun getFTView(viewResolver: &{ViewResolver.Resolver}): FTView {
36
38
  let maybeFTView = viewResolver.resolveView(Type<FTView>())
37
39
  if let ftView = maybeFTView {
38
40
  return ftView as! FTView
@@ -43,38 +45,38 @@ pub contract FungibleTokenMetadataViews {
43
45
  )
44
46
  }
45
47
 
46
- /// View to expose the information needed to showcase this FT.
47
- /// This can be used by applications to give an overview and
48
+ /// View to expose the information needed to showcase this FT.
49
+ /// This can be used by applications to give an overview and
48
50
  /// graphics of the FT.
49
51
  ///
50
- pub struct FTDisplay {
52
+ access(all) struct FTDisplay {
51
53
  /// The display name for this token.
52
54
  ///
53
55
  /// Example: "Flow"
54
56
  ///
55
- pub let name: String
57
+ access(all) let name: String
56
58
 
57
59
  /// The abbreviated symbol for this token.
58
60
  ///
59
61
  /// Example: "FLOW"
60
- pub let symbol: String
62
+ access(all) let symbol: String
61
63
 
62
64
  /// A description the provides an overview of this token.
63
65
  ///
64
66
  /// Example: "The FLOW token is the native currency of the Flow network."
65
- pub let description: String
67
+ access(all) let description: String
66
68
 
67
69
  /// External link to a URL to view more information about the fungible token.
68
- pub let externalURL: MetadataViews.ExternalURL
70
+ access(all) let externalURL: MetadataViews.ExternalURL
69
71
 
70
72
  /// One or more versions of the fungible token logo.
71
- pub let logos: MetadataViews.Medias
73
+ access(all) let logos: MetadataViews.Medias
72
74
 
73
75
  /// Social links to reach the fungible token's social homepages.
74
76
  /// Possible keys may be "instagram", "twitter", "discord", etc.
75
- pub let socials: {String: MetadataViews.ExternalURL}
77
+ access(all) let socials: {String: MetadataViews.ExternalURL}
76
78
 
77
- init(
79
+ view init(
78
80
  name: String,
79
81
  symbol: String,
80
82
  description: String,
@@ -92,11 +94,11 @@ pub contract FungibleTokenMetadataViews {
92
94
  }
93
95
 
94
96
  /// Helper to get FTDisplay in a way that will return a typed optional.
95
- ///
97
+ ///
96
98
  /// @param viewResolver: A reference to the resolver resource
97
99
  /// @return An optional FTDisplay struct
98
100
  ///
99
- pub fun getFTDisplay(_ viewResolver: &{MetadataViews.Resolver}): FTDisplay? {
101
+ access(all) fun getFTDisplay(_ viewResolver: &{ViewResolver.Resolver}): FTDisplay? {
100
102
  if let maybeDisplayView = viewResolver.resolveView(Type<FTDisplay>()) {
101
103
  if let displayView = maybeDisplayView as? FTDisplay {
102
104
  return displayView
@@ -106,40 +108,40 @@ pub contract FungibleTokenMetadataViews {
106
108
  }
107
109
 
108
110
  /// 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
111
+ /// This can be used by applications to setup a FT vault with proper
110
112
  /// storage and public capabilities.
111
113
  ///
112
- pub struct FTVaultData {
114
+ access(all) struct FTVaultData {
113
115
  /// Path in storage where this FT vault is recommended to be stored.
114
- pub let storagePath: StoragePath
116
+ access(all) let storagePath: StoragePath
115
117
 
116
118
  /// Public path which must be linked to expose the public receiver capability.
117
- pub let receiverPath: PublicPath
119
+ access(all) let receiverPath: PublicPath
118
120
 
119
121
  /// Public path which must be linked to expose the balance and resolver public capabilities.
120
- pub let metadataPath: PublicPath
122
+ access(all) let metadataPath: PublicPath
121
123
 
122
- /// Private path which should be linked to expose the provider capability to withdraw funds
124
+ /// Private path which should be linked to expose the provider capability to withdraw funds
123
125
  /// from the vault.
124
- pub let providerPath: PrivatePath
126
+ access(all) let providerPath: PrivatePath
125
127
 
126
- /// Type that should be linked at the `receiverPath`. This is a restricted type requiring
128
+ /// Type that should be linked at the `receiverPath`. This is a restricted type requiring
127
129
  /// the `FungibleToken.Receiver` interface.
128
- pub let receiverLinkedType: Type
130
+ access(all) let receiverLinkedType: Type
129
131
 
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
132
+ /// Type that should be linked at the `receiverPath`. This is a restricted type requiring
133
+ /// the `ViewResolver.Resolver` interfaces.
134
+ access(all) let metadataLinkedType: Type
133
135
 
134
- /// Type that should be linked at the aforementioned private path. This
136
+ /// Type that should be linked at the aforementioned private path. This
135
137
  /// is normally a restricted type with at a minimum the `FungibleToken.Provider` interface.
136
- pub let providerLinkedType: Type
138
+ access(all) let providerLinkedType: Type
137
139
 
138
140
  /// Function that allows creation of an empty FT vault that is intended
139
141
  /// to store the funds.
140
- pub let createEmptyVault: ((): @FungibleToken.Vault)
142
+ access(all) let createEmptyVault: fun(): @{FungibleToken.Vault}
141
143
 
142
- init(
144
+ view init(
143
145
  storagePath: StoragePath,
144
146
  receiverPath: PublicPath,
145
147
  metadataPath: PublicPath,
@@ -147,11 +149,11 @@ pub contract FungibleTokenMetadataViews {
147
149
  receiverLinkedType: Type,
148
150
  metadataLinkedType: Type,
149
151
  providerLinkedType: Type,
150
- createEmptyVaultFunction: ((): @FungibleToken.Vault)
152
+ createEmptyVaultFunction: fun(): @{FungibleToken.Vault}
151
153
  ) {
152
154
  pre {
153
155
  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."
156
+ metadataLinkedType.isSubtype(of: Type<&{ViewResolver.Resolver}>()): "Metadata public type must include ViewResolver.Resolver interfaces."
155
157
  providerLinkedType.isSubtype(of: Type<&{FungibleToken.Provider}>()): "Provider type must include FungibleToken.Provider interface."
156
158
  }
157
159
  self.storagePath = storagePath
@@ -170,7 +172,7 @@ pub contract FungibleTokenMetadataViews {
170
172
  /// @param viewResolver: A reference to the resolver resource
171
173
  /// @return A optional FTVaultData struct
172
174
  ///
173
- pub fun getFTVaultData(_ viewResolver: &{MetadataViews.Resolver}): FTVaultData? {
175
+ access(all) fun getFTVaultData(_ viewResolver: &{ViewResolver.Resolver}): FTVaultData? {
174
176
  if let view = viewResolver.resolveView(Type<FTVaultData>()) {
175
177
  if let v = view as? FTVaultData {
176
178
  return v
@@ -179,5 +181,12 @@ pub contract FungibleTokenMetadataViews {
179
181
  return nil
180
182
  }
181
183
 
184
+ /// View to expose the total supply of the Vault's token
185
+ access(all) struct TotalSupply {
186
+ access(all) let supply: UFix64
187
+
188
+ view init(totalSupply: UFix64) {
189
+ self.supply = totalSupply
190
+ }
191
+ }
182
192
  }
183
-