solana_libra_stdlib 0.0.0

Solana Libra stdlib
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 = *&copy(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 = *&copy(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;
    }

}