Skip to content

feat(standards): add AuthMultisigSmart #2973

Draft
onurinanc wants to merge 61 commits into
nextfrom
onur-auth-multisig-smart
Draft

feat(standards): add AuthMultisigSmart #2973
onurinanc wants to merge 61 commits into
nextfrom
onur-auth-multisig-smart

Conversation

@onurinanc
Copy link
Copy Markdown
Collaborator

@onurinanc onurinanc commented May 22, 2026

This is a draft version of AuthMultisigSmart which is not ready to merge yet. The aim of this draft is to get some insights for the PR before make it ready to merge.

This is a big PR and still lacks of some improvements such as:

  • Guardian integration
  • Some procedures are lack of best practices (nits)
  • More clarity on comments
  • Integration of Smart Config

That's being said, it's a draft PR.

Here are some the design discussion that shaped AuthMultisigSmart that needs be investigated before diving into it.

Copy link
Copy Markdown
Contributor

@PhilippGackstatter PhilippGackstatter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the PR @onurinanc.

The PR is very large which makes it quite difficult to wrap my head around. Roughly 3000 lines is tests, but could we still split up the feature logic into multiple PRs? For example, it seems the timelock controller and spending limits do not depend on each other, so could these be moved to a separate PR? I'm open to other ideas of course, but somehow reducing the line count would be awesome, as I think this PR as-is will be tricky to iterate on.

/// This bundles the tracked spending window, the amount breakpoints used to derive a spending
/// tier, and the approval threshold required for each tier.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct SpendingPolicyConfig {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think SpendingPolicyConfig isn't clearer than just SpendingPolicy, so I'd suggest renaming it to the latter.

/// `propose_expiration_delta` controls the transaction expiration delta applied to proposal
/// transactions.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct TimelockControllerConfig {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To align with SpendingPolicy, could this be TimelockPolicy? I'm not sure I understand which part is a "controller".

Comment on lines +85 to +94
/// Identifies the oracle instance used by smart multisig price lookups.
///
/// This value is stored as a `(prefix, suffix)` pair so the configured foreign price-reader
/// procedure can distinguish which oracle feed should be queried during spending-policy
/// evaluation.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OracleId {
prefix: Felt,
suffix: Felt,
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Judging from the usage, this is the ID of an account, right? If so, I think we should definitely wrap AccountId here, otherwise any two felts are considered valid at the Rust level, but will fail at the contract level.

Comment on lines +70 to +74
struct TestOracleFixture {
account: Account,
oracle_id: [Felt; 2],
get_price_proc_root: Word,
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If oracle_id is always set to account.id(), I think we don't need to include it here, right? Or if we do, I'd include it as OracleId for type safety.

Comment on lines +307 to +317
create_multisig_smart_account_with_assets_and_oracle(
threshold,
public_keys,
auth_scheme,
multisig_starting_assets
.into_iter()
.map(|(account_id, amount)| FungibleAsset::new(account_id, amount).unwrap())
.collect(),
[500, 1000, 2000, 1500],
[1, 2, 3, 4],
proc_policy_map,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I think this would be easier to read if it was AmountLimits::new(500, 1000, 2000, 1500), same for TierThresholds.

Comment on lines +829 to 836
loc_load.3 u32max
# => [policy_or_spending_threshold, num_verified_signatures, TX_SUMMARY_COMMITMENT]

# compute_tx_threshold expects default_threshold on top, policy_threshold underneath.
loc_load.1
# => [default_threshold, policy_threshold, num_verified_signatures, TX_SUMMARY_COMMITMENT]
# => [default_threshold, policy_or_spending_threshold, num_verified_signatures, TX_SUMMARY_COMMITMENT]

exec.compute_tx_threshold
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: We're computing part of the threshold inline here and part of it in compute_tx_threshold. To make this easier to follow, I'd also move the u32max logic into compute_tx_threshold.

Comment on lines +16 to +20
pub use timelock_controller::update_timelock_controller
pub use timelock_controller::propose_transaction
pub use timelock_controller::cancel_transaction_proposal
pub use timelock_controller::cancel_and_propose_new_transaction
pub use timelock_controller::execute_proposed_transaction
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Afaict, transaction proposal and execution lives in timelock_controller because this relates to the idea of "delayed" execution, right? This connection doesn't click for me that much, so I wonder if we should rename this module. Maybe miden::standards::auth::multisig_smart::delayed_execution?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants