Archived Code

Athena Contract

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol";

//athena should probably inherit the functions from OpenWorkDAOAthena 

contract Athena is Initializable, UUPSUpgradeable, OwnableUpgradeable, ReentrancyGuardUpgradeable {
    using SafeERC20Upgradeable for IERC20Upgradeable;
    using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;



    event MemberAdditionProposalCreated(uint256 indexed proposalId, string oracleName, address candidate);
    event MemberAdded(string oracleName, address candidate);
    event MemberRemovalProposalCreated(uint256 indexed proposalId, string oracleName, address candidate);
    event MemberRemoved(string oracleName, address candidate);
    event SkillVerificationProposalCreated(uint256 indexed proposalId, string oracleName, address candidate, string skill);
    event SkillVerified(string oracleName, address candidate, string skill);
    event MembershipFinalized(string oracleName, address candidate);

    // Function to create a proposal for adding a new member
    function proposeAddMember(string memory oracleName, address candidate) public {
        require(oracles[oracleName].isActive, "Oracle is not active");
        require(oracles[oracleName].members.contains(msg.sender), "Only current members can propose");
        
        uint256 proposalId = createProposal(oracleName, "Add new member");
        proposals[proposalId].candidate = candidate;

        emit MemberAdditionProposalCreated(proposalId, oracleName, candidate);
    }

    // Function to create a proposal for removing a member
    function proposeRemoveMember(string memory oracleName, address candidate) public {
        require(oracles[oracleName].isActive, "Oracle is not active");
        require(oracles[oracleName].members.contains(msg.sender), "Only current members can propose");
        require(oracles[oracleName].members.contains(candidate), "Candidate is not a member");

        uint256 proposalId = createProposal(oracleName, "Remove member");
        proposals[proposalId].candidate = candidate;

        emit MemberRemovalProposalCreated(proposalId, oracleName, candidate);
    }

    // Function to create a proposal for verifying a member's skill
    function proposeVerifySkill(string memory oracleName, address candidate, string memory skill) public {
        require(oracles[oracleName].isActive, "Oracle is not active");
        require(oracles[oracleName].members.contains(msg.sender), "Only current members can propose");

        uint256 proposalId = createProposal(oracleName, "Verify skill: " + skill);
        proposals[proposalId].candidate = candidate;
        proposals[proposalId].skill = skill;

        emit SkillVerificationProposalCreated(proposalId, oracleName, candidate, skill);
    }

    // Function to execute skill verification proposal
    function executeSkillVerification(string memory oracleName, uint256 proposalId) public {
        Proposal storage proposal = proposals[proposalId];
        require(proposal.executed == false, "Proposal already executed");
        require(proposal.votesFor > proposal.votesAgainst, "Proposal did not pass");
        require(block.timestamp >= proposal.startTime + MIN_VOTING_DURATION, "Voting period not yet finished");

        emit SkillVerified(oracleName, proposal.candidate, proposal.skill);
        proposal.executed = true;
    }

    // Function to execute removal of a member
    function executeRemoveMember(string memory oracleName, uint256 proposalId) public {
        Proposal storage proposal = proposals[proposalId];
        require(proposal.executed == false, "Proposal already executed");
        require(proposal.votesFor > proposal.votesAgainst, "Proposal did not pass");
        require(block.timestamp >= proposal.startTime + MIN_VOTING_DURATION, "Voting period not yet finished");
        require(oracles[oracleName].members.contains(proposal.candidate), "Candidate is not a member");

        oracles[oracleName].members.remove(proposal.candidate);
        proposal.executed = true;
        emit MemberRemoved(oracleName, proposal.candidate);
    }

    // Function to stake tokens and join the oracle after a proposal is approved
    function stakeAndJoin(string memory oracleName, uint256 proposalId) public {
        Proposal storage proposal = proposals[proposalId];
        require(proposal.candidate == msg.sender, "Only the candidate can finalize membership");
        require(proposal.votesFor > proposal.votesAgainst, "Proposal did not pass");
        require(members[msg.sender].stakedTokens[oracleName] == 0, "Member already staked");

        uint256 amountToStake = minStake;
        require(openWorkToken.transferFrom(msg.sender, address(this), amountToStake), "Stake transfer failed");

        members[msg.sender].stakedTokens[oracleName] += amountToStake;
        oracles[oracleName].votingPower[msg.sender] += amountToStake;
        oracles[oracleName].members.add(msg.sender);

        proposal.executed = true;
        emit MembershipFinalized(oracleName, msg.sender);
    }

    // Override the createProposal function to handle proposal creation
    function createProposal(string memory oracleName, string memory description) internal returns (uint256) {
        Oracle storage oracle = oracles[oracleName];
        uint256 proposalId = oracle.proposals.length;
        oracle.proposals.push(Proposal({
            id: proposalId,
            description: description,
            votesFor: 0,
            votesAgainst: 0,
            startTime: block.timestamp,
            executed: false,
            candidate: address(0),  // Initialize with the default zero address
            skill: ""               // Initialize with empty string for skill
        }));
        return proposalId;
    }
}

