Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add example transaction transferring child NFTs from parent account #177

Merged
merged 6 commits into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion scripts/test/test_get_all_collection_data_from_storage.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ access(all) fun getAllViewsFromAddress(_ address: Address): [MetadataViews.NFTCo
// Iterate over each public path
account.storage.forEachStored(fun (path: StoragePath, type: Type): Bool {
// Return if not the type we're looking for
if !type.isInstance(collectionType) && !type.isSubtype(of: collectionType) {
if type.isRecovered || (!type.isInstance(collectionType) && !type.isSubtype(of: collectionType)) {
return true
}
if let collectionRef = account.storage
Expand Down
31 changes: 31 additions & 0 deletions test/HybridCustody_tests.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,37 @@ fun testSendChildFtsWithParentSigner() {
Test.assert(recipientBalanceAfter == amount, message: "recipient balance should be".concat(amount.toString()))
}

access(all)
fun testSendChildNFTsWithParentSigner() {
let parent = Test.createAccount()
let child = Test.createAccount()
let recipient = Test.createAccount()

setupChildAndParent_FilterKindAll(child: child, parent: parent)

let mintAmount: UFix64 = 100.0
let amount: UFix64 = 10.0
setupNFTCollection(child)
setupNFTCollection(recipient)

mintNFTDefault(accounts[exampleNFT]!, receiver: child)
mintNFTDefault(accounts[exampleNFT]!, receiver: child)

let childIDs = (scriptExecutor("example-nft/get_ids.cdc", [child.address]) as! [UInt64]?)!
Test.assert(childIDs.length == 2, message: "no NFTs found in child account after minting")

let recipientIDs = (scriptExecutor("example-nft/get_ids.cdc", [recipient.address]) as! [UInt64]?)!
Test.assert(recipientIDs.length == 0, message: "NFTs found in recipient account without minting")

txExecutor("hybrid-custody/send_child_nfts_with_parent.cdc", [parent], [childIDs, recipient.address, child.address], nil)

let childIDsAfter = (scriptExecutor("example-nft/get_ids.cdc", [child.address]) as! [UInt64]?)!
Test.assert(childIDsAfter.length == 0, message: "NFTs found in child account after transfer - collection should be empty")

let recipientIDsAfter = (scriptExecutor("example-nft/get_ids.cdc", [recipient.address]) as! [UInt64]?)!
Test.assert(recipientIDsAfter.length == 2, message: "recipient should have received 2 NFTs from child")
}

access(all)
fun testAddExampleTokenToBalance() {
let child = Test.createAccount()
Expand Down
53 changes: 53 additions & 0 deletions transactions/hybrid-custody/send_child_nfts_with_parent.cdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import "NonFungibleToken"
import "MetadataViews"
import "ExampleNFT"

import "HybridCustody"
import "FungibleTokenMetadataViews"

transaction(ids: [UInt64], to: Address, child: Address) {

// reference to the child account's Collection Provider that holds the NFT being transferred
let provider: auth(NonFungibleToken.Withdraw) &{NonFungibleToken.Provider}
let collectionData: MetadataViews.NFTCollectionData

// signer is the parent account
prepare(signer: auth(Storage) &Account) {
// get the manager resource and borrow childAccount
let m = signer.storage.borrow<auth(HybridCustody.Manage) &HybridCustody.Manager>(from: HybridCustody.ManagerStoragePath)
?? panic("manager does not exist")
let childAcct = m.borrowAccount(addr: child) ?? panic("child account not found")

self.collectionData = ExampleNFT.resolveContractView(resourceType: nil, viewType: Type<MetadataViews.NFTCollectionData>()) as! MetadataViews.NFTCollectionData?
?? panic("Could not get the vault data view for ExampleNFT")
sisyphusSmiling marked this conversation as resolved.
Show resolved Hide resolved

// get Provider capability from child account
let capType = Type<auth(NonFungibleToken.Withdraw) &{NonFungibleToken.Provider}>()
let controllerID = childAcct.getControllerIDForType(type: capType, forPath: self.collectionData.storagePath)
?? panic("no controller found for capType")

let cap = childAcct.getCapability(controllerID: controllerID, type: capType) ?? panic("no cap found")
let providerCap = cap as! Capability<auth(NonFungibleToken.Withdraw) &{NonFungibleToken.Provider}>
assert(providerCap.check(), message: "invalid provider capability")

// get a reference to the child's stored NFT Collection Provider
self.provider = providerCap.borrow()!
}

execute {
// get the recipient's public account object
let recipient = getAccount(to)

// get a reference to the recipient's NFT Receiver
let receiverRef = recipient.capabilities.borrow<&{NonFungibleToken.Receiver}>(self.collectionData.publicPath)
?? panic("Could not borrow receiver reference to the recipient's Vault")
sisyphusSmiling marked this conversation as resolved.
Show resolved Hide resolved

for id in ids {
// withdraw the NFT from the child account's collection & deposit to the recipient's Receiver
receiverRef.deposit(
token: <-self.provider.withdraw(withdrawID: id)
)
}
}
}

Loading