-
Notifications
You must be signed in to change notification settings - Fork 63
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
## Type of change <!--Delete points that do not apply--> - New feature ## Changes The following changes have been made: - Creates a modular NFT library with the following core attributes: - `approve()` - Approves a user to transfer the token on the owner's behalf - `approved()` - Returns the approved user for the token - `balance_of()` - Returns the number of tokens a user owns - `is_approved_for_all()` - Returns whether a user is approved to transfer all tokens on another user's behalf - `mint()` - Instantiates a new token - `owner_of()` - Returns the owner of a token - `set_approval_for_all()` - Gives a user the ability to transfer all tokens on another user's behalf - `token_minted()` - Returns the number of tokens that have been minted - `transfer_to()` - Transfer a token from one owner to another - The following extensions are available: - Administrator - `admin()` - Returns the administrator - `set_admin()` - Sets an administrator - Burnable - `burn()` - Deletes the token - Meta Data - `meta_data()` - Returns the token's stored metadata - `set_meta_data()` - Store new metadata for the token - Supply - `max_supply()` - Returns the maximum set supply - `set_max_supply()` - Assigns the maximum supply ## Notes - More extensions may be available in the future if they are deemed common additions to NFTs - This PR bumps to repo from forc v0.30.0 to forc v0.30.1 for the latest formatter bug fix ## Related Issues <!--Delete everything after the "#" symbol and replace it with a number. No spaces between hash and number--> Closes #19
- Loading branch information
Showing
51 changed files
with
2,266 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
library sway_libs; | ||
|
||
dep merkle_proof/binary_merkle_proof; | ||
dep nft/nft; | ||
dep string/string; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
## Overview | ||
|
||
A non-fungible token (NFT) is a unique token that has an identifier which distinguishes itself from other tokens within the same token contract. Unlike Fuel's Native Assets, these tokens are not fungible with one another and may contain metadata or other traits giving them distinctive characteristics. | ||
|
||
Some common applications of an NFT include artwork / collectibles, DeFi short positions, deeds, and more. | ||
|
||
For more information please see the [specification](./SPECIFICATION.md). | ||
|
||
# Using the Library | ||
|
||
## Getting Started | ||
|
||
In order to use the `NFT` library, Sway-libs must be added as a dependency to the project's Forc.toml file. To add Sway-libs as a dependency to the Forc.toml file in your project please see the [README.md](../../../README.md). Once this has been done, you may import the `NFT` library using the `use` keyword and explicitly state which functions you will be using. For a list of all functions please see the [specification](./SPECIFICATION.md). | ||
|
||
```rust | ||
use sway_libs::nft::{ | ||
approve, | ||
mint, | ||
owner_of, | ||
transfer, | ||
}; | ||
``` | ||
|
||
## Basic Functionality | ||
|
||
Once imported, a `NFT` can be minted by calling the `mint` function. | ||
|
||
```rust | ||
// The user which shall own the newly minted NFT | ||
let new_owner = msg_sender().unwrap(); | ||
// The id of the newly minted token | ||
let token_id = 1; | ||
|
||
NFTCore::mint(new_owner, token_id); | ||
``` | ||
|
||
Tokens may be transferred by calling the `transfer` function. | ||
|
||
```rust | ||
// The user which the token shall be transferred to | ||
let new_owner = msg_sender().unwrap(); | ||
// The id of the token which will be transferred | ||
let token_id = 1; | ||
|
||
transfer(new_owner, token_id); | ||
``` | ||
|
||
You may check the owner of a token by calling the `owner_of` function. | ||
|
||
```rust | ||
let token_id: = 1; | ||
let owner = owner_of(token_id).unwrap(); | ||
``` | ||
|
||
Other users may be approved to transfer a token on another's behalf by calling the `approve` function. | ||
|
||
```rust | ||
// The user which may transfer the token | ||
let approved_user = msg_sender().unwrap(); | ||
// The id of the token which they may transfer | ||
let token_id = 1; | ||
|
||
approve(approved_user, token_id); | ||
``` | ||
|
||
## Extensions | ||
|
||
There are a number of different extensions which you may use to further enchance your non-fungible tokens. | ||
|
||
These include: | ||
1. [Metadata](./extensions/meta_data/meta_data.sw) | ||
2. [Burning functionality](./extensions/burnable/burnable.sw) | ||
3. [Administrative capabilities](./extensions/administrator/administrator.sw) | ||
4. [Supply limits](./extensions/supply.sw) | ||
|
||
For more information please see the [specification](./SPECIFICATION.md). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
Table of Contents | ||
- [Overview](#overview) | ||
- [Use Cases](#use-cases) | ||
- [Core Public Functions](#core-public-functions) | ||
- [`approve()`](#approve) | ||
- [`approved()`](#approved) | ||
- [`balance_of()`](#balance_of) | ||
- [`is_approved_for_all()`](#is-approved-for-all) | ||
- [`mint()`](#mint) | ||
- [`owner_of()`](#owner-of) | ||
- [`set_approval_for_all()`](#set_approval-for-all) | ||
- [`tokens_minted()`](#tokens-minted) | ||
- [`transfer()`](#transfer) | ||
- [Extension Public Functions](#extension-public-functions) | ||
- [Administrator](#administrator) | ||
- [`admin()`](#admin) | ||
- [`set_admin()`](#set-admin) | ||
- [Burnable](#burnable) | ||
- [`burn()`](#burn) | ||
- [Metadata](#metadata) | ||
- [`meta_data()`](#meta-data) | ||
- [`set_meta_data()`](#set-meta-data) | ||
- [Supply](#supply) | ||
- [`max_supply()`](#max-supply) | ||
- [`set_max_supply()`](#set-max-supply) | ||
|
||
# Overview | ||
|
||
This document provides an overview of the NFT library. | ||
|
||
It outlines the use cases, i.e. specification, and describes how to implement the library. | ||
|
||
# Use Cases | ||
|
||
The NFT library can be used anytime individual tokens with distictive characteritics are needed. | ||
|
||
Traits can be implemented to provide additional features to the `NFTCore` struct. Some traits are already provided in the extensions portion of this NFT library. | ||
|
||
## Core Public Functions | ||
|
||
These core functions are basic functionality that should be added to all NFTs, regardless of extensions. It is expected that these functions can be called from any other contract. | ||
|
||
### `approve()` | ||
|
||
Gives permission to another user to transfer a single, specific token on the owner's behalf. | ||
|
||
### `approved()` | ||
|
||
Returns the user which is permissioned to transfer the token on the owner's behalf. | ||
|
||
### `balance_of()` | ||
|
||
Returns the number of tokens owned by a user. | ||
|
||
### `is_approved_for_all()` | ||
|
||
Returns whether a user is approved to transfer **all** tokens on another user's behalf. | ||
|
||
### `mint()` | ||
|
||
Creates a new token with an owner and an id. | ||
|
||
### `owner_of()` | ||
|
||
Returns the owner of a specific token. | ||
|
||
### `set_approval_for_all()` | ||
|
||
Give permission to a user to transfer **all** tokens owned by another user's behalf. | ||
|
||
### `tokens_minted()` | ||
|
||
The total number of tokens that have been minted. | ||
|
||
### `transfer()` | ||
|
||
Transfers ownership of the token from one user to another. | ||
|
||
## Extension Public Functions | ||
|
||
These extensions are optional and not all NFTs will have these implemented. Whether they should be used is a case-by-case basis. | ||
|
||
### Administrator | ||
|
||
#### `admin()` | ||
|
||
Returns the adiminstrator of the `NFT` library. | ||
|
||
#### `set_admin()` | ||
|
||
Sets the administrator of the `NFT` library. | ||
|
||
### Burnable | ||
|
||
#### `burn()` | ||
|
||
Deletes the specified token. | ||
|
||
### Metadata | ||
|
||
#### `meta_data()` | ||
|
||
Returns the stored data associated with the specified token. | ||
|
||
#### `set_meta_data()` | ||
|
||
Stores a struct containing information / data particular to an individual token. | ||
|
||
### Supply | ||
|
||
#### `max_supply()` | ||
|
||
Returns the maximum number of tokens that may be minted. | ||
|
||
#### `set_max_supply()` | ||
|
||
Sets the maximum number of tokens that may be minted. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
library errors; | ||
|
||
pub enum AccessError { | ||
OwnerDoesNotExist: (), | ||
SenderNotOwner: (), | ||
SenderNotOwnerOrApproved: (), | ||
} | ||
|
||
pub enum InputError { | ||
TokenAlreadyExists: (), | ||
TokenDoesNotExist: (), | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
library events; | ||
|
||
pub struct ApprovalEvent { | ||
/// The user that has gotten approval to transfer the specified token. | ||
/// If an approval was revoked, the `Option` will be `None`. | ||
approved: Option<Identity>, | ||
/// The user that has given or revoked approval to transfer his/her tokens. | ||
owner: Identity, | ||
/// The unique identifier of the token which the approved may transfer. | ||
token_id: u64, | ||
} | ||
|
||
pub struct MintEvent { | ||
/// The owner of the newly minted tokens. | ||
owner: Identity, | ||
/// The token id that has been minted. | ||
token_id: u64, | ||
} | ||
|
||
pub struct OperatorEvent { | ||
/// The boolean that signifies whether the `operator` has been approved | ||
approved: bool, | ||
/// The user which may or may not transfer all tokens on the owner's behalf. | ||
operator: Identity, | ||
/// The user which has given or revoked approval to the operator to transfer all of their | ||
/// tokens on their behalf. | ||
owner: Identity, | ||
} | ||
|
||
pub struct TransferEvent { | ||
/// The user which previously owned the token that has been transfered. | ||
from: Identity, | ||
// The user that made the transfer. This can be the owner, the approved user, or the operator. | ||
sender: Identity, | ||
/// The user which now owns the token that has been transfered. | ||
to: Identity, | ||
/// The unique identifier of the token which has transfered ownership. | ||
token_id: u64, | ||
} |
37 changes: 37 additions & 0 deletions
37
sway_libs/src/nft/extensions/administrator/administrator.sw
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
library administrator; | ||
|
||
dep administrator_errors; | ||
dep administrator_events; | ||
|
||
use administrator_errors::AdminError; | ||
use administrator_events::AdminEvent; | ||
use ::nft::nft_storage::ADMIN; | ||
use std::{auth::msg_sender, logging::log, storage::{get, store}}; | ||
|
||
/// Returns the administrator for the library. | ||
#[storage(read)] | ||
pub fn admin() -> Option<Identity> { | ||
get::<Option<Identity>>(ADMIN) | ||
} | ||
|
||
/// Changes the library's administrator. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `admin` - The user which is to be set as the new admin. | ||
/// | ||
/// # Reverts | ||
/// | ||
/// * When the admin is storage is not `None`. | ||
/// * When the sender is not the `admin` in storage. | ||
#[storage(read, write)] | ||
pub fn set_admin(new_admin: Option<Identity>) { | ||
let admin = get::<Option<Identity>>(ADMIN); | ||
require(admin.is_none() || (admin.is_some() && admin.unwrap() == msg_sender().unwrap()), AdminError::SenderNotAdmin); | ||
|
||
store(ADMIN, new_admin); | ||
|
||
log(AdminEvent { | ||
admin: new_admin, | ||
}); | ||
} |
5 changes: 5 additions & 0 deletions
5
sway_libs/src/nft/extensions/administrator/administrator_errors.sw
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
library administrator_errors; | ||
|
||
pub enum AdminError { | ||
SenderNotAdmin: (), | ||
} |
6 changes: 6 additions & 0 deletions
6
sway_libs/src/nft/extensions/administrator/administrator_events.sw
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
library administrator_events; | ||
|
||
pub struct AdminEvent { | ||
/// The user which is now the admin of this contract. | ||
admin: Option<Identity>, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
library burnable; | ||
|
||
dep burnable_events; | ||
|
||
use burnable_events::BurnEvent; | ||
use ::nft::{errors::{AccessError, InputError}, nft_core::NFTCore, nft_storage::{BALANCES, TOKENS}}; | ||
use std::{auth::msg_sender, hash::sha256, logging::log, storage::{get, store}}; | ||
|
||
pub trait Burnable { | ||
/// Deletes this token from storage and decrements the balance of the owner. | ||
/// | ||
/// * Reverts | ||
/// | ||
/// * When sender is not the owner of the token. | ||
#[storage(read, write)] | ||
fn burn(self); | ||
} | ||
|
||
impl Burnable for NFTCore { | ||
#[storage(read, write)] | ||
fn burn(self) { | ||
require(self.owner == msg_sender().unwrap(), AccessError::SenderNotOwner); | ||
|
||
store(sha256((BALANCES, self.owner)), get::<u64>(sha256((BALANCES, self.owner))) - 1); | ||
store(sha256((TOKENS, self.token_id)), Option::None::<NFTCore>()); | ||
|
||
log(BurnEvent { | ||
owner: self.owner, | ||
token_id: self.token_id, | ||
}); | ||
} | ||
} | ||
|
||
/// Burns the specified token. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// * `token_id` - The id of the token to burn. | ||
/// | ||
/// # Reverts | ||
/// | ||
/// * When the `token_id` specified does not map to an existing token. | ||
#[storage(read, write)] | ||
pub fn burn(token_id: u64) { | ||
let nft = get::<Option<NFTCore>>(sha256((TOKENS, token_id))); | ||
require(nft.is_some(), InputError::TokenDoesNotExist); | ||
nft.unwrap().burn(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
library burnable_events; | ||
|
||
pub struct BurnEvent { | ||
/// The user that has burned their token. | ||
owner: Identity, | ||
/// The unique identifier of the token which has been burned. | ||
token_id: u64, | ||
} |
Oops, something went wrong.