ox 1.8.10 → 1.8.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/core/Authorization.d.ts.map +1 -1
- package/dist/core/Authorization.js +44 -6
- package/dist/core/Authorization.js.map +1 -1
- package/dist/core/Siwe.d.ts.map +1 -1
- package/dist/core/Siwe.js +1 -1
- package/dist/core/Siwe.js.map +1 -1
- package/dist/tempo/AccountConfig.d.ts +7 -17
- package/dist/tempo/AccountConfig.d.ts.map +1 -1
- package/dist/tempo/AccountConfig.js +8 -26
- package/dist/tempo/AccountConfig.js.map +1 -1
- package/dist/tempo/AccountOperation.d.ts +1 -1
- package/dist/tempo/AccountOperation.js +1 -1
- package/dist/tempo/index.d.ts +1 -3
- package/dist/tempo/index.d.ts.map +1 -1
- package/dist/tempo/index.js +1 -3
- package/dist/tempo/index.js.map +1 -1
- package/dist/zod/Authorization.d.ts.map +1 -1
- package/dist/zod/Authorization.js +6 -9
- package/dist/zod/Authorization.js.map +1 -1
- package/package.json +1 -1
- package/src/core/Authorization.ts +43 -6
- package/src/core/Siwe.ts +1 -1
- package/src/core/_test/Authorization.test.ts +166 -0
- package/src/core/_test/Siwe.test.ts +53 -0
- package/src/core/_test/TransactionEnvelopeEip7702.test.ts +66 -0
- package/src/tempo/AccountConfig.test.ts +34 -47
- package/src/tempo/AccountConfig.ts +9 -37
- package/src/tempo/AccountOperation.test.ts +36 -37
- package/src/tempo/AccountOperation.ts +1 -1
- package/src/tempo/SignatureEnvelope.test.ts +1 -3
- package/src/tempo/configurableAccounts.e2e.test.ts +1 -2
- package/src/tempo/index.ts +1 -3
- package/src/version.ts +1 -1
- package/src/zod/Authorization.ts +6 -24
- package/src/zod/_test/Authorization.test.ts +35 -2
- package/src/zod/_test/TransactionRequest.test.ts +1 -1
|
@@ -179,7 +179,11 @@ export declare namespace from {
|
|
|
179
179
|
*/
|
|
180
180
|
export function fromRpc(authorization: Rpc): Signed {
|
|
181
181
|
const { address, chainId, nonce } = authorization
|
|
182
|
-
|
|
182
|
+
// EIP-7702 permits any `y_parity` below 2**8 in an authorization tuple, so
|
|
183
|
+
// check `yParity` against one byte rather than against 0 or 1.
|
|
184
|
+
const signature = Signature.fromRpc(authorization)
|
|
185
|
+
Signature.assert({ r: signature.r, s: signature.s })
|
|
186
|
+
assertYParity(signature.yParity)
|
|
183
187
|
|
|
184
188
|
return {
|
|
185
189
|
address,
|
|
@@ -278,8 +282,18 @@ export function fromTuple<const tuple extends Tuple>(
|
|
|
278
282
|
chainId: chainId === '0x' ? 0 : Number(chainId),
|
|
279
283
|
nonce: nonce === '0x' ? 0n : BigInt(nonce),
|
|
280
284
|
}
|
|
281
|
-
if (yParity && r && s)
|
|
282
|
-
|
|
285
|
+
if (yParity && r && s) {
|
|
286
|
+
// EIP-7702 permits any `y_parity` below 2**8 in an authorization tuple, so
|
|
287
|
+
// check `yParity` against one byte rather than against 0 or 1.
|
|
288
|
+
const signature = {
|
|
289
|
+
r: Hex.padLeft(r, 32),
|
|
290
|
+
s: Hex.padLeft(s, 32),
|
|
291
|
+
yParity: yParity === '0x' ? 0 : Number(yParity),
|
|
292
|
+
}
|
|
293
|
+
Signature.assert({ r: signature.r, s: signature.s })
|
|
294
|
+
assertYParity(signature.yParity)
|
|
295
|
+
args = { ...args, ...signature }
|
|
296
|
+
}
|
|
283
297
|
return from(args) as never
|
|
284
298
|
}
|
|
285
299
|
|
|
@@ -500,6 +514,7 @@ export declare namespace hash {
|
|
|
500
514
|
*/
|
|
501
515
|
export function toRpc(authorization: toRpc.Input): Rpc {
|
|
502
516
|
const { address, chainId, nonce, ...signature } = authorization
|
|
517
|
+
assertYParity(Number(signature.yParity))
|
|
503
518
|
|
|
504
519
|
return {
|
|
505
520
|
address,
|
|
@@ -576,13 +591,23 @@ export declare namespace toRpcList {
|
|
|
576
591
|
export function toTuple<const authorization extends Authorization>(
|
|
577
592
|
authorization: authorization,
|
|
578
593
|
): toTuple.ReturnType<authorization> {
|
|
579
|
-
const { address, chainId, nonce } = authorization
|
|
580
|
-
const signature = Signature.extract(
|
|
594
|
+
const { address, chainId, nonce, r, s, yParity } = authorization
|
|
595
|
+
const signature = Signature.extract({ r, s })
|
|
596
|
+
if (signature && typeof yParity !== 'undefined') assertYParity(yParity)
|
|
581
597
|
return [
|
|
582
598
|
chainId ? Hex.fromNumber(chainId) : '0x',
|
|
583
599
|
address,
|
|
584
600
|
nonce ? Hex.fromNumber(nonce) : '0x',
|
|
585
|
-
|
|
601
|
+
// EIP-7702 permits any `y_parity` below 2**8 in an authorization tuple, and a
|
|
602
|
+
// tuple that fails recovery does not invalidate the transaction. Encode
|
|
603
|
+
// `yParity` as is, so that serialization preserves the transaction hash.
|
|
604
|
+
...(signature
|
|
605
|
+
? [
|
|
606
|
+
yParity ? Hex.fromNumber(yParity, { size: 1 }) : '0x',
|
|
607
|
+
Hex.trimLeft(signature.r),
|
|
608
|
+
Hex.trimLeft(signature.s),
|
|
609
|
+
]
|
|
610
|
+
: []),
|
|
586
611
|
] as never
|
|
587
612
|
}
|
|
588
613
|
|
|
@@ -656,3 +681,15 @@ export declare namespace toTupleList {
|
|
|
656
681
|
|
|
657
682
|
type ErrorType = Errors.GlobalErrorType
|
|
658
683
|
}
|
|
684
|
+
|
|
685
|
+
// Asserts that an EIP-7702 authorization `yParity` fits in one byte.
|
|
686
|
+
function assertYParity(yParity: number) {
|
|
687
|
+
if (Number.isInteger(yParity) && yParity >= 0 && yParity < 256) return
|
|
688
|
+
throw new Hex.IntegerOutOfRangeError({
|
|
689
|
+
max: '255',
|
|
690
|
+
min: '0',
|
|
691
|
+
signed: false,
|
|
692
|
+
size: 1,
|
|
693
|
+
value: `${yParity}`,
|
|
694
|
+
})
|
|
695
|
+
}
|
package/src/core/Siwe.ts
CHANGED
|
@@ -4,7 +4,7 @@ import * as Hex from './Hex.js'
|
|
|
4
4
|
import type { ExactPartial } from './internal/types.js'
|
|
5
5
|
|
|
6
6
|
export const domainRegex =
|
|
7
|
-
/^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}(:[0-9]{1,5})?$/
|
|
7
|
+
/^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+(?:[a-zA-Z]{2,63}|[xX][nN]--[a-zA-Z0-9-]{0,58}[a-zA-Z0-9])(:[0-9]{1,5})?$/
|
|
8
8
|
|
|
9
9
|
export const ipRegex =
|
|
10
10
|
/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(:[0-9]{1,5})?$/
|
|
@@ -151,6 +151,43 @@ describe('fromRpc', () => {
|
|
|
151
151
|
}
|
|
152
152
|
`)
|
|
153
153
|
})
|
|
154
|
+
|
|
155
|
+
test('behavior: yParity above 1', () => {
|
|
156
|
+
expect(
|
|
157
|
+
Authorization.fromRpc({
|
|
158
|
+
address: '0xc498cea4bfedbb8de856491bdd9967e677775f4f',
|
|
159
|
+
chainId: '0x0',
|
|
160
|
+
nonce: '0x6',
|
|
161
|
+
r: '0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512',
|
|
162
|
+
s: '0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191',
|
|
163
|
+
yParity: '0x1c',
|
|
164
|
+
}),
|
|
165
|
+
).toMatchInlineSnapshot(`
|
|
166
|
+
{
|
|
167
|
+
"address": "0xc498cea4bfedbb8de856491bdd9967e677775f4f",
|
|
168
|
+
"chainId": 0,
|
|
169
|
+
"nonce": 6n,
|
|
170
|
+
"r": "0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512",
|
|
171
|
+
"s": "0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191",
|
|
172
|
+
"yParity": 28,
|
|
173
|
+
}
|
|
174
|
+
`)
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
test('error: yParity above 2**8 - 1', () => {
|
|
178
|
+
expect(() =>
|
|
179
|
+
Authorization.fromRpc({
|
|
180
|
+
address: '0xc498cea4bfedbb8de856491bdd9967e677775f4f',
|
|
181
|
+
chainId: '0x0',
|
|
182
|
+
nonce: '0x6',
|
|
183
|
+
r: '0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512',
|
|
184
|
+
s: '0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191',
|
|
185
|
+
yParity: '0x100',
|
|
186
|
+
}),
|
|
187
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
188
|
+
`[Hex.IntegerOutOfRangeError: Number \`256\` is not in safe 8-bit unsigned integer range (\`0\` to \`255\`)]`,
|
|
189
|
+
)
|
|
190
|
+
})
|
|
154
191
|
})
|
|
155
192
|
|
|
156
193
|
describe('fromRpcList', () => {
|
|
@@ -251,6 +288,44 @@ describe('fromTuple', () => {
|
|
|
251
288
|
}
|
|
252
289
|
`)
|
|
253
290
|
})
|
|
291
|
+
|
|
292
|
+
test('behavior: yParity above 1', () => {
|
|
293
|
+
const tuple = [
|
|
294
|
+
'0x',
|
|
295
|
+
'0xc498cea4bfedbb8de856491bdd9967e677775f4f',
|
|
296
|
+
'0x06',
|
|
297
|
+
'0x1c',
|
|
298
|
+
'0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512',
|
|
299
|
+
'0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191',
|
|
300
|
+
] as const satisfies Authorization.Tuple
|
|
301
|
+
const authorization = Authorization.fromTuple(tuple)
|
|
302
|
+
expect(authorization).toMatchInlineSnapshot(`
|
|
303
|
+
{
|
|
304
|
+
"address": "0xc498cea4bfedbb8de856491bdd9967e677775f4f",
|
|
305
|
+
"chainId": 0,
|
|
306
|
+
"nonce": 6n,
|
|
307
|
+
"r": "0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512",
|
|
308
|
+
"s": "0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191",
|
|
309
|
+
"yParity": 28,
|
|
310
|
+
}
|
|
311
|
+
`)
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
test('error: yParity above 2**8 - 1', () => {
|
|
315
|
+
const tuple = [
|
|
316
|
+
'0x',
|
|
317
|
+
'0xc498cea4bfedbb8de856491bdd9967e677775f4f',
|
|
318
|
+
'0x06',
|
|
319
|
+
'0x0100',
|
|
320
|
+
'0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512',
|
|
321
|
+
'0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191',
|
|
322
|
+
] as const satisfies Authorization.Tuple
|
|
323
|
+
expect(() =>
|
|
324
|
+
Authorization.fromTuple(tuple),
|
|
325
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
326
|
+
`[Hex.IntegerOutOfRangeError: Number \`256\` is not in safe 8-bit unsigned integer range (\`0\` to \`255\`)]`,
|
|
327
|
+
)
|
|
328
|
+
})
|
|
254
329
|
})
|
|
255
330
|
|
|
256
331
|
describe('fromTupleList', () => {
|
|
@@ -454,6 +529,43 @@ describe('toRpc', () => {
|
|
|
454
529
|
expect(fromBigint).toEqual(fromNumber)
|
|
455
530
|
expect(fromBigint).toEqual(fromHex)
|
|
456
531
|
})
|
|
532
|
+
|
|
533
|
+
test('behavior: yParity above 1', () => {
|
|
534
|
+
expect(
|
|
535
|
+
Authorization.toRpc({
|
|
536
|
+
address: '0xc498cea4bfedbb8de856491bdd9967e677775f4f',
|
|
537
|
+
chainId: 0,
|
|
538
|
+
nonce: 6n,
|
|
539
|
+
r: '0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512',
|
|
540
|
+
s: '0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191',
|
|
541
|
+
yParity: 28,
|
|
542
|
+
}),
|
|
543
|
+
).toMatchInlineSnapshot(`
|
|
544
|
+
{
|
|
545
|
+
"address": "0xc498cea4bfedbb8de856491bdd9967e677775f4f",
|
|
546
|
+
"chainId": "0x0",
|
|
547
|
+
"nonce": "0x6",
|
|
548
|
+
"r": "0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512",
|
|
549
|
+
"s": "0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191",
|
|
550
|
+
"yParity": "0x1c",
|
|
551
|
+
}
|
|
552
|
+
`)
|
|
553
|
+
})
|
|
554
|
+
|
|
555
|
+
test('error: yParity above 2**8 - 1', () => {
|
|
556
|
+
expect(() =>
|
|
557
|
+
Authorization.toRpc({
|
|
558
|
+
address: '0xc498cea4bfedbb8de856491bdd9967e677775f4f',
|
|
559
|
+
chainId: 0,
|
|
560
|
+
nonce: 6n,
|
|
561
|
+
r: '0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512',
|
|
562
|
+
s: '0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191',
|
|
563
|
+
yParity: 256,
|
|
564
|
+
}),
|
|
565
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
566
|
+
`[Hex.IntegerOutOfRangeError: Number \`256\` is not in safe 8-bit unsigned integer range (\`0\` to \`255\`)]`,
|
|
567
|
+
)
|
|
568
|
+
})
|
|
457
569
|
})
|
|
458
570
|
|
|
459
571
|
describe('toRpcList', () => {
|
|
@@ -540,6 +652,60 @@ describe('toTuple', () => {
|
|
|
540
652
|
`)
|
|
541
653
|
}
|
|
542
654
|
})
|
|
655
|
+
|
|
656
|
+
test('behavior: yParity above 1', () => {
|
|
657
|
+
const authorization = Authorization.from({
|
|
658
|
+
address: '0xc498cea4bfedbb8de856491bdd9967e677775f4f',
|
|
659
|
+
chainId: 0,
|
|
660
|
+
nonce: 6n,
|
|
661
|
+
r: '0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512',
|
|
662
|
+
s: '0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191',
|
|
663
|
+
yParity: 28,
|
|
664
|
+
})
|
|
665
|
+
const tuple = Authorization.toTuple(authorization)
|
|
666
|
+
expect(tuple).toMatchInlineSnapshot(`
|
|
667
|
+
[
|
|
668
|
+
"0x",
|
|
669
|
+
"0xc498cea4bfedbb8de856491bdd9967e677775f4f",
|
|
670
|
+
"0x6",
|
|
671
|
+
"0x1c",
|
|
672
|
+
"0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512",
|
|
673
|
+
"0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191",
|
|
674
|
+
]
|
|
675
|
+
`)
|
|
676
|
+
})
|
|
677
|
+
|
|
678
|
+
test('error: yParity above 2**8 - 1', () => {
|
|
679
|
+
const authorization = Authorization.from({
|
|
680
|
+
address: '0xc498cea4bfedbb8de856491bdd9967e677775f4f',
|
|
681
|
+
chainId: 0,
|
|
682
|
+
nonce: 6n,
|
|
683
|
+
r: '0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512',
|
|
684
|
+
s: '0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191',
|
|
685
|
+
yParity: 256,
|
|
686
|
+
})
|
|
687
|
+
expect(() =>
|
|
688
|
+
Authorization.toTuple(authorization),
|
|
689
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
690
|
+
`[Hex.IntegerOutOfRangeError: Number \`256\` is not in safe 8-bit unsigned integer range (\`0\` to \`255\`)]`,
|
|
691
|
+
)
|
|
692
|
+
})
|
|
693
|
+
|
|
694
|
+
test('error: yParity not an integer', () => {
|
|
695
|
+
const authorization = Authorization.from({
|
|
696
|
+
address: '0xc498cea4bfedbb8de856491bdd9967e677775f4f',
|
|
697
|
+
chainId: 0,
|
|
698
|
+
nonce: 6n,
|
|
699
|
+
r: '0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512',
|
|
700
|
+
s: '0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191',
|
|
701
|
+
yParity: Number.NaN,
|
|
702
|
+
})
|
|
703
|
+
expect(() =>
|
|
704
|
+
Authorization.toTuple(authorization),
|
|
705
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
706
|
+
`[Hex.IntegerOutOfRangeError: Number \`NaN\` is not in safe 8-bit unsigned integer range (\`0\` to \`255\`)]`,
|
|
707
|
+
)
|
|
708
|
+
})
|
|
543
709
|
})
|
|
544
710
|
|
|
545
711
|
describe('toTupleList', () => {
|
|
@@ -61,6 +61,40 @@ describe('createMessage', () => {
|
|
|
61
61
|
0xA0Cf798816D4b9b9866b5330EEa46a18382f251e
|
|
62
62
|
|
|
63
63
|
|
|
64
|
+
URI: https://example.com/path
|
|
65
|
+
Version: 1
|
|
66
|
+
Chain ID: 1
|
|
67
|
+
Nonce: foobarbaz
|
|
68
|
+
Issued At: 2023-02-01T00:00:00.000Z"
|
|
69
|
+
`)
|
|
70
|
+
|
|
71
|
+
expect(
|
|
72
|
+
Siwe.createMessage({
|
|
73
|
+
...message,
|
|
74
|
+
domain: 'example.xn--p1ai',
|
|
75
|
+
}),
|
|
76
|
+
).toMatchInlineSnapshot(`
|
|
77
|
+
"example.xn--p1ai wants you to sign in with your Ethereum account:
|
|
78
|
+
0xA0Cf798816D4b9b9866b5330EEa46a18382f251e
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
URI: https://example.com/path
|
|
82
|
+
Version: 1
|
|
83
|
+
Chain ID: 1
|
|
84
|
+
Nonce: foobarbaz
|
|
85
|
+
Issued At: 2023-02-01T00:00:00.000Z"
|
|
86
|
+
`)
|
|
87
|
+
|
|
88
|
+
expect(
|
|
89
|
+
Siwe.createMessage({
|
|
90
|
+
...message,
|
|
91
|
+
domain: 'example.XN--P1AI',
|
|
92
|
+
}),
|
|
93
|
+
).toMatchInlineSnapshot(`
|
|
94
|
+
"example.XN--P1AI wants you to sign in with your Ethereum account:
|
|
95
|
+
0xA0Cf798816D4b9b9866b5330EEa46a18382f251e
|
|
96
|
+
|
|
97
|
+
|
|
64
98
|
URI: https://example.com/path
|
|
65
99
|
Version: 1
|
|
66
100
|
Chain ID: 1
|
|
@@ -431,6 +465,12 @@ describe('createMessage', () => {
|
|
|
431
465
|
'example.com:3000',
|
|
432
466
|
'localhost:3000',
|
|
433
467
|
'127.0.0.1:3000',
|
|
468
|
+
'example.xN--p1ai',
|
|
469
|
+
'example.xn--p1ai:443',
|
|
470
|
+
'example.xn--vermgensberater-ctb',
|
|
471
|
+
// 63 octets: "xn--" plus 59 LDH characters.
|
|
472
|
+
`example.xn--${'a'.repeat(59)}`,
|
|
473
|
+
`example.${'a'.repeat(63)}`,
|
|
434
474
|
])('valid domain `%s`', (domain) => {
|
|
435
475
|
expect(
|
|
436
476
|
Siwe.createMessage({
|
|
@@ -449,6 +489,13 @@ describe('createMessage', () => {
|
|
|
449
489
|
'http://127.0.0.1:3000',
|
|
450
490
|
'foobarbaz',
|
|
451
491
|
'-example.com',
|
|
492
|
+
'example.xn--',
|
|
493
|
+
'example.xn--p1ai-',
|
|
494
|
+
'example.xx--p1ai',
|
|
495
|
+
'xn--p1ai',
|
|
496
|
+
// 64 octets: one past the maximum label length.
|
|
497
|
+
`example.xn--${'a'.repeat(60)}`,
|
|
498
|
+
`example.${'a'.repeat(64)}`,
|
|
452
499
|
])('invalid domain `%s`', (domain) => {
|
|
453
500
|
expect(() =>
|
|
454
501
|
Siwe.createMessage({
|
|
@@ -459,6 +506,12 @@ describe('createMessage', () => {
|
|
|
459
506
|
})
|
|
460
507
|
})
|
|
461
508
|
|
|
509
|
+
describe('domainRegex', () => {
|
|
510
|
+
test('behavior: captures the port in group 3', () => {
|
|
511
|
+
expect(Siwe.domainRegex.exec('example.xn--p1ai:443')?.[3]).toBe(':443')
|
|
512
|
+
})
|
|
513
|
+
})
|
|
514
|
+
|
|
462
515
|
describe('generateNonce', () => {
|
|
463
516
|
test('default', () => {
|
|
464
517
|
const nonce = Siwe.generateNonce()
|
|
@@ -181,6 +181,40 @@ describe('deserialize', () => {
|
|
|
181
181
|
})
|
|
182
182
|
})
|
|
183
183
|
|
|
184
|
+
test('behavior: authorization yParity above 1', () => {
|
|
185
|
+
// Mainnet transaction 0xaec8420968abd74e70ef5b3099d6ba7baa3f069c4f718d7c4d729d591cffcb09,
|
|
186
|
+
// whose authorization holds a `y_parity` of 28.
|
|
187
|
+
const serialized =
|
|
188
|
+
'0x04f8c90102843b9aca0084408206be830186a094db35624115a810cf541988294a57766cd02acc828080c0f85cf85a8094c498cea4bfedbb8de856491bdd9967e677775f4f061ca044754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512a027a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b19180a0287d894b2ebb8a178a55810b242af186c73de663382358363d58b42628bbded3a0678f589cd41571248f24df7e60912d05f14c76471b859f4abd956c612bf175ee'
|
|
189
|
+
|
|
190
|
+
const envelope = TxEnvelopeEip7702.deserialize(serialized)
|
|
191
|
+
expect(envelope).toMatchInlineSnapshot(`
|
|
192
|
+
{
|
|
193
|
+
"authorizationList": [
|
|
194
|
+
{
|
|
195
|
+
"address": "0xc498cea4bfedbb8de856491bdd9967e677775f4f",
|
|
196
|
+
"chainId": 0,
|
|
197
|
+
"nonce": 6n,
|
|
198
|
+
"r": "0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512",
|
|
199
|
+
"s": "0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191",
|
|
200
|
+
"yParity": 28,
|
|
201
|
+
},
|
|
202
|
+
],
|
|
203
|
+
"chainId": 1,
|
|
204
|
+
"gas": 100000n,
|
|
205
|
+
"maxFeePerGas": 1082263230n,
|
|
206
|
+
"maxPriorityFeePerGas": 1000000000n,
|
|
207
|
+
"nonce": 2n,
|
|
208
|
+
"r": "0x287d894b2ebb8a178a55810b242af186c73de663382358363d58b42628bbded3",
|
|
209
|
+
"s": "0x678f589cd41571248f24df7e60912d05f14c76471b859f4abd956c612bf175ee",
|
|
210
|
+
"to": "0xdb35624115a810cf541988294a57766cd02acc82",
|
|
211
|
+
"type": "eip7702",
|
|
212
|
+
"yParity": 0,
|
|
213
|
+
}
|
|
214
|
+
`)
|
|
215
|
+
expect(TxEnvelopeEip7702.serialize(envelope)).toBe(serialized)
|
|
216
|
+
})
|
|
217
|
+
|
|
184
218
|
describe('raw', () => {
|
|
185
219
|
test('default', () => {
|
|
186
220
|
const serialized = `0x04${Rlp.fromHex([
|
|
@@ -529,6 +563,38 @@ describe('hash', () => {
|
|
|
529
563
|
`"0xa5ccd813e459b9154917af19270091cf3312bd759af08e0e18cd2560ef586cf4"`,
|
|
530
564
|
)
|
|
531
565
|
})
|
|
566
|
+
|
|
567
|
+
test('behavior: authorization yParity above 1', () => {
|
|
568
|
+
// Mainnet transaction 0xaec8420968abd74e70ef5b3099d6ba7baa3f069c4f718d7c4d729d591cffcb09,
|
|
569
|
+
// whose authorization holds a `y_parity` of 28.
|
|
570
|
+
const envelope = TxEnvelopeEip7702.from({
|
|
571
|
+
authorizationList: [
|
|
572
|
+
{
|
|
573
|
+
address: '0xc498cea4bfedbb8de856491bdd9967e677775f4f',
|
|
574
|
+
chainId: 0,
|
|
575
|
+
nonce: 6n,
|
|
576
|
+
r: '0x44754b7f217808e21f1935cfa450380e17a3ab8f2c6996c0190d678f0c14a512',
|
|
577
|
+
s: '0x27a6b869798cbbbd8d538dbc95b9bb28783bf08f8ef88ad6bb82552d0b47b191',
|
|
578
|
+
yParity: 28,
|
|
579
|
+
},
|
|
580
|
+
],
|
|
581
|
+
chainId: 1,
|
|
582
|
+
gas: 100000n,
|
|
583
|
+
maxFeePerGas: 1082263230n,
|
|
584
|
+
maxPriorityFeePerGas: 1000000000n,
|
|
585
|
+
nonce: 2n,
|
|
586
|
+
r: '0x287d894b2ebb8a178a55810b242af186c73de663382358363d58b42628bbded3',
|
|
587
|
+
s: '0x678f589cd41571248f24df7e60912d05f14c76471b859f4abd956c612bf175ee',
|
|
588
|
+
to: '0xdb35624115a810cf541988294a57766cd02acc82',
|
|
589
|
+
value: 0n,
|
|
590
|
+
yParity: 0,
|
|
591
|
+
})
|
|
592
|
+
|
|
593
|
+
const hash = TxEnvelopeEip7702.hash(envelope)
|
|
594
|
+
expect(hash).toMatchInlineSnapshot(
|
|
595
|
+
`"0xaec8420968abd74e70ef5b3099d6ba7baa3f069c4f718d7c4d729d591cffcb09"`,
|
|
596
|
+
)
|
|
597
|
+
})
|
|
532
598
|
})
|
|
533
599
|
|
|
534
600
|
describe('serialize', () => {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { factory } from '../../test/tempo/configurableAccounts.js'
|
|
2
1
|
import { Hash, Hex, Rlp } from 'ox'
|
|
3
2
|
import { AccountConfig } from 'ox/tempo'
|
|
4
3
|
import { describe, expect, test } from 'vp/test'
|
|
@@ -10,13 +9,12 @@ const config = AccountConfig.from({
|
|
|
10
9
|
owners: [{ owner: owner_1, weight: 1 }],
|
|
11
10
|
threshold: 1,
|
|
12
11
|
})
|
|
13
|
-
const account = AccountConfig.getAddress(config
|
|
12
|
+
const account = AccountConfig.getAddress(config)
|
|
14
13
|
|
|
15
14
|
// Vectors from Tempo `crates/primitives/tests/configurable_account.rs`
|
|
16
15
|
// (`configurable_account_hashes_follow_vectors_and_documented_layout`).
|
|
17
16
|
const tempo = {
|
|
18
17
|
account: '0x91847576f406d0842ad7c1a0c97c22a122e64278',
|
|
19
|
-
factory: '0x9999999999999999999999999999999999999999',
|
|
20
18
|
} as const
|
|
21
19
|
|
|
22
20
|
describe('from', () => {
|
|
@@ -180,78 +178,67 @@ describe('fromUpgrade', () => {
|
|
|
180
178
|
describe('getAddress', () => {
|
|
181
179
|
test('example: matches the Tempo vectors', () => {
|
|
182
180
|
expect({
|
|
183
|
-
maxOwners: AccountConfig.getAddress(
|
|
184
|
-
{
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
{ factory: tempo.factory },
|
|
192
|
-
),
|
|
193
|
-
single: AccountConfig.getAddress(config, { factory: tempo.factory }),
|
|
181
|
+
maxOwners: AccountConfig.getAddress({
|
|
182
|
+
owners: Array.from({ length: AccountConfig.maxOwners }, (_, i) => ({
|
|
183
|
+
owner: Hex.padLeft(Hex.fromNumber(i + 1), 20),
|
|
184
|
+
weight: 1,
|
|
185
|
+
})),
|
|
186
|
+
threshold: 8,
|
|
187
|
+
}),
|
|
188
|
+
single: AccountConfig.getAddress(config),
|
|
194
189
|
}).toMatchInlineSnapshot(`
|
|
195
190
|
{
|
|
196
|
-
"maxOwners": "
|
|
197
|
-
"single": "
|
|
191
|
+
"maxOwners": "0x9859f0316567499ebcd81d3417c0622999d7179f",
|
|
192
|
+
"single": "0xcbb727e2489c904a905420e794e8275b6150bfe1",
|
|
198
193
|
}
|
|
199
194
|
`)
|
|
200
195
|
})
|
|
201
196
|
|
|
202
|
-
test('example: matches the frozen
|
|
197
|
+
test('example: matches the frozen keccak vector', () => {
|
|
203
198
|
expect(account).toMatchInlineSnapshot(
|
|
204
|
-
`"
|
|
199
|
+
`"0xcbb727e2489c904a905420e794e8275b6150bfe1"`,
|
|
205
200
|
)
|
|
206
201
|
expect(account).not.toBe('0x8820d1497eeaf4f68e00b2cfc00a2f3b1dbb00da')
|
|
207
202
|
})
|
|
208
203
|
|
|
209
204
|
test('behavior: includes salt, threshold, and owners', () => {
|
|
210
205
|
expect(
|
|
211
|
-
AccountConfig.getAddress(
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
{ factory },
|
|
221
|
-
),
|
|
222
|
-
).toMatchInlineSnapshot(`"0x1baa996a4f142d99999aa22f1cb1eb97eed2a24a"`)
|
|
206
|
+
AccountConfig.getAddress({
|
|
207
|
+
owners: [
|
|
208
|
+
{ owner: owner_1, weight: 1 },
|
|
209
|
+
{ owner: owner_2, weight: 2 },
|
|
210
|
+
],
|
|
211
|
+
salt: `0x${'42'.repeat(32)}`,
|
|
212
|
+
threshold: 2,
|
|
213
|
+
}),
|
|
214
|
+
).toMatchInlineSnapshot(`"0x870b14ffcb3d1bd52be7cc6e8358a35712fec535"`)
|
|
223
215
|
})
|
|
224
216
|
|
|
225
217
|
test('behavior: is stable and binds the salt', () => {
|
|
226
218
|
expect({
|
|
227
|
-
repeated: AccountConfig.getAddress(config
|
|
228
|
-
salted: AccountConfig.getAddress(
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
},
|
|
233
|
-
{ factory },
|
|
234
|
-
),
|
|
219
|
+
repeated: AccountConfig.getAddress(config),
|
|
220
|
+
salted: AccountConfig.getAddress({
|
|
221
|
+
...config,
|
|
222
|
+
salt: `0x${'42'.repeat(32)}`,
|
|
223
|
+
}),
|
|
235
224
|
}).toMatchInlineSnapshot(`
|
|
236
225
|
{
|
|
237
|
-
"repeated": "
|
|
238
|
-
"salted": "
|
|
226
|
+
"repeated": "0xcbb727e2489c904a905420e794e8275b6150bfe1",
|
|
227
|
+
"salted": "0xfc6a724c4715d331ec47dc8c1636798956fd3e4d",
|
|
239
228
|
}
|
|
240
229
|
`)
|
|
241
230
|
})
|
|
242
231
|
|
|
243
232
|
test('error: rejects a current configuration', () => {
|
|
244
233
|
expect(() =>
|
|
245
|
-
AccountConfig.getAddress({ ...config, version: 1n }
|
|
234
|
+
AccountConfig.getAddress({ ...config, version: 1n }),
|
|
246
235
|
).toThrowErrorMatchingInlineSnapshot(
|
|
247
236
|
`[AccountConfig.InvalidConfigError: Invalid account config: account address requires version zero.]`,
|
|
248
237
|
)
|
|
249
238
|
})
|
|
250
239
|
|
|
251
240
|
test('behavior: accepts numeric zero for an initial configuration', () => {
|
|
252
|
-
expect(
|
|
253
|
-
AccountConfig.getAddress({ ...config, version: 0 }, { factory }),
|
|
254
|
-
).toBe(account)
|
|
241
|
+
expect(AccountConfig.getAddress({ ...config, version: 0 })).toBe(account)
|
|
255
242
|
})
|
|
256
243
|
})
|
|
257
244
|
|
|
@@ -308,7 +295,7 @@ describe('getSignPayload', () => {
|
|
|
308
295
|
expect(
|
|
309
296
|
AccountConfig.getSignPayload({ account, config, payload }),
|
|
310
297
|
).toMatchInlineSnapshot(
|
|
311
|
-
`"
|
|
298
|
+
`"0x53a60618dd8fd4d01c2c94a4d9dc482dbb7b97115eb448a4590d153b933e549a"`,
|
|
312
299
|
)
|
|
313
300
|
})
|
|
314
301
|
|
|
@@ -449,14 +436,14 @@ describe('assert/validate', () => {
|
|
|
449
436
|
})
|
|
450
437
|
const rlp = Rlp.fromHex(AccountConfig.toTuple(boundary))
|
|
451
438
|
expect({
|
|
452
|
-
account: AccountConfig.getAddress(boundary
|
|
439
|
+
account: AccountConfig.getAddress(boundary),
|
|
453
440
|
commitment: AccountConfig.getCommitment(boundary),
|
|
454
441
|
rlpHash: Hash.keccak256(rlp),
|
|
455
442
|
rlpLength: Hex.size(rlp),
|
|
456
443
|
valid: AccountConfig.validate(boundary),
|
|
457
444
|
}).toMatchInlineSnapshot(`
|
|
458
445
|
{
|
|
459
|
-
"account": "
|
|
446
|
+
"account": "0x9859f0316567499ebcd81d3417c0622999d7179f",
|
|
460
447
|
"commitment": "0xa9282ca5b73ac63b7e27f49cafa6ab13bd2aa79fc45267cf27342db73150cd46",
|
|
461
448
|
"rlpHash": "0xbaf0d030add91caaa10815d2e99c942f1e39b0d199216973781adb4fc1af6955",
|
|
462
449
|
"rlpLength": 1145,
|