Skip to content

Commit

Permalink
Allow modules to mint on their own authority (Sovereign-Labs#728)
Browse files Browse the repository at this point in the history
* Allow modules to mint on their own authority

* Fix typos in token::mint signature

* Allow modules to create tokens

* Fix nits

* lint

* Fix tests

* Fix tests
  • Loading branch information
preston-evans98 authored Aug 28, 2023
1 parent 2dae19d commit 216fb16
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ impl<

// Mint tokens and send them
self.bank
.mint(
.mint_from_eoa(
&coins,
context.sender(),
&C::new(reward_address),
Expand Down
39 changes: 26 additions & 13 deletions module-system/module-implementations/sov-bank/src/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl<C: sov_modules_api::Context> Bank<C> {
/// Creates a token from a set of configuration parameters.
/// Checks if a token already exists at that address. If so return an error.
#[allow(clippy::too_many_arguments)]
pub(crate) fn create_token(
pub fn create_token(
&self,
token_name: String,
salt: u64,
Expand All @@ -73,7 +73,7 @@ impl<C: sov_modules_api::Context> Bank<C> {
authorized_minters: Vec<C::Address>,
context: &C,
working_set: &mut WorkingSet<C::Storage>,
) -> Result<CallResponse> {
) -> Result<C::Address> {
let (token_address, token) = Token::<C>::create(
&token_name,
&[(minter_address, initial_balance)],
Expand All @@ -93,7 +93,7 @@ impl<C: sov_modules_api::Context> Bank<C> {
}

self.tokens.set(&token_address, &token, working_set);
Ok(CallResponse::default())
Ok(token_address)
}

/// Transfers the set of `coins` to the address specified by `to`.
Expand Down Expand Up @@ -137,33 +137,46 @@ impl<C: sov_modules_api::Context> Bank<C> {
Ok(CallResponse::default())
}

/// Mints the `coins` set by the address `minter_address`. If the token address doesn't exist return an error.
/// Mints the `coins`to the address `mint_to_address` using the externally owned account ("EOA") supplied by
/// `context.sender()` as the authorizer.
/// Returns an error if the token address doesn't exist or `context.sender()` is not authorized to mint tokens.
/// Calls the [`Token::mint`] function and update the `self.tokens` set to store the new balance.
pub fn mint_from_eoa(
&self,
coins: &Coins<C>,
mint_to_address: &C::Address,
context: &C,
working_set: &mut WorkingSet<C::Storage>,
) -> Result<()> {
self.mint(coins, mint_to_address, context.sender(), working_set)
}

/// Mints the `coins` to the address `mint_to_address` if `authorizer` is an allowed minter.
/// Returns an error if the token address doesn't exist or `context.sender()` is not authorized to mint tokens.
/// Calls the [`Token::mint`] function and update the `self.tokens` set to store the new minted address.
pub fn mint(
&self,
coins: &Coins<C>,
minter_address: &C::Address,
context: &C,
mint_to_address: &C::Address,
authorizer: &C::Address,
working_set: &mut WorkingSet<C::Storage>,
) -> Result<CallResponse> {
) -> Result<()> {
let context_logger = || {
format!(
"Failed mint coins({}) to {} by minter {}",
coins,
minter_address,
context.sender()
"Failed mint coins({}) to {} by authorizer {}",
coins, mint_to_address, authorizer
)
};
let mut token = self
.tokens
.get_or_err(&coins.token_address, working_set)
.with_context(context_logger)?;
token
.mint(context.sender(), minter_address, coins.amount, working_set)
.mint(authorizer, mint_to_address, coins.amount, working_set)
.with_context(context_logger)?;
self.tokens.set(&coins.token_address, &token, working_set);

Ok(CallResponse::default())
Ok(())
}

/// Tries to freeze the token address `token_address`.
Expand Down
28 changes: 17 additions & 11 deletions module-system/module-implementations/sov-bank/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ mod utils;

/// Specifies the call methods using in that module.
pub use call::CallMessage;
use sov_modules_api::{Error, ModuleInfo};
use sov_modules_api::{CallResponse, Error, ModuleInfo};
use sov_state::WorkingSet;
use token::Token;
/// Specifies an interfact to interact with tokens.
Expand Down Expand Up @@ -80,15 +80,18 @@ impl<C: sov_modules_api::Context> sov_modules_api::Module for Bank<C> {
initial_balance,
minter_address,
authorized_minters,
} => Ok(self.create_token(
token_name,
salt,
initial_balance,
minter_address,
authorized_minters,
context,
working_set,
)?),
} => {
self.create_token(
token_name,
salt,
initial_balance,
minter_address,
authorized_minters,
context,
working_set,
)?;
Ok(CallResponse::default())
}

call::CallMessage::Transfer { to, coins } => {
Ok(self.transfer(to, coins, context, working_set)?)
Expand All @@ -99,7 +102,10 @@ impl<C: sov_modules_api::Context> sov_modules_api::Module for Bank<C> {
call::CallMessage::Mint {
coins,
minter_address,
} => Ok(self.mint(&coins, &minter_address, context, working_set)?),
} => {
self.mint_from_eoa(&coins, &minter_address, context, working_set)?;
Ok(CallResponse::default())
}

call::CallMessage::Freeze { token_address } => {
Ok(self.freeze(token_address, context, working_set)?)
Expand Down
14 changes: 7 additions & 7 deletions module-system/module-implementations/sov-bank/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,32 +164,32 @@ impl<C: sov_modules_api::Context> Token<C> {
Ok(())
}

/// Mints a given `amount` of token sent by `sender` to the specified `minter_address`.
/// Mints a given `amount` of token sent by `sender` to the specified `mint_to_address`.
/// Checks that the `authorized_minters` set is not empty for the token and that the `sender`
/// is an `authorized_minter`. If so, update the balances of token for the `minter_address` by
/// is an `authorized_minter`. If so, update the balances of token for the `mint_to_address` by
/// adding the minted tokens. Updates the `total_supply` of that token.
pub(crate) fn mint(
&mut self,
sender: &C::Address,
minter_address: &C::Address,
authorizer: &C::Address,
mint_to_address: &C::Address,
amount: Amount,
working_set: &mut WorkingSet<C::Storage>,
) -> Result<()> {
if self.authorized_minters.is_empty() {
bail!("Attempt to mint frozen token {}", self.name)
}

self.is_authorized_minter(sender)?;
self.is_authorized_minter(authorizer)?;
let to_balance: Amount = self
.balances
.get(minter_address, working_set)
.get(mint_to_address, working_set)
.unwrap_or_default()
.checked_add(amount)
.ok_or(anyhow::Error::msg(
"Account balance overflow in the mint method of bank module",
))?;

self.balances.set(minter_address, &to_balance, working_set);
self.balances.set(mint_to_address, &to_balance, working_set);
self.total_supply = self
.total_supply
.checked_add(amount)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ fn freeze_token() {
assert!(chain.next().is_none());
assert_eq!(
format!(
"Failed mint coins(token_address={} amount={}) to {} by minter {}",
"Failed mint coins(token_address={} amount={}) to {} by authorizer {}",
token_address, mint_amount, new_holder, minter_address
),
message_1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ fn mint_token() {

assert_eq!(
format!(
"Failed mint coins(token_address={} amount={}) to {} by minter {}",
"Failed mint coins(token_address={} amount={}) to {} by authorizer {}",
token_address, mint_amount, new_holder, unauthorized_address
),
message_1
Expand Down Expand Up @@ -155,7 +155,7 @@ fn mint_token() {
assert!(chain.next().is_none());
assert_eq!(
format!(
"Failed mint coins(token_address={} amount={}) to {} by minter {}",
"Failed mint coins(token_address={} amount={}) to {} by authorizer {}",
token_address, mint_amount, new_holder, minter_address,
),
message_1
Expand Down Expand Up @@ -223,7 +223,7 @@ fn mint_token() {
assert!(chain.next().is_none());
assert_eq!(
format!(
"Failed mint coins(token_address={} amount={}) to {} by minter {}",
"Failed mint coins(token_address={} amount={}) to {} by authorizer {}",
token_address,
u64::MAX,
new_holder,
Expand Down Expand Up @@ -262,7 +262,7 @@ fn mint_token() {
assert!(chain.next().is_none());
assert_eq!(
format!(
"Failed mint coins(token_address={} amount={}) to {} by minter {}",
"Failed mint coins(token_address={} amount={}) to {} by authorizer {}",
token_address,
u64::MAX - 1,
new_holder,
Expand Down

0 comments on commit 216fb16

Please sign in to comment.