@web3dotorg/evm-slc-core-contracts 0.3.2

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,8 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.28;
3
+
4
+ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
5
+
6
+ interface IWrappedToken is IERC20 {
7
+ function deposit() external payable returns (bool);
8
+ }
@@ -0,0 +1,22 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.28;
3
+
4
+ library Errors {
5
+ error InsufficientStakeAmount(
6
+ address subject,
7
+ uint256 requestedAmount,
8
+ uint256 availibleAmount
9
+ );
10
+ error InvalidStakeAmount(uint256 amount_);
11
+ error NotDAOSLC(address sender);
12
+ error ParameterIsNotSet(address parametersRegistry, string parameterName);
13
+ error InvalidParametersRegistry();
14
+ error NoRewardsAvailible(address subject);
15
+ error InvalidGovernance();
16
+ error InvalidERC20Token();
17
+ error SenderExpectedToBeDAOSLC(address sender);
18
+ error SenderExpectedToBeGovernance(address sender);
19
+ error ValueShouldBeInBasisPoints(uint256 value);
20
+ error ParameterIsNotSynced(string parameterName);
21
+ error ParameterIsAlreadySynced(string parameterName);
22
+ }
@@ -0,0 +1,78 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.28;
3
+
4
+ import {PRECISION} from "@solarity/solidity-lib/utils/Globals.sol";
5
+
6
+ /// @dev The library is used for neutrals pseudo-random selection based on their stake
7
+ library NeutralsSelection {
8
+ error CountOfAddressesMustBeTheSameAsWeights(uint256 addressesCount, uint256 weightsCount);
9
+ error KmustBeInRangeOfAddresesLength(uint256 k, uint256 addressesLength);
10
+
11
+ /// @param seed -- bytes, which is used as a seed
12
+ /// @return randomNumber -- uint256, which is a pseudo-random number in range [0, PRECISION)
13
+ function getRandomNumber(bytes memory seed) internal pure returns (uint256) {
14
+ return uint256(keccak256(seed)) % PRECISION;
15
+ }
16
+
17
+ function selectTopAddressesByWeight(
18
+ address[] memory addresses_,
19
+ uint256[] memory weights_,
20
+ uint256 k_
21
+ ) internal pure {
22
+ require(
23
+ addresses_.length == weights_.length,
24
+ CountOfAddressesMustBeTheSameAsWeights(addresses_.length, weights_.length)
25
+ );
26
+
27
+ require(
28
+ 0 < k_ && k_ <= addresses_.length,
29
+ KmustBeInRangeOfAddresesLength(k_, addresses_.length)
30
+ );
31
+
32
+ _selectTop(addresses_, weights_, 0, addresses_.length - 1, k_);
33
+ }
34
+
35
+ function _selectTop(
36
+ address[] memory addresses_,
37
+ uint256[] memory weights_,
38
+ uint256 left_,
39
+ uint256 right_,
40
+ uint256 k_
41
+ ) private pure {
42
+ uint256 pivot_ = _partition(addresses_, weights_, left_, right_);
43
+ uint256 count_ = pivot_ - left_ + 1;
44
+
45
+ if (count_ == k_) {
46
+ return;
47
+ }
48
+
49
+ if (count_ < k_) {
50
+ _selectTop(addresses_, weights_, pivot_ + 1, right_, k_ - count_);
51
+ } else {
52
+ _selectTop(addresses_, weights_, left_, pivot_ - 1, k_);
53
+ }
54
+ }
55
+
56
+ function _partition(
57
+ address[] memory addresses_,
58
+ uint256[] memory weights_,
59
+ uint256 left_,
60
+ uint256 right_
61
+ ) private pure returns (uint256) {
62
+ uint256 pivot_ = weights_[right_];
63
+ uint256 i = left_;
64
+
65
+ for (uint256 j = left_; j < right_; ++j) {
66
+ if (weights_[j] > pivot_) {
67
+ (weights_[i], weights_[j]) = (weights_[j], weights_[i]);
68
+ (addresses_[i], addresses_[j]) = (addresses_[j], addresses_[i]);
69
+ ++i;
70
+ }
71
+ }
72
+
73
+ (weights_[i], weights_[right_]) = (weights_[right_], weights_[i]);
74
+ (addresses_[i], addresses_[right_]) = (addresses_[right_], addresses_[i]);
75
+
76
+ return i;
77
+ }
78
+ }
@@ -0,0 +1,4 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.28;
3
+
4
+ import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
@@ -0,0 +1,75 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.28;
3
+
4
+ import {IGovernance} from "../interfaces/IGovernance.sol";
5
+ import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
6
+ import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
7
+
8
+ contract MockGovernance is IGovernance, ERC165 {
9
+ struct ServiceRequestCall {
10
+ address requester;
11
+ uint256 serviceFee;
12
+ uint256 neutralsNumber;
13
+ string additionalLink;
14
+ bytes data;
15
+ }
16
+
17
+ bool public _processServiceRequestResult;
18
+ ServiceRequestCall public _lastCall;
19
+ address public _systemToken;
20
+ address public _parametersRegistry;
21
+
22
+ function setProcessServiceRequestResult(bool result_) external {
23
+ _processServiceRequestResult = result_;
24
+ }
25
+
26
+ function setSystemToken(address token_) external {
27
+ _systemToken = token_;
28
+ }
29
+
30
+ function setParametersRegistry(address registry_) external {
31
+ _parametersRegistry = registry_;
32
+ }
33
+
34
+ function getSystemToken() external view override returns (address) {
35
+ return _systemToken;
36
+ }
37
+
38
+ function getParametersRegistry() external view override returns (address) {
39
+ return _parametersRegistry;
40
+ }
41
+
42
+ function processServiceRequest(
43
+ address requester_,
44
+ uint256 serviceFee_,
45
+ uint256 neutralsNumber_,
46
+ string memory additionalLink_,
47
+ bytes memory data_
48
+ ) external payable override returns (bool) {
49
+ _lastCall = ServiceRequestCall({
50
+ requester: requester_,
51
+ serviceFee: serviceFee_,
52
+ neutralsNumber: neutralsNumber_,
53
+ additionalLink: additionalLink_,
54
+ data: data_
55
+ });
56
+
57
+ return _processServiceRequestResult;
58
+ }
59
+
60
+ function proposeOperations(
61
+ uint256 proposalId_,
62
+ OperationBundle memory operationBundle_
63
+ ) external {}
64
+
65
+ function getLastProcessServiceRequestCall() external view returns (ServiceRequestCall memory) {
66
+ return _lastCall;
67
+ }
68
+
69
+ function supportsInterface(
70
+ bytes4 interfaceId
71
+ ) public view virtual override(ERC165, IERC165) returns (bool) {
72
+ return
73
+ interfaceId == type(IGovernance).interfaceId || super.supportsInterface(interfaceId);
74
+ }
75
+ }
@@ -0,0 +1,126 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.28;
3
+
4
+ import {INeutralsRegistry} from "../interfaces/INeutralsRegistry.sol";
5
+
6
+ /**
7
+ * @title MockNeutralsRegistry
8
+ * @notice Minimal mock for Governance/NeutralsRegistry tests
9
+ */
10
+ contract MockNeutralsRegistry is INeutralsRegistry {
11
+ struct NeutralsInfo {
12
+ uint256 selfStake;
13
+ uint256 weight;
14
+ uint256 delegatedStake;
15
+ uint256 rewards;
16
+ uint256 delegationShare;
17
+ bool isActive;
18
+ bool isPaused;
19
+ string externalLink;
20
+ }
21
+
22
+ address private _governance;
23
+ address private _token;
24
+ address[] private _neutrals;
25
+ mapping(address => bool) private _isNeutral;
26
+ mapping(address => NeutralsInfo) private _neutralsInfo;
27
+
28
+ function setGovernance(address governance_) external {
29
+ _governance = governance_;
30
+ }
31
+
32
+ function setToken(address token_) external {
33
+ _token = token_;
34
+ }
35
+
36
+ function addNeutral(address neutral_, string calldata externalLink_) external {
37
+ if (!_isNeutral[neutral_]) {
38
+ _neutrals.push(neutral_);
39
+ _isNeutral[neutral_] = true;
40
+ }
41
+ _neutralsInfo[neutral_] = NeutralsInfo(0, 0, 0, 0, 0, true, false, externalLink_);
42
+ }
43
+
44
+ function addNeutrals(address[] memory neutrals_) external {
45
+ for (uint256 i = 0; i < neutrals_.length; i++) {
46
+ if (!_isNeutral[neutrals_[i]]) {
47
+ _neutrals.push(neutrals_[i]);
48
+ _isNeutral[neutrals_[i]] = true;
49
+ }
50
+ _neutralsInfo[neutrals_[i]] = NeutralsInfo(
51
+ 0,
52
+ 0,
53
+ 0,
54
+ 0,
55
+ 0,
56
+ true,
57
+ false,
58
+ "http://test.neutral.me"
59
+ );
60
+ }
61
+ }
62
+
63
+ function removeNeutral(address neutral_) external {
64
+ if (!_isNeutral[neutral_]) return;
65
+ uint256 len = _neutrals.length;
66
+ for (uint256 i = 0; i < len; ++i) {
67
+ if (_neutrals[i] == neutral_) {
68
+ _neutrals[i] = _neutrals[len - 1];
69
+ _neutrals.pop();
70
+ break;
71
+ }
72
+ }
73
+ _isNeutral[neutral_] = false;
74
+ delete _neutralsInfo[neutral_];
75
+ }
76
+
77
+ function clearNeutrals() external {
78
+ for (uint256 i = 0; i < _neutrals.length; ++i) {
79
+ _isNeutral[_neutrals[i]] = false;
80
+ delete _neutralsInfo[_neutrals[i]];
81
+ }
82
+ delete _neutrals;
83
+ }
84
+
85
+ // --- INeutralsRegistry ---
86
+ function getNeutralsSlice(uint256 number_) external view override returns (address[] memory) {
87
+ uint256 n = _neutrals.length < number_ ? _neutrals.length : number_;
88
+ address[] memory slice = new address[](n);
89
+ for (uint256 i = 0; i < n; ++i) {
90
+ slice[i] = _neutrals[i];
91
+ }
92
+ return slice;
93
+ }
94
+
95
+ function getNeutralsCount() external view override returns (uint256) {
96
+ return _neutrals.length;
97
+ }
98
+
99
+ function isNeutral(address candidate_) external view override returns (bool) {
100
+ return _isNeutral[candidate_];
101
+ }
102
+
103
+ function slashNeutral(address neutral_, uint256 amount_) external override {
104
+ // no-op for mock
105
+ }
106
+
107
+ function distributeRewards(
108
+ address[] calldata selectedNeutrals_,
109
+ uint256 amount_
110
+ ) external override {
111
+ emit RewardsDistributed(selectedNeutrals_, amount_);
112
+ }
113
+
114
+ // --- Extra for tests ---
115
+ function getNeutralInfo(address candidate_) external view returns (NeutralsInfo memory) {
116
+ return _neutralsInfo[candidate_];
117
+ }
118
+
119
+ function getActiveNeutrals() external view returns (address[] memory) {
120
+ return _neutrals;
121
+ }
122
+
123
+ function supportsInterface(bytes4 interfaceId) public pure override returns (bool) {
124
+ return interfaceId == type(INeutralsRegistry).interfaceId || interfaceId == 0x01ffc9a7; // IERC165
125
+ }
126
+ }
@@ -0,0 +1,14 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.28;
3
+
4
+ contract SimpleContract {
5
+ uint256 public value;
6
+
7
+ function setValue(uint256 newValue_) external {
8
+ value = newValue_;
9
+ }
10
+
11
+ function getValue() external view returns (uint256) {
12
+ return value;
13
+ }
14
+ }
@@ -0,0 +1,24 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.28;
3
+
4
+ import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
5
+
6
+ import {IWrappedToken} from "../interfaces/IWrappedToken.sol";
7
+
8
+ contract WrappedToken is ERC20, IWrappedToken {
9
+ constructor() ERC20("Mock Wrapped Token", "MVT") {}
10
+
11
+ function mint(address to_, uint256 amount_) public {
12
+ _mint(to_, amount_);
13
+ }
14
+
15
+ function burn(address to_, uint256 amount_) public {
16
+ _burn(to_, amount_);
17
+ }
18
+
19
+ function deposit() external payable override returns (bool) {
20
+ mint(msg.sender, msg.value);
21
+
22
+ return true;
23
+ }
24
+ }
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@web3dotorg/evm-slc-core-contracts",
3
+ "version": "0.3.2",
4
+ "author": "<TBD>",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/web3dotorg/evm-slc-core.git"
8
+ },
9
+ "homepage": "https://github.com/web3dotorg/evm-slc-core#readme",
10
+ "bugs": {
11
+ "url": "https://github.com/web3dotorg/evm-slc-core/issues"
12
+ },
13
+ "publishConfig": {
14
+ "access": "public",
15
+ "tag": "latest"
16
+ },
17
+ "keywords": [
18
+ "solidity",
19
+ "smart-contracts",
20
+ "web3"
21
+ ],
22
+ "dependencies": {
23
+ "@openzeppelin/contracts": "5.3.0",
24
+ "@openzeppelin/contracts-upgradeable": "5.3.0",
25
+ "@solarity/solidity-lib": "3.1.1"
26
+ }
27
+ }
@@ -0,0 +1,119 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.28;
3
+
4
+ import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
5
+ import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
6
+
7
+ import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
8
+
9
+ import {ISLCCore} from "../interfaces/ISLCCore.sol";
10
+ import {IGovernance} from "../interfaces/IGovernance.sol";
11
+
12
+ contract SLCCore is ISLCCore, ERC165, Initializable {
13
+ struct SLCCoreStorage {
14
+ IGovernance governance;
15
+ // General SLC information
16
+ address slcCreator;
17
+ uint256 slcCreationTimestamp;
18
+ string legalDocumentLink;
19
+ bytes data;
20
+ }
21
+
22
+ // keccak256(abi.encode(uint256(keccak256("evm-slc-core.storage.SLCCore")) - 1)) & ~bytes32(uint256(0xff))
23
+ bytes32 private constant SLC_CORE_STORAGE_LOCATION =
24
+ 0xf304ff929824090662a6977433af60f5d227e05590d7b320d3ccf44d6a708900;
25
+
26
+ receive() external payable {}
27
+
28
+ modifier onlyGovernance() {
29
+ _requireGovernance();
30
+ _;
31
+ }
32
+
33
+ constructor() {
34
+ _disableInitializers();
35
+ }
36
+
37
+ function __SLCCore_init(
38
+ address creator_,
39
+ address governance_,
40
+ string calldata legalDocumentLink_,
41
+ bytes calldata data_
42
+ ) external initializer {
43
+ SLCCoreStorage storage $ = _getSLCCoreStorage();
44
+
45
+ $.legalDocumentLink = legalDocumentLink_;
46
+ $.data = data_;
47
+ $.governance = IGovernance(governance_);
48
+
49
+ $.slcCreator = creator_;
50
+ $.slcCreationTimestamp = block.timestamp;
51
+
52
+ emit SLCInitialized(creator_, legalDocumentLink_);
53
+ }
54
+
55
+ function requestService(
56
+ uint256 serviceFee_,
57
+ uint256 neutralsNumber_,
58
+ string calldata additionalLink_,
59
+ bytes calldata data_
60
+ ) external payable virtual returns (bool) {
61
+ emit ServiceRequested(msg.sender, serviceFee_, neutralsNumber_, additionalLink_);
62
+
63
+ return
64
+ _getSLCCoreStorage().governance.processServiceRequest{value: msg.value}(
65
+ msg.sender,
66
+ serviceFee_,
67
+ neutralsNumber_,
68
+ additionalLink_,
69
+ data_
70
+ );
71
+ }
72
+
73
+ /* solhint-disable-next-line gas-calldata-parameters */
74
+ function arbitraryExecute(
75
+ IGovernance.OperationType operation_,
76
+ address to_,
77
+ bytes memory data_,
78
+ uint256 value_
79
+ ) external virtual onlyGovernance returns (bool success) {
80
+ if (data_.length == 0 && value_ == 0) return true;
81
+
82
+ if (operation_ == IGovernance.OperationType.DelegateCall) {
83
+ /* solhint-disable-next-line no-inline-assembly */
84
+ assembly ("memory-safe") {
85
+ success := delegatecall(gas(), to_, add(data_, 0x20), mload(data_), 0, 0)
86
+ }
87
+ } else {
88
+ /* solhint-disable-next-line no-inline-assembly */
89
+ assembly ("memory-safe") {
90
+ success := call(gas(), to_, value_, add(data_, 0x20), mload(data_), 0, 0)
91
+ }
92
+ }
93
+
94
+ require(success, FailedToExecuteArbitraryCall(operation_, to_, data_, value_));
95
+
96
+ emit ArbitraryExecute(operation_, to_, data_, value_);
97
+ }
98
+
99
+ function supportsInterface(
100
+ bytes4 interfaceId
101
+ ) public view override(IERC165, ERC165) returns (bool) {
102
+ return super.supportsInterface(interfaceId) || interfaceId == type(ISLCCore).interfaceId;
103
+ }
104
+
105
+ function getSLCCoreStorage() external pure returns (SLCCoreStorage memory) {
106
+ return _getSLCCoreStorage();
107
+ }
108
+
109
+ function _requireGovernance() internal view {
110
+ require(address(_getSLCCoreStorage().governance) == msg.sender, NotGovernance(msg.sender));
111
+ }
112
+
113
+ function _getSLCCoreStorage() private pure returns (SLCCoreStorage storage $) {
114
+ /* solhint-disable-next-line no-inline-assembly */
115
+ assembly ("memory-safe") {
116
+ $.slot := SLC_CORE_STORAGE_LOCATION
117
+ }
118
+ }
119
+ }