@flowtyio/flow-contracts 0.1.0-beta.11 → 0.1.0-beta.12

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.
@@ -1,5 +1,7 @@
1
1
  // Third-party imports
2
2
  import "MetadataViews"
3
+ import "ViewResolver"
4
+ import "Burner"
3
5
 
4
6
  // HC-owned imports
5
7
  import "CapabilityFactory"
@@ -27,39 +29,43 @@ import "CapabilityFilter"
27
29
  ///
28
30
  /// Repo reference: https://github.com/onflow/hybrid-custody
29
31
  ///
30
- pub contract HybridCustody {
32
+ access(all) contract HybridCustody {
33
+ access(all) entitlement Owner
34
+ access(all) entitlement Child
35
+ access(all) entitlement Publish
36
+ access(all) entitlement Manage
31
37
 
32
38
  /* --- Canonical Paths --- */
33
39
  //
34
40
  // Note: Paths for ChildAccount & Delegator are derived from the parent's address
35
41
  //
36
- pub let OwnedAccountStoragePath: StoragePath
37
- pub let OwnedAccountPublicPath: PublicPath
38
- pub let OwnedAccountPrivatePath: PrivatePath
42
+ access(all) let OwnedAccountStoragePath: StoragePath
43
+ access(all) let OwnedAccountPublicPath: PublicPath
44
+ access(all) let OwnedAccountPrivatePath: PrivatePath
39
45
 
40
- pub let ManagerStoragePath: StoragePath
41
- pub let ManagerPublicPath: PublicPath
42
- pub let ManagerPrivatePath: PrivatePath
46
+ access(all) let ManagerStoragePath: StoragePath
47
+ access(all) let ManagerPublicPath: PublicPath
48
+ access(all) let ManagerPrivatePath: PrivatePath
43
49
 
44
- pub let LinkedAccountPrivatePath: PrivatePath
45
- pub let BorrowableAccountPrivatePath: PrivatePath
50
+ access(all) let LinkedAccountPrivatePath: PrivatePath
51
+ access(all) let BorrowableAccountPrivatePath: PrivatePath
46
52
 
47
53
  /* --- Events --- */
48
54
  //
49
55
  /// Manager creation event
50
- pub event CreatedManager(id: UInt64)
56
+ access(all) event CreatedManager(id: UInt64)
51
57
  /// OwnedAccount creation event
52
- pub event CreatedOwnedAccount(id: UInt64, child: Address)
58
+ access(all) event CreatedOwnedAccount(id: UInt64, child: Address)
53
59
  /// ChildAccount added/removed from Manager
54
60
  /// active : added to Manager
55
61
  /// !active : removed from Manager
56
- pub event AccountUpdated(id: UInt64?, child: Address, parent: Address, active: Bool)
62
+ access(all) event AccountUpdated(id: UInt64?, child: Address, parent: Address?, active: Bool)
57
63
  /// OwnedAccount added/removed or sealed
58
64
  /// active && owner != nil : added to Manager
59
65
  /// !active && owner == nil : removed from Manager
60
- pub event OwnershipUpdated(id: UInt64, child: Address, previousOwner: Address?, owner: Address?, active: Bool)
66
+ access(all) event OwnershipUpdated(id: UInt64, child: Address, previousOwner: Address?, owner: Address?, active: Bool)
61
67
  /// ChildAccount ready to be redeemed by emitted pendingParent
62
- pub event ChildAccountPublished(
68
+ access(all) event ChildAccountPublished(
63
69
  ownedAcctID: UInt64,
64
70
  childAcctID: UInt64,
65
71
  capDelegatorID: UInt64,
@@ -70,49 +76,52 @@ pub contract HybridCustody {
70
76
  pendingParent: Address
71
77
  )
72
78
  /// OwnedAccount granted ownership to a new address, publishing a Capability for the pendingOwner
73
- pub event OwnershipGranted(ownedAcctID: UInt64, child: Address, previousOwner: Address?, pendingOwner: Address)
79
+ access(all) event OwnershipGranted(ownedAcctID: UInt64, child: Address, previousOwner: Address?, pendingOwner: Address)
74
80
  /// Account has been sealed - keys revoked, new AuthAccount Capability generated
75
- pub event AccountSealed(id: UInt64, address: Address, parents: [Address])
81
+ access(all) event AccountSealed(id: UInt64, address: Address, parents: [Address])
76
82
 
77
83
  /// An OwnedAccount shares the BorrowableAccount capability to itelf with ChildAccount resources
78
84
  ///
79
- pub resource interface BorrowableAccount {
80
- access(contract) fun borrowAccount(): &AuthAccount
81
- pub fun check(): Bool
85
+ access(all) resource interface BorrowableAccount {
86
+ access(contract) view fun _borrowAccount(): auth(Storage, Contracts, Keys, Inbox, Capabilities) &Account
87
+ access(all) view fun check(): Bool
82
88
  }
83
89
 
84
90
  /// Public methods anyone can call on an OwnedAccount
85
91
  ///
86
- pub resource interface OwnedAccountPublic {
92
+ access(all) resource interface OwnedAccountPublic {
87
93
  /// Returns the addresses of all parent accounts
88
- pub fun getParentAddresses(): [Address]
94
+ access(all) view fun getParentAddresses(): [Address]
89
95
 
90
96
  /// Returns associated parent addresses and their redeemed status - true if redeemed, false if pending
91
- pub fun getParentStatuses(): {Address: Bool}
97
+ access(all) view fun getParentStatuses(): {Address: Bool}
92
98
 
93
99
  /// Returns true if the given address is a parent of this child and has redeemed it. Returns false if the given
94
100
  /// address is a parent of this child and has NOT redeemed it. Returns nil if the given address it not a parent
95
101
  /// of this child account.
96
- pub fun getRedeemedStatus(addr: Address): Bool?
102
+ access(all) view fun getRedeemedStatus(addr: Address): Bool?
97
103
 
98
104
  /// A callback function to mark a parent as redeemed on the child account.
99
105
  access(contract) fun setRedeemed(_ addr: Address)
106
+
107
+ /// A helper function to find what controller Id to ask for if you are looking for a specific type of capability
108
+ access(all) view fun getControllerIDForType(type: Type, forPath: StoragePath): UInt64?
100
109
  }
101
110
 
102
111
  /// Private interface accessible to the owner of the OwnedAccount
103
112
  ///
104
- pub resource interface OwnedAccountPrivate {
113
+ access(all) resource interface OwnedAccountPrivate {
105
114
  /// Deletes the ChildAccount resource being used to share access to this OwnedAccount with the supplied parent
106
115
  /// address, and unlinks the paths it was using to reach the underlying account.
107
- pub fun removeParent(parent: Address): Bool
116
+ access(Owner | Remove) fun removeParent(parent: Address): Bool
108
117
 
109
118
  /// Sets up a new ChildAccount resource for the given parentAddress to redeem. This child account uses the
110
119
  /// supplied factory and filter to manage what can be obtained from the child account, and a new
111
120
  /// CapabilityDelegator resource is created for the sharing of one-off capabilities. Each of these pieces of
112
121
  /// access control are managed through the child account.
113
- pub fun publishToParent(
122
+ access(Publish | Owner) fun publishToParent(
114
123
  parentAddress: Address,
115
- factory: Capability<&CapabilityFactory.Manager{CapabilityFactory.Getter}>,
124
+ factory: Capability<&{CapabilityFactory.Getter}>,
116
125
  filter: Capability<&{CapabilityFilter.Filter}>
117
126
  ) {
118
127
  pre {
@@ -124,7 +133,7 @@ pub contract HybridCustody {
124
133
  /// Passes ownership of this child account to the given address. Once executed, all active keys on the child
125
134
  /// account will be revoked, and the active AuthAccount Capability being used by to obtain capabilities will be
126
135
  /// rotated, preventing anyone without the newly generated Capability from gaining access to the account.
127
- pub fun giveOwnership(to: Address)
136
+ access(Owner) fun giveOwnership(to: Address)
128
137
 
129
138
  /// Revokes all keys on an account, unlinks all currently active AuthAccount capabilities, then makes a new one
130
139
  /// and replaces the OwnedAccount's underlying AuthAccount Capability with the new one to ensure that all
@@ -132,12 +141,12 @@ pub contract HybridCustody {
132
141
  /// Unless this method is executed via the giveOwnership function, this will leave an account **without** an
133
142
  /// owner.
134
143
  /// USE WITH EXTREME CAUTION.
135
- pub fun seal()
144
+ access(Owner) fun seal()
136
145
 
137
146
  // setCapabilityFactoryForParent
138
147
  // Override the existing CapabilityFactory Capability for a given parent. This will allow the owner of the
139
148
  // account to start managing their own factory of capabilities to be able to retrieve
140
- pub fun setCapabilityFactoryForParent(parent: Address, cap: Capability<&CapabilityFactory.Manager{CapabilityFactory.Getter}>) {
149
+ access(Owner) fun setCapabilityFactoryForParent(parent: Address, cap: Capability<&{CapabilityFactory.Getter}>) {
141
150
  pre {
142
151
  cap.check(): "Invalid CapabilityFactory.Getter Capability provided"
143
152
  }
@@ -145,7 +154,7 @@ pub contract HybridCustody {
145
154
 
146
155
  /// Override the existing CapabilityFilter Capability for a given parent. This will allow the owner of the
147
156
  /// account to start managing their own filter for retrieving Capabilities on Private Paths
148
- pub fun setCapabilityFilterForParent(parent: Address, cap: Capability<&{CapabilityFilter.Filter}>) {
157
+ access(Owner) fun setCapabilityFilterForParent(parent: Address, cap: Capability<&{CapabilityFilter.Filter}>) {
149
158
  pre {
150
159
  cap.check(): "Invalid CapabilityFilter Capability provided"
151
160
  }
@@ -153,66 +162,67 @@ pub contract HybridCustody {
153
162
 
154
163
  /// Adds a capability to a parent's managed @ChildAccount resource. The Capability can be made public,
155
164
  /// permitting anyone to borrow it.
156
- pub fun addCapabilityToDelegator(parent: Address, cap: Capability, isPublic: Bool) {
165
+ access(Owner) fun addCapabilityToDelegator(parent: Address, cap: Capability, isPublic: Bool) {
157
166
  pre {
158
167
  cap.check<&AnyResource>(): "Invalid Capability provided"
159
168
  }
160
169
  }
161
170
 
162
171
  /// Removes a Capability from the CapabilityDelegator used by the specified parent address
163
- pub fun removeCapabilityFromDelegator(parent: Address, cap: Capability)
172
+ access(Owner) fun removeCapabilityFromDelegator(parent: Address, cap: Capability)
164
173
 
165
174
  /// Returns the address of this OwnedAccount
166
- pub fun getAddress(): Address
175
+ access(all) view fun getAddress(): Address
167
176
 
168
177
  /// Checks if this OwnedAccount is a child of the specified address
169
- pub fun isChildOf(_ addr: Address): Bool
178
+ access(all) view fun isChildOf(_ addr: Address): Bool
170
179
 
171
180
  /// Returns all addresses which are parents of this OwnedAccount
172
- pub fun getParentAddresses(): [Address]
181
+ access(all) view fun getParentAddresses(): [Address]
173
182
 
174
183
  /// Borrows this OwnedAccount's AuthAccount Capability
175
- pub fun borrowAccount(): &AuthAccount?
184
+ access(Owner) view fun borrowAccount(): auth(Storage, Contracts, Keys, Inbox, Capabilities) &Account
176
185
 
177
186
  /// Returns the current owner of this account, if there is one
178
- pub fun getOwner(): Address?
187
+ access(all) view fun getOwner(): Address?
179
188
 
180
189
  /// Returns the pending owner of this account, if there is one
181
- pub fun getPendingOwner(): Address?
190
+ access(all) view fun getPendingOwner(): Address?
182
191
 
183
192
  /// A callback which is invoked when a parent redeems an owned account
184
193
  access(contract) fun setOwnerCallback(_ addr: Address)
185
194
 
186
195
  /// Destroys all outstanding AuthAccount capabilities on this owned account, and creates a new one for the
187
196
  /// OwnedAccount to use
188
- pub fun rotateAuthAccount()
197
+ access(Owner) fun rotateAuthAccount()
189
198
 
190
199
  /// Revokes all keys on this account
191
- pub fun revokeAllKeys()
200
+ access(Owner) fun revokeAllKeys()
192
201
  }
193
202
 
194
203
  /// Public methods exposed on a ChildAccount resource. OwnedAccountPublic will share some methods here, but isn't
195
204
  /// necessarily the same.
196
205
  ///
197
- pub resource interface AccountPublic {
198
- pub fun getPublicCapability(path: PublicPath, type: Type): Capability?
199
- pub fun getPublicCapFromDelegator(type: Type): Capability?
200
- pub fun getAddress(): Address
206
+ access(all) resource interface AccountPublic {
207
+ access(all) view fun getPublicCapability(path: PublicPath, type: Type): Capability?
208
+ access(all) view fun getPublicCapFromDelegator(type: Type): Capability?
209
+ access(all) view fun getAddress(): Address
210
+ access(all) view fun getCapabilityFactoryManager(): &{CapabilityFactory.Getter}?
211
+ access(all) view fun getCapabilityFilter(): &{CapabilityFilter.Filter}?
212
+ access(all) view fun getControllerIDForType(type: Type, forPath: StoragePath): UInt64?
201
213
  }
202
214
 
203
215
  /// Methods accessible to the designated parent of a ChildAccount
204
216
  ///
205
- pub resource interface AccountPrivate {
206
- pub fun getCapability(path: CapabilityPath, type: Type): Capability? {
217
+ access(all) resource interface AccountPrivate {
218
+ access(Child) view fun getCapability(controllerID: UInt64, type: Type): Capability? {
207
219
  post {
208
220
  result == nil || [true, nil].contains(self.getManagerCapabilityFilter()?.allowed(cap: result!)):
209
221
  "Capability is not allowed by this account's Parent"
210
222
  }
211
223
  }
212
- pub fun getPublicCapability(path: PublicPath, type: Type): Capability?
213
- pub fun getManagerCapabilityFilter(): &{CapabilityFilter.Filter}?
214
- pub fun getPublicCapFromDelegator(type: Type): Capability?
215
- pub fun getPrivateCapFromDelegator(type: Type): Capability? {
224
+ access(all) view fun getManagerCapabilityFilter(): &{CapabilityFilter.Filter}?
225
+ access(Child) view fun getPrivateCapFromDelegator(type: Type): Capability? {
216
226
  post {
217
227
  result == nil || [true, nil].contains(self.getManagerCapabilityFilter()?.allowed(cap: result!)):
218
228
  "Capability is not allowed by this account's Parent"
@@ -229,14 +239,14 @@ pub contract HybridCustody {
229
239
 
230
240
  /// Entry point for a parent to obtain, maintain and access Capabilities or perform other actions on child accounts
231
241
  ///
232
- pub resource interface ManagerPrivate {
233
- pub fun addAccount(cap: Capability<&{AccountPrivate, AccountPublic, MetadataViews.Resolver}>)
234
- pub fun borrowAccount(addr: Address): &{AccountPrivate, AccountPublic, MetadataViews.Resolver}?
235
- pub fun removeChild(addr: Address)
236
- pub fun addOwnedAccount(cap: Capability<&{OwnedAccountPrivate, OwnedAccountPublic, MetadataViews.Resolver}>)
237
- pub fun borrowOwnedAccount(addr: Address): &{OwnedAccountPrivate, OwnedAccountPublic, MetadataViews.Resolver}?
238
- pub fun removeOwned(addr: Address)
239
- pub fun setManagerCapabilityFilter(cap: Capability<&{CapabilityFilter.Filter}>?, childAddress: Address) {
242
+ access(all) resource interface ManagerPrivate {
243
+ access(Manage) fun addAccount(cap: Capability<auth(Child) &{AccountPrivate, AccountPublic, ViewResolver.Resolver}>)
244
+ access(Manage) fun borrowAccount(addr: Address): auth(Child) &{AccountPrivate, AccountPublic, ViewResolver.Resolver}?
245
+ access(Manage) fun removeChild(addr: Address)
246
+ access(Manage) fun addOwnedAccount(cap: Capability<auth(Owner) &{OwnedAccountPrivate, OwnedAccountPublic, ViewResolver.Resolver}>)
247
+ access(Manage) fun borrowOwnedAccount(addr: Address): auth(Owner) &{OwnedAccountPrivate, OwnedAccountPublic, ViewResolver.Resolver}?
248
+ access(Manage) fun removeOwned(addr: Address)
249
+ access(Manage) fun setManagerCapabilityFilter(cap: Capability<&{CapabilityFilter.Filter}>?, childAddress: Address) {
240
250
  pre {
241
251
  cap == nil || cap!.check(): "Invalid Manager Capability Filter"
242
252
  }
@@ -245,39 +255,40 @@ pub contract HybridCustody {
245
255
 
246
256
  /// Functions anyone can call on a manager to get information about an account such as What child accounts it has
247
257
  /// Functions anyone can call on a manager to get information about an account such as what child accounts it has
248
- pub resource interface ManagerPublic {
249
- pub fun borrowAccountPublic(addr: Address): &{AccountPublic, MetadataViews.Resolver}?
250
- pub fun getChildAddresses(): [Address]
251
- pub fun getOwnedAddresses(): [Address]
252
- pub fun getChildAccountDisplay(address: Address): MetadataViews.Display?
258
+ access(all) resource interface ManagerPublic {
259
+ access(all) fun borrowAccountPublic(addr: Address): &{AccountPublic, ViewResolver.Resolver}?
260
+ access(all) fun getChildAddresses(): [Address]
261
+ access(all) fun getOwnedAddresses(): [Address]
262
+ access(all) fun getChildAccountDisplay(address: Address): MetadataViews.Display?
253
263
  access(contract) fun removeParentCallback(child: Address)
254
264
  }
255
265
 
256
266
  /// A resource for an account which fills the Parent role of the Child-Parent account management Model. A Manager
257
267
  /// can redeem or remove child accounts, and obtain any capabilities exposed by the child account to them.
258
268
  ///
259
- pub resource Manager: ManagerPrivate, ManagerPublic, MetadataViews.Resolver {
269
+ access(all) resource Manager: ManagerPrivate, ManagerPublic, ViewResolver.Resolver, Burner.Burnable {
270
+ access(all) event ResourceDestroyed(uuid: UInt64 = self.uuid)
260
271
 
261
272
  /// Mapping of restricted access child account Capabilities indexed by their address
262
- pub let childAccounts: {Address: Capability<&{AccountPrivate, AccountPublic, MetadataViews.Resolver}>}
273
+ access(self) let childAccounts: {Address: Capability<auth(Child) &{AccountPrivate, AccountPublic, ViewResolver.Resolver}>}
263
274
  /// Mapping of unrestricted owned account Capabilities indexed by their address
264
- pub let ownedAccounts: {Address: Capability<&{OwnedAccountPrivate, OwnedAccountPublic, MetadataViews.Resolver}>}
275
+ access(self) let ownedAccounts: {Address: Capability<auth(Owner) &{OwnedAccountPrivate, OwnedAccountPublic, ViewResolver.Resolver}>}
265
276
 
266
277
  /// A bucket of structs so that the Manager resource can be easily extended with new functionality.
267
- pub let data: {String: AnyStruct}
278
+ access(self) let data: {String: AnyStruct}
268
279
  /// A bucket of resources so that the Manager resource can be easily extended with new functionality.
269
- pub let resources: @{String: AnyResource}
280
+ access(self) let resources: @{String: AnyResource}
270
281
 
271
282
  /// An optional filter to gate what capabilities are permitted to be returned from a child account For example,
272
283
  /// Dapper Wallet parent account's should not be able to retrieve any FungibleToken Provider capabilities.
273
- pub var filter: Capability<&{CapabilityFilter.Filter}>?
284
+ access(self) var filter: Capability<&{CapabilityFilter.Filter}>?
274
285
 
275
286
  // display metadata for a child account exists on its parent
276
- pub let childAccountDisplays: {Address: MetadataViews.Display}
287
+ access(self) let childAccountDisplays: {Address: MetadataViews.Display}
277
288
 
278
289
  /// Sets the Display on the ChildAccount. If nil, the display is removed.
279
290
  ///
280
- pub fun setChildAccountDisplay(address: Address, _ d: MetadataViews.Display?) {
291
+ access(Manage) fun setChildAccountDisplay(address: Address, _ d: MetadataViews.Display?) {
281
292
  pre {
282
293
  self.childAccounts[address] != nil: "There is no child account with this address"
283
294
  }
@@ -293,7 +304,7 @@ pub contract HybridCustody {
293
304
  /// Adds a ChildAccount Capability to this Manager. If a default Filter is set in the manager, it will also be
294
305
  /// added to the ChildAccount
295
306
  ///
296
- pub fun addAccount(cap: Capability<&{AccountPrivate, AccountPublic, MetadataViews.Resolver}>) {
307
+ access(Manage) fun addAccount(cap: Capability<auth(Child) &{AccountPrivate, AccountPublic, ViewResolver.Resolver}>) {
297
308
  pre {
298
309
  self.childAccounts[cap.address] == nil: "There is already a child account with this address"
299
310
  }
@@ -311,17 +322,17 @@ pub contract HybridCustody {
311
322
 
312
323
  /// Sets the default Filter Capability for this Manager. Does not propagate to child accounts.
313
324
  ///
314
- pub fun setDefaultManagerCapabilityFilter(cap: Capability<&{CapabilityFilter.Filter}>?) {
325
+ access(Manage) fun setDefaultManagerCapabilityFilter(cap: Capability<&{CapabilityFilter.Filter}>?) {
315
326
  pre {
316
327
  cap == nil || cap!.check(): "supplied capability must be nil or check must pass"
317
328
  }
318
329
 
319
330
  self.filter = cap
320
331
  }
321
-
332
+
322
333
  /// Sets the Filter Capability for this Manager, propagating to the specified child account
323
334
  ///
324
- pub fun setManagerCapabilityFilter(cap: Capability<&{CapabilityFilter.Filter}>?, childAddress: Address) {
335
+ access(Manage) fun setManagerCapabilityFilter(cap: Capability<&{CapabilityFilter.Filter}>?, childAddress: Address) {
325
336
  let acct = self.borrowAccount(addr: childAddress)
326
337
  ?? panic("child account not found")
327
338
 
@@ -331,7 +342,7 @@ pub contract HybridCustody {
331
342
  /// Removes specified child account from the Manager's child accounts. Callbacks to the child account remove
332
343
  /// any associated resources and Capabilities
333
344
  ///
334
- pub fun removeChild(addr: Address) {
345
+ access(Manage) fun removeChild(addr: Address) {
335
346
  let cap = self.childAccounts.remove(key: addr)
336
347
  ?? panic("child account not found")
337
348
 
@@ -347,9 +358,11 @@ pub contract HybridCustody {
347
358
  // Get the child account id before removing capability
348
359
  let id: UInt64 = acct.uuid
349
360
 
350
- acct.parentRemoveChildCallback(parent: self.owner!.address)
361
+ if self.owner != nil {
362
+ acct.parentRemoveChildCallback(parent: self.owner!.address)
363
+ }
351
364
 
352
- emit AccountUpdated(id: id, child: cap.address, parent: self.owner!.address, active: false)
365
+ emit AccountUpdated(id: id, child: cap.address, parent: self.owner?.address, active: false)
353
366
  }
354
367
 
355
368
  /// Contract callback that removes a child account from the Manager's child accounts in the event a child
@@ -363,7 +376,7 @@ pub contract HybridCustody {
363
376
  /// Adds an owned account to the Manager's list of owned accounts, setting the Manager account as the owner of
364
377
  /// the given account
365
378
  ///
366
- pub fun addOwnedAccount(cap: Capability<&{OwnedAccountPrivate, OwnedAccountPublic, MetadataViews.Resolver}>) {
379
+ access(Manage) fun addOwnedAccount(cap: Capability<auth(Owner) &{OwnedAccountPrivate, OwnedAccountPublic, ViewResolver.Resolver}>) {
367
380
  pre {
368
381
  self.ownedAccounts[cap.address] == nil: "There is already an owned account with this address"
369
382
  }
@@ -384,7 +397,7 @@ pub contract HybridCustody {
384
397
 
385
398
  /// Returns a reference to a child account
386
399
  ///
387
- pub fun borrowAccount(addr: Address): &{AccountPrivate, AccountPublic, MetadataViews.Resolver}? {
400
+ access(Manage) fun borrowAccount(addr: Address): auth(Child) &{AccountPrivate, AccountPublic, ViewResolver.Resolver}? {
388
401
  let cap = self.childAccounts[addr]
389
402
  if cap == nil {
390
403
  return nil
@@ -395,7 +408,7 @@ pub contract HybridCustody {
395
408
 
396
409
  /// Returns a reference to a child account's public AccountPublic interface
397
410
  ///
398
- pub fun borrowAccountPublic(addr: Address): &{AccountPublic, MetadataViews.Resolver}? {
411
+ access(all) fun borrowAccountPublic(addr: Address): &{AccountPublic, ViewResolver.Resolver}? {
399
412
  let cap = self.childAccounts[addr]
400
413
  if cap == nil {
401
414
  return nil
@@ -406,7 +419,7 @@ pub contract HybridCustody {
406
419
 
407
420
  /// Returns a reference to an owned account
408
421
  ///
409
- pub fun borrowOwnedAccount(addr: Address): &{OwnedAccountPrivate, OwnedAccountPublic, MetadataViews.Resolver}? {
422
+ access(Manage) fun borrowOwnedAccount(addr: Address): auth(Owner) &{OwnedAccountPrivate, OwnedAccountPublic, ViewResolver.Resolver}? {
410
423
  if let cap = self.ownedAccounts[addr] {
411
424
  return cap.borrow()
412
425
  }
@@ -417,7 +430,7 @@ pub contract HybridCustody {
417
430
  /// Removes specified child account from the Manager's child accounts. Callbacks to the child account remove
418
431
  /// any associated resources and Capabilities
419
432
  ///
420
- pub fun removeOwned(addr: Address) {
433
+ access(Manage) fun removeOwned(addr: Address) {
421
434
  if let acct = self.ownedAccounts.remove(key: addr) {
422
435
  if acct.check() {
423
436
  acct.borrow()!.seal()
@@ -437,7 +450,7 @@ pub contract HybridCustody {
437
450
  /// mechanism intended to easily transfer 'root' access on this account to another account and an attempt to
438
451
  /// minimize access vectors.
439
452
  ///
440
- pub fun giveOwnership(addr: Address, to: Address) {
453
+ access(Manage) fun giveOwnership(addr: Address, to: Address) {
441
454
  let acct = self.ownedAccounts.remove(key: addr)
442
455
  ?? panic("account not found")
443
456
 
@@ -446,31 +459,31 @@ pub contract HybridCustody {
446
459
 
447
460
  /// Returns an array of child account addresses
448
461
  ///
449
- pub fun getChildAddresses(): [Address] {
462
+ access(all) view fun getChildAddresses(): [Address] {
450
463
  return self.childAccounts.keys
451
464
  }
452
465
 
453
466
  /// Returns an array of owned account addresses
454
467
  ///
455
- pub fun getOwnedAddresses(): [Address] {
468
+ access(all) view fun getOwnedAddresses(): [Address] {
456
469
  return self.ownedAccounts.keys
457
470
  }
458
471
 
459
472
  /// Retrieves the parent-defined display for the given child account
460
473
  ///
461
- pub fun getChildAccountDisplay(address: Address): MetadataViews.Display? {
474
+ access(all) view fun getChildAccountDisplay(address: Address): MetadataViews.Display? {
462
475
  return self.childAccountDisplays[address]
463
476
  }
464
477
 
465
478
  /// Returns the types of supported views - none at this time
466
479
  ///
467
- pub fun getViews(): [Type] {
480
+ access(all) view fun getViews(): [Type] {
468
481
  return []
469
482
  }
470
483
 
471
484
  /// Resolves the given view if supported - none at this time
472
485
  ///
473
- pub fun resolveView(_ view: Type): AnyStruct? {
486
+ access(all) view fun resolveView(_ view: Type): AnyStruct? {
474
487
  return nil
475
488
  }
476
489
 
@@ -487,8 +500,19 @@ pub contract HybridCustody {
487
500
  self.resources <- {}
488
501
  }
489
502
 
490
- destroy () {
491
- destroy self.resources
503
+ // When a manager resource is destroyed, attempt to remove this parent from every
504
+ // child account it currently has
505
+ //
506
+ // Destruction will fail if there are any owned account to prevent loss of access to an account
507
+ access(contract) fun burnCallback() {
508
+ pre {
509
+ // Prevent accidental burning of a resource that has ownership of other accounts
510
+ self.ownedAccounts.length == 0: "cannot destroy a manager with owned accounts"
511
+ }
512
+
513
+ for c in self.childAccounts.keys {
514
+ self.removeChild(addr: c)
515
+ }
492
516
  }
493
517
  }
494
518
 
@@ -501,27 +525,29 @@ pub contract HybridCustody {
501
525
  /// able to manage all ChildAccount resources it shares, without worrying about whether the upstream parent can do
502
526
  /// anything to prevent it.
503
527
  ///
504
- pub resource ChildAccount: AccountPrivate, AccountPublic, MetadataViews.Resolver {
528
+ access(all) resource ChildAccount: AccountPrivate, AccountPublic, ViewResolver.Resolver, Burner.Burnable {
529
+ access(all) event ResourceDestroyed(uuid: UInt64 = self.uuid, address: Address = self.childCap.address, parent: Address = self.parent)
530
+
505
531
  /// A Capability providing access to the underlying child account
506
- access(self) let childCap: Capability<&{BorrowableAccount, OwnedAccountPublic, MetadataViews.Resolver}>
532
+ access(self) let childCap: Capability<&{BorrowableAccount, OwnedAccountPublic, ViewResolver.Resolver}>
507
533
 
508
534
  /// The CapabilityFactory Manager is a ChildAccount's way of limiting what types can be asked for by its parent
509
535
  /// account. The CapabilityFactory returns Capabilities which can be casted to their appropriate types once
510
536
  /// obtained, but only if the child account has configured their factory to allow it. For instance, a
511
537
  /// ChildAccount might choose to expose NonFungibleToken.Provider, but not FungibleToken.Provider
512
- pub var factory: Capability<&CapabilityFactory.Manager{CapabilityFactory.Getter}>
538
+ access(self) var factory: Capability<&{CapabilityFactory.Getter}>
513
539
 
514
540
  /// The CapabilityFilter is a restriction put at the front of obtaining any non-public Capability. Some wallets
515
541
  /// might want to give access to NonFungibleToken.Provider, but only to **some** of the collections it manages,
516
542
  /// not all of them.
517
- pub var filter: Capability<&{CapabilityFilter.Filter}>
543
+ access(self) var filter: Capability<&{CapabilityFilter.Filter}>
518
544
 
519
545
  /// The CapabilityDelegator is a way to share one-off capabilities from the child account. These capabilities
520
546
  /// can be public OR private and are separate from the factory which returns a capability at a given path as a
521
547
  /// certain type. When using the CapabilityDelegator, you do not have the ability to specify which path a
522
548
  /// capability came from. For instance, Dapper Wallet might choose to expose a Capability to their Full TopShot
523
549
  /// collection, but only to the path that the collection exists in.
524
- pub let delegator: Capability<&CapabilityDelegator.Delegator{CapabilityDelegator.GetterPublic, CapabilityDelegator.GetterPrivate}>
550
+ access(self) let delegator: Capability<auth(Capabilities) &{CapabilityDelegator.GetterPublic, CapabilityDelegator.GetterPrivate}>
525
551
 
526
552
  /// managerCapabilityFilter is a component optionally given to a child account when a manager redeems it. If
527
553
  /// this filter is not nil, any Capability returned through the `getCapability` function checks that the
@@ -536,11 +562,11 @@ pub contract HybridCustody {
536
562
 
537
563
  /// ChildAccount resources have a 1:1 association with parent accounts, the named parent Address here is the
538
564
  /// one with a Capability on this resource.
539
- pub let parent: Address
565
+ access(all) let parent: Address
540
566
 
541
567
  /// Returns the Address of the underlying child account
542
568
  ///
543
- pub fun getAddress(): Address {
569
+ access(all) view fun getAddress(): Address {
544
570
  return self.childCap.address
545
571
  }
546
572
 
@@ -560,24 +586,24 @@ pub contract HybridCustody {
560
586
 
561
587
  /// Sets the CapabiltyFactory.Manager Capability
562
588
  ///
563
- pub fun setCapabilityFactory(cap: Capability<&CapabilityFactory.Manager{CapabilityFactory.Getter}>) {
589
+ access(contract) fun setCapabilityFactory(cap: Capability<&{CapabilityFactory.Getter}>) {
564
590
  self.factory = cap
565
591
  }
566
592
 
567
593
  /// Sets the Filter Capability as the one provided
568
594
  ///
569
- pub fun setCapabilityFilter(cap: Capability<&{CapabilityFilter.Filter}>) {
595
+ access(contract) fun setCapabilityFilter(cap: Capability<&{CapabilityFilter.Filter}>) {
570
596
  self.filter = cap
571
597
  }
572
598
 
573
599
  /// The main function to a child account's capabilities from a parent account. When a PrivatePath type is used,
574
600
  /// the CapabilityFilter will be borrowed and the Capability being returned will be checked against it to
575
- /// ensure that borrowing is permitted.
601
+ /// ensure that borrowing is permitted. If not allowed, nil is returned.
576
602
  /// Also know that this method retrieves Capabilities via the CapabilityFactory path. To retrieve arbitrary
577
603
  /// Capabilities, see `getPrivateCapFromDelegator()` and `getPublicCapFromDelegator()` which use the
578
604
  /// `Delegator` retrieval path.
579
605
  ///
580
- pub fun getCapability(path: CapabilityPath, type: Type): Capability? {
606
+ access(Child) view fun getCapability(controllerID: UInt64, type: Type): Capability? {
581
607
  let child = self.childCap.borrow() ?? panic("failed to borrow child account")
582
608
 
583
609
  let f = self.factory.borrow()!.getFactory(type)
@@ -585,12 +611,17 @@ pub contract HybridCustody {
585
611
  return nil
586
612
  }
587
613
 
588
- let acct = child.borrowAccount()
614
+ let acct = child._borrowAccount()
615
+ let tmp = f!.getCapability(acct: acct, controllerID: controllerID)
616
+ if tmp == nil {
617
+ return nil
618
+ }
589
619
 
590
- let cap = f!.getCapability(acct: acct, path: path)
591
-
592
- if path.getType() == Type<PrivatePath>() {
593
- assert(self.filter.borrow()!.allowed(cap: cap), message: "requested capability is not allowed")
620
+ let cap = tmp!
621
+ // Check that private capabilities are allowed by either internal or manager filter (if assigned)
622
+ // If not allowed, return nil
623
+ if self.filter.borrow()!.allowed(cap: cap) == false || (self.getManagerCapabilityFilter()?.allowed(cap: cap) ?? true) == false {
624
+ return nil
594
625
  }
595
626
 
596
627
  return cap
@@ -599,7 +630,7 @@ pub contract HybridCustody {
599
630
  /// Retrieves a private Capability from the Delegator or nil none is found of the given type. Useful for
600
631
  /// arbitrary Capability retrieval
601
632
  ///
602
- pub fun getPrivateCapFromDelegator(type: Type): Capability? {
633
+ access(Child) view fun getPrivateCapFromDelegator(type: Type): Capability? {
603
634
  if let d = self.delegator.borrow() {
604
635
  return d.getPrivateCapability(type)
605
636
  }
@@ -610,7 +641,7 @@ pub contract HybridCustody {
610
641
  /// Retrieves a public Capability from the Delegator or nil none is found of the given type. Useful for
611
642
  /// arbitrary Capability retrieval
612
643
  ///
613
- pub fun getPublicCapFromDelegator(type: Type): Capability? {
644
+ access(all) view fun getPublicCapFromDelegator(type: Type): Capability? {
614
645
  if let d = self.delegator.borrow() {
615
646
  return d.getPublicCapability(type)
616
647
  }
@@ -620,37 +651,43 @@ pub contract HybridCustody {
620
651
  /// Enables retrieval of public Capabilities of the given type from the specified path or nil if none is found.
621
652
  /// Callers should be aware this method uses the `CapabilityFactory` retrieval path.
622
653
  ///
623
- pub fun getPublicCapability(path: PublicPath, type: Type): Capability? {
624
- return self.getCapability(path: path, type: type)
654
+ access(all) view fun getPublicCapability(path: PublicPath, type: Type): Capability? {
655
+ let child = self.childCap.borrow() ?? panic("failed to borrow child account")
656
+
657
+ let f = self.factory.borrow()!.getFactory(type)
658
+ if f == nil {
659
+ return nil
660
+ }
661
+
662
+ let acct = child._borrowAccount()
663
+ return f!.getPublicCapability(acct: acct, path: path)
625
664
  }
626
665
 
627
666
  /// Returns a reference to the stored managerCapabilityFilter if one exists
628
667
  ///
629
- pub fun getManagerCapabilityFilter(): &{CapabilityFilter.Filter}? {
668
+ access(all) view fun getManagerCapabilityFilter(): &{CapabilityFilter.Filter}? {
630
669
  return self.managerCapabilityFilter != nil ? self.managerCapabilityFilter!.borrow() : nil
631
670
  }
632
671
 
633
672
  /// Sets the child account as redeemed by the given Address
634
673
  ///
635
674
  access(contract) fun setRedeemed(_ addr: Address) {
636
- let acct = self.childCap.borrow()!.borrowAccount()
637
- if let o = acct.borrow<&OwnedAccount>(from: HybridCustody.OwnedAccountStoragePath) {
638
- o.setRedeemed(addr)
639
- }
675
+ let acct = self.childCap.borrow()!._borrowAccount()
676
+ acct.storage.borrow<&OwnedAccount>(from: HybridCustody.OwnedAccountStoragePath)?.setRedeemed(addr)
640
677
  }
641
678
 
642
679
  /// Returns a reference to the stored delegator, generally used for arbitrary Capability retrieval
643
680
  ///
644
- pub fun borrowCapabilityDelegator(): &CapabilityDelegator.Delegator? {
681
+ access(Owner) fun borrowCapabilityDelegator(): auth(Capabilities) &CapabilityDelegator.Delegator? {
645
682
  let path = HybridCustody.getCapabilityDelegatorIdentifier(self.parent)
646
- return self.childCap.borrow()!.borrowAccount().borrow<&CapabilityDelegator.Delegator>(
683
+ return self.childCap.borrow()!._borrowAccount().storage.borrow<auth(Capabilities) &CapabilityDelegator.Delegator>(
647
684
  from: StoragePath(identifier: path)!
648
685
  )
649
686
  }
650
687
 
651
688
  /// Returns a list of supported metadata views
652
689
  ///
653
- pub fun getViews(): [Type] {
690
+ access(all) view fun getViews(): [Type] {
654
691
  return [
655
692
  Type<MetadataViews.Display>()
656
693
  ]
@@ -658,17 +695,22 @@ pub contract HybridCustody {
658
695
 
659
696
  /// Resolves a view of the given type if supported
660
697
  ///
661
- pub fun resolveView(_ view: Type): AnyStruct? {
698
+ access(all) fun resolveView(_ view: Type): AnyStruct? {
662
699
  switch view {
663
700
  case Type<MetadataViews.Display>():
664
701
  let childAddress = self.getAddress()
665
- let manager = getAccount(self.parent).getCapability<&HybridCustody.Manager{HybridCustody.ManagerPublic}>(HybridCustody.ManagerPublicPath)
702
+ let tmp = getAccount(self.parent).capabilities.get<&{HybridCustody.ManagerPublic}>(HybridCustody.ManagerPublicPath)
703
+ if tmp == nil {
704
+ return nil
705
+ }
706
+
707
+ let manager = tmp!
666
708
 
667
709
  if !manager.check() {
668
710
  return nil
669
711
  }
670
712
 
671
- return manager!.borrow()!.getChildAccountDisplay(address: childAddress)
713
+ return manager.borrow()!.getChildAccountDisplay(address: childAddress)
672
714
  }
673
715
  return nil
674
716
  }
@@ -681,22 +723,22 @@ pub contract HybridCustody {
681
723
  return
682
724
  }
683
725
 
684
- let child: &AnyResource{HybridCustody.BorrowableAccount} = self.childCap.borrow()!
726
+ let child: &{HybridCustody.BorrowableAccount} = self.childCap.borrow()!
685
727
  if !child.check() {
686
728
  return
687
729
  }
688
730
 
689
- let acct = child.borrowAccount()
690
- if let ownedAcct = acct.borrow<&OwnedAccount>(from: HybridCustody.OwnedAccountStoragePath) {
731
+ let acct = child._borrowAccount()
732
+ if let ownedAcct = acct.storage.borrow<auth(Owner) &OwnedAccount>(from: HybridCustody.OwnedAccountStoragePath) {
691
733
  ownedAcct.removeParent(parent: parent)
692
734
  }
693
735
  }
694
736
 
695
737
  init(
696
- _ childCap: Capability<&{BorrowableAccount, OwnedAccountPublic, MetadataViews.Resolver}>,
697
- _ factory: Capability<&CapabilityFactory.Manager{CapabilityFactory.Getter}>,
738
+ _ childCap: Capability<&{BorrowableAccount, OwnedAccountPublic, ViewResolver.Resolver}>,
739
+ _ factory: Capability<&{CapabilityFactory.Getter}>,
698
740
  _ filter: Capability<&{CapabilityFilter.Filter}>,
699
- _ delegator: Capability<&CapabilityDelegator.Delegator{CapabilityDelegator.GetterPublic, CapabilityDelegator.GetterPrivate}>,
741
+ _ delegator: Capability<auth(Capabilities) &{CapabilityDelegator.GetterPublic, CapabilityDelegator.GetterPrivate}>,
700
742
  _ parent: Address
701
743
  ) {
702
744
  pre {
@@ -716,8 +758,30 @@ pub contract HybridCustody {
716
758
  self.resources <- {}
717
759
  }
718
760
 
719
- destroy () {
720
- destroy <- self.resources
761
+ /// Returns a capability to this child account's CapabilityFilter
762
+ ///
763
+ access(all) view fun getCapabilityFilter(): &{CapabilityFilter.Filter}? {
764
+ return self.filter.check() ? self.filter.borrow() : nil
765
+ }
766
+
767
+ /// Returns a capability to this child account's CapabilityFactory
768
+ ///
769
+ access(all) view fun getCapabilityFactoryManager(): &{CapabilityFactory.Getter}? {
770
+ return self.factory.check() ? self.factory.borrow() : nil
771
+ }
772
+
773
+ access(all) view fun getControllerIDForType(type: Type, forPath: StoragePath): UInt64? {
774
+ let child = self.childCap.borrow()
775
+ if child == nil {
776
+ return nil
777
+ }
778
+
779
+ return child!.getControllerIDForType(type: type, forPath: forPath)
780
+ }
781
+
782
+ // When a ChildAccount is destroyed, attempt to remove it from the parent account as well
783
+ access(contract) fun burnCallback() {
784
+ self.parentRemoveChildCallback(parent: self.parent)
721
785
  }
722
786
  }
723
787
 
@@ -730,18 +794,19 @@ pub contract HybridCustody {
730
794
  /// accounts would still exist, allowing a form of Hybrid Custody which has no true owner over an account, but
731
795
  /// shared partial ownership.
732
796
  ///
733
- pub resource OwnedAccount: OwnedAccountPrivate, BorrowableAccount, OwnedAccountPublic, MetadataViews.Resolver {
797
+ access(all) resource OwnedAccount: OwnedAccountPrivate, BorrowableAccount, OwnedAccountPublic, ViewResolver.Resolver, Burner.Burnable {
798
+ access(all) event ResourceDestroyed(uuid: UInt64 = self.uuid, addr: Address = self.acct.address)
734
799
  /// Capability on the underlying account object
735
- access(self) var acct: Capability<&AuthAccount>
800
+ access(self) var acct: Capability<auth(Storage, Contracts, Keys, Inbox, Capabilities) &Account>
736
801
 
737
802
  /// Mapping of current and pending parents, true and false respectively
738
- pub let parents: {Address: Bool}
803
+ access(all) let parents: {Address: Bool}
739
804
  /// Address of the pending owner, if one exists
740
- pub var pendingOwner: Address?
805
+ access(all) var pendingOwner: Address?
741
806
  /// Address of the current owner, if one exists
742
- pub var acctOwner: Address?
807
+ access(all) var acctOwner: Address?
743
808
  /// Owned status of this account
744
- pub var currentlyOwned: Bool
809
+ access(all) var currentlyOwned: Bool
745
810
 
746
811
  /// A bucket of structs so that the OwnedAccount resource can be easily extended with new functionality.
747
812
  access(self) let data: {String: AnyStruct}
@@ -792,12 +857,12 @@ pub contract HybridCustody {
792
857
  /// 4. Publish the newly made private link to the designated parent's inbox for them to claim on their @Manager
793
858
  /// resource.
794
859
  ///
795
- pub fun publishToParent(
860
+ access(Publish | Owner) fun publishToParent(
796
861
  parentAddress: Address,
797
- factory: Capability<&CapabilityFactory.Manager{CapabilityFactory.Getter}>,
862
+ factory: Capability<&{CapabilityFactory.Getter}>,
798
863
  filter: Capability<&{CapabilityFilter.Filter}>
799
864
  ) {
800
- pre{
865
+ pre {
801
866
  self.parents[parentAddress] == nil: "Address pending or already redeemed as parent"
802
867
  }
803
868
  let capDelegatorIdentifier = HybridCustody.getCapabilityDelegatorIdentifier(parentAddress)
@@ -808,41 +873,32 @@ pub contract HybridCustody {
808
873
  let capDelegatorStorage = StoragePath(identifier: capDelegatorIdentifier)!
809
874
  let acct = self.borrowAccount()
810
875
 
811
- assert(acct.borrow<&AnyResource>(from: capDelegatorStorage) == nil, message: "conflicting resource found in capability delegator storage slot for parentAddress")
812
- assert(acct.borrow<&AnyResource>(from: childAccountStorage) == nil, message: "conflicting resource found in child account storage slot for parentAddress")
876
+ assert(acct.storage.borrow<&AnyResource>(from: capDelegatorStorage) == nil, message: "conflicting resource found in capability delegator storage slot for parentAddress")
877
+ assert(acct.storage.borrow<&AnyResource>(from: childAccountStorage) == nil, message: "conflicting resource found in child account storage slot for parentAddress")
813
878
 
814
- if acct.borrow<&CapabilityDelegator.Delegator>(from: capDelegatorStorage) == nil {
879
+ if acct.storage.borrow<&CapabilityDelegator.Delegator>(from: capDelegatorStorage) == nil {
815
880
  let delegator <- CapabilityDelegator.createDelegator()
816
- acct.save(<-delegator, to: capDelegatorStorage)
881
+ acct.storage.save(<-delegator, to: capDelegatorStorage)
817
882
  }
818
883
 
819
884
  let capDelegatorPublic = PublicPath(identifier: capDelegatorIdentifier)!
820
- let capDelegatorPrivate = PrivatePath(identifier: capDelegatorIdentifier)!
885
+ // let capDelegatorPrivate = PrivatePath(identifier: capDelegatorIdentifier)!
821
886
 
822
- acct.link<&CapabilityDelegator.Delegator{CapabilityDelegator.GetterPublic}>(
823
- capDelegatorPublic,
824
- target: capDelegatorStorage
825
- )
826
- acct.link<&CapabilityDelegator.Delegator{CapabilityDelegator.GetterPublic, CapabilityDelegator.GetterPrivate}>(
827
- capDelegatorPrivate,
828
- target: capDelegatorStorage
829
- )
830
- let delegator = acct.getCapability<&CapabilityDelegator.Delegator{CapabilityDelegator.GetterPublic, CapabilityDelegator.GetterPrivate}>(
831
- capDelegatorPrivate
832
- )
887
+ let pubCap = acct.capabilities.storage.issue<&{CapabilityDelegator.GetterPublic}>(capDelegatorStorage)
888
+ acct.capabilities.publish(pubCap, at: capDelegatorPublic)
889
+
890
+ let delegator = acct.capabilities.storage.issue<auth(Capabilities) &{CapabilityDelegator.GetterPublic, CapabilityDelegator.GetterPrivate}>(capDelegatorStorage)
833
891
  assert(delegator.check(), message: "failed to setup capability delegator for parent address")
834
892
 
835
- let borrowableCap = self.borrowAccount().getCapability<&{BorrowableAccount, OwnedAccountPublic, MetadataViews.Resolver}>(
836
- HybridCustody.OwnedAccountPrivatePath
893
+ let borrowableCap = self.borrowAccount().capabilities.storage.issue<&{BorrowableAccount, OwnedAccountPublic, ViewResolver.Resolver}>(
894
+ HybridCustody.OwnedAccountStoragePath
837
895
  )
838
- let childAcct <- create ChildAccount(borrowableCap, factory, filter, delegator, parentAddress)
839
896
 
897
+ let childAcct <- create ChildAccount(borrowableCap, factory, filter, delegator, parentAddress)
840
898
  let childAccountPrivatePath = PrivatePath(identifier: identifier)!
841
899
 
842
- acct.save(<-childAcct, to: childAccountStorage)
843
- acct.link<&ChildAccount{AccountPrivate, AccountPublic, MetadataViews.Resolver}>(childAccountPrivatePath, target: childAccountStorage)
844
-
845
- let delegatorCap = acct.getCapability<&ChildAccount{AccountPrivate, AccountPublic, MetadataViews.Resolver}>(childAccountPrivatePath)
900
+ acct.storage.save(<-childAcct, to: childAccountStorage)
901
+ let delegatorCap = acct.capabilities.storage.issue<auth(Child) &{AccountPrivate, AccountPublic, ViewResolver.Resolver}>(childAccountStorage)
846
902
  assert(delegatorCap.check(), message: "Delegator capability check failed")
847
903
 
848
904
  acct.inbox.publish(delegatorCap, name: identifier, recipient: parentAddress)
@@ -862,38 +918,43 @@ pub contract HybridCustody {
862
918
 
863
919
  /// Checks the validity of the encapsulated account Capability
864
920
  ///
865
- pub fun check(): Bool {
921
+ access(all) view fun check(): Bool {
866
922
  return self.acct.check()
867
923
  }
868
924
 
869
925
  /// Returns a reference to the encapsulated account object
870
926
  ///
871
- pub fun borrowAccount(): &AuthAccount {
872
- return self.acct.borrow()!
927
+ access(Owner) view fun borrowAccount(): auth(Storage, Contracts, Keys, Inbox, Capabilities) &Account {
928
+ return self.acct.borrow() ?? panic("unable to borrow Account Capability")
929
+ }
930
+
931
+ // Used internally so that child account resources are able to borrow their underlying Account reference
932
+ access(contract) view fun _borrowAccount(): auth(Storage, Contracts, Keys, Inbox, Capabilities) &Account {
933
+ return self.borrowAccount()
873
934
  }
874
935
 
875
936
  /// Returns the addresses of all associated parents pending and active
876
937
  ///
877
- pub fun getParentAddresses(): [Address] {
938
+ access(all) view fun getParentAddresses(): [Address] {
878
939
  return self.parents.keys
879
940
  }
880
941
 
881
942
  /// Returns whether the given address is a parent of this account
882
943
  ///
883
- pub fun isChildOf(_ addr: Address): Bool {
944
+ access(all) view fun isChildOf(_ addr: Address): Bool {
884
945
  return self.parents[addr] != nil
885
946
  }
886
947
 
887
948
  /// Returns nil if the given address is not a parent, false if the parent has not redeemed the child account
888
949
  /// yet, and true if they have
889
950
  ///
890
- pub fun getRedeemedStatus(addr: Address): Bool? {
951
+ access(all) view fun getRedeemedStatus(addr: Address): Bool? {
891
952
  return self.parents[addr]
892
953
  }
893
954
 
894
955
  /// Returns associated parent addresses and their redeemed status
895
956
  ///
896
- pub fun getParentStatuses(): {Address: Bool} {
957
+ access(all) view fun getParentStatuses(): {Address: Bool} {
897
958
  return self.parents
898
959
  }
899
960
 
@@ -901,7 +962,7 @@ pub contract HybridCustody {
901
962
  /// configured for the provided parent address. Once done, the parent will not have any valid capabilities with
902
963
  /// which to access the child account.
903
964
  ///
904
- pub fun removeParent(parent: Address): Bool {
965
+ access(Owner | Remove) fun removeParent(parent: Address): Bool {
905
966
  if self.parents[parent] == nil {
906
967
  return false
907
968
  }
@@ -909,21 +970,28 @@ pub contract HybridCustody {
909
970
  let capDelegatorIdentifier = HybridCustody.getCapabilityDelegatorIdentifier(parent)
910
971
 
911
972
  let acct = self.borrowAccount()
912
- acct.unlink(PrivatePath(identifier: identifier)!)
913
- acct.unlink(PublicPath(identifier: identifier)!)
914
973
 
915
- acct.unlink(PrivatePath(identifier: capDelegatorIdentifier)!)
916
- acct.unlink(PublicPath(identifier: capDelegatorIdentifier)!)
974
+ // get all controllers which target this storage path
975
+ let storagePath = StoragePath(identifier: identifier)!
976
+ let childAccountControllers = acct.capabilities.storage.getControllers(forPath: storagePath)
977
+ for c in childAccountControllers {
978
+ c.delete()
979
+ }
980
+ Burner.burn(<- acct.storage.load<@AnyResource>(from: storagePath))
917
981
 
918
- destroy <- acct.load<@AnyResource>(from: StoragePath(identifier: identifier)!)
919
- destroy <- acct.load<@AnyResource>(from: StoragePath(identifier: capDelegatorIdentifier)!)
982
+ let delegatorStoragePath = StoragePath(identifier: capDelegatorIdentifier)!
983
+ let delegatorControllers = acct.capabilities.storage.getControllers(forPath: delegatorStoragePath)
984
+ for c in delegatorControllers {
985
+ c.delete()
986
+ }
987
+ Burner.burn(<- acct.storage.load<@AnyResource>(from: delegatorStoragePath))
920
988
 
921
989
  self.parents.remove(key: parent)
922
990
  emit AccountUpdated(id: self.uuid, child: self.acct.address, parent: parent, active: false)
923
991
 
924
- let parentManager = getAccount(parent).getCapability<&Manager{ManagerPublic}>(HybridCustody.ManagerPublicPath)
925
- if parentManager.check() {
926
- parentManager.borrow()?.removeParentCallback(child: self.owner!.address)
992
+ let parentManager = getAccount(parent).capabilities.get<&{ManagerPublic}>(HybridCustody.ManagerPublicPath)
993
+ if parentManager?.check() == true {
994
+ parentManager!.borrow()?.removeParentCallback(child: acct.address)
927
995
  }
928
996
 
929
997
  return true
@@ -931,21 +999,21 @@ pub contract HybridCustody {
931
999
 
932
1000
  /// Returns the address of the encapsulated account
933
1001
  ///
934
- pub fun getAddress(): Address {
1002
+ access(all) view fun getAddress(): Address {
935
1003
  return self.acct.address
936
1004
  }
937
1005
 
938
1006
  /// Returns the address of the pending owner if one is assigned. Pending owners are assigned when ownership has
939
1007
  /// been granted, but has not yet been redeemed.
940
1008
  ///
941
- pub fun getPendingOwner(): Address? {
1009
+ access(all) view fun getPendingOwner(): Address? {
942
1010
  return self.pendingOwner
943
1011
  }
944
1012
 
945
1013
  /// Returns the address of the current owner if one is assigned. Current owners are assigned when ownership has
946
1014
  /// been redeemed.
947
1015
  ///
948
- pub fun getOwner(): Address? {
1016
+ access(all) view fun getOwner(): Address? {
949
1017
  if !self.currentlyOwned {
950
1018
  return nil
951
1019
  }
@@ -961,22 +1029,17 @@ pub contract HybridCustody {
961
1029
  /// mechanism intended to easily transfer 'root' access on this account to another account and an attempt to
962
1030
  /// minimize access vectors.
963
1031
  ///
964
- pub fun giveOwnership(to: Address) {
1032
+ access(Owner) fun giveOwnership(to: Address) {
965
1033
  self.seal()
966
1034
 
967
1035
  let acct = self.borrowAccount()
968
- // Unlink existing owner's Capability if owner exists
969
- if self.acctOwner != nil {
970
- acct.unlink(
971
- PrivatePath(identifier: HybridCustody.getOwnerIdentifier(self.acctOwner!))!
972
- )
973
- }
1036
+
974
1037
  // Link a Capability for the new owner, retrieve & publish
975
1038
  let identifier = HybridCustody.getOwnerIdentifier(to)
976
- let cap = acct.link<&{OwnedAccountPrivate, OwnedAccountPublic, MetadataViews.Resolver}>(
977
- PrivatePath(identifier: identifier)!,
978
- target: HybridCustody.OwnedAccountStoragePath
979
- ) ?? panic("failed to link child account capability")
1039
+ let cap = acct.capabilities.storage.issue<auth(Owner) &{OwnedAccountPrivate, OwnedAccountPublic, ViewResolver.Resolver}>(HybridCustody.OwnedAccountStoragePath)
1040
+
1041
+ // make sure we can borrow the newly issued owned account
1042
+ cap.borrow()!.borrowAccount()
980
1043
 
981
1044
  acct.inbox.publish(cap, name: identifier, recipient: to)
982
1045
 
@@ -988,7 +1051,7 @@ pub contract HybridCustody {
988
1051
 
989
1052
  /// Revokes all keys on the underlying account
990
1053
  ///
991
- pub fun revokeAllKeys() {
1054
+ access(Owner) fun revokeAllKeys() {
992
1055
  let acct = self.borrowAccount()
993
1056
 
994
1057
  // Revoke all keys
@@ -1007,33 +1070,25 @@ pub contract HybridCustody {
1007
1070
  /// assumes ownership of an account to guarantee that the previous owner doesn't maintain admin access to the
1008
1071
  /// account via other AuthAccount Capabilities.
1009
1072
  ///
1010
- pub fun rotateAuthAccount() {
1073
+ access(Owner) fun rotateAuthAccount() {
1011
1074
  let acct = self.borrowAccount()
1012
1075
 
1013
1076
  // Find all active AuthAccount capabilities so they can be removed after we make the new auth account cap
1014
- let pathsToUnlink: [PrivatePath] = []
1015
- acct.forEachPrivate(fun (path: PrivatePath, type: Type): Bool {
1016
- if type.identifier == "Capability<&AuthAccount>" {
1017
- pathsToUnlink.append(path)
1018
- }
1019
- return true
1020
- })
1077
+ let controllersToDestroy = acct.capabilities.account.getControllers()
1021
1078
 
1022
1079
  // Link a new AuthAccount Capability
1023
- // NOTE: This path cannot be sufficiently randomly generated, an app calling this function could build a
1024
- // capability to this path before it is made, thus maintaining ownership despite making it look like they
1025
- // gave it away. Until capability controllers, this method should not be fully trusted.
1026
- let authAcctPath = "HybridCustodyRelinquished".concat(HybridCustody.account.address.toString()).concat(getCurrentBlock().height.toString())
1027
- let acctCap = acct.linkAccount(PrivatePath(identifier: authAcctPath)!)!
1080
+ let acctCap = acct.capabilities.account.issue<auth(Storage, Contracts, Keys, Inbox, Capabilities) &Account>()
1028
1081
 
1029
1082
  self.acct = acctCap
1030
1083
  let newAcct = self.acct.borrow()!
1031
1084
 
1032
1085
  // cleanup, remove all previously found paths. We had to do it in this order because we will be unlinking
1033
1086
  // the existing path which will cause a deference issue with the originally borrowed auth account
1034
- for p in pathsToUnlink {
1035
- newAcct.unlink(p)
1087
+ for con in controllersToDestroy {
1088
+ newAcct.capabilities.account.getController(byCapabilityID: con.capabilityID)?.delete()
1036
1089
  }
1090
+
1091
+ assert(self.acct.check(), message: "new auth account capability is not valid")
1037
1092
  }
1038
1093
 
1039
1094
  /// Revokes all keys on an account, unlinks all currently active AuthAccount capabilities, then makes a new one
@@ -1043,7 +1098,7 @@ pub contract HybridCustody {
1043
1098
  ///
1044
1099
  /// USE WITH EXTREME CAUTION.
1045
1100
  ///
1046
- pub fun seal() {
1101
+ access(Owner) fun seal() {
1047
1102
  self.rotateAuthAccount()
1048
1103
  self.revokeAllKeys() // There needs to be a path to giving ownership that doesn't revoke keys
1049
1104
  emit AccountSealed(id: self.uuid, address: self.acct.address, parents: self.parents.keys)
@@ -1052,16 +1107,16 @@ pub contract HybridCustody {
1052
1107
 
1053
1108
  /// Retrieves a reference to the ChildAccount associated with the given parent account if one exists.
1054
1109
  ///
1055
- pub fun borrowChildAccount(parent: Address): &ChildAccount? {
1110
+ access(Owner) fun borrowChildAccount(parent: Address): auth(Capabilities) &ChildAccount? {
1056
1111
  let identifier = HybridCustody.getChildAccountIdentifier(parent)
1057
- return self.borrowAccount().borrow<&ChildAccount>(from: StoragePath(identifier: identifier)!)
1112
+ return self.borrowAccount().storage.borrow<auth(Capabilities) &ChildAccount>(from: StoragePath(identifier: identifier)!)
1058
1113
  }
1059
1114
 
1060
1115
  /// Sets the CapabilityFactory Manager for the specified parent in the associated ChildAccount.
1061
1116
  ///
1062
- pub fun setCapabilityFactoryForParent(
1117
+ access(Owner) fun setCapabilityFactoryForParent(
1063
1118
  parent: Address,
1064
- cap: Capability<&CapabilityFactory.Manager{CapabilityFactory.Getter}>
1119
+ cap: Capability<&{CapabilityFactory.Getter}>
1065
1120
  ) {
1066
1121
  let p = self.borrowChildAccount(parent: parent) ?? panic("could not find parent address")
1067
1122
  p.setCapabilityFactory(cap: cap)
@@ -1069,21 +1124,21 @@ pub contract HybridCustody {
1069
1124
 
1070
1125
  /// Sets the Filter for the specified parent in the associated ChildAccount.
1071
1126
  ///
1072
- pub fun setCapabilityFilterForParent(parent: Address, cap: Capability<&{CapabilityFilter.Filter}>) {
1127
+ access(Owner) fun setCapabilityFilterForParent(parent: Address, cap: Capability<&{CapabilityFilter.Filter}>) {
1073
1128
  let p = self.borrowChildAccount(parent: parent) ?? panic("could not find parent address")
1074
1129
  p.setCapabilityFilter(cap: cap)
1075
1130
  }
1076
1131
 
1077
1132
  /// Retrieves a reference to the Delegator associated with the given parent account if one exists.
1078
1133
  ///
1079
- pub fun borrowCapabilityDelegatorForParent(parent: Address): &CapabilityDelegator.Delegator? {
1134
+ access(Owner) fun borrowCapabilityDelegatorForParent(parent: Address): auth(Mutate) &CapabilityDelegator.Delegator? {
1080
1135
  let identifier = HybridCustody.getCapabilityDelegatorIdentifier(parent)
1081
- return self.borrowAccount().borrow<&CapabilityDelegator.Delegator>(from: StoragePath(identifier: identifier)!)
1136
+ return self.borrowAccount().storage.borrow<auth(Mutate) &CapabilityDelegator.Delegator>(from: StoragePath(identifier: identifier)!)
1082
1137
  }
1083
1138
 
1084
1139
  /// Adds the provided Capability to the Delegator associated with the given parent account.
1085
1140
  ///
1086
- pub fun addCapabilityToDelegator(parent: Address, cap: Capability, isPublic: Bool) {
1141
+ access(Owner) fun addCapabilityToDelegator(parent: Address, cap: Capability, isPublic: Bool) {
1087
1142
  let p = self.borrowChildAccount(parent: parent) ?? panic("could not find parent address")
1088
1143
  let delegator = self.borrowCapabilityDelegatorForParent(parent: parent)
1089
1144
  ?? panic("could not borrow capability delegator resource for parent address")
@@ -1092,20 +1147,20 @@ pub contract HybridCustody {
1092
1147
 
1093
1148
  /// Removes the provided Capability from the Delegator associated with the given parent account.
1094
1149
  ///
1095
- pub fun removeCapabilityFromDelegator(parent: Address, cap: Capability) {
1150
+ access(Owner) fun removeCapabilityFromDelegator(parent: Address, cap: Capability) {
1096
1151
  let p = self.borrowChildAccount(parent: parent) ?? panic("could not find parent address")
1097
1152
  let delegator = self.borrowCapabilityDelegatorForParent(parent: parent)
1098
1153
  ?? panic("could not borrow capability delegator resource for parent address")
1099
1154
  delegator.removeCapability(cap: cap)
1100
1155
  }
1101
1156
 
1102
- pub fun getViews(): [Type] {
1157
+ access(all) view fun getViews(): [Type] {
1103
1158
  return [
1104
1159
  Type<MetadataViews.Display>()
1105
1160
  ]
1106
1161
  }
1107
1162
 
1108
- pub fun resolveView(_ view: Type): AnyStruct? {
1163
+ access(all) fun resolveView(_ view: Type): AnyStruct? {
1109
1164
  switch view {
1110
1165
  case Type<MetadataViews.Display>():
1111
1166
  return self.display
@@ -1115,12 +1170,27 @@ pub contract HybridCustody {
1115
1170
 
1116
1171
  /// Sets this OwnedAccount's display to the one provided
1117
1172
  ///
1118
- pub fun setDisplay(_ d: MetadataViews.Display) {
1173
+ access(Owner) fun setDisplay(_ d: MetadataViews.Display) {
1119
1174
  self.display = d
1120
1175
  }
1121
1176
 
1177
+ access(all) view fun getControllerIDForType(type: Type, forPath: StoragePath): UInt64? {
1178
+ let acct = self.acct.borrow()
1179
+ if acct == nil {
1180
+ return nil
1181
+ }
1182
+
1183
+ for c in acct!.capabilities.storage.getControllers(forPath: forPath) {
1184
+ if c.borrowType.isSubtype(of: type) {
1185
+ return c.capabilityID
1186
+ }
1187
+ }
1188
+
1189
+ return nil
1190
+ }
1191
+
1122
1192
  init(
1123
- _ acct: Capability<&AuthAccount>
1193
+ _ acct: Capability<auth(Storage, Contracts, Keys, Inbox, Capabilities) &Account>
1124
1194
  ) {
1125
1195
  self.acct = acct
1126
1196
 
@@ -1134,36 +1204,39 @@ pub contract HybridCustody {
1134
1204
  self.display = nil
1135
1205
  }
1136
1206
 
1137
- destroy () {
1138
- destroy <- self.resources
1207
+ // When an OwnedAccount is destroyed, remove it from every configured parent account
1208
+ access(contract) fun burnCallback() {
1209
+ for p in self.parents.keys {
1210
+ self.removeParent(parent: p)
1211
+ }
1139
1212
  }
1140
1213
  }
1141
1214
 
1142
1215
  /// Utility function to get the path identifier for a parent address when interacting with a ChildAccount and its
1143
1216
  /// parents
1144
1217
  ///
1145
- pub fun getChildAccountIdentifier(_ addr: Address): String {
1218
+ access(all) view fun getChildAccountIdentifier(_ addr: Address): String {
1146
1219
  return "ChildAccount_".concat(addr.toString())
1147
1220
  }
1148
1221
 
1149
1222
  /// Utility function to get the path identifier for a parent address when interacting with a Delegator and its
1150
1223
  /// parents
1151
1224
  ///
1152
- pub fun getCapabilityDelegatorIdentifier(_ addr: Address): String {
1225
+ access(all) view fun getCapabilityDelegatorIdentifier(_ addr: Address): String {
1153
1226
  return "ChildCapabilityDelegator_".concat(addr.toString())
1154
1227
  }
1155
1228
 
1156
1229
  /// Utility function to get the path identifier for a parent address when interacting with an OwnedAccount and its
1157
1230
  /// owners
1158
1231
  ///
1159
- pub fun getOwnerIdentifier(_ addr: Address): String {
1232
+ access(all) view fun getOwnerIdentifier(_ addr: Address): String {
1160
1233
  return "HybridCustodyOwnedAccount_".concat(HybridCustody.account.address.toString()).concat(addr.toString())
1161
1234
  }
1162
1235
 
1163
1236
  /// Returns an OwnedAccount wrapping the provided AuthAccount Capability.
1164
1237
  ///
1165
- pub fun createOwnedAccount(
1166
- acct: Capability<&AuthAccount>
1238
+ access(all) fun createOwnedAccount(
1239
+ acct: Capability<auth(Storage, Contracts, Keys, Inbox, Capabilities) &Account>
1167
1240
  ): @OwnedAccount {
1168
1241
  pre {
1169
1242
  acct.check(): "invalid auth account capability"
@@ -1176,7 +1249,7 @@ pub contract HybridCustody {
1176
1249
 
1177
1250
  /// Returns a new Manager with the provided Filter as default (if not nil).
1178
1251
  ///
1179
- pub fun createManager(filter: Capability<&{CapabilityFilter.Filter}>?): @Manager {
1252
+ access(all) fun createManager(filter: Capability<&{CapabilityFilter.Filter}>?): @Manager {
1180
1253
  pre {
1181
1254
  filter == nil || filter!.check(): "Invalid CapabilityFilter Filter capability provided"
1182
1255
  }