@prism-ing/wallet 0.1.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.
Files changed (113) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/LICENSE +21 -0
  3. package/README.md +596 -0
  4. package/SPEC.md +192 -0
  5. package/dist/backends/squads-recovery-backend.d.ts +59 -0
  6. package/dist/backends/squads-recovery-backend.d.ts.map +1 -0
  7. package/dist/backends/squads-recovery-backend.js +81 -0
  8. package/dist/backends/squads-recovery-backend.js.map +1 -0
  9. package/dist/backends/squads-types.d.ts +74 -0
  10. package/dist/backends/squads-types.d.ts.map +1 -0
  11. package/dist/backends/squads-types.js +22 -0
  12. package/dist/backends/squads-types.js.map +1 -0
  13. package/dist/backends/zerodev-policy-mapper.d.ts +41 -0
  14. package/dist/backends/zerodev-policy-mapper.d.ts.map +1 -0
  15. package/dist/backends/zerodev-policy-mapper.js +127 -0
  16. package/dist/backends/zerodev-policy-mapper.js.map +1 -0
  17. package/dist/backends/zerodev-session-backend.d.ts +43 -0
  18. package/dist/backends/zerodev-session-backend.d.ts.map +1 -0
  19. package/dist/backends/zerodev-session-backend.js +63 -0
  20. package/dist/backends/zerodev-session-backend.js.map +1 -0
  21. package/dist/backends/zerodev-types.d.ts +104 -0
  22. package/dist/backends/zerodev-types.d.ts.map +1 -0
  23. package/dist/backends/zerodev-types.js +13 -0
  24. package/dist/backends/zerodev-types.js.map +1 -0
  25. package/dist/create-wallet.d.ts +89 -0
  26. package/dist/create-wallet.d.ts.map +1 -0
  27. package/dist/create-wallet.js +235 -0
  28. package/dist/create-wallet.js.map +1 -0
  29. package/dist/cross-chain.d.ts +64 -0
  30. package/dist/cross-chain.d.ts.map +1 -0
  31. package/dist/cross-chain.js +200 -0
  32. package/dist/cross-chain.js.map +1 -0
  33. package/dist/errors.d.ts +115 -0
  34. package/dist/errors.d.ts.map +1 -0
  35. package/dist/errors.js +97 -0
  36. package/dist/errors.js.map +1 -0
  37. package/dist/index.d.ts +55 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +52 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/internal/base58.d.ts +8 -0
  42. package/dist/internal/base58.d.ts.map +1 -0
  43. package/dist/internal/base58.js +34 -0
  44. package/dist/internal/base58.js.map +1 -0
  45. package/dist/internal/eip712.d.ts +41 -0
  46. package/dist/internal/eip712.d.ts.map +1 -0
  47. package/dist/internal/eip712.js +182 -0
  48. package/dist/internal/eip712.js.map +1 -0
  49. package/dist/internal/file-spend-persistence.d.ts +9 -0
  50. package/dist/internal/file-spend-persistence.d.ts.map +1 -0
  51. package/dist/internal/file-spend-persistence.js +58 -0
  52. package/dist/internal/file-spend-persistence.js.map +1 -0
  53. package/dist/internal/onebalance-client.d.ts +59 -0
  54. package/dist/internal/onebalance-client.d.ts.map +1 -0
  55. package/dist/internal/onebalance-client.js +2 -0
  56. package/dist/internal/onebalance-client.js.map +1 -0
  57. package/dist/internal/onebalance-http-client.d.ts +25 -0
  58. package/dist/internal/onebalance-http-client.d.ts.map +1 -0
  59. package/dist/internal/onebalance-http-client.js +161 -0
  60. package/dist/internal/onebalance-http-client.js.map +1 -0
  61. package/dist/internal/onebalance-types.d.ts +201 -0
  62. package/dist/internal/onebalance-types.d.ts.map +1 -0
  63. package/dist/internal/onebalance-types.js +39 -0
  64. package/dist/internal/onebalance-types.js.map +1 -0
  65. package/dist/internal/platform.d.ts +14 -0
  66. package/dist/internal/platform.d.ts.map +1 -0
  67. package/dist/internal/platform.js +22 -0
  68. package/dist/internal/platform.js.map +1 -0
  69. package/dist/internal/quote-verifier.d.ts +71 -0
  70. package/dist/internal/quote-verifier.d.ts.map +1 -0
  71. package/dist/internal/quote-verifier.js +172 -0
  72. package/dist/internal/quote-verifier.js.map +1 -0
  73. package/dist/internal/recovery-manager.d.ts +29 -0
  74. package/dist/internal/recovery-manager.d.ts.map +1 -0
  75. package/dist/internal/recovery-manager.js +161 -0
  76. package/dist/internal/recovery-manager.js.map +1 -0
  77. package/dist/result.d.ts +132 -0
  78. package/dist/result.d.ts.map +1 -0
  79. package/dist/result.js +114 -0
  80. package/dist/result.js.map +1 -0
  81. package/dist/schemas.d.ts +184 -0
  82. package/dist/schemas.d.ts.map +1 -0
  83. package/dist/schemas.js +76 -0
  84. package/dist/schemas.js.map +1 -0
  85. package/dist/session-keys.d.ts +53 -0
  86. package/dist/session-keys.d.ts.map +1 -0
  87. package/dist/session-keys.js +345 -0
  88. package/dist/session-keys.js.map +1 -0
  89. package/dist/signers/node-signing-backend.d.ts +11 -0
  90. package/dist/signers/node-signing-backend.d.ts.map +1 -0
  91. package/dist/signers/node-signing-backend.js +120 -0
  92. package/dist/signers/node-signing-backend.js.map +1 -0
  93. package/dist/signers/ows-adapter.d.ts +70 -0
  94. package/dist/signers/ows-adapter.d.ts.map +1 -0
  95. package/dist/signers/ows-adapter.js +53 -0
  96. package/dist/signers/ows-adapter.js.map +1 -0
  97. package/dist/signers/ows-signing-backend.d.ts +25 -0
  98. package/dist/signers/ows-signing-backend.d.ts.map +1 -0
  99. package/dist/signers/ows-signing-backend.js +192 -0
  100. package/dist/signers/ows-signing-backend.js.map +1 -0
  101. package/dist/signers/secure-enclave-backend.d.ts +19 -0
  102. package/dist/signers/secure-enclave-backend.d.ts.map +1 -0
  103. package/dist/signers/secure-enclave-backend.js +201 -0
  104. package/dist/signers/secure-enclave-backend.js.map +1 -0
  105. package/dist/signers/secure-enclave-types.d.ts +98 -0
  106. package/dist/signers/secure-enclave-types.d.ts.map +1 -0
  107. package/dist/signers/secure-enclave-types.js +12 -0
  108. package/dist/signers/secure-enclave-types.js.map +1 -0
  109. package/dist/types.d.ts +371 -0
  110. package/dist/types.d.ts.map +1 -0
  111. package/dist/types.js +2 -0
  112. package/dist/types.js.map +1 -0
  113. package/package.json +85 -0
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Zod schemas for @prism-ing/wallet input validation.
3
+ *
4
+ * @remarks
5
+ * External data enters the system exactly once, through these schemas.
6
+ * After parsing, the inferred types are trusted everywhere downstream.
7
+ *
8
+ * @packageDocumentation
9
+ */
10
+ import { z } from 'zod';
11
+ // ---------------------------------------------------------------------------
12
+ // Primitives
13
+ // ---------------------------------------------------------------------------
14
+ /** Schema for an EVM address (0x-prefixed, 40 hex chars). */
15
+ export const AddressSchema = z
16
+ .string()
17
+ .regex(/^0x[a-fA-F0-9]{40}$/, 'Invalid EVM address');
18
+ /** Schema for a Solana public key (base58, 32-44 chars). */
19
+ export const SolanaPublicKeySchema = z
20
+ .string()
21
+ .regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/, 'Invalid Solana public key');
22
+ /** Schema for a positive bigint amount. */
23
+ export const PositiveBigIntSchema = z
24
+ .bigint()
25
+ .refine((n) => n > 0n, 'Amount must be positive');
26
+ /** Schema for basis points (0-10000). */
27
+ export const BpsSchema = z
28
+ .number()
29
+ .int()
30
+ .min(0)
31
+ .max(10_000);
32
+ // ---------------------------------------------------------------------------
33
+ // Wallet Config
34
+ // ---------------------------------------------------------------------------
35
+ export const SignerConfigSchema = z.object({
36
+ walletName: z.string().min(1, 'Wallet name is required'),
37
+ passphrase: z.string().optional(),
38
+ apiKey: z.string().optional(),
39
+ vaultPath: z.string().optional(),
40
+ });
41
+ export const RecoveryConfigSchema = z.object({
42
+ evm: z
43
+ .object({
44
+ guardians: z.array(AddressSchema).min(1),
45
+ threshold: z.number().int().min(1),
46
+ })
47
+ .optional(),
48
+ });
49
+ export const AccountTypeSchema = z.literal('kernel-v3.1-ecdsa');
50
+ export const WalletConfigSchema = z.object({
51
+ signer: SignerConfigSchema,
52
+ oneBalanceApiKey: z.string().min(1, 'OneBalance API key is required'),
53
+ accountType: AccountTypeSchema.optional().default('kernel-v3.1-ecdsa'),
54
+ chains: z.array(z.number().int().positive()).optional(),
55
+ recovery: RecoveryConfigSchema.optional(),
56
+ });
57
+ // ---------------------------------------------------------------------------
58
+ // Deposit
59
+ // ---------------------------------------------------------------------------
60
+ export const DepositParamsSchema = z.object({
61
+ token: AddressSchema,
62
+ amount: PositiveBigIntSchema,
63
+ chainId: z.number().int().positive(),
64
+ });
65
+ // ---------------------------------------------------------------------------
66
+ // Cross-Chain Swap
67
+ // ---------------------------------------------------------------------------
68
+ export const CrossChainSwapParamsSchema = z.object({
69
+ tokenIn: AddressSchema,
70
+ chainIn: z.number().int().positive(),
71
+ tokenOut: AddressSchema,
72
+ chainOut: z.number().int().positive(),
73
+ amount: PositiveBigIntSchema,
74
+ slippageBps: BpsSchema.optional().default(50),
75
+ });
76
+ //# sourceMappingURL=schemas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ import type { PrismSigner, SessionKeyHandle, SessionKeyManager, SessionKeyBackend, SpendPersistence } from './types.js';
2
+ import type { WalletError } from './errors.js';
3
+ /**
4
+ * Create a session key manager for the given root signer.
5
+ *
6
+ * @remarks
7
+ * The root signer is used as the underlying signing implementation.
8
+ * Session keys wrap it with policy enforcement — the root key's
9
+ * signing capability is gated by the session's constraints.
10
+ *
11
+ * If a {@link SessionKeyBackend} is provided, session keys are also
12
+ * registered on-chain via ZeroDev permission validators, providing
13
+ * contract-level enforcement in addition to client-side checks.
14
+ *
15
+ * @param rootSigner - The root PrismSigner to wrap.
16
+ * @param backend - Optional on-chain session key backend.
17
+ * @param persistence - Optional spend persistence adapter. Required when
18
+ * `maxTotalAmount` is set without a backend, to ensure cumulative caps
19
+ * survive process restarts.
20
+ * @returns A {@link SessionKeyManager} for creating and managing sessions.
21
+ */
22
+ export declare function createSessionKeyManager(rootSigner: PrismSigner, backend?: SessionKeyBackend, persistence?: SpendPersistence): SessionKeyManager;
23
+ /**
24
+ * Record a spend against a session key's cumulative total.
25
+ *
26
+ * @remarks
27
+ * Call this after a successful cross-chain execution to track
28
+ * cumulative spend against the session's {@link SessionKeyPolicy.maxTotalAmount}.
29
+ *
30
+ * @param manager - The session key manager.
31
+ * @param sessionId - The session key ID.
32
+ * @param amount - The amount spent (smallest unit, as string).
33
+ * @returns A WalletError if the spend would violate policy, undefined if ok.
34
+ */
35
+ export declare function recordSessionSpend(manager: SessionKeyManager, sessionId: string, amount: string): WalletError | undefined;
36
+ /**
37
+ * Validate an operation against a session key's policy before execution.
38
+ *
39
+ * @remarks
40
+ * Use this to pre-check whether a cross-chain operation would be allowed
41
+ * by the session key's policy. Call before `executeCrossChain` to fail fast.
42
+ *
43
+ * @param session - The session key handle.
44
+ * @param params - Operation parameters to validate.
45
+ * @returns A WalletError if the operation violates policy, undefined if allowed.
46
+ */
47
+ export declare function validateSessionOperation(session: SessionKeyHandle, params: {
48
+ readonly asset?: string;
49
+ readonly amount?: string;
50
+ readonly recipient?: string;
51
+ readonly chainId?: number;
52
+ }): WalletError | undefined;
53
+ //# sourceMappingURL=session-keys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-keys.d.ts","sourceRoot":"","sources":["../src/session-keys.ts"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EACV,WAAW,EAGX,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AA4I/C;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,WAAW,EACvB,OAAO,CAAC,EAAE,iBAAiB,EAC3B,WAAW,CAAC,EAAE,gBAAgB,GAC7B,iBAAiB,CAkInB;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,iBAAiB,EAC1B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb,WAAW,GAAG,SAAS,CAqCzB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE;IACN,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B,GACA,WAAW,GAAG,SAAS,CA6EzB"}
@@ -0,0 +1,345 @@
1
+ /**
2
+ * Session key manager — scoped, ephemeral signers with policy enforcement.
3
+ *
4
+ * @remarks
5
+ * Session keys wrap the root {@link PrismSigner} and enforce policy constraints
6
+ * (asset whitelist, amount caps, expiration, recipient restrictions) before
7
+ * delegating to the underlying signer. This limits blast radius if an agent
8
+ * process is compromised — the session key can only do what the policy allows.
9
+ *
10
+ * On-chain enforcement is optional via {@link SessionKeyBackend} (ZeroDev
11
+ * permission validators). Even without on-chain support, client-side policy
12
+ * enforcement provides defense-in-depth for agent workflows.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * import { createSessionKeyManager } from '@prism-ing/wallet';
17
+ *
18
+ * const manager = createSessionKeyManager(rootSigner);
19
+ *
20
+ * const session = manager.createSessionKey({
21
+ * expiresAt: Math.floor(Date.now() / 1000) + 3600, // 1 hour
22
+ * allowedAssets: ['ob:usdc'],
23
+ * maxAmountPerOp: '1000000000', // 1000 USDC (6 decimals)
24
+ * maxTotalAmount: '5000000000', // 5000 USDC cumulative
25
+ * allowedChains: [8453, 42161], // Base + Arbitrum only
26
+ * });
27
+ *
28
+ * // Use session.signer wherever PrismSigner is accepted
29
+ * const result = await executeCrossChain(client, session.signer, params, accounts);
30
+ *
31
+ * // Revoke when done
32
+ * manager.revokeSessionKey(session.sessionId);
33
+ * ```
34
+ *
35
+ * @packageDocumentation
36
+ */
37
+ import { randomBytes, bytesToHex } from '@noble/hashes/utils';
38
+ import { walletErrors } from './errors.js';
39
+ /**
40
+ * Module-level registry for session state. Allows `recordSessionSpend` to
41
+ * mutate internal state without exposing it on the public interface.
42
+ * @internal
43
+ */
44
+ const stateRegistry = new WeakMap();
45
+ // ---------------------------------------------------------------------------
46
+ // Policy Enforcement
47
+ // ---------------------------------------------------------------------------
48
+ /**
49
+ * Validate an operation against a session key policy.
50
+ * Returns a WalletError if the policy is violated, undefined if ok.
51
+ *
52
+ * @internal
53
+ */
54
+ function checkPolicy(sessionId, policy, state, asset, amount, recipient, chainId) {
55
+ // Check revocation
56
+ if (state.revoked) {
57
+ return walletErrors.sessionKeyExpired(sessionId, 0);
58
+ }
59
+ // Check expiration
60
+ const nowSec = Math.floor(Date.now() / 1000);
61
+ if (nowSec >= policy.expiresAt) {
62
+ return walletErrors.sessionKeyExpired(sessionId, policy.expiresAt);
63
+ }
64
+ // Check allowed assets
65
+ if (asset !== undefined &&
66
+ policy.allowedAssets !== undefined &&
67
+ policy.allowedAssets.length > 0 &&
68
+ !policy.allowedAssets.includes(asset)) {
69
+ return walletErrors.sessionKeyPolicyViolation(sessionId, `Asset "${asset}" not in allowed list: [${policy.allowedAssets.join(', ')}]`);
70
+ }
71
+ // Check per-operation amount cap
72
+ if (amount !== undefined && policy.maxAmountPerOp !== undefined) {
73
+ const opAmount = BigInt(amount);
74
+ const maxPerOp = BigInt(policy.maxAmountPerOp);
75
+ if (opAmount > maxPerOp) {
76
+ return walletErrors.sessionKeyPolicyViolation(sessionId, `Amount ${amount} exceeds per-operation cap ${policy.maxAmountPerOp}`);
77
+ }
78
+ }
79
+ // Check cumulative total
80
+ if (amount !== undefined && policy.maxTotalAmount !== undefined) {
81
+ const opAmount = BigInt(amount);
82
+ const maxTotal = BigInt(policy.maxTotalAmount);
83
+ if (state.totalSpent + opAmount > maxTotal) {
84
+ return walletErrors.sessionKeyPolicyViolation(sessionId, `Cumulative spend ${String(state.totalSpent + opAmount)} would exceed total cap ${policy.maxTotalAmount}`);
85
+ }
86
+ }
87
+ // Check allowed recipients (case-insensitive for EVM addresses)
88
+ if (recipient !== undefined &&
89
+ policy.allowedRecipients !== undefined &&
90
+ policy.allowedRecipients.length > 0) {
91
+ const recipientLower = recipient.toLowerCase();
92
+ const allowed = policy.allowedRecipients.some((r) => r.toLowerCase() === recipientLower);
93
+ if (!allowed) {
94
+ return walletErrors.sessionKeyPolicyViolation(sessionId, `Recipient "${recipient}" not in allowed list`);
95
+ }
96
+ }
97
+ // Check allowed chains
98
+ if (chainId !== undefined &&
99
+ policy.allowedChains !== undefined &&
100
+ policy.allowedChains.length > 0 &&
101
+ !policy.allowedChains.includes(chainId)) {
102
+ return walletErrors.sessionKeyPolicyViolation(sessionId, `Chain ${chainId} not in allowed list: [${policy.allowedChains.join(', ')}]`);
103
+ }
104
+ return undefined;
105
+ }
106
+ /**
107
+ * Extract chain ID from EIP-712 typed data domain if present.
108
+ * @internal
109
+ */
110
+ function extractChainId(payload) {
111
+ const chainId = payload.domain.chainId;
112
+ if (typeof chainId === 'number')
113
+ return chainId;
114
+ if (typeof chainId === 'string')
115
+ return parseInt(chainId, 10) || undefined;
116
+ return undefined;
117
+ }
118
+ // ---------------------------------------------------------------------------
119
+ // Factory
120
+ // ---------------------------------------------------------------------------
121
+ /**
122
+ * Create a session key manager for the given root signer.
123
+ *
124
+ * @remarks
125
+ * The root signer is used as the underlying signing implementation.
126
+ * Session keys wrap it with policy enforcement — the root key's
127
+ * signing capability is gated by the session's constraints.
128
+ *
129
+ * If a {@link SessionKeyBackend} is provided, session keys are also
130
+ * registered on-chain via ZeroDev permission validators, providing
131
+ * contract-level enforcement in addition to client-side checks.
132
+ *
133
+ * @param rootSigner - The root PrismSigner to wrap.
134
+ * @param backend - Optional on-chain session key backend.
135
+ * @param persistence - Optional spend persistence adapter. Required when
136
+ * `maxTotalAmount` is set without a backend, to ensure cumulative caps
137
+ * survive process restarts.
138
+ * @returns A {@link SessionKeyManager} for creating and managing sessions.
139
+ */
140
+ export function createSessionKeyManager(rootSigner, backend, persistence) {
141
+ const sessions = new Map();
142
+ // Register in module-level registry so recordSessionSpend can access state
143
+ // (set after manager is created, below)
144
+ const manager = {
145
+ createSessionKey(policy) {
146
+ // Enforce: if maxTotalAmount is set, require persistence or on-chain backend
147
+ if (policy.maxTotalAmount !== undefined &&
148
+ backend === undefined &&
149
+ persistence === undefined) {
150
+ throw new Error('maxTotalAmount requires either a SessionKeyBackend (on-chain enforcement) ' +
151
+ 'or SpendPersistence adapter. Without enforcement, cumulative spend caps ' +
152
+ 'reset on process restart. Remove maxTotalAmount or provide an enforcement backend.');
153
+ }
154
+ const sessionId = bytesToHex(randomBytes(16));
155
+ const state = { totalSpent: 0n, revoked: false };
156
+ const sessionSigner = {
157
+ evmAddress: rootSigner.evmAddress,
158
+ solanaAddress: rootSigner.solanaAddress,
159
+ async signMessage(message) {
160
+ const violation = checkPolicy(sessionId, policy, state);
161
+ if (violation !== undefined) {
162
+ throw new Error(`Session key error: ${violation.code}`);
163
+ }
164
+ return rootSigner.signMessage(message);
165
+ },
166
+ async signTypedData(payload) {
167
+ const chainId = extractChainId(payload);
168
+ const violation = checkPolicy(sessionId, policy, state, undefined, undefined, undefined, chainId);
169
+ if (violation !== undefined) {
170
+ throw new Error(`Session key error: ${violation.code}`);
171
+ }
172
+ return rootSigner.signTypedData(payload);
173
+ },
174
+ async signTransaction(tx) {
175
+ const violation = checkPolicy(sessionId, policy, state);
176
+ if (violation !== undefined) {
177
+ throw new Error(`Session key error: ${violation.code}`);
178
+ }
179
+ return rootSigner.signTransaction(tx);
180
+ },
181
+ };
182
+ // Start on-chain registration (non-blocking, but awaitable)
183
+ const onChainRegistration = backend !== undefined
184
+ ? backend.registerSessionKey(rootSigner.evmAddress, policy)
185
+ : undefined;
186
+ // Load persisted spend state if persistence is available
187
+ const initialized = persistence !== undefined
188
+ ? persistence.load(sessionId).then((loaded) => { state.totalSpent = loaded; })
189
+ : undefined;
190
+ const handle = {
191
+ sessionId,
192
+ signer: sessionSigner,
193
+ policy,
194
+ get totalSpent() {
195
+ return String(state.totalSpent);
196
+ },
197
+ get isActive() {
198
+ if (state.revoked)
199
+ return false;
200
+ const nowSec = Math.floor(Date.now() / 1000);
201
+ return nowSec < policy.expiresAt;
202
+ },
203
+ onChainRegistration,
204
+ ...(initialized !== undefined ? { initialized } : {}),
205
+ };
206
+ sessions.set(sessionId, { handle, state });
207
+ return handle;
208
+ },
209
+ revokeSessionKey(sessionId) {
210
+ const entry = sessions.get(sessionId);
211
+ if (entry === undefined)
212
+ return false;
213
+ entry.state.revoked = true;
214
+ sessions.delete(sessionId);
215
+ // Fire-and-forget on-chain revocation if backend provided
216
+ if (backend !== undefined) {
217
+ void backend.revokeSessionKey(rootSigner.evmAddress);
218
+ }
219
+ return true;
220
+ },
221
+ getActiveSessions() {
222
+ const active = [];
223
+ for (const entry of sessions.values()) {
224
+ if (entry.handle.isActive) {
225
+ active.push(entry.handle);
226
+ }
227
+ }
228
+ return active;
229
+ },
230
+ getSession(sessionId) {
231
+ const entry = sessions.get(sessionId);
232
+ if (entry === undefined)
233
+ return undefined;
234
+ return entry.handle;
235
+ },
236
+ };
237
+ const registry = persistence !== undefined
238
+ ? { sessions, persistence }
239
+ : { sessions };
240
+ stateRegistry.set(manager, registry);
241
+ return manager;
242
+ }
243
+ // ---------------------------------------------------------------------------
244
+ // Session-Aware Cross-Chain Execution
245
+ // ---------------------------------------------------------------------------
246
+ /**
247
+ * Record a spend against a session key's cumulative total.
248
+ *
249
+ * @remarks
250
+ * Call this after a successful cross-chain execution to track
251
+ * cumulative spend against the session's {@link SessionKeyPolicy.maxTotalAmount}.
252
+ *
253
+ * @param manager - The session key manager.
254
+ * @param sessionId - The session key ID.
255
+ * @param amount - The amount spent (smallest unit, as string).
256
+ * @returns A WalletError if the spend would violate policy, undefined if ok.
257
+ */
258
+ export function recordSessionSpend(manager, sessionId, amount) {
259
+ const registry = stateRegistry.get(manager);
260
+ if (registry === undefined) {
261
+ return walletErrors.sessionKeyExpired(sessionId, 0);
262
+ }
263
+ const entry = registry.sessions.get(sessionId);
264
+ if (entry === undefined) {
265
+ return walletErrors.sessionKeyExpired(sessionId, 0);
266
+ }
267
+ if (!entry.handle.isActive) {
268
+ return walletErrors.sessionKeyExpired(sessionId, entry.handle.policy.expiresAt);
269
+ }
270
+ const opAmount = BigInt(amount);
271
+ // Check cumulative total before recording
272
+ if (entry.handle.policy.maxTotalAmount !== undefined) {
273
+ const totalAfter = entry.state.totalSpent + opAmount;
274
+ if (totalAfter > BigInt(entry.handle.policy.maxTotalAmount)) {
275
+ return walletErrors.sessionKeyPolicyViolation(sessionId, `Cumulative spend ${String(totalAfter)} would exceed total cap ${entry.handle.policy.maxTotalAmount}`);
276
+ }
277
+ }
278
+ // Actually increment the spend counter
279
+ entry.state.totalSpent += opAmount;
280
+ // Persist if adapter available (fire-and-forget)
281
+ if (registry.persistence !== undefined) {
282
+ void registry.persistence.save(sessionId, entry.state.totalSpent);
283
+ }
284
+ return undefined;
285
+ }
286
+ /**
287
+ * Validate an operation against a session key's policy before execution.
288
+ *
289
+ * @remarks
290
+ * Use this to pre-check whether a cross-chain operation would be allowed
291
+ * by the session key's policy. Call before `executeCrossChain` to fail fast.
292
+ *
293
+ * @param session - The session key handle.
294
+ * @param params - Operation parameters to validate.
295
+ * @returns A WalletError if the operation violates policy, undefined if allowed.
296
+ */
297
+ export function validateSessionOperation(session, params) {
298
+ if (!session.isActive) {
299
+ return walletErrors.sessionKeyExpired(session.sessionId, session.policy.expiresAt);
300
+ }
301
+ // Check expiration
302
+ const nowSec = Math.floor(Date.now() / 1000);
303
+ if (nowSec >= session.policy.expiresAt) {
304
+ return walletErrors.sessionKeyExpired(session.sessionId, session.policy.expiresAt);
305
+ }
306
+ // Check allowed assets
307
+ if (params.asset !== undefined &&
308
+ session.policy.allowedAssets !== undefined &&
309
+ session.policy.allowedAssets.length > 0 &&
310
+ !session.policy.allowedAssets.includes(params.asset)) {
311
+ return walletErrors.sessionKeyPolicyViolation(session.sessionId, `Asset "${params.asset}" not in allowed list: [${session.policy.allowedAssets.join(', ')}]`);
312
+ }
313
+ // Check per-operation amount cap
314
+ if (params.amount !== undefined && session.policy.maxAmountPerOp !== undefined) {
315
+ if (BigInt(params.amount) > BigInt(session.policy.maxAmountPerOp)) {
316
+ return walletErrors.sessionKeyPolicyViolation(session.sessionId, `Amount ${params.amount} exceeds per-operation cap ${session.policy.maxAmountPerOp}`);
317
+ }
318
+ }
319
+ // Check cumulative total
320
+ if (params.amount !== undefined && session.policy.maxTotalAmount !== undefined) {
321
+ const totalAfter = BigInt(session.totalSpent) + BigInt(params.amount);
322
+ if (totalAfter > BigInt(session.policy.maxTotalAmount)) {
323
+ return walletErrors.sessionKeyPolicyViolation(session.sessionId, `Cumulative spend ${String(totalAfter)} would exceed total cap ${session.policy.maxTotalAmount}`);
324
+ }
325
+ }
326
+ // Check allowed recipients (case-insensitive for EVM addresses)
327
+ if (params.recipient !== undefined &&
328
+ session.policy.allowedRecipients !== undefined &&
329
+ session.policy.allowedRecipients.length > 0) {
330
+ const recipientLower = params.recipient.toLowerCase();
331
+ const allowed = session.policy.allowedRecipients.some((r) => r.toLowerCase() === recipientLower);
332
+ if (!allowed) {
333
+ return walletErrors.sessionKeyPolicyViolation(session.sessionId, `Recipient "${params.recipient}" not in allowed list`);
334
+ }
335
+ }
336
+ // Check allowed chains
337
+ if (params.chainId !== undefined &&
338
+ session.policy.allowedChains !== undefined &&
339
+ session.policy.allowedChains.length > 0 &&
340
+ !session.policy.allowedChains.includes(params.chainId)) {
341
+ return walletErrors.sessionKeyPolicyViolation(session.sessionId, `Chain ${params.chainId} not in allowed list: [${session.policy.allowedChains.join(', ')}]`);
342
+ }
343
+ return undefined;
344
+ }
345
+ //# sourceMappingURL=session-keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-keys.js","sourceRoot":"","sources":["../src/session-keys.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { SigningBackend } from '../signers/ows-adapter.js';
2
+ /**
3
+ * Create a Node.js software signing backend.
4
+ *
5
+ * @remarks
6
+ * Generates secp256k1 (EVM) and ed25519 (Solana) key pairs using
7
+ * cryptographically secure randomness from `@noble/hashes`.
8
+ * Private key material is held in memory only — never serialized or exported.
9
+ */
10
+ export declare function createNodeSigningBackend(): SigningBackend;
11
+ //# sourceMappingURL=node-signing-backend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-signing-backend.d.ts","sourceRoot":"","sources":["../../src/signers/node-signing-backend.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,cAAc,EAAc,MAAM,2BAA2B,CAAC;AAgD5E;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,IAAI,cAAc,CA2FzD"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Node.js software signing backend for OWS.
3
+ *
4
+ * @remarks
5
+ * Uses `@noble/curves` for secp256k1 (EVM) and ed25519 (Solana) signing.
6
+ * Private key material is held in memory and never exposed via public types.
7
+ * For production iOS builds, the Secure Enclave backend replaces this.
8
+ *
9
+ * @internal
10
+ */
11
+ import { secp256k1 } from '@noble/curves/secp256k1';
12
+ import { ed25519 } from '@noble/curves/ed25519';
13
+ import { keccak_256 } from '@noble/hashes/sha3';
14
+ import { bytesToHex, randomBytes } from '@noble/hashes/utils';
15
+ import { Ok, Err } from '../result.js';
16
+ import { walletErrors } from '../errors.js';
17
+ import { base58Encode } from '../internal/base58.js';
18
+ import { hashTypedData, personalSignHash, isSolanaTransaction } from '../internal/eip712.js';
19
+ /** Overwrite a Uint8Array with zeros to clear key material from memory. */
20
+ function zeroUint8Array(arr) {
21
+ arr.fill(0);
22
+ }
23
+ // ---------------------------------------------------------------------------
24
+ // EVM Address Derivation
25
+ // ---------------------------------------------------------------------------
26
+ function deriveEvmAddress(privateKey) {
27
+ const publicKey = secp256k1.getPublicKey(privateKey, false);
28
+ // Drop the 0x04 prefix byte, hash the remaining 64 bytes
29
+ const hash = keccak_256(publicKey.subarray(1));
30
+ // Take last 20 bytes
31
+ const addressBytes = hash.subarray(12);
32
+ return `0x${bytesToHex(addressBytes)}`;
33
+ }
34
+ // ---------------------------------------------------------------------------
35
+ // Signature Encoding
36
+ // ---------------------------------------------------------------------------
37
+ function encodeSecp256k1Signature(sig) {
38
+ const r = sig.r.toString(16).padStart(64, '0');
39
+ const s = sig.s.toString(16).padStart(64, '0');
40
+ const v = (sig.recovery + 27).toString(16).padStart(2, '0');
41
+ return `0x${r}${s}${v}`;
42
+ }
43
+ // ---------------------------------------------------------------------------
44
+ // Factory
45
+ // ---------------------------------------------------------------------------
46
+ /**
47
+ * Create a Node.js software signing backend.
48
+ *
49
+ * @remarks
50
+ * Generates secp256k1 (EVM) and ed25519 (Solana) key pairs using
51
+ * cryptographically secure randomness from `@noble/hashes`.
52
+ * Private key material is held in memory only — never serialized or exported.
53
+ */
54
+ export function createNodeSigningBackend() {
55
+ const keyStore = new Map();
56
+ const backend = {
57
+ async generateKeyPair() {
58
+ const evmPrivateKey = randomBytes(32);
59
+ const solanaPrivateKey = randomBytes(32);
60
+ const evmAddress = deriveEvmAddress(evmPrivateKey);
61
+ const solanaPubkey = ed25519.getPublicKey(solanaPrivateKey);
62
+ const solanaAddress = base58Encode(solanaPubkey);
63
+ keyStore.set(evmAddress, { evmPrivateKey, solanaPrivateKey });
64
+ return Ok({
65
+ evmAddress,
66
+ solanaAddress,
67
+ platform: 'node',
68
+ });
69
+ },
70
+ async signMessage(keys, message) {
71
+ const stored = keyStore.get(keys.evmAddress);
72
+ if (!stored)
73
+ return Err(walletErrors.keyNotFound(keys.evmAddress));
74
+ const hash = personalSignHash(message);
75
+ const sig = secp256k1.sign(hash, stored.evmPrivateKey);
76
+ return Ok(encodeSecp256k1Signature(sig));
77
+ },
78
+ async signTypedData(keys, payload) {
79
+ const stored = keyStore.get(keys.evmAddress);
80
+ if (!stored)
81
+ return Err(walletErrors.keyNotFound(keys.evmAddress));
82
+ const hash = hashTypedData(payload);
83
+ const sig = secp256k1.sign(hash, stored.evmPrivateKey);
84
+ return Ok(encodeSecp256k1Signature(sig));
85
+ },
86
+ async signTransaction(keys, tx) {
87
+ const stored = keyStore.get(keys.evmAddress);
88
+ if (!stored)
89
+ return Err(walletErrors.keyNotFound(keys.evmAddress));
90
+ if (!isSolanaTransaction(tx)) {
91
+ return Err(walletErrors.signingRejected('Unsupported transaction type'));
92
+ }
93
+ const messageBytes = tx.message.serialize();
94
+ const signature = ed25519.sign(messageBytes, stored.solanaPrivateKey);
95
+ tx.signatures[0] = signature;
96
+ return Ok(tx);
97
+ },
98
+ async withAuthContext(_prompt, fn) {
99
+ return Ok(await fn());
100
+ },
101
+ destroy() {
102
+ for (const stored of keyStore.values()) {
103
+ zeroUint8Array(stored.evmPrivateKey);
104
+ zeroUint8Array(stored.solanaPrivateKey);
105
+ }
106
+ keyStore.clear();
107
+ },
108
+ removeKeyPair(evmAddress) {
109
+ const stored = keyStore.get(evmAddress);
110
+ if (!stored)
111
+ return Err(walletErrors.keyNotFound(evmAddress));
112
+ zeroUint8Array(stored.evmPrivateKey);
113
+ zeroUint8Array(stored.solanaPrivateKey);
114
+ keyStore.delete(evmAddress);
115
+ return Ok(undefined);
116
+ },
117
+ };
118
+ return backend;
119
+ }
120
+ //# sourceMappingURL=node-signing-backend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-signing-backend.js","sourceRoot":"","sources":["../../src/signers/node-signing-backend.ts"],"names":[],"mappings":"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"}