Overview
S Balance
0 S
S Value
-More Info
Private Name Tags
ContractCreator
GENESIS at txn GENESIS_d1005eed00000000000000000000000000000000
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Initialize All | 1 | 18 days ago | IN | 0 S | 0 |
Latest 1 internal transaction
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
1 | 18 days ago | Contract Creation | 0 S |
Loading...
Loading
Contract Source Code Verified (Genesis Bytecode Match Only)
Contract Name:
NetworkInitializer
Compiler Version
v0.8.27+commit.40a35a09
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.27; import {ISFC} from "../interfaces/ISFC.sol"; import {NodeDriver} from "./NodeDriver.sol"; import {NodeDriverAuth} from "./NodeDriverAuth.sol"; import {ConstantsManager} from "./ConstantsManager.sol"; import {Decimal} from "../common/Decimal.sol"; /** * @custom:security-contact [email protected] */ contract NetworkInitializer { // Initialize NodeDriverAuth, NodeDriver and SFC in one call to allow fewer genesis transactions function initializeAll( uint256 sealedEpoch, uint256 totalSupply, address payable _sfc, address _auth, address _driver, address _evmWriter, address _owner ) external { NodeDriver(_driver).initialize(_auth, _evmWriter, _owner); NodeDriverAuth(_auth).initialize(_sfc, _driver, _owner); ConstantsManager consts = new ConstantsManager(address(this)); consts.updateMinSelfStake(500_000 * 1e18); consts.updateMaxDelegatedRatio(16 * Decimal.unit()); consts.updateValidatorCommission((15 * Decimal.unit()) / 100); consts.updateBurntFeeShare(0); consts.updateTreasuryFeeShare((90 * Decimal.unit()) / 100); consts.updateWithdrawalPeriodEpochs(3); consts.updateWithdrawalPeriodTime(60 * 60 * 24 * 7); consts.updateBaseRewardPerSecond(1_000); consts.updateOfflinePenaltyThresholdTime(5 days); consts.updateOfflinePenaltyThresholdBlocksNum(1_000); consts.updateTargetGasPowerPerSecond(30_000_000); consts.updateGasPriceBalancingCounterweight(3_600); consts.updateAverageUptimeEpochWindow(100); consts.updateMinAverageUptime(0); // check disabled by default consts.transferOwnership(_owner); ISFC(_sfc).initialize(sealedEpoch, totalSupply, _auth, address(consts), _owner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol"; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is set to the address provided by the deployer. This can * later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { /// @custom:storage-location erc7201:openzeppelin.storage.Ownable struct OwnableStorage { address _owner; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300; function _getOwnableStorage() private pure returns (OwnableStorage storage $) { assembly { $.slot := OwnableStorageLocation } } /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ function __Ownable_init(address initialOwner) internal onlyInitializing { __Ownable_init_unchained(initialOwner); } function __Ownable_init_unchained(address initialOwner) internal onlyInitializing { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { OwnableStorage storage $ = _getOwnableStorage(); return $._owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { OwnableStorage storage $ = _getOwnableStorage(); address oldOwner = $._owner; $._owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.20; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Storage of the initializable contract. * * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions * when using with upgradeable contracts. * * @custom:storage-location erc7201:openzeppelin.storage.Initializable */ struct InitializableStorage { /** * @dev Indicates that the contract has been initialized. */ uint64 _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool _initializing; } // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; /** * @dev The contract is already initialized. */ error InvalidInitialization(); /** * @dev The contract is not initializing. */ error NotInitializing(); /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint64 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in * production. * * Emits an {Initialized} event. */ modifier initializer() { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); // Cache values to avoid duplicated sloads bool isTopLevelCall = !$._initializing; uint64 initialized = $._initialized; // Allowed calls: // - initialSetup: the contract is not in the initializing state and no previous version was // initialized // - construction: the contract is initialized at version 1 (no reininitialization) and the // current contract is just being deployed bool initialSetup = initialized == 0 && isTopLevelCall; bool construction = initialized == 1 && address(this).code.length == 0; if (!initialSetup && !construction) { revert InvalidInitialization(); } $._initialized = 1; if (isTopLevelCall) { $._initializing = true; } _; if (isTopLevelCall) { $._initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint64 version) { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing || $._initialized >= version) { revert InvalidInitialization(); } $._initialized = version; $._initializing = true; _; $._initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { _checkInitializing(); _; } /** * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. */ function _checkInitializing() internal view virtual { if (!_isInitializing()) { revert NotInitializing(); } } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { // solhint-disable-next-line var-name-mixedcase InitializableStorage storage $ = _getInitializableStorage(); if ($._initializing) { revert InvalidInitialization(); } if ($._initialized != type(uint64).max) { $._initialized = type(uint64).max; emit Initialized(type(uint64).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint64) { return _getInitializableStorage()._initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _getInitializableStorage()._initializing; } /** * @dev Returns a pointer to the storage namespace. */ // solhint-disable-next-line var-name-mixedcase function _getInitializableStorage() private pure returns (InitializableStorage storage $) { assembly { $.slot := INITIALIZABLE_STORAGE } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (proxy/utils/UUPSUpgradeable.sol) pragma solidity ^0.8.20; import {IERC1822Proxiable} from "@openzeppelin/contracts/interfaces/draft-IERC1822.sol"; import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol"; import {Initializable} from "./Initializable.sol"; /** * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. * * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing * `UUPSUpgradeable` with a custom implementation of upgrades. * * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. */ abstract contract UUPSUpgradeable is Initializable, IERC1822Proxiable { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable address private immutable __self = address(this); /** * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)` * and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called, * while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string. * If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function * during an upgrade. */ string public constant UPGRADE_INTERFACE_VERSION = "5.0.0"; /** * @dev The call is from an unauthorized context. */ error UUPSUnauthorizedCallContext(); /** * @dev The storage `slot` is unsupported as a UUID. */ error UUPSUnsupportedProxiableUUID(bytes32 slot); /** * @dev Check that the execution is being performed through a delegatecall call and that the execution context is * a proxy contract with an implementation (as defined in ERC-1967) pointing to self. This should only be the case * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a * function through ERC-1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to * fail. */ modifier onlyProxy() { _checkProxy(); _; } /** * @dev Check that the execution is not being performed through a delegate call. This allows a function to be * callable on the implementing contract but not through proxies. */ modifier notDelegated() { _checkNotDelegated(); _; } function __UUPSUpgradeable_init() internal onlyInitializing { } function __UUPSUpgradeable_init_unchained() internal onlyInitializing { } /** * @dev Implementation of the ERC-1822 {proxiableUUID} function. This returns the storage slot used by the * implementation. It is used to validate the implementation's compatibility when performing an upgrade. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. */ function proxiableUUID() external view virtual notDelegated returns (bytes32) { return ERC1967Utils.IMPLEMENTATION_SLOT; } /** * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call * encoded in `data`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. * * @custom:oz-upgrades-unsafe-allow-reachable delegatecall */ function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, data); } /** * @dev Reverts if the execution is not performed via delegatecall or the execution * context is not of a proxy with an ERC-1967 compliant implementation pointing to self. * See {_onlyProxy}. */ function _checkProxy() internal view virtual { if ( address(this) == __self || // Must be called through delegatecall ERC1967Utils.getImplementation() != __self // Must be called through an active proxy ) { revert UUPSUnauthorizedCallContext(); } } /** * @dev Reverts if the execution is performed via delegatecall. * See {notDelegated}. */ function _checkNotDelegated() internal view virtual { if (address(this) != __self) { // Must not be called through delegatecall revert UUPSUnauthorizedCallContext(); } } /** * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by * {upgradeToAndCall}. * * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. * * ```solidity * function _authorizeUpgrade(address) internal onlyOwner {} * ``` */ function _authorizeUpgrade(address newImplementation) internal virtual; /** * @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call. * * As a security check, {proxiableUUID} is invoked in the new implementation, and the return value * is expected to be the implementation slot in ERC-1967. * * Emits an {IERC1967-Upgraded} event. */ function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private { try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) { revert UUPSUnsupportedProxiableUUID(slot); } ERC1967Utils.upgradeToAndCall(newImplementation, data); } catch { // The implementation is not UUPS revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; import {Initializable} from "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {Context} from "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is set to the address provided by the deployer. This can * later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ constructor(address initialOwner) { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.20; /** * @dev ERC-1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822Proxiable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1967.sol) pragma solidity ^0.8.20; /** * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC. */ interface IERC1967 { /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Emitted when the beacon is changed. */ event BeaconUpgraded(address indexed beacon); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.20; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeacon { /** * @dev Must return an address that can be used as a delegate call target. * * {UpgradeableBeacon} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (proxy/ERC1967/ERC1967Utils.sol) pragma solidity ^0.8.21; import {IBeacon} from "../beacon/IBeacon.sol"; import {IERC1967} from "../../interfaces/IERC1967.sol"; import {Address} from "../../utils/Address.sol"; import {StorageSlot} from "../../utils/StorageSlot.sol"; /** * @dev This library provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[ERC-1967] slots. */ library ERC1967Utils { /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev The `implementation` of the proxy is invalid. */ error ERC1967InvalidImplementation(address implementation); /** * @dev The `admin` of the proxy is invalid. */ error ERC1967InvalidAdmin(address admin); /** * @dev The `beacon` of the proxy is invalid. */ error ERC1967InvalidBeacon(address beacon); /** * @dev An upgrade function sees `msg.value > 0` that may be lost. */ error ERC1967NonPayable(); /** * @dev Returns the current implementation address. */ function getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the ERC-1967 implementation slot. */ function _setImplementation(address newImplementation) private { if (newImplementation.code.length == 0) { revert ERC1967InvalidImplementation(newImplementation); } StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Performs implementation upgrade with additional setup call if data is nonempty. * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected * to avoid stuck value in the contract. * * Emits an {IERC1967-Upgraded} event. */ function upgradeToAndCall(address newImplementation, bytes memory data) internal { _setImplementation(newImplementation); emit IERC1967.Upgraded(newImplementation); if (data.length > 0) { Address.functionDelegateCall(newImplementation, data); } else { _checkNonPayable(); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Returns the current admin. * * TIP: To get this value clients can read directly from the storage slot shown below (specified by ERC-1967) using * the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call. * `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103` */ function getAdmin() internal view returns (address) { return StorageSlot.getAddressSlot(ADMIN_SLOT).value; } /** * @dev Stores a new address in the ERC-1967 admin slot. */ function _setAdmin(address newAdmin) private { if (newAdmin == address(0)) { revert ERC1967InvalidAdmin(address(0)); } StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {IERC1967-AdminChanged} event. */ function changeAdmin(address newAdmin) internal { emit IERC1967.AdminChanged(getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1. */ // solhint-disable-next-line private-vars-leading-underscore bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Returns the current beacon. */ function getBeacon() internal view returns (address) { return StorageSlot.getAddressSlot(BEACON_SLOT).value; } /** * @dev Stores a new beacon in the ERC-1967 beacon slot. */ function _setBeacon(address newBeacon) private { if (newBeacon.code.length == 0) { revert ERC1967InvalidBeacon(newBeacon); } StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon; address beaconImplementation = IBeacon(newBeacon).implementation(); if (beaconImplementation.code.length == 0) { revert ERC1967InvalidImplementation(beaconImplementation); } } /** * @dev Change the beacon and trigger a setup call if data is nonempty. * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected * to avoid stuck value in the contract. * * Emits an {IERC1967-BeaconUpgraded} event. * * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for * efficiency. */ function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal { _setBeacon(newBeacon); emit IERC1967.BeaconUpgraded(newBeacon); if (data.length > 0) { Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); } else { _checkNonPayable(); } } /** * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract * if an upgrade doesn't perform an initialization call. */ function _checkNonPayable() private { if (msg.value > 0) { revert ERC1967NonPayable(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/Address.sol) pragma solidity ^0.8.20; import {Errors} from "./Errors.sol"; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert Errors.InsufficientBalance(address(this).balance, amount); } (bool success, ) = recipient.call{value: amount}(""); if (!success) { revert Errors.FailedCall(); } } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {Errors.FailedCall} error. * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { if (address(this).balance < value) { revert Errors.InsufficientBalance(address(this).balance, value); } (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case * of an unsuccessful call. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { if (!success) { _revert(returndata); } else { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (returndata.length == 0 && target.code.length == 0) { revert AddressEmptyCode(target); } return returndata; } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {Errors.FailedCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (!success) { _revert(returndata); } else { return returndata; } } /** * @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}. */ function _revert(bytes memory returndata) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly ("memory-safe") { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert Errors.FailedCall(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol) pragma solidity ^0.8.20; /** * @dev Collection of common custom errors used in multiple contracts * * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library. * It is recommended to avoid relying on the error API for critical functionality. * * _Available since v5.1._ */ library Errors { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error InsufficientBalance(uint256 balance, uint256 needed); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedCall(); /** * @dev The deployment failed. */ error FailedDeployment(); /** * @dev A necessary precompile is missing. */ error MissingPrecompile(address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.20; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC-1967 implementation slot: * ```solidity * contract ERC1967 { * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot. * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(newImplementation.code.length > 0); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * TIP: Consider using this library along with {SlotDerivation}. */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct Int256Slot { int256 value; } struct StringSlot { string value; } struct BytesSlot { bytes value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `Int256Slot` with member `value` located at `slot`. */ function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns a `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns an `StringSlot` representation of the string storage pointer `store`. */ function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { assembly ("memory-safe") { r.slot := store.slot } } /** * @dev Returns a `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { assembly ("memory-safe") { r.slot := slot } } /** * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. */ function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { assembly ("memory-safe") { r.slot := store.slot } } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.27; /** * @custom:security-contact [email protected] */ library Decimal { // unit is used for decimals, e.g. 0.123456 function unit() internal pure returns (uint256) { return 1e18; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.27; /** * @title EVM Writer Interface * @notice Allows the NodeDriver contract to write into the state database. * @dev Implemented in the native code of the Sonic client. * @custom:security-contact [email protected] */ interface IEVMWriter { function setBalance(address acc, uint256 value) external; function copyCode(address acc, address from) external; function swapCode(address acc, address where) external; function setStorage(address acc, bytes32 key, bytes32 value) external; function incNonce(address acc, uint256 diff) external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.27; /** * @title Node Driver Contract Interface * @notice Ensures interaction of on-chain contracts with the Sonic client itself. * @dev Methods with onlyNode modifier are called by Sonic internal txs during epoch sealing. * @custom:security-contact [email protected] */ interface INodeDriver { /// Set an initial validator. Called only as part of network initialization/genesis file generating. function setGenesisValidator( address auth, uint256 validatorID, bytes calldata pubkey, uint256 createdTime ) external; /// Set an initial delegation. Called only as part of network initialization/genesis file generating. function setGenesisDelegation(address delegator, uint256 toValidatorID, uint256 stake) external; /// Deactivate a validator. Called by network node when a double-sign of the given validator is registered. /// Is called before sealEpoch() call. function deactivateValidator(uint256 validatorID, uint256 status) external; /// Seal epoch. Called BEFORE epoch sealing made by the client itself. function sealEpoch( uint256[] calldata offlineTimes, uint256[] calldata offlineBlocks, uint256[] calldata uptimes, uint256[] calldata originatedTxsFee ) external; /// Seal epoch. Called AFTER epoch sealing made by the client itself. function sealEpochValidators(uint256[] calldata nextValidatorIDs) external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.27; /** * @title Node Driver Executable * @notice A batch of operations to be executed with NodeDriver permissions. * @notice Contracts implementing this interface should be executed using NodeDriverAuth.execute() or mutExecute(). * @custom:security-contact [email protected] */ interface INodeDriverExecutable { function execute() external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.27; /** * @title Special Fee Contract for Sonic network * @notice The SFC maintains a list of validators and delegators and distributes rewards to them. * @custom:security-contact [email protected] */ interface ISFC { event CreatedValidator( uint256 indexed validatorID, address indexed auth, uint256 createdEpoch, uint256 createdTime ); event Delegated(address indexed delegator, uint256 indexed toValidatorID, uint256 amount); event Undelegated(address indexed delegator, uint256 indexed toValidatorID, uint256 indexed wrID, uint256 amount); event Withdrawn( address indexed delegator, uint256 indexed toValidatorID, uint256 indexed wrID, uint256 amount, uint256 penalty ); event ClaimedRewards(address indexed delegator, uint256 indexed toValidatorID, uint256 rewards); event RestakedRewards(address indexed delegator, uint256 indexed toValidatorID, uint256 rewards); event BurntFTM(uint256 amount); event UpdatedSlashingRefundRatio(uint256 indexed validatorID, uint256 refundRatio); event RefundedSlashedLegacyDelegation(address indexed delegator, uint256 indexed validatorID, uint256 amount); event DeactivatedValidator(uint256 indexed validatorID, uint256 deactivatedEpoch, uint256 deactivatedTime); event ChangedValidatorStatus(uint256 indexed validatorID, uint256 status); event AnnouncedRedirection(address indexed from, address indexed to); function currentSealedEpoch() external view returns (uint256); function getEpochSnapshot( uint256 ) external view returns ( uint256 endTime, uint256 endBlock, uint256 epochFee, uint256 baseRewardPerSecond, uint256 totalStake, uint256 totalSupply ); function getStake(address, uint256) external view returns (uint256); function getValidator( uint256 ) external view returns ( uint256 status, uint256 receivedStake, address auth, uint256 createdEpoch, uint256 createdTime, uint256 deactivatedTime, uint256 deactivatedEpoch ); function getValidatorID(address) external view returns (uint256); function getValidatorPubkey(uint256) external view returns (bytes memory); function pubkeyAddressToValidatorID(address pubkeyAddress) external view returns (uint256); function getWithdrawalRequest( address, uint256, uint256 ) external view returns (uint256 epoch, uint256 time, uint256 amount); function isOwner() external view returns (bool); function lastValidatorID() external view returns (uint256); function minGasPrice() external view returns (uint256); function owner() external view returns (address); function renounceOwnership() external; function slashingRefundRatio(uint256) external view returns (uint256); function stashedRewardsUntilEpoch(address, uint256) external view returns (uint256); function totalActiveStake() external view returns (uint256); function totalStake() external view returns (uint256); function totalSupply() external view returns (uint256); function transferOwnership(address newOwner) external; function treasuryAddress() external view returns (address); function version() external pure returns (bytes3); function currentEpoch() external view returns (uint256); function updateConstsAddress(address v) external; function constsAddress() external view returns (address); function getEpochValidatorIDs(uint256 epoch) external view returns (uint256[] memory); function getEpochReceivedStake(uint256 epoch, uint256 validatorID) external view returns (uint256); function getEpochAccumulatedRewardPerToken(uint256 epoch, uint256 validatorID) external view returns (uint256); function getEpochAccumulatedUptime(uint256 epoch, uint256 validatorID) external view returns (uint256); function getEpochAverageUptime(uint256 epoch, uint256 validatorID) external view returns (uint32); function getEpochAccumulatedOriginatedTxsFee(uint256 epoch, uint256 validatorID) external view returns (uint256); function getEpochOfflineTime(uint256 epoch, uint256 validatorID) external view returns (uint256); function getEpochOfflineBlocks(uint256 epoch, uint256 validatorID) external view returns (uint256); function getEpochEndBlock(uint256 epoch) external view returns (uint256); function rewardsStash(address delegator, uint256 validatorID) external view returns (uint256); function createValidator(bytes calldata pubkey) external payable; function getSelfStake(uint256 validatorID) external view returns (uint256); function delegate(uint256 toValidatorID) external payable; function undelegate(uint256 toValidatorID, uint256 wrID, uint256 amount) external; function isSlashed(uint256 validatorID) external view returns (bool); function withdraw(uint256 toValidatorID, uint256 wrID) external; function deactivateValidator(uint256 validatorID, uint256 status) external; function pendingRewards(address delegator, uint256 toValidatorID) external view returns (uint256); function stashRewards(address delegator, uint256 toValidatorID) external; function claimRewards(uint256 toValidatorID) external; function restakeRewards(uint256 toValidatorID) external; function updateSlashingRefundRatio(uint256 validatorID, uint256 refundRatio) external; function updateTreasuryAddress(address v) external; function burnFTM(uint256 amount) external; function sealEpoch( uint256[] calldata offlineTime, uint256[] calldata offlineBlocks, uint256[] calldata uptimes, uint256[] calldata originatedTxsFee ) external; function sealEpochValidators(uint256[] calldata nextValidatorIDs) external; function initialize( uint256 sealedEpoch, uint256 _totalSupply, address nodeDriver, address consts, address _owner ) external; function setGenesisValidator( address auth, uint256 validatorID, bytes calldata pubkey, uint256 createdTime ) external; function setGenesisDelegation(address delegator, uint256 toValidatorID, uint256 stake) external; function updateStakeSubscriberAddress(address v) external; function stakeSubscriberAddress() external view returns (address); function setRedirectionAuthorizer(address v) external; function announceRedirection(address to) external; function initiateRedirection(address from, address to) external; function redirect(address to) external; }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.27; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {Decimal} from "../common/Decimal.sol"; /** * @custom:security-contact [email protected] */ contract ConstantsManager is Ownable { // Minimum amount of stake for a validator, i.e., 500000 FTM uint256 public minSelfStake; // Maximum ratio of delegations a validator can have, say, 15 times of self-stake uint256 public maxDelegatedRatio; // The commission fee in percentage a validator will get from a delegation, e.g., 15% uint256 public validatorCommission; // The percentage of fees to burn, e.g., 20% uint256 public burntFeeShare; // The percentage of fees to transfer to treasury address, e.g., 10% uint256 public treasuryFeeShare; // the number of epochs that undelegated stake is locked for uint256 public withdrawalPeriodEpochs; // the number of seconds that undelegated stake is locked for uint256 public withdrawalPeriodTime; uint256 public baseRewardPerSecond; uint256 public offlinePenaltyThresholdBlocksNum; uint256 public offlinePenaltyThresholdTime; uint256 public targetGasPowerPerSecond; uint256 public gasPriceBalancingCounterweight; // The number of epochs to calculate the average uptime ratio from, acceptable bound [10, 87600]. // Is also the minimum number of epochs necessary for deactivation of offline validators. uint32 public averageUptimeEpochWindow; // Minimum average uptime ratio in fixed-point format; acceptable bounds [0,0.9]. // Zero to disable validators deactivation by this metric. uint64 public minAverageUptime; // The address of the recipient that receives issued tokens // as a counterparty to the burnt FTM tokens address public issuedTokensRecipient; /** * @dev Given value is too small */ error ValueTooSmall(); /** * @dev Given value is too large */ error ValueTooLarge(); constructor(address owner) Ownable(owner) {} function updateMinSelfStake(uint256 v) external virtual onlyOwner { if (v < 100000 * 1e18) { revert ValueTooSmall(); } if (v > 10000000 * 1e18) { revert ValueTooLarge(); } minSelfStake = v; } function updateMaxDelegatedRatio(uint256 v) external virtual onlyOwner { if (v < Decimal.unit()) { revert ValueTooSmall(); } if (v > 31 * Decimal.unit()) { revert ValueTooLarge(); } maxDelegatedRatio = v; } function updateValidatorCommission(uint256 v) external virtual onlyOwner { if (v > Decimal.unit() / 2) { revert ValueTooLarge(); } validatorCommission = v; } function updateBurntFeeShare(uint256 v) external virtual onlyOwner { if (v > Decimal.unit() / 2) { revert ValueTooLarge(); } burntFeeShare = v; } function updateTreasuryFeeShare(uint256 v) external virtual onlyOwner { if (v > Decimal.unit()) { revert ValueTooLarge(); } treasuryFeeShare = v; } function updateWithdrawalPeriodEpochs(uint256 v) external virtual onlyOwner { if (v < 2) { revert ValueTooSmall(); } if (v > 100) { revert ValueTooLarge(); } withdrawalPeriodEpochs = v; } function updateWithdrawalPeriodTime(uint256 v) external virtual onlyOwner { if (v < 86400) { revert ValueTooSmall(); } if (v > 30 * 86400) { revert ValueTooLarge(); } withdrawalPeriodTime = v; } function updateBaseRewardPerSecond(uint256 v) external virtual onlyOwner { if (v > 32 * 1e18) { revert ValueTooLarge(); } baseRewardPerSecond = v; } function updateOfflinePenaltyThresholdTime(uint256 v) external virtual onlyOwner { if (v < 86400) { revert ValueTooSmall(); } if (v > 10 * 86400) { revert ValueTooLarge(); } offlinePenaltyThresholdTime = v; } function updateOfflinePenaltyThresholdBlocksNum(uint256 v) external virtual onlyOwner { if (v < 100) { revert ValueTooSmall(); } if (v > 1000000) { revert ValueTooLarge(); } offlinePenaltyThresholdBlocksNum = v; } function updateTargetGasPowerPerSecond(uint256 v) external virtual onlyOwner { if (v < 1000000) { revert ValueTooSmall(); } if (v > 500000000) { revert ValueTooLarge(); } targetGasPowerPerSecond = v; } function updateGasPriceBalancingCounterweight(uint256 v) external virtual onlyOwner { if (v < 100) { revert ValueTooSmall(); } if (v > 10 * 86400) { revert ValueTooLarge(); } gasPriceBalancingCounterweight = v; } function updateAverageUptimeEpochWindow(uint32 v) external virtual onlyOwner { if (v < 10) { // needs to be long enough to allow permissible downtime for validators maintenance revert ValueTooSmall(); } if (v > 87600) { revert ValueTooLarge(); } averageUptimeEpochWindow = v; } function updateMinAverageUptime(uint64 v) external virtual onlyOwner { if (v > ((Decimal.unit() * 9) / 10)) { revert ValueTooLarge(); } minAverageUptime = v; } function updateIssuedTokensRecipient(address v) external virtual onlyOwner { issuedTokensRecipient = v; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.27; import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import {NodeDriverAuth} from "./NodeDriverAuth.sol"; import {IEVMWriter} from "../interfaces/IEVMWriter.sol"; import {INodeDriver} from "../interfaces/INodeDriver.sol"; /** * @title Node Driver Contract * @notice Ensures interaction of on-chain contracts with the Sonic client itself. * @dev Methods with onlyNode modifier are called by Sonic internal txs during epoch sealing. * @custom:security-contact [email protected] */ contract NodeDriver is OwnableUpgradeable, UUPSUpgradeable, INodeDriver { NodeDriverAuth internal backend; IEVMWriter internal evmWriter; error NotNode(); error NotBackend(); /// Callable only by NodeDriverAuth (which mediates calls from SFC and from admins) modifier onlyBackend() { if (msg.sender != address(backend)) { revert NotBackend(); } _; } event UpdateValidatorWeight(uint256 indexed validatorID, uint256 weight); event UpdateValidatorPubkey(uint256 indexed validatorID, bytes pubkey); event UpdateNetworkRules(bytes diff); event UpdateNetworkVersion(uint256 version); event AdvanceEpochs(uint256 num); /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } /// Initialization is called only once, after the contract deployment. /// Because the contract code is written directly into genesis, constructor cannot be used. function initialize(address _backend, address _evmWriterAddress, address _owner) external initializer { __Ownable_init(_owner); __UUPSUpgradeable_init(); backend = NodeDriverAuth(_backend); evmWriter = IEVMWriter(_evmWriterAddress); } /// Override the upgrade authorization check to allow upgrades only from the owner. // solhint-disable-next-line no-empty-blocks function _authorizeUpgrade(address) internal override onlyOwner {} function setBalance(address acc, uint256 value) external onlyBackend { evmWriter.setBalance(acc, value); } function copyCode(address acc, address from) external onlyBackend { evmWriter.copyCode(acc, from); } function swapCode(address acc, address where) external onlyBackend { evmWriter.swapCode(acc, where); } function setStorage(address acc, bytes32 key, bytes32 value) external onlyBackend { evmWriter.setStorage(acc, key, value); } function incNonce(address acc, uint256 diff) external onlyBackend { evmWriter.incNonce(acc, diff); } /// Update network rules configuring the chain. /// Emitted event is being observed by Sonic client. function updateNetworkRules(bytes calldata diff) external onlyBackend { emit UpdateNetworkRules(diff); } /// Update advertised version of the network. /// Emitted event is being observed by Sonic client. function updateNetworkVersion(uint256 version) external onlyBackend { emit UpdateNetworkVersion(version); } /// Enforce sealing given number of epochs. /// Emitted event is being observed by Sonic client. function advanceEpochs(uint256 num) external onlyBackend { emit AdvanceEpochs(num); } /// Update weight of a validator. Used to propagate a stake change from SFC to the client. /// Emitted event is being observed by Sonic client. function updateValidatorWeight(uint256 validatorID, uint256 value) external onlyBackend { emit UpdateValidatorWeight(validatorID, value); } /// Update public key of a validator. Used to propagate a change from SFC to the client. /// Emitted event is being observed by Sonic client. function updateValidatorPubkey(uint256 validatorID, bytes calldata pubkey) external onlyBackend { emit UpdateValidatorPubkey(validatorID, pubkey); } /// Callable only from Sonic client itself as an internal tx. /// Used for propagating network event (validator doublesign, epoch sealing) from node to SFC. modifier onlyNode() { if (msg.sender != address(0)) { revert NotNode(); } _; } // Methods which are called only by the node /// Set an initial validator. Called only as part of network initialization/genesis file generating. function setGenesisValidator( address auth, uint256 validatorID, bytes calldata pubkey, uint256 createdTime ) external onlyNode { backend.setGenesisValidator(auth, validatorID, pubkey, createdTime); } /// Set an initial delegation. Called only as part of network initialization/genesis file generating. function setGenesisDelegation(address delegator, uint256 toValidatorID, uint256 stake) external onlyNode { backend.setGenesisDelegation(delegator, toValidatorID, stake); } /// Deactivate a validator. Called by network node when a double-sign of the given validator is registered. /// Is called before sealEpoch() call. function deactivateValidator(uint256 validatorID, uint256 status) external onlyNode { backend.deactivateValidator(validatorID, status); } /// Seal epoch. Called BEFORE epoch sealing made by the client itself. function sealEpoch( uint256[] calldata offlineTimes, uint256[] calldata offlineBlocks, uint256[] calldata uptimes, uint256[] calldata originatedTxsFee ) external onlyNode { backend.sealEpoch(offlineTimes, offlineBlocks, uptimes, originatedTxsFee); } /// Seal epoch. Called AFTER epoch sealing made by the client itself. function sealEpochValidators(uint256[] calldata nextValidatorIDs) external onlyNode { backend.sealEpochValidators(nextValidatorIDs); } uint256[50] private __gap; }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.27; import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import {ISFC} from "../interfaces/ISFC.sol"; import {NodeDriver} from "./NodeDriver.sol"; import {INodeDriverExecutable} from "../interfaces/INodeDriverExecutable.sol"; /** * @custom:security-contact [email protected] */ contract NodeDriverAuth is OwnableUpgradeable, UUPSUpgradeable { ISFC internal sfc; NodeDriver internal driver; error NotSFC(); error NotDriver(); error NotContract(); error SelfCodeHashMismatch(); error DriverCodeHashMismatch(); error RecipientNotSFC(); /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } // Initialize NodeDriverAuth, NodeDriver and SFC in one call to allow fewer genesis transactions function initialize(address payable _sfc, address _driver, address _owner) external initializer { __Ownable_init(_owner); __UUPSUpgradeable_init(); driver = NodeDriver(_driver); sfc = ISFC(_sfc); } /// Override the upgrade authorization check to allow upgrades only from the owner. // solhint-disable-next-line no-empty-blocks function _authorizeUpgrade(address) internal override onlyOwner {} /// Callable only by SFC contract. modifier onlySFC() { if (msg.sender != address(sfc)) { revert NotSFC(); } _; } /// Callable only by NodeDriver (mediates messages from the network client) modifier onlyDriver() { if (msg.sender != address(driver)) { revert NotDriver(); } _; } function _execute(address executable, address newOwner, bytes32 selfCodeHash, bytes32 driverCodeHash) internal { _transferOwnership(executable); INodeDriverExecutable(executable).execute(); _transferOwnership(newOwner); //require(driver.backend() == address(this), "ownership of driver is lost"); if (_getCodeHash(address(this)) != selfCodeHash) { revert SelfCodeHashMismatch(); } if (_getCodeHash(address(driver)) != driverCodeHash) { revert DriverCodeHashMismatch(); } } /// Execute a batch update of network configuration. /// Run given contract with a permission of the NodeDriverAuth owner. /// Does not allow changing NodeDriver and NodeDriverAuth code. function execute(address executable) external onlyOwner { _execute(executable, owner(), _getCodeHash(address(this)), _getCodeHash(address(driver))); } /// Execute a batch update of network configuration. /// Run given contract with a permission of the NodeDriverAuth owner. /// Allows changing NodeDriver and NodeDriverAuth code. function mutExecute( address executable, address newOwner, bytes32 selfCodeHash, bytes32 driverCodeHash ) external onlyOwner { _execute(executable, newOwner, selfCodeHash, driverCodeHash); } /// Mint native token. To be used by SFC for minting validators rewards. function incBalance(address acc, uint256 diff) external onlySFC { driver.setBalance(acc, address(acc).balance + diff); } /// Upgrade code of given contract by coping it from other deployed contract. /// Avoids setting code to an external address. function upgradeCode(address acc, address from) external onlyOwner { if (!isContract(acc) || !isContract(from)) { revert NotContract(); } driver.copyCode(acc, from); } /// Upgrade code of given contract by coping it from other deployed contract. /// Does not avoid setting code to an external address. (DANGEROUS!) function copyCode(address acc, address from) external onlyOwner { driver.copyCode(acc, from); } /// Increment nonce of the given account. function incNonce(address acc, uint256 diff) external onlyOwner { driver.incNonce(acc, diff); } /// Update network rules by providing a JSON patch. function updateNetworkRules(bytes calldata diff) external onlyOwner { driver.updateNetworkRules(diff); } /// Update advertised network version. function updateNetworkVersion(uint256 version) external onlyOwner { driver.updateNetworkVersion(version); } /// Enforce sealing given number of epochs. function advanceEpochs(uint256 num) external onlyOwner { driver.advanceEpochs(num); } /// Update weight of a validator. Used to propagate a stake change from SFC to the client. function updateValidatorWeight(uint256 validatorID, uint256 value) external onlySFC { driver.updateValidatorWeight(validatorID, value); } /// Update public key of a validator. Used to propagate a change from SFC to the client. function updateValidatorPubkey(uint256 validatorID, bytes calldata pubkey) external onlySFC { driver.updateValidatorPubkey(validatorID, pubkey); } /// Set an initial validator into SFC. Called only as part of network initialization/genesis file generating. function setGenesisValidator( address auth, uint256 validatorID, bytes calldata pubkey, uint256 createdTime ) external onlyDriver { sfc.setGenesisValidator(auth, validatorID, pubkey, createdTime); } /// Set an initial delegation. Called only as part of network initialization/genesis file generating. function setGenesisDelegation(address delegator, uint256 toValidatorID, uint256 stake) external onlyDriver { sfc.setGenesisDelegation(delegator, toValidatorID, stake); } /// Deactivate a validator. Called by network node when a double-sign of the given validator is registered. /// Is called before sealEpoch() call. function deactivateValidator(uint256 validatorID, uint256 status) external onlyDriver { sfc.deactivateValidator(validatorID, status); } /// Seal epoch. Called BEFORE epoch sealing made by the client itself. function sealEpoch( uint256[] calldata offlineTimes, uint256[] calldata offlineBlocks, uint256[] calldata uptimes, uint256[] calldata originatedTxsFee ) external onlyDriver { sfc.sealEpoch(offlineTimes, offlineBlocks, uptimes, originatedTxsFee); } /// Seal epoch. Called AFTER epoch sealing made by the client itself. function sealEpochValidators(uint256[] calldata nextValidatorIDs) external onlyDriver { sfc.sealEpochValidators(nextValidatorIDs); } function isContract(address account) internal view returns (bool) { uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } function _getCodeHash(address addr) internal view returns (bytes32) { bytes32 codeHash; assembly { codeHash := extcodehash(addr) } return codeHash; } uint256[50] private __gap; }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.27; import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import {Decimal} from "../common/Decimal.sol"; import {NodeDriverAuth} from "./NodeDriverAuth.sol"; import {ConstantsManager} from "./ConstantsManager.sol"; import {Version} from "../version/Version.sol"; /** * @title Special Fee Contract for Sonic network * @notice The SFC maintains a list of validators and delegators and distributes rewards to them. * @custom:security-contact [email protected] */ contract SFC is OwnableUpgradeable, UUPSUpgradeable, Version { uint256 internal constant OK_STATUS = 0; uint256 internal constant WITHDRAWN_BIT = 1; uint256 internal constant OFFLINE_BIT = 1 << 3; uint256 internal constant OFFLINE_AVG_BIT = 1 << 4; uint256 internal constant DOUBLESIGN_BIT = 1 << 7; uint256 internal constant CHEATER_MASK = DOUBLESIGN_BIT; /** * @dev The staking for validation */ struct Validator { uint256 status; uint256 receivedStake; // from all delegators (weight of the validator) address auth; // self-stake delegator uint256 createdEpoch; uint256 createdTime; uint256 deactivatedTime; uint256 deactivatedEpoch; } NodeDriverAuth internal node; // last sealed epoch (currentEpoch - 1) uint256 public currentSealedEpoch; mapping(uint256 validatorID => Validator) public getValidator; mapping(address auth => uint256 validatorID) public getValidatorID; mapping(uint256 validatorID => bytes pubkey) public getValidatorPubkey; uint256 public lastValidatorID; // total stake of all validators - includes slashed/offline validators uint256 public totalStake; // total stake of active (OK_STATUS) validators (total weight) uint256 public totalActiveStake; // unresolved fees that failed to be send to the treasury uint256 public unresolvedTreasuryFees; // delegator => validator ID => stashed rewards (to be claimed/restaked) mapping(address delegator => mapping(uint256 validatorID => uint256 stashedRewards)) internal _rewardsStash; // delegator => validator ID => last epoch number for which were rewards stashed mapping(address delegator => mapping(uint256 validatorID => uint256 epoch)) public stashedRewardsUntilEpoch; struct WithdrawalRequest { uint256 epoch; // epoch where undelegated uint256 time; // when undelegated uint256 amount; } // delegator => validator ID => withdrawal ID => withdrawal request mapping(address delegator => mapping(uint256 validatorID => mapping(uint256 wrID => WithdrawalRequest))) public getWithdrawalRequest; // delegator => validator ID => current stake mapping(address delegator => mapping(uint256 validatorID => uint256 stake)) public getStake; // data structure to compute average uptime for each active validator struct AverageUptime { // average uptime ratio as a value between 0 and 1e18 uint64 averageUptime; // remainder from the division in the average calculation uint32 remainder; // number of epochs in the average (at most averageUptimeEpochsWindow) uint32 epochs; } struct EpochSnapshot { // validator ID => validator weight in the epoch mapping(uint256 => uint256) receivedStake; // validator ID => accumulated ( delegatorsReward * 1e18 / receivedStake ) mapping(uint256 => uint256) accumulatedRewardPerToken; // validator ID => accumulated online time mapping(uint256 => uint256) accumulatedUptime; // validator ID => average uptime as a percentage mapping(uint256 => AverageUptime) averageUptime; // validator ID => gas fees from txs originated by the validator mapping(uint256 => uint256) accumulatedOriginatedTxsFee; mapping(uint256 => uint256) offlineTime; mapping(uint256 => uint256) offlineBlocks; uint256[] validatorIDs; uint256 endTime; uint256 endBlock; uint256 epochFee; // gas fees from txs in the epoch uint256 baseRewardPerSecond; // the base reward to divide among validators for each second of the epoch uint256 totalStake; // total weight of all validators uint256 totalSupply; // total supply of native tokens } // the total supply of native tokens in the chain uint256 public totalSupply; // epoch id => epoch snapshot mapping(uint256 epoch => EpochSnapshot) public getEpochSnapshot; // validator ID -> slashing refund ratio (allows to withdraw slashed stake) mapping(uint256 validatorID => uint256 refundRatio) public slashingRefundRatio; // the treasure contract (receives unlock penalties and a part of epoch fees) address public treasuryAddress; ConstantsManager internal c; // the contract subscribed to stake changes notifications address public stakeSubscriberAddress; // address derived from the validator pubkey => validator id mapping(address pubkeyAddress => uint256 validatorID) public pubkeyAddressToValidatorID; // address authorized to initiate redirection address public redirectionAuthorizer; // delegator => withdrawals receiver mapping(address delegator => address receiver) public getRedirectionRequest; // delegator => withdrawals receiver mapping(address delegator => address receiver) public getRedirection; struct SealEpochRewardsCtx { uint256[] baseRewardWeights; uint256 totalBaseRewardWeight; uint256[] txRewardWeights; uint256 totalTxRewardWeight; uint256 epochFee; } // auth error NotDriverAuth(); error NotAuthorized(); // addresses error ZeroAddress(); error SameAddress(); // values error ZeroAmount(); error ZeroRewards(); // pubkeys error PubkeyUsedByOtherValidator(); error MalformedPubkey(); // redirections error AlreadyRedirected(); error SameRedirectionAuthorizer(); error Redirected(); // validators error ValidatorNotExists(); error ValidatorExists(); error ValidatorNotActive(); error ValidatorDelegationLimitExceeded(); error NotDeactivatedStatus(); // requests error RequestExists(); error RequestNotExists(); // transfers error TransfersNotAllowed(); error TransferFailed(); // stake changes subscriber error StakeSubscriberFailed(); // staking error InsufficientSelfStake(); error NotEnoughTimePassed(); error NotEnoughEpochsPassed(); error StakeIsFullySlashed(); // stashing error NothingToStash(); // slashing error ValidatorNotSlashed(); error RefundRatioTooHigh(); // treasury error TreasuryNotSet(); error NoUnresolvedTreasuryFees(); event DeactivatedValidator(uint256 indexed validatorID, uint256 deactivatedEpoch, uint256 deactivatedTime); event ChangedValidatorStatus(uint256 indexed validatorID, uint256 status); event CreatedValidator( uint256 indexed validatorID, address indexed auth, uint256 createdEpoch, uint256 createdTime ); event Delegated(address indexed delegator, uint256 indexed toValidatorID, uint256 amount); event Undelegated(address indexed delegator, uint256 indexed toValidatorID, uint256 indexed wrID, uint256 amount); event Withdrawn( address indexed delegator, uint256 indexed toValidatorID, uint256 indexed wrID, uint256 amount, uint256 penalty ); event ClaimedRewards(address indexed delegator, uint256 indexed toValidatorID, uint256 rewards); event RestakedRewards(address indexed delegator, uint256 indexed toValidatorID, uint256 rewards); event BurntFTM(uint256 amount); event UpdatedSlashingRefundRatio(uint256 indexed validatorID, uint256 refundRatio); event RefundedSlashedLegacyDelegation(address indexed delegator, uint256 indexed validatorID, uint256 amount); event AnnouncedRedirection(address indexed from, address indexed to); event TreasuryFeesResolved(uint256 amount); modifier onlyDriver() { if (!isNode(msg.sender)) { revert NotDriverAuth(); } _; } /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } /// Initialization is called only once, after the contract deployment. /// Because the contract code is written directly into genesis, constructor cannot be used. function initialize( uint256 sealedEpoch, uint256 _totalSupply, address nodeDriver, address _c, address owner ) external initializer { __Ownable_init(owner); __UUPSUpgradeable_init(); currentSealedEpoch = sealedEpoch; node = NodeDriverAuth(nodeDriver); c = ConstantsManager(_c); totalSupply = _totalSupply; getEpochSnapshot[sealedEpoch].endTime = _now(); } /// Override the upgrade authorization check to allow upgrades only from the owner. // solhint-disable-next-line no-empty-blocks function _authorizeUpgrade(address) internal override onlyOwner {} /// Receive fallback to revert transfers. receive() external payable { revert TransfersNotAllowed(); } /// Set admin address responsible for initiating redirections. function setRedirectionAuthorizer(address v) external onlyOwner { if (redirectionAuthorizer == v) { revert SameRedirectionAuthorizer(); } redirectionAuthorizer = v; } /// Announce redirection of address to be called by validator whose auth key was compromised. /// Produced events are used to notify redirect authorizer about redirection request. /// Redirect authorizer then initiates creating of appropriate redirect by calling initiateRedirection(). function announceRedirection(address to) external { emit AnnouncedRedirection(msg.sender, to); } /// Initiate redirection of withdrawals/claims for a compromised validator account. /// Needs to be accepted by validator key holder before the redirect is active. function initiateRedirection(address from, address to) external { if (msg.sender != redirectionAuthorizer) { revert NotAuthorized(); } if (getRedirection[from] == to) { revert AlreadyRedirected(); } if (from == to) { revert SameAddress(); } getRedirectionRequest[from] = to; } /// Accept redirection proposal. /// Redirection must by accepted by the validator key holder before it start to be applied. function redirect(address to) external { address from = msg.sender; if (to == address(0)) { revert ZeroAddress(); } if (getRedirectionRequest[from] != to) { revert RequestNotExists(); } getRedirection[from] = to; getRedirectionRequest[from] = address(0); } /// Seal current epoch - deactivate validators who were offline too long, create an epoch snapshot /// for the current epoch (provides information for rewards calculation), calculate new minimal gas price. /// This method is called BEFORE the epoch sealing made by the client itself. function sealEpoch( uint256[] calldata offlineTime, uint256[] calldata offlineBlocks, uint256[] calldata uptimes, uint256[] calldata originatedTxsFee ) external onlyDriver { EpochSnapshot storage snapshot = getEpochSnapshot[currentEpoch()]; uint256[] memory validatorIDs = snapshot.validatorIDs; _sealEpochOffline(snapshot, validatorIDs, offlineTime, offlineBlocks); { EpochSnapshot storage prevSnapshot = getEpochSnapshot[currentSealedEpoch]; uint256 epochDuration = 1; if (_now() > prevSnapshot.endTime) { epochDuration = _now() - prevSnapshot.endTime; } _sealEpochRewards(epochDuration, snapshot, prevSnapshot, validatorIDs, uptimes, originatedTxsFee); _sealEpochAverageUptime(epochDuration, snapshot, prevSnapshot, validatorIDs, uptimes); } currentSealedEpoch = currentEpoch(); snapshot.endTime = _now(); snapshot.endBlock = block.number; snapshot.baseRewardPerSecond = c.baseRewardPerSecond(); snapshot.totalSupply = totalSupply; } /// Finish epoch sealing - store validators of the new epoch into a snapshot. /// This method is called AFTER the epoch sealing made by the client itself. function sealEpochValidators(uint256[] calldata nextValidatorIDs) external onlyDriver { EpochSnapshot storage snapshot = getEpochSnapshot[currentEpoch()]; // fill data for the next snapshot for (uint256 i = 0; i < nextValidatorIDs.length; i++) { uint256 validatorID = nextValidatorIDs[i]; uint256 receivedStake = getValidator[validatorID].receivedStake; snapshot.receivedStake[validatorID] = receivedStake; snapshot.totalStake = snapshot.totalStake + receivedStake; } snapshot.validatorIDs = nextValidatorIDs; } /// Set an initial validator. /// Called only as part of network initialization/genesis file generating. function setGenesisValidator( address auth, uint256 validatorID, bytes calldata pubkey, uint256 createdTime ) external onlyDriver { _rawCreateValidator( auth, validatorID, pubkey, OK_STATUS, 0, // createdEpoch createdTime, 0, // deactivatedEpoch - not deactivated 0 // deactivatedTime - not deactivated ); if (validatorID > lastValidatorID) { lastValidatorID = validatorID; } } /// Set an initial delegation. /// Called only as part of network initialization/genesis file generating. function setGenesisDelegation(address delegator, uint256 toValidatorID, uint256 stake) external onlyDriver { _rawDelegate(delegator, toValidatorID, stake, false); _mintNativeToken(stake); } /// Create a validator with a given public key while using attached value as the validator's self-stake. function createValidator(bytes calldata pubkey) external payable { if (msg.value < c.minSelfStake()) { revert InsufficientSelfStake(); } if (pubkey.length != 66 || pubkey[0] != 0xc0) { revert MalformedPubkey(); } if (pubkeyAddressToValidatorID[_pubkeyToAddress(pubkey)] != 0) { revert PubkeyUsedByOtherValidator(); } _createValidator(msg.sender, pubkey); _delegate(msg.sender, lastValidatorID, msg.value); } /// Update slashing refund ratio for a validator. /// The refund ratio is used to calculate the amount of stake that can be withdrawn after slashing. function updateSlashingRefundRatio(uint256 validatorID, uint256 refundRatio) external onlyOwner { if (!isSlashed(validatorID)) { revert ValidatorNotSlashed(); } if (refundRatio > Decimal.unit()) { revert RefundRatioTooHigh(); } slashingRefundRatio[validatorID] = refundRatio; emit UpdatedSlashingRefundRatio(validatorID, refundRatio); } /// Delegate stake to a validator. function delegate(uint256 toValidatorID) external payable { _delegate(msg.sender, toValidatorID, msg.value); } /// Withdraw stake from a validator after its un-delegation. /// Un-delegated stake is locked for a certain period of time. function withdraw(uint256 toValidatorID, uint256 wrID) public { _withdraw(msg.sender, toValidatorID, wrID, _receiverOf(msg.sender)); } /// Deactivate a validator. /// Called by the chain client when a client misbehavior is observed. function deactivateValidator(uint256 validatorID, uint256 status) external onlyDriver { if (status == OK_STATUS) { revert NotDeactivatedStatus(); } _setValidatorDeactivated(validatorID, status); _syncValidator(validatorID, false); address validatorAddr = getValidator[validatorID].auth; _notifyStakeSubscriber(validatorAddr, validatorAddr, false); } /// Stash rewards for a delegator. function stashRewards(address delegator, uint256 toValidatorID) external { if (!_stashRewards(delegator, toValidatorID)) { revert NothingToStash(); } } /// Resolve failed treasury transfers and send the unresolved fees to the treasury address. function resolveTreasuryFees() external { if (treasuryAddress == address(0)) { revert TreasuryNotSet(); } if (unresolvedTreasuryFees == 0) { revert NoUnresolvedTreasuryFees(); } // zero the fees before sending to prevent re-entrancy uint256 fees = unresolvedTreasuryFees; unresolvedTreasuryFees = 0; (bool success, ) = treasuryAddress.call{value: fees, gas: 1000000}(""); if (!success) { revert TransferFailed(); } emit TreasuryFeesResolved(fees); } /// burnFTM allows SFC to burn an arbitrary amount of FTM tokens. function burnFTM(uint256 amount) external onlyOwner { _burnFTM(amount); } /// Issue tokens to the issued tokens recipient as a counterparty to the burnt FTM tokens. function issueTokens(uint256 amount) external onlyOwner { if (c.issuedTokensRecipient() == address(0)) { revert ZeroAddress(); } node.incBalance(c.issuedTokensRecipient(), amount); totalSupply += amount; } /// Update treasury address. function updateTreasuryAddress(address v) external onlyOwner { treasuryAddress = v; } /// Update consts address. function updateConstsAddress(address v) external onlyOwner { c = ConstantsManager(v); } /// Update voteBook address. function updateStakeSubscriberAddress(address v) external onlyOwner { stakeSubscriberAddress = v; } /// Get consts address. function constsAddress() external view returns (address) { return address(c); } /// Claim rewards for stake delegated to a validator. function claimRewards(uint256 toValidatorID) public { address delegator = msg.sender; uint256 rewards = _claimRewards(delegator, toValidatorID); // It's important that we transfer after erasing (protection against Re-Entrancy) (bool sent, ) = _receiverOf(delegator).call{value: rewards}(""); if (!sent) { revert TransferFailed(); } emit ClaimedRewards(delegator, toValidatorID, rewards); } /// Get amount of currently stashed rewards. function rewardsStash(address delegator, uint256 validatorID) public view returns (uint256) { return _rewardsStash[delegator][validatorID]; } /// Un-delegate stake from a validator. function undelegate(uint256 toValidatorID, uint256 wrID, uint256 amount) public { address delegator = msg.sender; _stashRewards(delegator, toValidatorID); if (amount == 0) { revert ZeroAmount(); } if (getWithdrawalRequest[delegator][toValidatorID][wrID].amount != 0) { revert RequestExists(); } _rawUndelegate(delegator, toValidatorID, amount, true, false, true); getWithdrawalRequest[delegator][toValidatorID][wrID].amount = amount; getWithdrawalRequest[delegator][toValidatorID][wrID].epoch = currentEpoch(); getWithdrawalRequest[delegator][toValidatorID][wrID].time = _now(); _syncValidator(toValidatorID, false); emit Undelegated(delegator, toValidatorID, wrID, amount); } /// Re-stake rewards - claim rewards for staking and delegate it immediately /// to the same validator - add it to the current stake. function restakeRewards(uint256 toValidatorID) public { address delegator = msg.sender; uint256 rewards = _claimRewards(delegator, toValidatorID); _delegate(delegator, toValidatorID, rewards); emit RestakedRewards(delegator, toValidatorID, rewards); } /// Get the current epoch number. function currentEpoch() public view returns (uint256) { return currentSealedEpoch + 1; } /// Get self-stake of a validator. function getSelfStake(uint256 validatorID) public view returns (uint256) { return getStake[getValidator[validatorID].auth][validatorID]; } /// Get validator IDs for given epoch. function getEpochValidatorIDs(uint256 epoch) public view returns (uint256[] memory) { return getEpochSnapshot[epoch].validatorIDs; } /// Get received stake for a validator in a given epoch. function getEpochReceivedStake(uint256 epoch, uint256 validatorID) public view returns (uint256) { return getEpochSnapshot[epoch].receivedStake[validatorID]; } /// Get accumulated reward per token for a validator in a given epoch. function getEpochAccumulatedRewardPerToken(uint256 epoch, uint256 validatorID) public view returns (uint256) { return getEpochSnapshot[epoch].accumulatedRewardPerToken[validatorID]; } /// Get accumulated uptime for a validator in a given epoch. function getEpochAccumulatedUptime(uint256 epoch, uint256 validatorID) public view returns (uint256) { return getEpochSnapshot[epoch].accumulatedUptime[validatorID]; } /// Get average uptime for a validator in a given epoch. function getEpochAverageUptime(uint256 epoch, uint256 validatorID) public view returns (uint64) { return getEpochSnapshot[epoch].averageUptime[validatorID].averageUptime; } /// Get accumulated originated txs fee for a validator in a given epoch. function getEpochAccumulatedOriginatedTxsFee(uint256 epoch, uint256 validatorID) public view returns (uint256) { return getEpochSnapshot[epoch].accumulatedOriginatedTxsFee[validatorID]; } /// Get offline time for a validator in a given epoch. function getEpochOfflineTime(uint256 epoch, uint256 validatorID) public view returns (uint256) { return getEpochSnapshot[epoch].offlineTime[validatorID]; } /// Get offline blocks for a validator in a given epoch. function getEpochOfflineBlocks(uint256 epoch, uint256 validatorID) public view returns (uint256) { return getEpochSnapshot[epoch].offlineBlocks[validatorID]; } /// Get end block for a given epoch. function getEpochEndBlock(uint256 epoch) public view returns (uint256) { return getEpochSnapshot[epoch].endBlock; } /// Check whether the given validator is slashed - the stake (or its part) cannot /// be withdrawn because of misbehavior (double-sign) of the validator. function isSlashed(uint256 validatorID) public view returns (bool) { return getValidator[validatorID].status & CHEATER_MASK != 0; } /// Get the amount of rewards which can be currently claimed by the given delegator for the given validator. function pendingRewards(address delegator, uint256 toValidatorID) public view returns (uint256) { uint256 reward = _newRewards(delegator, toValidatorID); return _rewardsStash[delegator][toValidatorID] + reward; } /// Check whether the self-stake covers the required fraction of all delegations for the given validator. function _checkDelegatedStakeLimit(uint256 validatorID) internal view returns (bool) { return getValidator[validatorID].receivedStake <= (getSelfStake(validatorID) * c.maxDelegatedRatio()) / Decimal.unit(); } /// Check if an address is the NodeDriverAuth contract. function isNode(address addr) internal view virtual returns (bool) { return addr == address(node); } /// Delegate stake to a validator. function _delegate(address delegator, uint256 toValidatorID, uint256 amount) internal { if (!_validatorExists(toValidatorID)) { revert ValidatorNotExists(); } if (getValidator[toValidatorID].status != OK_STATUS) { revert ValidatorNotActive(); } _rawDelegate(delegator, toValidatorID, amount, true); if (!_checkDelegatedStakeLimit(toValidatorID)) { revert ValidatorDelegationLimitExceeded(); } } /// Delegate stake to a validator without checking delegation limit. function _rawDelegate(address delegator, uint256 toValidatorID, uint256 amount, bool strict) internal { if (amount == 0) { revert ZeroAmount(); } _stashRewards(delegator, toValidatorID); getStake[delegator][toValidatorID] = getStake[delegator][toValidatorID] + amount; uint256 origStake = getValidator[toValidatorID].receivedStake; getValidator[toValidatorID].receivedStake = origStake + amount; totalStake = totalStake + amount; if (getValidator[toValidatorID].status == OK_STATUS) { totalActiveStake = totalActiveStake + amount; } _syncValidator(toValidatorID, origStake == 0); emit Delegated(delegator, toValidatorID, amount); _notifyStakeSubscriber(delegator, getValidator[toValidatorID].auth, strict); } /// Un-delegate stake from a validator. function _rawUndelegate( address delegator, uint256 toValidatorID, uint256 amount, bool strict, bool forceful, bool checkDelegatedStake ) internal { getStake[delegator][toValidatorID] -= amount; getValidator[toValidatorID].receivedStake = getValidator[toValidatorID].receivedStake - amount; totalStake = totalStake - amount; if (getValidator[toValidatorID].status == OK_STATUS) { totalActiveStake = totalActiveStake - amount; } uint256 selfStakeAfterwards = getSelfStake(toValidatorID); if (selfStakeAfterwards != 0 && getValidator[toValidatorID].status == OK_STATUS) { if (!(selfStakeAfterwards >= c.minSelfStake())) { if (forceful) { revert InsufficientSelfStake(); } else { _setValidatorDeactivated(toValidatorID, WITHDRAWN_BIT); } } if (checkDelegatedStake && !_checkDelegatedStakeLimit(toValidatorID)) { revert ValidatorDelegationLimitExceeded(); } } else { _setValidatorDeactivated(toValidatorID, WITHDRAWN_BIT); } _notifyStakeSubscriber(delegator, getValidator[toValidatorID].auth, strict); } /// Get slashing penalty for a stake. function getSlashingPenalty( uint256 amount, bool isCheater, uint256 refundRatio ) internal pure returns (uint256 penalty) { if (!isCheater || refundRatio >= Decimal.unit()) { return 0; } // round penalty upwards (ceiling) to prevent dust amount attacks penalty = (amount * (Decimal.unit() - refundRatio)) / Decimal.unit() + 1; if (penalty > amount) { return amount; } return penalty; } /// Withdraw stake from a validator. /// The stake must be undelegated first. function _withdraw(address delegator, uint256 toValidatorID, uint256 wrID, address payable receiver) private { WithdrawalRequest memory request = getWithdrawalRequest[delegator][toValidatorID][wrID]; if (request.epoch == 0) { revert RequestNotExists(); } uint256 requestTime = request.time; uint256 requestEpoch = request.epoch; if ( getValidator[toValidatorID].deactivatedTime != 0 && getValidator[toValidatorID].deactivatedTime < requestTime ) { requestTime = getValidator[toValidatorID].deactivatedTime; requestEpoch = getValidator[toValidatorID].deactivatedEpoch; } if (_now() < requestTime + c.withdrawalPeriodTime()) { revert NotEnoughTimePassed(); } if (currentEpoch() < requestEpoch + c.withdrawalPeriodEpochs()) { revert NotEnoughEpochsPassed(); } uint256 amount = getWithdrawalRequest[delegator][toValidatorID][wrID].amount; bool isCheater = isSlashed(toValidatorID); uint256 penalty = getSlashingPenalty(amount, isCheater, slashingRefundRatio[toValidatorID]); delete getWithdrawalRequest[delegator][toValidatorID][wrID]; if (amount <= penalty) { revert StakeIsFullySlashed(); } // It's important that we transfer after erasing (protection against Re-Entrancy) (bool sent, ) = receiver.call{value: amount - penalty}(""); if (!sent) { revert TransferFailed(); } _burnFTM(penalty); emit Withdrawn(delegator, toValidatorID, wrID, amount - penalty, penalty); } /// Get highest epoch for which can be claimed rewards for the given validator. // If the validator is deactivated, the highest payable epoch is the deactivation epoch // or the current epoch, whichever is lower function _highestPayableEpoch(uint256 validatorID) internal view returns (uint256) { if (getValidator[validatorID].deactivatedEpoch != 0) { if (currentSealedEpoch < getValidator[validatorID].deactivatedEpoch) { return currentSealedEpoch; } return getValidator[validatorID].deactivatedEpoch; } return currentSealedEpoch; } /// Get new rewards for a delegator. /// The rewards are calculated from the last stashed epoch until the highest payable epoch. function _newRewards(address delegator, uint256 toValidatorID) internal view returns (uint256) { uint256 stashedUntil = stashedRewardsUntilEpoch[delegator][toValidatorID]; uint256 payableUntil = _highestPayableEpoch(toValidatorID); uint256 wholeStake = getStake[delegator][toValidatorID]; uint256 fullReward = _newRewardsOf(wholeStake, toValidatorID, stashedUntil, payableUntil); return fullReward; } /// Get new rewards for a delegator for a given stake amount and epoch range. function _newRewardsOf( uint256 stakeAmount, uint256 toValidatorID, uint256 fromEpoch, uint256 toEpoch ) internal view returns (uint256) { if (fromEpoch >= toEpoch) { return 0; } uint256 stashedRate = getEpochSnapshot[fromEpoch].accumulatedRewardPerToken[toValidatorID]; uint256 currentRate = getEpochSnapshot[toEpoch].accumulatedRewardPerToken[toValidatorID]; return ((currentRate - stashedRate) * stakeAmount) / Decimal.unit(); } /// Stash rewards for a delegator. function _stashRewards(address delegator, uint256 toValidatorID) internal returns (bool updated) { uint256 nonStashedReward = _newRewards(delegator, toValidatorID); stashedRewardsUntilEpoch[delegator][toValidatorID] = _highestPayableEpoch(toValidatorID); _rewardsStash[delegator][toValidatorID] += nonStashedReward; return nonStashedReward != 0; } /// Claim rewards for a delegator. function _claimRewards(address delegator, uint256 toValidatorID) internal returns (uint256) { _stashRewards(delegator, toValidatorID); uint256 rewards = _rewardsStash[delegator][toValidatorID]; if (rewards == 0) { revert ZeroRewards(); } delete _rewardsStash[delegator][toValidatorID]; // It's important that we mint after erasing (protection against Re-Entrancy) _mintNativeToken(rewards); return rewards; } /// Burn FTM tokens. /// The tokens are sent to the zero address. function _burnFTM(uint256 amount) internal { if (amount != 0) { payable(address(0)).transfer(amount); emit BurntFTM(amount); } } /// Get epoch end time. function epochEndTime(uint256 epoch) internal view returns (uint256) { return getEpochSnapshot[epoch].endTime; } /// Check if an address is redirected. function _redirected(address addr) internal view returns (bool) { return getRedirection[addr] != address(0); } /// Get address which should receive rewards and withdrawn stake for the given delegator. /// The delegator is usually the receiver, unless a redirection is created. function _receiverOf(address addr) internal view returns (address payable) { address to = getRedirection[addr]; if (to == address(0)) { return payable(address(uint160(addr))); } return payable(address(uint160(to))); } /// Seal epoch - sync validators. function _sealEpochOffline( EpochSnapshot storage snapshot, uint256[] memory validatorIDs, uint256[] memory offlineTime, uint256[] memory offlineBlocks ) internal { // mark offline nodes for (uint256 i = 0; i < validatorIDs.length; i++) { if ( offlineBlocks[i] > c.offlinePenaltyThresholdBlocksNum() && offlineTime[i] >= c.offlinePenaltyThresholdTime() ) { _setValidatorDeactivated(validatorIDs[i], OFFLINE_BIT); _syncValidator(validatorIDs[i], false); } // log data snapshot.offlineTime[validatorIDs[i]] = offlineTime[i]; snapshot.offlineBlocks[validatorIDs[i]] = offlineBlocks[i]; } } /// Seal epoch - calculate rewards. function _sealEpochRewards( uint256 epochDuration, EpochSnapshot storage snapshot, EpochSnapshot storage prevSnapshot, uint256[] memory validatorIDs, uint256[] memory uptimes, uint256[] memory accumulatedOriginatedTxsFee ) internal { SealEpochRewardsCtx memory ctx = SealEpochRewardsCtx( new uint256[](validatorIDs.length), 0, new uint256[](validatorIDs.length), 0, 0 ); for (uint256 i = 0; i < validatorIDs.length; i++) { uint256 prevAccumulatedTxsFee = prevSnapshot.accumulatedOriginatedTxsFee[validatorIDs[i]]; uint256 originatedTxsFee = 0; if (accumulatedOriginatedTxsFee[i] > prevAccumulatedTxsFee) { originatedTxsFee = accumulatedOriginatedTxsFee[i] - prevAccumulatedTxsFee; } // txRewardWeight = {originatedTxsFee} * {uptime} // originatedTxsFee is roughly proportional to {uptime} * {stake}, so the whole formula is roughly // {stake} * {uptime} ^ 2 ctx.txRewardWeights[i] = (originatedTxsFee * uptimes[i]) / epochDuration; ctx.totalTxRewardWeight = ctx.totalTxRewardWeight + ctx.txRewardWeights[i]; ctx.epochFee = ctx.epochFee + originatedTxsFee; } for (uint256 i = 0; i < validatorIDs.length; i++) { // baseRewardWeight = {stake} * {uptime ^ 2} ctx.baseRewardWeights[i] = (((snapshot.receivedStake[validatorIDs[i]] * uptimes[i]) / epochDuration) * uptimes[i]) / epochDuration; ctx.totalBaseRewardWeight = ctx.totalBaseRewardWeight + ctx.baseRewardWeights[i]; } for (uint256 i = 0; i < validatorIDs.length; i++) { uint256 rawReward = _calcRawValidatorEpochBaseReward( epochDuration, c.baseRewardPerSecond(), ctx.baseRewardWeights[i], ctx.totalBaseRewardWeight ); rawReward = rawReward + _calcRawValidatorEpochTxReward(ctx.epochFee, ctx.txRewardWeights[i], ctx.totalTxRewardWeight); uint256 validatorID = validatorIDs[i]; address validatorAddr = getValidator[validatorID].auth; // accounting validator's commission uint256 commissionRewardFull = _calcValidatorCommission(rawReward, c.validatorCommission()); uint256 selfStake = getStake[validatorAddr][validatorID]; if (selfStake != 0) { _rewardsStash[validatorAddr][validatorID] += commissionRewardFull; } // accounting reward per token for delegators uint256 delegatorsReward = rawReward - commissionRewardFull; // note: use latest stake for the sake of rewards distribution accuracy, not snapshot.receivedStake uint256 receivedStake = getValidator[validatorID].receivedStake; uint256 rewardPerToken = 0; if (receivedStake != 0) { rewardPerToken = (delegatorsReward * Decimal.unit()) / receivedStake; } snapshot.accumulatedRewardPerToken[validatorID] = prevSnapshot.accumulatedRewardPerToken[validatorID] + rewardPerToken; snapshot.accumulatedOriginatedTxsFee[validatorID] = accumulatedOriginatedTxsFee[i]; snapshot.accumulatedUptime[validatorID] = prevSnapshot.accumulatedUptime[validatorID] + uptimes[i]; } snapshot.epochFee = ctx.epochFee; if (totalSupply > snapshot.epochFee) { totalSupply -= snapshot.epochFee; } else { totalSupply = 0; } // transfer 10% of fees to treasury if (treasuryAddress != address(0)) { uint256 feeShare = (ctx.epochFee * c.treasuryFeeShare()) / Decimal.unit(); _mintNativeToken(feeShare); (bool success, ) = treasuryAddress.call{value: feeShare, gas: 1000000}(""); // solhint-disable-next-line no-empty-blocks if (!success) { // ignore treasury transfer failure // the treasury failure must not endanger the epoch sealing // store the unresolved treasury fees to be resolved later unresolvedTreasuryFees += feeShare; } } } /// Seal epoch - recalculate average uptime time of validators function _sealEpochAverageUptime( uint256 epochDuration, EpochSnapshot storage snapshot, EpochSnapshot storage prevSnapshot, uint256[] memory validatorIDs, uint256[] memory uptimes ) internal { for (uint256 i = 0; i < validatorIDs.length; i++) { uint256 validatorID = validatorIDs[i]; // compute normalised uptime as a percentage in the fixed-point format uint256 normalisedUptime = (uptimes[i] * Decimal.unit()) / epochDuration; if (normalisedUptime > Decimal.unit()) { normalisedUptime = Decimal.unit(); } AverageUptime memory previous = prevSnapshot.averageUptime[validatorID]; AverageUptime memory current = _addElementIntoAverageUptime(uint64(normalisedUptime), previous); snapshot.averageUptime[validatorID] = current; // remove validator if average uptime drops below min average uptime // (by setting minAverageUptime to zero, this check is ignored) if (current.averageUptime < c.minAverageUptime() && current.epochs >= c.averageUptimeEpochWindow()) { _setValidatorDeactivated(validatorID, OFFLINE_AVG_BIT); _syncValidator(validatorID, false); } } } function _addElementIntoAverageUptime( uint64 newValue, AverageUptime memory prev ) private view returns (AverageUptime memory) { AverageUptime memory cur; if (prev.epochs == 0) { cur.averageUptime = newValue; // the only element for the average cur.epochs = 1; return cur; } // the number of elements the average is calculated from uint128 n = prev.epochs + 1; // add new value into the average uint128 tmp = (n - 1) * uint128(prev.averageUptime) + uint128(newValue) + prev.remainder; cur.averageUptime = uint64(tmp / n); cur.remainder = uint32(tmp % n); if (cur.averageUptime > Decimal.unit()) { cur.averageUptime = uint64(Decimal.unit()); } if (prev.epochs < c.averageUptimeEpochWindow()) { cur.epochs = prev.epochs + 1; } else { cur.epochs = prev.epochs; } return cur; } /// Create a new validator. function _createValidator(address auth, bytes calldata pubkey) internal { uint256 validatorID = ++lastValidatorID; _rawCreateValidator(auth, validatorID, pubkey, OK_STATUS, currentEpoch(), _now(), 0, 0); } /// Create a new validator without incrementing lastValidatorID. function _rawCreateValidator( address auth, uint256 validatorID, bytes calldata pubkey, uint256 status, uint256 createdEpoch, uint256 createdTime, uint256 deactivatedEpoch, uint256 deactivatedTime ) internal { if (getValidatorID[auth] != 0) { revert ValidatorExists(); } getValidatorID[auth] = validatorID; getValidator[validatorID].status = status; getValidator[validatorID].createdEpoch = createdEpoch; getValidator[validatorID].createdTime = createdTime; getValidator[validatorID].deactivatedTime = deactivatedTime; getValidator[validatorID].deactivatedEpoch = deactivatedEpoch; getValidator[validatorID].auth = auth; getValidatorPubkey[validatorID] = pubkey; pubkeyAddressToValidatorID[_pubkeyToAddress(pubkey)] = validatorID; emit CreatedValidator(validatorID, auth, createdEpoch, createdTime); if (deactivatedEpoch != 0) { emit DeactivatedValidator(validatorID, deactivatedEpoch, deactivatedTime); } if (status != 0) { emit ChangedValidatorStatus(validatorID, status); } } /// Calculate raw validator epoch transaction reward. function _calcRawValidatorEpochTxReward( uint256 epochFee, uint256 txRewardWeight, uint256 totalTxRewardWeight ) internal view returns (uint256) { if (txRewardWeight == 0) { return 0; } uint256 txReward = (epochFee * txRewardWeight) / totalTxRewardWeight; // fee reward except burntFeeShare and treasuryFeeShare return (txReward * (Decimal.unit() - c.burntFeeShare() - c.treasuryFeeShare())) / Decimal.unit(); } /// Calculate raw validator epoch base reward. function _calcRawValidatorEpochBaseReward( uint256 epochDuration, uint256 _baseRewardPerSecond, uint256 baseRewardWeight, uint256 totalBaseRewardWeight ) internal pure returns (uint256) { if (baseRewardWeight == 0) { return 0; } uint256 totalReward = epochDuration * _baseRewardPerSecond; return (totalReward * baseRewardWeight) / totalBaseRewardWeight; } /// Mint native token. function _mintNativeToken(uint256 amount) internal { // balance will be increased after the transaction is processed node.incBalance(address(this), amount); totalSupply = totalSupply + amount; } /// Notify stake subscriber about staking changes. /// Used to recount votes from delegators in the governance contract. function _notifyStakeSubscriber(address delegator, address validatorAuth, bool strict) internal { if (stakeSubscriberAddress != address(0)) { // Don't allow announceStakeChange to use up all the gas // solhint-disable-next-line avoid-low-level-calls (bool success, ) = stakeSubscriberAddress.call{gas: 8000000}( abi.encodeWithSignature("announceStakeChange(address,address)", delegator, validatorAuth) ); // Don't revert if announceStakeChange failed unless strict mode enabled if (!success && strict) { revert StakeSubscriberFailed(); } } } /// Set validator deactivated status. function _setValidatorDeactivated(uint256 validatorID, uint256 status) internal { if (getValidator[validatorID].status == OK_STATUS && status != OK_STATUS) { totalActiveStake = totalActiveStake - getValidator[validatorID].receivedStake; } // status as a number is proportional to severity if (status > getValidator[validatorID].status) { getValidator[validatorID].status = status; if (getValidator[validatorID].deactivatedEpoch == 0) { getValidator[validatorID].deactivatedEpoch = currentEpoch(); getValidator[validatorID].deactivatedTime = _now(); emit DeactivatedValidator( validatorID, getValidator[validatorID].deactivatedEpoch, getValidator[validatorID].deactivatedTime ); } emit ChangedValidatorStatus(validatorID, status); } } /// Sync validator with node. function _syncValidator(uint256 validatorID, bool syncPubkey) public { if (!_validatorExists(validatorID)) { revert ValidatorNotExists(); } // emit special log for node uint256 weight = getValidator[validatorID].receivedStake; if (getValidator[validatorID].status != OK_STATUS) { weight = 0; } node.updateValidatorWeight(validatorID, weight); if (syncPubkey && weight != 0) { node.updateValidatorPubkey(validatorID, getValidatorPubkey[validatorID]); } } /// Check if a validator exists. function _validatorExists(uint256 validatorID) internal view returns (bool) { return getValidator[validatorID].createdTime != 0; } /// Calculate validator commission. function _calcValidatorCommission(uint256 rawReward, uint256 commission) internal pure returns (uint256) { return (rawReward * commission) / Decimal.unit(); } /// Derive address from validator private key function _pubkeyToAddress(bytes calldata pubkey) private pure returns (address) { return address(uint160(uint256(keccak256(pubkey[2:])))); } /// Get current time. function _now() internal view virtual returns (uint256) { return block.timestamp; } uint256[50] private __gap; }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.27; /** * @dev Version contract gives the versioning information of the implementation contract */ contract Version { /** * @dev Returns the version of the SFC contract */ function version() public pure returns (bytes3) { return 0x040000; // version 4.0.0 } }
{ "evmVersion": "cancun", "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"uint256","name":"sealedEpoch","type":"uint256"},{"internalType":"uint256","name":"totalSupply","type":"uint256"},{"internalType":"address payable","name":"_sfc","type":"address"},{"internalType":"address","name":"_auth","type":"address"},{"internalType":"address","name":"_driver","type":"address"},{"internalType":"address","name":"_evmWriter","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"initializeAll","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063c80e15131461002d575b5f5ffd5b61004061003b36600461076d565b610042565b005b60405163c0c53b8b60e01b81526001600160a01b0385811660048301528381166024830152828116604483015284169063c0c53b8b906064015f604051808303815f87803b158015610092575f5ffd5b505af11580156100a4573d5f5f3e3d5ffd5b505060405163c0c53b8b60e01b81526001600160a01b038881166004830152868116602483015284811660448301528716925063c0c53b8b91506064015f604051808303815f87803b1580156100f8575f5ffd5b505af115801561010a573d5f5f3e3d5ffd5b505050505f3060405161011c90610749565b6001600160a01b039091168152602001604051809103905ff080158015610145573d5f5f3e3d5ffd5b5060405163866c4b1760e01b81526969e10de76676d080000060048201529091506001600160a01b0382169063866c4b17906024015f604051808303815f87803b158015610191575f5ffd5b505af11580156101a3573d5f5f3e3d5ffd5b50505050806001600160a01b03166381ffcdf16101c5670de0b6b3a764000090565b6101d09060106107ec565b6040518263ffffffff1660e01b81526004016101ee91815260200190565b5f604051808303815f87803b158015610205575f5ffd5b505af1158015610217573d5f5f3e3d5ffd5b50505050806001600160a01b0316632ee71132606461023b670de0b6b3a764000090565b61024690600f6107ec565b6102509190610815565b6040518263ffffffff1660e01b815260040161026e91815260200190565b5f604051808303815f87803b158015610285575f5ffd5b505af1158015610297573d5f5f3e3d5ffd5b5050604051632bb9fe8d60e01b81525f60048201526001600160a01b0384169250632bb9fe8d91506024015f604051808303815f87803b1580156102d9575f5ffd5b505af11580156102eb573d5f5f3e3d5ffd5b50505050806001600160a01b031663f8d5177e606461030f670de0b6b3a764000090565b61031a90605a6107ec565b6103249190610815565b6040518263ffffffff1660e01b815260040161034291815260200190565b5f604051808303815f87803b158015610359575f5ffd5b505af115801561036b573d5f5f3e3d5ffd5b5050604051634783c5fd60e11b8152600360048201526001600160a01b0384169250638f078bfa91506024015f604051808303815f87803b1580156103ae575f5ffd5b505af11580156103c0573d5f5f3e3d5ffd5b5050604051631154d9a960e21b815262093a8060048201526001600160a01b038416925063455366a491506024015f604051808303815f87803b158015610405575f5ffd5b505af1158015610417573d5f5f3e3d5ffd5b505060405163b6d9edd560e01b81526103e860048201526001600160a01b038416925063b6d9edd591506024015f604051808303815f87803b15801561045b575f5ffd5b505af115801561046d573d5f5f3e3d5ffd5b5050604051630c691d7760e31b81526206978060048201526001600160a01b0384169250636348ebb891506024015f604051808303815f87803b1580156104b2575f5ffd5b505af11580156104c4573d5f5f3e3d5ffd5b5050604051631742747360e11b81526103e860048201526001600160a01b0384169250632e84e8e691506024015f604051808303815f87803b158015610508575f5ffd5b505af115801561051a573d5f5f3e3d5ffd5b5050604051634332686760e01b81526301c9c38060048201526001600160a01b0384169250634332686791506024015f604051808303815f87803b158015610560575f5ffd5b505af1158015610572573d5f5f3e3d5ffd5b50506040516369fa46df60e11b8152610e1060048201526001600160a01b038416925063d3f48dbe91506024015f604051808303815f87803b1580156105b6575f5ffd5b505af11580156105c8573d5f5f3e3d5ffd5b50506040516312b6e2b960e11b8152606460048201526001600160a01b038416925063256dc57291506024015f604051808303815f87803b15801561060b575f5ffd5b505af115801561061d573d5f5f3e3d5ffd5b505060405163165e263960e01b81525f60048201526001600160a01b038416925063165e263991506024015f604051808303815f87803b15801561065f575f5ffd5b505af1158015610671573d5f5f3e3d5ffd5b505060405163f2fde38b60e01b81526001600160a01b0385811660048301528416925063f2fde38b91506024015f604051808303815f87803b1580156106b5575f5ffd5b505af11580156106c7573d5f5f3e3d5ffd5b5050604051633fbfd4df60e01b8152600481018b9052602481018a90526001600160a01b0388811660448301528481166064830152858116608483015289169250633fbfd4df915060a4015f604051808303815f87803b158015610729575f5ffd5b505af115801561073b573d5f5f3e3d5ffd5b505050505050505050505050565b610bef8061083583390190565b6001600160a01b038116811461076a575f5ffd5b50565b5f5f5f5f5f5f5f60e0888a031215610783575f5ffd5b8735965060208801359550604088013561079c81610756565b945060608801356107ac81610756565b935060808801356107bc81610756565b925060a08801356107cc81610756565b915060c08801356107dc81610756565b8091505092959891949750929550565b808202811582820484141761080f57634e487b7160e01b5f52601160045260245ffd5b92915050565b5f8261082f57634e487b7160e01b5f52601260045260245ffd5b50049056fe6080604052348015600e575f5ffd5b50604051610bef380380610bef833981016040819052602b9160b4565b806001600160a01b038116605857604051631e4fbdf760e01b81525f600482015260240160405180910390fd5b605f816065565b505060df565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f6020828403121560c3575f5ffd5b81516001600160a01b038116811460d8575f5ffd5b9392505050565b610b03806100ec5f395ff3fe608060405234801561000f575f5ffd5b50600436106101f1575f3560e01c8063715018a611610114578063a7786515116100a9578063c74dd62111610079578063c74dd621146103ff578063d3f48dbe14610408578063d9a7c1f91461041b578063f2fde38b14610424578063f8d5177e14610437575f5ffd5b8063a7786515146103d1578063b6d9edd5146103da578063b82b8427146103ed578063c5f530af146103f6575f5ffd5b8063866c4b17116100e4578063866c4b17146103925780638da5cb5b146103a55780638f078bfa146103b557806394c3e914146103c8575f5ffd5b8063715018a614610332578063754e92e31461033a57806375840fab1461034d57806381ffcdf11461037f575f5ffd5b80632ee711321161018a578063455366a41161015a578063455366a4146102fa5780635a68f01a1461030d5780636348ebb814610316578063650acd6614610329575f5ffd5b80632ee71132146102a65780633a3ef66c146102b95780633fa22548146102c257806343326867146102e7575f5ffd5b8063256dc572116101c5578063256dc572146102645780632bb9fe8d146102775780632c8c36a51461028a5780632e84e8e614610293575f5ffd5b8062cc7f83146101f5578063165e2639146102115780631c254337146102265780632265f2841461025b575b5f5ffd5b6101fe600a5481565b6040519081526020015b60405180910390f35b61022461021f3660046109f7565b61044a565b005b600d5461024290640100000000900467ffffffffffffffff1681565b60405167ffffffffffffffff9091168152602001610208565b6101fe60025481565b610224610272366004610a25565b6104cb565b610224610285366004610a48565b610541565b6101fe600c5481565b6102246102a1366004610a48565b610581565b6102246102b4366004610a48565b6105d4565b6101fe600b5481565b600d546102d29063ffffffff1681565b60405163ffffffff9091168152602001610208565b6102246102f5366004610a48565b610614565b610224610308366004610a48565b61066a565b6101fe60095481565b610224610324366004610a48565b6106bf565b6101fe60065481565b610224610714565b610224610348366004610a5f565b610727565b600d5461036790600160601b90046001600160a01b031681565b6040516001600160a01b039091168152602001610208565b61022461038d366004610a48565b61075c565b6102246103a0366004610a48565b6107c5565b5f546001600160a01b0316610367565b6102246103c3366004610a48565b610829565b6101fe60055481565b6101fe60035481565b6102246103e8366004610a48565b61087a565b6101fe60075481565b6101fe60015481565b6101fe60045481565b610224610416366004610a48565b6108b1565b6101fe60085481565b610224610432366004610a5f565b610904565b610224610445366004610a48565b610946565b61045261097c565b600a610467670de0b6b3a76400006009610a85565b6104719190610aae565b8167ffffffffffffffff16111561049b57604051632ad907fb60e01b815260040160405180910390fd5b600d805467ffffffffffffffff909216640100000000026bffffffffffffffff0000000019909216919091179055565b6104d361097c565b600a8163ffffffff1610156104fb57604051639a721da360e01b815260040160405180910390fd5b620156308163ffffffff16111561052557604051632ad907fb60e01b815260040160405180910390fd5b600d805463ffffffff191663ffffffff92909216919091179055565b61054961097c565b61055c6002670de0b6b3a7640000610aae565b81111561057c57604051632ad907fb60e01b815260040160405180910390fd5b600455565b61058961097c565b60648110156105ab57604051639a721da360e01b815260040160405180910390fd5b620f42408111156105cf57604051632ad907fb60e01b815260040160405180910390fd5b600955565b6105dc61097c565b6105ef6002670de0b6b3a7640000610aae565b81111561060f57604051632ad907fb60e01b815260040160405180910390fd5b600355565b61061c61097c565b620f424081101561064057604051639a721da360e01b815260040160405180910390fd5b631dcd650081111561066557604051632ad907fb60e01b815260040160405180910390fd5b600b55565b61067261097c565b6201518081101561069657604051639a721da360e01b815260040160405180910390fd5b62278d008111156106ba57604051632ad907fb60e01b815260040160405180910390fd5b600755565b6106c761097c565b620151808110156106eb57604051639a721da360e01b815260040160405180910390fd5b620d2f0081111561070f57604051632ad907fb60e01b815260040160405180910390fd5b600a55565b61071c61097c565b6107255f6109a8565b565b61072f61097c565b600d80546001600160a01b03909216600160601b026bffffffffffffffffffffffff909216919091179055565b61076461097c565b670de0b6b3a764000081101561078d57604051639a721da360e01b815260040160405180910390fd5b6107a0670de0b6b3a7640000601f610a85565b8111156107c057604051632ad907fb60e01b815260040160405180910390fd5b600255565b6107cd61097c565b69152d02c7e14af68000008110156107f857604051639a721da360e01b815260040160405180910390fd5b6a084595161401484a00000081111561082457604051632ad907fb60e01b815260040160405180910390fd5b600155565b61083161097c565b600281101561085357604051639a721da360e01b815260040160405180910390fd5b606481111561087557604051632ad907fb60e01b815260040160405180910390fd5b600655565b61088261097c565b6801bc16d674ec8000008111156108ac57604051632ad907fb60e01b815260040160405180910390fd5b600855565b6108b961097c565b60648110156108db57604051639a721da360e01b815260040160405180910390fd5b620d2f008111156108ff57604051632ad907fb60e01b815260040160405180910390fd5b600c55565b61090c61097c565b6001600160a01b03811661093a57604051631e4fbdf760e01b81525f60048201526024015b60405180910390fd5b610943816109a8565b50565b61094e61097c565b670de0b6b3a764000081111561097757604051632ad907fb60e01b815260040160405180910390fd5b600555565b5f546001600160a01b031633146107255760405163118cdaa760e01b8152336004820152602401610931565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f60208284031215610a07575f5ffd5b813567ffffffffffffffff81168114610a1e575f5ffd5b9392505050565b5f60208284031215610a35575f5ffd5b813563ffffffff81168114610a1e575f5ffd5b5f60208284031215610a58575f5ffd5b5035919050565b5f60208284031215610a6f575f5ffd5b81356001600160a01b0381168114610a1e575f5ffd5b8082028115828204841417610aa857634e487b7160e01b5f52601160045260245ffd5b92915050565b5f82610ac857634e487b7160e01b5f52601260045260245ffd5b50049056fea264697066735822122046699d5933485ff13f4f6da75e2ad4fcb2fbe66e2c3e0c1f9fb38fec389adafb64736f6c634300081b0033a264697066735822122082f7a5059cfe29ee3b781a0182f0f468c809f0a6fa8374734b6886fd400048cb64736f6c634300081b0033
Deployed Bytecode
0x608060405234801561000f575f5ffd5b5060043610610029575f3560e01c8063c80e15131461002d575b5f5ffd5b61004061003b36600461076d565b610042565b005b60405163c0c53b8b60e01b81526001600160a01b0385811660048301528381166024830152828116604483015284169063c0c53b8b906064015f604051808303815f87803b158015610092575f5ffd5b505af11580156100a4573d5f5f3e3d5ffd5b505060405163c0c53b8b60e01b81526001600160a01b038881166004830152868116602483015284811660448301528716925063c0c53b8b91506064015f604051808303815f87803b1580156100f8575f5ffd5b505af115801561010a573d5f5f3e3d5ffd5b505050505f3060405161011c90610749565b6001600160a01b039091168152602001604051809103905ff080158015610145573d5f5f3e3d5ffd5b5060405163866c4b1760e01b81526969e10de76676d080000060048201529091506001600160a01b0382169063866c4b17906024015f604051808303815f87803b158015610191575f5ffd5b505af11580156101a3573d5f5f3e3d5ffd5b50505050806001600160a01b03166381ffcdf16101c5670de0b6b3a764000090565b6101d09060106107ec565b6040518263ffffffff1660e01b81526004016101ee91815260200190565b5f604051808303815f87803b158015610205575f5ffd5b505af1158015610217573d5f5f3e3d5ffd5b50505050806001600160a01b0316632ee71132606461023b670de0b6b3a764000090565b61024690600f6107ec565b6102509190610815565b6040518263ffffffff1660e01b815260040161026e91815260200190565b5f604051808303815f87803b158015610285575f5ffd5b505af1158015610297573d5f5f3e3d5ffd5b5050604051632bb9fe8d60e01b81525f60048201526001600160a01b0384169250632bb9fe8d91506024015f604051808303815f87803b1580156102d9575f5ffd5b505af11580156102eb573d5f5f3e3d5ffd5b50505050806001600160a01b031663f8d5177e606461030f670de0b6b3a764000090565b61031a90605a6107ec565b6103249190610815565b6040518263ffffffff1660e01b815260040161034291815260200190565b5f604051808303815f87803b158015610359575f5ffd5b505af115801561036b573d5f5f3e3d5ffd5b5050604051634783c5fd60e11b8152600360048201526001600160a01b0384169250638f078bfa91506024015f604051808303815f87803b1580156103ae575f5ffd5b505af11580156103c0573d5f5f3e3d5ffd5b5050604051631154d9a960e21b815262093a8060048201526001600160a01b038416925063455366a491506024015f604051808303815f87803b158015610405575f5ffd5b505af1158015610417573d5f5f3e3d5ffd5b505060405163b6d9edd560e01b81526103e860048201526001600160a01b038416925063b6d9edd591506024015f604051808303815f87803b15801561045b575f5ffd5b505af115801561046d573d5f5f3e3d5ffd5b5050604051630c691d7760e31b81526206978060048201526001600160a01b0384169250636348ebb891506024015f604051808303815f87803b1580156104b2575f5ffd5b505af11580156104c4573d5f5f3e3d5ffd5b5050604051631742747360e11b81526103e860048201526001600160a01b0384169250632e84e8e691506024015f604051808303815f87803b158015610508575f5ffd5b505af115801561051a573d5f5f3e3d5ffd5b5050604051634332686760e01b81526301c9c38060048201526001600160a01b0384169250634332686791506024015f604051808303815f87803b158015610560575f5ffd5b505af1158015610572573d5f5f3e3d5ffd5b50506040516369fa46df60e11b8152610e1060048201526001600160a01b038416925063d3f48dbe91506024015f604051808303815f87803b1580156105b6575f5ffd5b505af11580156105c8573d5f5f3e3d5ffd5b50506040516312b6e2b960e11b8152606460048201526001600160a01b038416925063256dc57291506024015f604051808303815f87803b15801561060b575f5ffd5b505af115801561061d573d5f5f3e3d5ffd5b505060405163165e263960e01b81525f60048201526001600160a01b038416925063165e263991506024015f604051808303815f87803b15801561065f575f5ffd5b505af1158015610671573d5f5f3e3d5ffd5b505060405163f2fde38b60e01b81526001600160a01b0385811660048301528416925063f2fde38b91506024015f604051808303815f87803b1580156106b5575f5ffd5b505af11580156106c7573d5f5f3e3d5ffd5b5050604051633fbfd4df60e01b8152600481018b9052602481018a90526001600160a01b0388811660448301528481166064830152858116608483015289169250633fbfd4df915060a4015f604051808303815f87803b158015610729575f5ffd5b505af115801561073b573d5f5f3e3d5ffd5b505050505050505050505050565b610bef8061083583390190565b6001600160a01b038116811461076a575f5ffd5b50565b5f5f5f5f5f5f5f60e0888a031215610783575f5ffd5b8735965060208801359550604088013561079c81610756565b945060608801356107ac81610756565b935060808801356107bc81610756565b925060a08801356107cc81610756565b915060c08801356107dc81610756565b8091505092959891949750929550565b808202811582820484141761080f57634e487b7160e01b5f52601160045260245ffd5b92915050565b5f8261082f57634e487b7160e01b5f52601260045260245ffd5b50049056fe6080604052348015600e575f5ffd5b50604051610bef380380610bef833981016040819052602b9160b4565b806001600160a01b038116605857604051631e4fbdf760e01b81525f600482015260240160405180910390fd5b605f816065565b505060df565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f6020828403121560c3575f5ffd5b81516001600160a01b038116811460d8575f5ffd5b9392505050565b610b03806100ec5f395ff3fe608060405234801561000f575f5ffd5b50600436106101f1575f3560e01c8063715018a611610114578063a7786515116100a9578063c74dd62111610079578063c74dd621146103ff578063d3f48dbe14610408578063d9a7c1f91461041b578063f2fde38b14610424578063f8d5177e14610437575f5ffd5b8063a7786515146103d1578063b6d9edd5146103da578063b82b8427146103ed578063c5f530af146103f6575f5ffd5b8063866c4b17116100e4578063866c4b17146103925780638da5cb5b146103a55780638f078bfa146103b557806394c3e914146103c8575f5ffd5b8063715018a614610332578063754e92e31461033a57806375840fab1461034d57806381ffcdf11461037f575f5ffd5b80632ee711321161018a578063455366a41161015a578063455366a4146102fa5780635a68f01a1461030d5780636348ebb814610316578063650acd6614610329575f5ffd5b80632ee71132146102a65780633a3ef66c146102b95780633fa22548146102c257806343326867146102e7575f5ffd5b8063256dc572116101c5578063256dc572146102645780632bb9fe8d146102775780632c8c36a51461028a5780632e84e8e614610293575f5ffd5b8062cc7f83146101f5578063165e2639146102115780631c254337146102265780632265f2841461025b575b5f5ffd5b6101fe600a5481565b6040519081526020015b60405180910390f35b61022461021f3660046109f7565b61044a565b005b600d5461024290640100000000900467ffffffffffffffff1681565b60405167ffffffffffffffff9091168152602001610208565b6101fe60025481565b610224610272366004610a25565b6104cb565b610224610285366004610a48565b610541565b6101fe600c5481565b6102246102a1366004610a48565b610581565b6102246102b4366004610a48565b6105d4565b6101fe600b5481565b600d546102d29063ffffffff1681565b60405163ffffffff9091168152602001610208565b6102246102f5366004610a48565b610614565b610224610308366004610a48565b61066a565b6101fe60095481565b610224610324366004610a48565b6106bf565b6101fe60065481565b610224610714565b610224610348366004610a5f565b610727565b600d5461036790600160601b90046001600160a01b031681565b6040516001600160a01b039091168152602001610208565b61022461038d366004610a48565b61075c565b6102246103a0366004610a48565b6107c5565b5f546001600160a01b0316610367565b6102246103c3366004610a48565b610829565b6101fe60055481565b6101fe60035481565b6102246103e8366004610a48565b61087a565b6101fe60075481565b6101fe60015481565b6101fe60045481565b610224610416366004610a48565b6108b1565b6101fe60085481565b610224610432366004610a5f565b610904565b610224610445366004610a48565b610946565b61045261097c565b600a610467670de0b6b3a76400006009610a85565b6104719190610aae565b8167ffffffffffffffff16111561049b57604051632ad907fb60e01b815260040160405180910390fd5b600d805467ffffffffffffffff909216640100000000026bffffffffffffffff0000000019909216919091179055565b6104d361097c565b600a8163ffffffff1610156104fb57604051639a721da360e01b815260040160405180910390fd5b620156308163ffffffff16111561052557604051632ad907fb60e01b815260040160405180910390fd5b600d805463ffffffff191663ffffffff92909216919091179055565b61054961097c565b61055c6002670de0b6b3a7640000610aae565b81111561057c57604051632ad907fb60e01b815260040160405180910390fd5b600455565b61058961097c565b60648110156105ab57604051639a721da360e01b815260040160405180910390fd5b620f42408111156105cf57604051632ad907fb60e01b815260040160405180910390fd5b600955565b6105dc61097c565b6105ef6002670de0b6b3a7640000610aae565b81111561060f57604051632ad907fb60e01b815260040160405180910390fd5b600355565b61061c61097c565b620f424081101561064057604051639a721da360e01b815260040160405180910390fd5b631dcd650081111561066557604051632ad907fb60e01b815260040160405180910390fd5b600b55565b61067261097c565b6201518081101561069657604051639a721da360e01b815260040160405180910390fd5b62278d008111156106ba57604051632ad907fb60e01b815260040160405180910390fd5b600755565b6106c761097c565b620151808110156106eb57604051639a721da360e01b815260040160405180910390fd5b620d2f0081111561070f57604051632ad907fb60e01b815260040160405180910390fd5b600a55565b61071c61097c565b6107255f6109a8565b565b61072f61097c565b600d80546001600160a01b03909216600160601b026bffffffffffffffffffffffff909216919091179055565b61076461097c565b670de0b6b3a764000081101561078d57604051639a721da360e01b815260040160405180910390fd5b6107a0670de0b6b3a7640000601f610a85565b8111156107c057604051632ad907fb60e01b815260040160405180910390fd5b600255565b6107cd61097c565b69152d02c7e14af68000008110156107f857604051639a721da360e01b815260040160405180910390fd5b6a084595161401484a00000081111561082457604051632ad907fb60e01b815260040160405180910390fd5b600155565b61083161097c565b600281101561085357604051639a721da360e01b815260040160405180910390fd5b606481111561087557604051632ad907fb60e01b815260040160405180910390fd5b600655565b61088261097c565b6801bc16d674ec8000008111156108ac57604051632ad907fb60e01b815260040160405180910390fd5b600855565b6108b961097c565b60648110156108db57604051639a721da360e01b815260040160405180910390fd5b620d2f008111156108ff57604051632ad907fb60e01b815260040160405180910390fd5b600c55565b61090c61097c565b6001600160a01b03811661093a57604051631e4fbdf760e01b81525f60048201526024015b60405180910390fd5b610943816109a8565b50565b61094e61097c565b670de0b6b3a764000081111561097757604051632ad907fb60e01b815260040160405180910390fd5b600555565b5f546001600160a01b031633146107255760405163118cdaa760e01b8152336004820152602401610931565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b5f60208284031215610a07575f5ffd5b813567ffffffffffffffff81168114610a1e575f5ffd5b9392505050565b5f60208284031215610a35575f5ffd5b813563ffffffff81168114610a1e575f5ffd5b5f60208284031215610a58575f5ffd5b5035919050565b5f60208284031215610a6f575f5ffd5b81356001600160a01b0381168114610a1e575f5ffd5b8082028115828204841417610aa857634e487b7160e01b5f52601160045260245ffd5b92915050565b5f82610ac857634e487b7160e01b5f52601260045260245ffd5b50049056fea264697066735822122046699d5933485ff13f4f6da75e2ad4fcb2fbe66e2c3e0c1f9fb38fec389adafb64736f6c634300081b0033a264697066735822122082f7a5059cfe29ee3b781a0182f0f468c809f0a6fa8374734b6886fd400048cb64736f6c634300081b0033
Deployed Bytecode Sourcemap
375:1515:19:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;510:1378;;;;;;:::i;:::-;;:::i;:::-;;;746:57;;-1:-1:-1;;;746:57:19;;-1:-1:-1;;;;;1486:32:24;;;746:57:19;;;1468:51:24;1555:32;;;1535:18;;;1528:60;1624:32;;;1604:18;;;1597:60;746:30:19;;;;;1441:18:24;;746:57:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;813:55:19;;-1:-1:-1;;;813:55:19;;-1:-1:-1;;;;;1486:32:24;;;813:55:19;;;1468:51:24;1555:32;;;1535:18;;;1528:60;1624:32;;;1604:18;;;1597:60;813:32:19;;;-1:-1:-1;813:32:19;;-1:-1:-1;1441:18:24;;813:55:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;879:23;934:4;905:35;;;;;:::i;:::-;-1:-1:-1;;;;;2250:32:24;;;2232:51;;2220:2;2205:18;905:35:19;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;950:41:19;;-1:-1:-1;;;950:41:19;;976:14;950:41;;;2471:25:24;879:61:19;;-1:-1:-1;;;;;;950:25:19;;;;;2444:18:24;;950:41:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1001:6;-1:-1:-1;;;;;1001:30:19;;1037:14;262:4:13;;197:76;1037:14:19;1032:19;;:2;:19;:::i;:::-;1001:51;;;;;;;;;;;;;2471:25:24;;2459:2;2444:18;;2294:208;1001:51:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1062:6;-1:-1:-1;;;;;1062:32:19;;1119:3;1101:14;262:4:13;;197:76;1101:14:19;1096:19;;:2;:19;:::i;:::-;1095:27;;;;:::i;:::-;1062:61;;;;;;;;;;;;;2471:25:24;;2459:2;2444:18;;2294:208;1062:61:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1133:29:19;;-1:-1:-1;;;1133:29:19;;1160:1;1133:29;;;2471:25:24;-1:-1:-1;;;;;1133:26:19;;;-1:-1:-1;1133:26:19;;-1:-1:-1;2444:18:24;;1133:29:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1172:6;-1:-1:-1;;;;;1172:29:19;;1226:3;1208:14;262:4:13;;197:76;1208:14:19;1203:19;;:2;:19;:::i;:::-;1202:27;;;;:::i;:::-;1172:58;;;;;;;;;;;;;2471:25:24;;2459:2;2444:18;;2294:208;1172:58:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1240:38:19;;-1:-1:-1;;;1240:38:19;;1276:1;1240:38;;;2471:25:24;-1:-1:-1;;;;;1240:35:19;;;-1:-1:-1;1240:35:19;;-1:-1:-1;2444:18:24;;1240:38:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1288:51:19;;-1:-1:-1;;;1288:51:19;;1322:16;1288:51;;;2471:25:24;-1:-1:-1;;;;;1288:33:19;;;-1:-1:-1;1288:33:19;;-1:-1:-1;2444:18:24;;1288:51:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1349:39:19;;-1:-1:-1;;;1349:39:19;;1382:5;1349:39;;;2471:25:24;-1:-1:-1;;;;;1349:32:19;;;-1:-1:-1;1349:32:19;;-1:-1:-1;2444:18:24;;1349:39:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1398:48:19;;-1:-1:-1;;;1398:48:19;;1439:6;1398:48;;;2471:25:24;-1:-1:-1;;;;;1398:40:19;;;-1:-1:-1;1398:40:19;;-1:-1:-1;2444:18:24;;1398:48:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1456:52:19;;-1:-1:-1;;;1456:52:19;;1502:5;1456:52;;;2471:25:24;-1:-1:-1;;;;;1456:45:19;;;-1:-1:-1;1456:45:19;;-1:-1:-1;2444:18:24;;1456:52:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1518:48:19;;-1:-1:-1;;;1518:48:19;;1555:10;1518:48;;;2471:25:24;-1:-1:-1;;;;;1518:36:19;;;-1:-1:-1;1518:36:19;;-1:-1:-1;2444:18:24;;1518:48:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1576:50:19;;-1:-1:-1;;;1576:50:19;;1620:5;1576:50;;;2471:25:24;-1:-1:-1;;;;;1576:43:19;;;-1:-1:-1;1576:43:19;;-1:-1:-1;2444:18:24;;1576:50:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1636:42:19;;-1:-1:-1;;;1636:42:19;;1674:3;1636:42;;;4689::24;-1:-1:-1;;;;;1636:37:19;;;-1:-1:-1;1636:37:19;;-1:-1:-1;4662:18:24;;1636:42:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1688:32:19;;-1:-1:-1;;;1688:32:19;;1718:1;1688:32;;;4895:50:24;-1:-1:-1;;;;;1688:29:19;;;-1:-1:-1;1688:29:19;;-1:-1:-1;4868:18:24;;1688:32:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1759:32:19;;-1:-1:-1;;;1759:32:19;;-1:-1:-1;;;;;2250:32:24;;;1759::19;;;2232:51:24;1759:24:19;;;-1:-1:-1;1759:24:19;;-1:-1:-1;2205:18:24;;1759:32:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;1802:79:19;;-1:-1:-1;;;1802:79:19;;;;;5215:25:24;;;5256:18;;;5249:34;;;-1:-1:-1;;;;;5319:32:24;;;5299:18;;;5292:60;5388:32;;;5368:18;;;5361:60;5458:32;;;5437:19;;;5430:61;1802:21:19;;;-1:-1:-1;1802:21:19;;-1:-1:-1;5187:19:24;;1802:79:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;736:1152;510:1378;;;;;;;:::o;-1:-1:-1:-;;;;;;;;:::o;14:139:24:-;-1:-1:-1;;;;;97:31:24;;87:42;;77:70;;143:1;140;133:12;77:70;14:139;:::o;158:1103::-;279:6;287;295;303;311;319;327;380:3;368:9;359:7;355:23;351:33;348:53;;;397:1;394;387:12;348:53;442:23;;;-1:-1:-1;562:2:24;547:18;;534:32;;-1:-1:-1;644:2:24;629:18;;616:32;657:41;616:32;657:41;:::i;:::-;717:7;-1:-1:-1;776:2:24;761:18;;748:32;789:41;748:32;789:41;:::i;:::-;849:7;-1:-1:-1;908:3:24;893:19;;880:33;922:41;880:33;922:41;:::i;:::-;982:7;-1:-1:-1;1041:3:24;1026:19;;1013:33;1055:41;1013:33;1055:41;:::i;:::-;1115:7;-1:-1:-1;1174:3:24;1159:19;;1146:33;1188:41;1146:33;1188:41;:::i;:::-;1248:7;1238:17;;;158:1103;;;;;;;;;;:::o;2507:265::-;2580:9;;;2611;;2628:15;;;2622:22;;2608:37;2598:168;;2688:10;2683:3;2679:20;2676:1;2669:31;2723:4;2720:1;2713:15;2751:4;2748:1;2741:15;2598:168;2507:265;;;;:::o;2959:217::-;2999:1;3025;3015:132;;3069:10;3064:3;3060:20;3057:1;3050:31;3104:4;3101:1;3094:15;3132:4;3129:1;3122:15;3015:132;-1:-1:-1;3161:9:24;;2959:217::o
Swarm Source
ipfs://82f7a5059cfe29ee3b781a0182f0f468c809f0a6fa8374734b6886fd400048cb
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.