@0xsequence/wallet-core 3.0.0 → 3.0.1

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.
@@ -1,5 +1,5 @@
1
1
 
2
2
 
3
- > @0xsequence/wallet-core@3.0.0 build /home/taylan/development/sequence/sequence.js/packages/wallet/core
3
+ > @0xsequence/wallet-core@3.0.1 build /home/taylan/development/sequence/sequence.js/packages/wallet/core
4
4
  > tsc
5
5
 
@@ -1,4 +1,4 @@
1
1
 
2
- > @0xsequence/wallet-core@3.0.0 lint /home/taylan/development/sequence/sequence.js/packages/wallet/core
2
+ > @0xsequence/wallet-core@3.0.1 lint /home/taylan/development/sequence/sequence.js/packages/wallet/core
3
3
  > eslint . --max-warnings 0
4
4
 
@@ -0,0 +1,290 @@
1
+
2
+ > @0xsequence/wallet-core@3.0.0 test /home/taylan/development/sequence/sequence.js/packages/wallet/core
3
+ > vitest run
4
+
5
+
6
+  RUN  v4.0.18 /home/taylan/development/sequence/sequence.js/packages/wallet/core
7
+
8
+ ✓ test/signers-pk-encrypted.test.ts (19 tests) 29ms
9
+ ✓ test/state/debug.test.ts (14 tests) 17ms
10
+ ✓ test/state/local/memory.test.ts (16 tests) 7ms
11
+ ✓ test/envelope.test.ts (39 tests) 10ms
12
+ ✓ test/signers-passkey.test.ts (29 tests) 22ms
13
+ ✓ test/signers-pk.test.ts (16 tests) 52ms
14
+ ✓ test/relayer/bundler.test.ts (13 tests) 8ms
15
+ ✓ test/signers-index.test.ts (7 tests) 6ms
16
+ ✓ test/state/cached.test.ts (32 tests) 32ms
17
+ ✓ test/state/utils.test.ts (14 tests) 41ms
18
+ stdout | test/utils/session/permission-builder.test.ts > PermissionBuilder > should build an exact match permission
19
+ random calldata 0x13c07e55dfcc1767dc61947cf4e682647766111b1a6eccbb142b129a33561172792fd57005cdccd72748c3712c683432100286ff7ec0350355e3
20
+ random calldata 0x676403f8db056f24887c114919b8d73c
21
+ random calldata 0x1cef0b331be4ab4bcedaf8c60ef55cd08d9f8860cbd690f98f089cc4eb790fb0b7fbda64a4c99af02d01c8af7fc8d1ac24bd49
22
+ random calldata 0x6241c96dc68afea32ed2b8bb7de83e64c5972f8118aaeb3a6f9efb42cba1a3e0a89e283649ce9c40e01fb5fe297265c5cd2f44bcf4775834006f67b3e5
23
+ random calldata 0xfd645629d946efed2d538e40b6236f9a32bbfe7f5d9a911e8d4ae6e3c84aa04db842d8d138644b0748a4eb0da4f2b6099feba18c098306953ee5f61d64dc94d47cfbc6ae4afc5c42fc4c21c8abfe042a410132f8e0b8dadbf969169b6f80ca18
24
+ random calldata 0x413a7b1c2623423d03469e0d1be53bf6c007f178b9a2e08ffdc7ea77192fdf69656783434f350bd5bffd9076364559785805d8e56548efbe122328b23f3a162bcfc7baa248cfa3b336bd12a7e7f50eebb3805b9eef
25
+ random calldata 0x550e368c11c8718b4b555d700a916ba152192b12cf2504deb7
26
+ random calldata 0x9a9f47cadb002c7c9d320bfc3c230521b0f78d9a6ef5c2f90d89b5632e98f7f395af3acc5cf2bee8ff528012a52d7127b6a41acbbbcb3a72278a954b4d81bc3a3b13b8d9d3240b47798ba9790700f58c4216aae2f5a2a10c0145cf6c65
27
+ random calldata 0x
28
+ random calldata 0x34dd00e3b98f155f8e0e984bde
29
+
30
+ stdout | test/wallet.test.ts
31
+ [dotenv@17.3.1] injecting env (0) from .env.test.local -- tip: ⚙️ specify custom .env file path with { path: '/custom/path/.env' }
32
+
33
+ ✓ test/signers-guard.test.ts (4 tests) 18ms
34
+ stdout | test/session-manager.test.ts
35
+ [dotenv@17.3.1] injecting env (0) from .env.test.local -- tip: ⚙️ specify custom .env file path with { path: '/custom/path/.env' }
36
+
37
+ ✓ test/signers-session-explicit.test.ts (25 tests) 18ms
38
+ ✓ test/utils/session/permission-builder.test.ts (28 tests) 42ms
39
+ ❯ test/wallet.test.ts (8 tests | 4 failed) 57ms
40
+  × should sign a message 42ms
41
+  × should sign a typed data message 3ms
42
+  × should sign a message 2ms
43
+  × should sign a typed data message 2ms
44
+ ✓ Should reject unsafe wallet creation 2ms
45
+ ✓ Should reject unsafe wallet update 3ms
46
+ ✓ Should accept unsafe wallet creation in unsafe mode 1ms
47
+ ✓ Should accept unsafe wallet update in unsafe mode 1ms
48
+ ✓ test/signers-session-implicit.test.ts (28 tests) 88ms
49
+ ❯ test/session-manager.test.ts (90 tests | 85 failed) 205ms
50
+  × should load from state 35ms
51
+  × should create and sign with an implicit session 35ms
52
+  × should create and sign with a multiple implicit sessions 8ms
53
+  × should fail to sign with a multiple implicit sessions with different identity signers 8ms
54
+  × should create and sign with an explicit session 2ms
55
+  × should create and sign with an explicit session with 0 chainId 2ms
56
+ ✓ should fail to sign with an expired explicit session 4ms
57
+  × signs a payload using an implicit session 3ms
58
+  × signs a payload using an explicit session with allowAll and value limit 1ms
59
+  × signs using explicit session with onlyOnce, consumes usage and rejects second call 1ms
60
+  × signs an ERC20 approve using an explicit session 1ms
61
+  × signs a payload sending value using an explicit session 1ms
62
+  × signs a payload sending two transactions with cumulative rules using an explicit session 1ms
63
+  × using explicit session, sends value, then uses a non-incremental permission 1ms
64
+  × two explicit sessions with same value limit: exhaust first then second send uses second session (increment from non-increment calls only) 1ms
65
+  × prepareIncrement returns null when calls contain only an increment call (no non-increment calls) 1ms
66
+  × prepareIncrement([increment, nonIncrementCall]) produces same increment data as prepareIncrement([nonIncrementCall]) 1ms
67
+  × payload with implicit and explicit: increment built only from explicit non-increment call 1ms
68
+  × should load from state 1ms
69
+  × should create and sign with an implicit session 3ms
70
+  × should create and sign with a multiple implicit sessions 3ms
71
+  × should fail to sign with a multiple implicit sessions with different identity signers 3ms
72
+  × should create and sign with an explicit session 1ms
73
+  × should create and sign with an explicit session with 0 chainId 1ms
74
+ ✓ should fail to sign with an expired explicit session 1ms
75
+  × signs a payload using an implicit session 1ms
76
+  × signs a payload using an explicit session with allowAll and value limit 1ms
77
+  × signs using explicit session with onlyOnce, consumes usage and rejects second call 1ms
78
+  × signs an ERC20 approve using an explicit session 1ms
79
+  × signs a payload sending value using an explicit session 1ms
80
+  × signs a payload sending two transactions with cumulative rules using an explicit session 1ms
81
+  × using explicit session, sends value, then uses a non-incremental permission 1ms
82
+  × two explicit sessions with same value limit: exhaust first then second send uses second session (increment from non-increment calls only) 1ms
83
+  × prepareIncrement returns null when calls contain only an increment call (no non-increment calls) 1ms
84
+  × prepareIncrement([increment, nonIncrementCall]) produces same increment data as prepareIncrement([nonIncrementCall]) 1ms
85
+  × payload with implicit and explicit: increment built only from explicit non-increment call 1ms
86
+  × should load from state 2ms
87
+  × should create and sign with an implicit session 2ms
88
+  × should create and sign with a multiple implicit sessions 3ms
89
+  × should fail to sign with a multiple implicit sessions with different identity signers 3ms
90
+  × should create and sign with an explicit session 1ms
91
+  × should create and sign with an explicit session with 0 chainId 1ms
92
+ ✓ should fail to sign with an expired explicit session 1ms
93
+  × signs a payload using an implicit session 1ms
94
+  × signs a payload using an explicit session with allowAll and value limit 1ms
95
+  × signs using explicit session with onlyOnce, consumes usage and rejects second call 1ms
96
+  × signs an ERC20 approve using an explicit session 1ms
97
+  × signs a payload sending value using an explicit session 1ms
98
+  × signs a payload sending two transactions with cumulative rules using an explicit session 1ms
99
+  × using explicit session, sends value, then uses a non-incremental permission 1ms
100
+  × two explicit sessions with same value limit: exhaust first then second send uses second session (increment from non-increment calls only) 1ms
101
+  × prepareIncrement returns null when calls contain only an increment call (no non-increment calls) 1ms
102
+  × prepareIncrement([increment, nonIncrementCall]) produces same increment data as prepareIncrement([nonIncrementCall]) 1ms
103
+  × payload with implicit and explicit: increment built only from explicit non-increment call 1ms
104
+  × should load from state 1ms
105
+  × should create and sign with an implicit session 2ms
106
+  × should create and sign with a multiple implicit sessions 6ms
107
+  × should fail to sign with a multiple implicit sessions with different identity signers 4ms
108
+  × should create and sign with an explicit session 1ms
109
+  × should create and sign with an explicit session with 0 chainId 1ms
110
+ ✓ should fail to sign with an expired explicit session 1ms
111
+  × signs a payload using an implicit session 1ms
112
+  × signs a payload using an explicit session with allowAll and value limit 1ms
113
+  × signs using explicit session with onlyOnce, consumes usage and rejects second call 1ms
114
+  × signs an ERC20 approve using an explicit session 1ms
115
+  × signs a payload sending value using an explicit session 1ms
116
+  × signs a payload sending two transactions with cumulative rules using an explicit session 1ms
117
+  × using explicit session, sends value, then uses a non-incremental permission 1ms
118
+  × two explicit sessions with same value limit: exhaust first then second send uses second session (increment from non-increment calls only) 3ms
119
+  × prepareIncrement returns null when calls contain only an increment call (no non-increment calls) 1ms
120
+  × prepareIncrement([increment, nonIncrementCall]) produces same increment data as prepareIncrement([nonIncrementCall]) 1ms
121
+  × payload with implicit and explicit: increment built only from explicit non-increment call 1ms
122
+  × should load from state 1ms
123
+  × should create and sign with an implicit session 3ms
124
+  × should create and sign with a multiple implicit sessions 3ms
125
+  × should fail to sign with a multiple implicit sessions with different identity signers 3ms
126
+  × should create and sign with an explicit session 1ms
127
+  × should create and sign with an explicit session with 0 chainId 1ms
128
+ ✓ should fail to sign with an expired explicit session 2ms
129
+  × signs a payload using an implicit session 1ms
130
+  × signs a payload using an explicit session with allowAll and value limit 1ms
131
+  × signs using explicit session with onlyOnce, consumes usage and rejects second call 1ms
132
+  × signs an ERC20 approve using an explicit session 1ms
133
+  × signs a payload sending value using an explicit session 1ms
134
+  × signs a payload sending two transactions with cumulative rules using an explicit session 1ms
135
+  × using explicit session, sends value, then uses a non-incremental permission 1ms
136
+  × two explicit sessions with same value limit: exhaust first then second send uses second session (increment from non-increment calls only) 2ms
137
+  × prepareIncrement returns null when calls contain only an increment call (no non-increment calls) 1ms
138
+  × prepareIncrement([increment, nonIncrementCall]) produces same increment data as prepareIncrement([nonIncrementCall]) 1ms
139
+  × payload with implicit and explicit: increment built only from explicit non-increment call 1ms
140
+
141
+ ⎯⎯⎯⎯⎯⎯ Failed Tests 89 ⎯⎯⎯⎯⎯⎯⎯
142
+
143
+  FAIL  test/session-manager.test.ts > SessionManager (Dev1) > should load from state
144
+  FAIL  test/session-manager.test.ts > SessionManager (Dev1) > should create and sign with an implicit session
145
+  FAIL  test/session-manager.test.ts > SessionManager (Dev1) > should create and sign with a multiple implicit sessions
146
+  FAIL  test/session-manager.test.ts > SessionManager (Dev1) > should fail to sign with a multiple implicit sessions with different identity signers
147
+  FAIL  test/session-manager.test.ts > SessionManager (Dev1) > should create and sign with an explicit session
148
+  FAIL  test/session-manager.test.ts > SessionManager (Dev1) > should create and sign with an explicit session with 0 chainId
149
+  FAIL  test/session-manager.test.ts > SessionManager (Dev1) > signs a payload using an implicit session
150
+  FAIL  test/session-manager.test.ts > SessionManager (Dev1) > signs a payload using an explicit session with allowAll and value limit
151
+  FAIL  test/session-manager.test.ts > SessionManager (Dev1) > signs using explicit session with onlyOnce, consumes usage and rejects second call
152
+  FAIL  test/session-manager.test.ts > SessionManager (Dev1) > signs an ERC20 approve using an explicit session
153
+  FAIL  test/session-manager.test.ts > SessionManager (Dev1) > signs a payload sending value using an explicit session
154
+  FAIL  test/session-manager.test.ts > SessionManager (Dev1) > signs a payload sending two transactions with cumulative rules using an explicit session
155
+  FAIL  test/session-manager.test.ts > SessionManager (Dev1) > using explicit session, sends value, then uses a non-incremental permission
156
+  FAIL  test/session-manager.test.ts > SessionManager (Dev1) > two explicit sessions with same value limit: exhaust first then second send uses second session (increment from non-increment calls only)
157
+  FAIL  test/session-manager.test.ts > SessionManager (Dev1) > increment built from non-increment calls only > prepareIncrement returns null when calls contain only an increment call (no non-increment calls)
158
+  FAIL  test/session-manager.test.ts > SessionManager (Dev1) > increment built from non-increment calls only > prepareIncrement([increment, nonIncrementCall]) produces same increment data as prepareIncrement([nonIncrementCall])
159
+  FAIL  test/session-manager.test.ts > SessionManager (Dev1) > increment built from non-increment calls only > payload with implicit and explicit: increment built only from explicit non-increment call
160
+  FAIL  test/session-manager.test.ts > SessionManager (Dev2) > should load from state
161
+  FAIL  test/session-manager.test.ts > SessionManager (Dev2) > should create and sign with an implicit session
162
+  FAIL  test/session-manager.test.ts > SessionManager (Dev2) > should create and sign with a multiple implicit sessions
163
+  FAIL  test/session-manager.test.ts > SessionManager (Dev2) > should fail to sign with a multiple implicit sessions with different identity signers
164
+  FAIL  test/session-manager.test.ts > SessionManager (Dev2) > should create and sign with an explicit session
165
+  FAIL  test/session-manager.test.ts > SessionManager (Dev2) > should create and sign with an explicit session with 0 chainId
166
+  FAIL  test/session-manager.test.ts > SessionManager (Dev2) > signs a payload using an implicit session
167
+  FAIL  test/session-manager.test.ts > SessionManager (Dev2) > signs a payload using an explicit session with allowAll and value limit
168
+  FAIL  test/session-manager.test.ts > SessionManager (Dev2) > signs using explicit session with onlyOnce, consumes usage and rejects second call
169
+  FAIL  test/session-manager.test.ts > SessionManager (Dev2) > signs an ERC20 approve using an explicit session
170
+  FAIL  test/session-manager.test.ts > SessionManager (Dev2) > signs a payload sending value using an explicit session
171
+  FAIL  test/session-manager.test.ts > SessionManager (Dev2) > signs a payload sending two transactions with cumulative rules using an explicit session
172
+  FAIL  test/session-manager.test.ts > SessionManager (Dev2) > using explicit session, sends value, then uses a non-incremental permission
173
+  FAIL  test/session-manager.test.ts > SessionManager (Dev2) > two explicit sessions with same value limit: exhaust first then second send uses second session (increment from non-increment calls only)
174
+  FAIL  test/session-manager.test.ts > SessionManager (Dev2) > increment built from non-increment calls only > prepareIncrement returns null when calls contain only an increment call (no non-increment calls)
175
+  FAIL  test/session-manager.test.ts > SessionManager (Dev2) > increment built from non-increment calls only > prepareIncrement([increment, nonIncrementCall]) produces same increment data as prepareIncrement([nonIncrementCall])
176
+  FAIL  test/session-manager.test.ts > SessionManager (Dev2) > increment built from non-increment calls only > payload with implicit and explicit: increment built only from explicit non-increment call
177
+  FAIL  test/session-manager.test.ts > SessionManager (Rc3) > should load from state
178
+  FAIL  test/session-manager.test.ts > SessionManager (Rc3) > should create and sign with an implicit session
179
+  FAIL  test/session-manager.test.ts > SessionManager (Rc3) > should create and sign with a multiple implicit sessions
180
+  FAIL  test/session-manager.test.ts > SessionManager (Rc3) > should fail to sign with a multiple implicit sessions with different identity signers
181
+  FAIL  test/session-manager.test.ts > SessionManager (Rc3) > should create and sign with an explicit session
182
+  FAIL  test/session-manager.test.ts > SessionManager (Rc3) > should create and sign with an explicit session with 0 chainId
183
+  FAIL  test/session-manager.test.ts > SessionManager (Rc3) > signs a payload using an implicit session
184
+  FAIL  test/session-manager.test.ts > SessionManager (Rc3) > signs a payload using an explicit session with allowAll and value limit
185
+  FAIL  test/session-manager.test.ts > SessionManager (Rc3) > signs using explicit session with onlyOnce, consumes usage and rejects second call
186
+  FAIL  test/session-manager.test.ts > SessionManager (Rc3) > signs an ERC20 approve using an explicit session
187
+  FAIL  test/session-manager.test.ts > SessionManager (Rc3) > signs a payload sending value using an explicit session
188
+  FAIL  test/session-manager.test.ts > SessionManager (Rc3) > signs a payload sending two transactions with cumulative rules using an explicit session
189
+  FAIL  test/session-manager.test.ts > SessionManager (Rc3) > using explicit session, sends value, then uses a non-incremental permission
190
+  FAIL  test/session-manager.test.ts > SessionManager (Rc3) > two explicit sessions with same value limit: exhaust first then second send uses second session (increment from non-increment calls only)
191
+  FAIL  test/session-manager.test.ts > SessionManager (Rc3) > increment built from non-increment calls only > prepareIncrement returns null when calls contain only an increment call (no non-increment calls)
192
+  FAIL  test/session-manager.test.ts > SessionManager (Rc3) > increment built from non-increment calls only > prepareIncrement([increment, nonIncrementCall]) produces same increment data as prepareIncrement([nonIncrementCall])
193
+  FAIL  test/session-manager.test.ts > SessionManager (Rc3) > increment built from non-increment calls only > payload with implicit and explicit: increment built only from explicit non-increment call
194
+  FAIL  test/session-manager.test.ts > SessionManager (Rc4) > should load from state
195
+  FAIL  test/session-manager.test.ts > SessionManager (Rc4) > should create and sign with an implicit session
196
+  FAIL  test/session-manager.test.ts > SessionManager (Rc4) > should create and sign with a multiple implicit sessions
197
+  FAIL  test/session-manager.test.ts > SessionManager (Rc4) > should fail to sign with a multiple implicit sessions with different identity signers
198
+  FAIL  test/session-manager.test.ts > SessionManager (Rc4) > should create and sign with an explicit session
199
+  FAIL  test/session-manager.test.ts > SessionManager (Rc4) > should create and sign with an explicit session with 0 chainId
200
+  FAIL  test/session-manager.test.ts > SessionManager (Rc4) > signs a payload using an implicit session
201
+  FAIL  test/session-manager.test.ts > SessionManager (Rc4) > signs a payload using an explicit session with allowAll and value limit
202
+  FAIL  test/session-manager.test.ts > SessionManager (Rc4) > signs using explicit session with onlyOnce, consumes usage and rejects second call
203
+  FAIL  test/session-manager.test.ts > SessionManager (Rc4) > signs an ERC20 approve using an explicit session
204
+  FAIL  test/session-manager.test.ts > SessionManager (Rc4) > signs a payload sending value using an explicit session
205
+  FAIL  test/session-manager.test.ts > SessionManager (Rc4) > signs a payload sending two transactions with cumulative rules using an explicit session
206
+  FAIL  test/session-manager.test.ts > SessionManager (Rc4) > using explicit session, sends value, then uses a non-incremental permission
207
+  FAIL  test/session-manager.test.ts > SessionManager (Rc4) > two explicit sessions with same value limit: exhaust first then second send uses second session (increment from non-increment calls only)
208
+  FAIL  test/session-manager.test.ts > SessionManager (Rc4) > increment built from non-increment calls only > prepareIncrement returns null when calls contain only an increment call (no non-increment calls)
209
+  FAIL  test/session-manager.test.ts > SessionManager (Rc4) > increment built from non-increment calls only > prepareIncrement([increment, nonIncrementCall]) produces same increment data as prepareIncrement([nonIncrementCall])
210
+  FAIL  test/session-manager.test.ts > SessionManager (Rc4) > increment built from non-increment calls only > payload with implicit and explicit: increment built only from explicit non-increment call
211
+  FAIL  test/session-manager.test.ts > SessionManager (Rc5) > should load from state
212
+  FAIL  test/session-manager.test.ts > SessionManager (Rc5) > should create and sign with an implicit session
213
+  FAIL  test/session-manager.test.ts > SessionManager (Rc5) > should create and sign with a multiple implicit sessions
214
+  FAIL  test/session-manager.test.ts > SessionManager (Rc5) > should fail to sign with a multiple implicit sessions with different identity signers
215
+  FAIL  test/session-manager.test.ts > SessionManager (Rc5) > should create and sign with an explicit session
216
+  FAIL  test/session-manager.test.ts > SessionManager (Rc5) > should create and sign with an explicit session with 0 chainId
217
+  FAIL  test/session-manager.test.ts > SessionManager (Rc5) > signs a payload using an implicit session
218
+  FAIL  test/session-manager.test.ts > SessionManager (Rc5) > signs a payload using an explicit session with allowAll and value limit
219
+  FAIL  test/session-manager.test.ts > SessionManager (Rc5) > signs using explicit session with onlyOnce, consumes usage and rejects second call
220
+  FAIL  test/session-manager.test.ts > SessionManager (Rc5) > signs an ERC20 approve using an explicit session
221
+  FAIL  test/session-manager.test.ts > SessionManager (Rc5) > signs a payload sending value using an explicit session
222
+  FAIL  test/session-manager.test.ts > SessionManager (Rc5) > signs a payload sending two transactions with cumulative rules using an explicit session
223
+  FAIL  test/session-manager.test.ts > SessionManager (Rc5) > using explicit session, sends value, then uses a non-incremental permission
224
+  FAIL  test/session-manager.test.ts > SessionManager (Rc5) > two explicit sessions with same value limit: exhaust first then second send uses second session (increment from non-increment calls only)
225
+  FAIL  test/session-manager.test.ts > SessionManager (Rc5) > increment built from non-increment calls only > prepareIncrement returns null when calls contain only an increment call (no non-increment calls)
226
+  FAIL  test/session-manager.test.ts > SessionManager (Rc5) > increment built from non-increment calls only > prepareIncrement([increment, nonIncrementCall]) produces same increment data as prepareIncrement([nonIncrementCall])
227
+  FAIL  test/session-manager.test.ts > SessionManager (Rc5) > increment built from non-increment calls only > payload with implicit and explicit: increment built only from explicit non-increment call
228
+  FAIL  test/wallet.test.ts > Wallet > deployed > should sign a message
229
+  FAIL  test/wallet.test.ts > Wallet > deployed > should sign a typed data message
230
+  FAIL  test/wallet.test.ts > Wallet > not-deployed > should sign a message
231
+  FAIL  test/wallet.test.ts > Wallet > not-deployed > should sign a typed data message
232
+ RpcResponse.InternalError: fetch failed
233
+  ❯ ../../../node_modules/.pnpm/ox@0.9.17_typescript@5.9.3_zod@4.2.0/node_modules/ox/_esm/core/internal/promise.js:20:25
234
+
235
+ Caused by: TypeError: fetch failed
236
+  ❯ ../../../node_modules/.pnpm/ox@0.9.17_typescript@5.9.3_zod@4.2.0/node_modules/ox/_esm/core/internal/promise.js:20:25
237
+
238
+ {
239
+ stack: 'AggregateError: \n' +
240
+ ' at internalConnectMultiple (node:net:1134:18)\n' +
241
+ ' at internalConnectMultiple (node:net:1210:5)\n' +
242
+ ' at afterConnectMultiple (node:net:1715:7)',
243
+ errors: [
244
+ {
245
+ stack: 'Error: connect ECONNREFUSED 127.0.0.1:8545\n' +
246
+ ' at createConnectionError (node:net:1678:14)\n' +
247
+ ' at afterConnectMultiple (node:net:1708:16)',
248
+ message: 'connect ECONNREFUSED 127.0.0.1:8545',
249
+ errno: -111,
250
+ code: 'ECONNREFUSED',
251
+ syscall: 'connect',
252
+ address: '127.0.0.1',
253
+ port: 8545,
254
+ constructor: 'Function<Error>',
255
+ name: 'Error',
256
+ toString: 'Function<toString>'
257
+ },
258
+ {
259
+ stack: 'Error: connect ENETUNREACH ::1:8545 - Local (:::0)\n' +
260
+ ' at internalConnectMultiple (node:net:1206:16)\n' +
261
+ ' at afterConnectMultiple (node:net:1715:7)',
262
+ message: 'connect ENETUNREACH ::1:8545 - Local (:::0)',
263
+ errno: -101,
264
+ code: 'ENETUNREACH',
265
+ syscall: 'connect',
266
+ address: '::1',
267
+ port: 8545,
268
+ constructor: 'Function<Error>',
269
+ name: 'Error',
270
+ toString: 'Function<toString>'
271
+ }
272
+ ],
273
+ code: 'ECONNREFUSED',
274
+ constructor: 'Function<AggregateError>',
275
+ name: 'Caused by: AggregateError',
276
+ message: '',
277
+ toString: 'Function<toString>',
278
+ stacks: []
279
+ }
280
+ ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
281
+ Serialized Error: { errors: [ { stack: 'Error: connect ECONNREFUSED 127.0.0.1:8545\n at createConnectionError (node:net:1678:14)\n at afterConnectMultiple (node:net:1708:16)', message: 'connect ECONNREFUSED 127.0.0.1:8545', errno: -111, code: 'ECONNREFUSED', syscall: 'connect', address: '127.0.0.1', port: 8545, constructor: 'Function<Error>', name: 'Error', toString: 'Function<toString>' }, { stack: 'Error: connect ENETUNREACH ::1:8545 - Local (:::0)\n at internalConnectMultiple (node:net:1206:16)\n at afterConnectMultiple (node:net:1715:7)', message: 'connect ENETUNREACH ::1:8545 - Local (:::0)', errno: -101, code: 'ENETUNREACH', syscall: 'connect', address: '::1', port: 8545, constructor: 'Function<Error>', name: 'Error', toString: 'Function<toString>' } ], code: 'ECONNREFUSED' }
282
+ ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/89]⎯
283
+
284
+
285
+  Test Files  2 failed | 14 passed (16)
286
+  Tests  89 failed | 293 passed (382)
287
+  Start at  12:35:18
288
+  Duration  1.36s (transform 3.62s, setup 0ms, import 12.03s, tests 651ms, environment 2ms)
289
+
290
+  ELIFECYCLE  Test failed. See above for more details.
@@ -1,4 +1,4 @@
1
1
 
