@0xsequence/catapult 1.3.3 → 1.3.4

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 (45) hide show
  1. package/README.md +16 -0
  2. package/dist/commands/run.d.ts.map +1 -1
  3. package/dist/commands/run.js +4 -2
  4. package/dist/commands/run.js.map +1 -1
  5. package/dist/lib/__tests__/deployer.spec.js +71 -1
  6. package/dist/lib/__tests__/deployer.spec.js.map +1 -1
  7. package/dist/lib/core/__tests__/engine.spec.js +270 -0
  8. package/dist/lib/core/__tests__/engine.spec.js.map +1 -1
  9. package/dist/lib/core/__tests__/resolver.spec.js +132 -0
  10. package/dist/lib/core/__tests__/resolver.spec.js.map +1 -1
  11. package/dist/lib/core/engine.d.ts +13 -0
  12. package/dist/lib/core/engine.d.ts.map +1 -1
  13. package/dist/lib/core/engine.js +59 -5
  14. package/dist/lib/core/engine.js.map +1 -1
  15. package/dist/lib/core/resolver.d.ts +1 -0
  16. package/dist/lib/core/resolver.d.ts.map +1 -1
  17. package/dist/lib/core/resolver.js +24 -7
  18. package/dist/lib/core/resolver.js.map +1 -1
  19. package/dist/lib/deployer.d.ts +2 -0
  20. package/dist/lib/deployer.d.ts.map +1 -1
  21. package/dist/lib/deployer.js +18 -1
  22. package/dist/lib/deployer.js.map +1 -1
  23. package/dist/lib/events/cli-adapter.d.ts.map +1 -1
  24. package/dist/lib/events/cli-adapter.js +20 -0
  25. package/dist/lib/events/cli-adapter.js.map +1 -1
  26. package/dist/lib/events/types.d.ts +25 -1
  27. package/dist/lib/events/types.d.ts.map +1 -1
  28. package/dist/lib/types/values.d.ts +8 -1
  29. package/dist/lib/types/values.d.ts.map +1 -1
  30. package/dist/lib/utils/assertion.d.ts +4 -0
  31. package/dist/lib/utils/assertion.d.ts.map +1 -0
  32. package/dist/lib/utils/assertion.js +27 -0
  33. package/dist/lib/utils/assertion.js.map +1 -0
  34. package/package.json +12 -13
  35. package/src/commands/run.ts +4 -1
  36. package/src/lib/__tests__/deployer.spec.ts +108 -1
  37. package/src/lib/core/__tests__/engine.spec.ts +321 -0
  38. package/src/lib/core/__tests__/resolver.spec.ts +150 -1
  39. package/src/lib/core/engine.ts +92 -6
  40. package/src/lib/core/resolver.ts +29 -8
  41. package/src/lib/deployer.ts +28 -1
  42. package/src/lib/events/cli-adapter.ts +24 -0
  43. package/src/lib/events/types.ts +29 -1
  44. package/src/lib/types/values.ts +10 -1
  45. package/src/lib/utils/assertion.ts +24 -0
@@ -1542,4 +1542,325 @@ describe('ExecutionEngine', () => {
1542
1542
  expect(context.getOutput('nick-test-default-bytecode.success')).toBe(true)
1543
1543
  })
1544
1544
  })
1545
+
1546
+ describe('ignore verify errors feature', () => {
1547
+ beforeEach(() => {
1548
+ // Mock fs.readFile to return valid build info
1549
+ jest.doMock('fs/promises', () => ({
1550
+ readFile: jest.fn().mockResolvedValue(JSON.stringify({
1551
+ _format: 'hh-sol-build-info-1',
1552
+ id: 'test-id',
1553
+ solcVersion: '0.8.0',
1554
+ input: {
1555
+ language: 'Solidity',
1556
+ sources: {
1557
+ 'TestContract.sol': {
1558
+ content: 'contract TestContract { }'
1559
+ }
1560
+ },
1561
+ settings: {
1562
+ optimizer: { enabled: true, runs: 200 },
1563
+ outputSelection: { '*': { '*': ['*'] } }
1564
+ }
1565
+ },
1566
+ output: {
1567
+ contracts: {},
1568
+ sources: {}
1569
+ }
1570
+ }))
1571
+ }))
1572
+
1573
+ // Create a mock verification registry with a failing platform
1574
+ const mockVerificationRegistry = new VerificationPlatformRegistry()
1575
+ const mockPlatform = {
1576
+ name: 'mock-platform',
1577
+ supportsNetwork: jest.fn().mockReturnValue(true),
1578
+ isConfigured: jest.fn().mockReturnValue(true),
1579
+ getConfigurationRequirements: jest.fn().mockReturnValue(''),
1580
+ isContractAlreadyVerified: jest.fn().mockResolvedValue(false),
1581
+ verifyContract: jest.fn().mockRejectedValue(new Error('Verification failed'))
1582
+ }
1583
+ mockVerificationRegistry.register(mockPlatform)
1584
+
1585
+ engine = new ExecutionEngine(templates, {
1586
+ verificationRegistry: mockVerificationRegistry,
1587
+ ignoreVerifyErrors: true
1588
+ })
1589
+ })
1590
+
1591
+ it('should collect verification warnings when ignoreVerifyErrors is enabled', async () => {
1592
+ const mockContract = {
1593
+ sourceName: 'TestContract.sol',
1594
+ contractName: 'TestContract',
1595
+ compiler: { version: '0.8.0' },
1596
+ buildInfoId: 'test-build-id',
1597
+ source: 'contract TestContract { }',
1598
+ creationCode: '0x608060405234801561000f575f5ffd5b50602a5f526020601ff3',
1599
+ abi: [],
1600
+ _sources: new Set(['TestContract.sol', '/path/to/build-info/test.json'])
1601
+ }
1602
+
1603
+ context.contractRepository.addForTesting({
1604
+ contractName: mockContract.contractName,
1605
+ abi: mockContract.abi,
1606
+ bytecode: mockContract.creationCode,
1607
+ sourceName: mockContract.sourceName,
1608
+ source: mockContract.source,
1609
+ compiler: mockContract.compiler,
1610
+ buildInfoId: mockContract.buildInfoId,
1611
+ _path: '/test/path',
1612
+ _hash: 'test-hash'
1613
+ })
1614
+
1615
+ const action: Action = {
1616
+ type: 'verify-contract',
1617
+ name: 'test-verify',
1618
+ arguments: {
1619
+ address: TEST_ADDRESSES.RECIPIENT_1,
1620
+ contract: '{{Contract(TestContract)}}',
1621
+ platform: 'mock-platform'
1622
+ }
1623
+ }
1624
+
1625
+ // Should not throw even though verification fails
1626
+ await expect((engine as any).executePrimitive(action, context, new Map()))
1627
+ .resolves.not.toThrow()
1628
+
1629
+ // Should have collected the warning
1630
+ const warnings = engine.getVerificationWarnings()
1631
+ expect(warnings).toHaveLength(1)
1632
+ expect(warnings[0]).toMatchObject({
1633
+ actionName: 'test-verify',
1634
+ address: TEST_ADDRESSES.RECIPIENT_1,
1635
+ contractName: 'TestContract.sol:TestContract',
1636
+ platform: 'mock-platform',
1637
+ error: 'Action "test-verify": No build-info file found in contract sources'
1638
+ })
1639
+ })
1640
+
1641
+ it('should throw verification errors when ignoreVerifyErrors is disabled', async () => {
1642
+ // Create engine with ignoreVerifyErrors disabled
1643
+ const mockVerificationRegistry = new VerificationPlatformRegistry()
1644
+ const mockPlatform = {
1645
+ name: 'mock-platform',
1646
+ supportsNetwork: jest.fn().mockReturnValue(true),
1647
+ isConfigured: jest.fn().mockReturnValue(true),
1648
+ getConfigurationRequirements: jest.fn().mockReturnValue(''),
1649
+ isContractAlreadyVerified: jest.fn().mockResolvedValue(false),
1650
+ verifyContract: jest.fn().mockRejectedValue(new Error('Verification failed'))
1651
+ }
1652
+ mockVerificationRegistry.register(mockPlatform)
1653
+
1654
+ const engineWithoutIgnore = new ExecutionEngine(templates, {
1655
+ verificationRegistry: mockVerificationRegistry,
1656
+ ignoreVerifyErrors: false
1657
+ })
1658
+
1659
+ const mockContract = {
1660
+ sourceName: 'TestContract.sol',
1661
+ contractName: 'TestContract',
1662
+ compiler: { version: '0.8.0' },
1663
+ buildInfoId: 'test-build-id',
1664
+ source: 'contract TestContract { }',
1665
+ creationCode: '0x608060405234801561000f575f5ffd5b50602a5f526020601ff3',
1666
+ abi: [],
1667
+ _sources: new Set(['TestContract.sol', '/path/to/build-info/test.json'])
1668
+ }
1669
+
1670
+ context.contractRepository.addForTesting({
1671
+ contractName: mockContract.contractName,
1672
+ abi: mockContract.abi,
1673
+ bytecode: mockContract.creationCode,
1674
+ sourceName: mockContract.sourceName,
1675
+ source: mockContract.source,
1676
+ compiler: mockContract.compiler,
1677
+ buildInfoId: mockContract.buildInfoId,
1678
+ _path: '/test/path',
1679
+ _hash: 'test-hash'
1680
+ })
1681
+
1682
+ const action: Action = {
1683
+ type: 'verify-contract',
1684
+ name: 'test-verify',
1685
+ arguments: {
1686
+ address: TEST_ADDRESSES.RECIPIENT_1,
1687
+ contract: '{{Contract(TestContract)}}',
1688
+ platform: 'mock-platform'
1689
+ }
1690
+ }
1691
+
1692
+ // Should throw when ignoreVerifyErrors is disabled
1693
+ await expect((engineWithoutIgnore as any).executePrimitive(action, context, new Map()))
1694
+ .rejects.toThrow('Action "test-verify": No build-info file found in contract sources')
1695
+ })
1696
+
1697
+ it('should handle multiple platform verification failures with ignoreVerifyErrors', async () => {
1698
+ const mockVerificationRegistry = new VerificationPlatformRegistry()
1699
+
1700
+ // Create multiple failing platforms
1701
+ const platforms = ['platform1', 'platform2', 'platform3']
1702
+ platforms.forEach(name => {
1703
+ const mockPlatform = {
1704
+ name,
1705
+ supportsNetwork: jest.fn().mockReturnValue(true),
1706
+ isConfigured: jest.fn().mockReturnValue(true),
1707
+ getConfigurationRequirements: jest.fn().mockReturnValue(''),
1708
+ isContractAlreadyVerified: jest.fn().mockResolvedValue(false),
1709
+ verifyContract: jest.fn().mockRejectedValue(new Error(`${name} verification failed`))
1710
+ }
1711
+ mockVerificationRegistry.register(mockPlatform)
1712
+ })
1713
+
1714
+ engine = new ExecutionEngine(templates, {
1715
+ verificationRegistry: mockVerificationRegistry,
1716
+ ignoreVerifyErrors: true
1717
+ })
1718
+
1719
+ const mockContract = {
1720
+ sourceName: 'TestContract.sol',
1721
+ contractName: 'TestContract',
1722
+ compiler: { version: '0.8.0' },
1723
+ buildInfoId: 'test-build-id',
1724
+ source: 'contract TestContract { }',
1725
+ creationCode: '0x608060405234801561000f575f5ffd5b50602a5f526020601ff3',
1726
+ abi: [],
1727
+ _sources: new Set(['TestContract.sol', '/path/to/build-info/test.json'])
1728
+ }
1729
+
1730
+ context.contractRepository.addForTesting({
1731
+ contractName: mockContract.contractName,
1732
+ abi: mockContract.abi,
1733
+ bytecode: mockContract.creationCode,
1734
+ sourceName: mockContract.sourceName,
1735
+ source: mockContract.source,
1736
+ compiler: mockContract.compiler,
1737
+ buildInfoId: mockContract.buildInfoId,
1738
+ _path: '/test/path',
1739
+ _hash: 'test-hash'
1740
+ })
1741
+
1742
+ const action: Action = {
1743
+ type: 'verify-contract',
1744
+ name: 'test-verify',
1745
+ arguments: {
1746
+ address: TEST_ADDRESSES.RECIPIENT_1,
1747
+ contract: '{{Contract(TestContract)}}',
1748
+ platform: platforms
1749
+ }
1750
+ }
1751
+
1752
+ // Should not throw even with multiple platform failures
1753
+ await expect((engine as any).executePrimitive(action, context, new Map()))
1754
+ .resolves.not.toThrow()
1755
+
1756
+ // Should have collected warnings for all platforms
1757
+ const warnings = engine.getVerificationWarnings()
1758
+ expect(warnings).toHaveLength(3)
1759
+
1760
+ platforms.forEach((platform, index) => {
1761
+ expect(warnings[index]).toMatchObject({
1762
+ actionName: 'test-verify',
1763
+ platform,
1764
+ error: 'Action "test-verify": No build-info file found in contract sources'
1765
+ })
1766
+ })
1767
+ })
1768
+
1769
+ it('should provide methods to get and clear verification warnings', () => {
1770
+ // Initially empty
1771
+ expect(engine.getVerificationWarnings()).toEqual([])
1772
+
1773
+ // Manually add a warning (simulating what happens during verification)
1774
+ ;(engine as any).verificationWarnings.push({
1775
+ actionName: 'test',
1776
+ address: '0x123',
1777
+ contractName: 'Test',
1778
+ platform: 'test-platform',
1779
+ error: 'test error'
1780
+ })
1781
+
1782
+ // Should return the warning
1783
+ const warnings = engine.getVerificationWarnings()
1784
+ expect(warnings).toHaveLength(1)
1785
+ expect(warnings[0]).toMatchObject({
1786
+ actionName: 'test',
1787
+ error: 'test error'
1788
+ })
1789
+
1790
+ // Clear warnings
1791
+ engine.clearVerificationWarnings()
1792
+ expect(engine.getVerificationWarnings()).toEqual([])
1793
+ })
1794
+
1795
+ it('should emit verification_skipped events when all platforms fail and ignoreVerifyErrors is enabled', async () => {
1796
+ const mockVerificationRegistry = new VerificationPlatformRegistry()
1797
+ const mockPlatform = {
1798
+ name: 'mock-platform',
1799
+ supportsNetwork: jest.fn().mockReturnValue(true),
1800
+ isConfigured: jest.fn().mockReturnValue(true),
1801
+ getConfigurationRequirements: jest.fn().mockReturnValue(''),
1802
+ isContractAlreadyVerified: jest.fn().mockResolvedValue(false),
1803
+ verifyContract: jest.fn().mockRejectedValue(new Error('Verification failed'))
1804
+ }
1805
+ mockVerificationRegistry.register(mockPlatform)
1806
+ mockVerificationRegistry.getConfiguredPlatforms = jest.fn().mockReturnValue([mockPlatform])
1807
+
1808
+ const mockEventEmitter = {
1809
+ emitEvent: jest.fn()
1810
+ }
1811
+
1812
+ engine = new ExecutionEngine(templates, {
1813
+ verificationRegistry: mockVerificationRegistry,
1814
+ ignoreVerifyErrors: true,
1815
+ eventEmitter: mockEventEmitter as any
1816
+ })
1817
+
1818
+ const mockContract = {
1819
+ sourceName: 'TestContract.sol',
1820
+ contractName: 'TestContract',
1821
+ compiler: { version: '0.8.0' },
1822
+ buildInfoId: 'test-build-id',
1823
+ source: 'contract TestContract { }',
1824
+ creationCode: '0x608060405234801561000f575f5ffd5b50602a5f526020601ff3',
1825
+ abi: [],
1826
+ _sources: new Set(['TestContract.sol', '/path/to/build-info/test.json'])
1827
+ }
1828
+
1829
+ context.contractRepository.addForTesting({
1830
+ contractName: mockContract.contractName,
1831
+ abi: mockContract.abi,
1832
+ bytecode: mockContract.creationCode,
1833
+ sourceName: mockContract.sourceName,
1834
+ source: mockContract.source,
1835
+ compiler: mockContract.compiler,
1836
+ buildInfoId: mockContract.buildInfoId,
1837
+ _path: '/test/path',
1838
+ _hash: 'test-hash'
1839
+ })
1840
+
1841
+ const action: Action = {
1842
+ type: 'verify-contract',
1843
+ name: 'test-verify',
1844
+ arguments: {
1845
+ address: TEST_ADDRESSES.RECIPIENT_1,
1846
+ contract: '{{Contract(TestContract)}}',
1847
+ platform: 'all'
1848
+ }
1849
+ }
1850
+
1851
+ await (engine as any).executePrimitive(action, context, new Map())
1852
+
1853
+ // Should emit verification_skipped event
1854
+ expect(mockEventEmitter.emitEvent).toHaveBeenCalledWith(
1855
+ expect.objectContaining({
1856
+ type: 'verification_skipped',
1857
+ level: 'warn',
1858
+ data: expect.objectContaining({
1859
+ actionName: 'test-verify',
1860
+ reason: expect.stringContaining('continuing due to --ignore-verify-errors')
1861
+ })
1862
+ })
1863
+ )
1864
+ })
1865
+ })
1545
1866
  })
