Skip to content

Commit

Permalink
[fungible_assets] fix bugs, add tests and change object api
Browse files Browse the repository at this point in the history
  • Loading branch information
lightmark committed Apr 6, 2023
1 parent 535f4f5 commit c767194
Show file tree
Hide file tree
Showing 8 changed files with 242 additions and 118 deletions.
157 changes: 95 additions & 62 deletions aptos-move/framework/aptos-framework/doc/fungible_asset.md

Large diffs are not rendered by default.

7 changes: 3 additions & 4 deletions aptos-move/framework/aptos-framework/doc/object.md
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@ Produces an ObjectId from the given address. This is not verified.
<pre><code><b>public</b> <b>fun</b> <a href="object.md#0x1_object_address_to_object">address_to_object</a>&lt;T: key&gt;(<a href="object.md#0x1_object">object</a>: <b>address</b>): <a href="object.md#0x1_object_Object">Object</a>&lt;T&gt; {
<b>assert</b>!(<b>exists</b>&lt;<a href="object.md#0x1_object_ObjectCore">ObjectCore</a>&gt;(<a href="object.md#0x1_object">object</a>), <a href="../../aptos-stdlib/../move-stdlib/doc/error.md#0x1_error_not_found">error::not_found</a>(<a href="object.md#0x1_object_EOBJECT_DOES_NOT_EXIST">EOBJECT_DOES_NOT_EXIST</a>));
<b>assert</b>!(<a href="object.md#0x1_object_exists_at">exists_at</a>&lt;T&gt;(<a href="object.md#0x1_object">object</a>), <a href="../../aptos-stdlib/../move-stdlib/doc/error.md#0x1_error_not_found">error::not_found</a>(<a href="object.md#0x1_object_ERESOURCE_DOES_NOT_EXIST">ERESOURCE_DOES_NOT_EXIST</a>));
<a href="object.md#0x1_object_Object">Object</a>&lt;T&gt;{ inner: <a href="object.md#0x1_object">object</a> }
<a href="object.md#0x1_object_Object">Object</a>&lt;T&gt; { inner: <a href="object.md#0x1_object">object</a> }
}
</code></pre>

Expand Down Expand Up @@ -753,7 +753,7 @@ Create a new object whose address is derived based on the creator account addres
Derivde objects, similar to named objects, cannot be deleted.


<pre><code><b>public</b> <b>fun</b> <a href="object.md#0x1_object_create_user_derived_object">create_user_derived_object</a>(creator: &<a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>, derive_ref: &<a href="object.md#0x1_object_DeriveRef">object::DeriveRef</a>): <a href="object.md#0x1_object_ConstructorRef">object::ConstructorRef</a>
<pre><code><b>public</b>(<b>friend</b>) <b>fun</b> <a href="object.md#0x1_object_create_user_derived_object">create_user_derived_object</a>(creator_address: <b>address</b>, derive_ref: &<a href="object.md#0x1_object_DeriveRef">object::DeriveRef</a>): <a href="object.md#0x1_object_ConstructorRef">object::ConstructorRef</a>
</code></pre>


