diff --git a/README.md b/README.md index aeea29b..58173ba 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # NFL Smart Contracts ## NFL Contract Addresses -| Testnet | TBC | -| Mainnet | TBC | +| Testnet | e4cf4bdc1751c65d | [Flow View Source](https://flow-view-source.com/mainnet/account/0xe4cf4bdc1751c65d) +| Mainnet | 4dfd62c88d1b6462 | [Flow View Source](https://flow-view-source.com/testnet/account/0x4dfd62c88d1b6462) ## Entities diff --git a/contracts/AllDayShardedCollection.cdc b/contracts/AllDayShardedCollection.cdc deleted file mode 100644 index a7b0f4a..0000000 --- a/contracts/AllDayShardedCollection.cdc +++ /dev/null @@ -1,173 +0,0 @@ -/* - Description: Central Collection for a large number of Moment NFTs - - Adapted from: GeniesShardedCollection.cdc - Authors: Joshua Hannan joshua.hannan@dapperlabs.com - Bastian Muller bastian@dapperlabs.com - Rhea Myers rhea.myers@dapperlabs.com - - [...] - - When Cadence is updated to allow larger dictionaries, - then this contract can be retired. -*/ - -import NonFungibleToken from "./NonFungibleToken.cdc" -import AllDay from "./AllDay.cdc" - -pub contract AllDayShardedCollection { - // Named Paths - // - pub let CollectionStoragePath: StoragePath - - // ShardedCollection stores a dictionary of AllDay Collections - // A AllDay NFT is stored in the field that corresponds to its id % numBuckets - pub resource ShardedCollection: - AllDay.MomentNFTCollectionPublic, - NonFungibleToken.Provider, - NonFungibleToken.Receiver, - NonFungibleToken.CollectionPublic - { - // Dictionary of AllDay collections - pub var collections: @{UInt64: AllDay.Collection} - - // The number of buckets to split AllDay NFTs into - // This makes storage more efficient and performant - pub let numBuckets: UInt64 - - init(numBuckets: UInt64) { - self.collections <- {} - self.numBuckets = numBuckets - - // Create a new empty collection for each bucket - var i: UInt64 = 0 - while i < numBuckets { - - self.collections[i] <-! AllDay.createEmptyCollection() as! @AllDay.Collection - - i = i + (1 as UInt64) - } - } - - // withdraw removes a AllDay NFT from one of the Collections - // and moves it to the caller - pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT { - post { - result.id == withdrawID: "The ID of the withdrawn NFT is incorrect" - } - // Find the bucket it should be withdrawn from - let bucket = withdrawID % self.numBuckets - - // Withdraw the AllDay NFT - let token <- self.collections[bucket]?.withdraw(withdrawID: withdrawID)! - - return <-token - } - - // batchWithdraw withdraws multiple tokens and returns them as a Collection - // - // Parameters: ids: an array of the IDs to be withdrawn from the Collection - // - // Returns: @NonFungibleToken.Collection a Collection containing the AllDay NFTs - // that were withdrawn - pub fun batchWithdraw(ids: [UInt64]): @NonFungibleToken.Collection { - var batchCollection <- AllDay.createEmptyCollection() - - // Iterate through the ids and withdraw them from the Collection - for id in ids { - batchCollection.deposit(token: <-self.withdraw(withdrawID: id)) - } - return <-batchCollection - } - - // deposit takes a AllDay NFT and adds it to the Collections dictionary - pub fun deposit(token: @NonFungibleToken.NFT) { - - // Find the bucket this corresponds to - let bucket = token.id % self.numBuckets - - // Remove the collection - let collection <- self.collections.remove(key: bucket)! - - // Deposit the nft into the bucket - collection.deposit(token: <-token) - - // Put the Collection back in storage - self.collections[bucket] <-! collection - } - - // batchDeposit takes a Collection object as an argument - // and deposits each contained NFT into this Collection - pub fun batchDeposit(tokens: @NonFungibleToken.Collection) { - let keys = tokens.getIDs() - - // Iterate through the keys in the Collection and deposit each one - for key in keys { - self.deposit(token: <-tokens.withdraw(withdrawID: key)) - } - destroy tokens - } - - // getIDs returns an array of the IDs that are in the Collection - pub fun getIDs(): [UInt64] { - - var ids: [UInt64] = [] - // Concatenate IDs in all the Collections - for key in self.collections.keys { - for id in self.collections[key]?.getIDs() ?? [] { - ids.append(id) - } - } - return ids - } - - // borrowNFT Returns a borrowed reference to a AllDay NFT in the Collection - // so that the caller can read data and call methods from it - pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT { - post { - result.id == id: "The ID of the reference is incorrect" - } - - // Get the bucket of the nft to be borrowed - let bucket = id % self.numBuckets - - // Find NFT in the collections and borrow a reference - return self.collections[bucket]?.borrowNFT(id: id)! - } - - // borrowMomentNFT Returns a borrowed reference to a AllDay NFT in the Collection - // so that the caller can read data and call methods from it - // They can use this to read its setID, playID, serialNumber, - // or any of the setData or Play Data associated with it by - // getting the setID or playID and reading those fields from - // the smart contract - // - // Parameters: id: The ID of the NFT to get the reference for - // - // Returns: A reference to the NFT - pub fun borrowMomentNFT(id: UInt64): &AllDay.NFT? { - - // Get the bucket of the nft to be borrowed - let bucket = id % self.numBuckets - - return self.collections[bucket]?.borrowMomentNFT(id: id) ?? nil - } - - // If a transaction destroys the Collection object, - // All the NFTs contained within are also destroyed - destroy() { - destroy self.collections - } - } - - // Creates an empty ShardedCollection and returns it to the caller - pub fun createEmptyCollection(numBuckets: UInt64): @ShardedCollection { - return <-create ShardedCollection(numBuckets: numBuckets) - } - - init() { - // Set the named paths - self.CollectionStoragePath = /storage/AllDayShardedNFTCollection - } -} - \ No newline at end of file diff --git a/lib/go/test/allday_test.go b/lib/go/test/allday_test.go index 1f59c5d..39f3945 100644 --- a/lib/go/test/allday_test.go +++ b/lib/go/test/allday_test.go @@ -538,115 +538,3 @@ func testMintMomentNFT( assert.Equal(t, previousSupply, newSupply) } } - -//------------------------------------------------------------ -// ShardedCollection -// ------------------------------------------------------------ -func TestShardedCollection(t *testing.T) { - b := newEmulator() - - contracts := AllDayDeployContracts(t, b) - // Set up for NFT Minting - createTestEditions(t, b, contracts) - user1Address, user1Signer := createAccount(t, b) - user2Address, user2Signer := createAccount(t, b) - numMomentNFTs := uint64(20) - - t.Run("Creating a sharded collection should work", func(t *testing.T) { - setupShardedCollection( - t, - b, - contracts, - user1Address, - user1Signer, - uint64(75), - false, - ) - }) - - t.Run("Creating a sharded collection twice for the same address should not work", func(t *testing.T) { - setupShardedCollection( - t, - b, - contracts, - user1Address, - user1Signer, - uint64(75), - true, - ) - }) - - t.Run("Minting to a sharded collection should work", func(t *testing.T) { - numMomentNFTsAlready := getMomentNFTSupply(t, b, contracts) - for i := uint64(1); i < numMomentNFTs; i++ { - testMintMomentNFT( - t, - b, - contracts, - uint64(2), - user1Address, - uint64(numMomentNFTsAlready+i), - uint64(numMomentNFTsAlready+i), - false, - ) - } - }) - - t.Run("Transferring from a sharded collection to a collection should work", func(t *testing.T) { - setupAllDay(t, b, user2Address, user2Signer, contracts) - // Transfer the first 10 moments from ShardedCollection to Collection - for i := uint64(1); i <= 10; i++ { - transferMomentNFTFromShardedCollection( - t, - b, - contracts, - user1Address, - user1Signer, - i, - user2Address, - false, - ) - } - }) - - t.Run("Batch transferring from a sharded collection to a collection should work", func(t *testing.T) { - user2Address, user2Signer := createAccount(t, b) - setupAllDay(t, b, user2Address, user2Signer, contracts) - - // Make the list of IDs to transfer - nftIDs := []uint64{} - for i := uint64(11); i < 20; i++ { - nftIDs = append(nftIDs, i) - } - // Transfer the next 10 moments from ShardedCollection to Collection - batchTransferMomentNFTsFromShardedCollection( - t, - b, - contracts, - user1Address, - user1Signer, - nftIDs, - user2Address, - false, - ) - }) - - t.Run("Transferring from a collection to a collection should work", func(t *testing.T) { - user3Address, user3Signer := createAccount(t, b) - setupAllDay(t, b, user3Address, user3Signer, contracts) - - // Transfer the first 10 moments from Collection to Collection - for i := uint64(1); i <= 10; i++ { - transferMomentNFT( - t, - b, - contracts, - user2Address, - user2Signer, - i, - user3Address, - false, - ) - } - }) -} diff --git a/lib/go/test/templates.go b/lib/go/test/templates.go index 9278b65..842cbb8 100644 --- a/lib/go/test/templates.go +++ b/lib/go/test/templates.go @@ -9,9 +9,8 @@ import ( // Handle relative paths by making these regular expressions const ( - nftAddressPlaceholder = "\"[^\"]*NonFungibleToken.cdc\"" - AllDayAddressPlaceholder = "\"[^\"]*AllDay.cdc\"" - AllDayShardedCollectionAddressPlaceholder = "\"[^\"]*AllDayShardedCollection.cdc\"" + nftAddressPlaceholder = "\"[^\"]*NonFungibleToken.cdc\"" + AllDayAddressPlaceholder = "\"[^\"]*AllDay.cdc\"" ) const ( @@ -23,12 +22,6 @@ const ( AllDaySetupAccountPath = AllDayTransactionsRootPath + "/user/setup_AllDay_account.cdc" AllDayAccountIsSetupPath = AllDayScriptsRootPath + "/user/account_is_setup.cdc" - // ShardedCollection - AllDayShardedCollectionPath = "../../../contracts/AllDayShardedCollection.cdc" - AllDaySetupShardedCollectionPath = AllDayTransactionsRootPath + "/admin/sharded_collection/setup_sharded_collection.cdc" - AllDayTransferMomentNFTFromShardedCollectionPath = AllDayTransactionsRootPath + "/admin/sharded_collection/transfer_AllDay_nft_from_sharded_collection.cdc" - AllDayBatchTransferMomentNFTsFromShardedCollectionPath = AllDayTransactionsRootPath + "/admin/sharded_collection/batch_transfer_AllDay_nfts_from_sharded_collection.cdc" - // Series AllDayCreateSeriesPath = AllDayTransactionsRootPath + "/admin/series/create_series.cdc" AllDayCloseSeriesPath = AllDayTransactionsRootPath + "/admin/series/close_series.cdc" @@ -75,9 +68,6 @@ func replaceAddresses(code []byte, contracts Contracts) []byte { AllDayRe := regexp.MustCompile(AllDayAddressPlaceholder) code = AllDayRe.ReplaceAll(code, []byte("0x"+contracts.AllDayAddress.String())) - AllDayShardedCollectionRe := regexp.MustCompile(AllDayShardedCollectionAddressPlaceholder) - code = AllDayShardedCollectionRe.ReplaceAll(code, []byte("0x"+contracts.AllDayShardedCollectionAddress.String())) - return code } @@ -104,42 +94,6 @@ func loadAllDayAccountIsSetupScript(contracts Contracts) []byte { ) } -//------------------------------------------------------------ -// Sharded Collection -//------------------------------------------------------------ -func loadAllDayShardedCollection(nftAddress flow.Address, AllDayAddress flow.Address) []byte { - code := readFile(AllDayShardedCollectionPath) - - nftRe := regexp.MustCompile(nftAddressPlaceholder) - code = nftRe.ReplaceAll(code, []byte("0x"+nftAddress.String())) - - AllDayRe := regexp.MustCompile(AllDayAddressPlaceholder) - code = AllDayRe.ReplaceAll(code, []byte("0x"+AllDayAddress.String())) - - return code -} - -func loadAllDaySetupShardedCollectionTransaction(contracts Contracts) []byte { - return replaceAddresses( - readFile(AllDaySetupShardedCollectionPath), - contracts, - ) -} - -func loadAllDayTransferMomentNFTFromShardedCollectionTransaction(contracts Contracts) []byte { - return replaceAddresses( - readFile(AllDayTransferMomentNFTFromShardedCollectionPath), - contracts, - ) -} - -func loadAllDayBatchTransferMomentNFTsFromShardedCollectionTransaction(contracts Contracts) []byte { - return replaceAddresses( - readFile(AllDayBatchTransferMomentNFTsFromShardedCollectionPath), - contracts, - ) -} - //------------------------------------------------------------ // Series //------------------------------------------------------------ diff --git a/lib/go/test/test.go b/lib/go/test/test.go index abda22b..04b830a 100644 --- a/lib/go/test/test.go +++ b/lib/go/test/test.go @@ -29,10 +29,9 @@ var ( ) type Contracts struct { - NFTAddress flow.Address - AllDayAddress flow.Address - AllDaySigner crypto.Signer - AllDayShardedCollectionAddress flow.Address + NFTAddress flow.Address + AllDayAddress flow.Address + AllDaySigner crypto.Signer } func deployNFTContract(t *testing.T, b *emulator.Blockchain) flow.Address { @@ -92,45 +91,10 @@ func AllDayDeployContracts(t *testing.T, b *emulator.Blockchain) Contracts { _, err = b.CommitBlock() require.NoError(t, err) - AllDayShardedCollectionAccountKey, AllDayShardedCollectionSigner := accountKeys.NewWithSigner() - AllDayShardedCollectionCode := loadAllDayShardedCollection(nftAddress, AllDayAddress) - - AllDayShardedCollectionAddress, err := b.CreateAccount( - []*flow.AccountKey{AllDayShardedCollectionAccountKey}, - nil, - ) - require.NoError(t, err) - - fundAccount(t, b, AllDayShardedCollectionAddress, defaultAccountFunding) - - tx2 := sdktemplates.AddAccountContract( - AllDayShardedCollectionAddress, - sdktemplates.Contract{ - Name: "AllDayShardedCollection", - Source: string(AllDayShardedCollectionCode), - }, - ) - - tx2. - SetGasLimit(100). - SetProposalKey(b.ServiceKey().Address, b.ServiceKey().Index, b.ServiceKey().SequenceNumber). - SetPayer(b.ServiceKey().Address) - - signAndSubmit( - t, b, tx2, - []flow.Address{b.ServiceKey().Address, AllDayShardedCollectionAddress}, - []crypto.Signer{b.ServiceKey().Signer(), AllDayShardedCollectionSigner}, - false, - ) - - _, err = b.CommitBlock() - require.NoError(t, err) - return Contracts{ nftAddress, AllDayAddress, AllDaySigner, - AllDayShardedCollectionAddress, } } diff --git a/lib/go/test/transactions.go b/lib/go/test/transactions.go index 01268d5..cb1c4c2 100644 --- a/lib/go/test/transactions.go +++ b/lib/go/test/transactions.go @@ -43,105 +43,6 @@ func fundAccount( ) } -/* - NOTE: This requires extra storage, and higher gas. -*/ - -func setupShardedCollection( - t *testing.T, - b *emulator.Blockchain, - contracts Contracts, - recipientAddress flow.Address, - recipientSigner crypto.Signer, - numberOfBuckets uint64, - shouldRevert bool, -) { - // We need additional storage to hold the shards - fundAccount( - t, - b, - recipientAddress, - "0.01", - ) - - tx := flow.NewTransaction(). - SetScript(loadAllDaySetupShardedCollectionTransaction(contracts)). - SetGasLimit(800). - SetProposalKey(b.ServiceKey().Address, b.ServiceKey().Index, b.ServiceKey().SequenceNumber). - SetPayer(b.ServiceKey().Address). - AddAuthorizer(recipientAddress) - tx.AddArgument(cadence.NewUInt64(numberOfBuckets)) - - signAndSubmit( - t, b, tx, - []flow.Address{b.ServiceKey().Address, recipientAddress}, - []crypto.Signer{b.ServiceKey().Signer(), recipientSigner}, - shouldRevert, - ) -} - -func transferMomentNFTFromShardedCollection( - t *testing.T, - b *emulator.Blockchain, - contracts Contracts, - senderAddress flow.Address, - senderSigner crypto.Signer, - nftID uint64, - recipientAddress flow.Address, - shouldRevert bool, -) { - tx := flow.NewTransaction(). - SetScript(loadAllDayTransferMomentNFTFromShardedCollectionTransaction(contracts)). - SetGasLimit(100). - SetProposalKey(b.ServiceKey().Address, b.ServiceKey().Index, b.ServiceKey().SequenceNumber). - SetPayer(b.ServiceKey().Address). - AddAuthorizer(senderAddress) - tx.AddArgument(cadence.BytesToAddress(recipientAddress.Bytes())) - tx.AddArgument(cadence.NewUInt64(nftID)) - - signAndSubmit( - t, b, tx, - []flow.Address{b.ServiceKey().Address, senderAddress}, - []crypto.Signer{b.ServiceKey().Signer(), senderSigner}, - shouldRevert, - ) -} - -/* - NOTE: This requires higher gas. -*/ - -func batchTransferMomentNFTsFromShardedCollection( - t *testing.T, - b *emulator.Blockchain, - contracts Contracts, - senderAddress flow.Address, - senderSigner crypto.Signer, - nftIDs []uint64, - recipientAddress flow.Address, - shouldRevert bool, -) { - cadenceIDs := make([]cadence.Value, len(nftIDs)) - for i, id := range nftIDs { - cadenceIDs[i] = cadence.NewUInt64(id) - } - tx := flow.NewTransaction(). - SetScript(loadAllDayBatchTransferMomentNFTsFromShardedCollectionTransaction(contracts)). - SetGasLimit(uint64(100+(50*len(nftIDs)))). - SetProposalKey(b.ServiceKey().Address, b.ServiceKey().Index, b.ServiceKey().SequenceNumber). - SetPayer(b.ServiceKey().Address). - AddAuthorizer(senderAddress) - tx.AddArgument(cadence.BytesToAddress(recipientAddress.Bytes())) - tx.AddArgument(cadence.NewArray(cadenceIDs)) - - signAndSubmit( - t, b, tx, - []flow.Address{b.ServiceKey().Address, senderAddress}, - []crypto.Signer{b.ServiceKey().Signer(), senderSigner}, - shouldRevert, - ) -} - //------------------------------------------------------------ // Series //------------------------------------------------------------ diff --git a/transactions/admin/sharded_collection/batch_transfer_allday_nfts_from_sharded_collection.cdc b/transactions/admin/sharded_collection/batch_transfer_allday_nfts_from_sharded_collection.cdc deleted file mode 100644 index ffcf2f2..0000000 --- a/transactions/admin/sharded_collection/batch_transfer_allday_nfts_from_sharded_collection.cdc +++ /dev/null @@ -1,37 +0,0 @@ -import NonFungibleToken from "../../../contracts/NonFungibleToken.cdc" -import AllDay from "../../../contracts/AllDay.cdc" -import AllDayShardedCollection from "../../../contracts/AllDayShardedCollection.cdc" - -// This transaction deposits a number of NFTs to a recipient - -// Parameters -// -// recipient: the Flow address who will receive the NFTs -// momentNFTIDs: an array of momentNFT IDs of NFTs that recipient will receive - -transaction(recipient: Address, momentNFTIDs: [UInt64]) { - - let transferTokens: @NonFungibleToken.Collection - - prepare(acct: AuthAccount) { - - self.transferTokens <- acct.borrow<&AllDayShardedCollection.ShardedCollection>( - from: AllDayShardedCollection.CollectionStoragePath - )! - .batchWithdraw(ids: momentNFTIDs) - } - - execute { - - // get the recipient's public account object - let recipient = getAccount(recipient) - - // get the Collection reference for the receiver - let receiverRef = recipient.getCapability(AllDay.CollectionPublicPath) - .borrow<&{AllDay.MomentNFTCollectionPublic}>()! - - // deposit the NFT in the receivers collection - receiverRef.batchDeposit(tokens: <-self.transferTokens) - } -} - diff --git a/transactions/admin/sharded_collection/setup_sharded_collection.cdc b/transactions/admin/sharded_collection/setup_sharded_collection.cdc deleted file mode 100644 index 4e1ff11..0000000 --- a/transactions/admin/sharded_collection/setup_sharded_collection.cdc +++ /dev/null @@ -1,35 +0,0 @@ -import NonFungibleToken from "../../../contracts/NonFungibleToken.cdc" -import AllDay from "../../../contracts/AllDay.cdc" -import AllDayShardedCollection from "../../../contracts/AllDayShardedCollection.cdc" - -// This transaction creates and stores an empty NFT collection -// and creates a public capability for it. -// NFTs are split into a number of buckets -// This makes storage more efficient and performant - -// Parameters -// -// numBuckets: The number of buckets to split NFTs into - -transaction(numBuckets: UInt64) { - - prepare(acct: AuthAccount) { - - if acct.borrow<&AllDayShardedCollection.ShardedCollection>(from: AllDayShardedCollection.CollectionStoragePath) == nil { - - let collection <- AllDayShardedCollection.createEmptyCollection(numBuckets: numBuckets) - // Put a new Collection in storage - acct.save(<-collection, to: AllDayShardedCollection.CollectionStoragePath) - - // create a public capability for the collection - if acct.link<&{AllDay.MomentNFTCollectionPublic}>(AllDay.CollectionPublicPath, target: AllDayShardedCollection.CollectionStoragePath) == nil { - acct.unlink(AllDay.CollectionPublicPath) - } - - acct.link<&{AllDay.MomentNFTCollectionPublic}>(AllDay.CollectionPublicPath, target: AllDayShardedCollection.CollectionStoragePath) - } else { - panic("Sharded Collection already exists!") - } - } -} - diff --git a/transactions/admin/sharded_collection/transfer_allday_nft_from_sharded_collection.cdc b/transactions/admin/sharded_collection/transfer_allday_nft_from_sharded_collection.cdc deleted file mode 100644 index 8823454..0000000 --- a/transactions/admin/sharded_collection/transfer_allday_nft_from_sharded_collection.cdc +++ /dev/null @@ -1,37 +0,0 @@ -import NonFungibleToken from "../../../contracts/NonFungibleToken.cdc" -import AllDay from "../../../contracts/AllDay.cdc" -import AllDayShardedCollection from "../../../contracts/AllDayShardedCollection.cdc" - -// This transaction deposits an NFT to a recipient - -// Parameters -// -// recipient: the Flow address who will receive the NFT -// momentID: moment ID of NFT that recipient will receive - -transaction(recipient: Address, momentID: UInt64) { - - let transferToken: @NonFungibleToken.NFT - - prepare(acct: AuthAccount) { - - self.transferToken <- acct.borrow<&AllDayShardedCollection.ShardedCollection>( - from: AllDayShardedCollection.CollectionStoragePath - )! - .withdraw(withdrawID: momentID) - } - - execute { - - // get the recipient's public account object - let recipient = getAccount(recipient) - - // get the Collection reference for the receiver - let receiverRef = recipient.getCapability(AllDay.CollectionPublicPath) - .borrow<&{AllDay.MomentNFTCollectionPublic}>()! - - // deposit the NFT in the receivers collection - receiverRef.deposit(token: <-self.transferToken) - } -} -