Contract Address Details

0xd813419749b3c2cDc94A2F9Cfcf154113264a9d6

Contract Name
ColdStaking
Creator
0x01000b–179bbf at 0xf90d17–b4b503
Balance
2,514,848.62959784114623563 CLO ( )
Tokens
Fetching tokens...
Transactions
283,945 Transactions
Transfers
2 Transfers
Gas Used
21,572,001,720
Last Balance Update
14631365
Contract name:
ColdStaking




Optimization enabled
true
Compiler version
v0.4.26+commit.4563c3fc




Optimization runs
200
EVM Version
default




Verified at
2022-06-09T14:54:18.357011Z

Contract source code

pragma solidity ^0.4.24;

/**
 * @title SafeMath
 * @dev Math operations with safety checks that throw on error
 */
library SafeMath {
  function mul(uint a, uint b) internal pure returns (uint) {
    if (a == 0) {
      return 0;
    }
    uint c = a * b;
    require(c / a == b);
    return c;
  }

  function div(uint a, uint b) internal pure returns (uint) {
    // assert(b > 0); // Solidity automatically throws when dividing by 0
    uint c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
    return c;
  }

  function sub(uint a, uint b) internal pure returns (uint) {
    require(b <= a);
    return a - b;
  }

  function add(uint a, uint b) internal pure returns (uint) {
    uint c = a + b;
    require(c >= a);
    return c;
  }
}

