Skip to content

Commit 54b296e

Browse files
committed
Main contract and test code complete (minus DAO)
1 parent 8791a71 commit 54b296e

File tree

9 files changed

+1039
-110
lines changed

9 files changed

+1039
-110
lines changed

src/SmartnodesCoordinator.sol

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,8 @@ contract SmartnodesCoordinator is ReentrancyGuard {
116116
constructor(
117117
uint128 _updateTime,
118118
uint8 _requiredApprovalsPercentage,
119-
address _smartnodesCore
119+
address _smartnodesCore,
120+
address[] memory _genesisNodes
120121
) {
121122
if (
122123
_requiredApprovalsPercentage == 0 ||
@@ -133,9 +134,9 @@ contract SmartnodesCoordinator is ReentrancyGuard {
133134

134135
timeConfig = TimeConfig({
135136
updateTime: _updateTime,
136-
lastExecutionTime: uint128(block.timestamp)
137+
lastExecutionTime: 0 // This is set to 0, which allows the first proposal to be submitted by any validator
137138
});
138-
139+
currentRoundValidators = _genesisNodes;
139140
roundData = RoundData({currentRoundId: 1, nextProposalId: 1});
140141
}
141142

@@ -506,7 +507,7 @@ contract SmartnodesCoordinator is ReentrancyGuard {
506507

507508
function _isCurrentRoundExpired() internal view returns (bool) {
508509
TimeConfig memory tc = timeConfig;
509-
return block.timestamp > tc.lastExecutionTime + (tc.updateTime << 1); // * 2 using bit shift
510+
return block.timestamp > tc.lastExecutionTime + (tc.updateTime << 1);
510511
}
511512

512513
// ============= VIEW FUNCTIONS =============

src/SmartnodesCore.sol

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,10 @@ contract SmartnodesCore {
6161
uint8 private constant MAX_NETWORKS = 16;
6262

6363
ISmartnodesToken private immutable i_tokenContract;
64-
ISmartnodesCoordinator private immutable i_validatorContract;
6564

6665
/** State Variables */
66+
ISmartnodesCoordinator private validatorContract;
67+
6768
uint256 public jobCounter;
6869
uint8 public networkCounter;
6970

@@ -90,19 +91,24 @@ contract SmartnodesCore {
9091
event NetworkRemoved(uint8 indexed networkId);
9192

9293
modifier onlyCoordinator() {
93-
if (msg.sender != address(i_validatorContract))
94+
if (msg.sender != address(validatorContract))
9495
revert SmartnodesCore__NotValidatorMultisig();
9596
_;
9697
}
9798

98-
constructor(address _tokenContract, address _validatorContract) {
99-
i_validatorContract = ISmartnodesCoordinator(_validatorContract);
99+
constructor(address _tokenContract) {
100100
i_tokenContract = ISmartnodesToken(_tokenContract);
101101

102102
jobCounter = 0;
103103
networkCounter = 0;
104104
}
105105

106+
function setCoordinator(address _validatorContract) external {
107+
if (address(validatorContract) == address(0)) {
108+
validatorContract = ISmartnodesCoordinator(_validatorContract);
109+
}
110+
}
111+
106112
// ============= Core Functions =============
107113
/**
108114
* @notice Add a new network to the system
Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
// SPDX-License-Identifier: MIT
22
pragma solidity ^0.8.22;
33

4-
import {SmartnodesToken} from "../SmartnodesToken.sol";
5-
import {SmartnodesCore} from "../SmartnodesCore.sol";
4+
import {SmartnodesToken} from "./SmartnodesToken.sol";
5+
import {SmartnodesCore} from "./SmartnodesCore.sol";
6+
import {SmartnodesCoordinator} from "./SmartnodesCoordinator.sol";
67

78
/**
89
* @title SmartnodesDeployer
@@ -33,7 +34,14 @@ contract SmartnodesDeployer {
3334
*/
3435
function deploySmartnodesEcosystem(
3536
address[] memory _genesisNodes
36-
) public returns (address tokenAddress, address coreAddress) {
37+
)
38+
public
39+
returns (
40+
address tokenAddress,
41+
address coreAddress,
42+
address coordinatorAddress
43+
)
44+
{
3745
// Validate genesis nodes
3846
require(
3947
_genesisNodes.length > 0,
@@ -59,10 +67,12 @@ contract SmartnodesDeployer {
5967

6068
try this._deployContracts(_genesisNodes) returns (
6169
address token,
62-
address core
70+
address core,
71+
address coordinator
6372
) {
6473
tokenAddress = token;
6574
coreAddress = core;
75+
coordinatorAddress = coordinator;
6676

6777
emit SmartnodesEcosystemDeployed(
6878
tokenAddress,
@@ -87,7 +97,14 @@ contract SmartnodesDeployer {
8797
*/
8898
function _deployContracts(
8999
address[] memory _genesisNodes
90-
) external returns (address tokenAddress, address coreAddress) {
100+
)
101+
external
102+
returns (
103+
address tokenAddress,
104+
address coreAddress,
105+
address coordinatorAddress
106+
)
107+
{
91108
require(msg.sender == address(this), "Internal function only");
92109

93110
// Step 1: Deploy SmartnodesToken first
@@ -98,10 +115,20 @@ contract SmartnodesDeployer {
98115
SmartnodesCore core = new SmartnodesCore(tokenAddress);
99116
coreAddress = address(core);
100117

101-
// Step 3: Set the core contract in token (critical for proper functioning)
118+
// Step 3: Deploy SmartnodesCoordinator with core address
119+
SmartnodesCoordinator coordinator = new SmartnodesCoordinator(
120+
uint128(3600), // Update time (1 hour)
121+
uint8(66), // Approvals percentage
122+
coreAddress,
123+
_genesisNodes
124+
);
125+
coordinatorAddress = address(coordinator);
126+
127+
// Step 4: Set the core contract in token (critical for proper functioning)
102128
token.setSmartnodesCore(coreAddress);
129+
core.setCoordinator(coordinatorAddress);
103130

104-
// Step 4: Transfer token ownership to deployer (msg.sender of original call)
131+
// Step 5: Transfer token ownership to deployer (msg.sender of original call)
105132
token.transferOwnership(tx.origin);
106133
}
107134

@@ -129,18 +156,21 @@ contract SmartnodesDeployer {
129156
*/
130157
function batchDeploy(
131158
DeploymentConfig[] memory configs
132-
) external returns (address[2][] memory deployments) {
159+
) external returns (address[3][] memory deployments) {
133160
require(configs.length > 0, "No configurations provided");
134161
require(configs.length <= 5, "Too many batch deployments");
135162

136-
deployments = new address[2][](configs.length);
163+
deployments = new address[3][](configs.length);
137164

138165
for (uint256 i = 0; i < configs.length; i++) {
139-
(address token, address core) = deploySmartnodesEcosystem(
140-
configs[i].genesisNodes
141-
);
166+
(
167+
address token,
168+
address core,
169+
address coordinator
170+
) = deploySmartnodesEcosystem(configs[i].genesisNodes);
142171
deployments[i][0] = token;
143172
deployments[i][1] = core;
173+
deployments[i][2] = coordinator;
144174
}
145175
}
146176
}

src/SmartnodesToken.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ contract SmartnodesToken is ERC20, Ownable {
103103
// Mint initial tokens to genesis nodes
104104
uint256 gensisNodesLength = _genesisNodes.length;
105105
for (uint256 i = 0; i < gensisNodesLength; i++) {
106-
_mint(_genesisNodes[i], s_validatorLockAmount);
106+
_mint(_genesisNodes[i], s_validatorLockAmount * 2);
107107
}
108108
}
109109

src/test/SmartnodesToken.t.sol

Whitespace-only changes.

test/BaseTest.sol

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.22;
3+
4+
import {Test} from "forge-std/Test.sol";
5+
import {SmartnodesToken} from "../src/SmartnodesToken.sol";
6+
import {SmartnodesCore} from "../src/SmartnodesCore.sol";
7+
import {SmartnodesDeployer} from "../src/SmartnodesDeployer.sol";
8+
import {SmartnodesCoordinator} from "../src/SmartnodesCoordinator.sol";
9+
10+
/**
11+
* @title BaseSmartnodesTest
12+
* @notice Base test contract with common setup for all Smartnodes tests
13+
*/
14+
abstract contract BaseSmartnodesTest is Test {
15+
// Contract instances
16+
SmartnodesToken public token;
17+
SmartnodesCore public core;
18+
SmartnodesCoordinator public coordinator;
19+
SmartnodesDeployer public deployer;
20+
21+
// Test addresses
22+
address public deployerAddr = makeAddr("deployer");
23+
address public user1 = makeAddr("user1");
24+
address public user2 = makeAddr("user2");
25+
address public user3 = makeAddr("user3");
26+
address public validator1 = makeAddr("validator1");
27+
address public validator2 = makeAddr("validator2");
28+
address public validator3 = makeAddr("validator3");
29+
address public worker1 = makeAddr("worker1");
30+
address public worker2 = makeAddr("worker2");
31+
address public worker3 = makeAddr("worker3");
32+
address[] public genesisNodes;
33+
34+
// Test constants
35+
bytes32 constant USER1_PUBKEY = keccak256("user1_pubkey");
36+
bytes32 constant USER2_PUBKEY = keccak256("user2_pubkey");
37+
bytes32 constant VALIDATOR1_PUBKEY = keccak256("validator1_pubkey");
38+
bytes32 constant VALIDATOR2_PUBKEY = keccak256("validator2_pubkey");
39+
bytes32 constant JOB_ID_1 = keccak256("job1");
40+
bytes32 constant JOB_ID_2 = keccak256("job2");
41+
42+
function setUp() public virtual {
43+
_deployContracts();
44+
_setupInitialState();
45+
}
46+
47+
function _deployContracts() internal {
48+
vm.startPrank(deployerAddr);
49+
50+
// Setup genesis nodes
51+
genesisNodes.push(validator1);
52+
genesisNodes.push(validator2);
53+
genesisNodes.push(user1);
54+
genesisNodes.push(user2);
55+
56+
// Deploy ecosystem
57+
deployer = new SmartnodesDeployer();
58+
(
59+
address tokenAddress,
60+
address coreAddress,
61+
address coordinatorAddress
62+
) = deployer.deploySmartnodesEcosystem(genesisNodes);
63+
64+
// Create contract instances
65+
token = SmartnodesToken(tokenAddress);
66+
core = SmartnodesCore(coreAddress);
67+
coordinator = SmartnodesCoordinator(coordinatorAddress);
68+
69+
vm.stopPrank();
70+
}
71+
72+
function _setupInitialState() internal virtual {
73+
// createTestValidator(validator1, VALIDATOR1_PUBKEY);
74+
// createTestValidator(validator2, VALIDATOR2_PUBKEY);
75+
// vm.prank(validator2);
76+
// core.createValidator(VALIDATOR2_PUBKEY);
77+
}
78+
79+
// ============= Helper Functions =============
80+
81+
function addTestNetwork(
82+
string memory networkName
83+
) internal returns (uint8) {
84+
vm.prank(deployerAddr);
85+
core.addNetwork(networkName);
86+
return core.networkCounter();
87+
}
88+
89+
function createTestValidator(address validator, bytes32 pubkey) internal {
90+
vm.prank(validator);
91+
core.createValidator(pubkey);
92+
}
93+
94+
function createTestUser(address user, bytes32 pubkey) internal {
95+
vm.prank(user);
96+
core.createUser(pubkey);
97+
}
98+
99+
function fundUserWithETH(address user, uint256 amount) internal {
100+
vm.deal(user, amount);
101+
}
102+
103+
function createTestJob(
104+
address user,
105+
bytes32 jobId,
106+
uint8 networkId,
107+
uint256[] memory capacities,
108+
uint256 ethPayment
109+
) internal {
110+
vm.prank(user);
111+
if (ethPayment > 0) {
112+
core.requestJob{value: ethPayment}(
113+
user == user1 ? USER1_PUBKEY : USER2_PUBKEY,
114+
jobId,
115+
networkId,
116+
capacities,
117+
0
118+
);
119+
} else {
120+
core.requestJob(
121+
user == user1 ? USER1_PUBKEY : USER2_PUBKEY,
122+
jobId,
123+
networkId,
124+
capacities,
125+
1000e18 // Default SNO payment
126+
);
127+
}
128+
}
129+
130+
function createBasicProposal(address validator) internal returns (uint256) {
131+
// Helper to create a basic proposal for testing
132+
bytes32[] memory jobHashes = new bytes32[](1);
133+
jobHashes[0] = JOB_ID_1;
134+
135+
address[] memory jobWorkers = new address[](1);
136+
jobWorkers[0] = worker1;
137+
138+
uint256[] memory jobCapacities = new uint256[](1);
139+
jobCapacities[0] = 100;
140+
141+
address[] memory validatorsToRemove = new address[](0);
142+
143+
bytes32 proposalHash = keccak256(
144+
abi.encode(
145+
validatorsToRemove,
146+
jobHashes,
147+
jobCapacities,
148+
jobWorkers,
149+
block.timestamp
150+
)
151+
);
152+
153+
vm.prank(validator);
154+
coordinator.createProposal(proposalHash);
155+
156+
(, uint128 nextProposalId) = coordinator.roundData();
157+
return nextProposalId - 1;
158+
}
159+
}

0 commit comments

Comments
 (0)