@web3dotorg/evm-slc-core-contracts 0.3.13 → 0.3.15
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/governance/ExecutorsRegistry.sol +23 -0
- package/governance/Governance.sol +46 -264
- package/governance/NeutralsRegistry.sol +1 -1
- package/libs/GovernanceUtils.sol +304 -0
- package/package.json +1 -1
- package/utils/Globals.sol +24 -0
|
@@ -41,6 +41,7 @@ contract ExecutorsRegistry is IExecutorsRegistry, ERC165, UUPSUpgradeable, AValu
|
|
|
41
41
|
bool isApproved;
|
|
42
42
|
bool isActive;
|
|
43
43
|
bool isStandby;
|
|
44
|
+
string externalLink;
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
struct WithdrawalAnnouncement {
|
|
@@ -320,6 +321,19 @@ contract ExecutorsRegistry is IExecutorsRegistry, ERC165, UUPSUpgradeable, AValu
|
|
|
320
321
|
emit RewardsClaimed(msg.sender, rewards_);
|
|
321
322
|
}
|
|
322
323
|
|
|
324
|
+
/**
|
|
325
|
+
* @notice Set an external link for the executor (e.g., profile or info page)
|
|
326
|
+
* @param externalLink_ The external link string
|
|
327
|
+
*/
|
|
328
|
+
function setExternalLink(string calldata externalLink_) external {
|
|
329
|
+
ExecutorsRegistryStorage storage $ = _getExecutorsRegistryStorage();
|
|
330
|
+
ExecutorInfo storage executorInfo = $.executors[msg.sender];
|
|
331
|
+
|
|
332
|
+
if (executorInfo.stake == 0) revert ExecutorHasNoStake(msg.sender);
|
|
333
|
+
|
|
334
|
+
executorInfo.externalLink = externalLink_;
|
|
335
|
+
}
|
|
336
|
+
|
|
323
337
|
/**
|
|
324
338
|
* @notice Synchronize local maxActiveExecutors parameter with the one in the registry
|
|
325
339
|
*/
|
|
@@ -362,6 +376,15 @@ contract ExecutorsRegistry is IExecutorsRegistry, ERC165, UUPSUpgradeable, AValu
|
|
|
362
376
|
return _getExecutorsRegistryStorage().executors[executor_];
|
|
363
377
|
}
|
|
364
378
|
|
|
379
|
+
/**
|
|
380
|
+
* @notice Get the external link set by an executor
|
|
381
|
+
* @param executor_ Address of the executor
|
|
382
|
+
* @return The external link string
|
|
383
|
+
*/
|
|
384
|
+
function getExternalLink(address executor_) external view returns (string memory) {
|
|
385
|
+
return _getExecutorsRegistryStorage().executors[executor_].externalLink;
|
|
386
|
+
}
|
|
387
|
+
|
|
365
388
|
/**
|
|
366
389
|
* @notice Get active executors list with pagination
|
|
367
390
|
* @param offset_ Starting index
|
|
@@ -22,11 +22,13 @@ import {IGovernance} from "../interfaces/IGovernance.sol";
|
|
|
22
22
|
import {IQParameters} from "../interfaces/IQParameters.sol";
|
|
23
23
|
import {INeutralsRegistry} from "../interfaces/INeutralsRegistry.sol";
|
|
24
24
|
import {IExecutorsRegistry} from "../interfaces/IExecutorsRegistry.sol";
|
|
25
|
+
import {GovernanceUtils} from "../libs/GovernanceUtils.sol";
|
|
25
26
|
import {DAOSLC_PARAM_NAME, TREASURY_ADDRESS_PARAM_NAME} from "../utils/Globals.sol";
|
|
26
27
|
|
|
28
|
+
import * as Globals from "../utils/Globals.sol";
|
|
29
|
+
|
|
27
30
|
contract Governance is IGovernance, GovernorUpgradeable, UUPSUpgradeable {
|
|
28
31
|
using EnumerableSet for EnumerableSet.AddressSet;
|
|
29
|
-
|
|
30
32
|
using SafeERC20 for IWrappedToken;
|
|
31
33
|
|
|
32
34
|
// keccak256(abi.encode(uint256(keccak256("evm-slc-core.storage.Governance")) - 1)) & ~bytes32(uint256(0xff))
|
|
@@ -36,30 +38,6 @@ contract Governance is IGovernance, GovernorUpgradeable, UUPSUpgradeable {
|
|
|
36
38
|
bytes32 private constant GOVERNOR_STORAGE_LOCATION =
|
|
37
39
|
0x7c712897014dbe49c045ef1299aa2d5f9e67e48eea4403efa21f1e0f3ac0cb00;
|
|
38
40
|
|
|
39
|
-
string private constant VOTING_DELAY_PARAM_NAME = "slc.governance.votingDelay";
|
|
40
|
-
|
|
41
|
-
// solhint-disable-next-line gas-small-strings
|
|
42
|
-
string private constant NEUTRALS_VOTING_PERIOD_PARAM_NAME =
|
|
43
|
-
"slc.governance.neutralsVotingPeriod";
|
|
44
|
-
|
|
45
|
-
// solhint-disable-next-line gas-small-strings
|
|
46
|
-
string private constant EXECUTORS_VOTING_PERIOD_PARAM_NAME =
|
|
47
|
-
"slc.governance.executorsVotingPeriod";
|
|
48
|
-
|
|
49
|
-
// solhint-disable-next-line gas-small-strings
|
|
50
|
-
string private constant NEUTRALS_THRESHOLD_PARAM_NAME = "slc.governance.neutralsThreshold";
|
|
51
|
-
|
|
52
|
-
// solhint-disable-next-line gas-small-strings
|
|
53
|
-
string private constant EXECUTORS_THRESHOLD_PARAM_NAME = "slc.governance.executorsThreshold";
|
|
54
|
-
|
|
55
|
-
string private constant EXECUTORS_SHARE_PARAM_NAME = "slc.governance.executorsShare";
|
|
56
|
-
|
|
57
|
-
string private constant NEUTRALS_SHARE_PARAM_NAME = "slc.governance.neutralsShare";
|
|
58
|
-
|
|
59
|
-
string private constant TREASURY_SHARE_PARAM_NAME = "slc.governance.treasuryShare";
|
|
60
|
-
|
|
61
|
-
string private constant MIN_SERVICE_FEE_PARAM_NAME = "slc.governance.minServiceFee";
|
|
62
|
-
|
|
63
41
|
enum VotingPhase {
|
|
64
42
|
None,
|
|
65
43
|
Neutrals,
|
|
@@ -92,7 +70,7 @@ contract Governance is IGovernance, GovernorUpgradeable, UUPSUpgradeable {
|
|
|
92
70
|
VotingPhase votingPhase;
|
|
93
71
|
bytes32 leadingOperationHash;
|
|
94
72
|
// Proposals
|
|
95
|
-
uint256
|
|
73
|
+
uint256 proposalNonce;
|
|
96
74
|
uint256[] proposalIds;
|
|
97
75
|
}
|
|
98
76
|
|
|
@@ -114,7 +92,7 @@ contract Governance is IGovernance, GovernorUpgradeable, UUPSUpgradeable {
|
|
|
114
92
|
struct SLCProposalState {
|
|
115
93
|
// Parent data
|
|
116
94
|
address slcCore;
|
|
117
|
-
uint256
|
|
95
|
+
uint256 requestId;
|
|
118
96
|
// Voting parameters
|
|
119
97
|
uint256 neutralsThreshold;
|
|
120
98
|
uint256 executorsThreshold;
|
|
@@ -193,9 +171,14 @@ contract Governance is IGovernance, GovernorUpgradeable, UUPSUpgradeable {
|
|
|
193
171
|
uint256 minServiceFee_ = _getMinServiceFee();
|
|
194
172
|
require(serviceFee_ >= minServiceFee_, ServiceFeeTooLow(serviceFee_, minServiceFee_));
|
|
195
173
|
|
|
196
|
-
|
|
174
|
+
// solhint-disable-next-line gas-increment-by-one
|
|
175
|
+
uint256 requestCounter_ = $.slcGovernanceState[slcCore_].totalRequestsCount++;
|
|
176
|
+
|
|
177
|
+
uint256 proposalId_ = _makeProposal(
|
|
197
178
|
additionalLink_,
|
|
198
|
-
requester_
|
|
179
|
+
requester_,
|
|
180
|
+
slcCore_,
|
|
181
|
+
requestCounter_
|
|
199
182
|
);
|
|
200
183
|
|
|
201
184
|
address[] memory selectedNeutrals_ = $.neutralsRegistry.getNeutralsSlice(neutralsNumber_);
|
|
@@ -224,41 +207,7 @@ contract Governance is IGovernance, GovernorUpgradeable, UUPSUpgradeable {
|
|
|
224
207
|
uint256 proposalId_,
|
|
225
208
|
OperationBundle calldata operationBundle_
|
|
226
209
|
) external {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
ServiceRequestState storage requestState = $
|
|
230
|
-
.slcGovernanceState[$.proposalState[proposalId_].slcCore]
|
|
231
|
-
.requestState[$.proposalState[proposalId_].requestNumber];
|
|
232
|
-
|
|
233
|
-
require(
|
|
234
|
-
requestState.votingPhase == VotingPhase.Neutrals,
|
|
235
|
-
InvalidVotingPhaseForProposeOperations(requestState.votingPhase)
|
|
236
|
-
);
|
|
237
|
-
|
|
238
|
-
require(
|
|
239
|
-
requestState.selectedNeutrals.contains(msg.sender),
|
|
240
|
-
AccountNotSelected(msg.sender)
|
|
241
|
-
);
|
|
242
|
-
|
|
243
|
-
SLCProposalState storage proposalState = $.proposalState[proposalId_];
|
|
244
|
-
|
|
245
|
-
bytes32 operationHash_ = hashOperation(operationBundle_);
|
|
246
|
-
|
|
247
|
-
bytes32 previousOperationHash_ = proposalState.neutralToOperation[msg.sender];
|
|
248
|
-
if (previousOperationHash_ != bytes32(0)) {
|
|
249
|
-
proposalState.operationByNeutral[previousOperationHash_].remove(msg.sender);
|
|
250
|
-
|
|
251
|
-
if (proposalState.operationByNeutral[previousOperationHash_].length() == 0) {
|
|
252
|
-
_removeOperation(proposalState, previousOperationHash_);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
proposalState.operationByNeutral[operationHash_].add(msg.sender);
|
|
257
|
-
proposalState.neutralToOperation[msg.sender] = operationHash_;
|
|
258
|
-
|
|
259
|
-
_addOperation(proposalState, operationBundle_, operationHash_);
|
|
260
|
-
|
|
261
|
-
proposalState.operationBundleByHash[operationHash_] = operationBundle_;
|
|
210
|
+
GovernanceUtils.handleProposeOperations(proposalId_, operationBundle_);
|
|
262
211
|
}
|
|
263
212
|
|
|
264
213
|
function implementation() external view returns (address) {
|
|
@@ -343,7 +292,7 @@ contract Governance is IGovernance, GovernorUpgradeable, UUPSUpgradeable {
|
|
|
343
292
|
|
|
344
293
|
ServiceRequestState storage requestState = $
|
|
345
294
|
.slcGovernanceState[proposalState.slcCore]
|
|
346
|
-
.requestState[proposalState.
|
|
295
|
+
.requestState[proposalState.requestId];
|
|
347
296
|
|
|
348
297
|
uint256 selectedNeutralsLength_ = requestState.selectedNeutrals.length();
|
|
349
298
|
bytes32[] memory neutralToOperationHashes_ = new bytes32[](selectedNeutralsLength_);
|
|
@@ -388,7 +337,7 @@ contract Governance is IGovernance, GovernorUpgradeable, UUPSUpgradeable {
|
|
|
388
337
|
data: requestState.data,
|
|
389
338
|
votingPhase: requestState.votingPhase,
|
|
390
339
|
leadingOperationHash: requestState.leadingOperationHash,
|
|
391
|
-
requestNonce: requestState.
|
|
340
|
+
requestNonce: requestState.proposalNonce,
|
|
392
341
|
proposalIds: requestState.proposalIds
|
|
393
342
|
});
|
|
394
343
|
}
|
|
@@ -441,7 +390,7 @@ contract Governance is IGovernance, GovernorUpgradeable, UUPSUpgradeable {
|
|
|
441
390
|
* @inheritdoc IGovernor
|
|
442
391
|
*/
|
|
443
392
|
function votingDelay() public view override returns (uint256) {
|
|
444
|
-
return _getGovernanceStorage().parametersRegistry.getUint(VOTING_DELAY_PARAM_NAME);
|
|
393
|
+
return _getGovernanceStorage().parametersRegistry.getUint(Globals.VOTING_DELAY_PARAM_NAME);
|
|
445
394
|
}
|
|
446
395
|
|
|
447
396
|
/**
|
|
@@ -468,12 +417,16 @@ contract Governance is IGovernance, GovernorUpgradeable, UUPSUpgradeable {
|
|
|
468
417
|
|
|
469
418
|
function getNeutralsVotingPeriod() public view returns (uint256) {
|
|
470
419
|
return
|
|
471
|
-
_getGovernanceStorage().parametersRegistry.getUint(
|
|
420
|
+
_getGovernanceStorage().parametersRegistry.getUint(
|
|
421
|
+
Globals.NEUTRALS_VOTING_PERIOD_PARAM_NAME
|
|
422
|
+
);
|
|
472
423
|
}
|
|
473
424
|
|
|
474
425
|
function getExecutorsVotingPeriod() public view returns (uint256) {
|
|
475
426
|
return
|
|
476
|
-
_getGovernanceStorage().parametersRegistry.getUint(
|
|
427
|
+
_getGovernanceStorage().parametersRegistry.getUint(
|
|
428
|
+
Globals.EXECUTORS_VOTING_PERIOD_PARAM_NAME
|
|
429
|
+
);
|
|
477
430
|
}
|
|
478
431
|
|
|
479
432
|
/**
|
|
@@ -481,7 +434,7 @@ contract Governance is IGovernance, GovernorUpgradeable, UUPSUpgradeable {
|
|
|
481
434
|
*/
|
|
482
435
|
function getNeutralsThreshold() public view returns (uint256) {
|
|
483
436
|
uint256 neutralsThreshold_ = _getGovernanceStorage().parametersRegistry.getUint(
|
|
484
|
-
NEUTRALS_THRESHOLD_PARAM_NAME
|
|
437
|
+
Globals.NEUTRALS_THRESHOLD_PARAM_NAME
|
|
485
438
|
);
|
|
486
439
|
|
|
487
440
|
if (neutralsThreshold_ > 100) {
|
|
@@ -496,7 +449,7 @@ contract Governance is IGovernance, GovernorUpgradeable, UUPSUpgradeable {
|
|
|
496
449
|
*/
|
|
497
450
|
function getExecutorsThreshold() public view returns (uint256) {
|
|
498
451
|
uint256 executorsThreshold_ = _getGovernanceStorage().parametersRegistry.getUint(
|
|
499
|
-
EXECUTORS_THRESHOLD_PARAM_NAME
|
|
452
|
+
Globals.EXECUTORS_THRESHOLD_PARAM_NAME
|
|
500
453
|
);
|
|
501
454
|
|
|
502
455
|
if (executorsThreshold_ > 100) {
|
|
@@ -520,50 +473,7 @@ contract Governance is IGovernance, GovernorUpgradeable, UUPSUpgradeable {
|
|
|
520
473
|
uint256 proposalId_,
|
|
521
474
|
address[] memory selectedNeutrals_
|
|
522
475
|
) internal {
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
ServiceRequestState storage requestState = $
|
|
526
|
-
.slcGovernanceState[$.proposalState[proposalId_].slcCore]
|
|
527
|
-
.requestState[$.proposalState[proposalId_].requestNumber];
|
|
528
|
-
|
|
529
|
-
uint256 serviceFee_ = requestState.serviceFee;
|
|
530
|
-
if (serviceFee_ == 0 && msg.value == 0) return;
|
|
531
|
-
|
|
532
|
-
if (msg.value > 0) {
|
|
533
|
-
require(serviceFee_ == msg.value, InvalidServiceFee(serviceFee_, msg.value));
|
|
534
|
-
$.token.deposit{value: msg.value}();
|
|
535
|
-
} else {
|
|
536
|
-
$.token.safeTransferFrom(requestState.requester, address(this), serviceFee_);
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
uint256 executorsShare_ = _getExecutorsShare();
|
|
540
|
-
uint256 neutralsShare_ = _getNeutralsShare();
|
|
541
|
-
uint256 treasuryShare_ = _getTreasuryShare();
|
|
542
|
-
|
|
543
|
-
// Validate shares total 100%
|
|
544
|
-
uint256 totalShares_ = executorsShare_ + neutralsShare_ + treasuryShare_;
|
|
545
|
-
require(totalShares_ == 100, InvalidSharesTotal(totalShares_));
|
|
546
|
-
|
|
547
|
-
// Calculate amounts
|
|
548
|
-
uint256 executorsAmount_ = (serviceFee_ * executorsShare_) / 100;
|
|
549
|
-
uint256 neutralsAmount_ = (serviceFee_ * neutralsShare_) / 100;
|
|
550
|
-
uint256 treasuryAmount_ = (serviceFee_ * treasuryShare_) / 100;
|
|
551
|
-
|
|
552
|
-
// Distribute to executors
|
|
553
|
-
if (executorsAmount_ > 0) {
|
|
554
|
-
$.executorsRegistry.distributeRewards(executorsAmount_);
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
// Distribute to neutrals
|
|
558
|
-
if (neutralsAmount_ > 0) {
|
|
559
|
-
$.neutralsRegistry.distributeRewards(selectedNeutrals_, neutralsAmount_);
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
// Send to treasury
|
|
563
|
-
if (treasuryAmount_ > 0) {
|
|
564
|
-
address treasury_ = _getTreasuryAddress();
|
|
565
|
-
$.token.safeTransfer(treasury_, treasuryAmount_);
|
|
566
|
-
}
|
|
476
|
+
GovernanceUtils.distributeServiceFeeRewards(proposalId_, selectedNeutrals_);
|
|
567
477
|
}
|
|
568
478
|
|
|
569
479
|
function _executeOperations(
|
|
@@ -573,34 +483,7 @@ contract Governance is IGovernance, GovernorUpgradeable, UUPSUpgradeable {
|
|
|
573
483
|
bytes[] memory /*calldatas*/,
|
|
574
484
|
bytes32 /*descriptionHash*/
|
|
575
485
|
) internal override {
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
ServiceRequestState storage requestState = $
|
|
579
|
-
.slcGovernanceState[$.proposalState[proposalId].slcCore]
|
|
580
|
-
.requestState[$.proposalState[proposalId].requestNumber];
|
|
581
|
-
|
|
582
|
-
bytes32 leadingOperationHash_ = requestState.leadingOperationHash;
|
|
583
|
-
if (leadingOperationHash_ == bytes32(0)) {
|
|
584
|
-
revert Unreachable();
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
OperationBundle storage leadingOperationBundle_ = $
|
|
588
|
-
.proposalState[proposalId]
|
|
589
|
-
.operationBundleByHash[leadingOperationHash_];
|
|
590
|
-
|
|
591
|
-
ISLCCore slcCore_ = ISLCCore(targets[0]);
|
|
592
|
-
|
|
593
|
-
uint256 operationsLength_ = leadingOperationBundle_.operations.length;
|
|
594
|
-
for (uint256 i = 0; i < operationsLength_; ++i) {
|
|
595
|
-
slcCore_.arbitraryExecute(
|
|
596
|
-
leadingOperationBundle_.operations[i].operation_,
|
|
597
|
-
leadingOperationBundle_.operations[i].to_,
|
|
598
|
-
leadingOperationBundle_.operations[i].data_,
|
|
599
|
-
leadingOperationBundle_.operations[i].value_
|
|
600
|
-
);
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
requestState.votingPhase = VotingPhase.Executed;
|
|
486
|
+
GovernanceUtils.executeOperations(proposalId, targets);
|
|
604
487
|
}
|
|
605
488
|
|
|
606
489
|
/**
|
|
@@ -620,7 +503,7 @@ contract Governance is IGovernance, GovernorUpgradeable, UUPSUpgradeable {
|
|
|
620
503
|
|
|
621
504
|
ServiceRequestState storage requestState = $
|
|
622
505
|
.slcGovernanceState[$.proposalState[proposalId].slcCore]
|
|
623
|
-
.requestState[$.proposalState[proposalId].
|
|
506
|
+
.requestState[$.proposalState[proposalId].requestId];
|
|
624
507
|
|
|
625
508
|
require($.executorsRegistry.isExecutor(account), AccountNotExecutor(account));
|
|
626
509
|
|
|
@@ -651,9 +534,11 @@ contract Governance is IGovernance, GovernorUpgradeable, UUPSUpgradeable {
|
|
|
651
534
|
$.proposalState[proposalId].negativeExecutorVotes.length() >=
|
|
652
535
|
$.proposalState[proposalId].executorsThreshold
|
|
653
536
|
) {
|
|
654
|
-
|
|
537
|
+
uint256 newProposalId_ = _makeProposal(
|
|
655
538
|
requestState.additionalLink,
|
|
656
|
-
requestState.requester
|
|
539
|
+
requestState.requester,
|
|
540
|
+
$.proposalState[proposalId].slcCore,
|
|
541
|
+
requestState.requestId
|
|
657
542
|
);
|
|
658
543
|
_fillProposalState(newProposalId_);
|
|
659
544
|
|
|
@@ -703,44 +588,27 @@ contract Governance is IGovernance, GovernorUpgradeable, UUPSUpgradeable {
|
|
|
703
588
|
}
|
|
704
589
|
|
|
705
590
|
function _getDAOSLC() internal view returns (address) {
|
|
706
|
-
return _getGovernanceStorage().parametersRegistry.getAddr(DAOSLC_PARAM_NAME);
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
function _getExecutorsShare() internal view returns (uint256) {
|
|
710
|
-
return _getGovernanceStorage().parametersRegistry.getUint(EXECUTORS_SHARE_PARAM_NAME);
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
function _getNeutralsShare() internal view returns (uint256) {
|
|
714
|
-
return _getGovernanceStorage().parametersRegistry.getUint(NEUTRALS_SHARE_PARAM_NAME);
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
function _getTreasuryShare() internal view returns (uint256) {
|
|
718
|
-
return _getGovernanceStorage().parametersRegistry.getUint(TREASURY_SHARE_PARAM_NAME);
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
function _getTreasuryAddress() internal view returns (address) {
|
|
722
|
-
return _getGovernanceStorage().parametersRegistry.getAddr(TREASURY_ADDRESS_PARAM_NAME);
|
|
591
|
+
return _getGovernanceStorage().parametersRegistry.getAddr(Globals.DAOSLC_PARAM_NAME);
|
|
723
592
|
}
|
|
724
593
|
|
|
725
594
|
function _getMinServiceFee() internal view returns (uint256) {
|
|
726
|
-
return
|
|
595
|
+
return
|
|
596
|
+
_getGovernanceStorage().parametersRegistry.getUint(Globals.MIN_SERVICE_FEE_PARAM_NAME);
|
|
727
597
|
}
|
|
728
598
|
|
|
729
599
|
function _makeProposal(
|
|
730
600
|
string memory additionalLink_,
|
|
731
|
-
address requester_
|
|
732
|
-
|
|
601
|
+
address requester_,
|
|
602
|
+
address slcCore_,
|
|
603
|
+
uint256 requestId_
|
|
604
|
+
) private returns (uint256 proposalId_) {
|
|
733
605
|
GovernanceStorage storage $ = _getGovernanceStorage();
|
|
734
606
|
|
|
735
|
-
address slcCore_ = msg.sender;
|
|
736
|
-
|
|
737
607
|
// solhint-disable-next-line gas-increment-by-one
|
|
738
|
-
|
|
739
|
-
// solhint-disable-next-line gas-increment-by-one
|
|
740
|
-
uint256 requestNonce_ = $
|
|
608
|
+
uint256 proposalNonce_ = $
|
|
741
609
|
.slcGovernanceState[slcCore_]
|
|
742
|
-
.requestState[
|
|
743
|
-
.
|
|
610
|
+
.requestState[requestId_]
|
|
611
|
+
.proposalNonce++;
|
|
744
612
|
|
|
745
613
|
address[] memory targets = new address[](1);
|
|
746
614
|
targets[0] = slcCore_;
|
|
@@ -749,18 +617,18 @@ contract Governance is IGovernance, GovernorUpgradeable, UUPSUpgradeable {
|
|
|
749
617
|
values[0] = 0;
|
|
750
618
|
|
|
751
619
|
bytes[] memory calldatas = new bytes[](1);
|
|
752
|
-
calldatas[0] = abi.encodePacked(
|
|
620
|
+
calldatas[0] = abi.encodePacked(requestId_, proposalNonce_);
|
|
753
621
|
|
|
754
622
|
proposalId_ = _propose(targets, values, calldatas, additionalLink_, requester_);
|
|
755
623
|
|
|
756
624
|
$.proposalState[proposalId_].slcCore = slcCore_;
|
|
757
|
-
$.proposalState[proposalId_].
|
|
625
|
+
$.proposalState[proposalId_].requestId = requestId_;
|
|
758
626
|
}
|
|
759
627
|
|
|
760
628
|
function _executeProposal(uint256 proposalId_) private {
|
|
761
629
|
GovernanceStorage storage $ = _getGovernanceStorage();
|
|
762
630
|
|
|
763
|
-
uint256 requestCounter_ = $.proposalState[proposalId_].
|
|
631
|
+
uint256 requestCounter_ = $.proposalState[proposalId_].requestId;
|
|
764
632
|
ServiceRequestState storage requestState = $
|
|
765
633
|
.slcGovernanceState[$.proposalState[proposalId_].slcCore]
|
|
766
634
|
.requestState[requestCounter_];
|
|
@@ -770,7 +638,7 @@ contract Governance is IGovernance, GovernorUpgradeable, UUPSUpgradeable {
|
|
|
770
638
|
|
|
771
639
|
// Here we need to execute the previous proposal related to this request
|
|
772
640
|
bytes[] memory calldatas = new bytes[](1);
|
|
773
|
-
calldatas[0] = abi.encodePacked(requestCounter_, requestState.
|
|
641
|
+
calldatas[0] = abi.encodePacked(requestCounter_, requestState.proposalNonce - 1);
|
|
774
642
|
|
|
775
643
|
execute(
|
|
776
644
|
targets,
|
|
@@ -781,93 +649,7 @@ contract Governance is IGovernance, GovernorUpgradeable, UUPSUpgradeable {
|
|
|
781
649
|
}
|
|
782
650
|
|
|
783
651
|
function _fillProposalState(uint256 proposalId_) private {
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
ServiceRequestState storage requestState = $
|
|
787
|
-
.slcGovernanceState[$.proposalState[proposalId_].slcCore]
|
|
788
|
-
.requestState[$.proposalState[proposalId_].requestNumber];
|
|
789
|
-
|
|
790
|
-
uint256 neutralsLength_ = requestState.selectedNeutrals.length();
|
|
791
|
-
|
|
792
|
-
$.proposalState[proposalId_].neutralsThreshold = Math.mulDiv(
|
|
793
|
-
neutralsLength_,
|
|
794
|
-
getNeutralsThreshold(),
|
|
795
|
-
100,
|
|
796
|
-
Math.Rounding.Ceil
|
|
797
|
-
);
|
|
798
|
-
|
|
799
|
-
uint256 executorsCount_ = $.executorsRegistry.getExecutorsCount();
|
|
800
|
-
$.proposalState[proposalId_].executorsThreshold = Math.mulDiv(
|
|
801
|
-
executorsCount_,
|
|
802
|
-
getExecutorsThreshold(),
|
|
803
|
-
100,
|
|
804
|
-
Math.Rounding.Ceil
|
|
805
|
-
);
|
|
806
|
-
|
|
807
|
-
requestState.proposalIds.push(proposalId_);
|
|
808
|
-
|
|
809
|
-
requestState.votingPhase = VotingPhase.Neutrals;
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
function _addOperation(
|
|
813
|
-
SLCProposalState storage proposalState,
|
|
814
|
-
OperationBundle memory operationBundle_,
|
|
815
|
-
bytes32 operationHash_
|
|
816
|
-
) private returns (bool) {
|
|
817
|
-
if (!_containsOperation(proposalState, operationHash_)) {
|
|
818
|
-
proposalState.operationBundles.push(operationBundle_);
|
|
819
|
-
// The value is stored at length-1, but we add 1 to all indexes
|
|
820
|
-
// and use 0 as a sentinel value
|
|
821
|
-
proposalState.operationBundlePosition[operationHash_] = proposalState
|
|
822
|
-
.operationBundles
|
|
823
|
-
.length;
|
|
824
|
-
return true;
|
|
825
|
-
} else {
|
|
826
|
-
return false;
|
|
827
|
-
}
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
function _removeOperation(
|
|
831
|
-
SLCProposalState storage proposalState,
|
|
832
|
-
bytes32 operationHash_
|
|
833
|
-
) private returns (bool) {
|
|
834
|
-
// We cache the value's position to prevent multiple reads from the same storage slot
|
|
835
|
-
uint256 position_ = proposalState.operationBundlePosition[operationHash_];
|
|
836
|
-
|
|
837
|
-
if (position_ != 0) {
|
|
838
|
-
// Equivalent to contains(set, value)
|
|
839
|
-
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
|
|
840
|
-
// the array, and then remove the last element (sometimes called as 'swap and pop').
|
|
841
|
-
|
|
842
|
-
uint256 valueIndex_ = position_ - 1;
|
|
843
|
-
uint256 lastIndex_ = proposalState.operationBundles.length - 1;
|
|
844
|
-
|
|
845
|
-
if (valueIndex_ != lastIndex_) {
|
|
846
|
-
OperationBundle storage lastValue = proposalState.operationBundles[lastIndex_];
|
|
847
|
-
|
|
848
|
-
// Move the lastValue to the index where the value to delete is
|
|
849
|
-
proposalState.operationBundles[valueIndex_] = lastValue;
|
|
850
|
-
// Update the tracked position of the lastValue (that was just moved)
|
|
851
|
-
proposalState.operationBundlePosition[hashOperation(lastValue)] = position_;
|
|
852
|
-
}
|
|
853
|
-
|
|
854
|
-
// Delete the slot where the moved value was stored
|
|
855
|
-
proposalState.operationBundles.pop();
|
|
856
|
-
|
|
857
|
-
// Delete the tracked position for the deleted slot
|
|
858
|
-
delete proposalState.operationBundlePosition[operationHash_];
|
|
859
|
-
|
|
860
|
-
return true;
|
|
861
|
-
} else {
|
|
862
|
-
return false;
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
function _containsOperation(
|
|
867
|
-
SLCProposalState storage proposalState,
|
|
868
|
-
bytes32 operationHash_
|
|
869
|
-
) private view returns (bool) {
|
|
870
|
-
return proposalState.operationBundlePosition[operationHash_] != 0;
|
|
652
|
+
GovernanceUtils.fillProposalState(proposalId_);
|
|
871
653
|
}
|
|
872
654
|
|
|
873
655
|
function _findLeadingOperation(uint256 proposalId_) private view returns (bytes32) {
|
|
@@ -287,7 +287,7 @@ contract NeutralsRegistry is INeutralsRegistry, ERC165, UUPSUpgradeable {
|
|
|
287
287
|
|
|
288
288
|
uint256 amount_ = announcement.amount;
|
|
289
289
|
|
|
290
|
-
delete $.delegations[
|
|
290
|
+
delete $.delegations[msg.sender][neutral_].withdrawal;
|
|
291
291
|
|
|
292
292
|
if ($.delegations[msg.sender][neutral_].delegatedAmount == 0) {
|
|
293
293
|
$.neutralsPerDelegator[msg.sender].remove(neutral_);
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.28;
|
|
3
|
+
|
|
4
|
+
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
|
|
5
|
+
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
|
6
|
+
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
|
|
7
|
+
import {GovernorUpgradeable} from "@openzeppelin/contracts-upgradeable/governance/GovernorUpgradeable.sol";
|
|
8
|
+
|
|
9
|
+
import {ISLCCore} from "../interfaces/ISLCCore.sol";
|
|
10
|
+
import {Governance} from "../governance/Governance.sol";
|
|
11
|
+
import {IGovernance} from "../interfaces/IGovernance.sol";
|
|
12
|
+
import {IWrappedToken} from "../interfaces/IWrappedToken.sol";
|
|
13
|
+
import * as Globals from "../utils/Globals.sol";
|
|
14
|
+
|
|
15
|
+
library GovernanceUtils {
|
|
16
|
+
using EnumerableSet for EnumerableSet.AddressSet;
|
|
17
|
+
using SafeERC20 for IWrappedToken;
|
|
18
|
+
|
|
19
|
+
bytes32 private constant GOVERNANCE_STORAGE_LOCATION =
|
|
20
|
+
0xb93e2841340255f69de4f9300770e3cc1894dc081e8bf6d34a78e9ac897c7900;
|
|
21
|
+
|
|
22
|
+
bytes32 private constant GOVERNOR_STORAGE_LOCATION =
|
|
23
|
+
0x7c712897014dbe49c045ef1299aa2d5f9e67e48eea4403efa21f1e0f3ac0cb00;
|
|
24
|
+
|
|
25
|
+
function handleProposeOperations(
|
|
26
|
+
uint256 proposalId_,
|
|
27
|
+
IGovernance.OperationBundle calldata operationBundle_
|
|
28
|
+
) external {
|
|
29
|
+
Governance.GovernanceStorage storage $ = _getGovernanceStorage();
|
|
30
|
+
|
|
31
|
+
Governance.ServiceRequestState storage requestState = $
|
|
32
|
+
.slcGovernanceState[$.proposalState[proposalId_].slcCore]
|
|
33
|
+
.requestState[$.proposalState[proposalId_].requestId];
|
|
34
|
+
|
|
35
|
+
require(
|
|
36
|
+
requestState.votingPhase == Governance.VotingPhase.Neutrals,
|
|
37
|
+
Governance.InvalidVotingPhaseForProposeOperations(requestState.votingPhase)
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
require(
|
|
41
|
+
requestState.selectedNeutrals.contains(msg.sender),
|
|
42
|
+
Governance.AccountNotSelected(msg.sender)
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
Governance.SLCProposalState storage proposalState = $.proposalState[proposalId_];
|
|
46
|
+
|
|
47
|
+
bytes32 operationHash_ = hashOperation(operationBundle_);
|
|
48
|
+
|
|
49
|
+
bytes32 previousOperationHash_ = proposalState.neutralToOperation[msg.sender];
|
|
50
|
+
if (previousOperationHash_ != bytes32(0)) {
|
|
51
|
+
proposalState.operationByNeutral[previousOperationHash_].remove(msg.sender);
|
|
52
|
+
|
|
53
|
+
if (proposalState.operationByNeutral[previousOperationHash_].length() == 0) {
|
|
54
|
+
_removeOperation(proposalState, previousOperationHash_);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
proposalState.operationByNeutral[operationHash_].add(msg.sender);
|
|
59
|
+
proposalState.neutralToOperation[msg.sender] = operationHash_;
|
|
60
|
+
|
|
61
|
+
_addOperation(proposalState, operationBundle_, operationHash_);
|
|
62
|
+
|
|
63
|
+
proposalState.operationBundleByHash[operationHash_] = operationBundle_;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function fillProposalState(uint256 proposalId_) external {
|
|
67
|
+
Governance.GovernanceStorage storage $ = _getGovernanceStorage();
|
|
68
|
+
|
|
69
|
+
Governance.ServiceRequestState storage requestState = $
|
|
70
|
+
.slcGovernanceState[$.proposalState[proposalId_].slcCore]
|
|
71
|
+
.requestState[$.proposalState[proposalId_].requestId];
|
|
72
|
+
|
|
73
|
+
uint256 neutralsLength_ = requestState.selectedNeutrals.length();
|
|
74
|
+
|
|
75
|
+
$.proposalState[proposalId_].neutralsThreshold = Math.mulDiv(
|
|
76
|
+
neutralsLength_,
|
|
77
|
+
getNeutralsThreshold(),
|
|
78
|
+
100,
|
|
79
|
+
Math.Rounding.Ceil
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
uint256 executorsCount_ = $.executorsRegistry.getExecutorsCount();
|
|
83
|
+
$.proposalState[proposalId_].executorsThreshold = Math.mulDiv(
|
|
84
|
+
executorsCount_,
|
|
85
|
+
getExecutorsThreshold(),
|
|
86
|
+
100,
|
|
87
|
+
Math.Rounding.Ceil
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
requestState.proposalIds.push(proposalId_);
|
|
91
|
+
|
|
92
|
+
requestState.votingPhase = Governance.VotingPhase.Neutrals;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function distributeServiceFeeRewards(
|
|
96
|
+
uint256 proposalId_,
|
|
97
|
+
address[] memory selectedNeutrals_
|
|
98
|
+
) external {
|
|
99
|
+
Governance.GovernanceStorage storage $ = _getGovernanceStorage();
|
|
100
|
+
|
|
101
|
+
Governance.ServiceRequestState storage requestState = $
|
|
102
|
+
.slcGovernanceState[$.proposalState[proposalId_].slcCore]
|
|
103
|
+
.requestState[$.proposalState[proposalId_].requestId];
|
|
104
|
+
|
|
105
|
+
uint256 serviceFee_ = requestState.serviceFee;
|
|
106
|
+
if (serviceFee_ == 0 && msg.value == 0) return;
|
|
107
|
+
|
|
108
|
+
if (msg.value > 0) {
|
|
109
|
+
require(
|
|
110
|
+
serviceFee_ == msg.value,
|
|
111
|
+
Governance.InvalidServiceFee(serviceFee_, msg.value)
|
|
112
|
+
);
|
|
113
|
+
$.token.deposit{value: msg.value}();
|
|
114
|
+
} else {
|
|
115
|
+
$.token.safeTransferFrom(requestState.requester, address(this), serviceFee_);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
uint256 executorsShare_ = getExecutorsShare();
|
|
119
|
+
uint256 neutralsShare_ = getNeutralsShare();
|
|
120
|
+
uint256 treasuryShare_ = getTreasuryShare();
|
|
121
|
+
|
|
122
|
+
// Validate shares total 100%
|
|
123
|
+
uint256 totalShares_ = executorsShare_ + neutralsShare_ + treasuryShare_;
|
|
124
|
+
require(totalShares_ == 100, Governance.InvalidSharesTotal(totalShares_));
|
|
125
|
+
|
|
126
|
+
// Calculate amounts
|
|
127
|
+
uint256 executorsAmount_ = (serviceFee_ * executorsShare_) / 100;
|
|
128
|
+
uint256 neutralsAmount_ = (serviceFee_ * neutralsShare_) / 100;
|
|
129
|
+
uint256 treasuryAmount_ = (serviceFee_ * treasuryShare_) / 100;
|
|
130
|
+
|
|
131
|
+
// Distribute to executors
|
|
132
|
+
if (executorsAmount_ > 0) {
|
|
133
|
+
$.executorsRegistry.distributeRewards(executorsAmount_);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Distribute to neutrals
|
|
137
|
+
if (neutralsAmount_ > 0) {
|
|
138
|
+
$.neutralsRegistry.distributeRewards(selectedNeutrals_, neutralsAmount_);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Send to treasury
|
|
142
|
+
if (treasuryAmount_ > 0) {
|
|
143
|
+
address treasury_ = getTreasuryAddress();
|
|
144
|
+
$.token.safeTransfer(treasury_, treasuryAmount_);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function executeOperations(uint256 proposalId, address[] memory targets) external {
|
|
149
|
+
Governance.GovernanceStorage storage $ = _getGovernanceStorage();
|
|
150
|
+
|
|
151
|
+
Governance.ServiceRequestState storage requestState = $
|
|
152
|
+
.slcGovernanceState[$.proposalState[proposalId].slcCore]
|
|
153
|
+
.requestState[$.proposalState[proposalId].requestId];
|
|
154
|
+
|
|
155
|
+
bytes32 leadingOperationHash_ = requestState.leadingOperationHash;
|
|
156
|
+
if (leadingOperationHash_ == bytes32(0)) {
|
|
157
|
+
revert Governance.Unreachable();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
IGovernance.OperationBundle storage leadingOperationBundle_ = $
|
|
161
|
+
.proposalState[proposalId]
|
|
162
|
+
.operationBundleByHash[leadingOperationHash_];
|
|
163
|
+
|
|
164
|
+
ISLCCore slcCore_ = ISLCCore(targets[0]);
|
|
165
|
+
|
|
166
|
+
uint256 operationsLength_ = leadingOperationBundle_.operations.length;
|
|
167
|
+
for (uint256 i = 0; i < operationsLength_; ++i) {
|
|
168
|
+
slcCore_.arbitraryExecute(
|
|
169
|
+
leadingOperationBundle_.operations[i].operation_,
|
|
170
|
+
leadingOperationBundle_.operations[i].to_,
|
|
171
|
+
leadingOperationBundle_.operations[i].data_,
|
|
172
|
+
leadingOperationBundle_.operations[i].value_
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
requestState.votingPhase = Governance.VotingPhase.Executed;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function hashOperation(
|
|
180
|
+
IGovernance.OperationBundle memory operation_
|
|
181
|
+
) public pure returns (bytes32) {
|
|
182
|
+
return keccak256(abi.encode(operation_));
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function getExecutorsShare() public view returns (uint256) {
|
|
186
|
+
return
|
|
187
|
+
_getGovernanceStorage().parametersRegistry.getUint(Globals.EXECUTORS_SHARE_PARAM_NAME);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function getNeutralsShare() public view returns (uint256) {
|
|
191
|
+
return
|
|
192
|
+
_getGovernanceStorage().parametersRegistry.getUint(Globals.NEUTRALS_SHARE_PARAM_NAME);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function getTreasuryShare() public view returns (uint256) {
|
|
196
|
+
return
|
|
197
|
+
_getGovernanceStorage().parametersRegistry.getUint(Globals.TREASURY_SHARE_PARAM_NAME);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function getTreasuryAddress() public view returns (address) {
|
|
201
|
+
return
|
|
202
|
+
_getGovernanceStorage().parametersRegistry.getAddr(
|
|
203
|
+
Globals.TREASURY_ADDRESS_PARAM_NAME
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function getNeutralsThreshold() public view returns (uint256) {
|
|
208
|
+
uint256 neutralsThreshold_ = _getGovernanceStorage().parametersRegistry.getUint(
|
|
209
|
+
Globals.NEUTRALS_THRESHOLD_PARAM_NAME
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
if (neutralsThreshold_ > 100) {
|
|
213
|
+
revert Governance.NeutralsThresholdTooHigh(neutralsThreshold_);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return neutralsThreshold_;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function getExecutorsThreshold() public view returns (uint256) {
|
|
220
|
+
uint256 executorsThreshold_ = _getGovernanceStorage().parametersRegistry.getUint(
|
|
221
|
+
Globals.EXECUTORS_THRESHOLD_PARAM_NAME
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
if (executorsThreshold_ > 100) {
|
|
225
|
+
revert Governance.ExecutorsThresholdTooHigh(executorsThreshold_);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return executorsThreshold_;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function _addOperation(
|
|
232
|
+
Governance.SLCProposalState storage proposalState,
|
|
233
|
+
IGovernance.OperationBundle memory operationBundle_,
|
|
234
|
+
bytes32 operationHash_
|
|
235
|
+
) private returns (bool) {
|
|
236
|
+
if (!_containsOperation(proposalState, operationHash_)) {
|
|
237
|
+
proposalState.operationBundles.push(operationBundle_);
|
|
238
|
+
// The value is stored at length-1, but we add 1 to all indexes
|
|
239
|
+
// and use 0 as a sentinel value
|
|
240
|
+
proposalState.operationBundlePosition[operationHash_] = proposalState
|
|
241
|
+
.operationBundles
|
|
242
|
+
.length;
|
|
243
|
+
return true;
|
|
244
|
+
} else {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function _containsOperation(
|
|
250
|
+
Governance.SLCProposalState storage proposalState,
|
|
251
|
+
bytes32 operationHash_
|
|
252
|
+
) private view returns (bool) {
|
|
253
|
+
return proposalState.operationBundlePosition[operationHash_] != 0;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function _removeOperation(
|
|
257
|
+
Governance.SLCProposalState storage proposalState,
|
|
258
|
+
bytes32 operationHash_
|
|
259
|
+
) private returns (bool) {
|
|
260
|
+
// We cache the value's position to prevent multiple reads from the same storage slot
|
|
261
|
+
uint256 position_ = proposalState.operationBundlePosition[operationHash_];
|
|
262
|
+
|
|
263
|
+
if (position_ != 0) {
|
|
264
|
+
// Equivalent to contains(set, value)
|
|
265
|
+
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
|
|
266
|
+
// the array, and then remove the last element (sometimes called as 'swap and pop').
|
|
267
|
+
|
|
268
|
+
uint256 valueIndex_ = position_ - 1;
|
|
269
|
+
uint256 lastIndex_ = proposalState.operationBundles.length - 1;
|
|
270
|
+
|
|
271
|
+
if (valueIndex_ != lastIndex_) {
|
|
272
|
+
IGovernance.OperationBundle storage lastValue = proposalState.operationBundles[
|
|
273
|
+
lastIndex_
|
|
274
|
+
];
|
|
275
|
+
|
|
276
|
+
// Move the lastValue to the index where the value to delete is
|
|
277
|
+
proposalState.operationBundles[valueIndex_] = lastValue;
|
|
278
|
+
// Update the tracked position of the lastValue (that was just moved)
|
|
279
|
+
proposalState.operationBundlePosition[hashOperation(lastValue)] = position_;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Delete the slot where the moved value was stored
|
|
283
|
+
proposalState.operationBundles.pop();
|
|
284
|
+
|
|
285
|
+
// Delete the tracked position for the deleted slot
|
|
286
|
+
delete proposalState.operationBundlePosition[operationHash_];
|
|
287
|
+
|
|
288
|
+
return true;
|
|
289
|
+
} else {
|
|
290
|
+
return false;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function _getGovernanceStorage()
|
|
295
|
+
private
|
|
296
|
+
pure
|
|
297
|
+
returns (Governance.GovernanceStorage storage $)
|
|
298
|
+
{
|
|
299
|
+
/* solhint-disable-next-line no-inline-assembly */
|
|
300
|
+
assembly ("memory-safe") {
|
|
301
|
+
$.slot := GOVERNANCE_STORAGE_LOCATION
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
package/package.json
CHANGED
package/utils/Globals.sol
CHANGED
|
@@ -4,4 +4,28 @@ pragma solidity ^0.8.28;
|
|
|
4
4
|
string constant TREASURY_ADDRESS_PARAM_NAME = "slc.general.treasuryAddress";
|
|
5
5
|
string constant DAOSLC_PARAM_NAME = "slc.general.daoSLC";
|
|
6
6
|
|
|
7
|
+
// Governance
|
|
8
|
+
|
|
9
|
+
string constant VOTING_DELAY_PARAM_NAME = "slc.governance.votingDelay";
|
|
10
|
+
|
|
11
|
+
// solhint-disable-next-line gas-small-strings
|
|
12
|
+
string constant NEUTRALS_VOTING_PERIOD_PARAM_NAME = "slc.governance.neutralsVotingPeriod";
|
|
13
|
+
|
|
14
|
+
// solhint-disable-next-line gas-small-strings
|
|
15
|
+
string constant EXECUTORS_VOTING_PERIOD_PARAM_NAME = "slc.governance.executorsVotingPeriod";
|
|
16
|
+
|
|
17
|
+
// solhint-disable-next-line gas-small-strings
|
|
18
|
+
string constant NEUTRALS_THRESHOLD_PARAM_NAME = "slc.governance.neutralsThreshold";
|
|
19
|
+
|
|
20
|
+
// solhint-disable-next-line gas-small-strings
|
|
21
|
+
string constant EXECUTORS_THRESHOLD_PARAM_NAME = "slc.governance.executorsThreshold";
|
|
22
|
+
|
|
23
|
+
string constant EXECUTORS_SHARE_PARAM_NAME = "slc.governance.executorsShare";
|
|
24
|
+
|
|
25
|
+
string constant NEUTRALS_SHARE_PARAM_NAME = "slc.governance.neutralsShare";
|
|
26
|
+
|
|
27
|
+
string constant TREASURY_SHARE_PARAM_NAME = "slc.governance.treasuryShare";
|
|
28
|
+
|
|
29
|
+
string constant MIN_SERVICE_FEE_PARAM_NAME = "slc.governance.minServiceFee";
|
|
30
|
+
|
|
7
31
|
uint256 constant MAX_BASIS_POINTS = 100_00;
|