Files
CurrenciCombo/contracts/NotaryRegistry.sol

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;
}
}