@towns-protocol/contracts 0.0.415 → 0.0.418

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@towns-protocol/contracts",
3
- "version": "0.0.415",
3
+ "version": "0.0.418",
4
4
  "scripts": {
5
5
  "clean": "forge clean",
6
6
  "compile": "forge build",
@@ -33,7 +33,7 @@
33
33
  "@layerzerolabs/oapp-evm": "^0.3.2",
34
34
  "@openzeppelin/merkle-tree": "^1.0.8",
35
35
  "@prb/test": "^0.6.4",
36
- "@towns-protocol/prettier-config": "^0.0.415",
36
+ "@towns-protocol/prettier-config": "^0.0.418",
37
37
  "@wagmi/cli": "^2.2.0",
38
38
  "forge-std": "github:foundry-rs/forge-std#v1.10.0",
39
39
  "prettier": "^3.5.3",
@@ -53,5 +53,5 @@
53
53
  "publishConfig": {
54
54
  "access": "public"
55
55
  },
56
- "gitHead": "27f0f8758cd1a18fad7a2774490389e48637942b"
56
+ "gitHead": "735b3a67557584795c76b4b1632da911fcfe3abc"
57
57
  }
@@ -19,6 +19,7 @@ import {DeploySpaceFactory} from "../diamonds/DeploySpaceFactory.s.sol";
19
19
  import {DeploySimpleAppBeacon} from "../diamonds/DeploySimpleAppBeacon.s.sol";
20
20
  import {DeployIdentityRegistry} from "../facets/DeployIdentityRegistry.s.sol";
21
21
  import {DeployReputationRegistry} from "../facets/DeployReputationRegistry.s.sol";
22
+ import {DeployValidationRegistry} from "../facets/DeployValidationRegistry.s.sol";
22
23
 
23
24
  // contracts
24
25
  import {Diamond} from "@towns-protocol/diamond/src/Diamond.sol";
