forked from aptos-labs/aptos-core
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ManagedCoin contains a simple approach to creating and managing coins. It is intended primarily for demonstration purposes. Closes: aptos-labs#1015
- Loading branch information
1 parent
b80dc23
commit 88091bc
Showing
2 changed files
with
184 additions
and
1 deletion.
There are no files selected for viewing
179 changes: 179 additions & 0 deletions
179
aptos-move/framework/aptos-framework/sources/ManagedCoin.move
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,179 @@ | ||
/// ManagedCoin is built to make a simple walkthrough of the Coins module. | ||
/// It contains scripts you will need to initialize, mint, burn, transfer coins. | ||
/// By utilizing this current module, a developer can create his own coin and care less about mint and burn capabilities, | ||
module AptosFramework::ManagedCoin { | ||
use Std::ASCII; | ||
use Std::Errors; | ||
use Std::Signer; | ||
|
||
use AptosFramework::Coin::{Self, BurnCapability, MintCapability}; | ||
|
||
// | ||
// Errors | ||
// | ||
|
||
/// When no capabilities (burn/mint) found on an account. | ||
const ENO_CAPABILITIES: u64 = 0; | ||
|
||
// | ||
// Data structures | ||
// | ||
|
||
/// Capabilities resource storing mint and burn capabilities. | ||
/// The resource is stored on the account that initialized coin `CoinType`. | ||
struct Capabilities<phantom CoinType> has key { | ||
mint_cap: MintCapability<CoinType>, | ||
burn_cap: BurnCapability<CoinType>, | ||
} | ||
|
||
// | ||
// Public functions | ||
// | ||
|
||
/// Withdraw an `amount` of coin `CoinType` from `account` and burn it. | ||
public(script) fun burn<CoinType>( | ||
account: &signer, | ||
amount: u64, | ||
) acquires Capabilities { | ||
let account_addr = Signer::address_of(account); | ||
|
||
assert!( | ||
exists<Capabilities<CoinType>>(account_addr), | ||
Errors::not_published(ENO_CAPABILITIES), | ||
); | ||
|
||
let capabilities = borrow_global<Capabilities<CoinType>>(account_addr); | ||
|
||
let to_burn = Coin::withdraw<CoinType>(account, amount); | ||
Coin::burn(to_burn, &capabilities.burn_cap); | ||
} | ||
|
||
/// Initialize new coin `CoinType` in Aptos Blockchain. | ||
/// Mint and Burn Capabilities will be stored under `account` in `Capabilities` resource. | ||
public(script) fun initialize<CoinType>( | ||
account: &signer, | ||
name: vector<u8>, | ||
symbol: vector<u8>, | ||
decimals: u64, | ||
monitor_supply: bool, | ||
) { | ||
let (mint_cap, burn_cap) = Coin::initialize<CoinType>( | ||
account, | ||
ASCII::string(name), | ||
ASCII::string(symbol), | ||
decimals, | ||
monitor_supply, | ||
); | ||
|
||
move_to(account, Capabilities<CoinType>{ | ||
mint_cap, | ||
burn_cap, | ||
}); | ||
} | ||
|
||
/// Create new coins `CoinType` and deposit them into dst_addr's account. | ||
public(script) fun mint<CoinType>( | ||
account: &signer, | ||
dst_addr: address, | ||
amount: u64, | ||
) acquires Capabilities { | ||
let account_addr = Signer::address_of(account); | ||
|
||
assert!( | ||
exists<Capabilities<CoinType>>(account_addr), | ||
Errors::not_published(ENO_CAPABILITIES), | ||
); | ||
|
||
let capabilities = borrow_global<Capabilities<CoinType>>(account_addr); | ||
let coins_minted = Coin::mint(amount, &capabilities.mint_cap); | ||
Coin::deposit(dst_addr, coins_minted); | ||
} | ||
|
||
/// Creating a resource that stores balance of `CoinType` on user's account, withdraw and deposit event handlers. | ||
/// Required if user wants to start accepting deposits of `CoinType` in his account. | ||
public(script) fun register<CoinType>(account: &signer) { | ||
Coin::register<CoinType>(account); | ||
} | ||
|
||
// | ||
// Tests | ||
// | ||
|
||
#[test_only] | ||
use Std::Option; | ||
|
||
#[test_only] | ||
struct FakeMoney { } | ||
|
||
#[test(source = @0x1, destination = @0x2)] | ||
public(script) fun test_end_to_end( | ||
source: signer, | ||
destination: signer, | ||
) acquires Capabilities { | ||
let source_addr = Signer::address_of(&source); | ||
let destination_addr = Signer::address_of(&destination); | ||
|
||
initialize<FakeMoney>( | ||
&source, | ||
b"Fake Money", | ||
b"FMD", | ||
10, | ||
true | ||
); | ||
assert!(Coin::is_registered<FakeMoney>(), 0); | ||
|
||
register<FakeMoney>(&source); | ||
register<FakeMoney>(&destination); | ||
|
||
mint<FakeMoney>(&source, source_addr, 50); | ||
mint<FakeMoney>(&source, destination_addr, 10); | ||
assert!(Coin::balance<FakeMoney>(source_addr) == 50, 1); | ||
assert!(Coin::balance<FakeMoney>(destination_addr) == 10, 2); | ||
|
||
let supply = Coin::supply<FakeMoney>(); | ||
assert!(Option::is_some(&supply), 1); | ||
assert!(Option::extract(&mut supply) == 60, 2); | ||
|
||
Coin::transfer<FakeMoney>(&source, destination_addr, 10); | ||
assert!(Coin::balance<FakeMoney>(source_addr) == 40, 3); | ||
assert!(Coin::balance<FakeMoney>(destination_addr) == 20, 4); | ||
|
||
burn<FakeMoney>(&source, 40); | ||
|
||
assert!(Coin::balance<FakeMoney>(source_addr) == 0, 1); | ||
|
||
let new_supply = Coin::supply<FakeMoney>(); | ||
assert!(Option::extract(&mut new_supply) == 20, 2); | ||
} | ||
|
||
#[test(source = @0x1, destination = @0x2)] | ||
#[expected_failure(abort_code = 5)] | ||
public(script) fun fail_mint( | ||
source: signer, | ||
destination: signer, | ||
) acquires Capabilities { | ||
let source_addr = Signer::address_of(&source); | ||
|
||
initialize<FakeMoney>(&source, b"Fake money", b"FMD", 1, true); | ||
register<FakeMoney>(&source); | ||
register<FakeMoney>(&destination); | ||
|
||
mint<FakeMoney>(&destination, source_addr, 100); | ||
} | ||
|
||
#[test(source = @0x1, destination = @0x2)] | ||
#[expected_failure(abort_code = 5)] | ||
public(script) fun fail_burn( | ||
source: signer, | ||
destination: signer, | ||
) acquires Capabilities { | ||
let source_addr = Signer::address_of(&source); | ||
|
||
initialize<FakeMoney>(&source, b"Fake money", b"FMD", 1, true); | ||
register<FakeMoney>(&source); | ||
register<FakeMoney>(&destination); | ||
|
||
mint<FakeMoney>(&source, source_addr, 100); | ||
burn<FakeMoney>(&destination, 10); | ||
} | ||
} |
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