Skip to Content

@cfxdevkit/compiler


@cfxdevkit/compiler / TEST_CONTRACTS

Variable: TEST_CONTRACTS

const TEST_CONTRACTS: object

Defined in: templates/index.ts:52

Registry of all bundled test contracts.

Keys are the contract names that appear in the ABI.

Type Declaration

BasicNFT

readonly BasicNFT: object

BasicNFT.description

readonly description: "ERC-721 NFT from scratch — teaches token ownership, approvals, transfer" = 'ERC-721 NFT from scratch — teaches token ownership, approvals, transfer'

BasicNFT.getCompiled()

readonly getCompiled: () => CompilationOutput = getERC721Contract

Returns

CompilationOutput

BasicNFT.name

readonly name: "BasicNFT" = 'BasicNFT'

BasicNFT.source

readonly source: ”// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\n/**\n * @title BasicNFT\n * @notice Minimal ERC-721 implementation from scratch.\n * Teaches: mappings, token ownership, approval patterns, events.\n */\ncontract BasicNFT {\n string public name;\n string public symbol;\n address public owner;\n uint256 public nextTokenId;\n\n mapping(uint256 => address) private _ownerOf;\n mapping(address => uint256) private _balanceOf;\n mapping(uint256 => address) private _approved;\n mapping(address => mapping(address => bool)) private _operatorApprovals;\n mapping(uint256 => string) private _tokenURIs;\n\n event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n event Approval(address indexed tokenOwner, address indexed approved, uint256 indexed tokenId);\n event ApprovalForAll(address indexed tokenOwner, address indexed operator, bool approved);\n\n modifier onlyOwner() {\n require(msg.sender == owner, “BasicNFT: not the owner”);\n _;\n }\n\n constructor(string memory _name, string memory _symbol) {\n name = _name;\n symbol = _symbol;\n owner = msg.sender;\n }\n\n function balanceOf(address account) public view returns (uint256) {\n require(account != address(0), “BasicNFT: zero address”);\n return _balanceOf[account];\n }\n\n function ownerOf(uint256 tokenId) public view returns (address) {\n address tokenOwner = _ownerOf[tokenId];\n require(tokenOwner != address(0), “BasicNFT: token does not exist”);\n return tokenOwner;\n }\n\n function tokenURI(uint256 tokenId) public view returns (string memory) {\n require(_ownerOf[tokenId] != address(0), “BasicNFT: token does not exist”);\n return _tokenURIs[tokenId];\n }\n\n /// @notice Mint a new token to `to` with metadata URI `uri`.\n function mint(address to, string calldata uri) external onlyOwner returns (uint256) {\n require(to != address(0), “BasicNFT: mint to zero address”);\n uint256 tokenId = nextTokenId++;\n _ownerOf[tokenId] = to;\n _balanceOf[to]++;\n _tokenURIs[tokenId] = uri;\n emit Transfer(address(0), to, tokenId);\n return tokenId;\n }\n\n function approve(address to, uint256 tokenId) external {\n address tokenOwner = ownerOf(tokenId);\n require(msg.sender == tokenOwner || _operatorApprovals[tokenOwner][msg.sender],\n “BasicNFT: not authorized”);\n _approved[tokenId] = to;\n emit Approval(tokenOwner, to, tokenId);\n }\n\n function getApproved(uint256 tokenId) public view returns (address) {\n require(_ownerOf[tokenId] != address(0), “BasicNFT: token does not exist”);\n return _approved[tokenId];\n }\n\n function setApprovalForAll(address operator, bool approved) external {\n require(operator != msg.sender, “BasicNFT: approve to caller”);\n _operatorApprovals[msg.sender][operator] = approved;\n emit ApprovalForAll(msg.sender, operator, approved);\n }\n\n function isApprovedForAll(address tokenOwner, address operator) public view returns (bool) {\n return _operatorApprovals[tokenOwner][operator];\n }\n\n function transferFrom(address from, address to, uint256 tokenId) public {\n require(to != address(0), “BasicNFT: transfer to zero address”);\n address tokenOwner = ownerOf(tokenId);\n require(tokenOwner == from, “BasicNFT: wrong from address”);\n require(\n msg.sender == tokenOwner ||\n msg.sender == _approved[tokenId] ||\n _operatorApprovals[tokenOwner][msg.sender],\n “BasicNFT: not authorized”\n );\n _balanceOf[from]—;\n _balanceOf[to]++;\n _ownerOf[tokenId] = to;\n delete _approved[tokenId];\n emit Transfer(from, to, tokenId);\n }\n}” = ERC721_SOURCE