2
- > @0xsequence/wallet-core@3.0.0 typecheck /home/taylan/development/sequence/sequence.js/packages/wallet/core
2
+ > @0xsequence/wallet-core@3.0.1 typecheck /home/taylan/development/sequence/sequence.js/packages/wallet/core
3
3
  > tsc --noEmit
4
4
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # @0xsequence/wallet-core
2
2
 
3
+ ## 3.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Network and session fixes
8
+ - Updated dependencies
9
+ - @0xsequence/guard@3.0.1
10
+ - @0xsequence/relayer@3.0.1
11
+ - @0xsequence/wallet-primitives@3.0.1
12
+
3
13
  ## 3.0.0
4
14
 
5
15
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"explicit.d.ts","sourceRoot":"","sources":["../../../src/signers/session/explicit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AAC/G,OAAO,EAA8B,OAAO,EAAe,GAAG,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAA;AACpF,OAAO,EAAiB,OAAO,EAAE,MAAM,gBAAgB,CAAA;AACvD,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEvF,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,UAAU,CAAC,kBAAkB,EAAE,QAAQ,CAAC,CAAA;AAI1E,qBAAa,QAAS,YAAW,qBAAqB;IACpD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IAErC,SAAgB,OAAO,EAAE,OAAO,CAAC,OAAO,CAAA;IACxC,SAAgB,kBAAkB,EAAE,UAAU,CAAC,kBAAkB,CAAA;gBAErD,UAAU,EAAE,GAAG,CAAC,GAAG,GAAG,OAAO,EAAE,kBAAkB,EAAE,cAAc;IAS7E,OAAO,CAAC,eAAe,EAAE,aAAa,CAAC,gBAAgB,EAAE,OAAO,EAAE,MAAM,GAAG,qBAAqB;IA+C1F,uBAAuB,CAC3B,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,OAAO,CAAC,IAAI,EAClB,qBAAqB,EAAE,OAAO,CAAC,OAAO,EACtC,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,GAC3B,OAAO,CAAC,UAAU,CAAC,UAAU,GAAG,SAAS,CAAC;IAmC7C,OAAO,CAAC,sBAAsB;IAmB9B,OAAO,CAAC,iBAAiB;IAYnB,kBAAkB,CACtB,UAAU,EAAE,UAAU,CAAC,UAAU,EACjC,IAAI,EAAE,OAAO,CAAC,IAAI,EAClB,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,qBAAqB,EAAE,OAAO,CAAC,OAAO,EACtC,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,GAC3B,OAAO,CAAC,OAAO,CAAC;IAsDb,aAAa,CACjB,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,OAAO,CAAC,IAAI,EAClB,qBAAqB,EAAE,OAAO,CAAC,OAAO,EACtC,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,GAC3B,OAAO,CAAC,OAAO,CAAC;IAiBb,QAAQ,CACZ,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,CAAC,KAAK,EACtB,OAAO,EAAE,MAAM,EACf,qBAAqB,EAAE,OAAO,CAAC,OAAO,EACtC,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,GAC3B,OAAO,CAAC,gBAAgB,CAAC,oBAAoB,CAAC;YAiCnC,qBAAqB;IAwB7B,iBAAiB,CACrB,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,EACrB,qBAAqB,EAAE,OAAO,CAAC,OAAO,EACtC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,GAC1B,OAAO,CAAC,UAAU,EAAE,CAAC;CA8EzB"}
1
+ {"version":3,"file":"explicit.d.ts","sourceRoot":"","sources":["../../../src/signers/session/explicit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AAC/G,OAAO,EAA8B,OAAO,EAAe,GAAG,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAA;AACpF,OAAO,EAAiB,OAAO,EAAE,MAAM,gBAAgB,CAAA;AACvD,OAAO,EAAE,qBAAqB,EAAmB,qBAAqB,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAExG,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,UAAU,CAAC,kBAAkB,EAAE,QAAQ,CAAC,CAAA;AAI1E,qBAAa,QAAS,YAAW,qBAAqB;IACpD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IAErC,SAAgB,OAAO,EAAE,OAAO,CAAC,OAAO,CAAA;IACxC,SAAgB,kBAAkB,EAAE,UAAU,CAAC,kBAAkB,CAAA;gBAErD,UAAU,EAAE,GAAG,CAAC,GAAG,GAAG,OAAO,EAAE,kBAAkB,EAAE,cAAc;IAS7E,OAAO,CAAC,eAAe,EAAE,aAAa,CAAC,gBAAgB,EAAE,OAAO,EAAE,MAAM,GAAG,qBAAqB;IA+C1F,uBAAuB,CAC3B,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,OAAO,CAAC,IAAI,EAClB,qBAAqB,EAAE,OAAO,CAAC,OAAO,EACtC,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,GAC3B,OAAO,CAAC,UAAU,CAAC,UAAU,GAAG,SAAS,CAAC;IAmC7C,OAAO,CAAC,sBAAsB;IAmB9B,OAAO,CAAC,iBAAiB;IAYnB,kBAAkB,CACtB,UAAU,EAAE,UAAU,CAAC,UAAU,EACjC,IAAI,EAAE,OAAO,CAAC,IAAI,EAClB,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,qBAAqB,EAAE,OAAO,CAAC,OAAO,EACtC,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,GAC3B,OAAO,CAAC,OAAO,CAAC;IAsDb,aAAa,CACjB,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,OAAO,CAAC,IAAI,EAClB,qBAAqB,EAAE,OAAO,CAAC,OAAO,EACtC,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,GAC3B,OAAO,CAAC,OAAO,CAAC;IAab,QAAQ,CACZ,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,CAAC,KAAK,EACtB,OAAO,EAAE,MAAM,EACf,qBAAqB,EAAE,OAAO,CAAC,OAAO,EACtC,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,GAC3B,OAAO,CAAC,gBAAgB,CAAC,oBAAoB,CAAC;YA6BnC,qBAAqB;IAwB7B,iBAAiB,CACrB,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,EACrB,qBAAqB,EAAE,OAAO,CAAC,OAAO,EACtC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,GAC1B,OAAO,CAAC,UAAU,EAAE,CAAC;CA8EzB"}
@@ -1,6 +1,7 @@
1
1
  import { Constants, Permission, SessionConfig, SessionSignature } from '@0xsequence/wallet-primitives';
2
2
  import { AbiFunction, AbiParameters, Address, Bytes, Hash, Hex } from 'ox';
3
3
  import { MemoryPkStore } from '../pk/index.js';
4
+ import { isIncrementCall } from './session.js';
4
5
  const VALUE_TRACKING_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
5
6
  export class Explicit {
6
7
  _privateKey;
@@ -143,9 +144,7 @@ export class Explicit {
143
144
  return true;
144
145
  }
145
146
  async supportedCall(wallet, chainId, call, sessionManagerAddress, provider) {
146
- if (Address.isEqual(call.to, sessionManagerAddress) &&
147
- Hex.size(call.data) > 4 &&
148
- Hex.isEqual(Hex.slice(call.data, 0, 4), AbiFunction.getSelector(Constants.INCREMENT_USAGE_LIMIT))) {
147
+ if (isIncrementCall(call, sessionManagerAddress)) {
149
148
  // Can sign increment usage calls
150
149
  return true;
151
150
  }
@@ -158,9 +157,7 @@ export class Explicit {
158
157
  async signCall(wallet, chainId, payload, callIdx, sessionManagerAddress, provider) {
159
158
  const call = payload.calls[callIdx];
160
159
  let permissionIndex;
161
- if (Address.isEqual(call.to, sessionManagerAddress) &&
162
- Hex.size(call.data) > 4 &&
163
- Hex.isEqual(Hex.slice(call.data, 0, 4), AbiFunction.getSelector(Constants.INCREMENT_USAGE_LIMIT))) {
160
+ if (isIncrementCall(call, sessionManagerAddress)) {
164
161
  // Permission check not required. Use the first permission
165
162
  permissionIndex = 0;
166
163
  }
@@ -23,4 +23,5 @@ export interface ImplicitSessionSigner extends SessionSigner {
23
23
  }
24
24
  export declare function isExplicitSessionSigner(signer: SessionSigner): signer is ExplicitSessionSigner;
25
25
  export declare function isImplicitSessionSigner(signer: SessionSigner): signer is ImplicitSessionSigner;
26
+ export declare function isIncrementCall(call: Payload.Call, sessionManagerAddress: Address.Address): boolean;
26
27
  //# sourceMappingURL=session.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/signers/session/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AACxF,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAA;AAE3C,MAAM,MAAM,0BAA0B,GAClC,SAAS,GACT,mBAAmB,GACnB,sBAAsB,GACtB,qBAAqB,GACrB,0BAA0B,GAC1B,2BAA2B,GAC3B,0BAA0B,GAC1B,aAAa,CAAA;AAEjB,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE,OAAO,CAAA;IAChB,aAAa,CAAC,EAAE,0BAA0B,CAAA;CAC3C,CAAA;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IAGnD,OAAO,EAAE,CAAC,eAAe,EAAE,aAAa,CAAC,gBAAgB,EAAE,OAAO,EAAE,MAAM,KAAK,qBAAqB,CAAA;IAGpG,aAAa,EAAE,CACb,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,OAAO,CAAC,IAAI,EAClB,qBAAqB,EAAE,OAAO,CAAC,OAAO,EACtC,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,KACzB,OAAO,CAAC,OAAO,CAAC,CAAA;IAGrB,QAAQ,EAAE,CACR,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,CAAC,KAAK,EACtB,OAAO,EAAE,MAAM,EACf,qBAAqB,EAAE,OAAO,CAAC,OAAO,EACtC,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,KACzB,OAAO,CAAC,gBAAgB,CAAC,oBAAoB,CAAC,CAAA;CACpD;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,SAAS,EAAE,GAAG,CAAC,GAAG,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,WAAW,qBAAsB,SAAQ,aAAa;IAC1D,iBAAiB,EAAE,CACjB,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,EACrB,qBAAqB,EAAE,OAAO,CAAC,OAAO,EACtC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,KACxB,OAAO,CAAC,UAAU,EAAE,CAAC,CAAA;CAC3B;AAED,MAAM,WAAW,qBAAsB,SAAQ,aAAa;IAC1D,cAAc,EAAE,OAAO,CAAC,OAAO,CAAA;CAChC;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,IAAI,qBAAqB,CAE9F;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,IAAI,qBAAqB,CAE9F"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/signers/session/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAA;AACnG,OAAO,EAAe,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAA;AAExD,MAAM,MAAM,0BAA0B,GAClC,SAAS,GACT,mBAAmB,GACnB,sBAAsB,GACtB,qBAAqB,GACrB,0BAA0B,GAC1B,2BAA2B,GAC3B,0BAA0B,GAC1B,aAAa,CAAA;AAEjB,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE,OAAO,CAAA;IAChB,aAAa,CAAC,EAAE,0BAA0B,CAAA;CAC3C,CAAA;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IAGnD,OAAO,EAAE,CAAC,eAAe,EAAE,aAAa,CAAC,gBAAgB,EAAE,OAAO,EAAE,MAAM,KAAK,qBAAqB,CAAA;IAGpG,aAAa,EAAE,CACb,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,OAAO,CAAC,IAAI,EAClB,qBAAqB,EAAE,OAAO,CAAC,OAAO,EACtC,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,KACzB,OAAO,CAAC,OAAO,CAAC,CAAA;IAGrB,QAAQ,EAAE,CACR,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,CAAC,KAAK,EACtB,OAAO,EAAE,MAAM,EACf,qBAAqB,EAAE,OAAO,CAAC,OAAO,EACtC,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,KACzB,OAAO,CAAC,gBAAgB,CAAC,oBAAoB,CAAC,CAAA;CACpD;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,SAAS,EAAE,GAAG,CAAC,GAAG,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,WAAW,qBAAsB,SAAQ,aAAa;IAC1D,iBAAiB,EAAE,CACjB,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,EACrB,qBAAqB,EAAE,OAAO,CAAC,OAAO,EACtC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,KACxB,OAAO,CAAC,UAAU,EAAE,CAAC,CAAA;CAC3B;AAED,MAAM,WAAW,qBAAsB,SAAQ,aAAa;IAC1D,cAAc,EAAE,OAAO,CAAC,OAAO,CAAA;CAChC;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,IAAI,qBAAqB,CAE9F;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,IAAI,qBAAqB,CAE9F;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,qBAAqB,EAAE,OAAO,CAAC,OAAO,GAAG,OAAO,CAMnG"}
@@ -1,6 +1,13 @@
1
+ import { Constants } from '@0xsequence/wallet-primitives';
2
+ import { AbiFunction, Address, Hex } from 'ox';
1
3
  export function isExplicitSessionSigner(signer) {
2
4
  return 'prepareIncrements' in signer;
3
5
  }
4
6
  export function isImplicitSessionSigner(signer) {
5
7
  return 'identitySigner' in signer;
6
8
  }
9
+ export function isIncrementCall(call, sessionManagerAddress) {
10
+ return (Address.isEqual(call.to, sessionManagerAddress) &&
11
+ Hex.size(call.data) >= 4 &&
12
+ Hex.isEqual(Hex.slice(call.data, 0, 4), AbiFunction.getSelector(Constants.INCREMENT_USAGE_LIMIT)));
13
+ }
@@ -31,6 +31,10 @@ export declare class SessionManager implements SapientSigner {
31
31
  isValid: boolean;
32
32
  invalidReason?: SessionSignerInvalidReason;
33
33
  }[]>;
34
+ /**
35
+ * Find one signer per call from the given candidate list (first that supports each call).
36
+ */
37
+ private findSignersForCallsWithCandidates;
34
38
  findSignersForCalls(wallet: Address.Address, chainId: number, calls: Payload.Call[]): Promise<SessionSigner[]>;
35
39
  prepareIncrement(wallet: Address.Address, chainId: number, calls: Payload.Call[]): Promise<Payload.Call | null>;
36
40
  signSapient(wallet: Address.Address, chainId: number, payload: Payload.Parented, imageHash: Hex.Hex): Promise<SignatureTypes.SignatureOfSapientSignerLeaf>;
@@ -1 +1 @@
1
- {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/signers/session-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,OAAO,EACP,aAAa,EAEb,SAAS,IAAI,cAAc,EAC5B,MAAM,+BAA+B,CAAA;AACtC,OAAO,EAAe,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAA;AACxD,OAAO,KAAK,KAAK,MAAM,mBAAmB,CAAA;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,EACL,QAAQ,EACR,QAAQ,EAER,aAAa,EACb,0BAA0B,EAG3B,MAAM,oBAAoB,CAAA;AAE3B,MAAM,MAAM,qBAAqB,GAAG;IAClC,qBAAqB,EAAE,OAAO,CAAC,OAAO,CAAA;IACtC,aAAa,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAA;IAC9B,eAAe,CAAC,EAAE,QAAQ,EAAE,CAAA;IAC5B,eAAe,CAAC,EAAE,QAAQ,EAAE,CAAA;IAC5B,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAA;CAC7B,CAAA;AAID,qBAAa,cAAe,YAAW,aAAa;IAShD,QAAQ,CAAC,MAAM,EAAE,MAAM;IARzB,SAAgB,aAAa,EAAE,KAAK,CAAC,QAAQ,CAAA;IAC7C,SAAgB,OAAO,EAAE,OAAO,CAAC,OAAO,CAAA;IAExC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAY;IAC7C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAY;IAC7C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAmB;gBAGnC,MAAM,EAAE,MAAM,EACvB,OAAO,EAAE,qBAAqB;IAShC,IAAI,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,SAAS,CAAC,CAE5C;IAEK,YAAY,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,SAAS,CAAC;IASlD,IAAI,QAAQ,IAAI,OAAO,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAEtD;IAEK,WAAW,IAAI,OAAO,CAAC,aAAa,CAAC,gBAAgB,CAAC;IAY5D,YAAY,CAAC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,GAAG,cAAc;IAUzD,kBAAkB,CAAC,MAAM,EAAE,QAAQ,GAAG,cAAc;IAWpD,kBAAkB,CAAC,MAAM,EAAE,QAAQ,GAAG,cAAc;IAY9C,kBAAkB,CACtB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;QAAE,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,aAAa,CAAC,EAAE,0BAA0B,CAAA;KAAE,EAAE,CAAC;IAgBjG,mBAAmB,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAmD9G,gBAAgB,CACpB,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,GACpB,OAAO,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAmDzB,WAAW,CACf,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,CAAC,QAAQ,EACzB,SAAS,EAAE,GAAG,CAAC,GAAG,GACjB,OAAO,CAAC,cAAc,CAAC,4BAA4B,CAAC;IAgHjD,uBAAuB,CAC3B,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,CAAC,QAAQ,EACzB,SAAS,EAAE,cAAc,CAAC,4BAA4B,GACrD,OAAO,CAAC,OAAO,CAAC;CAsCpB"}
1
+ {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/signers/session-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,OAAO,EACP,aAAa,EAEb,SAAS,IAAI,cAAc,EAC5B,MAAM,+BAA+B,CAAA;AACtC,OAAO,EAAe,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAA;AACxD,OAAO,KAAK,KAAK,MAAM,mBAAmB,CAAA;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,EACL,QAAQ,EACR,QAAQ,EAER,aAAa,EACb,0BAA0B,EAI3B,MAAM,oBAAoB,CAAA;AAE3B,MAAM,MAAM,qBAAqB,GAAG;IAClC,qBAAqB,EAAE,OAAO,CAAC,OAAO,CAAA;IACtC,aAAa,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAA;IAC9B,eAAe,CAAC,EAAE,QAAQ,EAAE,CAAA;IAC5B,eAAe,CAAC,EAAE,QAAQ,EAAE,CAAA;IAC5B,QAAQ,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAA;CAC7B,CAAA;AAID,qBAAa,cAAe,YAAW,aAAa;IAShD,QAAQ,CAAC,MAAM,EAAE,MAAM;IARzB,SAAgB,aAAa,EAAE,KAAK,CAAC,QAAQ,CAAA;IAC7C,SAAgB,OAAO,EAAE,OAAO,CAAC,OAAO,CAAA;IAExC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAY;IAC7C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAY;IAC7C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAmB;gBAGnC,MAAM,EAAE,MAAM,EACvB,OAAO,EAAE,qBAAqB;IAShC,IAAI,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,SAAS,CAAC,CAE5C;IAEK,YAAY,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,SAAS,CAAC;IASlD,IAAI,QAAQ,IAAI,OAAO,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAEtD;IAEK,WAAW,IAAI,OAAO,CAAC,aAAa,CAAC,gBAAgB,CAAC;IAY5D,YAAY,CAAC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,GAAG,cAAc;IAUzD,kBAAkB,CAAC,MAAM,EAAE,QAAQ,GAAG,cAAc;IAWpD,kBAAkB,CAAC,MAAM,EAAE,QAAQ,GAAG,cAAc;IAY9C,kBAAkB,CACtB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;QAAE,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,aAAa,CAAC,EAAE,0BAA0B,CAAA;KAAE,EAAE,CAAC;IAgBvG;;OAEG;YACW,iCAAiC;IAyCzC,mBAAmB,CAAC,MAAM,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IA4D9G,gBAAgB,CACpB,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE,GACpB,OAAO,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAsDzB,WAAW,CACf,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,CAAC,QAAQ,EACzB,SAAS,EAAE,GAAG,CAAC,GAAG,GACjB,OAAO,CAAC,cAAc,CAAC,4BAA4B,CAAC;IAgHjD,uBAAuB,CAC3B,MAAM,EAAE,OAAO,CAAC,OAAO,EACvB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,CAAC,QAAQ,EACzB,SAAS,EAAE,cAAc,CAAC,4BAA4B,GACrD,OAAO,CAAC,OAAO,CAAC;CAsCpB"}
@@ -1,6 +1,6 @@
1
1
  import { Config, Constants, Extensions, Payload, SessionConfig, SessionSignature, } from '@0xsequence/wallet-primitives';
2
2
  import { AbiFunction, Address, Hex } from 'ox';
3
- import { isExplicitSessionSigner, isImplicitSessionSigner, } from './session/index.js';
3
+ import { isExplicitSessionSigner, isImplicitSessionSigner, isIncrementCall, } from './session/index.js';
4
4
  const MAX_SPACE = 2n ** 80n - 1n;
5
5
  export class SessionManager {
6
6
  wallet;
@@ -86,19 +86,10 @@ export class SessionManager {
86
86
  invalidReason,
87
87
  }));
88
88
  }
89
- async findSignersForCalls(wallet, chainId, calls) {
90
- // Only use signers that match the topology
91
- const topology = await this.topology;
92
- const identitySigners = SessionConfig.getIdentitySigners(topology);
93
- if (identitySigners.length === 0) {
94
- throw new Error('Identity signers not found');
95
- }
96
- // Prioritize implicit signers
97
- const availableSigners = [...this._implicitSigners, ...this._explicitSigners];
98
- if (availableSigners.length === 0) {
99
- throw new Error('No signers match the topology');
100
- }
101
- // Find supported signers for each call
89
+ /**
90
+ * Find one signer per call from the given candidate list (first that supports each call).
91
+ */
92
+ async findSignersForCallsWithCandidates(wallet, chainId, calls, topology, availableSigners) {
102
93
  const signers = [];
103
94
  for (const call of calls) {
104
95
  let supported = false;
@@ -128,7 +119,56 @@ export class SessionManager {
128
119
  if (expiredSupportedSigner) {
129
120
  throw new Error(`Signer supporting call is expired: ${expiredSupportedSigner.address}`);
130
121
  }
131
- throw new Error(`No signer supported for call. ` + `Call: to=${call.to}, data=${call.data}, value=${call.value}, `);
122
+ throw new Error(`No signer supported for call. Call: to=${call.to}, data=${call.data}, value=${call.value}, `);
123
+ }
124
+ }
125
+ return signers;
126
+ }
127
+ async findSignersForCalls(wallet, chainId, calls) {
128
+ const topology = await this.topology;
129
+ const identitySigners = SessionConfig.getIdentitySigners(topology);
130
+ if (identitySigners.length === 0) {
131
+ throw new Error('Identity signers not found');
132
+ }
133
+ const availableSigners = [...this._implicitSigners, ...this._explicitSigners];
134
+ if (availableSigners.length === 0) {
135
+ throw new Error('No signers match the topology');
136
+ }
137
+ const nonIncrementCalls = [];
138
+ const incrementCalls = [];
139
+ for (const call of calls) {
140
+ if (isIncrementCall(call, this.address)) {
141
+ incrementCalls.push(call);
142
+ }
143
+ else {
144
+ nonIncrementCalls.push(call);
145
+ }
146
+ }
147
+ // Find signers for non-increment calls
148
+ const nonIncrementSigners = nonIncrementCalls.length > 0
149
+ ? await this.findSignersForCallsWithCandidates(wallet, chainId, nonIncrementCalls, topology, availableSigners)
150
+ : [];
151
+ let incrementSigners = [];
152
+ if (incrementCalls.length > 0) {
153
+ // Find signers for increment calls, preferring signers that signed non-increment calls
154
+ const incrementCandidates = [
155
+ ...nonIncrementSigners,
156
+ ...availableSigners.filter((s) => !nonIncrementSigners.includes(s)),
157
+ ];
158
+ incrementSigners = await this.findSignersForCallsWithCandidates(wallet, chainId, incrementCalls, topology, incrementCandidates);
159
+ }
160
+ // Merge back in original call order
161
+ const signers = [];
162
+ let nonIncrementIndex = 0;
163
+ let incrementIndex = 0;
164
+ for (const call of calls) {
165
+ if (isIncrementCall(call, this.address)) {
166
+ signers.push(incrementSigners[incrementIndex]);
167
+ incrementIndex++;
168
+ }
169
+ else {
170
+ signers.push(nonIncrementSigners[nonIncrementIndex]);
171
+ nonIncrementIndex++;
132
172
  }
133
173
  }
134
174
  return signers;
@@ -138,17 +178,20 @@ export class SessionManager {
138
178
  throw new Error('No calls provided');
139
179
  }
140
180
  const signers = await this.findSignersForCalls(wallet, chainId, calls);
141
- // Create a map of signers to their associated calls
142
- const signerToCalls = new Map();
181
+ // Map each signer to only their non-increment calls
182
+ const signerToNonIncrementCalls = new Map();
143
183
  signers.forEach((signer, index) => {
144
184
  const call = calls[index];
145
- const existingCalls = signerToCalls.get(signer) || [];
146
- signerToCalls.set(signer, [...existingCalls, call]);
185
+ if (isIncrementCall(call, this.address)) {
186
+ return;
187
+ }
188
+ const existing = signerToNonIncrementCalls.get(signer) || [];
189
+ signerToNonIncrementCalls.set(signer, [...existing, call]);
147
190
  });
148
- // Prepare increments for each explicit signer with their associated calls
149
- const increments = (await Promise.all(Array.from(signerToCalls.entries()).map(async ([signer, associatedCalls]) => {
191
+ // Prepare increments for each explicit signer from their non-increment calls only
192
+ const increments = (await Promise.all(Array.from(signerToNonIncrementCalls.entries()).map(async ([signer, nonIncrementCalls]) => {
150
193
  if (isExplicitSessionSigner(signer)) {
151
- return signer.prepareIncrements(wallet, chainId, associatedCalls, this.address, this._provider);
194
+ return signer.prepareIncrements(wallet, chainId, nonIncrementCalls, this.address, this._provider);
152
195
  }
153
196
  return [];
154
197
  }))).flat();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@0xsequence/wallet-core",
3
- "version": "3.0.0",
3
+ "version": "3.0.1",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -27,9 +27,9 @@
27
27
  "mipd": "^0.0.7",
28
28
  "ox": "^0.9.17",
29
29
  "viem": "^2.40.3",
30
- "@0xsequence/guard": "^3.0.0",
31
- "@0xsequence/wallet-primitives": "^3.0.0",
32
- "@0xsequence/relayer": "^3.0.0"
30
+ "@0xsequence/relayer": "^3.0.1",
31
+ "@0xsequence/wallet-primitives": "^3.0.1",
32
+ "@0xsequence/guard": "^3.0.1"
33
33
  },
34
34
  "scripts": {
35
35
  "build": "tsc",
@@ -1,7 +1,7 @@
1
1
  import { Constants, Payload, Permission, SessionConfig, SessionSignature } from '@0xsequence/wallet-primitives'
2
2
  import { AbiFunction, AbiParameters, Address, Bytes, Hash, Hex, Provider } from 'ox'
3
3
  import { MemoryPkStore, PkStore } from '../pk/index.js'
4
- import { ExplicitSessionSigner, SessionSignerValidity, UsageLimit } from './session.js'
4
+ import { ExplicitSessionSigner, isIncrementCall, SessionSignerValidity, UsageLimit } from './session.js'
5
5
 
6
6
  export type ExplicitParams = Omit<Permission.SessionPermissions, 'signer'>
7
7
 
@@ -208,11 +208,7 @@ export class Explicit implements ExplicitSessionSigner {
208
208
  sessionManagerAddress: Address.Address,
209
209
  provider?: Provider.Provider,
210
210
  ): Promise<boolean> {
211
- if (
212
- Address.isEqual(call.to, sessionManagerAddress) &&
213
- Hex.size(call.data) > 4 &&
214
- Hex.isEqual(Hex.slice(call.data, 0, 4), AbiFunction.getSelector(Constants.INCREMENT_USAGE_LIMIT))
215
- ) {
211
+ if (isIncrementCall(call, sessionManagerAddress)) {
216
212
  // Can sign increment usage calls
217
213
  return true
218
214
  }
@@ -234,11 +230,7 @@ export class Explicit implements ExplicitSessionSigner {
234
230
  ): Promise<SessionSignature.SessionCallSignature> {
235
231
  const call = payload.calls[callIdx]!
236
232
  let permissionIndex: number
237
- if (
238
- Address.isEqual(call.to, sessionManagerAddress) &&
239
- Hex.size(call.data) > 4 &&
240
- Hex.isEqual(Hex.slice(call.data, 0, 4), AbiFunction.getSelector(Constants.INCREMENT_USAGE_LIMIT))
241
- ) {
233
+ if (isIncrementCall(call, sessionManagerAddress)) {
242
234
  // Permission check not required. Use the first permission
243
235
  permissionIndex = 0
244
236
  } else {
@@ -1,5 +1,5 @@
1
- import { Payload, SessionConfig, SessionSignature } from '@0xsequence/wallet-primitives'
2
- import { Address, Hex, Provider } from 'ox'
1
+ import { Constants, Payload, SessionConfig, SessionSignature } from '@0xsequence/wallet-primitives'
2
+ import { AbiFunction, Address, Hex, Provider } from 'ox'
3
3
 
4
4
  export type SessionSignerInvalidReason =
5
5
  | 'Expired'
@@ -68,3 +68,11 @@ export function isExplicitSessionSigner(signer: SessionSigner): signer is Explic
68
68
  export function isImplicitSessionSigner(signer: SessionSigner): signer is ImplicitSessionSigner {
69
69
  return 'identitySigner' in signer
70
70
  }
71
+
72
+ export function isIncrementCall(call: Payload.Call, sessionManagerAddress: Address.Address): boolean {
73
+ return (
74
+ Address.isEqual(call.to, sessionManagerAddress) &&
75
+ Hex.size(call.data) >= 4 &&
76
+ Hex.isEqual(Hex.slice(call.data, 0, 4), AbiFunction.getSelector(Constants.INCREMENT_USAGE_LIMIT))
77
+ )
78
+ }
@@ -18,6 +18,7 @@ import {
18
18
  SessionSigner,
19
19
  SessionSignerInvalidReason,
20
20
  isImplicitSessionSigner,
21
+ isIncrementCall,
21
22
  UsageLimit,
22
23
  } from './session/index.js'
23
24
 
@@ -130,21 +131,16 @@ export class SessionManager implements SapientSigner {
130
131
  }))
131
132
  }
132
133
 
133
- async findSignersForCalls(wallet: Address.Address, chainId: number, calls: Payload.Call[]): Promise<SessionSigner[]> {
134
- // Only use signers that match the topology
135
- const topology = await this.topology
136
- const identitySigners = SessionConfig.getIdentitySigners(topology)
137
- if (identitySigners.length === 0) {
138
- throw new Error('Identity signers not found')
139
- }
140
-
141
- // Prioritize implicit signers
142
- const availableSigners = [...this._implicitSigners, ...this._explicitSigners]
143
- if (availableSigners.length === 0) {
144
- throw new Error('No signers match the topology')
145
- }
146
-
147
- // Find supported signers for each call
134
+ /**
135
+ * Find one signer per call from the given candidate list (first that supports each call).
136
+ */
137
+ private async findSignersForCallsWithCandidates(
138
+ wallet: Address.Address,
139
+ chainId: number,
140
+ calls: Payload.Call[],
141
+ topology: SessionConfig.SessionsTopology,
142
+ availableSigners: SessionSigner[],
143
+ ): Promise<SessionSigner[]> {
148
144
  const signers: SessionSigner[] = []
149
145
  for (const call of calls) {
150
146
  let supported = false
@@ -173,9 +169,67 @@ export class SessionManager implements SapientSigner {
173
169
  if (expiredSupportedSigner) {
174
170
  throw new Error(`Signer supporting call is expired: ${expiredSupportedSigner.address}`)
175
171
  }
176
- throw new Error(
177
- `No signer supported for call. ` + `Call: to=${call.to}, data=${call.data}, value=${call.value}, `,
178
- )
172
+ throw new Error(`No signer supported for call. Call: to=${call.to}, data=${call.data}, value=${call.value}, `)
173
+ }
174
+ }
175
+ return signers
176
+ }
177
+
178
+ async findSignersForCalls(wallet: Address.Address, chainId: number, calls: Payload.Call[]): Promise<SessionSigner[]> {
179
+ const topology = await this.topology
180
+ const identitySigners = SessionConfig.getIdentitySigners(topology)
181
+ if (identitySigners.length === 0) {
182
+ throw new Error('Identity signers not found')
183
+ }
184
+
185
+ const availableSigners = [...this._implicitSigners, ...this._explicitSigners]
186
+ if (availableSigners.length === 0) {
187
+ throw new Error('No signers match the topology')
188
+ }
189
+
190
+ const nonIncrementCalls: Payload.Call[] = []
191
+ const incrementCalls: Payload.Call[] = []
192
+ for (const call of calls) {
193
+ if (isIncrementCall(call, this.address)) {
194
+ incrementCalls.push(call)
195
+ } else {
196
+ nonIncrementCalls.push(call)
197
+ }
198
+ }
199
+
200
+ // Find signers for non-increment calls
201
+ const nonIncrementSigners =
202
+ nonIncrementCalls.length > 0
203
+ ? await this.findSignersForCallsWithCandidates(wallet, chainId, nonIncrementCalls, topology, availableSigners)
204
+ : []
205
+
206
+ let incrementSigners: SessionSigner[] = []
207
+ if (incrementCalls.length > 0) {
208
+ // Find signers for increment calls, preferring signers that signed non-increment calls
209
+ const incrementCandidates = [
210
+ ...nonIncrementSigners,
211
+ ...availableSigners.filter((s) => !nonIncrementSigners.includes(s)),
212
+ ]
213
+ incrementSigners = await this.findSignersForCallsWithCandidates(
214
+ wallet,
215
+ chainId,
216
+ incrementCalls,
217
+ topology,
218
+ incrementCandidates,
219
+ )
220
+ }
221
+
222
+ // Merge back in original call order
223
+ const signers: SessionSigner[] = []
224
+ let nonIncrementIndex = 0
225
+ let incrementIndex = 0
226
+ for (const call of calls) {
227
+ if (isIncrementCall(call, this.address)) {
228
+ signers.push(incrementSigners[incrementIndex]!)
229
+ incrementIndex++
230
+ } else {
231
+ signers.push(nonIncrementSigners[nonIncrementIndex]!)
232
+ nonIncrementIndex++
179
233
  }
180
234
  }
181
235
  return signers
@@ -191,20 +245,23 @@ export class SessionManager implements SapientSigner {
191
245
  }
192
246
  const signers = await this.findSignersForCalls(wallet, chainId, calls)
193
247
 
194
- // Create a map of signers to their associated calls
195
- const signerToCalls = new Map<SessionSigner, Payload.Call[]>()
248
+ // Map each signer to only their non-increment calls
249
+ const signerToNonIncrementCalls = new Map<SessionSigner, Payload.Call[]>()
196
250
  signers.forEach((signer, index) => {
197
251
  const call = calls[index]!
198
- const existingCalls = signerToCalls.get(signer) || []
199
- signerToCalls.set(signer, [...existingCalls, call])
252
+ if (isIncrementCall(call, this.address)) {
253
+ return
254
+ }
255
+ const existing = signerToNonIncrementCalls.get(signer) || []
256
+ signerToNonIncrementCalls.set(signer, [...existing, call])
200
257
  })
201
258
 
202
- // Prepare increments for each explicit signer with their associated calls
259
+ // Prepare increments for each explicit signer from their non-increment calls only
203
260
  const increments: UsageLimit[] = (
204
261
  await Promise.all(
205
- Array.from(signerToCalls.entries()).map(async ([signer, associatedCalls]) => {
262
+ Array.from(signerToNonIncrementCalls.entries()).map(async ([signer, nonIncrementCalls]) => {
206
263
  if (isExplicitSessionSigner(signer)) {
207
- return signer.prepareIncrements(wallet, chainId, associatedCalls, this.address, this._provider!)
264
+ return signer.prepareIncrements(wallet, chainId, nonIncrementCalls, this.address, this._provider!)
208
265
  }
209
266
  return []
210
267
  }),
package/test/constants.ts CHANGED
@@ -5,6 +5,8 @@ import { Abi, AbiEvent, Address } from 'ox'
5
5
  const envFile = process.env.CI ? '.env.test' : '.env.test.local'
6
6
  dotenvConfig({ path: envFile })
7
7
 
8
+ // Contracts are deployed on Arbitrum
9
+
8
10
  // Requires https://example.com redirectUrl
9
11
  export const EMITTER_ADDRESS1: Address.Address = '0xad90eB52BC180Bd9f66f50981E196f3E996278D3'
10
12
  // Requires https://another-example.com redirectUrl
@@ -1,4 +1,4 @@
1
- import { Extensions } from '@0xsequence/wallet-primitives'
1
+ import { Constants, Extensions } from '@0xsequence/wallet-primitives'
2
2
  import { AbiEvent, AbiFunction, Address, Bytes, Hex, Provider, RpcTransport, Secp256k1 } from 'ox'
3
3
  import { describe, expect, it } from 'vitest'
4
4
  import { Attestation, GenericTree, Payload, Permission, SessionConfig } from '../../primitives/src/index.js'
@@ -731,7 +731,7 @@ for (const extension of ALL_EXTENSIONS) {
731
731
  )
732
732
 
733
733
  it(
734
- 'signs a payload using an explicit session',
734
+ 'signs a payload using an explicit session with allowAll and value limit',
735
735
  async () => {
736
736
  const provider = Provider.from(RpcTransport.fromHttp(LOCAL_RPC_URL))
737
737
  const chainId = Number(await provider.request({ method: 'eth_chainId' }))
@@ -804,7 +804,7 @@ for (const extension of ALL_EXTENSIONS) {
804
804
  )
805
805
 
806
806
  it(
807
- 'signs a payload using an explicit session',
807
+ 'signs using explicit session with onlyOnce, consumes usage and rejects second call',
808
808
  async () => {
809
809
  const provider = Provider.from(RpcTransport.fromHttp(LOCAL_RPC_URL))
810
810
  const chainId = Number(await provider.request({ method: 'eth_chainId' }))
@@ -1357,5 +1357,347 @@ for (const extension of ALL_EXTENSIONS) {
1357
1357
  },
1358
1358
  timeout,
1359
1359
  )
1360
+
1361
+ it(
1362
+ 'two explicit sessions with same value limit: exhaust first then second send uses second session (increment from non-increment calls only)',
1363
+ async () => {
1364
+ const provider = Provider.from(RpcTransport.fromHttp(LOCAL_RPC_URL))
1365
+ const chainId = Number(await provider.request({ method: 'eth_chainId' }))
1366
+
1367
+ const identityPrivateKey = Secp256k1.randomPrivateKey()
1368
+ const identityAddress = Address.fromPublicKey(Secp256k1.getPublicKey({ privateKey: identityPrivateKey }))
1369
+ const stateProvider = new State.Local.Provider()
1370
+
1371
+ const targetAddress = randomAddress()
1372
+ const valueLimit = 500000000000000000n // 0.5 ETH per session
1373
+
1374
+ const sessionPermission: ExplicitSessionConfig = {
1375
+ chainId,
1376
+ valueLimit,
1377
+ deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
1378
+ permissions: [PermissionBuilder.for(targetAddress).allowAll().build()],
1379
+ }
1380
+
1381
+ const explicitPrivateKey1 = Secp256k1.randomPrivateKey()
1382
+ const explicitSigner1 = new Signers.Session.Explicit(explicitPrivateKey1, {
1383
+ ...sessionPermission,
1384
+ })
1385
+
1386
+ const explicitPrivateKey2 = Secp256k1.randomPrivateKey()
1387
+ const explicitSigner2 = new Signers.Session.Explicit(explicitPrivateKey2, {
1388
+ ...sessionPermission,
1389
+ })
1390
+
1391
+ let sessionTopology = SessionConfig.addExplicitSession(SessionConfig.emptySessionsTopology(identityAddress), {
1392
+ ...sessionPermission,
1393
+ signer: explicitSigner1.address,
1394
+ })
1395
+ sessionTopology = SessionConfig.addExplicitSession(sessionTopology, {
1396
+ ...sessionPermission,
1397
+ signer: explicitSigner2.address,
1398
+ })
1399
+ await stateProvider.saveTree(SessionConfig.sessionsTopologyToConfigurationTree(sessionTopology))
1400
+ const imageHash = GenericTree.hash(SessionConfig.sessionsTopologyToConfigurationTree(sessionTopology))
1401
+
1402
+ const wallet = await Wallet.fromConfiguration(
1403
+ {
1404
+ threshold: 1n,
1405
+ checkpoint: 0n,
1406
+ topology: [{ type: 'sapient-signer', address: extension.sessions, weight: 1n, imageHash }, Hex.random(32)],
1407
+ },
1408
+ { stateProvider },
1409
+ )
1410
+ // Fund wallet with 2 ETH so we can send 0.5 ETH twice (each tx needs value + gas)
1411
+ await provider.request({
1412
+ method: 'anvil_setBalance',
1413
+ params: [wallet.address, Hex.fromNumber(2n * 1000000000000000000n)],
1414
+ })
1415
+
1416
+ const sessionManager = new Signers.SessionManager(wallet, {
1417
+ provider,
1418
+ sessionManagerAddress: extension.sessions,
1419
+ explicitSigners: [explicitSigner1, explicitSigner2],
1420
+ })
1421
+
1422
+ const call: Payload.Call = {
1423
+ to: targetAddress,
1424
+ value: valueLimit, // one full limit
1425
+ data: '0x' as Hex.Hex,
1426
+ gasLimit: 0n,
1427
+ delegateCall: false,
1428
+ onlyFallback: false,
1429
+ behaviorOnError: 'revert',
1430
+ }
1431
+
1432
+ // First send: uses first session (exhausts it)
1433
+ const increment1 = await sessionManager.prepareIncrement(wallet.address, chainId, [call])
1434
+ expect(increment1).not.toBeNull()
1435
+ const calls1 = includeIncrement([call], increment1!, extension.sessions)
1436
+ const tx1 = await buildAndSignCall(wallet, sessionManager, calls1, provider, chainId)
1437
+ await simulateTransaction(provider, tx1)
1438
+
1439
+ // Second send: same call. First session is exhausted so findSignersForCalls picks second session.
1440
+ // Payload is [call, increment] (or [increment, call]). signSapient must derive expectedIncrement
1441
+ // from non-increment calls only so it matches the increment we built for the second session.
1442
+ const increment2 = await sessionManager.prepareIncrement(wallet.address, chainId, [call])
1443
+ expect(increment2).not.toBeNull()
1444
+ const calls2 = includeIncrement([call], increment2!, extension.sessions)
1445
+ const tx2 = await buildAndSignCall(wallet, sessionManager, calls2, provider, chainId)
1446
+ await simulateTransaction(provider, tx2)
1447
+ },
1448
+ timeout,
1449
+ )
1450
+
1451
+ describe('increment built from non-increment calls only', () => {
1452
+ it(
1453
+ 'prepareIncrement returns null when calls contain only an increment call (no non-increment calls)',
1454
+ async () => {
1455
+ const provider = Provider.from(RpcTransport.fromHttp(LOCAL_RPC_URL))
1456
+ const chainId = Number(await provider.request({ method: 'eth_chainId' }))
1457
+
1458
+ const identityPrivateKey = Secp256k1.randomPrivateKey()
1459
+ const identityAddress = Address.fromPublicKey(Secp256k1.getPublicKey({ privateKey: identityPrivateKey }))
1460
+ const stateProvider = new State.Local.Provider()
1461
+
1462
+ const sessionPermission: ExplicitSessionConfig = {
1463
+ chainId,
1464
+ valueLimit: 0n,
1465
+ deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
1466
+ permissions: [PermissionBuilder.for(EMITTER_ADDRESS1).allowAll().build()],
1467
+ }
1468
+ const explicitSigner = new Signers.Session.Explicit(Secp256k1.randomPrivateKey(), sessionPermission)
1469
+ const sessionTopology = SessionConfig.addExplicitSession(
1470
+ SessionConfig.emptySessionsTopology(identityAddress),
1471
+ {
1472
+ ...sessionPermission,
1473
+ signer: explicitSigner.address,
1474
+ },
1475
+ )
1476
+ await stateProvider.saveTree(SessionConfig.sessionsTopologyToConfigurationTree(sessionTopology))
1477
+ const imageHash = GenericTree.hash(SessionConfig.sessionsTopologyToConfigurationTree(sessionTopology))
1478
+
1479
+ const wallet = await Wallet.fromConfiguration(
1480
+ {
1481
+ threshold: 1n,
1482
+ checkpoint: 0n,
1483
+ topology: [
1484
+ { type: 'sapient-signer', address: extension.sessions, weight: 1n, imageHash },
1485
+ Hex.random(32),
1486
+ ],
1487
+ },
1488
+ { stateProvider },
1489
+ )
1490
+ const sessionManager = new Signers.SessionManager(wallet, {
1491
+ provider,
1492
+ sessionManagerAddress: extension.sessions,
1493
+ explicitSigners: [explicitSigner],
1494
+ })
1495
+
1496
+ // Only an increment call (no non-increment calls). Contract would reject payload with only self-call; we return null.
1497
+ const incrementOnlyCall: Payload.Call = {
1498
+ to: extension.sessions,
1499
+ data: AbiFunction.encodeData(Constants.INCREMENT_USAGE_LIMIT, [[]]),
1500
+ value: 0n,
1501
+ gasLimit: 0n,
1502
+ delegateCall: false,
1503
+ onlyFallback: false,
1504
+ behaviorOnError: 'revert',
1505
+ }
1506
+ const result = await sessionManager.prepareIncrement(wallet.address, chainId, [incrementOnlyCall])
1507
+ expect(result).toBeNull()
1508
+ },
1509
+ timeout,
1510
+ )
1511
+
1512
+ it(
1513
+ 'prepareIncrement([increment, nonIncrementCall]) produces same increment data as prepareIncrement([nonIncrementCall])',
1514
+ async () => {
1515
+ const provider = Provider.from(RpcTransport.fromHttp(LOCAL_RPC_URL))
1516
+ const chainId = Number(await provider.request({ method: 'eth_chainId' }))
1517
+
1518
+ const identityPrivateKey = Secp256k1.randomPrivateKey()
1519
+ const identityAddress = Address.fromPublicKey(Secp256k1.getPublicKey({ privateKey: identityPrivateKey }))
1520
+ const stateProvider = new State.Local.Provider()
1521
+
1522
+ const sessionPermission: ExplicitSessionConfig = {
1523
+ chainId,
1524
+ valueLimit: 0n,
1525
+ deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
1526
+ permissions: [PermissionBuilder.for(EMITTER_ADDRESS1).forFunction(EMITTER_FUNCTIONS[0]).onlyOnce().build()],
1527
+ }
1528
+ const explicitSigner = new Signers.Session.Explicit(Secp256k1.randomPrivateKey(), sessionPermission)
1529
+ const sessionTopology = SessionConfig.addExplicitSession(
1530
+ SessionConfig.emptySessionsTopology(identityAddress),
1531
+ {
1532
+ ...sessionPermission,
1533
+ signer: explicitSigner.address,
1534
+ },
1535
+ )
1536
+ await stateProvider.saveTree(SessionConfig.sessionsTopologyToConfigurationTree(sessionTopology))
1537
+ const imageHash = GenericTree.hash(SessionConfig.sessionsTopologyToConfigurationTree(sessionTopology))
1538
+
1539
+ const wallet = await Wallet.fromConfiguration(
1540
+ {
1541
+ threshold: 1n,
1542
+ checkpoint: 0n,
1543
+ topology: [
1544
+ { type: 'sapient-signer', address: extension.sessions, weight: 1n, imageHash },
1545
+ Hex.random(32),
1546
+ ],
1547
+ },
1548
+ { stateProvider },
1549
+ )
1550
+ const sessionManager = new Signers.SessionManager(wallet, {
1551
+ provider,
1552
+ sessionManagerAddress: extension.sessions,
1553
+ explicitSigners: [explicitSigner],
1554
+ })
1555
+
1556
+ const nonIncrementCall: Payload.Call = {
1557
+ to: EMITTER_ADDRESS1,
1558
+ value: 0n,
1559
+ data: AbiFunction.encodeData(EMITTER_FUNCTIONS[0]),
1560
+ gasLimit: 0n,
1561
+ delegateCall: false,
1562
+ onlyFallback: false,
1563
+ behaviorOnError: 'revert',
1564
+ }
1565
+
1566
+ const fromNonIncrementOnly = await sessionManager.prepareIncrement(wallet.address, chainId, [
1567
+ nonIncrementCall,
1568
+ ])
1569
+ expect(fromNonIncrementOnly).not.toBeNull()
1570
+
1571
+ // Pass [staleIncrement, nonIncrementCall] — increment is ignored when building; result should match
1572
+ const withStaleIncrement = await sessionManager.prepareIncrement(wallet.address, chainId, [
1573
+ fromNonIncrementOnly!,
1574
+ nonIncrementCall,
1575
+ ])
1576
+ expect(withStaleIncrement).not.toBeNull()
1577
+ expect(withStaleIncrement!.data).toEqual(fromNonIncrementOnly!.data)
1578
+ },
1579
+ timeout,
1580
+ )
1581
+
1582
+ it(
1583
+ 'payload with implicit and explicit: increment built only from explicit non-increment call',
1584
+ async () => {
1585
+ const provider = Provider.from(RpcTransport.fromHttp(LOCAL_RPC_URL))
1586
+ const chainId = Number(await provider.request({ method: 'eth_chainId' }))
1587
+
1588
+ const identityPrivateKey = Secp256k1.randomPrivateKey()
1589
+ const identityAddress = Address.fromPublicKey(Secp256k1.getPublicKey({ privateKey: identityPrivateKey }))
1590
+ const stateProvider = new State.Local.Provider()
1591
+
1592
+ const redirectUrl = 'https://example.com'
1593
+ const implicitSigner = await createImplicitSigner(redirectUrl, identityPrivateKey)
1594
+ const sessionPermission: ExplicitSessionConfig = {
1595
+ chainId,
1596
+ valueLimit: 0n,
1597
+ deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
1598
+ permissions: [PermissionBuilder.for(EMITTER_ADDRESS1).forFunction(EMITTER_FUNCTIONS[0]).onlyOnce().build()],
1599
+ }
1600
+ const explicitSigner = new Signers.Session.Explicit(Secp256k1.randomPrivateKey(), sessionPermission)
1601
+
1602
+ // Topology: identity + blacklist (implicit) + explicit session
1603
+ let sessionTopology = SessionConfig.emptySessionsTopology(identityAddress)
1604
+ sessionTopology = SessionConfig.addExplicitSession(sessionTopology, {
1605
+ ...sessionPermission,
1606
+ signer: explicitSigner.address,
1607
+ })
1608
+ await stateProvider.saveTree(SessionConfig.sessionsTopologyToConfigurationTree(sessionTopology))
1609
+ const imageHash = GenericTree.hash(SessionConfig.sessionsTopologyToConfigurationTree(sessionTopology))
1610
+
1611
+ const wallet = await Wallet.fromConfiguration(
1612
+ {
1613
+ threshold: 1n,
1614
+ checkpoint: 0n,
1615
+ topology: [
1616
+ { type: 'sapient-signer', address: extension.sessions, weight: 1n, imageHash },
1617
+ Hex.random(32),
1618
+ ],
1619
+ },
1620
+ { stateProvider },
1621
+ )
1622
+ const sessionManager = new Signers.SessionManager(wallet, {
1623
+ provider,
1624
+ sessionManagerAddress: extension.sessions,
1625
+ implicitSigners: [implicitSigner],
1626
+ explicitSigners: [explicitSigner],
1627
+ })
1628
+
1629
+ // Explicit call only (onlyOnce produces an increment; implicit does not match this target)
1630
+ const call: Payload.Call = {
1631
+ to: EMITTER_ADDRESS1,
1632
+ value: 0n,
1633
+ data: AbiFunction.encodeData(EMITTER_FUNCTIONS[0]),
1634
+ gasLimit: 0n,
1635
+ delegateCall: false,
1636
+ onlyFallback: false,
1637
+ behaviorOnError: 'revert',
1638
+ }
1639
+ const increment = await sessionManager.prepareIncrement(wallet.address, chainId, [call])
1640
+ expect(increment).not.toBeNull()
1641
+ const calls = includeIncrement([call], increment!, extension.sessions)
1642
+ const transaction = await buildAndSignCall(wallet, sessionManager, calls, provider, chainId)
1643
+ await simulateTransaction(provider, transaction, EMITTER_EVENT_TOPICS[0])
1644
+ },
1645
+ timeout,
1646
+ )
1647
+
1648
+ it('signSapient handles selector-only self increment call consistently', async () => {
1649
+ const identityPrivateKey = Secp256k1.randomPrivateKey()
1650
+ const identityAddress = Address.fromPublicKey(Secp256k1.getPublicKey({ privateKey: identityPrivateKey }))
1651
+ const stateProvider = new State.Local.Provider()
1652
+
1653
+ const explicitSigner = new Signers.Session.Explicit(Secp256k1.randomPrivateKey(), {
1654
+ chainId: 0,
1655
+ valueLimit: 0n,
1656
+ deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
1657
+ permissions: [PermissionBuilder.for(EMITTER_ADDRESS1).allowAll().build()],
1658
+ })
1659
+
1660
+ const sessionTopology = SessionConfig.addExplicitSession(SessionConfig.emptySessionsTopology(identityAddress), {
1661
+ ...explicitSigner.sessionPermissions,
1662
+ signer: explicitSigner.address,
1663
+ })
1664
+ await stateProvider.saveTree(SessionConfig.sessionsTopologyToConfigurationTree(sessionTopology))
1665
+ const imageHash = GenericTree.hash(SessionConfig.sessionsTopologyToConfigurationTree(sessionTopology))
1666
+
1667
+ const wallet = await Wallet.fromConfiguration(
1668
+ {
1669
+ threshold: 1n,
1670
+ checkpoint: 0n,
1671
+ topology: [{ type: 'sapient-signer', address: extension.sessions, weight: 1n, imageHash }, Hex.random(32)],
1672
+ },
1673
+ { stateProvider },
1674
+ )
1675
+ const sessionManager = new Signers.SessionManager(wallet, {
1676
+ sessionManagerAddress: extension.sessions,
1677
+ explicitSigners: [explicitSigner],
1678
+ })
1679
+
1680
+ const payload: Payload.Parented = {
1681
+ type: 'call',
1682
+ nonce: 0n,
1683
+ space: 0n,
1684
+ calls: [
1685
+ {
1686
+ to: extension.sessions,
1687
+ data: AbiFunction.getSelector(Constants.INCREMENT_USAGE_LIMIT),
1688
+ value: 0n,
1689
+ gasLimit: 0n,
1690
+ delegateCall: false,
1691
+ onlyFallback: false,
1692
+ behaviorOnError: 'revert',
1693
+ },
1694
+ ],
1695
+ parentWallets: [wallet.address],
1696
+ }
1697
+
1698
+ const signature = await sessionManager.signSapient(wallet.address, 0, payload, imageHash)
1699
+ expect(signature.type).toBe('sapient')
1700
+ })
1701
+ })
1360
1702
  })
1361
1703
  }