Contract 0x396dd1f7E3c8044784937935F834C3F8d58EB497 2

 
Txn Hash Method
Block
From
To
Value [Txn Fee]
0x3b2cec3224a05d87a17f98479b691c21d1c6ac286377378428b30d5b9373cea2Claim339527412022-10-30 17:36:5689 days 23 hrs ago0x714d7baf5067855eba892296b6c6d94a09857010 IN  0x396dd1f7e3c8044784937935f834c3f8d58eb4970 ETH0.00001163
0x726215c93cbe5876c98b72552acb37617c1d398cba553ee21f5b84976ab255a7Claim89195962022-03-30 17:16:29303 days 23 hrs ago0x935c0a8c155c023dd360db853b0f1339a6f3bffc IN  0x396dd1f7e3c8044784937935f834c3f8d58eb4970 ETH0.00019459746 ETH
0xadcfd3e468d2e936fbf436f3ef544532108a7fc5b0fadeacd9bdbc30f704549cClaim84021052022-03-23 10:05:15311 days 7 hrs ago0xd110421a743a19a6dee233c32417c089b2684f1c IN  0x396dd1f7e3c8044784937935f834c3f8d58eb4970 ETH0.000144769265 ETH
0xe661808ea4f5f065bf6c98b2de338adca361d3aeeb1bb9444020d75407f78cdbClaim73330342022-03-03 2:59:08331 days 14 hrs ago0x5ee42438d0d8fc399c94ef3543665e993e847b49 IN  0x396dd1f7e3c8044784937935f834c3f8d58eb4970 ETH0.000233519945 ETH
0xcecd1f5a307c508d0f8c68486f0393b0d414161a567490b460353e1af9c3a3b1New Bid57535722022-02-09 23:12:55352 days 18 hrs ago0x167539702b5501aadd9b0b85e53532fd57cc71a9 IN  0x396dd1f7e3c8044784937935f834c3f8d58eb4970.25 ETH0.000681082173 ETH
0x8aaecf104f97df0555e025e2c11bb12205267b1a5b5002fcbfb72d8b59543738Claim56315502022-02-08 9:45:46354 days 7 hrs ago0xad63e4d4be2229b080d20311c1402a2e45cf7e75 IN  0x396dd1f7e3c8044784937935f834c3f8d58eb4970 ETH0.000375781187 ETH
0xbcf9aab80cd4448460384b59bd0d214c935a3223d20cfabb0bdbc0918fff7eaeClaim56248172022-02-08 7:41:29354 days 9 hrs ago0x36d4759ddaf74ebfb30547cd18d47f3778b6d132 IN  0x396dd1f7e3c8044784937935f834c3f8d58eb4970 ETH0.000377274968 ETH
0x250ee824e15cb1e2d97f5b448a7fdf77ce8f1cb4809a373db6f47426512fa829Claim56246822022-02-08 7:37:26354 days 9 hrs ago0xdd260de0c2e09c5ebf5796f0f30ad254bce136b0 IN  0x396dd1f7e3c8044784937935f834c3f8d58eb4970 ETH0.000376056841 ETH
0x0cce4d31d077ec1e8931b352464c10d57bb670c4ee26f05774c10e9849b6ed7fClaim56153212022-02-08 5:10:16354 days 12 hrs ago0x6ff019baf384c9035d42efaa1fc28f23918ad0ed IN  0x396dd1f7e3c8044784937935f834c3f8d58eb4970 ETH0.000382154175 ETH
0x496e692843af4f9264cd61ea900096fc8e095d350fff85df18d1c7def050178dClaim56152752022-02-08 5:09:37354 days 12 hrs ago0x36d4759ddaf74ebfb30547cd18d47f3778b6d132 IN  0x396dd1f7e3c8044784937935f834c3f8d58eb4970 ETH0.00038872698 ETH
0x7faf134dc3027796c94e9576f01a23e2a8fe8b380e45e34b95d6a2ac1b964f5bNew Bid54559572022-02-05 17:54:22356 days 23 hrs ago0x3b99e794378bd057f3ad7aea9206fb6c01f3ee60 IN  0x396dd1f7e3c8044784937935f834c3f8d58eb4970.1337 ETH0.000703784206 ETH
0xd02ffd98d2279fa94ddbc4c411cfb2e53e50792089032b5f781b9131f595d27eClaim53957202022-02-03 19:18:46358 days 21 hrs ago0xa0e1eee5ce9881c716ed5d09377f693dfbb65a9a IN  0x396dd1f7e3c8044784937935f834c3f8d58eb4970 ETH0.000456537184 ETH
0x04396c103ee9afe36312acf4bf28f12f2665f3eb4fdeed6b3fc42b92eefca733Claim53688442022-02-03 2:17:16359 days 14 hrs ago0xbfc016652a6708b20ae850ee92d2ea23cca5f31a IN  0x396dd1f7e3c8044784937935f834c3f8d58eb4970 ETH0.000527883864 ETH
0xd8b86bd78823aea38b51ec12e872b23b8895c595abd8545353aa52d90e3becabNew Bid53687392022-02-03 2:10:48359 days 15 hrs ago0x36d4759ddaf74ebfb30547cd18d47f3778b6d132 IN  0x396dd1f7e3c8044784937935f834c3f8d58eb4970.1333 ETH0.001018205838 ETH
0xcd23c1aa77bbc4a8071ec079c6bb77b272f1e28fb03b51f222579315500f6a7cClaim53686102022-02-03 2:01:20359 days 15 hrs ago0xbfc016652a6708b20ae850ee92d2ea23cca5f31a IN  0x396dd1f7e3c8044784937935f834c3f8d58eb4970 ETH0.00052793798 ETH
0xee60aef33dcb61a812e4c72e26ef2d9cbfcdc23694a47dd087d29d16d44d786cNew Bid53686012022-02-03 2:01:20359 days 15 hrs ago0xbfc016652a6708b20ae850ee92d2ea23cca5f31a IN  0x396dd1f7e3c8044784937935f834c3f8d58eb4970.05 ETH0.001015355283 ETH
0x45170694aee10396df530b8dce22b6639e914deeff89957bdd5ace9e997e01f6Set First53680732022-02-03 1:29:55359 days 15 hrs ago0xd67fb5ac62142317fb3dc411b506ee1fd54c1762 IN  0x396dd1f7e3c8044784937935f834c3f8d58eb4970 ETH0.000569430151 ETH
0x64d7447fe306af0e5ae2b889b10f29b86fe93d9bd0926affd9e2bc3bab96182eSet First53496992022-02-02 14:55:11360 days 2 hrs ago0xd67fb5ac62142317fb3dc411b506ee1fd54c1762 IN  0x396dd1f7e3c8044784937935f834c3f8d58eb4970 ETH0.000553642383 ETH
0xcb86c573fc018f4e8663dfbaa5c66414c6543150ab7a1fe7e369a3a13a0cd818Set First53496772022-02-02 14:54:41360 days 2 hrs ago0xd67fb5ac62142317fb3dc411b506ee1fd54c1762 IN  0x396dd1f7e3c8044784937935f834c3f8d58eb4970 ETH0.000551900198 ETH
0x991328ef56ba4b6fab5145659ee57adfb32a789c46208b51265d28d9be1e9278Set First53491192022-02-02 14:38:58360 days 2 hrs ago0xd67fb5ac62142317fb3dc411b506ee1fd54c1762 IN  0x396dd1f7e3c8044784937935f834c3f8d58eb4970 ETH0.000551900198 ETH
0x58d3d09f78fed3cd1f52f4f527a8ebb62e3c3b5e394edfd0c8ec4217e415bdb9End Auction53348552022-02-02 2:19:10360 days 14 hrs ago0x7fa0bbf4856bf37ea8d0e9d1b47514abf17beb84 IN  0x396dd1f7e3c8044784937935f834c3f8d58eb4970 ETH0.001325367166 ETH
0x3ad1e9ca131aae1e86d0dedef43a30d9435aacc1c332b2c49f4f82b8e45d8a94New Bid53238882022-02-01 17:38:30360 days 23 hrs ago0xbcf485f6763810763f1c113a6127c4a5b7be30db IN  0x396dd1f7e3c8044784937935f834c3f8d58eb4970.2 ETH0.000916753637 ETH
0x07f76a0d7c1e071cda5729f54c5f0427b873a0a34bddf7383b1a2385b21e7fe5New Bid53069582022-02-01 6:22:10361 days 10 hrs ago0xbfc016652a6708b20ae850ee92d2ea23cca5f31a IN  0x396dd1f7e3c8044784937935f834c3f8d58eb4970.05 ETH0.00100154779 ETH
0xc98b723b08daf73c8e234a9bfd0f1bb73dea3162fb4b580e852a70aa42a5216dClaim53068952022-02-01 6:18:32361 days 10 hrs ago0xbfc016652a6708b20ae850ee92d2ea23cca5f31a IN  0x396dd1f7e3c8044784937935f834c3f8d58eb4970 ETH0.000463712122 ETH
0xcc113be04129480810b756a23b7f255c2a20237d0ff29f90f296226083b1f6a7End Auction53000402022-02-01 2:17:55361 days 14 hrs ago0x7fa0bbf4856bf37ea8d0e9d1b47514abf17beb84 IN  0x396dd1f7e3c8044784937935f834c3f8d58eb4970 ETH0.001015464176 ETH
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0x3b2cec3224a05d87a17f98479b691c21d1c6ac286377378428b30d5b9373cea2339527412022-10-30 17:36:5689 days 23 hrs ago 0x396dd1f7e3c8044784937935f834c3f8d58eb4970x714d7baf5067855eba892296b6c6d94a098570100 ETH
0x726215c93cbe5876c98b72552acb37617c1d398cba553ee21f5b84976ab255a789195962022-03-30 17:16:29303 days 23 hrs ago 0x396dd1f7e3c8044784937935f834c3f8d58eb4970x935c0a8c155c023dd360db853b0f1339a6f3bffc0 ETH
0x726215c93cbe5876c98b72552acb37617c1d398cba553ee21f5b84976ab255a789195962022-03-30 17:16:29303 days 23 hrs ago 0x396dd1f7e3c8044784937935f834c3f8d58eb4970x935c0a8c155c023dd360db853b0f1339a6f3bffc0 ETH
0xadcfd3e468d2e936fbf436f3ef544532108a7fc5b0fadeacd9bdbc30f704549c84021052022-03-23 10:05:15311 days 7 hrs ago 0x396dd1f7e3c8044784937935f834c3f8d58eb4970xd110421a743a19a6dee233c32417c089b2684f1c0 ETH
0xe661808ea4f5f065bf6c98b2de338adca361d3aeeb1bb9444020d75407f78cdb73330342022-03-03 2:59:08331 days 14 hrs ago 0x396dd1f7e3c8044784937935f834c3f8d58eb4970x5ee42438d0d8fc399c94ef3543665e993e847b490 ETH
0xcecd1f5a307c508d0f8c68486f0393b0d414161a567490b460353e1af9c3a3b157535722022-02-09 23:12:55352 days 18 hrs ago 0x396dd1f7e3c8044784937935f834c3f8d58eb4970x167539702b5501aadd9b0b85e53532fd57cc71a90 ETH
0xcecd1f5a307c508d0f8c68486f0393b0d414161a567490b460353e1af9c3a3b157535722022-02-09 23:12:55352 days 18 hrs ago 0x396dd1f7e3c8044784937935f834c3f8d58eb497 0x014dea5dd7ce12ce494b553f133739873247021f0 ETH
0x8aaecf104f97df0555e025e2c11bb12205267b1a5b5002fcbfb72d8b5954373856315502022-02-08 9:45:46354 days 7 hrs ago 0x396dd1f7e3c8044784937935f834c3f8d58eb4970xad63e4d4be2229b080d20311c1402a2e45cf7e750 ETH
0xbcf9aab80cd4448460384b59bd0d214c935a3223d20cfabb0bdbc0918fff7eae56248172022-02-08 7:41:29354 days 9 hrs ago 0x396dd1f7e3c8044784937935f834c3f8d58eb4970x36d4759ddaf74ebfb30547cd18d47f3778b6d1320 ETH
0x250ee824e15cb1e2d97f5b448a7fdf77ce8f1cb4809a373db6f47426512fa82956246822022-02-08 7:37:26354 days 9 hrs ago 0x396dd1f7e3c8044784937935f834c3f8d58eb4970xdd260de0c2e09c5ebf5796f0f30ad254bce136b00 ETH
0x0cce4d31d077ec1e8931b352464c10d57bb670c4ee26f05774c10e9849b6ed7f56153212022-02-08 5:10:16354 days 12 hrs ago 0x396dd1f7e3c8044784937935f834c3f8d58eb4970x6ff019baf384c9035d42efaa1fc28f23918ad0ed0 ETH
0x496e692843af4f9264cd61ea900096fc8e095d350fff85df18d1c7def050178d56152752022-02-08 5:09:37354 days 12 hrs ago 0x396dd1f7e3c8044784937935f834c3f8d58eb4970x36d4759ddaf74ebfb30547cd18d47f3778b6d1320.1333 ETH
0x7faf134dc3027796c94e9576f01a23e2a8fe8b380e45e34b95d6a2ac1b964f5b54559572022-02-05 17:54:22356 days 23 hrs ago 0x396dd1f7e3c8044784937935f834c3f8d58eb4970x3b99e794378bd057f3ad7aea9206fb6c01f3ee600 ETH
0x7faf134dc3027796c94e9576f01a23e2a8fe8b380e45e34b95d6a2ac1b964f5b54559572022-02-05 17:54:22356 days 23 hrs ago 0x396dd1f7e3c8044784937935f834c3f8d58eb497 0x014dea5dd7ce12ce494b553f133739873247021f0 ETH
0xd02ffd98d2279fa94ddbc4c411cfb2e53e50792089032b5f781b9131f595d27e53957202022-02-03 19:18:46358 days 21 hrs ago 0x396dd1f7e3c8044784937935f834c3f8d58eb4970xa0e1eee5ce9881c716ed5d09377f693dfbb65a9a0 ETH
0x04396c103ee9afe36312acf4bf28f12f2665f3eb4fdeed6b3fc42b92eefca73353688442022-02-03 2:17:16359 days 14 hrs ago 0x396dd1f7e3c8044784937935f834c3f8d58eb4970xbfc016652a6708b20ae850ee92d2ea23cca5f31a0.05 ETH
0xd8b86bd78823aea38b51ec12e872b23b8895c595abd8545353aa52d90e3becab53687392022-02-03 2:10:48359 days 15 hrs ago 0x396dd1f7e3c8044784937935f834c3f8d58eb4970x36d4759ddaf74ebfb30547cd18d47f3778b6d1320 ETH
0xd8b86bd78823aea38b51ec12e872b23b8895c595abd8545353aa52d90e3becab53687392022-02-03 2:10:48359 days 15 hrs ago 0x396dd1f7e3c8044784937935f834c3f8d58eb497 0x014dea5dd7ce12ce494b553f133739873247021f0 ETH
0xcd23c1aa77bbc4a8071ec079c6bb77b272f1e28fb03b51f222579315500f6a7c53686102022-02-03 2:01:20359 days 15 hrs ago 0x396dd1f7e3c8044784937935f834c3f8d58eb4970xbfc016652a6708b20ae850ee92d2ea23cca5f31a0.05 ETH
0xee60aef33dcb61a812e4c72e26ef2d9cbfcdc23694a47dd087d29d16d44d786c53686012022-02-03 2:01:20359 days 15 hrs ago 0x396dd1f7e3c8044784937935f834c3f8d58eb4970xbfc016652a6708b20ae850ee92d2ea23cca5f31a0 ETH
0xee60aef33dcb61a812e4c72e26ef2d9cbfcdc23694a47dd087d29d16d44d786c53686012022-02-03 2:01:20359 days 15 hrs ago 0x396dd1f7e3c8044784937935f834c3f8d58eb497 0x014dea5dd7ce12ce494b553f133739873247021f0 ETH
0x58d3d09f78fed3cd1f52f4f527a8ebb62e3c3b5e394edfd0c8ec4217e415bdb953348552022-02-02 2:19:10360 days 14 hrs ago 0x396dd1f7e3c8044784937935f834c3f8d58eb497 0x014dea5dd7ce12ce494b553f133739873247021f0.2 ETH
0x3ad1e9ca131aae1e86d0dedef43a30d9435aacc1c332b2c49f4f82b8e45d8a9453238882022-02-01 17:38:30360 days 23 hrs ago 0x396dd1f7e3c8044784937935f834c3f8d58eb4970xbcf485f6763810763f1c113a6127c4a5b7be30db0 ETH
0x3ad1e9ca131aae1e86d0dedef43a30d9435aacc1c332b2c49f4f82b8e45d8a9453238882022-02-01 17:38:30360 days 23 hrs ago 0x396dd1f7e3c8044784937935f834c3f8d58eb497 0x014dea5dd7ce12ce494b553f133739873247021f0 ETH
0x07f76a0d7c1e071cda5729f54c5f0427b873a0a34bddf7383b1a2385b21e7fe553069582022-02-01 6:22:10361 days 10 hrs ago 0x396dd1f7e3c8044784937935f834c3f8d58eb4970xbfc016652a6708b20ae850ee92d2ea23cca5f31a0 ETH
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
BountyAuction