Counter

readonly Counter: object

Counter.description

readonly description: "Ownable step counter with increment/decrement/reset — ideal first contract" = 'Ownable step counter with increment/decrement/reset — ideal first contract'

Counter.getCompiled()

readonly getCompiled: () => CompilationOutput = getCounterContract

Returns

CompilationOutput

Counter.name

readonly name: "Counter" = 'Counter'

Counter.source

readonly source: ”// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\n/**\n * @title Counter\n * @notice A simple counter contract — great first contract to understand\n * state variables, modifiers, events, and ownership.\n */\ncontract Counter {\n uint256 public count;\n address public owner;\n uint256 public step;\n\n event CountChanged(uint256 indexed previous, uint256 indexed current, address indexed by);\n event StepChanged(uint256 newStep);\n\n modifier onlyOwner() {\n require(msg.sender == owner, “Counter: not the owner”);\n _;\n }\n\n constructor() {\n owner = msg.sender;\n step = 1;\n }\n\n /// @notice Increment the counter by `step`.\n function increment() external {\n uint256 prev = count;\n count += step;\n emit CountChanged(prev, count, msg.sender);\n }\n\n /// @notice Decrement the counter by `step` (reverts on underflow).\n function decrement() external {\n require(count >= step, “Counter: underflow”);\n uint256 prev = count;\n count -= step;\n emit CountChanged(prev, count, msg.sender);\n }\n\n /// @notice Reset the counter to zero (owner only).\n function reset() external onlyOwner {\n uint256 prev = count;\n count = 0;\n emit CountChanged(prev, 0, msg.sender);\n }\n\n /// @notice Change the increment/decrement step (owner only).\n function setStep(uint256 newStep) external onlyOwner {\n require(newStep > 0, “Counter: step must be > 0”);\n step = newStep;\n emit StepChanged(newStep);\n }\n}” = COUNTER_SOURCE

Escrow

readonly Escrow: object

Escrow.description

readonly description: "Three-party escrow with arbiter — teaches payable, state machines, CFX transfers" = 'Three-party escrow with arbiter — teaches payable, state machines, CFX transfers'

Escrow.getCompiled()

readonly getCompiled: () => CompilationOutput = getEscrowContract

Returns

CompilationOutput

Escrow.name

readonly name: "Escrow" = 'Escrow'

Escrow.source

