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

feat: add NFT standard #3

Merged
merged 22 commits into from
May 20, 2021
Merged
Changes from 1 commit
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
Prev Previous commit
Next Next commit
add trait deployment addresses, improve wording, replace id with ID
  • Loading branch information
friedger committed Mar 17, 2021
commit b16b169e54b1e03f2eb9a7f5c4343a2b27b40b89
17 changes: 8 additions & 9 deletions sips/sips/sip-009-nft-standard.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ In blockchains with smart contracts, including the Stacks blockchain, developers

The Stacks blockchain's programming language for developing smart contracts, Clarity, has built-in language primitives to define and use non-fungible tokens. Although those primitives exists, there is value in defining a common interface (known in Clarity as a "trait") that allows different smart contracts to interoperate with non-fungible token contracts in a reusable way. This SIP defines that trait.

NFTs always belong to one smart contract. They are enumerated starting at 1. The current last id is provided by a smart contract function.
Each NFT always belong to one smart contract. NFTs of a smart contract are enumerated starting at 1. The current last ID is provided by a smart contract function. The asset ID together with the contract ID defines a globally unique NFT.

# Specification

Expand Down Expand Up @@ -65,7 +65,7 @@ Takes an NFT identifier and returns a response containing the principal owning t

If a call to function `get-owner` returns some principal `A`, then it must return the same value until the `transfer` function is called with principal `A` as the sender.

For any call to `get-owner` with an id greater than the last token id returned by the `get-last-token-id` function, the call must return a response `(ok none)`.
For any call to `get-owner` with an ID greater than the last token ID returned by the `get-last-token-id` function, the call must return a response `(ok none)`.

This function must never return an error response. It can be defined as read-only, i.e. `define-read-only`.

Expand All @@ -79,7 +79,7 @@ This function must be defined with define-public, as it alters state, and must b

After a successful call to `transfer`, the function `get-owner` must return the recipient of the `transfer` call as the new owner.

For any call to `transfer` with an id greater than the last token id returned by the `get-last-token-id` function, the call must return an error response.
For any call to `transfer` with an ID greater than the last token ID returned by the `get-last-token-id` function, the call must return an error response.

When returning an error from this function, the error must follow the pattern defined below:

Expand Down Expand Up @@ -108,7 +108,7 @@ When returning an error from this function, the error must follow the pattern de

## Use of native asset functions

Although it is not possible to mandate in a Clarity trait, contract implementers must use at least one built-in native non-fungible assets that are provided as Clarity primitives. This allows clients to use Post Conditions (explained below), and takes advantages of other benefits, like native support for these asset balances and transfers through `stacks-blockchain-api`. The reference implementations included in this SIP use the native asset primitives, and provide a good boilerplate for their usage.
Although it is not possible to mandate in a Clarity trait, contract implementers must define at least one built-in native non-fungible [asset class](https://app.sigle.io/friedger.id/FDwT_3yuMrHDQm-Ai1OVS) that are provided as Clarity primitives. This allows clients to use Post Conditions (explained below), and takes advantages of other benefits, like native support for these asset balances and transfers through `stacks-blockchain-api`. The reference implementations included in this SIP use the native asset primitives, and provide a good boilerplate for their usage.

The native asset functions include:

Expand All @@ -120,7 +120,7 @@ The native asset functions include:

The following requirements for using native asset functions are defined:
### Transfer
If the `transfer` function is called from a client without a post-condition in deny mode or without any NFT condition about a changed owner, then the function call must fail with `abort_by_post_condition`.
If the `transfer` function is called from a client without a [post-condition](https://docs.blockstack.org/understand-stacks/transactions#post-conditions) in deny mode or without any NFT condition about a changed owner, then the function call must fail with `abort_by_post_condition`.
# Using NFTs in applications

Developers who wish to use a non-fungible token contract in an application should first be provided, or keep track of, various different non-fungible token implementations. When validating a non-fungible token contract, they should fetch the interface and/or source code for that contract. If the contract implements the trait, then the application can use this standard's contract interface for making transfers and getting other details defined in this standard.
Expand All @@ -138,8 +138,7 @@ For example, when applications call the `transfer` function, they should _always
NFTs are an established asset class on blockchains. Read for example [here](https://www.ledger.com/academy/what-are-nft).

## EIP 721
Ethereum has [EIP 721](https://eips.ethereum.org/EIPS/eip-721) that defined non-fungible tokens on the Ethereum blockchain. Notable differences are that the transfer function in EIP 721 uses a different ordering of the arguments ending with the token id. The transfer function in this SIP uses the token id as the first argument which is in line with the other native functions in Clarity. Furthermore, this SIP only defines a function for getting the URI pointing to the metadata of an NFT. The specifications for schema and other properties of the token metadata should be defined in a separate SIP.

Ethereum has [EIP 721](https://eips.ethereum.org/EIPS/eip-721) that defined non-fungible tokens on the Ethereum blockchain. Notable differences are that the transfer function in EIP 721 uses a different ordering of the arguments ending with the token id. The transfer function in this SIP uses the token ID as the first argument which is in line with the other native functions in Clarity. Furthermore, this SIP only defines a function for getting the URI pointing to the metadata of an NFT. The specifications for schema and other properties of the token metadata should be defined in a separate SIP.

# Backwards Compatibility

Expand All @@ -149,10 +148,10 @@ Not applicable

This SIP is activated if 5 contracts are deployed that use the same trait that follows this specification. This must happen before Bitcoin tip #700,000.

A trait that follows this specification is available on mainnet as [`SP1JSH2FPE8BWNTP228YZ1AZZ0HE0064PS6RXRAY4.nft-trait.nft-trait`](https://explorer.stacks.co/txid/0xe547bca01878eaaf4758a067d3f522691a8928fcade0b0a4930a825c10d082bc?chain=mainnet) and on testnet as [`ST1JSH2FPE8BWNTP228YZ1AZZ0HE0064PS54Q30F0.nft-trait.nft-trait`](https://explorer.stacks.co/txid/0x07922820aca1ef6bbadddd1a19212befe11c9dc5da9bce0248d93915e2fb80d4?chain=testnet).

# Reference Implementations

## Source code
### Friedger's clarity-smart-contracts
https://github.com/friedger/clarity-smart-contracts/blob/master/contracts/sips/nft-trait.clar

Deployment on testnet: TODO