Git Product home page Git Product logo

nba-smart-contracts's Introduction

NBA Top Shot

Introduction

This repository contains the smart contracts and transactions that implement the core functionality of NBA Top Shot.

The smart contracts are written in Cadence, a new resource oriented smart contract programming language designed for the Flow Blockchain.

What is NBA Top Shot

NBA Top Shot is the official digital collectibles game for the National Basketball Association. Players collect and trade digital collectibles that represent highlights from the best players in the world. See more at nbatopshot.com

What is Flow?

Flow is a new blockchain for open worlds. Read more about it here.

What is Cadence?

Cadence is a new Resource-oriented programming language for developing smart contracts for the Flow Blockchain. Read more about it here

We recommend that anyone who is reading this should have already completed the Cadence Tutorials so they can build a basic understanding of the programming language.

Resource-oriented programming, and by extension Cadence, is the perfect programming environment for Non-Fungible Tokens (NFTs), because users are able to store their NFT objects directly in their accounts and transact peer-to-peer. Please see the blog post about resources to understand why they are perfect for digital assets like NBA Top Shot Moments.

Contributing

If you see an issue with the code for the contracts, the transactions, scripts, documentation, or anything else, please do not hesitate to make an issue or a pull request with your desired changes. This is an open source project and we welcome all assistance from the community!

Top Shot Contract Addresses

TopShot.cdc: This is the main Top Shot smart contract that defines the core functionality of the NFT.

Network Contract Address
Testnet 0x877931736ee77cff
Mainnet 0x0b2a3299cc857e29

MarketTopShot.cdc: This is the top shot marketplace contract that allows users to buy and sell their NFTs.

Network Contract Address
Testnet 0x547f177b243b4d80
Mainnet 0xc1e4f4f4c4257510

Non Fungible Token Standard

The NBA Top Shot contracts utilize the Flow NFT standard which is equivalent to ERC-721 or ERC-1155 on Ethereum. If you want to build an NFT contract, please familiarize yourself with the Flow NFT standard before starting and make sure you utilize it in your project in order to be interoperable with other tokens and contracts that implement the standard.

Top Shot Marketplace contract

The top shot marketplace contract was designed in the very early days of Cadence, and therefore uses some language features that are NOT RECOMMENDED to use by newer projects. For example, the marketplace contract stores the moments that are for sale in the sale collection. The correct way to manage this in cadence is to give a collection capability to the market collection so that the nfts do not have to leave the main collection when going up for sale. The sale collection would use this capability to withdraw moments from the main collection when they are purchased.

This way, any other smart contracts that need to check a user's account for what they own only need to check the main collection and not all of the sale collections that could possibly be in their account.

See the kitty items marketplace contract for an example of the current best practices when it comes to marketplace contracts.

Directory Structure

The directories here are organized into contracts, scripts, and transactions.

Contracts contain the source code for the Top Shot contracts that are deployed to Flow.

Scripts contain read-only transactions to get information about the state of someone's Collection or about the state of the TopShot contract.

Transactions contain the transactions that various admins and users can use to perform actions in the smart contract like creating plays and sets, minting Moments, and transferring Moments.

  • contracts/ : Where the Top Shot related smart contracts live.
  • transactions/ : This directory contains all the transactions and scripts that are associated with the Top Shot smart contracts.
  • transactions/scripts/ : This contains all the read-only Cadence scripts that are used to read information from the smart contract or from a resource in account storage.
  • lib/ : This directory contains packages for specific programming languages to be able to read copies of the Top Shot smart contracts, transaction templates, and scripts. Also contains automated tests written in those languages. Currently, Go is the only language that is supported, but we are hoping to add javascript and other languages soon. See the README in lib/go/ for more information about how to use the Go packages.

Top Shot Contract Overview

Each Top Shot Moment NFT represents a play from a game in the NBA season. Plays are grouped into sets which usually have some overarching theme, like rarity or the type of the play.

A set can have one or more plays in it and the same play can exist in multiple sets, but the combination of a play and a set, otherwise known as an edition, is unique and is what classifies an individual Moment.

Multiple Moments can be minted from the same edition and each receives a serial number that indicates where in the edition it was minted.

Each Moment is a resource object with roughly the following structure:

pub resource Moment {

    // global unique Moment ID
    pub let id: UInt64
    
    // the ID of the Set that the Moment comes from
    pub let setID: UInt32

    // the ID of the Play that the Moment references
    pub let playID: UInt32

    // the place in the edition that this Moment was minted
    // Otherwise known as the serial number
    pub let serialNumber: UInt32
}

The other types that are defined in TopShot are as follows:

  • Play: A struct type that holds most of the metadata for the Moments. All plays in Top Shot will be stored and modified in the main contract.
  • SetData: A struct that contains constant information about sets in Top Shot like the name, the series, the id, and such.
  • Set: A resource that contains variable data for sets and the functionality to modify sets, like adding and retiring plays, locking the set, and minting Moments from the set.
  • MomentData: A struct that contains the metadata associated with a Moment. instances of it will be stored in each Moment.
  • NFT: A resource type that is the NFT that represents the Moment highlight a user owns. It stores its unique ID and other metadata. This is the collectible object that the users store in their accounts.
  • Collection: Similar to the NFTCollection resource from the NFT example, this resource is a repository for a user's Moments. Users can withdraw and deposit from this collection and get information about the contained Moments.
  • Admin: This is a resource type that can be used by admins to perform various actions in the smart contract like starting a new series, creating a new play or set, and getting a reference to an existing set.
  • QuerySetData: A struct that contains the metadata associated with a set. This is currently the only way to access the metadata of a set. Can be accessed by calling the public function in the TopShot smart contract called getSetData(setID)

