did:cow, a proposal for an ID resolution method with most of the convenience of did:plc/did:web and the robustness of a public blockchain
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

shorter method/event names

+46 -46
+5 -5
README.md
··· 92 92 93 93 ### 6.2 Read (Resolution) 94 94 95 - Call `resolveCow(initial_controller_address, initial_wrapped_did)` against the registry contract. 95 + Call `resolve(initial_controller_address, initial_wrapped_did)` against the registry contract. 96 96 97 97 The did:cow registry contract performs the following steps: 98 98 ··· 114 114 115 115 Call `deactivate(initial_controller_address, initial_wrapped_did)` from the current controller to permanently deactivate a did:cow ID. If the did:cow ID has not been registered on-chain yet, it will be registered automatically in the same transaction. 116 116 117 - After deactivation, `resolveCow` returns an empty string and the DID cannot be reactivated. 117 + After deactivation, `resolve` returns an empty string and the DID cannot be reactivated. 118 118 119 119 NB: It is permitted to set the controller to `0x0` via `updateController` without deactivating, in which case the DID continues to resolve but can never be updated or deactivated. 120 120 ··· 166 166 Deployed on Sepolia testnet: [`0xfca809F35369b6A5F47f52226893Ae1B55eE281b`](https://sepolia.etherscan.io/address/0xfca809F35369b6A5F47f52226893Ae1B55eE281b) 167 167 168 168 **Contract functions (`CowRegistry.sol`):** 169 - - `calculateCowHash(controller, wrappedDID)` — derive the registry key for a did:cow ID 170 - - `resolveCow(controller, wrappedDID)` — return current controller and wrapped DID without needing to pre-compute the hash 171 - - `initializeCow(controller, wrappedDID)` — optionally pre-register before first update 169 + - `calculateHash(controller, wrappedDID)` — derive the registry key for a did:cow ID 170 + - `resolve(controller, wrappedDID)` — return current controller and wrapped DID without needing to pre-compute the hash 171 + - `initialize(controller, wrappedDID)` — optionally pre-register before first update 172 172 - `updateWrappedDID(controller, wrappedDID, newWrappedDID)` — update wrapped DID, registering if needed 173 173 - `updateWrappedDIDByHash(cowHash, newWrappedDID)` — update wrapped DID by pre-computed hash 174 174 - `updateController(controller, wrappedDID, newController)` — transfer control, registering if needed
+4 -4
cli/cow.py
··· 179 179 w3 = _w3() 180 180 contract = _contract(w3) 181 181 182 - wrapped_did, _ = contract.functions.resolveCow( 182 + wrapped_did, _ = contract.functions.resolve( 183 183 _controller_address(controller_hex), 184 184 initial_wrapped, 185 185 ).call() ··· 200 200 w3 = _w3() 201 201 contract = _contract(w3) 202 202 203 - wrapped_did, controller = contract.functions.resolveCow( 203 + wrapped_did, controller = contract.functions.resolve( 204 204 _controller_address(controller_hex), 205 205 initial_wrapped, 206 206 ).call() ··· 209 209 click.echo("status: deactivated") 210 210 return 211 211 212 - cow_hash = contract.functions.calculateCowHash( 212 + cow_hash = contract.functions.calculateHash( 213 213 _controller_address(controller_hex), 214 214 initial_wrapped, 215 215 ).call() ··· 288 288 contract = _contract(w3) 289 289 account = _account(w3) 290 290 291 - tx = contract.functions.initializeCow( 291 + tx = contract.functions.initialize( 292 292 _controller_address(controller_hex), 293 293 initial_wrapped, 294 294 ).build_transaction({"from": account.address})
+17 -17
src/CowRegistry.sol
··· 29 29 mapping(bytes32 => Cow) public cows; 30 30 31 31 /// @notice Emitted when a cow is registered on-chain for the first time. 32 - event CowInitialized(bytes32 indexed cowHash, address controller, string wrappedDID); 32 + event Initialized(bytes32 indexed cowHash, address controller, string wrappedDID); 33 33 34 34 /// @notice Emitted when a cow is permanently deactivated. 35 - event CowDeactivated(bytes32 indexed cowHash); 35 + event Deactivated(bytes32 indexed cowHash); 36 36 37 37 /// @notice Emitted when a cow's controller address is updated. 38 38 event ControllerUpdated(bytes32 indexed cowHash, address controller); ··· 44 44 /// @param _controller The initial controller address. 45 45 /// @param _wrappedDID The initial wrapped DID, without the leading "did:" prefix. 46 46 /// @return The keccak256 hash used as the key in the cows mapping. 47 - function calculateCowHash(address _controller, string memory _wrappedDID) public pure returns (bytes32) { 47 + function calculateHash(address _controller, string memory _wrappedDID) public pure returns (bytes32) { 48 48 return keccak256(abi.encodePacked(_controller, _wrappedDID)); 49 49 } 50 50 ··· 53 53 /// @param _controller The initial controller address from the did:cow identifier. 54 54 /// @param _wrappedDID The initial wrapped DID from the did:cow identifier, without "did:". 55 55 /// @return cowHash The registry key for this did:cow identifier. 56 - function _ensureCowInitialized(address _controller, string memory _wrappedDID) internal returns (bytes32 cowHash) { 57 - cowHash = calculateCowHash(_controller, _wrappedDID); 56 + function _ensureInitialized(address _controller, string memory _wrappedDID) internal returns (bytes32 cowHash) { 57 + cowHash = calculateHash(_controller, _wrappedDID); 58 58 Cow storage cow = cows[cowHash]; 59 59 if (cow.deactivated) revert AlreadyDeactivated(); 60 60 if (!cow.initialized) { ··· 62 62 cow.initialized = true; 63 63 cow.controller = _controller; 64 64 cow.wrappedDID = _wrappedDID; 65 - emit CowInitialized(cowHash, _controller, _wrappedDID); 65 + emit Initialized(cowHash, _controller, _wrappedDID); 66 66 } 67 67 return cowHash; 68 68 } ··· 72 72 /// may not yet be registered on-chain. 73 73 /// Setting _controller to address(0) makes the cow permanently uncontrollable 74 74 /// without deactivating it — it will continue to resolve but can never be updated. 75 - /// @param _cowHash The cow's registry key, as returned by calculateCowHash. 75 + /// @param _cowHash The cow's registry key, as returned by calculateHash. 76 76 /// @param _controller The new controller address. 77 77 function updateControllerByHash(bytes32 _cowHash, address _controller) public { 78 78 Cow storage cow = cows[_cowHash]; ··· 87 87 /// @notice Update the wrapped DID for an already-registered cow. 88 88 /// @dev Caller must be the current controller. Use updateWrappedDID if the cow 89 89 /// may not yet be registered on-chain. 90 - /// @param _cowHash The cow's registry key, as returned by calculateCowHash. 90 + /// @param _cowHash The cow's registry key, as returned by calculateHash. 91 91 /// @param _wrappedDID The new wrapped DID, without the leading "did:" prefix. 92 92 function updateWrappedDIDByHash(bytes32 _cowHash, string memory _wrappedDID) public { 93 93 Cow storage cow = cows[_cowHash]; ··· 103 103 /// @notice Permanently deactivate an already-registered cow. 104 104 /// @dev Caller must be the current controller. Deactivation is irreversible. 105 105 /// Use deactivate if the cow may not yet be registered on-chain. 106 - /// @param _cowHash The cow's registry key, as returned by calculateCowHash. 106 + /// @param _cowHash The cow's registry key, as returned by calculateHash. 107 107 function deactivateByHash(bytes32 _cowHash) public { 108 108 Cow storage cow = cows[_cowHash]; 109 109 if (!cow.initialized) revert NotInitialized(); ··· 114 114 cow.controller = address(0); 115 115 cow.wrappedDID = ""; 116 116 117 - emit CowDeactivated(_cowHash); 117 + emit Deactivated(_cowHash); 118 118 } 119 119 120 120 /// @notice Optionally pre-register a cow on-chain before its first update. ··· 122 122 /// deactivate all register the cow automatically if needed. 123 123 /// @param _controller The initial controller address. 124 124 /// @param _wrappedDID The initial wrapped DID, without the leading "did:" prefix. 125 - function initializeCow(address _controller, string memory _wrappedDID) external { 126 - _ensureCowInitialized(_controller, _wrappedDID); 125 + function initialize(address _controller, string memory _wrappedDID) external { 126 + _ensureInitialized(_controller, _wrappedDID); 127 127 } 128 128 129 129 /// @notice Transfer control to a new address, registering the cow on-chain if not already present. ··· 131 131 /// @param _wrappedDID The initial wrapped DID from the did:cow identifier, without "did:". 132 132 /// @param _newController The new controller address. 133 133 function updateController(address _controller, string memory _wrappedDID, address _newController) external { 134 - bytes32 cowHash = _ensureCowInitialized(_controller, _wrappedDID); 134 + bytes32 cowHash = _ensureInitialized(_controller, _wrappedDID); 135 135 updateControllerByHash(cowHash, _newController); 136 136 } 137 137 ··· 140 140 /// @param _wrappedDID The initial wrapped DID from the did:cow identifier, without "did:". 141 141 /// @param _newWrappedDID The new wrapped DID, without the leading "did:" prefix. 142 142 function updateWrappedDID(address _controller, string memory _wrappedDID, string memory _newWrappedDID) external { 143 - bytes32 cowHash = _ensureCowInitialized(_controller, _wrappedDID); 143 + bytes32 cowHash = _ensureInitialized(_controller, _wrappedDID); 144 144 updateWrappedDIDByHash(cowHash, _newWrappedDID); 145 145 } 146 146 ··· 149 149 /// @param _controller The initial controller address from the did:cow identifier. 150 150 /// @param _wrappedDID The initial wrapped DID from the did:cow identifier, without "did:". 151 151 function deactivate(address _controller, string memory _wrappedDID) external { 152 - bytes32 cowHash = _ensureCowInitialized(_controller, _wrappedDID); 152 + bytes32 cowHash = _ensureInitialized(_controller, _wrappedDID); 153 153 deactivateByHash(cowHash); 154 154 } 155 155 ··· 159 159 /// @param _wrappedDID The initial wrapped DID from the did:cow identifier, without "did:". 160 160 /// @return wrappedDID The current full wrapped DID (with "did:" prepended), or empty string if deactivated. 161 161 /// @return controller The current controller address. 162 - function resolveCow(address _controller, string memory _wrappedDID) 162 + function resolve(address _controller, string memory _wrappedDID) 163 163 external 164 164 view 165 165 returns (string memory wrappedDID, address controller) 166 166 { 167 - bytes32 cowHash = calculateCowHash(_controller, _wrappedDID); 167 + bytes32 cowHash = calculateHash(_controller, _wrappedDID); 168 168 Cow storage cow = cows[cowHash]; 169 169 if (cow.deactivated) { 170 170 return ("", address(0));
+20 -20
test/CowRegistry.t.sol
··· 25 25 } 26 26 27 27 function _init(address ctrl, string memory did) internal returns (bytes32) { 28 - registry.initializeCow(ctrl, did); 29 - return registry.calculateCowHash(ctrl, did); 28 + registry.initialize(ctrl, did); 29 + return registry.calculateHash(ctrl, did); 30 30 } 31 31 32 32 // ========================================================================= 33 - // updateWrappedDID — pre-registered (initializeCow already called) 33 + // updateWrappedDID — pre-registered (initialize already called) 34 34 // ========================================================================= 35 35 36 36 function test_preregistered_updateWrappedDID_plc1_to_plc2() public { ··· 165 165 vm.prank(controller1); 166 166 registry.updateWrappedDID(controller1, plcDID1, plcDID2); 167 167 168 - bytes32 cowHash = registry.calculateCowHash(controller1, plcDID1); 168 + bytes32 cowHash = registry.calculateHash(controller1, plcDID1); 169 169 (,,, string memory did) = registry.cows(cowHash); 170 170 assertEq(did, plcDID2); 171 171 } ··· 174 174 vm.prank(controller2); 175 175 registry.updateWrappedDID(controller2, plcDID2, plcDID1); 176 176 177 - bytes32 cowHash = registry.calculateCowHash(controller2, plcDID2); 177 + bytes32 cowHash = registry.calculateHash(controller2, plcDID2); 178 178 (,,, string memory did) = registry.cows(cowHash); 179 179 assertEq(did, plcDID1); 180 180 } ··· 183 183 vm.prank(controller1); 184 184 registry.updateWrappedDID(controller1, plcDID1, webDIDShort); 185 185 186 - bytes32 cowHash = registry.calculateCowHash(controller1, plcDID1); 186 + bytes32 cowHash = registry.calculateHash(controller1, plcDID1); 187 187 (,,, string memory did) = registry.cows(cowHash); 188 188 assertEq(did, webDIDShort); 189 189 } ··· 192 192 vm.prank(controller1); 193 193 registry.updateWrappedDID(controller1, plcDID1, webDIDMedium); 194 194 195 - bytes32 cowHash = registry.calculateCowHash(controller1, plcDID1); 195 + bytes32 cowHash = registry.calculateHash(controller1, plcDID1); 196 196 (,,, string memory did) = registry.cows(cowHash); 197 197 assertEq(did, webDIDMedium); 198 198 } ··· 201 201 vm.prank(controller1); 202 202 registry.updateWrappedDID(controller1, plcDID1, webDIDLong); 203 203 204 - bytes32 cowHash = registry.calculateCowHash(controller1, plcDID1); 204 + bytes32 cowHash = registry.calculateHash(controller1, plcDID1); 205 205 (,,, string memory did) = registry.cows(cowHash); 206 206 assertEq(did, webDIDLong); 207 207 } ··· 210 210 vm.prank(controller1); 211 211 registry.updateWrappedDID(controller1, plcDID1, webDIDVeryLong); 212 212 213 - bytes32 cowHash = registry.calculateCowHash(controller1, plcDID1); 213 + bytes32 cowHash = registry.calculateHash(controller1, plcDID1); 214 214 (,,, string memory did) = registry.cows(cowHash); 215 215 assertEq(did, webDIDVeryLong); 216 216 } ··· 223 223 vm.prank(controller1); 224 224 registry.updateController(controller1, plcDID1, controller2); 225 225 226 - bytes32 cowHash = registry.calculateCowHash(controller1, plcDID1); 226 + bytes32 cowHash = registry.calculateHash(controller1, plcDID1); 227 227 (address ctrl,,,) = registry.cows(cowHash); 228 228 assertEq(ctrl, controller2); 229 229 } ··· 232 232 vm.prank(controller2); 233 233 registry.updateController(controller2, plcDID2, controller1); 234 234 235 - bytes32 cowHash = registry.calculateCowHash(controller2, plcDID2); 235 + bytes32 cowHash = registry.calculateHash(controller2, plcDID2); 236 236 (address ctrl,,,) = registry.cows(cowHash); 237 237 assertEq(ctrl, controller1); 238 238 } ··· 241 241 vm.prank(controller1); 242 242 registry.updateController(controller1, webDIDShort, controller2); 243 243 244 - bytes32 cowHash = registry.calculateCowHash(controller1, webDIDShort); 244 + bytes32 cowHash = registry.calculateHash(controller1, webDIDShort); 245 245 (address ctrl,,,) = registry.cows(cowHash); 246 246 assertEq(ctrl, controller2); 247 247 } ··· 250 250 vm.prank(controller1); 251 251 registry.updateController(controller1, webDIDMedium, controller2); 252 252 253 - bytes32 cowHash = registry.calculateCowHash(controller1, webDIDMedium); 253 + bytes32 cowHash = registry.calculateHash(controller1, webDIDMedium); 254 254 (address ctrl,,,) = registry.cows(cowHash); 255 255 assertEq(ctrl, controller2); 256 256 } ··· 259 259 vm.prank(controller1); 260 260 registry.updateController(controller1, webDIDLong, controller2); 261 261 262 - bytes32 cowHash = registry.calculateCowHash(controller1, webDIDLong); 262 + bytes32 cowHash = registry.calculateHash(controller1, webDIDLong); 263 263 (address ctrl,,,) = registry.cows(cowHash); 264 264 assertEq(ctrl, controller2); 265 265 } ··· 268 268 vm.prank(controller1); 269 269 registry.updateController(controller1, webDIDVeryLong, controller2); 270 270 271 - bytes32 cowHash = registry.calculateCowHash(controller1, webDIDVeryLong); 271 + bytes32 cowHash = registry.calculateHash(controller1, webDIDVeryLong); 272 272 (address ctrl,,,) = registry.cows(cowHash); 273 273 assertEq(ctrl, controller2); 274 274 } ··· 299 299 vm.prank(controller1); 300 300 registry.deactivate(controller1, plcDID1); 301 301 302 - bytes32 cowHash = registry.calculateCowHash(controller1, plcDID1); 302 + bytes32 cowHash = registry.calculateHash(controller1, plcDID1); 303 303 vm.prank(controller1); 304 304 vm.expectRevert(CowRegistry.AlreadyDeactivated.selector); 305 305 registry.updateWrappedDIDByHash(cowHash, plcDID2); ··· 342 342 // ========================================================================= 343 343 344 344 function test_updateWrappedDID_rejectsNotInitialized() public { 345 - bytes32 cowHash = registry.calculateCowHash(controller1, plcDID1); 345 + bytes32 cowHash = registry.calculateHash(controller1, plcDID1); 346 346 347 347 vm.prank(controller1); 348 348 vm.expectRevert(CowRegistry.NotInitialized.selector); ··· 350 350 } 351 351 352 352 function test_updateController_rejectsNotInitialized() public { 353 - bytes32 cowHash = registry.calculateCowHash(controller1, plcDID1); 353 + bytes32 cowHash = registry.calculateHash(controller1, plcDID1); 354 354 355 355 vm.prank(controller1); 356 356 vm.expectRevert(CowRegistry.NotInitialized.selector); ··· 358 358 } 359 359 360 360 function test_deactivate_rejectsNotInitialized() public { 361 - bytes32 cowHash = registry.calculateCowHash(controller1, plcDID1); 361 + bytes32 cowHash = registry.calculateHash(controller1, plcDID1); 362 362 363 363 vm.prank(controller1); 364 364 vm.expectRevert(CowRegistry.NotInitialized.selector); ··· 368 368 function test_initialize_rejectsEmptyWrappedDID() public { 369 369 vm.prank(controller1); 370 370 vm.expectRevert(CowRegistry.EmptyWrappedDID.selector); 371 - registry.initializeCow(controller1, ""); 371 + registry.initialize(controller1, ""); 372 372 } 373 373 }