Compiler Version
v0.8.0+commit.c7dfd78e

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 9 : Auction.sol
pragma solidity ^0.8.0;

import "./PricingSession.sol";
import "./ABCTreasury.sol";
import "./helpers/ReentrancyGuard.sol";


///@author Medici
///@title Bounty auction contract for Abacus
contract BountyAuction is ReentrancyGuard {

    /// @notice store pricing session address 
    PricingSession public session;

    /// @notice store treasury address
    ABCTreasury public treasury;

    /* ======== ADDRESS ======== */

    /// @notice store contract admin address
    address public admin;

    /// @notice store ABC token contract
    address public ABCToken;

    /* ======== BOOL ======== */

    /// @notice track auction active status 
    bool public auctionStatus;

    /// @notice used for customizable first session timeline
    bool public firstSession;

    /* ======== UINT ======== */

    /// @notice used to map to current bounty auction
    uint public nonce;

    /* ======== MAPPINGS ======== */

    /*//////////////////////////////
    //     PER AUCTION STORAGE    //
    //////////////////////////////*/

    /// @notice maps the auction nonce to it's highest bid value
    mapping(uint => uint) public highestBid;
    
    /// @notice maps the auction nonce to it's highest bidder
    mapping(uint => address) public highestBidder;

    /// @notice maps the auction nonce to it's end timestamp
    mapping(uint => uint) public endTime;
    
    /// @notice maps the auction nonce to it's winner
    mapping(uint => address) public winners;
    
    /// @notice maps the action to all it's votes mapped to the voter
    mapping(uint => mapping(address => AuctionVote)) public userVote;

    /*//////////////////////////////
    //     PER ACCOUNT STORAGE    //
    //////////////////////////////*/

    mapping(address => uint) bidTime;

    mapping(address => uint) tvl;

    /* ======== STRUCTS ======== */

    /// @notice stores bidders core information
    struct AuctionVote {

        address nftAddress;
        uint tokenid;
        uint intitialAppraisal;
        uint bid;
    }

    /* ======== EVENTS ======== */
    event newBidSubmitted(address _bidder, uint _bidAmount, address _nftAddress, uint _tokenid, uint _initialAppraisal);
    event auctionEnded(address _highestBidder, uint _highestBid, address _nftAddress, uint _tokenid, uint _initialAppraisal);

    /* ======== Constructor ======== */

    constructor() {
        
        /// @notice set contract admin
        admin = msg.sender;

        /// @notice set session account status to signify auction is active
        auctionStatus = true;
    }

    /* ======== ADMIN ======== */
    
    ///@notice toggles active status of Auction contract
    function toggleAuction() external {
        require(msg.sender == admin);
        auctionStatus = !auctionStatus;
        nonce++;
    }

    /// @notice set session contract to be stored
    /// @param _session address of desired Pricing Session principle contract
    function setSessionContract(address _session) external {
        require(msg.sender == admin);
        session = PricingSession(payable(_session));
    }

    /// @notice set treasury contract to be stored
    /// @param _treasury address of desired ABC treasury address
    function setTreasury(address _treasury) external {
        require(msg.sender == admin);
        treasury = ABCTreasury(payable(_treasury));
    }

    /// @notice set token contract to be stored
    /// @param _token address of desired ABC token contract
    function setToken(address _token) external {
        require(msg.sender == admin);
        ABCToken = _token;
    }

    /// @notice change the state of first session once first auction is complete
    /// @param _state bool representative of whether or not we're currently in the first session
    function setFirst(bool _state) external {
        require(msg.sender == admin);
        firstSession = _state;
    }

    /* ======== AUCTION INTERACTION ======== */

    /// @notice allow user to submit new bid
    /// @param _nftAddress - address of the ERC721/ERC1155 token
    /// @param _tokenid - ID of the token
    /// @param _initialAppraisal - initial nft appraisal 
    function newBid(address _nftAddress, uint _tokenid, uint _initialAppraisal) nonReentrant payable external {
        require(
            msg.value > highestBid[nonce]
            && auctionStatus
            && (session.nftNonce(_nftAddress,_tokenid) == 0 || session.getStatus(_nftAddress, _tokenid) == 5)
        );
        bidTime[msg.sender] = block.timestamp;
        highestBidder[nonce] = msg.sender;
        highestBid[nonce] = msg.value;
        tvl[msg.sender] -= userVote[nonce][msg.sender].bid;
        (bool sent, ) = payable(msg.sender).call{value: userVote[nonce][msg.sender].bid}("");
        require(sent);
        userVote[nonce][msg.sender].nftAddress = _nftAddress;
        userVote[nonce][msg.sender].tokenid = _tokenid;
        userVote[nonce][msg.sender].intitialAppraisal = _initialAppraisal;
        userVote[nonce][msg.sender].bid = msg.value;
        tvl[msg.sender] += msg.value;
        emit newBidSubmitted(msg.sender, msg.value, _nftAddress, _tokenid, _initialAppraisal);
    }

    /// @notice allow add to past bid
    /// @param _nftAddress - address of the ERC721/ERC1155 token
    /// @param _tokenid - ID of the token
    function addToBid(address _nftAddress, uint _tokenid) nonReentrant payable external {
        require(
            userVote[nonce][msg.sender].bid + msg.value > highestBid[nonce] 
            && auctionStatus
            && (session.nftNonce(_nftAddress,_tokenid) == 0 || session.getStatus(_nftAddress, _tokenid) == 5)
        );
        userVote[nonce][msg.sender].bid += msg.value;
        highestBidder[nonce] = msg.sender;
        highestBid[nonce] = userVote[nonce][msg.sender].bid;
        tvl[msg.sender] += msg.value;
    }

    /// @notice allow user to change nft that they'd like appraised if they win
    /// @param _nftAddress users desired NFT address for session to be created
    /// @param _tokenid users desired tokenid for session to be created
    /// @param _initialAppraisal users desired initial appraisal value for session to be created
    function changeInfo(address _nftAddress, uint _tokenid, uint _initialAppraisal) external {
        require(userVote[nonce][msg.sender].nftAddress != address(0) && auctionStatus);
        userVote[nonce][msg.sender].nftAddress = _nftAddress;
        userVote[nonce][msg.sender].tokenid = _tokenid;
        userVote[nonce][msg.sender].intitialAppraisal = _initialAppraisal;
    }

    /// @notice triggered when auction ends, starts session for highest bidder
    function endAuction() nonReentrant external {
        if(firstSession) {
            require(msg.sender == admin);
        }
        require(endTime[nonce] < block.timestamp && auctionStatus);
        uint bountySend = userVote[nonce][highestBidder[nonce]].bid;
        tvl[highestBidder[nonce]] -= bountySend;
        session.createNewSession{value: bountySend}(
            userVote[nonce][highestBidder[nonce]].nftAddress, 
            userVote[nonce][highestBidder[nonce]].tokenid,
            userVote[nonce][highestBidder[nonce]].intitialAppraisal,
            86400
        );
        userVote[nonce][highestBidder[nonce]].bid = 0;
        endTime[++nonce] = block.timestamp + 86400;
        emit auctionEnded(
            highestBidder[nonce], 
            userVote[nonce][highestBidder[nonce]].bid, 
            userVote[nonce][highestBidder[nonce]].nftAddress, 
            userVote[nonce][highestBidder[nonce]].tokenid, 
            userVote[nonce][highestBidder[nonce]].intitialAppraisal
        );
    }

    /// @notice allows users to claim non-employed funds
    function claim() nonReentrant external {
        uint returnValue;
        if(highestBidder[nonce] != msg.sender) {
            returnValue = tvl[msg.sender];
            userVote[nonce][msg.sender].bid = 0;
        }
        else {
            returnValue = tvl[msg.sender] - userVote[nonce][msg.sender].bid;
        }
        tvl[msg.sender] -= returnValue;
        (bool sent, ) = payable(msg.sender).call{value: returnValue}("");
        require(sent);
    }
}