Metadata structs associated with plays and sets are stored in the main smart contract and can be queried by anyone. For example, If a player wanted to find out the name of the team that the player represented in their Moment plays for, they would call a public function in the TopShot smart contract called getPlayMetaDataByField, providing, from their owned Moment, the play and field that they want to query. They can do the same with information about sets by calling getSetData with the setID.

The power to create new plays, sets, and Moments rests with the owner of the Admin resource.

Admins create plays and sets which are stored in the main smart contract, Admins can add plays to sets to create editions, which Moments can be minted from.

Admins also can restrict the abilities of sets and editions to be further expanded. A set begins as being unlocked, which means plays can be added to it, but when an admin locks the set, plays can no longer be added to it. This cannot be reversed.

The same applies to editions. Editions start out open, and an admin can mint as many Moments they want from the edition. When an admin retires the edition, Moments can no longer be minted from that edition. This cannot be reversed.

These rules are in place to ensure the scarcity of sets and editions once they are closed.

Once a user owns a Moment object, that Moment is stored directly in their account storage via their Collection object. The collection object contains a dictionary that stores the Moments and gives utility functions to move them in and out and to read data about the collection and its Moments.

How to Deploy and Test the Top Shot Contract in VSCode

The first step for using any smart contract is deploying it to the blockchain, or emulator in our case. Do these commands in vscode. See the vscode extension instructions to learn how to use it.

  1. Start the emulator with the Run emulator vscode command.
  2. Open the NonFungibleToken.cdc file from the flow-nft repo and the TopShot.cdc file. Feel free to read as much as you want to familiarize yourself with the contracts.
  3. In NonFungibleToken.cdc, click the deploy contract to account above the Dummy contract at the bottom of the file to deploy it. This also deploys the NonFungbleToken interface.
  4. In TopShot.cdc, make sure it imports NonFungibleToken from the account you deployed it to.
  5. Click the deploy contract to account button that appears over the TopShot contract declaration to deploy it to a new account.

This deploys the contract code. It also runs the contract's init function, which initializes the contract storage variables, stores the Collection and Admin resources in account storage, and creates links to the Collection.

As you can see, whenever we want to call a function, read a field, or use a type that is defined in a smart contract, we simply import that contract from the address it is defined in and then use the imported contract to access those type definitions and fields.

After the contracts have been deployed, you can run the sample transactions to interact with the contracts. The sample transactions are meant to be used in an automated context, so they use transaction arguments and string template fields. These make it easier for a program to use and interact with them. If you are running these transactions manually in the Flow Playground or vscode extension, you will need to remove the transaction arguments and hard code the values that they are used for.

You also need to replace the ADDRESS placeholders with the actual Flow addresses that you want to import from.

How to Run Transactions Against the Top Shot Contract

This repository contains sample transactions that can be executed against the Top Shot contract either via Flow CLI or using VSCode. This section will describe how to create a new Top Shot set on the Flow emulator.

Send Transaction with Flow CLI

  1. Install the Flow CLI and emulator
  2. Initialize the flow emulator configuration.
    flow emulator --init
  3. Configure the contracts & deployment section of the initialized flow.json file.
  4. Start the emulator.
    flow emulator
  5. On TopShot.cdc substitute the placeholder address import NonFungibleToken from 0xNFTADDRESS with the address the NonFungibleToken was deployed to. This will be the emulator address found in the accounts object of the initialized flow.json.
  6. Deploy the NonFungibleToken & TopShot contracts to the flow emulator.
    flow project deploy --network=emulator
  7. Use the Flow CLI to execute transactions against the emulator. This transaction creates a new set on the flow emulator called "new set name".
    flow transactions send ./transactions/admin/create_set.cdc "new set name"

Send Transaction with VSCode

  1. Install and configure VSCode extension.
  2. Start flow emulator by running the VSCode command.
    Cadence: Run emulator
  3. On TopShot.cdc substitute the placeholder address import NonFungibleToken from 0xNFTADDRESS with the address the NonFungibleToken was deployed to. Typically, this will be the service account address.
  4. Above the contract definition pub contract interface NonFungibleToken you will see and press text to deploy this contract to the service account.
  5. Above the contract definition pub contract TopShot: NonFungibleToken you will see and press text to deploy this contract to the service account.
  6. Navigate to transactions/admin/create_set.cdc Substitute the placeholder address import TopShot from 0xNFTADDRESS with the address TopShot.cdc was deployed to.
  7. Transactions run in VSCode cannot take arguments. Replace the line transaction(setName : String) with transaction() and find every instance of setName in the contract and replace with a hard coded value like "new set name".
  8. Above the line transaction() you will now see and press the text Send signed by service account. This will create a set on the flow emulator called "new set name".

