Skip to content

Commit

Permalink
NFT ABI (#56)
Browse files Browse the repository at this point in the history
## Type of change

<!--Delete points that do not apply-->

- Improvement (refactoring, restructuring repository, cleaning tech
debt, ...)

## Changes

The following changes have been made:

- Add NFT ABI
- Add Supply ABI
- Add Administrator ABI
- Add Burn ABI
- Rename metadata to token_metadata to differentiate between contract
and individual token metadata

## Notes

- All NFT implementations should follow the same ABI, meaning we should
provide this ABI in the library.

## Related Issues

<!--Delete everything after the "#" symbol and replace it with a number.
No spaces between hash and number-->

Closes #55

Co-authored-by: bitzoic <[email protected]>
  • Loading branch information
bitzoic and bitzoic authored Nov 23, 2022
1 parent e677765 commit f5539c1
Show file tree
Hide file tree
Showing 14 changed files with 152 additions and 118 deletions.
26 changes: 13 additions & 13 deletions sway_libs/src/nft/SPECIFICATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,24 @@ Table of Contents
- [`approve()`](#approve)
- [`approved()`](#approved)
- [`balance_of()`](#balance_of)
- [`is_approved_for_all()`](#is-approved-for-all)
- [`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)
- [`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)
- [`set_admin()`](#set_admin)
- [Burnable](#burnable)
- [`burn()`](#burn)
- [Metadata](#metadata)
- [`meta_data()`](#meta-data)
- [`set_meta_data()`](#set-meta-data)
- [Token Metadata](#token-metadata)
- [`token_metadata()`](#token_metadata)
- [`set_token_metadata()`](#set_token_metadata)
- [Supply](#supply)
- [`max_supply()`](#max-supply)
- [`set_max_supply()`](#set-max-supply)
- [`max_supply()`](#max_supply)
- [`set_max_supply()`](#set_max_supply)

# Overview

Expand Down Expand Up @@ -96,13 +96,13 @@ Sets the administrator of the `NFT` library.

Deletes the specified token.

### Metadata
### Token Metadata

#### `meta_data()`
#### `token_metadata()`

Returns the stored data associated with the specified token.

#### `set_meta_data()`
#### `set_token_metadata()`

Stores a struct containing information / data particular to an individual token.

Expand Down
7 changes: 7 additions & 0 deletions sway_libs/src/nft/extensions/administrator/administrator.sw
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ use administrator_events::AdminEvent;
use ::nft::nft_storage::ADMIN;
use std::{auth::msg_sender, logging::log, storage::{get, store}};

abi Administrator {
#[storage(read)]
fn admin() -> Option<Identity>;
#[storage(read, write)]
fn set_admin(new_admin: Option<Identity>);
}

/// Returns the administrator for the library.
#[storage(read)]
pub fn admin() -> Option<Identity> {
Expand Down
5 changes: 5 additions & 0 deletions sway_libs/src/nft/extensions/burnable/burnable.sw
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ 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}};

abi Burn {
#[storage(read, write)]
fn burn(token_id: u64);
}

pub trait Burnable {
/// Deletes this token from storage and decrements the balance of the owner.
///
Expand Down
7 changes: 7 additions & 0 deletions sway_libs/src/nft/extensions/supply/supply.sw
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ use std::{logging::log, storage::{get, store}};
use supply_errors::SupplyError;
use supply_events::SupplyEvent;

abi Supply {
#[storage(read)]
fn max_supply() -> Option<u64>;
#[storage(read, write)]
fn set_max_supply(supply: Option<u64>);
}

/// Returns the maximum supply that has been set for the NFT library.
#[storage(read)]
pub fn max_supply() -> Option<u64> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
library meta_data;
library token_metadata;

dep meta_data_structures;
dep token_metadata_structures;

use meta_data_structures::NFTMetaData;
use ::nft::{errors::InputError, nft_core::NFTCore, nft_storage::{META_DATA, TOKENS}};
use token_metadata_structures::NFTMetadata;
use ::nft::{errors::InputError, nft_core::NFTCore, nft_storage::{TOKEN_METADATA, TOKENS}};
use std::{hash::sha256, storage::{get, store}};

pub trait MetaData<T> {
pub trait TokenMetadata<T> {
/// Returns the metadata for this token
#[storage(read)]
fn meta_data(self) -> Option<T>;
fn token_metadata(self) -> Option<T>;

/// Creates new metadata for this token.
///
/// # Arguments
///
/// * `metadata` - The new metadata to overwrite the existing metadata.
/// * `token_metadata` - The new metadata to overwrite the existing metadata.
#[storage(write)]
fn set_meta_data(self, metadata: Option<T>);
fn set_token_metadata(self, token_metadata: Option<T>);
}

impl<T> MetaData<T> for NFTCore {
impl<T> TokenMetadata<T> for NFTCore {
#[storage(read)]
fn meta_data(self) -> Option<T> {
get::<Option<T>>(sha256((META_DATA, self.token_id)))
fn token_metadata(self) -> Option<T> {
get::<Option<T>>(sha256((TOKEN_METADATA, self.token_id)))
}

#[storage(write)]
fn set_meta_data(self, metadata: Option<T>) {
store(sha256((META_DATA, self.token_id)), metadata);
fn set_token_metadata(self, token_metadata: Option<T>) {
store(sha256((TOKEN_METADATA, self.token_id)), token_metadata);
}
}

Expand All @@ -38,11 +38,11 @@ impl<T> MetaData<T> for NFTCore {
///
/// * `token_id` - The id of the token which the metadata should be returned
#[storage(read)]
pub fn meta_data<T>(token_id: u64) -> Option<T> {
pub fn token_metadata<T>(token_id: u64) -> Option<T> {
let nft = get::<Option<NFTCore>>(sha256((TOKENS, token_id)));
match nft {
Option::Some(nft) => {
nft.meta_data()
nft.token_metadata()
},
Option::None => {
Option::None
Expand All @@ -54,16 +54,16 @@ pub fn meta_data<T>(token_id: u64) -> Option<T> {
///
/// # Arguments
///
/// * `metadata` - The metadata which should be set.
/// * `token_metadata` - The metadata which should be set.
/// * `token_id` - The token which the metadata should be set for.
///
/// # Reverts
///
/// * When the `token_id` does not map to an existing token
#[storage(read, write)]
pub fn set_meta_data<T>(metadata: Option<T>, token_id: u64) {
pub fn set_token_metadata<T>(token_metadata: Option<T>, token_id: u64) {
let nft = get::<Option<NFTCore>>(sha256((TOKENS, token_id)));
require(nft.is_some(), InputError::TokenDoesNotExist);

nft.unwrap().set_meta_data(metadata);
nft.unwrap().set_token_metadata(token_metadata);
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
library meta_data_structures;
library token_metadata_structures;

pub struct NFTMetaData {
pub struct NFTMetadata {
// This is left as an example. Support for StorageVec in struct is needed here.
// Developers may also implement their own metadata structs with properties they may need
// and use the MetaData trait.
value: u64,
}

impl NFTMetaData {
impl NFTMetadata {
fn new(value: u64) -> Self {
Self { value }
}
Expand Down
23 changes: 22 additions & 1 deletion sway_libs/src/nft/nft.sw
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ dep errors;
dep events;
dep extensions/administrator/administrator;
dep extensions/burnable/burnable;
dep extensions/meta_data/meta_data;
dep extensions/token_metadata/token_metadata;
dep extensions/supply/supply;

use errors::InputError;
Expand All @@ -16,6 +16,27 @@ use nft_core::NFTCore;
use nft_storage::{BALANCES, OPERATOR_APPROVAL, TOKENS, TOKENS_MINTED};
use std::{auth::msg_sender, hash::sha256, logging::log, storage::{get, store}};

abi NFT {
#[storage(read, write)]
fn approve(approved: Option<Identity>, token_id: u64);
#[storage(read)]
fn approved(token_id: u64) -> Option<Identity>;
#[storage(read)]
fn balance_of(owner: Identity) -> u64;
#[storage(read)]
fn is_approved_for_all(operator: Identity, owner: Identity) -> bool;
#[storage(read, write)]
fn mint(amount: u64, to: Identity);
#[storage(read)]
fn owner_of(token_id: u64) -> Option<Identity>;
#[storage(write)]
fn set_approval_for_all(approve: bool, operator: Identity);
#[storage(read)]
fn tokens_minted() -> u64;
#[storage(read, write)]
fn transfer(to: Identity, token_id: u64);
}

/// Sets the approved identity for a specific token.
///
/// To revoke approval the approved user should be `None`.
Expand Down
2 changes: 1 addition & 1 deletion sway_libs/src/nft/nft_storage.sw
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub const ADMIN: b256 = 0x100000000000000000000000000000000000000000000000000000
pub const APPROVED: b256 = 0x2000000000000000000000000000000000000000000000000000000000000000;
pub const BALANCES: b256 = 0x3000000000000000000000000000000000000000000000000000000000000000;
pub const MAX_SUPPLY: b256 = 0x4000000000000000000000000000000000000000000000000000000000000000;
pub const META_DATA: b256 = 0x5000000000000000000000000000000000000000000000000000000000000000;
pub const TOKEN_METADATA: b256 = 0x5000000000000000000000000000000000000000000000000000000000000000;
pub const OPERATOR_APPROVAL: b256 = 0x6000000000000000000000000000000000000000000000000000000000000000;
pub const TOKENS: b256 = 0x7000000000000000000000000000000000000000000000000000000000000000;
pub const TOKENS_MINTED: b256 = 0x8000000000000000000000000000000000000000000000000000000000000000;
10 changes: 5 additions & 5 deletions tests/src/test_projects/harness.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// Add test modules here:

mod merkle_proof;
mod signed_i8;
mod nft_core;
mod nft_extensions;
mod signed_i128;
mod signed_i16;
mod signed_i256;
mod signed_i32;
mod signed_i64;
mod signed_i128;
mod signed_i256;
mod nft_core;
mod nft_extensions;
mod signed_i8;
mod string;
24 changes: 2 additions & 22 deletions tests/src/test_projects/nft_core/src/main.sw
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,14 @@ use sway_libs::nft::{
balance_of,
is_approved_for_all,
mint,
NFT,
owner_of,
set_approval_for_all,
tokens_minted,
transfer,
};

abi NFT_Core_Test {
#[storage(read, write)]
fn approve(approved: Option<Identity>, token_id: u64);
#[storage(read)]
fn approved(token_id: u64) -> Option<Identity>;
#[storage(read)]
fn balance_of(owner: Identity) -> u64;
#[storage(read)]
fn is_approved_for_all(operator: Identity, owner: Identity) -> bool;
#[storage(read, write)]
fn mint(amount: u64, to: Identity);
#[storage(read)]
fn owner_of(token_id: u64) -> Option<Identity>;
#[storage(write)]
fn set_approval_for_all(approve: bool, operator: Identity);
#[storage(read)]
fn tokens_minted() -> u64;
#[storage(read, write)]
fn transfer(to: Identity, token_id: u64);
}

impl NFT_Core_Test for Contract {
impl NFT for Contract {
#[storage(read, write)]
fn approve(approved_identity: Option<Identity>, token_id: u64) {
approve(approved_identity, token_id);
Expand Down
Loading

0 comments on commit f5539c1

Please sign in to comment.