102 lines
3.1 KiB
Solidity
102 lines
3.1 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.20;
|
|
|
|
import "@openzeppelin/contracts/access/Ownable.sol";
|
|
import "./interfaces/INotaryRegistry.sol";
|
|
|
|
/**
|
|
* @title NotaryRegistry
|
|
* @notice Immutable registry for plan hashes, codehashes, and audit trail
|
|
*/
|
|
contract NotaryRegistry is INotaryRegistry, Ownable {
|
|
mapping(bytes32 => PlanRecord) public plans;
|
|
mapping(bytes32 => CodehashRecord) public codehashes;
|
|
|
|
event PlanRegistered(bytes32 indexed planId, address indexed creator, bytes32 planHash);
|
|
event PlanFinalized(bytes32 indexed planId, bool success, bytes32 receiptHash);
|
|
event CodehashRegistered(address indexed contractAddress, bytes32 codehash, string version);
|
|
|
|
/**
|
|
* @notice Register a plan with notary
|
|
*/
|
|
function registerPlan(
|
|
bytes32 planId,
|
|
IComboHandler.Step[] calldata steps,
|
|
address creator
|
|
) external override {
|
|
require(plans[planId].registeredAt == 0, "Plan already registered");
|
|
|
|
bytes32 planHash = keccak256(abi.encode(planId, steps, creator));
|
|
|
|
plans[planId] = PlanRecord({
|
|
planHash: planHash,
|
|
creator: creator,
|
|
registeredAt: block.timestamp,
|
|
finalizedAt: 0,
|
|
success: false,
|
|
receiptHash: bytes32(0)
|
|
});
|
|
|
|
emit PlanRegistered(planId, creator, planHash);
|
|
}
|
|
|
|
/**
|
|
* @notice Finalize a plan with execution result
|
|
*/
|
|
function finalizePlan(
|
|
bytes32 planId,
|
|
bool success
|
|
) external override {
|
|
PlanRecord storage record = plans[planId];
|
|
require(record.registeredAt > 0, "Plan not registered");
|
|
require(record.finalizedAt == 0, "Plan already finalized");
|
|
|
|
bytes32 receiptHash = keccak256(abi.encode(planId, success, block.timestamp));
|
|
|
|
record.finalizedAt = block.timestamp;
|
|
record.success = success;
|
|
record.receiptHash = receiptHash;
|
|
|
|
emit PlanFinalized(planId, success, receiptHash);
|
|
}
|
|
|
|
/**
|
|
* @notice Register contract codehash for upgrade verification
|
|
*/
|
|
function registerCodehash(
|
|
address contractAddress,
|
|
bytes32 codehash,
|
|
string calldata version
|
|
) external onlyOwner {
|
|
codehashes[keccak256(abi.encodePacked(contractAddress, version))] = CodehashRecord({
|
|
contractAddress: contractAddress,
|
|
codehash: codehash,
|
|
version: version,
|
|
registeredAt: block.timestamp
|
|
});
|
|
|
|
emit CodehashRegistered(contractAddress, codehash, version);
|
|
}
|
|
|
|
/**
|
|
* @notice Get plan record
|
|
*/
|
|
function getPlan(bytes32 planId) external view returns (PlanRecord memory) {
|
|
return plans[planId];
|
|
}
|
|
|
|
/**
|
|
* @notice Verify codehash matches registered version
|
|
*/
|
|
function verifyCodehash(
|
|
address contractAddress,
|
|
bytes32 codehash,
|
|
string calldata version
|
|
) external view returns (bool) {
|
|
bytes32 key = keccak256(abi.encodePacked(contractAddress, version));
|
|
CodehashRecord memory record = codehashes[key];
|
|
return record.codehash == codehash && record.registeredAt > 0;
|
|
}
|
|
}
|
|
|