How to run the automated tests for the contracts

See the lib/go README for instructions about how to run the automated tests.

Instructions for creating plays and minting moments

A common order of creating new Moments would be

  1. Creating new plays with transactions/admin/create_play.cdc.
  2. Creating new sets with transactions/admin/create_set.cdc.
  3. Adding plays to the sets to create editions with transactions/admin/add_plays_to_set.cdc.
  4. Minting Moments from those editions with transactions/admin/batch_mint_moment.cdc.

You can also see the scripts in transactions/scripts to see how information can be read from the real Top Shot smart contract deployed on the Flow Beta Mainnet.

Accessing the NBA Top Shot smart contract on Flow Beta Mainnet

The Flow Beta mainnet is still a work in progress and still has a limited number of accounts that can run nodes and submit transactions. Anyone can read data from the contract by running any of the scripts in the transactions directory using one of the public access nodes.

For example, this is how you would query the total supply via the Flow CLI.

flow scripts execute transactions/scripts/get_totalSupply.cdc --host access.mainnet.nodes.onflow.org:9000

Make sure that the import address in the script is correct for mainnet.

NBA Top Shot Events

The smart contract and its various resources will emit certain events that show when specific actions are taken, like transferring an NFT. This is a list of events that can be emitted, and what each event means. You can find definitions for interpreting these events in Go by seeing the lib/go/events package.

  • pub event ContractInitialized()

    This event is emitted when the TopShot contract is created.

Events for plays

  • pub event PlayCreated(id: UInt32, metadata: {String:String})

    Emitted when a new play has been created and added to the smart contract by an admin.

  • pub event NewSeriesStarted(newCurrentSeries: UInt32)

    Emitted when a new series has been triggered by an admin.

Events for set-Related actions

  • pub event SetCreated(setID: UInt32, series: UInt32)

    Emitted when a new set is created.

  • pub event PlayAddedToSet(setID: UInt32, playID: UInt32)

    Emitted when a new play is added to a set.

  • pub event PlayRetiredFromSet(setID: UInt32, playID: UInt32, numMoments: UInt32)

    Emitted when a play is retired from a set. Indicates that that play/set combination and cannot be used to mint moments any more.

  • pub event SetLocked(setID: UInt32)

    Emitted when a set is locked, meaning plays cannot be added.

  • pub event MomentMinted(momentID: UInt64, playID: UInt32, setID: UInt32, serialNumber: UInt32)

    Emitted when a Moment is minted from a set. The momentID is the global unique identifier that differentiates a Moment from all other Top Shot Moments in existence. The serialNumber is the identifier that differentiates the Moment within an Edition. It corresponds to the place in that edition where it was minted.

Events for Collection-related actions

  • pub event Withdraw(id: UInt64, from: Address?)

    Emitted when a Moment is withdrawn from a collection. id refers to the global Moment ID. If the collection was in an account's storage when it was withdrawn, from will show the address of the account that it was withdrawn from. If the collection was not in storage when the Moment was withdrawn, from will be nil.

  • pub event Deposit(id: UInt64, to: Address?)

    Emitted when a Moment is deposited into a collection. id refers to the global Moment ID. If the collection was in an account's storage when it was deposited, to will show the address of the account that it was deposited to. If the collection was not in storage when the Moment was deposited, to will be nil.

Top Shot NFT Metadata

NFT metadata is represented in a flexible and modular way using the standard proposed in FLIP-0636. The Top Shot contract implements the MetadataViews.Resolver interface, which standardizes the display of Top Shot NFT in accordance with FLIP-0636. The Top Shot contract also defines a custom view of moment play data called TopShotMomentMetadataView.

NBA Top Shot Packs

NBA Top Shot packs are currently off-chain and not managed by the NBA Top Shot smart contract. Moments in a pack are minted on-chain, and assembled into a pack for purchase off-chain on the NBA Top Shot platform. When a collector purchases a pack, the moments within the pack are transferred directly to this collector on-chain. The NBA Top Shot smart contract has no knowledge of packs.

NBA Top Shot Marketplace

The contracts/MarketTopShot.cdc contract allows users to create a sale object in their account to sell their Moments.

When a user wants to sell their Moment, they create a sale collection in their account and specify a beneficiary of a cut of the sale if they wish.

A Top Shot Sale Collection contains a capability to the owner's moment collection that allows the sale to withdraw the moment when it is purchased.

When another user wants to buy the Moment that is for sale, they simply send their fungible tokens to the purchase function and if they sent the correct amount, they get the Moment back.

Events for Market-related actions

  • pub event MomentListed(id: UInt64, price: UFix64, seller: Address?)

    Emitted when a user lists a Moment for sale in their SaleCollection.

  • pub event MomentPriceChanged(id: UInt64, newPrice: UFix64, seller: Address?)

    Emitted when a user changes the price of their Moment.

  • pub event MomentPurchased(id: UInt64, price: UFix64, seller: Address?)

    Emitted when a user purchases a Moment that is for sale.

  • pub event MomentWithdrawn(id: UInt64, owner: Address?)

    Emitted when a seller withdraws their Moment from their SaleCollection.

  • pub event CutPercentageChanged(newPercent: UFix64, seller: Address?)

    Emitted when a seller changes the percentage cut that is taken from their sales and sent to a beneficiary.

