Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"contracts/ShukaGovernance.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "./ValidatorNetwork.sol";
/**
* @title ShukaGovernance
* @dev Decentralized governance for Shuka protocol decisions
* @notice Enables community-driven protocol upgrades and parameter changes
*/
contract ShukaGovernance {
// Proposal types
enum ProposalType {
PARAMETER_CHANGE,
CONTRACT_UPGRADE,
VALIDATOR_ADDITION,
VALIDATOR_REMOVAL,
FEE_ADJUSTMENT,
EMERGENCY_ACTION
}
// Proposal status
enum ProposalStatus {
PENDING,
ACTIVE,
CANCELLED,
DEFEATED,
SUCCEEDED,
QUEUED,
EXPIRED,
EXECUTED
}
// Proposal structure
struct Proposal {
uint256 id;
address proposer;
ProposalType proposalType;
string description;
address[] targets;
uint256[] values;
bytes[] calldatas;
uint256 startBlock;
uint256 endBlock;
uint256 forVotes;
uint256 againstVotes;
uint256 abstainVotes;
ProposalStatus status;
mapping(address => Receipt) receipts;
uint256 eta; // Execution time for timelock
bool executed;
}
// Voting receipt
struct Receipt {
bool hasVoted;
uint8 support; // 0 = Against, 1 = For, 2 = Abstain
uint256 votes;
}
// Constants
uint256 public constant VOTING_PERIOD = 3 days;
uint256 public constant VOTING_DELAY = 1 days;
uint256 public constant PROPOSAL_THRESHOLD = 0.01 ether; // Min stake to propose
uint256 public constant QUORUM_PERCENTAGE = 4; // 4% of total stake
uint256 public constant TIMELOCK_DELAY = 2 days;
// State variables
address public admin;
address public validatorNetworkAddress;
address public trustOracleAddress;
address public licenseAnchorAddress;
uint256 public proposalCount;
mapping(uint256 => Proposal) public proposals;
mapping(address => uint256) public latestProposalIds;
// Governance token (voting power from validator stakes)
mapping(address => uint256) public votingPower;
uint256 public totalVotingPower;
// Timelock
mapping(bytes32 => bool) public queuedTransactions;
// Events
event ProposalCreated(
uint256 id,
address proposer,
address[] targets,
uint256[] values,
string[] signatures,
bytes[] calldatas,
uint256 startBlock,
uint256 endBlock,
string description
);
event VoteCast(
address indexed voter,
uint256 proposalId,
uint8 support,
uint256 votes,
string reason
);
event ProposalCanceled(uint256 id);
event ProposalQueued(uint256 id, uint256 eta);
event ProposalExecuted(uint256 id);
event VotingPowerUpdated(address indexed account, uint256 oldPower, uint256 newPower);
// Modifiers
modifier onlyAdmin() {
require(msg.sender == admin, "Only admin");
_;
}
modifier onlyValidatorNetwork() {
require(msg.sender == validatorNetworkAddress, "Only validator network");
_;
}
constructor(
address _validatorNetwork,
address _trustOracle,
address _licenseAnchor
) {
admin = msg.sender;
validatorNetworkAddress = _validatorNetwork;
trustOracleAddress = _trustOracle;
licenseAnchorAddress = _licenseAnchor;
}
/**
* @dev Update voting power based on validator stakes
* @param _voter Address of the voter
* @param _newPower New voting power
*/
function updateVotingPower(address _voter, uint256 _newPower) external onlyValidatorNetwork {
uint256 oldPower = votingPower[_voter];
votingPower[_voter] = _newPower;
totalVotingPower = totalVotingPower - oldPower + _newPower;
emit VotingPowerUpdated(_voter, oldPower, _newPower);
}
/**
* @dev Create a new proposal
* @param _targets Target addresses for calls
* @param _values ETH values for calls
* @param _calldatas Encoded function calls
* @param _description Proposal description
*/
function propose(
address[] memory _targets,
uint256[] memory _values,
bytes[] memory _calldatas,
string memory _description,
ProposalType _proposalType
) external returns (uint256) {
require(
votingPower[msg.sender] >= PROPOSAL_THRESHOLD,
"Below proposal threshold"
);
require(
_targets.length == _values.length && _targets.length == _calldatas.length,
"Proposal function mismatch"
);
require(_targets.length > 0, "Must provide actions");
uint256 proposalId = ++proposalCount;
Proposal storage newProposal = proposals[proposalId];
newProposal.id = proposalId;
newProposal.proposer = msg.sender;
newProposal.proposalType = _proposalType;
newProposal.description = _description;
newProposal.targets = _targets;
newProposal.values = _values;
newProposal.calldatas = _calldatas;
newProposal.startBlock = block.number + VOTING_DELAY;
newProposal.endBlock = newProposal.startBlock + VOTING_PERIOD;
newProposal.status = ProposalStatus.PENDING;
latestProposalIds[msg.sender] = proposalId;
emit ProposalCreated(
proposalId,
msg.sender,
_targets,
_values,
new string[](_targets.length), // Signatures not used in this version
_calldatas,
newProposal.startBlock,
newProposal.endBlock,
_description
);
return proposalId;
}
/**
* @dev Cast a vote on a proposal
* @param _proposalId ID of the proposal
* @param _support Vote type (0=Against, 1=For, 2=Abstain)
*/
function castVote(uint256 _proposalId, uint8 _support) external {
return _castVote(msg.sender, _proposalId, _support, "");
}
/**
* @dev Cast a vote with reason
* @param _proposalId ID of the proposal
* @param _support Vote type
* @param _reason Reason for vote
*/
function castVoteWithReason(
uint256 _proposalId,
uint8 _support,
string calldata _reason
) external {
return _castVote(msg.sender, _proposalId, _support, _reason);
}
/**
* @dev Internal function to cast a vote
*/
function _castVote(
address _voter,
uint256 _proposalId,
uint8 _support,
string memory _reason
) internal {
require(state(_proposalId) == ProposalStatus.ACTIVE, "Voting closed");
require(_support <= 2, "Invalid vote type");
Proposal storage proposal = proposals[_proposalId];
Receipt storage receipt = proposal.receipts[_voter];
require(!receipt.hasVoted, "Already voted");
uint256 votes = votingPower[_voter];
require(votes > 0, "No voting power");
if (_support == 0) {
proposal.againstVotes += votes;
} else if (_support == 1) {
proposal.forVotes += votes;
} else {
proposal.abstainVotes += votes;
}
receipt.hasVoted = true;
receipt.support = _support;
receipt.votes = votes;
emit VoteCast(_voter, _proposalId, _support, votes, _reason);
}
/**
* @dev Get the state of a proposal
* @param _proposalId ID of the proposal
*/
function state(uint256 _proposalId) public view returns (ProposalStatus) {
Proposal storage proposal = proposals[_proposalId];
if (proposal.executed) {
return ProposalStatus.EXECUTED;
}
if (proposal.status == ProposalStatus.CANCELLED) {
return ProposalStatus.CANCELLED;
}
if (block.number <= proposal.startBlock) {
return ProposalStatus.PENDING;
}
if (block.number <= proposal.endBlock) {
return ProposalStatus.ACTIVE;
}
if (proposal.forVotes <= proposal.againstVotes ||
proposal.forVotes < quorumVotes()) {
return ProposalStatus.DEFEATED;
}
if (proposal.eta == 0) {
return ProposalStatus.SUCCEEDED;
}
if (block.timestamp >= proposal.eta + TIMELOCK_DELAY) {
return ProposalStatus.EXPIRED;
}
return ProposalStatus.QUEUED;
}
/**
* @dev Queue a successful proposal for execution
* @param _proposalId ID of the proposal
*/
function queue(uint256 _proposalId) external {
require(state(_proposalId) == ProposalStatus.SUCCEEDED, "Proposal not succeeded");
Proposal storage proposal = proposals[_proposalId];
uint256 eta = block.timestamp + TIMELOCK_DELAY;
for (uint256 i = 0; i < proposal.targets.length; i++) {
bytes32 txHash = keccak256(
abi.encode(
proposal.targets[i],
proposal.values[i],
proposal.calldatas[i],
eta
)
);
queuedTransactions[txHash] = true;
}
proposal.eta = eta;
emit ProposalQueued(_proposalId, eta);
}
/**
* @dev Execute a queued proposal
* @param _proposalId ID of the proposal
*/
function execute(uint256 _proposalId) external payable {
require(state(_proposalId) == ProposalStatus.QUEUED, "Proposal not queued");
Proposal storage proposal = proposals[_proposalId];
require(block.timestamp >= proposal.eta, "Still in timelock");
require(block.timestamp <= proposal.eta + TIMELOCK_DELAY, "Execution window expired");
proposal.executed = true;
for (uint256 i = 0; i < proposal.targets.length; i++) {
bytes32 txHash = keccak256(
abi.encode(
proposal.targets[i],
proposal.values[i],
proposal.calldatas[i],
proposal.eta
)
);
require(queuedTransactions[txHash], "Transaction not queued");
queuedTransactions[txHash] = false;
(bool success,) = proposal.targets[i].call{value: proposal.values[i]}(
proposal.calldatas[i]
);
require(success, "Transaction execution failed");
}
emit ProposalExecuted(_proposalId);
}
/**
* @dev Cancel a proposal
* @param _proposalId ID of the proposal
*/
function cancel(uint256 _proposalId) external {
Proposal storage proposal = proposals[_proposalId];
require(
msg.sender == proposal.proposer || msg.sender == admin,
"Cannot cancel"
);
require(
state(_proposalId) != ProposalStatus.EXECUTED,
"Cannot cancel executed proposal"
);
proposal.status = ProposalStatus.CANCELLED;
// Clear timelock if queued
if (proposal.eta != 0) {
for (uint256 i = 0; i < proposal.targets.length; i++) {
bytes32 txHash = keccak256(
abi.encode(
proposal.targets[i],
proposal.values[i],
proposal.calldatas[i],
proposal.eta
)
);
queuedTransactions[txHash] = false;
}
}
emit ProposalCanceled(_proposalId);
}
/**
* @dev Get the required quorum votes
*/
function quorumVotes() public view returns (uint256) {
return (totalVotingPower * QUORUM_PERCENTAGE) / 100;
}
/**
* @dev Get proposal details
* @param _proposalId ID of the proposal
*/
function getProposal(uint256 _proposalId) external view returns (
address proposer,
string memory description,
uint256 forVotes,
uint256 againstVotes,
uint256 abstainVotes,
uint256 startBlock,
uint256 endBlock,
ProposalStatus status
) {
Proposal storage proposal = proposals[_proposalId];
return (
proposal.proposer,
proposal.description,
proposal.forVotes,
proposal.againstVotes,
proposal.abstainVotes,
proposal.startBlock,
proposal.endBlock,
state(_proposalId)
);
}
/**
* @dev Get actions of a proposal
* @param _proposalId ID of the proposal
*/
function getActions(uint256 _proposalId) external view returns (
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas
) {
Proposal storage proposal = proposals[_proposalId];
return (proposal.targets, proposal.values, proposal.calldatas);
}
/**
* @dev Get receipt of a voter for a proposal
* @param _proposalId ID of the proposal
* @param _voter Address of the voter
*/
function getReceipt(uint256 _proposalId, address _voter) external view returns (
bool hasVoted,
uint8 support,
uint256 votes
) {
Receipt memory receipt = proposals[_proposalId].receipts[_voter];
return (receipt.hasVoted, receipt.support, receipt.votes);
}
/**
* @dev Emergency function to update contract addresses
* @param _validatorNetwork New validator network address
* @param _trustOracle New trust oracle address
* @param _licenseAnchor New license anchor address
*/
function updateContractAddresses(
address _validatorNetwork,
address _trustOracle,
address _licenseAnchor
) external onlyAdmin {
validatorNetworkAddress = _validatorNetwork;
trustOracleAddress = _trustOracle;
licenseAnchorAddress = _licenseAnchor;
}
/**
* @dev Sync voting power with validator network
*/
function syncVotingPower() external {
ValidatorNetwork validator = ValidatorNetwork(validatorNetworkAddress);
address[] memory validators = validator.getActiveValidators();
uint256 newTotalPower = 0;
for (uint256 i = 0; i < validators.length; i++) {
(,uint256 stakedAmount,,,,,,,,,,) = validator.validators(validators[i]);
votingPower[validators[i]] = stakedAmount;
newTotalPower += stakedAmount;
}
totalVotingPower = newTotalPower;
}
/**
* @dev Receive ETH for proposal execution
*/
receive() external payable {}
}"
},
"contracts/ValidatorNetwork.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
/**
* @title ValidatorNetwork
* @dev Decentralized validator network with Byzantine fault tolerance for Shuka
* @notice Implements multi-validator consensus for trust verification
*/
contract ValidatorNetwork {
// Validator states
enum ValidatorStatus { INACTIVE, ACTIVE, SUSPENDED, SLASHED }
// Consensus proposal states
enum ProposalStatus { PENDING, APPROVED, REJECTED, EXECUTED, EXPIRED }
// Validator information
struct Validator {
address validatorAddress;
uint256 stakedAmount;
uint256 reputationScore;
ValidatorStatus status;
uint256 totalValidations;
uint256 successfulValidations;
uint256 failedValidations;
uint256 lastActiveBlock;
uint256 slashingEvents;
bool isAIAgent;
string aiAgentId;
uint256 joinedAt;
}
// Consensus proposal for validation
struct ConsensusProposal {
uint256 proposalId;
address proposer;
bytes32 dataHash;
string proposalType;
bytes proposalData;
uint256 votesFor;
uint256 votesAgainst;
uint256 totalVotes;
mapping(address => bool) hasVoted;
mapping(address => bool) voteValue;
ProposalStatus status;
uint256 createdAt;
uint256 executedAt;
uint256 expiresAt;
}
// AI Agent validation record
struct AIValidation {
string agentId;
address agentWallet;
bytes32 validationHash;
uint256 confidence;
string validationType;
uint256 timestamp;
bool isValid;
}
// Constants for Byzantine fault tolerance
uint256 public constant MINIMUM_VALIDATORS = 3;
uint256 public constant BYZANTINE_THRESHOLD = 67; // 67% for Byzantine fault tolerance
uint256 public constant MINIMUM_STAKE = 0.01 ether;
uint256 public constant SLASHING_PENALTY = 10; // 10% of stake
uint256 public constant PROPOSAL_DURATION = 1 hours;
uint256 public constant VALIDATOR_TIMEOUT = 7 days;
// State variables
address public admin;
address public trustOracleAddress;
address public proofRegistryAddress;
mapping(address => Validator) public validators;
mapping(uint256 => ConsensusProposal) public proposals;
mapping(string => AIValidation[]) public aiValidations;
mapping(address => uint256) public pendingRewards;
mapping(bytes32 => bool) public processedValidations;
address[] public activeValidatorList;
uint256 public proposalCounter;
uint256 public totalStaked;
uint256 public totalValidations;
uint256 public rewardPool;
// Events
event ValidatorJoined(address indexed validator, uint256 stake, bool isAI);
event ValidatorExited(address indexed validator, uint256 returnedStake);
event ValidatorSlashed(address indexed validator, uint256 penalty, string reason);
event ProposalCreated(uint256 indexed proposalId, address proposer, string proposalType);
event VoteCast(uint256 indexed proposalId, address voter, bool support);
event ProposalExecuted(uint256 indexed proposalId, bool approved);
event ValidationRecorded(bytes32 validationHash, address validator, bool result);
event RewardDistributed(address indexed validator, uint256 amount);
event AIValidationRecorded(string agentId, bytes32 validationHash, uint256 confidence);
// Modifiers
modifier onlyAdmin() {
require(msg.sender == admin, "Only admin");
_;
}
modifier onlyActiveValidator() {
require(validators[msg.sender].status == ValidatorStatus.ACTIVE, "Not active validator");
_;
}
modifier validatorExists(address _validator) {
require(validators[_validator].validatorAddress != address(0), "Validator not found");
_;
}
constructor(address _trustOracle, address _proofRegistry) {
admin = msg.sender;
trustOracleAddress = _trustOracle;
proofRegistryAddress = _proofRegistry;
}
/**
* @dev Join as a validator by staking ETH
* @param _isAIAgent Whether this is an AI agent validator
* @param _aiAgentId ID of the AI agent (if applicable)
*/
function joinAsValidator(bool _isAIAgent, string memory _aiAgentId) external payable {
require(msg.value >= MINIMUM_STAKE, "Insufficient stake");
require(validators[msg.sender].validatorAddress == address(0), "Already a validator");
validators[msg.sender] = Validator({
validatorAddress: msg.sender,
stakedAmount: msg.value,
reputationScore: 100,
status: ValidatorStatus.ACTIVE,
totalValidations: 0,
successfulValidations: 0,
failedValidations: 0,
lastActiveBlock: block.number,
slashingEvents: 0,
isAIAgent: _isAIAgent,
aiAgentId: _aiAgentId,
joinedAt: block.timestamp
});
activeValidatorList.push(msg.sender);
totalStaked += msg.value;
emit ValidatorJoined(msg.sender, msg.value, _isAIAgent);
}
/**
* @dev Create a consensus proposal for validation
* @param _dataHash Hash of the data to validate
* @param _proposalType Type of proposal
* @param _proposalData Encoded proposal data
*/
function createConsensusProposal(
bytes32 _dataHash,
string memory _proposalType,
bytes memory _proposalData
) public onlyActiveValidator returns (uint256) {
require(!processedValidations[_dataHash], "Already processed");
uint256 proposalId = ++proposalCounter;
ConsensusProposal storage proposal = proposals[proposalId];
proposal.proposalId = proposalId;
proposal.proposer = msg.sender;
proposal.dataHash = _dataHash;
proposal.proposalType = _proposalType;
proposal.proposalData = _proposalData;
proposal.status = ProposalStatus.PENDING;
proposal.createdAt = block.timestamp;
proposal.expiresAt = block.timestamp + PROPOSAL_DURATION;
emit ProposalCreated(proposalId, msg.sender, _proposalType);
return proposalId;
}
/**
* @dev Vote on a consensus proposal
* @param _proposalId ID of the proposal
* @param _support Whether to support the proposal
*/
function voteOnProposal(uint256 _proposalId, bool _support) external onlyActiveValidator {
ConsensusProposal storage proposal = proposals[_proposalId];
require(proposal.status == ProposalStatus.PENDING, "Proposal not pending");
require(block.timestamp <= proposal.expiresAt, "Proposal expired");
require(!proposal.hasVoted[msg.sender], "Already voted");
proposal.hasVoted[msg.sender] = true;
proposal.voteValue[msg.sender] = _support;
proposal.totalVotes++;
// Weight vote by stake
uint256 voteWeight = validators[msg.sender].stakedAmount;
if (_support) {
proposal.votesFor += voteWeight;
} else {
proposal.votesAgainst += voteWeight;
}
emit VoteCast(_proposalId, msg.sender, _support);
// Check if we have enough votes to execute
_checkAndExecuteProposal(_proposalId);
}
/**
* @dev Check if proposal has reached consensus and execute
* @param _proposalId ID of the proposal
*/
function _checkAndExecuteProposal(uint256 _proposalId) internal {
ConsensusProposal storage proposal = proposals[_proposalId];
// Need participation from at least 2/3 of validators
uint256 requiredParticipation = (activeValidatorList.length * 2) / 3;
if (proposal.totalVotes < requiredParticipation && proposal.totalVotes < MINIMUM_VALIDATORS) {
return;
}
uint256 totalVoteWeight = proposal.votesFor + proposal.votesAgainst;
if (totalVoteWeight == 0) return;
uint256 approvalPercentage = (proposal.votesFor * 100) / totalVoteWeight;
if (approvalPercentage >= BYZANTINE_THRESHOLD) {
proposal.status = ProposalStatus.APPROVED;
proposal.executedAt = block.timestamp;
processedValidations[proposal.dataHash] = true;
// Reward validators who voted correctly
_distributeRewards(_proposalId, true);
// Execute proposal action
_executeProposalAction(proposal);
emit ProposalExecuted(_proposalId, true);
} else if (approvalPercentage < (100 - BYZANTINE_THRESHOLD)) {
proposal.status = ProposalStatus.REJECTED;
proposal.executedAt = block.timestamp;
// Punish validators who voted incorrectly
_distributeRewards(_proposalId, false);
emit ProposalExecuted(_proposalId, false);
}
}
/**
* @dev Execute the action specified in an approved proposal
* @param proposal The approved proposal
*/
function _executeProposalAction(ConsensusProposal storage proposal) internal {
// Decode and execute based on proposal type
if (keccak256(bytes(proposal.proposalType)) == keccak256("TRUST_UPDATE")) {
// Call TrustOracle to update trust score
(bool success,) = trustOracleAddress.call(proposal.proposalData);
require(success, "Trust update failed");
} else if (keccak256(bytes(proposal.proposalType)) == keccak256("PROOF_VALIDATION")) {
// Call ProofRegistry to validate proof
(bool success,) = proofRegistryAddress.call(proposal.proposalData);
require(success, "Proof validation failed");
}
emit ValidationRecorded(proposal.dataHash, proposal.proposer, true);
}
/**
* @dev Distribute rewards to validators based on voting outcome
* @param _proposalId ID of the proposal
* @param _approvedOutcome Whether the proposal was approved
*/
function _distributeRewards(uint256 _proposalId, bool _approvedOutcome) internal {
ConsensusProposal storage proposal = proposals[_proposalId];
uint256 rewardPerValidator = rewardPool / (proposal.totalVotes > 0 ? proposal.totalVotes : 1);
for (uint256 i = 0; i < activeValidatorList.length; i++) {
address validator = activeValidatorList[i];
if (proposal.hasVoted[validator]) {
bool votedCorrectly = proposal.voteValue[validator] == _approvedOutcome;
if (votedCorrectly) {
// Reward for correct vote
pendingRewards[validator] += rewardPerValidator;
validators[validator].successfulValidations++;
validators[validator].reputationScore = min(100, validators[validator].reputationScore + 1);
emit RewardDistributed(validator, rewardPerValidator);
} else {
// Penalty for incorrect vote
validators[validator].failedValidations++;
validators[validator].reputationScore = validators[validator].reputationScore > 5 ?
validators[validator].reputationScore - 5 : 0;
// Slash if reputation too low
if (validators[validator].reputationScore < 20) {
_slashValidator(validator, "Low reputation");
}
}
validators[validator].totalValidations++;
}
}
}
/**
* @dev Record validation from an AI agent
* @param _agentId ID of the AI agent
* @param _validationHash Hash of the validation
* @param _confidence Confidence level (0-100)
* @param _validationType Type of validation
*/
function recordAIValidation(
string memory _agentId,
bytes32 _validationHash,
uint256 _confidence,
string memory _validationType
) external onlyActiveValidator {
require(validators[msg.sender].isAIAgent, "Not an AI validator");
require(_confidence <= 100, "Invalid confidence");
AIValidation memory validation = AIValidation({
agentId: _agentId,
agentWallet: msg.sender,
validationHash: _validationHash,
confidence: _confidence,
validationType: _validationType,
timestamp: block.timestamp,
isValid: true
});
aiValidations[_agentId].push(validation);
// Update validator activity
validators[msg.sender].lastActiveBlock = block.number;
validators[msg.sender].totalValidations++;
emit AIValidationRecorded(_agentId, _validationHash, _confidence);
// If confidence is high enough, auto-create proposal
if (_confidence >= 80) {
bytes memory proposalData = abi.encode(msg.sender, _validationHash, _confidence);
createConsensusProposal(_validationHash, _validationType, proposalData);
}
}
/**
* @dev Slash a validator for misbehavior
* @param _validator Address of the validator to slash
* @param _reason Reason for slashing
*/
function _slashValidator(address _validator, string memory _reason) internal {
Validator storage validator = validators[_validator];
uint256 penalty = (validator.stakedAmount * SLASHING_PENALTY) / 100;
validator.stakedAmount -= penalty;
validator.slashingEvents++;
rewardPool += penalty;
if (validator.slashingEvents >= 3 || validator.stakedAmount < MINIMUM_STAKE) {
validator.status = ValidatorStatus.SLASHED;
_removeFromActiveList(_validator);
} else {
validator.status = ValidatorStatus.SUSPENDED;
}
emit ValidatorSlashed(_validator, penalty, _reason);
}
/**
* @dev Exit as a validator and withdraw stake
*/
function exitAsValidator() external validatorExists(msg.sender) {
Validator storage validator = validators[msg.sender];
require(validator.status != ValidatorStatus.SLASHED, "Validator is slashed");
uint256 stakeToReturn = validator.stakedAmount;
uint256 rewards = pendingRewards[msg.sender];
uint256 totalReturn = stakeToReturn + rewards;
validator.status = ValidatorStatus.INACTIVE;
validator.stakedAmount = 0;
pendingRewards[msg.sender] = 0;
totalStaked -= stakeToReturn;
_removeFromActiveList(msg.sender);
(bool success,) = msg.sender.call{value: totalReturn}("");
require(success, "Transfer failed");
emit ValidatorExited(msg.sender, totalReturn);
}
/**
* @dev Claim pending rewards
*/
function claimRewards() external {
uint256 rewards = pendingRewards[msg.sender];
require(rewards > 0, "No rewards");
pendingRewards[msg.sender] = 0;
(bool success,) = msg.sender.call{value: rewards}("");
require(success, "Transfer failed");
emit RewardDistributed(msg.sender, rewards);
}
/**
* @dev Check validator health and slash inactive ones
*/
function checkValidatorHealth() external {
for (uint256 i = 0; i < activeValidatorList.length; i++) {
address validator = activeValidatorList[i];
Validator storage v = validators[validator];
if (block.number - v.lastActiveBlock > VALIDATOR_TIMEOUT) {
_slashValidator(validator, "Inactivity");
}
}
}
/**
* @dev Remove validator from active list
* @param _validator Address to remove
*/
function _removeFromActiveList(address _validator) internal {
for (uint256 i = 0; i < activeValidatorList.length; i++) {
if (activeValidatorList[i] == _validator) {
activeValidatorList[i] = activeValidatorList[activeValidatorList.length - 1];
activeValidatorList.pop();
break;
}
}
}
/**
* @dev Get active validator count
*/
function getActiveValidatorCount() external view returns (uint256) {
return activeValidatorList.length;
}
/**
* @dev Get all active validators
*/
function getActiveValidators() external view returns (address[] memory) {
return activeValidatorList;
}
/**
* @dev Check if consensus is possible
*/
function isConsensusReady() external view returns (bool) {
return activeValidatorList.length >= MINIMUM_VALIDATORS;
}
/**
* @dev Get validator details
*/
function getValidatorDetails(address _validator) external view returns (Validator memory) {
return validators[_validator];
}
/**
* @dev Fund reward pool
*/
function fundRewardPool() external payable {
rewardPool += msg.value;
}
/**
* @dev Update contract addresses
*/
function updateContractAddresses(address _trustOracle, address _proofRegistry) external onlyAdmin {
trustOracleAddress = _trustOracle;
proofRegistryAddress = _proofRegistry;
}
/**
* @dev Min function
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Batch validator operations for gas optimization
* @param _validators Array of validator addresses
* @param _actions Array of actions (0=suspend, 1=reactivate, 2=slash)
*/
function batchValidatorOperations(
address[] memory _validators,
uint256[] memory _actions
) external onlyAdmin {
require(_validators.length == _actions.length, "Array mismatch");
for (uint256 i = 0; i < _validators.length; i++) {
Validator storage v = validators[_validators[i]];
if (v.validatorAddress == address(0)) continue;
if (_actions[i] == 0) {
v.status = ValidatorStatus.SUSPENDED;
} else if (_actions[i] == 1 && v.status == ValidatorStatus.SUSPENDED) {
v.status = ValidatorStatus.ACTIVE;
} else if (_actions[i] == 2) {
_slashValidator(_validators[i], "Admin action");
}
}
}
/**
* @dev Emergency pause for critical situations
*/
bool public emergencyPause;
modifier notPaused() {
require(!emergencyPause, "Contract paused");
_;
}
function toggleEmergencyPause() external onlyAdmin {
emergencyPause = !emergencyPause;
}
/**
* @dev Get proposal status
*/
function getProposalStatus(uint256 _proposalId) external view returns (ProposalStatus) {
return proposals[_proposalId].status;
}
}"
}
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
},
"viaIR": true,
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}
}}
Submitted on: 2025-09-28 16:02:45
Comments
Log in to comment.
No comments yet.