@@ -1,7 +1,7 @@
1
1
  import { ethers } from 'ethers'
2
2
  import { ValueResolver } from '../resolver'
3
3
  import { ExecutionContext } from '../context'
4
- import { BasicArithmeticValue, Network, ReadBalanceValue, ComputeCreate2Value, ConstructorEncodeValue, AbiEncodeValue, AbiPackValue, CallValue, ContractExistsValue } from '../../types'
4
+ import { BasicArithmeticValue, Network, ReadBalanceValue, ComputeCreate2Value, ConstructorEncodeValue, AbiEncodeValue, AbiPackValue, CallValue, ContractExistsValue, ComputeCreateValue } from '../../types'
5
5
  import { ContractRepository } from '../../contracts/repository'
6
6
 
7
7
  describe('ValueResolver', () => {
@@ -494,6 +494,155 @@ describe('ValueResolver', () => {
494
494
  })
495
495
  })
496
496
 
497
+ describe('compute-create', () => {
498
+ it('should compute CREATE address with hardcoded test case 1', async () => {
499
+ const value: ComputeCreateValue = {
500
+ type: 'compute-create',
501
+ arguments: {
502
+ deployerAddress: '0x0000000000000000000000000000000000000000',
503
+ nonce: '0',
504
+ },
505
+ }
506
+ const result = await resolver.resolve(value, context)
507
+ expect(result).toBe('0xBd770416a3345F91E4B34576cb804a576fa48EB1')
508
+ })
509
+
510
+ it('should compute CREATE address with hardcoded test case 2', async () => {
511
+ const value: ComputeCreateValue = {
512
+ type: 'compute-create',
513
+ arguments: {
514
+ deployerAddress: '0xC6064FfBaDB0687Da29721C8EC02ACa71e735a3e',
515
+ nonce: '1',
516
+ },
517
+ }
518
+ const result = await resolver.resolve(value, context)
519
+ expect(result).toBe('0x6d2E686984620c01Af3cd125F9E1A2E23a972FFc')
520
+ })
521
+
522
+ it('should compute CREATE address with hardcoded test case 3', async () => {
523
+ const value: ComputeCreateValue = {
524
+ type: 'compute-create',
525
+ arguments: {
526
+ deployerAddress: '0xC6064FfBaDB0687Da29721C8EC02ACa71e735a3e',
527
+ nonce: '2',
528
+ },
529
+ }
530
+ const result = await resolver.resolve(value, context)
531
+ expect(result).toBe('0xBA6CfaFc33eD8229D2Af9a5a7BC22e8834cE0873')
532
+ })
533
+
534
+ it('should compute CREATE address with hardcoded test case ERC-2470', async () => {
535
+ const value: ComputeCreateValue = {
536
+ type: 'compute-create',
537
+ arguments: {
538
+ deployerAddress: '0xBb6e024b9cFFACB947A71991E386681B1Cd1477D',
539
+ nonce: '0',
540
+ },
541
+ }
542
+ const result = await resolver.resolve(value, context)
543
+ expect(result).toBe('0xce0042B868300000d44A59004Da54A005ffdcf9f')
544
+ })
545
+
546
+ it('should compute CREATE address with hardcoded test case Universal Deployer', async () => {
547
+ const value: ComputeCreateValue = {
548
+ type: 'compute-create',
549
+ arguments: {
550
+ deployerAddress: '0x9c5a87452d4FAC0cbd53BDCA580b20A45526B3AB',
551
+ nonce: '0',
552
+ },
553
+ }
554
+ const result = await resolver.resolve(value, context)
555
+ expect(result).toBe('0x1B926fBB24A9F78DCDd3272f2d86F5D0660E59c0')
556
+ })
557
+
558
+ it('should resolve values from context before computing CREATE address', async () => {
559
+ context.setOutput('myDeployer', '0x0000000000000000000000000000000000000000')
560
+ context.setOutput('myNonce', '0')
561
+
562
+ const value: ComputeCreateValue = {
563
+ type: 'compute-create',
564
+ arguments: {
565
+ deployerAddress: '{{myDeployer}}',
566
+ nonce: '{{myNonce}}',
567
+ },
568
+ }
569
+ const result = await resolver.resolve(value, context)
570
+ expect(result).toBe('0xBd770416a3345F91E4B34576cb804a576fa48EB1')
571
+ })
572
+
573
+ it('should throw error for invalid deployer address', async () => {
574
+ const value: ComputeCreateValue = {
575
+ type: 'compute-create',
576
+ arguments: {
577
+ deployerAddress: 'invalid-address',
578
+ nonce: '0',
579
+ },
580
+ }
581
+
582
+ await expect(resolver.resolve(value, context)).rejects.toThrow('Invalid deployer address: invalid-address')
583
+ })
584
+
585
+ it('should throw error for invalid nonce', async () => {
586
+ const value: ComputeCreateValue = {
587
+ type: 'compute-create',
588
+ arguments: {
589
+ deployerAddress: '0x0000000000000000000000000000000000000000',
590
+ nonce: 'invalid-nonce',
591
+ },
592
+ }
593
+
594
+ await expect(resolver.resolve(value, context)).rejects.toThrow('Invalid nonce: invalid-nonce')
595
+ })
596
+
597
+ it('should throw error for null deployer address', async () => {
598
+ const value: ComputeCreateValue = {
599
+ type: 'compute-create',
600
+ arguments: {
601
+ deployerAddress: null as any,
602
+ nonce: '0',
603
+ },
604
+ }
605
+
606
+ await expect(resolver.resolve(value, context)).rejects.toThrow('Invalid deployer address: null')
607
+ })
608
+
609
+ it('should throw error for undefined nonce', async () => {
610
+ const value: ComputeCreateValue = {
611
+ type: 'compute-create',
612
+ arguments: {
613
+ deployerAddress: '0x0000000000000000000000000000000000000000',
614
+ nonce: undefined as any,
615
+ },
616
+ }
617
+
618
+ await expect(resolver.resolve(value, context)).rejects.toThrow('Invalid nonce: undefined')
619
+ })
620
+
621
+ it('should handle checksummed addresses', async () => {
622
+ const value: ComputeCreateValue = {
623
+ type: 'compute-create',
624
+ arguments: {
625
+ deployerAddress: '0xdEADBEeF00000000000000000000000000000000',
626
+ nonce: '0',
627
+ },
628
+ }
629
+ const result = await resolver.resolve(value, context)
630
+ expect(result).toBe('0xf2048C36a5536FeA3Bc71d49ed59f2c65C546EEA')
631
+ })
632
+
633
+ it('should handle number nonce', async () => {
634
+ const value: ComputeCreateValue = {
635
+ type: 'compute-create',
636
+ arguments: {
637
+ deployerAddress: '0x0000000000000000000000000000000000000000',
638
+ nonce: 69420,
639
+ },
640
+ }
641
+ const result = await resolver.resolve(value, context)
642
+ expect(result).toBe('0x7Bd7F19787DA009bD75b849c92Db10CE11916487')
643
+ })
644
+ })
645
+
497
646
  describe('constructor-encode', () => {
498
647
  it('should encode creation code with no constructor arguments', async () => {
499
648
  const value = {
@@ -13,6 +13,7 @@ export type EngineOptions = {
13
13
  verificationRegistry?: VerificationPlatformRegistry
14
14
  noPostCheckConditions?: boolean
15
15
  allowMultipleNicksMethodTests?: boolean
16
+ ignoreVerifyErrors?: boolean
16
17
  }
17
18
 
18
19
  /**
@@ -27,7 +28,17 @@ export class ExecutionEngine {
27
28
  private readonly verificationRegistry: VerificationPlatformRegistry
28
29
  private readonly noPostCheckConditions: boolean
29
30
  private readonly allowMultipleNicksMethodTests: boolean
31
+ private readonly ignoreVerifyErrors: boolean
30
32
  private nicksMethodTested: boolean = false
33
+ private verificationWarnings: Array<{
34
+ actionName: string
35
+ address: string
36
+ contractName: string
37
+ platform: string
38
+ error: string
39
+ jobName?: string
40
+ networkName?: string
41
+ }> = []
31
42
 
32
43
  constructor(templates: Map<string, Template>, options?: EngineOptions) {
33
44
  this.resolver = new ValueResolver()
@@ -36,6 +47,7 @@ export class ExecutionEngine {
36
47
  this.verificationRegistry = options?.verificationRegistry || createDefaultVerificationRegistry()
37
48
  this.noPostCheckConditions = options?.noPostCheckConditions ?? false
38
49
  this.allowMultipleNicksMethodTests = options?.allowMultipleNicksMethodTests ?? false
50
+ this.ignoreVerifyErrors = options?.ignoreVerifyErrors ?? false
39
51
  }
40
52
 
41
53
  /**
@@ -631,6 +643,20 @@ export class ExecutionEngine {
631
643
  )
632
644
  anySuccess = true
633
645
  } catch (error) {
646
+ const errorMessage = error instanceof Error ? error.message : String(error)
647
+
648
+ // If ignoreVerifyErrors is enabled, add to warnings and continue
649
+ if (this.ignoreVerifyErrors) {
650
+ this.verificationWarnings.push({
651
+ actionName: actionName,
652
+ address,
653
+ contractName,
654
+ platform: platform.name,
655
+ error: errorMessage,
656
+ networkName: network.name
657
+ })
658
+ }
659
+
634
660
  // Log the error but continue with other platforms
635
661
  this.events.emitEvent({
636
662
  type: 'verification_failed',
@@ -640,14 +666,26 @@ export class ExecutionEngine {
640
666
  address,
641
667
  contractName,
642
668
  platform: platform.name,
643
- error: error instanceof Error ? error.message : String(error)
669
+ error: errorMessage
644
670
  }
645
671
  })
646
672
  }
647
673
  }
648
674
 
649
675
  if (!anySuccess) {
650
- throw new Error(`Verification failed on all configured platforms for network ${network.name}`)
676
+ if (this.ignoreVerifyErrors) {
677
+ // Don't throw error if ignoreVerifyErrors is enabled - warnings already collected
678
+ this.events.emitEvent({
679
+ type: 'verification_skipped',
680
+ level: 'warn',
681
+ data: {
682
+ actionName: actionName,
683
+ reason: `Verification failed on all configured platforms for network ${network.name}, but continuing due to --ignore-verify-errors`
684
+ }
685
+ })
686
+ } else {
687
+ throw new Error(`Verification failed on all configured platforms for network ${network.name}`)
688
+ }
651
689
  }
652
690
  } else {
653
691
  // Handle specific platform(s) verification
@@ -673,6 +711,20 @@ export class ExecutionEngine {
673
711
  )
674
712
  anySuccess = true
675
713
  } catch (error) {
714
+ const errorMessage = error instanceof Error ? error.message : String(error)
715
+
716
+ // If ignoreVerifyErrors is enabled, add to warnings
717
+ if (this.ignoreVerifyErrors) {
718
+ this.verificationWarnings.push({
719
+ actionName: actionName,
720
+ address,
721
+ contractName,
722
+ platform: platform.name,
723
+ error: errorMessage,
724
+ networkName: network.name
725
+ })
726
+ }
727
+
676
728
  // Log the error but continue with other platforms if multiple specified
677
729
  this.events.emitEvent({
678
730
  type: 'verification_failed',
@@ -682,19 +734,31 @@ export class ExecutionEngine {
682
734
  address,
683
735
  contractName,
684
736
  platform: platform.name,
685
- error: error instanceof Error ? error.message : String(error)
737
+ error: errorMessage
686
738
  }
687
739
  })
688
740
 
689
- // If only one platform specified, re-throw the error
690
- if (platformsToTry.length === 1) {
741
+ // If only one platform specified, re-throw the error unless ignoreVerifyErrors is enabled
742
+ if (platformsToTry.length === 1 && !this.ignoreVerifyErrors) {
691
743
  throw error
692
744
  }
693
745
  }
694
746
  }
695
747
 
696
748
  if (!anySuccess && platformsToTry.length > 1) {
697
- throw new Error(`Verification failed on all specified platforms: ${platformsToTry.join(', ')}`)
749
+ if (this.ignoreVerifyErrors) {
750
+ // Don't throw error if ignoreVerifyErrors is enabled - warnings already collected
751
+ this.events.emitEvent({
752
+ type: 'verification_skipped',
753
+ level: 'warn',
754
+ data: {
755
+ actionName: actionName,
756
+ reason: `Verification failed on all specified platforms: ${platformsToTry.join(', ')}, but continuing due to --ignore-verify-errors`
757
+ }
758
+ })
759
+ } else {
760
+ throw new Error(`Verification failed on all specified platforms: ${platformsToTry.join(', ')}`)
761
+ }
698
762
  }
699
763
  }
700
764
 
@@ -1635,4 +1699,26 @@ export class ExecutionEngine {
1635
1699
 
1636
1700
  return sorted
1637
1701
  }
1702
+
1703
+ /**
1704
+ * Get all verification warnings that were collected when ignoreVerifyErrors is enabled
1705
+ */
1706
+ public getVerificationWarnings(): Array<{
1707
+ actionName: string
1708
+ address: string
1709
+ contractName: string
1710
+ platform: string
1711
+ error: string
1712
+ jobName?: string
1713
+ networkName?: string
1714
+ }> {
1715
+ return [...this.verificationWarnings]
1716
+ }
1717
+
1718
+ /**
1719
+ * Clear verification warnings (useful for testing)
1720
+ */
1721
+ public clearVerificationWarnings(): void {
1722
+ this.verificationWarnings = []
1723
+ }
1638
1724
  }