Skip to content

Commit

Permalink
[sui framework] Balance manages Supply; TreasuryCap -> Supply, (Myste…
Browse files Browse the repository at this point in the history
…nLabs#2656)

- adds Supply to balance module
- Coin is no longer unique in TreasuryCaps - other coin impl can do it to
- coin::withdraw -> coin::take
- coin::deposit -> coin::put
- examples updated with new apis
- governance now operates on Supply
  • Loading branch information
damirka authored Jun 29, 2022
1 parent 317485a commit a6156ae
Show file tree
Hide file tree
Showing 21 changed files with 183 additions and 132 deletions.
68 changes: 44 additions & 24 deletions crates/sui-framework/sources/balance.move
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
// Copyright (c) 2022, Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

/// A storable handler for `Coin` balances.
/// Allows separation of the transferable `Coin` type and the storable
/// `Balance` eliminating the need to create new IDs for each application
/// that needs to hold coins.
/// A storable handler for Balances in general. Is used in the `Coin`
/// module to allow balance operations and can be used to implement
/// custom coins with `Supply` and `Balance`s.
module sui::balance {
friend sui::coin;
friend sui::sui_system;

/// For when trying to destroy a non-zero balance.
const ENonZero: u64 = 0;

/// For when an overflow is happening on Supply operations.
const EOverflow: u64 = 1;

/// For when trying to withdraw more than there is.
const ENotEnough: u64 = 0;
const ENotEnough: u64 = 2;

/// A Supply of T. Used for minting and burning.
/// Wrapped into a `TreasuryCap` in the `Coin` module.
struct Supply<phantom T> has store {
value: u64
}

/// Storable balance - an inner struct of a Coin type.
/// Can be used to store coins which don't need to have the
Expand All @@ -27,15 +33,41 @@ module sui::balance {
self.value
}

/// Get the `Supply` value.
public fun supply_value<T>(supply: &Supply<T>): u64 {
supply.value
}

/// Create a new supply for type T.
public fun create_supply<T: drop>(_witness: T): Supply<T> {
Supply { value: 0 }
}

/// Increase supply by `value` and create a new `Balance<T>` with this value.
public fun increase_supply<T>(self: &mut Supply<T>, value: u64): Balance<T> {
assert!(value < (18446744073709551615u64 - self.value), EOverflow);
self.value = self.value + value;
Balance { value }
}

/// Burn a Balance<T> and decrease Supply<T>.
public fun decrease_supply<T>(self: &mut Supply<T>, balance: Balance<T>): u64 {
let Balance { value } = balance;
assert!(self.value >= value, EOverflow);
self.value = self.value - value;
value
}

/// Create a zero `Balance` for type `T`.
public fun zero<T>(): Balance<T> {
Balance { value: 0 }
}

/// Join two balances together.
public fun join<T>(self: &mut Balance<T>, balance: Balance<T>) {
public fun join<T>(self: &mut Balance<T>, balance: Balance<T>): u64 {
let Balance { value } = balance;
self.value = self.value + value;
value
}

/// Split a `Balance` and take a sub balance from it.
Expand All @@ -51,29 +83,17 @@ module sui::balance {
let Balance { value: _ } = balance;
}

/// Can only be called by sui::coin.
/// Create a `Balance` with a predefined value; required for minting new `Coin`s.
public(friend) fun create_with_value<T>(value: u64): Balance<T> {
Balance { value }
}

/// Can only be called by sui::coin.
/// Destroy a `Balance` returning its value. Required for burning `Coin`s
public(friend) fun destroy<T>(self: Balance<T>): u64 {
let Balance { value } = self;
value
}

#[test_only]
/// Create a `Balance` of any coin for testing purposes.
public fun create_for_testing<T>(value: u64): Balance<T> {
create_with_value(value)
Balance { value }
}

#[test_only]
/// Destroy a `Balance` with any value in it for testing purposes.
public fun destroy_for_testing<T>(self: Balance<T>): u64 {
destroy(self)
let Balance { value } = self;
value
}
}

Expand Down
87 changes: 56 additions & 31 deletions crates/sui-framework/sources/coin.move
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

module sui::coin {
use sui::balance::{Self, Balance};
use sui::balance::{Self, Balance, Supply};
use sui::id::{Self, VersionedID};
use sui::transfer;
use sui::tx_context::{Self, TxContext};
Expand All @@ -18,10 +18,44 @@ module sui::coin {
/// coins of type `T`. Transferable
struct TreasuryCap<phantom T> has key, store {
id: VersionedID,
total_supply: u64
total_supply: Supply<T>
}

// === Balance accessors and type morphing methods ===
// === Supply <-> TreasuryCap morphing and accessors ===

/// Return the total number of `T`'s in circulation.
public fun total_supply<T>(cap: &TreasuryCap<T>): u64 {
balance::supply_value(&cap.total_supply)
}

/// Wrap a `Supply` into a transferable `TreasuryCap`.
public fun treasury_from_supply<T>(total_supply: Supply<T>, ctx: &mut TxContext): TreasuryCap<T> {
TreasuryCap { id: tx_context::new_id(ctx), total_supply }
}

/// Unwrap `TreasuryCap` getting the `Supply`.
public fun treasury_into_supply<T>(treasury: TreasuryCap<T>): Supply<T> {
let TreasuryCap { id, total_supply } = treasury;
id::delete(id);
total_supply
}

/// Get immutable reference to the treasury's `Supply`.
public fun supply<T>(treasury: &mut TreasuryCap<T>): &Supply<T> {
&treasury.total_supply
}

/// Get mutable reference to the treasury's `Supply`.
public fun supply_mut<T>(treasury: &mut TreasuryCap<T>): &mut Supply<T> {
&mut treasury.total_supply
}

// === Balance <-> Coin accessors and type morphing ===

/// Public getter for the coin's value
public fun value<T>(self: &Coin<T>): u64 {
balance::value(&self.balance)
}

/// Get immutable reference to the balance of a coin.
public fun balance<T>(coin: &Coin<T>): &Balance<T> {
Expand All @@ -45,10 +79,9 @@ module sui::coin {
balance
}

/// Subtract `value` from `Balance` and create a new coin
/// worth `value` with ID `id`.
/// Take a `Coin` worth of `value` from `Balance`.
/// Aborts if `value > balance.value`
public fun withdraw<T>(
public fun take<T>(
balance: &mut Balance<T>, value: u64, ctx: &mut TxContext,
): Coin<T> {
Coin {
Expand All @@ -57,8 +90,8 @@ module sui::coin {
}
}

/// Deposit a `Coin` to the `Balance`
public fun deposit<T>(balance: &mut Balance<T>, coin: Coin<T>) {
/// Put a `Coin<T>` to the `Balance<T>`.
public fun put<T>(balance: &mut Balance<T>, coin: Coin<T>) {
balance::join(balance, into_balance(coin));
}

Expand Down Expand Up @@ -95,16 +128,11 @@ module sui::coin {
vector::destroy_empty(coins)
}

/// Public getter for the coin's value
public fun value<T>(self: &Coin<T>): u64 {
balance::value(&self.balance)
}

/// Destroy a coin with value zero
public fun destroy_zero<T>(c: Coin<T>) {
let Coin { id, balance } = c;
id::delete(id);
balance::destroy_zero(balance);
balance::destroy_zero(balance)
}

// === Registering new coin types and managing the coin supply ===
Expand All @@ -122,10 +150,13 @@ module sui::coin {
/// module initializer with a `witness` object that can only be created
/// in the initializer).
public fun create_currency<T: drop>(
_witness: T,
witness: T,
ctx: &mut TxContext
): TreasuryCap<T> {
TreasuryCap { id: tx_context::new_id(ctx), total_supply: 0 }
TreasuryCap {
id: tx_context::new_id(ctx),
total_supply: balance::create_supply(witness)
}
}

/// Create a coin worth `value`. and increase the total supply
Expand All @@ -135,7 +166,7 @@ module sui::coin {
): Coin<T> {
Coin {
id: tx_context::new_id(ctx),
balance: mint_balance(cap, value)
balance: balance::increase_supply(&mut cap.total_supply, value)
}
}

Expand All @@ -145,23 +176,15 @@ module sui::coin {
public fun mint_balance<T>(
cap: &mut TreasuryCap<T>, value: u64
): Balance<T> {
cap.total_supply = cap.total_supply + value;
balance::create_with_value(value)
balance::increase_supply(&mut cap.total_supply, value)
}

/// Destroy the coin `c` and decrease the total supply in `cap`
/// accordingly.
public fun burn<T>(cap: &mut TreasuryCap<T>, c: Coin<T>): u64 {
let Coin { id, balance } = c;
let value = balance::destroy<T>(balance);
id::delete(id);
cap.total_supply = cap.total_supply - value;
value
}

/// Return the total number of `T`'s in circulation
public fun total_supply<T>(cap: &TreasuryCap<T>): u64 {
cap.total_supply
balance::decrease_supply(&mut cap.total_supply, balance)
}

/// Give away the treasury cap to `recipient`
Expand All @@ -188,14 +211,16 @@ module sui::coin {
public entry fun split_and_transfer<T>(
c: &mut Coin<T>, amount: u64, recipient: address, ctx: &mut TxContext
) {
transfer::transfer(withdraw(&mut c.balance, amount, ctx), recipient)
transfer::transfer(take(&mut c.balance, amount, ctx), recipient)
}

/// Split coin `self` to two coins, one with balance `split_amount`,
/// and the remaining balance is left is `self`.
public entry fun split<T>(self: &mut Coin<T>, split_amount: u64, ctx: &mut TxContext) {
let new_coin = withdraw(&mut self.balance, split_amount, ctx);
transfer::transfer(new_coin, tx_context::sender(ctx));
transfer::transfer(
take(&mut self.balance, split_amount, ctx),
tx_context::sender(ctx)
)
}

/// Split coin `self` into multiple coins, each with balance specified
Expand All @@ -214,7 +239,7 @@ module sui::coin {
#[test_only]
/// Mint coins of any type for (obviously!) testing purposes only
public fun mint_for_testing<T>(value: u64, ctx: &mut TxContext): Coin<T> {
Coin { id: tx_context::new_id(ctx), balance: balance::create_with_value(value) }
Coin { id: tx_context::new_id(ctx), balance: balance::create_for_testing(value) }
}

#[test_only]
Expand Down
12 changes: 6 additions & 6 deletions crates/sui-framework/sources/governance/genesis.move
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
module sui::genesis {
use std::vector;

use sui::coin;
use sui::balance;
use sui::sui;
use sui::sui_system;
use sui::tx_context::TxContext;
Expand Down Expand Up @@ -32,10 +32,10 @@ module sui::genesis {
validator_names: vector<vector<u8>>,
validator_net_addresses: vector<vector<u8>>,
validator_stakes: vector<u64>,
ctx: &mut TxContext,
_ctx: &mut TxContext,
) {
let treasury_cap = sui::new(ctx);
let storage_fund = coin::mint_balance(&mut treasury_cap, INIT_STORAGE_FUND);
let sui_supply = sui::new();
let storage_fund = balance::increase_supply(&mut sui_supply, INIT_STORAGE_FUND);
let validators = vector::empty();
let count = vector::length(&validator_pubkeys);
assert!(
Expand All @@ -57,13 +57,13 @@ module sui::genesis {
pubkey,
name,
net_address,
coin::mint_balance(&mut treasury_cap, stake),
balance::increase_supply(&mut sui_supply, stake),
));
i = i + 1;
};
sui_system::create(
validators,
treasury_cap,
sui_supply,
storage_fund,
INIT_MAX_VALIDATOR_COUNT,
INIT_MIN_VALIDATOR_STAKE,
Expand Down
16 changes: 8 additions & 8 deletions crates/sui-framework/sources/governance/sui_system.move
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// SPDX-License-Identifier: Apache-2.0

module sui::sui_system {
use sui::balance::{Self, Balance};
use sui::coin::{Self, Coin, TreasuryCap};
use sui::balance::{Self, Balance, Supply};
use sui::coin::{Self, Coin};
use sui::delegation::{Self, Delegation};
use sui::epoch_reward_record::{Self, EpochRewardRecord};
use sui::id::{Self, VersionedID};
Expand Down Expand Up @@ -40,7 +40,7 @@ module sui::sui_system {
/// Contains all information about the validators.
validators: ValidatorSet,
/// The SUI treasury capability needed to mint SUI.
treasury_cap: TreasuryCap<SUI>,
sui_supply: Supply<SUI>,
/// The storage fund.
storage_fund: Balance<SUI>,
/// A list of system config parameters.
Expand All @@ -56,7 +56,7 @@ module sui::sui_system {
/// This function will be called only once in Genesis.
public(friend) fun create(
validators: vector<Validator>,
treasury_cap: TreasuryCap<SUI>,
sui_supply: Supply<SUI>,
storage_fund: Balance<SUI>,
max_validator_candidate_count: u64,
min_validator_stake: u64,
Expand All @@ -67,7 +67,7 @@ module sui::sui_system {
id: id::get_sui_system_state_object_id(),
epoch: 0,
validators: validator_set::new(validators),
treasury_cap,
sui_supply,
storage_fund,
parameters: SystemParameters {
min_validator_stake,
Expand Down Expand Up @@ -237,8 +237,8 @@ module sui::sui_system {
// Validator will make a special system call with sender set as 0x0.
assert!(tx_context::sender(ctx) == @0x0, 0);

let storage_reward = balance::create_with_value(storage_charge);
let computation_reward = balance::create_with_value(computation_charge);
let storage_reward = balance::increase_supply(&mut self.sui_supply, storage_charge);
let computation_reward = balance::increase_supply(&mut self.sui_supply, computation_charge);

let delegation_stake = validator_set::delegation_stake(&self.validators);
let validator_stake = validator_set::validator_stake(&self.validators);
Expand Down Expand Up @@ -268,7 +268,7 @@ module sui::sui_system {
);
// Because of precision issues with integer divisions, we expect that there will be some
// remaining balance in `computation_reward`. All of these go to the storage fund.
balance::join(&mut self.storage_fund, computation_reward)
balance::join(&mut self.storage_fund, computation_reward);
}

/// Return the current epoch number. Useful for applications that need a coarse-grained concept of time,
Expand Down
2 changes: 1 addition & 1 deletion crates/sui-framework/sources/governance/validator.move
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ module sui::validator {
balance::join(&mut self.stake, pending_stake);
};
if (self.pending_withdraw > 0) {
let coin = coin::withdraw(&mut self.stake, self.pending_withdraw, ctx);
let coin = coin::take(&mut self.stake, self.pending_withdraw, ctx);
coin::transfer(coin, self.metadata.sui_address);
self.pending_withdraw = 0;
};
Expand Down
Loading

0 comments on commit a6156ae

Please sign in to comment.