@latticexyz/world-modules 2.0.12-type-resolutions-effc7ab1 → 2.0.12-type-resolutions-ad8cc987

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.
Files changed (90) hide show
  1. package/cache/solidity-files-cache.json +1 -1
  2. package/package.json +9 -8
  3. package/src/index.sol +25 -0
  4. package/src/interfaces/IBaseWorld.sol +16 -0
  5. package/src/interfaces/IERC20System.sol +33 -0
  6. package/src/interfaces/IERC721System.sol +43 -0
  7. package/src/interfaces/IPuppetFactorySystem.sol +15 -0
  8. package/src/interfaces/IUniqueEntitySystem.sol +13 -0
  9. package/src/interfaces/IUnstable_CallWithSignatureSystem.sol +20 -0
  10. package/src/modules/callwithsignature/ECDSA.sol +174 -0
  11. package/src/modules/callwithsignature/IERC1271.sol +17 -0
  12. package/src/modules/callwithsignature/IUnstable_CallWithSignatureErrors.sol +9 -0
  13. package/src/modules/callwithsignature/SignatureChecker.sol +50 -0
  14. package/src/modules/callwithsignature/Unstable_CallWithSignatureModule.sol +48 -0
  15. package/src/modules/callwithsignature/Unstable_CallWithSignatureSystem.sol +36 -0
  16. package/src/modules/callwithsignature/constants.sol +10 -0
  17. package/src/modules/callwithsignature/getSignedMessageHash.sol +54 -0
  18. package/src/modules/callwithsignature/tables/CallWithSignatureNonces.sol +199 -0
  19. package/src/modules/callwithsignature/validateCallWithSignature.sol +31 -0
  20. package/src/modules/erc20-puppet/ERC20Module.sol +88 -0
  21. package/src/modules/erc20-puppet/ERC20System.sol +286 -0
  22. package/src/modules/erc20-puppet/IERC20.sol +94 -0
  23. package/src/modules/erc20-puppet/IERC20Errors.sol +49 -0
  24. package/src/modules/erc20-puppet/IERC20Events.sol +18 -0
  25. package/src/modules/erc20-puppet/IERC20Mintable.sol +25 -0
  26. package/src/modules/erc20-puppet/constants.sol +20 -0
  27. package/src/modules/erc20-puppet/registerERC20.sol +35 -0
  28. package/src/modules/erc20-puppet/tables/Allowances.sol +208 -0
  29. package/src/modules/erc20-puppet/tables/ERC20Metadata.sol +604 -0
  30. package/src/modules/erc20-puppet/tables/ERC20Registry.sol +199 -0
  31. package/src/modules/erc20-puppet/tables/TotalSupply.sol +184 -0
  32. package/src/modules/erc20-puppet/utils.sol +30 -0
  33. package/src/modules/erc721-puppet/ERC721Module.sol +95 -0
  34. package/src/modules/erc721-puppet/ERC721System.sol +531 -0
  35. package/src/modules/erc721-puppet/IERC721.sol +120 -0
  36. package/src/modules/erc721-puppet/IERC721Errors.sol +61 -0
  37. package/src/modules/erc721-puppet/IERC721Events.sol +23 -0
  38. package/src/modules/erc721-puppet/IERC721Metadata.sol +27 -0
  39. package/src/modules/erc721-puppet/IERC721Mintable.sol +53 -0
  40. package/src/modules/erc721-puppet/IERC721Receiver.sol +28 -0
  41. package/src/modules/erc721-puppet/constants.sol +23 -0
  42. package/src/modules/erc721-puppet/libraries/LibString.sol +77 -0
  43. package/src/modules/erc721-puppet/registerERC721.sol +37 -0
  44. package/src/modules/erc721-puppet/tables/ERC721Metadata.sol +703 -0
  45. package/src/modules/erc721-puppet/tables/ERC721Registry.sol +199 -0
  46. package/src/modules/erc721-puppet/tables/OperatorApproval.sol +220 -0
  47. package/src/modules/erc721-puppet/tables/Owners.sol +196 -0
  48. package/src/modules/erc721-puppet/tables/TokenApproval.sol +196 -0
  49. package/src/modules/erc721-puppet/tables/TokenURI.sol +450 -0
  50. package/src/modules/erc721-puppet/utils.sol +38 -0
  51. package/src/modules/keysintable/KeysInTableHook.sol +141 -0
  52. package/src/modules/keysintable/KeysInTableModule.sol +110 -0
  53. package/src/modules/keysintable/constants.sol +7 -0
  54. package/src/modules/keysintable/getKeysInTable.sol +81 -0
  55. package/src/modules/keysintable/hasKey.sol +28 -0
  56. package/src/modules/keysintable/query.sol +200 -0
  57. package/src/modules/keysintable/tables/KeysInTable.sol +1638 -0
  58. package/src/modules/keysintable/tables/UsedKeysIndex.sol +414 -0
  59. package/src/modules/keyswithvalue/KeysWithValueHook.sol +158 -0
  60. package/src/modules/keyswithvalue/KeysWithValueModule.sol +103 -0
  61. package/src/modules/keyswithvalue/constants.sol +7 -0
  62. package/src/modules/keyswithvalue/getKeysWithValue.sol +58 -0
  63. package/src/modules/keyswithvalue/getTargetTableId.sol +32 -0
  64. package/src/modules/keyswithvalue/tables/KeysWithValue.sol +668 -0
  65. package/src/modules/puppet/Puppet.sol +80 -0
  66. package/src/modules/puppet/PuppetDelegationControl.sol +17 -0
  67. package/src/modules/puppet/PuppetFactorySystem.sol +25 -0
  68. package/src/modules/puppet/PuppetMaster.sol +19 -0
  69. package/src/modules/puppet/PuppetModule.sol +64 -0
  70. package/src/modules/puppet/constants.sol +23 -0
  71. package/src/modules/puppet/createPuppet.sol +24 -0
  72. package/src/modules/puppet/tables/PuppetRegistry.sol +199 -0
  73. package/src/modules/puppet/utils.sol +10 -0
  74. package/src/modules/std-delegations/CallboundDelegationControl.sol +64 -0
  75. package/src/modules/std-delegations/StandardDelegationsModule.sol +55 -0
  76. package/src/modules/std-delegations/SystemboundDelegationControl.sol +54 -0
  77. package/src/modules/std-delegations/TimeboundDelegationControl.sol +27 -0
  78. package/src/modules/std-delegations/constants.sol +21 -0
  79. package/src/modules/std-delegations/tables/CallboundDelegations.sol +287 -0
  80. package/src/modules/std-delegations/tables/SystemboundDelegations.sol +256 -0
  81. package/src/modules/std-delegations/tables/TimeboundDelegations.sol +211 -0
  82. package/src/modules/tokens/tables/Balances.sol +196 -0
  83. package/src/modules/uniqueentity/UniqueEntityModule.sol +73 -0
  84. package/src/modules/uniqueentity/UniqueEntitySystem.sol +18 -0
  85. package/src/modules/uniqueentity/constants.sol +13 -0
  86. package/src/modules/uniqueentity/getUniqueEntity.sol +26 -0
  87. package/src/modules/uniqueentity/tables/UniqueEntity.sol +238 -0
  88. package/src/modules/utils/ArrayLib.sol +55 -0
  89. package/src/utils/AccessControlLib.sol +55 -0
  90. package/src/utils/SystemSwitch.sol +80 -0
