文件 1 的 9:Helpers.sol
pragma solidity 0.7.6;
pragma abicoder v2;
function getChainId() pure returns (uint256) {
uint256 chainId;
assembly {
chainId := chainid()
}
return chainId;
}
function isContract(address account) view returns (bool) {
bytes32 codehash;
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
assembly {
codehash := extcodehash(account)
}
return (codehash != accountHash && codehash != 0x0);
}
文件 2 的 9:IExecutorWithTimelock.sol
pragma solidity 0.7.6;
pragma abicoder v2;
import {IKyberGovernance} from './IKyberGovernance.sol';
interface IExecutorWithTimelock {
event NewPendingAdmin(address newPendingAdmin);
event NewAdmin(address newAdmin);
event NewDelay(uint256 delay);
event QueuedAction(
bytes32 actionHash,
address indexed target,
uint256 value,
string signature,
bytes data,
uint256 executionTime,
bool withDelegatecall
);
event CancelledAction(
bytes32 actionHash,
address indexed target,
uint256 value,
string signature,
bytes data,
uint256 executionTime,
bool withDelegatecall
);
event ExecutedAction(
bytes32 actionHash,
address indexed target,
uint256 value,
string signature,
bytes data,
uint256 executionTime,
bool withDelegatecall,
bytes resultData
);
function queueTransaction(
address target,
uint256 value,
string memory signature,
bytes memory data,
uint256 executionTime,
bool withDelegatecall
) external returns (bytes32);
function executeTransaction(
address target,
uint256 value,
string memory signature,
bytes memory data,
uint256 executionTime,
bool withDelegatecall
) external payable returns (bytes memory);
function cancelTransaction(
address target,
uint256 value,
string memory signature,
bytes memory data,
uint256 executionTime,
bool withDelegatecall
) external returns (bytes32);
function getAdmin() external view returns (address);
function getPendingAdmin() external view returns (address);
function getDelay() external view returns (uint256);
function isActionQueued(bytes32 actionHash) external view returns (bool);
function isProposalOverGracePeriod(IKyberGovernance governance, uint256 proposalId)
external
view
returns (bool);
function GRACE_PERIOD() external view returns (uint256);
function MINIMUM_DELAY() external view returns (uint256);
function MAXIMUM_DELAY() external view returns (uint256);
}
文件 3 的 9:IKyberGovernance.sol
pragma solidity 0.7.6;
pragma abicoder v2;
import {IExecutorWithTimelock} from './IExecutorWithTimelock.sol';
import {IVotingPowerStrategy} from './IVotingPowerStrategy.sol';
interface IKyberGovernance {
enum ProposalState {
Pending,
Canceled,
Active,
Failed,
Succeeded,
Queued,
Expired,
Executed,
Finalized
}
enum ProposalType {Generic, Binary}
struct Vote {
uint32 optionBitMask;
uint224 votingPower;
}
struct ProposalWithoutVote {
uint256 id;
ProposalType proposalType;
address creator;
IExecutorWithTimelock executor;
IVotingPowerStrategy strategy;
address[] targets;
uint256[] weiValues;
string[] signatures;
bytes[] calldatas;
bool[] withDelegatecalls;
string[] options;
uint256[] voteCounts;
uint256 totalVotes;
uint256 maxVotingPower;
uint256 startTime;
uint256 endTime;
uint256 executionTime;
string link;
bool executed;
bool canceled;
}
struct Proposal {
ProposalWithoutVote proposalData;
mapping(address => Vote) votes;
}
struct BinaryProposalParams {
address[] targets;
uint256[] weiValues;
string[] signatures;
bytes[] calldatas;
bool[] withDelegatecalls;
}
event BinaryProposalCreated(
uint256 proposalId,
address indexed creator,
IExecutorWithTimelock indexed executor,
IVotingPowerStrategy indexed strategy,
address[] targets,
uint256[] weiValues,
string[] signatures,
bytes[] calldatas,
bool[] withDelegatecalls,
uint256 startTime,
uint256 endTime,
string link,
uint256 maxVotingPower
);
event GenericProposalCreated(
uint256 proposalId,
address indexed creator,
IExecutorWithTimelock indexed executor,
IVotingPowerStrategy indexed strategy,
string[] options,
uint256 startTime,
uint256 endTime,
string link,
uint256 maxVotingPower
);
event ProposalCanceled(uint256 proposalId);
event ProposalQueued(
uint256 indexed proposalId,
uint256 executionTime,
address indexed initiatorQueueing
);
event ProposalExecuted(uint256 proposalId, address indexed initiatorExecution);
event VoteEmitted(
uint256 indexed proposalId,
address indexed voter,
uint32 indexed voteOptions,
uint224 votingPower
);
event VotingPowerChanged(
uint256 indexed proposalId,
address indexed voter,
uint32 indexed voteOptions,
uint224 oldVotingPower,
uint224 newVotingPower
);
event DaoOperatorTransferred(address indexed newDaoOperator);
event ExecutorAuthorized(address indexed executor);
event ExecutorUnauthorized(address indexed executor);
event VotingPowerStrategyAuthorized(address indexed strategy);
event VotingPowerStrategyUnauthorized(address indexed strategy);
function handleVotingPowerChanged(
address staker,
uint256 newVotingPower,
uint256[] calldata proposalIds
) external;
function createBinaryProposal(
IExecutorWithTimelock executor,
IVotingPowerStrategy strategy,
BinaryProposalParams memory executionParams,
uint256 startTime,
uint256 endTime,
string memory link
) external returns (uint256 proposalId);
function createGenericProposal(
IExecutorWithTimelock executor,
IVotingPowerStrategy strategy,
string[] memory options,
uint256 startTime,
uint256 endTime,
string memory link
) external returns (uint256 proposalId);
function cancel(uint256 proposalId) external;
function queue(uint256 proposalId) external;
function execute(uint256 proposalId) external payable;
function submitVote(uint256 proposalId, uint256 optionBitMask) external;
function submitVoteBySignature(
uint256 proposalId,
uint256 choice,
uint8 v,
bytes32 r,
bytes32 s
) external;
function authorizeExecutors(address[] calldata executors) external;
function unauthorizeExecutors(address[] calldata executors) external;
function authorizeVotingPowerStrategies(address[] calldata strategies) external;
function unauthorizeVotingPowerStrategies(address[] calldata strategies) external;
function isExecutorAuthorized(address executor) external view returns (bool);
function isVotingPowerStrategyAuthorized(address strategy) external view returns (bool);
function getDaoOperator() external view returns (address);
function getProposalsCount() external view returns (uint256);
function getProposalById(uint256 proposalId) external view returns (ProposalWithoutVote memory);
function getProposalVoteDataById(uint256 proposalId)
external
view
returns (
uint256,
uint256[] memory,
string[] memory
);
function getVoteOnProposal(uint256 proposalId, address voter)
external
view
returns (Vote memory);
function getProposalState(uint256 proposalId) external view returns (ProposalState);
}
文件 4 的 9:IProposalValidator.sol
pragma solidity 0.7.6;
pragma abicoder v2;
import {IKyberGovernance} from './IKyberGovernance.sol';
import {IVotingPowerStrategy} from './IVotingPowerStrategy.sol';
interface IProposalValidator {
function validateBinaryProposalCreation(
IVotingPowerStrategy strategy,
address creator,
uint256 startTime,
uint256 endTime,
address daoOperator
) external view returns (bool);
function validateGenericProposalCreation(
IVotingPowerStrategy strategy,
address creator,
uint256 startTime,
uint256 endTime,
string[] calldata options,
address daoOperator
) external view returns (bool);
function validateProposalCancellation(
IKyberGovernance governance,
uint256 proposalId,
address user
) external view returns (bool);
function isBinaryProposalPassed(IKyberGovernance governance, uint256 proposalId)
external
view
returns (bool);
function isQuorumValid(IKyberGovernance governance, uint256 proposalId)
external
view
returns (bool);
function isVoteDifferentialValid(IKyberGovernance governance, uint256 proposalId)
external
view
returns (bool);
function MAX_VOTING_OPTIONS() external view returns (uint256);
function MIN_VOTING_DURATION() external view returns (uint256);
function VOTE_DIFFERENTIAL() external view returns (uint256);
function MINIMUM_QUORUM() external view returns (uint256);
}
文件 5 的 9:IVotingPowerStrategy.sol
pragma solidity 0.7.6;
pragma abicoder v2;
import {IWithdrawHandler} from '../staking/IWithdrawHandler.sol';
interface IVotingPowerStrategy is IWithdrawHandler {
function handleProposalCreation(
uint256 proposalId,
uint256 startTime,
uint256 endTime
) external;
function handleProposalCancellation(uint256 proposalId) external;
function handleVote(
address voter,
uint256 proposalId,
uint256 choice
) external returns (uint256 votingPower);
function getVotingPower(address voter, uint256 timestamp)
external
view
returns (uint256 votingPower);
function validateProposalCreation(uint256 startTime, uint256 endTime)
external
view
returns (bool);
function getMaxVotingPower() external view returns (uint256);
}
文件 6 的 9:IWithdrawHandler.sol
pragma solidity 0.7.6;
pragma abicoder v2;
interface IWithdrawHandler {
function handleWithdrawal(address staker, uint256 reduceAmount) external;
}
文件 7 的 9:KyberGovernance.sol
pragma solidity 0.7.6;
pragma abicoder v2;
import {SafeMath} from '@openzeppelin/contracts/math/SafeMath.sol';
import {PermissionAdmin} from '@kyber.network/utils-sc/contracts/PermissionAdmin.sol';
import {IKyberGovernance} from '../interfaces/governance/IKyberGovernance.sol';
import {IExecutorWithTimelock} from '../interfaces/governance/IExecutorWithTimelock.sol';
import {IVotingPowerStrategy} from '../interfaces/governance/IVotingPowerStrategy.sol';
import {IProposalValidator} from '../interfaces/governance/IProposalValidator.sol';
import {getChainId} from '../misc/Helpers.sol';
contract KyberGovernance is IKyberGovernance, PermissionAdmin {
using SafeMath for uint256;
bytes32 public constant DOMAIN_TYPEHASH = keccak256(
'EIP712Domain(string name,uint256 chainId,address verifyingContract)'
);
bytes32 public constant VOTE_EMITTED_TYPEHASH = keccak256(
'VoteEmitted(uint256 id,uint256 optionBitMask)'
);
string public constant NAME = 'Kyber Governance';
address private _daoOperator;
uint256 private _proposalsCount;
mapping(uint256 => Proposal) private _proposals;
mapping(address => bool) private _authorizedExecutors;
mapping(address => bool) private _authorizedVotingPowerStrategies;
constructor(
address admin,
address daoOperator,
address[] memory executors,
address[] memory votingPowerStrategies
) PermissionAdmin(admin) {
require(daoOperator != address(0), 'invalid dao operator');
_daoOperator = daoOperator;
_authorizeExecutors(executors);
_authorizeVotingPowerStrategies(votingPowerStrategies);
}
function createBinaryProposal(
IExecutorWithTimelock executor,
IVotingPowerStrategy strategy,
BinaryProposalParams memory executionParams,
uint256 startTime,
uint256 endTime,
string memory link
) external override returns (uint256 proposalId) {
require(executionParams.targets.length != 0, 'create binary invalid empty targets');
require(
executionParams.targets.length == executionParams.weiValues.length &&
executionParams.targets.length == executionParams.signatures.length &&
executionParams.targets.length == executionParams.calldatas.length &&
executionParams.targets.length == executionParams.withDelegatecalls.length,
'create binary inconsistent params length'
);
require(isExecutorAuthorized(address(executor)), 'create binary executor not authorized');
require(
isVotingPowerStrategyAuthorized(address(strategy)),
'create binary strategy not authorized'
);
proposalId = _proposalsCount;
require(
IProposalValidator(address(executor)).validateBinaryProposalCreation(
strategy,
msg.sender,
startTime,
endTime,
_daoOperator
),
'validate proposal creation invalid'
);
ProposalWithoutVote storage newProposalData = _proposals[proposalId].proposalData;
newProposalData.id = proposalId;
newProposalData.proposalType = ProposalType.Binary;
newProposalData.creator = msg.sender;
newProposalData.executor = executor;
newProposalData.targets = executionParams.targets;
newProposalData.weiValues = executionParams.weiValues;
newProposalData.signatures = executionParams.signatures;
newProposalData.calldatas = executionParams.calldatas;
newProposalData.withDelegatecalls = executionParams.withDelegatecalls;
newProposalData.startTime = startTime;
newProposalData.endTime = endTime;
newProposalData.strategy = strategy;
newProposalData.link = link;
newProposalData.options.push('YES');
newProposalData.options.push('NO');
newProposalData.voteCounts.push(0);
newProposalData.voteCounts.push(0);
newProposalData.maxVotingPower = strategy.getMaxVotingPower();
_proposalsCount++;
strategy.handleProposalCreation(proposalId, startTime, endTime);
emit BinaryProposalCreated(
proposalId,
msg.sender,
executor,
strategy,
executionParams.targets,
executionParams.weiValues,
executionParams.signatures,
executionParams.calldatas,
executionParams.withDelegatecalls,
startTime,
endTime,
link,
newProposalData.maxVotingPower
);
}
function createGenericProposal(
IExecutorWithTimelock executor,
IVotingPowerStrategy strategy,
string[] memory options,
uint256 startTime,
uint256 endTime,
string memory link
)
external override returns (uint256 proposalId)
{
require(
isExecutorAuthorized(address(executor)),
'create generic executor not authorized'
);
require(
isVotingPowerStrategyAuthorized(address(strategy)),
'create generic strategy not authorized'
);
proposalId = _proposalsCount;
require(
IProposalValidator(address(executor)).validateGenericProposalCreation(
strategy,
msg.sender,
startTime,
endTime,
options,
_daoOperator
),
'validate proposal creation invalid'
);
Proposal storage newProposal = _proposals[proposalId];
ProposalWithoutVote storage newProposalData = newProposal.proposalData;
newProposalData.id = proposalId;
newProposalData.proposalType = ProposalType.Generic;
newProposalData.creator = msg.sender;
newProposalData.executor = executor;
newProposalData.startTime = startTime;
newProposalData.endTime = endTime;
newProposalData.strategy = strategy;
newProposalData.link = link;
newProposalData.options = options;
newProposalData.voteCounts = new uint256[](options.length);
newProposalData.maxVotingPower = strategy.getMaxVotingPower();
_proposalsCount++;
strategy.handleProposalCreation(proposalId, startTime, endTime);
emit GenericProposalCreated(
proposalId,
msg.sender,
executor,
strategy,
options,
startTime,
endTime,
link,
newProposalData.maxVotingPower
);
}
function cancel(uint256 proposalId) external override {
require(proposalId < _proposalsCount, 'invalid proposal id');
ProposalState state = getProposalState(proposalId);
require(
state != ProposalState.Executed &&
state != ProposalState.Canceled &&
state != ProposalState.Expired &&
state != ProposalState.Finalized,
'invalid state to cancel'
);
ProposalWithoutVote storage proposal = _proposals[proposalId].proposalData;
require(
msg.sender == _daoOperator ||
IProposalValidator(address(proposal.executor)).validateProposalCancellation(
IKyberGovernance(this),
proposalId,
proposal.creator
),
'validate proposal cancellation failed'
);
proposal.canceled = true;
if (proposal.proposalType == ProposalType.Binary) {
for (uint256 i = 0; i < proposal.targets.length; i++) {
proposal.executor.cancelTransaction(
proposal.targets[i],
proposal.weiValues[i],
proposal.signatures[i],
proposal.calldatas[i],
proposal.executionTime,
proposal.withDelegatecalls[i]
);
}
}
proposal.strategy.handleProposalCancellation(proposalId);
emit ProposalCanceled(proposalId);
}
function queue(uint256 proposalId) external override {
require(proposalId < _proposalsCount, 'invalid proposal id');
require(
getProposalState(proposalId) == ProposalState.Succeeded,
'invalid state to queue'
);
ProposalWithoutVote storage proposal = _proposals[proposalId].proposalData;
assert(proposal.proposalType == ProposalType.Binary);
uint256 executionTime = block.timestamp.add(proposal.executor.getDelay());
for (uint256 i = 0; i < proposal.targets.length; i++) {
_queueOrRevert(
proposal.executor,
proposal.targets[i],
proposal.weiValues[i],
proposal.signatures[i],
proposal.calldatas[i],
executionTime,
proposal.withDelegatecalls[i]
);
}
proposal.executionTime = executionTime;
emit ProposalQueued(proposalId, executionTime, msg.sender);
}
function execute(uint256 proposalId) external override payable {
require(proposalId < _proposalsCount, 'invalid proposal id');
require(getProposalState(proposalId) == ProposalState.Queued, 'only queued proposals');
ProposalWithoutVote storage proposal = _proposals[proposalId].proposalData;
assert(proposal.proposalType == ProposalType.Binary);
proposal.executed = true;
for (uint256 i = 0; i < proposal.targets.length; i++) {
proposal.executor.executeTransaction{value: proposal.weiValues[i]}(
proposal.targets[i],
proposal.weiValues[i],
proposal.signatures[i],
proposal.calldatas[i],
proposal.executionTime,
proposal.withDelegatecalls[i]
);
}
emit ProposalExecuted(proposalId, msg.sender);
}
function submitVote(uint256 proposalId, uint256 optionBitMask) external override {
return _submitVote(msg.sender, proposalId, optionBitMask);
}
function submitVoteBySignature(
uint256 proposalId,
uint256 optionBitMask,
uint8 v,
bytes32 r,
bytes32 s
) external override {
bytes32 digest = keccak256(
abi.encodePacked(
'\x19\x01',
keccak256(
abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(NAME)), getChainId(), address(this))
),
keccak256(abi.encode(VOTE_EMITTED_TYPEHASH, proposalId, optionBitMask))
)
);
address signer = ecrecover(digest, v, r, s);
require(signer != address(0), 'invalid signature');
return _submitVote(signer, proposalId, optionBitMask);
}
function handleVotingPowerChanged(
address voter,
uint256 newVotingPower,
uint256[] calldata proposalIds
) external override {
uint224 safeNewVotingPower = _safeUint224(newVotingPower);
for (uint256 i = 0; i < proposalIds.length; i++) {
if (getProposalState(proposalIds[i]) != ProposalState.Active) continue;
ProposalWithoutVote storage proposal = _proposals[proposalIds[i]].proposalData;
require(address(proposal.strategy) == msg.sender, 'invalid voting power strategy');
Vote memory vote = _proposals[proposalIds[i]].votes[voter];
if (vote.optionBitMask == 0) continue;
uint256 oldVotingPower = uint256(vote.votingPower);
proposal.totalVotes = proposal.totalVotes.add(newVotingPower).sub(oldVotingPower);
for (uint256 j = 0; j < proposal.options.length; j++) {
if (vote.optionBitMask & (2**j) == 2**j) {
proposal.voteCounts[j] = proposal.voteCounts[j].add(newVotingPower).sub(oldVotingPower);
}
}
_proposals[proposalIds[i]].votes[voter].votingPower = safeNewVotingPower;
emit VotingPowerChanged(
proposalIds[i],
voter,
vote.optionBitMask,
vote.votingPower,
safeNewVotingPower
);
}
}
function transferDaoOperator(address newDaoOperator) external {
require(msg.sender == _daoOperator, 'only dao operator');
require(newDaoOperator != address(0), 'invalid dao operator');
_daoOperator = newDaoOperator;
emit DaoOperatorTransferred(newDaoOperator);
}
function authorizeExecutors(address[] memory executors)
public override onlyAdmin
{
_authorizeExecutors(executors);
}
function unauthorizeExecutors(address[] memory executors)
public override onlyAdmin
{
_unauthorizeExecutors(executors);
}
function authorizeVotingPowerStrategies(address[] memory strategies)
public override onlyAdmin
{
_authorizeVotingPowerStrategies(strategies);
}
function unauthorizeVotingPowerStrategies(address[] memory strategies)
public
override
onlyAdmin
{
_unauthorizedVotingPowerStrategies(strategies);
}
function isExecutorAuthorized(address executor) public override view returns (bool) {
return _authorizedExecutors[executor];
}
function isVotingPowerStrategyAuthorized(address strategy) public override view returns (bool) {
return _authorizedVotingPowerStrategies[strategy];
}
function getDaoOperator() external override view returns (address) {
return _daoOperator;
}
function getProposalsCount() external override view returns (uint256) {
return _proposalsCount;
}
function getProposalById(uint256 proposalId)
external
override
view
returns (ProposalWithoutVote memory)
{
return _proposals[proposalId].proposalData;
}
function getProposalVoteDataById(uint256 proposalId)
external
override
view
returns (
uint256,
uint256[] memory,
string[] memory
)
{
ProposalWithoutVote storage proposal = _proposals[proposalId].proposalData;
return (proposal.totalVotes, proposal.voteCounts, proposal.options);
}
function getVoteOnProposal(uint256 proposalId, address voter)
external
override
view
returns (Vote memory)
{
return _proposals[proposalId].votes[voter];
}
function getProposalState(uint256 proposalId) public override view returns (ProposalState) {
require(proposalId < _proposalsCount, 'invalid proposal id');
ProposalWithoutVote storage proposal = _proposals[proposalId].proposalData;
if (proposal.canceled) {
return ProposalState.Canceled;
} else if (block.timestamp < proposal.startTime) {
return ProposalState.Pending;
} else if (block.timestamp <= proposal.endTime) {
return ProposalState.Active;
} else if (proposal.proposalType == ProposalType.Generic) {
return ProposalState.Finalized;
} else if (
!IProposalValidator(address(proposal.executor)).isBinaryProposalPassed(
IKyberGovernance(this),
proposalId
)
) {
return ProposalState.Failed;
} else if (proposal.executionTime == 0) {
return ProposalState.Succeeded;
} else if (proposal.executed) {
return ProposalState.Executed;
} else if (proposal.executor.isProposalOverGracePeriod(this, proposalId)) {
return ProposalState.Expired;
} else {
return ProposalState.Queued;
}
}
function _queueOrRevert(
IExecutorWithTimelock executor,
address target,
uint256 value,
string memory signature,
bytes memory callData,
uint256 executionTime,
bool withDelegatecall
) internal {
require(
!executor.isActionQueued(
keccak256(abi.encode(target, value, signature, callData, executionTime, withDelegatecall))
),
'duplicated action'
);
executor.queueTransaction(target, value, signature, callData, executionTime, withDelegatecall);
}
function _submitVote(
address voter,
uint256 proposalId,
uint256 optionBitMask
) internal {
require(proposalId < _proposalsCount, 'invalid proposal id');
require(getProposalState(proposalId) == ProposalState.Active, 'voting closed');
ProposalWithoutVote storage proposal = _proposals[proposalId].proposalData;
uint256 numOptions = proposal.options.length;
if (proposal.proposalType == ProposalType.Binary) {
require(optionBitMask == 1 || optionBitMask == 2, 'wrong vote for binary proposal');
} else {
require(
optionBitMask > 0 && optionBitMask < 2**numOptions,
'invalid options for generic proposal'
);
}
Vote memory vote = _proposals[proposalId].votes[voter];
uint256 votingPower = proposal.strategy.handleVote(voter, proposalId, optionBitMask);
if (vote.optionBitMask == 0) {
proposal.totalVotes = proposal.totalVotes.add(votingPower);
}
for (uint256 i = 0; i < proposal.options.length; i++) {
bool hasVoted = (vote.optionBitMask & (2**i)) == 2**i;
bool isVoting = (optionBitMask & (2**i)) == 2**i;
if (hasVoted && !isVoting) {
proposal.voteCounts[i] = proposal.voteCounts[i].sub(votingPower);
} else if (!hasVoted && isVoting) {
proposal.voteCounts[i] = proposal.voteCounts[i].add(votingPower);
}
}
_proposals[proposalId].votes[voter] = Vote({
optionBitMask: _safeUint32(optionBitMask),
votingPower: _safeUint224(votingPower)
});
emit VoteEmitted(proposalId, voter, _safeUint32(optionBitMask), _safeUint224(votingPower));
}
function _authorizeExecutors(address[] memory executors) internal {
for(uint256 i = 0; i < executors.length; i++) {
_authorizedExecutors[executors[i]] = true;
emit ExecutorAuthorized(executors[i]);
}
}
function _unauthorizeExecutors(address[] memory executors) internal {
for(uint256 i = 0; i < executors.length; i++) {
_authorizedExecutors[executors[i]] = false;
emit ExecutorUnauthorized(executors[i]);
}
}
function _authorizeVotingPowerStrategies(address[] memory strategies) internal {
for(uint256 i = 0; i < strategies.length; i++) {
_authorizedVotingPowerStrategies[strategies[i]] = true;
emit VotingPowerStrategyAuthorized(strategies[i]);
}
}
function _unauthorizedVotingPowerStrategies(address[] memory strategies) internal {
for(uint256 i = 0; i < strategies.length; i++) {
_authorizedVotingPowerStrategies[strategies[i]] = false;
emit VotingPowerStrategyUnauthorized(strategies[i]);
}
}
function _safeUint224(uint256 value) internal pure returns (uint224) {
require(value < 2**224 - 1, 'value is too big (uint224)');
return uint224(value);
}
function _safeUint32(uint256 value) internal pure returns (uint32) {
require(value < 2**32 - 1, 'value is too big (uint32)');
return uint32(value);
}
}
文件 8 的 9:PermissionAdmin.sol
pragma solidity 0.7.6;
abstract contract PermissionAdmin {
address public admin;
address public pendingAdmin;
event AdminClaimed(address newAdmin, address previousAdmin);
event TransferAdminPending(address pendingAdmin);
constructor(address _admin) {
require(_admin != address(0), "admin 0");
admin = _admin;
}
modifier onlyAdmin() {
require(msg.sender == admin, "only admin");
_;
}
function transferAdmin(address newAdmin) public onlyAdmin {
require(newAdmin != address(0), "new admin 0");
emit TransferAdminPending(newAdmin);
pendingAdmin = newAdmin;
}
function transferAdminQuickly(address newAdmin) public onlyAdmin {
require(newAdmin != address(0), "admin 0");
emit TransferAdminPending(newAdmin);
emit AdminClaimed(newAdmin, admin);
admin = newAdmin;
}
function claimAdmin() public {
require(pendingAdmin == msg.sender, "not pending");
emit AdminClaimed(pendingAdmin, admin);
admin = pendingAdmin;
pendingAdmin = address(0);
}
}
文件 9 的 9:SafeMath.sol
pragma solidity ^0.7.0;
library SafeMath {
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a / b);
}
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a % b);
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) return 0;
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a / b;
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a % b;
}
}
{
"compilationTarget": {
"contracts/governance/KyberGovernance.sol": "KyberGovernance"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 1000
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"daoOperator","type":"address"},{"internalType":"address[]","name":"executors","type":"address[]"},{"internalType":"address[]","name":"votingPowerStrategies","type":"address[]"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"}],"name":"AdminClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"proposalId","type":"uint256"},{"indexed":true,"internalType":"address","name":"creator","type":"address"},{"indexed":true,"internalType":"contract IExecutorWithTimelock","name":"executor","type":"address"},{"indexed":true,"internalType":"contract IVotingPowerStrategy","name":"strategy","type":"address"},{"indexed":false,"internalType":"address[]","name":"targets","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"weiValues","type":"uint256[]"},{"indexed":false,"internalType":"string[]","name":"signatures","type":"string[]"},{"indexed":false,"internalType":"bytes[]","name":"calldatas","type":"bytes[]"},{"indexed":false,"internalType":"bool[]","name":"withDelegatecalls","type":"bool[]"},{"indexed":false,"internalType":"uint256","name":"startTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTime","type":"uint256"},{"indexed":false,"internalType":"string","name":"link","type":"string"},{"indexed":false,"internalType":"uint256","name":"maxVotingPower","type":"uint256"}],"name":"BinaryProposalCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newDaoOperator","type":"address"}],"name":"DaoOperatorTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"executor","type":"address"}],"name":"ExecutorAuthorized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"executor","type":"address"}],"name":"ExecutorUnauthorized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"proposalId","type":"uint256"},{"indexed":true,"internalType":"address","name":"creator","type":"address"},{"indexed":true,"internalType":"contract IExecutorWithTimelock","name":"executor","type":"address"},{"indexed":true,"internalType":"contract IVotingPowerStrategy","name":"strategy","type":"address"},{"indexed":false,"internalType":"string[]","name":"options","type":"string[]"},{"indexed":false,"internalType":"uint256","name":"startTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTime","type":"uint256"},{"indexed":false,"internalType":"string","name":"link","type":"string"},{"indexed":false,"internalType":"uint256","name":"maxVotingPower","type":"uint256"}],"name":"GenericProposalCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"ProposalCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"proposalId","type":"uint256"},{"indexed":true,"internalType":"address","name":"initiatorExecution","type":"address"}],"name":"ProposalExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"proposalId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"executionTime","type":"uint256"},{"indexed":true,"internalType":"address","name":"initiatorQueueing","type":"address"}],"name":"ProposalQueued","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"pendingAdmin","type":"address"}],"name":"TransferAdminPending","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"proposalId","type":"uint256"},{"indexed":true,"internalType":"address","name":"voter","type":"address"},{"indexed":true,"internalType":"uint32","name":"voteOptions","type":"uint32"},{"indexed":false,"internalType":"uint224","name":"votingPower","type":"uint224"}],"name":"VoteEmitted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"proposalId","type":"uint256"},{"indexed":true,"internalType":"address","name":"voter","type":"address"},{"indexed":true,"internalType":"uint32","name":"voteOptions","type":"uint32"},{"indexed":false,"internalType":"uint224","name":"oldVotingPower","type":"uint224"},{"indexed":false,"internalType":"uint224","name":"newVotingPower","type":"uint224"}],"name":"VotingPowerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"strategy","type":"address"}],"name":"VotingPowerStrategyAuthorized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"strategy","type":"address"}],"name":"VotingPowerStrategyUnauthorized","type":"event"},{"inputs":[],"name":"DOMAIN_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VOTE_EMITTED_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"executors","type":"address[]"}],"name":"authorizeExecutors","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"strategies","type":"address[]"}],"name":"authorizeVotingPowerStrategies","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"cancel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IExecutorWithTimelock","name":"executor","type":"address"},{"internalType":"contract IVotingPowerStrategy","name":"strategy","type":"address"},{"components":[{"internalType":"address[]","name":"targets","type":"address[]"},{"internalType":"uint256[]","name":"weiValues","type":"uint256[]"},{"internalType":"string[]","name":"signatures","type":"string[]"},{"internalType":"bytes[]","name":"calldatas","type":"bytes[]"},{"internalType":"bool[]","name":"withDelegatecalls","type":"bool[]"}],"internalType":"struct IKyberGovernance.BinaryProposalParams","name":"executionParams","type":"tuple"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"string","name":"link","type":"string"}],"name":"createBinaryProposal","outputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IExecutorWithTimelock","name":"executor","type":"address"},{"internalType":"contract IVotingPowerStrategy","name":"strategy","type":"address"},{"internalType":"string[]","name":"options","type":"string[]"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"string","name":"link","type":"string"}],"name":"createGenericProposal","outputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"execute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"getDaoOperator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"getProposalById","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"enum IKyberGovernance.ProposalType","name":"proposalType","type":"uint8"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"contract IExecutorWithTimelock","name":"executor","type":"address"},{"internalType":"contract IVotingPowerStrategy","name":"strategy","type":"address"},{"internalType":"address[]","name":"targets","type":"address[]"},{"internalType":"uint256[]","name":"weiValues","type":"uint256[]"},{"internalType":"string[]","name":"signatures","type":"string[]"},{"internalType":"bytes[]","name":"calldatas","type":"bytes[]"},{"internalType":"bool[]","name":"withDelegatecalls","type":"bool[]"},{"internalType":"string[]","name":"options","type":"string[]"},{"internalType":"uint256[]","name":"voteCounts","type":"uint256[]"},{"internalType":"uint256","name":"totalVotes","type":"uint256"},{"internalType":"uint256","name":"maxVotingPower","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"executionTime","type":"uint256"},{"internalType":"string","name":"link","type":"string"},{"internalType":"bool","name":"executed","type":"bool"},{"internalType":"bool","name":"canceled","type":"bool"}],"internalType":"struct IKyberGovernance.ProposalWithoutVote","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"getProposalState","outputs":[{"internalType":"enum IKyberGovernance.ProposalState","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"getProposalVoteDataById","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"string[]","name":"","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getProposalsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"},{"internalType":"address","name":"voter","type":"address"}],"name":"getVoteOnProposal","outputs":[{"components":[{"internalType":"uint32","name":"optionBitMask","type":"uint32"},{"internalType":"uint224","name":"votingPower","type":"uint224"}],"internalType":"struct IKyberGovernance.Vote","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"voter","type":"address"},{"internalType":"uint256","name":"newVotingPower","type":"uint256"},{"internalType":"uint256[]","name":"proposalIds","type":"uint256[]"}],"name":"handleVotingPowerChanged","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"executor","type":"address"}],"name":"isExecutorAuthorized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"strategy","type":"address"}],"name":"isVotingPowerStrategyAuthorized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"queue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"},{"internalType":"uint256","name":"optionBitMask","type":"uint256"}],"name":"submitVote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"},{"internalType":"uint256","name":"optionBitMask","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"submitVoteBySignature","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"transferAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"transferAdminQuickly","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newDaoOperator","type":"address"}],"name":"transferDaoOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"executors","type":"address[]"}],"name":"unauthorizeExecutors","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"strategies","type":"address[]"}],"name":"unauthorizeVotingPowerStrategies","outputs":[],"stateMutability":"nonpayable","type":"function"}]