ox 0.14.24 → 0.14.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/_cjs/tempo/Channel.js +31 -11
- package/_cjs/tempo/Channel.js.map +1 -1
- package/_cjs/tempo/KeyAuthorization.js +130 -57
- package/_cjs/tempo/KeyAuthorization.js.map +1 -1
- package/_cjs/tempo/index.js +1 -2
- package/_cjs/tempo/index.js.map +1 -1
- package/_cjs/version.js +1 -1
- package/_esm/tempo/Channel.js +56 -13
- package/_esm/tempo/Channel.js.map +1 -1
- package/_esm/tempo/KeyAuthorization.js +155 -62
- package/_esm/tempo/KeyAuthorization.js.map +1 -1
- package/_esm/tempo/index.js +9 -30
- package/_esm/tempo/index.js.map +1 -1
- package/_esm/version.js +1 -1
- package/_types/tempo/Channel.d.ts +73 -8
- package/_types/tempo/Channel.d.ts.map +1 -1
- package/_types/tempo/KeyAuthorization.d.ts +54 -2
- package/_types/tempo/KeyAuthorization.d.ts.map +1 -1
- package/_types/tempo/index.d.ts +9 -30
- package/_types/tempo/index.d.ts.map +1 -1
- package/_types/version.d.ts +1 -1
- package/package.json +2 -8
- package/tempo/Channel.test.ts +99 -16
- package/tempo/Channel.ts +127 -18
- package/tempo/KeyAuthorization.test.ts +333 -0
- package/tempo/KeyAuthorization.ts +240 -72
- package/tempo/e2e.test.ts +330 -0
- package/tempo/index.ts +9 -30
- package/version.ts +1 -1
- package/_cjs/tempo/ChannelDescriptor.js +0 -24
- package/_cjs/tempo/ChannelDescriptor.js.map +0 -1
- package/_esm/tempo/ChannelDescriptor.js +0 -43
- package/_esm/tempo/ChannelDescriptor.js.map +0 -1
- package/_types/tempo/ChannelDescriptor.d.ts +0 -73
- package/_types/tempo/ChannelDescriptor.d.ts.map +0 -1
- package/tempo/ChannelDescriptor/package.json +0 -6
- package/tempo/ChannelDescriptor.test.ts +0 -93
- package/tempo/ChannelDescriptor.ts +0 -115
|
@@ -2133,3 +2133,336 @@ describe('toTuple', () => {
|
|
|
2133
2133
|
])
|
|
2134
2134
|
})
|
|
2135
2135
|
})
|
|
2136
|
+
|
|
2137
|
+
describe('witness (TIP-1053)', () => {
|
|
2138
|
+
const witness =
|
|
2139
|
+
'0x1111111111111111111111111111111111111111111111111111111111111111' as const
|
|
2140
|
+
const witness_other =
|
|
2141
|
+
'0x2222222222222222222222222222222222222222222222222222222222222222' as const
|
|
2142
|
+
|
|
2143
|
+
test('from: preserves witness', () => {
|
|
2144
|
+
const authorization = KeyAuthorization.from({
|
|
2145
|
+
address,
|
|
2146
|
+
chainId: 1n,
|
|
2147
|
+
type: 'secp256k1',
|
|
2148
|
+
witness,
|
|
2149
|
+
})
|
|
2150
|
+
expect(authorization.witness).toBe(witness)
|
|
2151
|
+
})
|
|
2152
|
+
|
|
2153
|
+
test('from: throws on non-32-byte witness', () => {
|
|
2154
|
+
expect(() =>
|
|
2155
|
+
KeyAuthorization.from({
|
|
2156
|
+
address,
|
|
2157
|
+
chainId: 1n,
|
|
2158
|
+
type: 'secp256k1',
|
|
2159
|
+
witness: '0xdeadbeef',
|
|
2160
|
+
}),
|
|
2161
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
2162
|
+
`[KeyAuthorization.InvalidWitnessSizeError: Witness \`0xdeadbeef\` must be exactly 32 bytes (got 4 bytes).]`,
|
|
2163
|
+
)
|
|
2164
|
+
})
|
|
2165
|
+
|
|
2166
|
+
test('toTuple: appends witness as trailing field with defaulted earlier fields', () => {
|
|
2167
|
+
const authorization = KeyAuthorization.from({
|
|
2168
|
+
address,
|
|
2169
|
+
chainId: 1n,
|
|
2170
|
+
type: 'secp256k1',
|
|
2171
|
+
witness,
|
|
2172
|
+
})
|
|
2173
|
+
const [authTuple] = KeyAuthorization.toTuple(authorization)
|
|
2174
|
+
expect(authTuple).toEqual([
|
|
2175
|
+
'0x1', // chainId
|
|
2176
|
+
'0x', // keyType (secp256k1)
|
|
2177
|
+
address,
|
|
2178
|
+
'0x', // expiry default (never expires)
|
|
2179
|
+
'0x', // limits absent (RLP null placeholder)
|
|
2180
|
+
'0x', // scopes absent (RLP null placeholder)
|
|
2181
|
+
witness,
|
|
2182
|
+
])
|
|
2183
|
+
})
|
|
2184
|
+
|
|
2185
|
+
test('toTuple: omits witness when absent (byte-equivalent to pre-TIP-1053)', () => {
|
|
2186
|
+
const withoutWitness = KeyAuthorization.from({
|
|
2187
|
+
address,
|
|
2188
|
+
chainId: 1n,
|
|
2189
|
+
type: 'secp256k1',
|
|
2190
|
+
})
|
|
2191
|
+
const [authTuple] = KeyAuthorization.toTuple(withoutWitness)
|
|
2192
|
+
expect((authTuple as unknown as unknown[]).length).toBe(3)
|
|
2193
|
+
})
|
|
2194
|
+
|
|
2195
|
+
test('serialize/deserialize: roundtrip with witness only', () => {
|
|
2196
|
+
const authorization = KeyAuthorization.from({
|
|
2197
|
+
address,
|
|
2198
|
+
chainId: 1n,
|
|
2199
|
+
type: 'secp256k1',
|
|
2200
|
+
witness,
|
|
2201
|
+
})
|
|
2202
|
+
const serialized = KeyAuthorization.serialize(authorization)
|
|
2203
|
+
const restored = KeyAuthorization.deserialize(serialized)
|
|
2204
|
+
expect(restored.witness).toBe(witness)
|
|
2205
|
+
expect(restored.expiry).toBeUndefined()
|
|
2206
|
+
expect(restored.limits).toBeUndefined()
|
|
2207
|
+
expect(restored.scopes).toBeUndefined()
|
|
2208
|
+
})
|
|
2209
|
+
|
|
2210
|
+
test('serialize/deserialize: roundtrip with witness + expiry + limits + scopes', () => {
|
|
2211
|
+
const authorization = KeyAuthorization.from({
|
|
2212
|
+
address,
|
|
2213
|
+
chainId: 1n,
|
|
2214
|
+
expiry,
|
|
2215
|
+
type: 'secp256k1',
|
|
2216
|
+
limits: [{ token, limit: Value.from('10', 6) }],
|
|
2217
|
+
scopes: [
|
|
2218
|
+
{
|
|
2219
|
+
address: token,
|
|
2220
|
+
selector: '0xa9059cbb',
|
|
2221
|
+
recipients: ['0x1111111111111111111111111111111111111111'],
|
|
2222
|
+
},
|
|
2223
|
+
],
|
|
2224
|
+
witness,
|
|
2225
|
+
})
|
|
2226
|
+
const serialized = KeyAuthorization.serialize(authorization)
|
|
2227
|
+
const restored = KeyAuthorization.deserialize(serialized)
|
|
2228
|
+
expect(restored.witness).toBe(witness)
|
|
2229
|
+
expect(restored.expiry).toBe(expiry)
|
|
2230
|
+
expect(restored.limits?.[0]?.limit).toBe(10000000n)
|
|
2231
|
+
expect(restored.scopes?.[0]?.selector).toBe('0xa9059cbb')
|
|
2232
|
+
})
|
|
2233
|
+
|
|
2234
|
+
test('toRpc/fromRpc: roundtrip with witness', () => {
|
|
2235
|
+
const authorization = KeyAuthorization.from(
|
|
2236
|
+
{
|
|
2237
|
+
address,
|
|
2238
|
+
chainId: 1n,
|
|
2239
|
+
type: 'secp256k1',
|
|
2240
|
+
witness,
|
|
2241
|
+
},
|
|
2242
|
+
{ signature: SignatureEnvelope.from(signature_secp256k1) },
|
|
2243
|
+
)
|
|
2244
|
+
const rpc = KeyAuthorization.toRpc(authorization)
|
|
2245
|
+
expect(rpc.witness).toBe(witness)
|
|
2246
|
+
const restored = KeyAuthorization.fromRpc(rpc)
|
|
2247
|
+
expect(restored.witness).toBe(witness)
|
|
2248
|
+
})
|
|
2249
|
+
|
|
2250
|
+
test('hash: changes when witness changes', () => {
|
|
2251
|
+
const a = KeyAuthorization.from({
|
|
2252
|
+
address,
|
|
2253
|
+
chainId: 1n,
|
|
2254
|
+
type: 'secp256k1',
|
|
2255
|
+
witness,
|
|
2256
|
+
})
|
|
2257
|
+
const b = KeyAuthorization.from({
|
|
2258
|
+
address,
|
|
2259
|
+
chainId: 1n,
|
|
2260
|
+
type: 'secp256k1',
|
|
2261
|
+
witness: witness_other,
|
|
2262
|
+
})
|
|
2263
|
+
expect(KeyAuthorization.hash(a)).not.toBe(KeyAuthorization.hash(b))
|
|
2264
|
+
})
|
|
2265
|
+
|
|
2266
|
+
test('hash: witness-less encoding matches pre-TIP-1053 hash', () => {
|
|
2267
|
+
const before = KeyAuthorization.from({
|
|
2268
|
+
address,
|
|
2269
|
+
chainId: 1n,
|
|
2270
|
+
type: 'secp256k1',
|
|
2271
|
+
})
|
|
2272
|
+
// Re-create the same auth (no witness field). Hash must be identical.
|
|
2273
|
+
const again = KeyAuthorization.from({
|
|
2274
|
+
address,
|
|
2275
|
+
chainId: 1n,
|
|
2276
|
+
type: 'secp256k1',
|
|
2277
|
+
})
|
|
2278
|
+
expect(KeyAuthorization.hash(before)).toBe(KeyAuthorization.hash(again))
|
|
2279
|
+
})
|
|
2280
|
+
|
|
2281
|
+
test('fromTuple: extracts trailing witness', () => {
|
|
2282
|
+
const restored = KeyAuthorization.fromTuple([
|
|
2283
|
+
['0x01', '0x', address, '0x', [], [], witness],
|
|
2284
|
+
])
|
|
2285
|
+
expect(restored.witness).toBe(witness)
|
|
2286
|
+
})
|
|
2287
|
+
|
|
2288
|
+
test('fromTuple: throws on non-32-byte witness', () => {
|
|
2289
|
+
expect(() =>
|
|
2290
|
+
KeyAuthorization.fromTuple([
|
|
2291
|
+
['0x01', '0x', address, '0x', [], [], '0xdeadbeef'],
|
|
2292
|
+
]),
|
|
2293
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
2294
|
+
`[KeyAuthorization.InvalidWitnessSizeError: Witness \`0xdeadbeef\` must be exactly 32 bytes (got 4 bytes).]`,
|
|
2295
|
+
)
|
|
2296
|
+
})
|
|
2297
|
+
|
|
2298
|
+
test('signing flow: signature verifies against witness-bearing hash', () => {
|
|
2299
|
+
const authorization = KeyAuthorization.from({
|
|
2300
|
+
address,
|
|
2301
|
+
chainId: 1n,
|
|
2302
|
+
type: 'secp256k1',
|
|
2303
|
+
witness,
|
|
2304
|
+
})
|
|
2305
|
+
const payload = KeyAuthorization.getSignPayload(authorization)
|
|
2306
|
+
const sig = Secp256k1.sign({
|
|
2307
|
+
payload,
|
|
2308
|
+
privateKey: privateKey_secp256k1,
|
|
2309
|
+
})
|
|
2310
|
+
const signed = KeyAuthorization.from(authorization, {
|
|
2311
|
+
signature: SignatureEnvelope.from(sig),
|
|
2312
|
+
})
|
|
2313
|
+
const serialized = KeyAuthorization.serialize(signed)
|
|
2314
|
+
const restored = KeyAuthorization.deserialize(serialized)
|
|
2315
|
+
expect(restored.witness).toBe(witness)
|
|
2316
|
+
// The hash of the restored payload matches what was signed.
|
|
2317
|
+
expect(KeyAuthorization.hash(restored)).toBe(payload)
|
|
2318
|
+
})
|
|
2319
|
+
})
|
|
2320
|
+
|
|
2321
|
+
describe('admin keys (TIP-1049)', () => {
|
|
2322
|
+
const account = '0x1111111111111111111111111111111111111111' as const
|
|
2323
|
+
|
|
2324
|
+
test('from: preserves isAdmin and account', () => {
|
|
2325
|
+
const authorization = KeyAuthorization.from({
|
|
2326
|
+
address,
|
|
2327
|
+
account,
|
|
2328
|
+
chainId: 1n,
|
|
2329
|
+
isAdmin: true,
|
|
2330
|
+
type: 'secp256k1',
|
|
2331
|
+
})
|
|
2332
|
+
expect(authorization.isAdmin).toBe(true)
|
|
2333
|
+
expect(authorization.account).toBe(account)
|
|
2334
|
+
})
|
|
2335
|
+
|
|
2336
|
+
test('toTuple: emits isAdmin + account together', () => {
|
|
2337
|
+
const authorization = KeyAuthorization.from({
|
|
2338
|
+
address,
|
|
2339
|
+
account,
|
|
2340
|
+
chainId: 1n,
|
|
2341
|
+
isAdmin: true,
|
|
2342
|
+
type: 'secp256k1',
|
|
2343
|
+
})
|
|
2344
|
+
const [authTuple] = KeyAuthorization.toTuple(authorization)
|
|
2345
|
+
expect(authTuple).toEqual([
|
|
2346
|
+
'0x1',
|
|
2347
|
+
'0x',
|
|
2348
|
+
address,
|
|
2349
|
+
'0x', // expiry placeholder
|
|
2350
|
+
'0x', // limits placeholder
|
|
2351
|
+
'0x', // scopes placeholder
|
|
2352
|
+
'0x', // witness placeholder
|
|
2353
|
+
'0x01', // isAdmin = true
|
|
2354
|
+
account,
|
|
2355
|
+
])
|
|
2356
|
+
})
|
|
2357
|
+
|
|
2358
|
+
test('toTuple: omits both when neither is set (byte-equivalent to pre-TIP-1049)', () => {
|
|
2359
|
+
const authorization = KeyAuthorization.from({
|
|
2360
|
+
address,
|
|
2361
|
+
chainId: 1n,
|
|
2362
|
+
type: 'secp256k1',
|
|
2363
|
+
})
|
|
2364
|
+
const [authTuple] = KeyAuthorization.toTuple(authorization)
|
|
2365
|
+
expect((authTuple as unknown as unknown[]).length).toBe(3)
|
|
2366
|
+
})
|
|
2367
|
+
|
|
2368
|
+
test('fromTuple: drops orphan isAdmin without account', () => {
|
|
2369
|
+
const restored = KeyAuthorization.fromTuple([
|
|
2370
|
+
['0x01', '0x', address, '0x', [], [], '0x', '0x01'],
|
|
2371
|
+
])
|
|
2372
|
+
expect(restored.isAdmin).toBeUndefined()
|
|
2373
|
+
expect(restored.account).toBeUndefined()
|
|
2374
|
+
})
|
|
2375
|
+
|
|
2376
|
+
test('fromTuple: drops orphan account without isAdmin', () => {
|
|
2377
|
+
const restored = KeyAuthorization.fromTuple([
|
|
2378
|
+
['0x01', '0x', address, '0x', [], [], '0x', '0x', account],
|
|
2379
|
+
])
|
|
2380
|
+
expect(restored.isAdmin).toBeUndefined()
|
|
2381
|
+
expect(restored.account).toBeUndefined()
|
|
2382
|
+
})
|
|
2383
|
+
|
|
2384
|
+
test('fromTuple: extracts isAdmin + account together', () => {
|
|
2385
|
+
const restored = KeyAuthorization.fromTuple([
|
|
2386
|
+
['0x01', '0x', address, '0x', [], [], '0x', '0x01', account],
|
|
2387
|
+
])
|
|
2388
|
+
expect(restored.isAdmin).toBe(true)
|
|
2389
|
+
expect(restored.account).toBe(account)
|
|
2390
|
+
})
|
|
2391
|
+
|
|
2392
|
+
test('fromTuple: throws on invalid admin marker', () => {
|
|
2393
|
+
expect(() =>
|
|
2394
|
+
KeyAuthorization.fromTuple([
|
|
2395
|
+
['0x01', '0x', address, '0x', [], [], '0x', '0x02'],
|
|
2396
|
+
]),
|
|
2397
|
+
).toThrowErrorMatchingInlineSnapshot(
|
|
2398
|
+
`[KeyAuthorization.InvalidAdminMarkerError: Admin marker \`0x02\` is invalid; expected \`0x01\` (TIP-1049).]`,
|
|
2399
|
+
)
|
|
2400
|
+
})
|
|
2401
|
+
|
|
2402
|
+
test('serialize/deserialize: roundtrip with isAdmin + account', () => {
|
|
2403
|
+
const authorization = KeyAuthorization.from({
|
|
2404
|
+
address,
|
|
2405
|
+
account,
|
|
2406
|
+
chainId: 1n,
|
|
2407
|
+
isAdmin: true,
|
|
2408
|
+
type: 'secp256k1',
|
|
2409
|
+
})
|
|
2410
|
+
const serialized = KeyAuthorization.serialize(authorization)
|
|
2411
|
+
const restored = KeyAuthorization.deserialize(serialized)
|
|
2412
|
+
expect(restored.isAdmin).toBe(true)
|
|
2413
|
+
expect(restored.account).toBe(account)
|
|
2414
|
+
})
|
|
2415
|
+
|
|
2416
|
+
test('toRpc/fromRpc: roundtrip with isAdmin + account', () => {
|
|
2417
|
+
const authorization = KeyAuthorization.from(
|
|
2418
|
+
{
|
|
2419
|
+
address,
|
|
2420
|
+
account,
|
|
2421
|
+
chainId: 1n,
|
|
2422
|
+
isAdmin: true,
|
|
2423
|
+
type: 'secp256k1',
|
|
2424
|
+
},
|
|
2425
|
+
{ signature: SignatureEnvelope.from(signature_secp256k1) },
|
|
2426
|
+
)
|
|
2427
|
+
const rpc = KeyAuthorization.toRpc(authorization)
|
|
2428
|
+
expect(rpc.isAdmin).toBe(true)
|
|
2429
|
+
expect(rpc.account).toBe(account)
|
|
2430
|
+
const restored = KeyAuthorization.fromRpc(rpc)
|
|
2431
|
+
expect(restored.isAdmin).toBe(true)
|
|
2432
|
+
expect(restored.account).toBe(account)
|
|
2433
|
+
})
|
|
2434
|
+
|
|
2435
|
+
test('hash: changes when admin pair is added', () => {
|
|
2436
|
+
const plain = KeyAuthorization.from({
|
|
2437
|
+
address,
|
|
2438
|
+
chainId: 1n,
|
|
2439
|
+
type: 'secp256k1',
|
|
2440
|
+
})
|
|
2441
|
+
const admin = KeyAuthorization.from({
|
|
2442
|
+
address,
|
|
2443
|
+
account,
|
|
2444
|
+
chainId: 1n,
|
|
2445
|
+
isAdmin: true,
|
|
2446
|
+
type: 'secp256k1',
|
|
2447
|
+
})
|
|
2448
|
+
expect(KeyAuthorization.hash(plain)).not.toBe(KeyAuthorization.hash(admin))
|
|
2449
|
+
})
|
|
2450
|
+
|
|
2451
|
+
test('hash: changes when account in admin pair changes', () => {
|
|
2452
|
+
const a = KeyAuthorization.from({
|
|
2453
|
+
address,
|
|
2454
|
+
account,
|
|
2455
|
+
chainId: 1n,
|
|
2456
|
+
isAdmin: true,
|
|
2457
|
+
type: 'secp256k1',
|
|
2458
|
+
})
|
|
2459
|
+
const b = KeyAuthorization.from({
|
|
2460
|
+
address,
|
|
2461
|
+
account: '0x2222222222222222222222222222222222222222',
|
|
2462
|
+
chainId: 1n,
|
|
2463
|
+
isAdmin: true,
|
|
2464
|
+
type: 'secp256k1',
|
|
2465
|
+
})
|
|
2466
|
+
expect(KeyAuthorization.hash(a)).not.toBe(KeyAuthorization.hash(b))
|
|
2467
|
+
})
|
|
2468
|
+
})
|