ETH Price: $2,269.08 (-5.74%)

Transaction Decoder

Block:
17626837 at Jul-05-2023 09:38:35 AM +UTC
Transaction Fee:
0.003858517766605116 ETH $8.76
Gas Used:
60,141 Gas / 64.157858476 Gwei

Emitted Events:

20 ChainportCongress.VoteCast( voter=[Sender] 0x894107b7b5051409f279e8300774b2f62febe057, proposalId=42, support=True )

Account State Difference:

  Address   Before After State Difference Code
0x894107B7...62Febe057
(ChainPort: Deployer 2)
2.679820634244157193 Eth
Nonce: 313
2.675962116477552077 Eth
Nonce: 314
0.003858517766605116
0xB6b4C7aC...6a83884a1
(Flashbots: Builder)
0.049521408928060378 Eth0.050321284228060378 Eth0.0007998753

Execution Trace

ChainportCongress.castVote( proposalId=42, support=True )
  • ChainportCongressMembersRegistry.isMember( _address=0x894107B7b5051409f279E8300774B2f62Febe057 ) => ( True )
    File 1 of 2: ChainportCongress
    /**
     *Submitted for verification at BscScan.com on 2021-05-25
    */
    
    // Sources flattened with hardhat v2.3.0 https://hardhat.org
    
    // File contracts/interfaces/ICongressMembersRegistry.sol
    
    pragma solidity ^0.6.12;
    
    /**
     * IHordCongressMembersRegistry contract.
     * @author Nikola Madjarevic
     * Date created: 21.3.21.
     * Github: madjarevicn
     */
    interface ICongressMembersRegistry {
        function isMember(address _address) external view returns (bool);
        function getMinimalQuorum() external view returns (uint256);
    }
    
    
    // File contracts/governance/ChainportCongress.sol
    
    pragma solidity ^0.6.12;
    pragma experimental ABIEncoderV2;
    
    /**
     * ChainportCongress contract.
     * @author Nikola Madjarevic
     * Date created: 18.3.21.
     * Github: madjarevicn
     */
    contract ChainportCongress {
        /// @notice The name of this contract
        string public constant name = "ChainportCongress";
    
        // Members registry contract
        ICongressMembersRegistry membersRegistry;
    
        /// @notice The total number of proposals
        uint public proposalCount;
    
        struct Proposal {
            // Unique id for looking up a proposal
            uint id;
    
            // Creator of the proposal
            address proposer;
    
            // the ordered list of target addresses for calls to be made
            address[] targets;
    
            // The ordered list of values (i.e. msg.value) to be passed to the calls to be made
            uint[] values;
    
            // The ordered list of function signatures to be called
            string[] signatures;
    
            // The ordered list of calldata to be passed to each call
            bytes[] calldatas;
    
            // Current number of votes in favor of this proposal
            uint forVotes;
    
            // Current number of votes in opposition to this proposal
            uint againstVotes;
    
            // Flag marking whether the proposal has been canceled
            bool canceled;
    
            // Flag marking whether the proposal has been executed
            bool executed;
    
            // Timestamp when proposal is created
            uint timestamp;
    
            // Receipts of ballots for the entire set of voters
            mapping (address => Receipt) receipts;
        }
    
        /// @notice Ballot receipt record for a voter
        struct Receipt {
            // Whether or not a vote has been cast
            bool hasVoted;
    
            // Whether or not the voter supports the proposal
            bool support;
        }
    
        /// @notice The official record of all proposals ever proposed
        mapping (uint => Proposal) public proposals;
    
        /// @notice An event emitted when a new proposal is created
        event ProposalCreated(uint id, address proposer, address[] targets, uint[] values, string[] signatures, bytes[] calldatas, string description);
    
        /// @notice An event emitted when a vote has been cast on a proposal
        event VoteCast(address voter, uint proposalId, bool support);
    
        /// @notice An event emitted when a proposal has been canceled
        event ProposalCanceled(uint id);
    
        /// @notice An event emitted when a proposal has been executed
        event ProposalExecuted(uint id);
    
        /// @notice An event emitted everytime ether is received
        event ReceivedEther(address sender, uint amount);
    
        /// @notice Event which will fire every time transaction is executed
        event ExecuteTransaction(address indexed target, uint value, string signature,  bytes data);
    
        modifier onlyMember {
            require(membersRegistry.isMember(msg.sender) == true, "Only ChainportCongress member can call this function");
            _;
        }
    
        /// One time call function to set members registry contract
        function setMembersRegistry(
            address _membersRegistry
        )
        external
        {
            require(address(membersRegistry) == address(0x0), "ChainportCongress:setMembersRegistry: membersRegistry is already set");
            membersRegistry = ICongressMembersRegistry(_membersRegistry);
        }
    
        function propose(
            address[] memory targets,
            uint[] memory values,
            string[] memory signatures,
            bytes[] memory calldatas,
            string memory description
        )
        external
        onlyMember
        returns (uint)
        {
            require(
                targets.length == values.length &&
                targets.length == signatures.length &&
                targets.length == calldatas.length,
                "ChainportCongress::propose: proposal function information arity mismatch"
            );
    
            require(targets.length != 0, "ChainportCongress::propose: must provide actions");
    
            proposalCount++;
    
            Proposal memory newProposal = Proposal({
                id: proposalCount,
                proposer: msg.sender,
                targets: targets,
                values: values,
                signatures: signatures,
                calldatas: calldatas,
                forVotes: 0,
                againstVotes: 0,
                canceled: false,
                executed: false,
                timestamp: block.timestamp
            });
    
            proposals[newProposal.id] = newProposal;
    
            emit ProposalCreated(newProposal.id, msg.sender, targets, values, signatures, calldatas, description);
            return newProposal.id;
        }
    
    
        function castVote(
            uint proposalId,
            bool support
        )
        external
        onlyMember
        {
            return _castVote(msg.sender, proposalId, support);
        }
    
    
        function execute(
            uint proposalId
        )
        external
        onlyMember
        payable
        {
            // load the proposal
            Proposal storage proposal = proposals[proposalId];
            // Require that proposal is not previously executed neither cancelled
            require(proposal.executed == false && proposal.canceled == false);
            // Mark that proposal is executed
            proposal.executed = true;
            // Require that votes in favor of proposal are greater or equal to minimalQuorum
            require(proposal.forVotes >= membersRegistry.getMinimalQuorum());
    
            for (uint i = 0; i < proposal.targets.length; i++) {
                bytes memory callData;
    
                if (bytes(proposal.signatures[i]).length == 0) {
                    callData = proposal.calldatas[i];
                } else {
                    callData = abi.encodePacked(bytes4(keccak256(bytes(proposal.signatures[i]))), proposal.calldatas[i]);
                }
    
                // solium-disable-next-line security/no-call-value
                (bool success,) = proposal.targets[i].call{value:proposal.values[i]}(callData);
    
                // Require that transaction went through
                require(success, "ChainportCongress::executeTransaction: Transaction execution reverted.");
    
                // Emit event that transaction is being executed
                emit ExecuteTransaction(proposal.targets[i], proposal.values[i], proposal.signatures[i], proposal.calldatas[i]);
            }
    
            // Emit event that proposal executed
            emit ProposalExecuted(proposalId);
        }
    
        function cancel(uint proposalId) external onlyMember {
            Proposal storage proposal = proposals[proposalId];
            // Require that proposal is not previously executed neither cancelled
            require(proposal.executed == false && proposal.canceled == false, "ChainportCongress:cancel: Proposal already executed or canceled");
            // 3 days after proposal can get cancelled
            require(block.timestamp >= proposal.timestamp + 259200, "ChainportCongress:cancel: Time lock hasn't ended yet");
            // Proposal with reached minimalQuorum cant be cancelled
            require(proposal.forVotes < membersRegistry.getMinimalQuorum(), "ChainportCongress:cancel: Proposal already reached quorum");
            // Set that proposal is cancelled
            proposal.canceled = true;
            // Emit event
            emit ProposalCanceled(proposalId);
        }
    
        function _castVote(address voter, uint proposalId, bool support) internal {
            Proposal storage proposal = proposals[proposalId];
            Receipt storage receipt = proposal.receipts[voter];
            require(receipt.hasVoted == false, "ChainportCongress::_castVote: voter already voted");
    
            if (support) {
                proposal.forVotes = add256(proposal.forVotes, 1);
            } else {
                proposal.againstVotes = add256(proposal.againstVotes, 1);
            }
    
            receipt.hasVoted = true;
            receipt.support = support;
    
            emit VoteCast(voter, proposalId, support);
        }
    
        function getActions(uint proposalId) external view returns (address[] memory targets, uint[] memory values, string[] memory signatures, bytes[] memory calldatas) {
            Proposal storage p = proposals[proposalId];
            return (p.targets, p.values, p.signatures, p.calldatas);
        }
    
        function getMembersRegistry()
        external
        view
        returns (address)
        {
            return address(membersRegistry);
        }
    
        function add256(uint256 a, uint256 b) internal pure returns (uint) {
            uint c = a + b;
            require(c >= a, "addition overflow");
            return c;
        }
    
        receive() external payable {
            emit ReceivedEther(msg.sender, msg.value);
        }
    }

    File 2 of 2: ChainportCongressMembersRegistry
    /**
     *Submitted for verification at BscScan.com on 2021-05-25
    */
    
    // Sources flattened with hardhat v2.3.0 https://hardhat.org
    
    // File contracts/libraries/SafeMath.sol
    
    // SPDX-License-Identifier: MIT
    
    pragma solidity >=0.6.0 <0.8.0;
    
    /**
     * @dev Wrappers over Solidity's arithmetic operations with added overflow
     * checks.
     *
     * Arithmetic operations in Solidity wrap on overflow. This can easily result
     * in bugs, because programmers usually assume that an overflow raises an
     * error, which is the standard behavior in high level programming languages.
     * `SafeMath` restores this intuition by reverting the transaction when an
     * operation overflows.
     *
     * Using this library instead of the unchecked operations eliminates an entire
     * class of bugs, so it's recommended to use it always.
     */
    library SafeMath {
        /**
         * @dev Returns the addition of two unsigned integers, with an overflow flag.
         *
         * _Available since v3.4._
         */
        function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    
        /**
         * @dev Returns the substraction of two unsigned integers, with an overflow flag.
         *
         * _Available since v3.4._
         */
        function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    
        /**
         * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
         *
         * _Available since v3.4._
         */
        function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    
        /**
         * @dev Returns the division of two unsigned integers, with a division by zero flag.
         *
         * _Available since v3.4._
         */
        function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    
        /**
         * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
         *
         * _Available since v3.4._
         */
        function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    
        /**
         * @dev Returns the addition of two unsigned integers, reverting on
         * overflow.
         *
         * Counterpart to Solidity's `+` operator.
         *
         * Requirements:
         *
         * - Addition cannot overflow.
         */
        function add(uint256 a, uint256 b) internal pure returns (uint256) {
            uint256 c = a + b;
            require(c >= a, "SafeMath: addition overflow");
            return c;
        }
    
        /**
         * @dev Returns the subtraction of two unsigned integers, reverting on
         * overflow (when the result is negative).
         *
         * Counterpart to Solidity's `-` operator.
         *
         * Requirements:
         *
         * - Subtraction cannot overflow.
         */
        function sub(uint256 a, uint256 b) internal pure returns (uint256) {
            require(b <= a, "SafeMath: subtraction overflow");
            return a - b;
        }
    
        /**
         * @dev Returns the multiplication of two unsigned integers, reverting on
         * overflow.
         *
         * Counterpart to Solidity's `*` operator.
         *
         * Requirements:
         *
         * - Multiplication cannot overflow.
         */
        function mul(uint256 a, uint256 b) internal pure returns (uint256) {
            if (a == 0) return 0;
            uint256 c = a * b;
            require(c / a == b, "SafeMath: multiplication overflow");
            return c;
        }
    
        /**
         * @dev Returns the integer division of two unsigned integers, reverting on
         * division by zero. The result is rounded towards zero.
         *
         * Counterpart to Solidity's `/` operator. Note: this function uses a
         * `revert` opcode (which leaves remaining gas untouched) while Solidity
         * uses an invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         *
         * - The divisor cannot be zero.
         */
        function div(uint256 a, uint256 b) internal pure returns (uint256) {
            require(b > 0, "SafeMath: division by zero");
            return a / b;
        }
    
        /**
         * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
         * reverting when dividing by zero.
         *
         * Counterpart to Solidity's `%` operator. This function uses a `revert`
         * opcode (which leaves remaining gas untouched) while Solidity uses an
         * invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         *
         * - The divisor cannot be zero.
         */
        function mod(uint256 a, uint256 b) internal pure returns (uint256) {
            require(b > 0, "SafeMath: modulo by zero");
            return a % b;
        }
    
        /**
         * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
         * overflow (when the result is negative).
         *
         * CAUTION: This function is deprecated because it requires allocating memory for the error
         * message unnecessarily. For custom revert reasons use {trySub}.
         *
         * Counterpart to Solidity's `-` operator.
         *
         * Requirements:
         *
         * - Subtraction cannot overflow.
         */
        function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            require(b <= a, errorMessage);
            return a - b;
        }
    
        /**
         * @dev Returns the integer division of two unsigned integers, reverting with custom message on
         * division by zero. The result is rounded towards zero.
         *
         * CAUTION: This function is deprecated because it requires allocating memory for the error
         * message unnecessarily. For custom revert reasons use {tryDiv}.
         *
         * Counterpart to Solidity's `/` operator. Note: this function uses a
         * `revert` opcode (which leaves remaining gas untouched) while Solidity
         * uses an invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         *
         * - The divisor cannot be zero.
         */
        function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            require(b > 0, errorMessage);
            return a / b;
        }
    
        /**
         * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
         * reverting with custom message when dividing by zero.
         *
         * CAUTION: This function is deprecated because it requires allocating memory for the error
         * message unnecessarily. For custom revert reasons use {tryMod}.
         *
         * Counterpart to Solidity's `%` operator. This function uses a `revert`
         * opcode (which leaves remaining gas untouched) while Solidity uses an
         * invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         *
         * - The divisor cannot be zero.
         */
        function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
    
    
    // File contracts/governance/ChainportCongressMembersRegistry.sol
    
    pragma solidity ^0.6.12;
    
    /**
     * ChainportCongressMembersRegistry contract.
     * @author Nikola Madjarevic
     * Date created: 21.3.21.
     * Github: madjarevicn
     */
    contract ChainportCongressMembersRegistry {
    
        using SafeMath for *;
    
        /// @notice The name of this contract
        string public constant name = "ChainportCongressMembersRegistry";
    
        /// @notice Event to fire every time someone is added or removed from members
        event MembershipChanged(address member, bool isMember);
    
        /// @notice Chainport congress pointer
        address public chainportCongress;
    
        //The minimum number of voting members that must be in attendance
        uint256 minimalQuorum;
    
        // Mapping to check if the member is belonging to congress
        mapping (address => bool) isMemberInCongress;
    
        // Mapping address to member info
        mapping(address => Member) public address2Member;
    
        // Mapping to store all members addresses
        address[] public allMembers;
    
    
        struct Member {
            bytes32 name;
            uint memberSince;
        }
    
        modifier onlyChainportCongress {
            require(msg.sender == chainportCongress);
            _;
        }
    
        /**
         * @param initialCongressMembers is the array containing addresses of initial members
         */
        constructor(
            address[] memory initialCongressMembers,
            bytes32[] memory initialCongressMemberNames,
            address _chainportCongress
        )
        public
        {
            uint length = initialCongressMembers.length;
    
            for(uint i=0; i<length; i++) {
                addMemberInternal(
                    initialCongressMembers[i],
                    initialCongressMemberNames[i]
                );
            }
    
            chainportCongress = _chainportCongress;
        }
    
    
        function changeMinimumQuorum(
            uint newMinimumQuorum
        )
        external
        onlyChainportCongress
        {
            require(newMinimumQuorum > 0);
            minimalQuorum = newMinimumQuorum;
        }
    
        /**
         * Add member
         *
         * Make `targetMember` a member named `memberName`
         *
         * @param targetMember ethereum address to be added
         * @param memberName public name for that member
         */
        function addMember(
            address targetMember,
            bytes32 memberName
        )
        external
        onlyChainportCongress
        {
            addMemberInternal(targetMember, memberName);
        }
    
    
        function addMemberInternal(
            address targetMember,
            bytes32 memberName
        )
        internal
        {
            //Require that this member is not already a member of congress
            require(isMemberInCongress[targetMember] == false);
            // Update basic member information
            address2Member[targetMember] = Member({
                memberSince: block.timestamp,
                name: memberName
            });
            // Add member to list of all members
            allMembers.push(targetMember);
            // Update minimum quorum
            minimalQuorum = allMembers.length.sub(1);
            // Mark that user is member in congress
            isMemberInCongress[targetMember] = true;
            // Fire an event
            emit MembershipChanged(targetMember, true);
        }
    
        /**
         * Remove member
         *
         * @notice Remove membership from `targetMember`
         *
         * @param targetMember ethereum address to be removed
         */
        function removeMember(
            address targetMember
        )
        external
        onlyChainportCongress
        {
            require(isMemberInCongress[targetMember] == true);
    
            uint length = allMembers.length;
    
            uint i=0;
    
            // Find selected member
            while(allMembers[i] != targetMember) {
                if(i == length) {
                    revert();
                }
                i++;
            }
    
            // Move the last member to this place
            allMembers[i] = allMembers[length-1];
    
            // Remove the last member
            allMembers.pop();
    
            //Remove him from state mapping
            isMemberInCongress[targetMember] = false;
    
            //Remove his state to empty member
            address2Member[targetMember] = Member({
                memberSince: block.timestamp,
                name: "0x0"
            });
    
            //Reduce 1 member from quorum
            minimalQuorum = minimalQuorum.sub(1);
    
            // Emit event that member is removed.
            emit MembershipChanged(targetMember, false);
        }
    
        /**
         * @notice Function which will be exposed and congress will use it as "modifier"
         * @param _address is the address we're willing to check if it belongs to congress
         * @return true/false depending if it is either a member or not
         */
        function isMember(
            address _address
        )
        external
        view
        returns (bool)
        {
            return isMemberInCongress[_address];
        }
    
        /// @notice Getter for length for how many members are currently
        /// @return length of members
        function getNumberOfMembers()
        external
        view
        returns (uint)
        {
            return allMembers.length;
        }
    
        /// @notice Function to get addresses of all members in congress
        /// @return array of addresses
        function getAllMemberAddresses()
        external
        view
        returns (address[] memory)
        {
            return allMembers;
        }
    
        /// Get member information
        function getMemberInfo(
            address _member
        )
        external
        view
        returns (address, bytes32, uint)
        {
            Member memory member = address2Member[_member];
            return (
                _member,
                member.name,
                member.memberSince
            );
        }
    
        function getMinimalQuorum()
        external
        view
        returns (uint256)
        {
            return minimalQuorum;
        }
    }