Different Versions of the Market Contract

There are two versions of the Top Shot Market Contract. TopShotMarket.cdc is the original version of the contract that was used for the first set of sales in the p2p marketplace, but we made improvements to it which are now in TopShotMarketV3.cdc.

There is also a V2 version that was deployed to mainnet, but will never be used.

Both versions define a SaleCollection resource that users store in their account. The resource manages the logic of the sale like listings, de-listing, prices, and purchases. The first version actually stores the moments that are for sale, but we realized that this causes issues if other contracts need to access a user's main collection to see what they own. We created the second version to simply store a capability to the owner's moment collection so that the moments that are for sale do not need to be removed from the main collection to be put up for sale. In this version, when a moment is purchased, the sale collection uses the capability to withdraw the moment from the main collection and returns it to the buyer.

The new version of the market contract is currently NOT DEPLOYED to mainnet, but it will be deployed and utilized in the near future.

TopShot contract improvement

Some improvements were made to the Topshot contract to reflect some cadence best practices and fix a bug. In-depth explanation on the changes and why we made them can be found in our Blog Post

TopShot Locking Contract Overview

Contract Name: TopShotLocking

TopShot NFTs can be locked for a duration meaning they are unable to be withdrawn, listed for sale, burned, etc. In the NBA TopShot product users are rewarded for locking their moments.

An NFT may be unlocked after the lock duration has passed, or the contract admin has marked it eligible for unlocking.

The moment is locked even if expiry has passed until the owner requests it be unlocked. The address which owns the locked NFT must make an unlocking transaction once it is eligible.

Available functions

lockNFT

pub fun lockNFT(nft: @NonFungibleToken.NFT, expiryTimestamp: UFix64): @NonFungibleToken.NFT
Takes a TopShot.NFT resource and sets it in the lockedNFTs dictionary, the value of the entry is the expiry timestamp
Params:
nft - a NonFungibleToken.NFT resource, but must conform to TopShot.NFT asserted at runtime
expiryTimestamp - the unix timestamp in seconds at which this nft can be unlocked

Example:

let collectionRef = acct.borrow<&TopShot.Collection>(from: /storage/MomentCollection)
            ?? panic("Could not borrow from MomentCollection in storage")

let ONE_YEAR_IN_SECONDS: UFix64 = UFix64(31536000)
collectionRef.lock(id: 1, duration: ONE_YEAR_IN_SECONDS)

unlockNFT

pub fun unlockNFT(nft: @NonFungibleToken.NFT): @NonFungibleToken.NFT
Takes a NonFungibleToken.NFT resource and attempts to remove it from the lockedNFTs dictionary. This function will panic if the nft lock has not expired or been overridden by an admin. Params:
nft - a NonFungibleToken.NFT resource

Example:

let collectionRef = acct.borrow<&TopShot.Collection>(from: /storage/MomentCollection)
            ?? panic("Could not borrow from MomentCollection in storage")

collectionRef.unlock(id: 1)

isLocked

pub fun isLocked(nftRef: &NonFungibleToken.NFT): Bool
Returns true if the moment is locked

getLockExpiry

pub fun getLockExpiry(nftRef: &NonFungibleToken.NFT): UFix64
Returns the unix timestamp when the nft is eligible for unlock

Admin Functions

markNFTUnlockable

pub fun markNFTUnlockable(nftRef: &NonFungibleToken.NFT)
Places the nft id in an unlockableNFTs dictionary. This dictionary is checked in the unlockNFT function and bypasses the expiryTimestamp Params:
nftRef - a reference to an NonFungibleToken.NFT resource

Example:

let adminRef: &NFTLocking.Admin

prepare(acct: AuthAccount) {
    // Set TopShotLocking admin ref
    self.adminRef = acct.borrow<&NFTLocking.Admin>(from: /storage/TopShotLockingAdmin)!
}

execute {
    // Set Top Shot NFT Owner collection ref
    let owner = getAccount(0x179b6b1cb6755e31)
    let collectionRef = owner.getCapability(/public/MomentCollection).borrow<&{TopShot.MomentCollectionPublic}>()
        ?? panic("Could not reference owner's moment collection")

    let nftRef = collectionRef.borrowNFT(id: 1)
    self.adminRef.markNFTUnlockable(nftRef: nftRef)
}

Contracts Honoring the Lock

  • TopShot withdraw
  • MarketTopShot relies on the NFT being withdrawn first so no additional code is needed
  • TopShotMarketV3 listForSale

License

The works in these folders /dapperlabs/nba-smart-contracts/blob/master/contracts/TopShot.cdc /dapperlabs/nba-smart-contracts/blob/master/contracts/MarketTopShot.cdc /dapperlabs/nba-smart-contracts/blob/master/contracts/MarketTopShotV3.cdc /dapperlabs/nba-smart-contracts/blob/master/contracts/TopShotAdminReceiver.cdc /dapperlabs/nba-smart-contracts/blob/master/contracts/TopShotShardedCollection.cdc

are under the Unlicense https://github.com/onflow/flow-NFT/blob/master/LICENSE

nba-smart-contracts's People

Contributors

