Skip to content

Commit

Permalink
[aptos-framework] respect maximum number of tokens in a collection
Browse files Browse the repository at this point in the history
  • Loading branch information
davidiw authored and aptos-bot committed Mar 30, 2022
1 parent bb94947 commit 3bbfed0
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ compiled_package_info:
? address: "0000000000000000000000000000000000000000000000000000000000000001"
name: Version
: CoreFramework
source_digest: 507A59A4F71D20A97BC954433274D35B8FCBDE7DC13BC62EAB2A7024EB430E99
source_digest: B69B939CB6B56A5AFBC4B30EFF658E882FCE272C01D0B2D0E564937B1F9BE96F
build_flags:
dev_mode: false
test_mode: false
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ This module provides the foundation for (collectible) Tokens often called NFTs
- [Function `create_finite_collection_script`](#0x1_Token_create_finite_collection_script)
- [Function `create_unlimited_collection_script`](#0x1_Token_create_unlimited_collection_script)
- [Function `create_collection`](#0x1_Token_create_collection)
- [Function `claim_token_ownership`](#0x1_Token_claim_token_ownership)
- [Function `initialize_gallery`](#0x1_Token_initialize_gallery)
- [Function `initialize_token_metadata`](#0x1_Token_initialize_token_metadata)
- [Function `create_token_script`](#0x1_Token_create_token_script)
Expand Down Expand Up @@ -303,6 +304,15 @@ This module provides the foundation for (collectible) Tokens often called NFTs



<a name="0x1_Token_EMAXIMUM_NUMBER_OF_TOKENS_FOR_COLLECTION"></a>



<pre><code><b>const</b> <a href="Token.md#0x1_Token_EMAXIMUM_NUMBER_OF_TOKENS_FOR_COLLECTION">EMAXIMUM_NUMBER_OF_TOKENS_FOR_COLLECTION</a>: u64 = 3;
</code></pre>



<a name="0x1_Token_EMISSING_CLAIMED_TOKEN"></a>


Expand Down Expand Up @@ -459,6 +469,40 @@ This module provides the foundation for (collectible) Tokens often called NFTs



</details>

<a name="0x1_Token_claim_token_ownership"></a>

## Function `claim_token_ownership`



<pre><code><b>public</b> <b>fun</b> <a href="Token.md#0x1_Token_claim_token_ownership">claim_token_ownership</a>(account: &signer, token: <a href="Token.md#0x1_Token_Token">Token::Token</a>): <a href="Token.md#0x1_Token_Token">Token::Token</a>
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="Token.md#0x1_Token_claim_token_ownership">claim_token_ownership</a>(
account: &signer,
token: <a href="Token.md#0x1_Token">Token</a>,
): <a href="Token.md#0x1_Token">Token</a> <b>acquires</b> <a href="Token.md#0x1_Token_Collections">Collections</a> {
<b>let</b> creator_addr = <a href="../../../../../../../aptos-framework/releases/artifacts/current/build/MoveStdlib/docs/GUID.md#0x1_GUID_id_creator_address">GUID::id_creator_address</a>(&token.id);
<b>let</b> collections = &<b>mut</b> <b>borrow_global_mut</b>&lt;<a href="Token.md#0x1_Token_Collections">Collections</a>&gt;(creator_addr).collections;
<b>let</b> collection = <a href="Table.md#0x1_Table_borrow_mut">Table::borrow_mut</a>(collections, &token.collection);
<b>if</b> (<a href="Table.md#0x1_Table_borrow">Table::borrow</a>(&collection.tokens, &token.name).supply == 1) {
<a href="Table.md#0x1_Table_remove">Table::remove</a>(&<b>mut</b> collection.claimed_tokens, &token.name);
<a href="Table.md#0x1_Table_insert">Table::insert</a>(&<b>mut</b> collection.claimed_tokens, *&token.name, <a href="../../../../../../../aptos-framework/releases/artifacts/current/build/MoveStdlib/docs/Signer.md#0x1_Signer_address_of">Signer::address_of</a>(account))
};
token
}
</code></pre>



</details>

<a name="0x1_Token_initialize_gallery"></a>
Expand Down Expand Up @@ -622,6 +666,14 @@ This module provides the foundation for (collectible) Tokens often called NFTs
): ID <b>acquires</b> <a href="Token.md#0x1_Token_Collections">Collections</a>, <a href="Token.md#0x1_Token_Gallery">Gallery</a> {
<b>let</b> account_addr = <a href="../../../../../../../aptos-framework/releases/artifacts/current/build/MoveStdlib/docs/Signer.md#0x1_Signer_address_of">Signer::address_of</a>(account);
<b>let</b> collections = &<b>mut</b> <b>borrow_global_mut</b>&lt;<a href="Token.md#0x1_Token_Collections">Collections</a>&gt;(account_addr).collections;
<b>let</b> collection = <a href="Table.md#0x1_Table_borrow_mut">Table::borrow_mut</a>(collections, &collection_name);

<b>if</b> (<a href="../../../../../../../aptos-framework/releases/artifacts/current/build/MoveStdlib/docs/Option.md#0x1_Option_is_some">Option::is_some</a>(&collection.maximum)) {
<b>let</b> current = <a href="Table.md#0x1_Table_count">Table::count</a>(&collection.tokens);
<b>let</b> maximum = <a href="../../../../../../../aptos-framework/releases/artifacts/current/build/MoveStdlib/docs/Option.md#0x1_Option_borrow">Option::borrow</a>(&collection.maximum);
<b>assert</b>!(current != *maximum, <a href="Token.md#0x1_Token_EMAXIMUM_NUMBER_OF_TOKENS_FOR_COLLECTION">EMAXIMUM_NUMBER_OF_TOKENS_FOR_COLLECTION</a>)
};

<b>let</b> gallery = &<b>mut</b> <b>borrow_global_mut</b>&lt;<a href="Token.md#0x1_Token_Gallery">Gallery</a>&gt;(account_addr).gallery;

<b>let</b> token_id = <a href="../../../../../../../aptos-framework/releases/artifacts/current/build/MoveStdlib/docs/GUID.md#0x1_GUID_id">GUID::id</a>(&<a href="../../../../../../../aptos-framework/releases/artifacts/current/build/MoveStdlib/docs/GUID.md#0x1_GUID_create">GUID::create</a>(account));
Expand All @@ -640,12 +692,12 @@ This module provides the foundation for (collectible) Tokens often called NFTs
uri,
};

<b>let</b> collection = <a href="Table.md#0x1_Table_borrow_mut">Table::borrow_mut</a>(collections, &collection_name);
<b>if</b> (supply == 1) {
<a href="Table.md#0x1_Table_insert">Table::insert</a>(&<b>mut</b> collection.claimed_tokens, *&name, account_addr)
};
<a href="Table.md#0x1_Table_insert">Table::insert</a>(&<b>mut</b> collection.tokens, name, token_data);

<b>let</b> token = <a href="Token.md#0x1_Token_claim_token_ownership">claim_token_ownership</a>(account, token);
<a href="Table.md#0x1_Table_insert">Table::insert</a>(gallery, *&token_id, token);
token_id
}
Expand Down Expand Up @@ -789,13 +841,7 @@ This module provides the foundation for (collectible) Tokens often called NFTs
<a href="Token.md#0x1_Token_initialize_gallery">initialize_gallery</a>(account)
};

<b>let</b> creator_addr = <a href="../../../../../../../aptos-framework/releases/artifacts/current/build/MoveStdlib/docs/GUID.md#0x1_GUID_id_creator_address">GUID::id_creator_address</a>(&token.id);
<b>let</b> collections = &<b>mut</b> <b>borrow_global_mut</b>&lt;<a href="Token.md#0x1_Token_Collections">Collections</a>&gt;(creator_addr).collections;
<b>let</b> collection = <a href="Table.md#0x1_Table_borrow_mut">Table::borrow_mut</a>(collections, &token.collection);
<b>if</b> (<a href="Table.md#0x1_Table_borrow">Table::borrow</a>(&collection.tokens, &token.name).supply == 1) {
<a href="Table.md#0x1_Table_remove">Table::remove</a>(&<b>mut</b> collection.claimed_tokens, &token.name);
<a href="Table.md#0x1_Table_insert">Table::insert</a>(&<b>mut</b> collection.claimed_tokens, *&token.name, account_addr)
};
<b>let</b> token = <a href="Token.md#0x1_Token_claim_token_ownership">claim_token_ownership</a>(account, token);

<b>let</b> gallery = &<b>mut</b> <b>borrow_global_mut</b>&lt;<a href="Token.md#0x1_Token_Gallery">Gallery</a>&gt;(account_addr).gallery;
<b>if</b> (<a href="Table.md#0x1_Table_contains_key">Table::contains_key</a>(gallery, &token.id)) {
Expand Down Expand Up @@ -897,7 +943,7 @@ This module provides the foundation for (collectible) Tokens often called NFTs
<a href="../../../../../../../aptos-framework/releases/artifacts/current/build/MoveStdlib/docs/ASCII.md#0x1_ASCII_string">ASCII::string</a>(b"<a href="Token.md#0x1_Token_Collection">Collection</a>: Hello, World"),
*&collection_name,
<a href="../../../../../../../aptos-framework/releases/artifacts/current/build/MoveStdlib/docs/ASCII.md#0x1_ASCII_string">ASCII::string</a>(b"https://aptos.dev"),
<a href="../../../../../../../aptos-framework/releases/artifacts/current/build/MoveStdlib/docs/Option.md#0x1_Option_none">Option::none</a>(),
<a href="../../../../../../../aptos-framework/releases/artifacts/current/build/MoveStdlib/docs/Option.md#0x1_Option_some">Option::some</a>(1),
);

<b>let</b> token_id = <a href="Token.md#0x1_Token_create_token">create_token</a>(
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module AptosFramework::Token {
const EINSUFFICIENT_BALANCE: u64 = 0;
const EMISSING_CLAIMED_TOKEN: u64 = 1;
const EINVALID_TOKEN_MERGE: u64 = 2;
const EMAXIMUM_NUMBER_OF_TOKENS_FOR_COLLECTION: u64 = 3;

// A creator may publish multiple collections
struct Collections has key {
Expand Down Expand Up @@ -106,6 +107,22 @@ module AptosFramework::Token {
Table::insert(collections, *&name, collection);
}

// Enables storage solutions of Tokens outside of this module to inform the collection the
// current hosting address of a token.
public fun claim_token_ownership(
account: &signer,
token: Token,
): Token acquires Collections {
let creator_addr = GUID::id_creator_address(&token.id);
let collections = &mut borrow_global_mut<Collections>(creator_addr).collections;
let collection = Table::borrow_mut(collections, &token.collection);
if (Table::borrow(&collection.tokens, &token.name).supply == 1) {
Table::remove(&mut collection.claimed_tokens, &token.name);
Table::insert(&mut collection.claimed_tokens, *&token.name, Signer::address_of(account))
};
token
}

// An account's set of Tokens
struct Gallery has key {
gallery: Table<ID, Token>,
Expand Down Expand Up @@ -212,6 +229,14 @@ module AptosFramework::Token {
): ID acquires Collections, Gallery {
let account_addr = Signer::address_of(account);
let collections = &mut borrow_global_mut<Collections>(account_addr).collections;
let collection = Table::borrow_mut(collections, &collection_name);

if (Option::is_some(&collection.maximum)) {
let current = Table::count(&collection.tokens);
let maximum = Option::borrow(&collection.maximum);
assert!(current != *maximum, EMAXIMUM_NUMBER_OF_TOKENS_FOR_COLLECTION)
};

let gallery = &mut borrow_global_mut<Gallery>(account_addr).gallery;

let token_id = GUID::id(&GUID::create(account));
Expand All @@ -230,12 +255,12 @@ module AptosFramework::Token {
uri,
};

let collection = Table::borrow_mut(collections, &collection_name);
if (supply == 1) {
Table::insert(&mut collection.claimed_tokens, *&name, account_addr)
};
Table::insert(&mut collection.tokens, name, token_data);

let token = claim_token_ownership(account, token);
Table::insert(gallery, *&token_id, token);
token_id
}
Expand Down Expand Up @@ -299,13 +324,7 @@ module AptosFramework::Token {
initialize_gallery(account)
};

let creator_addr = GUID::id_creator_address(&token.id);
let collections = &mut borrow_global_mut<Collections>(creator_addr).collections;
let collection = Table::borrow_mut(collections, &token.collection);
if (Table::borrow(&collection.tokens, &token.name).supply == 1) {
Table::remove(&mut collection.claimed_tokens, &token.name);
Table::insert(&mut collection.claimed_tokens, *&token.name, account_addr)
};
let token = claim_token_ownership(account, token);

let gallery = &mut borrow_global_mut<Gallery>(account_addr).gallery;
if (Table::contains_key(gallery, &token.id)) {
Expand Down Expand Up @@ -378,6 +397,20 @@ module AptosFramework::Token {
deposit_token(&owner, token_2);
}

#[test(creator = @0x1)]
#[expected_failure(abort_code = 3)]
public fun test_maximum(creator: signer) acquires Collections, Gallery {
let (collection_name, _token_id) = create_collection_and_token(&creator, 2);
create_token(
&creator,
collection_name,
ASCII::string(b"Token: Hello, Token 2"),
ASCII::string(b"Hello, Token 2"),
1,
ASCII::string(b"https://aptos.dev"),
);
}

fun create_collection_and_token(
creator: &signer,
amount: u64,
Expand All @@ -388,7 +421,7 @@ module AptosFramework::Token {
ASCII::string(b"Collection: Hello, World"),
*&collection_name,
ASCII::string(b"https://aptos.dev"),
Option::none(),
Option::some(1),
);

let token_id = create_token(
Expand Down
Binary file not shown.
26 changes: 24 additions & 2 deletions aptos-move/framework/aptos-framework/sources/Token.move
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module AptosFramework::Token {
const EINSUFFICIENT_BALANCE: u64 = 0;
const EMISSING_CLAIMED_TOKEN: u64 = 1;
const EINVALID_TOKEN_MERGE: u64 = 2;
const EMAXIMUM_NUMBER_OF_TOKENS_FOR_COLLECTION: u64 = 3;

// A creator may publish multiple collections
struct Collections has key {
Expand Down Expand Up @@ -228,6 +229,14 @@ module AptosFramework::Token {
): ID acquires Collections, Gallery {
let account_addr = Signer::address_of(account);
let collections = &mut borrow_global_mut<Collections>(account_addr).collections;
let collection = Table::borrow_mut(collections, &collection_name);

if (Option::is_some(&collection.maximum)) {
let current = Table::count(&collection.tokens);
let maximum = Option::borrow(&collection.maximum);
assert!(current != *maximum, EMAXIMUM_NUMBER_OF_TOKENS_FOR_COLLECTION)
};

let gallery = &mut borrow_global_mut<Gallery>(account_addr).gallery;

let token_id = GUID::id(&GUID::create(account));
Expand All @@ -246,7 +255,6 @@ module AptosFramework::Token {
uri,
};

let collection = Table::borrow_mut(collections, &collection_name);
if (supply == 1) {
Table::insert(&mut collection.claimed_tokens, *&name, account_addr)
};
Expand Down Expand Up @@ -389,6 +397,20 @@ module AptosFramework::Token {
deposit_token(&owner, token_2);
}

#[test(creator = @0x1)]
#[expected_failure(abort_code = 3)]
public fun test_maximum(creator: signer) acquires Collections, Gallery {
let (collection_name, _token_id) = create_collection_and_token(&creator, 2);
create_token(
&creator,
collection_name,
ASCII::string(b"Token: Hello, Token 2"),
ASCII::string(b"Hello, Token 2"),
1,
ASCII::string(b"https://aptos.dev"),
);
}

fun create_collection_and_token(
creator: &signer,
amount: u64,
Expand All @@ -399,7 +421,7 @@ module AptosFramework::Token {
ASCII::string(b"Collection: Hello, World"),
*&collection_name,
ASCII::string(b"https://aptos.dev"),
Option::none(),
Option::some(1),
);

let token_id = create_token(
Expand Down

0 comments on commit 3bbfed0

Please sign in to comment.