feat: add universal resource policy profile registry

This commit is contained in:
defiQUG
2026-04-24 22:06:26 -07:00
parent 045a6a9245
commit 4540ec4480
3 changed files with 114 additions and 0 deletions

View File

@@ -0,0 +1,64 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
/**
* @title PolicyProfileRegistry
* @notice Minimal on-chain anchor for URA `policyProfileId` rows (content hash + version + effective time).
* Pair with off-chain `config/universal-resource-activation/policy-profiles.json` and
* `scripts/ura/policy-profiles-content-hash.mjs` in the proxmox repo. Not a full GRU M00 diamond.
*/
contract PolicyProfileRegistry is AccessControl {
bytes32 public constant PUBLISHER_ROLE = keccak256("PUBLISHER_ROLE");
struct Record {
bytes32 contentHash;
uint64 version;
uint256 effectiveFrom;
bool exists;
}
mapping(bytes32 => Record) private _records;
event ProfilePublished(
bytes32 indexed profileKey,
string policyProfileId,
bytes32 contentHash,
uint64 version,
uint256 effectiveFrom
);
constructor(address admin) {
require(admin != address(0), "PolicyProfileRegistry: admin");
_grantRole(DEFAULT_ADMIN_ROLE, admin);
_grantRole(PUBLISHER_ROLE, admin);
}
function profileKey(string calldata policyProfileId) public pure returns (bytes32) {
return keccak256(bytes(policyProfileId));
}
/**
* @param contentHash keccak256 of canonical JSON for this profile row (see proxmox hash script)
*/
function publishProfile(
string calldata policyProfileId,
bytes32 contentHash,
uint64 version,
uint256 effectiveFrom
) external onlyRole(PUBLISHER_ROLE) {
bytes32 key = profileKey(policyProfileId);
_records[key] = Record({
contentHash: contentHash,
version: version,
effectiveFrom: effectiveFrom,
exists: true
});
emit ProfilePublished(key, policyProfileId, contentHash, version, effectiveFrom);
}
function getRecord(string calldata policyProfileId) external view returns (Record memory) {
return _records[profileKey(policyProfileId)];
}
}

View File

@@ -0,0 +1,21 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Script, console2} from "forge-std/Script.sol";
import {PolicyProfileRegistry} from "../../contracts/universal-resource/PolicyProfileRegistry.sol";
/// @notice Deploy standalone URA policy profile anchor (not full GRU M00). Set POLICY_PROFILE_REGISTRY_ADMIN or defaults to deployer.
contract DeployPolicyProfileRegistry is Script {
function run() external {
uint256 pk = vm.envUint("PRIVATE_KEY");
address deployer = vm.addr(pk);
address admin = vm.envOr("POLICY_PROFILE_REGISTRY_ADMIN", deployer);
vm.startBroadcast(pk);
PolicyProfileRegistry reg = new PolicyProfileRegistry(admin);
vm.stopBroadcast();
console2.log("PolicyProfileRegistry", address(reg));
console2.log("admin", admin);
}
}

View File

@@ -0,0 +1,29 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Test} from "forge-std/Test.sol";
import {PolicyProfileRegistry} from "../../contracts/universal-resource/PolicyProfileRegistry.sol";
contract PolicyProfileRegistryTest is Test {
PolicyProfileRegistry internal reg;
address internal admin = address(0xA11CE);
function setUp() public {
vm.prank(admin);
reg = new PolicyProfileRegistry(admin);
}
function testPublishAndRead() public {
bytes32 h = keccak256("profile-json");
vm.prank(admin);
reg.publishProfile("institutional_custody_skr_v1", h, 1, block.timestamp);
PolicyProfileRegistry.Record memory r = reg.getRecord("institutional_custody_skr_v1");
assertTrue(r.exists);
assertEq(r.contentHash, h);
assertEq(r.version, 1);
}
function testProfileKeyStable() public view {
assertEq(reg.profileKey("a"), keccak256(bytes("a")));
}
}