File 2 of 9 : PricingSession.sol
pragma solidity ^0.8.0;

import "./helpers/ReentrancyGuard.sol";
import "./interfaces/IABCTreasury.sol";
import "./libraries/SafeMath.sol";
import "./libraries/sqrtLibrary.sol";
import "./libraries/PostSessionLibrary.sol";
import "./interfaces/IERC20.sol";
import "./ABCTreasury.sol";

/// @author Medici
/// @title Pricing session contract for Abacus
contract PricingSession is ReentrancyGuard {

    using SafeMath for uint;

    /* ======== ADDRESS ======== */

    address public ABCToken;
    ABCTreasury public Treasury;
    address public admin;
    address auction;

    /* ======== BOOL ======== */

    bool auctionStatus;
    bool tokenStatus;
    
    /* ======== MAPPINGS ======== */

    /// @notice maps each user to their total points earned
    mapping(address => uint) public points;

    /// @notice maps each user to their total profit earned
    mapping(address => uint) public profitStored;

    /// @notice maps each user to their principal stored
    mapping(address => uint) public principalStored;

    /// @notice maps each NFT to its current nonce value
    mapping(address => mapping (uint => uint)) public nftNonce; 

    mapping(uint => mapping(address => mapping(uint => VotingSessionMapping))) NftSessionMap;

    /// @notice maps each NFT pricing session (nonce dependent) to its necessary session checks (i.e. checking session progression)
    /// @dev nonce => tokenAddress => tokenId => session metadata
    mapping(uint => mapping(address => mapping(uint => VotingSessionChecks))) public NftSessionCheck;

    /// @notice maps each NFT pricing session (nonce dependent) to its necessary session core values (i.e. total participants, total stake, etc...)
    mapping(uint => mapping(address => mapping(uint => VotingSessionCore))) public NftSessionCore;

    /// @notice maps each NFT pricing session (nonce dependent) to its final appraisal value output
    mapping(uint => mapping(address => mapping(uint => uint))) public finalAppraisalValue;
    
    /* ======== STRUCTS ======== */

    /// @notice tracks all of the mappings necessary to operate a session
    struct VotingSessionMapping {

        mapping (address => uint) voterCheck;
        mapping (address => uint) winnerPoints;
        mapping (address => uint) amountHarvested;
        mapping (address => Voter) nftVotes;
    }

    /// @notice track necessary session checks (i.e. whether its time to weigh votes or harvest)
    struct VotingSessionChecks {

        uint sessionProgression;
        uint calls;
        uint correct;
        uint incorrect;
        uint timeFinalAppraisalSet;
    }

    /// @notice track the core values of a session (max appraisal value, total session stake, etc...)
    struct VotingSessionCore {

        uint endTime;
        uint bounty;
        uint lowestStake;
        uint maxAppraisal;
        uint totalAppraisalValue;
        uint totalSessionStake;
        uint totalProfit;
        uint totalWinnerPoints;
        uint totalVotes;
        uint uniqueVoters;
        uint votingTime;
    }

    /// @notice track voter information
    struct Voter {

        bytes32 concealedAppraisal;
        uint base;
        uint appraisal;
        uint stake;
    }

    /* ======== EVENTS ======== */

    event PricingSessionCreated(address creator_, uint nonce, address nftAddress_, uint tokenid_, uint initialAppraisal_, uint bounty_);
    event newAppraisalAdded(address voter_, uint nonce, address nftAddress_, uint tokenid_, uint stake_, bytes32 userHash_);
    event bountyIncreased(address sender_, uint nonce, address nftAddress_, uint tokenid_, uint amount_);
    event appraisalIncreased(address sender_, uint nonce, address nftAddress_, uint tokenid_, uint amount_);
    event voteWeighed(address user_, uint nonce, address nftAddress_, uint tokenid_, uint appraisal);
    event finalAppraisalDetermined(uint nonce, address nftAddress_, uint tokenid_, uint finalAppraisal, uint amountOfParticipants, uint totalStake);
    event userHarvested(address user_, uint nonce, address nftAddress_, uint tokenid_, uint harvested);
    event ethClaimedByUser(address user_, uint ethClaimed);
    event ethToABCExchange(address user_, uint ethExchanged, uint ppSent);
    event sessionEnded(address nftAddress, uint tokenid, uint nonce);

    /* ======== CONSTRUCTOR ======== */

    constructor(address _treasury, address _auction) {
        Treasury = ABCTreasury(payable(_treasury));
        auction = _auction;
        admin = msg.sender;
        auctionStatus = true;
        tokenStatus = false;
    }

    /// @notice set the auction address to be referenced throughout the contract
    /// @param _auction desired auction address to be stored and referenced in contract
    function setAuction(address _auction) external {
        require(msg.sender == admin);
        auction = _auction;
    }

    /// @notice set the auction status based on the active/inactive status of the bounty auction
    /// @param status desired auction status to be stored and referenced in contract
    function setAuctionStatus(bool status) external {
        require(msg.sender == admin); 
        auctionStatus = status;
    }

    function setABCToken(address _token) external {
        ABCToken = _token;
        tokenStatus = true;
    }

    /// @notice Allow user to create new session and attach initial bounty
    /**
    @dev NFT sessions are indexed using a nonce per specific nft.
    The mapping is done by mapping a nonce to an NFT address to the 
    NFT token id. 
    */ 
    /// @param nftAddress NFT contract address of desired NFT to be priced
    /// @param tokenid NFT token id of desired NFT to be priced 
    /// @param _initialAppraisal appraisal value for max value to be instantiated against
    /// @param _votingTime voting window duration
    function createNewSession(
        address nftAddress,
        uint tokenid,
        uint _initialAppraisal,
        uint _votingTime
    ) stopOverwrite(nftAddress, tokenid) external payable {
        require(_votingTime <= 1 days && (!auctionStatus || msg.sender == auction));
        VotingSessionCore storage sessionCore = NftSessionCore[nftNonce[nftAddress][tokenid]][nftAddress][tokenid];
        if(msg.sender == auction) {}
        else {
            uint abcCost = 0.005 ether *(ethToAbc());
            (bool abcSent) = IERC20(ABCToken).transferFrom(msg.sender, address(Treasury), abcCost);
            require(abcSent);
        }
        if(nftNonce[nftAddress][tokenid] == 0 || getStatus(nftAddress, tokenid) == 5) {}
        else if(block.timestamp > sessionCore.endTime + sessionCore.votingTime * 3) {
            _executeEnd(nftAddress, tokenid);
        }
        nftNonce[nftAddress][tokenid]++;
        VotingSessionCore storage sessionCoreNew = NftSessionCore[nftNonce[nftAddress][tokenid]][nftAddress][tokenid];
        sessionCoreNew.votingTime = _votingTime;
        sessionCoreNew.maxAppraisal = 69420 * _initialAppraisal / 1000;
        sessionCoreNew.lowestStake = 100000 ether;
        sessionCoreNew.endTime = block.timestamp + _votingTime;
        sessionCoreNew.bounty = msg.value;
        emit PricingSessionCreated(msg.sender, nftNonce[nftAddress][tokenid], nftAddress, tokenid, _initialAppraisal, msg.value);
    }

    function depositPrincipal() nonReentrant payable external {
        principalStored[msg.sender] += msg.value;
    }

    /// @notice allows user to reclaim principalUsed in batches
    function claimPrincipalUsed(uint _amount) nonReentrant external {
        require(_amount <= principalStored[msg.sender]);
        principalStored[msg.sender] -= _amount;
        (bool sent, ) = msg.sender.call{value: _amount}("");
        require(sent);
    }

    /// @notice allows user to claim batched earnings
    /// @param trigger denotes whether the user desires it in ETH (1) or ABC (2)
    function claimProfitsEarned(uint trigger, uint _amount) nonReentrant external {
        require(trigger == 1 || trigger == 2);
        if(trigger == 2) {
            require(tokenStatus);
        }
        require(profitStored[msg.sender] >= _amount);
        if(trigger == 1) {
            (bool sent1, ) = msg.sender.call{value: _amount}("");
            require(sent1);
            profitStored[msg.sender] -= _amount;
            emit ethClaimedByUser(msg.sender, _amount);
        }
        else if(trigger == 2) {
            uint abcAmount = _amount / (0.00005 ether + 0.000015 ether * Treasury.tokensClaimed()/(1000000*1e18));
            uint abcPayout = ((_amount / (0.00005 ether + 0.000015 ether * Treasury.tokensClaimed()/(1000000*1e18))) + (_amount / (0.00005 ether + 0.000015 ether * Treasury.tokensClaimed() + abcAmount) / (1000000*1e18)) / 2);
            (bool sent3, ) = payable(Treasury).call{value: _amount}("");
            require(sent3);
            profitStored[msg.sender] -= _amount;
            Treasury.sendABCToken(msg.sender, abcPayout * 1e18);
            emit ethToABCExchange(msg.sender, _amount, abcPayout);
        }
    } 

    /* ======== USER VOTE FUNCTIONS ======== */
    
    /// @notice Allows user to set vote in party 
    /** 
    @dev Users appraisal is hashed so users can't track final appraisal and submit vote right before session ends.
    Therefore, users must remember their appraisal in order to reveal their appraisal in the next function.
    */
    /// @param nftAddress NFT contract address of NFT being appraised
    /// @param tokenid NFT tokenid of NFT being appraised
    /// @param concealedAppraisal concealed bid that is a hash of the appraisooooors appraisal value, wallet address, and seed number
    function setVote(
        address nftAddress,
        uint tokenid,
        uint stake,
        bytes32 concealedAppraisal
    ) properVote(nftAddress, tokenid, stake) external {
        uint nonce = nftNonce[nftAddress][tokenid];
        VotingSessionCore storage sessionCore = NftSessionCore[nonce][nftAddress][tokenid];
        VotingSessionMapping storage sessionMap = NftSessionMap[nonce][nftAddress][tokenid];
        require(sessionCore.endTime > block.timestamp && stake <= principalStored[msg.sender]);
        sessionMap.voterCheck[msg.sender] = 1;
        principalStored[msg.sender] -= stake;
        if (stake < sessionCore.lowestStake) {
            sessionCore.lowestStake = stake;
        }
        sessionCore.uniqueVoters++;
        sessionCore.totalSessionStake = sessionCore.totalSessionStake.add(stake);
        sessionMap.nftVotes[msg.sender].concealedAppraisal = concealedAppraisal;
        sessionMap.nftVotes[msg.sender].stake = stake;
        emit newAppraisalAdded(msg.sender, nonce, nftAddress, tokenid, stake, concealedAppraisal);
    }

    /// @notice allow user to update value inputs of their vote while voting is still active
    /// @param nftAddress NFT contract address of NFT being appraised
    /// @param tokenid NFT tokenid of NFT being appraised
    /// @param concealedAppraisal concealed bid that is a hash of the appraisooooors new appraisal value, wallet address, and seed number
    function updateVote(
        address nftAddress,
        uint tokenid,
        bytes32 concealedAppraisal
    ) external {
        uint nonce = nftNonce[nftAddress][tokenid];
        VotingSessionCore storage sessionCore = NftSessionCore[nonce][nftAddress][tokenid];
        VotingSessionMapping storage sessionMap = NftSessionMap[nonce][nftAddress][tokenid];
        require(sessionMap.voterCheck[msg.sender] == 1);
        require(sessionCore.endTime > block.timestamp);
        sessionMap.nftVotes[msg.sender].concealedAppraisal = concealedAppraisal;
    }

    /// @notice Reveals user vote and weights based on the sessions lowest stake
    /**
    @dev calculation can be found in the weightVoteLibrary.sol file. 
    Votes are weighted as sqrt(userStake/lowestStake). Depending on a votes weight
    it is then added as multiple votes of that appraisal (i.e. if someoneone has
    voting weight of 8, 8 votes are submitted using their appraisal).
    */
    /// @param nftAddress NFT contract address of NFT being appraised
    /// @param tokenid NFT tokenid of NFT being appraised
    /// @param appraisal appraisooooor appraisal value used to unlock concealed appraisal
    /// @param seedNum appraisooooor seed number used to unlock concealed appraisal
    function weightVote(address nftAddress, uint tokenid, uint appraisal, uint seedNum) checkParticipation(nftAddress, tokenid) nonReentrant external {
        uint nonce = nftNonce[nftAddress][tokenid];
        VotingSessionCore storage sessionCore = NftSessionCore[nonce][nftAddress][tokenid];
        VotingSessionMapping storage sessionMap = NftSessionMap[nonce][nftAddress][tokenid];
        VotingSessionChecks storage sessionCheck = NftSessionCheck[nonce][nftAddress][tokenid];
        require(sessionCheck.sessionProgression < 2
                && sessionCore.endTime < block.timestamp
                && sessionMap.voterCheck[msg.sender] == 1
                && sessionMap.nftVotes[msg.sender].concealedAppraisal == keccak256(abi.encodePacked(appraisal, msg.sender, seedNum))
                && sessionCore.maxAppraisal >= appraisal
        );
        sessionMap.voterCheck[msg.sender] = 2;
        if(sessionCheck.sessionProgression == 0) {
            sessionCheck.sessionProgression = 1;
        }
        _weigh(nftAddress, tokenid, appraisal);
        emit voteWeighed(msg.sender, nonce, nftAddress, tokenid, appraisal);
        if(sessionCheck.calls == sessionCore.uniqueVoters || sessionCore.endTime + sessionCore.votingTime < block.timestamp) {
            sessionCheck.sessionProgression = 2;
            sessionCore.uniqueVoters = sessionCheck.calls;
            sessionCheck.calls = 0;
        }
    }
    
    /// @notice takes average of appraisals and outputs a final appraisal value.
    /// @param nftAddress NFT contract address of NFT being appraised
    /// @param tokenid NFT tokenid of NFT being appraised
    function setFinalAppraisal(address nftAddress, uint tokenid) public {
        uint nonce = nftNonce[nftAddress][tokenid];
        VotingSessionCore storage sessionCore = NftSessionCore[nonce][nftAddress][tokenid];
        VotingSessionChecks storage sessionCheck = NftSessionCheck[nonce][nftAddress][tokenid];
        require(
            (block.timestamp > sessionCore.endTime + sessionCore.votingTime || sessionCheck.sessionProgression == 2)
            && sessionCheck.sessionProgression <= 2
        );
        Treasury.updateNftPriced();
        if(sessionCheck.calls != 0) {
            sessionCore.uniqueVoters = sessionCheck.calls;
        }
        sessionCore.totalProfit += sessionCore.bounty;
        sessionCore.totalSessionStake += sessionCore.bounty;
        sessionCheck.calls = 0;
        sessionCheck.timeFinalAppraisalSet = block.timestamp;
        finalAppraisalValue[nonce][nftAddress][tokenid] = (sessionCore.totalAppraisalValue)/(sessionCore.totalVotes);
        sessionCheck.sessionProgression = 3;
        emit finalAppraisalDetermined(nftNonce[nftAddress][tokenid], nftAddress, tokenid, finalAppraisalValue[nftNonce[nftAddress][tokenid]][nftAddress][tokenid], sessionCore.uniqueVoters, sessionCore.totalSessionStake);
    }

    /// @notice Calculates users base and harvests their loss before returning remaining stake
    /**
    @dev A couple notes:
    1. Base is calculated based on margin of error.
        > +/- 5% = 1
        > +/- 4% = 2
        > +/- 3% = 3
        > +/- 2% = 4
        > +/- 1% = 5
        > Exact = 6
    2. winnerPoints are calculated based on --> base * stake
    3. Losses are harvested based on --> (margin of error - 5%) * stake
    */
    /// @param nftAddress NFT contract address of NFT being appraised
    /// @param tokenid NFT tokenid of NFT being appraised
    function harvest(address nftAddress, uint tokenid) checkParticipation(nftAddress, tokenid) nonReentrant external {
        uint nonce = nftNonce[nftAddress][tokenid];
        VotingSessionCore storage sessionCore = NftSessionCore[nonce][nftAddress][tokenid];
        VotingSessionChecks storage sessionCheck = NftSessionCheck[nonce][nftAddress][tokenid];
        VotingSessionMapping storage sessionMap = NftSessionMap[nonce][nftAddress][tokenid];
        require(
            sessionCheck.sessionProgression == 3
            && sessionMap.voterCheck[msg.sender] == 2
        );
        sessionCheck.calls++;
        sessionMap.voterCheck[msg.sender] = 3;
        
        _harvest(nftAddress, tokenid);

        sessionMap.nftVotes[msg.sender].stake -= sessionMap.amountHarvested[msg.sender];
        uint commission = PostSessionLibrary.setCommission(address(Treasury).balance).mul(sessionMap.amountHarvested[msg.sender]).div(10000);
        sessionCore.totalSessionStake -= commission;
        sessionMap.amountHarvested[msg.sender] -= commission;
        sessionCore.totalProfit += sessionMap.amountHarvested[msg.sender];
        Treasury.updateProfitGenerated(sessionMap.amountHarvested[msg.sender]);
        (bool sent, ) = payable(Treasury).call{value: commission}("");
        require(sent);
        emit userHarvested(msg.sender, nonce, nftAddress, tokenid, sessionMap.amountHarvested[msg.sender]);

        if(sessionCheck.calls == sessionCore.uniqueVoters) {
            sessionCheck.sessionProgression = 4;
            sessionCore.uniqueVoters = sessionCheck.calls;
            sessionCheck.calls = 0;
        }
    }

    /// @notice User claims principal stake along with any earned profits in ETH or ABC form
    /**
    @dev 
    1. Calculates user principal return value
    2. Enacts sybil defense mechanism
    3. Edits totalProfits and totalSessionStake to reflect claim
    5. Pays out principal
    6. Adds profit credit to profitStored
    */
    /// @param nftAddress NFT contract address of NFT being appraised
    /// @param tokenid NFT tokenid of NFT being appraised
    function claim(address nftAddress, uint tokenid) checkParticipation(nftAddress, tokenid) nonReentrant external returns(uint) {
        uint nonce = nftNonce[nftAddress][tokenid];
        VotingSessionCore storage sessionCore = NftSessionCore[nonce][nftAddress][tokenid];
        VotingSessionChecks storage sessionCheck = NftSessionCheck[nonce][nftAddress][tokenid];
        VotingSessionMapping storage sessionMap = NftSessionMap[nonce][nftAddress][tokenid];
        if (sessionCheck.timeFinalAppraisalSet == 0) {
            require(
            sessionCheck.sessionProgression == 4
            || block.timestamp > (sessionCore.endTime + sessionCore.votingTime * 2)
            );
        }
        else{
            require(
            (block.timestamp > sessionCheck.timeFinalAppraisalSet + sessionCore.votingTime || sessionCheck.sessionProgression == 4)
            && sessionCheck.sessionProgression <= 4
            && sessionMap.voterCheck[msg.sender] == 3
            );
        }
        uint principalReturn;
        sessionMap.voterCheck[msg.sender] = 4;
        if(sessionCheck.sessionProgression == 3) {
            sessionCore.uniqueVoters = sessionCheck.calls;
            sessionCheck.calls = 0;
            sessionCheck.sessionProgression = 4;
        }
        if(sessionCheck.correct * 100 / (sessionCheck.correct + sessionCheck.incorrect) >= 90) {
            principalReturn += sessionMap.nftVotes[msg.sender].stake + sessionMap.amountHarvested[msg.sender];
        }
        else {
            principalReturn += sessionMap.nftVotes[msg.sender].stake;
        }
        sessionCheck.calls++;
        uint payout;
        if(sessionMap.winnerPoints[msg.sender] == 0) {
            payout = 0;
        }
        else {
            payout = sessionCore.totalProfit * sessionMap.winnerPoints[msg.sender] / sessionCore.totalWinnerPoints;
        }
        profitStored[msg.sender] += payout;
        sessionCore.totalProfit -= payout;
        sessionCore.totalSessionStake -= payout + principalReturn;
        principalStored[msg.sender] += principalReturn;
        sessionCore.totalWinnerPoints -= sessionMap.winnerPoints[msg.sender];
        sessionMap.winnerPoints[msg.sender] = 0;
        if(sessionCheck.calls == sessionCore.uniqueVoters || block.timestamp > sessionCheck.timeFinalAppraisalSet + sessionCore.votingTime*2) {
            sessionCheck.sessionProgression = 5;
            _executeEnd(nftAddress, tokenid);
            return 0;
        }

        return 1;
    }
    
    /// @notice Custodial function to clear funds and remove session as child
    /// @dev Caller receives 10% of the funds that are meant to be cleared
    /// @param nftAddress NFT contract address of NFT being appraised
    /// @param tokenid NFT tokenid of NFT being appraised
    function endSession(address nftAddress, uint tokenid) public {
        uint nonce = nftNonce[nftAddress][tokenid];
        VotingSessionCore storage sessionCore = NftSessionCore[nonce][nftAddress][tokenid];
        VotingSessionChecks storage sessionCheck = NftSessionCheck[nonce][nftAddress][tokenid];
        if (sessionCheck.timeFinalAppraisalSet == 0) {
            revert();
        }
        else{
            require(
                (block.timestamp > sessionCheck.timeFinalAppraisalSet + sessionCore.votingTime * 2 || sessionCheck.sessionProgression == 5)
            );
            _executeEnd(nftAddress, tokenid);
        }
    }

    /* ======== INTERNAL FUNCTIONS ======== */

    function _weigh(address nftAddress, uint tokenid, uint appraisal) internal {
        uint nonce = nftNonce[nftAddress][tokenid];
        VotingSessionCore storage sessionCore = NftSessionCore[nonce][nftAddress][tokenid];
        VotingSessionMapping storage sessionMap = NftSessionMap[nonce][nftAddress][tokenid];
        VotingSessionChecks storage sessionCheck = NftSessionCheck[nonce][nftAddress][tokenid];
        sessionMap.nftVotes[msg.sender].appraisal = appraisal;
        uint weight = sqrtLibrary.sqrt(sessionMap.nftVotes[msg.sender].stake/sessionCore.lowestStake);
        sessionCore.totalVotes += weight;
        sessionCheck.calls++;
        
        sessionCore.totalAppraisalValue = sessionCore.totalAppraisalValue.add((weight) * appraisal);
    }

    function _harvest(address nftAddress, uint tokenid) internal {
        uint nonce = nftNonce[nftAddress][tokenid];
        VotingSessionCore storage sessionCore = NftSessionCore[nonce][nftAddress][tokenid];
        VotingSessionChecks storage sessionCheck = NftSessionCheck[nonce][nftAddress][tokenid];
        VotingSessionMapping storage sessionMap = NftSessionMap[nonce][nftAddress][tokenid];
        sessionMap.nftVotes[msg.sender].base = 
            PostSessionLibrary.calculateBase(
                finalAppraisalValue[nftNonce[nftAddress][tokenid]][nftAddress][tokenid], 
                sessionMap.nftVotes[msg.sender].appraisal
            );
        uint weight = sqrtLibrary.sqrt(sessionMap.nftVotes[msg.sender].stake/sessionCore.lowestStake);
        if(sessionMap.nftVotes[msg.sender].base > 0) {
            sessionCore.totalWinnerPoints += sessionMap.nftVotes[msg.sender].base * weight;
            sessionMap.winnerPoints[msg.sender] = sessionMap.nftVotes[msg.sender].base * weight;
            sessionCheck.correct += weight;
        }
        else {
            sessionCheck.incorrect += weight;
        }
        
       sessionMap.amountHarvested[msg.sender] = PostSessionLibrary.harvest( 
            sessionMap.nftVotes[msg.sender].stake, 
            sessionMap.nftVotes[msg.sender].appraisal,
            finalAppraisalValue[nftNonce[nftAddress][tokenid]][nftAddress][tokenid]
        );
    }

    /// @notice executes custodial actions to end a session
    /** @dev Clears session claims to funds, distributes 95% of residual funds
    to treasury and the other 5% to the caller. Then proceeds to set the total
    session stake to 0 and emit an end session event to signify session completion. 
     */
    /// @param nftAddress NFT contract address of NFT being appraised
    /// @param tokenid NFT tokenid of NFT being appraised
    function _executeEnd(address nftAddress, uint tokenid) internal {
        uint nonce = nftNonce[nftAddress][tokenid];
        VotingSessionCore storage sessionCore = NftSessionCore[nonce][nftAddress][tokenid];
        VotingSessionChecks storage sessionCheck = NftSessionCheck[nonce][nftAddress][tokenid];
        sessionCheck.sessionProgression = 5;
        uint tPayout = 97*sessionCore.totalSessionStake/100;
        uint cPayout = sessionCore.totalSessionStake - tPayout;
        (bool sent, ) = payable(Treasury).call{value: tPayout}("");
        require(sent);
        (bool sent1, ) = msg.sender.call{value: cPayout}("");
        require(sent1);
        sessionCore.totalSessionStake = 0;
        emit sessionEnded(nftAddress, tokenid, nftNonce[nftAddress][tokenid]);
    }

    /* ======== FUND INCREASE ======== */

    /// @notice allow any user to add additional bounty on session of their choice
    /// @param nftAddress NFT contract address of NFT being appraised
    /// @param tokenid NFT tokenid of NFT being appraised
    function addToBounty(address nftAddress, uint tokenid) payable external {
        VotingSessionCore storage sessionCore = NftSessionCore[nftNonce[nftAddress][tokenid]][nftAddress][tokenid];
        require(sessionCore.endTime > block.timestamp);
        sessionCore.bounty += msg.value;
        sessionCore.totalSessionStake += msg.value;
        emit bountyIncreased(msg.sender, nftNonce[nftAddress][tokenid], nftAddress, tokenid, msg.value);
    }

    /* ======== VIEW FUNCTIONS ======== */

    /// @notice returns the status of the session in question
    /// @param nftAddress NFT contract address of NFT being appraised
    /// @param tokenid NFT tokenid of NFT being appraised
    function getStatus(address nftAddress, uint tokenid) view public returns(uint) {
        return NftSessionCheck[nftNonce[nftAddress][tokenid]][nftAddress][tokenid].sessionProgression;
    }

    /// @notice returns the current spot exchange rate of ETH to ABC
    function ethToAbc() view public returns(uint) {
        return 1e18 / (0.00005 ether + 0.000015 ether * Treasury.tokensClaimed() / (1000000*1e18));
    }

    /// @notice returns the payout earned from the current session
    /// @param nftAddress NFT contract address of NFT being appraised
    /// @param tokenid NFT tokenid of NFT being appraised
    function getEthPayout(address nftAddress, uint tokenid) view external returns(uint) {
        VotingSessionCore storage sessionCore = NftSessionCore[nftNonce[nftAddress][tokenid]][nftAddress][tokenid];
        if(sessionCore.totalWinnerPoints == 0) {
            return 0;
        }
        return sessionCore.totalSessionStake * NftSessionMap[nftNonce[nftAddress][tokenid]][nftAddress][tokenid].winnerPoints[msg.sender] / sessionCore.totalWinnerPoints;
    }

    /// @notice check the users status in terms of session interaction
    /// @param nftAddress NFT contract address of NFT being appraised
    /// @param tokenid NFT tokenid of NFT being appraised
    /// @param _user appraisooooor who's session progress is of interest
    function getVoterCheck(address nftAddress, uint tokenid, address _user) view external returns(uint) {
        return NftSessionMap[nftNonce[nftAddress][tokenid]][nftAddress][tokenid].voterCheck[_user];
    }

    /* ======== FALLBACK FUNCTIONS ======== */

    receive() external payable {}
    fallback() external payable {}

    /* ======== MODIFIERS ======== */

    /// @notice stop users from being able to create multiple sessions for the same NFT at the same time
    modifier stopOverwrite(
        address nftAddress, 
        uint tokenid
    ) {
        require(
            nftNonce[nftAddress][tokenid] == 0 
            || getStatus(nftAddress, tokenid) == 5
            || block.timestamp > NftSessionCore[nftNonce[nftAddress][tokenid]][nftAddress][tokenid].endTime + NftSessionCore[nftNonce[nftAddress][tokenid]][nftAddress][tokenid].votingTime * 3
        );
        _;
    }
    
    /// @notice makes sure that a user that submits a vote satisfies the proper voting parameters
    modifier properVote(
        address nftAddress,
        uint tokenid,
        uint stake
    ) {
        require(
            NftSessionMap[nftNonce[nftAddress][tokenid]][nftAddress][tokenid].voterCheck[msg.sender] == 0
            && stake >= 0.005 ether
        );
        _;
    }
    
    /// @notice checks the participation of the msg.sender 
    modifier checkParticipation(
        address nftAddress,
        uint tokenid
    ) {
        require(NftSessionMap[nftNonce[nftAddress][tokenid]][nftAddress][tokenid].voterCheck[msg.sender] > 0);
        _;
    }
}

