Facebook has officially announced its new cryptocurrency ‘Libra’ which they plan to launch in the early part of 2020.

This announcement took the cryptocurrency and blockchain industry by storm.

https://github.com/libra/libra

In Libra, the most attractive thing is the new programming language ‘Move’.

Source: https://libra.org/en-US/

According to the Libra official documentation, Move language is a new programming language for implementing custom transaction logic and “smart contracts” on the Libra Blockchain. Because of Libra’s goal to serve billions of people one day, Move language is designed with safety and security as the highest priorities.

Move is written in Rust language.

Move’s primary tasks include:

  1. Issuing cryptocurrencies, tokens, and digital assets
  2. Facilitating smooth and secure blockchain transactions
  3. Secure management of validators

Move, when fully developed, will enable developers to write smart contracts on the Libra blockchain. Until then, developers will have to manage with Move IR to create modules and transaction scripts.

Move IR: The Move IR compiler compiles the Move IR down to its bytecode representation.

https://github.com/libra/libra/blob/master/language/compiler/README.md

Implementation

The features we will implement in our token contract are listed below:

  1. Check token balance
  2. Withdraw tokens
  3. Deposit tokens
  4. Minting

Token contract:

We start by declaring the module and token resource, which holds the number of tokens.

module DToken {
    // A resource representing the DToken
    resource T {
        // The value of the coin. May be zero
        value: u64,
    }
}

Move Language has First Class Resources

The key feature of Move language is the ability to define custom resource types.
Move resources can never be duplicated, reused, or discarded. A resource type can only be created or destroyed by the module that defines the type.

  • T is a struct type with a single field value of a 64-bit unsigned integer.
  • Only the procedures of the  DToken module can create or destroy values of type T.
  • Other modules and transaction scripts can only write or reference the value field via the public procedures of module

Publishes an initial zero token to the sender:

This function should be called once before using this module. This function publishes initial zero dToken to the sender.

public publish() {
    move_to_sender<T>(T{ value: 0 });
    return;
} 

Mint new token:

Mint a new DToken.T worth value.

public mint(value: u64): R#Self.T {
    return T{value: move(value)};
}

Check token Balance:

The current balance of the Dtoken in the sender’s address. The request will be revert if an initial token hasn’t been published.

public balance(): u64 {
    let sender: address;
    let token_ref: &mut R#Self.T;
    let token_value: u64;

    sender = get_txn_sender();
    token_ref = borrow_global<T>(move(sender));
    token_value = *(&move(token_ref).value);

    return move(token_value);
}
  • BorrowGlobal a built-in procedure which takes an address as input and returns a reference to the unique instance of T published under that address
  • get_txn_sender() is the address currently interacting with the module. get_txn_sender() is similar to Solidity’s msg.sender.

Deposit tokens:

By utilizing this type-safe property we can define the function for depositing the `to_deposit` coin into the `payee`’s account

public deposit(payee: address, to_deposit: R#Self.T) {
        let payee_token_ref: &mut R#Self.T;
        let payee_token_value: u64;
        let to_deposit_value: u64;

        payee_token_ref = borrow_global<T>(move(payee));
        payee_token_value = *(&copy(payee_token_ref).value);

        T{ value: to_deposit_value } = move(to_deposit);

        *(&mut move(payee_token_ref).value) = move(payee_token_value) + 
        move(to_deposit_value);

        return;
}

Withdraw the tokens:

Withdraw `amount` DToken.T from the transaction sender’s account

public withdraw(amount: u64): R#Self.T {
        let sender: address;
        let sender_token_ref: &mut R#Self.T;
        let value: u64;
        
        // Load the sender
        sender = get_txn_sender();
        sender_token_ref = borrow_global<T>(move(sender));
        value = *(&copy(sender_token_ref).value);

        // Make sure that sender has enough tokens
        assert(copy(value) >= copy(amount), 1);

        *(&mut move(sender_token_ref).value) = move(value) - copy(amount);
        return T{ value: move(amount) };
}

Testing to verify the published module

import Transaction.DToken;