@@ -110,6 +111,7 @@ contract DeployAppRegistry is IDiamondInitHelper, DiamondHelper, Deployer {
110
111
  facetHelper.add("AppFactoryFacet");
111
112
  facetHelper.add("IdentityRegistryFacet");
112
113
  facetHelper.add("ReputationRegistryFacet");
114
+ facetHelper.add("ValidationRegistryFacet");
113
115
 
114
116
  facetHelper.deployBatch(deployer);
115
117
 
@@ -154,6 +156,13 @@ contract DeployAppRegistry is IDiamondInitHelper, DiamondHelper, Deployer {
154
156
  DeployReputationRegistry.makeInitData(FEEDBACK_SCHEMA, RESPONSE_SCHEMA)
155
157
  );
156
158
 
159
+ facet = facetHelper.getDeployedAddress("ValidationRegistryFacet");
160
+ addFacet(
161
+ makeCut(facet, FacetCutAction.Add, DeployValidationRegistry.selectors()),
162
+ facet,
163
+ DeployValidationRegistry.makeInitData()
164
+ );
165
+
157
166
  address multiInit = facetHelper.getDeployedAddress("MultiInit");
158
167
 
159
168
  return
@@ -192,6 +201,9 @@ contract DeployAppRegistry is IDiamondInitHelper, DiamondHelper, Deployer {
192
201
  if (facetName.eq("IdentityRegistryFacet")) {
193
202
  addCut(makeCut(facet, FacetCutAction.Add, DeployIdentityRegistry.selectors()));
194
203
  }
204
+ if (facetName.eq("ValidationRegistryFacet")) {
205
+ addCut(makeCut(facet, FacetCutAction.Add, DeployValidationRegistry.selectors()));
206
+ }
195
207
  }
196
208
 
197
209
  return baseFacets();
@@ -0,0 +1,54 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ // interfaces
5
+ import {IDiamond} from "@towns-protocol/diamond/src/IDiamond.sol";
6
+
7
+ // libraries
8
+ import {LibDeploy} from "@towns-protocol/diamond/src/utils/LibDeploy.sol";
9
+
10
+ // contracts
11
+ import {ValidationRegistryFacet} from "src/apps/facets/validation/ValidationRegistryFacet.sol";
12
+ import {DynamicArrayLib} from "solady/utils/DynamicArrayLib.sol";
13
+
14
+ library DeployValidationRegistry {
15
+ using DynamicArrayLib for DynamicArrayLib.DynamicArray;
16
+
17
+ function selectors() internal pure returns (bytes4[] memory res) {
18
+ uint256 selectorsCount = 6;
19
+ DynamicArrayLib.DynamicArray memory arr = DynamicArrayLib.p().reserve(selectorsCount);
20
+
21
+ arr.p(ValidationRegistryFacet.validationRequest.selector);
22
+ arr.p(ValidationRegistryFacet.validationResponse.selector);
23
+ arr.p(ValidationRegistryFacet.getValidationStatus.selector);
24
+ arr.p(ValidationRegistryFacet.getSummary.selector);
25
+ arr.p(ValidationRegistryFacet.getAgentValidations.selector);
26
+ arr.p(ValidationRegistryFacet.getValidatorRequests.selector);
27
+
28
+ bytes32[] memory selectors_ = arr.asBytes32Array();
29
+
30
+ assembly ("memory-safe") {
31
+ res := selectors_
32
+ }
33
+ }
34
+
35
+ function makeCut(
36
+ address facetAddress,
37
+ IDiamond.FacetCutAction action
38
+ ) internal pure returns (IDiamond.FacetCut memory) {
39
+ return
40
+ IDiamond.FacetCut({
41
+ action: action,
42
+ facetAddress: facetAddress,
43
+ functionSelectors: selectors()
44
+ });
45
+ }
46
+
47
+ function makeInitData() internal pure returns (bytes memory) {
48
+ return abi.encodeCall(ValidationRegistryFacet.__ValidationRegistryFacet_init, ());
49
+ }
50
+
51
+ function deploy() internal returns (address) {
52
+ return LibDeploy.deployCode("ValidationRegistryFacet.sol", "");
53
+ }
54
+ }
@@ -15,6 +15,7 @@ contract InteractSetStreamHistoryMiniblocks is Interaction {
15
15
  address riverRegistry = getDeployment("riverRegistry");
16
16
 
17
17
  uint64 userSettingsMiniblocks = 40;
18
+ uint64 spaceMiniblocks = 400;
18
19
 
19
20
  vm.startBroadcast(deployer);
20
21
  IRiverConfig(riverRegistry).setConfiguration(
@@ -22,6 +23,11 @@ contract InteractSetStreamHistoryMiniblocks is Interaction {
22
23
  0,
23
24
  abi.encode(userSettingsMiniblocks)
24
25
  );
26
+ IRiverConfig(riverRegistry).setConfiguration(
27
+ RiverConfigValues.STREAM_HISTORY_MINIBLOCKS_SPACE,
28
+ 0,
29
+ abi.encode(spaceMiniblocks)
30
+ );
25
31
  vm.stopBroadcast();
26
32
  }
27
33
  }
@@ -19,6 +19,8 @@ library RiverConfigValues {
19
19
  bytes32 public constant MB_RECENCY_CHECK = keccak256("stream.recencyconstraints.ageseconds");
20
20
  bytes32 public constant STREAM_HISTORY_MINIBLOCKS_USER_SETTINGS =
21
21
  keccak256("stream.historyminiblocks.a5");
22
+ bytes32 public constant STREAM_HISTORY_MINIBLOCKS_SPACE =
23
+ keccak256("stream.historyminiblocks.10");
22
24
  bytes32 public constant STREAM_TRIM_ACTIVATION_FACTOR =
23
25
  keccak256("stream.trimactivationfactor");
24
26
  }
@@ -0,0 +1,152 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.29;
3
+
4
+ // interfaces
5
+
6
+ // libraries
7
+
8
+ // contracts
9
+
10
+ /// @title IValidationRegistryBase
11
+ /// @notice Base interface for validation registry events
12
+ /// @dev Implements ERC-8004 validation event standards for trustless agent verification
13
+ interface IValidationRegistryBase {
14
+ /// @notice Emitted when an agent requests validation from a validator
15
+ /// @dev This event is emitted by validationRequest() and enables tracking of all validation requests
16
+ /// @param validatorAddress The address of the validator smart contract that will perform the validation
17
+ /// @param agentId The unique identifier of the agent requesting validation (ERC-721 tokenId from Identity Registry)
18
+ /// @param requestUri The URI pointing to off-chain data containing inputs, outputs, and all information needed for validation
19
+ /// @param requestHash The KECCAK-256 commitment hash of the request data (optional if requestUri is IPFS)
20
+ event ValidationRequest(
21
+ address indexed validatorAddress,
22
+ uint256 indexed agentId,
23
+ string requestUri,
24
+ bytes32 indexed requestHash
25
+ );
26
+
27
+ /// @notice Emitted when a validator responds to a validation request
28
+ /// @dev This event can be emitted multiple times for the same requestHash to support progressive validation states
29
+ /// @param validatorAddress The address of the validator providing the response
30
+ /// @param agentId The unique identifier of the agent being validated
31
+ /// @param requestHash The hash of the original validation request being responded to
32
+ /// @param response The validation result (0-100 scale: 0=failed, 100=passed, or intermediate values for spectrum outcomes)
33
+ /// @param responseUri The URI pointing to off-chain evidence or audit trail of the validation (optional)
34
+ /// @param responseHash The KECCAK-256 hash of the response data (optional if responseUri is IPFS, use bytes32(0) if not provided)
35
+ /// @param tag Custom categorization or additional metadata for the validation (optional, e.g., "soft-finality", "hard-finality")
36
+ event ValidationResponse(
37
+ address indexed validatorAddress,
38
+ uint256 indexed agentId,
39
+ bytes32 indexed requestHash,
40
+ uint8 response,
41
+ string responseUri,
42
+ bytes32 responseHash,
43
+ bytes32 tag
44
+ );
45
+
46
+ error ValidationRegistry__InvalidValidator();
47
+ error ValidationRegistry__InvalidAgent();
48
+ error ValidationRegistry__RequestAlreadyExists();
49
+ error ValidationRegistry__AgentNotExists();
50
+ error ValidationRegistry__NotAuthorized();
51
+ error ValidationRegistry__RequestNotFound();
52
+ error ValidationRegistry__InvalidResponseScore();
53
+ error ValidationRegistry__ZeroResponseRequiresMetadata();
54
+ }
55
+
56
+ /// @title IValidationRegistry
57
+ /// @notice Interface for the ERC-8004 Validation Registry enabling trustless agent verification
58
+ /// @dev This registry enables agents to request verification of their work through various trust models:
59
+ /// stake-secured inference re-execution, zkML verifiers, TEE oracles, or trusted judges.
60
+ /// The identityRegistry address is set at deployment and accessible via getIdentityRegistry().
61
+ /// All validation data is stored on-chain for composability and transparency.
62
+ interface IValidationRegistry is IValidationRegistryBase {
63
+ /// @notice Request validation of agent work from a validator smart contract
64
+ /// @dev MUST be called by the owner or operator of the agentId.
65
+ /// The requestUri should contain all information needed for validation including inputs and outputs.
66
+ /// The requestHash is a KECCAK-256 commitment to the request data (optional if requestUri is IPFS).
67
+ /// Emits a ValidationRequest event upon success.
68
+ /// @param validatorAddress The address of the validator smart contract that will perform the validation (mandatory)
69
+ /// @param agentId The unique identifier of the agent requesting validation (mandatory, must be validly registered)
70
+ /// @param requestUri The URI pointing to off-chain validation data (mandatory)
71
+ /// @param requestHash The KECCAK-256 hash of the request data (mandatory unless requestUri is content-addressable like IPFS)
72
+ function validationRequest(
73
+ address validatorAddress,
74
+ uint256 agentId,
75
+ string calldata requestUri,
76
+ bytes32 requestHash
77
+ ) external;
78
+
79
+ /// @notice Submit a validation response for a previously requested validation
80
+ /// @dev MUST be called by the validatorAddress specified in the original ValidationRequest.
81
+ /// Can be called multiple times for the same requestHash to support use cases like
82
+ /// progressive validation states or updates to validation status.
83
+ /// Stores requestHash, validatorAddress, agentId, response, lastUpdate, and tag on-chain.
84
+ /// Emits a ValidationResponse event upon success.
85
+ /// @param requestHash The hash of the validation request being responded to (mandatory)
86
+ /// @param response The validation result on a 0-100 scale where 0=failed, 100=passed, or intermediate values (mandatory)
87
+ /// @param responseUri The URI pointing to off-chain evidence or audit trail (optional, use empty string if not provided)
88
+ /// @param responseHash The KECCAK-256 hash of the response data (optional if responseUri is IPFS, use bytes32(0) if not provided)
89
+ /// @param tag Custom categorization or metadata for this validation response (optional, use bytes32(0) if not provided)
90
+ function validationResponse(
91
+ bytes32 requestHash,
92
+ uint8 response,
93
+ string calldata responseUri,
94
+ bytes32 responseHash,
95
+ bytes32 tag
96
+ ) external;
97
+
98
+ /// @notice Retrieve the current validation status for a specific request
99
+ /// @dev Returns the stored validation data for the given requestHash.
100
+ /// If no validation exists, returns zero values.
101
+ /// @param requestHash The hash of the validation request to query
102
+ /// @return validatorAddress The address of the validator that provided the response
103
+ /// @return agentId The unique identifier of the agent that was validated
104
+ /// @return response The validation result (0-100 scale)
105
+ /// @return tag The custom tag associated with this validation response
106
+ /// @return lastUpdate The timestamp of the last validation response update
107
+ function getValidationStatus(
108
+ bytes32 requestHash
109
+ )
110
+ external
111
+ view
112
+ returns (
113
+ address validatorAddress,
114
+ uint256 agentId,
115
+ uint8 response,
116
+ bytes32 tag,
117
+ uint256 lastUpdate
118
+ );
119
+
120
+ /// @notice Returns aggregated validation statistics for an agent
121
+ /// @dev Provides on-chain composable reputation metrics. The agentId parameter is mandatory;
122
+ /// validatorAddresses and tag are optional filters to narrow results.
123
+ /// Use empty array for validatorAddresses and bytes32(0) for tag to include all validations.
124
+ /// @param agentId The agent ID to get statistics for (mandatory)
125
+ /// @param validatorAddresses Array of validator addresses to filter by (optional, use empty array for no filter)
126
+ /// @param tag The tag to filter by (optional, use bytes32(0) for no filter)
127
+ /// @return count The total number of validations matching the filters
128
+ /// @return avgResponse The average validation response across all matching validations (0-100 scale)
129
+ function getSummary(
130
+ uint256 agentId,
131
+ address[] calldata validatorAddresses,
132
+ bytes32 tag
133
+ ) external view returns (uint64 count, uint8 avgResponse);
134
+
135
+ /// @notice Returns all validation request hashes for a specific agent
136
+ /// @dev Useful for discovering the complete validation history of an agent.
137
+ /// The returned hashes can be used with getValidationStatus() to retrieve full details.
138
+ /// @param agentId The agent ID to query validation requests for
139
+ /// @return requestHashes Array of all validation request hashes associated with this agent
140
+ function getAgentValidations(
141
+ uint256 agentId
142
+ ) external view returns (bytes32[] memory requestHashes);
143
+
144
+ /// @notice Returns all validation request hashes handled by a specific validator
145
+ /// @dev Useful for discovering all validations performed by a validator contract.
146
+ /// The returned hashes can be used with getValidationStatus() to retrieve full details.
147
+ /// @param validatorAddress The validator address to query validation requests for
148
+ /// @return requestHashes Array of all validation request hashes handled by this validator
149
+ function getValidatorRequests(
150
+ address validatorAddress
151
+ ) external view returns (bytes32[] memory requestHashes);
152
+ }
@@ -0,0 +1,158 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ // interfaces
5
+ import {IValidationRegistryBase} from "./IValidationRegistry.sol";
6
+
7
+ // libraries
8
+ import {CustomRevert} from "../../../utils/libraries/CustomRevert.sol";
9
+ import {ValidationRegistryStorage, ValidationStatus} from "./ValidationRegistryStorage.sol";
10
+ import {EnumerableSetLib} from "solady/utils/EnumerableSetLib.sol";
11
+
12
+ // contracts
13
+ import {ERC721ABase} from "../../../diamond/facets/token/ERC721A/ERC721ABase.sol";
14
+
15
+ abstract contract ValidationRegistryBase is IValidationRegistryBase, ERC721ABase {
16
+ using CustomRevert for bytes4;
17
+ using EnumerableSetLib for EnumerableSetLib.Bytes32Set;
18
+
19
+ function _requestValidation(
20
+ address validatorAddress,
21
+ uint256 agentId,
22
+ string calldata requestUri,
23
+ bytes32 requestHash
24
+ ) internal {
25
+ ValidationRegistryStorage.Layout storage $ = ValidationRegistryStorage.getLayout();
26
+ if ($.validations[requestHash].validatorAddress != address(0))
27
+ ValidationRegistry__RequestAlreadyExists.selector.revertWith();
28
+
29
+ ValidationStatus storage validation = $.validations[requestHash];
30
+ validation.validatorAddress = validatorAddress;
31
+ validation.agentId = agentId;
32
+ validation.lastUpdate = block.timestamp;
33
+
34
+ $.requestByAgent[agentId].add(requestHash);
35
+ $.requestByValidator[validatorAddress].add(requestHash);
36
+
37
+ emit ValidationRequest(validatorAddress, agentId, requestUri, requestHash);
38
+ }
39
+
40
+ function _responseValidation(
41
+ bytes32 requestHash,
42
+ uint8 response,
43
+ string calldata responseUri,
44
+ bytes32 responseHash,
45
+ bytes32 tag
46
+ ) internal {
47
+ ValidationRegistryStorage.Layout storage $ = ValidationRegistryStorage.getLayout();
48
+ ValidationStatus storage val = $.validations[requestHash];
49
+ if (val.validatorAddress == address(0))
50
+ ValidationRegistry__RequestNotFound.selector.revertWith();
51
+ if (msg.sender != val.validatorAddress)
52
+ ValidationRegistry__NotAuthorized.selector.revertWith();
53
+ if (response > 100) ValidationRegistry__InvalidResponseScore.selector.revertWith();
54
+ if (response == 0 && responseHash == bytes32(0) && tag == bytes32(0)) {
55
+ ValidationRegistry__ZeroResponseRequiresMetadata.selector.revertWith();
56
+ }
57
+
58
+ val.response = response;
59
+ val.responseHash = responseHash;
60
+ val.tag = tag;
61
+ val.lastUpdate = block.timestamp;
62
+
63
+ emit ValidationResponse(
64
+ val.validatorAddress,
65
+ val.agentId,
66
+ requestHash,
67
+ response,
68
+ responseUri,
69
+ responseHash,
70
+ tag
71
+ );
72
+ }
73
+
74
+ function _getValidationStatus(
75
+ bytes32 requestHash
76
+ ) internal view returns (ValidationStatus storage) {
77
+ ValidationRegistryStorage.Layout storage $ = ValidationRegistryStorage.getLayout();
78
+ return $.validations[requestHash];
79
+ }
80
+
81
+ function _getSummary(
82
+ uint256 agentId,
83
+ address[] calldata validatorAddresses,
84
+ bytes32 tag
85
+ ) internal view returns (uint64 count, uint8 avgResponse) {
86
+ uint256 totalResponse;
87
+
88
+ ValidationRegistryStorage.Layout storage $ = ValidationRegistryStorage.getLayout();
89
+ EnumerableSetLib.Bytes32Set storage requests = $.requestByAgent[agentId];
90
+
91
+ for (uint256 i; i < requests.length(); ++i) {
92
+ // Fetch the validation status for the current requestHash
93
+ ValidationStatus storage val = $.validations[requests.at(i)];
94
+
95
+ // If no validatorAddresses filter is provided (i.e., length == 0), match any validator.
96
+ // Otherwise, check if the validatorAddress matches any address in the filter array.
97
+ bool matchValidator = (validatorAddresses.length == 0);
98
+ if (!matchValidator) {
99
+ // Loop through validatorAddresses to see if current validation was made by any provided validator
100
+ for (uint256 j; j < validatorAddresses.length; ++j) {
101
+ if (val.validatorAddress == validatorAddresses[j]) {
102
+ matchValidator = true;
103
+ break; // Stop searching if a match is found
104
+ }
105
+ }
106
+ }
107
+
108
+ // Tag filtering: If a zero tag is provided (no filtering), any tag matches.
109
+ // Otherwise, only include validations whose tag matches the requested tag.
110
+ bool matchTag = (tag == bytes32(0)) || (val.tag == tag);
111
+
112
+ // Check if a response has been given: at least one of (response, responseHash, tag) must be non-zero
113
+ // This distinguishes between "request with no response" and "request with response=0"
114
+ bool hasResponse = (val.response > 0) ||
115
+ (val.responseHash != bytes32(0)) ||
116
+ (val.tag != bytes32(0));
117
+
118
+ // Only count responses that matched validator and tag criteria, and have actually been responded to
119
+ if (matchValidator && matchTag && hasResponse) {
120
+ totalResponse += val.response; // Add the response value for averaging
121
+ count++; // Increment the count of included responses
122
+ }
123
+ }
124
+
125
+ avgResponse = count > 0 ? uint8(totalResponse / count) : 0;
126
+ }
127
+
128
+ function _getAgentValidations(
129
+ uint256 agentId
130
+ ) internal view returns (bytes32[] memory requestHashes) {
131
+ ValidationRegistryStorage.Layout storage $ = ValidationRegistryStorage.getLayout();
132
+ return $.requestByAgent[agentId].values();
133
+ }
134
+
135
+ function _getValidatorRequests(
136
+ address validatorAddress
137
+ ) internal view returns (bytes32[] memory requestHashes) {
138
+ ValidationRegistryStorage.Layout storage $ = ValidationRegistryStorage.getLayout();
139
+ return $.requestByValidator[validatorAddress].values();
140
+ }
141
+
142
+ /// @dev Check validation request inputs
143
+ function _verifyValidationRequest(address validatorAddress, uint256 agentId) internal view {
144
+ if (validatorAddress == address(0))
145
+ ValidationRegistry__InvalidValidator.selector.revertWith();
146
+ if (agentId == 0) ValidationRegistry__InvalidAgent.selector.revertWith();
147
+ if (!_exists(agentId)) ValidationRegistry__AgentNotExists.selector.revertWith();
148
+
149
+ address owner = _ownerOf(agentId);
150
+ if (
151
+ msg.sender != owner &&
152
+ !_isApprovedForAll(owner, msg.sender) &&
153
+ msg.sender != _getApproved(agentId)
154
+ ) {
155
+ ValidationRegistry__NotAuthorized.selector.revertWith();
156
+ }
157
+ }
158
+ }
@@ -0,0 +1,88 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.29;
3
+
4
+ // interfaces
5
+ import {IValidationRegistry} from "./IValidationRegistry.sol";
6
+
7
+ // libraries
8
+ import {CustomRevert} from "../../../utils/libraries/CustomRevert.sol";
9
+ import {ValidationStatus} from "./ValidationRegistryStorage.sol";
10
+
11
+ // contracts
12
+ import {Facet} from "@towns-protocol/diamond/src/facets/Facet.sol";
13
+ import {ValidationRegistryBase} from "./ValidationRegistryBase.sol";
14
+
15
+ contract ValidationRegistryFacet is IValidationRegistry, Facet, ValidationRegistryBase {
16
+ using CustomRevert for bytes4;
17
+
18
+ function __ValidationRegistryFacet_init() external onlyInitializing {
19
+ __ValidationRegistryFacet_init_unchained();
20
+ }
21
+
22
+ function __ValidationRegistryFacet_init_unchained() internal {
23
+ _addInterface(type(IValidationRegistry).interfaceId);
24
+ }
25
+
26
+ /// @inheritdoc IValidationRegistry
27
+ function validationRequest(
28
+ address validatorAddress,
29
+ uint256 agentId,
30
+ string calldata requestUri,
31
+ bytes32 requestHash
32
+ ) external {
33
+ _verifyValidationRequest(validatorAddress, agentId);
34
+ _requestValidation(validatorAddress, agentId, requestUri, requestHash);
35
+ }
36
+
37
+ /// @inheritdoc IValidationRegistry
38
+ function validationResponse(
39
+ bytes32 requestHash,
40
+ uint8 response,
41
+ string calldata responseUri,
42
+ bytes32 responseHash,
43
+ bytes32 tag
44
+ ) external {
45
+ _responseValidation(requestHash, response, responseUri, responseHash, tag);
46
+ }
47
+
48
+ /// @inheritdoc IValidationRegistry
49
+ function getValidationStatus(
50
+ bytes32 requestHash
51
+ )
52
+ external
53
+ view
54
+ returns (
55
+ address validatorAddress,
56
+ uint256 agentId,
57
+ uint8 response,
58
+ bytes32 tag,
59
+ uint256 lastUpdate
60
+ )
61
+ {
62
+ ValidationStatus memory val = _getValidationStatus(requestHash);
63
+ return (val.validatorAddress, val.agentId, val.response, val.tag, val.lastUpdate);
64
+ }
65
+
66
+ /// @inheritdoc IValidationRegistry
67
+ function getSummary(
68
+ uint256 agentId,
69
+ address[] calldata validatorAddresses,
70
+ bytes32 tag
71
+ ) external view returns (uint64 count, uint8 avgResponse) {
72
+ return _getSummary(agentId, validatorAddresses, tag);
73
+ }
74
+
75
+ /// @inheritdoc IValidationRegistry
76
+ function getAgentValidations(
77
+ uint256 agentId
78
+ ) external view returns (bytes32[] memory requestHashes) {
79
+ return _getAgentValidations(agentId);
80
+ }
81
+
82
+ /// @inheritdoc IValidationRegistry
83
+ function getValidatorRequests(
84
+ address validatorAddress
85
+ ) external view returns (bytes32[] memory requestHashes) {
86
+ return _getValidatorRequests(validatorAddress);
87
+ }
88
+ }
@@ -0,0 +1,38 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.29;
3
+
4
+ // interfaces
5
+
6
+ // libraries
7
+ import {EnumerableSetLib} from "solady/utils/EnumerableSetLib.sol";
8
+
9
+ // contracts
10
+
11
+ struct ValidationStatus {
12
+ address validatorAddress;
13
+ uint256 agentId;
14
+ uint8 response; // 0..100
15
+ bytes32 responseHash;
16
+ bytes32 tag;
17
+ uint256 lastUpdate;
18
+ }
19
+
20
+ library ValidationRegistryStorage {
21
+ using EnumerableSetLib for EnumerableSetLib.Bytes32Set;
22
+
23
+ // keccak256(abi.encode(uint256(keccak256("apps.facets.validation.storage")) - 1)) & ~bytes32(uint256(0xff))
24
+ bytes32 internal constant STORAGE_SLOT =
25
+ 0x81b3fc8d09a49d21221f3e1495c2f4652ebf044e3338065682b43c2012468400;
26
+
27
+ struct Layout {
28
+ mapping(bytes32 requestHash => ValidationStatus) validations;
29
+ mapping(uint256 agentId => EnumerableSetLib.Bytes32Set requestHashes) requestByAgent;
30
+ mapping(address validatorAddress => EnumerableSetLib.Bytes32Set requestHashes) requestByValidator;
31
+ }
32
+
33
+ function getLayout() internal pure returns (Layout storage $) {
34
+ assembly {
35
+ $.slot := STORAGE_SLOT
36
+ }
37
+ }
38
+ }