File 3 of 9 : ABCTreasury.sol
// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.8.0;

import "./interfaces/IERC20.sol";

/// @author Medici
/// @title Treasury contract for Abacus
contract ABCTreasury {
    
    /* ======== UINT ======== */

    uint public nftsPriced;
    uint public profitGenerated;
    uint public tokensClaimed;

    /* ======== ADDRESS ======== */

    address public auction;
    address public pricingSession;
    address public admin;
    address public ABCToken;
    address public multisig;

    /* ======== CONSTRUCTOR ======== */

    constructor() {
        admin = msg.sender;
    }

    /* ======== ADMIN FUNCTIONS ======== */

    /// @notice set ABC token contract address 
    /// @param _ABCToken desired ABC token to be stored and referenced in contract
    function setABCTokenAddress(address _ABCToken) onlyAdmin external {
        require(ABCToken == address(0));
        ABCToken = _ABCToken;
    }

    function setMultisig(address _multisig) onlyAdmin external {
        multisig = _multisig;
    }

    /// @notice allow admin to withdraw funds to multisig in the case of emergency (ONLY USED IN THE CASE OF EMERGENCY)
    /// @param _amountAbc value of ABC to be withdrawn from the treasury to multisig (ONLY USED IN THE CASE OF EMERGENCY)
    /// @param _amountEth value of ETH to be withdrawn from the treasury to multisig (ONLY USED IN THE CASE OF EMERGENCY)
    function withdraw(uint _amountAbc, uint _amountEth) onlyAdmin external {
        IERC20(ABCToken).transfer(multisig, _amountAbc);
        (bool sent, ) = payable(multisig).call{value: _amountEth}("");
        require(sent, "Failed to send Ether");
    }

    /// @notice set newAdmin (or burn admin when the time comes)
    /// @param _newAdmin desired admin address to be stored and referenced in contract
    function setAdmin(address _newAdmin) onlyAdmin external {
        admin = _newAdmin;
    }

    /// @notice set pricing factory address to allow for updates
    /// @param _pricingFactory desired pricing session principle address to be stored and referenced in contract
    function setPricingSession(address _pricingFactory) onlyAdmin external {
        pricingSession = _pricingFactory;
    }

    /// @notice set auction contract for bounty auction period
    /// @param _auction desired auction address to be stored and referenced in contract
    function setAuction(address _auction) onlyAdmin external {
        auction = _auction;
    }

    /* ======== CHILD FUNCTIONS ======== */
    
    /// @notice send ABC to users that earn 
    /// @param recipient the user that will be receiving ABC 
    /// @param _amount the amount of ABC to be transferred to the recipient
    function sendABCToken(address recipient, uint _amount) external {
        require(msg.sender == pricingSession || msg.sender == admin);
        IERC20(ABCToken).transfer(recipient, _amount);
        tokensClaimed += _amount;
    }

    /// @notice Allows Factory contract to update the profit generated value
    /// @param _amount the amount of profit to update profitGenerated count
    function updateProfitGenerated(uint _amount) isFactory external { 
        profitGenerated += _amount;
    }
    
    /// @notice Allows Factory contract to update the amount of NFTs that have been priced
    function updateNftPriced() isFactory external {
        nftsPriced++;
    }

    /* ======== FALLBACKS ======== */

    receive() external payable {}
    fallback() external payable {}

    /* ======== MODIFIERS ======== */

    ///@notice check that msg.sender is admin
    modifier onlyAdmin() {
        require(admin == msg.sender, "not admin");
        _;
    }
    
    ///@notice check that msg.sender is factory
    modifier isFactory() {
        require(msg.sender == pricingSession, "not session contract");
        _;
    }
}