DAO Contract

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/governance/GovernorUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/governance/extensions/GovernorSettingsUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/governance/extensions/GovernorCountingSimpleUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/governance/extensions/GovernorVotesUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/governance/extensions/GovernorVotesQuorumFractionUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/governance/extensions/GovernorTimelockControlUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";

contract OpenWorkDAO is Initializable, GovernorUpgradeable, GovernorSettingsUpgradeable, GovernorCountingSimpleUpgradeable, GovernorVotesUpgradeable, GovernorVotesQuorumFractionUpgradeable, GovernorTimelockControlUpgradeable, OwnableUpgradeable, UUPSUpgradeable, ReentrancyGuardUpgradeable {
    using SafeERC20Upgradeable for IERC20Upgradeable;

    IERC20Upgradeable public token;
    uint256 public constant LOCK_PERIOD = 365 days;

    struct Stake {
        uint256 amount;
        uint256 startTime;
    }

    mapping(address => Stake) public stakes;

    function initialize(IVotes _token, TimelockControllerUpgradeable _timelock, address initialOwner)
        initializer public
    {
        __Governor_init("OpenWorkDAO");
        __GovernorSettings_init(7200 /* 1 day */, 50400 /* 1 week */, 1000000e18);
        __GovernorCountingSimple_init();
        __GovernorVotes_init(_token);
        __GovernorVotesQuorumFraction_init(30);
        __GovernorTimelockControl_init(_timelock);
        __Ownable_init();
        transferOwnership(initialOwner);
        __UUPSUpgradeable_init();
        token = IERC20Upgradeable(address(_token));
    }

    function stake(uint256 amount) public nonReentrant {
        token.safeTransferFrom(msg.sender, address(this), amount);
        stakes[msg.sender] = Stake({
            amount: stakes[msg.sender].amount + amount,
            startTime: block.timestamp
        });
    }

    function unstake(uint256 amount) public nonReentrant {
        require(stakes[msg.sender].amount >= amount, "Not enough staked");
        require(block.timestamp >= stakes[msg.sender].startTime + LOCK_PERIOD, "Stake is locked");
        stakes[msg.sender].amount -= amount;
        token.safeTransfer(msg.sender, amount);
    }

    function votingPower(address voter) public view override returns (uint256) {
        if (block.timestamp >= stakes[voter].startTime + LOCK_PERIOD) {
            return stakes[voter].amount;
        }
        return 0;
    }

    function _voteSucceeded(uint256 proposalId) internal view override returns (bool) {
        uint256 votesInFavor = proposalSnapshot(proposalId).forVotes;
        uint256 totalVotes = proposalSnapshot(proposalId).forVotes + proposalSnapshot(proposalId).againstVotes + proposalSnapshot(proposalId).abstainVotes;
        return (votesInFavor * 100) / totalVotes >= 80;
    }

    function transferERC20(address tokenAddress, address to, uint256 amount) public onlyGovernance {
        IERC20Upgradeable(tokenAddress).safeTransfer(to, amount);
    }

    function receiveERC20(address tokenAddress, uint256 amount) public {
        IERC20Upgradeable(tokenAddress).safeTransferFrom(msg.sender, address(this), amount);
    }

    // Override functions for governance controls
    function votingDelay() public view override(GovernorUpgradeable, GovernorSettingsUpgradeable) returns (uint256) {
        return super.votingDelay();
    }

    function votingPeriod() public view override(GovernorUpgradeable, GovernorSettingsUpgradeable) returns (uint256) {
        return super.votingPeriod();
    }

    function quorum(uint256 blockNumber) public view override(GovernorUpgradeable, GovernorVotesQuorumFractionUpgradeable) returns (uint256) {
        return super.quorum(blockNumber);
    }

    function proposalThreshold() public view override(GovernorUpgradeable, GovernorSettingsUpgradeable) returns (uint256) {
        return super.proposalThreshold();
    }

    function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
}
// note that where “onlyOwner” is, it should probably be the governor function allowing the DAO to vote and agree on an update

DAO Athena

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol";

