Skip to content

Conversation

@theiari
Copy link
Contributor

@theiari theiari commented Oct 21, 2025

Description of change

Implement "Account with Spending limit" example for abstract accounts.

Links to any relevant issues

fixes #8651

How the change has been tested

  • Basic tests (linting, compilation, formatting, unit/integration tests)
  • Patch-specific tests (correctness, functionality coverage)
  • I have added tests that prove my fix is effective or that my feature works
  • I have checked that new and existing unit tests pass locally with my changes

@vercel
Copy link

vercel bot commented Oct 21, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

6 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
apps-backend Ignored Ignored Preview Oct 22, 2025 2:12pm
apps-ui-kit Ignored Ignored Preview Oct 22, 2025 2:12pm
iota-evm-bridge Ignored Ignored Preview Oct 22, 2025 2:12pm
iota-multisig-toolkit Ignored Ignored Preview Oct 22, 2025 2:12pm
rebased-explorer Ignored Ignored Preview Oct 22, 2025 2:12pm
wallet-dashboard Ignored Ignored Preview Oct 22, 2025 2:12pm

@theiari theiari self-assigned this Oct 21, 2025
@theiari theiari added sc-platform Issues related to the Smart Contract Platform group. vm-language Issues related to the VM & Language Team labels Oct 21, 2025
@theiari theiari linked an issue Oct 21, 2025 that may be closed by this pull request
Copy link
Contributor

@TheMrAI TheMrAI left a comment

Choose a reason for hiding this comment

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

Haven't checked the tests yet, just skimmed the rest.

dynamic_field::add(account_id, SpendLimit {}, amount)
}

// === View Functions ===
Copy link
Contributor

Choose a reason for hiding this comment

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

Now I am not entirely sure which direction we are going in, but if we want this to be in the utilities and accounts
direction, then don't forget to supply detach and rotate functions as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same as above, added both detach and rotate in 7ae3716.

dynamic_field::borrow(account_id, SpendLimit {})
}

public fun borrow_mut(account_id: &mut UID): &mut u64 {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this is a public function not a view one, but I get confused on this from time to time.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved to public function section here: 7ae3716.


// === Structs ===

public struct SpendLimit has copy, drop, store {}
Copy link
Contributor

Choose a reason for hiding this comment

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

The pattern I tried to follow was to name the dynamic field and the containing module the same way.
spending_limit, SpendLimit, seems to be in minor inconsistency. Maybe it should be "SpendingLimit"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Makes sense. I changed it to SpendingLimit in 7ae3716.


public fun authenticate(
account: &SpendLimit,
amount: u64,
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you help me understand how this account type needs to work?
It looks somewhat odd that this amount is passed in as a value. The account can't really provide any protection in this regard right?
I have some vague memory that this is why we have the AuthContext, TxCommands fields, and vaguely remember you raising that there are some technical issues in calculating the gas I believe.

Copy link
Contributor

Choose a reason for hiding this comment

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

Good point from Davo. It’s not clear for me how it can be used for real authentication if we trust only the passed value? I assume we need some logic behind the arguments, like Davo mentioned, using Context etc., to work with a gas.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, that's a good point. I guess a solution might be to rely on vector<Coin<T>> type instead of u64.
I added a possible implementation here : 7ae3716 .

Not sure if that's enough, maybe there must be some extra logic behind AuthContext

@theiari theiari marked this pull request as ready for review October 21, 2025 11:46
@theiari theiari requested a review from a team as a code owner October 21, 2025 11:46
account::borrow_auth_info_v1(&account.id)
}

// === Admin Functions ===
Copy link
Contributor

Choose a reason for hiding this comment

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

I guess all of these empty comment sections should be cleaned up?
In account.move as well

Copy link
Contributor

Choose a reason for hiding this comment

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

Not necessarily. I started using that pattern to avoid issues in the future where we violate the code conventions.
Others follow different patterns, but this is probably the cleanest as the section names should always be the same and always in the same order.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just followed the latest flow 😄

assert!(amount <= *spending_limit, EOverspend);
}

public fun attach(account_id: &mut UID, amount: u64) {
Copy link
Contributor

@Dkwcs Dkwcs Oct 21, 2025

Choose a reason for hiding this comment

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

In this case it’s a minor thing, but for the full-fledged example it would be nice to have an appropriate functions to change the limit(e.g. Update())

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, you're right. Added both detach and rotate functions here: 7ae3716.

}

// Calculate the sum of coin values.
public fun calculate_coin_sum<T>(coins: &vector<Coin<T>>): u64 {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not entirely sure this is ok and if it should be kept public as well


public fun authenticate<T>(
account: &SpendLimit,
coins: &vector<Coin<T>>,
Copy link
Member

Choose a reason for hiding this comment

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

I don't get how this authenticate function prevents me from spending from the account. Some coins are passed here as auth inputs, but who to say that there are no more coins as PTB inputs that the authenticated transactions can spend?

On another note, spending limit without a time frame is rather useless, no? If I can spend $100 at a time, but I can repeat it as many times as I can then it's pretty easy to overspend :trollface:

If the intention is to have an account where you can only spend $X/period, it's pretty tought to implement without write access in the auth function.

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

Labels

sc-platform Issues related to the Smart Contract Platform group. vm-language Issues related to the VM & Language Team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement "Account With Spending Limit" using account abstraction

4 participants