Skip to content

Commit

Permalink
add back managed_coin example
Browse files Browse the repository at this point in the history
  • Loading branch information
lightmark committed Apr 12, 2023
1 parent 1ac7196 commit af43aab
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/// A coin example using managed_fungible_asset.
module fungible_asset_extension::coin_example {
use aptos_framework::object;
use aptos_framework::fungible_asset::{Metadata, FungibleAsset};
Expand Down
154 changes: 154 additions & 0 deletions aptos-move/move-examples/fungible_asset/sources/managed_coin.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/// A 2-in-1 module that combines managed_fungible_asset and coin_example into one module that when deployed, the
/// deployer will be creating a new managed fungible asset with the hardcoded supply config, name, symbol, and decimals.
/// The address of the asset can be obtained via get_metadata().
module fungible_asset_extension::managed_coin {
use aptos_framework::fungible_asset::{Self, MintRef, TransferRef, BurnRef, Metadata, FungibleAsset};
use aptos_framework::object::{Self, Object};
use aptos_framework::primary_store;
use std::error;
use std::signer;
use std::string::utf8;
use std::option;

/// Only fungible asset metadata owner can make changes.
const ENOT_OWNER: u64 = 1;

const ASSET_SYMBOL: vector<u8> = b"APT";

#[resource_group_member(group = aptos_framework::object::ObjectGroup)]
/// Hold refs to control the minting, transfer and burning of fungible assets.
struct ManagedFungibleAsset has key {
mint_ref: MintRef,
transfer_ref: TransferRef,
burn_ref: BurnRef,
}

/// Initialize metadata object and store the refs.
fun init_module(admin: &signer) {
let constructor_ref = &object::create_named_object(admin, ASSET_SYMBOL);
primary_store::create_primary_store_enabled_fungible_asset(
constructor_ref,
option::some(option::none()),
utf8(b"Aptos Token"), /* name */
utf8(ASSET_SYMBOL), /* symbol */
8, /* decimals */
);

// Create mint/burn/transfer refs to allow creator to manage the fungible asset.
let mint_ref = fungible_asset::generate_mint_ref(constructor_ref);
let burn_ref = fungible_asset::generate_burn_ref(constructor_ref);
let transfer_ref = fungible_asset::generate_transfer_ref(constructor_ref);
let metadata_object_signer = object::generate_signer(constructor_ref);
move_to(
&metadata_object_signer,
ManagedFungibleAsset { mint_ref, transfer_ref, burn_ref }
)
}

#[view]
/// Return the address of the managed fungible asset that's created when this module is deployed.
public fun get_metadata(): Object<Metadata> {
let asset_address = object::create_object_address(&@fungible_asset_extension, ASSET_SYMBOL);
object::address_to_object<Metadata>(asset_address)
}

/// Mint as the owner of metadata object.
public entry fun mint(admin: &signer, amount: u64, to: address) acquires ManagedFungibleAsset {
let asset = get_metadata();
let managed_fungible_asset = authorized_borrow_refs(admin, asset);
let to_wallet = primary_store::ensure_primary_store_exists(to, asset);
let fa = fungible_asset::mint(&managed_fungible_asset.mint_ref, amount);
fungible_asset::deposit_with_ref(&managed_fungible_asset.transfer_ref, to_wallet, fa);
}

/// Transfer as the owner of metadata object ignoring `allow_ungated_transfer` field.
public entry fun transfer(admin: &signer, from: address, to: address, amount: u64) acquires ManagedFungibleAsset {
let asset = get_metadata();
let transfer_ref = &authorized_borrow_refs(admin, asset).transfer_ref;
let from_wallet = primary_store::ensure_primary_store_exists(from, asset);
let to_wallet = primary_store::ensure_primary_store_exists(to, asset);
fungible_asset::transfer_with_ref(transfer_ref, from_wallet, to_wallet, amount);
}

/// Burn fungible assets as the owner of metadata object.
public entry fun burn(admin: &signer, from: address, amount: u64) acquires ManagedFungibleAsset {
let asset = get_metadata();
let burn_ref = &authorized_borrow_refs(admin, asset).burn_ref;
let from_wallet = primary_store::ensure_primary_store_exists(from, asset);
fungible_asset::burn_from(burn_ref, from_wallet, amount);
}

/// Freeze an account so it cannot transfer or receive fungible assets.
public entry fun freeze_account(admin: &signer, account: address) acquires ManagedFungibleAsset {
let asset = get_metadata();
let transfer_ref = &authorized_borrow_refs(admin, asset).transfer_ref;
let wallet = primary_store::ensure_primary_store_exists(account, asset);
fungible_asset::set_ungated_transfer(transfer_ref, wallet, false);
}

/// Unfreeze an account so it can transfer or receive fungible assets.
public entry fun unfreeze_account(admin: &signer, account: address) acquires ManagedFungibleAsset {
let asset = get_metadata();
let transfer_ref = &authorized_borrow_refs(admin, asset).transfer_ref;
let wallet = primary_store::ensure_primary_store_exists(account, asset);
fungible_asset::set_ungated_transfer(transfer_ref, wallet, true);
}

/// Withdraw as the owner of metadata object ignoring `allow_ungated_transfer` field.
public fun withdraw(admin: &signer, amount: u64, from: address): FungibleAsset acquires ManagedFungibleAsset {
let asset = get_metadata();
let transfer_ref = &authorized_borrow_refs(admin, asset).transfer_ref;
let from_wallet = primary_store::ensure_primary_store_exists(from, asset);
fungible_asset::withdraw_with_ref(transfer_ref, from_wallet, amount)
}

/// Deposit as the owner of metadata object ignoring `allow_ungated_transfer` field.
public fun deposit(admin: &signer, to: address, fa: FungibleAsset) acquires ManagedFungibleAsset {
let asset = get_metadata();
let transfer_ref = &authorized_borrow_refs(admin, asset).transfer_ref;
let to_wallet = primary_store::ensure_primary_store_exists(to, asset);
fungible_asset::deposit_with_ref(transfer_ref, to_wallet, fa);
}

/// Borrow the immutable reference of the refs of `metadata`.
/// This validates that the signer is the metadata object's owner.
inline fun authorized_borrow_refs(
owner: &signer,
asset: Object<Metadata>,
): &ManagedFungibleAsset acquires ManagedFungibleAsset {
assert!(object::is_owner(asset, signer::address_of(owner)), error::permission_denied(ENOT_OWNER));
borrow_global<ManagedFungibleAsset>(object::object_address(&asset))
}

#[test(creator = @0xcafe)]
fun test_basic_flow(
creator: &signer,
) acquires ManagedFungibleAsset {
init_module(creator);
let creator_address = signer::address_of(creator);
let aaron_address = @0xface;

mint(creator, 100, creator_address);
let asset = get_metadata();
assert!(primary_store::balance(creator_address, asset) == 100, 4);
freeze_account(creator, creator_address);
assert!(!primary_store::ungated_balance_transfer_allowed(creator_address, asset), 5);
transfer(creator, creator_address, aaron_address, 10);
assert!(primary_store::balance(aaron_address, asset) == 10, 6);

unfreeze_account(creator, creator_address);
assert!(primary_store::ungated_balance_transfer_allowed(creator_address, asset), 7);
burn(creator, creator_address, 90);
}

#[test(creator = @0xcafe, aaron = @0xface)]
#[expected_failure(abort_code = 0x50001, location = Self)]
fun test_permission_denied(
creator: &signer,
aaron: &signer
) acquires ManagedFungibleAsset {
init_module(creator);
let creator_address = signer::address_of(creator);
mint(aaron, 100, creator_address);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/// By deploying this module, the deployer will be creating a new managed fungible asset with the hardcoded
/// maximum supply, name, symbol, and decimals. The address of the asset can be obtained via get_asset().
/// The deployer will also become the initial admin and can mint/burn/freeze/unfreeze accounts.
/// By deploying this module, the deployer provide an extension layer upon fungible asset that helps manage
/// the refs for the deployer, who is set to be the initial admin that can mint/burn/freeze/unfreeze accounts.
/// The admin can transfer the asset via object::transfer() at any point to set a new admin.
module fungible_asset_extension::managed_fungible_asset {
use aptos_framework::fungible_asset::{Self, MintRef, TransferRef, BurnRef, FungibleAsset, Metadata};
Expand Down

0 comments on commit af43aab

Please sign in to comment.