dop-stick
Version:
Source control tooling for versionable-upgradeable smart contracts
147 lines • 7.03 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConstructorVerifier = void 0;
const ethers_1 = require("ethers");
const logger_1 = require("./logsAndMetrics/core/logger");
class ConstructorVerifier {
static async verifyConstructorArgs(factory, args, standardType) {
try {
// Get constructor fragment from factory
const constructorFragment = factory.interface.fragments.find((f) => f.type === 'constructor');
if (!constructorFragment) {
throw new Error('No constructor found in contract ABI');
}
// Verify based on standard type
switch (standardType) {
case 'standard-type-1':
return this.verifyType1Constructor(constructorFragment, args);
case 'standard-type-2':
return this.verifyType2Constructor(constructorFragment, args);
case 'standard-type-3':
return this.verifyType3Constructor(constructorFragment, args);
case 'custom':
logger_1.Logger.warning('Custom standard type: skipping constructor verification');
return true;
default:
throw new Error(`Unknown standard type: ${standardType}`);
}
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
logger_1.Logger.error(`Constructor verification failed: ${errorMessage}`);
throw error;
}
}
static verifyType1Constructor(constructorFragment, args) {
// Type 1: constructor(IDiamondCut.FacetCut[] memory _diamondCut, DiamondArgs memory _args)
// where DiamondArgs = { address owner; address init; bytes initCalldata; }
const expectedParams = [
{ name: '_diamondCut', type: 'tuple[]' },
{
name: 'diamondArgs',
type: 'tuple',
components: [
{ name: 'owner', type: 'address' },
{ name: 'init', type: 'address' },
{ name: 'initCalldata', type: 'bytes' }
]
}
];
return this.verifyParameters(constructorFragment, expectedParams, args);
}
static verifyType2Constructor(constructorFragment, args) {
// Type 2: constructor(IDiamondCut.FacetCut[] memory _diamondCut, DiamondArgs memory _args)
// where DiamondArgs = { address owner; }
const expectedParams = [
{ name: '_diamondCut', type: 'tuple[]' },
{
name: 'diamondArgs',
type: 'tuple',
components: [
{ name: 'owner', type: 'address' }
]
}
];
return this.verifyParameters(constructorFragment, expectedParams, args);
}
static verifyType3Constructor(constructorFragment, args) {
// Type 3: constructor(address _contractOwner, address _diamondCutFacet)
const expectedParams = [
{ name: '_contractOwner', type: 'address' },
{ name: '_diamondCutFacet', type: 'address' }
];
return this.verifyParameters(constructorFragment, expectedParams, args);
}
static verifyParameters(constructorFragment, expectedParams, args) {
const constructorParams = constructorFragment.inputs;
// Check parameter count
if (constructorParams.length !== expectedParams.length) {
throw new Error(`Constructor parameter count mismatch. Expected ${expectedParams.length}, got ${constructorParams.length}`);
}
// Check each parameter
for (let i = 0; i < expectedParams.length; i++) {
const expected = expectedParams[i];
const actual = constructorParams[i];
// Check parameter type
if (!this.isTypeCompatible(expected.type, actual.type)) {
throw new Error(`Parameter type mismatch for ${expected.name}. Expected ${expected.type}, got ${actual.type}`);
}
// For tuple types, verify components if they exist
if (expected.type === 'tuple' && expected.components) {
const actualComponents = actual.components;
if (!actualComponents) {
throw new Error(`Expected tuple components for ${expected.name} but none found`);
}
if (actualComponents.length !== expected.components.length) {
throw new Error(`Tuple component count mismatch for ${expected.name}. Expected ${expected.components.length}, got ${actualComponents.length}`);
}
// Verify each component
for (let j = 0; j < expected.components.length; j++) {
const expectedComp = expected.components[j];
const actualComp = actualComponents[j];
if (!this.isTypeCompatible(expectedComp.type, actualComp.type)) {
throw new Error(`Tuple component type mismatch for ${expected.name}.${expectedComp.name}. Expected ${expectedComp.type}, got ${actualComp.type}`);
}
}
}
// Check if required argument is provided
if (!(expected.name in args)) {
throw new Error(`Missing required constructor argument: ${expected.name}`);
}
}
return true;
}
static isTypeCompatible(expectedType, actualType) {
// Handle array types
if (expectedType.includes('[]') && actualType.includes('[]')) {
return this.isTypeCompatible(expectedType.replace('[]', ''), actualType.replace('[]', ''));
}
// Handle tuple types
if (expectedType.startsWith('tuple') && actualType.startsWith('tuple')) {
return true; // We handle tuple verification separately in verifyParameters
}
return expectedType === actualType;
}
static verify(args) {
// Verify all addresses in args
args.forEach((arg, index) => {
if (typeof arg === 'string' && arg.startsWith('0x')) {
if (!ethers_1.ethers.utils.isAddress(arg)) {
throw new Error(`Invalid address at position ${index}: ${arg}`);
}
}
else if (typeof arg === 'object') {
// Recursively check objects for addresses
Object.entries(arg).forEach(([key, value]) => {
if (typeof value === 'string' && value.startsWith('0x')) {
if (!ethers_1.ethers.utils.isAddress(value)) {
throw new Error(`Invalid address in ${key}: ${value}`);
}
}
});
}
});
}
}
exports.ConstructorVerifier = ConstructorVerifier;
//# sourceMappingURL=constructorVerifier.js.map