contract OpenWorkDAOAthena is Initializable, UUPSUpgradeable {
    using SafeERC20Upgradeable for IERC20Upgradeable;
    using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;

    IERC20Upgradeable public openWorkToken;
    uint256 public minStake;
    uint256 public minMembers;
    uint256 public constant ENTRY_STAKE = 1e6 * 1e18; // 1 million tokens, assuming 18 decimal places
    uint256 public constant MIN_VOTING_DURATION = 4 days; // Minimum voting duration

    struct Member {
        mapping(string => uint256) stakedTokens; // Tokens staked per oracle
    }

    struct Oracle {
        bool exists;
        bool isActive;
        EnumerableSetUpgradeable.AddressSet potentialMembers;
        EnumerableSetUpgradeable.AddressSet members;
        uint256 activationTimestamp;
        Proposal[] proposals;
        mapping(address => uint256) votingPower; // Voting power per member within this oracle
    }

    struct Proposal {
        uint256 id;
        string description;
        uint256 votesFor;
        uint256 votesAgainst;
        uint256 startTime; // Start time of the voting period
        bool executed;
        address candidate; // Candidate address for proposals
        string skill; // Skill information for skill verification
    }

    mapping(string => Oracle) public oracles; // All oracles [string is skill]
    mapping(address => Member) public members; // All members

    function initialize(IERC20Upgradeable _openWorkToken, uint256 _minStake, uint256 _minMembers) public initializer {
        __UUPSUpgradeable_init();
        openWorkToken = _openWorkToken;
        minStake = _minStake;
        minMembers = _minMembers;
    }

    function _authorizeUpgrade(address newImplementation) internal override onlyGovernance {}

    function createOracle(string memory oracleName) public {
        require(!oracles[oracleName].exists, "Oracle already exists");
        Oracle storage oracle = oracles[oracleName];
        oracle.exists = true;
        oracle.isActive = false;
        oracle.activationTimestamp = 0; // Initially inactive
    }

    function activateOracle(string memory oracleName) public { //maybe instead of public, it needs a governance only function
        require(oracles[oracleName].exists, "Oracle does not exist");
        require(!oracles[oracleName].isActive, "Oracle already active");
        oracles[oracleName].isActive = true;
        oracles[oracleName].activationTimestamp = block.timestamp;
    }

    function deactivateOracle(string memory oracleName) public {
        require(oracles[oracleName].exists, "Oracle does not exist");
        require(oracles[oracleName].isActive, "Oracle is not active");
        oracles[oracleName].isActive = false;
    }

    function addMember(string memory oracleName, address member) public {
        require(oracles[oracleName].isActive, "Oracle is not active");
        oracles[oracleName].members.add(member);
    }
//this should potentially be the governance making a member eligible (through potential member), then this is checked once they stake

    function removeMember(string memory oracleName, address member) public {
        require(oracles[oracleName].isActive, "Oracle is not active");
        oracles[oracleName].members.remove(member);
    }

    function stakeTokens(string memory oracleName, uint256 amount) public {
        require(oracles[oracleName].exists, "Oracle does not exist");
        require(amount >= ENTRY_STAKE, "Minimum stake not met");
        openWorkToken.safeTransferFrom(msg.sender, address(this), amount);
        members[msg.sender].stakedTokens[oracleName] += amount;
        oracles[oracleName].votingPower[msg.sender] += amount;
    }
//this should potentially be the the member going from the potential member list to actual member, given they’re eligible and staked now.


    function withdrawTokens(string memory oracleName, uint256 amount) public {
        require(oracles[oracleName].exists, "Oracle does not exist");
        Member storage member = members[msg.sender];
        require(member.stakedTokens[oracleName] >= amount, "Insufficient staked tokens");
        openWorkToken.safeTransfer(msg.sender, amount);
        member.stakedTokens[oracleName] -= amount;
        oracles[oracleName].votingPower[msg.sender] -= amount;
    }

    function createProposal(string memory oracleName, string memory description) public returns (uint256) {
        require(oracles[oracleName].isActive, "Oracle is not active");
        require(oracles[oracleName].members.contains(msg.sender), "Only members can propose");
        require(members[msg.sender].stakedTokens[oracleName] >= ENTRY_STAKE, "Insufficient stake");

        Oracle storage oracle = oracles[oracleName];
        uint256 proposalId = oracle.proposals.length;
        oracle.proposals.push(Proposal({
            id: proposalId,
            description: description,
            votesFor: 0,
            votesAgainst: 0,
            startTime: block.timestamp,
            executed: false,
            candidate: address(0), // Default to zero address
            skill: "" // Default to empty string
        }));
        return proposalId;
    }

    function voteOnProposal(string memory oracleName, uint256 proposalId, bool support) public {
        Oracle storage oracle = oracles[oracleName];
        Proposal storage proposal = oracle.proposals[proposalId];

        require(block.timestamp <= proposal.startTime + MIN_VOTING_DURATION, "Voting period has ended");
        require(!proposal.executed, "Proposal already executed");
        uint256 voterPower = oracle.votingPower[msg.sender];
        require(voterPower > 0, "No voting power");

        if (support) {
            proposal.votesFor += voterPower;
        } else {
            proposal.votesAgainst += voterPower;
        }
    }

    function executeProposal(string memory oracleName, uint256 proposalId) public {
        Oracle storage oracle = oracles[oracleName];
        Proposal storage proposal = oracle.proposals[proposalId];

        require(!proposal.executed, "Proposal already executed");
        require(block.timestamp >= proposal.startTime + MIN_VOTING_DURATION, "Minimum voting duration has not elapsed");
        require(proposal.votesFor > proposal.votesAgainst, "Proposal did not pass");

        proposal.executed = true; // Mark the proposal as executed
    }
}

Last updated