readonly source: ”// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\n/**\n * @title Escrow\n * @notice A three-party escrow contract. The depositor locks ETH/CFX, the\n * arbiter decides to release funds to the beneficiary or refund the\n * depositor. Teaches: payable functions, value transfers, state machines.\n */\ncontract Escrow {\n enum State { AWAITING_PAYMENT, AWAITING_DELIVERY, COMPLETE, REFUNDED }\n\n address public depositor;\n address public beneficiary;\n address public arbiter;\n uint256 public amount;\n State public state;\n\n event Deposited(address indexed depositor, uint256 amount);\n event Released(address indexed beneficiary, uint256 amount);\n event Refunded(address indexed depositor, uint256 amount);\n\n modifier onlyArbiter() {\n require(msg.sender == arbiter, “Escrow: not the arbiter”);\n _;\n }\n\n modifier inState(State expected) {\n require(state == expected, “Escrow: invalid state”);\n _;\n }\n\n /// @param _arbiter Trusted third party who can release or refund\n /// @param _beneficiary Address that will receive funds on approval\n constructor(address _arbiter, address _beneficiary) {\n require(_arbiter != address(0) && _beneficiary != address(0), “Escrow: zero address”);\n arbiter = _arbiter;\n beneficiary = _beneficiary;\n depositor = msg.sender;\n state = State.AWAITING_PAYMENT;\n }\n\n /// @notice Deposit funds into escrow. Must be called by the depositor.\n function deposit() external payable inState(State.AWAITING_PAYMENT) {\n require(msg.sender == depositor, “Escrow: only depositor can fund”);\n require(msg.value > 0, “Escrow: must send CFX”);\n amount = msg.value;\n state = State.AWAITING_DELIVERY;\n emit Deposited(msg.sender, msg.value);\n }\n\n /// @notice Release funds to the beneficiary (arbiter only).\n function release() external onlyArbiter inState(State.AWAITING_DELIVERY) {\n state = State.COMPLETE;\n uint256 bal = address(this).balance;\n payable(beneficiary).transfer(bal);\n emit Released(beneficiary, bal);\n }\n\n /// @notice Refund depositor (arbiter only).\n function refund() external onlyArbiter inState(State.AWAITING_DELIVERY) {\n state = State.REFUNDED;\n uint256 bal = address(this).balance;\n payable(depositor).transfer(bal);\n emit Refunded(depositor, bal);\n }\n\n /// @notice Returns the current balance held in escrow.\n function balance() external view returns (uint256) {\n return address(this).balance;\n }\n\n /// @notice Human-readable state name.\n function stateName() external view returns (string memory) {\n if (state == State.AWAITING_PAYMENT) return “AWAITING_PAYMENT”;\n if (state == State.AWAITING_DELIVERY) return “AWAITING_DELIVERY”;\n if (state == State.COMPLETE) return “COMPLETE”;\n return “REFUNDED”;\n }\n}” = ESCROW_SOURCE

MultiSigWallet

readonly MultiSigWallet: object

MultiSigWallet.description

readonly description: "M-of-N multi-signature wallet — teaches collective governance and low-level call" = 'M-of-N multi-signature wallet — teaches collective governance and low-level call'

MultiSigWallet.getCompiled()

readonly getCompiled: () => CompilationOutput = getMultiSigContract

Returns

CompilationOutput

MultiSigWallet.name

readonly name: "MultiSigWallet" = 'MultiSigWallet'

MultiSigWallet.source

