Contract Overview
Balance:
0 ETH
EtherValue:
$0.00
My Name Tag:
Not Available, login to update
[ Download CSV Export ]
Latest 13 internal transactions
[ Download CSV Export ]
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
KaliDAOfactory
Compiler Version
v0.8.14+commit.80d49f37
Optimization Enabled:
Yes with 11111 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.4; /// @notice Modern and gas-optimized ERC-20 + EIP-2612 implementation with COMP-style governance and pausing. /// @author Modified from Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/erc20/ERC20.sol) /// License-Identifier: AGPL-3.0-only abstract contract KaliDAOtoken { /*/////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate); event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance); event PauseFlipped(bool paused); /*/////////////////////////////////////////////////////////////// ERRORS //////////////////////////////////////////////////////////////*/ error NoArrayParity(); error Paused(); error SignatureExpired(); error NullAddress(); error InvalidNonce(); error NotDetermined(); error InvalidSignature(); error Uint32max(); error Uint96max(); /*/////////////////////////////////////////////////////////////// METADATA STORAGE //////////////////////////////////////////////////////////////*/ string public name; string public symbol; uint8 public constant decimals = 18; /*/////////////////////////////////////////////////////////////// ERC-20 STORAGE //////////////////////////////////////////////////////////////*/ uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; /*/////////////////////////////////////////////////////////////// EIP-2612 STORAGE //////////////////////////////////////////////////////////////*/ bytes32 public constant PERMIT_TYPEHASH = keccak256('Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)'); uint256 internal INITIAL_CHAIN_ID; bytes32 internal INITIAL_DOMAIN_SEPARATOR; mapping(address => uint256) public nonces; /*/////////////////////////////////////////////////////////////// DAO STORAGE //////////////////////////////////////////////////////////////*/ bool public paused; bytes32 public constant DELEGATION_TYPEHASH = keccak256('Delegation(address delegatee,uint256 nonce,uint256 deadline)'); mapping(address => address) internal _delegates; mapping(address => mapping(uint256 => Checkpoint)) public checkpoints; mapping(address => uint256) public numCheckpoints; struct Checkpoint { uint32 fromTimestamp; uint96 votes; } /*/////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ function _init( string memory name_, string memory symbol_, bool paused_, address[] memory voters_, uint256[] memory shares_ ) internal virtual { if (voters_.length != shares_.length) revert NoArrayParity(); name = name_; symbol = symbol_; paused = paused_; INITIAL_CHAIN_ID = block.chainid; INITIAL_DOMAIN_SEPARATOR = _computeDomainSeparator(); // cannot realistically overflow on human timescales unchecked { for (uint256 i; i < voters_.length; i++) { _mint(voters_[i], shares_[i]); } } } /*/////////////////////////////////////////////////////////////// ERC-20 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 amount) public payable virtual returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function transfer(address to, uint256 amount) public payable notPaused virtual returns (bool) { balanceOf[msg.sender] -= amount; // cannot overflow because the sum of all user // balances can't exceed the max uint256 value unchecked { balanceOf[to] += amount; } _moveDelegates(delegates(msg.sender), delegates(to), amount); emit Transfer(msg.sender, to, amount); return true; } function transferFrom( address from, address to, uint256 amount ) public payable notPaused virtual returns (bool) { if (allowance[from][msg.sender] != type(uint256).max) allowance[from][msg.sender] -= amount; balanceOf[from] -= amount; // cannot overflow because the sum of all user // balances can't exceed the max uint256 value unchecked { balanceOf[to] += amount; } _moveDelegates(delegates(from), delegates(to), amount); emit Transfer(from, to, amount); return true; } /*/////////////////////////////////////////////////////////////// EIP-2612 LOGIC //////////////////////////////////////////////////////////////*/ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public payable virtual { if (block.timestamp > deadline) revert SignatureExpired(); // cannot realistically overflow on human timescales unchecked { bytes32 digest = keccak256( abi.encodePacked( '\x19\x01', DOMAIN_SEPARATOR(), keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline)) ) ); address recoveredAddress = ecrecover(digest, v, r, s); if (recoveredAddress == address(0) || recoveredAddress != owner) revert InvalidSignature(); allowance[recoveredAddress][spender] = value; } emit Approval(owner, spender, value); } function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : _computeDomainSeparator(); } function _computeDomainSeparator() internal view virtual returns (bytes32) { return keccak256( abi.encode( keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'), keccak256(bytes(name)), keccak256('1'), block.chainid, address(this) ) ); } /*/////////////////////////////////////////////////////////////// DAO LOGIC //////////////////////////////////////////////////////////////*/ modifier notPaused() { if (paused) revert Paused(); _; } function delegates(address delegator) public view virtual returns (address) { address current = _delegates[delegator]; return current == address(0) ? delegator : current; } function getCurrentVotes(address account) public view virtual returns (uint256) { // this is safe from underflow because decrement only occurs if `nCheckpoints` is positive unchecked { uint256 nCheckpoints = numCheckpoints[account]; return nCheckpoints != 0 ? checkpoints[account][nCheckpoints - 1].votes : 0; } } function delegate(address delegatee) public payable virtual { _delegate(msg.sender, delegatee); } function delegateBySig( address delegatee, uint256 nonce, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public payable virtual { if (block.timestamp > deadline) revert SignatureExpired(); bytes32 structHash = keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, deadline)); bytes32 digest = keccak256(abi.encodePacked('\x19\x01', DOMAIN_SEPARATOR(), structHash)); address signatory = ecrecover(digest, v, r, s); if (signatory == address(0)) revert NullAddress(); // cannot realistically overflow on human timescales unchecked { if (nonce != nonces[signatory]++) revert InvalidNonce(); } _delegate(signatory, delegatee); } function getPriorVotes(address account, uint256 timestamp) public view virtual returns (uint96) { if (block.timestamp <= timestamp) revert NotDetermined(); uint256 nCheckpoints = numCheckpoints[account]; if (nCheckpoints == 0) return 0; // this is safe from underflow because decrement only occurs if `nCheckpoints` is positive unchecked { if (checkpoints[account][nCheckpoints - 1].fromTimestamp <= timestamp) return checkpoints[account][nCheckpoints - 1].votes; if (checkpoints[account][0].fromTimestamp > timestamp) return 0; uint256 lower; // this is safe from underflow because decrement only occurs if `nCheckpoints` is positive uint256 upper = nCheckpoints - 1; while (upper > lower) { // this is safe from underflow because `upper` ceiling is provided uint256 center = upper - (upper - lower) / 2; Checkpoint memory cp = checkpoints[account][center]; if (cp.fromTimestamp == timestamp) { return cp.votes; } else if (cp.fromTimestamp < timestamp) { lower = center; } else { upper = center - 1; } } return checkpoints[account][lower].votes; } } function _delegate(address delegator, address delegatee) internal virtual { address currentDelegate = delegates(delegator); _delegates[delegator] = delegatee; _moveDelegates(currentDelegate, delegatee, balanceOf[delegator]); emit DelegateChanged(delegator, currentDelegate, delegatee); } function _moveDelegates( address srcRep, address dstRep, uint256 amount ) internal virtual { if (srcRep != dstRep && amount != 0) if (srcRep != address(0)) { uint256 srcRepNum = numCheckpoints[srcRep]; uint256 srcRepOld = srcRepNum != 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0; uint256 srcRepNew = srcRepOld - amount; _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew); } if (dstRep != address(0)) { uint256 dstRepNum = numCheckpoints[dstRep]; uint256 dstRepOld = dstRepNum != 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0; uint256 dstRepNew = dstRepOld + amount; _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew); } } function _writeCheckpoint( address delegatee, uint256 nCheckpoints, uint256 oldVotes, uint256 newVotes ) internal virtual { unchecked { // this is safe from underflow because decrement only occurs if `nCheckpoints` is positive if (nCheckpoints != 0 && checkpoints[delegatee][nCheckpoints - 1].fromTimestamp == block.timestamp) { checkpoints[delegatee][nCheckpoints - 1].votes = _safeCastTo96(newVotes); } else { checkpoints[delegatee][nCheckpoints] = Checkpoint(_safeCastTo32(block.timestamp), _safeCastTo96(newVotes)); // cannot realistically overflow on human timescales numCheckpoints[delegatee] = nCheckpoints + 1; } } emit DelegateVotesChanged(delegatee, oldVotes, newVotes); } /*/////////////////////////////////////////////////////////////// MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 amount) internal virtual { totalSupply += amount; // cannot overflow because the sum of all user // balances can't exceed the max uint256 value unchecked { balanceOf[to] += amount; } _moveDelegates(address(0), delegates(to), amount); emit Transfer(address(0), to, amount); } function _burn(address from, uint256 amount) internal virtual { balanceOf[from] -= amount; // cannot underflow because a user's balance // will never be larger than the total supply unchecked { totalSupply -= amount; } _moveDelegates(delegates(from), address(0), amount); emit Transfer(from, address(0), amount); } function burn(uint256 amount) public payable virtual { _burn(msg.sender, amount); } function burnFrom(address from, uint256 amount) public payable virtual { if (allowance[from][msg.sender] != type(uint256).max) allowance[from][msg.sender] -= amount; _burn(from, amount); } /*/////////////////////////////////////////////////////////////// PAUSE LOGIC //////////////////////////////////////////////////////////////*/ function _flipPause() internal virtual { paused = !paused; emit PauseFlipped(paused); } /*/////////////////////////////////////////////////////////////// SAFECAST LOGIC //////////////////////////////////////////////////////////////*/ function _safeCastTo32(uint256 x) internal pure virtual returns (uint32) { if (x > type(uint32).max) revert Uint32max(); return uint32(x); } function _safeCastTo96(uint256 x) internal pure virtual returns (uint96) { if (x > type(uint96).max) revert Uint96max(); return uint96(x); } } /// @notice Helper utility that enables calling multiple local methods in a single call. /// @author Modified from Uniswap (https://github.com/Uniswap/v3-periphery/blob/main/contracts/base/Multicall.sol) abstract contract Multicall { function multicall(bytes[] calldata data) public payable virtual returns (bytes[] memory results) { results = new bytes[](data.length); // cannot realistically overflow on human timescales unchecked { for (uint256 i = 0; i < data.length; i++) { (bool success, bytes memory result) = address(this).delegatecall(data[i]); if (!success) { if (result.length < 68) revert(); assembly { result := add(result, 0x04) } revert(abi.decode(result, (string))); } results[i] = result; } } } } /// @notice Helper utility for NFT 'safe' transfers. abstract contract NFThelper { function onERC721Received( address, address, uint256, bytes calldata ) external pure returns (bytes4 sig) { sig = 0x150b7a02; // 'onERC721Received(address,address,uint256,bytes)' } function onERC1155Received( address, address, uint256, uint256, bytes calldata ) external pure returns (bytes4 sig) { sig = 0xf23a6e61; // 'onERC1155Received(address,address,uint256,uint256,bytes)' } function onERC1155BatchReceived( address, address, uint256[] calldata, uint256[] calldata, bytes calldata ) external pure returns (bytes4 sig) { sig = 0xbc197c81; // 'onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)' } } /// @notice Gas-optimized reentrancy protection. /// @author Modified from OpenZeppelin /// (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/security/ReentrancyGuard.sol) /// License-Identifier: MIT abstract contract ReentrancyGuard { error Reentrancy(); uint256 private constant NOT_ENTERED = 1; uint256 private constant ENTERED = 2; uint256 private status = NOT_ENTERED; modifier nonReentrant() { if (status == ENTERED) revert Reentrancy(); status = ENTERED; _; status = NOT_ENTERED; } } /// @notice Kali DAO membership extension interface. interface IKaliDAOextension { function setExtension(bytes calldata extensionData) external; function callExtension( address account, uint256 amount, bytes calldata extensionData ) external payable returns (bool mint, uint256 amountOut); } /// @notice Simple gas-optimized Kali DAO core module. contract KaliDAO is KaliDAOtoken, Multicall, NFThelper, ReentrancyGuard { /*/////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event NewProposal( address indexed proposer, uint256 indexed proposal, ProposalType indexed proposalType, string description, address[] accounts, uint256[] amounts, bytes[] payloads ); event ProposalCancelled(address indexed proposer, uint256 indexed proposal); event ProposalSponsored(address indexed sponsor, uint256 indexed proposal); event VoteCast(address indexed voter, uint256 indexed proposal, bool indexed approve); event ProposalProcessed(uint256 indexed proposal, bool indexed didProposalPass); /*/////////////////////////////////////////////////////////////// ERRORS //////////////////////////////////////////////////////////////*/ error Initialized(); error PeriodBounds(); error QuorumMax(); error SupermajorityBounds(); error InitCallFail(); error TypeBounds(); error NotProposer(); error Sponsored(); error NotMember(); error NotCurrentProposal(); error AlreadyVoted(); error NotVoteable(); error VotingNotEnded(); error PrevNotProcessed(); error NotExtension(); /*/////////////////////////////////////////////////////////////// DAO STORAGE //////////////////////////////////////////////////////////////*/ string public docs; uint256 private currentSponsoredProposal; uint256 public proposalCount; uint32 public votingPeriod; uint32 public gracePeriod; uint32 public quorum; // 1-100 uint32 public supermajority; // 1-100 bytes32 public constant VOTE_HASH = keccak256('SignVote(address signer,uint256 proposal,bool approve)'); mapping(address => bool) public extensions; mapping(uint256 => Proposal) public proposals; mapping(uint256 => ProposalState) public proposalStates; mapping(ProposalType => VoteType) public proposalVoteTypes; mapping(uint256 => mapping(address => bool)) public voted; mapping(address => uint256) public lastYesVote; enum ProposalType { MINT, // add membership BURN, // revoke membership CALL, // call contracts VPERIOD, // set `votingPeriod` GPERIOD, // set `gracePeriod` QUORUM, // set `quorum` SUPERMAJORITY, // set `supermajority` TYPE, // set `VoteType` to `ProposalType` PAUSE, // flip membership transferability EXTENSION, // flip `extensions` whitelisting ESCAPE, // delete pending proposal in case of revert DOCS // amend org docs } enum VoteType { SIMPLE_MAJORITY, SIMPLE_MAJORITY_QUORUM_REQUIRED, SUPERMAJORITY, SUPERMAJORITY_QUORUM_REQUIRED } struct Proposal { ProposalType proposalType; string description; address[] accounts; // member(s) being added/kicked; account(s) receiving payload uint256[] amounts; // value(s) to be minted/burned/spent; gov setting [0] bytes[] payloads; // data for CALL proposals uint256 prevProposal; uint96 yesVotes; uint96 noVotes; uint32 creationTime; address proposer; } struct ProposalState { bool passed; bool processed; } /*/////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ function init( string memory name_, string memory symbol_, string memory docs_, bool paused_, address[] memory extensions_, bytes[] memory extensionsData_, address[] calldata voters_, uint256[] calldata shares_, uint32[16] memory govSettings_ ) public payable nonReentrant virtual { if (extensions_.length != extensionsData_.length) revert NoArrayParity(); if (votingPeriod != 0) revert Initialized(); if (govSettings_[0] == 0 || govSettings_[0] > 365 days) revert PeriodBounds(); if (govSettings_[1] > 365 days) revert PeriodBounds(); if (govSettings_[2] > 100) revert QuorumMax(); if (govSettings_[3] <= 51 || govSettings_[3] > 100) revert SupermajorityBounds(); KaliDAOtoken._init(name_, symbol_, paused_, voters_, shares_); if (extensions_.length != 0) { // cannot realistically overflow on human timescales unchecked { for (uint256 i; i < extensions_.length; i++) { extensions[extensions_[i]] = true; if (extensionsData_[i].length > 3) { (bool success, ) = extensions_[i].call(extensionsData_[i]); if (!success) revert InitCallFail(); } } } } docs = docs_; votingPeriod = govSettings_[0]; gracePeriod = govSettings_[1]; quorum = govSettings_[2]; supermajority = govSettings_[3]; // set initial vote types proposalVoteTypes[ProposalType.MINT] = VoteType(govSettings_[4]); proposalVoteTypes[ProposalType.BURN] = VoteType(govSettings_[5]); proposalVoteTypes[ProposalType.CALL] = VoteType(govSettings_[6]); proposalVoteTypes[ProposalType.VPERIOD] = VoteType(govSettings_[7]); proposalVoteTypes[ProposalType.GPERIOD] = VoteType(govSettings_[8]); proposalVoteTypes[ProposalType.QUORUM] = VoteType(govSettings_[9]); proposalVoteTypes[ProposalType.SUPERMAJORITY] = VoteType(govSettings_[10]); proposalVoteTypes[ProposalType.TYPE] = VoteType(govSettings_[11]); proposalVoteTypes[ProposalType.PAUSE] = VoteType(govSettings_[12]); proposalVoteTypes[ProposalType.EXTENSION] = VoteType(govSettings_[13]); proposalVoteTypes[ProposalType.ESCAPE] = VoteType(govSettings_[14]); proposalVoteTypes[ProposalType.DOCS] = VoteType(govSettings_[15]); } /*/////////////////////////////////////////////////////////////// PROPOSAL LOGIC //////////////////////////////////////////////////////////////*/ function getProposalArrays(uint256 proposal) public view virtual returns ( address[] memory accounts, uint256[] memory amounts, bytes[] memory payloads ) { Proposal storage prop = proposals[proposal]; (accounts, amounts, payloads) = (prop.accounts, prop.amounts, prop.payloads); } function propose( ProposalType proposalType, string calldata description, address[] calldata accounts, uint256[] calldata amounts, bytes[] calldata payloads ) public payable nonReentrant virtual returns (uint256 proposal) { if (accounts.length != amounts.length || amounts.length != payloads.length) revert NoArrayParity(); if (proposalType == ProposalType.VPERIOD) if (amounts[0] == 0 || amounts[0] > 365 days) revert PeriodBounds(); if (proposalType == ProposalType.GPERIOD) if (amounts[0] > 365 days) revert PeriodBounds(); if (proposalType == ProposalType.QUORUM) if (amounts[0] > 100) revert QuorumMax(); if (proposalType == ProposalType.SUPERMAJORITY) if (amounts[0] <= 51 || amounts[0] > 100) revert SupermajorityBounds(); if (proposalType == ProposalType.TYPE) if (amounts[0] > 11 || amounts[1] > 3 || amounts.length != 2) revert TypeBounds(); bool selfSponsor; // if member or extension is making proposal, include sponsorship if (balanceOf[msg.sender] != 0 || extensions[msg.sender]) selfSponsor = true; // cannot realistically overflow on human timescales unchecked { proposalCount++; } proposal = proposalCount; proposals[proposal] = Proposal({ proposalType: proposalType, description: description, accounts: accounts, amounts: amounts, payloads: payloads, prevProposal: selfSponsor ? currentSponsoredProposal : 0, yesVotes: 0, noVotes: 0, creationTime: selfSponsor ? _safeCastTo32(block.timestamp) : 0, proposer: msg.sender }); if (selfSponsor) currentSponsoredProposal = proposal; emit NewProposal(msg.sender, proposal, proposalType, description, accounts, amounts, payloads); } function cancelProposal(uint256 proposal) public payable nonReentrant virtual { Proposal storage prop = proposals[proposal]; if (msg.sender != prop.proposer) revert NotProposer(); if (prop.creationTime != 0) revert Sponsored(); delete proposals[proposal]; emit ProposalCancelled(msg.sender, proposal); } function sponsorProposal(uint256 proposal) public payable nonReentrant virtual { Proposal storage prop = proposals[proposal]; if (balanceOf[msg.sender] == 0) revert NotMember(); if (prop.proposer == address(0)) revert NotCurrentProposal(); if (prop.creationTime != 0) revert Sponsored(); prop.prevProposal = currentSponsoredProposal; currentSponsoredProposal = proposal; prop.creationTime = _safeCastTo32(block.timestamp); emit ProposalSponsored(msg.sender, proposal); } function vote(uint256 proposal, bool approve) public payable nonReentrant virtual { _vote(msg.sender, proposal, approve); } function voteBySig( address signer, uint256 proposal, bool approve, uint8 v, bytes32 r, bytes32 s ) public payable nonReentrant virtual { bytes32 digest = keccak256( abi.encodePacked( '\x19\x01', DOMAIN_SEPARATOR(), keccak256( abi.encode( VOTE_HASH, signer, proposal, approve ) ) ) ); address recoveredAddress = ecrecover(digest, v, r, s); if (recoveredAddress == address(0) || recoveredAddress != signer) revert InvalidSignature(); _vote(signer, proposal, approve); } function _vote( address signer, uint256 proposal, bool approve ) internal virtual { Proposal storage prop = proposals[proposal]; if (voted[proposal][signer]) revert AlreadyVoted(); // this is safe from overflow because `votingPeriod` is capped so it will not combine // with unix time to exceed the max uint256 value unchecked { if (block.timestamp > prop.creationTime + votingPeriod) revert NotVoteable(); } uint96 weight = getPriorVotes(signer, prop.creationTime); // this is safe from overflow because `yesVotes` and `noVotes` are capped by `totalSupply` // which is checked for overflow in `KaliDAOtoken` contract unchecked { if (approve) { prop.yesVotes += weight; lastYesVote[signer] = proposal; } else { prop.noVotes += weight; } } voted[proposal][signer] = true; emit VoteCast(signer, proposal, approve); } function processProposal(uint256 proposal) public payable nonReentrant virtual returns ( bool didProposalPass, bytes[] memory results ) { Proposal storage prop = proposals[proposal]; VoteType voteType = proposalVoteTypes[prop.proposalType]; if (prop.creationTime == 0) revert NotCurrentProposal(); // this is safe from overflow because `votingPeriod` and `gracePeriod` are capped so they will not combine // with unix time to exceed the max uint256 value unchecked { if (block.timestamp <= prop.creationTime + votingPeriod + gracePeriod) revert VotingNotEnded(); } // skip previous proposal processing requirement in case of escape hatch if (prop.proposalType != ProposalType.ESCAPE) if (proposals[prop.prevProposal].creationTime != 0) revert PrevNotProcessed(); didProposalPass = _countVotes(voteType, prop.yesVotes, prop.noVotes); if (didProposalPass) { // cannot realistically overflow on human timescales unchecked { if (prop.proposalType == ProposalType.MINT) for (uint256 i; i < prop.accounts.length; i++) { _mint(prop.accounts[i], prop.amounts[i]); } if (prop.proposalType == ProposalType.BURN) for (uint256 i; i < prop.accounts.length; i++) { _burn(prop.accounts[i], prop.amounts[i]); } if (prop.proposalType == ProposalType.CALL) for (uint256 i; i < prop.accounts.length; i++) { results = new bytes[](prop.accounts.length); (, bytes memory result) = prop.accounts[i].call{value: prop.amounts[i]} (prop.payloads[i]); results[i] = result; } // governance settings if (prop.proposalType == ProposalType.VPERIOD) if (prop.amounts[0] != 0) votingPeriod = uint32(prop.amounts[0]); if (prop.proposalType == ProposalType.GPERIOD) if (prop.amounts[0] != 0) gracePeriod = uint32(prop.amounts[0]); if (prop.proposalType == ProposalType.QUORUM) if (prop.amounts[0] != 0) quorum = uint32(prop.amounts[0]); if (prop.proposalType == ProposalType.SUPERMAJORITY) if (prop.amounts[0] != 0) supermajority = uint32(prop.amounts[0]); if (prop.proposalType == ProposalType.TYPE) proposalVoteTypes[ProposalType(prop.amounts[0])] = VoteType(prop.amounts[1]); if (prop.proposalType == ProposalType.PAUSE) _flipPause(); if (prop.proposalType == ProposalType.EXTENSION) for (uint256 i; i < prop.accounts.length; i++) { if (prop.amounts[i] != 0) extensions[prop.accounts[i]] = !extensions[prop.accounts[i]]; if (prop.payloads[i].length > 3) IKaliDAOextension(prop.accounts[i]) .setExtension(prop.payloads[i]); } if (prop.proposalType == ProposalType.ESCAPE) delete proposals[prop.amounts[0]]; if (prop.proposalType == ProposalType.DOCS) docs = prop.description; proposalStates[proposal].passed = true; } } delete proposals[proposal]; proposalStates[proposal].processed = true; emit ProposalProcessed(proposal, didProposalPass); } function _countVotes( VoteType voteType, uint256 yesVotes, uint256 noVotes ) internal view virtual returns (bool didProposalPass) { // fail proposal if no participation if (yesVotes == 0 && noVotes == 0) return false; // rule out any failed quorums if (voteType == VoteType.SIMPLE_MAJORITY_QUORUM_REQUIRED || voteType == VoteType.SUPERMAJORITY_QUORUM_REQUIRED) { uint256 minVotes = (totalSupply * quorum) / 100; // this is safe from overflow because `yesVotes` and `noVotes` // supply are checked in `KaliDAOtoken` contract unchecked { uint256 votes = yesVotes + noVotes; if (votes < minVotes) return false; } } // simple majority check if (voteType == VoteType.SIMPLE_MAJORITY || voteType == VoteType.SIMPLE_MAJORITY_QUORUM_REQUIRED) { if (yesVotes > noVotes) return true; // supermajority check } else { // example: 7 yes, 2 no, supermajority = 66 // ((7+2) * 66) / 100 = 5.94; 7 yes will pass uint256 minYes = ((yesVotes + noVotes) * supermajority) / 100; if (yesVotes >= minYes) return true; } } /*/////////////////////////////////////////////////////////////// EXTENSIONS //////////////////////////////////////////////////////////////*/ receive() external payable virtual {} modifier onlyExtension { if (!extensions[msg.sender]) revert NotExtension(); _; } function callExtension( address extension, uint256 amount, bytes calldata extensionData ) public payable nonReentrant virtual returns (bool mint, uint256 amountOut) { if (!extensions[extension]) revert NotExtension(); (mint, amountOut) = IKaliDAOextension(extension).callExtension{value: msg.value} (msg.sender, amount, extensionData); if (mint) { if (amountOut != 0) _mint(msg.sender, amountOut); } else { if (amountOut != 0) _burn(msg.sender, amount); } } function mintShares(address to, uint256 amount) public payable onlyExtension virtual { _mint(to, amount); } function burnShares(address from, uint256 amount) public payable onlyExtension virtual { _burn(from, amount); } } /// @notice Ricardian LLC formation interface. interface IRicardianLLC { function mintLLC(address to) external payable; } /// @notice Factory to deploy Kali DAO. contract KaliDAOfactory is Multicall { event DAOdeployed( KaliDAO indexed kaliDAO, string name, string symbol, string docs, bool paused, address[] extensions, bytes[] extensionsData, address[] voters, uint256[] shares, uint32[16] govSettings ); error NullDeploy(); address payable private immutable kaliMaster; IRicardianLLC private immutable ricardianLLC; constructor(address payable kaliMaster_, IRicardianLLC ricardianLLC_) { kaliMaster = kaliMaster_; ricardianLLC = ricardianLLC_; } function deployKaliDAO( string memory name_, string memory symbol_, string memory docs_, bool paused_, address[] memory extensions_, bytes[] memory extensionsData_, address[] calldata voters_, uint256[] calldata shares_, uint32[16] memory govSettings_ ) public payable virtual returns (KaliDAO kaliDAO) { kaliDAO = KaliDAO(_cloneAsMinimalProxy(kaliMaster, name_)); kaliDAO.init( name_, symbol_, docs_, paused_, extensions_, extensionsData_, voters_, shares_, govSettings_ ); bytes memory docs = bytes(docs_); if (docs.length == 0) { ricardianLLC.mintLLC{value: msg.value}(address(kaliDAO)); } emit DAOdeployed(kaliDAO, name_, symbol_, docs_, paused_, extensions_, extensionsData_, voters_, shares_, govSettings_); } /// @dev modified from Aelin (https://github.com/AelinXYZ/aelin/blob/main/contracts/MinimalProxyFactory.sol) function _cloneAsMinimalProxy(address payable base, string memory name_) internal virtual returns (address payable clone) { bytes memory createData = abi.encodePacked( // constructor bytes10(0x3d602d80600a3d3981f3), // proxy code bytes10(0x363d3d373d3d3d363d73), base, bytes15(0x5af43d82803e903d91602b57fd5bf3) ); bytes32 salt = keccak256(bytes(name_)); assembly { clone := create2( 0, // no value add(createData, 0x20), // data mload(createData), salt ) } // if CREATE2 fails for some reason, address(0) is returned if (clone == address(0)) revert NullDeploy(); } }
{ "optimizer": { "enabled": true, "runs": 11111 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address payable","name":"kaliMaster_","type":"address"},{"internalType":"contract IRicardianLLC","name":"ricardianLLC_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"NullDeploy","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract KaliDAO","name":"kaliDAO","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"string","name":"symbol","type":"string"},{"indexed":false,"internalType":"string","name":"docs","type":"string"},{"indexed":false,"internalType":"bool","name":"paused","type":"bool"},{"indexed":false,"internalType":"address[]","name":"extensions","type":"address[]"},{"indexed":false,"internalType":"bytes[]","name":"extensionsData","type":"bytes[]"},{"indexed":false,"internalType":"address[]","name":"voters","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"shares","type":"uint256[]"},{"indexed":false,"internalType":"uint32[16]","name":"govSettings","type":"uint32[16]"}],"name":"DAOdeployed","type":"event"},{"inputs":[{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"string","name":"docs_","type":"string"},{"internalType":"bool","name":"paused_","type":"bool"},{"internalType":"address[]","name":"extensions_","type":"address[]"},{"internalType":"bytes[]","name":"extensionsData_","type":"bytes[]"},{"internalType":"address[]","name":"voters_","type":"address[]"},{"internalType":"uint256[]","name":"shares_","type":"uint256[]"},{"internalType":"uint32[16]","name":"govSettings_","type":"uint32[16]"}],"name":"deployKaliDAO","outputs":[{"internalType":"contract KaliDAO","name":"kaliDAO","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"payable","type":"function"}]
Contract Creation Code
60c060405234801561001057600080fd5b50604051610eb0380380610eb083398101604081905261002f9161005e565b6001600160a01b039182166080521660a052610098565b6001600160a01b038116811461005b57600080fd5b50565b6000806040838503121561007157600080fd5b825161007c81610046565b602084015190925061008d81610046565b809150509250929050565b60805160a051610df46100bc60003960006101a30152600060920152610df46000f3fe6080604052600436106100295760003560e01c806309ef16021461002e578063ac9650d81461006b575b600080fd5b61004161003c366004610860565b61008b565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b61007e6100793660046109af565b610274565b6040516100629190610ac0565b60006100b77f00000000000000000000000000000000000000000000000000000000000000008d6103e4565b6040517f97b55f8100000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff8216906397b55f8190610120908f908f908f908f908f908f908f908f908f908f908f90600401610b9f565b600060405180830381600087803b15801561013a57600080fd5b505af115801561014e573d6000803e3d6000fd5b50508b518c92506000039050610202576040517f6f0a5e7100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301527f00000000000000000000000000000000000000000000000000000000000000001690636f0a5e719034906024016000604051808303818588803b1580156101e857600080fd5b505af11580156101fc573d6000803e3d6000fd5b50505050505b8173ffffffffffffffffffffffffffffffffffffffff167f0712ea2ebe8ee974f78171c5f86c898cc0e2858fb69ed676083f8c60ee84ab128e8e8e8e8e8e8e8e8e8e8e60405161025c9b9a99989796959493929190610b9f565b60405180910390a2509b9a5050505050505050505050565b60608167ffffffffffffffff81111561028f5761028f61050b565b6040519080825280602002602001820160405280156102c257816020015b60608152602001906001900390816102ad5790505b50905060005b828110156103dd57600080308686858181106102e6576102e6610c90565b90506020028101906102f89190610cbf565b604051610306929190610d24565b600060405180830381855af49150503d8060008114610341576040519150601f19603f3d011682016040523d82523d6000602084013e610346565b606091505b5091509150816103b55760448151101561035f57600080fd5b600481019050808060200190518101906103799190610d34565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103ac9190610dab565b60405180910390fd5b808484815181106103c8576103c8610c90565b602090810291909101015250506001016102c8565b5092915050565b6040517f3d602d80600a3d3981f30000000000000000000000000000000000000000000060208201527f363d3d373d3d3d363d7300000000000000000000000000000000000000000000602a8201527fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606084901b1660348201527f5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000604882015260009081906057016040516020818303038152906040529050600083805190602001209050808251602084016000f5925073ffffffffffffffffffffffffffffffffffffffff8316610503576040517f8b1f004000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156105815761058161050b565b604052919050565b600067ffffffffffffffff8211156105a3576105a361050b565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60006105e26105dd84610589565b61053a565b90508281528383830111156105f657600080fd5b828260208301376000602084830101529392505050565b600082601f83011261061e57600080fd5b61062d838335602085016105cf565b9392505050565b8035801515811461064457600080fd5b919050565b600067ffffffffffffffff8211156106635761066361050b565b5060051b60200190565b803573ffffffffffffffffffffffffffffffffffffffff8116811461064457600080fd5b600082601f8301126106a257600080fd5b813560206106b26105dd83610649565b82815260059290921b840181019181810190868411156106d157600080fd5b8286015b848110156106f3576106e68161066d565b83529183019183016106d5565b509695505050505050565b600082601f83011261070f57600080fd5b8135602061071f6105dd83610649565b82815260059290921b8401810191818101908684111561073e57600080fd5b8286015b848110156106f357803567ffffffffffffffff8111156107625760008081fd5b8701603f810189136107745760008081fd5b6107858986830135604084016105cf565b845250918301918301610742565b60008083601f8401126107a557600080fd5b50813567ffffffffffffffff8111156107bd57600080fd5b6020830191508360208260051b85010111156107d857600080fd5b9250929050565b600082601f8301126107f057600080fd5b60405161020080820182811067ffffffffffffffff821117156108155761081561050b565b6040528301818582111561082857600080fd5b845b8281101561085557803563ffffffff811681146108475760008081fd5b82526020918201910161082a565b509195945050505050565b60008060008060008060008060008060006103008c8e03121561088257600080fd5b67ffffffffffffffff808d35111561089957600080fd5b6108a68e8e358f0161060d565b9b508060208e013511156108b957600080fd5b6108c98e60208f01358f0161060d565b9a508060408e013511156108dc57600080fd5b6108ec8e60408f01358f0161060d565b99506108fa60608e01610634565b98508060808e0135111561090d57600080fd5b61091d8e60808f01358f01610691565b97508060a08e0135111561093057600080fd5b6109408e60a08f01358f016106fe565b96508060c08e0135111561095357600080fd5b6109638e60c08f01358f01610793565b909650945060e08d013581101561097957600080fd5b5061098a8d60e08e01358e01610793565b909350915061099d8d6101008e016107df565b90509295989b509295989b9093969950565b600080602083850312156109c257600080fd5b823567ffffffffffffffff8111156109d957600080fd5b6109e585828601610793565b90969095509350505050565b60005b83811015610a0c5781810151838201526020016109f4565b83811115610a1b576000848401525b50505050565b60008151808452610a398160208601602086016109f1565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600081518084526020808501808196508360051b8101915082860160005b85811015610ab3578284038952610aa1848351610a21565b98850198935090840190600101610a89565b5091979650505050505050565b60208152600061062d6020830184610a6b565b8183526000602080850194508260005b85811015610b1c5773ffffffffffffffffffffffffffffffffffffffff610b098361066d565b1687529582019590820190600101610ae3565b509495945050505050565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115610b5957600080fd5b8260051b8083602087013760009401602001938452509192915050565b8060005b6010811015610a1b57815163ffffffff16845260209384019390910190600101610b7a565b6000610300808352610bb38184018f610a21565b9050602083820381850152610bc8828f610a21565b91508382036040850152610bdc828e610a21565b8c1515606086015284810360808601528b51808252828d0193509082019060005b81811015610c2f57845173ffffffffffffffffffffffffffffffffffffffff1683529383019391830191600101610bfd565b505084810360a0860152610c43818c610a6b565b9250505082810360c0840152610c5a81888a610ad3565b905082810360e0840152610c6f818688610b27565b915050610c80610100830184610b76565b9c9b505050505050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610cf457600080fd5b83018035915067ffffffffffffffff821115610d0f57600080fd5b6020019150368190038213156107d857600080fd5b8183823760009101908152919050565b600060208284031215610d4657600080fd5b815167ffffffffffffffff811115610d5d57600080fd5b8201601f81018413610d6e57600080fd5b8051610d7c6105dd82610589565b818152856020838501011115610d9157600080fd5b610da28260208301602086016109f1565b95945050505050565b60208152600061062d6020830184610a2156fea2646970667358221220bdb2ae1b307d94c21d1bca8d14c3e98d6f59896c8436e26b68eab4ea0dd5348864736f6c634300080e00330000000000000000000000000d46996d55bb33d32d43e610aac5b64b477e9cbd000000000000000000000000581b5e51ffbb742f92e818fb177cad8a30e43f3e
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000d46996d55bb33d32d43e610aac5b64b477e9cbd000000000000000000000000581b5e51ffbb742f92e818fb177cad8a30e43f3e
-----Decoded View---------------
Arg [0] : kaliMaster_ (address): 0x0D46996D55bB33D32D43E610aac5B64b477e9cBD
Arg [1] : ricardianLLC_ (address): 0x581b5E51fFBB742f92E818Fb177CAD8a30e43f3E
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000000d46996d55bb33d32d43e610aac5b64b477e9cbd
Arg [1] : 000000000000000000000000581b5e51ffbb742f92e818fb177cad8a30e43f3e
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.