Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Module 0x1::account_abstraction

use 0x1::auth_data;
use 0x1::bcs;
use 0x1::big_ordered_map;
use 0x1::create_signer;
use 0x1::error;
use 0x1::event;
use 0x1::features;
use 0x1::from_bcs;
use 0x1::function_info;
use 0x1::hash;
use 0x1::object;
use 0x1::option;
use 0x1::ordered_map;
use 0x1::permissioned_signer;
use 0x1::signer;
use 0x1::string;
use 0x1::system_addresses;
use 0x1::vector;

Struct UpdateDispatchableAuthenticator

#[event]
struct UpdateDispatchableAuthenticator has drop, store
Fields
account: address
update: vector<u8>
auth_function: function_info::FunctionInfo

Struct RemoveDispatchableAuthenticator

#[event]
struct RemoveDispatchableAuthenticator has drop, store
Fields
account: address

Enum Resource DispatchableAuthenticator

The dispatchable authenticator that defines how to authenticates this account in the specified module. An integral part of Account Abstraction.

#[resource_group_member(#[group = 0x1::object::ObjectGroup])]
enum DispatchableAuthenticator has copy, drop, key
Variants
V1
Fields
auth_functions: ordered_map::OrderedMap<function_info::FunctionInfo, bool>

Enum DerivableRegisterValue

enum DerivableRegisterValue has store
Variants
Empty
Fields

Enum Resource DerivableDispatchableAuthenticator

The dispatchable derivable-scoped authenticator, that defines how to authenticate

enum DerivableDispatchableAuthenticator has key
Variants
V1
Fields
auth_functions: big_ordered_map::BigOrderedMap<function_info::FunctionInfo, account_abstraction::DerivableRegisterValue>

Constants

const MAX_U64: u128 = 18446744073709551615;

const ENOT_MASTER_SIGNER: u64 = 4;

derivable_aa_account_address uses this for domain separation within its native implementation source is defined in Scheme enum in types/src/transaction/authenticator.rs

const DERIVABLE_ABSTRACTION_DERIVED_SCHEME: u8 = 5;

const EACCOUNT_ABSTRACTION_NOT_ENABLED: u64 = 8;

const EAUTH_FUNCTION_SIGNATURE_MISMATCH: u64 = 3;

const EDEPRECATED_FUNCTION: u64 = 6;

const EDERIVABLE_AA_NOT_INITIALIZED: u64 = 7;

const EDERIVABLE_ACCOUNT_ABSTRACTION_NOT_ENABLED: u64 = 9;

const EDISPATCHABLE_AUTHENTICATOR_IS_NOT_USED: u64 = 1;

const EFUNCTION_INFO_EXISTENCE: u64 = 2;

const EINCONSISTENT_SIGNER_ADDRESS: u64 = 5;

Function using_dispatchable_authenticator

Return true if the account is an abstracted account that can be authenticated with dispatchable move authenticator.

#[view]
public fun using_dispatchable_authenticator(addr: address): bool
Implementation
public fun using_dispatchable_authenticator(addr: address): bool {
    exists<DispatchableAuthenticator>(resource_addr(addr))
}

Function dispatchable_authenticator

Return the current dispatchable authenticator move function info. None means this authentication scheme is disabled.

#[view]
public fun dispatchable_authenticator(addr: address): option::Option<vector<function_info::FunctionInfo>>
Implementation
public fun dispatchable_authenticator(addr: address): Option<vector<FunctionInfo>> acquires DispatchableAuthenticator {
    let resource_addr = resource_addr(addr);
    if (exists<DispatchableAuthenticator>(resource_addr)) {
        option::some(
            DispatchableAuthenticator[resource_addr].auth_functions.keys()
        )
    } else { option::none() }
}

Function derive_account_address_view

Return the account address corresponding to the given abstract_public_key, for the derivable account abstraction defined by the given function.

#[view]
public fun derive_account_address_view(module_address: address, module_name: string::String, function_name: string::String, abstract_public_key: vector<u8>): address
Implementation
public fun derive_account_address_view(
    module_address: address,
    module_name: String,
    function_name: String,
    abstract_public_key: vector<u8>
): address {
    derive_account_address(
        function_info::new_function_info_from_address(module_address, module_name, function_name),
        &abstract_public_key,
    )
}

