module LibraCoin {
// A resource representing the Libra coin
resource T {
// The value of the coin. May be zero
value: u64,
}
// A singleton resource that grants access to `LibraCoin.mint`. Only the Association has one.
resource MintCapability {}
resource MarketCap {
// The sum of the values of all LibraCoin.T resources in the system
total_value: u64,
}
// Return a reference to the MintCapability published under the sender's account. Fails if the
// sender does not have a MintCapability.
// Since only the Association account has a mint capability, this will only succeed if it is
// invoked by a transaction sent by that account.
public mint_with_default_capability(amount: u64): R#Self.T {
let capability_ref: &mut R#Self.MintCapability;
let capability_immut_ref: &R#Self.MintCapability;
capability_ref = borrow_global<MintCapability>(get_txn_sender());
capability_immut_ref = freeze(move(capability_ref));
return Self.mint(move(amount), move(capability_immut_ref));
}
// Mint a new LibraCoin.T worth `value`. The caller must have a reference to a MintCapability.
// Only the Association account can acquire such a reference, and it can do so only via
// `borrow_sender_mint_capability`
public mint(value: u64, capability: &R#Self.MintCapability): R#Self.T {
let market_cap_ref: &mut R#Self.MarketCap;
let market_cap_total_value: u64;
release(move(capability));
// TODO: temporary measure for testnet only: limit minting to 1B coins at a time.
// this is to prevent the market cap's total value from hitting u64_max due to excessive
// minting. This will not be a problem in the production Libra system because coins will
// be backed with real-world assets, and thus minting will be correspondingly rarer.
assert(copy(value) <= 1000000000, 11);
// update market cap resource to reflect minting
market_cap_ref = borrow_global<MarketCap>(0x0);
market_cap_total_value = *©(market_cap_ref).total_value;
*(&mut move(market_cap_ref).total_value) = move(market_cap_total_value) + copy(value);
return T{value: move(value)};
}
// Temporary procedure that is called to burn off the collected gas fee
// In the future this will be replaced by the actual mechanism for collecting gas
public TODO_REMOVE_burn_gas_fee(coin: R#Self.T) {
let value: u64;
let market_cap_ref: &mut R#Self.MarketCap;
let market_cap_total_value: u64;
// destroy the coin
T { value } = move(coin);
// update market cap resource to reflect burning
market_cap_ref = borrow_global<MarketCap>(0x0);
market_cap_total_value = *©(market_cap_ref).total_value;
*(&mut move(market_cap_ref).total_value) = move(market_cap_total_value) - move(value);
return;
}
// This can only be invoked by the Association address, and only a single time.
// Currently, it is invoked in the genesis transaction
public initialize() {
// Only callable by the Association address
assert(get_txn_sender() == 0x0, 1);
move_to_sender<MintCapability>(MintCapability{});
move_to_sender<MarketCap>(MarketCap { total_value: 0 });
return;
}
// Return the total value of all Libra in the system
public market_cap(): u64 {
let market_cap_ref: &mut R#Self.MarketCap;
market_cap_ref = borrow_global<MarketCap>(0x0);
return *&move(market_cap_ref).total_value;
}
// Create a new LibraCoin.T with a value of 0
public zero(): R#Self.T {
return T{value: 0};
}
// Public accessor for the value of a coin
public value(coin_ref: &R#Self.T): u64 {
return *&move(coin_ref).value;
}
// Splits the given coin into two and returns them both
// It leverages `Self.withdraw` for any verifications of the values
public split(coin: R#Self.T, amount: u64): R#Self.T * R#Self.T {
let other: R#Self.T;
other = Self.withdraw(&mut coin, move(amount));
return move(coin), move(other);
}
// "Divides" the given coin into two, where original coin is modified in place
// The original coin will have value = original value - `amount`
// The new coin will have a value = `amount`
// Fails if the coins value is less than `amount`
public withdraw(coin_ref: &mut R#Self.T, amount: u64): R#Self.T {
let value: u64;
// Check that `amount` is less than the coin's value
value = *(&mut copy(coin_ref).value);
assert(copy(value) >= copy(amount), 10);
// Split the coin
*(&mut move(coin_ref).value) = move(value) - copy(amount);
return T{value: move(amount)};
}
// Merges two coins and returns a new coin whose value is equal to the sum of the two inputs
public join(coin1: R#Self.T, coin2: R#Self.T): R#Self.T {
Self.deposit(&mut coin1, move(coin2));
return move(coin1);
}
// "Merges" the two coins
// The coin passed in by reference will have a value equal to the sum of the two coins
// The `check` coin is consumed in the process
public deposit(coin_ref: &mut R#Self.T, check: R#Self.T) {
let value: u64;
let check_value: u64;
value = *(&mut copy(coin_ref).value);
T { value: check_value } = move(check);
*(&mut move(coin_ref).value)= move(value) + move(check_value);
return;
}
// Destroy a coin
// Fails if the value is non-zero
// The amount of LibraCoin.T in the system is a tightly controlled property,
// so you cannot "burn" any non-zero amount of LibraCoin.T
public destroy_zero(coin: R#Self.T) {
let value: u64;
T { value } = move(coin);
assert(move(value) == 0, 11);
return;
}
}