@0xsequence/catapult 1.3.13 → 1.3.15
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/dist/lib/__tests__/deployer.spec.js +22 -0
- package/dist/lib/__tests__/deployer.spec.js.map +1 -1
- package/dist/lib/core/__tests__/context.spec.d.ts +2 -0
- package/dist/lib/core/__tests__/context.spec.d.ts.map +1 -0
- package/dist/lib/core/__tests__/context.spec.js +25 -0
- package/dist/lib/core/__tests__/context.spec.js.map +1 -0
- package/dist/lib/core/__tests__/resolver.spec.js +20 -0
- package/dist/lib/core/__tests__/resolver.spec.js.map +1 -1
- package/dist/lib/core/context.js +2 -2
- package/dist/lib/core/context.js.map +1 -1
- package/dist/lib/core/resolver.d.ts +1 -0
- package/dist/lib/core/resolver.d.ts.map +1 -1
- package/dist/lib/core/resolver.js +39 -2
- package/dist/lib/core/resolver.js.map +1 -1
- package/dist/lib/deployer.d.ts.map +1 -1
- package/dist/lib/deployer.js +2 -1
- package/dist/lib/deployer.js.map +1 -1
- package/package.json +1 -1
- package/src/lib/__tests__/deployer.spec.ts +28 -0
- package/src/lib/core/__tests__/context.spec.ts +37 -0
- package/src/lib/core/__tests__/resolver.spec.ts +22 -0
- package/src/lib/core/context.ts +3 -3
- package/src/lib/core/resolver.ts +50 -3
- package/src/lib/deployer.ts +5 -3
package/package.json
CHANGED
|
@@ -460,6 +460,34 @@ describe('Deployer', () => {
|
|
|
460
460
|
'deploy2.address': '0xdeploy2'
|
|
461
461
|
})
|
|
462
462
|
})
|
|
463
|
+
|
|
464
|
+
it('should keep outputs empty when only skipped opt-in actions produce no keys', async () => {
|
|
465
|
+
const jobWithSkippedOptIn: Job = {
|
|
466
|
+
name: 'job-skipped-opt-in',
|
|
467
|
+
version: '1.0.0',
|
|
468
|
+
description: 'Job where the only opted-in action produced no outputs',
|
|
469
|
+
actions: [
|
|
470
|
+
{ name: 'deploy-action', template: 'template1', arguments: {}, output: false },
|
|
471
|
+
{ name: 'skipped-action', template: 'template1', arguments: {}, output: true }
|
|
472
|
+
]
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
mockLoader.jobs.clear()
|
|
476
|
+
mockLoader.jobs.set('job-skipped-opt-in', jobWithSkippedOptIn)
|
|
477
|
+
mockGraph.getExecutionOrder.mockReturnValue(['job-skipped-opt-in'])
|
|
478
|
+
|
|
479
|
+
mockContext.getOutputs.mockReturnValue(new Map<string, any>([
|
|
480
|
+
['deploy-action.address', '0xdeployaddress']
|
|
481
|
+
]))
|
|
482
|
+
|
|
483
|
+
const deployer = new Deployer(deployerOptions)
|
|
484
|
+
await deployer.run()
|
|
485
|
+
|
|
486
|
+
const outputCall = mockFs.writeFile.mock.calls[0]
|
|
487
|
+
const outputContent = JSON.parse(outputCall[1] as string)
|
|
488
|
+
|
|
489
|
+
expect(outputContent.networks[0].outputs).toEqual({})
|
|
490
|
+
})
|
|
463
491
|
})
|
|
464
492
|
|
|
465
493
|
describe('error handling', () => {
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ethers } from 'ethers'
|
|
2
|
+
import { ExecutionContext } from '../context'
|
|
3
|
+
import { Network } from '../../types'
|
|
4
|
+
|
|
5
|
+
describe('ExecutionContext', () => {
|
|
6
|
+
const network: Network = {
|
|
7
|
+
name: 'test',
|
|
8
|
+
chainId: 31337,
|
|
9
|
+
rpcUrl: 'http://127.0.0.1:8545'
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const contractRepository = {} as any
|
|
13
|
+
|
|
14
|
+
it('wraps private-key signers in a NonceManager', async () => {
|
|
15
|
+
const context = new ExecutionContext(
|
|
16
|
+
network,
|
|
17
|
+
'0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
|
|
18
|
+
contractRepository
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
const signer = await context.getResolvedSigner()
|
|
22
|
+
expect(signer).toBeInstanceOf(ethers.NonceManager)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('wraps promised signers in a NonceManager when first resolved', async () => {
|
|
26
|
+
const getSignerSpy = jest.spyOn(ethers.JsonRpcProvider.prototype, 'getSigner')
|
|
27
|
+
getSignerSpy.mockResolvedValue(
|
|
28
|
+
ethers.Wallet.createRandom().connect(new ethers.JsonRpcProvider(network.rpcUrl)) as any
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
const context = new ExecutionContext(network, undefined, contractRepository)
|
|
32
|
+
|
|
33
|
+
await expect(context.getResolvedSigner()).resolves.toBeInstanceOf(ethers.NonceManager)
|
|
34
|
+
|
|
35
|
+
getSignerSpy.mockRestore()
|
|
36
|
+
})
|
|
37
|
+
})
|
|
@@ -102,6 +102,28 @@ describe('ValueResolver', () => {
|
|
|
102
102
|
expect(await resolver.resolve(valueFalse, context)).toBe(false)
|
|
103
103
|
})
|
|
104
104
|
|
|
105
|
+
it('should treat nullish nested values as non-equal without throwing', async () => {
|
|
106
|
+
const value: BasicArithmeticValue = {
|
|
107
|
+
type: 'basic-arithmetic',
|
|
108
|
+
arguments: {
|
|
109
|
+
operation: 'eq',
|
|
110
|
+
values: [
|
|
111
|
+
{
|
|
112
|
+
type: 'call',
|
|
113
|
+
arguments: {
|
|
114
|
+
to: '0x1234567890123456789012345678901234567890',
|
|
115
|
+
signature: 'imageHash() returns (bytes32)',
|
|
116
|
+
values: [],
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
'0xfd72d46fd0d0a98780315f81790f051356f2f3101af4b5c3fb1c6da3237fb765',
|
|
120
|
+
],
|
|
121
|
+
},
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
await expect(resolver.resolve(value, context)).resolves.toBe(false)
|
|
125
|
+
})
|
|
126
|
+
|
|
105
127
|
it('should correctly evaluate "gt" (greater than)', async () => {
|
|
106
128
|
const valueTrue: BasicArithmeticValue = { type: 'basic-arithmetic', arguments: { operation: 'gt', values: [10, 5] } }
|
|
107
129
|
const valueFalse: BasicArithmeticValue = { type: 'basic-arithmetic', arguments: { operation: 'gt', values: [10, 10] } }
|
package/src/lib/core/context.ts
CHANGED
|
@@ -33,11 +33,11 @@ export class ExecutionContext {
|
|
|
33
33
|
|
|
34
34
|
// Determine the signer
|
|
35
35
|
if (privateKey) {
|
|
36
|
-
this.signer = new ethers.Wallet(privateKey, this.provider)
|
|
36
|
+
this.signer = new ethers.NonceManager(new ethers.Wallet(privateKey, this.provider))
|
|
37
37
|
} else if (network.rpcUrl) {
|
|
38
38
|
// If no private key, but RPC URL is provided, get a signer from the provider.
|
|
39
39
|
// This returns a Promise that we need to resolve on first use.
|
|
40
|
-
this.signer = this.provider.getSigner() // Keep as Promise
|
|
40
|
+
this.signer = this.provider.getSigner().then(signer => new ethers.NonceManager(signer)) // Keep as Promise
|
|
41
41
|
} else {
|
|
42
42
|
throw new Error('A private key must be provided or an RPC URL must be configured to obtain a signer for the network.')
|
|
43
43
|
}
|
|
@@ -124,4 +124,4 @@ export class ExecutionContext {
|
|
|
124
124
|
// Ignore errors during cleanup
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
|
-
}
|
|
127
|
+
}
|
package/src/lib/core/resolver.ts
CHANGED
|
@@ -362,19 +362,42 @@ export class ValueResolver {
|
|
|
362
362
|
throw new Error(`basic-arithmetic requires at least 2 values, got ${args.values?.length ?? 0}`)
|
|
363
363
|
}
|
|
364
364
|
|
|
365
|
+
switch (args.operation) {
|
|
366
|
+
// Equality (return boolean, tolerate nullish / non-numeric values)
|
|
367
|
+
case 'eq': {
|
|
368
|
+
const [a, b] = args.values
|
|
369
|
+
return this.valuesEqual(a, b)
|
|
370
|
+
}
|
|
371
|
+
case 'neq': {
|
|
372
|
+
const [a, b] = args.values
|
|
373
|
+
return !this.valuesEqual(a, b)
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Arithmetic (return string)
|
|
377
|
+
case 'add':
|
|
378
|
+
case 'sub':
|
|
379
|
+
case 'mul':
|
|
380
|
+
case 'div':
|
|
381
|
+
case 'gt':
|
|
382
|
+
case 'lt':
|
|
383
|
+
case 'gte':
|
|
384
|
+
case 'lte':
|
|
385
|
+
break
|
|
386
|
+
|
|
387
|
+
default:
|
|
388
|
+
throw new Error(`Unsupported basic-arithmetic operation: ${args.operation}`)
|
|
389
|
+
}
|
|
390
|
+
|
|
365
391
|
const numbers = args.values.map(v => ethers.toBigInt(v))
|
|
366
392
|
const [a, b] = numbers
|
|
367
393
|
|
|
368
394
|
switch (args.operation) {
|
|
369
|
-
// Arithmetic (return string)
|
|
370
395
|
case 'add': return numbers.reduce((sum, current) => sum + current).toString()
|
|
371
396
|
case 'sub': return (a - b).toString()
|
|
372
397
|
case 'mul': return (a * b).toString()
|
|
373
398
|
case 'div': return (a / b).toString()
|
|
374
399
|
|
|
375
400
|
// Comparison (return boolean)
|
|
376
|
-
case 'eq': return a === b
|
|
377
|
-
case 'neq': return a !== b
|
|
378
401
|
case 'gt': return a > b
|
|
379
402
|
case 'lt': return a < b
|
|
380
403
|
case 'gte': return a >= b
|
|
@@ -385,6 +408,30 @@ export class ValueResolver {
|
|
|
385
408
|
}
|
|
386
409
|
}
|
|
387
410
|
|
|
411
|
+
private valuesEqual(a: any, b: any): boolean {
|
|
412
|
+
if (a == null || b == null) {
|
|
413
|
+
return a == null && b == null
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
if (isBigNumberish(a) && isBigNumberish(b)) {
|
|
417
|
+
return ethers.toBigInt(a) === ethers.toBigInt(b)
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
if (typeof a === 'string' && typeof b === 'string') {
|
|
421
|
+
return a === b
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
if (typeof a === 'boolean' && typeof b === 'boolean') {
|
|
425
|
+
return a === b
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
if ((typeof a === 'object' && a !== null) || (typeof b === 'object' && b !== null)) {
|
|
429
|
+
return JSON.stringify(a) === JSON.stringify(b)
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
return a === b
|
|
433
|
+
}
|
|
434
|
+
|
|
388
435
|
private async resolveCall(args: CallValue['arguments'], context: ExecutionContext): Promise<any> {
|
|
389
436
|
const { to, signature, values } = args
|
|
390
437
|
|
package/src/lib/deployer.ts
CHANGED
|
@@ -879,8 +879,10 @@ export class Deployer {
|
|
|
879
879
|
|
|
880
880
|
// 3) Exclude any actions explicitly marked false (they won't be included by rules above anyway)
|
|
881
881
|
|
|
882
|
-
|
|
883
|
-
|
|
882
|
+
const hasExplicitOutputSelection = actionsWithCustomMap.length > 0 || actionsWithTrue.length > 0
|
|
883
|
+
|
|
884
|
+
// If the job has any explicit output selection, return the selected outputs even when empty.
|
|
885
|
+
if (hasExplicitOutputSelection) {
|
|
884
886
|
// Additionally, filter out any accidentally included outputs from actions marked false
|
|
885
887
|
for (const falseActionName of actionsWithFalse) {
|
|
886
888
|
for (const key of Array.from(result.keys())) {
|
|
@@ -976,4 +978,4 @@ export class Deployer {
|
|
|
976
978
|
// Return all entries: successes first, then errors
|
|
977
979
|
return [...successEntries, ...errorEntries]
|
|
978
980
|
}
|
|
979
|
-
}
|
|
981
|
+
}
|