@0xsequence/wallet-core 0.0.0-20250520201059

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 (106) hide show
  1. package/.turbo/turbo-build.log +5 -0
  2. package/CHANGELOG.md +9 -0
  3. package/LICENSE +202 -0
  4. package/dist/envelope.d.ts +34 -0
  5. package/dist/envelope.d.ts.map +1 -0
  6. package/dist/envelope.js +96 -0
  7. package/dist/index.d.ts +6 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +5 -0
  10. package/dist/relayer/index.d.ts +4 -0
  11. package/dist/relayer/index.d.ts.map +1 -0
  12. package/dist/relayer/index.js +3 -0
  13. package/dist/relayer/local.d.ts +28 -0
  14. package/dist/relayer/local.d.ts.map +1 -0
  15. package/dist/relayer/local.js +101 -0
  16. package/dist/relayer/pk-relayer.d.ts +18 -0
  17. package/dist/relayer/pk-relayer.d.ts.map +1 -0
  18. package/dist/relayer/pk-relayer.js +88 -0
  19. package/dist/relayer/relayer.d.ts +39 -0
  20. package/dist/relayer/relayer.d.ts.map +1 -0
  21. package/dist/relayer/relayer.js +1 -0
  22. package/dist/signers/index.d.ts +23 -0
  23. package/dist/signers/index.d.ts.map +1 -0
  24. package/dist/signers/index.js +10 -0
  25. package/dist/signers/passkey.d.ts +41 -0
  26. package/dist/signers/passkey.d.ts.map +1 -0
  27. package/dist/signers/passkey.js +196 -0
  28. package/dist/signers/pk/encrypted.d.ts +37 -0
  29. package/dist/signers/pk/encrypted.d.ts.map +1 -0
  30. package/dist/signers/pk/encrypted.js +123 -0
  31. package/dist/signers/pk/index.d.ts +35 -0
  32. package/dist/signers/pk/index.d.ts.map +1 -0
  33. package/dist/signers/pk/index.js +51 -0
  34. package/dist/signers/session/explicit.d.ts +18 -0
  35. package/dist/signers/session/explicit.d.ts.map +1 -0
  36. package/dist/signers/session/explicit.js +126 -0
  37. package/dist/signers/session/implicit.d.ts +20 -0
  38. package/dist/signers/session/implicit.d.ts.map +1 -0
  39. package/dist/signers/session/implicit.js +120 -0
  40. package/dist/signers/session/index.d.ts +4 -0
  41. package/dist/signers/session/index.d.ts.map +1 -0
  42. package/dist/signers/session/index.js +3 -0
  43. package/dist/signers/session/session.d.ts +11 -0
  44. package/dist/signers/session/session.d.ts.map +1 -0
  45. package/dist/signers/session/session.js +1 -0
  46. package/dist/signers/session-manager.d.ts +33 -0
  47. package/dist/signers/session-manager.d.ts.map +1 -0
  48. package/dist/signers/session-manager.js +181 -0
  49. package/dist/state/cached.d.ts +59 -0
  50. package/dist/state/cached.d.ts.map +1 -0
  51. package/dist/state/cached.js +157 -0
  52. package/dist/state/index.d.ts +61 -0
  53. package/dist/state/index.d.ts.map +1 -0
  54. package/dist/state/index.js +4 -0
  55. package/dist/state/local/index.d.ts +98 -0
  56. package/dist/state/local/index.d.ts.map +1 -0
  57. package/dist/state/local/index.js +247 -0
  58. package/dist/state/local/indexed-db.d.ts +41 -0
  59. package/dist/state/local/indexed-db.d.ts.map +1 -0
  60. package/dist/state/local/indexed-db.js +149 -0
  61. package/dist/state/local/memory.d.ts +41 -0
  62. package/dist/state/local/memory.d.ts.map +1 -0
  63. package/dist/state/local/memory.js +77 -0
  64. package/dist/state/remote/dev-http.d.ts +57 -0
  65. package/dist/state/remote/dev-http.d.ts.map +1 -0
  66. package/dist/state/remote/dev-http.js +162 -0
  67. package/dist/state/remote/index.d.ts +2 -0
  68. package/dist/state/remote/index.d.ts.map +1 -0
  69. package/dist/state/remote/index.js +1 -0
  70. package/dist/state/utils.d.ts +12 -0
  71. package/dist/state/utils.d.ts.map +1 -0
  72. package/dist/state/utils.js +29 -0
  73. package/dist/wallet.d.ts +58 -0
  74. package/dist/wallet.d.ts.map +1 -0
  75. package/dist/wallet.js +306 -0
  76. package/package.json +33 -0
  77. package/src/envelope.ts +148 -0
  78. package/src/index.ts +6 -0
  79. package/src/relayer/index.ts +3 -0
  80. package/src/relayer/local.ts +125 -0
  81. package/src/relayer/pk-relayer.ts +110 -0
  82. package/src/relayer/relayer.ts +52 -0
  83. package/src/signers/index.ts +44 -0
  84. package/src/signers/passkey.ts +284 -0
  85. package/src/signers/pk/encrypted.ts +153 -0
  86. package/src/signers/pk/index.ts +77 -0
  87. package/src/signers/session/explicit.ts +173 -0
  88. package/src/signers/session/implicit.ts +145 -0
  89. package/src/signers/session/index.ts +3 -0
  90. package/src/signers/session/session.ts +26 -0
  91. package/src/signers/session-manager.ts +241 -0
  92. package/src/state/cached.ts +233 -0
  93. package/src/state/index.ts +85 -0
  94. package/src/state/local/index.ts +422 -0
  95. package/src/state/local/indexed-db.ts +204 -0
  96. package/src/state/local/memory.ts +126 -0
  97. package/src/state/remote/dev-http.ts +253 -0
  98. package/src/state/remote/index.ts +1 -0
  99. package/src/state/utils.ts +50 -0
  100. package/src/wallet.ts +390 -0
  101. package/test/constants.ts +15 -0
  102. package/test/session-manager.test.ts +451 -0
  103. package/test/setup.ts +63 -0
  104. package/test/wallet.test.ts +90 -0
  105. package/tsconfig.json +10 -0
  106. package/vitest.config.ts +9 -0
