ox 1.7.4 → 1.8.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 (237) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/core/AbiEvent.d.ts.map +1 -1
  3. package/dist/core/AbiEvent.js +10 -9
  4. package/dist/core/AbiEvent.js.map +1 -1
  5. package/dist/core/Blobs.d.ts.map +1 -1
  6. package/dist/core/Blobs.js +6 -2
  7. package/dist/core/Blobs.js.map +1 -1
  8. package/dist/core/Frame.d.ts +290 -0
  9. package/dist/core/Frame.d.ts.map +1 -0
  10. package/dist/core/Frame.js +306 -0
  11. package/dist/core/Frame.js.map +1 -0
  12. package/dist/core/FrameReceipt.d.ts +92 -0
  13. package/dist/core/FrameReceipt.d.ts.map +1 -0
  14. package/dist/core/FrameReceipt.js +72 -0
  15. package/dist/core/FrameReceipt.js.map +1 -0
  16. package/dist/core/FrameSignature.d.ts +357 -0
  17. package/dist/core/FrameSignature.d.ts.map +1 -0
  18. package/dist/core/FrameSignature.js +411 -0
  19. package/dist/core/FrameSignature.js.map +1 -0
  20. package/dist/core/Signature.d.ts +6 -5
  21. package/dist/core/Signature.d.ts.map +1 -1
  22. package/dist/core/Signature.js +17 -7
  23. package/dist/core/Signature.js.map +1 -1
  24. package/dist/core/Siwe.d.ts.map +1 -1
  25. package/dist/core/Siwe.js +21 -1
  26. package/dist/core/Siwe.js.map +1 -1
  27. package/dist/core/Transaction.d.ts +29 -4
  28. package/dist/core/Transaction.d.ts.map +1 -1
  29. package/dist/core/Transaction.js +25 -4
  30. package/dist/core/Transaction.js.map +1 -1
  31. package/dist/core/TransactionReceipt.d.ts +13 -4
  32. package/dist/core/TransactionReceipt.d.ts.map +1 -1
  33. package/dist/core/TransactionReceipt.js +14 -0
  34. package/dist/core/TransactionReceipt.js.map +1 -1
  35. package/dist/core/TransactionRequest.d.ts +15 -7
  36. package/dist/core/TransactionRequest.d.ts.map +1 -1
  37. package/dist/core/TransactionRequest.js +47 -1
  38. package/dist/core/TransactionRequest.js.map +1 -1
  39. package/dist/core/TxEnvelope.d.ts +35 -21
  40. package/dist/core/TxEnvelope.d.ts.map +1 -1
  41. package/dist/core/TxEnvelope.js +46 -6
  42. package/dist/core/TxEnvelope.js.map +1 -1
  43. package/dist/core/TxEnvelopeEip8141.d.ts +341 -0
  44. package/dist/core/TxEnvelopeEip8141.d.ts.map +1 -0
  45. package/dist/core/TxEnvelopeEip8141.js +485 -0
  46. package/dist/core/TxEnvelopeEip8141.js.map +1 -0
  47. package/dist/core/internal/curves.d.ts +2 -0
  48. package/dist/core/internal/curves.d.ts.map +1 -1
  49. package/dist/core/internal/curves.js +2 -0
  50. package/dist/core/internal/curves.js.map +1 -1
  51. package/dist/index.d.ts +73 -0
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +73 -0
  54. package/dist/index.js.map +1 -1
  55. package/dist/tempo/KeyAuthorization.d.ts +42 -38
  56. package/dist/tempo/KeyAuthorization.d.ts.map +1 -1
  57. package/dist/tempo/KeyAuthorization.js +24 -4
  58. package/dist/tempo/KeyAuthorization.js.map +1 -1
  59. package/dist/tempo/MultisigConfig.d.ts +18 -15
  60. package/dist/tempo/MultisigConfig.d.ts.map +1 -1
  61. package/dist/tempo/MultisigConfig.js +49 -20
  62. package/dist/tempo/MultisigConfig.js.map +1 -1
  63. package/dist/tempo/MultisigOperation.d.ts +3 -2
  64. package/dist/tempo/MultisigOperation.d.ts.map +1 -1
  65. package/dist/tempo/MultisigOperation.js +20 -100
  66. package/dist/tempo/MultisigOperation.js.map +1 -1
  67. package/dist/tempo/MultisigSimulation.d.ts +2 -49
  68. package/dist/tempo/MultisigSimulation.d.ts.map +1 -1
  69. package/dist/tempo/MultisigSimulation.js +18 -46
  70. package/dist/tempo/MultisigSimulation.js.map +1 -1
  71. package/dist/tempo/SignatureEnvelope.d.ts +72 -140
  72. package/dist/tempo/SignatureEnvelope.d.ts.map +1 -1
  73. package/dist/tempo/SignatureEnvelope.js +130 -181
  74. package/dist/tempo/SignatureEnvelope.js.map +1 -1
  75. package/dist/tempo/Transaction.d.ts +2 -0
  76. package/dist/tempo/Transaction.d.ts.map +1 -1
  77. package/dist/tempo/TransactionReceipt.d.ts +2 -0
  78. package/dist/tempo/TransactionReceipt.d.ts.map +1 -1
  79. package/dist/tempo/TransactionRequest.d.ts +4 -2
  80. package/dist/tempo/TransactionRequest.d.ts.map +1 -1
  81. package/dist/tempo/TransactionRequest.js +6 -1
  82. package/dist/tempo/TransactionRequest.js.map +1 -1
  83. package/dist/tempo/index.d.ts +3 -1
  84. package/dist/tempo/index.d.ts.map +1 -1
  85. package/dist/tempo/index.js +3 -1
  86. package/dist/tempo/index.js.map +1 -1
  87. package/dist/zod/Block.d.ts +123 -0
  88. package/dist/zod/Block.d.ts.map +1 -1
  89. package/dist/zod/Frame.d.ts +73 -0
  90. package/dist/zod/Frame.d.ts.map +1 -0
  91. package/dist/zod/Frame.js +74 -0
  92. package/dist/zod/Frame.js.map +1 -0
  93. package/dist/zod/FrameReceipt.d.ts +50 -0
  94. package/dist/zod/FrameReceipt.d.ts.map +1 -0
  95. package/dist/zod/FrameReceipt.js +37 -0
  96. package/dist/zod/FrameReceipt.js.map +1 -0
  97. package/dist/zod/FrameSignature.d.ts +63 -0
  98. package/dist/zod/FrameSignature.d.ts.map +1 -0
  99. package/dist/zod/FrameSignature.js +66 -0
  100. package/dist/zod/FrameSignature.js.map +1 -0
  101. package/dist/zod/RpcSchema.d.ts +806 -11
  102. package/dist/zod/RpcSchema.d.ts.map +1 -1
  103. package/dist/zod/Transaction.d.ts +252 -0
  104. package/dist/zod/Transaction.d.ts.map +1 -1
  105. package/dist/zod/Transaction.js +54 -0
  106. package/dist/zod/Transaction.js.map +1 -1
  107. package/dist/zod/TransactionEnvelope.d.ts +233 -4
  108. package/dist/zod/TransactionEnvelope.d.ts.map +1 -1
  109. package/dist/zod/TransactionEnvelope.js +9 -0
  110. package/dist/zod/TransactionEnvelope.js.map +1 -1
  111. package/dist/zod/TransactionReceipt.d.ts +48 -0
  112. package/dist/zod/TransactionReceipt.d.ts.map +1 -1
  113. package/dist/zod/TransactionReceipt.js +8 -3
  114. package/dist/zod/TransactionReceipt.js.map +1 -1
  115. package/dist/zod/TransactionRequest.d.ts +50 -2
  116. package/dist/zod/TransactionRequest.d.ts.map +1 -1
  117. package/dist/zod/TransactionRequest.js +10 -4
  118. package/dist/zod/TransactionRequest.js.map +1 -1
  119. package/dist/zod/TxEnvelopeEip8141.d.ts +166 -0
  120. package/dist/zod/TxEnvelopeEip8141.d.ts.map +1 -0
  121. package/dist/zod/TxEnvelopeEip8141.js +76 -0
  122. package/dist/zod/TxEnvelopeEip8141.js.map +1 -0
  123. package/dist/zod/internal/Frame.d.ts +4 -0
  124. package/dist/zod/internal/Frame.d.ts.map +1 -0
  125. package/dist/zod/internal/Frame.js +17 -0
  126. package/dist/zod/internal/Frame.js.map +1 -0
  127. package/dist/zod/internal/rpcSchemas/Eth.d.ts +842 -11
  128. package/dist/zod/internal/rpcSchemas/Eth.d.ts.map +1 -1
  129. package/dist/zod/internal/rpcSchemas/Wallet.d.ts +56 -2
  130. package/dist/zod/internal/rpcSchemas/Wallet.d.ts.map +1 -1
  131. package/dist/zod/tempo/AuthorizationTempo.d.ts +350 -10
  132. package/dist/zod/tempo/AuthorizationTempo.d.ts.map +1 -1
  133. package/dist/zod/tempo/KeyAuthorization.d.ts +242 -422
  134. package/dist/zod/tempo/KeyAuthorization.d.ts.map +1 -1
  135. package/dist/zod/tempo/KeyAuthorization.js +29 -31
  136. package/dist/zod/tempo/KeyAuthorization.js.map +1 -1
  137. package/dist/zod/tempo/MultisigSimulation.d.ts +8 -76
  138. package/dist/zod/tempo/MultisigSimulation.d.ts.map +1 -1
  139. package/dist/zod/tempo/MultisigSimulation.js +3 -37
  140. package/dist/zod/tempo/MultisigSimulation.js.map +1 -1
  141. package/dist/zod/tempo/RpcSchemaTempo.d.ts +424 -228
  142. package/dist/zod/tempo/RpcSchemaTempo.d.ts.map +1 -1
  143. package/dist/zod/tempo/SignatureEnvelope.d.ts +105 -3
  144. package/dist/zod/tempo/SignatureEnvelope.d.ts.map +1 -1
  145. package/dist/zod/tempo/SignatureEnvelope.js +21 -9
  146. package/dist/zod/tempo/SignatureEnvelope.js.map +1 -1
  147. package/dist/zod/tempo/Transaction.d.ts +783 -432
  148. package/dist/zod/tempo/Transaction.d.ts.map +1 -1
  149. package/dist/zod/tempo/TransactionRequest.d.ts +590 -473
  150. package/dist/zod/tempo/TransactionRequest.d.ts.map +1 -1
  151. package/dist/zod/tempo/TransactionRequest.js +8 -0
  152. package/dist/zod/tempo/TransactionRequest.js.map +1 -1
  153. package/dist/zod/tempo/TxEnvelopeTempo.d.ts +327 -213
  154. package/dist/zod/tempo/TxEnvelopeTempo.d.ts.map +1 -1
  155. package/dist/zod/tempo/ZoneRpcAuthentication.d.ts +105 -3
  156. package/dist/zod/tempo/ZoneRpcAuthentication.d.ts.map +1 -1
  157. package/dist/zod/z.d.ts +4 -0
  158. package/dist/zod/z.d.ts.map +1 -1
  159. package/dist/zod/z.js +4 -0
  160. package/dist/zod/z.js.map +1 -1
  161. package/package.json +41 -1
  162. package/src/core/AbiEvent.ts +11 -9
  163. package/src/core/Blobs.ts +6 -2
  164. package/src/core/Frame.ts +443 -0
  165. package/src/core/FrameReceipt.ts +117 -0
  166. package/src/core/FrameSignature.ts +593 -0
  167. package/src/core/Signature.ts +41 -11
  168. package/src/core/Siwe.ts +20 -1
  169. package/src/core/Transaction.ts +82 -5
  170. package/src/core/TransactionReceipt.ts +41 -3
  171. package/src/core/TransactionRequest.ts +71 -4
  172. package/src/core/TxEnvelope.ts +159 -90
  173. package/src/core/TxEnvelopeEip8141.ts +715 -0
  174. package/src/core/_test/AbiEvent.test.ts +45 -0
  175. package/src/core/_test/Blobs.test.ts +22 -0
  176. package/src/core/_test/Frame.test-d.ts +96 -0
  177. package/src/core/_test/Frame.test.ts +267 -0
  178. package/src/core/_test/FrameReceipt.test.ts +86 -0
  179. package/src/core/_test/FrameSignature.test-d.ts +93 -0
  180. package/src/core/_test/FrameSignature.test.ts +554 -0
  181. package/src/core/_test/Signature.test.ts +166 -0
  182. package/src/core/_test/Siwe.test.ts +100 -1
  183. package/src/core/_test/Transaction.test.ts +33 -0
  184. package/src/core/_test/TransactionEnvelope.test-d.ts +74 -0
  185. package/src/core/_test/TransactionEnvelope.test.ts +107 -0
  186. package/src/core/_test/TransactionReceipt.test.ts +59 -0
  187. package/src/core/_test/TransactionRequest.test-d.ts +50 -0
  188. package/src/core/_test/TransactionRequest.test.ts +88 -1
  189. package/src/core/_test/TxEnvelopeEip8141.test-d.ts +44 -0
  190. package/src/core/_test/TxEnvelopeEip8141.test.ts +1775 -0
  191. package/src/core/_test/curves.test.ts +6 -1
  192. package/src/core/_test/index.test.ts +4 -0
  193. package/src/core/internal/curves.ts +4 -0
  194. package/src/index.ts +77 -0
  195. package/src/tempo/AuthorizationTempo.test.ts +8 -4
  196. package/src/tempo/KeyAuthorization.test-d.ts +16 -63
  197. package/src/tempo/KeyAuthorization.test.ts +69 -11
  198. package/src/tempo/KeyAuthorization.ts +107 -63
  199. package/src/tempo/MultisigConfig.test.ts +44 -20
  200. package/src/tempo/MultisigConfig.ts +65 -23
  201. package/src/tempo/MultisigOperation.test.ts +79 -550
  202. package/src/tempo/MultisigOperation.ts +31 -146
  203. package/src/tempo/MultisigSimulation.test-d.ts +2 -2
  204. package/src/tempo/MultisigSimulation.test.ts +21 -110
  205. package/src/tempo/MultisigSimulation.ts +25 -99
  206. package/src/tempo/SignatureEnvelope.test-d.ts +29 -47
  207. package/src/tempo/SignatureEnvelope.test.ts +328 -541
  208. package/src/tempo/SignatureEnvelope.ts +196 -291
  209. package/src/tempo/Transaction.test.ts +4 -4
  210. package/src/tempo/TransactionRequest.test.ts +17 -80
  211. package/src/tempo/TransactionRequest.ts +19 -2
  212. package/src/tempo/index.ts +3 -1
  213. package/src/tempo/multisig.e2e.test.ts +321 -860
  214. package/src/version.ts +1 -1
  215. package/src/zod/Frame.ts +82 -0
  216. package/src/zod/FrameReceipt.ts +48 -0
  217. package/src/zod/FrameSignature.ts +78 -0
  218. package/src/zod/Transaction.ts +63 -0
  219. package/src/zod/TransactionEnvelope.ts +33 -0
  220. package/src/zod/TransactionReceipt.ts +14 -3
  221. package/src/zod/TransactionRequest.ts +18 -3
  222. package/src/zod/TxEnvelopeEip8141.ts +102 -0
  223. package/src/zod/_test/Frame.test-d.ts +41 -0
  224. package/src/zod/_test/Frame.test.ts +54 -0
  225. package/src/zod/_test/FrameReceipt.test.ts +75 -0
  226. package/src/zod/_test/FrameSignature.test.ts +94 -0
  227. package/src/zod/_test/TxEnvelopeEip8141.test.ts +116 -0
  228. package/src/zod/internal/Frame.ts +26 -0
  229. package/src/zod/tempo/KeyAuthorization.ts +50 -39
  230. package/src/zod/tempo/MultisigSimulation.ts +3 -48
  231. package/src/zod/tempo/SignatureEnvelope.ts +46 -35
  232. package/src/zod/tempo/TransactionRequest.ts +14 -0
  233. package/src/zod/tempo/_test/KeyAuthorization.test.ts +69 -20
  234. package/src/zod/tempo/_test/MultisigSimulation.test.ts +6 -31
  235. package/src/zod/tempo/_test/SignatureEnvelope.test.ts +118 -85
  236. package/src/zod/tempo/_test/TransactionRequest.test.ts +9 -19
  237. package/src/zod/z.ts +4 -0