File 4 of 9 : ReentrancyGuard.sol
pragma solidity ^0.8.0;

/**
 * @title Helps contracts guard against reentrancy attacks.
 * @author Remco Bloemen <[email protected]π.com>, Eenae <[email protected]>
 * @dev If you mark a function `nonReentrant`, you should also
 * mark it `external`.
 */
contract ReentrancyGuard {

  /// @dev counter to allow mutex lock with only one SSTORE operation
  uint256 private _guardCounter = 1;

  /**
   * @dev Prevents a contract from calling itself, directly or indirectly.
   * If you mark a function `nonReentrant`, you should also
   * mark it `external`. Calling one `nonReentrant` function from
   * another is not supported. Instead, you can implement a
   * `private` function doing the actual work, and an `external`
   * wrapper marked as `nonReentrant`.
   */
  modifier nonReentrant() {
    _guardCounter += 1;
    uint256 localCounter = _guardCounter;
    _;
    require(localCounter == _guardCounter);
  }

}

File 5 of 9 : IABCTreasury.sol
pragma solidity ^0.8.0;

interface IABCTreasury {
    function sendABCToken(address recipient, uint _amount) external;

    function getTokensClaimed() external view returns(uint);
    
    function updateNftPriced() external;
    
    function updateProfitGenerated(uint _amount) external;

}

