tempo.ts 0.10.5 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/README.md +0 -41
- package/dist/viem/Account.d.ts +8 -3
- package/dist/viem/Account.d.ts.map +1 -1
- package/dist/viem/Account.js +9 -2
- package/dist/viem/Account.js.map +1 -1
- package/dist/viem/Actions/amm.d.ts +1 -1
- package/dist/viem/Actions/amm.d.ts.map +1 -1
- package/dist/viem/Actions/amm.js +1 -2
- package/dist/viem/Actions/amm.js.map +1 -1
- package/dist/viem/Actions/dex.d.ts +0 -35
- package/dist/viem/Actions/dex.d.ts.map +1 -1
- package/dist/viem/Actions/dex.js +0 -43
- package/dist/viem/Actions/dex.js.map +1 -1
- package/dist/viem/Actions/fee.d.ts +1 -1
- package/dist/viem/Actions/fee.d.ts.map +1 -1
- package/dist/viem/Actions/fee.js +1 -1
- package/dist/viem/Actions/fee.js.map +1 -1
- package/dist/viem/Actions/nonce.d.ts.map +1 -1
- package/dist/viem/Actions/nonce.js +6 -4
- package/dist/viem/Actions/nonce.js.map +1 -1
- package/dist/viem/Actions/token.d.ts +1 -2
- package/dist/viem/Actions/token.d.ts.map +1 -1
- package/dist/viem/Actions/token.js +1 -2
- package/dist/viem/Actions/token.js.map +1 -1
- package/dist/viem/Chain.d.ts +34 -34
- package/dist/viem/Chain.d.ts.map +1 -1
- package/dist/viem/Chain.js +2 -0
- package/dist/viem/Chain.js.map +1 -1
- package/dist/viem/Formatters.d.ts.map +1 -1
- package/dist/viem/Formatters.js +5 -3
- package/dist/viem/Formatters.js.map +1 -1
- package/dist/viem/Transaction.d.ts +8 -5
- package/dist/viem/Transaction.d.ts.map +1 -1
- package/dist/viem/Transaction.js +13 -3
- package/dist/viem/Transaction.js.map +1 -1
- package/dist/viem/internal/types.d.ts +1 -1
- package/dist/viem/internal/types.d.ts.map +1 -1
- package/dist/wagmi/Actions/dex.d.ts +1 -45
- package/dist/wagmi/Actions/dex.d.ts.map +1 -1
- package/dist/wagmi/Actions/dex.js +0 -55
- package/dist/wagmi/Actions/dex.js.map +1 -1
- package/dist/wagmi/Connector.d.ts +1 -1
- package/dist/wagmi/Connector.d.ts.map +1 -1
- package/dist/wagmi/Connector.js +1 -2
- package/dist/wagmi/Connector.js.map +1 -1
- package/dist/wagmi/Hooks/dex.d.ts +3 -46
- package/dist/wagmi/Hooks/dex.d.ts.map +1 -1
- package/dist/wagmi/Hooks/dex.js +2 -54
- package/dist/wagmi/Hooks/dex.js.map +1 -1
- package/dist/wagmi/index.d.ts +1 -1
- package/dist/wagmi/index.d.ts.map +1 -1
- package/dist/wagmi/index.js +1 -1
- package/dist/wagmi/index.js.map +1 -1
- package/package.json +5 -23
- package/src/viem/Account.test.ts +1 -1
- package/src/viem/Account.ts +11 -2
- package/src/viem/Actions/account.ts +1 -1
- package/src/viem/Actions/amm.ts +1 -2
- package/src/viem/Actions/dex.test.ts +1 -195
- package/src/viem/Actions/dex.ts +0 -53
- package/src/viem/Actions/fee.test.ts +2 -2
- package/src/viem/Actions/fee.ts +1 -1
- package/src/viem/Actions/nonce.test.ts +27 -14
- package/src/viem/Actions/nonce.ts +6 -4
- package/src/viem/Actions/token.test.ts +18 -52
- package/src/viem/Actions/token.ts +1 -2
- package/src/viem/Chain.ts +3 -1
- package/src/viem/Decorator.ts +0 -30
- package/src/viem/Formatters.ts +9 -3
- package/src/viem/Transaction.ts +23 -7
- package/src/viem/e2e.test.ts +19 -0
- package/src/viem/index.ts +12 -1
- package/src/viem/internal/types.ts +1 -1
- package/src/wagmi/Actions/dex.test.ts +0 -26
- package/src/wagmi/Actions/dex.ts +1 -111
- package/src/wagmi/Actions/nonce.test.ts +8 -4
- package/src/wagmi/Actions/token.test.ts +2 -2
- package/src/wagmi/Connector.ts +1 -2
- package/src/wagmi/Hooks/dex.test.ts +0 -26
- package/src/wagmi/Hooks/dex.ts +1 -88
- package/src/wagmi/Hooks/nonce.test.ts +3 -3
- package/src/wagmi/index.ts +4 -1
- package/dist/chains.d.ts +0 -73
- package/dist/chains.d.ts.map +0 -1
- package/dist/chains.js +0 -51
- package/dist/chains.js.map +0 -1
- package/dist/ox/AuthorizationTempo.d.ts +0 -450
- package/dist/ox/AuthorizationTempo.d.ts.map +0 -1
- package/dist/ox/AuthorizationTempo.js +0 -433
- package/dist/ox/AuthorizationTempo.js.map +0 -1
- package/dist/ox/KeyAuthorization.d.ts +0 -356
- package/dist/ox/KeyAuthorization.d.ts.map +0 -1
- package/dist/ox/KeyAuthorization.js +0 -359
- package/dist/ox/KeyAuthorization.js.map +0 -1
- package/dist/ox/Order.d.ts +0 -92
- package/dist/ox/Order.d.ts.map +0 -1
- package/dist/ox/Order.js +0 -88
- package/dist/ox/Order.js.map +0 -1
- package/dist/ox/OrdersFilters.d.ts +0 -72
- package/dist/ox/OrdersFilters.d.ts.map +0 -1
- package/dist/ox/OrdersFilters.js +0 -100
- package/dist/ox/OrdersFilters.js.map +0 -1
- package/dist/ox/Pagination.d.ts +0 -128
- package/dist/ox/Pagination.d.ts.map +0 -1
- package/dist/ox/Pagination.js +0 -78
- package/dist/ox/Pagination.js.map +0 -1
- package/dist/ox/PoolId.d.ts +0 -18
- package/dist/ox/PoolId.d.ts.map +0 -1
- package/dist/ox/PoolId.js +0 -13
- package/dist/ox/PoolId.js.map +0 -1
- package/dist/ox/RpcSchema.d.ts +0 -32
- package/dist/ox/RpcSchema.d.ts.map +0 -1
- package/dist/ox/RpcSchema.js +0 -2
- package/dist/ox/RpcSchema.js.map +0 -1
- package/dist/ox/SignatureEnvelope.d.ts +0 -260
- package/dist/ox/SignatureEnvelope.d.ts.map +0 -1
- package/dist/ox/SignatureEnvelope.js +0 -477
- package/dist/ox/SignatureEnvelope.js.map +0 -1
- package/dist/ox/Tick.d.ts +0 -115
- package/dist/ox/Tick.d.ts.map +0 -1
- package/dist/ox/Tick.js +0 -127
- package/dist/ox/Tick.js.map +0 -1
- package/dist/ox/TokenId.d.ts +0 -25
- package/dist/ox/TokenId.d.ts.map +0 -1
- package/dist/ox/TokenId.js +0 -41
- package/dist/ox/TokenId.js.map +0 -1
- package/dist/ox/TokenRole.d.ts +0 -11
- package/dist/ox/TokenRole.d.ts.map +0 -1
- package/dist/ox/TokenRole.js +0 -22
- package/dist/ox/TokenRole.js.map +0 -1
- package/dist/ox/Transaction.d.ts +0 -201
- package/dist/ox/Transaction.d.ts.map +0 -1
- package/dist/ox/Transaction.js +0 -167
- package/dist/ox/Transaction.js.map +0 -1
- package/dist/ox/TransactionEnvelopeTempo.d.ts +0 -470
- package/dist/ox/TransactionEnvelopeTempo.d.ts.map +0 -1
- package/dist/ox/TransactionEnvelopeTempo.js +0 -547
- package/dist/ox/TransactionEnvelopeTempo.js.map +0 -1
- package/dist/ox/TransactionReceipt.d.ts +0 -155
- package/dist/ox/TransactionReceipt.d.ts.map +0 -1
- package/dist/ox/TransactionReceipt.js +0 -136
- package/dist/ox/TransactionReceipt.js.map +0 -1
- package/dist/ox/TransactionRequest.d.ts +0 -76
- package/dist/ox/TransactionRequest.d.ts.map +0 -1
- package/dist/ox/TransactionRequest.js +0 -93
- package/dist/ox/TransactionRequest.js.map +0 -1
- package/dist/ox/index.d.ts +0 -14
- package/dist/ox/index.d.ts.map +0 -1
- package/dist/ox/index.js +0 -14
- package/dist/ox/index.js.map +0 -1
- package/dist/prool/Instance.d.ts +0 -101
- package/dist/prool/Instance.d.ts.map +0 -1
- package/dist/prool/Instance.js +0 -136
- package/dist/prool/Instance.js.map +0 -1
- package/dist/prool/chain.json +0 -238
- package/dist/prool/index.d.ts +0 -2
- package/dist/prool/index.d.ts.map +0 -1
- package/dist/prool/index.js +0 -2
- package/dist/prool/index.js.map +0 -1
- package/dist/viem/Actions/account.d.ts +0 -40
- package/dist/viem/Actions/account.d.ts.map +0 -1
- package/dist/viem/Actions/account.js +0 -86
- package/dist/viem/Actions/account.js.map +0 -1
- package/dist/viem/Actions/index.d.ts +0 -10
- package/dist/viem/Actions/index.d.ts.map +0 -1
- package/dist/viem/Actions/index.js +0 -10
- package/dist/viem/Actions/index.js.map +0 -1
- package/dist/viem/Decorator.d.ts +0 -2810
- package/dist/viem/Decorator.d.ts.map +0 -1
- package/dist/viem/Decorator.js +0 -138
- package/dist/viem/Decorator.js.map +0 -1
- package/dist/viem/P256.d.ts +0 -2
- package/dist/viem/P256.d.ts.map +0 -1
- package/dist/viem/P256.js +0 -2
- package/dist/viem/P256.js.map +0 -1
- package/dist/viem/Secp256k1.d.ts +0 -2
- package/dist/viem/Secp256k1.d.ts.map +0 -1
- package/dist/viem/Secp256k1.js +0 -2
- package/dist/viem/Secp256k1.js.map +0 -1
- package/dist/viem/TokenIds.d.ts +0 -2
- package/dist/viem/TokenIds.d.ts.map +0 -1
- package/dist/viem/TokenIds.js +0 -2
- package/dist/viem/TokenIds.js.map +0 -1
- package/dist/viem/index.d.ts +0 -17
- package/dist/viem/index.d.ts.map +0 -1
- package/dist/viem/index.js +0 -17
- package/dist/viem/index.js.map +0 -1
- package/src/ox/AuthorizationTempo.test.ts +0 -1256
- package/src/ox/AuthorizationTempo.ts +0 -648
- package/src/ox/KeyAuthorization.test.ts +0 -1332
- package/src/ox/KeyAuthorization.ts +0 -540
- package/src/ox/Order.test.ts +0 -78
- package/src/ox/Order.ts +0 -125
- package/src/ox/OrdersFilters.test.ts +0 -182
- package/src/ox/OrdersFilters.ts +0 -125
- package/src/ox/Pagination.test.ts +0 -162
- package/src/ox/Pagination.ts +0 -164
- package/src/ox/PoolId.test.ts +0 -33
- package/src/ox/PoolId.ts +0 -27
- package/src/ox/RpcSchema.ts +0 -35
- package/src/ox/SignatureEnvelope.test.ts +0 -1876
- package/src/ox/SignatureEnvelope.ts +0 -791
- package/src/ox/Tick.test.ts +0 -281
- package/src/ox/Tick.ts +0 -181
- package/src/ox/TokenId.test.ts +0 -40
- package/src/ox/TokenId.ts +0 -50
- package/src/ox/TokenRole.test.ts +0 -16
- package/src/ox/TokenRole.ts +0 -27
- package/src/ox/Transaction.test.ts +0 -523
- package/src/ox/Transaction.ts +0 -332
- package/src/ox/TransactionEnvelopeTempo.test.ts +0 -1352
- package/src/ox/TransactionEnvelopeTempo.ts +0 -905
- package/src/ox/TransactionReceipt.ts +0 -190
- package/src/ox/TransactionRequest.ts +0 -147
- package/src/ox/e2e.test.ts +0 -1393
- package/src/ox/index.ts +0 -13
- package/src/prool/Instance.test.ts +0 -43
- package/src/prool/Instance.ts +0 -247
- package/src/prool/chain.json +0 -238
- package/src/prool/index.ts +0 -1
- package/src/viem/Actions/__snapshots__/dex.test.ts.snap +0 -850
- package/src/wagmi/Actions/__snapshots__/dex.test.ts.snap +0 -310
- package/src/wagmi/Hooks/__snapshots__/dex.test.ts.snap +0 -457
|
@@ -1,1876 +0,0 @@
|
|
|
1
|
-
import { Hex, PublicKey, Secp256k1, Signature, WebAuthnP256 } from 'ox'
|
|
2
|
-
import { describe, expect, test } from 'vitest'
|
|
3
|
-
import * as SignatureEnvelope from './SignatureEnvelope.js'
|
|
4
|
-
|
|
5
|
-
const publicKey = PublicKey.from({
|
|
6
|
-
prefix: 4,
|
|
7
|
-
x: 78495282704852028275327922540131762143565388050940484317945369745559774511861n,
|
|
8
|
-
y: 8109764566587999957624872393871720746996669263962991155166704261108473113504n,
|
|
9
|
-
})
|
|
10
|
-
|
|
11
|
-
const p256Signature = Signature.from({
|
|
12
|
-
r: 92602584010956101470289867944347135737570451066466093224269890121909314569518n,
|
|
13
|
-
s: 54171125190222965779385658110416711469231271457324878825831748147306957269813n,
|
|
14
|
-
yParity: 0,
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
const signature_secp256k1 = Secp256k1.sign({
|
|
18
|
-
payload: '0xdeadbeef',
|
|
19
|
-
privateKey: Secp256k1.randomPrivateKey(),
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
const signature_p256 = SignatureEnvelope.from({
|
|
23
|
-
signature: p256Signature,
|
|
24
|
-
publicKey,
|
|
25
|
-
prehash: true,
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
const signature_webauthn = SignatureEnvelope.from({
|
|
29
|
-
signature: p256Signature,
|
|
30
|
-
publicKey,
|
|
31
|
-
metadata: {
|
|
32
|
-
authenticatorData: WebAuthnP256.getAuthenticatorData({ rpId: 'localhost' }),
|
|
33
|
-
clientDataJSON: WebAuthnP256.getClientDataJSON({
|
|
34
|
-
challenge: '0xdeadbeef',
|
|
35
|
-
origin: 'http://localhost',
|
|
36
|
-
}),
|
|
37
|
-
},
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
// Keychain signatures with different inner types
|
|
41
|
-
const signature_keychain_secp256k1 = SignatureEnvelope.from({
|
|
42
|
-
userAddress: '0x1234567890123456789012345678901234567890',
|
|
43
|
-
inner: SignatureEnvelope.from(signature_secp256k1),
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
const signature_keychain_p256 = SignatureEnvelope.from({
|
|
47
|
-
userAddress: '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd',
|
|
48
|
-
inner: signature_p256,
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
const signature_keychain_webauthn = SignatureEnvelope.from({
|
|
52
|
-
userAddress: '0xfedcbafedcbafedcbafedcbafedcbafedcbafedc',
|
|
53
|
-
inner: signature_webauthn,
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
describe('assert', () => {
|
|
57
|
-
describe('secp256k1', () => {
|
|
58
|
-
test('behavior: validates valid signature', () => {
|
|
59
|
-
expect(() =>
|
|
60
|
-
SignatureEnvelope.assert({
|
|
61
|
-
signature: signature_secp256k1,
|
|
62
|
-
type: 'secp256k1',
|
|
63
|
-
}),
|
|
64
|
-
).not.toThrow()
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
test('behavior: validates signature without explicit type', () => {
|
|
68
|
-
expect(() =>
|
|
69
|
-
SignatureEnvelope.assert({ signature: signature_secp256k1 }),
|
|
70
|
-
).not.toThrow()
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
test('error: throws on invalid signature values', () => {
|
|
74
|
-
expect(() =>
|
|
75
|
-
SignatureEnvelope.assert({
|
|
76
|
-
signature: {
|
|
77
|
-
r: 0n,
|
|
78
|
-
s: 0n,
|
|
79
|
-
yParity: 2,
|
|
80
|
-
},
|
|
81
|
-
type: 'secp256k1',
|
|
82
|
-
}),
|
|
83
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
84
|
-
`[Signature.InvalidYParityError: Value \`2\` is an invalid y-parity value. Y-parity must be 0 or 1.]`,
|
|
85
|
-
)
|
|
86
|
-
})
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
describe('p256', () => {
|
|
90
|
-
test('behavior: validates valid P256 signature', () => {
|
|
91
|
-
expect(() => SignatureEnvelope.assert(signature_p256)).not.toThrow()
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
test('behavior: validates P256 signature without explicit type', () => {
|
|
95
|
-
const { type: _, ...signatureWithoutType } = signature_p256
|
|
96
|
-
expect(() => SignatureEnvelope.assert(signatureWithoutType)).not.toThrow()
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
test('error: throws on invalid prehash type', () => {
|
|
100
|
-
expect(() =>
|
|
101
|
-
SignatureEnvelope.assert({
|
|
102
|
-
...signature_p256,
|
|
103
|
-
prehash: 'true' as any,
|
|
104
|
-
}),
|
|
105
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
106
|
-
`
|
|
107
|
-
[SignatureEnvelope.MissingPropertiesError: Signature envelope of type "p256" is missing required properties: \`prehash\`.
|
|
108
|
-
|
|
109
|
-
Provided: {"signature":{"r":"92602584010956101470289867944347135737570451066466093224269890121909314569518#__bigint","s":"54171125190222965779385658110416711469231271457324878825831748147306957269813#__bigint","yParity":0},"publicKey":{"prefix":4,"x":"78495282704852028275327922540131762143565388050940484317945369745559774511861#__bigint","y":"8109764566587999957624872393871720746996669263962991155166704261108473113504#__bigint"},"prehash":"true","type":"p256"}]
|
|
110
|
-
`,
|
|
111
|
-
)
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
test('error: throws on missing publicKey', () => {
|
|
115
|
-
const { publicKey: _, ...withoutPublicKey } = signature_p256
|
|
116
|
-
expect(() =>
|
|
117
|
-
SignatureEnvelope.assert(withoutPublicKey as any),
|
|
118
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
119
|
-
`
|
|
120
|
-
[SignatureEnvelope.MissingPropertiesError: Signature envelope of type "p256" is missing required properties: \`publicKey\`.
|
|
121
|
-
|
|
122
|
-
Provided: {"signature":{"r":"92602584010956101470289867944347135737570451066466093224269890121909314569518#__bigint","s":"54171125190222965779385658110416711469231271457324878825831748147306957269813#__bigint","yParity":0},"prehash":true,"type":"p256"}]
|
|
123
|
-
`,
|
|
124
|
-
)
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
test('error: throws on missing signature.r', () => {
|
|
128
|
-
const invalid = {
|
|
129
|
-
signature: { s: 1n } as any,
|
|
130
|
-
publicKey,
|
|
131
|
-
prehash: true,
|
|
132
|
-
type: 'p256' as const,
|
|
133
|
-
}
|
|
134
|
-
expect(() =>
|
|
135
|
-
SignatureEnvelope.assert(invalid),
|
|
136
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
137
|
-
`
|
|
138
|
-
[SignatureEnvelope.MissingPropertiesError: Signature envelope of type "p256" is missing required properties: \`signature.r\`.
|
|
139
|
-
|
|
140
|
-
Provided: {"signature":{"s":"1#__bigint"},"publicKey":{"prefix":4,"x":"78495282704852028275327922540131762143565388050940484317945369745559774511861#__bigint","y":"8109764566587999957624872393871720746996669263962991155166704261108473113504#__bigint"},"prehash":true,"type":"p256"}]
|
|
141
|
-
`,
|
|
142
|
-
)
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
test('error: throws on missing signature.s', () => {
|
|
146
|
-
const invalid = {
|
|
147
|
-
signature: { r: 1n } as any,
|
|
148
|
-
publicKey,
|
|
149
|
-
prehash: true,
|
|
150
|
-
type: 'p256' as const,
|
|
151
|
-
}
|
|
152
|
-
expect(() =>
|
|
153
|
-
SignatureEnvelope.assert(invalid),
|
|
154
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
155
|
-
`
|
|
156
|
-
[SignatureEnvelope.MissingPropertiesError: Signature envelope of type "p256" is missing required properties: \`signature.s\`.
|
|
157
|
-
|
|
158
|
-
Provided: {"signature":{"r":"1#__bigint"},"publicKey":{"prefix":4,"x":"78495282704852028275327922540131762143565388050940484317945369745559774511861#__bigint","y":"8109764566587999957624872393871720746996669263962991155166704261108473113504#__bigint"},"prehash":true,"type":"p256"}]
|
|
159
|
-
`,
|
|
160
|
-
)
|
|
161
|
-
})
|
|
162
|
-
|
|
163
|
-
test('error: throws on missing publicKey.x', () => {
|
|
164
|
-
const invalid = {
|
|
165
|
-
signature: p256Signature,
|
|
166
|
-
publicKey: { y: 1n } as any,
|
|
167
|
-
prehash: true,
|
|
168
|
-
type: 'p256' as const,
|
|
169
|
-
}
|
|
170
|
-
expect(() =>
|
|
171
|
-
SignatureEnvelope.assert(invalid),
|
|
172
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
173
|
-
`
|
|
174
|
-
[SignatureEnvelope.MissingPropertiesError: Signature envelope of type "p256" is missing required properties: \`publicKey.x\`.
|
|
175
|
-
|
|
176
|
-
Provided: {"signature":{"r":"92602584010956101470289867944347135737570451066466093224269890121909314569518#__bigint","s":"54171125190222965779385658110416711469231271457324878825831748147306957269813#__bigint","yParity":0},"publicKey":{"y":"1#__bigint"},"prehash":true,"type":"p256"}]
|
|
177
|
-
`,
|
|
178
|
-
)
|
|
179
|
-
})
|
|
180
|
-
|
|
181
|
-
test('error: throws on missing publicKey.y', () => {
|
|
182
|
-
const invalid = {
|
|
183
|
-
signature: p256Signature,
|
|
184
|
-
publicKey: { x: 1n } as any,
|
|
185
|
-
prehash: true,
|
|
186
|
-
type: 'p256' as const,
|
|
187
|
-
}
|
|
188
|
-
expect(() =>
|
|
189
|
-
SignatureEnvelope.assert(invalid),
|
|
190
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
191
|
-
`
|
|
192
|
-
[SignatureEnvelope.MissingPropertiesError: Signature envelope of type "p256" is missing required properties: \`publicKey.y\`.
|
|
193
|
-
|
|
194
|
-
Provided: {"signature":{"r":"92602584010956101470289867944347135737570451066466093224269890121909314569518#__bigint","s":"54171125190222965779385658110416711469231271457324878825831748147306957269813#__bigint","yParity":0},"publicKey":{"x":"1#__bigint"},"prehash":true,"type":"p256"}]
|
|
195
|
-
`,
|
|
196
|
-
)
|
|
197
|
-
})
|
|
198
|
-
|
|
199
|
-
test('error: throws with all missing properties listed', () => {
|
|
200
|
-
const invalid = {
|
|
201
|
-
signature: {} as any,
|
|
202
|
-
type: 'p256' as const,
|
|
203
|
-
}
|
|
204
|
-
expect(() =>
|
|
205
|
-
SignatureEnvelope.assert(invalid),
|
|
206
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
207
|
-
`
|
|
208
|
-
[SignatureEnvelope.MissingPropertiesError: Signature envelope of type "p256" is missing required properties: \`signature.r\`, \`signature.s\`, \`prehash\`, \`publicKey\`.
|
|
209
|
-
|
|
210
|
-
Provided: {"signature":{},"type":"p256"}]
|
|
211
|
-
`,
|
|
212
|
-
)
|
|
213
|
-
})
|
|
214
|
-
})
|
|
215
|
-
|
|
216
|
-
describe('webAuthn', () => {
|
|
217
|
-
test('behavior: validates valid WebAuthn signature', () => {
|
|
218
|
-
expect(() => SignatureEnvelope.assert(signature_webauthn)).not.toThrow()
|
|
219
|
-
})
|
|
220
|
-
|
|
221
|
-
test('behavior: validates WebAuthn signature without explicit type', () => {
|
|
222
|
-
const { type: _, ...signatureWithoutType } = signature_webauthn
|
|
223
|
-
expect(() => SignatureEnvelope.assert(signatureWithoutType)).not.toThrow()
|
|
224
|
-
})
|
|
225
|
-
|
|
226
|
-
test('error: throws on missing metadata', () => {
|
|
227
|
-
const { metadata: _, ...withoutMetadata } = signature_webauthn
|
|
228
|
-
expect(() =>
|
|
229
|
-
SignatureEnvelope.assert(withoutMetadata as any),
|
|
230
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
231
|
-
`
|
|
232
|
-
[SignatureEnvelope.MissingPropertiesError: Signature envelope of type "webAuthn" is missing required properties: \`metadata\`.
|
|
233
|
-
|
|
234
|
-
Provided: {"signature":{"r":"92602584010956101470289867944347135737570451066466093224269890121909314569518#__bigint","s":"54171125190222965779385658110416711469231271457324878825831748147306957269813#__bigint","yParity":0},"publicKey":{"prefix":4,"x":"78495282704852028275327922540131762143565388050940484317945369745559774511861#__bigint","y":"8109764566587999957624872393871720746996669263962991155166704261108473113504#__bigint"},"type":"webAuthn"}]
|
|
235
|
-
`,
|
|
236
|
-
)
|
|
237
|
-
})
|
|
238
|
-
|
|
239
|
-
test('error: throws on missing publicKey', () => {
|
|
240
|
-
const { publicKey: _, ...withoutPublicKey } = signature_webauthn
|
|
241
|
-
expect(() =>
|
|
242
|
-
SignatureEnvelope.assert(withoutPublicKey as any),
|
|
243
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
244
|
-
`
|
|
245
|
-
[SignatureEnvelope.MissingPropertiesError: Signature envelope of type "webAuthn" is missing required properties: \`publicKey\`.
|
|
246
|
-
|
|
247
|
-
Provided: {"signature":{"r":"92602584010956101470289867944347135737570451066466093224269890121909314569518#__bigint","s":"54171125190222965779385658110416711469231271457324878825831748147306957269813#__bigint","yParity":0},"metadata":{"authenticatorData":"0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000","clientDataJSON":"{\\"type\\":\\"webauthn.get\\",\\"challenge\\":\\"3q2-7w\\",\\"origin\\":\\"http://localhost\\",\\"crossOrigin\\":false}"},"type":"webAuthn"}]
|
|
248
|
-
`,
|
|
249
|
-
)
|
|
250
|
-
})
|
|
251
|
-
|
|
252
|
-
test('error: throws on missing signature.r', () => {
|
|
253
|
-
const invalid = {
|
|
254
|
-
signature: { s: 1n } as any,
|
|
255
|
-
publicKey,
|
|
256
|
-
metadata: {
|
|
257
|
-
authenticatorData: WebAuthnP256.getAuthenticatorData({
|
|
258
|
-
rpId: 'localhost',
|
|
259
|
-
}),
|
|
260
|
-
clientDataJSON: WebAuthnP256.getClientDataJSON({
|
|
261
|
-
challenge: '0xdeadbeef',
|
|
262
|
-
origin: 'http://localhost',
|
|
263
|
-
}),
|
|
264
|
-
},
|
|
265
|
-
type: 'webAuthn' as const,
|
|
266
|
-
}
|
|
267
|
-
expect(() =>
|
|
268
|
-
SignatureEnvelope.assert(invalid),
|
|
269
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
270
|
-
`
|
|
271
|
-
[SignatureEnvelope.MissingPropertiesError: Signature envelope of type "webAuthn" is missing required properties: \`signature.r\`.
|
|
272
|
-
|
|
273
|
-
Provided: {"signature":{"s":"1#__bigint"},"publicKey":{"prefix":4,"x":"78495282704852028275327922540131762143565388050940484317945369745559774511861#__bigint","y":"8109764566587999957624872393871720746996669263962991155166704261108473113504#__bigint"},"metadata":{"authenticatorData":"0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000","clientDataJSON":"{\\"type\\":\\"webauthn.get\\",\\"challenge\\":\\"3q2-7w\\",\\"origin\\":\\"http://localhost\\",\\"crossOrigin\\":false}"},"type":"webAuthn"}]
|
|
274
|
-
`,
|
|
275
|
-
)
|
|
276
|
-
})
|
|
277
|
-
|
|
278
|
-
test('error: throws on missing signature.s', () => {
|
|
279
|
-
const invalid = {
|
|
280
|
-
signature: { r: 1n } as any,
|
|
281
|
-
publicKey,
|
|
282
|
-
metadata: {
|
|
283
|
-
authenticatorData: WebAuthnP256.getAuthenticatorData({
|
|
284
|
-
rpId: 'localhost',
|
|
285
|
-
}),
|
|
286
|
-
clientDataJSON: WebAuthnP256.getClientDataJSON({
|
|
287
|
-
challenge: '0xdeadbeef',
|
|
288
|
-
origin: 'http://localhost',
|
|
289
|
-
}),
|
|
290
|
-
},
|
|
291
|
-
type: 'webAuthn' as const,
|
|
292
|
-
}
|
|
293
|
-
expect(() =>
|
|
294
|
-
SignatureEnvelope.assert(invalid),
|
|
295
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
296
|
-
`
|
|
297
|
-
[SignatureEnvelope.MissingPropertiesError: Signature envelope of type "webAuthn" is missing required properties: \`signature.s\`.
|
|
298
|
-
|
|
299
|
-
Provided: {"signature":{"r":"1#__bigint"},"publicKey":{"prefix":4,"x":"78495282704852028275327922540131762143565388050940484317945369745559774511861#__bigint","y":"8109764566587999957624872393871720746996669263962991155166704261108473113504#__bigint"},"metadata":{"authenticatorData":"0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000","clientDataJSON":"{\\"type\\":\\"webauthn.get\\",\\"challenge\\":\\"3q2-7w\\",\\"origin\\":\\"http://localhost\\",\\"crossOrigin\\":false}"},"type":"webAuthn"}]
|
|
300
|
-
`,
|
|
301
|
-
)
|
|
302
|
-
})
|
|
303
|
-
|
|
304
|
-
test('error: throws on missing metadata.authenticatorData', () => {
|
|
305
|
-
const invalid = {
|
|
306
|
-
signature: p256Signature,
|
|
307
|
-
publicKey,
|
|
308
|
-
metadata: {
|
|
309
|
-
clientDataJSON: WebAuthnP256.getClientDataJSON({
|
|
310
|
-
challenge: '0xdeadbeef',
|
|
311
|
-
origin: 'http://localhost',
|
|
312
|
-
}),
|
|
313
|
-
} as any,
|
|
314
|
-
type: 'webAuthn' as const,
|
|
315
|
-
}
|
|
316
|
-
expect(() =>
|
|
317
|
-
SignatureEnvelope.assert(invalid),
|
|
318
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
319
|
-
`
|
|
320
|
-
[SignatureEnvelope.MissingPropertiesError: Signature envelope of type "webAuthn" is missing required properties: \`metadata.authenticatorData\`.
|
|
321
|
-
|
|
322
|
-
Provided: {"signature":{"r":"92602584010956101470289867944347135737570451066466093224269890121909314569518#__bigint","s":"54171125190222965779385658110416711469231271457324878825831748147306957269813#__bigint","yParity":0},"publicKey":{"prefix":4,"x":"78495282704852028275327922540131762143565388050940484317945369745559774511861#__bigint","y":"8109764566587999957624872393871720746996669263962991155166704261108473113504#__bigint"},"metadata":{"clientDataJSON":"{\\"type\\":\\"webauthn.get\\",\\"challenge\\":\\"3q2-7w\\",\\"origin\\":\\"http://localhost\\",\\"crossOrigin\\":false}"},"type":"webAuthn"}]
|
|
323
|
-
`,
|
|
324
|
-
)
|
|
325
|
-
})
|
|
326
|
-
|
|
327
|
-
test('error: throws on missing metadata.clientDataJSON', () => {
|
|
328
|
-
const invalid = {
|
|
329
|
-
signature: p256Signature,
|
|
330
|
-
publicKey,
|
|
331
|
-
metadata: {
|
|
332
|
-
authenticatorData: WebAuthnP256.getAuthenticatorData({
|
|
333
|
-
rpId: 'localhost',
|
|
334
|
-
}),
|
|
335
|
-
} as any,
|
|
336
|
-
type: 'webAuthn' as const,
|
|
337
|
-
}
|
|
338
|
-
expect(() =>
|
|
339
|
-
SignatureEnvelope.assert(invalid),
|
|
340
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
341
|
-
`
|
|
342
|
-
[SignatureEnvelope.MissingPropertiesError: Signature envelope of type "webAuthn" is missing required properties: \`metadata.clientDataJSON\`.
|
|
343
|
-
|
|
344
|
-
Provided: {"signature":{"r":"92602584010956101470289867944347135737570451066466093224269890121909314569518#__bigint","s":"54171125190222965779385658110416711469231271457324878825831748147306957269813#__bigint","yParity":0},"publicKey":{"prefix":4,"x":"78495282704852028275327922540131762143565388050940484317945369745559774511861#__bigint","y":"8109764566587999957624872393871720746996669263962991155166704261108473113504#__bigint"},"metadata":{"authenticatorData":"0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000"},"type":"webAuthn"}]
|
|
345
|
-
`,
|
|
346
|
-
)
|
|
347
|
-
})
|
|
348
|
-
|
|
349
|
-
test('error: throws on missing publicKey.x', () => {
|
|
350
|
-
const invalid = {
|
|
351
|
-
signature: p256Signature,
|
|
352
|
-
publicKey: { y: 1n } as any,
|
|
353
|
-
metadata: {
|
|
354
|
-
authenticatorData: WebAuthnP256.getAuthenticatorData({
|
|
355
|
-
rpId: 'localhost',
|
|
356
|
-
}),
|
|
357
|
-
clientDataJSON: WebAuthnP256.getClientDataJSON({
|
|
358
|
-
challenge: '0xdeadbeef',
|
|
359
|
-
origin: 'http://localhost',
|
|
360
|
-
}),
|
|
361
|
-
},
|
|
362
|
-
type: 'webAuthn' as const,
|
|
363
|
-
}
|
|
364
|
-
expect(() =>
|
|
365
|
-
SignatureEnvelope.assert(invalid),
|
|
366
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
367
|
-
`
|
|
368
|
-
[SignatureEnvelope.MissingPropertiesError: Signature envelope of type "webAuthn" is missing required properties: \`publicKey.x\`.
|
|
369
|
-
|
|
370
|
-
Provided: {"signature":{"r":"92602584010956101470289867944347135737570451066466093224269890121909314569518#__bigint","s":"54171125190222965779385658110416711469231271457324878825831748147306957269813#__bigint","yParity":0},"publicKey":{"y":"1#__bigint"},"metadata":{"authenticatorData":"0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000","clientDataJSON":"{\\"type\\":\\"webauthn.get\\",\\"challenge\\":\\"3q2-7w\\",\\"origin\\":\\"http://localhost\\",\\"crossOrigin\\":false}"},"type":"webAuthn"}]
|
|
371
|
-
`,
|
|
372
|
-
)
|
|
373
|
-
})
|
|
374
|
-
|
|
375
|
-
test('error: throws on missing publicKey.y', () => {
|
|
376
|
-
const invalid = {
|
|
377
|
-
signature: p256Signature,
|
|
378
|
-
publicKey: { x: 1n } as any,
|
|
379
|
-
metadata: {
|
|
380
|
-
authenticatorData: WebAuthnP256.getAuthenticatorData({
|
|
381
|
-
rpId: 'localhost',
|
|
382
|
-
}),
|
|
383
|
-
clientDataJSON: WebAuthnP256.getClientDataJSON({
|
|
384
|
-
challenge: '0xdeadbeef',
|
|
385
|
-
origin: 'http://localhost',
|
|
386
|
-
}),
|
|
387
|
-
},
|
|
388
|
-
type: 'webAuthn' as const,
|
|
389
|
-
}
|
|
390
|
-
expect(() =>
|
|
391
|
-
SignatureEnvelope.assert(invalid),
|
|
392
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
393
|
-
`
|
|
394
|
-
[SignatureEnvelope.MissingPropertiesError: Signature envelope of type "webAuthn" is missing required properties: \`publicKey.y\`.
|
|
395
|
-
|
|
396
|
-
Provided: {"signature":{"r":"92602584010956101470289867944347135737570451066466093224269890121909314569518#__bigint","s":"54171125190222965779385658110416711469231271457324878825831748147306957269813#__bigint","yParity":0},"publicKey":{"x":"1#__bigint"},"metadata":{"authenticatorData":"0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000","clientDataJSON":"{\\"type\\":\\"webauthn.get\\",\\"challenge\\":\\"3q2-7w\\",\\"origin\\":\\"http://localhost\\",\\"crossOrigin\\":false}"},"type":"webAuthn"}]
|
|
397
|
-
`,
|
|
398
|
-
)
|
|
399
|
-
})
|
|
400
|
-
})
|
|
401
|
-
|
|
402
|
-
describe('keychain', () => {
|
|
403
|
-
test('behavior: validates valid keychain with secp256k1 inner', () => {
|
|
404
|
-
expect(() =>
|
|
405
|
-
SignatureEnvelope.assert(signature_keychain_secp256k1),
|
|
406
|
-
).not.toThrow()
|
|
407
|
-
})
|
|
408
|
-
|
|
409
|
-
test('behavior: validates valid keychain with p256 inner', () => {
|
|
410
|
-
expect(() =>
|
|
411
|
-
SignatureEnvelope.assert(signature_keychain_p256),
|
|
412
|
-
).not.toThrow()
|
|
413
|
-
})
|
|
414
|
-
|
|
415
|
-
test('behavior: validates valid keychain with webAuthn inner', () => {
|
|
416
|
-
expect(() =>
|
|
417
|
-
SignatureEnvelope.assert(signature_keychain_webauthn),
|
|
418
|
-
).not.toThrow()
|
|
419
|
-
})
|
|
420
|
-
|
|
421
|
-
test('behavior: validates keychain without explicit type', () => {
|
|
422
|
-
const { type: _, ...signatureWithoutType } = signature_keychain_secp256k1
|
|
423
|
-
expect(() => SignatureEnvelope.assert(signatureWithoutType)).not.toThrow()
|
|
424
|
-
})
|
|
425
|
-
|
|
426
|
-
test('error: throws on invalid inner signature', () => {
|
|
427
|
-
expect(() =>
|
|
428
|
-
SignatureEnvelope.assert({
|
|
429
|
-
userAddress: '0x1234567890123456789012345678901234567890',
|
|
430
|
-
inner: SignatureEnvelope.from({
|
|
431
|
-
r: 0n,
|
|
432
|
-
s: 0n,
|
|
433
|
-
yParity: 2,
|
|
434
|
-
}),
|
|
435
|
-
type: 'keychain',
|
|
436
|
-
} as any),
|
|
437
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
438
|
-
`[Signature.InvalidYParityError: Value \`2\` is an invalid y-parity value. Y-parity must be 0 or 1.]`,
|
|
439
|
-
)
|
|
440
|
-
})
|
|
441
|
-
})
|
|
442
|
-
|
|
443
|
-
test('error: throws on invalid envelope', () => {
|
|
444
|
-
expect(() =>
|
|
445
|
-
SignatureEnvelope.assert({} as any),
|
|
446
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
447
|
-
`[SignatureEnvelope.CoercionError: Unable to coerce value (\`{}\`) to a valid signature envelope.]`,
|
|
448
|
-
)
|
|
449
|
-
})
|
|
450
|
-
|
|
451
|
-
test('error: throws on incomplete signature', () => {
|
|
452
|
-
expect(() =>
|
|
453
|
-
SignatureEnvelope.assert({
|
|
454
|
-
r: 0n,
|
|
455
|
-
s: 0n,
|
|
456
|
-
} as any),
|
|
457
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
458
|
-
`[SignatureEnvelope.CoercionError: Unable to coerce value (\`{"r":"0#__bigint","s":"0#__bigint"}\`) to a valid signature envelope.]`,
|
|
459
|
-
)
|
|
460
|
-
})
|
|
461
|
-
})
|
|
462
|
-
|
|
463
|
-
describe('deserialize', () => {
|
|
464
|
-
describe('secp256k1', () => {
|
|
465
|
-
test('behavior: deserializes valid signature', () => {
|
|
466
|
-
const serialized = Signature.toHex(signature_secp256k1)
|
|
467
|
-
|
|
468
|
-
const envelope = SignatureEnvelope.deserialize(serialized)
|
|
469
|
-
|
|
470
|
-
expect(envelope).toMatchObject({
|
|
471
|
-
signature: {
|
|
472
|
-
r: signature_secp256k1.r,
|
|
473
|
-
s: signature_secp256k1.s,
|
|
474
|
-
yParity: signature_secp256k1.yParity,
|
|
475
|
-
},
|
|
476
|
-
type: 'secp256k1',
|
|
477
|
-
})
|
|
478
|
-
})
|
|
479
|
-
|
|
480
|
-
test('error: throws on invalid size', () => {
|
|
481
|
-
expect(() =>
|
|
482
|
-
SignatureEnvelope.deserialize('0xdeadbeef'),
|
|
483
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
484
|
-
`
|
|
485
|
-
[SignatureEnvelope.InvalidSerializedError: Unable to deserialize signature envelope: Unknown signature type identifier: 0xde. Expected 0x01 (P256) or 0x02 (WebAuthn)
|
|
486
|
-
|
|
487
|
-
Serialized: 0xdeadbeef]
|
|
488
|
-
`,
|
|
489
|
-
)
|
|
490
|
-
})
|
|
491
|
-
|
|
492
|
-
test('error: throws on invalid yParity', () => {
|
|
493
|
-
// Signature with invalid yParity (must be 0 or 1)
|
|
494
|
-
const invalidSig =
|
|
495
|
-
'0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000102'
|
|
496
|
-
expect(() =>
|
|
497
|
-
SignatureEnvelope.deserialize(invalidSig),
|
|
498
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
499
|
-
`[Signature.InvalidYParityError: Value \`2\` is an invalid y-parity value. Y-parity must be 0 or 1.]`,
|
|
500
|
-
)
|
|
501
|
-
})
|
|
502
|
-
})
|
|
503
|
-
|
|
504
|
-
describe('p256', () => {
|
|
505
|
-
test('behavior: deserializes P256 signature', () => {
|
|
506
|
-
const serialized = SignatureEnvelope.serialize(signature_p256)
|
|
507
|
-
const deserialized = SignatureEnvelope.deserialize(serialized)
|
|
508
|
-
|
|
509
|
-
expect(deserialized).toMatchObject({
|
|
510
|
-
signature: {
|
|
511
|
-
r: signature_p256.signature.r,
|
|
512
|
-
s: signature_p256.signature.s,
|
|
513
|
-
},
|
|
514
|
-
publicKey: {
|
|
515
|
-
x: signature_p256.publicKey.x,
|
|
516
|
-
y: signature_p256.publicKey.y,
|
|
517
|
-
},
|
|
518
|
-
prehash: signature_p256.prehash,
|
|
519
|
-
type: 'p256',
|
|
520
|
-
})
|
|
521
|
-
})
|
|
522
|
-
|
|
523
|
-
test('error: throws on invalid P256 signature length', () => {
|
|
524
|
-
// P256 signature with wrong length (should be 130 bytes total, but only 100)
|
|
525
|
-
const invalidSig = `0x01${'00'.repeat(100)}` as `0x${string}`
|
|
526
|
-
expect(() =>
|
|
527
|
-
SignatureEnvelope.deserialize(invalidSig),
|
|
528
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
529
|
-
`
|
|
530
|
-
[SignatureEnvelope.InvalidSerializedError: Unable to deserialize signature envelope: Invalid P256 signature envelope size: expected 129 bytes, got 100 bytes
|
|
531
|
-
|
|
532
|
-
Serialized: 0x0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]
|
|
533
|
-
`,
|
|
534
|
-
)
|
|
535
|
-
})
|
|
536
|
-
})
|
|
537
|
-
|
|
538
|
-
describe('webAuthn', () => {
|
|
539
|
-
test('behavior: deserializes WebAuthn signature', () => {
|
|
540
|
-
const serialized = SignatureEnvelope.serialize(signature_webauthn)
|
|
541
|
-
const deserialized = SignatureEnvelope.deserialize(serialized)
|
|
542
|
-
|
|
543
|
-
expect(deserialized).toMatchObject({
|
|
544
|
-
signature: {
|
|
545
|
-
r: signature_webauthn.signature.r,
|
|
546
|
-
s: signature_webauthn.signature.s,
|
|
547
|
-
},
|
|
548
|
-
publicKey: {
|
|
549
|
-
x: signature_webauthn.publicKey.x,
|
|
550
|
-
y: signature_webauthn.publicKey.y,
|
|
551
|
-
},
|
|
552
|
-
metadata: {
|
|
553
|
-
authenticatorData: signature_webauthn.metadata.authenticatorData,
|
|
554
|
-
clientDataJSON: signature_webauthn.metadata.clientDataJSON,
|
|
555
|
-
},
|
|
556
|
-
type: 'webAuthn',
|
|
557
|
-
})
|
|
558
|
-
})
|
|
559
|
-
|
|
560
|
-
test('error: throws on invalid WebAuthn signature length', () => {
|
|
561
|
-
// WebAuthn signature too short (must be at least 129 bytes: 1 type + 128 signature data)
|
|
562
|
-
const invalidSig = `0x02${'00'.repeat(100)}` as const
|
|
563
|
-
expect(() =>
|
|
564
|
-
SignatureEnvelope.deserialize(invalidSig),
|
|
565
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
566
|
-
`
|
|
567
|
-
[SignatureEnvelope.InvalidSerializedError: Unable to deserialize signature envelope: Invalid WebAuthn signature envelope size: expected at least 128 bytes, got 100 bytes
|
|
568
|
-
|
|
569
|
-
Serialized: 0x0200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]
|
|
570
|
-
`,
|
|
571
|
-
)
|
|
572
|
-
})
|
|
573
|
-
|
|
574
|
-
test('error: throws on invalid clientDataJSON', () => {
|
|
575
|
-
// Create a signature with invalid JSON (not properly formatted)
|
|
576
|
-
const invalidMetadata = {
|
|
577
|
-
authenticatorData: `0x${'00'.repeat(37)}` as const,
|
|
578
|
-
clientDataJSON: 'not-valid-json',
|
|
579
|
-
}
|
|
580
|
-
const serialized = SignatureEnvelope.serialize({
|
|
581
|
-
...signature_webauthn,
|
|
582
|
-
metadata: invalidMetadata,
|
|
583
|
-
})
|
|
584
|
-
|
|
585
|
-
expect(() =>
|
|
586
|
-
SignatureEnvelope.deserialize(serialized),
|
|
587
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
588
|
-
`
|
|
589
|
-
[SignatureEnvelope.InvalidSerializedError: Unable to deserialize signature envelope: Unable to parse WebAuthn metadata: could not extract valid authenticatorData and clientDataJSON
|
|
590
|
-
|
|
591
|
-
Serialized: 0x02000000000000000000000000000000000000000000000000000000000000000000000000006e6f742d76616c69642d6a736f6eccbb3485d4726235f13cb15ef394fb7158179fb7b1925eccec0147671090c52e77c3c53373cc1e3b05e7c23f609deb17cea8fe097300c45411237e9fe4166b35ad8ac16e167d6992c3e120d7f17d2376bc1cbcf30c46ba6dd00ce07303e742f511edf6ce1c32de66846f56afa7be1cbd729bc35750b6d0cdcf3ec9d75461aba0]
|
|
592
|
-
`,
|
|
593
|
-
)
|
|
594
|
-
})
|
|
595
|
-
|
|
596
|
-
test('error: throws on unknown type identifier', () => {
|
|
597
|
-
const unknownType = `0xff${'00'.repeat(129)}` as const
|
|
598
|
-
expect(() =>
|
|
599
|
-
SignatureEnvelope.deserialize(unknownType),
|
|
600
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
601
|
-
`
|
|
602
|
-
[SignatureEnvelope.InvalidSerializedError: Unable to deserialize signature envelope: Unknown signature type identifier: 0xff. Expected 0x01 (P256) or 0x02 (WebAuthn)
|
|
603
|
-
|
|
604
|
-
Serialized: 0xff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]
|
|
605
|
-
`,
|
|
606
|
-
)
|
|
607
|
-
})
|
|
608
|
-
})
|
|
609
|
-
|
|
610
|
-
describe('keychain', () => {
|
|
611
|
-
test('behavior: deserializes keychain signature with secp256k1 inner', () => {
|
|
612
|
-
const serialized = SignatureEnvelope.serialize(
|
|
613
|
-
signature_keychain_secp256k1,
|
|
614
|
-
)
|
|
615
|
-
const deserialized = SignatureEnvelope.deserialize(serialized)
|
|
616
|
-
|
|
617
|
-
expect(deserialized).toMatchObject({
|
|
618
|
-
userAddress: signature_keychain_secp256k1.userAddress,
|
|
619
|
-
inner: SignatureEnvelope.from(signature_secp256k1),
|
|
620
|
-
type: 'keychain',
|
|
621
|
-
})
|
|
622
|
-
})
|
|
623
|
-
|
|
624
|
-
test('behavior: deserializes keychain signature with p256 inner', () => {
|
|
625
|
-
const serialized = SignatureEnvelope.serialize(signature_keychain_p256)
|
|
626
|
-
const deserialized = SignatureEnvelope.deserialize(serialized)
|
|
627
|
-
|
|
628
|
-
expect(deserialized).toMatchInlineSnapshot(`
|
|
629
|
-
{
|
|
630
|
-
"inner": {
|
|
631
|
-
"prehash": true,
|
|
632
|
-
"publicKey": {
|
|
633
|
-
"prefix": 4,
|
|
634
|
-
"x": 78495282704852028275327922540131762143565388050940484317945369745559774511861n,
|
|
635
|
-
"y": 8109764566587999957624872393871720746996669263962991155166704261108473113504n,
|
|
636
|
-
},
|
|
637
|
-
"signature": {
|
|
638
|
-
"r": 92602584010956101470289867944347135737570451066466093224269890121909314569518n,
|
|
639
|
-
"s": 54171125190222965779385658110416711469231271457324878825831748147306957269813n,
|
|
640
|
-
},
|
|
641
|
-
"type": "p256",
|
|
642
|
-
},
|
|
643
|
-
"type": "keychain",
|
|
644
|
-
"userAddress": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
|
|
645
|
-
}
|
|
646
|
-
`)
|
|
647
|
-
})
|
|
648
|
-
|
|
649
|
-
test('behavior: deserializes keychain signature with webAuthn inner', () => {
|
|
650
|
-
const serialized = SignatureEnvelope.serialize(
|
|
651
|
-
signature_keychain_webauthn,
|
|
652
|
-
)
|
|
653
|
-
const deserialized = SignatureEnvelope.deserialize(serialized)
|
|
654
|
-
|
|
655
|
-
expect(deserialized).toMatchInlineSnapshot(`
|
|
656
|
-
{
|
|
657
|
-
"inner": {
|
|
658
|
-
"metadata": {
|
|
659
|
-
"authenticatorData": "0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000",
|
|
660
|
-
"clientDataJSON": "{"type":"webauthn.get","challenge":"3q2-7w","origin":"http://localhost","crossOrigin":false}",
|
|
661
|
-
},
|
|
662
|
-
"publicKey": {
|
|
663
|
-
"prefix": 4,
|
|
664
|
-
"x": 78495282704852028275327922540131762143565388050940484317945369745559774511861n,
|
|
665
|
-
"y": 8109764566587999957624872393871720746996669263962991155166704261108473113504n,
|
|
666
|
-
},
|
|
667
|
-
"signature": {
|
|
668
|
-
"r": 92602584010956101470289867944347135737570451066466093224269890121909314569518n,
|
|
669
|
-
"s": 54171125190222965779385658110416711469231271457324878825831748147306957269813n,
|
|
670
|
-
},
|
|
671
|
-
"type": "webAuthn",
|
|
672
|
-
},
|
|
673
|
-
"type": "keychain",
|
|
674
|
-
"userAddress": "0xfedcbafedcbafedcbafedcbafedcbafedcbafedc",
|
|
675
|
-
}
|
|
676
|
-
`)
|
|
677
|
-
})
|
|
678
|
-
|
|
679
|
-
test('error: throws on invalid keychain signature length', () => {
|
|
680
|
-
// Keychain signature too short (must be at least 21 bytes: 1 type + 20 address)
|
|
681
|
-
const invalidSig = `0x03${'00'.repeat(10)}` as const
|
|
682
|
-
expect(() =>
|
|
683
|
-
SignatureEnvelope.deserialize(invalidSig),
|
|
684
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
685
|
-
`[Hex.SliceOffsetOutOfBoundsError: Slice starting at offset \`20\` is out-of-bounds (size: \`10\`).]`,
|
|
686
|
-
)
|
|
687
|
-
})
|
|
688
|
-
})
|
|
689
|
-
})
|
|
690
|
-
|
|
691
|
-
describe('from', () => {
|
|
692
|
-
describe('secp256k1', () => {
|
|
693
|
-
test('behavior: coerces from hex string', () => {
|
|
694
|
-
const serialized = Signature.toHex(signature_secp256k1)
|
|
695
|
-
|
|
696
|
-
const envelope = SignatureEnvelope.from(serialized)
|
|
697
|
-
|
|
698
|
-
expect(envelope).toMatchObject({
|
|
699
|
-
signature: {
|
|
700
|
-
r: signature_secp256k1.r,
|
|
701
|
-
s: signature_secp256k1.s,
|
|
702
|
-
yParity: signature_secp256k1.yParity,
|
|
703
|
-
},
|
|
704
|
-
type: 'secp256k1',
|
|
705
|
-
})
|
|
706
|
-
})
|
|
707
|
-
|
|
708
|
-
test('behavior: returns object as-is', () => {
|
|
709
|
-
const envelope: SignatureEnvelope.SignatureEnvelope = {
|
|
710
|
-
signature: signature_secp256k1,
|
|
711
|
-
type: 'secp256k1',
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
const result = SignatureEnvelope.from(envelope)
|
|
715
|
-
|
|
716
|
-
expect(result).toEqual(envelope)
|
|
717
|
-
})
|
|
718
|
-
|
|
719
|
-
test('behavior: coerces from flat signature', () => {
|
|
720
|
-
const result = SignatureEnvelope.from(signature_secp256k1)
|
|
721
|
-
|
|
722
|
-
expect(result).toMatchObject({
|
|
723
|
-
signature: {
|
|
724
|
-
r: signature_secp256k1.r,
|
|
725
|
-
s: signature_secp256k1.s,
|
|
726
|
-
yParity: signature_secp256k1.yParity,
|
|
727
|
-
},
|
|
728
|
-
type: 'secp256k1',
|
|
729
|
-
})
|
|
730
|
-
})
|
|
731
|
-
})
|
|
732
|
-
|
|
733
|
-
describe('p256', () => {
|
|
734
|
-
test('behavior: coerces from hex string', () => {
|
|
735
|
-
const serialized = SignatureEnvelope.serialize(signature_p256)
|
|
736
|
-
const envelope = SignatureEnvelope.from(serialized)
|
|
737
|
-
|
|
738
|
-
expect(envelope).toMatchObject({
|
|
739
|
-
signature: {
|
|
740
|
-
r: signature_p256.signature.r,
|
|
741
|
-
s: signature_p256.signature.s,
|
|
742
|
-
},
|
|
743
|
-
type: 'p256',
|
|
744
|
-
})
|
|
745
|
-
})
|
|
746
|
-
|
|
747
|
-
test('behavior: adds type to object', () => {
|
|
748
|
-
const { type: _, ...withoutType } = signature_p256
|
|
749
|
-
const envelope = SignatureEnvelope.from(withoutType)
|
|
750
|
-
|
|
751
|
-
expect(envelope.type).toBe('p256')
|
|
752
|
-
})
|
|
753
|
-
})
|
|
754
|
-
|
|
755
|
-
describe('webAuthn', () => {
|
|
756
|
-
test('behavior: coerces from hex string', () => {
|
|
757
|
-
const serialized = SignatureEnvelope.serialize(signature_webauthn)
|
|
758
|
-
const envelope = SignatureEnvelope.from(serialized)
|
|
759
|
-
|
|
760
|
-
expect(envelope).toMatchObject({
|
|
761
|
-
signature: {
|
|
762
|
-
r: signature_webauthn.signature.r,
|
|
763
|
-
s: signature_webauthn.signature.s,
|
|
764
|
-
},
|
|
765
|
-
type: 'webAuthn',
|
|
766
|
-
})
|
|
767
|
-
})
|
|
768
|
-
|
|
769
|
-
test('behavior: adds type to object', () => {
|
|
770
|
-
const { type: _, ...withoutType } = signature_webauthn
|
|
771
|
-
const envelope = SignatureEnvelope.from(withoutType)
|
|
772
|
-
|
|
773
|
-
expect(envelope.type).toBe('webAuthn')
|
|
774
|
-
})
|
|
775
|
-
})
|
|
776
|
-
|
|
777
|
-
describe('keychain', () => {
|
|
778
|
-
test('behavior: coerces from hex string with secp256k1 inner', () => {
|
|
779
|
-
const serialized = SignatureEnvelope.serialize(
|
|
780
|
-
signature_keychain_secp256k1,
|
|
781
|
-
)
|
|
782
|
-
const envelope = SignatureEnvelope.from(serialized)
|
|
783
|
-
|
|
784
|
-
expect(envelope).toMatchObject({
|
|
785
|
-
userAddress: signature_keychain_secp256k1.userAddress,
|
|
786
|
-
inner: SignatureEnvelope.from(signature_secp256k1),
|
|
787
|
-
type: 'keychain',
|
|
788
|
-
})
|
|
789
|
-
})
|
|
790
|
-
|
|
791
|
-
test('behavior: coerces from hex string with p256 inner', () => {
|
|
792
|
-
const serialized = SignatureEnvelope.serialize(signature_keychain_p256)
|
|
793
|
-
const envelope = SignatureEnvelope.from(serialized)
|
|
794
|
-
|
|
795
|
-
expect(envelope).toMatchObject({
|
|
796
|
-
userAddress: signature_keychain_p256.userAddress,
|
|
797
|
-
type: 'keychain',
|
|
798
|
-
})
|
|
799
|
-
})
|
|
800
|
-
|
|
801
|
-
test('behavior: adds type to object', () => {
|
|
802
|
-
const { type: _, ...withoutType } = signature_keychain_secp256k1
|
|
803
|
-
const envelope = SignatureEnvelope.from(withoutType)
|
|
804
|
-
|
|
805
|
-
expect(envelope.type).toBe('keychain')
|
|
806
|
-
})
|
|
807
|
-
})
|
|
808
|
-
})
|
|
809
|
-
|
|
810
|
-
describe('getType', () => {
|
|
811
|
-
describe('secp256k1', () => {
|
|
812
|
-
test('behavior: returns explicit type', () => {
|
|
813
|
-
const envelope: SignatureEnvelope.SignatureEnvelope = {
|
|
814
|
-
signature: { r: 0n, s: 0n, yParity: 0 },
|
|
815
|
-
type: 'secp256k1',
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
expect(SignatureEnvelope.getType(envelope)).toBe('secp256k1')
|
|
819
|
-
})
|
|
820
|
-
|
|
821
|
-
test('behavior: infers type from properties', () => {
|
|
822
|
-
expect(
|
|
823
|
-
SignatureEnvelope.getType({ signature: signature_secp256k1 }),
|
|
824
|
-
).toBe('secp256k1')
|
|
825
|
-
})
|
|
826
|
-
|
|
827
|
-
test('behavior: infers type from flat signature', () => {
|
|
828
|
-
const signature = { r: 0n, s: 0n, yParity: 0 }
|
|
829
|
-
expect(SignatureEnvelope.getType(signature)).toBe('secp256k1')
|
|
830
|
-
})
|
|
831
|
-
})
|
|
832
|
-
|
|
833
|
-
describe('p256', () => {
|
|
834
|
-
test('behavior: returns explicit type', () => {
|
|
835
|
-
expect(SignatureEnvelope.getType(signature_p256)).toBe('p256')
|
|
836
|
-
})
|
|
837
|
-
|
|
838
|
-
test('behavior: infers type from properties', () => {
|
|
839
|
-
const { type: _, ...signatureWithoutType } = signature_p256
|
|
840
|
-
expect(SignatureEnvelope.getType(signatureWithoutType)).toBe('p256')
|
|
841
|
-
})
|
|
842
|
-
})
|
|
843
|
-
|
|
844
|
-
describe('webAuthn', () => {
|
|
845
|
-
test('behavior: returns explicit type', () => {
|
|
846
|
-
expect(SignatureEnvelope.getType(signature_webauthn)).toBe('webAuthn')
|
|
847
|
-
})
|
|
848
|
-
|
|
849
|
-
test('behavior: infers type from properties', () => {
|
|
850
|
-
const { type: _, ...signatureWithoutType } = signature_webauthn
|
|
851
|
-
expect(SignatureEnvelope.getType(signatureWithoutType)).toBe('webAuthn')
|
|
852
|
-
})
|
|
853
|
-
})
|
|
854
|
-
|
|
855
|
-
describe('keychain', () => {
|
|
856
|
-
test('behavior: returns explicit type', () => {
|
|
857
|
-
expect(SignatureEnvelope.getType(signature_keychain_secp256k1)).toBe(
|
|
858
|
-
'keychain',
|
|
859
|
-
)
|
|
860
|
-
})
|
|
861
|
-
|
|
862
|
-
test('behavior: infers type from properties', () => {
|
|
863
|
-
const { type: _, ...signatureWithoutType } = signature_keychain_secp256k1
|
|
864
|
-
expect(SignatureEnvelope.getType(signatureWithoutType)).toBe('keychain')
|
|
865
|
-
})
|
|
866
|
-
|
|
867
|
-
test('behavior: infers type for keychain with p256 inner', () => {
|
|
868
|
-
const { type: _, ...signatureWithoutType } = signature_keychain_p256
|
|
869
|
-
expect(SignatureEnvelope.getType(signatureWithoutType)).toBe('keychain')
|
|
870
|
-
})
|
|
871
|
-
|
|
872
|
-
test('behavior: infers type for keychain with webAuthn inner', () => {
|
|
873
|
-
const { type: _, ...signatureWithoutType } = signature_keychain_webauthn
|
|
874
|
-
expect(SignatureEnvelope.getType(signatureWithoutType)).toBe('keychain')
|
|
875
|
-
})
|
|
876
|
-
})
|
|
877
|
-
|
|
878
|
-
test('error: throws on invalid envelope', () => {
|
|
879
|
-
expect(() =>
|
|
880
|
-
SignatureEnvelope.getType({} as any),
|
|
881
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
882
|
-
`[SignatureEnvelope.CoercionError: Unable to coerce value (\`{}\`) to a valid signature envelope.]`,
|
|
883
|
-
)
|
|
884
|
-
})
|
|
885
|
-
|
|
886
|
-
test('error: throws on incomplete signature', () => {
|
|
887
|
-
expect(() =>
|
|
888
|
-
SignatureEnvelope.getType({
|
|
889
|
-
r: 0n,
|
|
890
|
-
s: 0n,
|
|
891
|
-
} as any),
|
|
892
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
893
|
-
`[SignatureEnvelope.CoercionError: Unable to coerce value (\`{"r":"0#__bigint","s":"0#__bigint"}\`) to a valid signature envelope.]`,
|
|
894
|
-
)
|
|
895
|
-
})
|
|
896
|
-
})
|
|
897
|
-
|
|
898
|
-
describe('serialize', () => {
|
|
899
|
-
describe('secp256k1', () => {
|
|
900
|
-
test('behavior: serializes with explicit type', () => {
|
|
901
|
-
const envelope: SignatureEnvelope.SignatureEnvelope = {
|
|
902
|
-
signature: signature_secp256k1,
|
|
903
|
-
type: 'secp256k1',
|
|
904
|
-
}
|
|
905
|
-
|
|
906
|
-
const serialized = SignatureEnvelope.serialize(envelope)
|
|
907
|
-
|
|
908
|
-
expect(serialized).toBe(Signature.toHex(signature_secp256k1))
|
|
909
|
-
})
|
|
910
|
-
|
|
911
|
-
test('behavior: serializes without explicit type', () => {
|
|
912
|
-
const serialized = SignatureEnvelope.serialize({
|
|
913
|
-
signature: signature_secp256k1,
|
|
914
|
-
type: 'secp256k1',
|
|
915
|
-
})
|
|
916
|
-
|
|
917
|
-
expect(serialized).toBe(Signature.toHex(signature_secp256k1))
|
|
918
|
-
})
|
|
919
|
-
})
|
|
920
|
-
|
|
921
|
-
describe('p256', () => {
|
|
922
|
-
test('behavior: serializes P256 signature with type identifier', () => {
|
|
923
|
-
const serialized = SignatureEnvelope.serialize(signature_p256)
|
|
924
|
-
|
|
925
|
-
// Should be 130 bytes: 1 (type) + 32 (r) + 32 (s) + 32 (pubKeyX) + 32 (pubKeyY) + 1 (prehash)
|
|
926
|
-
expect(serialized.length).toBe(2 + 130 * 2) // 2 for '0x' prefix + 130 bytes * 2 hex chars
|
|
927
|
-
|
|
928
|
-
// First byte should be P256 type identifier (0x01)
|
|
929
|
-
expect(serialized.slice(0, 4)).toBe('0x01')
|
|
930
|
-
})
|
|
931
|
-
|
|
932
|
-
test('behavior: serializes prehash flag correctly', () => {
|
|
933
|
-
const withPreHashFalse = { ...signature_p256, prehash: false }
|
|
934
|
-
const serialized = SignatureEnvelope.serialize(withPreHashFalse)
|
|
935
|
-
|
|
936
|
-
// Last byte should be 0x00 for false
|
|
937
|
-
expect(serialized.slice(-2)).toBe('00')
|
|
938
|
-
})
|
|
939
|
-
})
|
|
940
|
-
|
|
941
|
-
describe('webAuthn', () => {
|
|
942
|
-
test('behavior: serializes WebAuthn signature with type identifier', () => {
|
|
943
|
-
const serialized = SignatureEnvelope.serialize(signature_webauthn)
|
|
944
|
-
|
|
945
|
-
// Should be: 1 (type) + authenticatorData.length + clientDataJSON.length + 128 (signature components)
|
|
946
|
-
const authDataLength =
|
|
947
|
-
(signature_webauthn.metadata.authenticatorData.length - 2) / 2
|
|
948
|
-
const clientDataLength = signature_webauthn.metadata.clientDataJSON.length
|
|
949
|
-
const expectedLength =
|
|
950
|
-
2 + (1 + authDataLength + clientDataLength + 128) * 2
|
|
951
|
-
|
|
952
|
-
expect(serialized.length).toBe(expectedLength)
|
|
953
|
-
|
|
954
|
-
// First byte should be WebAuthn type identifier (0x02)
|
|
955
|
-
expect(serialized.slice(0, 4)).toBe('0x02')
|
|
956
|
-
})
|
|
957
|
-
|
|
958
|
-
test('behavior: preserves metadata', () => {
|
|
959
|
-
const serialized = SignatureEnvelope.serialize(signature_webauthn)
|
|
960
|
-
const deserialized = SignatureEnvelope.deserialize(serialized)
|
|
961
|
-
|
|
962
|
-
expect(deserialized.metadata?.authenticatorData).toBe(
|
|
963
|
-
signature_webauthn.metadata.authenticatorData,
|
|
964
|
-
)
|
|
965
|
-
expect(deserialized.metadata?.clientDataJSON).toBe(
|
|
966
|
-
signature_webauthn.metadata.clientDataJSON,
|
|
967
|
-
)
|
|
968
|
-
})
|
|
969
|
-
})
|
|
970
|
-
|
|
971
|
-
describe('keychain', () => {
|
|
972
|
-
test('behavior: serializes keychain signature with secp256k1 inner and type identifier', () => {
|
|
973
|
-
const serialized = SignatureEnvelope.serialize(
|
|
974
|
-
signature_keychain_secp256k1,
|
|
975
|
-
)
|
|
976
|
-
|
|
977
|
-
// Should be: 1 (type) + 20 (address) + 65 (secp256k1 signature)
|
|
978
|
-
expect(Hex.size(serialized)).toBe(1 + 20 + 65)
|
|
979
|
-
|
|
980
|
-
// First byte should be Keychain type identifier (0x03)
|
|
981
|
-
expect(Hex.slice(serialized, 0, 1)).toBe('0x03')
|
|
982
|
-
|
|
983
|
-
// Next 20 bytes should be the user address (without '0x')
|
|
984
|
-
expect(Hex.slice(serialized, 1, 21)).toBe(
|
|
985
|
-
signature_keychain_secp256k1.userAddress,
|
|
986
|
-
)
|
|
987
|
-
})
|
|
988
|
-
|
|
989
|
-
test('behavior: serializes keychain signature with p256 inner', () => {
|
|
990
|
-
const serialized = SignatureEnvelope.serialize(signature_keychain_p256)
|
|
991
|
-
|
|
992
|
-
// Should be: 1 (type) + 20 (address) + 130 (p256 signature with type)
|
|
993
|
-
expect(Hex.size(serialized)).toBe(1 + 20 + 130)
|
|
994
|
-
|
|
995
|
-
// First byte should be Keychain type identifier (0x03)
|
|
996
|
-
expect(Hex.slice(serialized, 0, 1)).toBe('0x03')
|
|
997
|
-
|
|
998
|
-
// Next 20 bytes should be the user address (without '0x')
|
|
999
|
-
expect(Hex.slice(serialized, 1, 21)).toBe(
|
|
1000
|
-
signature_keychain_p256.userAddress,
|
|
1001
|
-
)
|
|
1002
|
-
|
|
1003
|
-
// Next 130 bytes should be the p256 signature
|
|
1004
|
-
expect(Hex.slice(serialized, 21, 151)).toBe(
|
|
1005
|
-
SignatureEnvelope.serialize(signature_p256),
|
|
1006
|
-
)
|
|
1007
|
-
})
|
|
1008
|
-
|
|
1009
|
-
test('behavior: serializes keychain signature with webAuthn inner', () => {
|
|
1010
|
-
const serialized = SignatureEnvelope.serialize(
|
|
1011
|
-
signature_keychain_webauthn,
|
|
1012
|
-
)
|
|
1013
|
-
|
|
1014
|
-
// First byte should be Keychain type identifier (0x03)
|
|
1015
|
-
expect(Hex.slice(serialized, 0, 1)).toBe('0x03')
|
|
1016
|
-
|
|
1017
|
-
// Should contain the user address
|
|
1018
|
-
expect(Hex.slice(serialized, 1, 21)).toBe(
|
|
1019
|
-
signature_keychain_webauthn.userAddress,
|
|
1020
|
-
)
|
|
1021
|
-
|
|
1022
|
-
// Next N bytes should be the webAuthn signature
|
|
1023
|
-
expect(Hex.slice(serialized, 21)).toBe(
|
|
1024
|
-
SignatureEnvelope.serialize(signature_webauthn),
|
|
1025
|
-
)
|
|
1026
|
-
})
|
|
1027
|
-
|
|
1028
|
-
test('behavior: preserves userAddress and inner signature', () => {
|
|
1029
|
-
const serialized = SignatureEnvelope.serialize(
|
|
1030
|
-
signature_keychain_secp256k1,
|
|
1031
|
-
)
|
|
1032
|
-
const deserialized = SignatureEnvelope.deserialize(serialized)
|
|
1033
|
-
|
|
1034
|
-
expect(deserialized.userAddress).toBe(
|
|
1035
|
-
signature_keychain_secp256k1.userAddress,
|
|
1036
|
-
)
|
|
1037
|
-
expect(deserialized.inner).toMatchObject({
|
|
1038
|
-
type: 'secp256k1',
|
|
1039
|
-
signature: {
|
|
1040
|
-
r: signature_secp256k1.r,
|
|
1041
|
-
s: signature_secp256k1.s,
|
|
1042
|
-
yParity: signature_secp256k1.yParity,
|
|
1043
|
-
},
|
|
1044
|
-
})
|
|
1045
|
-
})
|
|
1046
|
-
})
|
|
1047
|
-
|
|
1048
|
-
describe('roundtrip', () => {
|
|
1049
|
-
describe('secp256k1', () => {
|
|
1050
|
-
test('behavior: roundtrips serialize -> deserialize', () => {
|
|
1051
|
-
const envelope: SignatureEnvelope.Secp256k1 = {
|
|
1052
|
-
signature: signature_secp256k1,
|
|
1053
|
-
type: 'secp256k1',
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1056
|
-
const serialized = SignatureEnvelope.serialize(envelope)
|
|
1057
|
-
const deserialized = SignatureEnvelope.deserialize(serialized)
|
|
1058
|
-
|
|
1059
|
-
expect(deserialized).toMatchObject({
|
|
1060
|
-
signature: {
|
|
1061
|
-
r: signature_secp256k1.r,
|
|
1062
|
-
s: signature_secp256k1.s,
|
|
1063
|
-
yParity: signature_secp256k1.yParity,
|
|
1064
|
-
},
|
|
1065
|
-
type: 'secp256k1',
|
|
1066
|
-
})
|
|
1067
|
-
})
|
|
1068
|
-
})
|
|
1069
|
-
|
|
1070
|
-
describe('p256', () => {
|
|
1071
|
-
test('behavior: roundtrips serialize -> deserialize', () => {
|
|
1072
|
-
const serialized = SignatureEnvelope.serialize(signature_p256)
|
|
1073
|
-
const deserialized = SignatureEnvelope.deserialize(serialized)
|
|
1074
|
-
|
|
1075
|
-
expect(deserialized).toMatchObject({
|
|
1076
|
-
signature: {
|
|
1077
|
-
r: signature_p256.signature.r,
|
|
1078
|
-
s: signature_p256.signature.s,
|
|
1079
|
-
},
|
|
1080
|
-
publicKey: {
|
|
1081
|
-
x: signature_p256.publicKey.x,
|
|
1082
|
-
y: signature_p256.publicKey.y,
|
|
1083
|
-
},
|
|
1084
|
-
prehash: signature_p256.prehash,
|
|
1085
|
-
type: 'p256',
|
|
1086
|
-
})
|
|
1087
|
-
})
|
|
1088
|
-
|
|
1089
|
-
test('behavior: handles prehash=false', () => {
|
|
1090
|
-
const signature = { ...signature_p256, prehash: false }
|
|
1091
|
-
const serialized = SignatureEnvelope.serialize(signature)
|
|
1092
|
-
const deserialized = SignatureEnvelope.deserialize(serialized)
|
|
1093
|
-
|
|
1094
|
-
expect(deserialized.prehash).toBe(false)
|
|
1095
|
-
})
|
|
1096
|
-
})
|
|
1097
|
-
|
|
1098
|
-
describe('webAuthn', () => {
|
|
1099
|
-
test('behavior: roundtrips serialize -> deserialize', () => {
|
|
1100
|
-
const serialized = SignatureEnvelope.serialize(signature_webauthn)
|
|
1101
|
-
const deserialized = SignatureEnvelope.deserialize(serialized)
|
|
1102
|
-
|
|
1103
|
-
expect(deserialized).toMatchObject({
|
|
1104
|
-
signature: {
|
|
1105
|
-
r: signature_webauthn.signature.r,
|
|
1106
|
-
s: signature_webauthn.signature.s,
|
|
1107
|
-
},
|
|
1108
|
-
publicKey: {
|
|
1109
|
-
x: signature_webauthn.publicKey.x,
|
|
1110
|
-
y: signature_webauthn.publicKey.y,
|
|
1111
|
-
},
|
|
1112
|
-
metadata: {
|
|
1113
|
-
authenticatorData: signature_webauthn.metadata.authenticatorData,
|
|
1114
|
-
clientDataJSON: signature_webauthn.metadata.clientDataJSON,
|
|
1115
|
-
},
|
|
1116
|
-
type: 'webAuthn',
|
|
1117
|
-
})
|
|
1118
|
-
})
|
|
1119
|
-
|
|
1120
|
-
test('behavior: handles variable-length clientDataJSON', () => {
|
|
1121
|
-
const longClientData = JSON.stringify({
|
|
1122
|
-
type: 'webAuthn.get',
|
|
1123
|
-
challenge: 'a'.repeat(100),
|
|
1124
|
-
origin: 'https://example.com',
|
|
1125
|
-
})
|
|
1126
|
-
|
|
1127
|
-
const signatureWithLongData = {
|
|
1128
|
-
...signature_webauthn,
|
|
1129
|
-
metadata: {
|
|
1130
|
-
...signature_webauthn.metadata,
|
|
1131
|
-
clientDataJSON: longClientData,
|
|
1132
|
-
},
|
|
1133
|
-
}
|
|
1134
|
-
|
|
1135
|
-
const serialized = SignatureEnvelope.serialize(signatureWithLongData)
|
|
1136
|
-
const deserialized = SignatureEnvelope.deserialize(serialized)
|
|
1137
|
-
|
|
1138
|
-
expect(deserialized.metadata?.clientDataJSON).toBe(longClientData)
|
|
1139
|
-
})
|
|
1140
|
-
})
|
|
1141
|
-
|
|
1142
|
-
describe('keychain', () => {
|
|
1143
|
-
test('behavior: roundtrips serialize -> deserialize with secp256k1 inner', () => {
|
|
1144
|
-
const serialized = SignatureEnvelope.serialize(
|
|
1145
|
-
signature_keychain_secp256k1,
|
|
1146
|
-
)
|
|
1147
|
-
const deserialized = SignatureEnvelope.deserialize(serialized)
|
|
1148
|
-
|
|
1149
|
-
expect(deserialized).toMatchObject(signature_keychain_secp256k1)
|
|
1150
|
-
})
|
|
1151
|
-
|
|
1152
|
-
test('behavior: roundtrips serialize -> deserialize with p256 inner', () => {
|
|
1153
|
-
const serialized = SignatureEnvelope.serialize(signature_keychain_p256)
|
|
1154
|
-
const deserialized = SignatureEnvelope.deserialize(serialized)
|
|
1155
|
-
|
|
1156
|
-
expect(deserialized).toMatchInlineSnapshot(`
|
|
1157
|
-
{
|
|
1158
|
-
"inner": {
|
|
1159
|
-
"prehash": true,
|
|
1160
|
-
"publicKey": {
|
|
1161
|
-
"prefix": 4,
|
|
1162
|
-
"x": 78495282704852028275327922540131762143565388050940484317945369745559774511861n,
|
|
1163
|
-
"y": 8109764566587999957624872393871720746996669263962991155166704261108473113504n,
|
|
1164
|
-
},
|
|
1165
|
-
"signature": {
|
|
1166
|
-
"r": 92602584010956101470289867944347135737570451066466093224269890121909314569518n,
|
|
1167
|
-
"s": 54171125190222965779385658110416711469231271457324878825831748147306957269813n,
|
|
1168
|
-
},
|
|
1169
|
-
"type": "p256",
|
|
1170
|
-
},
|
|
1171
|
-
"type": "keychain",
|
|
1172
|
-
"userAddress": "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd",
|
|
1173
|
-
}
|
|
1174
|
-
`)
|
|
1175
|
-
})
|
|
1176
|
-
|
|
1177
|
-
test('behavior: roundtrips serialize -> deserialize with webAuthn inner', () => {
|
|
1178
|
-
const serialized = SignatureEnvelope.serialize(
|
|
1179
|
-
signature_keychain_webauthn,
|
|
1180
|
-
)
|
|
1181
|
-
const deserialized = SignatureEnvelope.deserialize(serialized)
|
|
1182
|
-
|
|
1183
|
-
expect(deserialized).toMatchInlineSnapshot(`
|
|
1184
|
-
{
|
|
1185
|
-
"inner": {
|
|
1186
|
-
"metadata": {
|
|
1187
|
-
"authenticatorData": "0x49960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000",
|
|
1188
|
-
"clientDataJSON": "{"type":"webauthn.get","challenge":"3q2-7w","origin":"http://localhost","crossOrigin":false}",
|
|
1189
|
-
},
|
|
1190
|
-
"publicKey": {
|
|
1191
|
-
"prefix": 4,
|
|
1192
|
-
"x": 78495282704852028275327922540131762143565388050940484317945369745559774511861n,
|
|
1193
|
-
"y": 8109764566587999957624872393871720746996669263962991155166704261108473113504n,
|
|
1194
|
-
},
|
|
1195
|
-
"signature": {
|
|
1196
|
-
"r": 92602584010956101470289867944347135737570451066466093224269890121909314569518n,
|
|
1197
|
-
"s": 54171125190222965779385658110416711469231271457324878825831748147306957269813n,
|
|
1198
|
-
},
|
|
1199
|
-
"type": "webAuthn",
|
|
1200
|
-
},
|
|
1201
|
-
"type": "keychain",
|
|
1202
|
-
"userAddress": "0xfedcbafedcbafedcbafedcbafedcbafedcbafedc",
|
|
1203
|
-
}
|
|
1204
|
-
`)
|
|
1205
|
-
})
|
|
1206
|
-
})
|
|
1207
|
-
})
|
|
1208
|
-
|
|
1209
|
-
test('error: throws on invalid envelope', () => {
|
|
1210
|
-
const error = (() => {
|
|
1211
|
-
try {
|
|
1212
|
-
SignatureEnvelope.serialize({} as any)
|
|
1213
|
-
} catch (e) {
|
|
1214
|
-
return e
|
|
1215
|
-
}
|
|
1216
|
-
})() as SignatureEnvelope.CoercionError
|
|
1217
|
-
expect(error).toBeInstanceOf(SignatureEnvelope.CoercionError)
|
|
1218
|
-
expect(error.message).toMatchInlineSnapshot(
|
|
1219
|
-
`"Unable to coerce value (\`{}\`) to a valid signature envelope."`,
|
|
1220
|
-
)
|
|
1221
|
-
})
|
|
1222
|
-
})
|
|
1223
|
-
|
|
1224
|
-
describe('validate', () => {
|
|
1225
|
-
describe('secp256k1', () => {
|
|
1226
|
-
test('behavior: returns true for valid signature', () => {
|
|
1227
|
-
expect(
|
|
1228
|
-
SignatureEnvelope.validate({
|
|
1229
|
-
signature: signature_secp256k1,
|
|
1230
|
-
type: 'secp256k1',
|
|
1231
|
-
}),
|
|
1232
|
-
).toBe(true)
|
|
1233
|
-
})
|
|
1234
|
-
|
|
1235
|
-
test('behavior: returns true for signature without explicit type', () => {
|
|
1236
|
-
expect(
|
|
1237
|
-
SignatureEnvelope.validate({ signature: signature_secp256k1 }),
|
|
1238
|
-
).toBe(true)
|
|
1239
|
-
})
|
|
1240
|
-
|
|
1241
|
-
test('behavior: returns false for invalid signature values', () => {
|
|
1242
|
-
expect(
|
|
1243
|
-
SignatureEnvelope.validate({
|
|
1244
|
-
signature: {
|
|
1245
|
-
r: 0n,
|
|
1246
|
-
s: 0n,
|
|
1247
|
-
yParity: 2,
|
|
1248
|
-
},
|
|
1249
|
-
type: 'secp256k1',
|
|
1250
|
-
}),
|
|
1251
|
-
).toBe(false)
|
|
1252
|
-
})
|
|
1253
|
-
})
|
|
1254
|
-
|
|
1255
|
-
describe('p256', () => {
|
|
1256
|
-
test('behavior: returns true for valid P256 signature', () => {
|
|
1257
|
-
expect(SignatureEnvelope.validate(signature_p256)).toBe(true)
|
|
1258
|
-
})
|
|
1259
|
-
|
|
1260
|
-
test('behavior: returns false for invalid P256 signature', () => {
|
|
1261
|
-
expect(
|
|
1262
|
-
SignatureEnvelope.validate({
|
|
1263
|
-
...signature_p256,
|
|
1264
|
-
prehash: 'invalid' as any,
|
|
1265
|
-
}),
|
|
1266
|
-
).toBe(false)
|
|
1267
|
-
})
|
|
1268
|
-
})
|
|
1269
|
-
|
|
1270
|
-
describe('webAuthn', () => {
|
|
1271
|
-
test('behavior: returns true for valid WebAuthn signature', () => {
|
|
1272
|
-
expect(SignatureEnvelope.validate(signature_webauthn)).toBe(true)
|
|
1273
|
-
})
|
|
1274
|
-
|
|
1275
|
-
test('behavior: returns false for invalid WebAuthn signature', () => {
|
|
1276
|
-
const { metadata: _, ...withoutMetadata } = signature_webauthn
|
|
1277
|
-
expect(SignatureEnvelope.validate(withoutMetadata as any)).toBe(false)
|
|
1278
|
-
})
|
|
1279
|
-
})
|
|
1280
|
-
|
|
1281
|
-
describe('keychain', () => {
|
|
1282
|
-
test('behavior: returns true for valid keychain with secp256k1 inner', () => {
|
|
1283
|
-
expect(SignatureEnvelope.validate(signature_keychain_secp256k1)).toBe(
|
|
1284
|
-
true,
|
|
1285
|
-
)
|
|
1286
|
-
})
|
|
1287
|
-
|
|
1288
|
-
test('behavior: returns true for valid keychain with p256 inner', () => {
|
|
1289
|
-
expect(SignatureEnvelope.validate(signature_keychain_p256)).toBe(true)
|
|
1290
|
-
})
|
|
1291
|
-
|
|
1292
|
-
test('behavior: returns true for valid keychain with webAuthn inner', () => {
|
|
1293
|
-
expect(SignatureEnvelope.validate(signature_keychain_webauthn)).toBe(true)
|
|
1294
|
-
})
|
|
1295
|
-
|
|
1296
|
-
test('behavior: returns false for invalid keychain signature', () => {
|
|
1297
|
-
expect(
|
|
1298
|
-
SignatureEnvelope.validate({
|
|
1299
|
-
userAddress: '0x1234567890123456789012345678901234567890',
|
|
1300
|
-
inner: {
|
|
1301
|
-
signature: {
|
|
1302
|
-
r: 0n,
|
|
1303
|
-
s: 0n,
|
|
1304
|
-
yParity: 2,
|
|
1305
|
-
},
|
|
1306
|
-
type: 'secp256k1',
|
|
1307
|
-
},
|
|
1308
|
-
type: 'keychain',
|
|
1309
|
-
} as any),
|
|
1310
|
-
).toBe(false)
|
|
1311
|
-
})
|
|
1312
|
-
})
|
|
1313
|
-
|
|
1314
|
-
test('behavior: returns false for invalid envelope', () => {
|
|
1315
|
-
expect(SignatureEnvelope.validate({} as any)).toBe(false)
|
|
1316
|
-
})
|
|
1317
|
-
|
|
1318
|
-
test('behavior: returns false for incomplete signature', () => {
|
|
1319
|
-
expect(
|
|
1320
|
-
SignatureEnvelope.validate({
|
|
1321
|
-
r: 0n,
|
|
1322
|
-
s: 0n,
|
|
1323
|
-
} as any),
|
|
1324
|
-
).toBe(false)
|
|
1325
|
-
})
|
|
1326
|
-
})
|
|
1327
|
-
|
|
1328
|
-
describe('fromRpc', () => {
|
|
1329
|
-
describe('secp256k1', () => {
|
|
1330
|
-
test('behavior: converts RPC secp256k1 signature', () => {
|
|
1331
|
-
const rpc: SignatureEnvelope.Secp256k1Rpc = {
|
|
1332
|
-
r: Signature.toRpc(signature_secp256k1).r,
|
|
1333
|
-
s: Signature.toRpc(signature_secp256k1).s,
|
|
1334
|
-
yParity: Signature.toRpc(signature_secp256k1).yParity,
|
|
1335
|
-
type: 'secp256k1',
|
|
1336
|
-
}
|
|
1337
|
-
|
|
1338
|
-
const envelope = SignatureEnvelope.fromRpc(rpc)
|
|
1339
|
-
|
|
1340
|
-
expect(envelope).toMatchObject({
|
|
1341
|
-
signature: {
|
|
1342
|
-
r: signature_secp256k1.r,
|
|
1343
|
-
s: signature_secp256k1.s,
|
|
1344
|
-
yParity: signature_secp256k1.yParity,
|
|
1345
|
-
},
|
|
1346
|
-
type: 'secp256k1',
|
|
1347
|
-
})
|
|
1348
|
-
})
|
|
1349
|
-
})
|
|
1350
|
-
|
|
1351
|
-
describe('p256', () => {
|
|
1352
|
-
test('behavior: converts RPC P256 signature', () => {
|
|
1353
|
-
const rpc: SignatureEnvelope.P256Rpc = {
|
|
1354
|
-
prehash: true,
|
|
1355
|
-
pubKeyX: Hex.fromNumber(publicKey.x, { size: 32 }),
|
|
1356
|
-
pubKeyY: Hex.fromNumber(publicKey.y, { size: 32 }),
|
|
1357
|
-
r: Hex.fromNumber(p256Signature.r, { size: 32 }),
|
|
1358
|
-
s: Hex.fromNumber(p256Signature.s, { size: 32 }),
|
|
1359
|
-
type: 'p256',
|
|
1360
|
-
}
|
|
1361
|
-
|
|
1362
|
-
const envelope = SignatureEnvelope.fromRpc(rpc)
|
|
1363
|
-
|
|
1364
|
-
expect(envelope).toMatchObject({
|
|
1365
|
-
prehash: true,
|
|
1366
|
-
publicKey: {
|
|
1367
|
-
x: publicKey.x,
|
|
1368
|
-
y: publicKey.y,
|
|
1369
|
-
},
|
|
1370
|
-
signature: {
|
|
1371
|
-
r: p256Signature.r,
|
|
1372
|
-
s: p256Signature.s,
|
|
1373
|
-
},
|
|
1374
|
-
type: 'p256',
|
|
1375
|
-
})
|
|
1376
|
-
})
|
|
1377
|
-
})
|
|
1378
|
-
|
|
1379
|
-
describe('webAuthn', () => {
|
|
1380
|
-
test('behavior: converts RPC WebAuthn signature', () => {
|
|
1381
|
-
const webauthnData = WebAuthnP256.getAuthenticatorData({
|
|
1382
|
-
rpId: 'localhost',
|
|
1383
|
-
})
|
|
1384
|
-
const clientDataJSON = WebAuthnP256.getClientDataJSON({
|
|
1385
|
-
challenge: '0xdeadbeef',
|
|
1386
|
-
origin: 'http://localhost',
|
|
1387
|
-
})
|
|
1388
|
-
|
|
1389
|
-
const rpc: SignatureEnvelope.WebAuthnRpc = {
|
|
1390
|
-
pubKeyX: Hex.fromNumber(publicKey.x, { size: 32 }),
|
|
1391
|
-
pubKeyY: Hex.fromNumber(publicKey.y, { size: 32 }),
|
|
1392
|
-
r: Hex.fromNumber(p256Signature.r, { size: 32 }),
|
|
1393
|
-
s: Hex.fromNumber(p256Signature.s, { size: 32 }),
|
|
1394
|
-
type: 'webAuthn',
|
|
1395
|
-
webauthnData: Hex.concat(webauthnData, Hex.fromString(clientDataJSON)),
|
|
1396
|
-
}
|
|
1397
|
-
|
|
1398
|
-
const envelope = SignatureEnvelope.fromRpc(rpc)
|
|
1399
|
-
|
|
1400
|
-
expect(envelope).toMatchObject({
|
|
1401
|
-
metadata: {
|
|
1402
|
-
authenticatorData: webauthnData,
|
|
1403
|
-
clientDataJSON,
|
|
1404
|
-
},
|
|
1405
|
-
publicKey: {
|
|
1406
|
-
x: publicKey.x,
|
|
1407
|
-
y: publicKey.y,
|
|
1408
|
-
},
|
|
1409
|
-
signature: {
|
|
1410
|
-
r: p256Signature.r,
|
|
1411
|
-
s: p256Signature.s,
|
|
1412
|
-
},
|
|
1413
|
-
type: 'webAuthn',
|
|
1414
|
-
})
|
|
1415
|
-
})
|
|
1416
|
-
})
|
|
1417
|
-
|
|
1418
|
-
describe('keychain', () => {
|
|
1419
|
-
test('behavior: converts RPC keychain signature with secp256k1 inner', () => {
|
|
1420
|
-
const rpc: SignatureEnvelope.KeychainRpc = {
|
|
1421
|
-
type: 'keychain',
|
|
1422
|
-
userAddress: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
|
|
1423
|
-
signature: {
|
|
1424
|
-
type: 'secp256k1',
|
|
1425
|
-
r: '0xa2bb71146c20ce932456c043ebb2973ed205e07cd32c35a60bdefca1285fd132',
|
|
1426
|
-
s: '0x7cba10692bccdbfba9a215418443c2903dbee6fe5cb55c91172e47efc607840e',
|
|
1427
|
-
yParity: '0x1',
|
|
1428
|
-
},
|
|
1429
|
-
}
|
|
1430
|
-
|
|
1431
|
-
const envelope = SignatureEnvelope.fromRpc(rpc)
|
|
1432
|
-
|
|
1433
|
-
expect(envelope).toMatchObject({
|
|
1434
|
-
type: 'keychain',
|
|
1435
|
-
userAddress: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
|
|
1436
|
-
inner: {
|
|
1437
|
-
type: 'secp256k1',
|
|
1438
|
-
signature: {
|
|
1439
|
-
r: 0xa2bb71146c20ce932456c043ebb2973ed205e07cd32c35a60bdefca1285fd132n,
|
|
1440
|
-
s: 0x7cba10692bccdbfba9a215418443c2903dbee6fe5cb55c91172e47efc607840en,
|
|
1441
|
-
yParity: 1,
|
|
1442
|
-
},
|
|
1443
|
-
},
|
|
1444
|
-
})
|
|
1445
|
-
})
|
|
1446
|
-
|
|
1447
|
-
test('behavior: converts RPC keychain signature with p256 inner', () => {
|
|
1448
|
-
const rpc: SignatureEnvelope.KeychainRpc = {
|
|
1449
|
-
type: 'keychain',
|
|
1450
|
-
userAddress: '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd',
|
|
1451
|
-
signature: {
|
|
1452
|
-
prehash: true,
|
|
1453
|
-
pubKeyX: Hex.fromNumber(publicKey.x, { size: 32 }),
|
|
1454
|
-
pubKeyY: Hex.fromNumber(publicKey.y, { size: 32 }),
|
|
1455
|
-
r: Hex.fromNumber(p256Signature.r, { size: 32 }),
|
|
1456
|
-
s: Hex.fromNumber(p256Signature.s, { size: 32 }),
|
|
1457
|
-
type: 'p256',
|
|
1458
|
-
},
|
|
1459
|
-
}
|
|
1460
|
-
|
|
1461
|
-
const envelope = SignatureEnvelope.fromRpc(rpc)
|
|
1462
|
-
|
|
1463
|
-
expect(envelope).toMatchObject({
|
|
1464
|
-
type: 'keychain',
|
|
1465
|
-
userAddress: '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd',
|
|
1466
|
-
inner: {
|
|
1467
|
-
type: 'p256',
|
|
1468
|
-
prehash: true,
|
|
1469
|
-
publicKey: {
|
|
1470
|
-
x: publicKey.x,
|
|
1471
|
-
y: publicKey.y,
|
|
1472
|
-
},
|
|
1473
|
-
signature: {
|
|
1474
|
-
r: p256Signature.r,
|
|
1475
|
-
s: p256Signature.s,
|
|
1476
|
-
},
|
|
1477
|
-
},
|
|
1478
|
-
})
|
|
1479
|
-
})
|
|
1480
|
-
|
|
1481
|
-
test('behavior: converts RPC keychain signature with webAuthn inner', () => {
|
|
1482
|
-
const webauthnData = WebAuthnP256.getAuthenticatorData({
|
|
1483
|
-
rpId: 'localhost',
|
|
1484
|
-
})
|
|
1485
|
-
const clientDataJSON = WebAuthnP256.getClientDataJSON({
|
|
1486
|
-
challenge: '0xdeadbeef',
|
|
1487
|
-
origin: 'http://localhost',
|
|
1488
|
-
})
|
|
1489
|
-
|
|
1490
|
-
const rpc: SignatureEnvelope.KeychainRpc = {
|
|
1491
|
-
type: 'keychain',
|
|
1492
|
-
userAddress: '0xfedcbafedcbafedcbafedcbafedcbafedcbafedc',
|
|
1493
|
-
signature: {
|
|
1494
|
-
pubKeyX: Hex.fromNumber(publicKey.x, { size: 32 }),
|
|
1495
|
-
pubKeyY: Hex.fromNumber(publicKey.y, { size: 32 }),
|
|
1496
|
-
r: Hex.fromNumber(p256Signature.r, { size: 32 }),
|
|
1497
|
-
s: Hex.fromNumber(p256Signature.s, { size: 32 }),
|
|
1498
|
-
type: 'webAuthn',
|
|
1499
|
-
webauthnData: Hex.concat(
|
|
1500
|
-
webauthnData,
|
|
1501
|
-
Hex.fromString(clientDataJSON),
|
|
1502
|
-
),
|
|
1503
|
-
},
|
|
1504
|
-
}
|
|
1505
|
-
|
|
1506
|
-
const envelope = SignatureEnvelope.fromRpc(rpc)
|
|
1507
|
-
|
|
1508
|
-
expect(envelope).toMatchObject({
|
|
1509
|
-
type: 'keychain',
|
|
1510
|
-
userAddress: '0xfedcbafedcbafedcbafedcbafedcbafedcbafedc',
|
|
1511
|
-
inner: {
|
|
1512
|
-
type: 'webAuthn',
|
|
1513
|
-
metadata: {
|
|
1514
|
-
authenticatorData: webauthnData,
|
|
1515
|
-
clientDataJSON,
|
|
1516
|
-
},
|
|
1517
|
-
publicKey: {
|
|
1518
|
-
x: publicKey.x,
|
|
1519
|
-
y: publicKey.y,
|
|
1520
|
-
},
|
|
1521
|
-
signature: {
|
|
1522
|
-
r: p256Signature.r,
|
|
1523
|
-
s: p256Signature.s,
|
|
1524
|
-
},
|
|
1525
|
-
},
|
|
1526
|
-
})
|
|
1527
|
-
})
|
|
1528
|
-
})
|
|
1529
|
-
})
|
|
1530
|
-
|
|
1531
|
-
describe('toRpc', () => {
|
|
1532
|
-
describe('secp256k1', () => {
|
|
1533
|
-
test('behavior: converts secp256k1 signature to RPC', () => {
|
|
1534
|
-
const envelope: SignatureEnvelope.Secp256k1 = {
|
|
1535
|
-
signature: signature_secp256k1,
|
|
1536
|
-
type: 'secp256k1',
|
|
1537
|
-
}
|
|
1538
|
-
|
|
1539
|
-
const rpc = SignatureEnvelope.toRpc(envelope)
|
|
1540
|
-
|
|
1541
|
-
expect(rpc).toMatchObject({
|
|
1542
|
-
r: Signature.toRpc(signature_secp256k1).r,
|
|
1543
|
-
s: Signature.toRpc(signature_secp256k1).s,
|
|
1544
|
-
yParity: Signature.toRpc(signature_secp256k1).yParity,
|
|
1545
|
-
type: 'secp256k1',
|
|
1546
|
-
})
|
|
1547
|
-
})
|
|
1548
|
-
})
|
|
1549
|
-
|
|
1550
|
-
describe('p256', () => {
|
|
1551
|
-
test('behavior: converts P256 signature to RPC', () => {
|
|
1552
|
-
const rpc = SignatureEnvelope.toRpc(signature_p256)
|
|
1553
|
-
|
|
1554
|
-
expect(rpc.type).toBe('p256')
|
|
1555
|
-
expect(rpc.prehash).toBe(true)
|
|
1556
|
-
expect(typeof rpc.pubKeyX).toBe('string')
|
|
1557
|
-
expect(typeof rpc.pubKeyY).toBe('string')
|
|
1558
|
-
expect(typeof rpc.r).toBe('string')
|
|
1559
|
-
expect(typeof rpc.s).toBe('string')
|
|
1560
|
-
})
|
|
1561
|
-
|
|
1562
|
-
test('behavior: converts prehash=false correctly', () => {
|
|
1563
|
-
const withPrehashFalse = { ...signature_p256, prehash: false }
|
|
1564
|
-
const rpc = SignatureEnvelope.toRpc(withPrehashFalse)
|
|
1565
|
-
|
|
1566
|
-
expect(rpc.prehash).toBe(false)
|
|
1567
|
-
})
|
|
1568
|
-
})
|
|
1569
|
-
|
|
1570
|
-
describe('webAuthn', () => {
|
|
1571
|
-
test('behavior: converts WebAuthn signature to RPC', () => {
|
|
1572
|
-
const rpc = SignatureEnvelope.toRpc(
|
|
1573
|
-
signature_webauthn,
|
|
1574
|
-
) as SignatureEnvelope.WebAuthnRpc
|
|
1575
|
-
|
|
1576
|
-
expect(rpc.type).toBe('webAuthn')
|
|
1577
|
-
expect(typeof rpc.pubKeyX).toBe('string')
|
|
1578
|
-
expect(typeof rpc.pubKeyY).toBe('string')
|
|
1579
|
-
expect(typeof rpc.r).toBe('string')
|
|
1580
|
-
expect(typeof rpc.s).toBe('string')
|
|
1581
|
-
expect(typeof rpc.webauthnData).toBe('string')
|
|
1582
|
-
expect(rpc.webauthnData.startsWith('0x')).toBe(true)
|
|
1583
|
-
})
|
|
1584
|
-
|
|
1585
|
-
test('behavior: webauthnData contains authenticatorData and clientDataJSON', () => {
|
|
1586
|
-
const rpc = SignatureEnvelope.toRpc(
|
|
1587
|
-
signature_webauthn,
|
|
1588
|
-
) as SignatureEnvelope.WebAuthnRpc
|
|
1589
|
-
|
|
1590
|
-
// webauthnData should contain the concatenation of authenticatorData and clientDataJSON (as hex)
|
|
1591
|
-
expect(rpc.webauthnData).toContain(
|
|
1592
|
-
signature_webauthn.metadata.authenticatorData.slice(2),
|
|
1593
|
-
)
|
|
1594
|
-
})
|
|
1595
|
-
})
|
|
1596
|
-
|
|
1597
|
-
describe('keychain', () => {
|
|
1598
|
-
test('behavior: converts keychain signature with secp256k1 inner to RPC', () => {
|
|
1599
|
-
const envelope: SignatureEnvelope.Keychain = {
|
|
1600
|
-
type: 'keychain',
|
|
1601
|
-
userAddress: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
|
|
1602
|
-
inner: {
|
|
1603
|
-
signature: signature_secp256k1,
|
|
1604
|
-
type: 'secp256k1',
|
|
1605
|
-
},
|
|
1606
|
-
}
|
|
1607
|
-
|
|
1608
|
-
const rpc = SignatureEnvelope.toRpc(
|
|
1609
|
-
envelope,
|
|
1610
|
-
) as SignatureEnvelope.KeychainRpc
|
|
1611
|
-
|
|
1612
|
-
expect(rpc.type).toBe('keychain')
|
|
1613
|
-
expect(rpc.userAddress).toBe('0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266')
|
|
1614
|
-
expect(rpc.signature).toMatchObject({
|
|
1615
|
-
r: Signature.toRpc(signature_secp256k1).r,
|
|
1616
|
-
s: Signature.toRpc(signature_secp256k1).s,
|
|
1617
|
-
yParity: Signature.toRpc(signature_secp256k1).yParity,
|
|
1618
|
-
type: 'secp256k1',
|
|
1619
|
-
})
|
|
1620
|
-
})
|
|
1621
|
-
|
|
1622
|
-
test('behavior: converts keychain signature with p256 inner to RPC', () => {
|
|
1623
|
-
const rpc = SignatureEnvelope.toRpc(
|
|
1624
|
-
signature_keychain_p256,
|
|
1625
|
-
) as SignatureEnvelope.KeychainRpc
|
|
1626
|
-
|
|
1627
|
-
expect(rpc.type).toBe('keychain')
|
|
1628
|
-
expect(rpc.userAddress).toBe(signature_keychain_p256.userAddress)
|
|
1629
|
-
expect(rpc.signature.type).toBe('p256')
|
|
1630
|
-
expect(typeof rpc.signature.pubKeyX).toBe('string')
|
|
1631
|
-
expect(typeof rpc.signature.pubKeyY).toBe('string')
|
|
1632
|
-
})
|
|
1633
|
-
|
|
1634
|
-
test('behavior: converts keychain signature with webAuthn inner to RPC', () => {
|
|
1635
|
-
const rpc = SignatureEnvelope.toRpc(
|
|
1636
|
-
signature_keychain_webauthn,
|
|
1637
|
-
) as SignatureEnvelope.KeychainRpc
|
|
1638
|
-
|
|
1639
|
-
expect(rpc.type).toBe('keychain')
|
|
1640
|
-
expect(rpc.userAddress).toBe(signature_keychain_webauthn.userAddress)
|
|
1641
|
-
expect(rpc.signature.type).toBe('webAuthn')
|
|
1642
|
-
expect(typeof rpc.signature.pubKeyX).toBe('string')
|
|
1643
|
-
expect(typeof rpc.signature.webauthnData).toBe('string')
|
|
1644
|
-
})
|
|
1645
|
-
})
|
|
1646
|
-
})
|
|
1647
|
-
|
|
1648
|
-
describe('roundtrip: toRpc <-> fromRpc', () => {
|
|
1649
|
-
describe('secp256k1', () => {
|
|
1650
|
-
test('behavior: roundtrips toRpc -> fromRpc', () => {
|
|
1651
|
-
const envelope: SignatureEnvelope.Secp256k1 = {
|
|
1652
|
-
signature: signature_secp256k1,
|
|
1653
|
-
type: 'secp256k1',
|
|
1654
|
-
}
|
|
1655
|
-
|
|
1656
|
-
const rpc = SignatureEnvelope.toRpc(envelope)
|
|
1657
|
-
const roundtripped = SignatureEnvelope.fromRpc(rpc)
|
|
1658
|
-
|
|
1659
|
-
expect(roundtripped).toMatchObject({
|
|
1660
|
-
signature: {
|
|
1661
|
-
r: signature_secp256k1.r,
|
|
1662
|
-
s: signature_secp256k1.s,
|
|
1663
|
-
yParity: signature_secp256k1.yParity,
|
|
1664
|
-
},
|
|
1665
|
-
type: 'secp256k1',
|
|
1666
|
-
})
|
|
1667
|
-
})
|
|
1668
|
-
|
|
1669
|
-
test('behavior: roundtrips fromRpc -> toRpc', () => {
|
|
1670
|
-
const rpc: SignatureEnvelope.Secp256k1Rpc = {
|
|
1671
|
-
r: Signature.toRpc(signature_secp256k1).r,
|
|
1672
|
-
s: Signature.toRpc(signature_secp256k1).s,
|
|
1673
|
-
yParity: Signature.toRpc(signature_secp256k1).yParity,
|
|
1674
|
-
type: 'secp256k1',
|
|
1675
|
-
}
|
|
1676
|
-
|
|
1677
|
-
const envelope = SignatureEnvelope.fromRpc(rpc)
|
|
1678
|
-
const roundtripped = SignatureEnvelope.toRpc(envelope)
|
|
1679
|
-
|
|
1680
|
-
expect(roundtripped).toMatchObject(rpc)
|
|
1681
|
-
})
|
|
1682
|
-
})
|
|
1683
|
-
|
|
1684
|
-
describe('p256', () => {
|
|
1685
|
-
test('behavior: roundtrips toRpc -> fromRpc', () => {
|
|
1686
|
-
const rpc = SignatureEnvelope.toRpc(signature_p256)
|
|
1687
|
-
const roundtripped = SignatureEnvelope.fromRpc(rpc)
|
|
1688
|
-
|
|
1689
|
-
expect(roundtripped).toMatchObject({
|
|
1690
|
-
prehash: signature_p256.prehash,
|
|
1691
|
-
publicKey: {
|
|
1692
|
-
x: signature_p256.publicKey.x,
|
|
1693
|
-
y: signature_p256.publicKey.y,
|
|
1694
|
-
},
|
|
1695
|
-
signature: {
|
|
1696
|
-
r: signature_p256.signature.r,
|
|
1697
|
-
s: signature_p256.signature.s,
|
|
1698
|
-
},
|
|
1699
|
-
type: 'p256',
|
|
1700
|
-
})
|
|
1701
|
-
})
|
|
1702
|
-
|
|
1703
|
-
test('behavior: handles prehash=false in roundtrip', () => {
|
|
1704
|
-
const withPrehashFalse = { ...signature_p256, prehash: false }
|
|
1705
|
-
const rpc = SignatureEnvelope.toRpc(withPrehashFalse)
|
|
1706
|
-
const roundtripped = SignatureEnvelope.fromRpc(rpc)
|
|
1707
|
-
|
|
1708
|
-
expect(roundtripped.prehash).toBe(false)
|
|
1709
|
-
})
|
|
1710
|
-
})
|
|
1711
|
-
|
|
1712
|
-
describe('webAuthn', () => {
|
|
1713
|
-
test('behavior: roundtrips toRpc -> fromRpc', () => {
|
|
1714
|
-
const rpc = SignatureEnvelope.toRpc(signature_webauthn)
|
|
1715
|
-
const roundtripped = SignatureEnvelope.fromRpc(rpc)
|
|
1716
|
-
|
|
1717
|
-
expect(roundtripped).toMatchObject({
|
|
1718
|
-
metadata: {
|
|
1719
|
-
authenticatorData: signature_webauthn.metadata.authenticatorData,
|
|
1720
|
-
clientDataJSON: signature_webauthn.metadata.clientDataJSON,
|
|
1721
|
-
},
|
|
1722
|
-
publicKey: {
|
|
1723
|
-
x: signature_webauthn.publicKey.x,
|
|
1724
|
-
y: signature_webauthn.publicKey.y,
|
|
1725
|
-
},
|
|
1726
|
-
signature: {
|
|
1727
|
-
r: signature_webauthn.signature.r,
|
|
1728
|
-
s: signature_webauthn.signature.s,
|
|
1729
|
-
},
|
|
1730
|
-
type: 'webAuthn',
|
|
1731
|
-
})
|
|
1732
|
-
})
|
|
1733
|
-
|
|
1734
|
-
test('behavior: handles variable-length clientDataJSON in roundtrip', () => {
|
|
1735
|
-
const longClientData = JSON.stringify({
|
|
1736
|
-
type: 'webAuthn.get',
|
|
1737
|
-
challenge: 'a'.repeat(100),
|
|
1738
|
-
origin: 'https://example.com',
|
|
1739
|
-
crossOrigin: false,
|
|
1740
|
-
})
|
|
1741
|
-
|
|
1742
|
-
const signatureWithLongData = {
|
|
1743
|
-
...signature_webauthn,
|
|
1744
|
-
metadata: {
|
|
1745
|
-
...signature_webauthn.metadata,
|
|
1746
|
-
clientDataJSON: longClientData,
|
|
1747
|
-
},
|
|
1748
|
-
}
|
|
1749
|
-
|
|
1750
|
-
const rpc = SignatureEnvelope.toRpc(signatureWithLongData)
|
|
1751
|
-
const roundtripped = SignatureEnvelope.fromRpc(rpc)
|
|
1752
|
-
|
|
1753
|
-
expect(roundtripped.metadata?.clientDataJSON).toBe(longClientData)
|
|
1754
|
-
})
|
|
1755
|
-
})
|
|
1756
|
-
|
|
1757
|
-
describe('keychain', () => {
|
|
1758
|
-
test('behavior: roundtrips toRpc -> fromRpc with secp256k1 inner', () => {
|
|
1759
|
-
const envelope: SignatureEnvelope.Keychain = {
|
|
1760
|
-
type: 'keychain',
|
|
1761
|
-
userAddress: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
|
|
1762
|
-
inner: {
|
|
1763
|
-
signature: signature_secp256k1,
|
|
1764
|
-
type: 'secp256k1',
|
|
1765
|
-
},
|
|
1766
|
-
}
|
|
1767
|
-
|
|
1768
|
-
const rpc = SignatureEnvelope.toRpc(envelope)
|
|
1769
|
-
const roundtripped = SignatureEnvelope.fromRpc(rpc)
|
|
1770
|
-
|
|
1771
|
-
expect(roundtripped).toMatchObject({
|
|
1772
|
-
type: 'keychain',
|
|
1773
|
-
userAddress: envelope.userAddress,
|
|
1774
|
-
inner: {
|
|
1775
|
-
type: 'secp256k1',
|
|
1776
|
-
signature: {
|
|
1777
|
-
r: signature_secp256k1.r,
|
|
1778
|
-
s: signature_secp256k1.s,
|
|
1779
|
-
yParity: signature_secp256k1.yParity,
|
|
1780
|
-
},
|
|
1781
|
-
},
|
|
1782
|
-
})
|
|
1783
|
-
})
|
|
1784
|
-
|
|
1785
|
-
test('behavior: roundtrips toRpc -> fromRpc with p256 inner', () => {
|
|
1786
|
-
const rpc = SignatureEnvelope.toRpc(signature_keychain_p256)
|
|
1787
|
-
const roundtripped = SignatureEnvelope.fromRpc(rpc)
|
|
1788
|
-
|
|
1789
|
-
expect(roundtripped).toMatchObject({
|
|
1790
|
-
type: 'keychain',
|
|
1791
|
-
userAddress: signature_keychain_p256.userAddress,
|
|
1792
|
-
inner: {
|
|
1793
|
-
type: 'p256',
|
|
1794
|
-
prehash: signature_p256.prehash,
|
|
1795
|
-
publicKey: {
|
|
1796
|
-
x: signature_p256.publicKey.x,
|
|
1797
|
-
y: signature_p256.publicKey.y,
|
|
1798
|
-
},
|
|
1799
|
-
signature: {
|
|
1800
|
-
r: signature_p256.signature.r,
|
|
1801
|
-
s: signature_p256.signature.s,
|
|
1802
|
-
},
|
|
1803
|
-
},
|
|
1804
|
-
})
|
|
1805
|
-
})
|
|
1806
|
-
|
|
1807
|
-
test('behavior: roundtrips toRpc -> fromRpc with webAuthn inner', () => {
|
|
1808
|
-
const rpc = SignatureEnvelope.toRpc(signature_keychain_webauthn)
|
|
1809
|
-
const roundtripped = SignatureEnvelope.fromRpc(rpc)
|
|
1810
|
-
|
|
1811
|
-
expect(roundtripped).toMatchObject({
|
|
1812
|
-
type: 'keychain',
|
|
1813
|
-
userAddress: signature_keychain_webauthn.userAddress,
|
|
1814
|
-
inner: {
|
|
1815
|
-
type: 'webAuthn',
|
|
1816
|
-
metadata: {
|
|
1817
|
-
authenticatorData: signature_webauthn.metadata.authenticatorData,
|
|
1818
|
-
clientDataJSON: signature_webauthn.metadata.clientDataJSON,
|
|
1819
|
-
},
|
|
1820
|
-
publicKey: {
|
|
1821
|
-
x: signature_webauthn.publicKey.x,
|
|
1822
|
-
y: signature_webauthn.publicKey.y,
|
|
1823
|
-
},
|
|
1824
|
-
signature: {
|
|
1825
|
-
r: signature_webauthn.signature.r,
|
|
1826
|
-
s: signature_webauthn.signature.s,
|
|
1827
|
-
},
|
|
1828
|
-
},
|
|
1829
|
-
})
|
|
1830
|
-
})
|
|
1831
|
-
|
|
1832
|
-
test('behavior: roundtrips fromRpc -> toRpc with secp256k1 inner', () => {
|
|
1833
|
-
const rpc: SignatureEnvelope.KeychainRpc = {
|
|
1834
|
-
type: 'keychain',
|
|
1835
|
-
userAddress: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
|
|
1836
|
-
signature: {
|
|
1837
|
-
type: 'secp256k1',
|
|
1838
|
-
r: '0xa2bb71146c20ce932456c043ebb2973ed205e07cd32c35a60bdefca1285fd132',
|
|
1839
|
-
s: '0x7cba10692bccdbfba9a215418443c2903dbee6fe5cb55c91172e47efc607840e',
|
|
1840
|
-
yParity: '0x1',
|
|
1841
|
-
},
|
|
1842
|
-
}
|
|
1843
|
-
|
|
1844
|
-
const envelope = SignatureEnvelope.fromRpc(rpc)
|
|
1845
|
-
const roundtripped = SignatureEnvelope.toRpc(envelope)
|
|
1846
|
-
|
|
1847
|
-
expect(roundtripped).toMatchObject(rpc)
|
|
1848
|
-
})
|
|
1849
|
-
})
|
|
1850
|
-
})
|
|
1851
|
-
|
|
1852
|
-
describe('types', () => {
|
|
1853
|
-
test('behavior: contains all signature types', () => {
|
|
1854
|
-
expect(SignatureEnvelope.types).toEqual(['secp256k1', 'p256', 'webAuthn'])
|
|
1855
|
-
})
|
|
1856
|
-
})
|
|
1857
|
-
|
|
1858
|
-
describe('CoercionError', () => {
|
|
1859
|
-
test('behavior: formats error message with hex string', () => {
|
|
1860
|
-
const error = new SignatureEnvelope.CoercionError({
|
|
1861
|
-
envelope: '0xdeadbeef',
|
|
1862
|
-
})
|
|
1863
|
-
expect(error).toMatchInlineSnapshot(
|
|
1864
|
-
`[SignatureEnvelope.CoercionError: Unable to coerce value (\`"0xdeadbeef"\`) to a valid signature envelope.]`,
|
|
1865
|
-
)
|
|
1866
|
-
})
|
|
1867
|
-
|
|
1868
|
-
test('behavior: formats error message with object', () => {
|
|
1869
|
-
const error = new SignatureEnvelope.CoercionError({
|
|
1870
|
-
envelope: { r: 0n, s: 0n, yParity: 0 },
|
|
1871
|
-
})
|
|
1872
|
-
expect(error).toMatchInlineSnapshot(
|
|
1873
|
-
`[SignatureEnvelope.CoercionError: Unable to coerce value (\`{"r":"0#__bigint","s":"0#__bigint","yParity":0}\`) to a valid signature envelope.]`,
|
|
1874
|
-
)
|
|
1875
|
-
})
|
|
1876
|
-
})
|