Skip to content
This repository was archived by the owner on Jul 30, 2025. It is now read-only.

Commit 229d4bb

Browse files
Initial guide for Account Abstraction
1 parent ac7ccb2 commit 229d4bb

File tree

2 files changed

+297
-0
lines changed

2 files changed

+297
-0
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export default {
2+
"account-abstraction": {
3+
title: "Account Abstraction",
4+
},
5+
};
Lines changed: 292 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,292 @@
1+
---
2+
title: "Account Abstraction"
3+
---
4+
5+
import { Steps, Callout } from "nextra/components";
6+
7+
# Account Abstraction
8+
9+
Account Abstraction (AA) on Aptos **enables custom transaction authentication logic through Move modules**, allowing accounts to define their own rules beyond native cryptographic schemes.
10+
11+
## Core Concepts
12+
13+
### `FunctionInfo`
14+
15+
A struct defining the authentication function to be invoked.
16+
17+
```move
18+
struct FunctionInfo has copy, drop, store {
19+
module_address: address,
20+
module_name: String,
21+
function_name: String
22+
}
23+
```
24+
25+
The authentication function is responsible for defining the authentication logic using Move. It should return a signer if authentication is successful, otherwise it aborts the transaction.
26+
The only accepted authentication function signature that can be added onto an account is the following:
27+
28+
```move
29+
// The function can return a signer if authentication is successful, otherwise it aborts the transaction.
30+
public fun authenticate(account: signer, auth_data: AbstractionAuthData): signer;
31+
```
32+
33+
**Example (Move)**
34+
35+
```move
36+
module deployer::authenticator {
37+
use aptos_framework::auth_data::{AbstractionAuthData};
38+
39+
public fun authenticate(account: signer, auth_data: AbstractionAuthData): signer {
40+
// ... authentication logic ...
41+
account
42+
}
43+
}
44+
```
45+
46+
**Example (Typescript)**
47+
48+
```typescript
49+
const authenticationFunction = `${deployer}::authenticator:authenticate`;
50+
```
51+
52+
### `AbstractionAuthData`
53+
54+
An enum variant defining the authentication data to be passed to the authentication function. It contains:
55+
56+
- `digest`: The sha256 hash of the signing message.
57+
- `authenticator`: Abstract bytes that will be passed to the authentication function that will be used to verify the transaction.
58+
59+
```move
60+
enum AbstractionAuthData has copy, drop {
61+
V1 {
62+
digest: vector<u8>, // SHA3-256 hash of the signing message
63+
authenticator: vector<u8> // Custom auth data (e.g., signatures)
64+
},
65+
}
66+
```
67+
68+
**Example (Move)**
69+
70+
This example demonstrates a simple authentication logic that checks if the authenticator is equal to `"hello world"`.
71+
72+
```move
73+
module deployer::hello_world_authenticator {
74+
use aptos_framework::auth_data::{Self, AbstractionAuthData};
75+
76+
public fun authenticate(
77+
account: signer,
78+
auth_data: AbstractionAuthData
79+
): signer {
80+
let authenticator = *auth_data::authenticator(&auth_data);
81+
assert!(authenticator == b"hello world", 1);
82+
account
83+
}
84+
}
85+
```
86+
87+
**Example (Typescript)**
88+
89+
```typescript
90+
const abstractedAccount = new AbstractedAccount({
91+
/**
92+
* The result of the signer function will be available as the `authenticator` field in the `AbstractionAuthData` enum variant.
93+
*/
94+
signer: () => new TextEncoder().encode("hello world"),
95+
/**
96+
* The authentication function to be invoked.
97+
*/
98+
authenticationFunction: `${deployer}::hello_world_authenticator:authenticate`,
99+
});
100+
```
101+
102+
## Step-by-Step Guide
103+
104+
<Steps>
105+
106+
### 1. Deploy Authentication Module
107+
108+
In this example, we will deploy the `hello_world_authenticator` module. The `authenticate` function takes an `AbstractionAuthData` and returns a `signer`
109+
if the authentication is successful, otherwise it aborts the transaction. The authentication logic will only allow transactions that have an authenticator equal to `"hello world"`.
110+
111+
```move
112+
module deployer::hello_world_authenticator {
113+
use aptos_framework::auth_data::{Self, AbstractionAuthData};
114+
use std::bcs;
115+
116+
public fun authenticate(
117+
account: signer,
118+
auth_data: AbstractionAuthData
119+
): signer {
120+
let authenticator = *auth_data::authenticator(&auth_data);
121+
assert!(authenticator == bcs::to_bytes(&b"hello world"), 1);
122+
account
123+
}
124+
}
125+
```
126+
127+
To deploy the module, you can use the following commands from the [Aptos CLI](/en/build/cli). We assume that you already have set up a workspace with `aptos init` and
128+
declared the named addresses in your `Move.toml` file.
129+
130+
```bash
131+
aptos move publish --named-addresses deployer=0x1234567890123456789012345678901234567890
132+
```
133+
134+
### 2. Setup your Environment
135+
136+
Once deployed, you can setup your environment. In this example, we will use Devnet and create an account named `alice` which will act as our user.
137+
138+
```ts
139+
const DEPLOYER = "0x<hello_world_authenticator_deployer>"
140+
141+
const aptos = new Aptos(new AptosConfig({ network: Network.DEVNET }));
142+
143+
const alice = Account.generate();
144+
145+
const authenticationFunctionInfo = `${deployer}::hello_world_authenticator:authenticate`;
146+
```
147+
148+
### 3. (Optional) Check if Account Abstraction is Enabled
149+
150+
Before you ask them to enable account abstraction, you can check if the account has account abstraction enabled by calling the `isAccountAbstractionEnabled` function.
151+
This will return a boolean value indicating if the account has account abstraction enabled.
152+
153+
```ts
154+
const accountAbstractionStatus = await aptos.account.isAccountAbstractionEnabled({
155+
accountAddress: alice.accountAddress,
156+
authenticationFunction,
157+
});
158+
159+
console.log("Account Abstraction status: ", accountAbstractionStatus);
160+
```
161+
162+
### 4. Enable the Authentication Function
163+
164+
Assuming that the account does not have account abstraction enabled, you need to enable the authentication function for the account. This can be done by calling
165+
the `enableAccountAbstractionTransaction` function. This creates a raw transaction that needs to be signed and submitted to the network. In this example, `alice`
166+
will be the account that will be enabled.
167+
168+
```ts
169+
const transaction = aptos.abstraction.enableAccountAbstractionTransaction({
170+
accountAddress: alice.accountAddress,
171+
authenticationFunction: `${deployer}::hello_world_authenticator:authenticate`,
172+
});
173+
174+
const pendingTransaction = await aptos.signAndSubmitTransaction({
175+
transaction,
176+
signer: alice.signer,
177+
});
178+
179+
await aptos.waitForTransaction({ hash: pendingTransaction.hash });
180+
181+
console.log("Account Abstraction enabled for account: ", alice.accountAddress);
182+
```
183+
184+
<details>
185+
<summary>
186+
<b>Wallet Adapter Example</b>
187+
</summary>
188+
189+
<Callout>
190+
If you are using the wallet adapter, you can use the `signTransaction` function to sign the transaction before submitting it to the network.
191+
</Callout>
192+
193+
```tsx
194+
export default function useEnableAbstraction() {
195+
const { account, signTransaction } = useWallet();
196+
197+
return {
198+
enableAbstraction: async () => {
199+
if (!account) return;
200+
201+
// Note: The Aptos client must be defined somewhere in the application.
202+
const transaction = aptos.abstraction.enableAccountAbstractionTransaction({
203+
accountAddress: account.address,
204+
authenticationFunction: `${deployer}::hello_world_authenticator:authenticate`,
205+
});
206+
207+
const senderAuthenticator = await signTransaction(txn);
208+
209+
const pendingTxn = await aptos.transaction.submit.simple({
210+
transaction: txn,
211+
senderAuthenticator,
212+
});
213+
214+
return await aptos.waitForTransaction({ hash: pendingTxn.hash });
215+
}
216+
}
217+
}
218+
```
219+
220+
</details>
221+
222+
### 5. Create an Abstracted Account
223+
224+
Once the authentication function is enabled, you can create an abstracted account object for signing transactions. You must provide the authentication function that will be used to verify the transaction
225+
and a `signer` function that will be used to sign the transaction. The `signer` function is responsible for generating the authenticator that will be passed to the authentication function.
226+
227+
```ts
228+
const abstractedAccount = new AbstractedAccount({
229+
accountAddress: alice.accountAddress,
230+
signer: () => new TextEncoder().encode("hello world"),
231+
authenticationFunction: `${deployer}::hello_world_authenticator:authenticate`,
232+
});
233+
```
234+
235+
### 6. Sign and Submit a Transaction using the Abstracted Account
236+
237+
Once you have created the abstracted account, you can use it to sign transactions normally. It is important that the `sender` field in the transaction
238+
is the same as the abstracted account's address.
239+
240+
```ts
241+
const coinTransferTransaction = new aptos.transaction.build.simple({
242+
sender: abstractedAccount.accountAddress,
243+
data: {
244+
function: "0x1::coin::transfer",
245+
typeArguments: ["0x1::aptos_coin::AptosCoin"],
246+
functionArguments: [alice.accountAddress, 100],
247+
},
248+
});
249+
250+
const pendingCoinTransferTransaction = aptos.transaction.signAndSubmitTransaction({
251+
transaction: coinTransferTransaction,
252+
signer: abstractedAccount,
253+
});
254+
255+
await aptos.waitForTransaction({ hash: pendingCoinTransferTransaction.hash });
256+
257+
console.log("Coin transfer transaction submitted! ", pendingCoinTransferTransaction.hash);
258+
```
259+
260+
### 7. Conclusion
261+
262+
To verify that you have successfully sign and submitted the transaction using the abstracted account, you can use the explorer to check the transaction. If the
263+
transaction signature contains a `function_info` and `auth_data` field, it means you succesfully used account abstraction!
264+
265+
![Transaction Signature](https://i.imgur.com/HZylFnc.png)
266+
267+
</Steps>
268+
269+
## Management Operations
270+
271+
If you want to disable account abstraction for an account, you can use the `disableAccountAbstractionTransaction`. If you do not specify an authentication function,
272+
the transaction will disable all authentication functions for the account.
273+
274+
```ts
275+
const transaction = aptos.abstraction.disableAccountAbstractionTransaction({
276+
accountAddress: alice.accountAddress,
277+
/**
278+
* The authentication function to be disabled. If left `undefined`, all authentication functions will be disabled.
279+
*/
280+
authenticationFunction,
281+
});
282+
```
283+
284+
## Application User Experience
285+
286+
Applications that want to leverage account abstraction will want to provide a user experience that allows users to check if the account has account abstraction enabled,
287+
and to enable it, if it is not enabled.
288+
289+
290+
Below is a diagram of the UX flow for enabling account abstraction.
291+
292+
![Account Abstraction UX](https://i.imgur.com/1xcrFjG.png)

0 commit comments

Comments
 (0)