11// SPDX-License-Identifier: Apache-2.0
22pragma solidity ^ 0.8.11 ;
33
4+ /// @author thirdweb
5+
46import "../../extension/interface/IRulesEngine.sol " ;
57
68import "../../eip/interface/IERC20.sol " ;
79import "../../eip/interface/IERC721.sol " ;
810import "../../eip/interface/IERC1155.sol " ;
911
12+ import "../../openzeppelin-presets/utils/structs/EnumerableSet.sol " ;
13+
1014library RulesEngineStorage {
1115 bytes32 public constant RULES_ENGINE_STORAGE_POSITION = keccak256 ("rules.engine.storage " );
1216
1317 struct Data {
14- uint256 nextRuleId;
15- mapping (uint256 => IRulesEngine.RuleWithId) rules;
18+ address rulesEngineOverride;
19+ EnumerableSet.Bytes32Set ids;
20+ mapping (bytes32 => IRulesEngine.RuleWithId) rules;
1621 }
1722
1823 function rulesEngineStorage () internal pure returns (Data storage rulesEngineData ) {
@@ -24,61 +29,77 @@ library RulesEngineStorage {
2429}
2530
2631abstract contract RulesEngine is IRulesEngine {
32+ using EnumerableSet for EnumerableSet.Bytes32Set;
33+
2734 /*///////////////////////////////////////////////////////////////
2835 View functions
2936 //////////////////////////////////////////////////////////////*/
3037
3138 function getScore (address _tokenOwner ) public view returns (uint256 score ) {
32- uint256 len = _rulesEngineStorage ().nextRuleId;
39+ address engineOverride = getRulesEngineOverride ();
40+ if (engineOverride != address (0 )) {
41+ return IRulesEngine (engineOverride).getScore (_tokenOwner);
42+ }
43+
44+ bytes32 [] memory ids = _rulesEngineStorage ().ids.values ();
45+ uint256 len = ids.length ;
3346
3447 for (uint256 i = 0 ; i < len; i += 1 ) {
35- Rule memory rule = _rulesEngineStorage ().rules[i].rule;
36-
37- if (rule.tokenType == TokenType.ERC20 ) {
38- if (IERC20 (rule.token).balanceOf (_tokenOwner) >= rule.balance) {
39- score += rule.score;
40- }
41- } else if (rule.tokenType == TokenType.ERC721 ) {
42- if (IERC721 (rule.token).balanceOf (_tokenOwner) >= rule.balance) {
43- score += rule.score;
44- }
45- } else if (rule.tokenType == TokenType.ERC1155 ) {
46- if (IERC1155 (rule.token).balanceOf (_tokenOwner, rule.tokenId) >= rule.balance) {
47- score += rule.score;
48- }
49- }
48+ RuleWithId memory rule = _rulesEngineStorage ().rules[ids[i]];
49+ score += _getScoreForRule (_tokenOwner, rule);
5050 }
5151 }
5252
5353 function getAllRules () external view returns (RuleWithId[] memory rules ) {
54- uint256 len = _rulesEngineStorage ().nextRuleId;
55- uint256 count = 0 ;
54+ bytes32 [] memory ids = _rulesEngineStorage ().ids.values ();
55+ uint256 len = ids.length ;
56+
57+ rules = new RuleWithId [](len);
5658
5759 for (uint256 i = 0 ; i < len; i += 1 ) {
58- if (_rulesEngineStorage ().rules[i].rule.token != address (0 )) {
59- count++ ;
60- }
60+ rules[i] = _rulesEngineStorage ().rules[ids[i]];
6161 }
62+ }
6263
63- rules = new RuleWithId [](count);
64- uint256 idx = 0 ;
65- for (uint256 j = 0 ; j < len; j += 1 ) {
66- if (_rulesEngineStorage ().rules[j].rule.token != address (0 )) {
67- rules[idx++ ] = _rulesEngineStorage ().rules[j];
68- }
69- }
64+ function getRulesEngineOverride () public view returns (address rulesEngineAddress ) {
65+ rulesEngineAddress = _rulesEngineStorage ().rulesEngineOverride;
7066 }
7167
7268 /*///////////////////////////////////////////////////////////////
7369 External functions
7470 //////////////////////////////////////////////////////////////*/
7571
76- function createRule (Rule memory rule ) external returns (uint256 ruleId ) {
72+ function createRuleMulitiplicative (RuleTypeMultiplicative memory rule ) external returns (bytes32 ruleId ) {
73+ require (_canSetRules (), "RulesEngine: cannot set rules " );
74+
75+ ruleId = keccak256 (
76+ abi.encodePacked (rule.token, rule.tokenType, rule.tokenId, rule.scorePerOwnedToken, RuleType.Multiplicative)
77+ );
78+ _createRule (
79+ RuleWithId (
80+ ruleId,
81+ rule.token,
82+ rule.tokenType,
83+ rule.tokenId,
84+ 0 , // balance
85+ rule.scorePerOwnedToken,
86+ RuleType.Multiplicative
87+ )
88+ );
89+ }
90+
91+ function createRuleThreshold (RuleTypeThreshold memory rule ) external returns (bytes32 ruleId ) {
7792 require (_canSetRules (), "RulesEngine: cannot set rules " );
78- ruleId = _createRule (rule);
93+
94+ ruleId = keccak256 (
95+ abi.encodePacked (rule.token, rule.tokenType, rule.tokenId, rule.balance, rule.score, RuleType.Threshold)
96+ );
97+ _createRule (
98+ RuleWithId (ruleId, rule.token, rule.tokenType, rule.tokenId, rule.balance, rule.score, RuleType.Threshold)
99+ );
79100 }
80101
81- function deleteRule (uint256 _ruleId ) external {
102+ function deleteRule (bytes32 _ruleId ) external {
82103 require (_canSetRules (), "RulesEngine: cannot set rules " );
83104 _deleteRule (_ruleId);
84105 }
@@ -87,20 +108,50 @@ abstract contract RulesEngine is IRulesEngine {
87108 Internal functions
88109 //////////////////////////////////////////////////////////////*/
89110
90- function _createRule (Rule memory _rule ) internal returns (uint256 ruleId ) {
91- ruleId = _rulesEngineStorage ().nextRuleId++ ;
92- _rulesEngineStorage ().rules[ruleId] = RuleWithId (ruleId, _rule);
111+ function _getScoreForRule (address _tokenOwner , RuleWithId memory _rule ) internal view returns (uint256 score ) {
112+ uint256 balance = 0 ;
93113
94- emit RuleCreated (ruleId, _rule);
114+ if (_rule.tokenType == TokenType.ERC20 ) {
115+ balance = IERC20 (_rule.token).balanceOf (_tokenOwner);
116+ } else if (_rule.tokenType == TokenType.ERC721 ) {
117+ balance = IERC721 (_rule.token).balanceOf (_tokenOwner);
118+ } else if (_rule.tokenType == TokenType.ERC1155 ) {
119+ balance = IERC1155 (_rule.token).balanceOf (_tokenOwner, _rule.tokenId);
120+ }
121+
122+ if (_rule.ruleType == RuleType.Threshold) {
123+ if (balance >= _rule.balance) {
124+ score = _rule.score;
125+ }
126+ } else if (_rule.ruleType == RuleType.Multiplicative) {
127+ score = balance * _rule.score;
128+ }
95129 }
96130
97- function _deleteRule (uint256 _ruleId ) internal {
131+ function _createRule (RuleWithId memory _rule ) internal {
132+ require (_rulesEngineStorage ().ids.add (_rule.ruleId), "RulesEngine: rule already exists " );
133+ _rulesEngineStorage ().rules[_rule.ruleId] = _rule;
134+ emit RuleCreated (_rule.ruleId, _rule);
135+ }
136+
137+ function _deleteRule (bytes32 _ruleId ) internal {
138+ require (_rulesEngineStorage ().ids.remove (_ruleId), "RulesEngine: rule already exists " );
98139 delete _rulesEngineStorage ().rules[_ruleId];
140+ emit RuleDeleted (_ruleId);
141+ }
142+
143+ function setRulesEngineOverride (address _rulesEngineAddress ) external {
144+ require (_canOverrieRulesEngine (), "RulesEngine: cannot override rules engine " );
145+ _rulesEngineStorage ().rulesEngineOverride = _rulesEngineAddress;
146+
147+ emit RulesEngineOverriden (_rulesEngineAddress);
99148 }
100149
101150 function _rulesEngineStorage () internal pure returns (RulesEngineStorage.Data storage data ) {
102151 data = RulesEngineStorage.rulesEngineStorage ();
103152 }
104153
105154 function _canSetRules () internal view virtual returns (bool );
155+
156+ function _canOverrieRulesEngine () internal view virtual returns (bool );
106157}
0 commit comments