@@ -0,0 +1,126 @@
1
+ import { Context, Payload, Signature, Config, GenericTree } from '@0xsequence/wallet-primitives'
2
+ import { Address, Hex } from 'ox'
3
+ import { Store } from './index.js'
4
+
5
+ export class MemoryStore implements Store {
6
+ private configs = new Map<`0x${string}`, Config.Config>()
7
+ private counterfactualWallets = new Map<`0x${string}`, { imageHash: Hex.Hex; context: Context.Context }>()
8
+ private payloads = new Map<`0x${string}`, { content: Payload.Parented; chainId: bigint; wallet: Address.Address }>()
9
+ private signerSubdigests = new Map<string, Set<string>>()
10
+ private signatures = new Map<`0x${string}`, Signature.SignatureOfSignerLeaf>()
11
+
12
+ private sapientSignerSubdigests = new Map<string, Set<string>>()
13
+ private sapientSignatures = new Map<`0x${string}`, Signature.SignatureOfSapientSignerLeaf>()
14
+
15
+ private trees = new Map<`0x${string}`, GenericTree.Tree>()
16
+
17
+ private getSignatureKey(signer: Address.Address, subdigest: Hex.Hex): string {
18
+ return `${signer.toLowerCase()}-${subdigest.toLowerCase()}`
19
+ }
20
+
21
+ private getSapientSignatureKey(signer: Address.Address, subdigest: Hex.Hex, imageHash: Hex.Hex): string {
22
+ return `${signer.toLowerCase()}-${imageHash.toLowerCase()}-${subdigest.toLowerCase()}`
23
+ }
24
+
25
+ async loadConfig(imageHash: Hex.Hex): Promise<Config.Config | undefined> {
26
+ return this.configs.get(imageHash.toLowerCase() as `0x${string}`)
27
+ }
28
+
29
+ async saveConfig(imageHash: Hex.Hex, config: Config.Config): Promise<void> {
30
+ this.configs.set(imageHash.toLowerCase() as `0x${string}`, config)
31
+ }
32
+
33
+ async loadCounterfactualWallet(
34
+ wallet: Address.Address,
35
+ ): Promise<{ imageHash: Hex.Hex; context: Context.Context } | undefined> {
36
+ return this.counterfactualWallets.get(wallet.toLowerCase() as `0x${string}`)
37
+ }
38
+
39
+ async saveCounterfactualWallet(wallet: Address.Address, imageHash: Hex.Hex, context: Context.Context): Promise<void> {
40
+ this.counterfactualWallets.set(wallet.toLowerCase() as `0x${string}`, { imageHash, context })
41
+ }
42
+
43
+ async loadPayloadOfSubdigest(
44
+ subdigest: Hex.Hex,
45
+ ): Promise<{ content: Payload.Parented; chainId: bigint; wallet: Address.Address } | undefined> {
46
+ return this.payloads.get(subdigest.toLowerCase() as `0x${string}`)
47
+ }
48
+
49
+ async savePayloadOfSubdigest(
50
+ subdigest: Hex.Hex,
51
+ payload: { content: Payload.Parented; chainId: bigint; wallet: Address.Address },
52
+ ): Promise<void> {
53
+ this.payloads.set(subdigest.toLowerCase() as `0x${string}`, payload)
54
+ }
55
+
56
+ async loadSubdigestsOfSigner(signer: Address.Address): Promise<Hex.Hex[]> {
57
+ const subdigests = this.signerSubdigests.get(signer.toLowerCase() as `0x${string}`)
58
+ return subdigests ? Array.from(subdigests).map((s) => s as Hex.Hex) : []
59
+ }
60
+
61
+ async loadSignatureOfSubdigest(
62
+ signer: Address.Address,
63
+ subdigest: Hex.Hex,
64
+ ): Promise<Signature.SignatureOfSignerLeaf | undefined> {
65
+ const key = this.getSignatureKey(signer, subdigest)
66
+ return this.signatures.get(key as `0x${string}`)
67
+ }
68
+
69
+ async saveSignatureOfSubdigest(
70
+ signer: Address.Address,
71
+ subdigest: Hex.Hex,
72
+ signature: Signature.SignatureOfSignerLeaf,
73
+ ): Promise<void> {
74
+ const key = this.getSignatureKey(signer, subdigest)
75
+ this.signatures.set(key as `0x${string}`, signature)
76
+
77
+ const signerKey = signer.toLowerCase()
78
+ const subdigestKey = subdigest.toLowerCase()
79
+
80
+ if (!this.signerSubdigests.has(signerKey)) {
81
+ this.signerSubdigests.set(signerKey, new Set())
82
+ }
83
+ this.signerSubdigests.get(signerKey)!.add(subdigestKey)
84
+ }
85
+
86
+ async loadSubdigestsOfSapientSigner(signer: Address.Address, imageHash: Hex.Hex): Promise<Hex.Hex[]> {
87
+ const key = `${signer.toLowerCase()}-${imageHash.toLowerCase()}`
88
+ const subdigests = this.sapientSignerSubdigests.get(key)
89
+ return subdigests ? Array.from(subdigests).map((s) => s as Hex.Hex) : []
90
+ }
91
+
92
+ async loadSapientSignatureOfSubdigest(
93
+ signer: Address.Address,
94
+ subdigest: Hex.Hex,
95
+ imageHash: Hex.Hex,
96
+ ): Promise<Signature.SignatureOfSapientSignerLeaf | undefined> {
97
+ const key = this.getSapientSignatureKey(signer, subdigest, imageHash)
98
+ return this.sapientSignatures.get(key as `0x${string}`)
99
+ }
100
+
101
+ async saveSapientSignatureOfSubdigest(
102
+ signer: Address.Address,
103
+ subdigest: Hex.Hex,
104
+ imageHash: Hex.Hex,
105
+ signature: Signature.SignatureOfSapientSignerLeaf,
106
+ ): Promise<void> {
107
+ const key = this.getSapientSignatureKey(signer, subdigest, imageHash)
108
+ this.sapientSignatures.set(key as `0x${string}`, signature)
109
+
110
+ const signerKey = `${signer.toLowerCase()}-${imageHash.toLowerCase()}`
111
+ const subdigestKey = subdigest.toLowerCase()
112
+
113
+ if (!this.sapientSignerSubdigests.has(signerKey)) {
114
+ this.sapientSignerSubdigests.set(signerKey, new Set())
115
+ }
116
+ this.sapientSignerSubdigests.get(signerKey)!.add(subdigestKey)
117
+ }
118
+
119
+ async loadTree(rootHash: Hex.Hex): Promise<GenericTree.Tree | undefined> {
120
+ return this.trees.get(rootHash.toLowerCase() as `0x${string}`)
121
+ }
122
+
123
+ async saveTree(rootHash: Hex.Hex, tree: GenericTree.Tree): Promise<void> {
124
+ this.trees.set(rootHash.toLowerCase() as `0x${string}`, tree)
125
+ }
126
+ }
@@ -0,0 +1,253 @@
1
+ import { Address, Hex } from 'ox'
2
+ import { Config, Context, GenericTree, Payload, Signature, Utils } from '@0xsequence/wallet-primitives'
3
+ import { Provider } from '../index.js'
4
+
5
+ export class DevHttpProvider implements Provider {
6
+ private readonly baseUrl: string
7
+
8
+ constructor(baseUrl: string) {
9
+ // Remove trailing slash if present
10
+ this.baseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl
11
+ }
12
+
13
+ private async request<T>(method: 'GET' | 'POST', path: string, body?: any): Promise<T> {
14
+ const url = `${this.baseUrl}${path}`
15
+ const options: RequestInit = {
16
+ method,
17
+ headers: {},
18
+ }
19
+
20
+ if (body && method === 'POST') {
21
+ options.headers = { 'Content-Type': 'application/json' }
22
+ options.body = Utils.toJSON(body)
23
+ }
24
+
25
+ let response: Response
26
+ try {
27
+ response = await fetch(url, options)
28
+ } catch (networkError) {
29
+ // Handle immediate network errors (e.g., DNS resolution failure, refused connection)
30
+ console.error(`Network error during ${method} request to ${url}:`, networkError)
31
+ throw networkError // Re-throw network errors
32
+ }
33
+
34
+ // --- Error Handling for HTTP Status ---
35
+ if (!response.ok) {
36
+ let errorPayload: any = { message: `HTTP error! Status: ${response.status}` }
37
+ try {
38
+ const errorText = await response.text()
39
+ const errorJson = await Utils.fromJSON(errorText)
40
+ errorPayload = { ...errorPayload, ...errorJson }
41
+ } catch (e) {
42
+ try {
43
+ // If JSON parsing fails, try getting text for better error message
44
+ const errorText = await response.text()
45
+ errorPayload.body = errorText
46
+ } catch (textErr) {
47
+ // Ignore if reading text also fails
48
+ }
49
+ }
50
+ console.error('HTTP Request Failed:', errorPayload)
51
+ throw new Error(errorPayload.message || `Request failed for ${method} ${path} with status ${response.status}`)
52
+ }
53
+
54
+ // --- Response Body Handling (with fix for empty body) ---
55
+ try {
56
+ // Handle cases where POST might return 201/204 No Content
57
+ // 204 should definitely have no body. 201 might or might not.
58
+ if (response.status === 204) {
59
+ return undefined as T // No content expected
60
+ }
61
+ if (response.status === 201 && method === 'POST') {
62
+ // Attempt to parse JSON (e.g., for { success: true }), but handle empty body gracefully
63
+ const text = await response.clone().text() // Clone and check text first
64
+ if (text.trim() === '') {
65
+ return undefined as T // Treat empty 201 as success with no specific return data
66
+ }
67
+ // If not empty, try parsing JSON
68
+ const responseText = await response.text()
69
+ return (await Utils.fromJSON(responseText)) as T
70
+ }
71
+
72
+ // For 200 OK or other success statuses expecting a body
73
+ // Clone the response before attempting to read the body,
74
+ // so we can potentially read it again (as text) if json() fails.
75
+ const clonedResponse = response.clone()
76
+ const textContent = await clonedResponse.text() // Read as text first
77
+
78
+ if (textContent.trim() === '') {
79
+ // If the body is empty (or only whitespace) and status was OK (checked above),
80
+ // treat this as the server sending 'undefined' or 'null'.
81
+ // Return `undefined` to match the expected optional types in the Provider interface.
82
+ return undefined as T
83
+ } else {
84
+ // If there is content, attempt to parse it as JSON.
85
+ // We use the original response here, which hasn't had its body consumed yet.
86
+ const responseText = await response.text()
87
+ const data = await Utils.fromJSON(responseText)
88
+
89
+ // BigInt Deserialization note remains the same: manual conversion may be needed by consumer.
90
+ return data as T
91
+ }
92
+ } catch (error) {
93
+ // This catch block now primarily handles errors from response.json()
94
+ // if the non-empty textContent wasn't valid JSON.
95
+ console.error(`Error processing response body for ${method} ${url}:`, error)
96
+ // Also include the raw text in the error if possible
97
+ try {
98
+ const text = await response.text() // Try reading original response if not already done
99
+ throw new Error(
100
+ `Failed to parse JSON response from server. Status: ${response.status}. Body: "${text}". Original error: ${error instanceof Error ? error.message : String(error)}`,
101
+ )
102
+ } catch (readError) {
103
+ throw new Error(
104
+ `Failed to parse JSON response from server and could not read response body as text. Status: ${response.status}. Original error: ${error instanceof Error ? error.message : String(error)}`,
105
+ )
106
+ }
107
+ }
108
+ }
109
+
110
+ // --- Reader Methods ---
111
+
112
+ async getConfiguration(imageHash: Hex.Hex): Promise<Config.Config | undefined> {
113
+ // The response needs careful handling if BigInts are involved (threshold, checkpoint)
114
+ const config = await this.request<Config.Config | undefined>('GET', `/configuration/${imageHash}`)
115
+ // Manual conversion example (if needed by consumer):
116
+ // if (config?.threshold) config.threshold = BigInt(config.threshold);
117
+ // if (config?.checkpoint) config.checkpoint = BigInt(config.checkpoint);
118
+ return config
119
+ }
120
+
121
+ async getDeploy(wallet: Address.Address): Promise<{ imageHash: Hex.Hex; context: Context.Context } | undefined> {
122
+ return this.request('GET', `/deploy/${wallet}`)
123
+ }
124
+
125
+ async getWallets(signer: Address.Address): Promise<{
126
+ [wallet: Address.Address]: {
127
+ chainId: bigint
128
+ payload: Payload.Parented
129
+ signature: Signature.SignatureOfSignerLeaf
130
+ }
131
+ }> {
132
+ // Response `chainId` will be a string/number, needs conversion if BigInt is strictly required upstream
133
+ return this.request('GET', `/wallets/signer/${signer}`)
134
+ }
135
+
136
+ async getWalletsForSapient(
137
+ signer: Address.Address,
138
+ imageHash: Hex.Hex,
139
+ ): Promise<{
140
+ [wallet: Address.Address]: {
141
+ chainId: bigint
142
+ payload: Payload.Parented
143
+ signature: Signature.SignatureOfSapientSignerLeaf
144
+ }
145
+ }> {
146
+ // Response `chainId` will be a string/number, needs conversion
147
+ return this.request('GET', `/wallets/sapient/${signer}/${imageHash}`)
148
+ }
149
+
150
+ async getWitnessFor(
151
+ wallet: Address.Address,
152
+ signer: Address.Address,
153
+ ): Promise<
154
+ | {
155
+ chainId: bigint
156
+ payload: Payload.Parented
157
+ signature: Signature.SignatureOfSignerLeaf
158
+ }
159
+ | undefined
160
+ > {
161
+ // Response `chainId` will be a string/number, needs conversion
162
+ return this.request('GET', `/witness/${wallet}/signer/${signer}`)
163
+ }
164
+
165
+ async getWitnessForSapient(
166
+ wallet: Address.Address,
167
+ signer: Address.Address,
168
+ imageHash: Hex.Hex,
169
+ ): Promise<
170
+ | {
171
+ chainId: bigint
172
+ payload: Payload.Parented
173
+ signature: Signature.SignatureOfSapientSignerLeaf
174
+ }
175
+ | undefined
176
+ > {
177
+ // Response `chainId` will be a string/number, needs conversion
178
+ return this.request('GET', `/witness/sapient/${wallet}/${signer}/${imageHash}`)
179
+ }
180
+
181
+ async getConfigurationUpdates(
182
+ wallet: Address.Address,
183
+ fromImageHash: Hex.Hex,
184
+ options?: { allUpdates?: boolean },
185
+ ): Promise<Array<{ imageHash: Hex.Hex; signature: Signature.RawSignature }>> {
186
+ const query = options?.allUpdates ? '?allUpdates=true' : ''
187
+ // Response signature object might contain BigInts (threshold, checkpoint) as strings
188
+ return this.request('GET', `/configuration-updates/${wallet}/from/${fromImageHash}${query}`)
189
+ }
190
+
191
+ async getTree(rootHash: Hex.Hex): Promise<GenericTree.Tree | undefined> {
192
+ return this.request('GET', `/tree/${rootHash}`)
193
+ }
194
+
195
+ // --- Writer Methods ---
196
+
197
+ async saveWallet(deployConfiguration: Config.Config, context: Context.Context): Promise<void> {
198
+ await this.request<void>('POST', '/wallet', { deployConfiguration, context })
199
+ }
200
+
201
+ async saveWitnesses(
202
+ wallet: Address.Address,
203
+ chainId: bigint,
204
+ payload: Payload.Parented,
205
+ signatures: Signature.RawTopology,
206
+ ): Promise<void> {
207
+ // chainId will be correctly stringified by the jsonReplacer
208
+ await this.request<void>('POST', '/witnesses', { wallet, chainId, payload, signatures })
209
+ }
210
+
211
+ async saveUpdate(
212
+ wallet: Address.Address,
213
+ configuration: Config.Config,
214
+ signature: Signature.RawSignature,
215
+ ): Promise<void> {
216
+ // configuration and signature might contain BigInts, handled by replacer
217
+ await this.request<void>('POST', '/update', { wallet, configuration, signature })
218
+ }
219
+
220
+ async saveTree(tree: GenericTree.Tree): Promise<void> {
221
+ await this.request<void>('POST', '/tree', { tree })
222
+ }
223
+
224
+ saveConfiguration(config: Config.Config): Promise<void> {
225
+ return this.request<void>('POST', '/configuration', { config })
226
+ }
227
+
228
+ saveDeploy(imageHash: Hex.Hex, context: Context.Context): Promise<void> {
229
+ return this.request<void>('POST', '/deploy', { imageHash, context })
230
+ }
231
+
232
+ async getPayload(opHash: Hex.Hex): Promise<
233
+ | {
234
+ chainId: bigint
235
+ payload: Payload.Parented
236
+ wallet: Address.Address
237
+ }
238
+ | undefined
239
+ > {
240
+ return this.request<
241
+ | {
242
+ chainId: bigint
243
+ payload: Payload.Parented
244
+ wallet: Address.Address
245
+ }
246
+ | undefined
247
+ >('GET', `/payload/${opHash}`)
248
+ }
249
+
250
+ async savePayload(wallet: Address.Address, payload: Payload.Parented, chainId: bigint): Promise<void> {
251
+ return this.request<void>('POST', '/payload', { wallet, payload, chainId })
252
+ }
253
+ }
@@ -0,0 +1 @@
1
+ export * from './dev-http.js'
@@ -0,0 +1,50 @@
1
+ import { Payload, Signature } from '@0xsequence/wallet-primitives'
2
+ import { Address, Hex } from 'ox'
3
+ import { Reader } from './index.js'
4
+ import { isSapientSigner, SapientSigner, Signer } from '../signers/index.js'
5
+
6
+ export type WalletWithWitness<S extends Signer | SapientSigner> = {
7
+ wallet: Address.Address
8
+ chainId: bigint
9
+ payload: Payload.Parented
10
+ signature: S extends SapientSigner ? Signature.SignatureOfSapientSignerLeaf : Signature.SignatureOfSignerLeaf
11
+ }
12
+
13
+ export async function getWalletsFor<S extends Signer | SapientSigner>(
14
+ stateReader: Reader,
15
+ signer: S,
16
+ ): Promise<Array<WalletWithWitness<S>>> {
17
+ const wallets = await retrieveWallets(stateReader, signer)
18
+ return Object.entries(wallets).map(([wallet, { chainId, payload, signature }]) => {
19
+ Hex.assert(wallet)
20
+ return {
21
+ wallet,
22
+ chainId,
23
+ payload,
24
+ signature,
25
+ }
26
+ })
27
+ }
28
+
29
+ async function retrieveWallets<S extends Signer | SapientSigner>(
30
+ stateReader: Reader,
31
+ signer: S,
32
+ ): Promise<{
33
+ [wallet: `0x${string}`]: {
34
+ chainId: bigint
35
+ payload: Payload.Parented
36
+ signature: S extends SapientSigner ? Signature.SignatureOfSapientSignerLeaf : Signature.SignatureOfSignerLeaf
37
+ }
38
+ }> {
39
+ if (isSapientSigner(signer)) {
40
+ const [signerAddress, signerImageHash] = await Promise.all([signer.address, signer.imageHash])
41
+ if (signerImageHash) {
42
+ return stateReader.getWalletsForSapient(signerAddress, signerImageHash) as unknown as any
43
+ } else {
44
+ console.warn('Sapient signer has no imageHash')
45
+ return {} as any
46
+ }
47
+ } else {
48
+ return stateReader.getWallets(await signer.address) as unknown as any
49
+ }
50
+ }