Skip to content

Commit 57364e4

Browse files
committed
Merge branch 'main' into mike/update_consts_manager
# Conflicts: # contracts/sfc/ConstantsManager.sol # contracts/sfc/NetworkInitializer.sol
2 parents 6b738b0 + 1d0a4e1 commit 57364e4

File tree

8 files changed

+67
-58
lines changed

8 files changed

+67
-58
lines changed

contracts/interfaces/ISFC.sol

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ interface ISFC {
127127

128128
function getEpochEndBlock(uint256 epoch) external view returns (uint256);
129129

130+
function epochEndTime(uint256 epoch) external view returns (uint256);
131+
130132
function rewardsStash(address delegator, uint256 validatorID) external view returns (uint256);
131133

132134
function createValidator(bytes calldata pubkey) external payable;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity 0.8.27;
3+
4+
/**
5+
* @title Stake Subscriber Interface
6+
* @notice Used to recount votes from delegators in the governance contract
7+
* @custom:security-contact [email protected]
8+
*/
9+
interface IStakeSubscriber {
10+
function announceStakeChange(address delegator, address validator) external;
11+
}

contracts/sfc/ConstantsManager.sol

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,10 @@ contract ConstantsManager is Ownable {
5252
constructor(address owner) Ownable(owner) {}
5353

5454
function updateMinSelfStake(uint256 v) external virtual onlyOwner {
55-
if (v < 100000 * 1e18) {
55+
if (v < 100000 * Decimal.unit()) {
5656
revert ValueTooSmall();
5757
}
58-
if (v > 10000000 * 1e18) {
58+
if (v > 10000000 * Decimal.unit()) {
5959
revert ValueTooLarge();
6060
}
6161
minSelfStake = v;
@@ -113,7 +113,7 @@ contract ConstantsManager is Ownable {
113113
}
114114

115115
function updateBaseRewardPerSecond(uint256 v) external virtual onlyOwner {
116-
if (v > 32 * 1e18) {
116+
if (v > 32 * Decimal.unit()) {
117117
revert ValueTooLarge();
118118
}
119119
baseRewardPerSecond = v;

contracts/sfc/NetworkInitializer.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ contract NetworkInitializer {
2525
NodeDriverAuth(_auth).initialize(_sfc, _driver, _owner);
2626

2727
ConstantsManager consts = new ConstantsManager(address(this));
28-
consts.updateMinSelfStake(500_000 * 1e18);
28+
consts.updateMinSelfStake(500_000 * Decimal.unit());
2929
consts.updateMaxDelegatedRatio(16 * Decimal.unit());
3030
consts.updateValidatorCommission((15 * Decimal.unit()) / 100);
3131
consts.updateBurntFeeShare(0);

contracts/sfc/NodeDriverAuth.sol

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ contract NodeDriverAuth is OwnableUpgradeable, UUPSUpgradeable {
5858
_transferOwnership(executable);
5959
INodeDriverExecutable(executable).execute();
6060
_transferOwnership(newOwner);
61-
//require(driver.backend() == address(this), "ownership of driver is lost");
6261
if (_getCodeHash(address(this)) != selfCodeHash) {
6362
revert SelfCodeHashMismatch();
6463
}
@@ -68,7 +67,7 @@ contract NodeDriverAuth is OwnableUpgradeable, UUPSUpgradeable {
6867
}
6968

7069
/// Execute a batch update of network configuration.
71-
/// Run given contract with a permission of the NodeDriverAuth owner.
70+
/// The executable will run with the privileges of the NodeDriverAuth owner.
7271
/// Does not allow changing NodeDriver and NodeDriverAuth code.
7372
function execute(address executable) external onlyOwner {
7473
_execute(executable, owner(), _getCodeHash(address(this)), _getCodeHash(address(driver)));
@@ -91,7 +90,7 @@ contract NodeDriverAuth is OwnableUpgradeable, UUPSUpgradeable {
9190
driver.setBalance(acc, address(acc).balance + diff);
9291
}
9392

94-
/// Upgrade code of given contract by coping it from other deployed contract.
93+
/// Upgrade code of given contract by copying it from other deployed contract.
9594
/// Avoids setting code to an external address.
9695
function upgradeCode(address acc, address from) external onlyOwner {
9796
if (!isContract(acc) || !isContract(from)) {
@@ -100,7 +99,7 @@ contract NodeDriverAuth is OwnableUpgradeable, UUPSUpgradeable {
10099
driver.copyCode(acc, from);
101100
}
102101

103-
/// Upgrade code of given contract by coping it from other deployed contract.
102+
/// Upgrade code of given contract by copying it from other deployed contract.
104103
/// Does not avoid setting code to an external address. (DANGEROUS!)
105104
function copyCode(address acc, address from) external onlyOwner {
106105
driver.copyCode(acc, from);
@@ -173,20 +172,11 @@ contract NodeDriverAuth is OwnableUpgradeable, UUPSUpgradeable {
173172
}
174173

175174
function isContract(address account) internal view returns (bool) {
176-
uint256 size;
177-
// solhint-disable-next-line no-inline-assembly
178-
assembly {
179-
size := extcodesize(account)
180-
}
181-
return size > 0;
175+
return account.code.length > 0;
182176
}
183177

184178
function _getCodeHash(address addr) internal view returns (bytes32) {
185-
bytes32 codeHash;
186-
assembly {
187-
codeHash := extcodehash(addr)
188-
}
189-
return codeHash;
179+
return addr.codehash;
190180
}
191181

192182
uint256[50] private __gap;

contracts/sfc/SFC.sol

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {Decimal} from "../common/Decimal.sol";
77
import {NodeDriverAuth} from "./NodeDriverAuth.sol";
88
import {ConstantsManager} from "./ConstantsManager.sol";
99
import {Version} from "../version/Version.sol";
10+
import {IStakeSubscriber} from "../interfaces/IStakeSubscriber.sol";
1011

1112
/**
1213
* @title Special Fee Contract for Sonic network
@@ -84,17 +85,17 @@ contract SFC is OwnableUpgradeable, UUPSUpgradeable, Version {
8485

8586
struct EpochSnapshot {
8687
// validator ID => validator weight in the epoch
87-
mapping(uint256 => uint256) receivedStake;
88+
mapping(uint256 validatorID => uint256) receivedStake;
8889
// validator ID => accumulated ( delegatorsReward * 1e18 / receivedStake )
89-
mapping(uint256 => uint256) accumulatedRewardPerToken;
90+
mapping(uint256 validatorID => uint256) accumulatedRewardPerToken;
9091
// validator ID => accumulated online time
91-
mapping(uint256 => uint256) accumulatedUptime;
92+
mapping(uint256 validatorID => uint256) accumulatedUptime;
9293
// validator ID => average uptime as a percentage
93-
mapping(uint256 => AverageUptime) averageUptime;
94+
mapping(uint256 validatorID => AverageUptime) averageUptime;
9495
// validator ID => gas fees from txs originated by the validator
95-
mapping(uint256 => uint256) accumulatedOriginatedTxsFee;
96-
mapping(uint256 => uint256) offlineTime;
97-
mapping(uint256 => uint256) offlineBlocks;
96+
mapping(uint256 validatorID => uint256) accumulatedOriginatedTxsFee;
97+
mapping(uint256 validatorID => uint256) offlineTime;
98+
mapping(uint256 validatorID => uint256) offlineBlocks;
9899
uint256[] validatorIDs;
99100
uint256 endTime;
100101
uint256 endBlock;
@@ -224,7 +225,7 @@ contract SFC is OwnableUpgradeable, UUPSUpgradeable, Version {
224225
event TreasuryFeesResolved(uint256 amount);
225226

226227
modifier onlyDriver() {
227-
if (!isNode(msg.sender)) {
228+
if (!_isNode(msg.sender)) {
228229
revert NotDriverAuth();
229230
}
230231
_;
@@ -293,7 +294,7 @@ contract SFC is OwnableUpgradeable, UUPSUpgradeable, Version {
293294
}
294295

295296
/// Accept redirection proposal.
296-
/// Redirection must by accepted by the validator key holder before it start to be applied.
297+
/// Redirection must by accepted by the validator key holder before it starts to be applied.
297298
function redirect(address to) external {
298299
address from = msg.sender;
299300
if (to == address(0)) {
@@ -605,6 +606,11 @@ contract SFC is OwnableUpgradeable, UUPSUpgradeable, Version {
605606
return getEpochSnapshot[epoch].endBlock;
606607
}
607608

609+
/// Get epoch end time.
610+
function epochEndTime(uint256 epoch) public view returns (uint256) {
611+
return getEpochSnapshot[epoch].endTime;
612+
}
613+
608614
/// Check whether the given validator is slashed - the stake (or its part) cannot
609615
/// be withdrawn because of misbehavior (double-sign) of the validator.
610616
function isSlashed(uint256 validatorID) public view returns (bool) {
@@ -625,7 +631,7 @@ contract SFC is OwnableUpgradeable, UUPSUpgradeable, Version {
625631
}
626632

627633
/// Check if an address is the NodeDriverAuth contract.
628-
function isNode(address addr) internal view virtual returns (bool) {
634+
function _isNode(address addr) internal view virtual returns (bool) {
629635
return addr == address(node);
630636
}
631637

@@ -702,7 +708,7 @@ contract SFC is OwnableUpgradeable, UUPSUpgradeable, Version {
702708
}
703709

704710
/// Get slashing penalty for a stake.
705-
function getSlashingPenalty(
711+
function _getSlashingPenalty(
706712
uint256 amount,
707713
bool isCheater,
708714
uint256 refundRatio
@@ -746,7 +752,7 @@ contract SFC is OwnableUpgradeable, UUPSUpgradeable, Version {
746752

747753
uint256 amount = getWithdrawalRequest[delegator][toValidatorID][wrID].amount;
748754
bool isCheater = isSlashed(toValidatorID);
749-
uint256 penalty = getSlashingPenalty(amount, isCheater, slashingRefundRatio[toValidatorID]);
755+
uint256 penalty = _getSlashingPenalty(amount, isCheater, slashingRefundRatio[toValidatorID]);
750756
delete getWithdrawalRequest[delegator][toValidatorID][wrID];
751757

752758
if (amount <= penalty) {
@@ -834,11 +840,6 @@ contract SFC is OwnableUpgradeable, UUPSUpgradeable, Version {
834840
}
835841
}
836842

837-
/// Get epoch end time.
838-
function epochEndTime(uint256 epoch) internal view returns (uint256) {
839-
return getEpochSnapshot[epoch].endTime;
840-
}
841-
842843
/// Check if an address is redirected.
843844
function _redirected(address addr) internal view returns (bool) {
844845
return getRedirection[addr] != address(0);
@@ -1022,6 +1023,7 @@ contract SFC is OwnableUpgradeable, UUPSUpgradeable, Version {
10221023

10231024
if (cur.averageUptime > Decimal.unit()) {
10241025
cur.averageUptime = uint64(Decimal.unit());
1026+
cur.remainder = 0; // reset the remainder when capping the averageUptime
10251027
}
10261028
if (prev.epochs < c.averageUptimeEpochWindow()) {
10271029
cur.epochs = prev.epochs + 1;
@@ -1105,14 +1107,30 @@ contract SFC is OwnableUpgradeable, UUPSUpgradeable, Version {
11051107
totalSupply = totalSupply + amount;
11061108
}
11071109

1110+
/// Sync validator with node.
1111+
function _syncValidator(uint256 validatorID, bool syncPubkey) internal {
1112+
if (!_validatorExists(validatorID)) {
1113+
revert ValidatorNotExists();
1114+
}
1115+
// emit special log for node
1116+
uint256 weight = getValidator[validatorID].receivedStake;
1117+
if (getValidator[validatorID].status != OK_STATUS) {
1118+
weight = 0;
1119+
}
1120+
node.updateValidatorWeight(validatorID, weight);
1121+
if (syncPubkey && weight != 0) {
1122+
node.updateValidatorPubkey(validatorID, getValidatorPubkey[validatorID]);
1123+
}
1124+
}
1125+
11081126
/// Notify stake subscriber about staking changes.
11091127
/// Used to recount votes from delegators in the governance contract.
11101128
function _notifyStakeSubscriber(address delegator, address validatorAuth, bool strict) internal {
11111129
if (stakeSubscriberAddress != address(0)) {
11121130
// Don't allow announceStakeChange to use up all the gas
11131131
// solhint-disable-next-line avoid-low-level-calls
11141132
(bool success, ) = stakeSubscriberAddress.call{gas: 8000000}(
1115-
abi.encodeWithSignature("announceStakeChange(address,address)", delegator, validatorAuth)
1133+
abi.encodeCall(IStakeSubscriber.announceStakeChange, (delegator, validatorAuth))
11161134
);
11171135
// Don't revert if announceStakeChange failed unless strict mode enabled
11181136
if (!success && strict) {
@@ -1142,22 +1160,6 @@ contract SFC is OwnableUpgradeable, UUPSUpgradeable, Version {
11421160
}
11431161
}
11441162

1145-
/// Sync validator with node.
1146-
function _syncValidator(uint256 validatorID, bool syncPubkey) public {
1147-
if (!_validatorExists(validatorID)) {
1148-
revert ValidatorNotExists();
1149-
}
1150-
// emit special log for node
1151-
uint256 weight = getValidator[validatorID].receivedStake;
1152-
if (getValidator[validatorID].status != OK_STATUS) {
1153-
weight = 0;
1154-
}
1155-
node.updateValidatorWeight(validatorID, weight);
1156-
if (syncPubkey && weight != 0) {
1157-
node.updateValidatorPubkey(validatorID, getValidatorPubkey[validatorID]);
1158-
}
1159-
}
1160-
11611163
/// Check if a validator exists.
11621164
function _validatorExists(uint256 validatorID) internal view returns (bool) {
11631165
return getValidator[validatorID].createdTime != 0;

contracts/test/UnitTestSFC.sol

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,15 @@ contract UnitTestSFC is SFC {
4040
return time;
4141
}
4242

43-
function isNode(address addr) internal view override returns (bool) {
43+
function _isNode(address addr) internal view override returns (bool) {
4444
if (allowedNonNodeCalls) {
4545
return true;
4646
}
47-
return SFC.isNode(addr);
47+
return SFC._isNode(addr);
48+
}
49+
50+
function syncValidator(uint256 validatorID, bool syncPubkey) public {
51+
_syncValidator(validatorID, syncPubkey);
4852
}
4953
}
5054

@@ -62,7 +66,7 @@ contract UnitTestNetworkInitializer {
6266
NodeDriverAuth(_auth).initialize(_sfc, _driver, _owner);
6367

6468
UnitTestConstantsManager consts = new UnitTestConstantsManager(address(this));
65-
consts.updateMinSelfStake(0.3175000 * 1e18);
69+
consts.updateMinSelfStake((3175 * Decimal.unit()) / 10000);
6670
consts.updateMaxDelegatedRatio(16 * Decimal.unit());
6771
consts.updateValidatorCommission((15 * Decimal.unit()) / 100);
6872
consts.updateBurntFeeShare((20 * Decimal.unit()) / 100);

test/SFC.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ describe('SFC', () => {
9393
});
9494

9595
it('Should succeed and set genesis validator with bad status', async function () {
96-
await this.sfc._syncValidator(1, false);
96+
await this.sfc.syncValidator(1, false);
9797
});
9898

9999
it('Should revert when sealEpoch not called by node', async function () {
@@ -1056,7 +1056,7 @@ describe('SFC', () => {
10561056
});
10571057

10581058
it('Should revert when syncing if validator does not exist', async function () {
1059-
await expect(this.sfc._syncValidator(33, false)).to.be.revertedWithCustomError(this.sfc, 'ValidatorNotExists');
1059+
await expect(this.sfc.syncValidator(33, false)).to.be.revertedWithCustomError(this.sfc, 'ValidatorNotExists');
10601060
});
10611061
});
10621062

0 commit comments

Comments
 (0)