ox 0.14.26 → 0.14.28

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 (40) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/_cjs/tempo/MultisigConfig.js +127 -0
  3. package/_cjs/tempo/MultisigConfig.js.map +1 -0
  4. package/_cjs/tempo/ReceivePolicyReceipt.js +80 -0
  5. package/_cjs/tempo/ReceivePolicyReceipt.js.map +1 -0
  6. package/_cjs/tempo/SignatureEnvelope.js +107 -6
  7. package/_cjs/tempo/SignatureEnvelope.js.map +1 -1
  8. package/_cjs/tempo/index.js +3 -1
  9. package/_cjs/tempo/index.js.map +1 -1
  10. package/_cjs/version.js +1 -1
  11. package/_esm/tempo/MultisigConfig.js +312 -0
  12. package/_esm/tempo/MultisigConfig.js.map +1 -0
  13. package/_esm/tempo/ReceivePolicyReceipt.js +176 -0
  14. package/_esm/tempo/ReceivePolicyReceipt.js.map +1 -0
  15. package/_esm/tempo/SignatureEnvelope.js +170 -6
  16. package/_esm/tempo/SignatureEnvelope.js.map +1 -1
  17. package/_esm/tempo/index.js +48 -0
  18. package/_esm/tempo/index.js.map +1 -1
  19. package/_esm/version.js +1 -1
  20. package/_types/tempo/MultisigConfig.d.ts +270 -0
  21. package/_types/tempo/MultisigConfig.d.ts.map +1 -0
  22. package/_types/tempo/ReceivePolicyReceipt.d.ts +168 -0
  23. package/_types/tempo/ReceivePolicyReceipt.d.ts.map +1 -0
  24. package/_types/tempo/SignatureEnvelope.d.ts +106 -6
  25. package/_types/tempo/SignatureEnvelope.d.ts.map +1 -1
  26. package/_types/tempo/index.d.ts +48 -0
  27. package/_types/tempo/index.d.ts.map +1 -1
  28. package/_types/version.d.ts +1 -1
  29. package/package.json +11 -1
  30. package/tempo/MultisigConfig/package.json +6 -0
  31. package/tempo/MultisigConfig.test.ts +227 -0
  32. package/tempo/MultisigConfig.ts +423 -0
  33. package/tempo/ReceivePolicyReceipt/package.json +6 -0
  34. package/tempo/ReceivePolicyReceipt.test.ts +198 -0
  35. package/tempo/ReceivePolicyReceipt.ts +263 -0
  36. package/tempo/SignatureEnvelope.test.ts +213 -2
  37. package/tempo/SignatureEnvelope.ts +257 -9
  38. package/tempo/e2e.test.ts +217 -0
  39. package/tempo/index.ts +48 -0
  40. package/version.ts +1 -1
@@ -100,6 +100,32 @@ export * as Channel from './Channel.js';
100
100
  * @category Reference
101
101
  */
102
102
  export * as KeyAuthorization from './KeyAuthorization.js';
103
+ /**
104
+ * Native multisig account utilities (TIP-1061).
105
+ *
106
+ * Derives stable multisig account addresses and permanent config IDs from a weighted
107
+ * owner configuration, and computes the owner approval digest that owners sign.
108
+ *
109
+ * [TIP-1061](https://tips.sh/1061)
110
+ *
111
+ * @example
112
+ * ```ts twoslash
113
+ * import { MultisigConfig } from 'ox/tempo'
114
+ *
115
+ * const config = MultisigConfig.from({
116
+ * threshold: 2,
117
+ * owners: [
118
+ * { owner: '0x1111111111111111111111111111111111111111', weight: 1 },
119
+ * { owner: '0x2222222222222222222222222222222222222222', weight: 1 },
120
+ * ],
121
+ * })
122
+ *
123
+ * const account = MultisigConfig.getAddress({ config })
124
+ * ```
125
+ *
126
+ * @category Reference
127
+ */
128
+ export * as MultisigConfig from './MultisigConfig.js';
103
129
  /**
104
130
  * Utilities for constructing period durations (in seconds) for recurring spending limits.
105
131
  *
@@ -150,6 +176,28 @@ export * as Period from './Period.js';
150
176
  * @category Reference
151
177
  */
152
178
  export * as PoolId from './PoolId.js';
