Skip to content

Commit

Permalink
Mintable (#16)
Browse files Browse the repository at this point in the history
* mintable
  • Loading branch information
ozgunozerk authored Jan 25, 2025
1 parent 17556a7 commit ac71efa
Show file tree
Hide file tree
Showing 21 changed files with 1,789 additions and 45 deletions.
6 changes: 3 additions & 3 deletions contracts/token/fungible/src/extensions/burnable/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
pub mod storage;
mod tests;
mod test;

use soroban_sdk::{contractclient, symbol_short, Address, Env};

Expand All @@ -16,7 +16,7 @@ use soroban_sdk::{contractclient, symbol_short, Address, Env};
/// Excluding the `burn` functionality from the `[FungibleToken]` trait
/// is a deliberate design choice to accommodate flexibility and customization
/// for various smart contract use cases.
#[contractclient(name = "FungibleBurnableTokenClient")]
#[contractclient(name = "FungibleBurnableClient")]
pub trait FungibleBurnable {
/// Destroys `amount` of tokens from `account`. Updates the total
/// supply accordingly.
Expand All @@ -40,7 +40,7 @@ pub trait FungibleBurnable {
/// # Notes
///
/// We recommend using the [`crate::extensions::burnable::storage::burn()`]
/// function the `storage` module when implementing this function.
/// function from the `storage` module when implementing this function.
fn burn(e: &Env, from: &Address, amount: i128);

/// Destroys `amount` of tokens from `account`. Updates the total
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ extern crate std;
use soroban_sdk::{contract, testutils::Address as _, Address, Env};

use crate::{
extensions::burnable::storage::{burn, burn_from},
storage::{allowance, approve, balance, mint, total_supply},
extensions::{
burnable::storage::{burn, burn_from},
mintable::storage::mint,
},
storage::{allowance, approve, balance, total_supply},
};

#[contract]
Expand Down
57 changes: 57 additions & 0 deletions contracts/token/fungible/src/extensions/mintable/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
pub mod storage;
mod test;

use soroban_sdk::{contractclient, symbol_short, Address, Env};

/// Mintable Trait for Fungible Token
///
/// The `Mintable` trait extends the `FungibleToken` trait to provide the
/// capability to mint tokens. This trait is designed to be used in conjunction
/// with the `FungibleToken` trait.
///
/// Excluding the `mint` functionality from the `[FungibleToken]` trait
/// is a deliberate design choice to accommodate flexibility and customization
/// for various smart contract use cases.
#[contractclient(name = "FungibleMintableClient")]
pub trait FungibleMintable {
/// Creates `amount` of tokens and assigns them to `account`. Updates
/// the total supply accordingly.
///
/// # Arguments
///
/// * `e` - Access to the Soroban environment.
/// * `account` - The address receiving the new tokens.
/// * `amount` - The amount of tokens to mint.
///
/// # Events
///
/// * topics - `["mint", account: Address]`
/// * data - `[amount: i128]`
///
/// # Notes
///
/// We recommend using the [`crate::extensions::mintable::storage::mint()`]
/// function from the `storage` module when implementing this function.
///
/// IMPORTANT: Please do not forget that, you probably will want to have
/// some authorization controls for minting tokens.
fn mint(e: &Env, account: &Address, amount: i128);
}
// ################## EVENTS ##################

/// Emits an event indicating a mint of tokens.
///
/// # Arguments
///
/// * `e` - Access to Soroban environment.
/// * `account` - The address receiving the new tokens.
/// * `amount` - The amount of tokens to mint.
///
/// # Events
///
/// * topics - `["mint", account: Address]`
/// * data - `[amount: i128]`
pub fn emit_mint(e: &Env, account: &Address, amount: i128) {
let topics = (symbol_short!("mint"), account);
e.events().publish(topics, amount)
}
36 changes: 36 additions & 0 deletions contracts/token/fungible/src/extensions/mintable/storage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use soroban_sdk::{Address, Env};

use crate::{extensions::mintable::emit_mint, storage::update};

/// Creates `amount` of tokens and assigns them to `account`. Updates
/// the total supply accordingly.
///
/// # Arguments
///
/// * `e` - Access to the Soroban environment.
/// * `account` - The address receiving the new tokens.
/// * `amount` - The amount of tokens to mint.
///
/// # Events
///
/// * topics - `["mint", account: Address]`
/// * data - `[amount: i128]`
///
/// # Notes
///
/// IMPORTANT: This function lacks authorization controls. It is the
/// responsibility of the implementer to establish appropriate access
/// controls to ensure that only authorized accounts can execute minting
/// operations. Failure to implement proper authorization could lead to
/// security vulnerabilities and unauthorized token creation.
///
/// You probably want to do something like this (pseudo-code):
///
/// ```ignore
/// let admin = read_administrator(e)?;
/// admin.require_auth()?;
/// ```
pub fn mint(e: &Env, account: &Address, amount: i128) {
update(e, None, Some(account), amount);
emit_mint(e, account, amount);
}
25 changes: 25 additions & 0 deletions contracts/token/fungible/src/extensions/mintable/test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#![cfg(test)]

extern crate std;

use soroban_sdk::{contract, testutils::Address as _, Address, Env};

use crate::{
extensions::mintable::storage::mint,
storage::{balance, total_supply},
};

#[contract]
struct MockContract;

#[test]
fn mint_works() {
let e = Env::default();
let address = e.register(MockContract, ());
let account = Address::generate(&e);
e.as_contract(&address, || {
mint(&e, &account, 100);
assert_eq!(balance(&e, &account), 100);
assert_eq!(total_supply(&e), 100);
});
}
1 change: 1 addition & 0 deletions contracts/token/fungible/src/extensions/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub mod burnable;
pub mod mintable;
20 changes: 0 additions & 20 deletions contracts/token/fungible/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,26 +242,6 @@ pub fn spend_allowance(e: &Env, owner: &Address, spender: &Address, amount: i128
}
}

/// TODO: move to mintable
/// Creates `amount` of tokens and assigns them to `account`. Updates
/// the total supply accordingly.
///
/// # Arguments
///
/// * `e` - Access to the Soroban environment.
/// * `account` - The address receiving the new tokens.
/// * `amount` - The amount of tokens to mint.
///
/// # Errors
/// TODO
///
/// # Events
/// TODO
pub fn mint(e: &Env, account: &Address, amount: i128) {
update(e, None, Some(account), amount)
// TODO: emit_mint
}

/// Transfers `amount` of tokens from `from` to `to`.
///
/// # Arguments
Expand Down
23 changes: 7 additions & 16 deletions contracts/token/fungible/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@ use soroban_sdk::{
vec, Address, Env, IntoVal,
};

use crate::storage::{
allowance, approve, balance, mint, set_allowance, spend_allowance, total_supply, transfer,
transfer_from, update, StorageKey, BALANCE_EXTEND_AMOUNT, INSTANCE_EXTEND_AMOUNT,
use crate::{
extensions::mintable::storage::mint,
storage::{
allowance, approve, balance, set_allowance, spend_allowance, total_supply, transfer,
transfer_from, update, StorageKey, BALANCE_EXTEND_AMOUNT, INSTANCE_EXTEND_AMOUNT,
},
};

#[contract]
Expand Down Expand Up @@ -58,18 +61,6 @@ fn bump_instance_works() {
});
}

#[test]
fn mint_works() {
let e = Env::default();
let address = e.register(MockContract, ());
let account = Address::generate(&e);
e.as_contract(&address, || {
mint(&e, &account, 100);
assert_eq!(balance(&e, &account), 100);
assert_eq!(total_supply(&e), 100);
});
}

#[test]
fn approve_with_event() {
let e = Env::default();
Expand Down Expand Up @@ -205,7 +196,7 @@ fn transfer_works() {
assert_eq!(balance(&e, &recipient), 50);

let events = e.events().all();
assert_eq!(events.len(), 1);
assert_eq!(events.len(), 2);
});
}

Expand Down
Loading

0 comments on commit ac71efa

Please sign in to comment.