Function derive_account_address

Return the account address corresponding to the given abstract_public_key, for the derivable account abstraction defined by the given function. TODO: probably worth creating some module with all these derived functions, and do computation/caching in rust to avoid recomputation, as we do for objects.

public fun derive_account_address(derivable_func_info: function_info::FunctionInfo, abstract_public_key: &vector<u8>): address
Implementation
public fun derive_account_address(derivable_func_info: FunctionInfo, abstract_public_key: &vector<u8>): address {
    // using bcs serialized structs here - this allows for no need for separators.
    // Alternative would've been to create unique string, we would need to convert derivable_func_info into string,
    // then authentication_key to hex, and then we need separators as well - like ::
    let bytes = bcs::to_bytes(&derivable_func_info);
    bytes.append(bcs::to_bytes(abstract_public_key));
    bytes.push_back(DERIVABLE_ABSTRACTION_DERIVED_SCHEME);
    from_bcs::to_address(hash::sha3_256(bytes))
}

Function add_authentication_function

Add dispatchable authentication function that enables account abstraction via this function. Note: it is a private entry function that can only be called directly from transaction.

entry fun add_authentication_function(account: &signer, module_address: address, module_name: string::String, function_name: string::String)
Implementation
entry fun add_authentication_function(
    account: &signer,
    module_address: address,
    module_name: String,
    function_name: String,
) acquires DispatchableAuthenticator {
    assert!(features::is_account_abstraction_enabled(), error::invalid_state(EACCOUNT_ABSTRACTION_NOT_ENABLED));
    assert!(!is_permissioned_signer(account), error::permission_denied(ENOT_MASTER_SIGNER));
    update_dispatchable_authenticator_impl(
        account,
        function_info::new_function_info_from_address(module_address, module_name, function_name),
        true
    );
}

Function remove_authentication_function

Remove dispatchable authentication function that enables account abstraction via this function. dispatchable function needs to verify that signing_data.authenticator() is a valid signature of signing_data.digest(). Note: it is a private entry function that can only be called directly from transaction.

entry fun remove_authentication_function(account: &signer, module_address: address, module_name: string::String, function_name: string::String)
Implementation
entry fun remove_authentication_function(
    account: &signer,
    module_address: address,
    module_name: String,
    function_name: String,
) acquires DispatchableAuthenticator {
    assert!(!is_permissioned_signer(account), error::permission_denied(ENOT_MASTER_SIGNER));
    update_dispatchable_authenticator_impl(
        account,
        function_info::new_function_info_from_address(module_address, module_name, function_name),
        false
    );
}

Function remove_authenticator

Remove dispatchable authenticator so that all dispatchable authentication functions will be removed as well. After calling this function, the account is not abstracted at all. Note: it is a private entry function that can only be called directly from transaction.

entry fun remove_authenticator(account: &signer)
Implementation
entry fun remove_authenticator(
    account: &signer,
) acquires DispatchableAuthenticator {
    assert!(!is_permissioned_signer(account), error::permission_denied(ENOT_MASTER_SIGNER));
    let addr = signer::address_of(account);
    let resource_addr = resource_addr(addr);
    if (exists<DispatchableAuthenticator>(resource_addr)) {
        move_from<DispatchableAuthenticator>(resource_addr);
        event::emit(RemoveDispatchableAuthenticator {
            account: addr,
        });
    };
}

Function register_derivable_authentication_function

Add dispatchable derivable authentication function, that enables account abstraction via this function. This means all accounts within the domain can use it to authenticate, without needing an initialization (unlike non-domain AA). dispatchable function needs to verify two things:

  • that signing_data.derivable_abstract_signature() is a valid signature of signing_data.digest() (just like regular AA)
  • that signing_data.derivable_abstract_public_key() is correct identity representing the authenticator (missing this step would allow impersonation)

Note: This is public entry function, as it requires framework signer, and that can only be obtained as a part of the governance script.