readonly source: ”// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\n/**\n * @title MultiSigWallet\n * @notice M-of-N multisig wallet. Teaches: dynamic arrays, structs, the\n * low-level call pattern, and collaborative governance primitives.\n */\ncontract MultiSigWallet {\n struct Transaction {\n address to;\n uint256 value;\n bytes data;\n bool executed;\n uint256 confirmCount;\n }\n\n address[] public owners;\n uint256 public required;\n mapping(address => bool) public isOwner;\n Transaction[] public transactions;\n mapping(uint256 => mapping(address => bool)) public confirmed;\n\n event Deposit(address indexed sender, uint256 amount);\n event TransactionSubmitted(uint256 indexed txId, address indexed to, uint256 value);\n event TransactionConfirmed(uint256 indexed txId, address indexed owner);\n event ConfirmationRevoked(uint256 indexed txId, address indexed owner);\n event TransactionExecuted(uint256 indexed txId);\n\n modifier onlyOwner() {\n require(isOwner[msg.sender], “MultiSig: not an owner”);\n _;\n }\n\n modifier txExists(uint256 txId) {\n require(txId < transactions.length, “MultiSig: tx does not exist”);\n _;\n }\n\n modifier notExecuted(uint256 txId) {\n require(!transactions[txId].executed, “MultiSig: already executed”);\n _;\n }\n\n modifier notConfirmed(uint256 txId) {\n require(!confirmed[txId][msg.sender], “MultiSig: already confirmed”);\n _;\n }\n\n /// @param _owners List of owner addresses (no duplicates, no zero address)\n /// @param _required Number of confirmations needed to execute a transaction\n constructor(address[] memory _owners, uint256 _required) {\n require(_owners.length > 0, “MultiSig: need at least one owner”);\n require(_required > 0 && _required <= _owners.length, “MultiSig: invalid required count”);\n\n for (uint256 i = 0; i < _owners.length; i++) {\n address o = _owners[i];\n require(o != address(0), “MultiSig: zero address owner”);\n require(!isOwner[o], “MultiSig: duplicate owner”);\n isOwner[o] = true;\n owners.push(o);\n }\n required = _required;\n }\n\n receive() external payable {\n emit Deposit(msg.sender, msg.value);\n }\n\n /// @notice Submit a new transaction for confirmation.\n function submitTransaction(address to, uint256 value, bytes calldata data)\n external onlyOwner returns (uint256 txId)\n {\n txId = transactions.length;\n transactions.push(Transaction({ to: to, value: value, data: data, executed: false, confirmCount: 0 }));\n emit TransactionSubmitted(txId, to, value);\n }\n\n /// @notice Confirm a pending transaction.\n function confirmTransaction(uint256 txId)\n external onlyOwner txExists(txId) notExecuted(txId) notConfirmed(txId)\n {\n confirmed[txId][msg.sender] = true;\n transactions[txId].confirmCount++;\n emit TransactionConfirmed(txId, msg.sender);\n }\n\n /// @notice Revoke your confirmation for a pending transaction.\n function revokeConfirmation(uint256 txId)\n external onlyOwner txExists(txId) notExecuted(txId)\n {\n require(confirmed[txId][msg.sender], “MultiSig: not confirmed”);\n confirmed[txId][msg.sender] = false;\n transactions[txId].confirmCount—;\n emit ConfirmationRevoked(txId, msg.sender);\n }\n\n /// @notice Execute a transaction once it has enough confirmations.\n function executeTransaction(uint256 txId)\n external onlyOwner txExists(txId) notExecuted(txId)\n {\n Transaction storage txn = transactions[txId];\n require(txn.confirmCount >= required, “MultiSig: not enough confirmations”);\n txn.executed = true;\n (bool success, ) = txn.to.call{value: txn.value}(txn.data);\n require(success, “MultiSig: execution failed”);\n emit TransactionExecuted(txId);\n }\n\n /// @notice Contract’s current CFX balance.\n function balance() external view returns (uint256) {\n return address(this).balance;\n }\n\n /// @notice Total number of submitted transactions.\n function transactionCount() external view returns (uint256) {\n return transactions.length;\n }\n\n /// @notice List all owner addresses.\n function getOwners() external view returns (address[] memory) {\n return owners;\n }\n}” = MULTISIG_SOURCE

Registry

readonly Registry: object

Registry.description

readonly description: "On-chain name registry — teaches keccak256 keys, mappings, and string storage" = 'On-chain name registry — teaches keccak256 keys, mappings, and string storage'

Registry.getCompiled()

readonly getCompiled: () => CompilationOutput = getRegistryContract

Returns

CompilationOutput

Registry.name

readonly name: "Registry" = 'Registry'

Registry.source

