はじめに
前回はLibraCoin Moduleをみていきました。
Libra開発言語 MOVEのLibraCoinモジュール
今回はもう一つのよく使われるModuleであるLibraAccount
をみていきます。
LibraAccount
LibraAccount
モジュールコードはこんな感じです。
module LibraAccount {
import 0x0.LibraCoin;
import 0x0.Hash;
import 0x0.U64Util;
import 0x0.AddressUtil;
import 0x0.BytearrayUtil;
resource T {
authentication_key: bytearray,
balance: LibraCoin.T,
delegated_key_rotation_capability: bool,
delegated_withdrawal_capability: bool,
received_events: Self.EventHandle<Self.ReceivedPaymentEvent>,
sent_events: Self.EventHandle<Self.SentPaymentEvent>,
sequence_number: u64,
event_generator: Self.EventHandleGenerator,
}
resource WithdrawalCapability {
account_address: address,
}
resource KeyRotationCapability {
account_address: address,
}
struct SentPaymentEvent {
amount: u64,
payee: address,
metadata: bytearray,
}
struct ReceivedPaymentEvent {
amount: u64,
payer: address,
metadata: bytearray,
}
resource EventHandleGenerator {
counter: u64,
}
resource EventHandle<T: unrestricted> {
counter: u64,
guid: bytearray,
}
public deposit(payee: address, to_deposit: LibraCoin.T) acquires T {
Self.deposit_with_metadata(move(payee), move(to_deposit), h"");
return;
}
public deposit_with_metadata(
payee: address,
to_deposit: LibraCoin.T,
metadata: bytearray
) acquires T {
Self.deposit_with_sender_and_metadata(
move(payee),
get_txn_sender(),
move(to_deposit),
move(metadata)
);
return;
}
deposit_with_sender_and_metadata(
payee: address,
sender: address,
to_deposit: LibraCoin.T,
metadata: bytearray
) acquires T {
let deposit_value: u64;
let payee_account_ref: &mut Self.T;
let sender_account_ref: &mut Self.T;
deposit_value = LibraCoin.value(&to_deposit);
assert(copy(deposit_value) > 0, 7);
sender_account_ref = borrow_global_mut<T>(copy(sender));
Self.emit_event<Self.SentPaymentEvent>(
&mut move(sender_account_ref).sent_events,
SentPaymentEvent {
amount: copy(deposit_value),
payee: copy(payee),
metadata: copy(metadata)
},
);
payee_account_ref = borrow_global_mut<T>(move(payee));
LibraCoin.deposit(&mut copy(payee_account_ref).balance, move(to_deposit));
Self.emit_event<Self.ReceivedPaymentEvent>(
&mut move(payee_account_ref).received_events,
ReceivedPaymentEvent {
amount: move(deposit_value),
payer: move(sender),
metadata: move(metadata)
}
);
return;
}
public mint_to_address(payee: address, amount: u64) acquires T {
if (!exists<T>(copy(payee))) {
Self.create_account(copy(payee));
}
Self.deposit(move(payee), LibraCoin.mint_with_default_capability(move(amount)));
return;
}
withdraw_from_account(account: &mut Self.T, amount: u64): LibraCoin.T {
let to_withdraw: LibraCoin.T;
to_withdraw = LibraCoin.withdraw(&mut move(account).balance, copy(amount));
return move(to_withdraw);
}
public withdraw_from_sender(amount: u64): LibraCoin.T acquires T {
let sender_account: &mut Self.T;
sender_account = borrow_global_mut<T>(get_txn_sender());
if (*©(sender_account).delegated_withdrawal_capability) {
// The sender has delegated the privilege to withdraw from her account elsewhere--abort.
abort(11);
} else {
return Self.withdraw_from_account(move(sender_account), move(amount));
}
}
public withdraw_with_capability(
cap: &Self.WithdrawalCapability, amount: u64
): LibraCoin.T acquires T {
let account: &mut Self.T;
account = borrow_global_mut<T>(*&move(cap).account_address);
return Self.withdraw_from_account(move(account), move(amount));
}
public extract_sender_withdrawal_capability(): Self.WithdrawalCapability acquires T {
let sender: address;
let sender_account: &mut Self.T;
let delegated_ref: &mut bool;
sender = get_txn_sender();
sender_account = borrow_global_mut<T>(copy(sender));
delegated_ref = &mut move(sender_account).delegated_withdrawal_capability;
if (*copy(delegated_ref)) {
// We already extracted the unique withdrawal capability for this account.
abort(11);
} else {
*move(delegated_ref) = true; // ensure uniqueness of the capability
return WithdrawalCapability { account_address: move(sender) };
}
}
public restore_withdrawal_capability(cap: Self.WithdrawalCapability) acquires T {
let account_address: address;
let account: &mut Self.T;
WithdrawalCapability { account_address } = move(cap);
account = borrow_global_mut<T>(move(account_address));
*(&mut move(account).delegated_withdrawal_capability) = false;
return;
}
public pay_from_capability(
payee: address,
cap: &Self.WithdrawalCapability,
amount: u64,
metadata: bytearray
) acquires T {
if (!exists<T>(copy(payee))) {
Self.create_account(copy(payee));
}
Self.deposit_with_sender_and_metadata(
move(payee),
*©(cap).account_address,
Self.withdraw_with_capability(move(cap), move(amount)),
move(metadata),
);
return;
}
public pay_from_sender_with_metadata(
payee: address,
amount: u64,
metadata: bytearray
) acquires T {
if (!exists<T>(copy(payee))) {
Self.create_account(copy(payee));
}
Self.deposit_with_metadata(
move(payee),
Self.withdraw_from_sender(move(amount)),
move(metadata)
);
return;
}
public pay_from_sender(payee: address, amount: u64) acquires T {
Self.pay_from_sender_with_metadata(move(payee), move(amount), h"");
return;
}
rotate_authentication_key_for_account(account: &mut Self.T, new_authentication_key: bytearray) {
*(&mut move(account).authentication_key) = move(new_authentication_key);
return;
}
public rotate_authentication_key(new_authentication_key: bytearray) acquires T {
let sender_account: &mut Self.T;
sender_account = borrow_global_mut<T>(get_txn_sender());
if (*©(sender_account).delegated_key_rotation_capability) {
// The sender has delegated the privilege to rotate her key elsewhere--abort
abort(11);
} else {
// The sender has retained her key rotation privileges--proceed.
Self.rotate_authentication_key_for_account(
move(sender_account),
move(new_authentication_key)
);
return;
}
}
public rotate_authentication_key_with_capability(
cap: &Self.KeyRotationCapability,
new_authentication_key: bytearray,
) acquires T {
Self.rotate_authentication_key_for_account(
borrow_global_mut<T>(*&move(cap).account_address),
move(new_authentication_key)
);
return;
}
public extract_sender_key_rotation_capability(): Self.KeyRotationCapability acquires T {
let sender: address;
let delegated_ref: &mut bool;
sender = get_txn_sender();
delegated_ref = &mut borrow_global_mut<T>(copy(sender)).delegated_key_rotation_capability;
if (*copy(delegated_ref)) {
// We already extracted the unique key rotation capability for this account.
abort(11);
} else {
*move(delegated_ref) = true; // ensure uniqueness of the capability
return KeyRotationCapability { account_address: move(sender) };
}
}
public restore_key_rotation_capability(cap: Self.KeyRotationCapability) acquires T {
let account_address: address;
let account: &mut Self.T;
KeyRotationCapability { account_address } = move(cap);
account = borrow_global_mut<T>(move(account_address));
// extract_sender_key_rotation_capability again
*(&mut move(account).delegated_key_rotation_capability) = false;
return;
}
public create_account(fresh_address: address) {
let generator: Self.EventHandleGenerator;
generator = EventHandleGenerator {counter: 0};
Self.save_account(
copy(fresh_address),
T {
authentication_key: AddressUtil.address_to_bytes(copy(fresh_address)),
balance: LibraCoin.zero(),
delegated_key_rotation_capability: false,
delegated_withdrawal_capability: false,
received_events: Self.new_event_handle_impl<Self.ReceivedPaymentEvent>(&mut generator, copy(fresh_address)),
sent_events: Self.new_event_handle_impl<Self.SentPaymentEvent>(&mut generator, move(fresh_address)),
sequence_number: 0,
event_generator: move(generator),
}
);
return;
}
public create_new_account(fresh_address: address, initial_balance: u64) acquires T {
Self.create_account(copy(fresh_address));
if (copy(initial_balance) > 0) {
Self.pay_from_sender(move(fresh_address), move(initial_balance));
}
return;
}
native save_account(addr: address, account: Self.T);
balance_for_account(account: &Self.T): u64 {
let balance_value: u64;
balance_value = LibraCoin.value(&move(account).balance);
return move(balance_value);
}
public balance(addr: address): u64 acquires T {
return Self.balance_for_account(borrow_global<T>(move(addr)));
}
sequence_number_for_account(account: &Self.T): u64 {
return *(&move(account).sequence_number);
}
public sequence_number(addr: address): u64 acquires T {
return Self.sequence_number_for_account(borrow_global<T>(move(addr)));
}
public delegated_key_rotation_capability(addr: address): bool acquires T {
return *&(borrow_global<T>(move(addr))).delegated_key_rotation_capability;
}
public delegated_withdrawal_capability(addr: address): bool acquires T {
return *&(borrow_global<T>(move(addr))).delegated_withdrawal_capability;
}
public withdrawal_capability_address(cap: &Self.WithdrawalCapability): &address {
return &move(cap).account_address;
}
public key_rotation_capability_address(cap: &Self.KeyRotationCapability): &address {
return &move(cap).account_address;
}
public exists(check_addr: address): bool {
return exists<T>(move(check_addr));
}
prologue(
txn_sequence_number: u64,
txn_public_key: bytearray,
txn_gas_price: u64,
txn_max_gas_units: u64,
) acquires T {
let transaction_sender: address;
let sender_account: &mut Self.T;
let imm_sender_account: &Self.T;
let max_transaction_fee: u64;
let balance_amount: u64;
let sequence_number_value: u64;
transaction_sender = get_txn_sender();
assert(exists<T>(copy(transaction_sender)), 5);
sender_account = borrow_global_mut<T>(copy(transaction_sender));
assert(
Hash.sha3_256(move(txn_public_key)) == *(©(sender_account).authentication_key),
2
);
max_transaction_fee = move(txn_gas_price) * move(txn_max_gas_units);
imm_sender_account = freeze(copy(sender_account));
balance_amount = Self.balance_for_account(move(imm_sender_account));
assert(move(balance_amount) >= move(max_transaction_fee), 6);
sequence_number_value = *(&mut move(sender_account).sequence_number);
assert(copy(txn_sequence_number) >= copy(sequence_number_value), 3);
assert(move(txn_sequence_number) == move(sequence_number_value), 4);
return;
}
epilogue(
txn_sequence_number: u64,
txn_gas_price: u64,
txn_max_gas_units: u64,
gas_units_remaining: u64
) acquires T {
let sender_account: &mut Self.T;
let transaction_fee_account: &mut Self.T;
let imm_sender_account: &Self.T;
let transaction_fee_amount: u64;
let transaction_fee: LibraCoin.T;
sender_account = borrow_global_mut<T>(get_txn_sender());
transaction_fee_amount =
move(txn_gas_price) * (move(txn_max_gas_units) - move(gas_units_remaining));
imm_sender_account = freeze(copy(sender_account));
assert(
Self.balance_for_account(move(imm_sender_account)) >= copy(transaction_fee_amount),
6
);
transaction_fee =
Self.withdraw_from_account(
copy(sender_account),
move(transaction_fee_amount)
);
*(&mut move(sender_account).sequence_number) = move(txn_sequence_number) + 1;
transaction_fee_account = borrow_global_mut<T>(0xFEE);
LibraCoin.deposit(&mut move(transaction_fee_account).balance, move(transaction_fee));
return;
}
fresh_guid(counter: &mut Self.EventHandleGenerator, sender: address): bytearray {
let count: &mut u64;
let count_bytes: bytearray;
let preimage: bytearray;
let sender_bytes: bytearray;
count = &mut move(counter).counter;
sender_bytes = AddressUtil.address_to_bytes(move(sender));
count_bytes = U64Util.u64_to_bytes(*copy(count));
*move(count) = *copy(count) + 1;
preimage = BytearrayUtil.bytearray_concat(move(count_bytes), move(sender_bytes));
return move(preimage);
}
new_event_handle_impl<T: unrestricted>(counter: &mut Self.EventHandleGenerator, sender: address): Self.EventHandle<T> {
return EventHandle<T> {counter: 0, guid: Self.fresh_guid(move(counter), move(sender))};
}
public new_event_handle<T: unrestricted>(): Self.EventHandle<T> acquires T {
let sender_account_ref: &mut Self.T;
let sender_bytes: bytearray;
sender_account_ref = borrow_global_mut<T>(get_txn_sender());
return Self.new_event_handle_impl<T>(&mut (move(sender_account_ref)).event_generator, get_txn_sender());
}
public emit_event<T: unrestricted>(handle_ref: &mut Self.EventHandle<T>, msg: T) {
let count: &mut u64;
let guid: bytearray;
guid = *©(handle_ref).guid;
count = &mut move(handle_ref).counter;
Self.write_to_event_store<T>(move(guid), *copy(count), move(msg));
*move(count) = *copy(count) + 1;
return;
}
native write_to_event_store<T: unrestricted>(guid: bytearray, count: u64, msg: T);
public destroy_handle<T: unrestricted>(handle: Self.EventHandle<T>) {
let guid: bytearray;
let count: u64;
EventHandle<T> { count, guid } = move(handle);
return;
}
}
resource T
全てのアカウントはresource T
を持っています。
delegated_key_rotation_capability
とdelegated_withdrawal_capability
は誰かにアカウントの権限を委ねるものでERC20のallowanceに近いものだと思われます。その他のbalance, event, sequence_numberなどは他のDapp開発でもよく見るものですね。
resource T {
authentication_key: bytearray,
balance: LibraCoin.T,
delegated_key_rotation_capability: bool,
delegated_withdrawal_capability: bool,
received_events: Self.EventHandle<Self.ReceivedPaymentEvent>,
sent_events: Self.EventHandle<Self.SentPaymentEvent>,
sequence_number: u64,
event_generator: Self.EventHandleGenerator,
}
WithdrawalCapability, KeyRotationCapability
上記で説明したdelegated_key_rotation_capability
とdelegated_withdrawal_capability
のためのresourceです。指定したaddress
にアカウントの権限を譲渡できるようになっています。
resource WithdrawalCapability {
account_address: address,
}
resource KeyRotationCapability {
account_address: address,
}
Event
struct SentPaymentEvent {
amount: u64,
payee: address,
metadata: bytearray,
}
struct ReceivedPaymentEvent {
amount: u64,
payer: address,
metadata: bytearray,
}
resource EventHandleGenerator {
counter: u64,
}
resource EventHandle<T: unrestricted> {
counter: u64,
guid: bytearray,
}
・EventはSentPaymentEvent
やReceivedPaymentEvent
のようにstruct
で持つこどができるようです。
・EventHandleGenerator
はこのモジュール内のイベントに対してアドレス毎にIDを与えるためのもので、EventHandle<T: unrestricted>
はイベント毎にIDを与えて管理するものと考えられます。(理解することが難しく断言はできませんが、、)
create_account
Libra accountを作るための関数です。
public create_account(fresh_address: address) {
let generator: Self.EventHandleGenerator;
generator = EventHandleGenerator {counter: 0};
Self.save_account(
copy(fresh_address),
T {
authentication_key: AddressUtil.address_to_bytes(copy(fresh_address)),
balance: LibraCoin.zero(),
delegated_key_rotation_capability: false,
delegated_withdrawal_capability: false,
received_events: Self.new_event_handle_impl<Self.ReceivedPaymentEvent>(&mut generator, copy(fresh_address)),
sent_events: Self.new_event_handle_impl<Self.SentPaymentEvent>(&mut generator, move(fresh_address)),
sequence_number: 0,
event_generator: move(generator),
}
);
return;
}
native save_account(addr: address, account: Self.T);
・引数がfresh_address: address
となってるので、外で作成したアドレスは渡しているようです。どこかにアドレスを作成する関数があると思ったのですが、見つけることができませんでした。引き続き調査します。
・generator = EventHandleGenerator {counter: 0};
でアカウントのEventHandleGenerator
に設定しています。
・Self.save_account( ... );
で作成したいアドレスに紐づけてresource T
を保存してます。
deposit
to_deposit
分のLibra Coinをpayee
のアドレスに送るための3つの関数です。Libra coinを送るためにはdeposit
、deposit_with_metadata
、deposit_with_sender_and_metadata
の関数が必要になります。
public deposit(payee: address, to_deposit: LibraCoin.T) acquires T {
Self.deposit_with_metadata(move(payee), move(to_deposit), h"");
return;
}
public deposit_with_metadata(
payee: address,
to_deposit: LibraCoin.T,
metadata: bytearray
) acquires T {
Self.deposit_with_sender_and_metadata(
move(payee),
get_txn_sender(),
move(to_deposit),
move(metadata)
);
return;
}
deposit_with_sender_and_metadata(
payee: address,
sender: address,
to_deposit: LibraCoin.T,
metadata: bytearray
) acquires T {
let deposit_value: u64;
let payee_account_ref: &mut Self.T;
let sender_account_ref: &mut Self.T;
deposit_value = LibraCoin.value(&to_deposit);
assert(copy(deposit_value) > 0, 7);
sender_account_ref = borrow_global_mut<T>(copy(sender));
Self.emit_event<Self.SentPaymentEvent>(
&mut move(sender_account_ref).sent_events,
SentPaymentEvent {
amount: copy(deposit_value),
payee: copy(payee),
metadata: copy(metadata)
},
);
payee_account_ref = borrow_global_mut<T>(move(payee));
LibraCoin.deposit(&mut copy(payee_account_ref).balance, move(to_deposit));
Self.emit_event<Self.ReceivedPaymentEvent>(
&mut move(payee_account_ref).received_events,
ReceivedPaymentEvent {
amount: move(deposit_value),
payer: move(sender),
metadata: move(metadata)
}
);
return;
}
・Libra coinを送る相手のアドレスpayee: address
と、送る量to_deposit: LibraCoin.T
を引数として渡しています。
・Metadataを含めない場合はdeposit
の関数を呼びその中でからのMetadataを作ってもらい、Metadataを含めたい場合にはdeposit_with_metadata
関数で引数を渡す形になっているようです。最終的に全てdeposit_with_sender_and_metadata
に行き着きますがオフションを増やして使いやす区しているようです。
・deposit_value = LibraCoin.value(&to_deposit);
で送金者の送金分のLibra Coinを取得しています。LibraCoinモジュールのValue
関数は以下になります
public value(coin_ref: &Self.T): u64 {
return *&move(coin_ref).value;
}
・sender_account_ref = borrow_global_mut<T>(copy(sender));
で送信者のresource T
を取得しています。
リソースを取得する際はborrow_global<リソース名>(アドレス)
で取得できるようです。
*その後Self.emit_event<>
でイベントを発生させていますが、イベントは次の項目で記載します。
・同じようにpayee_account_ref = borrow_global_mut<T>(move(payee));
で受信者のresource T
を取得しています。
・LibraCoin.deposit(&mut copy(payee_account_ref).balance, move(to_deposit));
でLibra Coinが送金されます。前回の記事でも説明したように、LibraCoin.deposit
では2つのLibraCoinのバランスを合わせる形になっているので、受信者のLibraCoinのバランスと送金がくのバランスが引数として渡されています。
event
LibraCoinを送金した際のイベントです。
・・・
Self.emit_event<Self.SentPaymentEvent>(
&mut move(sender_account_ref).sent_events,
SentPaymentEvent {
amount: copy(deposit_value),
payee: copy(payee),
metadata: copy(metadata)
},
);
・・・
// Emit an event with payload `msg` by using handle's key and counter. Will change the payload from bytearray to a
// generic type parameter once we have generics.
public emit_event<T: unrestricted>(handle_ref: &mut Self.EventHandle<T>, msg: T) {
let count: &mut u64;
let guid: bytearray;
guid = *©(handle_ref).guid;
count = &mut move(handle_ref).counter;
Self.write_to_event_store<T>(move(guid), *copy(count), move(msg));
*move(count) = *copy(count) + 1;
return;
}
// Native procedure that writes to the actual event stream in Event store
// This will replace the "native" portion of EmitEvent bytecode
native write_to_event_store<T: unrestricted>(guid: bytearray, count: u64, msg: T);
・Self.emit_event<Self.SentPaymentEvent>( ... )
でeventを発火する関数を叩いています。引数にはresource T
のsent_events: Self.EventHandle<Self.SentPaymentEvent>
とSentPaymentEvent
のstructを渡しています。
・write_to_event_store
でeventがstoreされる場所に書き込まれているようです。おそらくこの関数の中でEventHandle
とSentPaymentEvent
は紐付けられてると思います。この辺りの書き方はかなり難しいですね、、全然理解できていません。
write_to_event_store
の引数に、EventHandleguid, count
とSentPaymentEvent
そのものであるmsg
が渡されてるので、イベントを参照する際はcount
を使ってできるのではないかと思います。
Eventの発行に関わるrerource, structをまとめてみました。Solidityのイベントと比べるとかなり複雑です。
resource T {
...
sent_events: Self.EventHandle<Self.SentPaymentEvent>,
...
event_generator: Self.EventHandleGenerator,
}
struct SentPaymentEvent {
amount: u64,
payee: address,
metadata: bytearray,
}
resource EventHandle<T: unrestricted> {
counter: u64,
guid: bytearray,
}
withdraw
deposit関係の関数では「to_deposit
分のLibra Coinをpayee
のアドレスに送る」と説明しました。LibraAccountにおいてwithdraw関数はto_deposit
のLibracoinを作る関数になります。
withdraw_from_account(account: &mut Self.T, amount: u64): LibraCoin.T {
let to_withdraw: LibraCoin.T;
to_withdraw = LibraCoin.withdraw(&mut move(account).balance, copy(amount));
return move(to_withdraw);
}
public withdraw_from_sender(amount: u64): LibraCoin.T acquires T {
let sender_account: &mut Self.T;
sender_account = borrow_global_mut<T>(get_txn_sender());
if (*©(sender_account).delegated_withdrawal_capability) {
abort(11);
} else {
return Self.withdraw_from_account(move(sender_account), move(amount));
}
}
withdraw_from_sender
→withdraw_from_account
の順番で処理が行われます。
・sender_account = borrow_global_mut<T>(get_txn_sender());
で関数の実行者に紐付くresource T
を参照しています。get_txn_sender()
で関数の実行者のアドレスを取得することができます。Solidityでいうとmsg.sender
を同じ扱いになります。
・条件分岐はresource T
のdelegated_withdrawal_capability
で判断されています。delegated_withdrawal_capability
がtrue
の場合、つまりLibraCoinの引き出し機能を関数実行者が誰かに譲っていることになるのでエラーになります。delegated_withdrawal_capability
がtrue
の場合にwithdraw_from_account
が実行されます。
・withdraw_from_account
では、自分のLibraCoinのバランスからamount
分だけ引き離したLibraCoin.T
を作成しています。関数の中ではLibraCoin
モジュールのwithdraw
が使われています。
Delegated Withdrawal Capability
今までdelegated_withdrawal_capability
が出てきていましたが、それを扱う関数になります。
extract_sender_withdrawal_capability
は自分のリブラアカウントからの引き出し権限を手放す関数で、restore_withdrawal_capability
で手放した引き出し権限をまた手元に戻す関数になっています。
public extract_sender_withdrawal_capability(): Self.WithdrawalCapability acquires T {
let sender: address;
let sender_account: &mut Self.T;
let delegated_ref: &mut bool;
sender = get_txn_sender();
sender_account = borrow_global_mut<T>(copy(sender));
delegated_ref = &mut move(sender_account).delegated_withdrawal_capability;
if (*copy(delegated_ref)) {
abort(11);
} else {
*move(delegated_ref) = true;
return WithdrawalCapability { account_address: move(sender) };
}
}
public restore_withdrawal_capability(cap: Self.WithdrawalCapability) acquires T {
let account_address: address;
let account: &mut Self.T;
WithdrawalCapability { account_address } = move(cap);
account = borrow_global_mut<T>(move(account_address));
*(&mut move(account).delegated_withdrawal_capability) = false;
return;
}
resource WithdrawalCapability {
account_address: address,
}
extract_sender_withdrawal_capability
ではdelegated_withdrawal_capability
をtrueにしてresourceのWithdrawalCapability
に関数実行者のアドレスを渡しています。
WithdrawalCapability
に紐付いているアカウントはLibraCoinの引き出しが可能になると説明されていましたが、extract_sender_withdrawal_capability
ではLibraCoinの引き出し権限がどのアドレスにも移動していないため、このresourceがなんのために用意されているresourceなのか理解できませんでした。ただ、LibraAccount
のモジュールにはWithdrawalCapability
のアドレスを移動する関数がなかったのですが、別のモジュールでWithdrawalCapability
のアドレスを移動させる関数があるかもしれません。要調査です。
restore_withdrawal_capability
関数ではWithdrawalCapability
を削除して、delegated_withdrawal_capability
をfalse
にしています。
・WithdrawalCapability { account_address } = move(cap);
でWithdrawalCapability
を削除しているようですが、引数にcap: Self.WithdrawalCapability
を渡しており、引数をそのままmove
することにより削除しているようです。
・この関数の中のaccount_address
が何のアドレスなのかわかりませんでした、、、どこから持って来るのだろう?Self.WithdrawalCapability
ってなってるから自分のアドレス??
終わりに
LibraAccountモジュールの主要な関数を見ていきました。LibraはEthereumと同様にアカウントベースのステート管理が採用されていますが、コードを見ているとステートの管理はMOVE言語の特徴によってBitcoinのUTXOに似ているなと感じました。
2つのデフォルトモジュールの中身を見ましたがrustと似た言語であるMOVEのコードの特徴を掴むのはなかなか難しいです。