@vaultkeepr/smart-account 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -0
- package/dist/index.d.mts +194 -95
- package/dist/index.d.ts +194 -95
- package/dist/index.js +333 -281
- package/dist/index.mjs +325 -273
- package/package.json +21 -6
- package/src/index.ts +16 -14
package/dist/index.d.ts
CHANGED
|
@@ -19,124 +19,59 @@ declare function getCachedSmartAccountAddress(): Address | null;
|
|
|
19
19
|
declare function getCachedSmartAccountMode(): VaultSmartAccount["mode"] | null;
|
|
20
20
|
declare function clearSmartAccountCache(): void;
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
type VaultIdentityMode = "password" | "passkey" | "biometric";
|
|
23
|
+
interface VaultIdentity {
|
|
24
|
+
ownerAddress: Address;
|
|
25
|
+
aaAddress: Address;
|
|
26
|
+
mode: VaultIdentityMode;
|
|
27
|
+
}
|
|
28
|
+
declare function deriveIdentity(ownerAccount: LocalAccount, mode: VaultIdentityMode): Promise<VaultIdentity>;
|
|
29
|
+
interface VerifyAAAuthParams {
|
|
30
|
+
signature: string;
|
|
31
|
+
message: string;
|
|
32
|
+
claimedOwner?: Address;
|
|
33
|
+
claimedAA?: Address | null;
|
|
34
|
+
timestamp: number;
|
|
35
|
+
}
|
|
36
|
+
interface VerifyAAAuthResult {
|
|
37
|
+
ok: boolean;
|
|
38
|
+
ownerAddress: Address;
|
|
39
|
+
aaAddress: Address;
|
|
40
|
+
}
|
|
41
|
+
declare function verifyAAAuth(params: VerifyAAAuthParams): Promise<VerifyAAAuthResult>;
|
|
23
42
|
|
|
24
|
-
declare
|
|
25
|
-
readonly name: "setCid";
|
|
26
|
-
readonly type: "function";
|
|
27
|
-
readonly stateMutability: "nonpayable";
|
|
28
|
-
readonly inputs: readonly [{
|
|
29
|
-
readonly name: "cid";
|
|
30
|
-
readonly type: "string";
|
|
31
|
-
}];
|
|
32
|
-
readonly outputs: readonly [];
|
|
33
|
-
}, {
|
|
34
|
-
readonly name: "deleteCid";
|
|
35
|
-
readonly type: "function";
|
|
36
|
-
readonly stateMutability: "nonpayable";
|
|
37
|
-
readonly inputs: readonly [];
|
|
38
|
-
readonly outputs: readonly [];
|
|
39
|
-
}, {
|
|
40
|
-
readonly name: "getCid";
|
|
41
|
-
readonly type: "function";
|
|
42
|
-
readonly stateMutability: "view";
|
|
43
|
-
readonly inputs: readonly [{
|
|
44
|
-
readonly name: "account";
|
|
45
|
-
readonly type: "address";
|
|
46
|
-
}];
|
|
47
|
-
readonly outputs: readonly [{
|
|
48
|
-
readonly name: "";
|
|
49
|
-
readonly type: "string";
|
|
50
|
-
}];
|
|
51
|
-
}, {
|
|
52
|
-
readonly name: "hasCid";
|
|
53
|
-
readonly type: "function";
|
|
54
|
-
readonly stateMutability: "view";
|
|
55
|
-
readonly inputs: readonly [{
|
|
56
|
-
readonly name: "account";
|
|
57
|
-
readonly type: "address";
|
|
58
|
-
}];
|
|
59
|
-
readonly outputs: readonly [{
|
|
60
|
-
readonly name: "";
|
|
61
|
-
readonly type: "bool";
|
|
62
|
-
}];
|
|
63
|
-
}, {
|
|
64
|
-
readonly name: "getUpdatedAt";
|
|
65
|
-
readonly type: "function";
|
|
66
|
-
readonly stateMutability: "view";
|
|
67
|
-
readonly inputs: readonly [{
|
|
68
|
-
readonly name: "account";
|
|
69
|
-
readonly type: "address";
|
|
70
|
-
}];
|
|
71
|
-
readonly outputs: readonly [{
|
|
72
|
-
readonly name: "";
|
|
73
|
-
readonly type: "uint256";
|
|
74
|
-
}];
|
|
75
|
-
}, {
|
|
76
|
-
readonly name: "nextAllowedUpdate";
|
|
77
|
-
readonly type: "function";
|
|
78
|
-
readonly stateMutability: "view";
|
|
79
|
-
readonly inputs: readonly [{
|
|
80
|
-
readonly name: "account";
|
|
81
|
-
readonly type: "address";
|
|
82
|
-
}];
|
|
83
|
-
readonly outputs: readonly [{
|
|
84
|
-
readonly name: "";
|
|
85
|
-
readonly type: "uint256";
|
|
86
|
-
}];
|
|
87
|
-
}, {
|
|
88
|
-
readonly name: "cooldownSeconds";
|
|
89
|
-
readonly type: "function";
|
|
90
|
-
readonly stateMutability: "view";
|
|
91
|
-
readonly inputs: readonly [];
|
|
92
|
-
readonly outputs: readonly [{
|
|
93
|
-
readonly name: "";
|
|
94
|
-
readonly type: "uint256";
|
|
95
|
-
}];
|
|
96
|
-
}];
|
|
97
|
-
declare function isCidRegistryConfigured(): boolean;
|
|
98
|
-
declare function publishCidOnChain(smartAccount: VaultSmartAccount, cid: string): Promise<`0x${string}` | null>;
|
|
99
|
-
declare function readCidOnChain(smartAccountAddress: Address): Promise<string | null>;
|
|
43
|
+
declare function getOwnerFromPassword(password: string, secretKey?: string): Promise<LocalAccount>;
|
|
100
44
|
|
|
101
45
|
declare function getPimlicoApiKey(): string;
|
|
102
46
|
declare function isSmartAccountConfigured(): boolean;
|
|
103
47
|
declare function getTargetChain(): Chain;
|
|
104
48
|
|
|
105
|
-
|
|
106
|
-
declare function flushCidOnChainSync(): Promise<boolean>;
|
|
107
|
-
declare function getOnChainSyncStatus(): {
|
|
108
|
-
hasPending: boolean;
|
|
109
|
-
pendingCid: string | null;
|
|
110
|
-
lastPublishedCid: string | null;
|
|
111
|
-
lastPublishTime: number;
|
|
112
|
-
isPublishing: boolean;
|
|
113
|
-
};
|
|
114
|
-
declare function resetOnChainSync(): void;
|
|
115
|
-
|
|
116
|
-
interface IdentityState {
|
|
49
|
+
interface IdentityState$1 {
|
|
117
50
|
owner: LocalAccount | null;
|
|
118
51
|
smartAccount: VaultSmartAccount | null;
|
|
119
52
|
mode: "password" | "passkey" | "biometric" | null;
|
|
120
53
|
initialized: boolean;
|
|
121
54
|
}
|
|
122
|
-
type IdentityListener = (state: IdentityState) => void;
|
|
55
|
+
type IdentityListener = (state: IdentityState$1) => void;
|
|
123
56
|
declare function initIdentityFromPassword(password: string, secretKey?: string): Promise<{
|
|
124
57
|
address: Address;
|
|
125
58
|
smartAccountAddress: Address | null;
|
|
59
|
+
aaAddress: Address | null;
|
|
126
60
|
}>;
|
|
127
61
|
declare function initIdentityFromSigner(signer: LocalAccount, mode?: "passkey" | "biometric"): Promise<{
|
|
128
62
|
address: Address;
|
|
129
63
|
smartAccountAddress: Address | null;
|
|
64
|
+
aaAddress: Address | null;
|
|
130
65
|
}>;
|
|
131
66
|
declare function clearIdentity(): void;
|
|
132
67
|
declare function getIdentityAddress(): Address | null;
|
|
133
68
|
declare function isIdentityConnected(): boolean;
|
|
134
69
|
declare function getIdentityOwner(): LocalAccount | null;
|
|
135
70
|
declare function getIdentitySmartAccount(): VaultSmartAccount | null;
|
|
136
|
-
declare function getIdentityMode(): IdentityState["mode"];
|
|
71
|
+
declare function getIdentityMode(): IdentityState$1["mode"];
|
|
137
72
|
declare function signMessageWithIdentity(message: string): Promise<`0x${string}`>;
|
|
138
73
|
declare function subscribeIdentity(listener: IdentityListener): () => void;
|
|
139
|
-
declare function getIdentitySnapshot(): IdentityState;
|
|
74
|
+
declare function getIdentitySnapshot(): IdentityState$1;
|
|
140
75
|
|
|
141
76
|
interface UseIdentityReturn {
|
|
142
77
|
address: Address | null;
|
|
@@ -145,9 +80,7 @@ interface UseIdentityReturn {
|
|
|
145
80
|
smartAccountAddress: Address | null;
|
|
146
81
|
signMessage: (message: string) => Promise<`0x${string}`>;
|
|
147
82
|
disconnect: () => void;
|
|
148
|
-
notifyOnChainSync: (cid: string) => void;
|
|
149
83
|
cleanupOnLock: () => Promise<void>;
|
|
150
|
-
flushOnChainSync: () => Promise<void>;
|
|
151
84
|
}
|
|
152
85
|
declare function useIdentity(): UseIdentityReturn;
|
|
153
86
|
|
|
@@ -156,4 +89,170 @@ declare function isValidSecretKey(key: string): boolean;
|
|
|
156
89
|
declare function formatSecretKeyForDisplay(key: string): string;
|
|
157
90
|
declare function parseSecretKeyInput(input: string): string;
|
|
158
91
|
|
|
159
|
-
|
|
92
|
+
/**
|
|
93
|
+
* Accounts without a secret key, and their one-time passage to a key.
|
|
94
|
+
*
|
|
95
|
+
* Rule: one secret key per account. A key-less account has the password identity as owner.
|
|
96
|
+
* Passing it to a key is a one-time move, in this order:
|
|
97
|
+
* 1. create the key as a pending key (this device keeps its identity);
|
|
98
|
+
* 2. copy the pointer under the key's Smart Account;
|
|
99
|
+
* 3. mark the legacy pointer as moved to that Smart Account;
|
|
100
|
+
* 4. activate the pending key on this device.
|
|
101
|
+
* Nothing is deleted. Devices that do not hold the key become read-only.
|
|
102
|
+
*
|
|
103
|
+
* A failure stops the sequence. A retry reuses the same pending key. A device never uses the
|
|
104
|
+
* new key before the legacy pointer has moved to its Smart Account.
|
|
105
|
+
*
|
|
106
|
+
* Pure logic. Network and storage are injected, so the order and the failure behaviour are
|
|
107
|
+
* tested without a device.
|
|
108
|
+
*/
|
|
109
|
+
/** Server view of the legacy (password identity) pointer. */
|
|
110
|
+
type PointerState = "none" | "active" | "moved";
|
|
111
|
+
type IdentityState = {
|
|
112
|
+
kind: "ready";
|
|
113
|
+
} | {
|
|
114
|
+
kind: "pass_to_key";
|
|
115
|
+
} | {
|
|
116
|
+
kind: "pair_required";
|
|
117
|
+
} | {
|
|
118
|
+
kind: "join_or_create";
|
|
119
|
+
};
|
|
120
|
+
declare function identityState(input: {
|
|
121
|
+
hasSecretKey: boolean;
|
|
122
|
+
pointer: PointerState;
|
|
123
|
+
}): IdentityState;
|
|
124
|
+
/**
|
|
125
|
+
* Writes are allowed while the account has not moved: a key-less account keeps writing to its
|
|
126
|
+
* legacy pointer until its passage ("nothing changes"). A moved pointer, or no pointer and no
|
|
127
|
+
* key, cannot be written from this device.
|
|
128
|
+
*/
|
|
129
|
+
declare function canWritePointer(state: IdentityState): boolean;
|
|
130
|
+
interface LegacyPointer {
|
|
131
|
+
cid: string | null;
|
|
132
|
+
moved: boolean;
|
|
133
|
+
/** Smart Account the pointer moved to, when moved. */
|
|
134
|
+
movedTo?: string;
|
|
135
|
+
}
|
|
136
|
+
interface PassageIO {
|
|
137
|
+
/** Reads the legacy (password identity) pointer. */
|
|
138
|
+
readLegacyPointer(): Promise<LegacyPointer>;
|
|
139
|
+
/** The pending key left by a passage on this device, or null. Never creates a key. */
|
|
140
|
+
peekPendingKey(): Promise<string | null>;
|
|
141
|
+
/** The pending key: created and kept in pending storage if absent. Same key on every retry. Does not change the identity. */
|
|
142
|
+
getOrCreatePendingKey(): Promise<string>;
|
|
143
|
+
/** Smart Account of the key's owner. */
|
|
144
|
+
smartAccountOf(secretKey: string): Promise<string>;
|
|
145
|
+
/** Writes the copy under the Smart Account, signed with the pending key. Idempotent. */
|
|
146
|
+
writeSmartAccountPointer(smartAccount: string, cid: string): Promise<void>;
|
|
147
|
+
/** Marks the legacy pointer as moved to the Smart Account, signed with the legacy owner. Idempotent for the same target. */
|
|
148
|
+
markLegacyMoved(smartAccount: string): Promise<void>;
|
|
149
|
+
/** Makes the pending key this device's account key. Called only once the legacy pointer has moved to its Smart Account. */
|
|
150
|
+
activatePendingKey(): Promise<void>;
|
|
151
|
+
/** Removes the pending key. Used when the account has moved to another key. */
|
|
152
|
+
discardPendingKey(): Promise<void>;
|
|
153
|
+
}
|
|
154
|
+
type PassageResult = {
|
|
155
|
+
status: "moved";
|
|
156
|
+
smartAccount: string;
|
|
157
|
+
} | {
|
|
158
|
+
status: "nothing_to_pass";
|
|
159
|
+
} | {
|
|
160
|
+
status: "already_moved";
|
|
161
|
+
} | {
|
|
162
|
+
status: "already_keyed";
|
|
163
|
+
};
|
|
164
|
+
declare function runPassage(io: PassageIO, opts: {
|
|
165
|
+
hasSecretKey: boolean;
|
|
166
|
+
}): Promise<PassageResult>;
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Client side of the passage to a key: the requests to the server, with the signatures and the
|
|
170
|
+
* storage supplied by each app. The order and the failure rules are in keyPassage.ts.
|
|
171
|
+
*
|
|
172
|
+
* Off in production: PASSAGE_ENABLED stays false until the server move route and the Smart
|
|
173
|
+
* Account namespace are deployed.
|
|
174
|
+
*/
|
|
175
|
+
|
|
176
|
+
/** Off until the server side (move route, Smart Account namespace) is deployed. */
|
|
177
|
+
declare const PASSAGE_ENABLED = false;
|
|
178
|
+
interface PassageEnv {
|
|
179
|
+
/** API origin, without trailing slash. */
|
|
180
|
+
apiBase: string;
|
|
181
|
+
fetch: typeof fetch;
|
|
182
|
+
/** EOA of the password identity (the legacy owner). */
|
|
183
|
+
legacyAddress: string;
|
|
184
|
+
/** Signs a message with the legacy owner. */
|
|
185
|
+
signLegacy(message: string): Promise<string>;
|
|
186
|
+
/** Signs a message with the owner of a secret key. */
|
|
187
|
+
signWithKey(secretKey: string, message: string): Promise<string>;
|
|
188
|
+
/** Smart Account of a secret key's owner. */
|
|
189
|
+
smartAccountOf(secretKey: string): Promise<string>;
|
|
190
|
+
/** The autosave delegation message the server verifies (wallet-messages). */
|
|
191
|
+
formatDelegation(sessionId: string, expiryTimestamp: number): string;
|
|
192
|
+
/** A new random secret key (client RNG). */
|
|
193
|
+
newSecretKey(): string;
|
|
194
|
+
/** A new random session id. */
|
|
195
|
+
newSessionId(): string;
|
|
196
|
+
/** Current time, in milliseconds. */
|
|
197
|
+
now(): number;
|
|
198
|
+
/** Pending key storage: encrypted at rest, never logged. */
|
|
199
|
+
pending: {
|
|
200
|
+
read(): Promise<string | null>;
|
|
201
|
+
write(secretKey: string): Promise<void>;
|
|
202
|
+
clear(): Promise<void>;
|
|
203
|
+
};
|
|
204
|
+
/** Stores the committed account key and updates this device's identity. */
|
|
205
|
+
activate(secretKey: string): Promise<void>;
|
|
206
|
+
}
|
|
207
|
+
declare function createPassageIO(env: PassageEnv): PassageIO;
|
|
208
|
+
/** The account's state on this device, for the UI. Changes nothing. */
|
|
209
|
+
declare function readPassageState(env: PassageEnv, hasSecretKey: boolean): Promise<IdentityState>;
|
|
210
|
+
/** Runs the one-time passage. On a failed step it throws, and the pending key is kept for a retry. */
|
|
211
|
+
declare function runPassageWith(env: PassageEnv, hasSecretKey: boolean): Promise<PassageResult>;
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Migration of an account that already has a secret key: its pointer moves from the legacy
|
|
215
|
+
* namespace (the owner EOA of the key) to the Smart Account namespace (SA of that EOA).
|
|
216
|
+
*
|
|
217
|
+
* Steps, with the device key as the owner signer (same routes as the one-time passage):
|
|
218
|
+
* 1. read the legacy pointer of the owner EOA;
|
|
219
|
+
* 2. if the SA has no pointer, copy the legacy CID under the SA (the server infers the SA namespace
|
|
220
|
+
* from the owner signature);
|
|
221
|
+
* 3. mark the legacy pointer moved to the SA (the server refuses it without the SA copy);
|
|
222
|
+
* 4. after the move the legacy pointer is frozen: read it again and make the SA equal to it.
|
|
223
|
+
* This closes the race where an old client wrote the legacy pointer between steps 1 and 3.
|
|
224
|
+
*
|
|
225
|
+
* Nothing is deleted. A failed step throws; the next unlock runs the same steps again.
|
|
226
|
+
* A conflict (the SA already holds a different CID) changes nothing: the device keeps the legacy pointer.
|
|
227
|
+
*
|
|
228
|
+
* Off until the server side is deployed: KEYED_MIGRATION_ENABLED stays false.
|
|
229
|
+
*/
|
|
230
|
+
/** Off until the Smart Account namespace and the move route are deployed. */
|
|
231
|
+
declare const KEYED_MIGRATION_ENABLED = false;
|
|
232
|
+
interface KeyedMigrationEnv {
|
|
233
|
+
apiBase: string;
|
|
234
|
+
fetch: typeof fetch;
|
|
235
|
+
/** Owner EOA derived from the device secret key. The legacy pointer lives under it. */
|
|
236
|
+
ownerAddress: string;
|
|
237
|
+
/** Smart Account of the owner EOA, computed on the device. Never taken from the server. */
|
|
238
|
+
smartAccount: string;
|
|
239
|
+
/** Signs with the device key (the owner EOA). */
|
|
240
|
+
signWithKey(message: string): Promise<string>;
|
|
241
|
+
formatDelegation(sessionId: string, expiryTimestamp: number): string;
|
|
242
|
+
newSessionId(): string;
|
|
243
|
+
now(): number;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* - moved: the legacy pointer is now moved to the SA, and the SA holds its CID.
|
|
247
|
+
* - already_moved: a previous run (or another device) already moved it to this SA.
|
|
248
|
+
* - no_pointer: no legacy pointer. Nothing to move: the device keeps the legacy namespace.
|
|
249
|
+
* - conflict: the SA holds a different CID. Nothing changed; to be reported, not resolved here.
|
|
250
|
+
*/
|
|
251
|
+
type KeyedMigrationStatus = "moved" | "already_moved" | "no_pointer" | "conflict";
|
|
252
|
+
/**
|
|
253
|
+
* Runs the migration for the device's account. Throws on any failed step: the caller keeps the legacy
|
|
254
|
+
* namespace and retries at the next unlock. Switches the device to the SA only on moved / already_moved.
|
|
255
|
+
*/
|
|
256
|
+
declare function migrateKeyedPointer(env: KeyedMigrationEnv): Promise<KeyedMigrationStatus>;
|
|
257
|
+
|
|
258
|
+
export { type CreateSmartAccountParams, type IdentityState, KEYED_MIGRATION_ENABLED, type KeyedMigrationEnv, type KeyedMigrationStatus, type LegacyPointer, PASSAGE_ENABLED, type PassageEnv, type PassageIO, type PassageResult, type PointerState, type UseIdentityReturn, type VaultIdentity, type VaultIdentityMode, type VaultSmartAccount, type VerifyAAAuthParams, type VerifyAAAuthResult, canWritePointer, clearIdentity, clearSmartAccountCache, computeSmartAccountAddress, createPassageIO, createVaultSmartAccount, deriveIdentity, formatSecretKeyForDisplay, generateSecretKey, getCachedSmartAccountAddress, getCachedSmartAccountMode, getIdentityAddress, getIdentityMode, getIdentityOwner, getIdentitySmartAccount, getIdentitySnapshot, getOwnerFromPassword, getPimlicoApiKey, getTargetChain, identityState, initIdentityFromPassword, initIdentityFromSigner, isIdentityConnected, isSmartAccountConfigured, isValidSecretKey, migrateKeyedPointer, parseSecretKeyInput, readPassageState, runPassage, runPassageWith, signMessageWithIdentity, subscribeIdentity, useIdentity, verifyAAAuth };
|