readonly source: ”// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\n/**\n * @title Registry\n * @notice A name-service-style registry. Any account can register a unique\n * human-readable name and point it to an address (or any string of\n * metadata). Teaches: keccak256 hashing, mapping lookups, require.\n */\ncontract Registry {\n struct Record {\n address owner;\n string value; // arbitrary value, e.g. an address string or URL\n uint256 createdAt;\n uint256 updatedAt;\n }\n\n mapping(bytes32 => Record) private _records; // keccak256(name) → Record\n mapping(address => string[]) private _ownedNames;\n\n event NameRegistered(string indexed name, address indexed owner, string value);\n event NameUpdated(string indexed name, address indexed owner, string newValue);\n event NameReleased(string indexed name, address indexed owner);\n\n modifier onlyNameOwner(string calldata name) {\n require(_records[_key(name)].owner == msg.sender, “Registry: not the name owner”);\n _;\n }\n\n /// @notice Register `name` pointing to `value`. Name must not already be taken.\n function register(string calldata name, string calldata value) external {\n require(bytes(name).length > 0, “Registry: empty name”);\n bytes32 key = _key(name);\n require(_records[key].owner == address(0), “Registry: name already taken”);\n _records[key] = Record({\n owner: msg.sender,\n value: value,\n createdAt: block.timestamp,\n updatedAt: block.timestamp\n });\n _ownedNames[msg.sender].push(name);\n emit NameRegistered(name, msg.sender, value);\n }\n\n /// @notice Update the value stored under a name you own.\n function update(string calldata name, string calldata newValue)\n external onlyNameOwner(name)\n {\n bytes32 key = _key(name);\n _records[key].value = newValue;\n _records[key].updatedAt = block.timestamp;\n emit NameUpdated(name, msg.sender, newValue);\n }\n\n /// @notice Release a name you own, making it available for re-registration.\n function release(string calldata name) external onlyNameOwner(name) {\n bytes32 key = _key(name);\n emit NameReleased(name, msg.sender);\n delete _records[key];\n }\n\n /// @notice Resolve a name to its stored value.\n function resolve(string calldata name) external view returns (string memory) {\n return _records[_key(name)].value;\n }\n\n /// @notice Return the full record for a name.\n function lookup(string calldata name)\n external view\n returns (address nameOwner, string memory value, uint256 createdAt, uint256 updatedAt)\n {\n Record storage r = _records[_key(name)];\n return (r.owner, r.value, r.createdAt, r.updatedAt);\n }\n\n /// @notice Check whether a name is available (not yet registered).\n function isAvailable(string calldata name) external view returns (bool) {\n return _records[_key(name)].owner == address(0);\n }\n\n /// @notice Return all names registered by `account`.\n function namesOf(address account) external view returns (string[] memory) {\n return _ownedNames[account];\n }\n\n function _key(string calldata name) private pure returns (bytes32) {\n return keccak256(bytes(name));\n }\n}” = REGISTRY_SOURCE

SimpleStorage

readonly SimpleStorage: object

SimpleStorage.description

readonly description: "Simple value-storage contract — useful for deployment smoke tests" = 'Simple value-storage contract — useful for deployment smoke tests'

SimpleStorage.getCompiled()

readonly getCompiled: () => CompilationOutput = getSimpleStorageContract

Get the compiled SimpleStorage contract artefact.

The result is memoised: compilation only runs once per process.

Returns

CompilationOutput

Throws

Error if solc compilation fails

Example
const { bytecode, abi } = getSimpleStorageContract(); // Deploy with a `uint256 initialValue` constructor argument

SimpleStorage.name

readonly name: "SimpleStorage" = 'SimpleStorage'

SimpleStorage.source

readonly source: ”// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\ncontract SimpleStorage {\n uint256 private storedValue;\n address public owner;\n\n event ValueChanged(uint256 indexed oldValue, uint256 indexed newValue, address indexed changedBy);\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n modifier onlyOwner() {\n require(msg.sender == owner, “SimpleStorage: caller is not the owner”);\n _;\n }\n\n constructor(uint256 initialValue) {\n storedValue = initialValue;\n owner = msg.sender;\n emit ValueChanged(0, initialValue, msg.sender);\n }\n\n function set(uint256 newValue) public {\n uint256 oldValue = storedValue;\n storedValue = newValue;\n emit ValueChanged(oldValue, newValue, msg.sender);\n }\n\n function get() public view returns (uint256) {\n return storedValue;\n }\n\n function increment() public {\n uint256 oldValue = storedValue;\n storedValue += 1;\n emit ValueChanged(oldValue, storedValue, msg.sender);\n }\n\n function transferOwnership(address newOwner) public onlyOwner {\n require(newOwner != address(0), “SimpleStorage: new owner is the zero address”);\n emit OwnershipTransferred(owner, newOwner);\n owner = newOwner;\n }\n}” = SIMPLE_STORAGE_SOURCE

