From 19012820f19e4b7128585178f820009a9f8afcdd Mon Sep 17 00:00:00 2001 From: Austin Kline Date: Tue, 28 May 2024 13:20:22 -0700 Subject: [PATCH] Crescendo (#48) * upgrade all LostAndFound contracts to Crescendo --- .github/workflows/unit-tests.yml | 2 +- codecov.yml | 3 + contracts/FeeEstimator.cdc | 36 +- contracts/LostAndFound.cdc | 349 +++++++++--------- contracts/LostAndFoundHelper.cdc | 24 +- contracts/standard/ExampleNFT.cdc | 188 ++++++---- contracts/standard/ExampleToken.cdc | 157 ++++++-- flow.json | 25 +- package-lock.json | 14 +- package.json | 2 +- run-tests.sh | 2 +- scripts/example-nft/borrow_all_tickets.cdc | 2 +- scripts/example-token/borrow_all_tickets.cdc | 2 +- scripts/import_contracts.cdc | 2 +- scripts/lost-and-found/borrow_all_tickets.cdc | 2 +- scripts/lost-and-found/check_ticket_item.cdc | 2 +- .../lost-and-found/estimate_deposit_nft.cdc | 8 +- scripts/lost-and-found/get_address.cdc | 2 +- .../lost-and-found/get_redeemable_types.cdc | 2 +- scripts/lost-and-found/get_shelf_owner.cdc | 2 +- .../lost-and-found/get_ticket_ft_balance.cdc | 2 +- scripts/lost-and-found/shelf_has_type.cdc | 2 +- tests/LostAndFound_tests.cdc | 210 +++++------ tests/test_helpers.cdc | 90 +++-- transactions/clear_all_tickets.cdc | 38 +- transactions/depositor/add_flow_tokens.cdc | 7 +- .../depositor/add_flow_tokens_public.cdc | 6 +- transactions/depositor/destroy.cdc | 6 +- transactions/depositor/set_threshold.cdc | 8 +- transactions/depositor/setup_depositor.cdc | 12 +- .../depositor/withdraw_below_threshold.cdc | 16 +- .../depositor/withdraw_to_threshold.cdc | 16 +- transactions/depositor/withdraw_tokens.cdc | 12 +- .../destroy_example_nft_storage.cdc | 8 +- .../mint_and_deposit_example_nft.cdc | 43 ++- .../mint_and_deposit_example_nfts.cdc | 25 +- .../mint_and_deposit_with_depositor.cdc | 8 +- transactions/example-nft/mint_example_nft.cdc | 7 +- .../example-nft/redeem_example_nft_all.cdc | 28 +- transactions/example-nft/setup.cdc | 45 ++- .../example-nft/setup_account_example_nft.cdc | 14 +- .../example-nft/try_send_example_nft.cdc | 47 ++- .../try_send_example_nft_with_depositor.cdc | 20 +- .../try_send_multiple_example_nft.cdc | 31 +- .../example-token/deposit_example_token.cdc | 28 +- .../deposit_example_token_with_depositor.cdc | 8 +- .../destroy_example_token_storage.cdc | 10 +- .../redeem_example_token_all.cdc | 32 +- transactions/example-token/setup.cdc | 53 ++- .../example-token/setup_account_ft.cdc | 22 +- .../example-token/try_send_example_token.cdc | 54 ++- .../try_send_example_token_depositor.cdc | 26 +- transactions/flow/mint_flow.cdc | 8 +- 53 files changed, 945 insertions(+), 823 deletions(-) create mode 100644 codecov.yml diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 4fc7f24..9f6fa88 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -26,7 +26,7 @@ jobs: - name: Install Flow dependencies run: npm i - name: Install Flow CLI - run: bash -ci "$(curl -fsSL https://raw.githubusercontent.com/onflow/flow-cli/master/install.sh)" -- v1.10.0 + run: bash -ci "$(curl -fsSL https://raw.githubusercontent.com/onflow/flow-cli/feature/stable-cadence/install.sh)" - name: Run tests run: | ./run-tests.sh diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..aa67c36 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,3 @@ +ignore: + - "contracts/standard/ExampleToken.cdc" + - "contracts/standard/ExampleNFT.cdc" \ No newline at end of file diff --git a/contracts/FeeEstimator.cdc b/contracts/FeeEstimator.cdc index 2337b75..23125dc 100644 --- a/contracts/FeeEstimator.cdc +++ b/contracts/FeeEstimator.cdc @@ -11,49 +11,41 @@ import "FlowToken" Consumers of this contract would then need to pop the resource out of the DepositEstimate resource to get it back */ -pub contract FeeEstimator { - pub resource DepositEstimate { - pub var item: @AnyResource? - pub var storageFee: UFix64 +access(all) contract FeeEstimator { + access(all) resource DepositEstimate { + access(all) var item: @AnyResource? + access(all) var storageFee: UFix64 init(item: @AnyResource, storageFee: UFix64) { self.item <- item self.storageFee = storageFee } - pub fun withdraw(): @AnyResource { - let resource <- self.item <- nil - return <-resource! - } - - destroy() { - pre { - self.item == nil: "cannot destroy with non-null item" - } - - destroy self.item + access(all) fun withdraw(): @AnyResource { + let r <- self.item <- nil + return <-r! } } - pub fun hasStorageCapacity(_ addr: Address, _ storageFee: UFix64): Bool { + access(all) fun hasStorageCapacity(_ addr: Address, _ storageFee: UFix64): Bool { return FlowStorageFees.defaultTokenAvailableBalance(addr) > storageFee } - pub fun estimateDeposit( + access(all) fun estimateDeposit( item: @AnyResource, ): @DepositEstimate { - let storageUsedBefore = FeeEstimator.account.storageUsed - FeeEstimator.account.save(<-item, to: /storage/temp) - let storageUsedAfter = FeeEstimator.account.storageUsed + let storageUsedBefore = FeeEstimator.account.storage.used + FeeEstimator.account.storage.save(<-item, to: /storage/temp) + let storageUsedAfter = FeeEstimator.account.storage.used let storageDiff = storageUsedAfter - storageUsedBefore let storageFee = FeeEstimator.storageUsedToFlowAmount(storageDiff) - let loadedItem <- FeeEstimator.account.load<@AnyResource>(from: /storage/temp)! + let loadedItem <- FeeEstimator.account.storage.load<@AnyResource>(from: /storage/temp)! let estimate <- create DepositEstimate(item: <-loadedItem, storageFee: storageFee) return <- estimate } - pub fun storageUsedToFlowAmount(_ storageUsed: UInt64): UFix64 { + access(all) fun storageUsedToFlowAmount(_ storageUsed: UInt64): UFix64 { let storageMB = FlowStorageFees.convertUInt64StorageBytesToUFix64Megabytes(storageUsed) return FlowStorageFees.storageCapacityToFlow(storageMB) } diff --git a/contracts/LostAndFound.cdc b/contracts/LostAndFound.cdc index fbbf089..713b957 100644 --- a/contracts/LostAndFound.cdc +++ b/contracts/LostAndFound.cdc @@ -27,49 +27,48 @@ import "FeeEstimator" // - NonFunigibleToken.Receiver // - FungibleToken.Receiver // - LostAndFound.ResourceReceiver (This is a placeholder so that non NFT and FT resources can be utilized here) -pub contract LostAndFound { +access(all) contract LostAndFound { access(contract) let storageFees: {UInt64: UFix64} - pub let LostAndFoundPublicPath: PublicPath - pub let LostAndFoundStoragePath: StoragePath - pub let DepositorPublicPath: PublicPath - pub let DepositorStoragePath: StoragePath + access(all) let LostAndFoundPublicPath: PublicPath + access(all) let LostAndFoundStoragePath: StoragePath + access(all) let DepositorPublicPath: PublicPath + access(all) let DepositorStoragePath: StoragePath - pub event TicketDeposited(redeemer: Address, ticketID: UInt64, type: Type, memo: String?, name: String?, description: String?, thumbnail: String?) - pub event TicketRedeemed(redeemer: Address, ticketID: UInt64, type: Type) - pub event BinDestroyed(redeemer: Address, type: Type) - pub event ShelfDestroyed(redeemer: Address) + access(all) event TicketDeposited(redeemer: Address, ticketID: UInt64, type: Type, memo: String?, name: String?, description: String?, thumbnail: String?) + access(all) event TicketRedeemed(redeemer: Address, ticketID: UInt64, type: Type) + access(all) event BinDestroyed(redeemer: Address, type: Type) + access(all) event ShelfDestroyed(redeemer: Address) - pub event DepositorCreated(uuid: UInt64) - pub event DepositorBalanceLow(uuid: UInt64, threshold: UFix64, balance: UFix64) - pub event DepositorTokensAdded(uuid: UInt64, tokens: UFix64, balance: UFix64) - pub event DepositorTokensWithdrawn(uuid: UInt64, tokens: UFix64, balance: UFix64) + access(all) event DepositorCreated(uuid: UInt64) + access(all) event DepositorBalanceLow(uuid: UInt64, threshold: UFix64, balance: UFix64) + access(all) event DepositorTokensAdded(uuid: UInt64, tokens: UFix64, balance: UFix64) + access(all) event DepositorTokensWithdrawn(uuid: UInt64, tokens: UFix64, balance: UFix64) + + // Used by the @Depositor resource and controls whether the depositor can be used + // or not to send resources to the LostAndFound + access(all) entitlement Deposit + + // Used by the @Depositor resource to manage settings such as low token threshold + access(all) entitlement Owner // Placeholder receiver so that any resource can be supported, not just FT and NFT Receivers - pub resource interface AnyResourceReceiver { - pub fun deposit(resource: @AnyResource) + access(all) resource interface AnyResourceReceiver { + access(Deposit) fun deposit(item: @AnyResource) } - pub resource DepositEstimate { - pub var item: @AnyResource? - pub let storageFee: UFix64 + access(all) resource DepositEstimate { + access(self) var item: @AnyResource? + access(all) let storageFee: UFix64 init(item: @AnyResource, storageFee: UFix64) { self.item <- item self.storageFee = storageFee } - pub fun withdraw(): @AnyResource { - let resource <- self.item <- nil - return <-resource! - } - - destroy() { - pre { - self.item == nil: "cannot destroy with non-null item" - } - - destroy self.item + access(all) fun withdraw(): @AnyResource { + let item <- self.item <- nil + return <-item! } } @@ -78,24 +77,30 @@ pub contract LostAndFound { // - memo: An optional message to attach to this ticket // - redeemer: The address which is allowed to withdraw the item from this ticket // - redeemed: Whether the ticket has been redeemed. This can only be set by the LostAndFound contract - pub resource Ticket { + access(all) resource Ticket { // The item to be redeemed access(contract) var item: @AnyResource? // An optional message to attach to this item. - pub let memo: String? + access(all) let memo: String? // an optional Display view so that frontend's that borrow this ticket know how to show it - pub let display: MetadataViews.Display? + access(all) let display: MetadataViews.Display? // The address that it allowed to withdraw the item fromt this ticket - pub let redeemer: Address + access(all) let redeemer: Address //The type of the resource (non-optional) so that bins can represent the true type of an item - pub let type: Type + access(all) let type: Type // State maintained by LostAndFound - pub var redeemed: Bool + access(all) var redeemed: Bool // flow token amount used to store this ticket is returned when the ticket is redeemed - access(contract) let flowTokenRepayment: Capability<&FlowToken.Vault{FungibleToken.Receiver}>? + access(contract) let flowTokenRepayment: Capability<&FlowToken.Vault>? - init (item: @AnyResource, memo: String?, display: MetadataViews.Display?, redeemer: Address, flowTokenRepayment: Capability<&FlowToken.Vault{FungibleToken.Receiver}>?) { + init ( + item: @AnyResource, + memo: String?, + display: MetadataViews.Display?, + redeemer: Address, + flowTokenRepayment: Capability<&FlowToken.Vault>? + ) { self.type = item.getType() self.item <- item self.memo = memo @@ -106,40 +111,40 @@ pub contract LostAndFound { self.flowTokenRepayment = flowTokenRepayment } - pub fun itemType(): Type { + access(all) view fun itemType(): Type { return self.type } - pub fun checkItem(): Bool { + access(all) fun checkItem(): Bool { return self.item != nil } // A function to get depositor address / flow Repayment address - pub fun getFlowRepaymentAddress() : Address? { + access(all) fun getFlowRepaymentAddress() : Address? { return self.flowTokenRepayment?.address } // If this is an instance of NFT, return the id , otherwise return nil - pub fun getNonFungibleTokenID() : UInt64? { - if self.type.isSubtype(of: Type<@NonFungibleToken.NFT>()) { - let ref = (&self.item as auth &AnyResource?)! - let nft = ref as! &NonFungibleToken.NFT + access(all) fun getNonFungibleTokenID() : UInt64? { + if self.type.isSubtype(of: Type<@{NonFungibleToken.NFT}>()) { + let ref = (&self.item as &AnyResource?)! + let nft = ref as! &{NonFungibleToken.NFT} return nft.id } return nil } // If this is an instance of FT, return the vault balance , otherwise return nil - pub fun getFungibleTokenBalance() : UFix64? { - if self.type.isSubtype(of: Type<@FungibleToken.Vault>()) { - let ref = (&self.item as auth &AnyResource?)! - let ft = ref as! &FungibleToken.Vault + access(all) fun getFungibleTokenBalance() : UFix64? { + if self.type.isSubtype(of: Type<@{FungibleToken.Vault}>()) { + let ref = (&self.item as &AnyResource?)! + let ft = ref as! &{FungibleToken.Vault} return ft.balance } return nil } - pub fun withdraw(receiver: Capability) { + access(contract) fun withdraw(receiver: Capability) { pre { receiver.address == self.redeemer: "receiver address and redeemer must match" !self.redeemed: "already redeemed" @@ -148,25 +153,25 @@ pub contract LostAndFound { var redeemableItem <- self.item <- nil let cap = receiver.borrow<&AnyResource>()! - if cap.isInstance(Type<@NonFungibleToken.Collection>()) { - let target = receiver.borrow<&AnyResource{NonFungibleToken.CollectionPublic}>()! - let token <- redeemableItem as! @NonFungibleToken.NFT? + if cap.isInstance(Type<@{NonFungibleToken.CollectionPublic}>()) { + let target = receiver.borrow<&{NonFungibleToken.CollectionPublic}>()! + let token <- redeemableItem as! @{NonFungibleToken.NFT}? self.redeemed = true emit TicketRedeemed(redeemer: self.redeemer, ticketID: self.uuid, type: token.getType()) target.deposit(token: <- token!) return - } else if cap.isInstance(Type<@FungibleToken.Vault>()) { - let target = receiver.borrow<&AnyResource{FungibleToken.Receiver}>()! - let token <- redeemableItem as! @FungibleToken.Vault? + } else if cap.isInstance(Type<@{FungibleToken.Vault}>()) { + let target = receiver.borrow<&{FungibleToken.Receiver}>()! + let token <- redeemableItem as! @{FungibleToken.Vault}? self.redeemed = true emit TicketRedeemed(redeemer: self.redeemer, ticketID: self.uuid, type: token.getType()) target.deposit(from: <- token!) return - } else if cap.isInstance(Type<@AnyResource{LostAndFound.AnyResourceReceiver}>()) { - let target = receiver.borrow<&{LostAndFound.AnyResourceReceiver}>()! + } else if cap.isInstance(Type<@{LostAndFound.AnyResourceReceiver}>()) { + let target = receiver.borrow()! self.redeemed = true emit TicketRedeemed(redeemer: self.redeemer, ticketID: self.uuid, type: redeemableItem.getType()) - target.deposit(resource: <- redeemableItem) + target.deposit(item: <- redeemableItem) return } else{ panic("cannot redeem resource to receiver") @@ -181,15 +186,13 @@ pub contract LostAndFound { return <-redeemableItem! } - // destructon is only allowed if the ticket has been redeemed and the underlying item is a our dummy resource - destroy () { + access(contract) fun safeDestroy() { pre { self.redeemed: "Ticket has not been redeemed" self.item == nil: "can only destroy if not holding any item" } LostAndFound.storageFees.remove(key: self.uuid) - destroy <-self.item } } @@ -197,11 +200,11 @@ pub contract LostAndFound { // A Bin is a resource that gathers tickets whos item have the same type. // For instance, if two TopShot Moments are deposited to the same redeemer, only one bin // will be made which will contain both tickets to redeem each individual moment. - pub resource Bin { + access(all) resource Bin { access(contract) let tickets: @{UInt64:Ticket} access(contract) let type: Type - pub let flowTokenRepayment: Capability<&{FungibleToken.Receiver}>? + access(all) let flowTokenRepayment: Capability<&{FungibleToken.Receiver}>? init (type: Type, flowTokenRepayment: Capability<&{FungibleToken.Receiver}>?) { self.tickets <- {} @@ -209,11 +212,11 @@ pub contract LostAndFound { self.flowTokenRepayment = flowTokenRepayment } - pub fun borrowTicket(id: UInt64): &LostAndFound.Ticket? { - return &self.tickets[id] as &LostAndFound.Ticket? + access(all) fun borrowTicket(id: UInt64): &LostAndFound.Ticket? { + return &self.tickets[id] } - pub fun borrowAllTicketsByType(): [&LostAndFound.Ticket] { + access(all) fun borrowAllTicketsByType(): [&LostAndFound.Ticket] { let tickets: [&LostAndFound.Ticket] = [] let ids = self.tickets.keys for id in ids { @@ -244,7 +247,7 @@ pub contract LostAndFound { emit TicketDeposited(redeemer: redeemer, ticketID: ticketID, type: self.type, memo: memo, name: name, description: description, thumbnail: thumbnail) } - pub fun getTicketIDs(): [UInt64] { + access(all) fun getTicketIDs(): [UInt64] { return self.tickets.keys } @@ -253,16 +256,17 @@ pub contract LostAndFound { return <- ticket! } - destroy () { - destroy <-self.tickets - LostAndFound.storageFees.remove(key: self.uuid) + access(contract) fun safeDestroy() { + pre { + self.tickets.length == 0: "cannot destroy bin with tickets in it" + } } } // A shelf is our top-level organization resource. // It groups bins by type to help make discovery of the assets that a // redeeming address can claim. - pub resource Shelf { + access(all) resource Shelf { access(self) let bins: @{String: Bin} access(self) let identifierToType: {String: Type} access(self) let redeemer: Address @@ -275,11 +279,11 @@ pub contract LostAndFound { self.flowTokenRepayment = flowTokenRepayment } - pub fun getOwner(): Address { + access(all) fun getOwner(): Address { return self.owner!.address } - pub fun getRedeemableTypes(): [Type] { + access(all) fun getRedeemableTypes(): [Type] { let types: [Type] = [] for k in self.bins.keys { let t = self.identifierToType[k]! @@ -290,26 +294,26 @@ pub contract LostAndFound { return types } - pub fun hasType(type: Type): Bool { + access(all) fun hasType(type: Type): Bool { return self.bins[type.identifier] != nil } - pub fun borrowBin(type: Type): &LostAndFound.Bin? { - return &self.bins[type.identifier] as &LostAndFound.Bin? + access(all) fun borrowBin(type: Type): &LostAndFound.Bin? { + return &self.bins[type.identifier] } access(contract) fun ensureBin(type: Type, flowTokenRepayment: Capability<&{FungibleToken.Receiver}>?): &Bin { if !self.bins.containsKey(type.identifier) { - let storageBefore = LostAndFound.account.storageUsed + let storageBefore = LostAndFound.account.storage.used let bin <- create Bin(type: type, flowTokenRepayment: flowTokenRepayment) let uuid = bin.uuid let oldValue <- self.bins.insert(key: type.identifier, <-bin) - LostAndFound.storageFees[uuid] = FeeEstimator.storageUsedToFlowAmount(LostAndFound.account.storageUsed - storageBefore) + LostAndFound.storageFees[uuid] = FeeEstimator.storageUsedToFlowAmount(LostAndFound.account.storage.used - storageBefore) self.identifierToType[type.identifier] = type destroy oldValue } - return (&self.bins[type.identifier] as &LostAndFound.Bin?)! + return (&self.bins[type.identifier])! } access(contract) fun deposit(ticket: @LostAndFound.Ticket, flowTokenRepayment: Capability<&{FungibleToken.Receiver}>?) { @@ -325,7 +329,7 @@ pub contract LostAndFound { // Only one of the three receiver options can be specified, and an optional maximum number of tickets // to redeem can be picked to prevent gas issues in case there are large numbers of tickets to be // redeemed at once. - pub fun redeemAll(type: Type, max: Int?, receiver: Capability) { + access(all) fun redeemAll(type: Type, max: Int?, receiver: Capability) { pre { receiver.address == self.redeemer: "receiver must match the redeemer of this shelf" self.bins.containsKey(type.identifier): "no bin for provided type" @@ -344,7 +348,7 @@ pub contract LostAndFound { } // Redeem a specific ticket instead of all of a certain type. - pub fun redeem(type: Type, ticketID: UInt64, receiver: Capability) { + access(all) fun redeem(type: Type, ticketID: UInt64, receiver: Capability) { pre { receiver.address == self.redeemer: "receiver must match the redeemer of this shelf" self.bins.containsKey(type.identifier): "no bin for provided type" @@ -361,6 +365,8 @@ pub contract LostAndFound { let repaymentVault <- refundProvider.withdraw(amount: LostAndFound.storageFees[uuid]!) refundCap!.borrow()!.deposit(from: <-repaymentVault) } + + ticket.safeDestroy() destroy ticket if borrowedBin.getTicketIDs().length == 0 { @@ -375,77 +381,81 @@ pub contract LostAndFound { let vault <- provider.withdraw(amount: LostAndFound.storageFees[uuid]!) flowTokenRepayment!.borrow()!.deposit(from: <-vault) } + + bin.safeDestroy() destroy bin } } - destroy () { - destroy <- self.bins + access(contract) fun safeDestroy() { + pre { + self.bins.length == 0: "cannot destroy a shelf with bins in it" + } LostAndFound.storageFees.remove(key: self.uuid) } } - access(contract) fun getFlowProvider(): &FlowToken.Vault{FungibleToken.Provider} { - return self.account.borrow<&FlowToken.Vault{FungibleToken.Provider}>(from: /storage/flowTokenVault)! + access(contract) fun getFlowProvider(): auth(FungibleToken.Withdraw) &FlowToken.Vault { + return self.account.storage.borrow(from: /storage/flowTokenVault)! } // ShelfManager is a light-weight wrapper to get our shelves into storage. - pub resource ShelfManager { + access(all) resource ShelfManager { access(self) let shelves: @{Address: Shelf} init() { self.shelves <- {} } - access(contract) fun ensureShelf(_ addr: Address, flowTokenRepayment: Capability<&FlowToken.Vault{FungibleToken.Receiver}>?): &LostAndFound.Shelf { + access(contract) fun ensureShelf(_ addr: Address, flowTokenRepayment: Capability<&FlowToken.Vault>?): &LostAndFound.Shelf { if !self.shelves.containsKey(addr) { - let storageBefore = LostAndFound.account.storageUsed + let storageBefore = LostAndFound.account.storage.used let shelf <- create Shelf(redeemer: addr, flowTokenRepayment: flowTokenRepayment) let uuid = shelf.uuid let oldValue <- self.shelves.insert(key: addr, <-shelf) - LostAndFound.storageFees[uuid] = FeeEstimator.storageUsedToFlowAmount(LostAndFound.account.storageUsed - storageBefore) + LostAndFound.storageFees[uuid] = FeeEstimator.storageUsedToFlowAmount(LostAndFound.account.storage.used - storageBefore) destroy oldValue } - return (&self.shelves[addr] as &LostAndFound.Shelf?)! + return (&self.shelves[addr])! } - pub fun deposit( + access(all) fun deposit( redeemer: Address, item: @AnyResource, memo: String?, display: MetadataViews.Display?, - storagePayment: &FungibleToken.Vault, - flowTokenRepayment: Capability<&FlowToken.Vault{FungibleToken.Receiver}>? + storagePayment: auth(FungibleToken.Withdraw) &{FungibleToken.Vault}, + flowTokenRepayment: Capability<&FlowToken.Vault>? ) : UInt64 { pre { flowTokenRepayment == nil || flowTokenRepayment!.check(): "flowTokenRepayment is not valid" storagePayment.getType() == Type<@FlowToken.Vault>(): "storage payment must be in flow tokens" } let receiver = LostAndFound.account - .getCapability<&FlowToken.Vault{FungibleToken.Receiver}>(/public/flowTokenReceiver) + .capabilities.get<&FlowToken.Vault>(/public/flowTokenReceiver) .borrow()! - let storageBeforeShelf = LostAndFound.account.storageUsed + let storageBeforeShelf = LostAndFound.account.storage.used let shelf = self.ensureShelf(redeemer, flowTokenRepayment: flowTokenRepayment) - if LostAndFound.account.storageUsed != storageBeforeShelf && LostAndFound.storageFees[shelf.uuid] != nil { + if LostAndFound.account.storage.used != storageBeforeShelf && LostAndFound.storageFees[shelf.uuid] != nil { receiver.deposit(from: <-storagePayment.withdraw(amount: LostAndFound.storageFees[shelf.uuid]!)) } - let storageBeforeBin = LostAndFound.account.storageUsed + let storageBeforeBin = LostAndFound.account.storage.used let bin = shelf.ensureBin(type: item.getType(), flowTokenRepayment: flowTokenRepayment) - if LostAndFound.account.storageUsed != storageBeforeBin { + if LostAndFound.account.storage.used != storageBeforeBin { receiver.deposit(from: <-storagePayment.withdraw(amount: LostAndFound.storageFees[bin.uuid]!)) } - let storageBefore = LostAndFound.account.storageUsed + let storageBefore = LostAndFound.account.storage.used let ticket <- create Ticket(item: <-item, memo: memo, display: display, redeemer: redeemer, flowTokenRepayment: flowTokenRepayment) let uuid = ticket.uuid let flowTokenRepayment = ticket.flowTokenRepayment shelf.deposit(ticket: <-ticket, flowTokenRepayment: flowTokenRepayment) - let storageUsedAfter = LostAndFound.account.storageUsed + let storageUsedAfter = LostAndFound.account.storage.used let storageFee = FeeEstimator.storageUsedToFlowAmount(storageUsedAfter - storageBefore) LostAndFound.storageFees[uuid] = storageFee @@ -454,15 +464,15 @@ pub contract LostAndFound { return uuid } - pub fun borrowShelf(redeemer: Address): &LostAndFound.Shelf? { - return &self.shelves[redeemer] as &LostAndFound.Shelf? + access(all) fun borrowShelf(redeemer: Address): &LostAndFound.Shelf? { + return &self.shelves[redeemer] } // deleteShelf // // delete a shelf if it has no redeemable types - pub fun deleteShelf(_ addr: Address) { - let storageBefore = LostAndFound.account.storageUsed + access(all) fun deleteShelf(_ addr: Address) { + let storageBefore = LostAndFound.account.storage.used assert(self.shelves.containsKey(addr), message: "shelf does not exist") let tmp <- self.shelves[addr] <- nil let shelf <-! tmp! @@ -475,23 +485,27 @@ pub contract LostAndFound { let vault <- provider.withdraw(amount: LostAndFound.storageFees[uuid]!) flowTokenRepayment!.borrow()!.deposit(from: <-vault) } + + shelf.safeDestroy() destroy shelf emit ShelfDestroyed(redeemer: addr) } - - destroy () { - destroy <-self.shelves + + access(contract) fun safeDestroy() { + pre { + self.shelves.length == 0: "cannot destroy shelf manager when it has shelves" + } } } - pub resource interface DepositorPublic { - pub fun balance(): UFix64 - pub fun addFlowTokens(vault: @FlowToken.Vault) + access(all) resource interface DepositorPublic { + access(all) fun balance(): UFix64 + access(all) fun addFlowTokens(vault: @FlowToken.Vault) } - pub resource Depositor: DepositorPublic { + access(all) resource Depositor: DepositorPublic { access(self) let flowTokenVault: @FlowToken.Vault - pub let flowTokenRepayment: Capability<&FlowToken.Vault{FungibleToken.Receiver}> + access(all) let flowTokenRepayment: Capability<&FlowToken.Vault> access(self) var lowBalanceThreshold: UFix64? access(self) fun checkForLowBalance(): Bool { @@ -503,45 +517,45 @@ pub contract LostAndFound { return false } - pub fun setLowBalanceThreshold(threshold: UFix64?) { + access(Owner) fun setLowBalanceThreshold(threshold: UFix64?) { self.lowBalanceThreshold = threshold } - pub fun getLowBalanceThreshold(): UFix64? { + access(Owner) fun getLowBalanceThreshold(): UFix64? { return self.lowBalanceThreshold } - pub fun deposit( + access(Deposit) fun deposit( redeemer: Address, item: @AnyResource, memo: String?, display: MetadataViews.Display? ) : UInt64 { let receiver = LostAndFound.account - .getCapability<&FlowToken.Vault{FungibleToken.Receiver}>(/public/flowTokenReceiver) + .capabilities.get<&FlowToken.Vault>(/public/flowTokenReceiver) .borrow()! - let storageBeforeShelf = LostAndFound.account.storageUsed + let storageBeforeShelf = LostAndFound.account.storage.used let shelfManager = LostAndFound.borrowShelfManager() let shelf = shelfManager.ensureShelf(redeemer, flowTokenRepayment: self.flowTokenRepayment) - if LostAndFound.account.storageUsed != storageBeforeShelf && LostAndFound.storageFees[shelf.uuid] != nil { + if LostAndFound.account.storage.used != storageBeforeShelf && LostAndFound.storageFees[shelf.uuid] != nil { receiver.deposit(from: <-self.withdrawTokens(amount: LostAndFound.storageFees[shelf.uuid]!)) } - let storageBeforeBin = LostAndFound.account.storageUsed + let storageBeforeBin = LostAndFound.account.storage.used let bin = shelf.ensureBin(type: item.getType(), flowTokenRepayment: self.flowTokenRepayment) - if storageBeforeBin != LostAndFound.account.storageUsed { + if storageBeforeBin != LostAndFound.account.storage.used { receiver.deposit(from: <-self.withdrawTokens(amount: LostAndFound.storageFees[bin.uuid]!)) } - let storageBefore = LostAndFound.account.storageUsed + let storageBefore = LostAndFound.account.storage.used let ticket <- create Ticket(item: <-item, memo: memo, display: display, redeemer: redeemer, flowTokenRepayment: self.flowTokenRepayment) let flowTokenRepayment = ticket.flowTokenRepayment let uuid = ticket.uuid shelf.deposit(ticket: <-ticket, flowTokenRepayment: flowTokenRepayment) - let storageFee = FeeEstimator.storageUsedToFlowAmount(LostAndFound.account.storageUsed - storageBefore) + let storageFee = FeeEstimator.storageUsedToFlowAmount(LostAndFound.account.storage.used - storageBefore) LostAndFound.storageFees[uuid] = storageFee let storagePaymentVault <- self.withdrawTokens(amount: storageFee) @@ -550,69 +564,67 @@ pub contract LostAndFound { return uuid } - pub fun trySendResource( - item: @AnyResource, - cap: Capability, - memo: String?, - display: MetadataViews.Display? + access(Deposit) fun trySendResource( + item: @AnyResource, + cap: Capability, + memo: String?, + display: MetadataViews.Display? ) { - if cap.check<&{NonFungibleToken.CollectionPublic}>() { - let nft <- item as! @NonFungibleToken.NFT + let nft <- item as! @{NonFungibleToken.NFT} cap.borrow<&{NonFungibleToken.CollectionPublic}>()!.deposit(token: <-nft) - } else if cap.check<&{NonFungibleToken.Receiver}>() { - let nft <- item as! @NonFungibleToken.NFT - cap.borrow<&{NonFungibleToken.Receiver}>()!.deposit(token: <-nft) } else if cap.check<&{FungibleToken.Receiver}>() { - let vault <- item as! @FungibleToken.Vault + let vault <- item as! @{FungibleToken.Vault} cap.borrow<&{FungibleToken.Receiver}>()!.deposit(from: <-vault) } else { self.deposit(redeemer: cap.address, item: <-item, memo: memo, display: display) } } - pub fun withdrawTokens(amount: UFix64): @FungibleToken.Vault { + access(Owner) fun withdrawTokens(amount: UFix64): @{FungibleToken.Vault} { let tokens <-self.flowTokenVault.withdraw(amount: amount) emit DepositorTokensWithdrawn(uuid: self.uuid, tokens: amount, balance: self.flowTokenVault.balance) self.checkForLowBalance() return <-tokens } - pub fun addFlowTokens(vault: @FlowToken.Vault) { + access(all) fun addFlowTokens(vault: @FlowToken.Vault) { let tokensAdded = vault.balance self.flowTokenVault.deposit(from: <-vault) emit DepositorTokensAdded(uuid: self.uuid, tokens: tokensAdded, balance: self.flowTokenVault.balance) self.checkForLowBalance() } - pub fun balance(): UFix64 { + access(all) fun balance(): UFix64 { return self.flowTokenVault.balance } - init(_ flowTokenRepayment: Capability<&FlowToken.Vault{FungibleToken.Receiver}>, lowBalanceThreshold: UFix64?) { + init(_ flowTokenRepayment: Capability<&FlowToken.Vault>, lowBalanceThreshold: UFix64?) { self.flowTokenRepayment = flowTokenRepayment - let vault <- FlowToken.createEmptyVault() - self.flowTokenVault <- vault as! @FlowToken.Vault + let vault <- FlowToken.createEmptyVault(vaultType: Type<@FlowToken.Vault>()) + self.flowTokenVault <- vault self.lowBalanceThreshold = lowBalanceThreshold } - destroy() { - self.flowTokenRepayment.borrow()!.deposit(from: <-self.flowTokenVault) + access(contract) fun safeDestroy() { + pre { + self.flowTokenVault.balance == 0.0: "depositor still has flow tokens to be withdrawn" + } } } - pub fun createDepositor(_ flowTokenRepayment: Capability<&FlowToken.Vault{FungibleToken.Receiver}>, lowBalanceThreshold: UFix64?): @Depositor { + access(all) fun createDepositor(_ flowTokenRepayment: Capability<&FlowToken.Vault>, lowBalanceThreshold: UFix64?): @Depositor { let depositor <- create Depositor(flowTokenRepayment, lowBalanceThreshold: lowBalanceThreshold) emit DepositorCreated(uuid: depositor.uuid) return <- depositor } - pub fun borrowShelfManager(): &LostAndFound.ShelfManager { - return self.account.getCapability<&LostAndFound.ShelfManager>(LostAndFound.LostAndFoundPublicPath).borrow()! + access(all) fun borrowShelfManager(): &LostAndFound.ShelfManager { + return self.account.capabilities.get<&LostAndFound.ShelfManager>(LostAndFound.LostAndFoundPublicPath).borrow()! } - pub fun borrowAllTicketsByType(addr: Address, type: Type): [&LostAndFound.Ticket] { + access(all) fun borrowAllTicketsByType(addr: Address, type: Type): [&LostAndFound.Ticket] { let manager = LostAndFound.borrowShelfManager() let shelf = manager.borrowShelf(redeemer: addr) if shelf == nil { @@ -627,7 +639,7 @@ pub contract LostAndFound { return bin!.borrowAllTicketsByType() } - pub fun borrowAllTickets(addr: Address): [&LostAndFound.Ticket] { + access(all) fun borrowAllTickets(addr: Address): [&LostAndFound.Ticket] { let manager = LostAndFound.borrowShelfManager() let shelf = manager.borrowShelf(redeemer: addr) if shelf == nil { @@ -645,19 +657,19 @@ pub contract LostAndFound { return allTickets } - pub fun redeemAll(type: Type, max: Int?, receiver: Capability) { + access(all) fun redeemAll(type: Type, max: Int?, receiver: Capability) { let manager = LostAndFound.borrowShelfManager() - let shelf = manager.borrowShelf(redeemer: receiver.address) + let shelf = manager.borrowShelf(redeemer: receiver.address)! assert(shelf != nil, message: "shelf not found") - shelf!.redeemAll(type: type, max: max, receiver: receiver) - let remainingTypes = shelf!.getRedeemableTypes() + shelf.redeemAll(type: type, max: max, receiver: receiver) + let remainingTypes = shelf.getRedeemableTypes() if remainingTypes.length == 0 { manager.deleteShelf(receiver.address) } } - pub fun estimateDeposit( + access(all) fun estimateDeposit( redeemer: Address, item: @AnyResource, memo: String?, @@ -678,7 +690,7 @@ pub contract LostAndFound { } } - let ftReceiver = LostAndFound.account.getCapability<&FlowToken.Vault{FungibleToken.Receiver}>(/public/flowTokenReceiver) + let ftReceiver = LostAndFound.account.capabilities.get<&FlowToken.Vault>(/public/flowTokenReceiver) let ticket <- create LostAndFound.Ticket(item: <-item, memo: memo, display: display, redeemer: redeemer, flowTokenRepayment: ftReceiver) let tmpEstimate <- FeeEstimator.estimateDeposit(item: <-ticket) let tmpItem <- tmpEstimate.withdraw() as! @LostAndFound.Ticket @@ -690,7 +702,7 @@ pub contract LostAndFound { return <- estimate } - pub fun getRedeemableTypes(_ addr: Address): [Type] { + access(all) fun getRedeemableTypes(_ addr: Address): [Type] { let manager = LostAndFound.borrowShelfManager() let shelf = manager.borrowShelf(redeemer: addr) if shelf == nil { @@ -700,13 +712,13 @@ pub contract LostAndFound { return shelf!.getRedeemableTypes() } - pub fun deposit( + access(all) fun deposit( redeemer: Address, item: @AnyResource, memo: String?, display: MetadataViews.Display?, - storagePayment: &FungibleToken.Vault, - flowTokenRepayment: Capability<&FlowToken.Vault{FungibleToken.Receiver}>? + storagePayment: auth(FungibleToken.Withdraw) &{FungibleToken.Vault}, + flowTokenRepayment: Capability<&FlowToken.Vault>? ) : UInt64 { pre { flowTokenRepayment == nil || flowTokenRepayment!.check(): "flowTokenRepayment is not valid" @@ -717,29 +729,26 @@ pub contract LostAndFound { return shelfManager.deposit(redeemer: redeemer, item: <-item, memo: memo, display: display, storagePayment: storagePayment, flowTokenRepayment: flowTokenRepayment) } - pub fun trySendResource( - resource: @AnyResource, + access(all) fun trySendResource( + item: @AnyResource, cap: Capability, memo: String?, display: MetadataViews.Display?, - storagePayment: &FungibleToken.Vault, - flowTokenRepayment: Capability<&FlowToken.Vault{FungibleToken.Receiver}> + storagePayment: auth(FungibleToken.Withdraw) &{FungibleToken.Vault}, + flowTokenRepayment: Capability<&FlowToken.Vault> ) { if cap.check<&{NonFungibleToken.CollectionPublic}>() { - let nft <- resource as! @NonFungibleToken.NFT + let nft <- item as! @{NonFungibleToken.NFT} cap.borrow<&{NonFungibleToken.CollectionPublic}>()!.deposit(token: <-nft) - } else if cap.check<&{NonFungibleToken.Receiver}>() { - let nft <- resource as! @NonFungibleToken.NFT - cap.borrow<&{NonFungibleToken.Receiver}>()!.deposit(token: <-nft) } else if cap.check<&{FungibleToken.Receiver}>() { - let vault <- resource as! @FungibleToken.Vault + let vault <- item as! @{FungibleToken.Vault} cap.borrow<&{FungibleToken.Receiver}>()!.deposit(from: <-vault) } else { - LostAndFound.deposit(redeemer: cap.address, item: <-resource, memo: memo, display: display, storagePayment: storagePayment, flowTokenRepayment: flowTokenRepayment) + LostAndFound.deposit(redeemer: cap.address, item: <-item, memo: memo, display: display, storagePayment: storagePayment, flowTokenRepayment: flowTokenRepayment) } } - pub fun getAddress(): Address { + access(all) fun getAddress(): Address { return self.account.address } @@ -752,8 +761,10 @@ pub contract LostAndFound { self.DepositorStoragePath = /storage/lostAndFoundDepositor let manager <- create ShelfManager() - self.account.save(<-manager, to: self.LostAndFoundStoragePath) - self.account.link<&LostAndFound.ShelfManager>(self.LostAndFoundPublicPath, target: self.LostAndFoundStoragePath) + self.account.storage.save(<-manager, to: self.LostAndFoundStoragePath) + + let cap = self.account.capabilities.storage.issue<&LostAndFound.ShelfManager>(self.LostAndFoundStoragePath) + self.account.capabilities.publish(cap, at: self.LostAndFoundPublicPath) } } \ No newline at end of file diff --git a/contracts/LostAndFoundHelper.cdc b/contracts/LostAndFoundHelper.cdc index 4148337..7476a0b 100644 --- a/contracts/LostAndFoundHelper.cdc +++ b/contracts/LostAndFoundHelper.cdc @@ -1,22 +1,22 @@ import "LostAndFound" -pub contract LostAndFoundHelper { +access(all) contract LostAndFoundHelper { - pub struct Ticket { + access(all) struct Ticket { // An optional message to attach to this item. - pub let memo: String? + access(all) let memo: String? // The address that it allowed to withdraw the item fromt this ticket - pub let redeemer: Address + access(all) let redeemer: Address //The type of the resource (non-optional) so that bins can represent the true type of an item - pub let type: Type - pub let typeIdentifier: String + access(all) let type: Type + access(all) let typeIdentifier: String // State maintained by LostAndFound - pub let redeemed: Bool - pub let name : String? - pub let description : String? - pub let thumbnail : String? - pub let ticketID : UInt64? + access(all) let redeemed: Bool + access(all) let name : String? + access(all) let description : String? + access(all) let thumbnail : String? + access(all) let ticketID : UInt64? init(_ ticket: &LostAndFound.Ticket, id: UInt64?) { self.memo = ticket.memo @@ -32,7 +32,7 @@ pub contract LostAndFoundHelper { } - pub fun constructResult(_ ticket: &LostAndFound.Ticket?, id:UInt64?) : LostAndFoundHelper.Ticket? { + access(all) fun constructResult(_ ticket: &LostAndFound.Ticket?, id:UInt64?) : LostAndFoundHelper.Ticket? { if ticket != nil { return LostAndFoundHelper.Ticket(ticket!, id: id) } diff --git a/contracts/standard/ExampleNFT.cdc b/contracts/standard/ExampleNFT.cdc index 8665095..45e74a1 100644 --- a/contracts/standard/ExampleNFT.cdc +++ b/contracts/standard/ExampleNFT.cdc @@ -14,31 +14,35 @@ import "MetadataViews" import "ViewResolver" import "FungibleToken" -pub contract ExampleNFT: NonFungibleToken, ViewResolver { +access(all) contract ExampleNFT: ViewResolver { - pub var totalSupply: UInt64 + access(all) var totalSupply: UInt64 - pub event ContractInitialized() - pub event Withdraw(id: UInt64, from: Address?) - pub event Deposit(id: UInt64, to: Address?) - pub event Mint(id: UInt64) + access(all) event ContractInitialized() + access(all) event Withdraw(id: UInt64, from: Address?) + access(all) event Deposit(id: UInt64, to: Address?) + access(all) event Mint(id: UInt64) - pub event CollectionCreated(id: UInt64) - pub event CollectionDestroyed(id: UInt64) + access(all) event CollectionCreated(id: UInt64) + access(all) event CollectionDestroyed(id: UInt64) - pub let CollectionStoragePath: StoragePath - pub let CollectionPublicPath: PublicPath - pub let MinterStoragePath: StoragePath - pub let MinterPublicPath: PublicPath + access(all) let CollectionStoragePath: StoragePath + access(all) let CollectionPublicPath: PublicPath + access(all) let MinterStoragePath: StoragePath + access(all) let MinterPublicPath: PublicPath - pub resource NFT: NonFungibleToken.INFT, MetadataViews.Resolver { - pub let id: UInt64 + access(all) resource NFT: NonFungibleToken.NFT, ViewResolver.Resolver { + access(all) let id: UInt64 - pub let name: String - pub let description: String - pub let thumbnail: String + access(all) let name: String + access(all) let description: String + access(all) let thumbnail: String access(self) var royalties: [MetadataViews.Royalty] + access(all) view fun getID(): UInt64 { + return self.id + } + init( id: UInt64, name: String, @@ -55,11 +59,11 @@ pub contract ExampleNFT: NonFungibleToken, ViewResolver { emit Mint(id: self.id) } - pub fun setRoyalties(_ royalties: [MetadataViews.Royalty]) { + access(Mutate) fun setRoyalties(_ royalties: [MetadataViews.Royalty]) { self.royalties = royalties } - pub fun getViews(): [Type] { + access(all) view fun getViews(): [Type] { return [ Type(), Type(), @@ -72,7 +76,7 @@ pub contract ExampleNFT: NonFungibleToken, ViewResolver { ] } - pub fun resolveView(_ view: Type): AnyStruct? { + access(all) fun resolveView(_ view: Type): AnyStruct? { switch view { case Type(): return MetadataViews.Display( @@ -105,11 +109,9 @@ pub contract ExampleNFT: NonFungibleToken, ViewResolver { return MetadataViews.NFTCollectionData( storagePath: ExampleNFT.CollectionStoragePath, publicPath: ExampleNFT.CollectionPublicPath, - providerPath: /private/exampleNFTCollection, - publicCollection: Type<&ExampleNFT.Collection{ExampleNFT.ExampleNFTCollectionPublic}>(), - publicLinkedType: Type<&ExampleNFT.Collection{ExampleNFT.ExampleNFTCollectionPublic,NonFungibleToken.CollectionPublic,NonFungibleToken.Receiver,MetadataViews.ResolverCollection}>(), - providerLinkedType: Type<&ExampleNFT.Collection{ExampleNFT.ExampleNFTCollectionPublic,NonFungibleToken.CollectionPublic,NonFungibleToken.Provider,MetadataViews.ResolverCollection}>(), - createEmptyCollectionFunction: (fun (): @NonFungibleToken.Collection { + publicCollection: Type<&ExampleNFT.Collection>(), + publicLinkedType: Type<&ExampleNFT.Collection>(), + createEmptyCollectionFunction: (fun (): @{NonFungibleToken.Collection} { return <-ExampleNFT.createEmptyCollection() }) ) @@ -140,13 +142,15 @@ pub contract ExampleNFT: NonFungibleToken, ViewResolver { } return nil } + + access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { + return <- create ExampleNFT.Collection() + } } - pub resource interface ExampleNFTCollectionPublic { - pub fun deposit(token: @NonFungibleToken.NFT) - pub fun getIDs(): [UInt64] - pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT - pub fun borrowExampleNFT(id: UInt64): &ExampleNFT.NFT? { + access(all) resource interface ExampleNFTCollectionPublic: NonFungibleToken.Collection { + access(all) fun deposit(token: @{NonFungibleToken.NFT}) + access(all) fun borrowExampleNFT(id: UInt64): &ExampleNFT.NFT? { post { (result == nil) || (result?.id == id): "Cannot borrow ExampleNFT reference: the ID of the returned reference is incorrect" @@ -154,18 +158,46 @@ pub contract ExampleNFT: NonFungibleToken, ViewResolver { } } - pub resource Collection: ExampleNFTCollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection { + access(all) resource Collection: ExampleNFTCollectionPublic { + access(all) event ResourceDestroyed(id: UInt64 = self.uuid) + // dictionary of NFT conforming tokens // NFT is a resource type with an `UInt64` ID field - pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT} + access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}} init () { self.ownedNFTs <- {} emit CollectionCreated(id: self.uuid) } + access(all) view fun getDefaultStoragePath(): StoragePath? { + return ExampleNFT.CollectionStoragePath + } + + access(all) view fun getDefaultPublicPath(): PublicPath? { + return ExampleNFT.CollectionPublicPath + } + + access(all) view fun getLength(): Int { + return self.ownedNFTs.length + } + + access(all) view fun getSupportedNFTTypes(): {Type: Bool} { + return { + Type<@ExampleNFT.NFT>(): true + } + } + + access(all) view fun isSupportedNFTType(type: Type): Bool { + return type == Type<@ExampleNFT.NFT>() + } + + access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { + return <- ExampleNFT.createEmptyCollection() + } + // withdraw removes an NFT from the collection and moves it to the caller - pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT { + access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} { let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT") emit Withdraw(id: token.id, from: self.owner?.address) @@ -175,7 +207,7 @@ pub contract ExampleNFT: NonFungibleToken, ViewResolver { // deposit takes a NFT and adds it to the collections dictionary // and adds the ID to the id array - pub fun deposit(token: @NonFungibleToken.NFT) { + access(all) fun deposit(token: @{NonFungibleToken.NFT}) { let token <- token as! @ExampleNFT.NFT let id: UInt64 = token.id @@ -189,51 +221,40 @@ pub contract ExampleNFT: NonFungibleToken, ViewResolver { } // getIDs returns an array of the IDs that are in the collection - pub fun getIDs(): [UInt64] { + access(all) view fun getIDs(): [UInt64] { return self.ownedNFTs.keys } // borrowNFT gets a reference to an NFT in the collection // so that the caller can read its metadata and call its methods - pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT { - return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)! + access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? { + return &self.ownedNFTs[id] } - pub fun borrowExampleNFT(id: UInt64): &ExampleNFT.NFT? { + access(all) fun borrowExampleNFT(id: UInt64): &ExampleNFT.NFT? { if self.ownedNFTs[id] != nil { // Create an authorized reference to allow downcasting - let ref = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! + let ref = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)! return ref as! &ExampleNFT.NFT } return nil } - - pub fun borrowViewResolver(id: UInt64): &AnyResource{MetadataViews.Resolver} { - let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)! - let exampleNFT = nft as! &ExampleNFT.NFT - return exampleNFT as &AnyResource{MetadataViews.Resolver} - } - - destroy() { - destroy self.ownedNFTs - emit CollectionDestroyed(id: self.uuid) - } } // public function that anyone can call to create a new empty collection - pub fun createEmptyCollection(): @ExampleNFT.Collection { - return <- (create Collection() as! @ExampleNFT.Collection) + access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { + return <- create Collection() } // Resource that an admin or something similar would own to be // able to mint new NFTs // - pub resource NFTMinter { + access(all) resource NFTMinter { // mintNFT mints a new NFT with a new ID // and deposit it in the recipients collection using their collection reference - pub fun mintNFT( - recipient: &{NonFungibleToken.CollectionPublic}, + access(all) fun mintNFT( + recipient: &{NonFungibleToken.Collection}, name: String, description: String, thumbnail: String, @@ -243,7 +264,7 @@ pub contract ExampleNFT: NonFungibleToken, ViewResolver { self.mintNFTWithId(recipient: recipient, name: name, description: description, thumbnail: thumbnail, royaltyReceipient: royaltyReceipient, id: ExampleNFT.totalSupply) } - pub fun mint( + access(all) fun mint( name: String, description: String, thumbnail: String, @@ -260,15 +281,15 @@ pub contract ExampleNFT: NonFungibleToken, ViewResolver { return <- newNFT } - pub fun mintNFTWithId( - recipient: &{NonFungibleToken.CollectionPublic}, + access(all) fun mintNFTWithId( + recipient: &{NonFungibleToken.Collection}, name: String, description: String, thumbnail: String, royaltyReceipient: Address, id: UInt64 ) { - let royaltyRecipient = getAccount(royaltyReceipient).getCapability<&AnyResource{FungibleToken.Receiver}>(/public/placeholder) + let royaltyRecipient = getAccount(royaltyReceipient).capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver)! let cutInfo = MetadataViews.Royalty(receiver: royaltyRecipient, cut: 0.05, description: "") // create a new NFT var newNFT <- create NFT( @@ -285,8 +306,8 @@ pub contract ExampleNFT: NonFungibleToken, ViewResolver { // mintNFT mints a new NFT with a new ID // and deposit it in the recipients collection using their collection reference - pub fun mintNFTWithRoyaltyCuts( - recipient: &{NonFungibleToken.CollectionPublic}, + access(all) fun mintNFTWithRoyaltyCuts( + recipient: &{NonFungibleToken.Collection}, name: String, description: String, thumbnail: String, @@ -298,7 +319,7 @@ pub contract ExampleNFT: NonFungibleToken, ViewResolver { var index = 0 while index < royaltyReceipients.length { - let royaltyRecipient = getAccount(royaltyReceipients[index]).getCapability<&AnyResource{FungibleToken.Receiver}>(/public/placeholder) + let royaltyRecipient = getAccount(royaltyReceipients[index]).capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver)! let cutInfo = MetadataViews.Royalty(receiver: royaltyRecipient, cut: royaltyCuts[index], description: "") royalties.append(cutInfo) index = index + 1 @@ -318,6 +339,22 @@ pub contract ExampleNFT: NonFungibleToken, ViewResolver { // deposit it in the recipient's account using their reference recipient.deposit(token: <-newNFT) } + + access(all) fun mintAndReturnNFT( + name: String, + description: String, + thumbnail: String + ): @ExampleNFT.NFT { + ExampleNFT.totalSupply = ExampleNFT.totalSupply + 1 + + return <- create ExampleNFT.NFT( + id: ExampleNFT.totalSupply, + name: name, + description: description, + thumbnail: thumbnail, + royalties: [] + ) + } } /// Function that resolves a metadata view for this contract. @@ -325,17 +362,15 @@ pub contract ExampleNFT: NonFungibleToken, ViewResolver { /// @param view: The Type of the desired view. /// @return A structure representing the requested view. /// - pub fun resolveView(_ view: Type): AnyStruct? { - switch view { + access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? { + switch viewType { case Type(): return MetadataViews.NFTCollectionData( storagePath: ExampleNFT.CollectionStoragePath, publicPath: ExampleNFT.CollectionPublicPath, - providerPath: /private/exampleNFTCollection, - publicCollection: Type<&ExampleNFT.Collection{ExampleNFT.ExampleNFTCollectionPublic}>(), - publicLinkedType: Type<&ExampleNFT.Collection{ExampleNFT.ExampleNFTCollectionPublic,NonFungibleToken.CollectionPublic,NonFungibleToken.Receiver,MetadataViews.ResolverCollection}>(), - providerLinkedType: Type<&ExampleNFT.Collection{ExampleNFT.ExampleNFTCollectionPublic,NonFungibleToken.CollectionPublic,NonFungibleToken.Provider,MetadataViews.ResolverCollection}>(), - createEmptyCollectionFunction: (fun (): @NonFungibleToken.Collection { + publicCollection: Type<&ExampleNFT.Collection>(), + publicLinkedType: Type<&ExampleNFT.Collection>(), + createEmptyCollectionFunction: (fun (): @{NonFungibleToken.Collection} { return <-ExampleNFT.createEmptyCollection() }) ) @@ -365,7 +400,7 @@ pub contract ExampleNFT: NonFungibleToken, ViewResolver { /// @return An array of Types defining the implemented views. This value will be used by /// developers to know which parameter to pass to the resolveView() method. /// - pub fun getViews(): [Type] { + access(all) view fun getContractViews(resourceType: Type?): [Type] { return [ Type(), Type() @@ -384,18 +419,17 @@ pub contract ExampleNFT: NonFungibleToken, ViewResolver { // Create a Collection resource and save it to storage let collection <- create Collection() - self.account.save(<-collection, to: self.CollectionStoragePath) + self.account.storage.save(<-collection, to: self.CollectionStoragePath) // create a public capability for the collection - self.account.link<&ExampleNFT.Collection{NonFungibleToken.CollectionPublic, ExampleNFT.ExampleNFTCollectionPublic, MetadataViews.ResolverCollection}>( - self.CollectionPublicPath, - target: self.CollectionStoragePath - ) + let cap = self.account.capabilities.storage.issue<&ExampleNFT.Collection>(self.CollectionStoragePath) + self.account.capabilities.publish(cap, at: self.CollectionPublicPath) // Create a Minter resource and save it to storage let minter <- create NFTMinter() - self.account.save(<-minter, to: self.MinterStoragePath) - self.account.link<&ExampleNFT.NFTMinter>(self.MinterPublicPath, target: self.MinterStoragePath) + self.account.storage.save(<-minter, to: self.MinterStoragePath) + let minterCap = self.account.capabilities.storage.issue<&ExampleNFT.NFTMinter>(self.MinterStoragePath) + self.account.capabilities.publish(minterCap, at: self.MinterPublicPath) emit ContractInitialized() } diff --git a/contracts/standard/ExampleToken.cdc b/contracts/standard/ExampleToken.cdc index d45ec7e..757ed19 100644 --- a/contracts/standard/ExampleToken.cdc +++ b/contracts/standard/ExampleToken.cdc @@ -1,44 +1,46 @@ import "FungibleToken" +import "MetadataViews" +import "FungibleTokenMetadataViews" -pub contract ExampleToken: FungibleToken { +access(all) contract ExampleToken { /// Total supply of ExampleTokens in existence - pub var totalSupply: UFix64 + access(all) var totalSupply: UFix64 /// TokensInitialized /// /// The event that is emitted when the contract is created - pub event TokensInitialized(initialSupply: UFix64) + access(all) event TokensInitialized(initialSupply: UFix64) /// TokensWithdrawn /// /// The event that is emitted when tokens are withdrawn from a Vault - pub event TokensWithdrawn(amount: UFix64, from: Address?) + access(all) event TokensWithdrawn(amount: UFix64, from: Address?) /// TokensDeposited /// /// The event that is emitted when tokens are deposited to a Vault - pub event TokensDeposited(amount: UFix64, to: Address?) + access(all) event TokensDeposited(amount: UFix64, to: Address?) /// TokensMinted /// /// The event that is emitted when new tokens are minted - pub event TokensMinted(amount: UFix64) + access(all) event TokensMinted(amount: UFix64) /// TokensBurned /// /// The event that is emitted when tokens are destroyed - pub event TokensBurned(amount: UFix64) + access(all) event TokensBurned(amount: UFix64) /// MinterCreated /// /// The event that is emitted when a new minter resource is created - pub event MinterCreated(allowedAmount: UFix64) + access(all) event MinterCreated(allowedAmount: UFix64) /// BurnerCreated /// /// The event that is emitted when a new burner resource is created - pub event BurnerCreated() + access(all) event BurnerCreated() /// Vault /// @@ -52,16 +54,36 @@ pub contract ExampleToken: FungibleToken { /// out of thin air. A special Minter resource needs to be defined to mint /// new tokens. /// - pub resource Vault: FungibleToken.Provider, FungibleToken.Receiver, FungibleToken.Balance { + access(all) resource Vault: FungibleToken.Vault { /// The total balance of this vault - pub var balance: UFix64 + access(all) var balance: UFix64 // initialize the balance at resource creation time init(balance: UFix64) { self.balance = balance } + access(all) view fun getBalance(): UFix64 { + return self.balance + } + + access(all) view fun getDefaultStoragePath(): StoragePath? { + return /storage/exampleTokenVault + } + + access(all) view fun getDefaultPublicPath(): PublicPath? { + return /public/exampleTokenPublic + } + + access(all) view fun getDefaultReceiverPath(): PublicPath? { + return /public/exampleTokenPublic + } + + access(all) view fun isAvailableToWithdraw(amount: UFix64): Bool { + return self.balance >= amount + } + /// withdraw /// /// Function that takes an amount as an argument @@ -72,12 +94,22 @@ pub contract ExampleToken: FungibleToken { /// created Vault to the context that called so it can be deposited /// elsewhere. /// - pub fun withdraw(amount: UFix64): @FungibleToken.Vault { + access(FungibleToken.Withdraw) fun withdraw(amount: UFix64): @{FungibleToken.Vault} { self.balance = self.balance - amount emit TokensWithdrawn(amount: amount, from: self.owner?.address) return <-create Vault(balance: amount) } + access(all) view fun getSupportedVaultTypes(): {Type: Bool} { + return { + Type<@ExampleToken.Vault>(): true + } + } + + access(all) view fun isSupportedVaultType(type: Type): Bool { + return type == Type<@ExampleToken.Vault>() + } + /// deposit /// /// Function that takes a Vault object as an argument and adds @@ -87,7 +119,7 @@ pub contract ExampleToken: FungibleToken { /// was a temporary holder of the tokens. The Vault's balance has /// been consumed and therefore can be destroyed. /// - pub fun deposit(from: @FungibleToken.Vault) { + access(all) fun deposit(from: @{FungibleToken.Vault}) { let vault <- from as! @ExampleToken.Vault self.balance = self.balance + vault.balance emit TokensDeposited(amount: vault.balance, to: self.owner?.address) @@ -95,8 +127,16 @@ pub contract ExampleToken: FungibleToken { destroy vault } - destroy() { - ExampleToken.totalSupply = ExampleToken.totalSupply - self.balance + access(all) fun createEmptyVault(): @Vault { + return <- ExampleToken.createEmptyVault() + } + + access(all) view fun getViews(): [Type] { + return ExampleToken.getContractViews(resourceType: nil) + } + + access(all) fun resolveView(_ view: Type): AnyStruct? { + return ExampleToken.resolveContractView(resourceType: nil, viewType: view) } } @@ -107,17 +147,17 @@ pub contract ExampleToken: FungibleToken { /// and store the returned Vault in their storage in order to allow their /// account to be able to receive deposits of this token type. /// - pub fun createEmptyVault(): @Vault { + access(all) fun createEmptyVault(): @Vault { return <-create Vault(balance: 0.0) } - pub resource Administrator { + access(all) resource Administrator { /// createNewMinter /// /// Function that creates and returns a new minter resource /// - pub fun createNewMinter(allowedAmount: UFix64): @Minter { + access(all) fun createNewMinter(allowedAmount: UFix64): @Minter { emit MinterCreated(allowedAmount: allowedAmount) return <-create Minter(allowedAmount: allowedAmount) } @@ -126,7 +166,7 @@ pub contract ExampleToken: FungibleToken { /// /// Function that creates and returns a new burner resource /// - pub fun createNewBurner(): @Burner { + access(all) fun createNewBurner(): @Burner { emit BurnerCreated() return <-create Burner() } @@ -136,17 +176,17 @@ pub contract ExampleToken: FungibleToken { /// /// Resource object that token admin accounts can hold to mint new tokens. /// - pub resource Minter { + access(all) resource Minter { /// The amount of tokens that the minter is allowed to mint - pub var allowedAmount: UFix64 + access(all) var allowedAmount: UFix64 /// mintTokens /// /// Function that mints new tokens, adds them to the total supply, /// and returns them to the calling context. /// - pub fun mintTokens(amount: UFix64): @ExampleToken.Vault { + access(all) fun mintTokens(amount: UFix64): @ExampleToken.Vault { pre { amount > 0.0: "Amount minted must be greater than zero" amount <= self.allowedAmount: "Amount minted must be less than the allowed amount" @@ -166,7 +206,7 @@ pub contract ExampleToken: FungibleToken { /// /// Resource object that token admin accounts can hold to burn tokens. /// - pub resource Burner { + access(all) resource Burner { /// burnTokens /// @@ -175,7 +215,7 @@ pub contract ExampleToken: FungibleToken { /// Note: the burned tokens are automatically subtracted from the /// total supply in the Vault destructor. /// - pub fun burnTokens(from: @FungibleToken.Vault) { + access(all) fun burnTokens(from: @{FungibleToken.Vault}) { let vault <- from as! @ExampleToken.Vault let amount = vault.balance destroy vault @@ -183,32 +223,73 @@ pub contract ExampleToken: FungibleToken { } } + access(all) view fun getContractViews(resourceType: Type?): [Type] { + return [Type(), + Type(), + Type(), + Type()] + } + + access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? { + switch viewType { + case Type(): + return FungibleTokenMetadataViews.FTView( + ftDisplay: self.resolveContractView(resourceType: nil, viewType: Type()) as! FungibleTokenMetadataViews.FTDisplay?, + ftVaultData: self.resolveContractView(resourceType: nil, viewType: Type()) as! FungibleTokenMetadataViews.FTVaultData? + ) + case Type(): + let media = MetadataViews.Media( + file: MetadataViews.HTTPFile( + url: "" + ), + mediaType: "image/svg+xml" + ) + let medias = MetadataViews.Medias([media]) + return FungibleTokenMetadataViews.FTDisplay( + name: "FLOW Network Token", + symbol: "FLOW", + description: "FLOW is the native token for the Flow blockchain. It is required for securing the network, transaction fees, storage fees, staking, FLIP voting and may be used by applications built on the Flow Blockchain", + externalURL: MetadataViews.ExternalURL("https://flow.com"), + logos: medias, + socials: { + "twitter": MetadataViews.ExternalURL("https://twitter.com/flow_blockchain") + } + ) + case Type(): + let vaultRef = ExampleToken.account.storage.borrow(from: /storage/exampleTokenVault) + ?? panic("Could not borrow reference to the contract's Vault!") + return FungibleTokenMetadataViews.FTVaultData( + storagePath: /storage/flowTokenVault, + receiverPath: /public/flowTokenReceiver, + metadataPath: /public/flowTokenBalance, + receiverLinkedType: Type<&{FungibleToken.Receiver, FungibleToken.Vault}>(), + metadataLinkedType: Type<&{FungibleToken.Balance, FungibleToken.Vault}>(), + createEmptyVaultFunction: (fun (): @{FungibleToken.Vault} { + return <-vaultRef.createEmptyVault() + }) + ) + case Type(): + return FungibleTokenMetadataViews.TotalSupply(totalSupply: ExampleToken.totalSupply) + } + return nil + } + init() { self.totalSupply = 1000.0 // Create the Vault with the total supply of tokens and save it in storage // let vault <- create Vault(balance: self.totalSupply) - self.account.save(<-vault, to: /storage/exampleTokenVault) + self.account.storage.save(<-vault, to: /storage/exampleTokenVault) // Create a public capability to the stored Vault that only exposes // the `deposit` method through the `Receiver` interface // - self.account.link<&{FungibleToken.Receiver}>( - /public/exampleTokenReceiver, - target: /storage/exampleTokenVault - ) - - // Create a public capability to the stored Vault that only exposes - // the `balance` field through the `Balance` interface - // - self.account.link<&ExampleToken.Vault{FungibleToken.Balance}>( - /public/exampleTokenBalance, - target: /storage/exampleTokenVault - ) + let publicCap = self.account.capabilities.storage.issue<&ExampleToken.Vault>(/storage/exampleTokenVault) + self.account.capabilities.publish(publicCap, at: /public/exampleTokenPublic) let admin <- create Administrator() - self.account.save(<-admin, to: /storage/exampleTokenAdmin) + self.account.storage.save(<-admin, to: /storage/exampleTokenAdmin) // Emit an event that shows that the contract was initialized // diff --git a/flow.json b/flow.json index be9905c..e33888f 100644 --- a/flow.json +++ b/flow.json @@ -9,7 +9,7 @@ "LostAndFound": { "source": "./contracts/LostAndFound.cdc", "aliases": { - "testing": "0x0000000000000005", + "testing": "0x0000000000000007", "emulator": "0xf8d6e0586b0a20c7", "testnet": "0xbe4635353f55bbd4", "mainnet": "0x473d6a2c37eab5be" @@ -18,31 +18,31 @@ "LostAndFoundHelper": { "source": "./contracts/LostAndFoundHelper.cdc", "aliases": { - "testing": "0x0000000000000005", + "testing": "0x0000000000000007", "emulator": "0xf8d6e0586b0a20c7", "testnet": "0xbe4635353f55bbd4", - "mainnet": "0x473d6a2c37eab5be" + "mainnet": "0x473d6a2c37eab5be" } }, "FeeEstimator": { "source": "./contracts/FeeEstimator.cdc", "aliases": { - "testing": "0x0000000000000005", + "testing": "0x0000000000000007", "emulator": "0xf8d6e0586b0a20c7", "testnet": "0xbe4635353f55bbd4", - "mainnet": "0x473d6a2c37eab5be" + "mainnet": "0x473d6a2c37eab5be" } }, "ExampleNFT": { "source": "./contracts/standard/ExampleNFT.cdc", "aliases": { - "testing": "0x0000000000000006" + "testing": "0x0000000000000008" } }, "ExampleToken": { "source": "./contracts/standard/ExampleToken.cdc", "aliases": { - "testing": "0x0000000000000007" + "testing": "0x0000000000000009" } }, "FungibleToken": { @@ -100,6 +100,14 @@ "testnet": "0x8c5303eaa26202d6", "mainnet": "0xf919ee77447b7497" } + }, + "Burner": { + "source": "./node_modules/@flowtyio/flow-contracts/contracts/Burner.cdc", + "aliases": { + "emulator": "0xf8d6e0586b0a20c7", + "testnet": "0x631e88ae7f1d7c20", + "mainnet": "0x1d7e57aa55817448" + } } }, "networks": { @@ -153,7 +161,8 @@ "FeeEstimator", "LostAndFoundHelper", "ViewResolver", - "FlowStorageFees" + "FlowStorageFees", + "Burner" ], "emulator-ft": [ "FungibleToken", diff --git a/package-lock.json b/package-lock.json index b5db30a..fbbd407 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,13 +9,13 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@flowtyio/flow-contracts": "^0.0.18" + "@flowtyio/flow-contracts": "^0.1.0-beta.21" } }, "node_modules/@flowtyio/flow-contracts": { - "version": "0.0.18", - "resolved": "https://registry.npmjs.org/@flowtyio/flow-contracts/-/flow-contracts-0.0.18.tgz", - "integrity": "sha512-uQVbUOZegx8sdk/T+ypYBjdVmcw7AGHANzrg+PdQCtYXBGJ3iEh9+vxwf2kNk2j6hw8djmWdZy36iUMZC3pwmg==", + "version": "0.1.0-beta.21", + "resolved": "https://registry.npmjs.org/@flowtyio/flow-contracts/-/flow-contracts-0.1.0-beta.21.tgz", + "integrity": "sha512-VHmwlxvjoJw/mNnmg2/BzndngkiIF8LsFNqR2CJh1Zoo5OVII+FqUoZkyOFmZ9ZiB7g9bWH9CCMelNxFhGnLWw==", "dependencies": { "commander": "^11.0.0" }, @@ -34,9 +34,9 @@ }, "dependencies": { "@flowtyio/flow-contracts": { - "version": "0.0.18", - "resolved": "https://registry.npmjs.org/@flowtyio/flow-contracts/-/flow-contracts-0.0.18.tgz", - "integrity": "sha512-uQVbUOZegx8sdk/T+ypYBjdVmcw7AGHANzrg+PdQCtYXBGJ3iEh9+vxwf2kNk2j6hw8djmWdZy36iUMZC3pwmg==", + "version": "0.1.0-beta.21", + "resolved": "https://registry.npmjs.org/@flowtyio/flow-contracts/-/flow-contracts-0.1.0-beta.21.tgz", + "integrity": "sha512-VHmwlxvjoJw/mNnmg2/BzndngkiIF8LsFNqR2CJh1Zoo5OVII+FqUoZkyOFmZ9ZiB7g9bWH9CCMelNxFhGnLWw==", "requires": { "commander": "^11.0.0" } diff --git a/package.json b/package.json index 5bdf3ea..88af175 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,6 @@ }, "homepage": "https://github.com/Flowtyio/lost-and-found#readme", "dependencies": { - "@flowtyio/flow-contracts": "^0.0.18" + "@flowtyio/flow-contracts": "^0.1.0-beta.21" } } diff --git a/run-tests.sh b/run-tests.sh index 1170378..e24de9a 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -2,4 +2,4 @@ set -e -flow test --cover --covercode="contracts" --coverprofile="coverage.lcov" tests/*_tests.cdc \ No newline at end of file +flow-c1 test --cover --covercode="contracts" --coverprofile="coverage.lcov" tests/*_tests.cdc \ No newline at end of file diff --git a/scripts/example-nft/borrow_all_tickets.cdc b/scripts/example-nft/borrow_all_tickets.cdc index 6ec4b6c..9538402 100644 --- a/scripts/example-nft/borrow_all_tickets.cdc +++ b/scripts/example-nft/borrow_all_tickets.cdc @@ -2,7 +2,7 @@ import "LostAndFound" import "LostAndFoundHelper" import "ExampleNFT" -pub fun main(addr: Address): [LostAndFoundHelper.Ticket] { +access(all) fun main(addr: Address): [LostAndFoundHelper.Ticket] { let tickets: [LostAndFoundHelper.Ticket] = [] for ticket in LostAndFound.borrowAllTicketsByType(addr: addr, type: Type<@ExampleNFT.NFT>()) { tickets.append(LostAndFoundHelper.constructResult(ticket, id: ticket.getNonFungibleTokenID())!) diff --git a/scripts/example-token/borrow_all_tickets.cdc b/scripts/example-token/borrow_all_tickets.cdc index 6c5e7ce..5a4ec05 100644 --- a/scripts/example-token/borrow_all_tickets.cdc +++ b/scripts/example-token/borrow_all_tickets.cdc @@ -2,7 +2,7 @@ import "LostAndFound" import "LostAndFoundHelper" import "ExampleToken" -pub fun main(addr: Address): [LostAndFoundHelper.Ticket] { +access(all) fun main(addr: Address): [LostAndFoundHelper.Ticket] { let tickets: [LostAndFoundHelper.Ticket] = [] for ticket in LostAndFound.borrowAllTicketsByType(addr: addr, type: Type<@ExampleToken.Vault>()) { tickets.append(LostAndFoundHelper.constructResult(ticket, id: ticket.getNonFungibleTokenID())!) diff --git a/scripts/import_contracts.cdc b/scripts/import_contracts.cdc index 3c5af3a..8d5194c 100644 --- a/scripts/import_contracts.cdc +++ b/scripts/import_contracts.cdc @@ -1,6 +1,6 @@ import "LostAndFound" -pub fun main(): Bool { +access(all) fun main(): Bool { return true } \ No newline at end of file diff --git a/scripts/lost-and-found/borrow_all_tickets.cdc b/scripts/lost-and-found/borrow_all_tickets.cdc index 66dc337..0403198 100644 --- a/scripts/lost-and-found/borrow_all_tickets.cdc +++ b/scripts/lost-and-found/borrow_all_tickets.cdc @@ -1,7 +1,7 @@ import "LostAndFound" import "LostAndFoundHelper" -pub fun main(addr: Address): [LostAndFoundHelper.Ticket] { +access(all) fun main(addr: Address): [LostAndFoundHelper.Ticket] { let tickets: [LostAndFoundHelper.Ticket] = [] for ticket in LostAndFound.borrowAllTickets(addr: addr) { tickets.append(LostAndFoundHelper.constructResult(ticket, id: ticket.getNonFungibleTokenID())!) diff --git a/scripts/lost-and-found/check_ticket_item.cdc b/scripts/lost-and-found/check_ticket_item.cdc index 5677712..dd1bc86 100644 --- a/scripts/lost-and-found/check_ticket_item.cdc +++ b/scripts/lost-and-found/check_ticket_item.cdc @@ -1,6 +1,6 @@ import "LostAndFound" -pub fun main(addr: Address, ticketID: UInt64, ticketTypeIdentifier: String): Bool { +access(all) fun main(addr: Address, ticketID: UInt64, ticketTypeIdentifier: String): Bool { let composite = CompositeType(ticketTypeIdentifier)! let manager = LostAndFound.borrowShelfManager() diff --git a/scripts/lost-and-found/estimate_deposit_nft.cdc b/scripts/lost-and-found/estimate_deposit_nft.cdc index 39b98de..ea4513c 100644 --- a/scripts/lost-and-found/estimate_deposit_nft.cdc +++ b/scripts/lost-and-found/estimate_deposit_nft.cdc @@ -1,15 +1,15 @@ import "LostAndFound" import "NonFungibleToken" -pub fun main(addr: Address, nftID: UInt64, nftStoragePath: StoragePath): UFix64 { - let acct = getAuthAccount(addr) - let c = acct.borrow<&{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic}>(from: nftStoragePath) +access(all) fun main(addr: Address, nftID: UInt64, nftStoragePath: StoragePath): UFix64 { + let acct = getAuthAccount(addr) + let c = acct.storage.borrow(from: nftStoragePath) ?? panic("collection not found") let nft <- c.withdraw(withdrawID: nftID) let estimate <- LostAndFound.estimateDeposit(redeemer: addr, item: <-nft, memo: nil, display: nil) let item <- estimate.withdraw() - c.deposit(token: <- (item as! @NonFungibleToken.NFT)) + c.deposit(token: <- (item as! @{NonFungibleToken.NFT})) let fee = estimate.storageFee destroy estimate diff --git a/scripts/lost-and-found/get_address.cdc b/scripts/lost-and-found/get_address.cdc index fb6775d..f2d8646 100644 --- a/scripts/lost-and-found/get_address.cdc +++ b/scripts/lost-and-found/get_address.cdc @@ -1,5 +1,5 @@ import "LostAndFound" -pub fun main(): Address { +access(all) fun main(): Address { return LostAndFound.getAddress() } \ No newline at end of file diff --git a/scripts/lost-and-found/get_redeemable_types.cdc b/scripts/lost-and-found/get_redeemable_types.cdc index 58b7170..ce77322 100644 --- a/scripts/lost-and-found/get_redeemable_types.cdc +++ b/scripts/lost-and-found/get_redeemable_types.cdc @@ -1,5 +1,5 @@ import "LostAndFound" -pub fun main(addr: Address): [Type] { +access(all) fun main(addr: Address): [Type] { return LostAndFound.getRedeemableTypes(addr) } \ No newline at end of file diff --git a/scripts/lost-and-found/get_shelf_owner.cdc b/scripts/lost-and-found/get_shelf_owner.cdc index 73de98f..7dccd7e 100644 --- a/scripts/lost-and-found/get_shelf_owner.cdc +++ b/scripts/lost-and-found/get_shelf_owner.cdc @@ -1,6 +1,6 @@ import "LostAndFound" -pub fun main(addr: Address): Address { +access(all) fun main(addr: Address): Address { let m = LostAndFound.borrowShelfManager() let shelf = m.borrowShelf(redeemer: addr)! return shelf.getOwner() diff --git a/scripts/lost-and-found/get_ticket_ft_balance.cdc b/scripts/lost-and-found/get_ticket_ft_balance.cdc index 1069b30..f937d8f 100644 --- a/scripts/lost-and-found/get_ticket_ft_balance.cdc +++ b/scripts/lost-and-found/get_ticket_ft_balance.cdc @@ -1,6 +1,6 @@ import "LostAndFound" -pub fun main(addr: Address, ticketID: UInt64, ticketTypeIdentifier: String): UFix64? { +access(all) fun main(addr: Address, ticketID: UInt64, ticketTypeIdentifier: String): UFix64? { let composite = CompositeType(ticketTypeIdentifier)! let manager = LostAndFound.borrowShelfManager() diff --git a/scripts/lost-and-found/shelf_has_type.cdc b/scripts/lost-and-found/shelf_has_type.cdc index 2523883..3c98c46 100644 --- a/scripts/lost-and-found/shelf_has_type.cdc +++ b/scripts/lost-and-found/shelf_has_type.cdc @@ -1,6 +1,6 @@ import "LostAndFound" -pub fun main(addr: Address, identifier: String): Bool { +access(all) fun main(addr: Address, identifier: String): Bool { let c = CompositeType(identifier)! let m = LostAndFound.borrowShelfManager() let shelf = m.borrowShelf(redeemer: addr) ?? panic("shelf not found for address") diff --git a/tests/LostAndFound_tests.cdc b/tests/LostAndFound_tests.cdc index 68d481e..7fa7c7d 100644 --- a/tests/LostAndFound_tests.cdc +++ b/tests/LostAndFound_tests.cdc @@ -6,7 +6,7 @@ import "LostAndFoundHelper" import "ExampleNFT" import "ExampleToken" -pub fun setup() { +access(all) fun setup() { deployAll() mintFlow(exampleNftAccount, 10.0) @@ -19,11 +19,11 @@ pub fun setup() { txExecutor("depositor/add_flow_tokens.cdc", [exampleTokenAccount], [lowBalanceThreshold]) } -pub fun testImport() { +access(all) fun testImport() { scriptExecutor("import_contracts.cdc", []) } -pub fun testEstimateDeposit() { +access(all) fun testEstimateDeposit() { let acct = getNewAccount() setupExampleNft(acct: acct) @@ -33,13 +33,13 @@ pub fun testEstimateDeposit() { Test.assert(estimate >= 0.00002, message: "fee is lower than expected") } -pub fun testDepositNft() { +access(all) fun testDepositNft() { let acct = getNewAccount() mintAndSendNft(acct) - let event = Test.eventsOfType(Type()).removeLast() as! LostAndFound.TicketDeposited - Test.assertEqual(event.redeemer, acct.address) - Test.assertEqual(exampleNftIdentifier(), event.type.identifier) + let e = Test.eventsOfType(Type()).removeLast() as! LostAndFound.TicketDeposited + Test.assertEqual(e.redeemer, acct.address) + Test.assertEqual(exampleNftIdentifier(), e.type.identifier) // estimate depositing another to see that the fee is reduced (we have initialized the shelf and bin for this user and resource type pairing) setupExampleNft(acct: acct) @@ -48,7 +48,7 @@ pub fun testDepositNft() { Test.assert(estimate == 0.0, message: "fee is higher than expected") } -pub fun testGetRedeemableTypes() { +access(all) fun testGetRedeemableTypes() { let acct = getNewAccount() mintAndSendNft(acct) @@ -61,78 +61,78 @@ pub fun testGetRedeemableTypes() { Test.assert(identifiers.contains(exampleNftIdentifier()), message: "example nft type not found") } -pub fun testTrySendNftResource_ValidCapability() { +access(all) fun testTrySendNftResource_ValidCapability() { let acct = getNewAccount() setupExampleNft(acct: acct) - trySendNft(acct) + trySendNft(acct, revoke: false) - let event = Test.eventsOfType(Type()).removeLast() as! ExampleNFT.Deposit - Test.assertEqual(acct.address, event.to!) + let e = Test.eventsOfType(Type()).removeLast() as! ExampleNFT.Deposit + Test.assertEqual(acct.address, e.to!) } -pub fun testTrySendNftResource_InvalidCapability() { +access(all) fun testTrySendNftResource_InvalidCapability() { let acct = getNewAccount() - trySendNft(acct) + trySendNft(acct, revoke: true) - let event = Test.eventsOfType(Type()).removeLast() as! LostAndFound.TicketDeposited - Test.assertEqual(event.redeemer, acct.address) - Test.assertEqual(exampleNftIdentifier(), event.type.identifier) + let e = Test.eventsOfType(Type()).removeLast() as! LostAndFound.TicketDeposited + Test.assertEqual(e.redeemer, acct.address) + Test.assertEqual(exampleNftIdentifier(), e.type.identifier) } -pub fun testTrySendFtResource_ValidCapability() { +access(all) fun testTrySendFtResource_ValidCapability() { let acct = getNewAccount() setupExampleToken(acct: acct) - trySendFt(acct, 1.0) - let event = Test.eventsOfType(Type()).removeLast() as! ExampleToken.TokensDeposited - Test.assertEqual(acct.address, event.to!) + trySendFt(acct, 1.0, revoke: false) + let e = Test.eventsOfType(Type()).removeLast() as! ExampleToken.TokensDeposited + Test.assertEqual(acct.address, e.to!) } -pub fun testTrySendFtResource_InvalidCapability() { +access(all) fun testTrySendFtResource_InvalidCapability() { let acct = getNewAccount() - trySendFt(acct, 1.0) - let event = Test.eventsOfType(Type()).removeLast() as! LostAndFound.TicketDeposited - Test.assertEqual(event.redeemer, acct.address) - Test.assertEqual(exampleTokenIdentifier(), event.type.identifier) + trySendFt(acct, 1.0, revoke: true) + let e = Test.eventsOfType(Type()).removeLast() as! LostAndFound.TicketDeposited + Test.assertEqual(e.redeemer, acct.address) + Test.assertEqual(exampleTokenIdentifier(), e.type.identifier) } -pub fun testRedeemAllTickets_ExampleNft() { +access(all) fun testRedeemAllTickets_ExampleNft() { let acct = getNewAccount() - let id = trySendNft(acct) + let id = trySendNft(acct, revoke: true) setupExampleNft(acct: acct) txExecutor("example-nft/redeem_example_nft_all.cdc", [acct], []) - let event = Test.eventsOfType(Type()).removeLast() as! ExampleNFT.Deposit - Test.assertEqual(acct.address, event.to!) - Test.assertEqual(id, event.id) + let e = Test.eventsOfType(Type()).removeLast() as! ExampleNFT.Deposit + Test.assertEqual(acct.address, e.to!) + Test.assertEqual(id, e.id) } -pub fun testRedeemAllTickets_ExampleToken() { +access(all) fun testRedeemAllTickets_ExampleToken() { let acct = getNewAccount() let amount = 5.0 - trySendFt(acct, amount) + trySendFt(acct, amount, revoke: true) setupExampleToken(acct: acct) txExecutor("example-token/redeem_example_token_all.cdc", [acct], []) - let event = Test.eventsOfType(Type()).removeLast() as! ExampleToken.TokensDeposited - Test.assertEqual(acct.address, event.to!) - Test.assertEqual(amount, event.amount) + let e = Test.eventsOfType(Type()).removeLast() as! ExampleToken.TokensDeposited + Test.assertEqual(acct.address, e.to!) + Test.assertEqual(amount, e.amount) } -pub fun testGetAddress() { +access(all) fun testGetAddress() { let addr = scriptExecutor("lost-and-found/get_address.cdc", [])! as! Address Test.assertEqual(lostAndFoundAccount.address, addr) } -pub fun testBorrowAllTickets() { +access(all) fun testBorrowAllTickets() { let acct = getNewAccount() let amount = 5.0 - trySendFt(acct, amount) - let id = trySendNft(acct) + trySendFt(acct, amount, revoke: true) + let id = trySendNft(acct, revoke: true) let tickets = scriptExecutor("lost-and-found/borrow_all_tickets.cdc", [acct.address])! as! [LostAndFoundHelper.Ticket] Test.assertEqual(2, tickets.length) @@ -156,54 +156,54 @@ pub fun testBorrowAllTickets() { Test.assertEqual(true, foundFt) } -pub fun testBorrowTicketsByType_Nft() { +access(all) fun testBorrowTicketsByType_Nft() { let acct = getNewAccount() - let id = trySendNft(acct) + let id = trySendNft(acct, revoke: true) let tickets = scriptExecutor("example-nft/borrow_all_tickets.cdc", [acct.address])! as! [LostAndFoundHelper.Ticket] Test.assertEqual(1, tickets.length) Test.assertEqual(id, tickets[0].ticketID!) } -pub fun testBorrowTicketsByType_Ft() { +access(all) fun testBorrowTicketsByType_Ft() { let acct = getNewAccount() let amount = 5.0 - trySendFt(acct, amount) + trySendFt(acct, amount, revoke: true) let tickets = scriptExecutor("example-token/borrow_all_tickets.cdc", [acct.address])! as! [LostAndFoundHelper.Ticket] Test.assertEqual(1, tickets.length) } -pub fun testCheckTicketItem() { +access(all) fun testCheckTicketItem() { let acct = getNewAccount() - trySendNft(acct) - let event = Test.eventsOfType(Type()).removeLast() as! LostAndFound.TicketDeposited + trySendNft(acct, revoke: true) + let e = Test.eventsOfType(Type()).removeLast() as! LostAndFound.TicketDeposited - let res = scriptExecutor("lost-and-found/check_ticket_item.cdc", [acct.address, event.ticketID, exampleNftIdentifier()])! as! Bool + let res = scriptExecutor("lost-and-found/check_ticket_item.cdc", [acct.address, e.ticketID, exampleNftIdentifier()])! as! Bool Test.assertEqual(true, res) } -pub fun testGetTicketFungibleTokenBalance() { +access(all) fun testGetTicketFungibleTokenBalance() { let acct = getNewAccount() let amount = 5.0 - trySendFt(acct, amount) - let event = Test.eventsOfType(Type()).removeLast() as! LostAndFound.TicketDeposited + trySendFt(acct, amount, revoke: true) + let e = Test.eventsOfType(Type()).removeLast() as! LostAndFound.TicketDeposited - let balance = scriptExecutor("lost-and-found/get_ticket_ft_balance.cdc", [acct.address, event.ticketID, exampleTokenIdentifier()])! as! UFix64 + let balance = scriptExecutor("lost-and-found/get_ticket_ft_balance.cdc", [acct.address, e.ticketID, exampleTokenIdentifier()])! as! UFix64 Test.assertEqual(amount, balance) } -pub fun testGetShelfOwner() { +access(all) fun testGetShelfOwner() { let acct = getNewAccount() - trySendNft(acct) + trySendNft(acct, revoke: true) let owner = scriptExecutor("lost-and-found/get_shelf_owner.cdc", [acct.address])! as! Address Test.assertEqual(lostAndFoundAccount.address, owner) } -pub fun testShelfHasType() { +access(all) fun testShelfHasType() { let acct = getNewAccount() - trySendNft(acct) + trySendNft(acct, revoke: true) let hasExampleNFT = scriptExecutor("lost-and-found/shelf_has_type.cdc", [acct.address, exampleNftIdentifier()])! as! Bool Test.assertEqual(true, hasExampleNFT) @@ -211,106 +211,106 @@ pub fun testShelfHasType() { Test.assertEqual(false, hasExampleToken) } -pub fun testDepositor_DepositNft() { +access(all) fun testDepositor_DepositNft() { let acct = getNewAccount() mintAndSendNftWithDepositor(acct) - let event = Test.eventsOfType(Type()).removeLast() as! LostAndFound.TicketDeposited - Test.assertEqual(event.redeemer, acct.address) - Test.assertEqual(exampleNftIdentifier(), event.type.identifier) + let e = Test.eventsOfType(Type()).removeLast() as! LostAndFound.TicketDeposited + Test.assertEqual(e.redeemer, acct.address) + Test.assertEqual(exampleNftIdentifier(), e.type.identifier) } -pub fun testDepositor_DepositFt() { +access(all) fun testDepositor_DepositFt() { let acct = getNewAccount() let amount = 5.0 mintAndSendExampleTokensWithDepositor(acct, amount) - let event = Test.eventsOfType(Type()).removeLast() as! LostAndFound.TicketDeposited - Test.assertEqual(event.redeemer, acct.address) - Test.assertEqual(exampleTokenIdentifier(), event.type.identifier) + let e = Test.eventsOfType(Type()).removeLast() as! LostAndFound.TicketDeposited + Test.assertEqual(e.redeemer, acct.address) + Test.assertEqual(exampleTokenIdentifier(), e.type.identifier) } -pub fun testDepositor_trySendNft_ValidCapability() { +access(all) fun testDepositor_trySendNft_ValidCapability() { let acct = getNewAccount() setupExampleNft(acct: acct) - let nftID = trySendNftWithDepositor(acct) + let nftID = trySendNftWithDepositor(acct, revoke: false) - let event = Test.eventsOfType(Type()).removeLast() as! ExampleNFT.Deposit - Test.assertEqual(acct.address, event.to!) - Test.assertEqual(nftID, event.id) + let e = Test.eventsOfType(Type()).removeLast() as! ExampleNFT.Deposit + Test.assertEqual(acct.address, e.to!) + Test.assertEqual(nftID, e.id) } -pub fun testDepositor_trySendNft_InvalidCapability() { +access(all) fun testDepositor_trySendNft_InvalidCapability() { let acct = getNewAccount() - let nftID = trySendNftWithDepositor(acct) + let nftID = trySendNftWithDepositor(acct, revoke: true) - let event = Test.eventsOfType(Type()).removeLast() as! LostAndFound.TicketDeposited - Test.assertEqual(acct.address, event.redeemer) - Test.assertEqual(exampleNftIdentifier(), event.type.identifier) + let e = Test.eventsOfType(Type()).removeLast() as! LostAndFound.TicketDeposited + Test.assertEqual(acct.address, e.redeemer) + Test.assertEqual(exampleNftIdentifier(), e.type.identifier) } -pub fun testDepositor_trySendFt_ValidCapability() { +access(all) fun testDepositor_trySendFt_ValidCapability() { let acct = getNewAccount() setupExampleToken(acct: acct) let amount = 5.0 - trySendFtWithDepositor(acct, amount) + trySendFtWithDepositor(acct, amount, revoke: false) - let event = Test.eventsOfType(Type()).removeLast() as! ExampleToken.TokensDeposited - Test.assertEqual(acct.address, event.to!) - Test.assertEqual(amount, event.amount) + let e = Test.eventsOfType(Type()).removeLast() as! ExampleToken.TokensDeposited + Test.assertEqual(acct.address, e.to!) + Test.assertEqual(amount, e.amount) } -pub fun testDepositor_trySendFt_InvalidCapability() { +access(all) fun testDepositor_trySendFt_InvalidCapability() { let acct = getNewAccount() let amount = 5.0 - trySendFtWithDepositor(acct, amount) + trySendFtWithDepositor(acct, amount, revoke: true) - let event = Test.eventsOfType(Type()).removeLast() as! LostAndFound.TicketDeposited - Test.assertEqual(acct.address, event.redeemer) - Test.assertEqual(exampleTokenIdentifier(), event.type.identifier) + let e = Test.eventsOfType(Type()).removeLast() as! LostAndFound.TicketDeposited + Test.assertEqual(acct.address, e.redeemer) + Test.assertEqual(exampleTokenIdentifier(), e.type.identifier) } -pub fun mintAndSendNft(_ acct: Test.Account): UInt64 { - txExecutor("example-nft/mint_and_deposit_example_nft.cdc", [exampleNftAccount], [acct.address]) - let event = Test.eventsOfType(Type()).removeLast() as! ExampleNFT.Mint +access(all) fun mintAndSendNft(_ acct: Test.TestAccount): UInt64 { + txExecutor("example-nft/mint_and_deposit_example_nft.cdc", [exampleNftAccount, acct], [acct.address]) + let e = Test.eventsOfType(Type()).removeLast() as! ExampleNFT.Mint - return event.id + return e.id } -pub fun trySendNft(_ acct: Test.Account): UInt64 { - txExecutor("example-nft/try_send_example_nft.cdc", [exampleNftAccount], [acct.address]) - let event = Test.eventsOfType(Type()).removeLast() as! ExampleNFT.Mint +access(all) fun trySendNft(_ acct: Test.TestAccount, revoke: Bool): UInt64 { + txExecutor("example-nft/try_send_example_nft.cdc", [exampleNftAccount, acct], [acct.address, revoke]) + let e = Test.eventsOfType(Type()).removeLast() as! ExampleNFT.Mint - return event.id + return e.id } -pub fun trySendFt(_ acct: Test.Account, _ amount: UFix64) { - txExecutor("example-token/try_send_example_token.cdc", [exampleTokenAccount], [acct.address, amount]) +access(all) fun trySendFt(_ acct: Test.TestAccount, _ amount: UFix64, revoke: Bool) { + txExecutor("example-token/try_send_example_token.cdc", [exampleTokenAccount, acct], [acct.address, amount, revoke]) } -pub fun mintAndSendNftWithDepositor(_ to: Test.Account): UInt64 { - txExecutor("example-nft/mint_and_deposit_with_depositor.cdc", [exampleNftAccount], [to.address]) - let event = Test.eventsOfType(Type()).removeLast() as! ExampleNFT.Mint +access(all) fun mintAndSendNftWithDepositor(_ to: Test.TestAccount): UInt64 { +txExecutor("example-nft/mint_and_deposit_with_depositor.cdc", [exampleNftAccount], [to.address]) + let e = Test.eventsOfType(Type()).removeLast() as! ExampleNFT.Mint - return event.id + return e.id } -pub fun mintAndSendExampleTokensWithDepositor(_ to: Test.Account, _ amount: UFix64) { +access(all) fun mintAndSendExampleTokensWithDepositor(_ to: Test.TestAccount, _ amount: UFix64) { txExecutor("example-token/deposit_example_token_with_depositor.cdc", [exampleTokenAccount], [to.address, amount]) } -pub fun trySendNftWithDepositor(_ to: Test.Account): UInt64 { - txExecutor("example-nft/try_send_example_nft_with_depositor.cdc", [exampleNftAccount], [to.address]) - let event = Test.eventsOfType(Type()).removeLast() as! ExampleNFT.Mint +access(all) fun trySendNftWithDepositor(_ to: Test.TestAccount, revoke: Bool): UInt64 { + txExecutor("example-nft/try_send_example_nft_with_depositor.cdc", [exampleNftAccount, to], [to.address, revoke]) + let e = Test.eventsOfType(Type()).removeLast() as! ExampleNFT.Mint - return event.id + return e.id } -pub fun trySendFtWithDepositor(_ to: Test.Account, _ amount: UFix64) { - txExecutor("example-token/try_send_example_token_depositor.cdc", [exampleTokenAccount], [to.address, amount]) +access(all) fun trySendFtWithDepositor(_ to: Test.TestAccount, _ amount: UFix64, revoke: Bool) { + txExecutor("example-token/try_send_example_token_depositor.cdc", [exampleTokenAccount, to], [to.address, amount, revoke]) } \ No newline at end of file diff --git a/tests/test_helpers.cdc b/tests/test_helpers.cdc index 3e421e8..6c0fb5a 100644 --- a/tests/test_helpers.cdc +++ b/tests/test_helpers.cdc @@ -3,30 +3,24 @@ import Test import "ExampleNFT" import "ExampleToken" -pub let lowBalanceThreshold = 1.0 +access(all) let lowBalanceThreshold = 1.0 // the cadence testing framework allocates 4 addresses for system acounts, // and 10 pre-created accounts for us to use for deployments: -pub let Account0x1 = Address(0x0000000000000001) -pub let Account0x2 = Address(0x0000000000000002) -pub let Account0x3 = Address(0x0000000000000003) -pub let Account0x4 = Address(0x0000000000000004) -pub let Account0x5 = Address(0x0000000000000005) -pub let Account0x6 = Address(0x0000000000000006) -pub let Account0x7 = Address(0x0000000000000007) -pub let Account0x8 = Address(0x0000000000000008) -pub let Account0x9 = Address(0x0000000000000009) -pub let Account0xa = Address(0x000000000000000a) -pub let Account0xb = Address(0x000000000000000b) -pub let Account0xc = Address(0x000000000000000c) -pub let Account0xd = Address(0x000000000000000d) -pub let Account0xe = Address(0x000000000000000e) - -pub let lostAndFoundAccount = Test.getAccount(Account0x5) -pub let exampleNftAccount = Test.getAccount(Account0x6) -pub let exampleTokenAccount = Test.getAccount(Account0x7) - -pub fun scriptExecutor(_ scriptName: String, _ arguments: [AnyStruct]): AnyStruct? { +access(all) let Account0x7 = Test.getAccount(0x0000000000000007) +access(all) let Account0x8 = Test.getAccount(0x0000000000000008) +access(all) let Account0x9 = Test.getAccount(0x0000000000000009) +access(all) let Account0xa = Test.getAccount(0x000000000000000a) +access(all) let Account0xb = Test.getAccount(0x000000000000000b) +access(all) let Account0xc = Test.getAccount(0x000000000000000c) +access(all) let Account0xd = Test.getAccount(0x000000000000000d) +access(all) let Account0xe = Test.getAccount(0x000000000000000e) + +access(all) let lostAndFoundAccount = Account0x7 +access(all) let exampleNftAccount = Account0x8 +access(all) let exampleTokenAccount = Account0x9 + +access(all) fun scriptExecutor(_ scriptName: String, _ arguments: [AnyStruct]): AnyStruct? { let scriptCode = loadCode(scriptName, "scripts") let scriptResult = Test.executeScript(scriptCode, arguments) @@ -37,7 +31,7 @@ pub fun scriptExecutor(_ scriptName: String, _ arguments: [AnyStruct]): AnyStruc return scriptResult.returnValue } -pub fun txExecutor(_ txName: String, _ signers: [Test.Account], _ arguments: [AnyStruct]): Test.TransactionResult { +access(all) fun txExecutor(_ txName: String, _ signers: [Test.TestAccount], _ arguments: [AnyStruct]): Test.TransactionResult { let txCode = loadCode(txName, "transactions") let authorizers: [Address] = [] @@ -60,11 +54,11 @@ pub fun txExecutor(_ txName: String, _ signers: [Test.Account], _ arguments: [An return txResult } -pub fun loadCode(_ fileName: String, _ baseDirectory: String): String { +access(all) fun loadCode(_ fileName: String, _ baseDirectory: String): String { return Test.readFile("../".concat(baseDirectory).concat("/").concat(fileName)) } -pub fun deployAll() { +access(all) fun deployAll() { deploy("ExampleNFT", "../contracts/standard/ExampleNFT.cdc", []) deploy("ExampleToken", "../contracts/standard/ExampleToken.cdc", []) deploy("FeeEstimator", "../contracts/FeeEstimator.cdc", []) @@ -72,72 +66,72 @@ pub fun deployAll() { deploy("LostAndFoundHelper", "../contracts/LostAndFoundHelper.cdc", []) } -pub fun deploy(_ name: String, _ path: String, _ arguments: [AnyStruct]) { +access(all) fun deploy(_ name: String, _ path: String, _ arguments: [AnyStruct]) { let err = Test.deployContract(name: name, path: path, arguments: arguments) Test.expect(err, Test.beNil()) } // Example NFT constants -pub let exampleNftStoragePath = /storage/exampleNFTCollection -pub let exampleNftPublicPath = /public/exampleNFTCollection -pub let exampleNftProviderPath = /private/exampleNFTCollection +access(all) let exampleNftStoragePath = /storage/exampleNFTCollection +access(all) let exampleNftPublicPath = /public/exampleNFTCollection +access(all) let exampleNftProviderPath = /private/exampleNFTCollection // Example Token constants -pub let exampleTokenStoragePath = /storage/exampleTokenVault -pub let exampleTokenReceiverPath = /public/exampleTokenReceiver -pub let exampleTokenProviderPath = /private/exampleTokenProvider -pub let exampleTokenBalancePath = /public/exampleTokenBalance +access(all) let exampleTokenStoragePath = /storage/exampleTokenVault +access(all) let exampleTokenReceiverPath = /public/exampleTokenReceiver +access(all) let exampleTokenProviderPath = /private/exampleTokenProvider +access(all) let exampleTokenBalancePath = /public/exampleTokenBalance -pub fun exampleNftIdentifier(): String { +access(all) fun exampleNftIdentifier(): String { return Type<@ExampleNFT.NFT>().identifier } -pub fun exampleTokenIdentifier(): String { +access(all) fun exampleTokenIdentifier(): String { return Type<@ExampleToken.Vault>().identifier } -pub fun getNewAccount(): Test.Account { +access(all) fun getNewAccount(): Test.TestAccount { let acct = Test.createAccount() return acct } -pub fun setupExampleToken(acct: Test.Account) { +access(all) fun setupExampleToken(acct: Test.TestAccount) { txExecutor("example-token/setup.cdc", [acct], []) } -pub fun setupExampleNft(acct: Test.Account) { +access(all) fun setupExampleNft(acct: Test.TestAccount) { txExecutor("example-nft/setup.cdc", [acct], []) } -pub fun mintExampleNfts(_ acct: Test.Account, _ num: Int): [UInt64] { +access(all) fun mintExampleNfts(_ acct: Test.TestAccount, _ num: Int): [UInt64] { let txRes = txExecutor("example-nft/mint_example_nft.cdc", [exampleNftAccount], [acct.address, num]) let events = Test.eventsOfType(Type()) let ids: [UInt64] = [] while ids.length < num { - let event = events.removeLast() as! ExampleNFT.Deposit - ids.append(event.id) + let e = events.removeLast() as! ExampleNFT.Deposit + ids.append(e.id) } return ids } -pub fun mintExampleNftByID(_ acct: Test.Account, _ id: UInt64): UInt64 { +access(all) fun mintExampleNftByID(_ acct: Test.TestAccount, _ id: UInt64): UInt64 { post { result == id } let txRes = txExecutor("example-nft/mint_example_nft_with_id.cdc", [exampleNftAccount], [acct.address, id]) let events = Test.eventsOfType(Type()) - let event = events.removeLast() as! ExampleNFT.Deposit - return event.id + let e = events.removeLast() as! ExampleNFT.Deposit + return e.id } -pub fun mintExampleTokens(_ acct: Test.Account, _ amount: UFix64) { +access(all) fun mintExampleTokens(_ acct: Test.TestAccount, _ amount: UFix64) { txExecutor("example-token/mint.cdc", [exampleTokenAccount], [acct.address, amount]) } -pub fun mintFlow(_ receiver: Test.Account, _ amount: UFix64) { +access(all) fun mintFlow(_ receiver: Test.TestAccount, _ amount: UFix64) { let code = loadCode("flow/mint_flow.cdc", "transactions") let tx = Test.Transaction( code: code, @@ -151,17 +145,17 @@ pub fun mintFlow(_ receiver: Test.Account, _ amount: UFix64) { } } -pub fun initializeDepositor(_ acct: Test.Account) { +access(all) fun initializeDepositor(_ acct: Test.TestAccount) { txExecutor("depositor/setup_depositor.cdc", [acct], [lowBalanceThreshold]) mintFlow(acct, lowBalanceThreshold + 1.0) txExecutor("depositor/add_flow_tokens.cdc", [acct], [lowBalanceThreshold]) } -pub fun initializeDepositorWithoutBalance(_ acct: Test.Account) { +access(all) fun initializeDepositorWithoutBalance(_ acct: Test.TestAccount) { txExecutor("depositor/setup_depositor.cdc", [acct], [lowBalanceThreshold]) } -pub fun getNewDepositor(): Test.Account { +access(all) fun getNewDepositor(): Test.TestAccount { let acct = getNewAccount() initializeDepositor(acct) return acct diff --git a/transactions/clear_all_tickets.cdc b/transactions/clear_all_tickets.cdc index 26bcd72..58d523d 100644 --- a/transactions/clear_all_tickets.cdc +++ b/transactions/clear_all_tickets.cdc @@ -8,57 +8,43 @@ import "LostAndFound" transaction { - prepare(signer: AuthAccount) { + prepare(signer: auth(Storage, Capabilities) &Account) { // Return early if the account already stores a ExampleToken Vault - if signer.borrow<&AnyResource>(from: /storage/exampleTokenVault) == nil { + if signer.storage.borrow<&AnyResource>(from: /storage/exampleTokenVault) == nil { // Create a new ExampleToken Vault and put it in storage - signer.save( + signer.storage.save( <-ExampleToken.createEmptyVault(), to: /storage/exampleTokenVault ) - // Create a public capability to the Vault that only exposes - // the deposit function through the Receiver interface - signer.link<&ExampleToken.Vault{FungibleToken.Receiver}>( - /public/exampleTokenReceiver, - target: /storage/exampleTokenVault - ) - - // Create a public capability to the Vault that only exposes - // the balance field through the Balance interface - signer.link<&ExampleToken.Vault{FungibleToken.Balance}>( - /public/exampleTokenBalance, - target: /storage/exampleTokenVault - ) + let cap = signer.capabilities.storage.issue<&ExampleToken.Vault>(/storage/exampleTokenVault) + signer.capabilities.publish(cap, at: /public/exampleTokenReceiver) + signer.capabilities.publish(cap, at: /public/exampleTokenBalance) } // Return early if the account already stores a ExampleToken Vault - if signer.borrow<&AnyResource>(from: ExampleNFT.CollectionStoragePath) == nil { + if signer.storage.borrow<&AnyResource>(from: ExampleNFT.CollectionStoragePath) == nil { // Create a new ExampleToken Vault and put it in storage - signer.save( + signer.storage.save( <-ExampleNFT.createEmptyCollection(), to: ExampleNFT.CollectionStoragePath ) - // Create a public capability to the Vault that only exposes - // the balance field through the Balance interface - signer.link<&ExampleNFT.Collection{NonFungibleToken.CollectionPublic}>( - ExampleNFT.CollectionPublicPath, - target: ExampleNFT.CollectionStoragePath - ) + let cap = signer.capabilities.storage.issue<&ExampleNFT.Collection>(ExampleNFT.CollectionStoragePath) + signer.capabilities.publish(cap, at: ExampleNFT.CollectionPublicPath) } let redeemableTypes = LostAndFound.getRedeemableTypes(signer.address) let nftType = Type<@ExampleNFT.NFT>() if redeemableTypes.contains(nftType) { - let nftReceiver = signer.getCapability<&AnyResource{NonFungibleToken.CollectionPublic}>(ExampleNFT.CollectionPublicPath) + let nftReceiver = signer.capabilities.get<&{NonFungibleToken.Collection}>(ExampleNFT.CollectionPublicPath)! LostAndFound.redeemAll(type: nftType, max: nil, receiver: nftReceiver) } let ftType = Type<@ExampleToken.Vault>() if redeemableTypes.contains(ftType) { - let ftReceiver = signer.getCapability<&AnyResource{FungibleToken.Receiver}>(/public/exampleTokenReceiver) + let ftReceiver = signer.capabilities.get<&{FungibleToken.Receiver}>(/public/exampleTokenReceiver)! LostAndFound.redeemAll(type: Type<@ExampleToken.Vault>(), max: nil, receiver: ftReceiver) } } diff --git a/transactions/depositor/add_flow_tokens.cdc b/transactions/depositor/add_flow_tokens.cdc index e87b41a..4d18436 100644 --- a/transactions/depositor/add_flow_tokens.cdc +++ b/transactions/depositor/add_flow_tokens.cdc @@ -2,14 +2,13 @@ import "LostAndFound" import "FungibleToken" import "FlowToken" - transaction(amount: UFix64) { - prepare(acct: AuthAccount) { - let flowVault = acct.borrow<&FlowToken.Vault>(from: /storage/flowTokenVault)! + prepare(acct: auth(Storage) &Account) { + let flowVault = acct.storage.borrow(from: /storage/flowTokenVault)! let tokens <- flowVault.withdraw(amount: amount) let vault <-tokens as! @FlowToken.Vault - let depositor = acct.borrow<&LostAndFound.Depositor>(from: LostAndFound.DepositorStoragePath)! + let depositor = acct.storage.borrow<&LostAndFound.Depositor>(from: LostAndFound.DepositorStoragePath)! depositor.addFlowTokens(vault: <- vault) } } diff --git a/transactions/depositor/add_flow_tokens_public.cdc b/transactions/depositor/add_flow_tokens_public.cdc index 0a8d1ca..497f958 100644 --- a/transactions/depositor/add_flow_tokens_public.cdc +++ b/transactions/depositor/add_flow_tokens_public.cdc @@ -4,12 +4,12 @@ import "FlowToken" transaction(addr: Address, amount: UFix64) { - prepare(acct: AuthAccount) { - let flowVault = acct.borrow<&FlowToken.Vault>(from: /storage/flowTokenVault)! + prepare(acct: auth(BorrowValue) &Account) { + let flowVault = acct.storage.borrow(from: /storage/flowTokenVault)! let tokens <- flowVault.withdraw(amount: amount) let vault <-tokens as! @FlowToken.Vault - let depositor = getAccount(addr).getCapability<&{LostAndFound.DepositorPublic}>(LostAndFound.DepositorPublicPath).borrow()! + let depositor = getAccount(addr).capabilities.get<&{LostAndFound.DepositorPublic}>(LostAndFound.DepositorPublicPath)!.borrow()! depositor.addFlowTokens(vault: <- vault) } } diff --git a/transactions/depositor/destroy.cdc b/transactions/depositor/destroy.cdc index 8ffd478..f08a6fb 100644 --- a/transactions/depositor/destroy.cdc +++ b/transactions/depositor/destroy.cdc @@ -1,10 +1,10 @@ import "LostAndFound" transaction { - prepare(acct: AuthAccount) { - let depositor <- acct.load<@AnyResource>(from: LostAndFound.DepositorStoragePath) + prepare(acct: auth(Storage, Capabilities) &Account) { + let depositor <- acct.storage.load<@AnyResource>(from: LostAndFound.DepositorStoragePath) destroy depositor - acct.unlink(LostAndFound.DepositorPublicPath) + acct.capabilities.unpublish(LostAndFound.DepositorPublicPath) } } diff --git a/transactions/depositor/set_threshold.cdc b/transactions/depositor/set_threshold.cdc index 828922b..8f668ec 100644 --- a/transactions/depositor/set_threshold.cdc +++ b/transactions/depositor/set_threshold.cdc @@ -3,11 +3,13 @@ import "FungibleToken" import "FlowToken" transaction(newThreshold: UFix64?) { - let lfDepositor: &LostAndFound.Depositor + let lfDepositor: auth(Mutate) &LostAndFound.Depositor - prepare(acct: AuthAccount) { - self.lfDepositor = acct.borrow<&LostAndFound.Depositor>(from: LostAndFound.DepositorStoragePath)! + prepare(acct: auth(Storage) &Account) { + self.lfDepositor = acct.storage.borrow(from: LostAndFound.DepositorStoragePath)! + } + execute { self.lfDepositor.setLowBalanceThreshold(threshold: newThreshold) } } diff --git a/transactions/depositor/setup_depositor.cdc b/transactions/depositor/setup_depositor.cdc index a90ed48..fe1b068 100644 --- a/transactions/depositor/setup_depositor.cdc +++ b/transactions/depositor/setup_depositor.cdc @@ -4,12 +4,14 @@ import "FlowToken" transaction(lowBalanceThreshold: UFix64?) { - prepare(acct: AuthAccount) { - if acct.borrow<&LostAndFound.Depositor>(from: LostAndFound.DepositorStoragePath) == nil { - let flowTokenRepayment = acct.getCapability<&FlowToken.Vault{FungibleToken.Receiver}>(/public/flowTokenReceiver) + prepare(acct: auth(Storage, Capabilities) &Account) { + if acct.storage.borrow<&LostAndFound.Depositor>(from: LostAndFound.DepositorStoragePath) == nil { + let flowTokenRepayment = acct.capabilities.get<&FlowToken.Vault>(/public/flowTokenReceiver) let depositor <- LostAndFound.createDepositor(flowTokenRepayment, lowBalanceThreshold: lowBalanceThreshold) - acct.save(<-depositor, to: LostAndFound.DepositorStoragePath) - acct.link<&LostAndFound.Depositor{LostAndFound.DepositorPublic}>(LostAndFound.DepositorPublicPath, target: LostAndFound.DepositorStoragePath) + acct.storage.save(<-depositor, to: LostAndFound.DepositorStoragePath) + + let cap = acct.capabilities.storage.issue<&{LostAndFound.DepositorPublic}>(LostAndFound.DepositorStoragePath) + acct.capabilities.publish(cap, at: LostAndFound.DepositorPublicPath) } } } diff --git a/transactions/depositor/withdraw_below_threshold.cdc b/transactions/depositor/withdraw_below_threshold.cdc index 4b6c1fd..a267471 100644 --- a/transactions/depositor/withdraw_below_threshold.cdc +++ b/transactions/depositor/withdraw_below_threshold.cdc @@ -4,18 +4,20 @@ import "FlowToken" transaction(lowBalanceThreshold: UFix64) { - prepare(acct: AuthAccount) { - if acct.borrow<&LostAndFound.Depositor>(from: LostAndFound.DepositorStoragePath) == nil { - let flowTokenRepayment = acct.getCapability<&FlowToken.Vault{FungibleToken.Receiver}>(/public/flowTokenReceiver) + prepare(acct: auth(Storage, Capabilities) &Account) { + if acct.storage.borrow<&LostAndFound.Depositor>(from: LostAndFound.DepositorStoragePath) == nil { + let flowTokenRepayment = acct.capabilities.get<&FlowToken.Vault>(/public/flowTokenReceiver) let depositor <- LostAndFound.createDepositor(flowTokenRepayment, lowBalanceThreshold: lowBalanceThreshold) - acct.save(<-depositor, to: LostAndFound.DepositorStoragePath) - acct.link<&LostAndFound.Depositor{LostAndFound.DepositorPublic}>(LostAndFound.DepositorPublicPath, target: LostAndFound.DepositorStoragePath) + acct.storage.save(<-depositor, to: LostAndFound.DepositorStoragePath) + + let cap = acct.capabilities.storage.issue<&LostAndFound.Depositor>(LostAndFound.DepositorStoragePath) + acct.capabilities.publish(cap, at: LostAndFound.DepositorPublicPath) } - let depositor = acct.borrow<&LostAndFound.Depositor>(from: LostAndFound.DepositorStoragePath)! + let depositor = acct.storage.borrow(from: LostAndFound.DepositorStoragePath)! let balance = depositor.balance() - let flowVault = acct.borrow<&FlowToken.Vault>(from: /storage/flowTokenVault)! + let flowVault = acct.storage.borrow(from: /storage/flowTokenVault)! let tokens <- flowVault.withdraw(amount: lowBalanceThreshold - balance + 1.0) let vault <-tokens as! @FlowToken.Vault diff --git a/transactions/depositor/withdraw_to_threshold.cdc b/transactions/depositor/withdraw_to_threshold.cdc index a28cc41..6414211 100644 --- a/transactions/depositor/withdraw_to_threshold.cdc +++ b/transactions/depositor/withdraw_to_threshold.cdc @@ -4,18 +4,20 @@ import "FlowToken" transaction(lowBalanceThreshold: UFix64) { - prepare(acct: AuthAccount) { - if acct.borrow<&LostAndFound.Depositor>(from: LostAndFound.DepositorStoragePath) == nil { - let flowTokenRepayment = acct.getCapability<&FlowToken.Vault{FungibleToken.Receiver}>(/public/flowTokenReceiver) + prepare(acct: auth(Storage, Capabilities) &Account) { + if acct.storage.borrow<&LostAndFound.Depositor>(from: LostAndFound.DepositorStoragePath) == nil { + let flowTokenRepayment = acct.capabilities.get<&FlowToken.Vault>(/public/flowTokenReceiver) let depositor <- LostAndFound.createDepositor(flowTokenRepayment, lowBalanceThreshold: lowBalanceThreshold) - acct.save(<-depositor, to: LostAndFound.DepositorStoragePath) - acct.link<&LostAndFound.Depositor{LostAndFound.DepositorPublic}>(LostAndFound.DepositorPublicPath, target: LostAndFound.DepositorStoragePath) + acct.storage.save(<-depositor, to: LostAndFound.DepositorStoragePath) + + let cap = acct.capabilities.storage.issue(LostAndFound.DepositorStoragePath) + acct.capabilities.publish(cap, at: LostAndFound.DepositorPublicPath) } - let depositor = acct.borrow<&LostAndFound.Depositor>(from: LostAndFound.DepositorStoragePath)! + let depositor = acct.storage.borrow<&LostAndFound.Depositor>(from: LostAndFound.DepositorStoragePath)! let balance = depositor.balance() - let flowVault = acct.borrow<&FlowToken.Vault>(from: /storage/flowTokenVault)! + let flowVault = acct.storage.borrow(from: /storage/flowTokenVault)! let tokens <- flowVault.withdraw(amount: lowBalanceThreshold - balance) let vault <-tokens as! @FlowToken.Vault diff --git a/transactions/depositor/withdraw_tokens.cdc b/transactions/depositor/withdraw_tokens.cdc index 2c94b61..0a093b3 100644 --- a/transactions/depositor/withdraw_tokens.cdc +++ b/transactions/depositor/withdraw_tokens.cdc @@ -4,12 +4,16 @@ import "FlowToken" transaction(amount: UFix64) { + let flowReceiver: &{FungibleToken.Receiver} - let lfDepositor: &LostAndFound.Depositor - prepare(acct: AuthAccount) { - self.flowReceiver = acct.borrow<&{FungibleToken.Receiver}>(from: /storage/flowTokenVault)! - self.lfDepositor = acct.borrow<&LostAndFound.Depositor>(from: LostAndFound.DepositorStoragePath)! + let lfDepositor: auth(Mutate) &LostAndFound.Depositor + + prepare(acct: auth(Storage) &Account) { + self.flowReceiver = acct.storage.borrow<&{FungibleToken.Receiver}>(from: /storage/flowTokenVault)! + self.lfDepositor = acct.storage.borrow(from: LostAndFound.DepositorStoragePath)! + } + execute { self.flowReceiver.deposit(from: <- self.lfDepositor.withdrawTokens(amount: amount)) } } diff --git a/transactions/example-nft/destroy_example_nft_storage.cdc b/transactions/example-nft/destroy_example_nft_storage.cdc index 572620d..ef418b5 100644 --- a/transactions/example-nft/destroy_example_nft_storage.cdc +++ b/transactions/example-nft/destroy_example_nft_storage.cdc @@ -3,9 +3,9 @@ import "FungibleToken" import "ExampleNFT" transaction { - prepare(signer: AuthAccount) { - let resource <- signer.load<@AnyResource>(from: ExampleNFT.CollectionStoragePath) - destroy resource - signer.unlink(ExampleNFT.CollectionPublicPath) + prepare(signer: auth(Storage, Capabilities) &Account) { + let r <- signer.storage.load<@AnyResource>(from: ExampleNFT.CollectionStoragePath) + destroy r + signer.capabilities.unpublish(ExampleNFT.CollectionPublicPath) } } \ No newline at end of file diff --git a/transactions/example-nft/mint_and_deposit_example_nft.cdc b/transactions/example-nft/mint_and_deposit_example_nft.cdc index d02c1f0..26fdc6f 100644 --- a/transactions/example-nft/mint_and_deposit_example_nft.cdc +++ b/transactions/example-nft/mint_and_deposit_example_nft.cdc @@ -10,44 +10,49 @@ transaction(recipient: Address) { // local variable for storing the minter reference let minter: &ExampleNFT.NFTMinter - let flowProvider: Capability<&FlowToken.Vault{FungibleToken.Provider}> - let flowReceiver: Capability<&FlowToken.Vault{FungibleToken.Receiver}> + let flowProvider: Capability + let flowReceiver: Capability<&FlowToken.Vault> + let nftReceiverCap: Capability<&{NonFungibleToken.Collection}> - prepare(acct: AuthAccount) { + prepare(sender: auth(Storage, Capabilities) &Account, receiver: auth(Storage, Capabilities) &Account) { // borrow a reference to the NFTMinter resource in storage - self.minter = acct.borrow<&ExampleNFT.NFTMinter>(from: /storage/exampleNFTMinter) + self.minter = sender.storage.borrow<&ExampleNFT.NFTMinter>(from: /storage/exampleNFTMinter) ?? panic("Could not borrow a reference to the NFT minter") - let flowTokenProviderPath = /private/flowTokenLostAndFoundProviderPath + var provider: Capability? = nil + sender.capabilities.storage.forEachController(forPath: /storage/flowTokenVault, fun(c: &StorageCapabilityController): Bool { + if c.borrowType == Type() { + provider = c.capability as! Capability + } - if !acct.getCapability<&FlowToken.Vault{FungibleToken.Provider}>(flowTokenProviderPath).check() { - acct.unlink(flowTokenProviderPath) - acct.link<&FlowToken.Vault{FungibleToken.Provider}>( - flowTokenProviderPath, - target: /storage/flowTokenVault - ) + return true + }) + + if provider == nil { + provider = sender.capabilities.storage.issue(/storage/flowTokenVault) } - self.flowProvider = acct.getCapability<&FlowToken.Vault{FungibleToken.Provider}>(flowTokenProviderPath) - self.flowReceiver = acct.getCapability<&FlowToken.Vault{FungibleToken.Receiver}>(/public/flowTokenReceiver) + self.flowProvider = provider! + self.flowReceiver = sender.capabilities.get<&FlowToken.Vault>(/public/flowTokenReceiver)! + + self.nftReceiverCap = receiver.capabilities.storage.issue<&{NonFungibleToken.Collection}>(ExampleNFT.CollectionStoragePath) + receiver.capabilities.storage.getController(byCapabilityID: self.nftReceiverCap.id)!.delete() } execute { - let cap: Capability<&AnyResource{NonFungibleToken.CollectionPublic}> = getAccount(recipient).getCapability<&{NonFungibleToken.CollectionPublic}>(ExampleNFT.CollectionPublicPath) - let token <- self.minter.mint(name: "some test nft", description: "desc", thumbnail: "image.png") let display = token.resolveView(Type()) as! MetadataViews.Display? let memo = "test memo" let depositEstimate <- LostAndFound.estimateDeposit(redeemer: recipient, item: <-token, memo: memo, display: display) let storageFee <- self.flowProvider.borrow()!.withdraw(amount: depositEstimate.storageFee) - let resource <- depositEstimate.withdraw() + let item <- depositEstimate.withdraw() LostAndFound.trySendResource( - resource: <-resource, - cap: cap, + item: <-item, + cap: self.nftReceiverCap, memo: memo, display: display, - storagePayment: &storageFee as &FungibleToken.Vault, + storagePayment: &storageFee as auth(FungibleToken.Withdraw) &{FungibleToken.Vault}, flowTokenRepayment: self.flowReceiver ) diff --git a/transactions/example-nft/mint_and_deposit_example_nfts.cdc b/transactions/example-nft/mint_and_deposit_example_nfts.cdc index f43bd27..8e05939 100644 --- a/transactions/example-nft/mint_and_deposit_example_nfts.cdc +++ b/transactions/example-nft/mint_and_deposit_example_nfts.cdc @@ -10,26 +10,17 @@ transaction(recipient: Address, numToMint: Int) { // local variable for storing the minter reference let minter: &ExampleNFT.NFTMinter - let flowProvider: Capability<&FlowToken.Vault{FungibleToken.Provider}> - let flowReceiver: Capability<&FlowToken.Vault{FungibleToken.Receiver}> + let flowProvider: Capability + let flowReceiver: Capability<&FlowToken.Vault> - prepare(acct: AuthAccount) { + prepare(acct: auth(Storage, Capabilities) &Account) { // borrow a reference to the NFTMinter resource in storage - self.minter = acct.borrow<&ExampleNFT.NFTMinter>(from: /storage/exampleNFTMinter) + self.minter = acct.storage.borrow<&ExampleNFT.NFTMinter>(from: /storage/exampleNFTMinter) ?? panic("Could not borrow a reference to the NFT minter") - let flowTokenProviderPath = /private/flowTokenLostAndFoundProviderPath - - if !acct.getCapability<&FlowToken.Vault{FungibleToken.Provider}>(flowTokenProviderPath).check() { - acct.unlink(flowTokenProviderPath) - acct.link<&FlowToken.Vault{FungibleToken.Provider}>( - flowTokenProviderPath, - target: /storage/flowTokenVault - ) - } - - self.flowProvider = acct.getCapability<&FlowToken.Vault{FungibleToken.Provider}>(flowTokenProviderPath) - self.flowReceiver = acct.getCapability<&FlowToken.Vault{FungibleToken.Receiver}>(/public/flowTokenReceiver) + let cap = acct.capabilities.storage.issue(/storage/flowTokenVault) + self.flowProvider = cap + self.flowReceiver = acct.capabilities.get<&FlowToken.Vault>(/public/flowTokenReceiver)! } execute { @@ -48,7 +39,7 @@ transaction(recipient: Address, numToMint: Int) { item: <-token, memo: memo, display: display, - storagePayment: &storageFee as &FungibleToken.Vault, + storagePayment: &storageFee as auth(FungibleToken.Withdraw) &{FungibleToken.Vault}, flowTokenRepayment: self.flowReceiver ) diff --git a/transactions/example-nft/mint_and_deposit_with_depositor.cdc b/transactions/example-nft/mint_and_deposit_with_depositor.cdc index 40c302d..03ec9aa 100644 --- a/transactions/example-nft/mint_and_deposit_with_depositor.cdc +++ b/transactions/example-nft/mint_and_deposit_with_depositor.cdc @@ -9,13 +9,13 @@ import "LostAndFound" transaction(recipient: Address) { // local variable for storing the minter reference let minter: &ExampleNFT.NFTMinter - let depositor: &LostAndFound.Depositor + let depositor: auth(LostAndFound.Deposit) &LostAndFound.Depositor - prepare(acct: AuthAccount) { + prepare(acct: auth(Storage, Capabilities) &Account) { // borrow a reference to the NFTMinter resource in storage - self.minter = acct.borrow<&ExampleNFT.NFTMinter>(from: /storage/exampleNFTMinter) + self.minter = acct.storage.borrow<&ExampleNFT.NFTMinter>(from: /storage/exampleNFTMinter) ?? panic("Could not borrow a reference to the NFT minter") - self.depositor = acct.borrow<&LostAndFound.Depositor>(from: LostAndFound.DepositorStoragePath)! + self.depositor = acct.storage.borrow(from: LostAndFound.DepositorStoragePath)! } execute { diff --git a/transactions/example-nft/mint_example_nft.cdc b/transactions/example-nft/mint_example_nft.cdc index 9e801ac..ae9f053 100644 --- a/transactions/example-nft/mint_example_nft.cdc +++ b/transactions/example-nft/mint_example_nft.cdc @@ -7,14 +7,15 @@ transaction(recipient: Address, num: Int) { // local variable for storing the minter reference let minter: &ExampleNFT.NFTMinter - prepare(acct: AuthAccount) { + prepare(acct: auth(Storage, Capabilities) &Account) { // borrow a reference to the NFTMinter resource in storage - self.minter = acct.borrow<&ExampleNFT.NFTMinter>(from: /storage/exampleNFTMinter) + self.minter = acct.storage.borrow<&ExampleNFT.NFTMinter>(from: /storage/exampleNFTMinter) ?? panic("Could not borrow a reference to the NFT minter") } execute { - let receiver = getAccount(recipient).getCapability<&{NonFungibleToken.CollectionPublic}>(ExampleNFT.CollectionPublicPath).borrow()! + let cap = getAccount(recipient).capabilities.get<&{NonFungibleToken.Collection}>(ExampleNFT.CollectionPublicPath) + let receiver = cap.borrow() ?? panic("unable to borrow collection") var count = 0 while count < num { diff --git a/transactions/example-nft/redeem_example_nft_all.cdc b/transactions/example-nft/redeem_example_nft_all.cdc index fa2662a..85fa2b0 100644 --- a/transactions/example-nft/redeem_example_nft_all.cdc +++ b/transactions/example-nft/redeem_example_nft_all.cdc @@ -4,30 +4,10 @@ import "NonFungibleToken" import "LostAndFound" transaction { - let receiver: Capability<&{NonFungibleToken.CollectionPublic}> - let redeemer: Address + prepare(acct: auth(Storage, Capabilities) &Account) { + let cap = acct.capabilities.storage.issue<&ExampleNFT.Collection>(ExampleNFT.CollectionStoragePath) + LostAndFound.redeemAll(type: Type<@ExampleNFT.NFT>(), max: nil, receiver: cap) - prepare(acct: AuthAccount) { - self.redeemer = acct.address - - if !acct.getCapability<&AnyResource{NonFungibleToken.CollectionPublic}>(ExampleNFT.CollectionPublicPath).check() { - let collection <- ExampleNFT.createEmptyCollection() - - // save it to the account - acct.save(<-collection, to: ExampleNFT.CollectionStoragePath) - - // create a public capability for the collection - acct.link<&AnyResource{NonFungibleToken.CollectionPublic}>( - ExampleNFT.CollectionPublicPath, - target: ExampleNFT.CollectionStoragePath - ) - } - - self.receiver = acct.getCapability<&AnyResource{NonFungibleToken.CollectionPublic}>(ExampleNFT.CollectionPublicPath) - assert(self.receiver.check(), message: "receiver not configured correctly!") - } - - execute { - LostAndFound.redeemAll(type: Type<@ExampleNFT.NFT>(), max: nil, receiver: self.receiver) + acct.capabilities.storage.getController(byCapabilityID: cap.id)!.delete() } } diff --git a/transactions/example-nft/setup.cdc b/transactions/example-nft/setup.cdc index 5149570..aa3f741 100644 --- a/transactions/example-nft/setup.cdc +++ b/transactions/example-nft/setup.cdc @@ -3,29 +3,44 @@ import "ExampleNFT" import "MetadataViews" transaction { - prepare(signer: AuthAccount) { + prepare(signer: auth(Storage, Capabilities) &Account) { // Return early if the account already stores a ExampleToken Vault - if signer.borrow<&ExampleNFT.Collection>(from: ExampleNFT.CollectionStoragePath) == nil { + if signer.storage.borrow<&ExampleNFT.Collection>(from: ExampleNFT.CollectionStoragePath) == nil { // Create a new ExampleToken Vault and put it in storage - signer.save( + signer.storage.save( <-ExampleNFT.createEmptyCollection(), to: ExampleNFT.CollectionStoragePath ) } - signer.unlink(ExampleNFT.CollectionPublicPath) - signer.unlink(/private/exampleNFTCollection) + let cd = ExampleNFT.resolveContractView(resourceType: nil, viewType: Type())! as! MetadataViews.NFTCollectionData - // Create a public capability to the Vault that only exposes - // the balance field through the Balance interface - signer.link<&ExampleNFT.Collection{NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection}>( - ExampleNFT.CollectionPublicPath, - target: ExampleNFT.CollectionStoragePath - ) + var pubCap = signer.capabilities.get<&ExampleNFT.Collection>(cd.publicPath) + if pubCap == nil { + pubCap = signer.capabilities.storage.issue<&ExampleNFT.Collection>(cd.storagePath) + } else if !pubCap!.check() { + pubCap = signer.capabilities.storage.issue<&ExampleNFT.Collection>(cd.storagePath) + } + + // does the public capability exist and succeed? + signer.capabilities.unpublish(cd.publicPath) + signer.capabilities.publish(pubCap!, at: cd.publicPath) + + // ensure there is a provider path for this collection + var foundProvider = false + let providerSubtype = Type() + let caps = signer.capabilities.storage.forEachController(forPath: cd.storagePath, fun(c: &StorageCapabilityController): Bool { + if providerSubtype.isSubtype(of: c.borrowType) { + foundProvider = true + } + return true + }) + + if foundProvider { + return + } - signer.link<&ExampleNFT.Collection{NonFungibleToken.CollectionPublic, NonFungibleToken.Provider}>( - /private/exampleNFTCollection, - target: ExampleNFT.CollectionStoragePath - ) + let cap = signer.capabilities.storage.issue(cd.storagePath) + assert(cap.check(), message: "unable to issue provider capability") } } \ No newline at end of file diff --git a/transactions/example-nft/setup_account_example_nft.cdc b/transactions/example-nft/setup_account_example_nft.cdc index 04a777e..a39b0b2 100644 --- a/transactions/example-nft/setup_account_example_nft.cdc +++ b/transactions/example-nft/setup_account_example_nft.cdc @@ -4,24 +4,20 @@ import "ExampleNFT" transaction { - prepare(signer: AuthAccount) { + prepare(signer: auth(Storage, Capabilities) &Account) { // Return early if the account already stores a ExampleToken Vault - if signer.borrow<&ExampleNFT.NFT>(from: ExampleNFT.CollectionStoragePath) != nil { + if signer.storage.borrow<&ExampleNFT.NFT>(from: ExampleNFT.CollectionStoragePath) != nil { return } // Create a new ExampleToken Vault and put it in storage - signer.save( + signer.storage.save( <-ExampleNFT.createEmptyCollection(), to: ExampleNFT.CollectionStoragePath ) - // Create a public capability to the Vault that only exposes - // the balance field through the Balance interface - signer.link<&ExampleNFT.Collection{NonFungibleToken.CollectionPublic}>( - ExampleNFT.CollectionPublicPath, - target: ExampleNFT.CollectionStoragePath - ) + let cap = signer.capabilities.storage.issue<&ExampleNFT.Collection>(ExampleNFT.CollectionStoragePath) + signer.capabilities.publish(cap, at: ExampleNFT.CollectionPublicPath) } } \ No newline at end of file diff --git a/transactions/example-nft/try_send_example_nft.cdc b/transactions/example-nft/try_send_example_nft.cdc index 16973c0..c01f11a 100644 --- a/transactions/example-nft/try_send_example_nft.cdc +++ b/transactions/example-nft/try_send_example_nft.cdc @@ -6,49 +6,56 @@ import "MetadataViews" import "LostAndFound" -transaction(recipient: Address) { +transaction(recipient: Address, revoke: Bool) { // local variable for storing the minter reference let minter: &ExampleNFT.NFTMinter - let flowProvider: Capability<&FlowToken.Vault{FungibleToken.Provider}> - let flowReceiver: Capability<&FlowToken.Vault{FungibleToken.Receiver}> + let flowProvider: Capability + let flowReceiver: Capability<&FlowToken.Vault> + let nftReceiverCap: Capability<&{NonFungibleToken.Collection}> - prepare(acct: AuthAccount) { + prepare(sender: auth(Storage,Capabilities) &Account, receiver: auth(Storage,Capabilities) &Account) { // borrow a reference to the NFTMinter resource in storage - self.minter = acct.borrow<&ExampleNFT.NFTMinter>(from: /storage/exampleNFTMinter) + self.minter = sender.storage.borrow<&ExampleNFT.NFTMinter>(from: /storage/exampleNFTMinter) ?? panic("Could not borrow a reference to the NFT minter") - let flowTokenProviderPath = /private/flowTokenLostAndFoundProviderPath + var provider: Capability? = nil + sender.capabilities.storage.forEachController(forPath: /storage/flowTokenVault, fun(c: &StorageCapabilityController): Bool { + if c.borrowType == Type() { + provider = c.capability as! Capability + } + return true + }) - if !acct.getCapability<&FlowToken.Vault{FungibleToken.Provider}>(flowTokenProviderPath).check() { - acct.unlink(flowTokenProviderPath) - acct.link<&FlowToken.Vault{FungibleToken.Provider}>( - flowTokenProviderPath, - target: /storage/flowTokenVault - ) + if provider == nil { + provider = sender.capabilities.storage.issue(/storage/flowTokenVault) } - self.flowProvider = acct.getCapability<&FlowToken.Vault{FungibleToken.Provider}>(flowTokenProviderPath) - self.flowReceiver = acct.getCapability<&FlowToken.Vault{FungibleToken.Receiver}>(/public/flowTokenReceiver) + self.flowProvider = provider! + self.flowReceiver = sender.capabilities.get<&FlowToken.Vault>(/public/flowTokenReceiver)! + + self.nftReceiverCap = receiver.capabilities.storage.issue<&{NonFungibleToken.Collection}>(ExampleNFT.CollectionStoragePath) + + if revoke { + receiver.capabilities.storage.getController(byCapabilityID: self.nftReceiverCap.id)!.delete() + } } execute { - let exampleNFTReceiver = getAccount(recipient).getCapability<&{NonFungibleToken.CollectionPublic}>(ExampleNFT.CollectionPublicPath) - let token <- self.minter.mint(name: "testname", description: "descr", thumbnail: "image.html") let display = token.resolveView(Type()) as! MetadataViews.Display? let memo = "test memo" let depositEstimate <- LostAndFound.estimateDeposit(redeemer: recipient, item: <-token, memo: memo, display: display) let storageFee <- self.flowProvider.borrow()!.withdraw(amount: depositEstimate.storageFee) - let resource <- depositEstimate.withdraw() + let item <- depositEstimate.withdraw() LostAndFound.trySendResource( - resource: <-resource, - cap: exampleNFTReceiver, + item: <-item, + cap: self.nftReceiverCap, memo: nil, display: display, - storagePayment: &storageFee as &FungibleToken.Vault, + storagePayment: &storageFee as auth(FungibleToken.Withdraw) &{FungibleToken.Vault}, flowTokenRepayment: self.flowReceiver ) diff --git a/transactions/example-nft/try_send_example_nft_with_depositor.cdc b/transactions/example-nft/try_send_example_nft_with_depositor.cdc index 6058736..b983eb0 100644 --- a/transactions/example-nft/try_send_example_nft_with_depositor.cdc +++ b/transactions/example-nft/try_send_example_nft_with_depositor.cdc @@ -6,27 +6,33 @@ import "MetadataViews" import "LostAndFound" -transaction(recipient: Address) { +transaction(recipient: Address, revoke: Bool) { // local variable for storing the minter reference let minter: &ExampleNFT.NFTMinter - let depositor: &LostAndFound.Depositor + let depositor: auth(LostAndFound.Deposit) &LostAndFound.Depositor + let nftReceiverCap: Capability<&{NonFungibleToken.Collection}> - prepare(acct: AuthAccount) { + prepare(sender: auth(Storage, Capabilities) &Account, receiver: auth(Storage, Capabilities) &Account) { // borrow a reference to the NFTMinter resource in storage - self.minter = acct.borrow<&ExampleNFT.NFTMinter>(from: /storage/exampleNFTMinter) + self.minter = sender.storage.borrow<&ExampleNFT.NFTMinter>(from: /storage/exampleNFTMinter) ?? panic("Could not borrow a reference to the NFT minter") - self.depositor = acct.borrow<&LostAndFound.Depositor>(from: LostAndFound.DepositorStoragePath)! + self.depositor = sender.storage.borrow(from: LostAndFound.DepositorStoragePath)! + + self.nftReceiverCap = receiver.capabilities.storage.issue<&{NonFungibleToken.Collection}>(ExampleNFT.CollectionStoragePath) + + if revoke { + receiver.capabilities.storage.getController(byCapabilityID: self.nftReceiverCap.id)!.delete() + } } execute { - let exampleNFTReceiver = getAccount(recipient).getCapability<&{NonFungibleToken.CollectionPublic}>(ExampleNFT.CollectionPublicPath) let token <- self.minter.mint(name: "testname", description: "descr", thumbnail: "image.html") let display = token.resolveView(Type()) as! MetadataViews.Display? let memo = "test memo" self.depositor.trySendResource( item: <-token, - cap: exampleNFTReceiver, + cap: self.nftReceiverCap, memo: memo, display: display ) diff --git a/transactions/example-nft/try_send_multiple_example_nft.cdc b/transactions/example-nft/try_send_multiple_example_nft.cdc index f0b4eae..a5e8ec4 100644 --- a/transactions/example-nft/try_send_multiple_example_nft.cdc +++ b/transactions/example-nft/try_send_multiple_example_nft.cdc @@ -10,48 +10,41 @@ transaction(recipient: Address, numToMint: Int) { // local variable for storing the minter reference let minter: &ExampleNFT.NFTMinter - let flowProvider: Capability<&FlowToken.Vault{FungibleToken.Provider}> - let flowReceiver: Capability<&FlowToken.Vault{FungibleToken.Receiver}> + let flowProvider: Capability + let flowReceiver: Capability<&FlowToken.Vault> - prepare(acct: AuthAccount) { + prepare(acct: auth(Storage, Capabilities) &Account) { // borrow a reference to the NFTMinter resource in storage - self.minter = acct.borrow<&ExampleNFT.NFTMinter>(from: /storage/exampleNFTMinter) + self.minter = acct.storage.borrow<&ExampleNFT.NFTMinter>(from: /storage/exampleNFTMinter) ?? panic("Could not borrow a reference to the NFT minter") let flowTokenProviderPath = /private/flowTokenLostAndFoundProviderPath + let cap = acct.capabilities.storage.issue(/storage/flowTokenVault) - if !acct.getCapability<&FlowToken.Vault{FungibleToken.Provider}>(flowTokenProviderPath).check() { - acct.unlink(flowTokenProviderPath) - acct.link<&FlowToken.Vault{FungibleToken.Provider}>( - flowTokenProviderPath, - target: /storage/flowTokenVault - ) - } - - self.flowProvider = acct.getCapability<&FlowToken.Vault{FungibleToken.Provider}>(flowTokenProviderPath) - self.flowReceiver = acct.getCapability<&FlowToken.Vault{FungibleToken.Receiver}>(/public/flowTokenReceiver) + self.flowProvider = cap + self.flowReceiver = acct.capabilities.get<&FlowToken.Vault>(/public/flowTokenReceiver)! } execute { - let exampleNFTReceiver = getAccount(recipient).getCapability<&{NonFungibleToken.CollectionPublic}>(ExampleNFT.CollectionPublicPath) + let exampleNFTReceiver = getAccount(recipient).capabilities.get<&{NonFungibleToken.CollectionPublic}>(ExampleNFT.CollectionPublicPath)! var numMinted = 0 while numMinted < numToMint { numMinted = numMinted + 1 - let token <- self.minter.mintAndReturnNFT(name: "testname", description: "descr", thumbnail: "image.html", royalties: []) as! @ExampleNFT.NFT + let token <- self.minter.mintAndReturnNFT(name: "testname", description: "descr", thumbnail: "image.html") let display = token.resolveView(Type()) as! MetadataViews.Display? let memo = "test memo" let depositEstimate <- LostAndFound.estimateDeposit(redeemer: recipient, item: <-token, memo: memo, display: display) let storageFee <- self.flowProvider.borrow()!.withdraw(amount: depositEstimate.storageFee) - let resource <- depositEstimate.withdraw() + let item <- depositEstimate.withdraw() LostAndFound.trySendResource( - resource: <-resource, + item: <-item, cap: exampleNFTReceiver, memo: nil, display: display, - storagePayment: &storageFee as &FungibleToken.Vault, + storagePayment: &storageFee as auth(FungibleToken.Withdraw) &{FungibleToken.Vault}, flowTokenRepayment: self.flowReceiver ) diff --git a/transactions/example-token/deposit_example_token.cdc b/transactions/example-token/deposit_example_token.cdc index abb51bc..17db8be 100644 --- a/transactions/example-token/deposit_example_token.cdc +++ b/transactions/example-token/deposit_example_token.cdc @@ -7,25 +7,17 @@ import "LostAndFound" transaction(redeemer: Address, amount: UFix64) { let tokenAdmin: &ExampleToken.Administrator - let flowProvider: Capability<&FlowToken.Vault{FungibleToken.Provider}> - let flowReceiver: Capability<&FlowToken.Vault{FungibleToken.Receiver}> + let flowProvider: Capability + let flowReceiver: Capability<&FlowToken.Vault> - prepare(acct: AuthAccount) { - self.tokenAdmin = acct.borrow<&ExampleToken.Administrator>(from: /storage/exampleTokenAdmin) + prepare(acct: auth(Storage, Capabilities) &Account) { + self.tokenAdmin = acct.storage.borrow<&ExampleToken.Administrator>(from: /storage/exampleTokenAdmin) ?? panic("acct is not the token admin") let flowTokenProviderPath = /private/flowTokenLostAndFoundProviderPath - - if !acct.getCapability<&FlowToken.Vault{FungibleToken.Provider}>(flowTokenProviderPath).check() { - acct.unlink(flowTokenProviderPath) - acct.link<&FlowToken.Vault{FungibleToken.Provider}>( - flowTokenProviderPath, - target: /storage/flowTokenVault - ) - } - - self.flowProvider = acct.getCapability<&FlowToken.Vault{FungibleToken.Provider}>(flowTokenProviderPath) - self.flowReceiver = acct.getCapability<&FlowToken.Vault{FungibleToken.Receiver}>(/public/flowTokenReceiver) + let cap = acct.capabilities.storage.issue(/storage/flowTokenVault) + self.flowProvider = cap + self.flowReceiver = acct.capabilities.get<&FlowToken.Vault>(/public/flowTokenReceiver)! } execute { @@ -34,14 +26,14 @@ transaction(redeemer: Address, amount: UFix64) { let memo = "test memo" let depositEstimate <- LostAndFound.estimateDeposit(redeemer: redeemer, item: <-mintedVault, memo: memo, display: nil) let storageFee <- self.flowProvider.borrow()!.withdraw(amount: depositEstimate.storageFee) - let resource <- depositEstimate.withdraw() + let item <- depositEstimate.withdraw() LostAndFound.deposit( redeemer: redeemer, - item: <-resource, + item: <-item, memo: memo, display: nil, - storagePayment: &storageFee as &FungibleToken.Vault, + storagePayment: &storageFee as auth(FungibleToken.Withdraw) &{FungibleToken.Vault}, flowTokenRepayment: self.flowReceiver ) diff --git a/transactions/example-token/deposit_example_token_with_depositor.cdc b/transactions/example-token/deposit_example_token_with_depositor.cdc index 8075dc9..1b38a20 100644 --- a/transactions/example-token/deposit_example_token_with_depositor.cdc +++ b/transactions/example-token/deposit_example_token_with_depositor.cdc @@ -6,12 +6,12 @@ import "LostAndFound" transaction(recipient: Address, amount: UFix64) { let tokenAdmin: &ExampleToken.Administrator - let depositor: &LostAndFound.Depositor + let depositor: auth(LostAndFound.Deposit) &LostAndFound.Depositor - prepare(acct: AuthAccount) { - self.tokenAdmin = acct.borrow<&ExampleToken.Administrator>(from: /storage/exampleTokenAdmin) + prepare(acct: auth(Storage, Capabilities) &Account) { + self.tokenAdmin = acct.storage.borrow<&ExampleToken.Administrator>(from: /storage/exampleTokenAdmin) ?? panic("acct is not the token admin") - self.depositor = acct.borrow<&LostAndFound.Depositor>(from: LostAndFound.DepositorStoragePath)! + self.depositor = acct.storage.borrow(from: LostAndFound.DepositorStoragePath)! } execute { diff --git a/transactions/example-token/destroy_example_token_storage.cdc b/transactions/example-token/destroy_example_token_storage.cdc index 59ee594..7a1ae92 100644 --- a/transactions/example-token/destroy_example_token_storage.cdc +++ b/transactions/example-token/destroy_example_token_storage.cdc @@ -5,10 +5,10 @@ import "ExampleToken" import "LostAndFound" transaction { - prepare(signer: AuthAccount) { - let resource <- signer.load<@AnyResource>(from: /storage/exampleTokenVault) - destroy resource - signer.unlink(/public/exampleTokenReceiver) - signer.unlink(/public/exampleTokenBalance) + prepare(signer: auth(Storage, Capabilities) &Account) { + destroy signer.storage.load<@AnyResource>(from: /storage/exampleTokenVault) + + signer.capabilities.unpublish(/public/exampleTokenReceiver) + signer.capabilities.unpublish(/public/exampleTokenBalance) } } \ No newline at end of file diff --git a/transactions/example-token/redeem_example_token_all.cdc b/transactions/example-token/redeem_example_token_all.cdc index 1f6fcd1..6ec7063 100644 --- a/transactions/example-token/redeem_example_token_all.cdc +++ b/transactions/example-token/redeem_example_token_all.cdc @@ -5,33 +5,9 @@ import "ExampleToken" import "LostAndFound" transaction() { - let receiver: Capability<&{FungibleToken.Receiver}> - let redeemer: Address - - prepare(acct: AuthAccount) { - self.redeemer = acct.address - - if !acct.getCapability<&AnyResource{FungibleToken.Receiver}>(/public/exampleTokenReceiver).check() { - acct.save( - <-ExampleToken.createEmptyVault(), - to: /storage/exampleTokenVault - ) - - acct.link<&ExampleToken.Vault{FungibleToken.Receiver}>( - /public/exampleTokenReceiver, - target: /storage/exampleTokenVault - ) - - acct.link<&ExampleToken.Vault{FungibleToken.Balance}>( - /public/exampleTokenBalance, - target: /storage/exampleTokenVault - ) - } - - self.receiver = acct.getCapability<&AnyResource{FungibleToken.Receiver}>(/public/exampleTokenReceiver) - } - - execute { - LostAndFound.redeemAll(type: Type<@ExampleToken.Vault>(), max: nil, receiver: self.receiver) + prepare(acct: auth(Storage, Capabilities) &Account) { + let cap = acct.capabilities.storage.issue<&ExampleToken.Vault>(/storage/exampleTokenVault) + LostAndFound.redeemAll(type: Type<@ExampleToken.Vault>(), max: nil, receiver: cap) + acct.capabilities.storage.getController(byCapabilityID: cap.id)!.delete() } } diff --git a/transactions/example-token/setup.cdc b/transactions/example-token/setup.cdc index 271e93b..3402c35 100644 --- a/transactions/example-token/setup.cdc +++ b/transactions/example-token/setup.cdc @@ -2,22 +2,45 @@ import "FungibleToken" import "ExampleToken" transaction { - prepare(acct: AuthAccount) { - if acct.borrow<&ExampleToken.Vault>(from: /storage/exampleTokenVault) == nil { - acct.save(<-ExampleToken.createEmptyVault(), to: /storage/exampleTokenVault) + prepare(acct: auth(Storage, Capabilities) &Account) { + if acct.storage.borrow<&ExampleToken.Vault>(from: /storage/exampleTokenVault) == nil { + acct.storage.save(<-ExampleToken.createEmptyVault(), to: /storage/exampleTokenVault) } - - acct.link<&{FungibleToken.Receiver}>( - /public/exampleTokenReceiver, - target: /storage/exampleTokenVault - ) - - acct.link<&{FungibleToken.Balance}>( - /public/exampleTokenBalance, - target: /storage/exampleTokenVault - ) - - acct.link<&{FungibleToken.Provider, FungibleToken.Balance, FungibleToken.Receiver}>(/private/exampleTokenProvider, target: /storage/exampleTokenVault) + + let v <- ExampleToken.createEmptyVault() + let publicPath = v.getDefaultPublicPath()! + let receiverPath = v.getDefaultReceiverPath()! + let storagePath = v.getDefaultStoragePath()! + destroy v + + var publicCap = acct.capabilities.get<&{FungibleToken.Vault}>(publicPath) + if publicCap == nil { + publicCap = acct.capabilities.storage.issue<&ExampleToken.Vault>(storagePath) + acct.capabilities.publish(publicCap!, at: publicPath) + } + + + var receiverCap = acct.capabilities.get<&{FungibleToken.Receiver}>(receiverPath) + if receiverCap == nil { + receiverCap = acct.capabilities.storage.issue<&{FungibleToken.Receiver}>(storagePath) + acct.capabilities.publish(receiverCap!, at: receiverPath) + } + + var foundProvider = false + let providerSubtype = Type() + let caps = acct.capabilities.storage.forEachController(forPath: storagePath, fun(c: &StorageCapabilityController): Bool { + if providerSubtype.isSubtype(of: c.borrowType) { + foundProvider = true + } + return true + }) + + if foundProvider { + return + } + + let cap = acct.capabilities.storage.issue(storagePath) + assert(cap.check(), message: "unable to issue provider capability") } } \ No newline at end of file diff --git a/transactions/example-token/setup_account_ft.cdc b/transactions/example-token/setup_account_ft.cdc index a11b056..ff04063 100644 --- a/transactions/example-token/setup_account_ft.cdc +++ b/transactions/example-token/setup_account_ft.cdc @@ -6,31 +6,21 @@ import "LostAndFound" transaction { - prepare(signer: AuthAccount) { + prepare(signer: auth(Storage, Capabilities) &Account) { // Return early if the account already stores a ExampleToken Vault - if signer.borrow<&ExampleToken.Vault>(from: /storage/exampleTokenVault) != nil { + if signer.storage.borrow<&ExampleToken.Vault>(from: /storage/exampleTokenVault) != nil { return } // Create a new ExampleToken Vault and put it in storage - signer.save( + signer.storage.save( <-ExampleToken.createEmptyVault(), to: /storage/exampleTokenVault ) - // Create a public capability to the Vault that only exposes - // the deposit function through the Receiver interface - signer.link<&ExampleToken.Vault{FungibleToken.Receiver}>( - /public/exampleTokenReceiver, - target: /storage/exampleTokenVault - ) - - // Create a public capability to the Vault that only exposes - // the balance field through the Balance interface - signer.link<&ExampleToken.Vault{FungibleToken.Balance}>( - /public/exampleTokenBalance, - target: /storage/exampleTokenVault - ) + let cap = signer.capabilities.storage.issue<&ExampleToken.Vault>(/storage/exampleTokenVault) + signer.capabilities.publish(cap, at: /public/exampleTokenReceiver) + signer.capabilities.publish(cap, at: /public/exampleTokenBalance) } } \ No newline at end of file diff --git a/transactions/example-token/try_send_example_token.cdc b/transactions/example-token/try_send_example_token.cdc index ade1fd4..91a8669 100644 --- a/transactions/example-token/try_send_example_token.cdc +++ b/transactions/example-token/try_send_example_token.cdc @@ -4,46 +4,60 @@ import "ExampleToken" import "LostAndFound" -transaction(recipient: Address, amount: UFix64) { +transaction(recipient: Address, amount: UFix64, revoke: Bool) { let tokenAdmin: &ExampleToken.Administrator - let flowProvider: Capability<&FlowToken.Vault{FungibleToken.Provider}> - let flowReceiver: Capability<&FlowToken.Vault{FungibleToken.Receiver}> + let flowProvider: Capability + let flowReceiver: Capability<&FlowToken.Vault> + let receiverCap: Capability<&{FungibleToken.Vault}> - prepare(acct: AuthAccount) { - self.tokenAdmin = acct.borrow<&ExampleToken.Administrator>(from: /storage/exampleTokenAdmin) + prepare(sender: auth(Storage, Capabilities) &Account, receiver: auth(Storage, Capabilities) &Account) { + let v <- ExampleToken.createEmptyVault() + let publicPath = v.getDefaultPublicPath()! + let receiverPath = v.getDefaultReceiverPath()! + let storagePath = v.getDefaultStoragePath()! + destroy v + + self.tokenAdmin = sender.storage.borrow<&ExampleToken.Administrator>(from: /storage/exampleTokenAdmin) ?? panic("acct is not the token admin") - let flowTokenProviderPath = /private/flowTokenLostAndFoundProviderPath + var provider: Capability? = nil + sender.capabilities.storage.forEachController(forPath: /storage/flowTokenVault, fun(c: &StorageCapabilityController): Bool { + if c.borrowType == Type() { + provider = c.capability as! Capability + } + + return true + }) - if !acct.getCapability<&FlowToken.Vault{FungibleToken.Provider}>(flowTokenProviderPath).check() { - acct.unlink(flowTokenProviderPath) - acct.link<&FlowToken.Vault{FungibleToken.Provider}>( - flowTokenProviderPath, - target: /storage/flowTokenVault - ) + if provider == nil { + provider = sender.capabilities.storage.issue(/storage/flowTokenVault) } - self.flowProvider = acct.getCapability<&FlowToken.Vault{FungibleToken.Provider}>(flowTokenProviderPath) - self.flowReceiver = acct.getCapability<&FlowToken.Vault{FungibleToken.Receiver}>(/public/flowTokenReceiver) + self.flowProvider = provider! + self.flowReceiver = sender.capabilities.get<&FlowToken.Vault>(/public/flowTokenReceiver)! + + self.receiverCap = receiver.capabilities.storage.issue<&{FungibleToken.Vault}>(storagePath) + + if revoke { + receiver.capabilities.storage.getController(byCapabilityID: self.receiverCap.id)!.delete() + } } execute { - let minter <- self.tokenAdmin.createNewMinter(allowedAmount: amount) let mintedVault <- minter.mintTokens(amount: amount) let memo = "test memo" let depositEstimate <- LostAndFound.estimateDeposit(redeemer: recipient, item: <-mintedVault, memo: memo, display: nil) let storageFee <- self.flowProvider.borrow()!.withdraw(amount: depositEstimate.storageFee) - let resource <- depositEstimate.withdraw() - let exampleTokenReceiver = getAccount(recipient).getCapability<&{FungibleToken.Receiver}>(/public/exampleTokenReceiver) + let item <- depositEstimate.withdraw() LostAndFound.trySendResource( - resource: <-resource, - cap: exampleTokenReceiver, + item: <-item, + cap: self.receiverCap, memo: nil, display: nil, - storagePayment: &storageFee as &FungibleToken.Vault, + storagePayment: &storageFee as auth(FungibleToken.Withdraw) &{FungibleToken.Vault}, flowTokenRepayment: self.flowReceiver ) diff --git a/transactions/example-token/try_send_example_token_depositor.cdc b/transactions/example-token/try_send_example_token_depositor.cdc index 00e0ca6..3da5819 100644 --- a/transactions/example-token/try_send_example_token_depositor.cdc +++ b/transactions/example-token/try_send_example_token_depositor.cdc @@ -4,25 +4,37 @@ import "ExampleToken" import "LostAndFound" -transaction(recipient: Address, amount: UFix64) { +transaction(recipient: Address, amount: UFix64, revoke: Bool) { let tokenAdmin: &ExampleToken.Administrator - let depositor: &LostAndFound.Depositor + let depositor: auth(LostAndFound.Deposit) &LostAndFound.Depositor + let receiverCap: Capability<&{FungibleToken.Vault}> - prepare(acct: AuthAccount) { - self.tokenAdmin = acct.borrow<&ExampleToken.Administrator>(from: /storage/exampleTokenAdmin) + prepare(sender: auth(Storage, Capabilities) &Account, receiver: auth(Storage, Capabilities) &Account) { + let v <- ExampleToken.createEmptyVault() + let publicPath = v.getDefaultPublicPath()! + let receiverPath = v.getDefaultReceiverPath()! + let storagePath = v.getDefaultStoragePath()! + destroy v + + self.tokenAdmin = sender.storage.borrow<&ExampleToken.Administrator>(from: /storage/exampleTokenAdmin) ?? panic("acct is not the token admin") - self.depositor = acct.borrow<&LostAndFound.Depositor>(from: LostAndFound.DepositorStoragePath)! + self.depositor = sender.storage.borrow(from: LostAndFound.DepositorStoragePath)! + + self.receiverCap = receiver.capabilities.storage.issue<&{FungibleToken.Vault}>(storagePath) + + if revoke { + receiver.capabilities.storage.getController(byCapabilityID: self.receiverCap.id)!.delete() + } } execute { let minter <- self.tokenAdmin.createNewMinter(allowedAmount: amount) let mintedVault <- minter.mintTokens(amount: amount) let memo = "test memo" - let exampleTokenReceiver = getAccount(recipient).getCapability<&{FungibleToken.Receiver}>(/public/exampleTokenReceiver) self.depositor.trySendResource( item: <-mintedVault, - cap: exampleTokenReceiver, + cap: self.receiverCap, memo: nil, display: nil ) diff --git a/transactions/flow/mint_flow.cdc b/transactions/flow/mint_flow.cdc index a2c26cf..7210ed6 100644 --- a/transactions/flow/mint_flow.cdc +++ b/transactions/flow/mint_flow.cdc @@ -2,14 +2,14 @@ import "FungibleToken" import "FlowToken" transaction(receiver: Address, amount: UFix64) { - prepare(account: AuthAccount) { - let flowVault = account.borrow<&FlowToken.Vault>( + prepare(account: auth(Storage) &Account) { + let flowVault = account.storage.borrow( from: /storage/flowTokenVault ) ?? panic("Could not borrow BlpToken.Vault reference") let receiverRef = getAccount(receiver) - .getCapability(/public/flowTokenReceiver) - .borrow<&FlowToken.Vault{FungibleToken.Receiver}>() + .capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver)! + .borrow() ?? panic("Could not borrow FungibleToken.Receiver reference") let tokens <- flowVault.withdraw(amount: amount)