Description:
Proxy contract enabling upgradeable smart contract patterns. Delegates calls to an implementation contract.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @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]
* ```
* 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 Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 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. Equivalent to `reinitializer(1)`.
*/
modifier initializer() {
bool isTopLevelCall = _setInitializedVersion(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.
*
* `initializer` is equivalent to `reinitializer(1)`, so 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.
*
* 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.
*/
modifier reinitializer(uint8 version) {
bool isTopLevelCall = _setInitializedVersion(version);
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_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() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @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.
*/
function _disableInitializers() internal virtual {
_setInitializedVersion(type(uint8).max);
}
function _setInitializedVersion(uint8 version) private returns (bool) {
// If the contract is initializing we ignore whether _initialized is set in order to support multiple
// inheritance patterns, but we only do this in the context of a constructor, and for the lowest level
// of initializers, because in other contexts the contract may have been reentered.
if (_initializing) {
require(
version == 1 && !AddressUpgradeable.isContract(address(this)),
"Initializable: contract is already initialized"
);
return false;
} else {
require(_initialized < version, "Initializable: contract is already initialized");
_initialized = version;
return true;
}
}
}
"
},
"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @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, it is bubbled up by this
* function (like regular Solidity function calls).
*
* 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.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @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`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// 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 {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
"
},
"@openzeppelin/contracts/token/ERC20/IERC20.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
"
},
"contracts/ISafeStakeClusterNode.sol": {
"content": "pragma solidity >0.5.0 <0.9.0;
// SPDX-License-Identifier: GPL-3.0-only
interface ISafeStakeClusterNode {
/***
* @dev Emitted when the validator node has been added.
* @param owner validator node's ethereum address that can collect fees.
* @param clusterNodePublicKey The public key of a validator.
*/
event ClusterNodeRegistration(
address indexed owner,
bytes clusterNodePublicKey
);
/**
* @dev Emitted when the validator sent a request to generate deposit data.
* @param clusterNodePublicKey The public key of a cluster.
* @param validatorCount The count of the request.
* @param operatorIds The operator ids of the validators.
* @param depositAmount The amount to deposit.
* @param withdrawAddress The address to withdraw the funds
*/
event ValidatorDepositDataGeneration(
bytes clusterNodePublicKey,
address owner,
bytes ownerPubkey,
uint256 validatorCount,
uint32[] operatorIds,
uint256 depositAmount,
address withdrawAddress
);
/**
* @dev Emitted when the validator sent a request to generate exit data.
* @param clusterNodePublicKey The public key of a cluster.
* @param validatorPubKeys The keys of the validators.
* @param activeEpoch The start epoch when exited.
*/
event ValidatorExitDataGeneration(
bytes clusterNodePublicKey,
address owner,
// bytes ownerPubkey,
bytes[] validatorPubKeys,
uint256 activeEpoch
);
/**
* @dev Generates the deposit data.
* @param clusterNodePublicKey The public key of the cluster node.
* @param validatorCount The count of the request.
* @param operatorIds The operator ids of the validators.
* @param depositAmount The amount to deposit.
* @param withdrawAddress The address to withdraw the funds
*/
function generateDepositData(
bytes calldata clusterNodePublicKey,
address owner,
bytes calldata ownerPubkey,
uint256 validatorCount,
uint32[] calldata operatorIds,
uint256 depositAmount,
address withdrawAddress
) external payable;
/**
* @dev Generates the exit data.
* @param clusterNodePublicKey The public key of the cluster node.
* @param validatorPubKeys The keys of the validators.
* @param activeEpoch The start epoch when exited.
*/
function generateExitData(
bytes calldata clusterNodePublicKey,
bytes[] calldata validatorPubKeys,
uint256 activeEpoch
) external payable;
/**
* @dev Returns the owner of the cluster node.
*/
function getActionFee(uint256 action) external view returns (uint256);
/**
* @dev Returns the owner of the cluster node.
* @param clusterNodePublicKey The public key of the cluster node.
*/
function getClusterNode( bytes calldata clusterNodePublicKey ) external view returns ( address owner, bool active );
}"
},
"contracts/ISafeStakeRegistryV3.sol": {
"content": "// File: contracts/ISafeStakeRegistry.sol
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.2;
interface ISafeStakeRegistryV3 {
event OperatorRemoval(uint32 operatorId, address indexed ownerAddress);
event OperatorVerified(address owner, bool fromDao, bool verified);
/**
* @dev Initializes the contract
* operatorFee and ownerAddress are setup in contract initialization. OwnerAddress has no way to update.
*/
function initialize(uint256 operatorFee, address owner) external;
/**
* @dev Registers a new operator.
* @param name Operator's display name.
* @param ownerAddress Operator's ethereum address that can collect fees.
* @param publicKey Operator's public key. Will be used to encrypt secret shares of validators keys.
*/
function registerOperator(string calldata name, address ownerAddress, bytes calldata publicKey) external returns (uint32);
/**
* @dev removes an operator.
* @param operatorId Operator id.
*/
function removeOperator(uint32 operatorId) external;
function verifyOperator(address owner, bool fromDao, bool verifed ) external;
/**
* @dev Updates an operator fee. Only system administrator can call this function to modify opeartor's fee.
* @param fee New operator fee.
*/
function updateOperatorFee(
uint64 fee
) external;
/**
* @dev Registers a new validator.
* @param ownerAddress The user's ethereum address that is the owner of the validator.
* @param publicKey Validator public key.
* @param operatorIds Operator ids.
* @param sharesPublicKeys Shares public keys.
* @param sharesEncrypted Encrypted private keys.
*/
function registerValidator(
address ownerAddress,
bytes calldata publicKey,
uint32[] calldata operatorIds,
bytes[] calldata sharesPublicKeys,
bytes[] calldata sharesEncrypted
) external;
/**
* @dev removes a validator.
* @param publicKey Validator's public key.
*/
function removeValidator(bytes calldata publicKey) external;
/**
* @dev enable validators that owned by the address. Only safestake network contract can call the function.
* @param ownerAddress owner address
*/
function enableOwnerValidators(address ownerAddress) external;
/**
* @dev disable validators that owned by the address. Only safestake network contract can call the function.
* @param ownerAddress owner address
*/
function disableOwnerValidators(address ownerAddress) external;
function isAccountRegisteredOperator(address ownerAddress) external returns(bool);
function isAccountRegisteredValidator(address ownerAddress) external returns(bool);
function isValidatorOwner(address owner, bytes calldata publicKey ) external returns(bool);
function _operatorFee() external view returns (uint256);
function checkOperatorsLength(uint256 len) external pure returns (bool);
function operator_detail(uint32 operatorId) external view returns (address owner, bool active);
function validatorOf(bytes calldata pubkey) external view returns(
address ownerAddress,
uint32[] memory operatorsIds,
uint32 indexInOwner,
bytes memory publicKey
);
function ownerOf(address ownerAddress) external view returns(
uint32 activeValidatorCount,
bool validatorsDisabled,
bytes[] memory validators
);
}"
},
"contracts/SafeStakeAccessControl.sol": {
"content": "// File: contracts/SafeStakeAccessControl.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
contract SafeStakeAccessControl is Initializable {
struct RoleData {
mapping(address => bool) members;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant ADMIN_ROLE = keccak256("A");
// bytes32 public constant UPGRADE_ROLE = keccak256("CONTRACT_UPGRADE_ROLE");
bytes32 public constant NODE_ROLE = keccak256("B");
bytes32 public constant SIGNER_ROLE = keccak256("C"); // replace owner address.
modifier onlyRole(bytes32 role) {
checkRole(role);
_;
}
function __Ownable_init() internal onlyInitializing {
address owner = _msgSender();
_roles[ADMIN_ROLE].members[owner] = true;
_roles[NODE_ROLE].members[owner] = true;
_roles[SIGNER_ROLE].members[owner] = true;
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function transferOwnership(
bytes32 role,
address newOwner
) public onlyRole(role) {
require(
newOwner != address(0)
);
_roles[role].members[_msgSender()] = false;
_roles[role].members[newOwner] = true;
}
function hasRole(bytes32 role, address account) public view returns (bool) {
return _roles[role].members[account];
}
function checkRole(bytes32 role) public view virtual {
require(hasRole(role, _msgSender()),"X0");
}
function grantRole(bytes32 role, address account) public virtual {
require(hasRole(ADMIN_ROLE, _msgSender()),"X1");
_roles[role].members[account] = true;
}
function revokeRole(bytes32 role, address account) public virtual {
require(hasRole(ADMIN_ROLE, _msgSender()),"X2");
_roles[role].members[account] = false;
}
}
"
},
"contracts/SafeStakeClusterNode.sol": {
"content": "// File: contracts/SafeStakeValidatorNode.sol
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >0.5.0 <0.9.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./ISafeStakeClusterNode.sol";
import "./SafeStakeAccessControl.sol";
import "./ISafeStakeRegistryV3.sol";
contract SafeStakeClusterNode is ISafeStakeClusterNode, SafeStakeAccessControl {
struct ClusterNodeData {
address owner;
bytes clusterNodePublicKey;
bool active;
}
enum Action {
GENERATE_KEYS,
GENERATE_DEPOSIT_DATA,
GENERATE_EXIT_DATA
}
mapping(bytes => ClusterNodeData) public _clusterNodes;
mapping(Action => uint256) public _actionFees;
address public _token;
ISafeStakeRegistryV3 _registry;
modifier check_cluster(bytes memory clusterNodePublicKey) {
// require(
// _clusterNodes[clusterNodePublicKey].owner == msg.sender,
// "Not the owner of the cluster node"
// );
require(
_clusterNodes[clusterNodePublicKey].active == true,
"Cluster node not active."
);
_;
}
function initialize( address token, ISafeStakeRegistryV3 registry) external initializer {
_token = token;
_registry = registry;
__Ownable_init();
}
function setActionFees(
Action[] memory action,
uint256[] memory fee )
external onlyRole(ADMIN_ROLE){
for (uint i = 0; i < action.length; i++) {
_actionFees[action[i]] = fee[i];
}
}
function checkSecurityLevel(
uint32[] memory operatorIds
) public pure returns (bool) {
uint256 len = operatorIds.length;
return len ==4 || len == 7 ;
}
function registerClusterNode(
bytes memory clusterNodePublicKey
) public {
require(
_clusterNodes[clusterNodePublicKey].active == false,
"Cluster node already active"
);
_clusterNodes[clusterNodePublicKey] = ClusterNodeData({
owner: msg.sender,
clusterNodePublicKey: clusterNodePublicKey,
active: true
});
emit ClusterNodeRegistration(
msg.sender,
clusterNodePublicKey
);
}
function generateDepositData(
bytes memory clusterNodePublicKey,
address owner,
bytes memory ownerPubkey,
uint256 validatorCount,
uint32[] memory operatorIds,
uint256 depositAmount,
address withdrawAddress
) public check_cluster(clusterNodePublicKey) payable{
require(
checkSecurityLevel(operatorIds) == true,
"Invalid operatorIds"
);
for(uint i = 0; i < operatorIds.length; i++){
(, bool active) = _registry.operator_detail(operatorIds[i]);
require(active == true, "Operator not found");
}
_executeAction(Action.GENERATE_DEPOSIT_DATA, validatorCount, operatorIds);
emit ValidatorDepositDataGeneration(
clusterNodePublicKey,
owner,
ownerPubkey,
validatorCount,
operatorIds,
depositAmount,
withdrawAddress
);
}
function generateExitData(
bytes memory clusterNodePublicKey,
bytes[] memory validatorPubKeys,
uint256 activeEpoch
) public check_cluster(clusterNodePublicKey) payable {
for(uint i = 0; i < validatorPubKeys.length; i++){
(address owner, , , ) = _registry.validatorOf(validatorPubKeys[i]);
require(owner == msg.sender, "Not the owner of the validator");
}
emit ValidatorExitDataGeneration(
clusterNodePublicKey,
msg.sender,
validatorPubKeys,
activeEpoch
);
}
function _deposit(address sender, uint256 tokenAmount) private {
require(tokenAmount > 0, "D1");
if( _token == address(0)){
require(msg.value == tokenAmount, "D0");
} else {
require(IERC20(_token).transferFrom(sender, address(this), tokenAmount), "D2");
}
}
function _executeAction(Action action, uint256 count, uint32[] memory operatorIds) internal {
uint256 all_fee = _actionFees[action] * count ;
_deposit(msg.sender, all_fee);
uint256 operator_fee = all_fee / operatorIds.length;
for(uint i = 0; i < operatorIds.length; i++){
(address owner, bool active) = _registry.operator_detail(operatorIds[i]);
if ( active ) {
if( _token == address(0)){
bool success = payable(owner).send(operator_fee);
require(success, "E3");
} else {
require( IERC20(_token).transfer(owner, operator_fee ) , "Transfer failed");
}
}
}
}
function getActionFee(uint256 action) public view returns (uint256) {
return _actionFees[Action(action)];
}
function getClusterNode(bytes memory clusterNodePublicKey)
public
view
returns (address owner, bool active)
{
ClusterNodeData memory clusterNode = _clusterNodes[clusterNodePublicKey];
return (clusterNode.owner, clusterNode.active);
}
function bytesToAddress(bytes memory _b) public pure returns (address addr) {
require(_b.length == 20, "BytesToAddress: Incorrect length");
assembly {
let word := mload(add(_b, 0x20))
addr := shr(96, word) // Shift Right by 96 bits
}
}
function modifyFeeToken(
address token
) external onlyRole(ADMIN_ROLE) {
_token = token;
}
receive() external payable {}
function version() external pure returns (uint32) {
return 10005;
}
uint256[50] ______gap;
}
"
}
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 800
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}
}}
Submitted on: 2025-09-30 16:15:30
Comments
Log in to comment.
No comments yet.