// 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.import0x0.LibraAccount;import0x0.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 failLibraAccount.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.import0x0.LibraAccount;import0x0.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`.import0x0.LibraAccount;import0x0.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 paymentsLibraAccount.deposit(move(payee1),move(coin1));LibraAccount.deposit(move(payee2),move(coin2));return;}
// A module for earmarking a coin for a specific recipientmoduleEarmarkedLibraCoin { 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.publiccreate(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.publicclaim_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);returnmove(t); }// Allow the creator of the earmarked coin to reclaim it.publicclaim_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));returnmove(t); }// Extract the Libra coin from its wrapper and return it to the caller.publicunwrap(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);returnmove(coin); }}