10thfloor avatar anatoly256 avatar austinkline avatar deewai avatar dependabot[bot] avatar ericlin2004 avatar fkenji avatar franklywatson avatar houseofhufflepuff avatar ianthpun avatar javiersoto15 avatar jkan2 avatar jordancoblin avatar joshuahannan avatar jrkhan avatar judezhu avatar kay-zee avatar marcusmolchany avatar omahs avatar phi-line avatar ppichier avatar qhou avatar quantumleaper avatar rrrkren avatar sadief avatar timongll avatar tpetrychyn avatar vdojnov avatar yeukovichd avatar zihehuang avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nba-smart-contracts's Issues

User stories for smart contract MVP

This is a list of stories or core features for the NBA Smart contract. We need to understand how to implement them in Flow.

  1. I want to authenticate a certain Account to mint tokens, i.e. only COO can mint tokens. Where should the authenticated account address to be stored? Is there any structured logs that can be stored onchain and queried back? Ethereum has Transaction Receipt
  2. I want to emit an event when a token gets minted. How to emit an event with data?
  3. I want the minted token to contain structured data
  4. I want to query the structured data of a minted token
  5. I want to query the owner of a minted token
  6. I want the token to be transferred by the owner to a new owner
  7. I want the owner to give approval to a certain account for transferring their tokens.
  8. I want the NFT to refer to storage data in another contract instead of duplicating data

@chrisaxiom @stevemynett

DOCS: Document parameters in sample transactions

Issue To Be Solved

Most of the sample transactions in transactions/ have parameters, but need documentation for what each parameter is.

(Optional): Suggest A Solution

  • Add comments to the top section of each transaction with a description of each parameter. See the transfer_moment.cdc transaction for an example, or suggest a better example here
// Parameters:
//
// recipient: The Flow address of the account to receive the moment.
// withdrawID: The id of the moment to be transferred

[Feature Request] Query nickname from a public account?

Thank you for providing an API to help us build third-party apps! After hours of reading through the code, I've been able to figure out how to fetch for Set and Moments, but I can't seem to find any information to fetch for username from an account (or address). I'm building a simple fun app to track your NBA topshot portfolio. Having the capability to access username will help the UX a lot. Will this be possible on the roadmap?

events for castMold and mintMoment

Describe the bug
currently no events are emitted from either of these functions, which would be useful for our waterhose to pick up in order to know the casting/minting was successful.

Expected behavior
The format of the event for castMold should just include in mold id.

event for mintMoment should include the mold ID and the moment id

as long as its giving us enough information about each one. I was aware there are certain byte limitations in ethereum, hopefully you can just push out the full moment/mold in the event for us to capture

Implement quality Restrictions

Qualities need to go from 1-16 and restricted based off their numbers:

Quality 1 - Base Set Tier 1 (Unlimited)
Quality 2 - Base Set Tier 2 (Unlimited, 3x as scarce as Tier 1)
Quality 11 - Rare (Scarce)
Quality 14 - Legendary (10x as scarce as Rare)
Quality 16 - Genesis (1/1 or 1/3) (edited)

Minting moments with a sub-edition

Issue To Be Solved

We will need a way for newly minted Top Shot NFTs to have a subedition. The sub edition is intended to have it's own serial number range. (e.g. if we were to mint 100 moments total, the diamond sub edition will have serials 1-10, the golden sub edition would have serials 1 - 25, the base edition would have serials 1-65, the total edition size would need to be 100)
We will also need a way to store the subedition of each NFT (with all existing moments defaulting to the 'base edition' sub edition).

(Optional): Suggest A Solution

Potential solution for adding to the existing TopShot contract with the bulk of functionality living in a new contract:
https://sketchboard.me/rDsJU4sQGlN

Initial pass at minting sub editions with their own serial range has been added here:
#163

Question/Docs/Readme: how do packs fit into things?

I'm not sure if this is the right place to post this (please close this issue if it's out of place) but after walking through the Readme, Topshot contract, and Market contract, it's not clear to me how/where packs are implemented. Since this is a core aspect of NBA topshots I thought it might make sense to shed more light on them in the readme, but I definitely could be wrong, I'm just getting into things.

Are moments minted before a pack actually sells? Or does purchasing a pack trigger a random selection of moments to be minted?

Does the process of buying a pack fall under the Topshot Market contract (ie would Market.MomentPurchase events include pack purchases?)

I did see one of the lib/go files, there was a reference to PackNFT, but I couldn't find any references to PackNFT anywhere else.

DOCS: Write a tutorial for using the templates package.

Issue To Be Solved

The Top Shot repo provides a templates package for generating transactions to interact with the smart contracts, but we need to document how to actually use the package to run transactions in your Go code.

Suggest A Solution

  • Write a tutorial for:
    • fetching the templates package with go get
    • Examples for fetching the contracts and templates. (you can see examples in the test package)

Ability to Search for Active Sales of a Specific Moment

The SaleCollection provides access to all of the moments that a specific user has listed, and MomentListed can be used to retrieve all of the recently listed moments by any user, however it does not appear that there is any way to retrieve all of the for-sale moments of a specific play.

