diff --git a/packages/evm/contracts/adapters/Wormhole/WormholeAdapter.sol b/packages/evm/contracts/adapters/Wormhole/WormholeAdapter.sol index 814986d7..a279bb09 100644 --- a/packages/evm/contracts/adapters/Wormhole/WormholeAdapter.sol +++ b/packages/evm/contracts/adapters/Wormhole/WormholeAdapter.sol @@ -6,29 +6,30 @@ import { OracleAdapter } from "../OracleAdapter.sol"; import { BlockHashOracleAdapter } from "../BlockHashOracleAdapter.sol"; contract WormholeAdapter is OracleAdapter, BlockHashOracleAdapter { - IWormhole public wormhole; - bytes32 public headerReporter; + IWormhole public immutable wormhole; + bytes32 public immutable reporter; + uint16 public immutable wormholeSourceChainId; + uint256 public immutable sourceChainId; error InvalidMessage(address emitter, VM vm, string reason); - error InvalidChainId(address emitter, uint16 chainId); + error InvalidEmitterChainId(address emitter, uint16 chainId); error InvalidReporter(address emitter, bytes32 reporter); - constructor(IWormhole _wormhole, bytes32 _headerReporter) { - wormhole = _wormhole; - headerReporter = _headerReporter; + constructor(IWormhole wormhole_, address reporter_, uint256 sourceChainId_, uint16 wormholeSourceChainId_) { + wormhole = wormhole_; + reporter = bytes32(uint256(uint160(reporter_))); + sourceChainId = sourceChainId_; + wormholeSourceChainId = wormholeSourceChainId_; } /// @dev Stores the block header for a given block. - /// @param blockNumber Identifier for the block for which to set the header. - /// @param chainId Identifier for the - /// @param vm Structured data reflecting the content of the Wormhole Verified Action Approval. - /// @notice Only callable by `wormhole` with a message passed from `headerReporter. - function storeBlockHeader(uint256 blockNumber, uint16 chainId, VM memory vm) public { - (VM memory _vm, bool valid, string memory reason) = wormhole.parseAndVerifyVM(abi.encode(vm)); + /// @param encodedVM Encoded data reflecting the content of the Wormhole Verified Action Approval. + function storeHashByEncodedVM(bytes calldata encodedVM) public { + (VM memory vm, bool valid, string memory reason) = wormhole.parseAndVerifyVM(encodedVM); if (!valid) revert InvalidMessage(address(this), vm, reason); - if (_vm.emitterChainId != chainId) revert InvalidChainId(address(this), _vm.emitterChainId); - if (_vm.emitterAddress != headerReporter) revert InvalidReporter(address(this), _vm.emitterAddress); - bytes32 newHash = abi.decode(_vm.payload, (bytes32)); - _storeHash(uint256(chainId), blockNumber, newHash); + if (vm.emitterChainId != wormholeSourceChainId) revert InvalidEmitterChainId(address(this), vm.emitterChainId); + if (vm.emitterAddress != reporter) revert InvalidReporter(address(this), vm.emitterAddress); + (uint256 id, bytes32 hash) = abi.decode(vm.payload, (uint256, bytes32)); + _storeHash(sourceChainId, id, hash); } } diff --git a/packages/evm/contracts/adapters/Wormhole/WormholeHeaderReporter.sol b/packages/evm/contracts/adapters/Wormhole/WormholeHeaderReporter.sol index 1fb0e366..81090eca 100644 --- a/packages/evm/contracts/adapters/Wormhole/WormholeHeaderReporter.sol +++ b/packages/evm/contracts/adapters/Wormhole/WormholeHeaderReporter.sol @@ -6,20 +6,19 @@ import { IWormhole } from "./IWormhole.sol"; contract WormholeHeaderReporter { IWormhole public immutable wormhole; - address public oracleAdapter; HeaderStorage public immutable headerStorage; - constructor(IWormhole _wormhole, HeaderStorage _headerStorage) { - wormhole = _wormhole; - headerStorage = _headerStorage; + constructor(IWormhole wormhole_, HeaderStorage headerStorage_) { + wormhole = wormhole_; + headerStorage = headerStorage_; } - /// @dev Reports the given block header to the oracleAdapter via the Wormhole. + /// @dev Reports the given block header to the adapter via the Wormhole. /// @param blockNumber Uint256 block number to pass over the Wormhole. /// @param sequence Uint64 value used to retrive generated VAA from the wormhole network. function reportHeader(uint256 blockNumber) public returns (uint64 sequence) { bytes32 blockHeader = headerStorage.storeBlockHeader(blockNumber); - bytes memory payload = abi.encodeWithSignature("storeBlockHeader(uint256,bytes32)", blockNumber, blockHeader); + bytes memory payload = abi.encode(blockNumber, blockHeader); uint32 nonce = 0; uint8 consistencyLevel = 201; sequence = wormhole.publishMessage(nonce, payload, consistencyLevel); diff --git a/packages/evm/tasks/deploy/index.ts b/packages/evm/tasks/deploy/index.ts index 2001043f..0846cce8 100644 --- a/packages/evm/tasks/deploy/index.ts +++ b/packages/evm/tasks/deploy/index.ts @@ -3,6 +3,7 @@ import { HardhatRuntimeEnvironment } from "hardhat/types" import "./hashi" import "./replay" +import "./wormhole" // eslint-disable-next-line @typescript-eslint/no-explicit-any export const verify = async (hre: HardhatRuntimeEnvironment, contract: Contract, constructorArguments: any = []) => { diff --git a/packages/evm/tasks/deploy/wormhole.ts b/packages/evm/tasks/deploy/wormhole.ts new file mode 100644 index 00000000..6d0fc9fe --- /dev/null +++ b/packages/evm/tasks/deploy/wormhole.ts @@ -0,0 +1,56 @@ +import type { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" +import { task, types } from "hardhat/config" +import type { TaskArguments } from "hardhat/types" + +import { verify } from "." +import type { WormholeAdapter } from "../../types/contracts/adapters/Wormhole/WormholeAdapter" +import type { WormholeHeaderReporter } from "../../types/contracts/adapters/Wormhole/WormholeHeaderReporter" +import type { WormholeAdapter__factory } from "../../types/factories/contracts/adapters/Wormhole/WormholeAdapter__factory" +import { WormholeHeaderReporter__factory } from "../../types/factories/contracts/adapters/Wormhole/WormholeHeaderReporter__factory" + +// Deploy on destination chain +task("deploy:Wormhole:Adapter") + .addParam("wormhole", "address of the Wormhole contract", undefined, types.string) + .addParam("reporter", "address of the hash reporter", undefined, types.string) + .addParam("chainId", "source chain id", undefined, types.string) + .addParam("wormholeChainId", "wormhole source chain id", undefined, types.string) + .addFlag("verify", "whether to verify the contract on Etherscan") + .setAction(async function (taskArguments: TaskArguments, hre) { + console.log("Deploying WormholeAdapter...") + const signers: SignerWithAddress[] = await hre.ethers.getSigners() + const wormholeAdapterFactory: WormholeAdapter__factory = ( + await hre.ethers.getContractFactory("WormholeAdapter") + ) + const constructorArguments = [ + taskArguments.wormhole, + taskArguments.reporter, + taskArguments.chainId, + taskArguments.wormholeChainId, + ] as const + const wormholeAdapter: WormholeAdapter = ( + await wormholeAdapterFactory.connect(signers[0]).deploy(...constructorArguments) + ) + await wormholeAdapter.deployed() + console.log("WormholeAdapter deployed to:", wormholeAdapter.address) + if (taskArguments.verify) await verify(hre, wormholeAdapter, constructorArguments) + }) + +// Deploy source chain +task("deploy:Wormhole:HeaderReporter") + .addParam("wormhole", "address of the Wormhole contract", undefined, types.string) + .addParam("headerStorage", "address of the header storage contract", undefined, types.string) + .addFlag("verify", "whether to verify the contract on Etherscan") + .setAction(async function (taskArguments: TaskArguments, hre) { + console.log("Deploying WormholeHeaderReporter...") + const signers: SignerWithAddress[] = await hre.ethers.getSigners() + const wormholeHeaderReporterFactory: WormholeHeaderReporter__factory = ( + await hre.ethers.getContractFactory("WormholeHeaderReporter") + ) + const constructorArguments = [taskArguments.wormhole, taskArguments.headerStorage] as const + const wormholeHeaderReporter: WormholeHeaderReporter = ( + await wormholeHeaderReporterFactory.connect(signers[0]).deploy(...constructorArguments) + ) + await wormholeHeaderReporter.deployed() + console.log("WormholeHeaderReporter deployed to:", wormholeHeaderReporter.address) + if (taskArguments.verify) await verify(hre, wormholeHeaderReporter, constructorArguments) + })