diff --git a/docs/standalone-usage.md b/docs/standalone-usage.md new file mode 100644 index 0000000..dfbde39 --- /dev/null +++ b/docs/standalone-usage.md @@ -0,0 +1,27 @@ +# GM-NET Standalone Bridge Usage + +If the official Gitlawb integration is still pending, you can use the bridge contract directly to anchor your repository state. + +## Contract Address (Base) +`0x...` (Deploying soon) + +## Usage Example (ethers.js) + +```javascript +const bridge = new ethers.Contract(BRIDGE_ADDRESS, BRIDGE_ABI, signer); + +// 1. Prepare your GM-NET state root +const stateRoot = "0x..."; + +// 2. Anchor your repo state +const tx = await bridge.anchorRepoState("did:key:z6Mk...", stateRoot); +await tx.wait(); + +console.log("State anchored to GM-NET!"); +``` + +## Verification +You can verify the latest anchored root for any DID: +```javascript +const root = await bridge.latestStateRoot(ethers.utils.id("did:key:z6Mk...")); +``` diff --git a/src/GitlawbStateAnchor.sol b/src/GitlawbStateAnchor.sol new file mode 100644 index 0000000..e26c8bf --- /dev/null +++ b/src/GitlawbStateAnchor.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +interface IGitlawbDIDRegistry { + function didToOwner(bytes32 didHash) external view returns (address); +} + +/// @title GitlawbStateAnchor +/// @notice Bridge between Gitlawb DIDs and GM-NET verifiable state roots. +/// @dev Powered by @bankr +contract GitlawbStateAnchor { + IGitlawbDIDRegistry public immutable registry; + + /// Maps keccak256(did) => latest anchored state root + mapping(bytes32 => bytes32) public latestStateRoot; + + event RepoStateAnchored(bytes32 indexed didHash, bytes32 indexed stateRoot, address indexed anchorer); + + error NotDIDOwner(bytes32 didHash, address caller); + + constructor(address _registry) { + registry = IGitlawbDIDRegistry(_registry); + } + + /// @notice Anchor a new state root for a Gitlawb DID. + /// @param did Full DID string (e.g. "did:key:z6Mk...") + /// @param stateRoot The bytes32 root from GM-NET + function anchorRepoState(string calldata did, bytes32 stateRoot) external { + bytes32 didHash = keccak256(bytes(did)); + address owner = registry.didToOwner(didHash); + + if (owner != msg.sender) revert NotDIDOwner(didHash, msg.sender); + + latestStateRoot[didHash] = stateRoot; + emit RepoStateAnchored(didHash, stateRoot, msg.sender); + } +}