contract ColdStaking {
    
    // NOTE: The contract only works for intervals of time > round_interval

    using SafeMath for uint;

    event StartStaking(address addr, uint value, uint amount, uint time);
    event WithdrawStake(address staker, uint amount);
    event Claim(address staker, uint reward);
    event DonationDeposited(address _address, uint value);

    struct Staker
    {
        uint amount;
        uint time;
    }


    uint public LastBlock = block.number;
    uint public Timestamp = now;    //timestamp of the last interaction with the contract.

    uint public TotalStakingWeight; //total weight = sum (each_staking_amount * each_staking_time).
    uint public TotalStakingAmount; //currently frozen amount for Staking.
    uint public StakingRewardPool;  //available amount for paying rewards.
    bool public CS_frozen;          //Cold Staking frozen.
    uint public staking_threshold = 0 ether;
    address public Treasury       = 0x3c06f218ce6dd8e2c535a8925a2edf81674984d9; // Callisto Staking Reserve address.

    uint public round_interval   = 27 days;     // 1 month.
    uint public max_delay        = 365 * 2 days;// 2 years.
    uint public DateStartStaking = 1541980800;  // 12.11.2018 0:0:0 UTC.


    //========== TESTNET VALUES ===========
    //uint public round_interval   = 10 minutes; 
    //uint public max_delay        = 2 days;
    //uint public DateStartStaking = 0;
    //========== END TEST VALUES ==========
    
    mapping(address => Staker) public staker;

    function freeze(bool _f) public only_treasurer
    {
        CS_frozen = _f;
    }

    function withdraw_rewards () public only_treasurer
    {
        if (CS_frozen)
        {
            StakingRewardPool = address(this).balance.sub(TotalStakingAmount);
            Treasury.transfer(StakingRewardPool);
        }
    }

    function clear_treasurer () public only_treasurer
    {
        require(block.number > 1800000 && !CS_frozen);
        Treasury = 0x00;
    }
	
    function() public payable
    {
        // No donations accepted to fallback!
        // Consider value deposit is an attempt to become staker.
        // May not accept deposit from other contracts due GAS limit.
        start_staking();
    }

    // this function can be called for manualy update TotalStakingAmount value.
    function new_block() public
    {
        if (block.number > LastBlock)   //run once per block.
        {
            uint _LastBlock = LastBlock;
            LastBlock = block.number;

            StakingRewardPool = address(this).balance.sub(TotalStakingAmount + msg.value);   //fix rewards pool for this block.
            // msg.value here for case new_block() is calling from start_staking(), and msg.value will be added to CurrentBlockDeposits.

            //The consensus protocol enforces block timestamps are always atleast +1 from their parent, so a node cannot "lie into the past". 
            if (now > Timestamp) //But with this condition I feel safer :) May be removed.
            {
                uint _blocks = block.number - _LastBlock;
                uint _seconds = now - Timestamp;
                if (_seconds > _blocks * 25) //if time goes far in the future, then use new time as 25 second * blocks.
                {
                    _seconds = _blocks * 25;
                }
                TotalStakingWeight += _seconds.mul(TotalStakingAmount);
                Timestamp += _seconds;
            }
        }
    }

    function start_staking() public staking_available payable
    {
        assert(msg.value >= staking_threshold);
        new_block(); //run once per block.
        
        // claim reward if available.
        if (staker[msg.sender].amount > 0)
        {
            if (Timestamp >= staker[msg.sender].time + round_interval)
            { 
                claim(); 
            }
            TotalStakingWeight = TotalStakingWeight.sub((Timestamp.sub(staker[msg.sender].time)).mul(staker[msg.sender].amount)); // remove from Weight        
        }

        TotalStakingAmount = TotalStakingAmount.add(msg.value);
        staker[msg.sender].time = Timestamp;
        staker[msg.sender].amount = staker[msg.sender].amount.add(msg.value);
       
        emit StartStaking(
            msg.sender,
            msg.value,
            staker[msg.sender].amount,
            staker[msg.sender].time
        );
    }

    function DEBUG_donation() public payable {
        emit DonationDeposited(msg.sender, msg.value);
    }

    function withdraw_stake() public only_staker
    {
        new_block(); //run once per block.
        require(Timestamp >= staker[msg.sender].time + round_interval); //reject withdrawal before complete round.

        uint _amount = staker[msg.sender].amount;
        // claim reward if available.
        claim(); 
        TotalStakingAmount = TotalStakingAmount.sub(_amount);
        TotalStakingWeight = TotalStakingWeight.sub((Timestamp.sub(staker[msg.sender].time)).mul(staker[msg.sender].amount)); // remove from Weight.
        
        staker[msg.sender].amount = 0;
        msg.sender.transfer(_amount);
        emit WithdrawStake(msg.sender, _amount);
    }

    //claim rewards
    function claim() public only_staker
    {
        if (CS_frozen) return; //Don't pay rewards when Cold Staking frozen.

        new_block(); //run once per block
        uint _StakingInterval = Timestamp.sub(staker[msg.sender].time);  //time interval of deposit.
        if (_StakingInterval >= round_interval)
        {
            uint _CompleteRoundsInterval = (_StakingInterval / round_interval).mul(round_interval); //only complete rounds.
            uint _StakerWeight = _CompleteRoundsInterval.mul(staker[msg.sender].amount); //Weight of completed rounds.
            uint _reward = StakingRewardPool.mul(_StakerWeight).div(TotalStakingWeight);  //StakingRewardPool * _StakerWeight/TotalStakingWeight

            StakingRewardPool = StakingRewardPool.sub(_reward);
            TotalStakingWeight = TotalStakingWeight.sub(_StakerWeight); // remove paid Weight.

            staker[msg.sender].time = staker[msg.sender].time.add(_CompleteRoundsInterval); // reset to paid time, staking continue without a loss of incomplete rounds.
	    
            msg.sender.transfer(_reward);
            emit Claim(msg.sender, _reward);
        }
    }

    //This function may be used for info only. This can show estimated user reward at current time.
    function stake_reward(address _addr) public constant returns (uint)
    {
        require(staker[_addr].amount > 0);
        require(!CS_frozen);

        uint _blocks = block.number - LastBlock;
        uint _seconds = now - Timestamp;
        if (_seconds > _blocks * 25) //if time goes far in the future, then use new time as 25 second * blocks.
        {
            _seconds = _blocks * 25;
        }
        uint _Timestamp = Timestamp + _seconds;
        uint _TotalStakingWeight = TotalStakingWeight + _seconds.mul(TotalStakingAmount);
        uint _StakingInterval = _Timestamp.sub(staker[_addr].time); //time interval of deposit.
	
        //uint _StakerWeight = _StakingInterval.mul(staker[_addr].amount); //Staker weight.
        uint _CompleteRoundsInterval = (_StakingInterval / round_interval).mul(round_interval); //only complete rounds.
        uint _StakerWeight = _CompleteRoundsInterval.mul(staker[_addr].amount); //Weight of completed rounds.
        uint _StakingRewardPool = address(this).balance.sub(TotalStakingAmount);
        return _StakingRewardPool.mul(_StakerWeight).div(_TotalStakingWeight);    //StakingRewardPool * _StakerWeight/TotalStakingWeight
    }

    modifier only_staker
    {
        require(staker[msg.sender].amount > 0);
        _;
    }

    modifier staking_available
    {
        require(now >= DateStartStaking && !CS_frozen);
        _;
    }

    modifier only_treasurer
    {
        require(msg.sender == Treasury);
        _;
    }

    //return deposit to inactive staker.
    function report_abuse(address _addr) public only_staker
    {
        require(staker[_addr].amount > 0);
        new_block(); //run once per block.
        require(Timestamp > staker[_addr].time.add(max_delay));
        
        uint _amount = staker[_addr].amount;
        
        TotalStakingAmount = TotalStakingAmount.sub(_amount);
        TotalStakingWeight = TotalStakingWeight.sub((Timestamp.sub(staker[_addr].time)).mul(_amount)); // remove from Weight.

        staker[_addr].amount = 0;
        _addr.transfer(_amount);
    }
}
        