public entry fun register_derivable_authentication_function(aptos_framework: &signer, module_address: address, module_name: string::String, function_name: string::String)
Implementation
public entry fun register_derivable_authentication_function(
    aptos_framework: &signer,
    module_address: address,
    module_name: String,
    function_name: String,
) acquires DerivableDispatchableAuthenticator {
    assert!(features::is_derivable_account_abstraction_enabled(), error::invalid_state(EDERIVABLE_ACCOUNT_ABSTRACTION_NOT_ENABLED));
    system_addresses::assert_aptos_framework(aptos_framework);

    DerivableDispatchableAuthenticator[@aptos_framework].auth_functions.add(
        function_info::new_function_info_from_address(module_address, module_name, function_name),
        DerivableRegisterValue::Empty,
    );
}

Function initialize

public entry fun initialize(aptos_framework: &signer)
Implementation
public entry fun initialize(aptos_framework: &signer) {
    system_addresses::assert_aptos_framework(aptos_framework);
    move_to(
        aptos_framework,
        DerivableDispatchableAuthenticator::V1 { auth_functions: big_ordered_map::new_with_config(0, 0, false) }
    );
}

Function resource_addr

fun resource_addr(source: address): address
Implementation
inline fun resource_addr(source: address): address {
    object::create_user_derived_object_address(source, @aptos_fungible_asset)
}

Function update_dispatchable_authenticator_impl

fun update_dispatchable_authenticator_impl(account: &signer, auth_function: function_info::FunctionInfo, is_add: bool)
Implementation
fun update_dispatchable_authenticator_impl(
    account: &signer,
    auth_function: FunctionInfo,
    is_add: bool,
) acquires DispatchableAuthenticator {
    let addr = signer::address_of(account);
    let resource_addr = resource_addr(addr);
    let dispatcher_auth_function_info = function_info::new_function_info_from_address(
        @aptos_framework,
        string::utf8(b"account_abstraction"),
        string::utf8(b"dispatchable_authenticate"),
    );
    assert!(
        function_info::check_dispatch_type_compatibility(&dispatcher_auth_function_info, &auth_function),
        error::invalid_argument(EAUTH_FUNCTION_SIGNATURE_MISMATCH)
    );
    if (is_add) {
        if (!exists<DispatchableAuthenticator>(resource_addr)) {
            move_to(
                &create_signer::create_signer(resource_addr),
                DispatchableAuthenticator::V1 { auth_functions: ordered_map::new() }
            );
        };
        let current_map = &mut borrow_global_mut<DispatchableAuthenticator>(resource_addr).auth_functions;
        assert!(
            !current_map.contains(&auth_function),
            error::already_exists(EFUNCTION_INFO_EXISTENCE)
        );
        current_map.add(auth_function, true);
        event::emit(
            UpdateDispatchableAuthenticator {
                account: addr,
                update: b"add",
                auth_function,
            }
        );
    } else {
        assert!(exists<DispatchableAuthenticator>(resource_addr), error::not_found(EFUNCTION_INFO_EXISTENCE));
        let current_map = &mut borrow_global_mut<DispatchableAuthenticator>(resource_addr).auth_functions;
        assert!(
            current_map.contains(&auth_function),
            error::not_found(EFUNCTION_INFO_EXISTENCE)
        );
        current_map.remove(&auth_function);
        event::emit(
            UpdateDispatchableAuthenticator {
                account: addr,
                update: b"remove",
                auth_function,
            }
        );
        if (current_map.length() == 0) {
            remove_authenticator(account);
        }
    };
}

Function dispatchable_authenticator_internal

fun dispatchable_authenticator_internal(addr: address): &ordered_map::OrderedMap<function_info::FunctionInfo, bool>
Implementation
inline fun dispatchable_authenticator_internal(addr: address): &OrderedMap<FunctionInfo, bool> {
    assert!(using_dispatchable_authenticator(addr), error::not_found(EDISPATCHABLE_AUTHENTICATOR_IS_NOT_USED));
    &DispatchableAuthenticator[resource_addr(addr)].auth_functions
}

Function dispatchable_derivable_authenticator_internal

