@towns-protocol/contracts 0.0.413 → 0.0.415

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.
@@ -0,0 +1,155 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ // interfaces
5
+ import {IReputationRegistry} from "./IReputationRegistry.sol";
6
+ import {ISchemaResolver} from "@ethereum-attestation-service/eas-contracts/resolver/ISchemaResolver.sol";
7
+
8
+ // libraries
9
+ import {ReputationRegistryStorage} from "./ReputationRegistryStorage.sol";
10
+
11
+ // contracts
12
+ import {Facet} from "@towns-protocol/diamond/src/facets/Facet.sol";
13
+ import {ReputationRegistryBase} from "./ReputationRegistryBase.sol";
14
+ import {SchemaBase} from "../schema/SchemaBase.sol";
15
+
16
+ contract ReputationRegistryFacet is IReputationRegistry, ReputationRegistryBase, SchemaBase, Facet {
17
+ function __ReputationRegistry_init(
18
+ string calldata feedbackSchema,
19
+ string calldata responseSchema
20
+ ) external onlyInitializing {
21
+ __ReputationRegistry_init_unchained(feedbackSchema, responseSchema);
22
+ }
23
+
24
+ function __ReputationRegistry_init_unchained(
25
+ string calldata feedbackSchema,
26
+ string calldata responseSchema
27
+ ) internal {
28
+ bytes32 feedbackSchemaId = _registerSchema(
29
+ feedbackSchema,
30
+ ISchemaResolver(address(0)),
31
+ true
32
+ );
33
+ bytes32 responseSchemaId = _registerSchema(
34
+ responseSchema,
35
+ ISchemaResolver(address(0)),
36
+ true
37
+ );
38
+
39
+ ReputationRegistryStorage.Layout storage $ = ReputationRegistryStorage.getLayout();
40
+ $.feedbackSchemaId = feedbackSchemaId;
41
+ $.responseSchemaId = responseSchemaId;
42
+ }
43
+
44
+ /// @inheritdoc IReputationRegistry
45
+ function giveFeedback(
46
+ uint256 agentId,
47
+ uint8 rating,
48
+ bytes32 tag1,
49
+ bytes32 tag2,
50
+ string calldata comment,
51
+ bytes32 commentHash
52
+ ) external {
53
+ Feedback memory feedback;
54
+ feedback.rating = rating;
55
+ feedback.tag1 = tag1;
56
+ feedback.tag2 = tag2;
57
+ _giveFeedback(agentId, feedback);
58
+ emit NewFeedback(agentId, msg.sender, rating, tag1, tag2, comment, commentHash);
59
+ }
60
+
61
+ /// @inheritdoc IReputationRegistry
62
+ function revokeFeedback(uint256 agentId, uint64 feedbackIndex) external {
63
+ _revokeFeedback(agentId, feedbackIndex);
64
+ }
65
+
66
+ /// @inheritdoc IReputationRegistry
67
+ function appendResponse(
68
+ uint256 agentId,
69
+ address reviewerAddress,
70
+ uint64 feedbackIndex,
71
+ string calldata comment,
72
+ bytes32 commentHash
73
+ ) external {
74
+ _appendResponse(agentId, reviewerAddress, feedbackIndex, comment, commentHash);
75
+ }
76
+
77
+ /// @inheritdoc IReputationRegistry
78
+ function getIdentityRegistry() external view returns (address) {
79
+ return address(this);
80
+ }
81
+
82
+ /// @inheritdoc IReputationRegistry
83
+ function getSummary(
84
+ uint256 agentId,
85
+ address[] calldata clientAddresses,
86
+ bytes32 tag1,
87
+ bytes32 tag2
88
+ ) external view returns (uint64 count, uint8 averageScore) {
89
+ return _getSummary(agentId, clientAddresses, tag1, tag2);
90
+ }
91
+
92
+ /// @inheritdoc IReputationRegistry
93
+ function readFeedback(
94
+ uint256 agentId,
95
+ address clientAddress,
96
+ uint64 index
97
+ ) external view returns (uint8 score, bytes32 tag1, bytes32 tag2, bool isRevoked) {
98
+ (Feedback memory feedback, bool revoked) = _readFeedback(agentId, clientAddress, index);
99
+ return (feedback.rating, feedback.tag1, feedback.tag2, revoked);
100
+ }
101
+
102
+ /// @inheritdoc IReputationRegistry
103
+ function readAllFeedback(
104
+ uint256 agentId,
105
+ address[] calldata clientAddresses,
106
+ bytes32 tag1,
107
+ bytes32 tag2,
108
+ bool includeRevoked
109
+ )
110
+ external
111
+ view
112
+ returns (
113
+ address[] memory,
114
+ uint8[] memory,
115
+ bytes32[] memory,
116
+ bytes32[] memory,
117
+ bool[] memory
118
+ )
119
+ {
120
+ AllFeedback memory allFeedback = _readAllFeedback(
121
+ agentId,
122
+ clientAddresses,
123
+ tag1,
124
+ tag2,
125
+ includeRevoked
126
+ );
127
+ return (
128
+ allFeedback.clients,
129
+ allFeedback.scores,
130
+ allFeedback.tag1s,
131
+ allFeedback.tag2s,
132
+ allFeedback.revokedStatuses
133
+ );
134
+ }
135
+
136
+ /// @inheritdoc IReputationRegistry
137
+ function getResponseCount(
138
+ uint256 agentId,
139
+ address clientAddress,
140
+ uint64 feedbackIndex,
141
+ address[] calldata responders
142
+ ) external view returns (uint256) {
143
+ return _getResponseCount(agentId, clientAddress, feedbackIndex, responders);
144
+ }
145
+
146
+ /// @inheritdoc IReputationRegistry
147
+ function getClients(uint256 agentId) external view returns (address[] memory) {
148
+ return _getClients(agentId);
149
+ }
150
+
151
+ /// @inheritdoc IReputationRegistry
152
+ function getLastIndex(uint256 agentId, address clientAddress) external view returns (uint64) {
153
+ return _getLastIndex(agentId, clientAddress);
154
+ }
155
+ }
@@ -0,0 +1,38 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ // interfaces
5
+
6
+ // libraries
7
+ import {EnumerableSetLib} from "solady/utils/EnumerableSetLib.sol";
8
+
9
+ // contracts
10
+
11
+ library ReputationRegistryStorage {
12
+ // keccak256(abi.encode(uint256(keccak256("apps.facets.reputation.storage")) - 1)) & ~bytes32(uint256(0xff))
13
+ bytes32 internal constant STORAGE_SLOT =
14
+ 0x501066df74618204890aa19abae8215a74ecf89f414b33f7d3fe6e08c61d9100;
15
+
16
+ struct Layout {
17
+ // feedback schema ID
18
+ bytes32 feedbackSchemaId;
19
+ // response schema ID
20
+ bytes32 responseSchemaId;
21
+ // agentId => clientAddress => last feedback index
22
+ mapping(uint256 => mapping(address => uint64)) lastIndex;
23
+ // agentId => clientAddress => feedback index => attestation ID
24
+ mapping(uint256 => mapping(address => mapping(uint64 => bytes32))) feedback;
25
+ // agentId => clients
26
+ mapping(uint256 => EnumerableSetLib.AddressSet) clients;
27
+ // agentId => client => feedback index => responders
28
+ mapping(uint256 => mapping(address => mapping(uint64 => EnumerableSetLib.AddressSet))) responders;
29
+ // agentId => client => feedback index => sender => count of responses
30
+ mapping(uint256 => mapping(address => mapping(uint64 => mapping(address => uint256)))) responseCount;
31
+ }
32
+
33
+ function getLayout() internal pure returns (Layout storage $) {
34
+ assembly {
35
+ $.slot := STORAGE_SLOT
36
+ }
37
+ }
38
+ }
@@ -2,6 +2,7 @@
2
2
  pragma solidity ^0.8.29;