main() {

    let sender: address;
    let minted_tokens: R#DToken.T;
    let balance: u64;

    sender = get_txn_sender();

    // Publish an dToken account
    DToken.publish();

    // Mint 100 dTokens
    minted_tokens = DToken.mint(100);

    // Deposit the freshly minted tokens
    DToken.deposit(move(sender), move(minted_tokens));

    // Test that the balance
    balance = DToken.balance();
    assert(move(balance) == 100, 3);

    return;
}

Run the test:

To run the token implementation test, you should perform the following steps:

Clone the Libra Core Repository:

git clone https://github.com/libra/libra.git

Change to the libra directory:

cd libra

Setup Libra Core:

To setup Libra Core, run the setup script to install the dependencies

./scripts/dev_setup.sh

The setup script performs these actions:

  • Installs rustup — rustup is an installer for the Rust programming language, which Libra Core is implemented in.
  • It Installs the required versions of the rust-toolchain.
  • Installs CMake — to manage the build process.
  • Installs protoc — a compiler for protocol buffers.
  • Also, installs Go — for building protocol buffers.

Copy the dToken Move IR source code to the test folder in the Libra repository located at language/functional_tests/tests/testsuite/module/

dToken Move IR source code:

modules:

module DToken {

    // A resource representing the DToken
    resource T {
        value: u64,
    }

    // Publishes an initial zero dToken to the sender.
    public publish() {
        move_to_sender<T>(T{ value: 0 });
        return;
    } 

    // Mint new dTokens.
    public mint(value: u64): R#Self.T {
        return T{value: move(value)};
    }

    // Returns an account's dToken balance.
    public balance(): u64 {
        let sender: address;
        let token_ref: &mut R#Self.T;
        let token_value: u64;

        sender = get_txn_sender();
        token_ref = borrow_global<T>(move(sender));
        token_value = *(&move(token_ref).value);

        return move(token_value);
    }

    // Deposit owned tokens to a payee's address
    public deposit(payee: address, to_deposit: R#Self.T) {
        let payee_token_ref: &mut R#Self.T;
        let payee_token_value: u64;
        let to_deposit_value: u64;

        payee_token_ref = borrow_global<T>(move(payee));
        payee_token_value = *(&copy(payee_token_ref).value);

        // Unpack and destroy to_deposit tokens
        T{ value: to_deposit_value } = move(to_deposit);

        // Increase the payees balance with the destroyed token amount
        *(&mut move(payee_token_ref).value) = move(payee_token_value) + move(to_deposit_value);

        return;
    }

    // Withdraw an amount of tokens of the sender and return it.
    public withdraw(amount: u64): R#Self.T {
        let sender: address;
        let sender_token_ref: &mut R#Self.T;
        let value: u64;

        sender = get_txn_sender();
        sender_token_ref = borrow_global<T>(move(sender));
        value = *(&copy(sender_token_ref).value);

        // Make sure that sender has enough tokens
        assert(copy(value) >= copy(amount), 1);

        // Split the senders token and return the amount specified
        *(&mut move(sender_token_ref).value) = move(value) - copy(amount);
        return T{ value: move(amount) };
    }
}

script:

// Performs simple testing to verify the published modules above.

import Transaction.DToken;

main() {

    let sender: address;
    let minted_tokens: R#DToken.T;
    let balance: u64;

    sender = get_txn_sender();

    // Publish an dToken account
    DToken.publish();

    // Mint 100 dTokens
    minted_tokens = DToken.mint(100);

    // Deposit the freshly minted tokens
    DToken.deposit(move(sender), move(minted_tokens));

    balance = DToken.balance();
    assert(move(balance) == 100, 3);

    return;
}

Execute the following command in the Libra repository:

cargo test -p functional_tests dToken

Note: If your tests failed, edit the `dToken.mvir` file and run the following command to rerun the tests:

cargo test -p functional_tests --test testsuite

Wrap up

Now you have an overview of the main characteristics of Move language. Thanks and cheers from the Deqode team.

Must Read: Stablecoins: The End of Volatility in Cryptocurrency

Author

Solutions Engineer at Deqode who has a broad skill set ranging from full-stack development and distributed computing to blockchain technologies. Experienced with Ethereum, Quorum, and Hyperledger Blockchain. Chirag is involved in many blockchain projects, in different stages of their life cycles.

Write A Comment