# Community Plugin Account

**URL:** <https://community.starknet.io/t/community-plugin-account/2126>\
**Category:** Starknet Technical Development\
**Tags:** accounts\
**Created:** [October 11, 2022, 6:43pm UTC](https://community.starknet.io/t/community-plugin-account/2126 "2022-10-11T18:43:06Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![juniset](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/juniset/32/40_2.png) [@juniset](https://community.starknet.io/u/juniset)\
**Post date:** [October 11, 2022, 6:43pm UTC](https://community.starknet.io/t/community-plugin-account/2126/1 "2022-10-11T18:43:06Z")

</div>

# starknet-plugin-account

Account abstraction opens a completely new design space for accounts.

This project is a community effort lead by [Argent](https://www.argent.xyz/), [Cartridge](https://cartridge.gg) and [Ledger](https://www.ledger.com/), to explore the possibility to make accounts more flexible and modular by defining a plugin account architecture which lets users compose functionalities they want to enable when creating their account. The proposed architecture also aims to make the account extendable by letting users add or remove functionalities after the account has been created.

The idea of modular smart-contracts is not new and several architectures have been proposed for Ethereum [Argent smart-wallet, Diamond Pattern]. However, it is the first time that this is applied to accounts directly by leveraging account abstraction.

## Account Abstraction:

In StarkNet accounts must comply to the `IAccount` interface:

```cairo
@contract_interface
namespace IAccount {

    func supportsInterface(interfaceId: felt) -> (success: felt) {
    }

    func isValidSignature(hash: felt, signature_len: felt, signature: felt*) -> (isValid: felt) {
    }

    func __validate__ (
        call_array_len: felt, call_array: CallArray*, calldata_len: felt, calldata: felt*
    ) {
    }

    func __validate_declare__ (class_hash: felt) {
    }

    func __validate_deploy__ (
        class_hash: felt, ctr_args_len: felt, ctr_args: felt*, salt: felt
    ) {
    }

    func __execute__ (
        call_array_len: felt, call_array: CallArray*, calldata_len: felt, calldata: felt*
    ) -> (response_len: felt, response: felt*) {
    }
}

```

The two important methods are ` __validate__ ` which is called by the Starknet OS to verify that the transaction is valid and that the account will pay the fee before ` __execute__ ` is called by the OS to execute the transaction.

The ` __validate__ ` method has some constraints to protect the network. In particular, its logic must be implemented in a small number of steps and it cannot access the mutable state of any other contracts (i.e. it can only read the storage of the account).

## PluginAccount:

The `PluginAccount` contract is the main account contract that supports the addition of plugins.

A plugin is a separate piece of logic that can extend the functionalities of the account.

In this first version we focus only on the validation of transactions so plugins can implement different validation logic. However, the architecture can be easily extended to let plugins handle the execution of transactions in the future.

The Plugin Account extends the base account interface with the following interface:

```cairo
    func addPlugin(plugin: felt, plugin_calldata_len: felt, plugin_calldata: felt*) {
    }

    func removePlugin(plugin: felt) {
    }

    func setDefaultPlugin(plugin: felt) {
    }

    func isPlugin(plugin: felt) -> (success: felt) {
    }

    func readOnPlugin(plugin: felt, selector: felt, calldata_len: felt, calldata: felt*) {
    }

    func getDefaultPlugin() -> (plugin: felt) {
    }

```

A plugin must expose the following interface:

```cairo
@contract_interface
namespace IPlugin {
    func initialize(
        calldata_len: felt,
        calldata: felt*) {}

    func validate(
        call_array_len: felt,
        call_array: CallArray*,
        calldata_len: felt,
        calldata: felt*) {}
}

```

Plugins can be enabled and disabled with the methods `addPlugin` and `removePlugin` respectively.

The presence of a plugin can be checked with the `isPlugin` method.

### Validating with a plugin:

For every transaction the caller can instruct the account to validate the multi-call with a given plugin provided that the plugin has been registered in the account. Once the plugin is identified, the account will delegate the validation of the transaction to the plugin by calling the `validate` method of the plugin.

We note that the plugin must be called with a `library_call` to comply to the constraints of the ` __validate__ ` method, which prevents accessing the storage of other contracts. I.e. the logic of the plugin is executed in the context of the account and the state of the plugin, if any, must be stored in the account.

To instruct the account to use a specific plugin we leverage the transaction signature data. By convention, the first item in the signature data specifies the class hash of the plugin which should be used for validation. If no valid plugin is specified the default plugin is used. Any additional context necessary to validate the transaction, such as the signature itself, should be appended to the signature data.

So to validate a call using a specific plugin, the signature data should look like `[pluginClassHash, ...]`

Similarly, the `isValidSignature` will validate a signature using the provided plugin in the passed signature data.

### The default Plugin:

If no plugin is specified, the default plugin is used to validate the transaction. There must always be a default plugin defined and this plugin must be properly initialised.

The default plugin is also used to implement the `supportsInterface` method of the account.

The default plugin can be changed with the method `setDefaultPlugin`.

### Changing the state of a plugin:

To manipulate the state of a plugin, the account has a ` __default__ ` method that will be called when a multi-call specifies a call to the account with an unknown selector. The plugin to call is the one used for the validation.

### Reading the state of a plugin:

The view methods of a plugin can be accessed through the `readOnPlugin` method.

The view methods of the default plugin can also be accessed through the ` __default__ ` method.

## Contributions

This project is still in development but we would love the hear the feedback of the StarkNet community. We would like to also encourage contributions to the repository.

For more info: [GitHub - argentlabs/starknet-plugin-account: A community project to standardise plugins in StarkNet account contracts](https://github.com/argentlabs/starknet-plugin-account)

---

<div class="post-metadata">

**Author:** ![gaetbout](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/gaetbout/32/712_2.png) [@gaetbout](https://community.starknet.io/u/gaetbout)\
**Post date:** [October 11, 2022, 9:36pm UTC](https://community.starknet.io/t/community-plugin-account/2126/2 "2022-10-11T21:36:26Z")

</div>

Hey,

I’d rename the method `isPlugin` to `hasPlugin` because then the function `isPlugin` could be misunderstood as a check whether the given felt is a plugin or not. Not that the given felt is a plugin that is existing to the Account.

I get a rough idea of what the function `readOnPlugin` would do, but I’d like a confirmation. Could you elaborate on what is its purpose?

> [@juniset](#):
>
> If no plugin is specified, the default plugin is used to validate the transaction. There must always be a default plugin defined and this plugin must be properly initialized.

It means that when deploying an implementation a default plugin has to be specified, right?

Maybe having a count/list of all plugins an account has could be handy?  
Or maybe it is best to keep it as simple as possible 🙂

G.

---

<div class="post-metadata">

**Author:** ![yoga\_Braavos](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/yoga_braavos/32/858_2.png) [@yoga\_Braavos](https://community.starknet.io/u/yoga_Braavos)\
**Post date:** [October 12, 2022, 2:46pm UTC](https://community.starknet.io/t/community-plugin-account/2126/3 "2022-10-12T14:46:31Z")

</div>

@juniset , regarding:

> ### Changing the state of a plugin:
> 
> To manipulate the state of a plugin, the account has a ` __default__ ` method that will be called when a multi-call specifies a call to the account with an unknown selector. The plugin to call is the one used for the validation.

1. I don’t think that configuration should be implicit. Maybe consider adding an explicit “configure” method into the Plugin API with generic `calldata_len` and `calldata`?
2. Wouldn’t this break in SN \> v0.10 since selectors were deprecated in `invoke` transactions so you can’t choose a selector (` __execute__ ` is chosen by default)
3. In case you meant here that you will send a reentrant multicall with a non-existing entrypoint, again I think this is not a great design due to this implicit reentrancy.

---

<div class="post-metadata">

**Author:** ![JakubPtak](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/jakubptak/32/867_2.png) [@JakubPtak](https://community.starknet.io/u/JakubPtak)\
**Post date:** [October 14, 2022, 7:34am UTC](https://community.starknet.io/t/community-plugin-account/2126/4 "2022-10-14T07:34:01Z")

</div>

Do we assume that a plugin is always connected to a specific application?  
If not, then using a class hash as id might be problematic when there are multiple applications using the same plugin that received updates over time. Application would have to call `hasPlugin` for every known version of a plugin to see which one is supported by the user.  
There would also be a problem when user updates a plugin before the application is updated to know about it - it won’t see that this functionality is available.

---

<div class="post-metadata">

**Author:** ![tarrencev](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/tarrencev/32/720_2.png) [@tarrencev](https://community.starknet.io/u/tarrencev)\
**Post date:** [October 18, 2022, 5:51pm UTC](https://community.starknet.io/t/community-plugin-account/2126/5 "2022-10-18T17:51:56Z")

</div>

Thanks for the feedback! Def agree with your concern on the use of ` __default__ `, theres a PR here to remove it as per your suggestion: [No Default Plugin by sgc-code · Pull Request #10 · argentlabs/starknet-plugin-account · GitHub](https://github.com/argentlabs/starknet-plugin-account/pull/10).

---

<div class="post-metadata">

**Author:** ![tarrencev](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/tarrencev/32/720_2.png) [@tarrencev](https://community.starknet.io/u/tarrencev)\
**Post date:** [October 18, 2022, 6:01pm UTC](https://community.starknet.io/t/community-plugin-account/2126/6 "2022-10-18T18:01:13Z")

</div>

Currently, plugins aren’t connected to a particular app, they exist generically on the account. A plugin could implement its own logic to route signature validation differently based on the application being called, which is similar to what the session keys plugin does.

I think along with the account implementation, we’ll have to stand up some offchain infrastructure to manage the currently supported plugins for an account. An application could also do interface introspection using `hasPlugin` with a plugin hash.

Generally though, most applications wouldn’t need to be aware of plugins. A plugin developer could provide an implementation of the account interface, which would handle constructing transactions/signatures.

---

<div class="post-metadata">

**Author:** ![milan](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/milan/32/23836_2.png) [@milan](https://community.starknet.io/u/milan)\
**Post date:** [November 23, 2022, 3:49pm UTC](https://community.starknet.io/t/community-plugin-account/2126/7 "2022-11-23T15:49:26Z")

</div>

Do I understand correctly that with the current plugin architecture:

1. only a single plugin can be specified (and hence executed) in one multicall?
2. an app has to _specifically_ include the plugin it wants to use in the calldata? So it has to be aware of the plugin’s existence and also if it’s installed in the account?

---

<div class="post-metadata">

**Author:** ![tarrencev](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/tarrencev/32/720_2.png) [@tarrencev](https://community.starknet.io/u/tarrencev)\
**Post date:** [November 29, 2022, 2:17am UTC](https://community.starknet.io/t/community-plugin-account/2126/8 "2022-11-29T02:17:51Z")

</div>

Currently, (1) is the case. We are experimenting with different architectures to support chaining plugins during execution:

> <https://github.com/argentlabs/starknet-plugin-account/pull/11>
>
> A rough poc of supporting chainable plugins for both \`validate\` and \`execute\`.
> …
> It modifies the expected signature payload to include a second argument which describes the particular plugins signature length.
> 
> \`\`\`
> plugin0\_selector, plugin0\_signature\_length, plugin0\_signature0, plugin0\_signature1, ..., pluginN\_selector, pluginN\_signature\_length, pluginN\_signature0, pluginN\_signature1\]
> \`\`\`
> 
> Plugins also behave similar behavior to http middleware where they can be chained and are able to mutate intermediate values, i.e. a plugin can operate on a provided \`Call\` and remove it from the execution payload for subsequent plugins.

For (2), the current implementation moves the plugin selection to the signature data. With the chainable architecture, you would be able to pass signed calldata to plugins too.

The account client does need to be aware of the implementation details to format calls / signatures correctly. This is usually handled by an account provider so the application developer doesn’t need to be concerned about it.

---

<div class="post-metadata">

**Author:** ![milan](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/milan/32/23836_2.png) [@milan](https://community.starknet.io/u/milan)\
**Post date:** [November 30, 2022, 10:16am UTC](https://community.starknet.io/t/community-plugin-account/2126/9 "2022-11-30T10:16:18Z")

</div>

Ok, this is brilliant.

My mental model of plugins since I first learnt about them was HTTP middleware so I’m happy you’re thinking about it the same. I think this is the right way to go. It will enable a wave of innovation to the benefit of normal users.

Not sure I understand the finer points in (2). Say we have an on chain game like Realms. The Realms team develops a plugin to restrict interactions of an account only with approved contracts and functions. A player installs this plugin to their StarkNet account (one dedicated to playing Realms). Some other party develops a malicious client to play Realms. If this player uses the malicious client, will the plugin still execute (becuase it’s installed in their account) or not (because the malicious client naturally wouldn’t want to include it in the calldata)?
