Abstract IOTA Accounts #35
miker83z
started this conversation in
Featured Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Proposal
Abstract
This proposal defines a new account type for the IOTA protocol: the Abstract IOTA (AI) Account. An AI Account features a stable on-chain identifier and programmable authentication logic, enabling smart-contract-based verification in place of traditional private key signatures.
From the perspective of decentralized applications (dApps) and their users, AI Accounts function identically to traditional Externally Owned Accounts (EOAs). The primary objective is to enable flexible authentication mechanisms while ensuring compatibility with existing infrastructure and maintaining consistent behavior at the protocol level.
Motivation
The primary aim of this proposal is to significantly improve user experience throughout the IOTA ecosystem by supporting a diverse range of account authentication methods. This initiative enables extensible user authentication while preserving the integrity of the base protocol and ensuring that backward compatibility is not compromised. Under this model, accounts can operate and authenticate without relying on private keys, instead utilizing external inputs or executable code.
Authentication paradigms enabled by this proposal include, but are not limited to:
Specification
This section presents the technical specification for implementing an Account Abstraction model within the IOTA protocol. The Abstract IOTA (AI) Account is a new account type designed to support flexible, programmable authentication while maintaining full compatibility with existing protocol components.
At a high level, the mechanism works as follows:
AuthenticatorFunctionannotated with#[authenticator].AuthenticatorFunctionvia anAuthenticatorFunctionRef.AuthenticatorFunction— passing the proof data from theMoveAuthenticatorsignature field — instead of performing traditional signature verification.AuthenticatorFunctionexecutes successfully, the transaction is considered authenticated; if it aborts, the transaction is rejected.Requirements
The proposed Account Abstraction model must adhere to the following constraints:
Protocol Design
To support AI Accounts, we propose the addition of a new set of modules within the
iota-framework. These modules define the core data structures and their associated methods for creating and interacting with an AI Account.Account Representation and Addressing
AI Accounts are represented as objects within the IOTA Move framework, each associated with a globally unique 32-byte
ObjectID. TheObjectIDserves as the AI Account Identifier and is itself a validIotaAddress. Ownership of on-chain objects by AI Accounts is expressed using the existingAddressOwner(IotaAddress)variant, where theIotaAddressis the AI Account Identifier.Background: IOTA Ownership Model
Every object in the IOTA Protocol has a well-defined owner. Only the owner can use their objects as input to a transaction. The current ownership semantics are as follows:
AddressOwner(IotaAddress)AddressOwner(IotaAddress=PubKey-derived)– Object owned by a single EOA; it can be set as input of a transaction if the EOA provides a valid signature using the private key associated with the public key from which theIotaAddresswas derived.AddressOwner(IotaAddress=ObjectID)– The owner is anIotaAddresswhich is interpreted as anObjectID. Objects are, in essence, owning other objects. To unlock such owned objects, they need to be received in a transaction the first time they are accessed after being transferred.ObjectOwner(IotaAddress=ObjectID)– Object owned by another object, in a hierarchical, parent-child relationship. The owned object can be dynamically accessed in transactions where the parent is used as input. This is used for Dynamic Fields.SharedOwner– Mutably accessible by any address; it can be set as input of a transaction with no checks.ImmutableOwner– Immutably accessible by any address; it can be set as input of a transaction with no checks.Rationale for
AddressOwnerWhile an ownership of type
ObjectOwnermight appear suitable for an AI Account, since it is indeed an object, it would require additional steps and access control logic when objects are transferred to it. Specifically, if anObjectOwnerownership relationship were established, the sender of an object would be required to use the AI Account object as input of the transfer transaction; moreover, mutable access to the AI Account object would also be necessary.Employing an
AddressOwnerownership relation, instead, allows the sender to simply use the AI Account Identifier as the address. This choice renders AI Accounts indistinguishable from EOA addresses at the ownership level.Objects transferred to an AI Account Identifier do not require explicit acceptance by the receiver. When set as inputs of a transaction, their "unlocking" is performed by verifying that the AI Account Identifier matches the sender of the transaction, thereby ensuring that the account is authenticated.
Figure 1 illustrates how the
AddressOwner(IotaAddress)ownership variant applies to both EOA and AI Accounts. As shown, the external interface is identical, but the underlying derivation and verification mechanisms differ at the protocol level.The following table summarizes the key differences:
0xffffaddress derived from the EOA public key.0xabcis theObjectIDof the object representing the account.IotaAddress = AIAccountID = ObjectID0x123with typeCoin<IOTA>, owner is0xffff.0x123with typeCoin<IOTA>, owner is0xabc.0xffff0xabcAuthenticatorFunctionthat was arbitrarily created by a third-party developer and dynamically linked to the AI Account Identifier.Move Authenticator
As seen above, AI Accounts are capable of initiating transactions, i.e., the AI Account Identifier can be used as sender of transactions. However, unlike EOAs, whose authentication derives from private key signatures, the AI Account Identifier is not necessarily tied to a specific cryptographic keypair, nor derived from one. Therefore, a new authentication flow is introduced into the protocol to allow the implementation of arbitrary authentication mechanisms in Move: the
MoveAuthenticator.The
MoveAuthenticatoris a protocol-level transaction signature variant that allows transaction senders to submit a vector of arguments in the transaction signature field that are passed to theAuthenticatorFunctionof the AI Account. This enables third-party developers to implement custom programmable authentication schemes using Move.Note
Digression on the structure of IOTA transactions
Currently, the structure of IOTA transactions includes:
TransactionData: Contains core transaction payload such as Programmable Transaction Blocks (PTB) commands and gas configuration.GenericSignatures: A vector of protocol-supported authenticators, currently includingMultiSig,Signature,ZkLoginAuthenticator (disabled), andPasskeyAuthenticator.The proposed addition of
MoveAuthenticatorextends the set ofGenericSignaturevariants to support dynamic authentication logic. With this extension, third-party developers can deploy Move packages implementing a customAuthenticatorFunction. An AI Account can then be configured to delegate its authentication to such a package. Inputs to theAuthenticatorFunctionare encoded asVec<CallArg>(whereCallArgis a type defining pure and object arguments) and provided in theMoveAuthenticatorsignature field. The function either completes successfully or aborts with an error if authentication fails.Figure 2 compares the authentication flow for transactions issued by EOA and AI Accounts. The key distinction is that EOAs rely on cryptographic signature verification at the protocol level, whereas AI Accounts delegate verification to a developer-defined
AuthenticatorFunctionexecuted in Move.The following subsections describe each authentication flow in detail.
(Traditional) EOA Transaction Authentication
TransactionDatais the payload that makes transactions cryptographically unique. It includes sender, inputs, commands and gas data. Passing the raw bytes of the payload to a hash function yields its digest, i.e.,TransactionDigest, which becomes the transaction identifier (encoded in base58).An EOA user signs the
TransactionDigestwith the EOA private key (the description is simplified for the sake of readability). This signature becomes the payload of theGenericSignaturepart of the transaction. Once transmitted to a validator, the transaction is authenticated by extracting the sender address and transaction digest from theTransactionDataand verifying them against the signature. If verification fails, the transaction is marked as invalid.Abstract Account Transaction Authentication
In the case of AI Accounts, the
TransactionDatapart is exactly the same as the EOA case; it necessitates no changes. The difference lies in theGenericSignaturepart. A developer-defined mechanism can be used (e.g., a different signature scheme, passkey method or business logic) to generate a proof on the client side that can be validated by theAuthenticatorFunctionin Move.This proof (or set of proofs) becomes the
MoveAuthenticatorpayload of theGenericSignaturefield of the transaction. Validators authenticate the transaction by executing the account’s dynamically linkedAuthenticatorFunctionMove function with the proof provided as input argument(s). It is important to note that theAuthenticatorFunctionhas a “rich” context: it has access to theTxContextcontained in theTransactionData, i.e., it knows theTransactionDigest, and also accesses the inputs and commands ofTransactionDatausing anAuthContext. ThisAuthContextstruct enables parsing of the PTB information included in theTransactionData.Should the execution of
AuthenticatorFunctionfail for any reason, the transaction is marked as invalid.The AI Account Interface
The AI Account representation in Move is designed such that third-party developers can implement any arbitrary type. There is no single AI Account framework object type; rather, any object type can become an AI Account provided it implements the required interface.
A Move type is considered an abstract account if, and only if:
id: UIDfield),0x2::account::AuthenticatorFunctionRefV1Keyand value of type0x2::authenticator_function::AuthenticatorFunctionRef.The type
0x2::account::AuthenticatorFunctionRefcontains the fields necessary to uniquely identify an on-chainAuthenticatorFunctiondefined by an external package. For version 1:Figure 3 illustrates a concrete example in which a custom Authenticator Move Package is deployed and linked to an AI Account to provide authentication:
In the example above, we imagine a scenario where a developer independently develops the Custom Authenticator package deployed at the address
0x789(i.e., package id). This package defines the account interface through a module namedcustom_auth. In this module a0x789::custom_auth::CustomAccountMove object type is defined, which represents a specific implementation of an AI Account. TheCustomAccountuses the fieldauth_helpersto store data on-chain; the logic governing this account is arbitrarily defined by the developer.The only field required to make
CustomAccountan AI Account is a dynamic field using the0x2::account::AuthenticatorFunctionRefV1Keykey and0x2::authenticator_function::AuthenticatorFunctionRefvalue. This dynamic field entry can only be created through a framework method in the0x2::accountmodule, namelycreate_account_v1.The object with id
0xabc, once becoming an AI Account, has an authentication method clearly defined by the “attached”AuthenticatorFunctionRef. This struct references a specific function within the category of Move functions known asAuthenticatorFunction. In the example, it references the0x789::custom_auth::authenticatefunction defined in the same module.The Authenticator Function
The
AuthenticatorFunctionis designed to be as generic as possible, allowing third-party developers to implement arbitrary authentication logic. For instance, in the above example, theCustomAccountobject'sauth_helpersfield can be used within theAuthenticatorFunction. This field contains on-chain data that may have been modified by other parties prior to authentication. In general, anAuthenticatorFunctionreceives inputs and can read from the ledger state to allow or reject access to the AI Account. Thevec<CallArg>passed through theMoveAuthenticatorpayload of theGenericSignaturepart of the transaction is converted into function parameters similarly to what happens today for PTBs.An
AuthenticatorFunctionMUST satisfy the following rules:Visibility: The function MUST be declared as a
publicnon-entryfunction.Read-only inputs: All inputs MUST be read-only. Accepted input types are pure types (integers, strings, etc.) and read-only references to objects. Owned Objects MUST NOT be passed as input; only Shared Objects and Immutable Objects are permitted.
First parameter — Account reference: The first parameter MUST be a reference to the same Move type as the AI Account being authenticated. The object ID of the argument passed for this parameter MUST be exactly equal to the AI Account Identifier (i.e., the sender of the transaction).
No return type: The function MUST NOT define a return type. Authentication succeeds if the function completes execution without error and fails if the function aborts.
Context parameters: The second-to-last parameter MUST be
&AuthContextand the last parameter MUST be&TxContext. TheAuthContextstruct exposes the underlying transaction fields (PTB inputs and commands), whileTxContextexposes the transaction digest, gas parameters, and sponsor details. These context values are not created by the user; the protocol automatically creates and injects them before execution. The presence ofAuthContextensures that anAuthenticatorFunctioncannot be invoked from within Move by other functions.Execution Lifecycle
From the protocol point of view, the
AuthenticatorFunctionis invoked twice during the transaction lifecycle:AuthenticatorFunctionrelated to the TX’s sender account with any shared object read-only reference or pure inputs.AuthenticatorFunctionis executed for the second time immediately before the normal execution.AuthenticatorFunctionexecution can still fail due to changes in the state of input shared objects. In this case the authentication gas cost is deducted, but no other state changes are committed to the ledger and the transaction execution result is ABORTED.Creating AuthenticatorFunctionRef
The
AuthenticatorFunctionRef, as described above, is a struct that uniquely identifies a function within a package deployed on-chain. Its creation is enabled via the Package Metadata Standard (see IIP-00 TODO).Figure 4 shows how the
PackageMetadataobject is used to validate and create anAuthenticatorFunctionRefduring package publication.Continuing with the same example from the previous subsection, consider the
CustomAuthenticatorpackage. When this package is published to the ledger, an associatedPackageMetadataimmutable object is created. This immutable object contains metadata for each module, including functions found in the0x789::custom_authmodule. Specifically, the0x789::custom_auth::authenticatefunction is designated as an "authenticator" within thePackageMetadataobject. To be designated as an authenticator, a function MUST follow the rules listed in the previous subsection and MUST be annotated with the#[authenticator]function attribute.The
PackageMetadataobject acts as a source of validation. This object is created by the protocol during package publication. If an#[authenticator]attribute is found for a function, the protocol validates that function using theiota-move-verifier. SincePackageMetadatais an immutable object that can only be created by the protocol, it cannot be forged with an unauthorized authenticator function.Given the trusted nature of the
PackageMetadata, anAuthenticatorFunctionRefcan be created by passing aPackageMetadataobject as input. The function0x2::authenticator_function::create_auth_function_reftakes aPackageMetadata, a module name, and a function name, then verifies whether these inputs resolve to a valid authenticator function; if so, it returns anAuthenticatorFunctionRef. This reference is then used to create an account.Rationale
This specification introduces a flexible, developer-centric model for account abstraction that preserves compatibility with the existing transaction format and authorization model. By leveraging Move's programmability and object-oriented design, the system supports a wide range of use cases—from key rotation and passwordless login to DAO-based access control and cross-device passkey authentication.
Alternative models—such as static multisignature schemes or fixed key lists—were deemed insufficient due to their lack of adaptability to dynamic and composable use cases. In contrast, the AI Account model integrates tightly with the Move-based models for asset management.
Similar models have emerged in other blockchain ecosystems, such as Ethereum’s ERC-4337 and Aptos’ dynamic dispatch system. However, this proposal is uniquely tailored to the IOTA protocol's architecture, emphasizing on-chain object ownership, deterministic addressing, and native MoveVM integration.
Backwards Compatibility
This proposal is designed to be fully backward compatible with the existing IOTA protocol. The following areas are affected:
TransactionDatastructure.MoveAuthenticatorvariant is added alongside the existing variants inGenericSignature. Existing signature types remain unaffected.AuthenticatorFunctionhook is introduced for transaction validation and pre-PTB execution. The existing validation pipeline is not modified.MoveAuthenticator.Test Cases
The following test cases SHOULD be implemented to validate the correctness and completeness of the AI Account model:
Reference Implementation
Main PR against the develop branch: iotaledger/iota#9586
References to Account Abstraction projects in Web3
Copyright
Copyright and related rights waived via CC0.
Discussion
The discussion should continue to look for improvements for this proposal.
CC @lzpap @valeriyr @iotaledger/vm-language
Beta Was this translation helpful? Give feedback.
All reactions