Expand All @@ -762,8 +762,7 @@ Derivde objects, similar to named objects, cannot be deleted.
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="object.md#0x1_object_create_user_derived_object">create_user_derived_object</a>(creator: &<a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>, derive_ref: &<a href="object.md#0x1_object_DeriveRef">DeriveRef</a>): <a href="object.md#0x1_object_ConstructorRef">ConstructorRef</a> {
<b>let</b> creator_address = <a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer_address_of">signer::address_of</a>(creator);
<pre><code><b>public</b>(<b>friend</b>) <b>fun</b> <a href="object.md#0x1_object_create_user_derived_object">create_user_derived_object</a>(creator_address: <b>address</b>, derive_ref: &<a href="object.md#0x1_object_DeriveRef">DeriveRef</a>): <a href="object.md#0x1_object_ConstructorRef">ConstructorRef</a> {
<b>let</b> obj_addr = <a href="object.md#0x1_object_create_user_derived_object_address">create_user_derived_object_address</a>(creator_address, derive_ref.self);
<a href="object.md#0x1_object_create_object_internal">create_object_internal</a>(creator_address, obj_addr, <b>false</b>)
}
Expand Down
45 changes: 28 additions & 17 deletions aptos-move/framework/aptos-framework/doc/primary_store.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ This defines the module for interacting with primary stores of accounts/objects,


- [Resource `DeriveRefPod`](#0x1_primary_store_DeriveRefPod)
- [Function `add_derived_ref_pod`](#0x1_primary_store_add_derived_ref_pod)
- [Function `create_primary_wallet_enabled_fungible_asset`](#0x1_primary_store_create_primary_wallet_enabled_fungible_asset)
- [Function `ensure_primary_store_exists`](#0x1_primary_store_ensure_primary_store_exists)
- [Function `create_primary_store`](#0x1_primary_store_create_primary_store)
- [Function `primary_store_address`](#0x1_primary_store_primary_store_address)
Expand All @@ -21,10 +21,10 @@ This defines the module for interacting with primary stores of accounts/objects,
- [Specification](#@Specification_0)


<pre><code><b>use</b> <a href="create_signer.md#0x1_create_signer">0x1::create_signer</a>;
<b>use</b> <a href="fungible_asset.md#0x1_fungible_asset">0x1::fungible_asset</a>;
<pre><code><b>use</b> <a href="fungible_asset.md#0x1_fungible_asset">0x1::fungible_asset</a>;
<b>use</b> <a href="object.md#0x1_object">0x1::object</a>;
<b>use</b> <a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">0x1::signer</a>;
<b>use</b> <a href="../../aptos-stdlib/../move-stdlib/doc/string.md#0x1_string">0x1::string</a>;
</code></pre>


Expand Down Expand Up @@ -57,15 +57,15 @@ Resource stored on the fungible asset metadata object to allow creating primary

</details>

<a name="0x1_primary_store_add_derived_ref_pod"></a>
<a name="0x1_primary_store_create_primary_wallet_enabled_fungible_asset"></a>

## Function `add_derived_ref_pod`
## Function `create_primary_wallet_enabled_fungible_asset`

Creators of fungible assets can call this to enable support for creating primary (deterministic) stores for
their users.


<pre><code><b>public</b> <b>fun</b> <a href="primary_store.md#0x1_primary_store_add_derived_ref_pod">add_derived_ref_pod</a>(constructor_ref: &<a href="object.md#0x1_object_ConstructorRef">object::ConstructorRef</a>)
<pre><code><b>public</b> <b>fun</b> <a href="primary_store.md#0x1_primary_store_create_primary_wallet_enabled_fungible_asset">create_primary_wallet_enabled_fungible_asset</a>(constructor_ref: &<a href="object.md#0x1_object_ConstructorRef">object::ConstructorRef</a>, maximum_supply: u64, name: <a href="../../aptos-stdlib/../move-stdlib/doc/string.md#0x1_string_String">string::String</a>, symbol: <a href="../../aptos-stdlib/../move-stdlib/doc/string.md#0x1_string_String">string::String</a>, decimals: u8)
</code></pre>


Expand All @@ -74,7 +74,14 @@ their users.
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="primary_store.md#0x1_primary_store_add_derived_ref_pod">add_derived_ref_pod</a>(constructor_ref: &ConstructorRef) {
<pre><code><b>public</b> <b>fun</b> <a href="primary_store.md#0x1_primary_store_create_primary_wallet_enabled_fungible_asset">create_primary_wallet_enabled_fungible_asset</a>(
constructor_ref: &ConstructorRef,
maximum_supply: u64,
name: String,
symbol: String,
decimals: u8,
) {
<a href="fungible_asset.md#0x1_fungible_asset_add_fungibility">fungible_asset::add_fungibility</a>(constructor_ref, maximum_supply, name, symbol, decimals);
<b>let</b> metadata_obj = &<a href="object.md#0x1_object_generate_signer">object::generate_signer</a>(constructor_ref);
<b>move_to</b>(metadata_obj, <a href="primary_store.md#0x1_primary_store_DeriveRefPod">DeriveRefPod</a> {
metadata_derive_ref: <a href="object.md#0x1_object_generate_derive_ref">object::generate_derive_ref</a>(constructor_ref),
Expand Down Expand Up @@ -106,9 +113,10 @@ their users.
metadata: Object&lt;T&gt;,
): Object&lt;FungibleAssetStore&gt; <b>acquires</b> <a href="primary_store.md#0x1_primary_store_DeriveRefPod">DeriveRefPod</a> {
<b>if</b> (!<a href="primary_store.md#0x1_primary_store_primary_store_exists">primary_store_exists</a>(owner, metadata)) {
<a href="primary_store.md#0x1_primary_store_create_primary_store">create_primary_store</a>(owner, metadata);
};
<a href="primary_store.md#0x1_primary_store">primary_store</a>(owner, metadata)
<a href="primary_store.md#0x1_primary_store_create_primary_store">create_primary_store</a>(owner, metadata)
} <b>else</b> {
<a href="primary_store.md#0x1_primary_store">primary_store</a>(owner, metadata)
}
}
</code></pre>

Expand Down Expand Up @@ -136,10 +144,9 @@ Create a primary store object to hold fungible asset for the given address.
owner_addr: <b>address</b>,
metadata: Object&lt;T&gt;,
): Object&lt;FungibleAssetStore&gt; <b>acquires</b> <a href="primary_store.md#0x1_primary_store_DeriveRefPod">DeriveRefPod</a> {
<b>let</b> owner = &<a href="create_signer.md#0x1_create_signer_create_signer">create_signer::create_signer</a>(owner_addr);
<b>let</b> metadata_addr = <a href="object.md#0x1_object_object_address">object::object_address</a>(&metadata);
<b>let</b> derive_ref = &<b>borrow_global</b>&lt;<a href="primary_store.md#0x1_primary_store_DeriveRefPod">DeriveRefPod</a>&gt;(metadata_addr).metadata_derive_ref;
<b>let</b> constructor_ref = &<a href="object.md#0x1_object_create_user_derived_object">object::create_user_derived_object</a>(owner, derive_ref);
<b>let</b> constructor_ref = &<a href="object.md#0x1_object_create_user_derived_object">object::create_user_derived_object</a>(owner_addr, derive_ref);

// Disable ungated transfer <b>as</b> deterministic stores shouldn't be transferrable.
<b>let</b> transfer_ref = &<a href="object.md#0x1_object_generate_transfer_ref">object::generate_transfer_ref</a>(constructor_ref);
Expand Down Expand Up @@ -273,7 +280,11 @@ Return whether the given account's primary store can do direct transfers.


<pre><code><b>public</b> <b>fun</b> <a href="primary_store.md#0x1_primary_store_ungated_transfer_allowed">ungated_transfer_allowed</a>&lt;T: key&gt;(<a href="account.md#0x1_account">account</a>: <b>address</b>, metadata: Object&lt;T&gt;): bool {
<a href="fungible_asset.md#0x1_fungible_asset_ungated_transfer_allowed">fungible_asset::ungated_transfer_allowed</a>(<a href="primary_store.md#0x1_primary_store">primary_store</a>(<a href="account.md#0x1_account">account</a>, metadata))
<b>if</b> (<a href="primary_store.md#0x1_primary_store_primary_store_exists">primary_store_exists</a>(<a href="account.md#0x1_account">account</a>, metadata)) {
<a href="fungible_asset.md#0x1_fungible_asset_ungated_transfer_allowed">fungible_asset::ungated_transfer_allowed</a>(<a href="primary_store.md#0x1_primary_store">primary_store</a>(<a href="account.md#0x1_account">account</a>, metadata))
} <b>else</b> {
<b>true</b>
}
}
</code></pre>

Expand All @@ -288,7 +299,7 @@ Return whether the given account's primary store can do direct transfers.
Withdraw <code>amount</code> of fungible asset from <code>store</code> by the owner.


<pre><code><b>public</b> <b>fun</b> <a href="primary_store.md#0x1_primary_store_withdraw">withdraw</a>&lt;T: key&gt;(owner: &<a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>, metadata: <a href="object.md#0x1_object_Object">object::Object</a>&lt;T&gt;, amount: u64): <a href="fungible_asset.md#0x1_fungible_asset_FuungibleAsset">fungible_asset::FuungibleAsset</a>
<pre><code><b>public</b> <b>fun</b> <a href="primary_store.md#0x1_primary_store_withdraw">withdraw</a>&lt;T: key&gt;(owner: &<a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>, metadata: <a href="object.md#0x1_object_Object">object::Object</a>&lt;T&gt;, amount: u64): <a href="fungible_asset.md#0x1_fungible_asset_FungibleAsset">fungible_asset::FungibleAsset</a>
</code></pre>


Expand All @@ -297,7 +308,7 @@ Withdraw <code>amount</code> of fungible asset from <code>store</code> by the ow
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="primary_store.md#0x1_primary_store_withdraw">withdraw</a>&lt;T: key&gt;(owner: &<a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>, metadata: Object&lt;T&gt;, amount: u64): FuungibleAsset {
<pre><code><b>public</b> <b>fun</b> <a href="primary_store.md#0x1_primary_store_withdraw">withdraw</a>&lt;T: key&gt;(owner: &<a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>, metadata: Object&lt;T&gt;, amount: u64): FungibleAsset {
<b>let</b> store = <a href="primary_store.md#0x1_primary_store">primary_store</a>(<a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer_address_of">signer::address_of</a>(owner), metadata);
<a href="fungible_asset.md#0x1_fungible_asset_withdraw">fungible_asset::withdraw</a>(owner, store, amount)
}
Expand All @@ -314,7 +325,7 @@ Withdraw <code>amount</code> of fungible asset from <code>store</code> by the ow
Deposit <code>amount</code> of fungible asset to the given account's primary store.


<pre><code><b>public</b> <b>fun</b> <a href="primary_store.md#0x1_primary_store_deposit">deposit</a>(owner: <b>address</b>, fa: <a href="fungible_asset.md#0x1_fungible_asset_FuungibleAsset">fungible_asset::FuungibleAsset</a>)
<pre><code><b>public</b> <b>fun</b> <a href="primary_store.md#0x1_primary_store_deposit">deposit</a>(owner: <b>address</b>, fa: <a href="fungible_asset.md#0x1_fungible_asset_FungibleAsset">fungible_asset::FungibleAsset</a>)
</code></pre>


Expand All @@ -323,7 +334,7 @@ Deposit <code>amount</code> of fungible asset to the given account's primary sto
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="primary_store.md#0x1_primary_store_deposit">deposit</a>(owner: <b>address</b>, fa: FuungibleAsset) <b>acquires</b> <a href="primary_store.md#0x1_primary_store_DeriveRefPod">DeriveRefPod</a> {
<pre><code><b>public</b> <b>fun</b> <a href="primary_store.md#0x1_primary_store_deposit">deposit</a>(owner: <b>address</b>, fa: FungibleAsset) <b>acquires</b> <a href="primary_store.md#0x1_primary_store_DeriveRefPod">DeriveRefPod</a> {
<b>let</b> metadata = <a href="fungible_asset.md#0x1_fungible_asset_asset_metadata">fungible_asset::asset_metadata</a>(&fa);
<b>let</b> store = <a href="primary_store.md#0x1_primary_store_ensure_primary_store_exists">ensure_primary_store_exists</a>(owner, metadata);
<a href="fungible_asset.md#0x1_fungible_asset_deposit">fungible_asset::deposit</a>(store, fa);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ module aptos_framework::create_signer {
friend aptos_framework::genesis;
friend aptos_framework::multisig_account;
friend aptos_framework::object;
friend aptos_framework::primary_store;

public(friend) native fun create_signer(addr: address): signer;
}
42 changes: 30 additions & 12 deletions aptos-move/framework/aptos-framework/sources/fungible_asset.move
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ module aptos_framework::fungible_asset {
const EFUNGIBLE_ASSET_AND_STORE_MISMATCH: u64 = 11;
/// Cannot destroy non-empty fungible assets.
const EAMOUNT_IS_NOT_ZERO: u64 = 12;
/// Burn ref and fungible asset do not match.
const EBURN_REF_AND_FUNGIBLE_ASSET_MISMATCH: u64 = 13;

#[resource_group_member(group = aptos_framework::object::ObjectGroup)]
/// Define the metadata required of an metadata to be fungible.
Expand Down Expand Up @@ -71,7 +73,7 @@ module aptos_framework::fungible_asset {
}

/// FungibleAsset can be passed into function for type safety and to guarantee a specific amount.
/// FungibleAsset cannot be stored directly and will have to be deposited back into a store.
/// FungibleAsset is ephermeral that it cannot be stored directly and will have to be deposited back into a store.
struct FungibleAsset {
metadata: Object<Metadata>,
amount: u64,
Expand Down Expand Up @@ -337,20 +339,25 @@ module aptos_framework::fungible_asset {
event::emit_event(&mut events.set_ungated_transfer_events, SetUngatedTransferEvent { transfer_allowed: allow });
}

public fun burn(ref: &BurnRef, fa: FungibleAsset) acquires Metadata {
let FungibleAsset {
metadata,
amount,
} = fa;
assert!(ref.metadata == metadata, error::invalid_argument(EBURN_REF_AND_FUNGIBLE_ASSET_MISMATCH));
decrease_supply(&metadata, amount);
}

/// Burn the `amount` of fungible metadata from the given store.
public fun burn<T: key>(
public fun burn_from<T: key>(
ref: &BurnRef,
store: Object<T>,
amount: u64
) acquires Metadata, FungibleAssetStore, FungibleAssetEvents {
let metadata = ref.metadata;
assert!(metadata == store_metadata(store), error::invalid_argument(EBURN_REF_AND_STORE_MISMATCH));
let store_addr = object::object_address(&store);
let FungibleAsset {
metadata,
amount,
} = withdraw_internal(store_addr, amount);
decrease_supply(&metadata, amount);
burn(ref, withdraw_internal(store_addr, amount));
}

/// Withdraw `amount` of fungible metadata from `store` ignoring `allow_ungated_transfer`.
Expand Down Expand Up @@ -413,10 +420,7 @@ module aptos_framework::fungible_asset {
assert!(amount == 0, error::invalid_argument(EAMOUNT_IS_NOT_ZERO));
}

fun deposit_internal<T: key>(
store: Object<T>,
fa: FungibleAsset
) acquires FungibleAssetStore, FungibleAssetEvents {
fun deposit_internal<T: key>(store: Object<T>, fa: FungibleAsset) acquires FungibleAssetStore, FungibleAssetEvents {
let FungibleAsset { metadata, amount } = fa;
let store_metadata = store_metadata(store);
assert!(metadata == store_metadata, error::invalid_argument(EFUNGIBLE_ASSET_AND_STORE_MISMATCH));
Expand Down Expand Up @@ -588,7 +592,7 @@ module aptos_framework::fungible_asset {
assert!(supply(test_token) == 100, 3);
deposit(aaron_store, fa);
// Burn
burn(&burn_ref, aaron_store, 30);
burn_from(&burn_ref, aaron_store, 30);
assert!(supply(test_token) == 70, 4);
// Transfer
transfer(creator, creator_store, aaron_store, 10);
Expand Down Expand Up @@ -632,4 +636,18 @@ module aptos_framework::fungible_asset {
assert!(!ungated_transfer_allowed(creator_store), 3);
assert!(!ungated_transfer_allowed(aaron_store), 4);
}

#[test(creator = @0xcafe)]
fun test_merge_and_exact(creator: &signer) acquires Metadata {
let (mint_ref, _transfer_ref, burn_ref, _) = create_fungible_asset(creator);
let fa = mint(&mint_ref, 100);
let cash = extract(&mut fa, 80);
assert!(fa.amount == 20, 1);
assert!(cash.amount == 80, 2);
let more_cash = extract(&mut fa, 20);
destroy_zero(fa);
merge(&mut cash, more_cash);
assert!(cash.amount == 100, 3);
burn(&burn_ref, cash);
}
}
Loading

0 comments on commit c767194

Please sign in to comment.