Skip to main content
PulseScanner.io

Address

0xebec7322af589f55af81063e40ebaa538ebaefeb
Current Holdings
$12.01
TXs sent
not counted
First Active
2023-10-08
block 18,517,014
Last Active
1,075 days ago
block 18,517,014
Funded By
0x6c34…5e89

Net worth historyi

12 snapshots · to block 27,438,524coverage change 26 Augcoverage change 27 Augcoverage change 27 Augcoverage change 27 Augcoverage change 27 Aug
partial matchTGCDAOsolc 0.8.2+commit.661d1103runtime partial · creation partial
// SPDX-License-Identifier: Unlicensed

pragma solidity 0.8.2;

interface IStaking {
   function checkHighestStaker(address user) external returns (bool);
   function mapUserInfo(address voter) external view returns (uint256, uint256, uint256, uint256, uint256, uint256, uint256);
}

contract TGCDAO {
	uint256 public immutable votingPeriod;
	uint256 public proposalCount;
	
	uint256[] public activeProposal;
	address public immutable staking;
	uint256 public lockedAmount;
	
	struct Proposal {
      uint256 id;
	  uint256 fundRequest;
      uint256 startTime;
      uint256 endTime;
      uint256 forVotes;
      uint256 againstVotes;
	  uint256 voters;
	  bool claimed;
	  address proposer;
	  mapping (address => Receipt) receipts;
    }
	
	struct Receipt {
	  bool hasVoted;
	  uint256 support;
    }
	
	enum ProposalState {
	  Active,
	  Defeated,
	  Succeeded    
	}
	
	mapping (address => uint256) public latestProposalIds;
	mapping (uint => Proposal) public proposals;
	
    event ProposalCreated(uint256 id, address proposer, uint256 startTime, uint256 endTime, string description);
    event VoteCast(address indexed voter, uint256 proposalId, uint256 support, uint256 votes);
    event ProposalCanceled(uint256 id);
	event ProposalApproved(uint256 id);
	
    constructor () {
	   votingPeriod = 7 * 86400;
	   staking = address(0x433BCe8d21E9a315878B970239Ea16470c46E035);
    }
	
	receive() external payable {}
	
    function propose(uint256 fundRequest, string memory description) public returns (uint256) {
        uint256 latestProposalId = latestProposalIds[msg.sender];
		if (latestProposalId != 0) {
           ProposalState proposersLatestProposalState = state(latestProposalId);
           require(proposersLatestProposalState != ProposalState.Active, "Governor::propose: one live proposal per proposer, found an already active proposal");
        }
		
		removeDefeatedProposal();
		
		require(IStaking(staking).checkHighestStaker(msg.sender),"Governor::propose: only top staker");
		require(fundRequest <= 100000000 * 10**18,"Governor::propose: max 100000000  PLS limit");
		require(fundRequest >= 1 * 10**18,"Governor::propose: min 1 PLS limit");
		require(address(this).balance - lockedAmount >= fundRequest,"Governor::propose: insufficient fund");
		
        proposalCount++;
        Proposal storage newProposal = proposals[proposalCount];
		
        newProposal.id = proposalCount;
		newProposal.fundRequest = fundRequest;
        newProposal.proposer = msg.sender;
        newProposal.startTime = block.timestamp;
        newProposal.endTime = block.timestamp + votingPeriod;
        newProposal.forVotes = 0;
        newProposal.againstVotes = 0;
		newProposal.claimed = false;
		newProposal.voters = 0;
		
        latestProposalIds[newProposal.proposer] = newProposal.id;
		lockedAmount += fundRequest; 
		
        emit ProposalCreated(newProposal.id, msg.sender, block.timestamp, (block.timestamp + votingPeriod), description);
        activeProposal.push(proposalCount);
		return newProposal.id;
    }
	
	function removeDefeatedProposal() public {
	    if(activeProposal.length > 0)
		{
		   for (uint256 i = 0; i < activeProposal.length; i++) 
		   {
		       uint256 proposalId = activeProposal[i];
			   Proposal storage proposal = proposals[proposalId];
			   if(state(proposalId) == ProposalState.Defeated)
			   {
				   lockedAmount -= proposal.fundRequest; 
				   activeProposal[i] = activeProposal[activeProposal.length - 1];
				   activeProposal.pop();
				   removeDefeatedProposal();
				   break;
			   } 
			   else if(state(proposalId) == ProposalState.Succeeded)
			   {
			       activeProposal[i] = activeProposal[activeProposal.length - 1];
				   activeProposal.pop();
				   removeDefeatedProposal();
				   break;
			   }
		   }
		}
	}
	
    function getReceipt(uint256 proposalId, address voter) external view returns (Receipt memory) {
       return proposals[proposalId].receipts[voter];
    }
	
    function state(uint256 proposalId) public view returns (ProposalState) {
        require(proposalCount >= proposalId, "Governor::state: invalid proposal id");
        Proposal storage proposal = proposals[proposalId];
        if (block.timestamp <= proposal.endTime) {
            return ProposalState.Active;
        } else if (proposal.forVotes <= proposal.againstVotes) {
            return ProposalState.Defeated;
        } if (proposal.forVotes > proposal.againstVotes && votingPercent(proposalId) >= 65 && proposal.voters >= 5) {
            return ProposalState.Succeeded;
        } else {
            return ProposalState.Defeated;
        }
    }
	
    function castVote(uint256 proposalId, uint256 support) external {
        removeDefeatedProposal();
		emit VoteCast(msg.sender, proposalId, support, castVoteInternal(msg.sender, proposalId, support));
    }
	
    function castVoteInternal(address voter, uint proposalId, uint256 support) internal returns (uint256) {
        (uint256 amount, , , , , , ) = IStaking(staking).mapUserInfo(voter);
		require(state(proposalId) == ProposalState.Active, "Governor::castVoteInternal: voting is closed");
		require(support <= 1, "Governor::castVoteInternal: invalid vote type");
        Proposal storage proposal = proposals[proposalId];
        Receipt storage receipt = proposal.receipts[voter];
        require(receipt.hasVoted == false, "Governor::castVoteInternal: voter already voted");
        require(amount > 0, "Governor::castVoteInternal: not eligible for voting");
		
        if (support == 0) 
		{
           proposal.againstVotes += amount;
        } 
		else if (support == 1) 
		{
           proposal.forVotes += amount;
        } 
		proposal.voters += 1;
        receipt.hasVoted = true;
        receipt.support = support;
        return (proposal.forVotes + proposal.againstVotes);
    }
	
	function claimFund(uint256 proposalId) external {
	   Proposal storage proposal = proposals[proposalId];
	   require(state(proposalId) == ProposalState.Succeeded, "Governor::claimFund: proposal is not succeeded");
	   require(proposal.claimed == false, "Governor::claimFund: Fund already claimed");
	   
	   proposal.claimed = true;
	   lockedAmount -= proposal.fundRequest; 
	   payable(address(proposal.proposer)).transfer(proposal.fundRequest);
    }
	
	function votingPercent(uint256 proposalId) public view returns(uint256){
	   Proposal storage proposal = proposals[proposalId];
	   
	   uint256 totalVote = proposal.forVotes + proposal.againstVotes;
	   return proposal.forVotes * 100 / totalVote;
    }
}