@@ -0,0 +1,414 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity >=0.8.24;
3
+
4
+ /* Autogenerated file. Do not edit manually. */
5
+
6
+ // Import store internals
7
+ import { IStore } from "@latticexyz/store/src/IStore.sol";
8
+ import { StoreSwitch } from "@latticexyz/store/src/StoreSwitch.sol";
9
+ import { StoreCore } from "@latticexyz/store/src/StoreCore.sol";
10
+ import { Bytes } from "@latticexyz/store/src/Bytes.sol";
11
+ import { Memory } from "@latticexyz/store/src/Memory.sol";
12
+ import { SliceLib } from "@latticexyz/store/src/Slice.sol";
13
+ import { EncodeArray } from "@latticexyz/store/src/tightcoder/EncodeArray.sol";
14
+ import { FieldLayout } from "@latticexyz/store/src/FieldLayout.sol";
15
+ import { Schema } from "@latticexyz/store/src/Schema.sol";
16
+ import { EncodedLengths, EncodedLengthsLib } from "@latticexyz/store/src/EncodedLengths.sol";
17
+ import { ResourceId } from "@latticexyz/store/src/ResourceId.sol";
18
+
19
+ // Import user types
20
+ import { ResourceId } from "@latticexyz/store/src/ResourceId.sol";
21
+
22
+ library UsedKeysIndex {
23
+ // Hex below is the result of `WorldResourceIdLib.encode({ namespace: "", name: "UsedKeysIndex", typeId: RESOURCE_TABLE });`
24
+ ResourceId constant _tableId = ResourceId.wrap(0x74620000000000000000000000000000557365644b657973496e646578000000);
25
+
26
+ FieldLayout constant _fieldLayout =
27
+ FieldLayout.wrap(0x0006020001050000000000000000000000000000000000000000000000000000);
28
+
29
+ // Hex-encoded key schema of (bytes32, bytes32)
30
+ Schema constant _keySchema = Schema.wrap(0x004002005f5f0000000000000000000000000000000000000000000000000000);
31
+ // Hex-encoded value schema of (bool, uint40)
32
+ Schema constant _valueSchema = Schema.wrap(0x0006020060040000000000000000000000000000000000000000000000000000);
33
+
34
+ /**
35
+ * @notice Get the table's key field names.
36
+ * @return keyNames An array of strings with the names of key fields.
37
+ */
38
+ function getKeyNames() internal pure returns (string[] memory keyNames) {
39
+ keyNames = new string[](2);
40
+ keyNames[0] = "sourceTableId";
41
+ keyNames[1] = "keysHash";
42
+ }
43
+
44
+ /**
45
+ * @notice Get the table's value field names.
46
+ * @return fieldNames An array of strings with the names of value fields.
47
+ */
48
+ function getFieldNames() internal pure returns (string[] memory fieldNames) {
49
+ fieldNames = new string[](2);
50
+ fieldNames[0] = "has";
51
+ fieldNames[1] = "index";
52
+ }
53
+
54
+ /**
55
+ * @notice Register the table with its config.
56
+ */
57
+ function register() internal {
58
+ StoreSwitch.registerTable(_tableId, _fieldLayout, _keySchema, _valueSchema, getKeyNames(), getFieldNames());
59
+ }
60
+
61
+ /**
62
+ * @notice Register the table with its config.
63
+ */
64
+ function _register() internal {
65
+ StoreCore.registerTable(_tableId, _fieldLayout, _keySchema, _valueSchema, getKeyNames(), getFieldNames());
66
+ }
67
+
68
+ /**
69
+ * @notice Register the table with its config (using the specified store).
70
+ */
71
+ function register(IStore _store) internal {
72
+ _store.registerTable(_tableId, _fieldLayout, _keySchema, _valueSchema, getKeyNames(), getFieldNames());
73
+ }
74
+
75
+ /**
76
+ * @notice Get has.
77
+ */
78
+ function getHas(ResourceId sourceTableId, bytes32 keysHash) internal view returns (bool has) {
79
+ bytes32[] memory _keyTuple = new bytes32[](2);
80
+ _keyTuple[0] = ResourceId.unwrap(sourceTableId);
81
+ _keyTuple[1] = keysHash;
82
+
83
+ bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 0, _fieldLayout);
84
+ return (_toBool(uint8(bytes1(_blob))));
85
+ }
86
+
87
+ /**
88
+ * @notice Get has.
89
+ */
90
+ function _getHas(ResourceId sourceTableId, bytes32 keysHash) internal view returns (bool has) {
91
+ bytes32[] memory _keyTuple = new bytes32[](2);
92
+ _keyTuple[0] = ResourceId.unwrap(sourceTableId);
93
+ _keyTuple[1] = keysHash;
94
+
95
+ bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 0, _fieldLayout);
96
+ return (_toBool(uint8(bytes1(_blob))));
97
+ }
98
+
99
+ /**
100
+ * @notice Get has (using the specified store).
101
+ */
102
+ function getHas(IStore _store, ResourceId sourceTableId, bytes32 keysHash) internal view returns (bool has) {
103
+ bytes32[] memory _keyTuple = new bytes32[](2);
104
+ _keyTuple[0] = ResourceId.unwrap(sourceTableId);
105
+ _keyTuple[1] = keysHash;
106
+
107
+ bytes32 _blob = _store.getStaticField(_tableId, _keyTuple, 0, _fieldLayout);
108
+ return (_toBool(uint8(bytes1(_blob))));
109
+ }
110
+
111
+ /**
112
+ * @notice Set has.
113
+ */
114
+ function setHas(ResourceId sourceTableId, bytes32 keysHash, bool has) internal {
115
+ bytes32[] memory _keyTuple = new bytes32[](2);
116
+ _keyTuple[0] = ResourceId.unwrap(sourceTableId);
117
+ _keyTuple[1] = keysHash;
118
+
119
+ StoreSwitch.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((has)), _fieldLayout);
120
+ }
121
+
122
+ /**
123
+ * @notice Set has.
124
+ */
125
+ function _setHas(ResourceId sourceTableId, bytes32 keysHash, bool has) internal {
126
+ bytes32[] memory _keyTuple = new bytes32[](2);
127
+ _keyTuple[0] = ResourceId.unwrap(sourceTableId);
128
+ _keyTuple[1] = keysHash;
129
+
130
+ StoreCore.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((has)), _fieldLayout);
131
+ }
132
+
133
+ /**
134
+ * @notice Set has (using the specified store).
135
+ */
136
+ function setHas(IStore _store, ResourceId sourceTableId, bytes32 keysHash, bool has) internal {
137
+ bytes32[] memory _keyTuple = new bytes32[](2);
138
+ _keyTuple[0] = ResourceId.unwrap(sourceTableId);
139
+ _keyTuple[1] = keysHash;
140
+
141
+ _store.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((has)), _fieldLayout);
142
+ }
143
+
144
+ /**
145
+ * @notice Get index.
146
+ */
147
+ function getIndex(ResourceId sourceTableId, bytes32 keysHash) internal view returns (uint40 index) {
148
+ bytes32[] memory _keyTuple = new bytes32[](2);
149
+ _keyTuple[0] = ResourceId.unwrap(sourceTableId);
150
+ _keyTuple[1] = keysHash;
151
+
152
+ bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 1, _fieldLayout);
153
+ return (uint40(bytes5(_blob)));
154
+ }
155
+
156
+ /**
157
+ * @notice Get index.
158
+ */
159
+ function _getIndex(ResourceId sourceTableId, bytes32 keysHash) internal view returns (uint40 index) {
160
+ bytes32[] memory _keyTuple = new bytes32[](2);
161
+ _keyTuple[0] = ResourceId.unwrap(sourceTableId);
162
+ _keyTuple[1] = keysHash;
163
+
164
+ bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 1, _fieldLayout);
165
+ return (uint40(bytes5(_blob)));
166
+ }
167
+
168
+ /**
169
+ * @notice Get index (using the specified store).
170
+ */
171
+ function getIndex(IStore _store, ResourceId sourceTableId, bytes32 keysHash) internal view returns (uint40 index) {
172
+ bytes32[] memory _keyTuple = new bytes32[](2);
173
+ _keyTuple[0] = ResourceId.unwrap(sourceTableId);
174
+ _keyTuple[1] = keysHash;
175
+
176
+ bytes32 _blob = _store.getStaticField(_tableId, _keyTuple, 1, _fieldLayout);
177
+ return (uint40(bytes5(_blob)));
178
+ }
179
+
180
+ /**
181
+ * @notice Set index.
182
+ */
183
+ function setIndex(ResourceId sourceTableId, bytes32 keysHash, uint40 index) internal {
184
+ bytes32[] memory _keyTuple = new bytes32[](2);
185
+ _keyTuple[0] = ResourceId.unwrap(sourceTableId);
186
+ _keyTuple[1] = keysHash;
187
+
188
+ StoreSwitch.setStaticField(_tableId, _keyTuple, 1, abi.encodePacked((index)), _fieldLayout);
189
+ }
190
+
191
+ /**
192
+ * @notice Set index.
193
+ */
194
+ function _setIndex(ResourceId sourceTableId, bytes32 keysHash, uint40 index) internal {
195
+ bytes32[] memory _keyTuple = new bytes32[](2);
196
+ _keyTuple[0] = ResourceId.unwrap(sourceTableId);
197
+ _keyTuple[1] = keysHash;
198
+
199
+ StoreCore.setStaticField(_tableId, _keyTuple, 1, abi.encodePacked((index)), _fieldLayout);
200
+ }
201
+
202
+ /**
203
+ * @notice Set index (using the specified store).
204
+ */
205
+ function setIndex(IStore _store, ResourceId sourceTableId, bytes32 keysHash, uint40 index) internal {
206
+ bytes32[] memory _keyTuple = new bytes32[](2);
207
+ _keyTuple[0] = ResourceId.unwrap(sourceTableId);
208
+ _keyTuple[1] = keysHash;
209
+
210
+ _store.setStaticField(_tableId, _keyTuple, 1, abi.encodePacked((index)), _fieldLayout);
211
+ }
212
+
213
+ /**
214
+ * @notice Get the full data.
215
+ */
216
+ function get(ResourceId sourceTableId, bytes32 keysHash) internal view returns (bool has, uint40 index) {
217
+ bytes32[] memory _keyTuple = new bytes32[](2);
218
+ _keyTuple[0] = ResourceId.unwrap(sourceTableId);
219
+ _keyTuple[1] = keysHash;
220
+
221
+ (bytes memory _staticData, EncodedLengths _encodedLengths, bytes memory _dynamicData) = StoreSwitch.getRecord(
222
+ _tableId,
223
+ _keyTuple,
224
+ _fieldLayout
225
+ );
226
+ return decode(_staticData, _encodedLengths, _dynamicData);
227
+ }
228
+
229
+ /**
230
+ * @notice Get the full data.
231
+ */
232
+ function _get(ResourceId sourceTableId, bytes32 keysHash) internal view returns (bool has, uint40 index) {
233
+ bytes32[] memory _keyTuple = new bytes32[](2);
234
+ _keyTuple[0] = ResourceId.unwrap(sourceTableId);
235
+ _keyTuple[1] = keysHash;
236
+
237
+ (bytes memory _staticData, EncodedLengths _encodedLengths, bytes memory _dynamicData) = StoreCore.getRecord(
238
+ _tableId,
239
+ _keyTuple,
240
+ _fieldLayout
241
+ );
242
+ return decode(_staticData, _encodedLengths, _dynamicData);
243
+ }
244
+
245
+ /**
246
+ * @notice Get the full data (using the specified store).
247
+ */
248
+ function get(
249
+ IStore _store,
250
+ ResourceId sourceTableId,
251
+ bytes32 keysHash
252
+ ) internal view returns (bool has, uint40 index) {
253
+ bytes32[] memory _keyTuple = new bytes32[](2);
254
+ _keyTuple[0] = ResourceId.unwrap(sourceTableId);
255
+ _keyTuple[1] = keysHash;
256
+
257
+ (bytes memory _staticData, EncodedLengths _encodedLengths, bytes memory _dynamicData) = _store.getRecord(
258
+ _tableId,
259
+ _keyTuple,
260
+ _fieldLayout
261
+ );
262
+ return decode(_staticData, _encodedLengths, _dynamicData);
263
+ }
264
+
265
+ /**
266
+ * @notice Set the full data using individual values.
267
+ */
268
+ function set(ResourceId sourceTableId, bytes32 keysHash, bool has, uint40 index) internal {
269
+ bytes memory _staticData = encodeStatic(has, index);
270
+
271
+ EncodedLengths _encodedLengths;
272
+ bytes memory _dynamicData;
273
+
274
+ bytes32[] memory _keyTuple = new bytes32[](2);
275
+ _keyTuple[0] = ResourceId.unwrap(sourceTableId);
276
+ _keyTuple[1] = keysHash;
277
+
278
+ StoreSwitch.setRecord(_tableId, _keyTuple, _staticData, _encodedLengths, _dynamicData);
279
+ }
280
+
281
+ /**
282
+ * @notice Set the full data using individual values.
283
+ */
284
+ function _set(ResourceId sourceTableId, bytes32 keysHash, bool has, uint40 index) internal {
285
+ bytes memory _staticData = encodeStatic(has, index);
286
+
287
+ EncodedLengths _encodedLengths;
288
+ bytes memory _dynamicData;
289
+
290
+ bytes32[] memory _keyTuple = new bytes32[](2);
291
+ _keyTuple[0] = ResourceId.unwrap(sourceTableId);
292
+ _keyTuple[1] = keysHash;
293
+
294
+ StoreCore.setRecord(_tableId, _keyTuple, _staticData, _encodedLengths, _dynamicData, _fieldLayout);
295
+ }
296
+
297
+ /**
298
+ * @notice Set the full data using individual values (using the specified store).
299
+ */
300
+ function set(IStore _store, ResourceId sourceTableId, bytes32 keysHash, bool has, uint40 index) internal {
301
+ bytes memory _staticData = encodeStatic(has, index);
302
+
303
+ EncodedLengths _encodedLengths;
304
+ bytes memory _dynamicData;
305
+
306
+ bytes32[] memory _keyTuple = new bytes32[](2);
307
+ _keyTuple[0] = ResourceId.unwrap(sourceTableId);
308
+ _keyTuple[1] = keysHash;
309
+
310
+ _store.setRecord(_tableId, _keyTuple, _staticData, _encodedLengths, _dynamicData);
311
+ }
312
+
313
+ /**
314
+ * @notice Decode the tightly packed blob of static data using this table's field layout.
315
+ */
316
+ function decodeStatic(bytes memory _blob) internal pure returns (bool has, uint40 index) {
317
+ has = (_toBool(uint8(Bytes.getBytes1(_blob, 0))));
318
+
319
+ index = (uint40(Bytes.getBytes5(_blob, 1)));
320
+ }
321
+
322
+ /**
323
+ * @notice Decode the tightly packed blobs using this table's field layout.
324
+ * @param _staticData Tightly packed static fields.
325
+ *
326
+ *
327
+ */
328
+ function decode(
329
+ bytes memory _staticData,
330
+ EncodedLengths,
331
+ bytes memory
332
+ ) internal pure returns (bool has, uint40 index) {
333
+ (has, index) = decodeStatic(_staticData);
334
+ }
335
+
336
+ /**
337
+ * @notice Delete all data for given keys.
338
+ */
339
+ function deleteRecord(ResourceId sourceTableId, bytes32 keysHash) internal {
340
+ bytes32[] memory _keyTuple = new bytes32[](2);
341
+ _keyTuple[0] = ResourceId.unwrap(sourceTableId);
342
+ _keyTuple[1] = keysHash;
343
+
344
+ StoreSwitch.deleteRecord(_tableId, _keyTuple);
345
+ }
346
+
347
+ /**
348
+ * @notice Delete all data for given keys.
349
+ */
350
+ function _deleteRecord(ResourceId sourceTableId, bytes32 keysHash) internal {
351
+ bytes32[] memory _keyTuple = new bytes32[](2);
352
+ _keyTuple[0] = ResourceId.unwrap(sourceTableId);
353
+ _keyTuple[1] = keysHash;
354
+
355
+ StoreCore.deleteRecord(_tableId, _keyTuple, _fieldLayout);
356
+ }
357
+
358
+ /**
359
+ * @notice Delete all data for given keys (using the specified store).
360
+ */
361
+ function deleteRecord(IStore _store, ResourceId sourceTableId, bytes32 keysHash) internal {
362
+ bytes32[] memory _keyTuple = new bytes32[](2);
363
+ _keyTuple[0] = ResourceId.unwrap(sourceTableId);
364
+ _keyTuple[1] = keysHash;
365
+
366
+ _store.deleteRecord(_tableId, _keyTuple);
367
+ }
368
+
369
+ /**
370
+ * @notice Tightly pack static (fixed length) data using this table's schema.
371
+ * @return The static data, encoded into a sequence of bytes.
372
+ */
373
+ function encodeStatic(bool has, uint40 index) internal pure returns (bytes memory) {
374
+ return abi.encodePacked(has, index);
375
+ }
376
+
377
+ /**
378
+ * @notice Encode all of a record's fields.
379
+ * @return The static (fixed length) data, encoded into a sequence of bytes.
380
+ * @return The lengths of the dynamic fields (packed into a single bytes32 value).
381
+ * @return The dynamic (variable length) data, encoded into a sequence of bytes.
382
+ */
383
+ function encode(bool has, uint40 index) internal pure returns (bytes memory, EncodedLengths, bytes memory) {
384
+ bytes memory _staticData = encodeStatic(has, index);
385
+
386
+ EncodedLengths _encodedLengths;
387
+ bytes memory _dynamicData;
388
+
389
+ return (_staticData, _encodedLengths, _dynamicData);
390
+ }
391
+
392
+ /**
393
+ * @notice Encode keys as a bytes32 array using this table's field layout.
394
+ */
395
+ function encodeKeyTuple(ResourceId sourceTableId, bytes32 keysHash) internal pure returns (bytes32[] memory) {
396
+ bytes32[] memory _keyTuple = new bytes32[](2);
397
+ _keyTuple[0] = ResourceId.unwrap(sourceTableId);
398
+ _keyTuple[1] = keysHash;
399
+
400
+ return _keyTuple;
401
+ }
402
+ }
403
+
404
+ /**
405
+ * @notice Cast a value to a bool.
406
+ * @dev Boolean values are encoded as uint8 (1 = true, 0 = false), but Solidity doesn't allow casting between uint8 and bool.
407
+ * @param value The uint8 value to convert.
408
+ * @return result The boolean value.
409
+ */
410
+ function _toBool(uint8 value) pure returns (bool result) {
411
+ assembly {
412
+ result := value
413
+ }
414
+ }
@@ -0,0 +1,158 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity >=0.8.24;
3
+
4
+ import { StoreHook } from "@latticexyz/store/src/StoreHook.sol";
5
+ import { Bytes } from "@latticexyz/store/src/Bytes.sol";
6
+ import { FieldLayout } from "@latticexyz/store/src/FieldLayout.sol";
7
+ import { StoreSwitch } from "@latticexyz/store/src/StoreSwitch.sol";
8
+ import { EncodedLengths } from "@latticexyz/store/src/EncodedLengths.sol";
9
+ import { Tables } from "@latticexyz/store/src/codegen/tables/Tables.sol";
10
+ import { IBaseWorld } from "@latticexyz/world/src/codegen/interfaces/IBaseWorld.sol";
11
+
12
+ import { ResourceId, WorldResourceIdInstance } from "@latticexyz/world/src/WorldResourceId.sol";
13
+
14
+ import { MODULE_NAMESPACE } from "./constants.sol";
15
+ import { KeysWithValue } from "./tables/KeysWithValue.sol";
16
+ import { ArrayLib } from "../utils/ArrayLib.sol";
17
+ import { getTargetTableId } from "./getTargetTableId.sol";
18
+
19
+ /**
20
+ * This is a very naive and inefficient implementation for now.
21
+ * We can optimize this by adding support for `setIndexOfField` in Store
22
+ * (See https://github.com/latticexyz/mud/issues/444)
23
+ *
24
+ * Note: if a table with composite keys is used, only the first key of the tuple is indexed
25
+ */
26
+ contract KeysWithValueHook is StoreHook {
27
+ using ArrayLib for bytes32[];
28
+ using WorldResourceIdInstance for ResourceId;
29
+
30
+ function _world() internal view returns (IBaseWorld) {
31
+ return IBaseWorld(StoreSwitch.getStoreAddress());
32
+ }
33
+
34
+ function onBeforeSetRecord(
35
+ ResourceId sourceTableId,
36
+ bytes32[] memory keyTuple,
37
+ bytes memory staticData,
38
+ EncodedLengths encodedLengths,
39
+ bytes memory dynamicData,
40
+ FieldLayout fieldLayout
41
+ ) public override {
42
+ ResourceId targetTableId = getTargetTableId(MODULE_NAMESPACE, sourceTableId);
43
+
44
+ // Get the previous value
45
+ bytes32 previousValue = _getRecordValueHash(sourceTableId, keyTuple, fieldLayout);
46
+
47
+ // Remove the key from the list of keys with the previous value
48
+ _removeKeyFromList(targetTableId, keyTuple[0], previousValue);
49
+
50
+ // Push the key to the list of keys with the new value
51
+ bytes memory data;
52
+ if (dynamicData.length > 0) {
53
+ data = abi.encodePacked(staticData, encodedLengths, dynamicData);
54
+ } else {
55
+ data = staticData;
56
+ }
57
+ KeysWithValue.push(targetTableId, keccak256(data), keyTuple[0]);
58
+ }
59
+
60
+ function onBeforeSpliceStaticData(
61
+ ResourceId sourceTableId,
62
+ bytes32[] memory keyTuple,
63
+ uint48,
64
+ bytes memory
65
+ ) public override {
66
+ // Remove the key from the list of keys with the previous value
67
+ FieldLayout fieldLayout = Tables.getFieldLayout(sourceTableId);
68
+ bytes32 previousValue = _getRecordValueHash(sourceTableId, keyTuple, fieldLayout);
69
+ ResourceId targetTableId = getTargetTableId(MODULE_NAMESPACE, sourceTableId);
70
+ _removeKeyFromList(targetTableId, keyTuple[0], previousValue);
71
+ }
72
+
73
+ function onAfterSpliceStaticData(
74
+ ResourceId sourceTableId,
75
+ bytes32[] memory keyTuple,
76
+ uint48,
77
+ bytes memory
78
+ ) public override {
79
+ // Add the key to the list of keys with the new value
80
+ FieldLayout fieldLayout = Tables.getFieldLayout(sourceTableId);
81
+ bytes32 newValue = _getRecordValueHash(sourceTableId, keyTuple, fieldLayout);
82
+ ResourceId targetTableId = getTargetTableId(MODULE_NAMESPACE, sourceTableId);
83
+ KeysWithValue.push(targetTableId, newValue, keyTuple[0]);
84
+ }
85
+
86
+ function onBeforeSpliceDynamicData(
87
+ ResourceId sourceTableId,
88
+ bytes32[] memory keyTuple,
89
+ uint8,
90
+ uint40,
91
+ uint40,
92
+ EncodedLengths,
93
+ bytes memory
94
+ ) public override {
95
+ // Remove the key from the list of keys with the previous value
96
+ FieldLayout fieldLayout = Tables.getFieldLayout(sourceTableId);
97
+ bytes32 previousValue = _getRecordValueHash(sourceTableId, keyTuple, fieldLayout);
98
+ ResourceId targetTableId = getTargetTableId(MODULE_NAMESPACE, sourceTableId);
99
+ _removeKeyFromList(targetTableId, keyTuple[0], previousValue);
100
+ }
101
+
102
+ function onAfterSpliceDynamicData(
103
+ ResourceId sourceTableId,
104
+ bytes32[] memory keyTuple,
105
+ uint8,
106
+ uint40,
107
+ uint40,
108
+ EncodedLengths,
109
+ bytes memory
110
+ ) public override {
111
+ // Add the key to the list of keys with the new value
112
+ FieldLayout fieldLayout = Tables.getFieldLayout(sourceTableId);
113
+ bytes32 newValue = _getRecordValueHash(sourceTableId, keyTuple, fieldLayout);
114
+ ResourceId targetTableId = getTargetTableId(MODULE_NAMESPACE, sourceTableId);
115
+ KeysWithValue.push(targetTableId, newValue, keyTuple[0]);
116
+ }
117
+
118
+ function onBeforeDeleteRecord(
119
+ ResourceId sourceTableId,
120
+ bytes32[] memory keyTuple,
121
+ FieldLayout fieldLayout
122
+ ) public override {
123
+ // Remove the key from the list of keys with the previous value
124
+ bytes32 previousValue = _getRecordValueHash(sourceTableId, keyTuple, fieldLayout);
125
+ ResourceId targetTableId = getTargetTableId(MODULE_NAMESPACE, sourceTableId);
126
+ _removeKeyFromList(targetTableId, keyTuple[0], previousValue);
127
+ }
128
+
129
+ function _getRecordValueHash(
130
+ ResourceId sourceTableId,
131
+ bytes32[] memory keyTuple,
132
+ FieldLayout fieldLayout
133
+ ) internal view returns (bytes32 valueHash) {
134
+ (bytes memory staticData, EncodedLengths encodedLengths, bytes memory dynamicData) = _world().getRecord(
135
+ sourceTableId,
136
+ keyTuple,
137
+ fieldLayout
138
+ );
139
+ if (dynamicData.length > 0) {
140
+ return keccak256(abi.encodePacked(staticData, encodedLengths, dynamicData));
141
+ } else {
142
+ return keccak256(staticData);
143
+ }
144
+ }
145
+
146
+ function _removeKeyFromList(ResourceId targetTableId, bytes32 key, bytes32 valueHash) internal {
147
+ // Get the keys with the previous value excluding the current key
148
+ bytes32[] memory keysWithPreviousValue = KeysWithValue.get(targetTableId, valueHash).filter(key);
149
+
150
+ if (keysWithPreviousValue.length == 0) {
151
+ // Delete the list of keys in this table
152
+ KeysWithValue.deleteRecord(targetTableId, valueHash);
153
+ } else {
154
+ // Set the keys with the previous value
155
+ KeysWithValue.set(targetTableId, valueHash, keysWithPreviousValue);
156
+ }
157
+ }
158
+ }
@@ -0,0 +1,103 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity >=0.8.24;
3
+ import { StoreSwitch } from "@latticexyz/store/src/StoreSwitch.sol";
4
+ import { BEFORE_SET_RECORD, BEFORE_SPLICE_STATIC_DATA, AFTER_SPLICE_STATIC_DATA, BEFORE_SPLICE_DYNAMIC_DATA, AFTER_SPLICE_DYNAMIC_DATA, BEFORE_DELETE_RECORD } from "@latticexyz/store/src/storeHookTypes.sol";
5
+ import { ResourceIds } from "@latticexyz/store/src/codegen/tables/ResourceIds.sol";
6
+
7
+ import { Module } from "@latticexyz/world/src/Module.sol";
8
+ import { IBaseWorld } from "@latticexyz/world/src/codegen/interfaces/IBaseWorld.sol";
9
+ import { InstalledModules } from "@latticexyz/world/src/codegen/index.sol";
10
+
11
+ import { WorldContextConsumer } from "@latticexyz/world/src/WorldContext.sol";
12
+ import { ResourceId, WorldResourceIdInstance } from "@latticexyz/world/src/WorldResourceId.sol";
13
+ import { revertWithBytes } from "@latticexyz/world/src/revertWithBytes.sol";
14
+
15
+ import { MODULE_NAMESPACE } from "./constants.sol";
16
+ import { KeysWithValueHook } from "./KeysWithValueHook.sol";
17
+ import { KeysWithValue } from "./tables/KeysWithValue.sol";
18
+ import { getTargetTableId } from "./getTargetTableId.sol";
19
+
20
+ /**
21
+ * This module deploys a hook that is called when a value is set in the `sourceTableId`
22
+ * provided in the install methods arguments. The hook keeps track of the keys that map to a given value.
23
+ * from value to list of keys with this value. This mapping is stored in a table registered
24
+ * by the module at the `targetTableId` provided in the install methods arguments.
25
+ *
26
+ * Note: if a table with composite keys is used, only the first key is indexed
27
+ *
28
+ * Note: this module currently only supports `installRoot` (via `World.installRootModule`).
29
+ * TODO: add support for `install` (via `World.installModule`) by using `callFrom` with the `msgSender()`
30
+ */
31
+ contract KeysWithValueModule is Module {
32
+ using WorldResourceIdInstance for ResourceId;
33
+
34
+ // The KeysWithValueHook is deployed once and infers the target table id
35
+ // from the source table id (passed as argument to the hook methods)
36
+ KeysWithValueHook private immutable hook = new KeysWithValueHook();
37
+
38
+ function installRoot(bytes memory encodedArgs) public {
39
+ // Naive check to ensure this is only installed once
40
+ // TODO: only revert if there's nothing to do
41
+ requireNotInstalled(__self, encodedArgs);
42
+
43
+ // Extract source table id from args
44
+ ResourceId sourceTableId = ResourceId.wrap(abi.decode(encodedArgs, (bytes32)));
45
+ ResourceId targetTableId = getTargetTableId(MODULE_NAMESPACE, sourceTableId);
46
+
47
+ IBaseWorld world = IBaseWorld(_world());
48
+
49
+ // Register the target namespace if it doesn't exist yet
50
+ if (!ResourceIds.getExists(targetTableId.getNamespaceId())) {
51
+ (bool registrationSuccess, bytes memory registrationReturnData) = address(world).delegatecall(
52
+ abi.encodeCall(world.registerNamespace, (targetTableId.getNamespaceId()))
53
+ );
54
+ if (!registrationSuccess) revertWithBytes(registrationReturnData);
55
+ }
56
+
57
+ // Register the target table
58
+ (bool success, bytes memory returnData) = address(world).delegatecall(
59
+ abi.encodeCall(
60
+ world.registerTable,
61
+ (
62
+ targetTableId,
63
+ KeysWithValue._fieldLayout,
64
+ KeysWithValue._keySchema,
65
+ KeysWithValue._valueSchema,
66
+ KeysWithValue.getKeyNames(),
67
+ KeysWithValue.getFieldNames()
68
+ )
69
+ )
70
+ );
71
+
72
+ if (!success) revertWithBytes(returnData);
73
+
74
+ // Grant the hook access to the target table
75
+ (success, returnData) = address(world).delegatecall(
76
+ abi.encodeCall(world.grantAccess, (targetTableId, address(hook)))
77
+ );
78
+
79
+ if (!success) revertWithBytes(returnData);
80
+
81
+ // Register a hook that is called when a value is set in the source table
82
+ (success, returnData) = address(world).delegatecall(
83
+ abi.encodeCall(
84
+ world.registerStoreHook,
85
+ (
86
+ sourceTableId,
87
+ hook,
88
+ BEFORE_SET_RECORD |
89
+ BEFORE_SPLICE_STATIC_DATA |
90
+ AFTER_SPLICE_STATIC_DATA |
91
+ BEFORE_SPLICE_DYNAMIC_DATA |
92
+ AFTER_SPLICE_DYNAMIC_DATA |
93
+ BEFORE_DELETE_RECORD
94
+ )
95
+ )
96
+ );
97
+ if (!success) revertWithBytes(returnData);
98
+ }
99
+
100
+ function install(bytes memory) public pure {
101
+ revert Module_NonRootInstallNotSupported();
102
+ }
103
+ }
@@ -0,0 +1,7 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity >=0.8.24;
3
+
4
+ // Limiting the module namespace to 7 bytes so the remaining 7 bytes
5
+ // can be used for an identifier of the source table namespace to avoid
6
+ // collisions between tables with the same name in different namespaces
7
+ bytes7 constant MODULE_NAMESPACE = "keywval";