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

Commit 9571e19

Browse files
0xmaayanhardsettingalyssaponzo
authored
Add DAA docs for the ts-sdk and wallet adapter (#873)
* add daa docs for the ts-sdk and wallet adapter * Updates to `derivable-account-abstraction.mdx` * Updated `cross-chain-wallet.mdx` * cross chain -> x-chain * fixing x-chain accounts term * missed one * Fixed wallet adapter meta --------- Co-authored-by: Gabriele Della Casa Venturelli <hardsetting@gmail.com> Co-authored-by: Alyssa Ponzo <alyssa.ponzo@gmail.com>
1 parent d2aef6e commit 9571e19

File tree

4 files changed

+366
-13
lines changed

4 files changed

+366
-13
lines changed

apps/nextra/pages/en/build/sdks/ts-sdk/account/_meta.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,7 @@ export default {
22
"account-abstraction": {
33
title: "Account Abstraction",
44
},
5+
"derivable-account-abstraction": {
6+
title: "Derivable Account Abstraction",
7+
},
58
};

apps/nextra/pages/en/build/sdks/ts-sdk/account/derivable-account-abstraction.mdx

Lines changed: 190 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,204 @@
22
title: "Derivable Account Abstraction"
33
---
44

5+
import { Steps } from "nextra/components";
6+
57
# Derivable Account Abstraction
68

7-
This document explains how derivable account abstraction works in Aptos using the TypeScript SDK. This feature is based on [AIP-113](https://github.com/aptos-foundation/AIPs/blob/main/aips/aip-113.md).
9+
[Derivable Account Abstraction (DAA)](https://github.com/aptos-foundation/AIPs/blob/main/aips/aip-113.md)
10+
is a standard for account abstraction that enables custom authentication schemes by registering a `derivable_authentication_function`.
11+
12+
DAA differs from vanilla [Account Abstraction (AA)](./account-abstraction) in that, for a given `derivable_authentication_function`,
13+
it defines how to deterministically derive the account address from an `abstract_public_key`, which can be done off-chain.
14+
15+
In contrast, vanilla AA is enabled for a specific pre-existing account by explicitly registering an on-chain `authentication_function`
16+
and submitting a transaction, which involves extra steps and costs gas for each account.
17+
18+
This allows registering secondary authentication schemes with identical user experience to the native ones.
19+
More specifically, this provides a flexible and secure way to manage cross-chain signatures. (see [x-chain accounts](../../wallet-adapter/x-chain-accounts.mdx))
20+
21+
## Core Concepts
22+
23+
### Authentication function
24+
25+
DAA works by defining an custom authentication scheme and registering a valid authentication function to perform on-chain authentication.
26+
27+
Each abstract account should have an associated `abstract_public_key` and should be able to produce `abstract_signature`s
28+
whose formats depend on the authentication scheme.
29+
30+
Simply put, the `derivable_authentication_function` needs to check that:
31+
- the `abstract_signature` is valid for the given `abstract_public_key`
32+
- the `abstract_signature` depends on the transaction's digest
33+
34+
```move
35+
// The function should return a signer if authentication is successful, otherwise it aborts the execution
36+
public fun authenticate(account: signer, auth_data: AbstractionAuthData): signer;
37+
```
38+
39+
The DAA framework automatically checks whether the address derived from `abstract_public_key` matches with the signer's address.
40+
41+
### Authentication data
42+
43+
`AbstractionAuthData` is an enum that represent the authentication data to be passed to custom authentication functions.
44+
It's used in all flavors of AA, but the `DerivableV1` variant defines the following fields:
45+
46+
- `digest`: The SHA3-256 hash of the signing message.
47+
- `abstract_signature`: Abstract signature bytes that need to be verified against `abstract_public_key`.
48+
- `abstract_public_key`: Abstract public key bytes associated to the abstract account
49+
50+
Here's what the Move enum looks like:
51+
52+
```move
53+
enum AbstractionAuthData has copy, drop {
54+
V1 { ... }, // Only applicable to vanilla AA
55+
DerivableV1 {
56+
digest: vector<u8>, // SHA3-256 hash of the signing message
57+
abstract_signature: vector<u8>,
58+
abstract_public_key: vector<u8>,
59+
}
60+
}
61+
```
62+
63+
**Why is the `digest` important?**
64+
65+
The `digest` is checked by the MoveVM to ensure that the signing message of the transaction being submitted is the same as the one presented in the `AbstractionAuthData`. This
66+
is important because it allows the authentication function to verify signatures with respect to the correct transaction.
67+
68+
For example, if you want to permit a public key to sign transactions on behalf of the user, you can permit the public key to sign a transaction with a specific payload.
69+
However, if a malicious user sends a signature for the correct public key but a different payload from the `digest`, the signature will not be valid.
70+
71+
### Account address derivation
72+
73+
With DAA, a given `derivable_authentication_function` defines a space of account addresses that can be deterministically derived from their associated `abstract_public_key`.
74+
75+
The on-chain function looks like the following:
76+
77+
```move
78+
public fun derive_account_address(derivable_func_info: FunctionInfo, abstract_public_key: &vector<u8>): address {
79+
let bytes = bcs::to_bytes(&derivable_func_info);
80+
bytes.append(bcs::to_bytes(abstract_public_key));
81+
bytes.push_back(DERIVABLE_ABSTRACTION_DERIVED_SCHEME);
82+
from_bcs::to_address(hash::sha3_256(bytes))
83+
}
84+
```
85+
86+
where `FunctionInfo` is a fully qualified identifier for a on-chain function:
87+
88+
```move
89+
struct FunctionInfo has copy, drop, store {
90+
module_address: address,
91+
module_name: String,
92+
function_name: String
93+
}
94+
```
95+
96+
The address derivation depends on the authentication function's identifier and on a DAA-specific domain separator.
97+
Because of this, each address space is isolated from the others and it's not possible for the same account to have multiple
98+
authentication functions.
99+
100+
**Example (Move)**
101+
102+
This example demonstrates domain account abstraction using ed25519 hex for signing.
103+
104+
```move
105+
module aptos_experimental::test_derivable_account_abstraction_ed25519_hex {
106+
use std::error;
107+
use aptos_std::string_utils;
108+
use aptos_std::ed25519::{
109+
Self,
110+
new_signature_from_bytes,
111+
new_unvalidated_public_key_from_bytes,
112+
};
113+
use aptos_framework::auth_data::AbstractionAuthData;
114+
115+
const EINVALID_SIGNATURE: u64 = 1;
116+
117+
/// Authorization function for derivable account abstraction.
118+
public fun authenticate(account: signer, aa_auth_data: AbstractionAuthData): signer {
119+
let hex_digest = string_utils::to_string(aa_auth_data.digest());
120+
121+
let public_key = new_unvalidated_public_key_from_bytes(*aa_auth_data.derivable_abstract_public_key());
122+
let signature = new_signature_from_bytes(*aa_auth_data.derivable_abstract_signature());
123+
assert!(
124+
ed25519::signature_verify_strict(
125+
&signature,
126+
&public_key,
127+
*hex_digest.bytes(),
128+
),
129+
error::permission_denied(EINVALID_SIGNATURE)
130+
);
131+
132+
account
133+
}
134+
}
135+
```
136+
137+
**Example (Typescript)**
138+
139+
```typescript
140+
const derivableAbstractedAccount = new DerivableAbstractedAccount({
141+
/**
142+
* The result of the signer function will be available as the `abstract_signature` field in the `AbstractionAuthData` enum variant.
143+
*/
144+
signer: (digest) => {
145+
const hexDigest = new TextEncoder().encode(Hex.fromHexInput(digest).toString());
146+
return solanaAccount.sign(hexDigest).toUint8Array();
147+
},
148+
/**
149+
* The authentication function to be invoked.
150+
*/
151+
authenticationFunction: `0x7::test_derivable_account_abstraction_ed25519_hex::authenticate`,
152+
/**
153+
* The abstract public key (i.e the account identity)
154+
*/
155+
abstractPublicKey: account.publicKey.toUint8Array(),
156+
});
157+
```
158+
159+
## Minimal Step-by-Step Guide
160+
161+
<Steps>
162+
163+
### 1. Generate a ED25519 key pair
164+
165+
```ts
166+
const ed25519Account = Account.generate();
167+
```
8168

9-
## Introduction
169+
### 2. Create a DAA
10170

11-
Derivable Account Abstraction is a feature that allows applications to create and manage accounts in a more flexible way, enabling better user experiences and more complex account structures.
171+
```ts
172+
const daa = new DerivableAbstractedAccount({
173+
signer: (digest) => {
174+
const hexDigest = new TextEncoder().encode(Hex.fromHexInput(digest).toString());
175+
return ed25519Account.sign(hexDigest).toUint8Array();
176+
},
177+
authenticationFunction: `0x7::test_derivable_account_abstraction_ed25519_hex::authenticate`,
178+
abstractPublicKey: ed25519Account.publicKey.toUint8Array(),
179+
});
180+
```
12181

13-
For detailed documentation on account abstraction, please see the [main Account Abstraction documentation](./account-abstraction.mdx).
182+
### 3. Fund the DAA to create it on chain
14183

15-
## Features
184+
```ts
185+
await aptos.fundAccount({ accountAddress: daa.accountAddress, amount: 1000000 });
186+
```
16187

17-
- Derive accounts from existing accounts
18-
- Create hierarchical account structures
19-
- Support for multi-signature accounts
20-
- Integration with various authentication methods
188+
### 4. Create a recipient account and transfer APT to it
21189

22-
## Technical Details
190+
```ts
191+
const recipient = Account.generate();
23192

24-
For technical details about this feature, please refer to [AIP-113](https://github.com/aptos-foundation/AIPs/blob/main/aips/aip-113.md).
193+
const pendingTxn = await aptos.transaction.signAndSubmitTransaction({
194+
signer: daa,
195+
transaction: await aptos.transferCoinTransaction({
196+
sender: daa.accountAddress,
197+
recipient: recipient.accountAddress,
198+
amount: 100,
199+
}),
200+
});
25201

26-
## Examples
202+
const response = await aptos.waitForTransaction({ transactionHash: pendingTxn.hash });
203+
```
27204

28-
For examples of how to use derivable account abstraction, see the main [Account Abstraction documentation](./account-abstraction.mdx).
205+
</Steps>

apps/nextra/pages/en/build/sdks/wallet-adapter/_meta.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,7 @@ export default {
1111
"wallet-standards": {
1212
title: "Aptos Wallet Standard",
1313
},
14+
"x-chain-accounts": {
15+
title: "X-Chain Accounts",
16+
},
1417
};

0 commit comments

Comments
 (0)