TestToken

readonly TestToken: object

TestToken.description

readonly description: "Minimal ERC20-compatible token with mint/burn — useful for DEX and approval tests" = 'Minimal ERC20-compatible token with mint/burn — useful for DEX and approval tests'

TestToken.getCompiled()

readonly getCompiled: () => CompilationOutput = getTestTokenContract

Get the compiled TestToken contract artefact.

The result is memoised: compilation only runs once per process.

Returns

CompilationOutput

Throws

Error if solc compilation fails

Example
const { bytecode, abi } = getTestTokenContract(); // Deploy with (name, symbol, initialSupply) constructor args

TestToken.name

readonly name: "TestToken" = 'TestToken'

TestToken.source

readonly source: ”// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\ncontract TestToken {\n string public name;\n string public symbol;\n uint8 public constant decimals = 18;\n uint256 public totalSupply;\n\n mapping(address => uint256) private balances;\n mapping(address => mapping(address => uint256)) private allowances;\n\n event Transfer(address indexed from, address indexed to, uint256 value);\n event Approval(address indexed owner, address indexed spender, uint256 value);\n\n constructor(string memory _name, string memory _symbol, uint256 _initialSupply) {\n name = _name;\n symbol = _symbol;\n totalSupply = _initialSupply * 10 ** decimals;\n balances[msg.sender] = totalSupply;\n emit Transfer(address(0), msg.sender, totalSupply);\n }\n\n function balanceOf(address account) public view returns (uint256) {\n return balances[account];\n }\n\n function allowance(address owner, address spender) public view returns (uint256) {\n return allowances[owner][spender];\n }\n\n function transfer(address to, uint256 amount) public returns (bool) {\n require(to != address(0), “TestToken: transfer to zero address”);\n require(balances[msg.sender] >= amount, “TestToken: insufficient balance”);\n balances[msg.sender] -= amount;\n balances[to] += amount;\n emit Transfer(msg.sender, to, amount);\n return true;\n }\n\n function approve(address spender, uint256 amount) public returns (bool) {\n require(spender != address(0), “TestToken: approve to zero address”);\n allowances[msg.sender][spender] = amount;\n emit Approval(msg.sender, spender, amount);\n return true;\n }\n\n function transferFrom(address from, address to, uint256 amount) public returns (bool) {\n require(from != address(0), “TestToken: transfer from zero address”);\n require(to != address(0), “TestToken: transfer to zero address”);\n require(balances[from] >= amount, “TestToken: insufficient balance”);\n require(allowances[from][msg.sender] >= amount, “TestToken: insufficient allowance”);\n balances[from] -= amount;\n balances[to] += amount;\n allowances[from][msg.sender] -= amount;\n emit Transfer(from, to, amount);\n return true;\n }\n\n function mint(address to, uint256 amount) public {\n require(to != address(0), “TestToken: mint to zero address”);\n totalSupply += amount;\n balances[to] += amount;\n emit Transfer(address(0), to, amount);\n }\n\n function burn(uint256 amount) public {\n require(balances[msg.sender] >= amount, “TestToken: burn amount exceeds balance”);\n balances[msg.sender] -= amount;\n totalSupply -= amount;\n emit Transfer(msg.sender, address(0), amount);\n }\n}” = TEST_TOKEN_SOURCE

Voting

readonly Voting: object

Voting.description

readonly description: "Ballot contract with delegation — teaches structs, weighted votes, governance" = 'Ballot contract with delegation — teaches structs, weighted votes, governance'

Voting.getCompiled()

readonly getCompiled: () => CompilationOutput = getVotingContract

Returns

CompilationOutput

Voting.name

readonly name: "Voting" = 'Voting'

Voting.source

