Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/v2-contracts/contracts/mock/interfaces/ICreateX.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

interface ICreateX {
struct Values {
uint256 constructorAmount;
uint256 initCallAmount;
}

function deployCreate2AndInit(
bytes32 salt_,
bytes memory initCode_,
bytes memory data_,
Values memory values_
) external payable returns (address newContract_);

function deployCreate2(
bytes32 salt_,
bytes memory initCode_
) external payable returns (address newContract_);

function computeCreate2Address(
bytes32 salt_,
bytes32 initCodeHash_
) external view returns (address computedAddress_);
}
40 changes: 40 additions & 0 deletions src/v2-contracts/deploy/1_SPVGatewayV2.migration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Deployer, Reporter } from "@solarity/hardhat-migrate";

import { SPVGatewayV2__factory, ICreateX__factory } from "@ethers-v6";

import { deployHistoryVerifier, getGuardedSalt } from "./helpers";
import { getConfig } from "./config/config";
import { ethers } from "hardhat";

export = async (deployer: Deployer) => {
const config = await getConfig();

const createXDeployer = await deployer.deployed(ICreateX__factory, "0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed");

const historyVerifierAddress = await deployHistoryVerifier(deployer);

const constructorArgsEncoded = SPVGatewayV2__factory.createInterface().encodeDeploy([
historyVerifierAddress,
config.chunkSize,
config.maxProofFrontierLength,
]);

const SPVGatewayV2Initcode = SPVGatewayV2__factory.bytecode + constructorArgsEncoded.slice(2);

const initCalldata = SPVGatewayV2__factory.createInterface().encodeFunctionData("__SPVGatewayV2_init()");

// zero address + 00 (cross-chain redeploy protection) + ASCII(SPV2Gateway)
const historicalSPVGatewaySalt = `0x0000000000000000000000000000000000000000005350563247617465776179`;

await createXDeployer.deployCreate2AndInit(historicalSPVGatewaySalt, SPVGatewayV2Initcode, initCalldata, {
constructorAmount: 0n,
initCallAmount: 0n,
});

const guardedSalt = getGuardedSalt(historicalSPVGatewaySalt);
const initcodeHash = ethers.keccak256(SPVGatewayV2Initcode);

const spvGatewayAddr = await createXDeployer.computeCreate2Address(guardedSalt, initcodeHash);

Reporter.reportContracts(["SPVGatewayV2", spvGatewayAddr]);
};
6 changes: 6 additions & 0 deletions src/v2-contracts/deploy/config/base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { DeployConfig } from "./types";

export const deployConfig: DeployConfig = {
chunkSize: 1n,
maxProofFrontierLength: 25n,
};
23 changes: 23 additions & 0 deletions src/v2-contracts/deploy/config/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import hre from "hardhat";

import { DeployConfig } from "./types";

export async function getConfig(): Promise<DeployConfig> {
if (hre.network.name == "localhost" || hre.network.name == "hardhat") {
return (await import("./localhost")).deployConfig;
}

if (hre.network.name == "sepolia") {
return (await import("./sepolia")).deployConfig;
}

if (hre.network.name == "base") {
return (await import("./base")).deployConfig;
}

if (hre.network.name == "ethereum") {
return (await import("./ethereum")).deployConfig;
}

throw new Error(`Config for network ${hre.network.name} is not specified`);
}
6 changes: 6 additions & 0 deletions src/v2-contracts/deploy/config/ethereum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { DeployConfig } from "./types";

export const deployConfig: DeployConfig = {
chunkSize: 1n,
maxProofFrontierLength: 25n,
};
6 changes: 6 additions & 0 deletions src/v2-contracts/deploy/config/localhost.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { DeployConfig } from "./types";

export const deployConfig: DeployConfig = {
chunkSize: 1n,
maxProofFrontierLength: 25n,
};
6 changes: 6 additions & 0 deletions src/v2-contracts/deploy/config/sepolia.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { DeployConfig } from "./types";

export const deployConfig: DeployConfig = {
chunkSize: 1n,
maxProofFrontierLength: 25n,
};
4 changes: 4 additions & 0 deletions src/v2-contracts/deploy/config/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export type DeployConfig = {
chunkSize: bigint;
maxProofFrontierLength: bigint;
};
5 changes: 5 additions & 0 deletions src/v2-contracts/deploy/helpers/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { ethers } from "hardhat";

export function getGuardedSalt(salt: string): string {
return ethers.keccak256(ethers.AbiCoder.defaultAbiCoder().encode(["bytes32"], [salt]));
}
2 changes: 2 additions & 0 deletions src/v2-contracts/deploy/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./helpers";
export * from "./verifiers";
29 changes: 29 additions & 0 deletions src/v2-contracts/deploy/helpers/verifiers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { getGuardedSalt } from "@/deploy/helpers/helpers";
import { ICreateX__factory, HistoryProofVerifier__factory } from "@/generated-types/ethers";
import { Deployer } from "@solarity/hardhat-migrate";
import { ethers } from "hardhat";

export async function deployHistoryVerifier(deployer: Deployer): Promise<string> {
const createXDeployer = await deployer.deployed(ICreateX__factory, "0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed");

const verifierBytecode = HistoryProofVerifier__factory.bytecode;
const verifierSalt = getHistoryVerifierSalt();

const verifierAddress = await createXDeployer.computeCreate2Address(
getGuardedSalt(verifierSalt),
ethers.keccak256(verifierBytecode),
);

if ((await ethers.provider.getCode(verifierAddress)).slice(2) == "") {
await createXDeployer.deployCreate2(verifierSalt, verifierBytecode);
}

return verifierAddress;
}

export function getHistoryVerifierSalt(): string {
const saltSuffix = ethers.hexlify(ethers.toUtf8Bytes(`HVerifier`));

// zero address + 00 (cross-chain redeploy protection) + 0000 + ASCII(HVerifier)
return `${ethers.ZeroAddress}000000${saltSuffix.slice(2)}`;
}