tempo.ts 0.0.5 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (195) hide show
  1. package/dist/chains.d.ts +244 -541
  2. package/dist/chains.d.ts.map +1 -1
  3. package/dist/chains.js +10 -23
  4. package/dist/chains.js.map +1 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/ox/SignatureEnvelope.d.ts +245 -0
  7. package/dist/ox/SignatureEnvelope.d.ts.map +1 -0
  8. package/dist/ox/SignatureEnvelope.js +437 -0
  9. package/dist/ox/SignatureEnvelope.js.map +1 -0
  10. package/dist/ox/Transaction.d.ts +61 -24
  11. package/dist/ox/Transaction.d.ts.map +1 -1
  12. package/dist/ox/Transaction.js +63 -18
  13. package/dist/ox/Transaction.js.map +1 -1
  14. package/dist/ox/TransactionEnvelopeAA.d.ts +461 -0
  15. package/dist/ox/TransactionEnvelopeAA.d.ts.map +1 -0
  16. package/dist/ox/TransactionEnvelopeAA.js +528 -0
  17. package/dist/ox/TransactionEnvelopeAA.js.map +1 -0
  18. package/dist/ox/TransactionRequest.d.ts +7 -5
  19. package/dist/ox/TransactionRequest.d.ts.map +1 -1
  20. package/dist/ox/TransactionRequest.js +21 -12
  21. package/dist/ox/TransactionRequest.js.map +1 -1
  22. package/dist/ox/index.d.ts +5 -4
  23. package/dist/ox/index.d.ts.map +1 -1
  24. package/dist/ox/index.js +5 -4
  25. package/dist/ox/index.js.map +1 -1
  26. package/dist/prool/Instance.d.ts +0 -4
  27. package/dist/prool/Instance.d.ts.map +1 -1
  28. package/dist/prool/Instance.js +7 -7
  29. package/dist/prool/Instance.js.map +1 -1
  30. package/dist/prool/index.d.ts +1 -1
  31. package/dist/prool/index.d.ts.map +1 -1
  32. package/dist/prool/index.js +1 -1
  33. package/dist/prool/index.js.map +1 -1
  34. package/dist/viem/{abis.d.ts → Abis.d.ts} +523 -9
  35. package/dist/viem/Abis.d.ts.map +1 -0
  36. package/dist/viem/{abis.js → Abis.js} +321 -9
  37. package/dist/viem/Abis.js.map +1 -0
  38. package/dist/viem/{actions → Actions}/amm.d.ts +21 -21
  39. package/dist/viem/Actions/amm.d.ts.map +1 -0
  40. package/dist/viem/{actions → Actions}/amm.js +55 -43
  41. package/dist/viem/Actions/amm.js.map +1 -0
  42. package/dist/viem/Actions/dex.d.ts +3263 -0
  43. package/dist/viem/Actions/dex.d.ts.map +1 -0
  44. package/dist/viem/Actions/dex.js +1357 -0
  45. package/dist/viem/Actions/dex.js.map +1 -0
  46. package/dist/viem/{actions → Actions}/fee.d.ts +8 -8
  47. package/dist/viem/Actions/fee.d.ts.map +1 -0
  48. package/dist/viem/{actions → Actions}/fee.js +14 -13
  49. package/dist/viem/Actions/fee.js.map +1 -0
  50. package/dist/viem/Actions/index.d.ts +6 -0
  51. package/dist/viem/Actions/index.d.ts.map +1 -0
  52. package/dist/viem/Actions/index.js +6 -0
  53. package/dist/viem/Actions/index.js.map +1 -0
  54. package/dist/viem/{actions → Actions}/policy.d.ts +19 -19
  55. package/dist/viem/Actions/policy.d.ts.map +1 -0
  56. package/dist/viem/{actions → Actions}/policy.js +59 -46
  57. package/dist/viem/Actions/policy.js.map +1 -0
  58. package/dist/viem/{actions → Actions}/token.d.ts +3251 -707
  59. package/dist/viem/Actions/token.d.ts.map +1 -0
  60. package/dist/viem/{actions → Actions}/token.js +420 -88
  61. package/dist/viem/Actions/token.js.map +1 -0
  62. package/dist/viem/Addresses.d.ts +9 -0
  63. package/dist/viem/Addresses.d.ts.map +1 -0
  64. package/dist/viem/Addresses.js +9 -0
  65. package/dist/viem/Addresses.js.map +1 -0
  66. package/dist/viem/{chain.d.ts → Chain.d.ts} +81 -57
  67. package/dist/viem/Chain.d.ts.map +1 -0
  68. package/dist/viem/{chain.js → Chain.js} +7 -7
  69. package/dist/viem/Chain.js.map +1 -0
  70. package/dist/viem/{client.d.ts → Client.d.ts} +4 -4
  71. package/dist/viem/Client.d.ts.map +1 -0
  72. package/dist/viem/{client.js → Client.js} +3 -3
  73. package/dist/viem/Client.js.map +1 -0
  74. package/dist/viem/{decorator.d.ts → Decorator.d.ts} +507 -5
  75. package/dist/viem/Decorator.d.ts.map +1 -0
  76. package/dist/viem/{decorator.js → Decorator.js} +31 -5
  77. package/dist/viem/Decorator.js.map +1 -0
  78. package/dist/viem/{formatters.d.ts → Formatters.d.ts} +2 -2
  79. package/dist/viem/Formatters.d.ts.map +1 -0
  80. package/dist/viem/{formatters.js → Formatters.js} +24 -17
  81. package/dist/viem/Formatters.js.map +1 -0
  82. package/dist/viem/Tick.d.ts +111 -0
  83. package/dist/viem/Tick.d.ts.map +1 -0
  84. package/dist/viem/Tick.js +127 -0
  85. package/dist/viem/Tick.js.map +1 -0
  86. package/dist/viem/TokenIds.d.ts +3 -0
  87. package/dist/viem/TokenIds.d.ts.map +1 -0
  88. package/dist/viem/TokenIds.js +3 -0
  89. package/dist/viem/TokenIds.js.map +1 -0
  90. package/dist/viem/Transaction.d.ts +57 -0
  91. package/dist/viem/Transaction.d.ts.map +1 -0
  92. package/dist/viem/Transaction.js +137 -0
  93. package/dist/viem/Transaction.js.map +1 -0
  94. package/dist/viem/{transport.d.ts → Transport.d.ts} +3 -3
  95. package/dist/viem/Transport.d.ts.map +1 -0
  96. package/dist/viem/{transport.js → Transport.js} +3 -3
  97. package/dist/viem/Transport.js.map +1 -0
  98. package/dist/viem/index.d.ts +13 -9
  99. package/dist/viem/index.d.ts.map +1 -1
  100. package/dist/viem/index.js +13 -9
  101. package/dist/viem/index.js.map +1 -1
  102. package/dist/viem/{types.d.ts → internal/types.d.ts} +3 -3
  103. package/dist/viem/internal/types.d.ts.map +1 -0
  104. package/dist/viem/{types.js.map → internal/types.js.map} +1 -1
  105. package/dist/viem/internal/utils.d.ts.map +1 -0
  106. package/dist/viem/internal/utils.js.map +1 -0
  107. package/package.json +87 -101
  108. package/src/chains.ts +10 -24
  109. package/src/ox/SignatureEnvelope.test.ts +1252 -0
  110. package/src/ox/SignatureEnvelope.ts +709 -0
  111. package/src/ox/Transaction.test.ts +144 -89
  112. package/src/ox/Transaction.ts +104 -29
  113. package/src/ox/TransactionEnvelopeAA.test.ts +1533 -0
  114. package/src/ox/TransactionEnvelopeAA.ts +858 -0
  115. package/src/ox/TransactionRequest.ts +25 -17
  116. package/src/ox/index.ts +2 -1
  117. package/src/prool/Instance.ts +6 -14
  118. package/src/prool/internal/chain.json +101 -27
  119. package/src/viem/{abis.ts → Abis.ts} +322 -8
  120. package/src/viem/{actions → Actions}/amm.test.ts +65 -68
  121. package/src/viem/{actions → Actions}/amm.ts +72 -60
  122. package/src/viem/Actions/dex.test.ts +1608 -0
  123. package/src/viem/Actions/dex.ts +2026 -0
  124. package/src/viem/{actions → Actions}/fee.test.ts +34 -36
  125. package/src/viem/{actions → Actions}/fee.ts +18 -17
  126. package/src/viem/{actions → Actions}/index.ts +1 -0
  127. package/src/viem/{actions → Actions}/policy.test.ts +2 -2
  128. package/src/viem/{actions → Actions}/policy.ts +77 -64
  129. package/src/viem/{actions → Actions}/token.test.ts +406 -67
  130. package/src/viem/{actions → Actions}/token.ts +675 -144
  131. package/src/viem/Addresses.ts +9 -0
  132. package/src/viem/{chain.ts → Chain.ts} +6 -6
  133. package/src/viem/{client.bench-d.ts → Client.bench-d.ts} +2 -2
  134. package/src/viem/{client.test.ts → Client.test.ts} +31 -6
  135. package/src/viem/{client.ts → Client.ts} +1 -1
  136. package/src/viem/{decorator.bench-d.ts → Decorator.bench-d.ts} +2 -2
  137. package/src/viem/{decorator.test.ts → Decorator.test.ts} +1 -0
  138. package/src/viem/{decorator.ts → Decorator.ts} +586 -4
  139. package/src/viem/{formatters.ts → Formatters.ts} +31 -20
  140. package/src/viem/Tick.test.ts +281 -0
  141. package/src/viem/Tick.ts +176 -0
  142. package/src/viem/TokenIds.ts +2 -0
  143. package/src/viem/Transaction.ts +303 -0
  144. package/src/viem/{transport.ts → Transport.ts} +5 -5
  145. package/src/viem/e2e.test.ts +153 -78
  146. package/src/viem/index.ts +13 -9
  147. package/src/viem/{types.ts → internal/types.ts} +3 -3
  148. package/dist/ox/TransactionEnvelopeFeeToken.d.ts +0 -393
  149. package/dist/ox/TransactionEnvelopeFeeToken.d.ts.map +0 -1
  150. package/dist/ox/TransactionEnvelopeFeeToken.js +0 -452
  151. package/dist/ox/TransactionEnvelopeFeeToken.js.map +0 -1
  152. package/dist/viem/abis.d.ts.map +0 -1
  153. package/dist/viem/abis.js.map +0 -1
  154. package/dist/viem/actions/amm.d.ts.map +0 -1
  155. package/dist/viem/actions/amm.js.map +0 -1
  156. package/dist/viem/actions/fee.d.ts.map +0 -1
  157. package/dist/viem/actions/fee.js.map +0 -1
  158. package/dist/viem/actions/index.d.ts +0 -5
  159. package/dist/viem/actions/index.d.ts.map +0 -1
  160. package/dist/viem/actions/index.js +0 -5
  161. package/dist/viem/actions/index.js.map +0 -1
  162. package/dist/viem/actions/policy.d.ts.map +0 -1
  163. package/dist/viem/actions/policy.js.map +0 -1
  164. package/dist/viem/actions/token.d.ts.map +0 -1
  165. package/dist/viem/actions/token.js.map +0 -1
  166. package/dist/viem/addresses.d.ts +0 -8
  167. package/dist/viem/addresses.d.ts.map +0 -1
  168. package/dist/viem/addresses.js +0 -8
  169. package/dist/viem/addresses.js.map +0 -1
  170. package/dist/viem/chain.d.ts.map +0 -1
  171. package/dist/viem/chain.js.map +0 -1
  172. package/dist/viem/client.d.ts.map +0 -1
  173. package/dist/viem/client.js.map +0 -1
  174. package/dist/viem/decorator.d.ts.map +0 -1
  175. package/dist/viem/decorator.js.map +0 -1
  176. package/dist/viem/formatters.d.ts.map +0 -1
  177. package/dist/viem/formatters.js.map +0 -1
  178. package/dist/viem/transaction.d.ts +0 -54
  179. package/dist/viem/transaction.d.ts.map +0 -1
  180. package/dist/viem/transaction.js +0 -108
  181. package/dist/viem/transaction.js.map +0 -1
  182. package/dist/viem/transport.d.ts.map +0 -1
  183. package/dist/viem/transport.js.map +0 -1
  184. package/dist/viem/types.d.ts.map +0 -1
  185. package/dist/viem/utils.d.ts.map +0 -1
  186. package/dist/viem/utils.js.map +0 -1
  187. package/src/ox/TransactionEnvelopeFeeToken.test.ts +0 -1119
  188. package/src/ox/TransactionEnvelopeFeeToken.ts +0 -717
  189. package/src/prool/internal/consensus.toml +0 -32
  190. package/src/viem/addresses.ts +0 -10
  191. package/src/viem/transaction.ts +0 -253
  192. /package/dist/viem/{types.js → internal/types.js} +0 -0
  193. /package/dist/viem/{utils.d.ts → internal/utils.d.ts} +0 -0
  194. /package/dist/viem/{utils.js → internal/utils.js} +0 -0
  195. /package/src/viem/{utils.ts → internal/utils.ts} +0 -0
