2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Libra開発言語 MOVEのLibraAccountモジュール

Posted at

はじめに

前回は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 (*&copy(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),
            *&copy(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 (*&copy(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)) == *(&copy(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 = *&copy(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_capabilitydelegated_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_capabilitydelegated_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はSentPaymentEventReceivedPaymentEventのように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を送るためにはdepositdeposit_with_metadatadeposit_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 = *&copy(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 Tsent_events: Self.EventHandle<Self.SentPaymentEvent>SentPaymentEventのstructを渡しています。

write_to_event_storeでeventがstoreされる場所に書き込まれているようです。おそらくこの関数の中でEventHandleSentPaymentEventは紐付けられてると思います。この辺りの書き方はかなり難しいですね、、全然理解できていません。
write_to_event_storeの引数に、EventHandleguid, countSentPaymentEventそのものである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 (*&copy(sender_account).delegated_withdrawal_capability) {
        abort(11);
    } else {
        return Self.withdraw_from_account(move(sender_account), move(amount));
    }
}

withdraw_from_senderwithdraw_from_accountの順番で処理が行われます。

sender_account = borrow_global_mut<T>(get_txn_sender());で関数の実行者に紐付くresource Tを参照しています。get_txn_sender()で関数の実行者のアドレスを取得することができます。Solidityでいうとmsg.senderを同じ扱いになります。

・条件分岐はresource Tdelegated_withdrawal_capabilityで判断されています。delegated_withdrawal_capabilitytrueの場合、つまりLibraCoinの引き出し機能を関数実行者が誰かに譲っていることになるのでエラーになります。delegated_withdrawal_capabilitytrueの場合に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_capabilityfalseにしています。
WithdrawalCapability { account_address } = move(cap);WithdrawalCapabilityを削除しているようですが、引数にcap: Self.WithdrawalCapabilityを渡しており、引数をそのままmoveすることにより削除しているようです。
・この関数の中のaccount_addressが何のアドレスなのかわかりませんでした、、、どこから持って来るのだろう?Self.WithdrawalCapabilityってなってるから自分のアドレス??

終わりに

LibraAccountモジュールの主要な関数を見ていきました。LibraはEthereumと同様にアカウントベースのステート管理が採用されていますが、コードを見ているとステートの管理はMOVE言語の特徴によってBitcoinのUTXOに似ているなと感じました。
2つのデフォルトモジュールの中身を見ましたがrustと似た言語であるMOVEのコードの特徴を掴むのはなかなか難しいです。

 

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?