I suppose that a developer could repeatedly check for new MomentListed, MomentWithdrawn, and MomentPurchased events, and use those to update their own database of all the moments that are currently for sale, though that would be tedious and only accurate to the point that they launched their code.

Am I missing an already-existing function to retrieve all of the listed moments in a specific play, or is there any plan to add this endpoint in the future?

DOCS: Clarify How to execute sample transactions manually

Issue To Be Solved

There might be some confusion about running manual transactions and scripts, because they are written to be used by application code and have string template features and arguments, which are not usable by any of our manual tools.

Suggest A Solution

  • Add clarifications to the instructions in README that say that you need to remove the arguments, remove the template fields, and hardcode the addresses and values that they were used for.
  • Give examples for executing these with the CLI
  • https://docs.onflow.org/flow-cli/

Add function to update Receiver capability for market

Since users will not be able to actually own USDF in their accounts, they cannot receive the tokens that are used to buy their NFT. Therefore, the receiver capability in the sale resource in the market contract needs to be able to be changed to a different receiver

  • Make the Receiver into a var
  • Write a function that changes the Receiver to a different Receiver
  • Initialize the receiver to the TopShot receiver at resource creation

Refactor tests

The tests in lib/go/tests seems to have a lot of repeated code. This should be converted to a test suite with a setup/teardown so code doesn't have to be repeated

Create Metadata Upgrade that conforms with the proposed NFT metadata standard

Instructions

Issue To Be Solved

The community is reaching final steps for the Flow NFT metadata standard, and for the last steps of it, it would be helpful to have some examples of the standard in practice. Top Shot is a great place to show it.

NFT Standard Repo Instructions Here (with example implementation): onflow/flow-nft#52
NFT Standard View Proposals (contribute to this discussion and use the relevant views from this): onflow/flow-nft#55

Example implementation for a different project is here: https://github.com/findonflow/find/blob/main/contracts/Art.cdc

Suggest A Solution

  • Get familiar with the metadata proposal
  • Define a view in the top shot smart contract for all the text-based metadata that the Top Shot NFT already contains in the metadata dictionary.
  • Add implementations of the getView and resolveView methods to the TopShot.NFT resource.
    • Should have a resolveView for MetadataViews.Display and for the newly defined view
  • Add these methods to the collection resource as well to get it for a specific NFT ID.
  • Write tests to ensure that these work properly
  • Add documentation for these metadata views and how to access them

TEMPLATES: Enhance `templates` go package to use the cadence templates

Issue To Be Solved

The templates package currently uses hard-coded transaction templates for generating the transaction and script code.
We would like to use the transactions located in the transactions/ directory for these template generating functions so we have a single source of truth for transactions and scripts

Suggest A Solution

  • Replace the functions in the various template files in lib/go/templates/ with calls to MustAssetString to get the string code from the transactions directory.
  • Use the go replaceAddresses functionality in template_utils.go to replace the addresses in the transactions.
  • Use other string replacement functionality to replace other fields in transactions that need to be replaced.
  • In the tests, when constructing transactions, use the AddArgument function to add arguments to transactions before they are submitted.

See the templates package and tests package in the flow-ft repository for examples on how this can be completed.

Update Marketplace Contract

Need to get the marketplace SC up-to-date and compatible with the topshot smart contract.

  • compatible with the nft and ft standards
  • compatible with topshot
  • create central marketplace where users can show that their sale is active and nba can take a cut from purchases made via it.
  • create sample transactions
  • document the contract and make a tutorial

Searching Specific Serial Number

Issue To Be Solved

There has to be a way to search a specific serial number, especially if there isn't any transaction history yet. How can I search search a specific serial number? For Example: If a player was born on 12286, and I want to buy that specific serial number, how can I search it to see who owns it? A lot of profiles will have their twitter accounts linked where I can talk to them about a specific moment.

Clicking on 'Circulating Count' and scrolling down would take over an hour. There has to be an easier way..? Please advise or consider this as an option for users.

Thanks,

CodePro

FEATURE: Javascript templates and contracts package

Issue To Be Solved

We current have a go package for getting transaction templates, but we should also have a javascript package so users of the contracts can import and use the correct versions without having to copy and paste.

Suggest A Solution

Create a lib/go/javascript/templates package that does a similar thing to the lib/go/templates package.
It should use the transactions and scripts in transactions/ as a source of truth, replace the import addresses with user provided addresses, and return the correct transaction texts.

NFT composition

Issue To Be Solved

Currently, the metadata/traits of Top Shot NFT are primarily defined by set and play (aka edition). It would be helpful to be able to add 'components' to individual NFTs that would contribute towards the metadata/traits of the moment.

Possible Solution

Create a new 'component' contract to manage components -> this will allow the owner of component resource to create a componentTransferRequest (resource temporarily stored on component contract), and an NFT owner to accept or decline the componentTransfer.

Sketch in progress of component interfaces:
https://sketchboard.me/xDpNRMTwBZLj#/

Context

Looking to add functionality to allow individual moments to have autographs (another resource type). Ideally, I would like to have the autograph make use of a generic system for adding components instead of implementing this as a one off.
I believe a fan asking a player for an autograph on their moment would in practice be very similar to flows that would be broadly useful.

Get all listings for a moment?

Instructions