Contract ABI

[{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"CS_frozen","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"TotalStakingWeight","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"StakingRewardPool","inputs":[],"constant":true},{"type":"function","stateMutability":"payable","payable":true,"outputs":[],"name":"start_staking","inputs":[],"constant":false},{"type":"function","stateMutability":"payable","payable":true,"outputs":[],"name":"DEBUG_donation","inputs":[],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"claim","inputs":[],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"Treasury","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"staking_threshold","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"round_interval","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"amount"},{"type":"uint256","name":"time"}],"name":"staker","inputs":[{"type":"address","name":""}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"DateStartStaking","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"report_abuse","inputs":[{"type":"address","name":"_addr"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"new_block","inputs":[],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"TotalStakingAmount","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"LastBlock","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"freeze","inputs":[{"type":"bool","name":"_f"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"stake_reward","inputs":[{"type":"address","name":"_addr"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"withdraw_rewards","inputs":[],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"withdraw_stake","inputs":[],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"max_delay","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"Timestamp","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"clear_treasurer","inputs":[],"constant":false},{"type":"fallback","stateMutability":"payable","payable":true},{"type":"event","name":"StartStaking","inputs":[{"type":"address","name":"addr","indexed":false},{"type":"uint256","name":"value","indexed":false},{"type":"uint256","name":"amount","indexed":false},{"type":"uint256","name":"time","indexed":false}],"anonymous":false},{"type":"event","name":"WithdrawStake","inputs":[{"type":"address","name":"staker","indexed":false},{"type":"uint256","name":"amount","indexed":false}],"anonymous":false},{"type":"event","name":"Claim","inputs":[{"type":"address","name":"staker","indexed":false},{"type":"uint256","name":"reward","indexed":false}],"anonymous":false},{"type":"event","name":"DonationDeposited","inputs":[{"type":"address","name":"_address","indexed":false},{"type":"uint256","name":"value","indexed":false}],"anonymous":false}]
            

Deployed ByteCode

0x6080604052600436106101275763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166304eba77a811461013157806314657ef01461015a5780631e37de4c146101815780631f288efb146101275780633a339a4c146101965780634e71d92d1461019e578063563df32f146101b35780635c854aa9146101e45780637157c113146101f957806382e4eda41461020e578063a070ecb614610248578063aaee69d91461025d578063b01ddc191461027e578063b3fefcf514610293578063b43e92fa146102a8578063b5bf15e5146102bd578063bf92b4ef146102d7578063c20a5997146102f8578063cd9488551461030d578063e2d4056814610322578063e6369e4114610337578063ff5987a31461034c575b61012f610361565b005b34801561013d57600080fd5b506101466104c6565b604080519115158252519081900360200190f35b34801561016657600080fd5b5061016f6104cf565b60408051918252519081900360200190f35b34801561018d57600080fd5b5061016f6104d5565b61012f6104db565b3480156101aa57600080fd5b5061012f610517565b3480156101bf57600080fd5b506101c86106c5565b60408051600160a060020a039092168252519081900360200190f35b3480156101f057600080fd5b5061016f6106d4565b34801561020557600080fd5b5061016f6106da565b34801561021a57600080fd5b5061022f600160a060020a03600435166106e0565b6040805192835260208301919091528051918290030190f35b34801561025457600080fd5b5061016f6106f9565b34801561026957600080fd5b5061012f600160a060020a03600435166106ff565b34801561028a57600080fd5b5061012f610836565b34801561029f57600080fd5b5061016f6108ba565b3480156102b457600080fd5b5061016f6108c0565b3480156102c957600080fd5b5061012f60043515156108c6565b3480156102e357600080fd5b5061016f600160a060020a03600435166108f0565b34801561030457600080fd5b5061012f610a22565b34801561031957600080fd5b5061012f610a9a565b34801561032e57600080fd5b5061016f610bc1565b34801561034357600080fd5b5061016f610bc7565b34801561035857600080fd5b5061012f610bcd565b600a544210158015610376575060055460ff16155b151561038157600080fd5b60065434101561038d57fe5b610395610836565b336000908152600b6020526040812054111561042457600854336000908152600b6020526040902060019081015490549101116103d4576103d4610517565b336000908152600b60205260409020805460019182015491546104209261041192916104059163ffffffff610c2316565b9063ffffffff610c3816565b6002549063ffffffff610c2316565b6002555b600354610437903463ffffffff610c7116565b60035560018054336000908152600b602052604090209182015554610462903463ffffffff610c7116565b336000818152600b6020908152604091829020848155600101548251938452349184019190915282820193909352606082019290925290517f2e8514bf9ee8365a5f08ec338e0c2c303db06a14eb982783ef9a2b9aacec8dc69181900360800190a1565b60055460ff1681565b60025481565b60045481565b6040805133815234602082015281517fe669e18d16cf72448be9ee29e977628bedcffa0e0c0cde5e8448849fb9426857929181900390910190a1565b336000908152600b6020526040812054819081908190811061053857600080fd5b60055460ff1615610548576106bf565b610550610836565b336000908152600b6020526040902060019081015490546105769163ffffffff610c2316565b60085490945084106106bf576105a26008546008548681151561059557fe5b049063ffffffff610c3816565b336000908152600b60205260409020549093506105c690849063ffffffff610c3816565b91506105ef6002546105e384600454610c3890919063ffffffff16565b9063ffffffff610c8316565b600454909150610605908263ffffffff610c2316565b60045560025461061b908363ffffffff610c2316565b600255336000908152600b6020526040902060010154610641908463ffffffff610c7116565b336000818152600b6020526040808220600101939093559151909183156108fc02918491818181858888f19350505050158015610682573d6000803e3d6000fd5b50604080513381526020810183905281517f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d4929181900390910190a15b50505050565b600754600160a060020a031681565b60065481565b60085481565b600b602052600090815260409020805460019091015482565b600a5481565b336000908152600b6020526040812054811061071a57600080fd5b600160a060020a0382166000908152600b60205260408120541161073d57600080fd5b610745610836565b600954600160a060020a0383166000908152600b60205260409020600101546107739163ffffffff610c7116565b6001541161078057600080fd5b50600160a060020a0381166000908152600b60205260409020546003546107ad908263ffffffff610c2316565b600355600160a060020a0382166000908152600b6020526040902060019081015490546107ea91610411918491610405919063ffffffff610c2316565b600255600160a060020a0382166000818152600b60205260408082208290555183156108fc0291849190818181858888f19350505050158015610831573d6000803e3d6000fd5b505050565b6000806000805443111561083157600080544390915560035490935061086690303190340163ffffffff610c2316565b60045560015442111561083157824303915060015442039050816019028111156108905750601981025b6003546108a490829063ffffffff610c3816565b6002805490910190556001805482019055505050565b60035481565b60005481565b600754600160a060020a031633146108dd57600080fd5b6005805460ff1916911515919091179055565b600160a060020a0381166000908152600b602052604081205481908190819081908190819081908190811061092457600080fd5b60055460ff161561093457600080fd5b600054430397506001544203965087601902871115610954578760190296505b8660015401955061097060035488610c3890919063ffffffff16565b600254600160a060020a038c166000908152600b6020526040902060010154910195506109a490879063ffffffff610c2316565b93506109b96008546008548681151561059557fe5b600160a060020a038b166000908152600b60205260409020549093506109e690849063ffffffff610c3816565b6003549092506109fe9030319063ffffffff610c2316565b9050610a14856105e3838563ffffffff610c3816565b9a9950505050505050505050565b600754600160a060020a03163314610a3957600080fd5b60055460ff1615610a9857600354610a599030319063ffffffff610c2316565b6004819055600754604051600160a060020a039091169180156108fc02916000818181858888f19350505050158015610a96573d6000803e3d6000fd5b505b565b336000908152600b60205260408120548110610ab557600080fd5b610abd610836565b600854336000908152600b60205260409020600190810154905491011115610ae457600080fd5b50336000908152600b6020526040902054610afd610517565b600354610b10908263ffffffff610c2316565b600355336000908152600b6020526040902080546001918201549154610b449261041192916104059163ffffffff610c2316565b600255336000818152600b60205260408082208290555183156108fc0291849190818181858888f19350505050158015610b82573d6000803e3d6000fd5b50604080513381526020810183905281517f141ef67c4a6d3ec2adfb2f66d33c2b11de5b4f34344757554d430570b18a92ec929181900390910190a150565b60095481565b60015481565b600754600160a060020a03163314610be457600080fd5b621b774043118015610bf9575060055460ff16155b1515610c0457600080fd5b6007805473ffffffffffffffffffffffffffffffffffffffff19169055565b600082821115610c3257600080fd5b50900390565b600080831515610c4b5760009150610c6a565b50828202828482811515610c5b57fe5b0414610c6657600080fd5b8091505b5092915050565b600082820183811015610c6657600080fd5b6000808284811515610c9157fe5b049493505050505600a165627a7a723058206aa121fb486bec70022c2971d0b10411b8ac1774e6646cb87c5162685d57da8f0029