179
+ /**
180
+ * TIP-1028 receive-policy claim receipt utilities.
181
+ *
182
+ * When an inbound transfer or mint violates the recipient's receive policy, the
183
+ * funds are redirected to the `ReceivePolicyGuard` and a `ClaimReceiptV1`
184
+ * witness is emitted. This module decodes those witnesses (required to later
185
+ * `claim` or `burn` the blocked funds) from raw bytes or transaction receipts.
186
+ *
187
+ * [TIP-1028](https://docs.tempo.xyz/protocol/tips/tip-1028)
188
+ *
189
+ * @example
190
+ * ```ts twoslash
191
+ * // @noErrors
192
+ * import { ReceivePolicyReceipt } from 'ox/tempo'
193
+ *
194
+ * const receipts = ReceivePolicyReceipt.fromTransactionReceipt(receipt)
195
+ * const decoded = ReceivePolicyReceipt.decode('0x...')
196
+ * ```
197
+ *
198
+ * @category Reference
199
+ */
200
+ export * as ReceivePolicyReceipt from './ReceivePolicyReceipt.js';
153
201
  /**
154
202
  * Union of all JSON-RPC Methods for the `tempo_` namespace.
155
203
  *
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../tempo/index.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAEhC,YAAY,EAAE,CAAA;AAEd;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,OAAO,KAAK,kBAAkB,MAAM,yBAAyB,CAAA;AAC7D;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,OAAO,KAAK,gBAAgB,MAAM,uBAAuB,CAAA;AACzD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AAErC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAA;AAErD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,iBAAiB,MAAM,wBAAwB,CAAA;AAC3D;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AACjD;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AACjC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAA;AAC/C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,kBAAkB,MAAM,yBAAyB,CAAA;AAC7D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,kBAAkB,MAAM,yBAAyB,CAAA;AAC7D;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,KAAK,eAAe,MAAM,sBAAsB,CAAA;AACvD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAA;AACrD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,KAAK,aAAa,MAAM,oBAAoB,CAAA;AAEnD;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,OAAO,KAAK,qBAAqB,MAAM,4BAA4B,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../tempo/index.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAEhC,YAAY,EAAE,CAAA;AAEd;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,OAAO,KAAK,kBAAkB,MAAM,yBAAyB,CAAA;AAC7D;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,OAAO,KAAK,gBAAgB,MAAM,uBAAuB,CAAA;AACzD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAA;AACrD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AAErC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,oBAAoB,MAAM,2BAA2B,CAAA;AACjE;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAA;AAErD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,iBAAiB,MAAM,wBAAwB,CAAA;AAC3D;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AACjD;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AACjC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AACvC;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAC3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAA;AAC/C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,kBAAkB,MAAM,yBAAyB,CAAA;AAC7D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,kBAAkB,MAAM,yBAAyB,CAAA;AAC7D;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,KAAK,eAAe,MAAM,sBAAsB,CAAA;AACvD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAA;AACrD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,KAAK,aAAa,MAAM,oBAAoB,CAAA;AAEnD;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,OAAO,KAAK,qBAAqB,MAAM,4BAA4B,CAAA"}
@@ -1,3 +1,3 @@
1
1
  /** @internal */
2
- export declare const version = "0.14.26";
2
+ export declare const version = "0.14.28";
3
3
  //# sourceMappingURL=version.d.ts.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ox",
3
3
  "description": "Ethereum Standard Library",
4
- "version": "0.14.26",
4
+ "version": "0.14.28",
5
5
  "main": "./_cjs/index.js",
6
6
  "module": "./_esm/index.js",
7
7
  "types": "./_types/index.d.ts",
@@ -513,6 +513,11 @@
513
513
  "import": "./_esm/tempo/KeyAuthorization.js",
514
514
  "default": "./_cjs/tempo/KeyAuthorization.js"
515
515
  },
516
+ "./tempo/MultisigConfig": {
517
+ "types": "./_types/tempo/MultisigConfig.d.ts",
518
+ "import": "./_esm/tempo/MultisigConfig.js",
519
+ "default": "./_cjs/tempo/MultisigConfig.js"
520
+ },
516
521
  "./tempo/Period": {
517
522
  "types": "./_types/tempo/Period.d.ts",
518
523
  "import": "./_esm/tempo/Period.js",
@@ -523,6 +528,11 @@
523
528
  "import": "./_esm/tempo/PoolId.js",
524
529
  "default": "./_cjs/tempo/PoolId.js"
525
530
  },
