0x1::Account
The module for the account resource that governs every account
Account
Balance
WithdrawCapability
KeyRotationCapability
WithdrawEvent
DepositEvent
AcceptTokenEvent
SignerDelegated
SignerCapability
AutoAcceptToken
RotateAuthKeyEvent
ExtractWithdrawCapEvent
SignerDelegateEvent
EventStore
remove_signer_capability
create_signer_with_cap
destroy_signer_cap
signer_address
is_signer_delegated
create_genesis_account
release_genesis_signer
create_account
create_account_with_address
make_account
create_signer
create_account_with_initial_amount
create_account_with_initial_amount_v2
create_account_with_initial_amount_entry
create_delegate_account
deposit_to_self
deposit
deposit_with_metadata
deposit_to_balance
withdraw_from_balance_v2
set_sequence_number
set_authentication_key
withdraw_from_balance
withdraw
withdraw_with_metadata
withdraw_with_capability
withdraw_with_capability_and_metadata
extract_withdraw_capability
restore_withdraw_capability
emit_account_withdraw_event
emit_account_deposit_event
pay_from_capability
pay_from_with_metadata
pay_from
rotate_authentication_key_with_capability
extract_key_rotation_capability
restore_key_rotation_capability
destroy_key_rotation_capability
rotate_authentication_key
rotate_authentication_key_entry
do_rotate_authentication_key
balance_for
balance
do_accept_token
accept_token
accept_token_entry
is_accepts_token
is_accept_token
can_auto_accept_token
set_auto_accept_token_entry
set_auto_accept_token
try_accept_token
sequence_number_for_account
sequence_number
authentication_key
delegated_key_rotation_capability
delegated_withdraw_capability
withdraw_capability_address
key_rotation_capability_address
exists_at
is_dummy_auth_key
is_dummy_auth_key_v2
txn_prologue
txn_prologue_v2
txn_epilogue
transaction_fee_simulate
txn_epilogue_v2
txn_epilogue_v3
remove_zero_balance_entry
remove_zero_balance
make_event_store_if_not_exist
use 0x1::Authenticator;
use 0x1::BCS;
use 0x1::CoreAddresses;
use 0x1::Errors;
use 0x1::Event;
use 0x1::Hash;
use 0x1::Math;
use 0x1::Option;
use 0x1::STC;
use 0x1::Signer;
use 0x1::Timestamp;
use 0x1::Token;
use 0x1::TransactionFee;
use 0x1::Vector;
Account
Every account has a Account::Account resource
struct Account has key
authentication_key: vector<u8>
withdrawal_capability: Option::Option<Account::WithdrawCapability>
withdrawal_capability
allows whoever holds this capability
to withdraw from the account. At the time of account creation
this capability is stored in this option. It can later be
"extracted" from this field via extract_withdraw_capability
,
and can also be restored via restore_withdraw_capability
.
key_rotation_capability: Option::Option<Account::KeyRotationCapability>
key_rotation_capability
allows whoever holds this capability
the ability to rotate the authentication key for the account. At
the time of account creation this capability is stored in this
option. It can later be "extracted" from this field via
extract_key_rotation_capability
, and can also be restored via
restore_key_rotation_capability
.
withdraw_events: Event::EventHandle<Account::WithdrawEvent>
deposit_events: Event::EventHandle<Account::DepositEvent>
accept_token_events: Event::EventHandle<Account::AcceptTokenEvent>
sequence_number: u64
Balance
A resource that holds the tokens stored in this account
struct Balance<TokenType> has key
token: Token::Token<TokenType>
WithdrawCapability
The holder of WithdrawCapability for account_address can withdraw Token from account_address/Account::Account/balance. There is at most one WithdrawCapability in existence for a given address.
struct WithdrawCapability has store
account_address: address
KeyRotationCapability
The holder of KeyRotationCapability for account_address can rotate the authentication key for account_address (i.e., write to account_address/Account::Account/authentication_key). There is at most one KeyRotationCapability in existence for a given address.
struct KeyRotationCapability has store
account_address: address
WithdrawEvent
Message for balance withdraw event.
struct WithdrawEvent has drop, store
amount: u128
token_code: Token::TokenCode
metadata: vector<u8>
struct DepositEvent has drop, store
amount: u128
token_code: Token::TokenCode
metadata: vector<u8>
struct AcceptTokenEvent has drop, store
token_code: Token::TokenCode
struct SignerDelegated has key
dummy_field: bool
struct SignerCapability has store
addr: address
struct AutoAcceptToken has key
enable: bool
struct RotateAuthKeyEvent has drop, store
account_address: address
new_auth_key: vector<u8>
struct ExtractWithdrawCapEvent has drop, store
account_address: address
struct SignerDelegateEvent has drop, store
account_address: address
struct EventStore has key
rotate_auth_key_events: Event::EventHandle<Account::RotateAuthKeyEvent>
extract_withdraw_cap_events: Event::EventHandle<Account::ExtractWithdrawCapEvent>
signer_delegate_events: Event::EventHandle<Account::SignerDelegateEvent>
const MAX_U64: u128 = 18446744073709551615;
const EDEPRECATED_FUNCTION: u64 = 19;
const EPROLOGUE_ACCOUNT_DOES_NOT_EXIST: u64 = 0;
The address bytes length
const ADDRESS_LENGTH: u64 = 16;
const CONTRACT_ACCOUNT_AUTH_KEY_PLACEHOLDER: vector<u8> = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
const DUMMY_AUTH_KEY: vector<u8> = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
const EADDRESS_AND_AUTH_KEY_MISMATCH: u64 = 105;
const EADDRESS_PUBLIC_KEY_INCONSISTENT: u64 = 104;
const EBAD_TRANSACTION_FEE_TOKEN: u64 = 18;
const ECOIN_DEPOSIT_IS_ZERO: u64 = 15;
const EINSUFFICIENT_BALANCE: u64 = 10;
const EKEY_ROTATION_CAPABILITY_ALREADY_EXTRACTED: u64 = 103;
const EMALFORMED_AUTHENTICATION_KEY: u64 = 102;
const EPROLOGUE_CANT_PAY_GAS_DEPOSIT: u64 = 4;
const EPROLOGUE_INVALID_ACCOUNT_AUTH_KEY: u64 = 1;
const EPROLOGUE_SEQUENCE_NUMBER_TOO_BIG: u64 = 9;
const EPROLOGUE_SEQUENCE_NUMBER_TOO_NEW: u64 = 3;
const EPROLOGUE_SEQUENCE_NUMBER_TOO_OLD: u64 = 2;
const EPROLOGUE_SIGNER_ALREADY_DELEGATED: u64 = 200;
const ERR_SIGNER_ALREADY_DELEGATED: u64 = 107;
const ERR_TOKEN_NOT_ACCEPT: u64 = 106;
const EWITHDRAWAL_CAPABILITY_ALREADY_EXTRACTED: u64 = 101;
## Function `remove_signer_capability`
A one-way action, once SignerCapability is removed from signer, the address cannot send txns anymore.
This function can only called once by signer.
public fun remove_signer_capability(signer: &signer): Account::SignerCapability
public fun remove_signer_capability(signer: &signer): SignerCapability
acquires Account, EventStore {
let signer_addr = Signer::address_of(signer);
assert!(!is_signer_delegated(signer_addr), Errors::invalid_state(ERR_SIGNER_ALREADY_DELEGATED));
// set to account auth key to noop.
{
let key_rotation_capability = extract_key_rotation_capability(signer);
rotate_authentication_key_with_capability(&key_rotation_capability, CONTRACT_ACCOUNT_AUTH_KEY_PLACEHOLDER);
destroy_key_rotation_capability(key_rotation_capability);
move_to(signer, SignerDelegated {});
make_event_store_if_not_exist(signer);
let event_store = borrow_global_mut<EventStore>(signer_addr);
Event::emit_event<SignerDelegateEvent>(
&mut event_store.signer_delegate_events,
SignerDelegateEvent {
account_address: signer_addr
}
);
};
let signer_cap = SignerCapability {addr: signer_addr };
signer_cap
}
public fun create_signer_with_cap(cap: &Account::SignerCapability): signer
public fun create_signer_with_cap(cap: &SignerCapability): signer {
create_signer(cap.addr)
}
public fun destroy_signer_cap(cap: Account::SignerCapability)
public fun destroy_signer_cap(cap: SignerCapability) {
let SignerCapability {addr: _} = cap;
}
public fun signer_address(cap: &Account::SignerCapability): address
public fun signer_address(cap: &SignerCapability): address {
cap.addr
}
public fun is_signer_delegated(addr: address): bool
public fun is_signer_delegated(addr: address): bool {
exists<SignerDelegated>(addr)
}
new_account_address
and return signer.
Genesis authentication_key is zero bytes.
public fun create_genesis_account(new_account_address: address): signer
public fun create_genesis_account(
new_account_address: address,
) :signer {
Timestamp::assert_genesis();
let new_account = create_signer(new_account_address);
make_account(&new_account, DUMMY_AUTH_KEY);
new_account
}
aborts_if !Timestamp::is_genesis();
aborts_if len(DUMMY_AUTH_KEY) != 32;
aborts_if exists<Account>(new_account_address);
public fun release_genesis_signer(_genesis_account: signer)
public fun release_genesis_signer(_genesis_account: signer){
}
aborts_if false;
public fun create_account<TokenType: store>(_authentication_key: vector<u8>): address
public fun create_account<TokenType: store>(_authentication_key: vector<u8>): address {
abort Errors::deprecated(EDEPRECATED_FUNCTION)
}
aborts_if true;
fresh_address
with a balance of zero and empty auth key, the address as init auth key for check transaction.
Creating an account at address StarcoinFramework will cause runtime failure as it is a
reserved address for the MoveVM.
public fun create_account_with_address<TokenType: store>(fresh_address: address)
public fun create_account_with_address<TokenType: store>(fresh_address: address) acquires Account {
let new_account = create_signer(fresh_address);
make_account(&new_account, DUMMY_AUTH_KEY);
// Make sure all account accept STC.
if (!STC::is_stc<TokenType>()){
do_accept_token<STC>(&new_account);
};
do_accept_token<TokenType>(&new_account);
}
aborts_if exists<Account>(fresh_address);
aborts_if Token::spec_token_code<TokenType>() != Token::spec_token_code<STC>() && exists<Balance<STC>>(fresh_address);
aborts_if exists<Balance<TokenType>>(fresh_address);
ensures exists_at(fresh_address);
ensures exists<Balance<TokenType>>(fresh_address);
fun make_account(new_account: &signer, authentication_key: vector<u8>)
fun make_account(
new_account: &signer,
authentication_key: vector<u8>,
) {
assert!(Vector::length(&authentication_key) == 32, Errors::invalid_argument(EMALFORMED_AUTHENTICATION_KEY));
let new_account_addr = Signer::address_of(new_account);
Event::publish_generator(new_account);
move_to(new_account, Account {
authentication_key,
withdrawal_capability: Option::some(
WithdrawCapability {
account_address: new_account_addr
}),
key_rotation_capability: Option::some(
KeyRotationCapability {
account_address: new_account_addr
}),
withdraw_events: Event::new_event_handle<WithdrawEvent>(new_account),
deposit_events: Event::new_event_handle<DepositEvent>(new_account),
accept_token_events: Event::new_event_handle<AcceptTokenEvent>(new_account),
sequence_number: 0,
});
move_to(new_account, AutoAcceptToken{enable: true});
move_to(new_account, EventStore {
rotate_auth_key_events: Event::new_event_handle<RotateAuthKeyEvent>(new_account),
extract_withdraw_cap_events: Event::new_event_handle<ExtractWithdrawCapEvent>(new_account),
signer_delegate_events: Event::new_event_handle<SignerDelegateEvent>(new_account),
});
}
aborts_if len(authentication_key) != 32;
aborts_if exists<Account>(Signer::address_of(new_account));
aborts_if exists<AutoAcceptToken>(Signer::address_of(new_account));
ensures exists_at(Signer::address_of(new_account));
fun create_signer(addr: address): signer
native fun create_signer(addr: address): signer;
public entry fun create_account_with_initial_amount<TokenType: store>(account: signer, fresh_address: address, _auth_key: vector<u8>, initial_amount: u128)
public entry fun create_account_with_initial_amount<TokenType: store>(account: signer, fresh_address: address, _auth_key: vector<u8>, initial_amount: u128)
acquires Account, Balance, AutoAcceptToken {
create_account_with_initial_amount_entry<TokenType>(account, fresh_address, initial_amount);
}
pragma verify = false;
public entry fun create_account_with_initial_amount_v2<TokenType: store>(account: signer, fresh_address: address, initial_amount: u128)
public entry fun create_account_with_initial_amount_v2<TokenType: store>(account: signer, fresh_address: address, initial_amount: u128)
acquires Account, Balance, AutoAcceptToken {
create_account_with_initial_amount_entry<TokenType>(account, fresh_address, initial_amount);
}
pragma verify = false;
public entry fun create_account_with_initial_amount_entry<TokenType: store>(account: signer, fresh_address: address, initial_amount: u128)
public entry fun create_account_with_initial_amount_entry<TokenType: store>(account: signer, fresh_address: address, initial_amount: u128)
acquires Account, Balance, AutoAcceptToken {
create_account_with_address<TokenType>(fresh_address);
if (initial_amount > 0) {
pay_from<TokenType>(&account, fresh_address, initial_amount);
};
}
SignerCapability
public fun create_delegate_account(sender: &signer): (address, Account::SignerCapability)
public fun create_delegate_account(sender: &signer) : (address, SignerCapability) acquires Balance, Account, EventStore {
let sender_address = Signer::address_of(sender);
let sequence_number = Self::sequence_number(sender_address);
// use stc balance as part of seed, just for new address more random.
let stc_balance = Self::balance<STC>(sender_address);
let seed_bytes = BCS::to_bytes(&sender_address);
Vector::append(&mut seed_bytes, BCS::to_bytes(&sequence_number));
Vector::append(&mut seed_bytes, BCS::to_bytes(&stc_balance));
let seed_hash = Hash::sha3_256(seed_bytes);
let i = 0;
let address_bytes = Vector::empty();
while (i < ADDRESS_LENGTH) {
Vector::push_back(&mut address_bytes, *Vector::borrow(&seed_hash,i));
i = i + 1;
};
let new_address = BCS::to_address(address_bytes);
Self::create_account_with_address<STC>(new_address);
let new_signer = Self::create_signer(new_address);
(new_address, Self::remove_signer_capability(&new_signer))
}
pragma verify = false;
to_deposit
token into the self's account balance
public fun deposit_to_self<TokenType: store>(account: &signer, to_deposit: Token::Token<TokenType>)
public fun deposit_to_self<TokenType: store>(account: &signer, to_deposit: Token<TokenType>)
acquires Account, Balance, AutoAcceptToken {
let account_address = Signer::address_of(account);
if (!is_accepts_token<TokenType>(account_address)){
do_accept_token<TokenType>(account);
};
deposit(account_address, to_deposit);
}
aborts_if to_deposit.value == 0;
let is_accepts_token = exists<Balance<TokenType>>(Signer::address_of(account));
aborts_if is_accepts_token && global<Balance<TokenType>>(Signer::address_of(account)).token.value + to_deposit.value > max_u128();
aborts_if !exists<Account>(Signer::address_of(account));
ensures exists<Balance<TokenType>>(Signer::address_of(account));
to_deposit
token into the receiver
's account balance with the no metadata
It's a reverse operation of withdraw
.
public fun deposit<TokenType: store>(receiver: address, to_deposit: Token::Token<TokenType>)
public fun deposit<TokenType: store>(
receiver: address,
to_deposit: Token<TokenType>,
) acquires Account, Balance, AutoAcceptToken {
deposit_with_metadata<TokenType>(receiver, to_deposit, x"")
}
include DepositWithMetadataAbortsIf<TokenType>;
to_deposit
token into the receiver
's account balance with the attached metadata
It's a reverse operation of withdraw_with_metadata
.
public fun deposit_with_metadata<TokenType: store>(receiver: address, to_deposit: Token::Token<TokenType>, metadata: vector<u8>)
public fun deposit_with_metadata<TokenType: store>(
receiver: address,
to_deposit: Token<TokenType>,
metadata: vector<u8>,
) acquires Account, Balance, AutoAcceptToken {
if (!exists_at(receiver)) {
create_account_with_address<TokenType>(receiver);
};
try_accept_token<TokenType>(receiver);
let deposit_value = Token::value(&to_deposit);
if (deposit_value > 0u128) {
// Deposit the `to_deposit` token
deposit_to_balance<TokenType>(borrow_global_mut<Balance<TokenType>>(receiver), to_deposit);
// emit deposit event
emit_account_deposit_event<TokenType>(receiver, deposit_value, metadata);
} else {
Token::destroy_zero(to_deposit);
};
}
include DepositWithMetadataAbortsIf<TokenType>;
ensures exists<Balance<TokenType>>(receiver);
ensures old(global<Balance<TokenType>>(receiver)).token.value + to_deposit.value == global<Balance<TokenType>>(receiver).token.value;
schema DepositWithMetadataAbortsIf<TokenType> {
receiver: address;
to_deposit: Token<TokenType>;
aborts_if to_deposit.value == 0;
aborts_if !exists<Account>(receiver);
aborts_if !exists<Balance<TokenType>>(receiver);
aborts_if global<Balance<TokenType>>(receiver).token.value + to_deposit.value > max_u128();
}
amount
to the given account balance
fun deposit_to_balance<TokenType: store>(balance: &mut Account::Balance<TokenType>, token: Token::Token<TokenType>)
fun deposit_to_balance<TokenType: store>(balance: &mut Balance<TokenType>, token: Token::Token<TokenType>) {
Token::deposit(&mut balance.token, token)
}
aborts_if balance.token.value + token.value > MAX_U128;
public(friend) fun withdraw_from_balance_v2<TokenType: store>(sender: address, amount: u128): Token::Token<TokenType>
public(friend) fun withdraw_from_balance_v2<TokenType: store>(sender:address, amount: u128): Token<TokenType> acquires Balance {
let balance = borrow_global_mut<Balance<TokenType>>(sender);
Token::withdraw(&mut balance.token, amount)
}
public(friend) fun set_sequence_number(sender: address, sequence_number: u64)
public (friend) fun set_sequence_number(sender: address, sequence_number: u64) acquires Account {
let account = borrow_global_mut<Account>(sender);
account.sequence_number = sequence_number;
}
public(friend) fun set_authentication_key(sender: address, auth_key: vector<u8>)
public (friend) fun set_authentication_key(sender:address,auth_key:vector<u8>) acquires Account{
let account = borrow_global_mut<Account>(sender);
account.authentication_key = auth_key;
}
amount
from the given account balance and return the withdrawn Tokenpublic fun withdraw_from_balance<TokenType: store>(balance: &mut Account::Balance<TokenType>, amount: u128): Token::Token<TokenType>
public fun withdraw_from_balance<TokenType: store>(balance: &mut Balance<TokenType>, amount: u128): Token<TokenType>{
Token::withdraw(&mut balance.token, amount)
}
aborts_if balance.token.value < amount;
amount
Tokenpublic fun withdraw<TokenType: store>(account: &signer, amount: u128): Token::Token<TokenType>
public fun withdraw<TokenType: store>(account: &signer, amount: u128): Token<TokenType>
acquires Account, Balance {
withdraw_with_metadata<TokenType>(account, amount, x"")
}
aborts_if !exists<Balance<TokenType>>(Signer::address_of(account));
aborts_if !exists<Account>(Signer::address_of(account));
aborts_if global<Balance<TokenType>>(Signer::address_of(account)).token.value < amount;
aborts_if Option::is_none(global<Account>(Signer::address_of(account)).withdrawal_capability);
amount
tokens from signer
with given metadata
.
public fun withdraw_with_metadata<TokenType: store>(account: &signer, amount: u128, metadata: vector<u8>): Token::Token<TokenType>
public fun withdraw_with_metadata<TokenType: store>(account: &signer, amount: u128, metadata: vector<u8>): Token<TokenType>
acquires Account, Balance {
let sender_addr = Signer::address_of(account);
let sender_balance = borrow_global_mut<Balance<TokenType>>(sender_addr);
// The sender_addr has delegated the privilege to withdraw from her account elsewhere--abort.
assert!(!delegated_withdraw_capability(sender_addr), Errors::invalid_state(EWITHDRAWAL_CAPABILITY_ALREADY_EXTRACTED));
if (amount == 0){
return Token::zero()
};
emit_account_withdraw_event<TokenType>(sender_addr, amount, metadata);
// The sender_addr has retained her withdrawal privileges--proceed.
withdraw_from_balance<TokenType>(sender_balance, amount)
}
aborts_if !exists<Balance<TokenType>>(Signer::address_of(account));
aborts_if !exists<Account>(Signer::address_of(account));
aborts_if global<Balance<TokenType>>(Signer::address_of(account)).token.value < amount;
aborts_if Option::is_none(global<Account>(Signer::address_of(account)).withdrawal_capability);
fun spec_withdraw<TokenType>(account: signer, amount: u128): Token<TokenType> {
Token<TokenType> { value: amount }
}
amount
Tokenpublic fun withdraw_with_capability<TokenType: store>(cap: &Account::WithdrawCapability, amount: u128): Token::Token<TokenType>
public fun withdraw_with_capability<TokenType: store>(
cap: &WithdrawCapability, amount: u128
): Token<TokenType> acquires Balance, Account {
withdraw_with_capability_and_metadata<TokenType>(cap, amount, x"")
}
aborts_if !exists<Balance<TokenType>>(cap.account_address);
aborts_if !exists<Account>(cap.account_address);
aborts_if global<Balance<TokenType>>(cap.account_address).token.value < amount;
amount
Tokenpublic fun withdraw_with_capability_and_metadata<TokenType: store>(cap: &Account::WithdrawCapability, amount: u128, metadata: vector<u8>): Token::Token<TokenType>
public fun withdraw_with_capability_and_metadata<TokenType: store>(
cap: &WithdrawCapability, amount: u128, metadata: vector<u8>
): Token<TokenType> acquires Balance, Account {
let balance = borrow_global_mut<Balance<TokenType>>(cap.account_address);
emit_account_withdraw_event<TokenType>(cap.account_address, amount, metadata);
withdraw_from_balance<TokenType>(balance , amount)
}
aborts_if !exists<Balance<TokenType>>(cap.account_address);
aborts_if !exists<Account>(cap.account_address);
aborts_if global<Balance<TokenType>>(cap.account_address).token.value < amount;
public fun extract_withdraw_capability(sender: &signer): Account::WithdrawCapability
public fun extract_withdraw_capability(
sender: &signer
): WithdrawCapability acquires Account, EventStore {
let sender_addr = Signer::address_of(sender);
// Abort if we already extracted the unique withdraw capability for this account.
assert!(!delegated_withdraw_capability(sender_addr), Errors::invalid_state(EWITHDRAWAL_CAPABILITY_ALREADY_EXTRACTED));
make_event_store_if_not_exist(sender);
let event_store = borrow_global_mut<EventStore>(sender_addr);
Event::emit_event<ExtractWithdrawCapEvent>(
&mut event_store.extract_withdraw_cap_events,
ExtractWithdrawCapEvent {
account_address: sender_addr,
}
);
let account = borrow_global_mut<Account>(sender_addr);
Option::extract(&mut account.withdrawal_capability)
}
aborts_if !exists<Account>(Signer::address_of(sender));
aborts_if Option::is_none(global<Account>( Signer::address_of(sender)).withdrawal_capability);
public fun restore_withdraw_capability(cap: Account::WithdrawCapability)
public fun restore_withdraw_capability(cap: WithdrawCapability)
acquires Account {
let account = borrow_global_mut<Account>(cap.account_address);
Option::fill(&mut account.withdrawal_capability, cap)
}
aborts_if Option::is_some(global<Account>(cap.account_address).withdrawal_capability);
aborts_if !exists<Account>(cap.account_address);
fun emit_account_withdraw_event<TokenType: store>(account: address, amount: u128, metadata: vector<u8>)
fun emit_account_withdraw_event<TokenType: store>(account: address, amount: u128, metadata: vector<u8>)
acquires Account {
// emit withdraw event
let account = borrow_global_mut<Account>(account);
Event::emit_event<WithdrawEvent>(&mut account.withdraw_events, WithdrawEvent {
amount,
token_code: Token::token_code<TokenType>(),
metadata,
});
}
aborts_if !exists<Account>(account);
fun emit_account_deposit_event<TokenType: store>(account: address, amount: u128, metadata: vector<u8>)
fun emit_account_deposit_event<TokenType: store>(account: address, amount: u128, metadata: vector<u8>)
acquires Account {
// emit withdraw event
let account = borrow_global_mut<Account>(account);
Event::emit_event<DepositEvent>(&mut account.deposit_events, DepositEvent {
amount,
token_code: Token::token_code<TokenType>(),
metadata,
});
}
aborts_if !exists<Account>(account);
amount
Tokenpayee
's account balance. Creates the payee
account if it doesn't exist.
public fun pay_from_capability<TokenType: store>(cap: &Account::WithdrawCapability, payee: address, amount: u128, metadata: vector<u8>)
public fun pay_from_capability<TokenType: store>(
cap: &WithdrawCapability,
payee: address,
amount: u128,
metadata: vector<u8>,
) acquires Account, Balance, AutoAcceptToken {
let tokens = withdraw_with_capability_and_metadata<TokenType>(cap, amount, *&metadata);
deposit_with_metadata<TokenType>(
payee,
tokens,
metadata,
);
}
aborts_if !exists<Balance<TokenType>>(cap.account_address);
aborts_if !exists<Account>(cap.account_address);
aborts_if global<Balance<TokenType>>(cap.account_address).token.value < amount;
aborts_if amount == 0;
aborts_if !exists<Account>(payee);
aborts_if !exists<Balance<TokenType>>(payee);
aborts_if cap.account_address != payee && global<Balance<TokenType>>(payee).token.value + amount > MAX_U128;
amount
Tokenpayee
address with the
attached metadata
Creates the payee
account if it does not exist
public fun pay_from_with_metadata<TokenType: store>(account: &signer, payee: address, amount: u128, metadata: vector<u8>)
public fun pay_from_with_metadata<TokenType: store>(
account: &signer,
payee: address,
amount: u128,
metadata: vector<u8>,
) acquires Account, Balance, AutoAcceptToken {
let tokens = withdraw_with_metadata<TokenType>(account, amount, *&metadata);
deposit_with_metadata<TokenType>(
payee,
tokens,
metadata,
);
}
aborts_if !exists<Balance<TokenType>>(Signer::address_of(account));
aborts_if !exists<Account>(Signer::address_of(account));
aborts_if global<Balance<TokenType>>(Signer::address_of(account)).token.value < amount;
aborts_if Option::is_none(global<Account>(Signer::address_of(account)).withdrawal_capability);
aborts_if amount == 0;
aborts_if !exists<Account>(payee);
aborts_if !exists<Balance<TokenType>>(payee);
aborts_if Signer::address_of(account) != payee && global<Balance<TokenType>>(payee).token.value + amount > max_u128();
schema DepositWithPayerAndMetadataAbortsIf<TokenType> {
payer: address;
payee: address;
to_deposit: Token<TokenType>;
aborts_if to_deposit.value == 0;
aborts_if !exists<Account>(payer);
aborts_if !exists<Account>(payee);
aborts_if !exists<Balance<TokenType>>(payee);
aborts_if global<Balance<TokenType>>(payee).token.value + to_deposit.value > max_u128();
}
amount
Tokenpayee
address
Creates the payee
account if it does not exist
public fun pay_from<TokenType: store>(account: &signer, payee: address, amount: u128)
public fun pay_from<TokenType: store>(
account: &signer,
payee: address,
amount: u128
) acquires Account, Balance, AutoAcceptToken {
pay_from_with_metadata<TokenType>(account, payee, amount, x"");
}
aborts_if !exists<Balance<TokenType>>(Signer::address_of(account));
aborts_if !exists<Account>(Signer::address_of(account));
aborts_if global<Balance<TokenType>>(Signer::address_of(account)).token.value < amount;
aborts_if Option::is_none(global<Account>(Signer::address_of(account)).withdrawal_capability);
aborts_if amount == 0;
aborts_if !exists<Account>(payee);
aborts_if !exists<Balance<TokenType>>(payee);
aborts_if Signer::address_of(account) != payee && global<Balance<TokenType>>(payee).token.value + amount > max_u128();
public fun rotate_authentication_key_with_capability(cap: &Account::KeyRotationCapability, new_authentication_key: vector<u8>)
public fun rotate_authentication_key_with_capability(
cap: &KeyRotationCapability,
new_authentication_key: vector<u8>,
) acquires Account {
let sender_account_resource = borrow_global_mut<Account>(cap.account_address);
// Don't allow rotating to clearly invalid key
assert!(Vector::length(&new_authentication_key) == 32, Errors::invalid_argument(EMALFORMED_AUTHENTICATION_KEY));
sender_account_resource.authentication_key = new_authentication_key;
}
aborts_if !exists<Account>(cap.account_address);
aborts_if len(new_authentication_key) != 32;
ensures global<Account>(cap.account_address).authentication_key == new_authentication_key;
fun spec_rotate_authentication_key_with_capability(addr: address, new_authentication_key: vector<u8>): bool {
global<Account>(addr).authentication_key == new_authentication_key
}
public fun extract_key_rotation_capability(account: &signer): Account::KeyRotationCapability
public fun extract_key_rotation_capability(account: &signer): KeyRotationCapability
acquires Account {
let account_address = Signer::address_of(account);
// Abort if we already extracted the unique key rotation capability for this account.
assert!(!delegated_key_rotation_capability(account_address), Errors::invalid_state(EKEY_ROTATION_CAPABILITY_ALREADY_EXTRACTED));
let account = borrow_global_mut<Account>(account_address);
Option::extract(&mut account.key_rotation_capability)
}
aborts_if !exists<Account>(Signer::address_of(account));
aborts_if Option::is_none(global<Account>(Signer::address_of(account)).key_rotation_capability);
public fun restore_key_rotation_capability(cap: Account::KeyRotationCapability)
public fun restore_key_rotation_capability(cap: KeyRotationCapability)
acquires Account {
let account = borrow_global_mut<Account>(cap.account_address);
Option::fill(&mut account.key_rotation_capability, cap)
}
aborts_if Option::is_some(global<Account>(cap.account_address).key_rotation_capability);
aborts_if !exists<Account>(cap.account_address);
public fun destroy_key_rotation_capability(cap: Account::KeyRotationCapability)
public fun destroy_key_rotation_capability(cap: KeyRotationCapability) {
let KeyRotationCapability {account_address: _} = cap;
}
public entry fun rotate_authentication_key(account: signer, new_key: vector<u8>)
public entry fun rotate_authentication_key(account: signer, new_key: vector<u8>) acquires Account, EventStore {
rotate_authentication_key_entry(account, new_key);
}
pragma verify = false;
public entry fun rotate_authentication_key_entry(account: signer, new_key: vector<u8>)
public entry fun rotate_authentication_key_entry(account: signer, new_key: vector<u8>) acquires Account, EventStore {
do_rotate_authentication_key(&account, new_key);
}
public fun do_rotate_authentication_key(account: &signer, new_key: vector<u8>)
public fun do_rotate_authentication_key(account: &signer, new_key: vector<u8>) acquires Account, EventStore {
let key_rotation_capability = extract_key_rotation_capability(account);
rotate_authentication_key_with_capability(&key_rotation_capability, copy new_key);
restore_key_rotation_capability(key_rotation_capability);
make_event_store_if_not_exist(account);
let signer_addr = Signer::address_of(account);
let event_store = borrow_global_mut<EventStore>(signer_addr);
Event::emit_event<RotateAuthKeyEvent>(
&mut event_store.rotate_auth_key_events,
RotateAuthKeyEvent {
account_address: signer_addr,
new_auth_key: new_key,
}
);
}
balance
for account
fun balance_for<TokenType: store>(balance: &Account::Balance<TokenType>): u128
fun balance_for<TokenType: store>(balance: &Balance<TokenType>): u128 {
Token::value<TokenType>(&balance.token)
}
aborts_if false;
addr
.
public fun balance<TokenType: store>(addr: address): u128
public fun balance<TokenType: store>(addr: address): u128 acquires Balance {
if (exists<Balance<TokenType>>(addr)) {
balance_for(borrow_global<Balance<TokenType>>(addr))
} else {
0u128
}
}
Token
type to the sending account.
public fun do_accept_token<TokenType: store>(account: &signer)
public fun do_accept_token<TokenType: store>(account: &signer) acquires Account {
move_to(account, Balance<TokenType>{ token: Token::zero<TokenType>() });
let token_code = Token::token_code<TokenType>();
// Load the sender's account
let sender_account_ref = borrow_global_mut<Account>(Signer::address_of(account));
// Log a sent event
Event::emit_event<AcceptTokenEvent>(
&mut sender_account_ref.accept_token_events,
AcceptTokenEvent {
token_code: token_code,
},
);
}
aborts_if exists<Balance<TokenType>>(Signer::address_of(account));
aborts_if !exists<Account>(Signer::address_of(account));
public entry fun accept_token<TokenType: store>(account: signer)
public entry fun accept_token<TokenType: store>(account: signer) acquires Account {
accept_token_entry<TokenType>(account);
}
pragma verify = false;
public entry fun accept_token_entry<TokenType: store>(account: signer)
public entry fun accept_token_entry<TokenType: store>(account: signer) acquires Account {
do_accept_token<TokenType>(&account);
}
public fun is_accepts_token<TokenType: store>(addr: address): bool
public fun is_accepts_token<TokenType: store>(addr: address): bool acquires AutoAcceptToken {
Self::is_accept_token<TokenType>(addr)
}
aborts_if false;
aborts_if false;
addr
accept Token
type tokens
public fun is_accept_token<TokenType: store>(addr: address): bool
public fun is_accept_token<TokenType: store>(addr: address): bool acquires AutoAcceptToken {
if (can_auto_accept_token(addr)) {
true
} else {
exists<Balance<TokenType>>(addr)
}
}
aborts_if false;
public fun can_auto_accept_token(addr: address): bool
public fun can_auto_accept_token(addr: address): bool acquires AutoAcceptToken {
if (exists<AutoAcceptToken>(addr)) {
borrow_global<AutoAcceptToken>(addr).enable
} else {
false
}
}
public entry fun set_auto_accept_token_entry(account: signer, enable: bool)
public entry fun set_auto_accept_token_entry(account: signer, enable: bool) acquires AutoAcceptToken {
set_auto_accept_token(&account, enable);
}
public fun set_auto_accept_token(account: &signer, enable: bool)
public fun set_auto_accept_token(account: &signer, enable: bool) acquires AutoAcceptToken {
let addr = Signer::address_of(account);
if (exists<AutoAcceptToken>(addr)) {
let config = borrow_global_mut<AutoAcceptToken>(addr);
config.enable = enable;
} else {
move_to(account, AutoAcceptToken{enable});
};
}
aborts_if false;
addr
.
fun try_accept_token<TokenType: store>(addr: address)
fun try_accept_token<TokenType: store>(addr: address) acquires AutoAcceptToken, Account {
if (!exists<Balance<TokenType>>(addr)) {
if (can_auto_accept_token(addr)) {
let signer = create_signer(addr);
do_accept_token<TokenType>(&signer);
}else{
abort Errors::not_published(ERR_TOKEN_NOT_ACCEPT)
}
};
}
aborts_if false;
account
fun sequence_number_for_account(account: &Account::Account): u64
fun sequence_number_for_account(account: &Account): u64 {
account.sequence_number
}
addr
public fun sequence_number(addr: address): u64
public fun sequence_number(addr: address): u64 acquires Account {
sequence_number_for_account(borrow_global<Account>(addr))
}
aborts_if !exists<Account>(addr);
public fun authentication_key(addr: address): vector<u8>
public fun authentication_key(addr: address): vector<u8> acquires Account {
*&borrow_global<Account>(addr).authentication_key
}
aborts_if !exists<Account>(addr);
addr
has delegated its key rotation capability
public fun delegated_key_rotation_capability(addr: address): bool
public fun delegated_key_rotation_capability(addr: address): bool
acquires Account {
Option::is_none(&borrow_global<Account>(addr).key_rotation_capability)
}
aborts_if !exists<Account>(addr);
addr
has delegated its withdraw capability
public fun delegated_withdraw_capability(addr: address): bool
public fun delegated_withdraw_capability(addr: address): bool
acquires Account {
Option::is_none(&borrow_global<Account>(addr).withdrawal_capability)
}
aborts_if !exists<Account>(addr);
public fun withdraw_capability_address(cap: &Account::WithdrawCapability): &address
public fun withdraw_capability_address(cap: &WithdrawCapability): &address {
&cap.account_address
}
aborts_if false;
public fun key_rotation_capability_address(cap: &Account::KeyRotationCapability): &address
public fun key_rotation_capability_address(cap: &KeyRotationCapability): &address {
&cap.account_address
}
aborts_if false;
check_addr
public fun exists_at(check_addr: address): bool
aborts_if false;
fun is_dummy_auth_key(account: &Account::Account): bool
fun is_dummy_auth_key(account: &Account): bool {
*&account.authentication_key == DUMMY_AUTH_KEY
}
public fun is_dummy_auth_key_v2(account: address): bool
public fun is_dummy_auth_key_v2(account: address): bool acquires Account {
let account = borrow_global_mut<Account>(account);
account.authentication_key == DUMMY_AUTH_KEY
}
public fun txn_prologue<TokenType: store>(account: &signer, txn_sender: address, txn_sequence_number: u64, txn_authentication_key_preimage: vector<u8>, txn_gas_price: u64, txn_max_gas_units: u64)
public fun txn_prologue<TokenType: store>(
account: &signer,
txn_sender: address,
txn_sequence_number: u64,
txn_authentication_key_preimage: vector<u8>,
txn_gas_price: u64,
txn_max_gas_units: u64,
) acquires Account, Balance {
txn_prologue_v2<TokenType>(
account,
txn_sender,
txn_sequence_number,
txn_authentication_key_preimage,
txn_gas_price,
txn_max_gas_units,
1,
1,
)
}
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
aborts_if !exists<Account>(txn_sender);
aborts_if global<Account>(txn_sender).authentication_key == DUMMY_AUTH_KEY && Authenticator::spec_derived_address(Hash::sha3_256(txn_authentication_key_preimage)) != txn_sender;
aborts_if global<Account>(txn_sender).authentication_key != DUMMY_AUTH_KEY && Hash::sha3_256(txn_authentication_key_preimage) != global<Account>(txn_sender).authentication_key;
aborts_if txn_sequence_number < global<Account>(txn_sender).sequence_number;
public fun txn_prologue_v2<TokenType: store>(account: &signer, txn_sender: address, txn_sequence_number: u64, txn_authentication_key_preimage: vector<u8>, txn_gas_price: u64, txn_max_gas_units: u64, stc_price: u128, stc_price_scaling: u128)
public fun txn_prologue_v2<TokenType: store>(
account: &signer,
txn_sender: address,
txn_sequence_number: u64,
txn_authentication_key_preimage: vector<u8>,
txn_gas_price: u64,
txn_max_gas_units: u64,
stc_price: u128,
stc_price_scaling: u128
) acquires Account, Balance {
CoreAddresses::assert_genesis_address(account);
// Verify that the transaction sender's account exists
assert!(exists_at(txn_sender), Errors::requires_address(EPROLOGUE_ACCOUNT_DOES_NOT_EXIST));
// Verify the account has not delegate its signer cap.
assert!(!is_signer_delegated(txn_sender), Errors::invalid_state(EPROLOGUE_SIGNER_ALREADY_DELEGATED));
// Load the transaction sender's account
let sender_account = borrow_global_mut<Account>(txn_sender);
if (is_dummy_auth_key(sender_account)){
// if sender's auth key is empty, use address as auth key for check transaction.
assert!(
Authenticator::derived_address(Hash::sha3_256(txn_authentication_key_preimage)) == txn_sender,
Errors::invalid_argument(EPROLOGUE_INVALID_ACCOUNT_AUTH_KEY)
);
}else{
// Check that the hash of the transaction's public key matches the account's auth key
assert!(
Hash::sha3_256(txn_authentication_key_preimage) == *&sender_account.authentication_key,
Errors::invalid_argument(EPROLOGUE_INVALID_ACCOUNT_AUTH_KEY)
);
};
// Check that the account has enough balance for all of the gas
let (max_transaction_fee_stc,max_transaction_fee_token) = transaction_fee_simulate(txn_gas_price,txn_max_gas_units,0, stc_price, stc_price_scaling);
assert!(
max_transaction_fee_stc <= MAX_U64,
Errors::invalid_argument(EPROLOGUE_CANT_PAY_GAS_DEPOSIT),
);
if (max_transaction_fee_stc > 0) {
assert!(
(txn_sequence_number as u128) < MAX_U64,
Errors::limit_exceeded(EPROLOGUE_SEQUENCE_NUMBER_TOO_BIG)
);
let balance_amount_token = balance<TokenType>(txn_sender);
assert!(balance_amount_token >= max_transaction_fee_token, Errors::invalid_argument(EPROLOGUE_CANT_PAY_GAS_DEPOSIT));
if (!is_stc<TokenType>()){
let balance_amount_stc= balance<STC>(CoreAddresses::GENESIS_ADDRESS());
assert!(balance_amount_stc >= max_transaction_fee_stc, Errors::invalid_argument(EPROLOGUE_CANT_PAY_GAS_DEPOSIT));
}
};
// Check that the transaction sequence number matches the sequence number of the account
assert!(txn_sequence_number >= sender_account.sequence_number, Errors::invalid_argument(EPROLOGUE_SEQUENCE_NUMBER_TOO_OLD));
assert!(txn_sequence_number == sender_account.sequence_number, Errors::invalid_argument(EPROLOGUE_SEQUENCE_NUMBER_TOO_NEW));
}
public fun txn_epilogue<TokenType: store>(account: &signer, txn_sender: address, txn_sequence_number: u64, txn_gas_price: u64, txn_max_gas_units: u64, gas_units_remaining: u64)
public fun txn_epilogue<TokenType: store>(
account: &signer,
txn_sender: address,
txn_sequence_number: u64,
txn_gas_price: u64,
txn_max_gas_units: u64,
gas_units_remaining: u64,
) acquires Account, Balance {
txn_epilogue_v3<TokenType>(account, txn_sender, txn_sequence_number, Vector::empty(), txn_gas_price, txn_max_gas_units, gas_units_remaining,1,1)
}
pragma verify = false;
public fun transaction_fee_simulate(txn_gas_price: u64, txn_max_gas_units: u64, gas_units_remaining: u64, stc_price: u128, stc_price_scaling: u128): (u128, u128)
public fun transaction_fee_simulate(
txn_gas_price:u64,
txn_max_gas_units: u64,
gas_units_remaining:u64,
stc_price: u128,
stc_price_scaling: u128,
): (u128, u128){
let transaction_fee_stc =(txn_gas_price * (txn_max_gas_units - gas_units_remaining) as u128);
let transaction_fee_token= Math::mul_div((transaction_fee_stc as u128), stc_price, stc_price_scaling);
transaction_fee_token = if (transaction_fee_token == 0 && transaction_fee_stc > 0 ) { 1 } else { transaction_fee_token};
(transaction_fee_stc, transaction_fee_token)
}
public fun txn_epilogue_v2<TokenType: store>(account: &signer, txn_sender: address, txn_sequence_number: u64, txn_authentication_key_preimage: vector<u8>, txn_gas_price: u64, txn_max_gas_units: u64, gas_units_remaining: u64)
public fun txn_epilogue_v2<TokenType: store>(
account: &signer,
txn_sender: address,
txn_sequence_number: u64,
txn_authentication_key_preimage: vector<u8>,
txn_gas_price: u64,
txn_max_gas_units: u64,
gas_units_remaining: u64,
) acquires Account, Balance {
txn_epilogue_v3<TokenType>(
account,
txn_sender,
txn_sequence_number,
txn_authentication_key_preimage,
txn_gas_price,
txn_max_gas_units,
gas_units_remaining,1,1)
}
pragma verify = false;
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
aborts_if !exists<Account>(txn_sender);
aborts_if !exists<Balance<TokenType>>(txn_sender);
aborts_if txn_max_gas_units < gas_units_remaining;
let transaction_fee_amount = txn_gas_price * (txn_max_gas_units - gas_units_remaining);
aborts_if transaction_fee_amount > max_u128();
aborts_if global<Balance<TokenType>>(txn_sender).token.value < transaction_fee_amount;
aborts_if txn_sequence_number + 1 > max_u64();
aborts_if txn_gas_price * (txn_max_gas_units - gas_units_remaining) > 0 &&
global<Balance<TokenType>>(txn_sender).token.value < txn_gas_price * (txn_max_gas_units - gas_units_remaining);
aborts_if txn_gas_price * (txn_max_gas_units - gas_units_remaining) > 0 &&
!exists<TransactionFee::TransactionFee<TokenType>>(CoreAddresses::GENESIS_ADDRESS());
aborts_if txn_gas_price * (txn_max_gas_units - gas_units_remaining) > 0 &&
global<TransactionFee::TransactionFee<TokenType>>(CoreAddresses::GENESIS_ADDRESS()).fee.value + txn_gas_price * (txn_max_gas_units - gas_units_remaining) > max_u128();
pragma verify = false;
aborts_if Signer::address_of(account) != CoreAddresses::GENESIS_ADDRESS();
aborts_if !exists<Account>(txn_sender);
aborts_if !exists<Balance<TokenType>>(txn_sender);
aborts_if txn_sequence_number + 1 > max_u64();
aborts_if !exists<Balance<TokenType>>(txn_sender);
aborts_if txn_max_gas_units < gas_units_remaining;
public fun txn_epilogue_v3<TokenType: store>(account: &signer, txn_sender: address, txn_sequence_number: u64, txn_authentication_key_preimage: vector<u8>, txn_gas_price: u64, txn_max_gas_units: u64, gas_units_remaining: u64, stc_price: u128, stc_price_scaling: u128)
public fun txn_epilogue_v3<TokenType: store>(
account: &signer,
txn_sender: address,
txn_sequence_number: u64,
txn_authentication_key_preimage: vector<u8>,
txn_gas_price: u64,
txn_max_gas_units: u64,
gas_units_remaining: u64,
stc_price: u128,
stc_price_scaling: u128,
) acquires Account, Balance {
CoreAddresses::assert_genesis_address(account);
// Charge for gas
let (transaction_fee_amount_stc,transaction_fee_amount_token) = transaction_fee_simulate(
txn_gas_price,
txn_max_gas_units,
gas_units_remaining,
stc_price,
stc_price_scaling);
assert!(
balance<TokenType>(txn_sender) >= transaction_fee_amount_token,
Errors::limit_exceeded(EINSUFFICIENT_BALANCE)
);
if (!is_stc<TokenType>()){
let genesis_balance_amount_stc=balance<STC>(CoreAddresses::GENESIS_ADDRESS());
assert!(genesis_balance_amount_stc >= transaction_fee_amount_stc,
Errors::invalid_argument(EPROLOGUE_CANT_PAY_GAS_DEPOSIT)
);
};
// Load the transaction sender's account and balance resources
let sender_account = borrow_global_mut<Account>(txn_sender);
// Bump the sequence number
sender_account.sequence_number = txn_sequence_number + 1;
// Set auth key when user send transaction first.
if (is_dummy_auth_key(sender_account) && !Vector::is_empty(&txn_authentication_key_preimage)){
sender_account.authentication_key = Hash::sha3_256(txn_authentication_key_preimage);
};
if (transaction_fee_amount_stc > 0) {
let transaction_fee_token = withdraw_from_balance(
borrow_global_mut<Balance<TokenType>>(txn_sender),
transaction_fee_amount_token
);
deposit_to_balance(borrow_global_mut<Balance<TokenType>>(CoreAddresses::GENESIS_ADDRESS()), transaction_fee_token);
let stc_fee_token = withdraw_from_balance(borrow_global_mut<Balance<STC>>(CoreAddresses::GENESIS_ADDRESS()), transaction_fee_amount_stc);
TransactionFee::pay_fee(stc_fee_token);
};
}
public entry fun remove_zero_balance_entry<TokenType: store>(account: signer)
public entry fun remove_zero_balance_entry<TokenType: store>(account: signer) acquires Balance {
remove_zero_balance<TokenType>(&account);
}
public fun remove_zero_balance<TokenType: store>(account: &signer)
public fun remove_zero_balance<TokenType: store>(account: &signer) acquires Balance {
let addr: address = Signer::address_of(account);
let Balance<TokenType> { token } = move_from<Balance<TokenType>>(addr);
Token::destroy_zero<TokenType>(token);
}
let addr = Signer::address_of(account);
aborts_if !exists<Balance<TokenType>>(addr);
ensures !exists<Balance<TokenType>>(addr);
fun make_event_store_if_not_exist(account: &signer)
fun make_event_store_if_not_exist(account: &signer) {
if (!exists<EventStore>(Signer::address_of(account))) {
move_to(account, EventStore {
rotate_auth_key_events: Event::new_event_handle<RotateAuthKeyEvent>(account),
extract_withdraw_cap_events: Event::new_event_handle<ExtractWithdrawCapEvent>(account),
signer_delegate_events: Event::new_event_handle<SignerDelegateEvent>(account),
})
};
}
pragma verify = false;
pragma aborts_if_is_strict = true;