File 6 of 9 : SafeMath.sol
pragma solidity ^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, 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) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * 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);
        uint256 c = a - b;

        return c;
    }

    /**
     * @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) {
        // 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 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts 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) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message 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, string memory errorMessage) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts 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) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message 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, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

File 7 of 9 : sqrtLibrary.sol
// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.8.0;

library sqrtLibrary {
    
    function sqrt(uint x) pure internal returns (uint y) {
        uint z = (x + 1) / 2;
        y = x;
        while (z < y) {
            y = z;
            z = (x / z + z) / 2;
        }
    }
}

File 8 of 9 : PostSessionLibrary.sol
// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.8.0;

import "./sqrtLibrary.sol";

library PostSessionLibrary {

    using sqrtLibrary for *;

    /////////////////////
    ///      Base     ///
    /////////////////////

    function calculateBase(uint finalAppraisalValue, uint userAppraisalValue) pure internal returns(uint){
        uint base = 1;
        uint userVal = 100 * userAppraisalValue;
        for(uint i=5; i >= 1; i--) {
            uint lowerOver = (100 + (i - 1)) * finalAppraisalValue;
            uint upperOver = (100 + i) * finalAppraisalValue;
            uint lowerUnder = (100 - i) * finalAppraisalValue;
            uint upperUnder = (100 - i + 1) * finalAppraisalValue;
            if (lowerOver < userVal && userVal <= upperOver) {
                return base; 
            }
            if (lowerUnder < userVal && userVal <= upperUnder) {
                return base;
            }
            base += 1;
        }
        if(userVal == 100*finalAppraisalValue) {
            return 6;
        }
        return 0;
    }

    /////////////////////
    ///    Harvest    ///
    /////////////////////

    // function harvestUserOver(uint _stake, uint _userAppraisal, uint _finalAppraisal) pure internal returns(uint) {
    //     return _stake * (_userAppraisal*100 - 105*_finalAppraisal)/(_finalAppraisal*100);
    // }
    
    // function harvestUserUnder(uint _stake, uint _userAppraisal, uint _finalAppraisal) pure internal returns(uint) {
    //     return _stake * (95*_finalAppraisal - 100*_userAppraisal)/(_finalAppraisal*100);
    // }

    function harvest(uint _stake, uint _userAppraisal, uint _finalAppraisal) pure internal returns(uint) {
        if(_userAppraisal*100 > 105*_finalAppraisal) {
            return _stake * (_userAppraisal*100 - 105*_finalAppraisal)/(_finalAppraisal*100);
        }
        else if(_userAppraisal*100 < 95*_finalAppraisal) {
            return _stake * (95*_finalAppraisal - 100*_userAppraisal)/(_finalAppraisal*100);
        }
        else {
            return 0;
        }
    }

    /////////////////////
    ///   Commission  ///
    /////////////////////   
    function setCommission(uint _treasurySize) pure internal returns(uint) {
        if (_treasurySize < 25000 ether) {
            return 500;
        }
        else if(_treasurySize >= 25000 ether && _treasurySize < 50000 ether) {
            return 400;
        }
        else if(_treasurySize >= 50000 ether && _treasurySize < 100000 ether) {
            return 300;
        }
        else if(_treasurySize >= 100000 ether && _treasurySize < 2000000 ether) {
            return 200;
        }
        else if(_treasurySize >= 200000 ether && _treasurySize < 400000 ether) {
            return 100;
        }
        else if(_treasurySize >= 400000 ether && _treasurySize < 700000 ether) {
            return 50;
        }
        else {
            return 25;
        }
    }


}

File 9 of 9 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

Settings
{
  "optimizer": {
    "enabled": false,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_highestBidder","type":"address"},{"indexed":false,"internalType":"uint256","name":"_highestBid","type":"uint256"},{"indexed":false,"internalType":"address","name":"_nftAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"_tokenid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_initialAppraisal","type":"uint256"}],"name":"auctionEnded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_bidder","type":"address"},{"indexed":false,"internalType":"uint256","name":"_bidAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"_nftAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"_tokenid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_initialAppraisal","type":"uint256"}],"name":"newBidSubmitted","type":"event"},{"inputs":[],"name":"ABCToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_nftAddress","type":"address"},{"internalType":"uint256","name":"_tokenid","type":"uint256"}],"name":"addToBid","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"auctionStatus","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_nftAddress","type":"address"},{"internalType":"uint256","name":"_tokenid","type":"uint256"},{"internalType":"uint256","name":"_initialAppraisal","type":"uint256"}],"name":"changeInfo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"endAuction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"endTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"firstSession","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"highestBid","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"highestBidder","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_nftAddress","type":"address"},{"internalType":"uint256","name":"_tokenid","type":"uint256"},{"internalType":"uint256","name":"_initialAppraisal","type":"uint256"}],"name":"newBid","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"session","outputs":[{"internalType":"contract PricingSession","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_state","type":"bool"}],"name":"setFirst","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_session","type":"address"}],"name":"setSessionContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"setToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_treasury","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"toggleAuction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"contract ABCTreasury","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"userVote","outputs":[{"internalType":"address","name":"nftAddress","type":"address"},{"internalType":"uint256","name":"tokenid","type":"uint256"},{"internalType":"uint256","name":"intitialAppraisal","type":"uint256"},{"internalType":"uint256","name":"bid","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"winners","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

6080604052600160005534801561001557600080fd5b5033600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600460146101000a81548160ff021916908315150217905550612614806100816000396000f3fe6080604052600436106101355760003560e01c80639d6a0f28116100ab578063d8ac34ee1161006f578063d8ac34ee146103e6578063dc37596d1461040f578063f0f442601461044f578063f851a44014610478578063faf206c2146104a3578063fe67a54b146104ce57610135565b80639d6a0f28146102ed578063a2fb117514610318578063a6fe2c5514610355578063affed0e01461037e578063b14c63c5146103a957610135565b8063451df52e116100fd578063451df52e146102105780634e71d92d1461024d5780635711b8f9146102645780635e3568b81461027b57806361d027b3146102a657806375b37d92146102d157610135565b8063144fa6d71461013a5780632d16502f146101635780633b22e0481461018c5780634223ac0f146101a857806344c816fa146101d3575b600080fd5b34801561014657600080fd5b50610161600480360381019061015c9190612069565b6104e5565b005b34801561016f57600080fd5b5061018a600480360381019061018591906120ce565b610583565b005b6101a660048036038101906101a19190612092565b610797565b005b3480156101b457600080fd5b506101bd610b56565b6040516101ca919061225d565b60405180910390f35b3480156101df57600080fd5b506101fa60048036038101906101f59190612146565b610b7c565b60405161020791906123cf565b60405180910390f35b34801561021c57600080fd5b5061023760048036038101906102329190612146565b610b94565b604051610244919061225d565b60405180910390f35b34801561025957600080fd5b50610262610bc7565b005b34801561027057600080fd5b50610279610e74565b005b34801561028757600080fd5b50610290610f12565b60405161029d91906123b4565b60405180910390f35b3480156102b257600080fd5b506102bb610f38565b6040516102c89190612399565b60405180910390f35b6102eb60048036038101906102e691906120ce565b610f5e565b005b3480156102f957600080fd5b50610302611599565b60405161030f919061237e565b60405180910390f35b34801561032457600080fd5b5061033f600480360381019061033a9190612146565b6115ac565b60405161034c919061225d565b60405180910390f35b34801561036157600080fd5b5061037c6004803603810190610377919061211d565b6115df565b005b34801561038a57600080fd5b50610393611656565b6040516103a091906123cf565b60405180910390f35b3480156103b557600080fd5b506103d060048036038101906103cb9190612146565b61165c565b6040516103dd91906123cf565b60405180910390f35b3480156103f257600080fd5b5061040d60048036038101906104089190612069565b611674565b005b34801561041b57600080fd5b5061043660048036038101906104319190612198565b611712565b6040516104469493929190612339565b60405180910390f35b34801561045b57600080fd5b5061047660048036038101906104719190612069565b61176f565b005b34801561048457600080fd5b5061048d61180d565b60405161049a919061225d565b60405180910390f35b3480156104af57600080fd5b506104b8611833565b6040516104c5919061237e565b60405180910390f35b3480156104da57600080fd5b506104e3611846565b005b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461053f57600080fd5b80600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600073ffffffffffffffffffffffffffffffffffffffff16600a6000600554815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141580156106415750600460149054906101000a900460ff165b61064a57600080fd5b82600a6000600554815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600a6000600554815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001018190555080600a6000600554815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020181905550505050565b60016000808282546107a991906123f5565b925050819055506000805490506006600060055481526020019081526020016000205434600a6000600554815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206003015461082d91906123f5565b1180156108465750600460149054906101000a900460ff165b80156109b557506000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632171d26e85856040518363ffffffff1660e01b81526004016108ac929190612278565b60206040518083038186803b1580156108c457600080fd5b505afa1580156108d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108fc919061216f565b14806109b457506005600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16634ce0ef9585856040518363ffffffff1660e01b8152600401610962929190612278565b60206040518083038186803b15801561097a57600080fd5b505afa15801561098e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109b2919061216f565b145b5b6109be57600080fd5b34600a6000600554815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206003016000828254610a2391906123f5565b925050819055503360076000600554815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600a6000600554815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600301546006600060055481526020019081526020016000208190555034600c60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254610b3c91906123f5565b925050819055506000548114610b5157600080fd5b505050565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60086020528060005260406000206000915090505481565b60076020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6001600080828254610bd991906123f5565b9250508190555060008054905060003373ffffffffffffffffffffffffffffffffffffffff1660076000600554815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610cf257600c60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490506000600a6000600554815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060030181905550610d95565b600a6000600554815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060030154600c60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610d92919061244b565b90505b80600c60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254610de4919061244b565b9250508190555060003373ffffffffffffffffffffffffffffffffffffffff1682604051610e1190612248565b60006040518083038185875af1925050503d8060008114610e4e576040519150601f19603f3d011682016040523d82523d6000602084013e610e53565b606091505b5050905080610e6157600080fd5b50506000548114610e7157600080fd5b50565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610ece57600080fd5b600460149054906101000a900460ff1615600460146101000a81548160ff02191690831515021790555060056000815480929190610f0b90612521565b9190505550565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6001600080828254610f7091906123f5565b925050819055506000805490506006600060055481526020019081526020016000205434118015610fad5750600460149054906101000a900460ff165b801561111c57506000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632171d26e86866040518363ffffffff1660e01b8152600401611013929190612278565b60206040518083038186803b15801561102b57600080fd5b505afa15801561103f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611063919061216f565b148061111b57506005600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16634ce0ef9586866040518363ffffffff1660e01b81526004016110c9929190612278565b60206040518083038186803b1580156110e157600080fd5b505afa1580156110f5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611119919061216f565b145b5b61112557600080fd5b42600b60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055503360076000600554815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055503460066000600554815260200190815260200160002081905550600a6000600554815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060030154600c60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461127b919061244b565b9250508190555060003373ffffffffffffffffffffffffffffffffffffffff16600a6000600554815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600301546040516112fd90612248565b60006040518083038185875af1925050503d806000811461133a576040519150601f19603f3d011682016040523d82523d6000602084013e61133f565b606091505b505090508061134d57600080fd5b84600a6000600554815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555083600a6000600554815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206001018190555082600a6000600554815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206002018190555034600a6000600554815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206003018190555034600c60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825461153e91906123f5565b925050819055507f0e756fa4a9fc804a0b7895c41d5d9aec59ef49bd0e10fca02f7c0fcdb354d49a333487878760405161157c9594939291906122a1565b60405180910390a150600054811461159357600080fd5b50505050565b600460149054906101000a900460ff1681565b60096020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461163957600080fd5b80600460156101000a81548160ff02191690831515021790555050565b60055481565b60066020528060005260406000206000915090505481565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146116ce57600080fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600a602052816000526040600020602052806000526040600020600091509150508060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16908060010154908060020154908060030154905084565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146117c957600080fd5b80600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600460159054906101000a900460ff1681565b600160008082825461185891906123f5565b92505081905550600080549050600460159054906101000a900460ff16156118d557600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146118d457600080fd5b5b42600860006005548152602001908152602001600020541080156119055750600460149054906101000a900460ff165b61190e57600080fd5b6000600a60006005548152602001908152602001600020600060076000600554815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060030154905080600c600060076000600554815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254611a21919061244b565b92505081905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166335d5593082600a60006005548152602001908152602001600020600060076000600554815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600a60006005548152602001908152602001600020600060076000600554815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010154600a60006005548152602001908152602001600020600060076000600554815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020154620151806040518663ffffffff1660e01b8152600401611c4b94939291906122f4565b6000604051808303818588803b158015611c6457600080fd5b505af1158015611c78573d6000803e3d6000fd5b50505050506000600a60006005548152602001908152602001600020600060076000600554815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600301819055506201518042611d1c91906123f5565b60086000600560008154611d2f90612521565b9190508190558152602001908152602001600020819055507fd1ba2b9a4165eb401ff2d35ac2d070d2f0c4377230fdde5a3d0193cbb2340fc860076000600554815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600a60006005548152602001908152602001600020600060076000600554815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060030154600a60006005548152602001908152602001600020600060076000600554815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600a60006005548152602001908152602001600020600060076000600554815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060010154600a60006005548152602001908152602001600020600060076000600554815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020154604051611ffb9594939291906122a1565b60405180910390a150600054811461201257600080fd5b50565b60008135905061202481612599565b92915050565b600081359050612039816125b0565b92915050565b60008135905061204e816125c7565b92915050565b600081519050612063816125c7565b92915050565b60006020828403121561207b57600080fd5b600061208984828501612015565b91505092915050565b600080604083850312156120a557600080fd5b60006120b385828601612015565b92505060206120c48582860161203f565b9150509250929050565b6000806000606084860312156120e357600080fd5b60006120f186828701612015565b93505060206121028682870161203f565b92505060406121138682870161203f565b9150509250925092565b60006020828403121561212f57600080fd5b600061213d8482850161202a565b91505092915050565b60006020828403121561215857600080fd5b60006121668482850161203f565b91505092915050565b60006020828403121561218157600080fd5b600061218f84828501612054565b91505092915050565b600080604083850312156121ab57600080fd5b60006121b98582860161203f565b92505060206121ca85828601612015565b9150509250929050565b6121dd8161247f565b82525050565b6121ec81612491565b82525050565b6121fb816124c7565b82525050565b61220a816124eb565b82525050565b6122198161250f565b82525050565b600061222c6000836123ea565b9150600082019050919050565b612242816124bd565b82525050565b60006122538261221f565b9150819050919050565b600060208201905061227260008301846121d4565b92915050565b600060408201905061228d60008301856121d4565b61229a6020830184612239565b9392505050565b600060a0820190506122b660008301886121d4565b6122c36020830187612239565b6122d060408301866121d4565b6122dd6060830185612239565b6122ea6080830184612239565b9695505050505050565b600060808201905061230960008301876121d4565b6123166020830186612239565b6123236040830185612239565b6123306060830184612210565b95945050505050565b600060808201905061234e60008301876121d4565b61235b6020830186612239565b6123686040830185612239565b6123756060830184612239565b95945050505050565b600060208201905061239360008301846121e3565b92915050565b60006020820190506123ae60008301846121f2565b92915050565b60006020820190506123c96000830184612201565b92915050565b60006020820190506123e46000830184612239565b92915050565b600081905092915050565b6000612400826124bd565b915061240b836124bd565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156124405761243f61256a565b5b828201905092915050565b6000612456826124bd565b9150612461836124bd565b9250828210156124745761247361256a565b5b828203905092915050565b600061248a8261249d565b9050919050565b60008115159050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60006124d2826124d9565b9050919050565b60006124e48261249d565b9050919050565b60006124f6826124fd565b9050919050565b60006125088261249d565b9050919050565b600061251a826124bd565b9050919050565b600061252c826124bd565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561255f5761255e61256a565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6125a28161247f565b81146125ad57600080fd5b50565b6125b981612491565b81146125c457600080fd5b50565b6125d0816124bd565b81146125db57600080fd5b5056fea26469706673582212200af47740d8f46fe421630141fe84b91479f44423f3a5012178961363375eb0a564736f6c63430008000033

Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.