Please fill out the template below to the best of your ability and include a label indicating which tool/service you were working with when you encountered the problem.

Issue To Be Solved

I was wondering if there was a feature where I can put in a moment ID and get all the listings with the serial number and price for that particular moment, similar to what we see on NBATopShot. If it already exists, can someone point me to the write API code? If not, are you guys planning to add that?

DOCS: Document parameters and return values in template scripts

Issue To Be Solved

Most of the sample transactions in scripts/ have parameters and return types, but need documentation for what each parameter is.

###: Suggest A Solution

  • Add comments to the top section of each transaction with a description of each parameter. See the get_metadata.cdc script for an example, or suggest a better format here.
// Paramters
// account: The Flow Address of the account whose moment data needs to be read
// id: The unique ID for the moment whose data needs to be read
//
// Returns: {String: String} A dictionary of all the play metadata associated
// with the specified moment

TXS: Improve transactions so that they all use correct `prepare` and `execute` syntax

Issue To Be Solved

It is a best practice in cadence to only perform actions that are associated with the transaction signer's account in the prepare phase of a transaction, and perform all external interaction in the execute phase.

Suggest A Solution

  • Update the sample transactions in transactions/ to use both phases.

Example: transactions/admin/add_plays_to_set.cdc would be changed from:

transaction(setID: UInt32, plays: [UInt32]) {

    prepare(acct: AuthAccount) {

        // borrow a reference to the Admin resource in storage
        let admin = acct.borrow<&TopShot.Admin>(from: /storage/TopShotAdmin)
            ?? panic("Cannot borrow a reference to the admin resource")

        // borrow a reference to the set to be added to
        let setRef = admin.borrowSet(setID: setID)

        // Add the specified play IDs
        setRef.addPlays(playIDs: plays)
    }
}

to:

import TopShot from 0xTOPSHOTADDRESS

// This transaction adds multiple plays to a set
		
transaction(setID: UInt32, plays: [UInt32]) {

    // Local variable for the topshot Admin object
    let adminRef: &TopShot.Admin

    prepare(acct: AuthAccount) {

        // borrow a reference to the Admin resource in storage
        self.adminRef = acct.borrow<&TopShot.Admin>(from: /storage/TopShotAdmin)!
    }

    execute() {

        // borrow a reference to the set to be added to
        let setRef = self.adminRef.borrowSet(setID: setID)

        // Add the specified play IDs
        setRef.addPlays(playIDs: plays)
    }
}

Deprecate old scripts, implement new

Describe the bug
theres a bunch of Generate____ calls inside moment_templates that are deprecrated, including ones that have to do with factorys/collections I believe. We may need an update so it will support calls like getAllMolds or getAllMoments.

Expected behavior
For now, some sort of script call that will return me casted molds & minted moments for us to validation, but ultimately will be useful for future features as well.

Add additional NFT Metadata Views

Issue To Be Solved

Many more metadata views have been added to the standard repo since the original standard was approved and deployed. The Top Shot contract should include the important ones so that its own 3rd party developers can use it and so that it can be a good example for other projects in the Flow ecosystem.

Suggest A Solution

Check out the latest views that have been added to the metadata standard

Add all views to the Top Shot contract that would be useful

Context

This probably will require a discussion with product managers to figure out how to show certain data on-chain and which data is important.

Revise Smart Contract Estimates

Estimates were originally written for Bamboo and are out of date. Revisit the Smart Contract column in the feature estimates spreadsheet and update.

NBA Smart Contract Formal Spec

What:

We need a formal specification for the smart contracts for the NBA MVP. This should include:

  1. Well-defined user stories for smart contract interaction
  2. List of smart contracts with intended storage, inputs, outputs, and interactions
  3. What kind of API that needs to be exposed to the various backend services

Resources:

Feature Brief:
https://docs.google.com/document/d/1wEWXq0ycuMsOmI3voZDwCli3hI96IoGmh58gSHPc_mU/edit#heading=h.dqsp1n6qc582
Stats Plan:
https://docs.google.com/spreadsheets/d/1muUZowii0pqoyi6OPK1VPNJi7keSc8_5zI9vu_QvfOY/edit#gid=0

Play-specific metadata

type PlayMetadata struct {
FullName string
FirstName string
LastName string
Birthdate string
Birthplace string
JerseyNumber string
DraftTeam string `json:",omitempty"` // Not all plays have draft information. Can be blank
DraftYear *int32 `json:",omitempty,string"` // Not all plays have draft information. Can be blank
DraftSelection string `json:",omitempty"` // Not all plays have draft information. Can be blank
DraftRound string `json:",omitempty"` // Not all plays have draft information. Can be blank
TeamAtMomentNBAID string
TeamAtMoment string
PrimaryPosition string
PlayerPosition string
Height *int32 `json:",string"`
Weight *int32 `json:",string"`
TotalYearsExperience string
NbaSeason string
DateOfMoment string
PlayCategory string
PlayType string
HomeTeamName string
AwayTeamName string
HomeTeamScore *int32 `json:",string"`
AwayTeamScore *int32 `json:",string"`
}

Hi @joshuahannan and co! Great work so far on bringing crypto to the masses with TopShot!

