// Simple peer-peer payment example.
// Use LibraAccount module published on the blockchain at account address
// 0x0...0 (with 64 zeroes). 0x0 is shorthand that the IR pads out to
// 256 bits (64 digits) by adding leading zeroes.
import 0x0.LibraAccount;
import 0x0.LibraCoin;
main(payee: address, amount: u64) {
// The bytecode (and consequently, the IR) has typed locals. The scope of
// each local is the entire procedure. All local variable declarations must
// be at the beginning of the procedure. Declaration and initialization of
// variables are separate operations, but the bytecode verifier will prevent
// any attempt to use an uninitialized variable.
let coin: LibraCoin.T;
// Acquire a LibraCoin.T resource with value `amount` from the sender's
// account. This will fail if the sender's balance is less than `amount`.
coin = LibraAccount.withdraw_from_sender(move(amount));
// Move the LibraCoin.T resource into the account of `payee`. If there is no
// account at the address `payee`, this step will fail
LibraAccount.deposit(move(payee), move(coin));
// Every procedure must end in a `return`. The IR compiler is very literal:
// it directly translates the source it is given. It will not do fancy
// things like inserting missing `return`s.
return;
}
// A small variant of the peer-peer payment example that creates a fresh
// account if one does not already exist.
import 0x0.LibraAccount;
import 0x0.LibraCoin;
main(payee: address, amount: u64) {
let coin: LibraCoin.T;
let account_exists: bool;
// Acquire a LibraCoin.T resource with value `amount` from the sender's
// account. This will fail if the sender's balance is less than `amount`.
coin = LibraAccount.withdraw_from_sender(move(amount));
account_exists = LibraAccount.exists(copy(payee));
if (!move(account_exists)) {
// Creates a fresh account at the address `payee` by publishing a
// LibraAccount.T resource under this address. If theres is already a
// LibraAccount.T resource under the address, this will fail.
create_account(copy(payee));
}
LibraAccount.deposit(move(payee), move(coin));
return;
}
让我们看一个更复杂的例子。 在此示例中,我们将使用交易脚本向多个收件人付款,而不仅仅是一个。
// Multiple payee example. This is written in a slightly verbose way to
// emphasize the ability to split a `LibraCoin.T` resource. The more concise
// way would be to use multiple calls to `LibraAccount.withdraw_from_sender`.
import 0x0.LibraAccount;
import 0x0.LibraCoin;
main(payee1: address, amount1: u64, payee2: address, amount2: u64) {
let coin1: LibraCoin.T;
let coin2: LibraCoin.T;
let total: u64;
total = move(amount1) + copy(amount2);
coin1 = LibraAccount.withdraw_from_sender(move(total));
// This mutates `coin1`, which now has value `amount1`.
// `coin2` has value `amount2`.
coin2 = LibraCoin.withdraw(&mut coin1, move(amount2));
// Perform the payments
LibraAccount.deposit(move(payee1), move(coin1));
LibraAccount.deposit(move(payee2), move(coin2));
return;
}
// A module for earmarking a coin for a specific recipient
module EarmarkedLibraCoin {
import 0x0.LibraCoin;
// A wrapper containing a Libra coin and the address of the recipient the
// coin is earmarked for.
resource T {
coin: LibraCoin.T,
recipient: address
}
// Create a new earmarked coin with the given `recipient`.
// Publish the coin under the transaction sender's account address.
public create(coin: LibraCoin.T, recipient: address) {
let t: Self.T;
// Construct or "pack" a new resource of type T. Only procedures of the
// `EarmarkedLibraCoin` module can create an `EarmarkedLibraCoin.T`.
t = T {
coin: move(coin),
recipient: move(recipient),
};
// Publish the earmarked coin under the transaction sender's account
// address. Each account can contain at most one resource of a given type;
// this call will fail if the sender already has a resource of this type.
move_to_sender<T>(move(t));
return;
}
// Allow the transaction sender to claim a coin that was earmarked for her.
public claim_for_recipient(earmarked_coin_address: address): Self.T acquires T {
let t: Self.T;
let t_ref: &Self.T;
let sender: address;
// Remove the earmarked coin resource published under `earmarked_coin_address`.
// If there is no resource of type T published under the address, this will fail.
t = move_from<T>(move(earmarked_coin_address));
t_ref = &t;
// This is a builtin that returns the address of the transaction sender.
sender = get_txn_sender();
// Ensure that the transaction sender is the recipient. If this assertion
// fails, the transaction will fail and none of its effects (e.g.,
// removing the earmarked coin) will be committed. 99 is an error code
// that will be emitted in the transaction output if the assertion fails.
assert(*(&move(t_ref).recipient) == move(sender), 99);
return move(t);
}
// Allow the creator of the earmarked coin to reclaim it.
public claim_for_creator(): Self.T acquires T {
let t: Self.T;
let sender: address;
sender = get_txn_sender();
// This will fail if no resource of type T under the sender's address.
t = move_from<T>(move(sender));
return move(t);
}
// Extract the Libra coin from its wrapper and return it to the caller.
public unwrap(t: Self.T): LibraCoin.T {
let coin: LibraCoin.T;
let recipient: address;
// This "unpacks" a resource type by destroying the outer resource, but
// returning its contents. Only the module that declares a resource type
// can unpack it.
T { coin, recipient } = move(t);
return move(coin);
}
}