Skip to content
Draft
13 changes: 5 additions & 8 deletions aptos-move/framework/aptos-framework/doc/aptos_coin.md
Original file line number Diff line number Diff line change
Expand Up @@ -406,11 +406,8 @@ Create delegated token for the address so the account could claim MintCapability


<pre><code><b>public</b> entry <b>fun</b> <a href="aptos_coin.md#0x1_aptos_coin_delegate_mint_capability">delegate_mint_capability</a>(<a href="account.md#0x1_account">account</a>: <a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer">signer</a>, <b>to</b>: <b>address</b>) <b>acquires</b> <a href="aptos_coin.md#0x1_aptos_coin_Delegations">Delegations</a> {
<a href="system_addresses.md#0x1_system_addresses_assert_aptos_framework">system_addresses::assert_aptos_framework</a>(&<a href="account.md#0x1_account">account</a>);
<b>let</b> delegations = &<b>mut</b> <b>borrow_global_mut</b>&lt;<a href="aptos_coin.md#0x1_aptos_coin_Delegations">Delegations</a>&gt;(@aptos_framework).inner;
<b>if</b> (!<b>exists</b>&lt;<a href="aptos_coin.md#0x1_aptos_coin_Delegations">Delegations</a>&gt;(<a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer_address_of">signer::address_of</a>(&<a href="account.md#0x1_account">account</a>))) {
<b>move_to</b>(&<a href="account.md#0x1_account">account</a>, <a href="aptos_coin.md#0x1_aptos_coin_Delegations">Delegations</a> { inner: <a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector">vector</a>[] });
};
<a href="system_addresses.md#0x1_system_addresses_assert_core_resource">system_addresses::assert_core_resource</a>(&<a href="account.md#0x1_account">account</a>);
<b>let</b> delegations = &<b>mut</b> <b>borrow_global_mut</b>&lt;<a href="aptos_coin.md#0x1_aptos_coin_Delegations">Delegations</a>&gt;(@core_resources).inner;
<a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector_for_each_ref">vector::for_each_ref</a>(delegations, |element| {
<b>let</b> element: &<a href="aptos_coin.md#0x1_aptos_coin_DelegatedMintCapability">DelegatedMintCapability</a> = element;
<b>assert</b>!(element.<b>to</b> != <b>to</b>, <a href="../../aptos-stdlib/../move-stdlib/doc/error.md#0x1_error_invalid_argument">error::invalid_argument</a>(<a href="aptos_coin.md#0x1_aptos_coin_EALREADY_DELEGATED">EALREADY_DELEGATED</a>));
Expand Down Expand Up @@ -444,11 +441,11 @@ Claim the delegated mint capability and destroy the delegated token.
<b>let</b> maybe_index = <a href="aptos_coin.md#0x1_aptos_coin_find_delegation">find_delegation</a>(<a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer_address_of">signer::address_of</a>(<a href="account.md#0x1_account">account</a>));
<b>assert</b>!(<a href="../../aptos-stdlib/../move-stdlib/doc/option.md#0x1_option_is_some">option::is_some</a>(&maybe_index), <a href="aptos_coin.md#0x1_aptos_coin_EDELEGATION_NOT_FOUND">EDELEGATION_NOT_FOUND</a>);
<b>let</b> idx = *<a href="../../aptos-stdlib/../move-stdlib/doc/option.md#0x1_option_borrow">option::borrow</a>(&maybe_index);
<b>let</b> delegations = &<b>mut</b> <b>borrow_global_mut</b>&lt;<a href="aptos_coin.md#0x1_aptos_coin_Delegations">Delegations</a>&gt;(@aptos_framework).inner;
<b>let</b> delegations = &<b>mut</b> <b>borrow_global_mut</b>&lt;<a href="aptos_coin.md#0x1_aptos_coin_Delegations">Delegations</a>&gt;(@core_resources).inner;
<b>let</b> <a href="aptos_coin.md#0x1_aptos_coin_DelegatedMintCapability">DelegatedMintCapability</a> { <b>to</b>: _ } = <a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector_swap_remove">vector::swap_remove</a>(delegations, idx);

// Make a <b>copy</b> of mint cap and give it <b>to</b> the specified <a href="account.md#0x1_account">account</a>.
<b>let</b> mint_cap = <b>borrow_global</b>&lt;<a href="aptos_coin.md#0x1_aptos_coin_MintCapStore">MintCapStore</a>&gt;(@aptos_framework).mint_cap;
<b>let</b> mint_cap = <b>borrow_global</b>&lt;<a href="aptos_coin.md#0x1_aptos_coin_MintCapStore">MintCapStore</a>&gt;(@core_resources).mint_cap;
<b>move_to</b>(<a href="account.md#0x1_account">account</a>, <a href="aptos_coin.md#0x1_aptos_coin_MintCapStore">MintCapStore</a> { mint_cap });
}
</code></pre>
Expand All @@ -473,7 +470,7 @@ Claim the delegated mint capability and destroy the delegated token.


<pre><code><b>fun</b> <a href="aptos_coin.md#0x1_aptos_coin_find_delegation">find_delegation</a>(addr: <b>address</b>): Option&lt;u64&gt; <b>acquires</b> <a href="aptos_coin.md#0x1_aptos_coin_Delegations">Delegations</a> {
<b>let</b> delegations = &<b>borrow_global</b>&lt;<a href="aptos_coin.md#0x1_aptos_coin_Delegations">Delegations</a>&gt;(@aptos_framework).inner;
<b>let</b> delegations = &<b>borrow_global</b>&lt;<a href="aptos_coin.md#0x1_aptos_coin_Delegations">Delegations</a>&gt;(@core_resources).inner;
<b>let</b> i = 0;
<b>let</b> len = <a href="../../aptos-stdlib/../move-stdlib/doc/vector.md#0x1_vector_length">vector::length</a>(delegations);
<b>let</b> index = <a href="../../aptos-stdlib/../move-stdlib/doc/option.md#0x1_option_none">option::none</a>();
Expand Down
16 changes: 16 additions & 0 deletions aptos-move/framework/aptos-framework/doc/staking_contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -1319,6 +1319,16 @@ Store amount must be at least the min stake required for a stake pool to join th



<a id="0x1_staking_contract_EINVALID_BENEFICIARY_ADDRESS"></a>

Beneficiary cannot be a reserved address that cannot receive coin distributions.


<pre><code><b>const</b> <a href="staking_contract.md#0x1_staking_contract_EINVALID_BENEFICIARY_ADDRESS">EINVALID_BENEFICIARY_ADDRESS</a>: u64 = 10;
</code></pre>



<a id="0x1_staking_contract_ENOT_STAKER_OR_OPERATOR_OR_BENEFICIARY"></a>

Caller must be either the staker, operator, or beneficiary.
Expand Down Expand Up @@ -2283,6 +2293,12 @@ the beneficiary. An operator can set one beneficiary for staking contract pools,
<b>assert</b>!(<a href="../../aptos-stdlib/../move-stdlib/doc/features.md#0x1_features_operator_beneficiary_change_enabled">features::operator_beneficiary_change_enabled</a>(), std::error::invalid_state(
<a href="staking_contract.md#0x1_staking_contract_EOPERATOR_BENEFICIARY_CHANGE_NOT_SUPPORTED">EOPERATOR_BENEFICIARY_CHANGE_NOT_SUPPORTED</a>
));
// @vm_reserved can never have an <a href="account.md#0x1_account">account</a> created for it, so it can't receive <a href="coin.md#0x1_coin">coin</a> distributions.
// Allowing it <b>as</b> a beneficiary would permanently brick distribution for the staking contract.
<b>assert</b>!(
new_beneficiary != @vm_reserved,
<a href="../../aptos-stdlib/../move-stdlib/doc/error.md#0x1_error_invalid_argument">error::invalid_argument</a>(<a href="staking_contract.md#0x1_staking_contract_EINVALID_BENEFICIARY_ADDRESS">EINVALID_BENEFICIARY_ADDRESS</a>),
);
// The beneficiay <b>address</b> of an operator is stored under the operator's <b>address</b>.
// So, the operator does not need <b>to</b> be validated <b>with</b> respect <b>to</b> a staking pool.
<b>let</b> operator_addr = <a href="../../aptos-stdlib/../move-stdlib/doc/signer.md#0x1_signer_address_of">signer::address_of</a>(operator);
Expand Down
47 changes: 5 additions & 42 deletions aptos-move/framework/aptos-framework/sources/aptos_coin.move
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,8 @@ module aptos_framework::aptos_coin {
/// Only callable in tests and testnets where the core resources account exists.
/// Create delegated token for the address so the account could claim MintCapability later.
public entry fun delegate_mint_capability(account: signer, to: address) acquires Delegations {
system_addresses::assert_aptos_framework(&account);
let delegations = &mut borrow_global_mut<Delegations>(@aptos_framework).inner;
if (!exists<Delegations>(signer::address_of(&account))) {
move_to(&account, Delegations { inner: vector[] });
};
system_addresses::assert_core_resource(&account);
let delegations = &mut borrow_global_mut<Delegations>(@core_resources).inner;
vector::for_each_ref(delegations, |element| {
let element: &DelegatedMintCapability = element;
assert!(element.to != to, error::invalid_argument(EALREADY_DELEGATED));
Expand All @@ -136,16 +133,16 @@ module aptos_framework::aptos_coin {
let maybe_index = find_delegation(signer::address_of(account));
assert!(option::is_some(&maybe_index), EDELEGATION_NOT_FOUND);
let idx = *option::borrow(&maybe_index);
let delegations = &mut borrow_global_mut<Delegations>(@aptos_framework).inner;
let delegations = &mut borrow_global_mut<Delegations>(@core_resources).inner;
let DelegatedMintCapability { to: _ } = vector::swap_remove(delegations, idx);

// Make a copy of mint cap and give it to the specified account.
let mint_cap = borrow_global<MintCapStore>(@aptos_framework).mint_cap;
let mint_cap = borrow_global<MintCapStore>(@core_resources).mint_cap;
move_to(account, MintCapStore { mint_cap });
}

fun find_delegation(addr: address): Option<u64> acquires Delegations {
let delegations = &borrow_global<Delegations>(@aptos_framework).inner;
let delegations = &borrow_global<Delegations>(@core_resources).inner;
let i = 0;
let len = vector::length(delegations);
let index = option::none();
Expand Down Expand Up @@ -196,7 +193,6 @@ module aptos_framework::aptos_coin {
#[test_only]
public fun initialize_for_test(aptos_framework: &signer): (BurnCapability<AptosCoin>, MintCapability<AptosCoin>) {
aggregator_factory::initialize_aggregator_factory_for_test(aptos_framework);
init_delegations(aptos_framework);
let (burn_cap, mint_cap) = initialize(aptos_framework);
coin::create_coin_conversion_map(aptos_framework);
coin::create_pairing<AptosCoin>(aptos_framework);
Expand All @@ -214,37 +210,4 @@ module aptos_framework::aptos_coin {
(burn_cap, mint_cap)
}

#[test_only]
/// Initializes the Delegations resource under `@aptos_framework`.
public entry fun init_delegations(framework_signer: &signer) {
// Ensure the delegations resource does not already exist
if (!exists<Delegations>(@aptos_framework)) {
move_to(framework_signer, Delegations { inner: vector[] });
}
}

#[test(aptos_framework = @aptos_framework, destination = @0x2)]
public entry fun test_destroy_mint_cap(
aptos_framework: &signer,
destination: &signer,
) acquires Delegations, MintCapStore {
// initialize the `aptos_coin`
let (burn_cap, mint_cap) = initialize_for_test(aptos_framework);

// get a copy of the framework signer for test
let aptos_framework_delegate = account::create_signer_for_test(signer::address_of(aptos_framework));

// delegate and claim the mint capability
delegate_mint_capability(aptos_framework_delegate, signer::address_of(destination));
claim_mint_capability(destination);

// destroy the mint Capability
destroy_mint_capability_from(aptos_framework, signer::address_of(destination));

// check if the mint capability is destroyed
assert!(!exists<MintCapStore>(signer::address_of(destination)), 2);

coin::destroy_burn_cap(burn_cap);
coin::destroy_mint_cap(mint_cap);
}
}
1 change: 1 addition & 0 deletions aptos-move/framework/move-stdlib/doc/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -848,6 +848,7 @@ Lifetime: transient

Whether the Atomic bridge is available
Lifetime: transient
Deprecated in favor of <code><a href="features.md#0x1_features_ALLOW_SERIALIZED_SCRIPT_ARGS">ALLOW_SERIALIZED_SCRIPT_ARGS</a></code> as feature flag 72


<pre><code><b>const</b> <a href="features.md#0x1_features_NATIVE_BRIDGE">NATIVE_BRIDGE</a>: u64 = 72;
Expand Down
20 changes: 19 additions & 1 deletion devtools/aptos-cargo-cli/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,22 @@ impl SelectedPackageArgs {
// Identify the merge base
let merge_base = self.identify_merge_base()?;

// If the branch is already up to date with the base branch (i.e. the merge base is the
// current base branch tip), it is not stale regardless of the base branch's commit
// cadence, so skip the age check below. This matters for slow-moving base branches like
// m1: the age check assumes the base branch gets frequent commits (true for upstream
// main), and would otherwise fail every PR whenever the base tip happens to be older
// than MAX_NUM_DAYS_SINCE_MERGE_BASE.
let base_ref = env::var("GITHUB_BASE_REF").unwrap_or_else(|_| "m1".to_string());
let base_tip = self.git_rev_parse(&format!("origin/{base_ref}"));
if !base_tip.is_empty() && merge_base == base_tip {
info!(
"The branch is up to date with the base branch (origin/{}); skipping the merge-base age check.",
base_ref
);
return Ok(());
}

// Get the commit timestamp of the merge-base
let commit_timestamp_output = Command::new("git")
.arg("show")
Expand Down Expand Up @@ -226,7 +242,9 @@ impl SelectedPackageArgs {
///
/// Note: if the merge-base is too old, an error will be returned.
fn identify_merge_base(&self) -> anyhow::Result<String> {
let base_ref = env::var("GITHUB_BASE_REF").unwrap_or_else(|_| "main".to_string());
// On pull_request events GITHUB_BASE_REF is the target branch. On push events it is
// unset, so fall back to this fork's default branch (m1), not upstream's "main".
let base_ref = env::var("GITHUB_BASE_REF").unwrap_or_else(|_| "m1".to_string());
let origin_base_ref = format!("origin/{base_ref}");

// Run the git merge-base command
Expand Down
8 changes: 8 additions & 0 deletions testsuite/smoke-test/src/account_abstraction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ fn bytes_to_base58(bytes: &[u8]) -> String {
String::from_utf8(result).unwrap()
}

// Ignored: account abstraction is not supported on Movement. Genesis AA initialization is
// intentionally gated off (see #238), so the derivable authenticators are never registered and
// this test cannot pass. Re-enable if/when AA is supported.
#[ignore]
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn test_solana_derivable_account() {
let swarm = SwarmBuilder::new_local(1).with_aptos().build().await;
Expand Down Expand Up @@ -152,6 +156,10 @@ async fn test_solana_derivable_account() {
.unwrap_or_else(|_| panic!("aa: {:?}", create_txn));
}

// Ignored: account abstraction is not supported on Movement. Genesis AA initialization is
// intentionally gated off (see #238), so the derivable authenticators are never registered and
// this test cannot pass. Re-enable if/when AA is supported.
#[ignore]
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn test_ethereum_derivable_account() {
let swarm = SwarmBuilder::new_local(1).with_aptos().build().await;
Expand Down
Loading