Move is a new programming language developed to provide a secure and programmable foundation for the Libra Blockchain. An account in the Libra Blockchain is where an arbitrary number of Move resources and Move modules are stored. Every transaction sent to the Libra Blockchain uses a transaction script written in Move to encode its logic. Transaction scripts can call procedures declared by a module to update the global state of the blockchain.
In the first part of this tutorial, I’ll give a high-level introduction to the main features of the Move language:
- Move Transaction Scripts Allows Programming LibraCoin Transactions
- Move Modules Enables Incorporation of “Smart Contracts”
- Move First-Class Resources
For the curious, the Move technical article contains more details about this programming language. Custom Moves are not supported in the initial testnet release, but these features are available for you to try in your test environment.
Main features of Move
Move Transaction Scripts allow transaction programming
- Each Libra transaction includes a Move transaction script that encodes logic that the validator will execute on behalf of the client (for example, to transfer Libra from A’s account to B’s account).
- Transaction scripts interact with Move Resources published in the Libra Blockchain’s global storage by calling the procedures of one or more Move modules.
- A transaction script is not stored in the global state and it cannot be called by other transaction scripts. This is a single use program.
- I will show some examples of trading scripts in the examples section below
Write a trading script
As I explained above (Move Transaction Scripts), the user writes a transaction script to request an update to the Libra Blockchain’s global storage. There are two important building blocks that will appear in almost any trading script: type
LibraAccount is the name of the module and
T is the name of the Resource declared by that module. This is a common naming convention in Move; The main type of the area declared by a module is usually named T.
When a user “has an account at address
0xff on Libra Blockchain”, what I mean is this address
0xff contains an instance of
LibraAccount.T Resource. Each non-empty address has a
LibraAccount.T Resource. This resource stores account data, such as sequence numbers, authentication keys, and balances. Any part of the Libra system that wants to interact with the account must do so by reading data from
LibraAccount.T Resource or call procedures of
Account balance is a kind of resource
LibraCoin.T. As I explained in Move Resources, this is a Libra coin. This type is a “first-class citizen” in the language just like any other Move Resources.
LibraCoin.T Resources can be stored in program variables, passed between procedures, etc.
I encourage you to be interested in the Move IR definitions of these two main resources in
LibraCoin modules in directory
Now let’s see how a programmer can interact with these modules and resources in a Transaction Scripts.
import 0x0.LibraAccount; import 0x0.LibraCoin; main(payee: address, amount: u64) let coin: R#LibraCoin.T; coin = LibraAccount.withdraw_from_sender(move(amount)); LibraAccount.deposit(move(payee), move(coin)); return;
This Transaction Scipt has the unfortunate problem that it will fail if there is no account under the address
payee. I will fix this problem by modifying the script to create an account for
payee if the account does not exist.
import 0x0.LibraAccount; import 0x0.LibraCoin; main(payee: address, amount: u64) let coin: R#LibraCoin.T; let account_exists: bool; coin = LibraAccount.withdraw_from_sender(move(amount)); account_exists = LibraAccount.exists(copy(payee)); if (!move(account_exists)) create_account(copy(payee)); LibraAccount.deposit(move(payee), move(coin)); return;
Let’s look at a more complex example. In this example, I will use the Transaction script to pay multiple recipients instead of just one.
import 0x0.LibraAccount; import 0x0.LibraCoin; main(payee1: address, amount1: u64, payee2: address, amount2: u64) let coin1: R#LibraCoin.T; let coin2: R#LibraCoin.T; let total: u64; total = move(amount1) + copy(amount2); coin1 = LibraAccount.withdraw_from_sender(move(total)); coin2 = LibraCoin.withdraw(&mut coin1, move(amount2)); // Perform the payments LibraAccount.deposit(move(payee1), move(coin1)); LibraAccount.deposit(move(payee2), move(coin2)); return;
To better understand the Transaction Scripts supported by Libra Blockchain in the first testnet version, you can refer to this directory in Libra Core.
Now I will write my own Move module instead of just reusing my existing modules
Let’s give the following example: User #1 will create an account at address a at some point in the future. User #2 wants to “spend” some money on User #1 so he can pull them into his account once it is created. But User #2 also wants to be able to get his/her money back if User #1 never creates an account.
To solve this problem for User #2, I will write a module
- Declare a new resource type
EarmarkedLibraCoin.Twrap Libra coin and recipient address.
- Allow User #2 to create such a type and publish it in his account (
- Allow User #1 to request resources (
- Allow anyone to have
EarmarkedLibraCoin.Tcan destroy it (
module EarmarkedLibraCoin import 0x0.LibraCoin; resource T coin: R#LibraCoin.T, recipient: address public create(coin: R#LibraCoin.T, recipient: address) let t: R#Self.T; t = T coin: move(coin), recipient: move(recipient), ; move_to_sender(move return; public claim_for_recipient(earmarked_coin_address: address): R#Self.T let t: R#Self.T; let t_ref: &R#Self.T; let sender: address; t = move_from(move(earmarked_coin_address)); t_ref = &t; sender = get_txn_sender(); assert(*(&move(t_ref).recipient) == move(sender), 99); return move public claim_for_creator(): R#Self.T let t: R#Self.T; let coin: R#LibraCoin.T; let recipient: address; let sender: address; sender = get_txn_sender(); t = move_from(move(sender)); return move public unwrap(t: R#Self.T): R#LibraCoin.T let coin: R#LibraCoin.T; let recipient: address; T coin, recipient = move return move(coin);
User #2 can generate some Libra Coin for User #1 by creating a Transaction Script called
create on the address of User #1 and
LibraCoin.T owned by User #2. When a created, User #1 can request funds by sending a transaction from a . This calls
claim_for_recipient, pass the result to
unwrap and return storage
LibraCoin wherever he wants. If User #1 takes too long to create an account under a and User #2 wants to claim his money back, User #2 can do so using
You may have noticed that the code in this module is agnostic to the internal structure of
LibraCoin.T. It can easily be written in generic programming (for example,
resource T coin: AnyResource, ... ).
The article ends here. Hopefully through this article, it will help you better understand Libra Coin as well as the Move programming language.
Bitcoin Magazine | Sirquy
Follow the Twitter page | Subscribe to Telegram channel | Follow the Facebook page