531
+ "./tempo/ReceivePolicyReceipt": {
532
+ "types": "./_types/tempo/ReceivePolicyReceipt.d.ts",
533
+ "import": "./_esm/tempo/ReceivePolicyReceipt.js",
534
+ "default": "./_cjs/tempo/ReceivePolicyReceipt.js"
535
+ },
526
536
  "./tempo/RpcSchemaTempo": {
527
537
  "types": "./_types/tempo/RpcSchemaTempo.d.ts",
528
538
  "import": "./_esm/tempo/RpcSchemaTempo.js",
@@ -0,0 +1,6 @@
1
+ {
2
+ "type": "module",
3
+ "types": "../../_types/tempo/MultisigConfig.d.ts",
4
+ "main": "../../_cjs/tempo/MultisigConfig.js",
5
+ "module": "../../_esm/tempo/MultisigConfig.js"
6
+ }
@@ -0,0 +1,227 @@
1
+ import { MultisigConfig } from 'ox/tempo'
2
+ import { describe, expect, test } from 'vitest'
3
+
4
+ // Ground-truth vectors independently computed via `cast keccak` over the exact
5
+ // preimages defined by TIP-1061 / the Tempo reference implementation.
6
+ const owner1 = '0x1111111111111111111111111111111111111111'
7
+ const owner2 = '0x2222222222222222222222222222222222222222'
8
+
9
+ const singleOwnerConfig = {
10
+ threshold: 1,
11
+ owners: [{ owner: owner1, weight: 1 }],
12
+ } as const
13
+
14
+ describe('from', () => {
15
+ test('sorts owners ascending by address', () => {
16
+ const config = MultisigConfig.from({
17
+ threshold: 2,
18
+ owners: [
19
+ { owner: owner2, weight: 1 },
20
+ { owner: owner1, weight: 1 },
21
+ ],
22
+ })
23
+ expect(config.owners.map((o) => o.owner)).toEqual([owner1, owner2])
24
+ })
25
+
26
+ test('asserts validity', () => {
27
+ expect(() =>
28
+ MultisigConfig.from({ threshold: 0, owners: [] }),
29
+ ).toThrowError()
30
+ })
31
+ })
32
+
33
+ describe('configId', () => {
34
+ test('matches independent ground truth', () => {
35
+ expect(MultisigConfig.toId(singleOwnerConfig)).toMatchInlineSnapshot(
36
+ `"0xd1f20e1a5bfdd89488f57f68db5bd1aae9a51b510f4a042b2604b57a0b7b471d"`,
37
+ )
38
+ })
39
+
40
+ test('is stable across calls', () => {
41
+ expect(MultisigConfig.toId(singleOwnerConfig)).toBe(
42
+ MultisigConfig.toId(singleOwnerConfig),
43
+ )
44
+ })
45
+
46
+ test('differs for a different salt', () => {
47
+ expect(MultisigConfig.toId(singleOwnerConfig)).not.toBe(
48
+ MultisigConfig.toId({
49
+ ...singleOwnerConfig,
50
+ salt: `0x${'42'.repeat(32)}`,
51
+ }),
52
+ )
53
+ })
54
+
55
+ test('throws on invalid config', () => {
56
+ expect(() =>
57
+ MultisigConfig.toId({
58
+ threshold: 5,
59
+ owners: singleOwnerConfig.owners,
60
+ }),
61
+ ).toThrowError()
62
+ })
63
+ })
64
+
65
+ describe('getAddress', () => {
66
+ test('matches independent ground truth', () => {
67
+ expect(
68
+ MultisigConfig.getAddress({ config: singleOwnerConfig }),
69
+ ).toMatchInlineSnapshot(`"0x6ca655065b1de473d903eebd50e5cb4996e10468"`)
70
+ })
71
+
72
+ test('derives from config or configId identically', () => {
73
+ const configId = MultisigConfig.toId(singleOwnerConfig)
74
+ expect(MultisigConfig.getAddress({ configId })).toBe(
75
+ MultisigConfig.getAddress({ config: singleOwnerConfig }),
76
+ )
77
+ })
78
+
79
+ test('config ID and address are chain-independent', () => {
80
+ // Derivation does not include chain ID; identical config → identical id/address.
81
+ const a = MultisigConfig.toId(singleOwnerConfig)
82
+ const b = MultisigConfig.toId(MultisigConfig.from(singleOwnerConfig))
83
+ expect(a).toBe(b)
84
+ })
85
+ })
86
+
87
+ describe('getSignPayload', () => {
88
+ test('matches independent ground truth', () => {
89
+ const configId = MultisigConfig.toId(singleOwnerConfig)
90
+ const account = MultisigConfig.getAddress({ configId })
91
+ expect(
92
+ MultisigConfig.getSignPayload({
93
+ payload: `0x${'42'.repeat(32)}`,
94
+ account,
95
+ configId,
96
+ }),
97
+ ).toMatchInlineSnapshot(
98
+ `"0xe3d66f6118b89a67c71c8137c46abf0c829056a46ee6a038a1b42c84529fc17e"`,
99
+ )
100
+ })
101
+ })
102
+
103
+ describe('toTuple / fromTuple', () => {
104
+ test('round-trips', () => {
105
+ const config = MultisigConfig.from({
106
+ threshold: 3,
107
+ owners: [
108
+ { owner: owner1, weight: 1 },
109
+ { owner: owner2, weight: 2 },
110
+ ],
111
+ })
112
+ const tuple = MultisigConfig.toTuple(config)
113
+ expect(MultisigConfig.fromTuple(tuple)).toEqual(config)
114
+ })
115
+
116
+ test('encodes each owner as `[owner, weight]`', () => {
117
+ const [, , owners] = MultisigConfig.toTuple(singleOwnerConfig)
118
+ expect(owners[0]).toEqual([owner1, '0x1'])
119
+ })
120
+
121
+ test('encodes salt as a full 32-byte string (first element)', () => {
122
+ const [salt] = MultisigConfig.toTuple(singleOwnerConfig)
123
+ expect(salt).toBe(MultisigConfig.zeroSalt)
124
+ })
125
+
126
+ test('round-trips a non-zero salt', () => {
127
+ const config = MultisigConfig.from({
128
+ ...singleOwnerConfig,
129
+ salt: `0x${'42'.repeat(32)}`,
130
+ })
131
+ const tuple = MultisigConfig.toTuple(config)
132
+ expect(tuple[0]).toBe(`0x${'42'.repeat(32)}`)
133
+ expect(MultisigConfig.fromTuple(tuple)).toEqual(config)
134
+ })
135
+ })
136
+
137
+ describe('assert / validate', () => {
138
+ test('valid config', () => {
139
+ expect(MultisigConfig.validate(singleOwnerConfig)).toBe(true)
140
+ })
141
+
142
+ test('empty owners', () => {
143
+ expect(MultisigConfig.validate({ threshold: 1, owners: [] })).toBe(false)
144
+ })
145
+
146
+ test('too many owners', () => {
147
+ const owners = Array.from({ length: 11 }, (_, i) => ({
148
+ owner: `0x${(i + 1).toString(16).padStart(40, '0')}` as `0x${string}`,
149
+ weight: 1,
150
+ }))
151
+ expect(MultisigConfig.validate({ threshold: 1, owners })).toBe(false)
152
+ })
153
+
154
+ test('zero threshold', () => {
155
+ expect(
156
+ MultisigConfig.validate({
157
+ threshold: 0,
158
+ owners: singleOwnerConfig.owners,
159
+ }),
160
+ ).toBe(false)
161
+ })
162
+
163
+ test('threshold exceeds total weight', () => {
164
+ expect(
165
+ MultisigConfig.validate({
166
+ threshold: 2,
167
+ owners: singleOwnerConfig.owners,
168
+ }),
169
+ ).toBe(false)
170
+ })
171
+
172
+ test('zero owner weight', () => {
173
+ expect(
174
+ MultisigConfig.validate({
175
+ threshold: 1,
176
+ owners: [{ owner: owner1, weight: 0 }],
177
+ }),
178
+ ).toBe(false)
179
+ })
180
+
181
+ test('zero owner address', () => {
182
+ expect(
183
+ MultisigConfig.validate({
184
+ threshold: 1,
185
+ owners: [
186
+ {
187
+ owner: '0x0000000000000000000000000000000000000000',
188
+ weight: 1,
189
+ },
190
+ ],
191
+ }),
192
+ ).toBe(false)
193
+ })
194
+
195
+ test('unsorted owners', () => {
196
+ expect(
197
+ MultisigConfig.validate({
198
+ threshold: 1,
199
+ owners: [
200
+ { owner: owner2, weight: 1 },
201
+ { owner: owner1, weight: 1 },
202
+ ],
203
+ }),
204
+ ).toBe(false)
205
+ })
206
+
207
+ test('duplicate owners', () => {
208
+ expect(
209
+ MultisigConfig.validate({
210
+ threshold: 1,
211
+ owners: [
212
+ { owner: owner1, weight: 1 },
213
+ { owner: owner1, weight: 1 },
214
+ ],
215
+ }),
216
+ ).toBe(false)
217
+ })
218
+
219
+ test('invalid salt size', () => {
220
+ expect(
221
+ MultisigConfig.validate({
222
+ ...singleOwnerConfig,
223
+ salt: '0x42',
224
+ }),
225
+ ).toBe(false)
226
+ })
227
+ })