I'm curious if there's any conversation around metadata that better identifies the actual play on the blockchain. Not that we don't want Dapper to exist forever and hope it will, but I think there's some (perhaps wise) reluctance to latch onto NFTs in general but specifically TS due to the reliance on the website to give real identifying information to the play (in addition to or even instead of things like the player's Draft Class, Birthplace, and other easily retrievable and super-duplicated-on-the-chain data). Ideally, data similar to the dataset on BigDataball but given the cost of putting too much data on the chain, I wonder if a helpful improvement might just be something like...

type PlayMetadata struct {
    ...
    HomeTeamScoreBeforePlay        *int32 `json:",string"`
    AwayTeamScoreBeforePlay        *int32 `json:",string"`
    HomeTeamScoreAfterPlay        *int32 `json:",string"`
    AwayTeamScoreAfterPlay        *int32 `json:",string"`
}

or

type PlayMetadata struct {
    ...
    QuarterAtPlayStart         *int32 `json:",string"`
    GameClockAtPlayStart         string
}

or at the very least, the lowest-hanging fruit since it already exists...

type PlayMetadata struct {
    ...
    Description         string
}

TXS: Post-Conditions for sample transactions

Issue To Be Solved

Some of the transactions should probably have post conditions to ensure correct behavior.

Suggest A Solution

  • Look through the sample transactions in transactions/
  • Find examples where a post condition could be added to ensure that the intended behavior was executed.
  • Make a PR with the additions for review

Can we use the MarketTopShot.cdc to buy and sell Moments?

Issue To Be Solved

So I am a bit of newb. I have programming knowledge, but I am really new to Cadence. I wanted to know if it was possible to buy and sell actual moments from the marketplace using this code. I have an account on Topshot and I am trying to make a script that can buy and sell my moments and not having to do them manually. Is it possible? If not, is it going to be added? Can I as a Topshot user use this code to buy/sell?

If we can, can you just really quick brief me through how I can do it? I read the README, but I still don't understand completely.

'Sold Out' flag on mold

Description

We need a flag that marks a certain moment editions of a mould as sold out, regardless of the quantity left for sale. Live ops will use this flag to end time boxed sales.

For example: The legendary edition of Moment A is only going to be available for a week. There will be a max of 1000 moments minted. At the end of the week we have only sold 500. We need to mark that edition as sold out in such a way that we are proving to the buyers that we can never put the remaining 500 up for sale.

In order to prevent mistakes we have been asked to build in a delay before the flag is activated. e.g. It takes 24 hours before the sold out flag is final. During the 24hours the flag can be undone. I am open to any suggestions around this feature.

cc @joshuahannan @AlanFalcon @rayhuynhdapper

Emit quality on MomentMinted

Describe the bug
Its hard to trace what type of moment being minted is without the quality. Shouldn't be too difficult to add that onto the event being emitted

Error fetching minted moment on mainnet4 using flow go sdk

Describe the bug
Error fetching minted moment on mainnet4

panic: error fetching minted moment from flow: client: rpc error: code = Internal desc = failed to execute the script on the execution node: rpc error: code = Internal desc = failed to execute script: failed to get state commitment for block (563530a19cd7d1e7e1c0935a137f0af50b5ac52513c47e5773797e7fd3c77fda): could not retrieve resource: key not found

To Reproduce
Steps to reproduce the behavior:

getMomentScript := `
		import TopShot from 0x0b2a3299cc857e29
        pub struct Moment {
          pub var id: UInt64
          pub var playId: UInt32
          pub var play: {String: String}
          pub var setId: UInt32
          pub var setName: String
		  pub var series: UInt32
          pub var serialNumber: UInt32
          init(id:UInt64, playId:UInt32, setId:UInt32, serialNumber:UInt32) {
            self.id = id
            self.playId = playId
            self.play = TopShot.getPlayMetaData(playID: self.playId)!
            self.setId = setId
            self.setName = TopShot.getSetName(setID: self.setId)!
			self.series = TopShot.getSetSeries(setID: self.setId)!
            self.serialNumber = serialNumber
          }
        }
		pub fun main(id: UInt64, playId: UInt32, setId: UInt32, serialNumber: UInt32): Moment {
			return Moment(id: id, playId: playId, setId: setId, serialNumber: serialNumber)
		}
`
  1. ExecuteScriptAtBlockHeight in flow go api
  // fetch latest block
	latestBlock, err := FlowClient.GetLatestBlock(context.Background(), false)
	if err != nil {
		return nil, fmt.Errorf("error fetching block from flow: %w", err)
	}
      res, err := FlowClient.ExecuteScriptAtBlockHeight(context.Background(), latestBlock.Height, []byte(getMomentScript), 
                []cadence.Value{
		cadence.UInt64(772738),
		cadence.UInt32(276),
		cadence.UInt32(2),
		cadence.UInt32(1129),
	})

Expected behavior
Return Moment

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • Ubuntu 18.04.5

Additional context
Add any other context about the problem here.

cannot find moments minted event using flow go-sdk

i am trying to get all events for moment minted in flow go-sdk, and tried with all mainnet endpoints from 1 to 5 but get an empty array . all works well with moment listed

can anyone tell me what range of block or endpoint should i use in which i can get a event for moments minted?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.