fun dispatchable_derivable_authenticator_internal(): &big_ordered_map::BigOrderedMap<function_info::FunctionInfo, account_abstraction::DerivableRegisterValue>
Implementation
inline fun dispatchable_derivable_authenticator_internal(): &BigOrderedMap<FunctionInfo, DerivableRegisterValue> {
    assert!(exists<DerivableDispatchableAuthenticator>(@aptos_framework), error::not_found(EDERIVABLE_AA_NOT_INITIALIZED));
    &DerivableDispatchableAuthenticator[@aptos_framework].auth_functions
}

Function authenticate

fun authenticate(account: signer, func_info: function_info::FunctionInfo, signing_data: auth_data::AbstractionAuthData): signer
Implementation
fun authenticate(
    account: signer,
    func_info: FunctionInfo,
    signing_data: AbstractionAuthData,
): signer acquires DispatchableAuthenticator, DerivableDispatchableAuthenticator {
    let master_signer_addr = signer::address_of(&account);

    if (signing_data.is_derivable()) {
        assert!(features::is_derivable_account_abstraction_enabled(), error::invalid_state(EDERIVABLE_ACCOUNT_ABSTRACTION_NOT_ENABLED));
        assert!(master_signer_addr == derive_account_address(func_info, signing_data.derivable_abstract_public_key()), error::invalid_state(EINCONSISTENT_SIGNER_ADDRESS));

        let func_infos = dispatchable_derivable_authenticator_internal();
        assert!(func_infos.contains(&func_info), error::not_found(EFUNCTION_INFO_EXISTENCE));
    } else {
        assert!(features::is_account_abstraction_enabled(), error::invalid_state(EACCOUNT_ABSTRACTION_NOT_ENABLED));

        let func_infos = dispatchable_authenticator_internal(master_signer_addr);
        assert!(func_infos.contains(&func_info), error::not_found(EFUNCTION_INFO_EXISTENCE));
    };

    function_info::load_module_from_function(&func_info);
    let returned_signer = dispatchable_authenticate(account, signing_data, &func_info);
    // Returned signer MUST represent the same account address. Otherwise, it may break the invariant of Aptos blockchain!
    assert!(
        master_signer_addr == signer::address_of(&returned_signer),
        error::invalid_state(EINCONSISTENT_SIGNER_ADDRESS)
    );
    returned_signer
}

Function dispatchable_authenticate

The native function to dispatch customized move authentication function.

fun dispatchable_authenticate(account: signer, signing_data: auth_data::AbstractionAuthData, function: &function_info::FunctionInfo): signer
Implementation
native fun dispatchable_authenticate(
    account: signer,
    signing_data: AbstractionAuthData,
    function: &FunctionInfo
): signer;

Function add_dispatchable_authentication_function

#[deprecated]
public entry fun add_dispatchable_authentication_function(_account: &signer, _module_address: address, _module_name: string::String, _function_name: string::String)
Implementation
public entry fun add_dispatchable_authentication_function(
    _account: &signer,
    _module_address: address,
    _module_name: String,
    _function_name: String,
) {
    abort std::error::unavailable(EDEPRECATED_FUNCTION)
}

Function remove_dispatchable_authentication_function

#[deprecated]
public entry fun remove_dispatchable_authentication_function(_account: &signer, _module_address: address, _module_name: string::String, _function_name: string::String)
Implementation
public entry fun remove_dispatchable_authentication_function(
    _account: &signer,
    _module_address: address,
    _module_name: String,
    _function_name: String,
) {
    abort std::error::unavailable(EDEPRECATED_FUNCTION)
}

Function remove_dispatchable_authenticator

#[deprecated]
public entry fun remove_dispatchable_authenticator(_account: &signer)
Implementation
public entry fun remove_dispatchable_authenticator(
    _account: &signer,
) {
    abort std::error::unavailable(EDEPRECATED_FUNCTION)
}

Specification

pragma verify = false;

fun spec_dispatchable_authenticate(
   account: signer,
   signing_data: AbstractionAuthData,
   function: &FunctionInfo
): signer;

Function dispatchable_authenticate

fun dispatchable_authenticate(account: signer, signing_data: auth_data::AbstractionAuthData, function: &function_info::FunctionInfo): signer
pragma opaque;
ensures [abstract] result == spec_dispatchable_authenticate(account, signing_data, function);