@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.
- package/README.md +16 -0
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +4 -2
- package/dist/commands/run.js.map +1 -1
- package/dist/lib/__tests__/deployer.spec.js +71 -1
- package/dist/lib/__tests__/deployer.spec.js.map +1 -1
- package/dist/lib/core/__tests__/engine.spec.js +270 -0
- package/dist/lib/core/__tests__/engine.spec.js.map +1 -1
- package/dist/lib/core/__tests__/resolver.spec.js +132 -0
- package/dist/lib/core/__tests__/resolver.spec.js.map +1 -1
- package/dist/lib/core/engine.d.ts +13 -0
- package/dist/lib/core/engine.d.ts.map +1 -1
- package/dist/lib/core/engine.js +59 -5
- package/dist/lib/core/engine.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 +24 -7
- package/dist/lib/core/resolver.js.map +1 -1
- package/dist/lib/deployer.d.ts +2 -0
- package/dist/lib/deployer.d.ts.map +1 -1
- package/dist/lib/deployer.js +18 -1
- package/dist/lib/deployer.js.map +1 -1
- package/dist/lib/events/cli-adapter.d.ts.map +1 -1
- package/dist/lib/events/cli-adapter.js +20 -0
- package/dist/lib/events/cli-adapter.js.map +1 -1
- package/dist/lib/events/types.d.ts +25 -1
- package/dist/lib/events/types.d.ts.map +1 -1
- package/dist/lib/types/values.d.ts +8 -1
- package/dist/lib/types/values.d.ts.map +1 -1
- package/dist/lib/utils/assertion.d.ts +4 -0
- package/dist/lib/utils/assertion.d.ts.map +1 -0
- package/dist/lib/utils/assertion.js +27 -0
- package/dist/lib/utils/assertion.js.map +1 -0
- package/package.json +12 -13
- package/src/commands/run.ts +4 -1
- package/src/lib/__tests__/deployer.spec.ts +108 -1
- package/src/lib/core/__tests__/engine.spec.ts +321 -0
- package/src/lib/core/__tests__/resolver.spec.ts +150 -1
- package/src/lib/core/engine.ts +92 -6
- package/src/lib/core/resolver.ts +29 -8
- package/src/lib/deployer.ts +28 -1
- package/src/lib/events/cli-adapter.ts +24 -0
- package/src/lib/events/types.ts +29 -1
- package/src/lib/types/values.ts +10 -1
- 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 = {
|
package/src/lib/core/engine.ts
CHANGED
|
@@ -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:
|
|
669
|
+
error: errorMessage
|
|
644
670
|
}
|
|
645
671
|
})
|
|
646
672
|
}
|
|
647
673
|
}
|
|
648
674
|
|
|
649
675
|
if (!anySuccess) {
|
|
650
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
}
|