readonly source: ”// SPDX-License-Identifier: MIT\npragma solidity ^0.8.20;\n\n/**\n * @title Voting\n * @notice A simple ballot contract. The chairperson registers voters and\n * proposals. Voters cast one vote (or delegate). Teaches structs,\n * mappings, weighted voting, and delegation.\n */\ncontract Voting {\n struct Voter {\n bool registered;\n bool voted;\n address delegate;\n uint256 vote; // index of the voted proposal\n uint256 weight; // delegated weight (starts at 1 for registered voters)\n }\n\n struct Proposal {\n string name;\n uint256 voteCount;\n }\n\n address public chairperson;\n mapping(address => Voter) public voters;\n Proposal[] public proposals;\n bool public votingOpen;\n\n event VoterRegistered(address indexed voter);\n event VoteCast(address indexed voter, uint256 indexed proposalIndex);\n event VoteDelegated(address indexed from, address indexed to);\n event VotingStatusChanged(bool open);\n\n modifier onlyChairperson() {\n require(msg.sender == chairperson, “Voting: not the chairperson”);\n _;\n }\n\n modifier whenOpen() {\n require(votingOpen, “Voting: voting is not open”);\n _;\n }\n\n /// @param proposalNames Array of human-readable proposal names\n constructor(string[] memory proposalNames) {\n chairperson = msg.sender;\n voters[chairperson].weight = 1;\n\n for (uint256 i = 0; i < proposalNames.length; i++) {\n proposals.push(Proposal({ name: proposalNames[i], voteCount: 0 }));\n }\n }\n\n /// @notice Open or close the voting period.\n function setVotingOpen(bool open) external onlyChairperson {\n votingOpen = open;\n emit VotingStatusChanged(open);\n }\n\n /// @notice Register a voter (chairperson only; must be done before they vote).\n function registerVoter(address voter) external onlyChairperson {\n require(!voters[voter].registered, “Voting: already registered”);\n voters[voter] = Voter({ registered: true, voted: false, delegate: address(0), vote: 0, weight: 1 });\n emit VoterRegistered(voter);\n }\n\n /// @notice Delegate your vote to `to`.\n function delegate(address to) external whenOpen {\n Voter storage sender = voters[msg.sender];\n require(sender.registered, “Voting: not registered”);\n require(!sender.voted, “Voting: already voted”);\n require(to != msg.sender, “Voting: self-delegation”);\n\n // Follow delegation chain (detect loops)\n address delegatee = to;\n while (voters[delegatee].delegate != address(0)) {\n delegatee = voters[delegatee].delegate;\n require(delegatee != msg.sender, “Voting: delegation loop”);\n }\n sender.voted = true;\n sender.delegate = delegatee;\n Voter storage d = voters[delegatee];\n if (d.voted) {\n proposals[d.vote].voteCount += sender.weight;\n } else {\n d.weight += sender.weight;\n }\n emit VoteDelegated(msg.sender, delegatee);\n }\n\n /// @notice Cast your vote for proposal at `proposalIndex`.\n function vote(uint256 proposalIndex) external whenOpen {\n Voter storage sender = voters[msg.sender];\n require(sender.registered, “Voting: not registered”);\n require(!sender.voted, “Voting: already voted”);\n require(proposalIndex < proposals.length, “Voting: invalid proposal”);\n sender.voted = true;\n sender.vote = proposalIndex;\n proposals[proposalIndex].voteCount += sender.weight;\n emit VoteCast(msg.sender, proposalIndex);\n }\n\n /// @notice Returns the index of the winning proposal.\n function winningProposal() public view returns (uint256 winnerIndex) {\n uint256 maxVotes;\n for (uint256 i = 0; i < proposals.length; i++) {\n if (proposals[i].voteCount > maxVotes) {\n maxVotes = proposals[i].voteCount;\n winnerIndex = i;\n }\n }\n }\n\n /// @notice Returns the name of the winning proposal.\n function winnerName() external view returns (string memory) {\n return proposals[winningProposal()].name;\n }\n\n /// @notice Total number of proposals.\n function proposalCount() external view returns (uint256) {\n return proposals.length;\n }\n}” = VOTING_SOURCE