Skip to content

Commit

Permalink
fix: verification endpoint alignment with etherscan
Browse files Browse the repository at this point in the history
  • Loading branch information
kiriyaga committed Dec 24, 2024
1 parent 83560f0 commit 4484934
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 14 deletions.
6 changes: 3 additions & 3 deletions packages/api/src/api/contract/contract.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ describe("ContractController", () => {
contractname: "contracts/HelloWorld.sol:HelloWorld",
compilerversion: "0.8.17",
optimizationUsed: "1",
zkCompilerVersion: "v1.3.14",
zksolcVersion: "v1.3.14",
constructorArguements: "0x94869207468657265210000000000000000000000000000000000000000000000",
runs: 700,
libraryname1: "contracts/MiniMath.sol:MiniMath",
Expand Down Expand Up @@ -426,7 +426,7 @@ describe("ContractController", () => {
contractname: "contracts/Greeter.vy:Greeter",
compilerversion: "0.3.3",
optimizationUsed: "1",
zkCompilerVersion: "v1.3.11",
zksolcVersion: "v1.3.11",
} as unknown as VerifyContractRequestDto;

pipeMock.mockReturnValue(
Expand All @@ -442,7 +442,7 @@ describe("ContractController", () => {
codeFormat: "vyper-multi-file",
compilerVyperVersion: "0.3.3",
compilerZkvyperVersion: "v1.3.11",
constructorArguments: undefined,
constructorArguments: null,
contractAddress: "0x14174c76E073f8efEf5C1FE0dd0f8c2Ca9F21e62",
contractName: "contracts/Greeter.vy:Greeter",
optimizationUsed: true,
Expand Down
31 changes: 26 additions & 5 deletions packages/api/src/api/contract/contract.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import {
ContractVerificationStatusResponse,
} from "../types";
import { VerifyContractResponseDto } from "../dtos/contract/verifyContractResponse.dto";

const entityName = "contract";

export const parseAddressListPipeExceptionFactory = () => new BadRequestException("Missing contract addresses");
Expand Down Expand Up @@ -136,6 +135,12 @@ export class ContractController {
ContractVerificationCodeFormatEnum.solidityJsonInput,
].includes(request.codeformat);

// eslint-disable-next-line @typescript-eslint/no-var-requires
const semver = require("semver");
if (semver.gte(request.zksolcVersion, "1.3.23")) {
request.compilerversion = `zkVM-${request.compilerversion}-1.0.1`;
}

if (isSolidityContract && request.sourceCode instanceof Object) {
const libraries: { [key: string]: Record<string, string> } = {};
for (let i = 1; i <= 10; i++) {
Expand Down Expand Up @@ -166,21 +171,37 @@ export class ContractController {
}
}

let formatedStringSourceCode = undefined;
if (isSolidityContract && typeof request.sourceCode === "string") {
try {
formatedStringSourceCode = JSON.parse(request.sourceCode);
if (formatedStringSourceCode.settings.optimizer?.enabled) {
request.optimizationUsed = "1";
}
} catch (e) {
formatedStringSourceCode = request.sourceCode;
}
}

const { data } = await firstValueFrom<{ data: number }>(
this.httpService
.post(`${this.contractVerificationApiUrl}/contract_verification`, {
codeFormat: request.codeformat,
contractAddress,
contractName: request.contractname,
optimizationUsed: request.optimizationUsed === "1",
sourceCode: request.sourceCode,
constructorArguments: request.constructorArguements,
sourceCode: typeof request.sourceCode === "string" ? formatedStringSourceCode : request.sourceCode,
constructorArguments: request.constructorArguements
? request.constructorArguements.slice(0, 2) !== "0x"
? `0x${request.constructorArguements}`
: request.constructorArguements
: null,
...(isSolidityContract && {
compilerZksolcVersion: request.zkCompilerVersion,
compilerZksolcVersion: request.zksolcVersion,
compilerSolcVersion: request.compilerversion,
}),
...(!isSolidityContract && {
compilerZkvyperVersion: request.zkCompilerVersion,
compilerZkvyperVersion: request.zksolcVersion,
compilerVyperVersion: request.compilerversion,
}),
})
Expand Down
14 changes: 8 additions & 6 deletions packages/api/src/api/dtos/contract/verifyContractRequest.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { IsInt, IsOptional, Max, Min, IsEnum, IsString, IsNotEmpty, Matches } fr
import { ApiProperty } from "@nestjs/swagger";
import { Type } from "class-transformer";
import { ContractVerificationCodeFormatEnum } from "../../types";
import { FormatAndValidateCompilerVersion } from "../../../common/decorators/formatAndValidateCompilerVersion";

const fullLibraryNameRegexp = new RegExp("^(.)+:(.)+$");

Expand Down Expand Up @@ -86,17 +87,18 @@ export class VerifyContractRequestDto {
})
@IsString()
@IsNotEmpty({ message: "Missing Or invalid compilerversion." })
@FormatAndValidateCompilerVersion({ message: "Invalid compilerversion format." })
public compilerversion: string;

@ApiProperty({
name: "zkCompilerVersion",
name: "zksolcVersion",
description: "Zk compiler version",
example: "v1.3.14",
required: true,
})
@IsString()
@IsNotEmpty({ message: "Missing zkCompilerVersion" })
public zkCompilerVersion: string;
@IsNotEmpty({ message: "Missing zksolcVersion" })
public zksolcVersion: string;

@ApiProperty({
name: "runs",
Expand All @@ -115,19 +117,19 @@ export class VerifyContractRequestDto {
name: "optimizationUsed",
description: "0 = No Optimization, 1 = Optimization used",
example: "1",
required: true,
required: false,
})
@IsEnum(["0", "1"], {
message: "Invalid optimizationUsed",
})
@IsNotEmpty({ message: "Missing optimizationUsed" })
@IsOptional()
public optimizationUsed: string;

@ApiProperty({
name: "constructorArguements",
description: "Contract constructor arguments",
example:
"0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000094869207468657265210000000000000000000000000000000000000000000000",
"0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000094869207468657265210000000000000000000000000000000000000000000000 or 000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000094869207468657265210000000000000000000000000000000000000000000000",
required: false,
})
@IsOptional()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { validate } from "class-validator";
import { FormatAndValidateCompilerVersion } from "./formatAndValidateCompilerVersion";

class TestDto {
constructor(version: string) {
this.version = version;
}

@FormatAndValidateCompilerVersion()
public version: string;
}

describe("FormatAndValidateCompilerVersion", () => {
it("when version is null returns a validation error", async () => {
const errors = await validate(new TestDto(null));
expect(errors.length).toBe(1);
expect(errors[0].property).toBe("version");
});

it("when version is an empty string returns a validation error", async () => {
const errors = await validate(new TestDto(""));
expect(errors.length).toBe(1);
expect(errors[0].property).toBe("version");
});

it("when version is a valid", async () => {
const errors = await validate(new TestDto("2.3.7"));
expect(errors.length).toBe(0);
});

it("when version is valid with commit", async () => {
const errors = await validate(new TestDto("2.5.7-commit.32"));
expect(errors.length).toBe(0);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { registerDecorator, ValidationOptions } from "class-validator";
export function FormatAndValidateCompilerVersion(validationOptions?: ValidationOptions) {
return function (object: any, propertyName: string) {
registerDecorator({
name: "formatAndValidateCompilerVersion",
target: object.constructor,
propertyName: propertyName,
options: validationOptions,
validator: {
validate(value: any) {
return value && typeof value === "string";
},
},
});
// Custom setter to format the value
Object.defineProperty(object, propertyName, {
set(value: string) {
const regex = /^(0\.\d+\.\d+(\.\d+)?|zkVM-\d+\.\d+\.\d+(\.\d+)?-\d+\.\d+\.\d+(\.\d+)?)$/;
if (value && !regex.test(value)) {
let [major, minor, patch] = value.split(".");
major = major.slice(1);
patch = patch.replace(/\+.*$/, "");
minor = minor;
const formattedValue = `${major}.${minor}.${patch}`;
Object.defineProperty(object, `_${propertyName}`, {
value: formattedValue,
writable: true,
configurable: true,
});
} else {
Object.defineProperty(object, `_${propertyName}`, {
value: value,
writable: true,
configurable: true,
});
}
},
get() {
return this[`_${propertyName}`];
},
});
};
}

0 comments on commit 4484934

Please sign in to comment.