@@ -0,0 +1,709 @@
1
+ import * as Errors from 'ox/Errors'
2
+ import * as Hex from 'ox/Hex'
3
+ import * as Json from 'ox/Json'
4
+ import type * as PublicKey from 'ox/PublicKey'
5
+ import * as Signature from 'ox/Signature'
6
+ import type * as WebAuthnP256 from 'ox/WebAuthnP256'
7
+ import type {
8
+ Assign,
9
+ Compute,
10
+ IsNarrowable,
11
+ OneOf,
12
+ PartialBy,
13
+ } from '../internal/types.js'
14
+
15
+ /** Signature type identifiers for encoding/decoding */
16
+ const serializedP256Type = '0x01'
17
+ const serializedWebAuthnType = '0x02'
18
+
19
+ /**
20
+ * Statically determines the signature type of an envelope at compile time.
21
+ *
22
+ * @example
23
+ * ```ts twoslash
24
+ * import type { SignatureEnvelope } from 'tempo.ts/ox'
25
+ *
26
+ * type Type = SignatureEnvelope.GetType<{ r: bigint; s: bigint; yParity: number }>
27
+ * // @log: 'secp256k1'
28
+ * ```
29
+ */
30
+ export type GetType<
31
+ envelope extends PartialBy<SignatureEnvelope, 'type'> | unknown,
32
+ > = unknown extends envelope
33
+ ? envelope extends unknown
34
+ ? Type
35
+ : never
36
+ : envelope extends { type: infer T extends Type }
37
+ ? T
38
+ : envelope extends {
39
+ signature: { r: bigint; s: bigint }
40
+ prehash: boolean
41
+ publicKey: PublicKey.PublicKey
42
+ }
43
+ ? 'p256'
44
+ : envelope extends {
45
+ signature: { r: bigint; s: bigint }
46
+ metadata: any
47
+ publicKey: PublicKey.PublicKey
48
+ }
49
+ ? 'webAuthn'
50
+ : envelope extends { r: bigint; s: bigint; yParity: number }
51
+ ? 'secp256k1'
52
+ : envelope extends {
53
+ signature: { r: bigint; s: bigint; yParity: number }
54
+ }
55
+ ? 'secp256k1'
56
+ : never
57
+
58
+ /**
59
+ * Represents a signature envelope that can contain different signature types.
60
+ *
61
+ * Supports:
62
+ * - secp256k1: Standard ECDSA signature (65 bytes)
63
+ * - p256: P256 signature with embedded public key and prehash flag (130 bytes)
64
+ * - webAuthn: WebAuthn signature with variable-length authenticator data
65
+ */
66
+ export type SignatureEnvelope<bigintType = bigint, numberType = number> = OneOf<
67
+ | Secp256k1<bigintType, numberType>
68
+ | P256<bigintType, numberType>
69
+ | WebAuthn<bigintType, numberType>
70
+ >
71
+
72
+ /**
73
+ * RPC-formatted signature envelope.
74
+ */
75
+ export type SignatureEnvelopeRpc = OneOf<Secp256k1Rpc | P256Rpc | WebAuthnRpc>
76
+
77
+ export type P256<bigintType = bigint, numberType = number> = {
78
+ prehash: boolean
79
+ publicKey: PublicKey.PublicKey
80
+ signature: Signature.Signature<false, bigintType, numberType>
81
+ type: 'p256'
82
+ }
83
+
84
+ export type P256Rpc = {
85
+ prehash: boolean
86
+ pubKeyX: Hex.Hex
87
+ pubKeyY: Hex.Hex
88
+ r: Hex.Hex
89
+ s: Hex.Hex
90
+ type: 'p256'
91
+ }
92
+
93
+ export type Secp256k1<bigintType = bigint, numberType = number> = {
94
+ signature: Signature.Signature<true, bigintType, numberType>
95
+ type: 'secp256k1'
96
+ }
97
+
98
+ export type Secp256k1Rpc = Compute<
99
+ Signature.Rpc<true> & {
100
+ v?: Hex.Hex | undefined
101
+ type: 'secp256k1'
102
+ }
103
+ >
104
+
105
+ export type Secp256k1Flat<
106
+ bigintType = bigint,
107
+ numberType = number,
108
+ > = Signature.Signature<true, bigintType, numberType> & {
109
+ type?: 'secp256k1' | undefined
110
+ }
111
+
112
+ export type WebAuthn<bigintType = bigint, numberType = number> = {
113
+ metadata: Pick<
114
+ WebAuthnP256.SignMetadata,
115
+ 'authenticatorData' | 'clientDataJSON'
116
+ >
117
+ signature: Signature.Signature<false, bigintType, numberType>
118
+ publicKey: PublicKey.PublicKey
119
+ type: 'webAuthn'
120
+ }
121
+
122
+ export type WebAuthnRpc = {
123
+ pubKeyX: Hex.Hex
124
+ pubKeyY: Hex.Hex
125
+ r: Hex.Hex
126
+ s: Hex.Hex
127
+ type: 'webAuthn'
128
+ webauthnData: Hex.Hex
129
+ }
130
+
131
+ /** Hex-encoded serialized signature envelope. */
132
+ export type Serialized = Hex.Hex
133
+
134
+ /** List of supported signature types. */
135
+ export const types = ['secp256k1', 'p256', 'webAuthn'] as const
136
+
137
+ /** Union type of supported signature types. */
138
+ export type Type = (typeof types)[number]
139
+
140
+ /**
141
+ * Asserts that a {@link SignatureEnvelope} is valid.
142
+ *
143
+ * @example
144
+ * ```ts twoslash
145
+ * import { SignatureEnvelope } from 'tempo.ts/ox'
146
+ *
147
+ * SignatureEnvelope.assert({
148
+ * r: 0n,
149
+ * s: 0n,
150
+ * yParity: 0,
151
+ * type: 'secp256k1',
152
+ * })
153
+ * ```
154
+ *
155
+ * @param envelope - The signature envelope to assert.
156
+ * @throws {CoercionError} If the envelope type cannot be determined.
157
+ */
158
+ export function assert(envelope: PartialBy<SignatureEnvelope, 'type'>): void {
159
+ const type = getType(envelope)
160
+
161
+ if (type === 'secp256k1') {
162
+ Signature.assert(envelope.signature)
163
+ return
164
+ }
165
+
166
+ if (type === 'p256') {
167
+ const p256 = envelope as P256
168
+ const missing: string[] = []
169
+
170
+ if (typeof p256.signature?.r !== 'bigint') missing.push('signature.r')
171
+ if (typeof p256.signature?.s !== 'bigint') missing.push('signature.s')
172
+ if (typeof p256.prehash !== 'boolean') missing.push('prehash')
173
+ if (!p256.publicKey) missing.push('publicKey')
174
+ else {
175
+ if (typeof p256.publicKey.x !== 'bigint') missing.push('publicKey.x')
176
+ if (typeof p256.publicKey.y !== 'bigint') missing.push('publicKey.y')
177
+ }
178
+
179
+ if (missing.length > 0)
180
+ throw new MissingPropertiesError({ envelope, missing, type: 'p256' })
181
+ return
182
+ }
183
+
184
+ if (type === 'webAuthn') {
185
+ const webauthn = envelope as WebAuthn
186
+ const missing: string[] = []
187
+
188
+ if (typeof webauthn.signature?.r !== 'bigint') missing.push('signature.r')
189
+ if (typeof webauthn.signature?.s !== 'bigint') missing.push('signature.s')
190
+ if (!webauthn.metadata) missing.push('metadata')
191
+ else {
192
+ if (!webauthn.metadata.authenticatorData)
193
+ missing.push('metadata.authenticatorData')
194
+ if (!webauthn.metadata.clientDataJSON)
195
+ missing.push('metadata.clientDataJSON')
196
+ }
197
+ if (!webauthn.publicKey) missing.push('publicKey')
198
+ else {
199
+ if (typeof webauthn.publicKey.x !== 'bigint') missing.push('publicKey.x')
200
+ if (typeof webauthn.publicKey.y !== 'bigint') missing.push('publicKey.y')
201
+ }
202
+
203
+ if (missing.length > 0)
204
+ throw new MissingPropertiesError({ envelope, missing, type: 'webAuthn' })
205
+ return
206
+ }
207
+ }
208
+
209
+ export declare namespace assert {
210
+ type ErrorType =
211
+ | CoercionError
212
+ | MissingPropertiesError
213
+ | Signature.assert.ErrorType
214
+ | Errors.GlobalErrorType
215
+ }
216
+
217
+ /**
218
+ * Deserializes a hex-encoded signature envelope into a typed signature object.
219
+ *
220
+ * For backward compatibility:
221
+ * - 65 bytes: secp256k1 signature (no type identifier)
222
+ * - 130 bytes: P256 signature (1 byte type + 129 bytes data)
223
+ * - 129+ bytes: WebAuthn signature (1 byte type + variable data)
224
+ *
225
+ * @param serialized - The hex-encoded signature envelope to deserialize.
226
+ * @returns The deserialized signature envelope.
227
+ * @throws {CoercionError} If the serialized value cannot be coerced to a valid signature envelope.
228
+ */
229
+ export function deserialize(serialized: Serialized): SignatureEnvelope {
230
+ const size = Hex.size(serialized)
231
+
232
+ // Backward compatibility: 65 bytes means secp256k1 without type identifier
233
+ if (size === 65) {
234
+ const signature = Signature.fromHex(serialized)
235
+ Signature.assert(signature)
236
+ return { signature, type: 'secp256k1' }
237
+ }
238
+
239
+ // For all other lengths, first byte is the type identifier
240
+ const typeId = Hex.slice(serialized, 0, 1)
241
+ const data = Hex.slice(serialized, 1)
242
+ const dataSize = Hex.size(data)
243
+
244
+ if (typeId === serializedP256Type) {
245
+ // P256: 32 (r) + 32 (s) + 32 (pubKeyX) + 32 (pubKeyY) + 1 (prehash) = 129 bytes
246
+ if (dataSize !== 129)
247
+ throw new InvalidSerializedError({
248
+ reason: `Invalid P256 signature envelope size: expected 129 bytes, got ${dataSize} bytes`,
249
+ serialized,
250
+ })
251
+
252
+ return {
253
+ publicKey: {
254
+ prefix: 4,
255
+ x: Hex.toBigInt(Hex.slice(data, 64, 96)),
256
+ y: Hex.toBigInt(Hex.slice(data, 96, 128)),
257
+ },
258
+ prehash: Hex.toNumber(Hex.slice(data, 128, 129)) !== 0,
259
+ signature: {
260
+ r: Hex.toBigInt(Hex.slice(data, 0, 32)),
261
+ s: Hex.toBigInt(Hex.slice(data, 32, 64)),
262
+ },
263
+ type: 'p256',
264
+ } as P256
265
+ }
266
+
267
+ if (typeId === serializedWebAuthnType) {
268
+ // WebAuthn: variable (webauthnData) + 32 (r) + 32 (s) + 32 (pubKeyX) + 32 (pubKeyY)
269
+ // Minimum: 128 bytes (at least some authenticator data + signature components)
270
+ if (dataSize < 128)
271
+ throw new InvalidSerializedError({
272
+ reason: `Invalid WebAuthn signature envelope size: expected at least 128 bytes, got ${dataSize} bytes`,
273
+ serialized,
274
+ })
275
+
276
+ const webauthnDataSize = dataSize - 128
277
+ const webauthnData = Hex.slice(data, 0, webauthnDataSize)
278
+
279
+ // Parse webauthnData into authenticatorData and clientDataJSON
280
+ // According to the Rust code, it's authenticatorData || clientDataJSON
281
+ // We need to find the split point (minimum authenticatorData is 37 bytes)
282
+ let authenticatorData: Hex.Hex | undefined
283
+ let clientDataJSON: string | undefined
284
+
285
+ // Try to find the JSON start (clientDataJSON should start with '{')
286
+ for (let split = 37; split < webauthnDataSize; split++) {
287
+ const potentialJson = Hex.toString(Hex.slice(webauthnData, split))
288
+ if (potentialJson.startsWith('{') && potentialJson.endsWith('}')) {
289
+ try {
290
+ JSON.parse(potentialJson)
291
+ authenticatorData = Hex.slice(webauthnData, 0, split)
292
+ clientDataJSON = potentialJson
293
+ break
294
+ } catch {}
295
+ }
296
+ }
297
+
298
+ if (!authenticatorData || !clientDataJSON)
299
+ throw new InvalidSerializedError({
300
+ reason:
301
+ 'Unable to parse WebAuthn metadata: could not extract valid authenticatorData and clientDataJSON',
302
+ serialized,
303
+ })
304
+
305
+ return {
306
+ publicKey: {
307
+ prefix: 4,
308
+ x: Hex.toBigInt(
309
+ Hex.slice(data, webauthnDataSize + 64, webauthnDataSize + 96),
310
+ ),
311
+ y: Hex.toBigInt(
312
+ Hex.slice(data, webauthnDataSize + 96, webauthnDataSize + 128),
313
+ ),
314
+ },
315
+ metadata: {
316
+ authenticatorData,
317
+ clientDataJSON,
318
+ },
319
+ signature: {
320
+ r: Hex.toBigInt(
321
+ Hex.slice(data, webauthnDataSize, webauthnDataSize + 32),
322
+ ),
323
+ s: Hex.toBigInt(
324
+ Hex.slice(data, webauthnDataSize + 32, webauthnDataSize + 64),
325
+ ),
326
+ },
327
+ type: 'webAuthn',
328
+ } as WebAuthn
329
+ }
330
+
331
+ throw new InvalidSerializedError({
332
+ reason: `Unknown signature type identifier: ${typeId}. Expected ${serializedP256Type} (P256) or ${serializedWebAuthnType} (WebAuthn)`,
333
+ serialized,
334
+ })
335
+ }
336
+
337
+ /**
338
+ * Coerces a value to a signature envelope.
339
+ *
340
+ * Accepts either a serialized hex string or an existing signature envelope object.
341
+ *
342
+ * @param value - The value to coerce (either a hex string or signature envelope).
343
+ * @returns The signature envelope.
344
+ */
345
+ export function from<const value extends from.Value>(
346
+ value: value | from.Value,
347
+ ): from.ReturnValue<value> {
348
+ if (typeof value === 'string') return deserialize(value) as never
349
+
350
+ if (
351
+ typeof value === 'object' &&
352
+ value !== null &&
353
+ 'r' in value &&
354
+ 's' in value &&
355
+ 'yParity' in value
356
+ )
357
+ return { signature: value, type: 'secp256k1' } as never
358
+
359
+ const type = getType(value)
360
+ return { ...value, type } as never
361
+ }
362
+
363
+ export declare namespace from {
364
+ type Value = PartialBy<SignatureEnvelope, 'type'> | Secp256k1Flat | Serialized
365
+
366
+ type ReturnValue<value extends Value> = Compute<
367
+ OneOf<
368
+ value extends Serialized
369
+ ? SignatureEnvelope
370
+ : value extends Secp256k1Flat
371
+ ? Secp256k1
372
+ : IsNarrowable<value, SignatureEnvelope> extends true
373
+ ? SignatureEnvelope
374
+ : Assign<value, { readonly type: GetType<value> }>
375
+ >
376
+ >
377
+ }
378
+
379
+ /**
380
+ * Converts an {@link SignatureEnvelopeRpc} to a {@link SignatureEnvelope}.
381
+ *
382
+ * @param envelope - The RPC signature envelope to convert.
383
+ * @returns The signature envelope with bigint values.
384
+ */
385
+ export function fromRpc(envelope: SignatureEnvelopeRpc): SignatureEnvelope {
386
+ if (envelope.type === 'secp256k1')
387
+ return {
388
+ signature: Signature.fromRpc(envelope),
389
+ type: 'secp256k1',
390
+ }
391
+
392
+ if (envelope.type === 'p256') {
393
+ return {
394
+ prehash: envelope.prehash,
395
+ publicKey: {
396
+ prefix: 4,
397
+ x: Hex.toBigInt(envelope.pubKeyX),
398
+ y: Hex.toBigInt(envelope.pubKeyY),
399
+ },
400
+ signature: {
401
+ r: Hex.toBigInt(envelope.r),
402
+ s: Hex.toBigInt(envelope.s),
403
+ },
404
+ type: 'p256',
405
+ }
406
+ }
407
+
408
+ if (envelope.type === 'webAuthn') {
409
+ const webauthnData = envelope.webauthnData
410
+ const webauthnDataSize = Hex.size(webauthnData)
411
+
412
+ // Parse webauthnData into authenticatorData and clientDataJSON
413
+ let authenticatorData: Hex.Hex | undefined
414
+ let clientDataJSON: string | undefined
415
+
416
+ // Try to find the JSON start (clientDataJSON should start with '{')
417
+ for (let split = 37; split < webauthnDataSize; split++) {
418
+ const potentialJson = Hex.toString(Hex.slice(webauthnData, split))
419
+ if (potentialJson.startsWith('{') && potentialJson.endsWith('}')) {
420
+ try {
421
+ JSON.parse(potentialJson)
422
+ authenticatorData = Hex.slice(webauthnData, 0, split)
423
+ clientDataJSON = potentialJson
424
+ break
425
+ } catch {}
426
+ }
427
+ }
428
+
429
+ if (!authenticatorData || !clientDataJSON)
430
+ throw new InvalidSerializedError({
431
+ reason:
432
+ 'Unable to parse WebAuthn metadata: could not extract valid authenticatorData and clientDataJSON',
433
+ serialized: webauthnData,
434
+ })
435
+
436
+ return {
437
+ metadata: {
438
+ authenticatorData,
439
+ clientDataJSON,
440
+ },
441
+ publicKey: {
442
+ prefix: 4,
443
+ x: Hex.toBigInt(envelope.pubKeyX),
444
+ y: Hex.toBigInt(envelope.pubKeyY),
445
+ },
446
+ signature: {
447
+ r: Hex.toBigInt(envelope.r),
448
+ s: Hex.toBigInt(envelope.s),
449
+ },
450
+ type: 'webAuthn',
451
+ }
452
+ }
453
+
454
+ throw new CoercionError({ envelope })
455
+ }
456
+
457
+ export declare namespace fromRpc {
458
+ type ErrorType =
459
+ | CoercionError
460
+ | InvalidSerializedError
461
+ | Signature.fromRpc.ErrorType
462
+ | Errors.GlobalErrorType
463
+ }
464
+
465
+ /**
466
+ * Determines the signature type of an envelope.
467
+ *
468
+ * @param envelope - The signature envelope to inspect.
469
+ * @returns The signature type ('secp256k1', 'p256', or 'webAuthn').
470
+ * @throws {CoercionError} If the envelope type cannot be determined.
471
+ */
472
+ export function getType<
473
+ envelope extends
474
+ | PartialBy<SignatureEnvelope, 'type'>
475
+ | Secp256k1Flat
476
+ | unknown,
477
+ >(envelope: envelope): GetType<envelope> {
478
+ if (typeof envelope !== 'object' || envelope === null)
479
+ throw new CoercionError({ envelope })
480
+
481
+ if ('type' in envelope && envelope.type) return envelope.type as never
482
+
483
+ // Detect secp256k1 signature (backwards compatibility: also support flat structure)
484
+ if (
485
+ 'signature' in envelope &&
486
+ !('publicKey' in envelope) &&
487
+ typeof envelope.signature === 'object' &&
488
+ envelope.signature !== null &&
489
+ 'r' in envelope.signature &&
490
+ 's' in envelope.signature &&
491
+ 'yParity' in envelope.signature
492
+ )
493
+ return 'secp256k1' as never
494
+
495
+ // Detect secp256k1 signature (flat structure)
496
+ if ('r' in envelope && 's' in envelope && 'yParity' in envelope)
497
+ return 'secp256k1' as never
498
+
499
+ // Detect P256 signature
500
+ if (
501
+ 'signature' in envelope &&
502
+ 'prehash' in envelope &&
503
+ 'publicKey' in envelope &&
504
+ typeof envelope.prehash === 'boolean'
505
+ )
506
+ return 'p256' as never
507
+
508
+ // Detect WebAuthn signature
509
+ if (
510
+ 'signature' in envelope &&
511
+ 'metadata' in envelope &&
512
+ 'publicKey' in envelope
513
+ )
514
+ return 'webAuthn' as never
515
+
516
+ throw new CoercionError({
517
+ envelope,
518
+ })
519
+ }
520
+
521
+ /**
522
+ * Serializes a signature envelope to a hex-encoded string.
523
+ *
524
+ * For backward compatibility:
525
+ * - secp256k1: encoded WITHOUT type identifier (65 bytes)
526
+ * - P256: encoded WITH type identifier prefix (130 bytes)
527
+ * - WebAuthn: encoded WITH type identifier prefix (variable length)
528
+ *
529
+ * @param envelope - The signature envelope to serialize.
530
+ * @returns The hex-encoded serialized signature.
531
+ * @throws {CoercionError} If the envelope cannot be serialized.
532
+ */
533
+ export function serialize(envelope: SignatureEnvelope): Serialized {
534
+ const type = getType(envelope)
535
+
536
+ // Backward compatibility: no type identifier for secp256k1
537
+ if (type === 'secp256k1') return Signature.toHex(envelope.signature)
538
+
539
+ if (type === 'p256') {
540
+ const p256 = envelope as P256
541
+ // Format: 1 byte (type) + 32 (r) + 32 (s) + 32 (pubKeyX) + 32 (pubKeyY) + 1 (prehash)
542
+ return Hex.concat(
543
+ serializedP256Type,
544
+ Hex.fromNumber(p256.signature.r, { size: 32 }),
545
+ Hex.fromNumber(p256.signature.s, { size: 32 }),
546
+ Hex.fromNumber(p256.publicKey.x, { size: 32 }),
547
+ Hex.fromNumber(p256.publicKey.y, { size: 32 }),
548
+ Hex.fromNumber(p256.prehash ? 1 : 0, { size: 1 }),
549
+ )
550
+ }
551
+
552
+ if (type === 'webAuthn') {
553
+ const webauthn = envelope as WebAuthn
554
+ // Format: 1 byte (type) + variable (authenticatorData || clientDataJSON) + 32 (r) + 32 (s) + 32 (pubKeyX) + 32 (pubKeyY)
555
+ const webauthnData = Hex.concat(
556
+ webauthn.metadata.authenticatorData,
557
+ Hex.fromString(webauthn.metadata.clientDataJSON),
558
+ )
559
+
560
+ return Hex.concat(
561
+ serializedWebAuthnType,
562
+ webauthnData,
563
+ Hex.fromNumber(webauthn.signature.r, { size: 32 }),
564
+ Hex.fromNumber(webauthn.signature.s, { size: 32 }),
565
+ Hex.fromNumber(webauthn.publicKey.x, { size: 32 }),
566
+ Hex.fromNumber(webauthn.publicKey.y, { size: 32 }),
567
+ )
568
+ }
569
+
570
+ throw new CoercionError({ envelope })
571
+ }
572
+
573
+ /**
574
+ * Converts a {@link SignatureEnvelope} to an {@link SignatureEnvelopeRpc}.
575
+ *
576
+ * @param envelope - The signature envelope to convert.
577
+ * @returns The RPC signature envelope with hex values.
578
+ */
579
+ export function toRpc(envelope: SignatureEnvelope): SignatureEnvelopeRpc {
580
+ const type = getType(envelope)
581
+
582
+ if (type === 'secp256k1') {
583
+ const secp256k1 = envelope as Secp256k1
584
+ return {
585
+ ...Signature.toRpc(secp256k1.signature),
586
+ type: 'secp256k1',
587
+ }
588
+ }
589
+
590
+ if (type === 'p256') {
591
+ const p256 = envelope as P256
592
+ return {
593
+ prehash: p256.prehash,
594
+ pubKeyX: Hex.fromNumber(p256.publicKey.x, { size: 32 }),
595
+ pubKeyY: Hex.fromNumber(p256.publicKey.y, { size: 32 }),
596
+ r: Hex.fromNumber(p256.signature.r, { size: 32 }),
597
+ s: Hex.fromNumber(p256.signature.s, { size: 32 }),
598
+ type: 'p256',
599
+ }
600
+ }
601
+
602
+ if (type === 'webAuthn') {
603
+ const webauthn = envelope as WebAuthn
604
+ const webauthnData = Hex.concat(
605
+ webauthn.metadata.authenticatorData,
606
+ Hex.fromString(webauthn.metadata.clientDataJSON),
607
+ )
608
+
609
+ return {
610
+ pubKeyX: Hex.fromNumber(webauthn.publicKey.x, { size: 32 }),
611
+ pubKeyY: Hex.fromNumber(webauthn.publicKey.y, { size: 32 }),
612
+ r: Hex.fromNumber(webauthn.signature.r, { size: 32 }),
613
+ s: Hex.fromNumber(webauthn.signature.s, { size: 32 }),
614
+ type: 'webAuthn',
615
+ webauthnData,
616
+ }
617
+ }
618
+
619
+ throw new CoercionError({ envelope })
620
+ }
621
+
622
+ export declare namespace toRpc {
623
+ type ErrorType =
624
+ | CoercionError
625
+ | Signature.toRpc.ErrorType
626
+ | Errors.GlobalErrorType
627
+ }
628
+
629
+ /**
630
+ * Validates a {@link SignatureEnvelope}. Returns `true` if the envelope is valid, `false` otherwise.
631
+ *
632
+ * @example
633
+ * ```ts twoslash
634
+ * import { SignatureEnvelope } from 'tempo.ts/ox'
635
+ *
636
+ * const valid = SignatureEnvelope.validate({
637
+ * signature: { r: 0n, s: 0n, yParity: 0 },
638
+ * type: 'secp256k1',
639
+ * })
640
+ * // @log: true
641
+ * ```
642
+ *
643
+ * @param envelope - The signature envelope to validate.
644
+ * @returns `true` if valid, `false` otherwise.
645
+ */
646
+ export function validate(
647
+ envelope: PartialBy<SignatureEnvelope, 'type'>,
648
+ ): boolean {
649
+ try {
650
+ assert(envelope)
651
+ return true
652
+ } catch {
653
+ return false
654
+ }
655
+ }
656
+
657
+ export declare namespace validate {
658
+ type ErrorType = Errors.GlobalErrorType
659
+ }
660
+
661
+ /**
662
+ * Error thrown when a signature envelope cannot be coerced to a valid type.
663
+ */
664
+ export class CoercionError extends Errors.BaseError {
665
+ override readonly name = 'SignatureEnvelope.CoercionError'
666
+ constructor({ envelope }: { envelope: unknown }) {
667
+ super(
668
+ `Unable to coerce value (\`${Json.stringify(envelope)}\`) to a valid signature envelope.`,
669
+ )
670
+ }
671
+ }
672
+
673
+ /**
674
+ * Error thrown when a signature envelope is missing required properties.
675
+ */
676
+ export class MissingPropertiesError extends Errors.BaseError {
677
+ override readonly name = 'SignatureEnvelope.MissingPropertiesError'
678
+ constructor({
679
+ envelope,
680
+ missing,
681
+ type,
682
+ }: {
683
+ envelope: unknown
684
+ missing: string[]
685
+ type: Type
686
+ }) {
687
+ super(
688
+ `Signature envelope of type "${type}" is missing required properties: ${missing.map((m) => `\`${m}\``).join(', ')}.\n\nProvided: ${Json.stringify(envelope)}`,
689
+ )
690
+ }
691
+ }
692
+
693
+ /**
694
+ * Error thrown when a serialized signature envelope cannot be deserialized.
695
+ */
696
+ export class InvalidSerializedError extends Errors.BaseError {
697
+ override readonly name = 'SignatureEnvelope.InvalidSerializedError'
698
+ constructor({
699
+ reason,
700
+ serialized,
701
+ }: {
702
+ reason: string
703
+ serialized: Hex.Hex
704
+ }) {
705
+ super(`Unable to deserialize signature envelope: ${reason}`, {
706
+ metaMessages: [`Serialized: ${serialized}`],
707
+ })
708
+ }
709
+ }