3
3
 
4
4
  // interfaces
5
+ import {IIdentityRegistryBase} from "../../facets/identity/IIdentityRegistry.sol";
5
6
 
6
7
  // libraries
7
8
 
@@ -26,6 +27,9 @@ interface ISimpleAppBase {
26
27
  /// @notice Thrown when the currency is invalid
27
28
  error SimpleApp__InvalidCurrency();
28
29
 
30
+ /// @notice Thrown when the agent is already promoted
31
+ error SimpleApp__AgentAlreadyPromoted();
32
+
29
33
  /// @notice Emitted when the app is initialized
30
34
  /// @param owner The owner of the app
31
35
  /// @param client The client of the app
@@ -55,9 +59,23 @@ interface ISimpleAppBase {
55
59
  /// @param oldClient The old client
56
60
  /// @param newClient The new client
57
61
  event ClientUpdated(address indexed oldClient, address indexed newClient);
62
+
63
+ /// @notice Emitted when the agent is promoted
64
+ /// @param owner The owner of the app
65
+ /// @param agentId The ID of the agent
66
+ event AgentPromoted(address indexed owner, uint256 indexed agentId);
58
67
  }
59
68
 
60
69
  interface ISimpleApp is ISimpleAppBase {
70
+ /// @notice Promotes the agent of the app
71
+ /// @param agentUri The URI pointing to the agent's registration file (e.g., ipfs://cid or https://domain.com/agent.json)
72
+ /// @param metadata The metadata of the agent
73
+ /// @return agentId The ID of the agent
74
+ function promoteAgent(
75
+ string calldata agentUri,
76
+ IIdentityRegistryBase.MetadataEntry[] calldata metadata
77
+ ) external returns (uint256 agentId);
78
+
61
79
  /// @notice Withdraws the ETH balance of the app to the recipient
62
80
  /// @param recipient The address to withdraw the ETH to
63
81
  function withdrawETH(address recipient) external;
@@ -74,4 +92,8 @@ interface ISimpleApp is ISimpleAppBase {
74
92
  /// @notice Updates the permissions of the app
75
93
  /// @param permissions The new permissions of the app
76
94
  function updatePermissions(bytes32[] calldata permissions) external;
95
+
96
+ /// @notice Returns the ID of the agent
97
+ /// @return agentId The ID of the agent
98
+ function getAgentId() external view returns (uint256 agentId);
77
99
  }
@@ -10,6 +10,7 @@ import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
10
10
  import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
11
11
  import {IERC1155Receiver} from "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
12
12
  import {IERC5267} from "@openzeppelin/contracts/interfaces/IERC5267.sol";
13
+ import {IIdentityRegistry, IIdentityRegistryBase} from "../../facets/identity/IIdentityRegistry.sol";
13
14
 
14
15
  // contracts
15
16
  import {BaseApp} from "../../../apps/BaseApp.sol";
@@ -22,13 +23,13 @@ import {ReentrancyGuardTransient} from "solady/utils/ReentrancyGuardTransient.so
22
23
 
23
24
  // libraries
24
25
  import {SimpleAppStorage} from "../../simple/app/SimpleAppStorage.sol";
25
- import {SimpleAccountStorage} from "../account/SimpleAccountStorage.sol";
26
26
  import {CustomRevert} from "../../../utils/libraries/CustomRevert.sol";
27
27
  import {CurrencyTransfer} from "../../../utils/libraries/CurrencyTransfer.sol";
28
28
  import {SignatureCheckerLib} from "solady/utils/SignatureCheckerLib.sol";
29
29
 
30
30
  contract SimpleAppFacet is
31
31
  ISimpleApp,
32
+ IIdentityRegistryBase,
32
33
  BaseApp,
33
34
  SimpleAccountFacet,
34
35
  IntrospectionFacet,
@@ -75,6 +76,19 @@ contract SimpleAppFacet is
75
76
  /* Simple App Functions */
76
77
  /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
77
78
 
79
+ /// @inheritdoc ISimpleApp
80
+ function promoteAgent(
81
+ string calldata agentUri,
82
+ MetadataEntry[] calldata metadata
83
+ ) external onlyOwner nonReentrant returns (uint256 agentId) {
84
+ SimpleAppStorage.Layout storage $ = SimpleAppStorage.getLayout();
85
+ if ($.agentId != 0) SimpleApp__AgentAlreadyPromoted.selector.revertWith();
86
+ address coordinator = _getCoordinator();
87
+ agentId = IIdentityRegistry(coordinator).register(agentUri, metadata);
88
+ $.agentId = agentId;
89
+ emit AgentPromoted(msg.sender, agentId);
90
+ }
91
+
78
92
  /// @inheritdoc ISimpleApp
79
93
  function withdrawETH(address recipient) external onlyOwner nonReentrant {
80
94
  if (recipient == address(0)) SimpleApp__ZeroAddress.selector.revertWith();
@@ -121,6 +135,11 @@ contract SimpleAppFacet is
121
135
  }
122
136
 
123
137
  // Public functions
138
+ /// @inheritdoc ISimpleApp
139
+ function getAgentId() external view returns (uint256) {
140
+ return SimpleAppStorage.getLayout().agentId;
141
+ }
142
+
124
143
  /// @inheritdoc IModule
125
144
  function moduleId() public view returns (string memory) {
126
145
  SimpleAppStorage.Layout storage $ = SimpleAppStorage.getLayout();
@@ -18,6 +18,7 @@ library SimpleAppStorage {
18
18
  uint256 installPrice;
19
19
  uint48 accessDuration;
20
20
  address client;
21
+ uint256 agentId;
21
22
  }
22
23
 
23
24
  function getLayout() internal pure returns (Layout storage l) {