@@ -0,0 +1,593 @@
1
+ import * as Address from './Address.js'
2
+ import * as Errors from './Errors.js'
3
+ import * as Hex from './Hex.js'
4
+ import { p256N, secp256k1N } from './internal/curves.js'
5
+ import type { Compute, UnionPartialBy } from './internal/types.js'
6
+ import * as PublicKey from './PublicKey.js'
7
+ import * as Signature from './Signature.js'
8
+
9
+ /** Signature schemes supported by EIP-8141. */
10
+ export const schemes = { arbitrary: 0, p256: 2, secp256k1: 1 } as const
11
+
12
+ /** A supported numeric or named frame signature scheme. */
13
+ export type Scheme =
14
+ | keyof typeof schemes
15
+ | (typeof schemes)[keyof typeof schemes]
16
+
17
+ /** Contract-defined signature bytes. */
18
+ export type Arbitrary = {
19
+ /** Explicit nonzero digest. Omit or use empty bytes for the transaction signing hash. */
20
+ payload?: Hex.Hex | undefined
21
+ /** Contract-defined verification scheme. */
22
+ scheme: 0 | 'arbitrary'
23
+ /** Opaque witness bytes. */
24
+ signature: Hex.Hex
25
+ /** Arbitrary signatures have no signer metadata. */
26
+ signer?: undefined
27
+ }
28
+
29
+ /** A structured secp256k1 signature entry. */
30
+ export type Secp256k1 = {
31
+ /** Explicit nonzero digest. Omit or use empty bytes for the transaction signing hash. */
32
+ payload?: Hex.Hex | undefined
33
+ /** secp256k1 verification scheme. */
34
+ scheme: 1 | 'secp256k1'
35
+ /** Recovered signature. Omit for an unsigned entry. */
36
+ signature?: Signature.Signature | undefined
37
+ /** Signer address. Omit to use the transaction sender. */
38
+ signer?: Address.Address | undefined
39
+ }
40
+
41
+ /** A structured P-256 signature entry. */
42
+ export type P256 = {
43
+ /** Explicit nonzero digest. Omit or use empty bytes for the transaction signing hash. */
44
+ payload?: Hex.Hex | undefined
45
+ /** P-256 verification scheme. */
46
+ scheme: 2 | 'p256'
47
+ /** Signer address. Omit to use the transaction sender. */
48
+ signer?: Address.Address | undefined
49
+ } & (
50
+ | {
51
+ /** Uncompressed P-256 public key. */
52
+ publicKey: PublicKey.PublicKey
53
+ /** P-256 signature. */
54
+ signature: Signature.Signature<false>
55
+ }
56
+ | {
57
+ /** Public key, if already known. Empty wire signatures do not retain it. */
58
+ publicKey?: PublicKey.PublicKey | undefined
59
+ /** Omit for an unsigned entry. */
60
+ signature?: undefined
61
+ }
62
+ )
63
+
64
+ /** An EIP-8141 signature entry. Empty payload selects the transaction signing hash. */
65
+ export type FrameSignature = Arbitrary | Secp256k1 | P256
66
+
67
+ /** JSON-RPC representation of a frame signature. */
68
+ export type Rpc = {
69
+ /** Explicit digest, or empty bytes for the transaction signing hash. */
70
+ msg: Hex.Hex
71
+ /** Signature verification scheme. */
72
+ scheme: 0 | 1 | 2
73
+ /** Encoded signature bytes. */
74
+ signature: Hex.Hex
75
+ /** Signer address; absent for the transaction sender. */
76
+ signer?: Address.Address | null | undefined
77
+ }
78
+
79
+ /** RLP-ready signature entry. The payload occupies the specification's `msg` field. */
80
+ export type Tuple = readonly [
81
+ scheme: Hex.Hex,
82
+ signer: Hex.Hex,
83
+ payload: Hex.Hex,
84
+ signature: Hex.Hex,
85
+ ]
86
+
87
+ /**
88
+ * Asserts that a {@link ox#FrameSignature.FrameSignature} is structurally valid.
89
+ *
90
+ * Checks metadata, signature scalars, and public key shape without verifying
91
+ * authorization.
92
+ *
93
+ * @example
94
+ * ### Basic Usage
95
+ *
96
+ * Unsigned protocol entries are accepted by default.
97
+ *
98
+ * ```ts twoslash
99
+ * import { FrameSignature } from 'ox'
100
+ *
101
+ * FrameSignature.assert({
102
+ * payload: '0x',
103
+ * scheme: 'secp256k1'
104
+ * })
105
+ * ```
106
+ *
107
+ * @example
108
+ * ### Requiring a Signature
109
+ *
110
+ * Set `signed` to require a protocol signature.
111
+ *
112
+ * ```ts twoslash
113
+ * import { FrameSignature, Hash, Secp256k1 } from 'ox'
114
+ *
115
+ * const payload = Hash.keccak256('0xdeadbeef')
116
+ * const privateKey = Secp256k1.randomPrivateKey()
117
+ * const signature = Secp256k1.sign({ payload, privateKey })
118
+ *
119
+ * const entry = FrameSignature.from({
120
+ * payload,
121
+ * scheme: 'secp256k1',
122
+ * signature
123
+ * })
124
+ *
125
+ * FrameSignature.assert(entry, { signed: true })
126
+ * ```
127
+ *
128
+ * @param entry - The signature entry to assert.
129
+ * @param options - Validation options.
130
+ */
131
+ export function assert(
132
+ entry: FrameSignature,
133
+ options: assert.Options = {},
134
+ ): void {
135
+ const scheme =
136
+ typeof entry.scheme === 'string' ? schemes[entry.scheme] : entry.scheme
137
+ if (!Number.isInteger(scheme) || scheme < 0 || scheme > 2)
138
+ throw new InvalidError('Unsupported signature scheme.')
139
+ if (scheme === 0 && entry.signer !== undefined)
140
+ throw new InvalidError('Arbitrary signatures cannot specify a signer.')
141
+ if (entry.signer !== undefined)
142
+ Address.assert(entry.signer, { strict: false })
143
+ const payload = entry.payload ?? '0x'
144
+ Hex.assert(payload, { strict: true })
145
+ if (
146
+ payload !== '0x' &&
147
+ (payload.length !== 66 || Hex.toBigInt(payload) === 0n)
148
+ )
149
+ throw new InvalidError('payload must be empty or a nonzero 32-byte digest.')
150
+ switch (entry.scheme) {
151
+ case 0:
152
+ case 'arbitrary':
153
+ Hex.assert(entry.signature, { strict: true })
154
+ if (entry.signature.length % 2 !== 0)
155
+ throw new InvalidError('signature must contain whole bytes.')
156
+ return
157
+ }
158
+ if (entry.scheme === 2 || entry.scheme === 'p256') {
159
+ if (entry.publicKey !== undefined) {
160
+ PublicKey.assert(entry.publicKey, { compressed: false })
161
+ for (const coordinate of [entry.publicKey.x, entry.publicKey.y]) {
162
+ Hex.assert(coordinate, { strict: true })
163
+ if (coordinate === '0x' || coordinate.length > 66)
164
+ throw new InvalidError('Public key coordinates must fit in 32 bytes.')
165
+ }
166
+ }
167
+ if (entry.signature !== undefined && entry.publicKey === undefined)
168
+ throw new InvalidError('P-256 signatures require a public key.')
169
+ }
170
+ if (entry.signature === undefined) {
171
+ if (options.signed) throw new InvalidError('Signature is required.')
172
+ return
173
+ }
174
+ Hex.assert(entry.signature.r, { strict: true })
175
+ Hex.assert(entry.signature.s, { strict: true })
176
+ if (
177
+ (scheme === 1 || entry.signature.yParity !== undefined) &&
178
+ entry.signature.yParity !== 0 &&
179
+ entry.signature.yParity !== 1
180
+ )
181
+ throw new InvalidError('Signature parity must be 0 or 1.')
182
+ Signature.assert(entry.signature, { recovered: scheme === 1 })
183
+ const r = Hex.toBigInt(entry.signature.r)
184
+ const s = Hex.toBigInt(entry.signature.s)
185
+ const order = scheme === 1 ? secp256k1N : p256N
186
+ if (
187
+ r === 0n ||
188
+ r >= order ||
189
+ s === 0n ||
190
+ s >= order ||
191
+ (scheme === 1 && s > order / 2n)
192
+ )
193
+ throw new InvalidError(
194
+ 'Signature scalars must be in range; secp256k1 requires low-s.',
195
+ )
196
+ }
197
+
198
+ export declare namespace assert {
199
+ type Options = {
200
+ /**
201
+ * Require a protocol signature. Does not perform cryptographic verification.
202
+ * @default false
203
+ */
204
+ signed?: boolean | undefined
205
+ }
206
+ type ErrorType =
207
+ | InvalidError
208
+ | Address.assert.ErrorType
209
+ | Hex.assert.ErrorType
210
+ | Hex.toBigInt.ErrorType
211
+ | PublicKey.assert.ErrorType
212
+ | Signature.assert.ErrorType
213
+ | Errors.GlobalErrorType
214
+ }
215
+
216
+ /**
217
+ * Coerces a value into a {@link ox#FrameSignature.FrameSignature}.
218
+ *
219
+ * Accepts arbitrary signature bytes or a structured signature entry. Omitted
220
+ * `scheme` and `payload` default to `'arbitrary'` and `'0x'`, respectively.
221
+ * An empty payload selects the canonical transaction signing hash; an explicit
222
+ * payload must be a nonzero 32-byte digest.
223
+ *
224
+ * @example
225
+ * ### From Hex
226
+ *
227
+ * Wrap arbitrary witness bytes for contract-defined verification.
228
+ *
229
+ * ```ts twoslash
230
+ * import { FrameSignature } from 'ox'
231
+ *
232
+ * const entry = FrameSignature.from('0xaabb')
233
+ * // @log: { payload: '0x', scheme: 'arbitrary', signature: '0xaabb' }
234
+ * ```
235
+ *
236
+ * @example
237
+ * ### Secp256k1
238
+ *
239
+ * Wrap a signature over an explicit digest, retaining the same payload in the entry.
240
+ *
241
+ * ```ts twoslash
242
+ * import { FrameSignature, Hash, Secp256k1 } from 'ox'
243
+ *
244
+ * const payload = Hash.keccak256('0xdeadbeef')
245
+ * const privateKey = Secp256k1.randomPrivateKey()
246
+ * const signature = Secp256k1.sign({ payload, privateKey })
247
+ *
248
+ * const entry = FrameSignature.from({
249
+ * payload,
250
+ * scheme: 'secp256k1',
251
+ * signature
252
+ * })
253
+ * ```
254
+ *
255
+ * @example
256
+ * ### P256
257
+ *
258
+ * Include the public key with a P-256 signature over an explicit digest.
259
+ *
260
+ * ```ts twoslash
261
+ * import { FrameSignature, Hash, P256 } from 'ox'
262
+ *
263
+ * const { privateKey, publicKey } = P256.createKeyPair()
264
+ * const payload = Hash.keccak256('0xdeadbeef')
265
+ * const signature = P256.sign({ payload, privateKey })
266
+ *
267
+ * const entry = FrameSignature.from({
268
+ * payload,
269
+ * publicKey,
270
+ * scheme: 'p256',
271
+ * signature
272
+ * })
273
+ * ```
274
+ *
275
+ * @example
276
+ * ### Unsigned Entries
277
+ *
278
+ * Omit the signature to prepare a protocol entry before signing the transaction.
279
+ *
280
+ * ```ts twoslash
281
+ * import { FrameSignature } from 'ox'
282
+ *
283
+ * const entry = FrameSignature.from({ scheme: 'secp256k1' })
284
+ * // @log: { payload: '0x', scheme: 'secp256k1' }
285
+ * ```
286
+ *
287
+ * @param entry - Arbitrary signature bytes or a structured signature entry.
288
+ * @returns The validated entry, preserving supplied signature and scheme types.
289
+ */
290
+ export function from<const entry extends from.Input>(
291
+ entry: entry | from.Input,
292
+ ): from.ReturnType<entry> {
293
+ const result = (
294
+ typeof entry === 'string'
295
+ ? { payload: '0x', scheme: 'arbitrary', signature: entry }
296
+ : {
297
+ ...entry,
298
+ payload: entry.payload ?? '0x',
299
+ scheme: entry.scheme ?? 'arbitrary',
300
+ }
301
+ ) as FrameSignature
302
+ assert(result)
303
+ return result as from.ReturnType<entry>
304
+ }
305
+
306
+ export declare namespace from {
307
+ type Input =
308
+ | Hex.Hex
309
+ | UnionPartialBy<Arbitrary, 'scheme' | 'payload'>
310
+ | UnionPartialBy<Secp256k1 | P256, 'payload'>
311
+ type ReturnType<entry extends Input = Input> = entry extends Hex.Hex
312
+ ? { payload: '0x'; scheme: 'arbitrary'; signature: entry }
313
+ : entry extends Input
314
+ ? Compute<
315
+ Omit<entry, 'scheme' | 'payload'> & {
316
+ payload: entry extends { payload: infer payload extends Hex.Hex }
317
+ ? payload
318
+ : 'payload' extends keyof entry
319
+ ? Exclude<entry['payload'], undefined> | '0x'
320
+ : '0x'
321
+ scheme: entry extends { scheme: infer scheme extends Scheme }
322
+ ? scheme
323
+ : 'scheme' extends keyof entry
324
+ ? Exclude<entry['scheme'], undefined> | 'arbitrary'
325
+ : 'arbitrary'
326
+ }
327
+ >
328
+ : never
329
+ type ErrorType = assert.ErrorType
330
+ }
331
+
332
+ /**
333
+ * Converts an RPC signature entry to a structured frame signature.
334
+ *
335
+ * @example
336
+ * ### Basic Usage
337
+ *
338
+ * ```ts twoslash
339
+ * import { FrameSignature } from 'ox'
340
+ *
341
+ * const entry = FrameSignature.fromRpc({
342
+ * msg: '0x',
343
+ * scheme: 0,
344
+ * signature: '0xdeadbeef'
345
+ * })
346
+ * ```
347
+ *
348
+ * @param entry - The value to convert.
349
+ * @returns The converted value.
350
+ */
351
+ export function fromRpc(entry: Rpc): FrameSignature {
352
+ return fromTuple([
353
+ entry.scheme === 0 ? '0x' : Hex.fromNumber(entry.scheme, { size: 1 }),
354
+ entry.signer ?? '0x',
355
+ entry.msg,
356
+ entry.signature,
357
+ ])
358
+ }
359
+
360
+ export declare namespace fromRpc {
361
+ type ErrorType = fromTuple.ErrorType | Hex.fromNumber.ErrorType
362
+ }
363
+
364
+ /**
365
+ * Converts a structured frame signature to its RPC representation.
366
+ *
367
+ * @example
368
+ * ### Basic Usage
369
+ *
370
+ * ```ts twoslash
371
+ * import { FrameSignature } from 'ox'
372
+ *
373
+ * const entry = FrameSignature.from('0xdeadbeef')
374
+ * const rpc = FrameSignature.toRpc(entry)
375
+ * ```
376
+ *
377
+ * @param entry - The value to convert.
378
+ * @returns The converted value.
379
+ */
380
+ export function toRpc(entry: FrameSignature): Rpc {
381
+ const [scheme, signer, msg, signature] = toTuple(entry)
382
+ return {
383
+ msg,
384
+ scheme: (scheme === '0x' ? 0 : Hex.toNumber(scheme)) as Rpc['scheme'],
385
+ signature,
386
+ ...(signer === '0x' ? {} : { signer }),
387
+ }
388
+ }
389
+
390
+ export declare namespace toRpc {
391
+ type ErrorType = toTuple.ErrorType | Hex.toNumber.ErrorType
392
+ }
393
+
394
+ /**
395
+ * Converts a {@link ox#FrameSignature.Tuple} to a structured
396
+ * {@link ox#FrameSignature.FrameSignature}.
397
+ *
398
+ * Returns a named scheme and unpacks protocol signatures. Empty protocol signatures
399
+ * become unsigned entries. Rejects noncanonical encodings.
400
+ *
401
+ * @example
402
+ * ### Basic Usage
403
+ *
404
+ * Decode an arbitrary signature tuple.
405
+ *
406
+ * ```ts twoslash
407
+ * import { FrameSignature } from 'ox'
408
+ *
409
+ * const entry = FrameSignature.fromTuple([
410
+ * '0x',
411
+ * '0x',
412
+ * '0x',
413
+ * '0xaabb'
414
+ * ])
415
+ * // @log: { payload: '0x', scheme: 'arbitrary', signature: '0xaabb' }
416
+ * ```
417
+ *
418
+ * @param tuple - The signature tuple to convert.
419
+ * @returns The decoded signature entry.
420
+ */
421
+ export function fromTuple(tuple: Tuple): FrameSignature {
422
+ if (!Array.isArray(tuple) || tuple.length !== 4)
423
+ throw new InvalidError('Expected [scheme, signer, payload, signature].')
424
+ const [scheme, signer, payload, signature] = tuple
425
+ Hex.assert(signer, { strict: true })
426
+ Hex.assert(signature, { strict: true })
427
+ if (signature.length % 2 !== 0)
428
+ throw new InvalidError('signature must contain whole bytes.')
429
+ if (scheme !== '0x' && scheme !== '0x01' && scheme !== '0x02')
430
+ throw new InvalidError(
431
+ 'Expected a canonical scheme encoding: empty bytes, 0x01, or 0x02.',
432
+ )
433
+ const metadata = { ...(signer === '0x' ? {} : { signer }), payload }
434
+ if (scheme === '0x') {
435
+ if (signer !== '0x')
436
+ throw new InvalidError('Arbitrary signatures cannot specify a signer.')
437
+ return from({ payload, scheme: 'arbitrary', signature })
438
+ }
439
+ if (signature === '0x')
440
+ return scheme === '0x01'
441
+ ? from({ ...metadata, scheme: 'secp256k1' })
442
+ : from({ ...metadata, scheme: 'p256' })
443
+ if (Hex.size(signature) !== (scheme === '0x01' ? 65 : 128))
444
+ throw new InvalidError('Invalid protocol signature length.')
445
+ if (scheme === '0x01') {
446
+ if (Hex.toNumber(Hex.slice(signature, 0, 1)) > 1)
447
+ throw new InvalidError('Recovery parity must be 0 or 1.')
448
+ return from({
449
+ ...metadata,
450
+ scheme: 'secp256k1',
451
+ signature: Signature.fromRecoveredBytes(Hex.toBytes(signature)),
452
+ })
453
+ }
454
+ const s = Hex.slice(signature, 32, 64)
455
+ if (Hex.toBigInt(s) > p256N / 2n)
456
+ throw new InvalidError('P-256 wire signatures require low-s.')
457
+ return from({
458
+ ...metadata,
459
+ publicKey: {
460
+ prefix: 4,
461
+ x: Hex.slice(signature, 64, 96),
462
+ y: Hex.slice(signature, 96, 128),
463
+ },
464
+ scheme: 'p256',
465
+ signature: { r: Hex.slice(signature, 0, 32), s },
466
+ })
467
+ }
468
+
469
+ export declare namespace fromTuple {
470
+ type ErrorType =
471
+ | assert.ErrorType
472
+ | Hex.slice.ErrorType
473
+ | Hex.toNumber.ErrorType
474
+ | Hex.toBytes.ErrorType
475
+ | Signature.fromRecoveredBytes.ErrorType
476
+ }
477
+
478
+ /**
479
+ * Converts a {@link ox#FrameSignature.FrameSignature} to its RLP-ready
480
+ * {@link ox#FrameSignature.Tuple}.
481
+ *
482
+ * Encodes numeric scheme identifiers and packs protocol signatures without mutating
483
+ * the entry. Omitted protocol signatures become empty bytes.
484
+ *
485
+ * @example
486
+ * ### Basic Usage
487
+ *
488
+ * Encode arbitrary witness bytes with the default scheme and payload.
489
+ *
490
+ * ```ts twoslash
491
+ * import { FrameSignature } from 'ox'
492
+ *
493
+ * const entry = FrameSignature.from('0xaabb')
494
+ * const tuple = FrameSignature.toTuple(entry)
495
+ * // @log: ['0x', '0x', '0x', '0xaabb']
496
+ * ```
497
+ *
498
+ * @param entry - The signature entry to convert.
499
+ * @returns The encoded signature tuple.
500
+ */
501
+ export function toTuple(entry: FrameSignature): Tuple {
502
+ assert(entry)
503
+ const scheme =
504
+ typeof entry.scheme === 'string' ? schemes[entry.scheme] : entry.scheme
505
+ const signature = (() => {
506
+ switch (entry.scheme) {
507
+ case 0:
508
+ case 'arbitrary':
509
+ return entry.signature
510
+ case 1:
511
+ case 'secp256k1':
512
+ return entry.signature === undefined
513
+ ? '0x'
514
+ : Hex.fromBytes(Signature.toRecoveredBytes(entry.signature))
515
+ case 2:
516
+ case 'p256': {
517
+ if (entry.signature === undefined) return '0x'
518
+ const { publicKey, signature } = entry
519
+ const s = Hex.toBigInt(signature.s)
520
+ return Hex.concat(
521
+ Hex.fromNumber(Hex.toBigInt(signature.r), { size: 32 }),
522
+ Hex.fromNumber(s > p256N / 2n ? p256N - s : s, { size: 32 }),
523
+ Hex.fromNumber(Hex.toBigInt(publicKey.x), { size: 32 }),
524
+ Hex.fromNumber(Hex.toBigInt(publicKey.y), { size: 32 }),
525
+ )
526
+ }
527
+ }
528
+ })()
529
+ return [
530
+ scheme ? Hex.fromNumber(scheme, { size: 1 }) : '0x',
531
+ entry.signer ?? '0x',
532
+ entry.payload ?? '0x',
533
+ signature,
534
+ ]
535
+ }
536
+
537
+ export declare namespace toTuple {
538
+ type ErrorType =
539
+ | assert.ErrorType
540
+ | Hex.fromNumber.ErrorType
541
+ | Hex.fromBytes.ErrorType
542
+ | Hex.concat.ErrorType
543
+ | Signature.toRecoveredBytes.ErrorType
544
+ }
545
+
546
+ /**
547
+ * Returns whether a {@link ox#FrameSignature.FrameSignature} is structurally valid.
548
+ *
549
+ * Performs the same checks as {@link ox#FrameSignature.(assert:function)}, returning
550
+ * `false` instead of throwing. Does not verify that the signature authorizes a payload.
551
+ *
552
+ * @example
553
+ * ### Basic Usage
554
+ *
555
+ * Require a signature when checking a protocol entry.
556
+ *
557
+ * ```ts twoslash
558
+ * import { FrameSignature } from 'ox'
559
+ *
560
+ * const entry = FrameSignature.from({ scheme: 'secp256k1' })
561
+ * const valid = FrameSignature.validate(entry, {
562
+ * signed: true
563
+ * })
564
+ * // @log: false
565
+ * ```
566
+ *
567
+ * @param entry - The signature entry to validate.
568
+ * @param options - Validation options.
569
+ * @returns Whether the entry is structurally valid.
570
+ */
571
+ export function validate(
572
+ entry: FrameSignature,
573
+ options: assert.Options = {},
574
+ ): boolean {
575
+ try {
576
+ assert(entry, options)
577
+ return true
578
+ } catch {
579
+ return false
580
+ }
581
+ }
582
+
583
+ export declare namespace validate {
584
+ type ErrorType = Errors.GlobalErrorType
585
+ }
586
+
587
+ /** Thrown when frame signature metadata or encoding is invalid. */
588
+ export class InvalidError extends Errors.BaseError {
589
+ override readonly name = 'FrameSignature.InvalidError'
590
+ constructor(details: string) {
591
+ super('Invalid frame signature.', { details })
592
+ }
593
+ }
@@ -564,13 +564,16 @@ export declare namespace toBytes {
564
564
  */
565
565
  export function toCompactBytes(signature: Signature<boolean>): Bytes.Bytes {
566
566
  const bytes = new Uint8Array(64)
567
- bytes.set(Bytes.fromHex(signature.r, { size: 32 }), 0)
568
- bytes.set(Bytes.fromHex(signature.s, { size: 32 }), 32)
567
+ bytes.set(Bytes.fromHex(Hex.padLeft(signature.r, 32)), 0)
568
+ bytes.set(Bytes.fromHex(Hex.padLeft(signature.s, 32)), 32)
569
569
  return bytes
570
570
  }
571
571
 
572
572
  export declare namespace toCompactBytes {
573
- type ErrorType = Bytes.fromHex.ErrorType | Errors.GlobalErrorType
573
+ type ErrorType =
574
+ | Hex.padLeft.ErrorType
575
+ | Bytes.fromHex.ErrorType
576
+ | Errors.GlobalErrorType
574
577
  }
575
578
 
576
579
  /**
@@ -591,6 +594,8 @@ export declare namespace toCompactBytes {
591
594
  * @returns The decoded {@link ox#Signature.Signature}.
592
595
  */
593
596
  export function fromCompactBytes(bytes: Bytes.Bytes): Signature<false> {
597
+ if (bytes.length !== 64)
598
+ throw new InvalidSerializedSizeError({ expectedSize: 64, signature: bytes })
594
599
  return {
595
600
  r: Hex.fromBytes(bytes.subarray(0, 32)),
596
601
  s: Hex.fromBytes(bytes.subarray(32, 64)),
@@ -598,7 +603,10 @@ export function fromCompactBytes(bytes: Bytes.Bytes): Signature<false> {
598
603
  }
599
604
 
600
605
  export declare namespace fromCompactBytes {
601
- type ErrorType = Hex.fromBytes.ErrorType | Errors.GlobalErrorType
606
+ type ErrorType =
607
+ | Hex.fromBytes.ErrorType
608
+ | InvalidSerializedSizeError
609
+ | Errors.GlobalErrorType
602
610
  }
603
611
 
604
612
  /**
@@ -621,15 +629,20 @@ export declare namespace fromCompactBytes {
621
629
  * @returns The 65-byte recovered representation.
622
630
  */
623
631
  export function toRecoveredBytes(signature: Signature): Bytes.Bytes {
632
+ assert(signature, { recovered: true })
624
633
  const bytes = new Uint8Array(65)
625
634
  bytes[0] = signature.yParity
626
- bytes.set(Bytes.fromHex(signature.r, { size: 32 }), 1)
627
- bytes.set(Bytes.fromHex(signature.s, { size: 32 }), 33)
635
+ bytes.set(Bytes.fromHex(Hex.padLeft(signature.r, 32)), 1)
636
+ bytes.set(Bytes.fromHex(Hex.padLeft(signature.s, 32)), 33)
628
637
  return bytes
629
638
  }
630
639
 
631
640
  export declare namespace toRecoveredBytes {
632
- type ErrorType = Bytes.fromNumber.ErrorType | Errors.GlobalErrorType
641
+ type ErrorType =
642
+ | assert.ErrorType
643
+ | Hex.padLeft.ErrorType
644
+ | Bytes.fromHex.ErrorType
645
+ | Errors.GlobalErrorType
633
646
  }
634
647
 
635
648
  /**
@@ -650,15 +663,24 @@ export declare namespace toRecoveredBytes {
650
663
  * @returns The decoded {@link ox#Signature.Signature}.
651
664
  */
652
665
  export function fromRecoveredBytes(bytes: Bytes.Bytes): Signature {
666
+ if (bytes.length !== 65)
667
+ throw new InvalidSerializedSizeError({ expectedSize: 65, signature: bytes })
668
+ const yParity = bytes[0]!
669
+ if (yParity !== 0 && yParity !== 1)
670
+ throw new InvalidYParityError({ value: yParity })
653
671
  return {
654
672
  r: Hex.fromBytes(bytes.subarray(1, 33)),
655
673
  s: Hex.fromBytes(bytes.subarray(33, 65)),
656
- yParity: bytes[0]!,
674
+ yParity,
657
675
  }
658
676
  }
659
677
 
660
678
  export declare namespace fromRecoveredBytes {
661
- type ErrorType = Hex.fromBytes.ErrorType | Errors.GlobalErrorType
679
+ type ErrorType =
680
+ | Hex.fromBytes.ErrorType
681
+ | InvalidSerializedSizeError
682
+ | InvalidYParityError
683
+ | Errors.GlobalErrorType
662
684
  }
663
685
 
664
686
  /**
@@ -945,10 +967,18 @@ export declare namespace yParityToV {
945
967
  export class InvalidSerializedSizeError extends Errors.BaseError {
946
968
  override readonly name = 'Signature.InvalidSerializedSizeError'
947
969
 
948
- constructor({ signature }: { signature: Hex.Hex | Bytes.Bytes }) {
970
+ constructor({
971
+ expectedSize,
972
+ signature,
973
+ }: {
974
+ expectedSize?: number | undefined
975
+ signature: Hex.Hex | Bytes.Bytes
976
+ }) {
949
977
  super(`Value \`${signature}\` is an invalid signature size.`, {
950
978
  metaMessages: [
951
- 'Expected: 64 bytes or 65 bytes.',
979
+ typeof expectedSize === 'number'
980
+ ? `Expected: ${expectedSize} bytes.`
981
+ : 'Expected: 64 bytes or 65 bytes.',
952
982
  `Received ${Hex.size(Hex.from(signature))} bytes.`,
953
983
  ],
954
984
  })