Contract 0x8ae9641920dc18689fffac9b426546fce68df303

 
Txn Hash Method
Block
From
To
Value [Txn Fee]
0x97deaccbc734a19a934470d68fa9d7d9af2a533442838b354e213af38f9d5695Withdraw From Fa...411546212022-06-23 12:53:02161 days 9 hrs ago0x1cd4dad7e89f9d07ae95d8eb178b77b6e40e2adb IN  0x8ae9641920dc18689fffac9b426546fce68df3030 FTM0.013127651619
0x35a3db1f0492ee77c2eb009263eba1f832c5d2c773d56aa48f28245602586f65Claim Rain From ...411545472022-06-23 12:51:21161 days 9 hrs ago0x1cd4dad7e89f9d07ae95d8eb178b77b6e40e2adb IN  0x8ae9641920dc18689fffac9b426546fce68df3030 FTM0.000156705564
0x34cda760ee6672a765b5f0b74d7ad0bc6551225107b044619b219f595c91bfdaClaim Rain From ...411545182022-06-23 12:50:51161 days 9 hrs ago0x1cd4dad7e89f9d07ae95d8eb178b77b6e40e2adb IN  0x8ae9641920dc18689fffac9b426546fce68df3030 FTM0.002965862113
0x1e1808664284f3789f216aeb216ae907979bf3da94945e24eb8336dc9c7d70ebWithdraw From Fa...402247402022-06-10 17:43:48174 days 4 hrs ago0x009a1d99cc92212200569afea8964cf9eb1ee013 IN  0x8ae9641920dc18689fffac9b426546fce68df3030 FTM0.003410741114
0xfd8660d130dafe34174d895efd1a500e71b968aeb585aa3806615330b33fbb93Claim Rain From ...402232522022-06-10 17:14:35174 days 5 hrs ago0x009a1d99cc92212200569afea8964cf9eb1ee013 IN  0x8ae9641920dc18689fffac9b426546fce68df3030 FTM0.00597521429
0x5c81c3b978b065efefb5f945f8558a9972c75f84a7f69a8a29dcc8ac5420d8ebWithdraw From Fa...399623282022-06-07 3:46:02177 days 18 hrs ago0xa67d2c03c3cfe6177a60caed0a4cfda7c7a563e0 IN  0x8ae9641920dc18689fffac9b426546fce68df3030 FTM0.001680611326
0x02a1aff35570db9193664ab56b51e552767781389d3c2e0361b8fdc7f44b2b3cWithdraw From Fa...398922562022-06-06 5:11:51178 days 17 hrs ago0xde03bc956fe3a4679bf15d5cecb08506ea889eb2 IN  0x8ae9641920dc18689fffac9b426546fce68df3030 FTM0.001674149515
0xd7126a7a0166eca52d18752b484448de0f19a8c15391edfaf9a470f776a89160Withdraw From Fa...398920962022-06-06 5:09:07178 days 17 hrs ago0x8514e0a3cb13da6c4c56122a0782adac91fcdc54 IN  0x8ae9641920dc18689fffac9b426546fce68df3030 FTM0.002078273107
0xc428976122a772b0f1f23fdce69403abd26ee77cfc19b9e741a59739515aa719Withdraw From Fa...398892062022-06-06 4:10:39178 days 18 hrs ago0x07d94adf04c3a4eb8632408f416de546f59c147d IN  0x8ae9641920dc18689fffac9b426546fce68df3030 FTM0.002120817074
0xe11c70e07242dba465c318baeda95949bbc3f373303194e5b8a5c65c8c7caa90Withdraw From Fa...398818212022-06-06 1:52:49178 days 20 hrs ago0x8f25818ff64be1abee91abca70c306b33b602062 IN  0x8ae9641920dc18689fffac9b426546fce68df3030 FTM0.002140147067
0x057ed1d49934bfb91ed5de570bbe1334a818a123fd330fc664ca43a998e8a4abWithdraw From Fa...398490722022-06-05 15:29:32179 days 7 hrs ago0x139f89702511940ae4589c394a3121385f48654e IN  0x8ae9641920dc18689fffac9b426546fce68df3030 FTM0.000621233096
0xfcc88cd902971ea6bac95e784d6ee72e4cddb6b3ace3beab8791a4af34659928Claim Rain From ...398471162022-06-05 14:53:30179 days 7 hrs ago0x7a0e7adb1b9a40a4b4656ad55102d46dfdd6c19d IN  0x8ae9641920dc18689fffac9b426546fce68df3030 FTM0.000390042765
0x55217757fca62a07bda377117c70c126c25bf3b636863bb2e049914d27269e45Withdraw From Fa...398470842022-06-05 14:52:57179 days 7 hrs ago0x7a0e7adb1b9a40a4b4656ad55102d46dfdd6c19d IN  0x8ae9641920dc18689fffac9b426546fce68df3030 FTM0.00089728507
0x81842a050286422230da25112450a0b28d361d08f6d20c5f0ee0d4d16d11bb53Withdraw From Fa...398456902022-06-05 14:23:22179 days 8 hrs ago0x3e590fbb993bf1e97f04fe615c64bfa37dd84999 IN  0x8ae9641920dc18689fffac9b426546fce68df3030 FTM0.000385885377
0xc91b46ef0d18db063ee3febd88fd2b7f509674d4e6b361ffb1de0b9e195d51ddClaim Rain From ...398456282022-06-05 14:22:07179 days 8 hrs ago0x3e590fbb993bf1e97f04fe615c64bfa37dd84999 IN  0x8ae9641920dc18689fffac9b426546fce68df3030 FTM0.000579669409
0xf9aa99b2d7deb530d90a1adaf635285adaf255fe557d10300abd2847e52babdeWithdraw From Fa...398450112022-06-05 14:10:24179 days 8 hrs ago0xa909be1ac709bc08bd8cd69604cee197360b3e33 IN  0x8ae9641920dc18689fffac9b426546fce68df3030 FTM0.001328057814
0x7ef611dc03853db2c97f8fdf89ccde59bbb01e5e147c656277dbb73edaba6cbfDeposit To Farm398351632022-06-05 10:52:08179 days 11 hrs ago0x8514e0a3cb13da6c4c56122a0782adac91fcdc54 IN  0x8ae9641920dc18689fffac9b426546fce68df3030 FTM0.000659044555
0x173580ec6a52371e2764a2631b77ff5b87db6729a157700151e1c1b1d1e6c77dWithdraw From Fa...398332662022-06-05 10:17:10179 days 12 hrs ago0xa909be1ac709bc08bd8cd69604cee197360b3e33 IN  0x8ae9641920dc18689fffac9b426546fce68df3030 FTM0.000583397919
0x44df571021cdb4e1cd9f1069d80d71bcd388dcdcc3edb4a0950130740f8e3bc3Withdraw From Fa...398313612022-06-05 9:41:25179 days 13 hrs ago0xdde659510144fd68b50e2a73e3dc671e4db65bad IN  0x8ae9641920dc18689fffac9b426546fce68df3030 FTM0.000620494813
0xab213c1879779da36cd9bd527484802237020d4f045a997501b9a308d178c031Claim Rain From ...398311812022-06-05 9:37:50179 days 13 hrs ago0xdde659510144fd68b50e2a73e3dc671e4db65bad IN  0x8ae9641920dc18689fffac9b426546fce68df3030 FTM0.004304127465
0x83cbb846713d54885936dba83eaf89f714041d79a592a57b24713f0a3cc8f644Deposit To Farm398231122022-06-05 7:05:07179 days 15 hrs ago0xa909be1ac709bc08bd8cd69604cee197360b3e33 IN  0x8ae9641920dc18689fffac9b426546fce68df3030 FTM0.000640649444
0xcc655403e3677bd309d71eacdb62ec22d3ddea49690b5f523e4858cb80830437Deposit To Farm398158032022-06-05 4:49:27179 days 17 hrs ago0xa67d2c03c3cfe6177a60caed0a4cfda7c7a563e0 IN  0x8ae9641920dc18689fffac9b426546fce68df3030 FTM0.00094243757
0xb5101bba77ad0a54be1bada8a92ba96460bd1f7ca777d8f21a645b1ff0fd79f1Withdraw From Fa...398145002022-06-05 4:23:35179 days 18 hrs ago0x8f25818ff64be1abee91abca70c306b33b602062 IN  0x8ae9641920dc18689fffac9b426546fce68df3030 FTM0.003132484604
0xe02e38dac794fb128fab18ff7538fed99e58d22ae5259e49f941121b8bb38148Claim Rain From ...398136622022-06-05 4:07:43179 days 18 hrs ago0x8f25818ff64be1abee91abca70c306b33b602062 IN  0x8ae9641920dc18689fffac9b426546fce68df3030 FTM0.005892305061
0xa01ee18999403d70bc6afee872337d681d9f78f44ff779579e438b2a6abebad7Claim Rain From ...397843762022-06-04 18:38:40180 days 4 hrs ago0x7a0e7adb1b9a40a4b4656ad55102d46dfdd6c19d IN  0x8ae9641920dc18689fffac9b426546fce68df3030 FTM0.000746320316
[ Download CSV Export 
Latest 1 internal transaction
Parent Txn Hash Block From To Value
0x9d38c8e0471f2947208fa7f33c861c166591f385095da35980d17a159eca0c43351201542022-04-03 10:29:06242 days 12 hrs ago 0xc333a03e8040cad31993e02615fd1b3f88447d95  Contract Creation0 FTM
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
SingleAssetRainFarm

Compiler Version
v0.8.12+commit.f00d7308

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 4 : SingleAssetRainFarm.sol
pragma solidity ^0.8.12;

import "./RainFarmStorage.sol";
import "./RainFarmInterface.sol";
import "../../Tools/Helpers/TransferHelper.sol";

interface IERC20ForRainFarmer {
    function decimals() external view returns (uint);
    function balanceOf(address account) external view returns (uint);
}

contract SingleAssetRainFarm is SingleAssetRainFarmStorage, RainFarmInterface {

    // ******* constants *******

    bytes32 public constant SingleAssetRainFarmContractHash = keccak256("SingleAssetRainFarm");

    // V1.0
    uint public constant version = 100;

    /// @notice The initial index for a farm
    uint public constant farmInitialIndex = 1e36;

    uint public constant baseUnit = 1e18;

    uint public immutable farmTokenUnit;
    uint public immutable rainTokenUnit;

    uint public immutable minDistributionPeriod;

    bool private _nonreentranceLock = false;


    // ******* events *******

    /**
      * @notice Emitted when pendingAdmin is changed
      */
    event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin);

    /**
      * @notice Emitted when pendingAdmin is accepted, which means admin is updated
      */
    event NewAdmin(address oldAdmin, address newAdmin);

    event FarmAdded(address indexed farmToken);

    event AllocatedRainToFarmer(address indexed farmer, uint deltaFarmerRainfall, uint farmIndex);

    event DistributionPeriodSet(uint oldDistributionPeriod, uint newDistributionPeriod);

    event StartTimeSet(uint oldStartTime, uint startTime);

    event BudgetSet(uint oldBudget, uint newBudget);

    event FarmSpeedSet(uint oldFarmSpeed, uint newFarmSpeed);


    // ******* constructor *******

    constructor(
        address _admin,
        uint _minDistributionPeriod,
        address _farmToken,
        address _rainToken
    ) SingleAssetRainFarmStorage(_rainToken, _farmToken) {
        contractNameHash = SingleAssetRainFarmContractHash;
        admin = _admin;

        uint farmTokenDecimals = IERC20ForRainFarmer(_farmToken).decimals();
        uint rainTokenDecimals = IERC20ForRainFarmer(_rainToken).decimals();

        farmTokenUnit = 10**farmTokenDecimals;
        rainTokenUnit = 10**rainTokenDecimals;

        // farmSpeed = 0;
        uint currentTime = getCurrentTime();
        FarmCurrentState storage farmCurrentState = farmCurrentState;
        farmCurrentState.index = farmInitialIndex; // state
        farmCurrentState.timestamp = currentTime; // state
        // farmCurrentState.totalSupply = 0;

        minDistributionPeriod = _minDistributionPeriod;

        emit FarmAdded(_farmToken);
    }

    modifier nonreentrance {
        require(!_nonreentranceLock, "Reentrance not allowed");
        _nonreentranceLock = true;
        _;
        _nonreentranceLock = false;
    }


    // ******* getters *******

    /**
     * @return the block timestamp.
     */
    function getCurrentTime() public view returns (uint) {
        return block.timestamp;
    }

    /**
     * @return the (derived) timestamp in which the distribution ends
     */
    function endTime() public view returns (uint) {
        return startTime + distributionPeriod;
    }

    /**
     * @return the address of the farm token
     */
    function getFarmToken() public view returns (address) {
        return farmToken;
    }

    /**
     * @return the address of the rain token
     */
    function getRainToken() public view returns (address) {
        return rainToken;
    }

    function getFarmSpeed() external view returns (uint) {
        return farmSpeed;
    }

    /**
     * @return the amount of rainToken committed since 'startTimeStamp'
     */
    function budgetCommitmentUntilNow() public view returns (uint) {
        uint currentTime = getCurrentTime();
        if (currentTime >= endTime()) {
            return budget;
        }

        uint _startTime = startTime;
        if (currentTime <= _startTime || budget == 0 || distributionPeriod == 0) {
            return 0;
        }

        uint deltaSeconds = currentTime - _startTime;
        uint rainCommitted = (deltaSeconds * farmSpeed);

        return rainCommitted;
    }

    /**
     * @return the amount of rain tokens that are not yet committed to distribution in the current distribution period.
     * DEV_NOTE : If state is 'fresh' this should return the value of 'budget'
     */
    function getRemainingBudget() public view returns (uint) {
        uint rainCommitment = budgetCommitmentUntilNow();

        if (budget <= rainCommitment) {
            return 0;
        } else {
            return budget - rainCommitment;
        }
    }

    /**
     * @return total rain being emitted to the farm per second
     */
    function getTotalRainSpeed(uint totalRain, uint totalSeconds) public pure returns (uint) {
        if (totalRain == 0 || totalSeconds == 0) {
            return 0;
        }
        /// @notice if rainToken decimals are small there might be a significant rounding error here
        return totalRain / totalSeconds;
    }

    // ******* admin ownership control *******

    /**
     * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.
     * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.
     * @param newPendingAdmin New pending admin.
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function _setPendingAdmin(address newPendingAdmin) override external nonreentrance returns (uint) {
        // Check caller = admin
        require(isAdmin(), "!admin");

        // Save current value, if any, for inclusion in log
        address oldPendingAdmin = pendingAdmin;

        // Store pendingAdmin with value newPendingAdmin
        pendingAdmin = newPendingAdmin;

        // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin)
        emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin);

        return 0;
    }

    /**
      * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin
      * @dev Admin function for pending admin to accept role and update admin
      * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
      */
    function _acceptAdmin() override external nonreentrance returns (uint) {
        // Check caller is pendingAdmin and pendingAdmin ≠ address(0)
        require(msg.sender == pendingAdmin && msg.sender != address(0), "Not the EXISTING pending admin");

        // Save current values for inclusion in log
        address oldAdmin = admin;
        address oldPendingAdmin = pendingAdmin;

        // Store admin with value pendingAdmin
        admin = pendingAdmin;

        // Clear the pending value
        pendingAdmin = address(0);

        emit NewAdmin(oldAdmin, admin);
        emit NewPendingAdmin(oldPendingAdmin, pendingAdmin);

        return 0;
    }

    // ******* admin setters and farm control *******

    /**
     * Allows admin to add rain to the program while keeping the current end time.
     * Any pulled rain will be used to increase the rainSpeed for the remaining time.
     */
    function pullNewRain(address pullRainFromAddress, uint pullRainAmount) override external nonreentrance {
        require(isAdmin(), "!admin");
        updateFarmIndexInternal();
        pullNewRainInternal(pullRainFromAddress, pullRainAmount);
    }

    /**
     * @notice The common function to call for continuing the emission program as is
     * @notice sets 'startTime' to now
     * @notice doesn't let changing 'distributionPeriod'
     * @notice only allows for pulling new rain
     * @notice requires getting the farm's index up to date -- happens in setRainfallConfigurationInternal()
     */
    function extendWithExistingConfiguration(address pullRainFromAddress, uint pullRainAmount) override external nonreentrance {
        require(isAdmin(), "!admin");
        updateFarmIndexInternal();

        uint currentTime = getCurrentTime();
        require(currentTime < endTime(), "cannot extend a finished program");

        setRainfallConfigurationInternal(0, 0);

        pullNewRainInternal(pullRainFromAddress, pullRainAmount);
    }

    /**
     * @notice Setter for rainfall configuration - startTime and distributionPeriod
     * @notice Not allowed while an active distribution is taking place
     * @notice requires getting the farm's index up to date -- happens in setRainfallConfigurationInternal()
     * @param _newStartTime the new starting time to be set
     * @param newDistributionPeriod the new distribution period to be set
     */
    function restartWithNewConfiguration(uint _newStartTime, uint newDistributionPeriod, address pullRainFromAddress, uint pullRainAmount) override external nonreentrance {
        require(isAdmin(), "!admin");
        updateFarmIndexInternal();

        uint currentTime = getCurrentTime();
        require(currentTime > endTime(), "not during active distribution");

        setRainfallConfigurationInternal(_newStartTime, newDistributionPeriod);

        pullNewRainInternal(pullRainFromAddress, pullRainAmount);
    }

    // ******* user interactions - deposit, withdraw, claim rain *******

    /**
     * Deposits to farm. nothing beyond that.
     */
    function depositToFarm(uint amount) override external nonreentrance {
        address farmer = msg.sender;
        updateFarmIndexInternal();
        updateFarmerIndexInternal(farmer);
        depositToFarmInternal(farmer, farmer, amount);
    }

    /**
     * Sender will deposit farm tokens on behalf of the farmer.
     */
    function depositToFarmOnBehalf(address farmer, uint amount) override external nonreentrance {
        updateFarmIndexInternal();
        updateFarmerIndexInternal(farmer);
        depositToFarmInternal(farmer, msg.sender, amount);
    }

    /**
     * Withdraws all of the farmer's (msg.sender) supply.
     * In addition, claims all rainfall.
     */
    function withdrawAllFromFarm() override external nonreentrance {
        address farmer = msg.sender;
        updateFarmIndexInternal();
        updateFarmerIndexInternal(farmer);
        withdrawFromFarmInternal(farmer, farmersCurrentSupply[farmer]);
    }

    /**
     * Withdraws a specific amount of the farmer's (msg.sender) supply.
     * In addition, claims all rainfall.
     */
    function withdrawFromFarm(uint amount) override external nonreentrance {
        address farmer = msg.sender;
        updateFarmIndexInternal();
        updateFarmerIndexInternal(farmer);
        withdrawFromFarmInternal(farmer, amount);
    }

    /**
     * @notice Claim all the rain accrued by farmer in the farm
     * @param farmer The address to claim rain for
     */
    function claimRainFromFarm(address farmer) override external nonreentrance {
        updateFarmIndexInternal();
        updateFarmerIndexInternal(farmer);
        address[] memory farmers = new address[](1);
        farmers[0] = farmer;
        return claimRainFromFarmToSomeFarmersInternal(farmers);
    }

    /**
     * @notice Claim all the rain accrued by farmers in the farm
     * @param farmers The addresses to claim rain for
     */
    function claimRainFromFarmToSomeFarmers(address[] calldata farmers) override external nonreentrance {
        updateFarmIndexInternal();
        for (uint j = 0; j < farmers.length; j++) {
            address farmer = farmers[j];
            updateFarmerIndexInternal(farmer);
        }
        claimRainFromFarmToSomeFarmersInternal(farmers);
    }

    // ******* emergency *******

    function emergencyWithdrawFromFarm() override external nonreentrance {
        address farmer = msg.sender;
        emergencyWithdrawFromFarmInternal(farmer);
        farmersRainfall[farmer] = 0; // state
    }

    // ******* rain token accounting and speeds (internal logic) *******

    /**
     * Allows to update the farm's stored state from outside.
     */
    function updateFarmIndex() override external nonreentrance {
        updateFarmIndexInternal();
    }

    /**
     * Allows to update the farmer's stored state from outside.
     */
    function updateFarmerIndex(address farmer) override external nonreentrance {
        updateFarmIndexInternal();
        updateFarmerIndexInternal(farmer);
    }

    // ******* internal setters *******

    /**
     * @notice Handles program configuration.
     * @param _newStartTime State time for the program, 0 means 'start now'.
     * @param _newDistributionPeriod Distribution period for the program, 0 means 'keep current'.
     */
    function setRainfallConfigurationInternal(uint _newStartTime, uint _newDistributionPeriod) internal {
        setRemainingBudget();

        setStartTime(_newStartTime);

        /// @notice 'newDistributionPeriod' = 0 implies distribution period stays as is
        if (_newDistributionPeriod != 0) {
            setDistributionPeriodInternal(_newDistributionPeriod);
        }
    }

    /*
     * Sets the budget stored value to the program's remaining budget plus the 'budgetToAdd'.
     * @param budgetToAdd Amount of rain tokens to add to the remaining budget.
     */
    function increaseBudget(uint budgetToAdd) internal {
        uint currentBudget = getRemainingBudget();
        setBudgetInternal(currentBudget + budgetToAdd);
    }

    /*
     * Sets the budget stored value ot the program's remaining budget.
     */
    function setRemainingBudget() internal {
        uint remainingBudget = getRemainingBudget();
        setBudgetInternal(remainingBudget);
    }

    // ******* single param setters *******

    /**
     * @notice Directly sets the program start time.
     * @param _newStartTime The wanted start time, must be in the future.
     *                      a 0 value means immediate start.
     */
    function setStartTime(uint _newStartTime) internal {
        uint currentTime = getCurrentTime();
        uint newStartTime = _newStartTime == 0 ? currentTime : _newStartTime;
        require(newStartTime >= currentTime, "cannot start in the past");
        uint oldStartTime = startTime;
        startTime = newStartTime;
        emit StartTimeSet(oldStartTime, startTime);
    }

    /**
     * @notice Directly sets the 'budget'
     */
    function setBudgetInternal(uint newBudget) internal {
        uint oldBudget = budget;
        budget = newBudget;
        emit BudgetSet(oldBudget, newBudget);
    }

    /**
     * @notice Directly sets the 'distributionPeriod'
     */
    function setDistributionPeriodInternal(uint newDistributionPeriod) internal {
        require(newDistributionPeriod > minDistributionPeriod, "Distribution period too short");
        uint oldDistributionPeriod = distributionPeriod;
        distributionPeriod = newDistributionPeriod;
        emit DistributionPeriodSet(oldDistributionPeriod, newDistributionPeriod);
    }

    /**
     * @notice Directly sets the 'farmSpeed'
     */
    function setFarmSpeed(uint newFarmSpeed) internal {
        uint oldFarmSpeed = farmSpeed;
        farmSpeed = newFarmSpeed;
        emit FarmSpeedSet(oldFarmSpeed, newFarmSpeed);
    }

    // ******* rain pulling *******

    /**
     * @notice pullNewRain from a general address using transferFrom
     * @notice Requires re-calculating the farm's speed
     * @notice admin can always add budget but can't change the rainfall configuration, including startTime
     * @notice requires getting the farm's index up to date -- happens in calculateFarmSpeed()
     * @notice may be called by anyone
     * @param pullRainFromAddress an address from which rain tokens will be pulled. Must be approved previously.
     * @param pullRainAmount the amount of rain tokens to pull from 'pullbudgetFrom'
     */
    function pullNewRainInternal(address pullRainFromAddress, uint pullRainAmount) internal {
        uint rainGained = 0;

        if (pullRainAmount > 0) {
            rainGained += pullRainTokens(pullRainFromAddress, pullRainAmount);
        }

        increaseBudget(rainGained);

        calculateFarmSpeed();
    }

    // ******* rain token accounting and speeds (internal logic) *******

    /**
     * @notice Sets the rain speeds using the current budget and the time left to distribute it
     * @notice Any change to the budget should occur before calling this function
     */
    function calculateFarmSpeed() internal {
        uint currentTime = getCurrentTime();
        uint _endTime = endTime();
        uint _startTime = startTime;
       
        uint finalTime = _endTime;
        uint initialTime = currentTime < _startTime ? _startTime : currentTime;

        uint distributionTimeframeLeft = finalTime > initialTime ? finalTime - initialTime : 0;
        uint totalRainSpeed = getTotalRainSpeed(budget, distributionTimeframeLeft);

        setFarmSpeed(totalRainSpeed);
    }

    /**
     * @notice Accrue rain token to a given farm by updating its index
     * @dev index is a cumulative sum of rain token gained per farm token from the beginning of time.
     */
    function updateFarmIndexInternal() internal {
        FarmCurrentState storage farmCurrnetState = farmCurrentState;
        uint _farmSpeed = farmSpeed;

        // Note : This part needs to know the actual 'program active run time' in seconds since the last 'farm index' calculation
        //         (not counting any time after the program end)
        uint farmTimestamp = farmCurrnetState.timestamp;
        uint currentTime = getCurrentTime();
        uint _endTime = endTime();
        uint _startTime = startTime;
        uint finalTime = currentTime > _endTime ? _endTime : currentTime; // min(current,end)
        uint initialTime = _startTime > farmTimestamp ? _startTime : farmTimestamp; // max(start,farm)
        bool isDeltaSecondsZero = _startTime > currentTime || initialTime > finalTime;
        uint deltaSeconds = isDeltaSecondsZero ? 0 : finalTime - initialTime;

        if (deltaSeconds > 0 && _farmSpeed > 0) {
            uint _totalSupply = totalSupply;
            uint rainfall = deltaSeconds * _farmSpeed;
            uint ratio = _totalSupply > 0 ? (rainfall * farmInitialIndex) / _totalSupply : 0;
            farmCurrnetState.index += ratio; // state
        }
        
        if (farmTimestamp < currentTime) {
            farmCurrnetState.timestamp = currentTime; // state
        }
    }

    function updateFarmSupplyInternal(uint supplyAddition, uint supplyReduction) internal {
        if (supplyAddition > 0) {
            totalSupply += supplyAddition; // state
        } else if (supplyReduction > 0) {
            require(totalSupply >= supplyReduction, "more than farm balance");
            totalSupply -= supplyReduction; // state
        }
    }

    /**
     * @notice Calculate rainfall to a specific farmer in a given farm and possibly transfer it to them
     * @param farmer The address of the farmer
     */
    function updateFarmerIndexInternal(address farmer) internal {
        FarmCurrentState memory farmCurrentState = farmCurrentState;
        uint farmIndex = farmCurrentState.index;
        uint farmerIndex = farmersCurrentIndex[farmer];
        uint deltaFarmerRainfall;

        require(farmIndex >= farmerIndex, "farmer can't be more advanced than farm");

        if (farmerIndex > 0) {
            uint deltaIndex = farmIndex - farmerIndex;
            uint farmerTokens = farmersCurrentSupply[farmer];
            if (deltaIndex > 0) {
                // Calculate new rain accrued: farmerTokens * accruedPerToken
                deltaFarmerRainfall = (farmerTokens * deltaIndex) / farmInitialIndex;
                uint totalFarmerRainfall = farmersRainfall[farmer] + deltaFarmerRainfall;
                farmersRainfall[farmer] = totalFarmerRainfall; // state
            }
        }

        farmersCurrentIndex[farmer] = farmIndex; // state

        emit AllocatedRainToFarmer(farmer, deltaFarmerRainfall, farmIndex);
    }

    /**
     * @notice Properly and safely adds/reduces the amount to both the farmer's and the farm's supply
     * @param farmer The farmer
     * @param supplyAddition Amount to add
     * @param supplyReduction Amount to reduce
     */
    function updateFarmerSupplyInternal(address farmer, uint supplyAddition, uint supplyReduction) internal {
        // Update farmer's supply if supplyAddition > 0 or supplyReduction > 0
        if (supplyAddition > 0) {
            farmersCurrentSupply[farmer] += supplyAddition; // state
        } else if (supplyReduction > 0) {
            /// @notice important - must fail if farmerCurrentState.supply < supplyReduction
            require(farmersCurrentSupply[farmer] >= supplyReduction, "more than farmer balance");
            farmersCurrentSupply[farmer] -= supplyReduction; // state
        }
        updateFarmSupplyInternal(supplyAddition, supplyReduction);
    }

    /**
     * @notice Zeros farmer's index and supply.
     */
    function emergencyUpdateFarmerIndexInternal(address farmer) internal {
        farmersCurrentIndex[farmer] = 0; // state
        farmersCurrentSupply[farmer] = 0; // state
    }

    // ******* user interactions - deposit, withdraw, claim rain *******

    /**
     * @notice Handles all deposit logic.
     * Will not allow to deposit when there is neither active program nor a planned one.
     * @param farmer The account that will get the farm tokens added to their supply.
     * @param payer The account that will have the farm tokens pulled from.
     * @param amount The farm tokens to pull.
     */
    function depositToFarmInternal(address farmer, address payer, uint amount) internal {
        uint currentTime = getCurrentTime();
        require(currentTime < endTime(), "too late");

        amount = pullFarmTokens(payer, amount);
        
        updateFarmerSupplyInternal(farmer, amount, 0);
    }

    /**
     * @notice withdraw always claims from farm, to only withdraw set amount=0
     * @param farmer The withdrawing farmer.
     * @param amount The withdrawal amount
     */
    function withdrawFromFarmInternal(address farmer, uint amount) internal {
        claimRainFromFarmInternal(farmer);
        if (amount > 0) {
            updateFarmerSupplyInternal(farmer, 0, amount);
            sendFarmTokens(farmer, amount);
        }
    }

    /*
     * @notice Claims the rainfall for all given farmers.
     * @param farmers The farmers to claim rainfall for.
     */
    function claimRainFromFarmToSomeFarmersInternal(address[] memory farmers) internal {
        for (uint j = 0; j < farmers.length; j++) {
            address farmer = farmers[j];
            farmersRainfall[farmer] = transferRainInternalSafe(farmer, farmersRainfall[farmer]); // state
        }
    }

    /**
     * @notice Safe-Transfer to the farmer's the entire rainfall the address deserves
     *         and updates the remaining rainfall.
     * @param farmer The farmer to claim rainfall for.
     */
    function claimRainFromFarmInternal(address farmer) internal {
        farmersRainfall[farmer] = transferRainInternalSafe(farmer, farmersRainfall[farmer]); // state
    }

    // ******* Farm&Rain Tokens interactions *******

    /**
     * @notice Safe transfer farm token from this contract.
     * @param payer The paying account.
     * @param amount The amount to send.
     */
    function pullFarmTokens(address payer, uint amount) internal returns (uint farmTokensGain) {
        address _farmToken = farmToken;

        uint balanceBefore = IERC20ForRainFarmer(_farmToken).balanceOf(address(this));
        TransferHelper.safeTransferFrom(_farmToken, payer, address(this), amount);
        uint balanceAfter = IERC20ForRainFarmer(_farmToken).balanceOf(address(this));

        farmTokensGain = balanceAfter - balanceBefore;
        require(farmTokensGain == amount, "must receive exact amount");
    }

    /**
     * A simple 'transferFrom' from the 'pullRainFromAddress' to this contract
     * with sanity checks to ensure this contract got the exact amount.
     * @param pullRainFromAddress The address to pull the rain from.
     * @param pullRainAmount The amount of rain to pull.
     */
    function pullRainTokens(address pullRainFromAddress, uint pullRainAmount) internal returns (uint rainTokensGain) {
        address _rainToken = rainToken;

        uint balanceBefore = IERC20ForRainFarmer(_rainToken).balanceOf(address(this));
        TransferHelper.safeTransferFrom(rainToken, pullRainFromAddress, address(this), pullRainAmount);
        uint balanceAfter = IERC20ForRainFarmer(_rainToken).balanceOf(address(this));

        rainTokensGain = balanceAfter - balanceBefore;
        require(rainTokensGain == pullRainAmount, "must receive exact amount");
    }

    /**
     * @notice Safe transfer farm token from this contract.
     * @param farmer The receiving farmer.
     * @param amount The amount to send.
     */
    function sendFarmTokens(address farmer, uint amount) internal {
        TransferHelper.safeTransfer(farmToken, farmer, amount);
    }

    /**
     * @param farmer The address of the farmer to transfer rain tokens to
     * @param amount The amount of rain tokens to (possibly) transfer
     * @return The amount of rain tokens owed by the contract to the user after this function executes
     */
    function transferRainInternalSafe(address farmer, uint amount) internal returns (uint) {
        address _rainToken = rainToken;
        uint rainTokenRemaining = IERC20ForRainFarmer(_rainToken).balanceOf(address(this));
        if (amount > 0 && amount <= rainTokenRemaining) {
            TransferHelper.safeTransfer(_rainToken, farmer, amount);
            return 0;
        }
        return amount;
    }


    // ******* admin *******

    /**
     * @notice Checks caller is admin
     */
    function isAdmin() internal view returns (bool) {
        return msg.sender == admin;
    }


    // ******* emergency *******

    /**
     * Sends all suuply balance to farmer (skipping rain claiming).
     * Farmer position will be zeroed out after.
     */
    function emergencyWithdrawFromFarmInternal(address farmer) internal {
        uint amount = farmersCurrentSupply[farmer];
        require(amount > 0, "nothing to withdraw");
        emergencyUpdateFarmerIndexInternal(farmer);
        sendFarmTokens(farmer, amount);
    }
}

File 2 of 4 : RainFarmStorage.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.12;

contract RainFarmAdminStorage {
    /**
    * @notice Administrator for this contract
    */
    address public admin;

    /**
    * @notice Pending administrator for this contract
    */
    address public pendingAdmin;
}

contract SingleAssetRainFarmStorage is RainFarmAdminStorage {

    // ******* rain data *******

    uint256 public budget;

    /// @notice Represented in seconds
    uint256 public startTime;
    uint256 public distributionPeriod;

    address public immutable rainToken;

    // ******* specific farm data *******

    address public immutable farmToken; // rainSPIRIT

    uint public farmSpeed;

    struct FarmCurrentState {
        /// @notice The farm's last updated index
        uint index;

        /// @notice The timestamp the index was last updated at
        uint timestamp;
    }
    FarmCurrentState public farmCurrentState;

    /// @notice The totalSupply deposited in farm token
    uint public totalSupply;


    // ******* user data *******

    /// @notice farmer address => farmer current index
    mapping(address => uint) public farmersCurrentIndex;

    /// @notice farmer address => farmer current supply
    mapping(address => uint) public farmersCurrentSupply;

    /// @notice The amount of rain tokens accrued but not yet transferred to each farmer
    mapping(address => uint) public farmersRainfall;

    constructor(address _rainToken, address _farmToken) {
        rainToken = _rainToken;
        farmToken = _farmToken;
    }
}

File 3 of 4 : RainFarmInterface.sol
pragma solidity ^0.8.12;

abstract contract RainFarmInterface {
    bool public isRainFarmer = true;
    bytes32 public contractNameHash;

    /*** admin setters and farm control ***/
    function pullNewRain(address pullRainFromAddress, uint pullRainAmount) virtual external;
    function extendWithExistingConfiguration(address pullRainFromAddress, uint pullRainAmount) virtual external;
    function restartWithNewConfiguration(
        uint _newStartTime,
        uint newDistributionPeriod,
        address pullRainFromAddress,
        uint pullRainAmount
    ) virtual external;

    /*** farm accounting and indexes ***/
    function updateFarmIndex() virtual external;
    function updateFarmerIndex(address farmer) virtual external;

    // *** user interactions - deposit, withdraw, claim rain ***/
    function depositToFarm(uint amount) virtual external;
    function depositToFarmOnBehalf(address farmer, uint amount) virtual external;
    function withdrawAllFromFarm() virtual external;
    function withdrawFromFarm(uint amount) virtual external;
    function claimRainFromFarm(address farmer) virtual external;
    function claimRainFromFarmToSomeFarmers(address[] calldata farmers) virtual external;

    // *** emergency ***
    function emergencyWithdrawFromFarm() virtual external;

    // *** admin ***
    function _setPendingAdmin(address newPendingAdmin) virtual external returns (uint);
    function _acceptAdmin() virtual external returns (uint);
}

File 4 of 4 : TransferHelper.sol
// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity >=0.6.0;

// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
library TransferHelper {
    function safeApprove(
        address token,
        address to,
        uint256 value
    ) internal {
        // bytes4(keccak256(bytes('approve(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
        require(
            success && (data.length == 0 || abi.decode(data, (bool))),
            'TransferHelper::safeApprove: approve failed'
        );
    }

    function safeTransfer(
        address token,
        address to,
        uint256 value
    ) internal {
        // bytes4(keccak256(bytes('transfer(address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
        require(
            success && (data.length == 0 || abi.decode(data, (bool))),
            'TransferHelper::safeTransfer: transfer failed'
        );
    }

    function safeTransferFrom(
        address token,
        address from,
        address to,
        uint256 value
    ) internal {
        // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
        require(
            success && (data.length == 0 || abi.decode(data, (bool))),
            'TransferHelper::transferFrom: transferFrom failed'
        );
    }

    function safeTransferETH(address to, uint256 value) internal {
        (bool success, ) = to.call{value: value}(new bytes(0));
        require(success, 'TransferHelper::safeTransferETH: ETH transfer failed');
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_admin","type":"address"},{"internalType":"uint256","name":"_minDistributionPeriod","type":"uint256"},{"internalType":"address","name":"_farmToken","type":"address"},{"internalType":"address","name":"_rainToken","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"farmer","type":"address"},{"indexed":false,"internalType":"uint256","name":"deltaFarmerRainfall","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"farmIndex","type":"uint256"}],"name":"AllocatedRainToFarmer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldBudget","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBudget","type":"uint256"}],"name":"BudgetSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldDistributionPeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newDistributionPeriod","type":"uint256"}],"name":"DistributionPeriodSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"farmToken","type":"address"}],"name":"FarmAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFarmSpeed","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFarmSpeed","type":"uint256"}],"name":"FarmSpeedSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"NewAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldPendingAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newPendingAdmin","type":"address"}],"name":"NewPendingAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldStartTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startTime","type":"uint256"}],"name":"StartTimeSet","type":"event"},{"inputs":[],"name":"SingleAssetRainFarmContractHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_acceptAdmin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newPendingAdmin","type":"address"}],"name":"_setPendingAdmin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseUnit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"budget","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"budgetCommitmentUntilNow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"farmer","type":"address"}],"name":"claimRainFromFarm","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"farmers","type":"address[]"}],"name":"claimRainFromFarmToSomeFarmers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractNameHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"depositToFarm","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"farmer","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"depositToFarmOnBehalf","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"distributionPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emergencyWithdrawFromFarm","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"endTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pullRainFromAddress","type":"address"},{"internalType":"uint256","name":"pullRainAmount","type":"uint256"}],"name":"extendWithExistingConfiguration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"farmCurrentState","outputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"farmInitialIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"farmSpeed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"farmToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"farmTokenUnit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"farmersCurrentIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"farmersCurrentSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"farmersRainfall","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFarmSpeed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFarmToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRainToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRemainingBudget","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"totalRain","type":"uint256"},{"internalType":"uint256","name":"totalSeconds","type":"uint256"}],"name":"getTotalRainSpeed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"isRainFarmer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minDistributionPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pullRainFromAddress","type":"address"},{"internalType":"uint256","name":"pullRainAmount","type":"uint256"}],"name":"pullNewRain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rainToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rainTokenUnit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newStartTime","type":"uint256"},{"internalType":"uint256","name":"newDistributionPeriod","type":"uint256"},{"internalType":"address","name":"pullRainFromAddress","type":"address"},{"internalType":"uint256","name":"pullRainAmount","type":"uint256"}],"name":"restartWithNewConfiguration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"updateFarmIndex","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"farmer","type":"address"}],"name":"updateFarmerIndex","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawAllFromFarm","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawFromFarm","outputs":[],"stateMutability":"nonpayable","type":"function"}]

610120604052600c805460ff19908116600117909155600e805490911690553480156200002b57600080fd5b506040516200245b3803806200245b8339810160408190526200004e916200020f565b6001600160a01b0381811660805282811660a08190527f5d60379cc35a07cb65119bc8e992e72a714154d36c0d35d04f15b840f7ce1560600d55600080546001600160a01b0319169287169290921782556040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa158015620000db573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000101919062000263565b90506000826001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000144573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200016a919062000263565b90506200017982600a62000392565b60c0526200018981600a62000392565b60e0526ec097ce7bc90715b34b9f100000000060069081554260078190556101008790526040519091906001600160a01b038716907fbfca0af3a33c0bcae29f7d07934c90e392c5d6c2ba686ce898528ee63bea8f5290600090a25050505050505050620003a7565b80516001600160a01b03811681146200020a57600080fd5b919050565b600080600080608085870312156200022657600080fd5b6200023185620001f2565b9350602085015192506200024860408601620001f2565b91506200025860608601620001f2565b905092959194509250565b6000602082840312156200027657600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b600181815b80851115620002d4578160001904821115620002b857620002b86200027d565b80851615620002c657918102915b93841c939080029062000298565b509250929050565b600082620002ed575060016200038c565b81620002fc575060006200038c565b8160018114620003155760028114620003205762000340565b60019150506200038c565b60ff8411156200033457620003346200027d565b50506001821b6200038c565b5060208310610133831016604e8410600b841016171562000365575081810a6200038c565b62000371838362000293565b80600019048211156200038857620003886200027d565b0290505b92915050565b6000620003a08383620002dc565b9392505050565b60805160a05160c05160e0516101005161203762000424600039600081816103a101526117c40152600061052a015260006104650152600081816103c5015281816104e10152818161139b01526116150152600081816102fe01528181610551015281816116530152818161188f015261190d01526120376000f3fe608060405234801561001057600080fd5b50600436106102735760003560e01c80637b48746d11610151578063c78ca939116100c3578063e3a775c311610087578063e3a775c3146105a6578063e46c3c72146105b9578063e9c714f2146105cc578063ed01bf29146105d4578063ee20d5dc146105dd578063f851a4401461060057600080fd5b8063c78ca93914610512578063cb68c77314610525578063cc74216a1461054c578063cdbd662a14610573578063da9f88f21461058657600080fd5b80639b610cd9116101155780639b610cd914610490578063a1170054146104a3578063b71d1a0c146104b6578063c1cb88eb146104c9578063c2442f93146104dc578063c2930f911461050357600080fd5b80637b48746d14610432578063817f8bd91461044557806382bb1bf51461044d5780639052bc86146104605780639b5017231461048757600080fd5b8063320aade0116101ea5780635064f76d116101ae5780635064f76d146103e95780635387014c146103f157806354fd4d50146104115780636ca7970b1461041957806377a15b611461042157806378e979251461042957600080fd5b8063320aade014610375578063469ab1e31461038a57806346ffc9c014610393578063480492b01461039c5780634d98493d146103c357600080fd5b80631c8b4abb1161023c5780631c8b4abb146102fc57806320b4aa0b1461033657806323862ba31461034c578063267822471461035457806329cb924d146103675780633197cbb61461036d57600080fd5b806291f24714610278578063019131621461028f5780630a7cfa18146102af57806315d2ff08146102d657806318160ddd146102f3575b600080fd5b6005545b6040519081526020015b60405180910390f35b61027c61029d366004611d4b565b600a6020526000908152604090205481565b61027c7f5d60379cc35a07cb65119bc8e992e72a714154d36c0d35d04f15b840f7ce156081565b600c546102e39060ff1681565b6040519015158152602001610286565b61027c60085481565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b039091168152602001610286565b61027c6ec097ce7bc90715b34b9f100000000081565b61027c610613565b60015461031e906001600160a01b031681565b4261027c565b61027c61067e565b610388610383366004611d66565b610695565b005b61027c600d5481565b61027c60055481565b61027c7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000061031e565b6103886106f9565b61027c6103ff366004611d4b565b60096020526000908152604090205481565b61027c606481565b61038861076c565b61027c6107b0565b61027c60035481565b610388610440366004611d4b565b6107e2565b610388610823565b61038861045b366004611d7f565b610881565b61027c7f000000000000000000000000000000000000000000000000000000000000000081565b61027c60045481565b61038861049e366004611da9565b6108cd565b6103886104b1366004611e1e565b610994565b61027c6104c4366004611d4b565b610a74565b6103886104d7366004611d66565b610b42565b61031e7f000000000000000000000000000000000000000000000000000000000000000081565b61027c670de0b6b3a764000081565b610388610520366004611d7f565b610b8e565b61027c7f000000000000000000000000000000000000000000000000000000000000000081565b61031e7f000000000000000000000000000000000000000000000000000000000000000081565b61027c610581366004611e5b565b610c6d565b61027c610594366004611d4b565b600b6020526000908152604090205481565b6103886105b4366004611d7f565b610c9a565b6103886105c7366004611d4b565b610d08565b61027c610da8565b61027c60025481565b6006546007546105eb919082565b60408051928352602083019190915201610286565b60005461031e906001600160a01b031681565b60004261061e61067e565b811061062c57505060025490565b600354808211158061063e5750600254155b806106495750600454155b156106575760009250505090565b60006106638284611e93565b90506000600554826106759190611eaa565b95945050505050565b60006004546003546106909190611ec9565b905090565b600e5460ff16156106c15760405162461bcd60e51b81526004016106b890611ee1565b60405180910390fd5b600e805460ff19166001179055336106d7610f05565b6106e081611007565b6106eb818284611199565b5050600e805460ff19169055565b600e5460ff161561071c5760405162461bcd60e51b81526004016106b890611ee1565b600e805460ff1916600117905533610732610f05565b61073b81611007565b6001600160a01b0381166000908152600a602052604090205461075f9082906111f9565b50600e805460ff19169055565b600e5460ff161561078f5760405162461bcd60e51b81526004016106b890611ee1565b600e805460ff191660011790556107a4610f05565b600e805460ff19169055565b6000806107bb610613565b905080600254116107ce57600091505090565b806002546107dc9190611e93565b91505090565b600e5460ff16156108055760405162461bcd60e51b81526004016106b890611ee1565b600e805460ff1916600117905561081a610f05565b61075f81611007565b600e5460ff16156108465760405162461bcd60e51b81526004016106b890611ee1565b600e805460ff191660011790553361085d81611222565b6001600160a01b03166000908152600b6020526040812055600e805460ff19169055565b600e5460ff16156108a45760405162461bcd60e51b81526004016106b890611ee1565b600e805460ff191660011790556108b9610f05565b6108c282611007565b6106eb823383611199565b600e5460ff16156108f05760405162461bcd60e51b81526004016106b890611ee1565b600e805460ff19166001179055610905610f05565b60005b8181101561095757600083838381811061092457610924611f11565b90506020020160208101906109399190611d4b565b905061094481611007565b508061094f81611f27565b915050610908565b506106eb8282808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506112a992505050565b600e5460ff16156109b75760405162461bcd60e51b81526004016106b890611ee1565b600e8054600160ff199091161790556000546001600160a01b031633146109f05760405162461bcd60e51b81526004016106b890611f42565b6109f8610f05565b42610a0161067e565b8111610a4f5760405162461bcd60e51b815260206004820152601e60248201527f6e6f7420647572696e672061637469766520646973747269627574696f6e000060448201526064016106b8565b610a59858561132e565b610a63838361134e565b5050600e805460ff19169055505050565b600e5460009060ff1615610a9a5760405162461bcd60e51b81526004016106b890611ee1565b600e8054600160ff199091161790556000546001600160a01b03163314610ad35760405162461bcd60e51b81526004016106b890611f42565b600180546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9910160405180910390a15050600e805460ff1916905550600090565b600e5460ff1615610b655760405162461bcd60e51b81526004016106b890611ee1565b600e805460ff1916600117905533610b7b610f05565b610b8481611007565b6106eb81836111f9565b600e5460ff1615610bb15760405162461bcd60e51b81526004016106b890611ee1565b600e8054600160ff199091161790556000546001600160a01b03163314610bea5760405162461bcd60e51b81526004016106b890611f42565b610bf2610f05565b42610bfb61067e565b8110610c495760405162461bcd60e51b815260206004820181905260248201527f63616e6e6f7420657874656e6420612066696e69736865642070726f6772616d60448201526064016106b8565b610c5460008061132e565b610c5e838361134e565b5050600e805460ff1916905550565b6000821580610c7a575081155b15610c8757506000610c94565b610c918284611f62565b90505b92915050565b600e5460ff1615610cbd5760405162461bcd60e51b81526004016106b890611ee1565b600e8054600160ff199091161790556000546001600160a01b03163314610cf65760405162461bcd60e51b81526004016106b890611f42565b610cfe610f05565b6106eb828261134e565b600e5460ff1615610d2b5760405162461bcd60e51b81526004016106b890611ee1565b600e805460ff19166001179055610d40610f05565b610d4981611007565b604080516001808252818301909252600091602080830190803683370190505090508181600081518110610d7f57610d7f611f11565b60200260200101906001600160a01b031690816001600160a01b0316815250506106eb816112a9565b600e5460009060ff1615610dce5760405162461bcd60e51b81526004016106b890611ee1565b600e8054600160ff199091168117909155546001600160a01b031633148015610df657503315155b610e425760405162461bcd60e51b815260206004820152601e60248201527f4e6f7420746865204558495354494e472070656e64696e672061646d696e000060448201526064016106b8565b60008054600180546001600160a01b038082166001600160a01b031980861682179096559490911690915560408051919092168082526020820184905292917ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc910160405180910390a1600154604080516001600160a01b03808516825290921660208301527fca4f2f25d0898edd99413412fb94012f9e54ec8142f9b093e7720646a95b16a9910160405180910390a15050600e805460ff1916905550600090565b60055460075460069190426000610f1a61067e565b6003549091506000828411610f2f5783610f31565b825b90506000858311610f425785610f44565b825b9050600085841180610f5557508282115b9050600081610f6d57610f688385611e93565b610f70565b60005b9050600081118015610f825750600089115b15610feb576008546000610f968b84611eaa565b90506000808311610fa8576000610fcc565b82610fc26ec097ce7bc90715b34b9f100000000084611eaa565b610fcc9190611f62565b9050808d6000016000828254610fe29190611ec9565b90915550505050505b86881015610ffb5760018a018790555b50505050505050505050565b6040805180820182526006548082526007546020808401919091526001600160a01b038516600090815260099091529283205491929091908183101561109f5760405162461bcd60e51b815260206004820152602760248201527f6661726d65722063616e2774206265206d6f726520616476616e636564207468604482015266616e206661726d60c81b60648201526084016106b8565b811561113d5760006110b18385611e93565b6001600160a01b0387166000908152600a6020526040902054909150811561113a576ec097ce7bc90715b34b9f10000000006110ed8383611eaa565b6110f79190611f62565b6001600160a01b0388166000908152600b60205260408120549194509061111f908590611ec9565b6001600160a01b0389166000908152600b6020526040902055505b50505b6001600160a01b03851660008181526009602090815260409182902086905581518481529081018690527f05cbb560cbcdea0e35c47338bcaa0ec9b5b43b8aae1a7f205be6a9a206a0aa97910160405180910390a25050505050565b426111a261067e565b81106111db5760405162461bcd60e51b8152602060048201526008602482015267746f6f206c61746560c01b60448201526064016106b8565b6111e58383611383565b91506111f3848360006114f1565b50505050565b611202826115d0565b801561121e57611214826000836114f1565b61121e8282611610565b5050565b6001600160a01b0381166000908152600a60205260409020548061127e5760405162461bcd60e51b81526020600482015260136024820152726e6f7468696e6720746f20776974686472617760681b60448201526064016106b8565b611214826001600160a01b03166000908152600960209081526040808320839055600a909152812055565b60005b815181101561121e5760008282815181106112c9576112c9611f11565b6020026020010151905061130281600b6000846001600160a01b03166001600160a01b031681526020019081526020016000205461163b565b6001600160a01b039091166000908152600b60205260409020558061132681611f27565b9150506112ac565b611336611700565b61133f82611718565b801561121e5761121e816117c2565b6000811561136d576113608383611877565b61136a9082611ec9565b90505b61137681611934565b61137e611952565b505050565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000009082906001600160a01b038316906370a0823190602401602060405180830381865afa1580156113ee573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114129190611f84565b9050611420828630876119b5565b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa158015611467573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061148b9190611f84565b90506114978282611e93565b93508484146114e85760405162461bcd60e51b815260206004820152601960248201527f6d757374207265636569766520657861637420616d6f756e740000000000000060448201526064016106b8565b50505092915050565b811561152a576001600160a01b0383166000908152600a60205260408120805484929061151f908490611ec9565b909155506115c69050565b80156115c6576001600160a01b0383166000908152600a60205260409020548111156115985760405162461bcd60e51b815260206004820152601860248201527f6d6f7265207468616e206661726d65722062616c616e6365000000000000000060448201526064016106b8565b6001600160a01b0383166000908152600a6020526040812080548392906115c0908490611e93565b90915550505b61137e8282611af3565b6001600160a01b0381166000908152600b60205260409020546115f490829061163b565b6001600160a01b039091166000908152600b6020526040902055565b61121e7f00000000000000000000000000000000000000000000000000000000000000008383611b82565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000009082906001600160a01b038316906370a0823190602401602060405180830381865afa1580156116a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116ca9190611f84565b90506000841180156116dc5750808411155b156116f7576116ec828686611b82565b600092505050610c94565b50919392505050565b600061170a6107b0565b905061171581611cb3565b50565b42600082156117275782611729565b815b90508181101561177b5760405162461bcd60e51b815260206004820152601860248201527f63616e6e6f7420737461727420696e207468652070617374000000000000000060448201526064016106b8565b600380549082905560408051828152602081018490527f229a47a590a5e543f42b381d9c7913437d6a22cbea20cdaa6c3fb425ce9ac28a910160405180910390a150505050565b7f000000000000000000000000000000000000000000000000000000000000000081116118315760405162461bcd60e51b815260206004820152601d60248201527f446973747269627574696f6e20706572696f6420746f6f2073686f727400000060448201526064016106b8565b600480549082905560408051828152602081018490527fb0b24597cd10b18eac3d1526dde0d6eb9326a5668442ee0a383a8aac2271cc5591015b60405180910390a15050565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000009082906001600160a01b038316906370a0823190602401602060405180830381865afa1580156118e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119069190611f84565b90506114207f00000000000000000000000000000000000000000000000000000000000000008630876119b5565b600061193e6107b0565b905061121e61194d8383611ec9565b611cb3565b42600061195d61067e565b6003549091508160008285106119735784611975565b825b90506000818311611987576000611991565b6119918284611e93565b905060006119a160025483610c6d565b90506119ac81611cf1565b50505050505050565b604080516001600160a01b0385811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b1790529151600092839290881691611a199190611f9d565b6000604051808303816000865af19150503d8060008114611a56576040519150601f19603f3d011682016040523d82523d6000602084013e611a5b565b606091505b5091509150818015611a85575080511580611a85575080806020019051810190611a859190611fd8565b611aeb5760405162461bcd60e51b815260206004820152603160248201527f5472616e7366657248656c7065723a3a7472616e7366657246726f6d3a207472604482015270185b9cd9995c919c9bdb4819985a5b1959607a1b60648201526084016106b8565b505050505050565b8115611b16578160086000828254611b0b9190611ec9565b9091555061121e9050565b801561121e57806008541015611b675760405162461bcd60e51b81526020600482015260166024820152756d6f7265207468616e206661726d2062616c616e636560501b60448201526064016106b8565b8060086000828254611b799190611e93565b90915550505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1790529151600092839290871691611bde9190611f9d565b6000604051808303816000865af19150503d8060008114611c1b576040519150601f19603f3d011682016040523d82523d6000602084013e611c20565b606091505b5091509150818015611c4a575080511580611c4a575080806020019051810190611c4a9190611fd8565b611cac5760405162461bcd60e51b815260206004820152602d60248201527f5472616e7366657248656c7065723a3a736166655472616e736665723a20747260448201526c185b9cd9995c8819985a5b1959609a1b60648201526084016106b8565b5050505050565b600280549082905560408051828152602081018490527f869e2577b006bf47ee981cf6fec2e25583548081c14b98deab587f77b5068038910161186b565b600580549082905560408051828152602081018490527f7440a7baa46bbca19ebcb4a4750505d363768047c87f4934d3e3410fc8f2f995910161186b565b80356001600160a01b0381168114611d4657600080fd5b919050565b600060208284031215611d5d57600080fd5b610c9182611d2f565b600060208284031215611d7857600080fd5b5035919050565b60008060408385031215611d9257600080fd5b611d9b83611d2f565b946020939093013593505050565b60008060208385031215611dbc57600080fd5b823567ffffffffffffffff80821115611dd457600080fd5b818501915085601f830112611de857600080fd5b813581811115611df757600080fd5b8660208260051b8501011115611e0c57600080fd5b60209290920196919550909350505050565b60008060008060808587031215611e3457600080fd5b8435935060208501359250611e4b60408601611d2f565b9396929550929360600135925050565b60008060408385031215611e6e57600080fd5b50508035926020909101359150565b634e487b7160e01b600052601160045260246000fd5b600082821015611ea557611ea5611e7d565b500390565b6000816000190483118215151615611ec457611ec4611e7d565b500290565b60008219821115611edc57611edc611e7d565b500190565b6020808252601690820152751499595b9d1c985b98d9481b9bdd08185b1b1bddd95960521b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b6000600019821415611f3b57611f3b611e7d565b5060010190565b60208082526006908201526510b0b236b4b760d11b604082015260600190565b600082611f7f57634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215611f9657600080fd5b5051919050565b6000825160005b81811015611fbe5760208186018101518583015201611fa4565b81811115611fcd576000828501525b509190910192915050565b600060208284031215611fea57600080fd5b81518015158114611ffa57600080fd5b939250505056fea264697066735822122001c5828fb659082a16949947d4ad5fb7050c80acb9d197d837f8dfd2191c347164736f6c634300080c0033000000000000000000000000c333a03e8040cad31993e02615fd1b3f88447d950000000000000000000000000000000000000000000000000000000000015180000000000000000000000000f9c6e3c123f0494a4447100bd7dbd536f43cc33a000000000000000000000000582423c10c9e83387a96d00a69ba3d11ee47b7b5

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000c333a03e8040cad31993e02615fd1b3f88447d950000000000000000000000000000000000000000000000000000000000015180000000000000000000000000f9c6e3c123f0494a4447100bd7dbd536f43cc33a000000000000000000000000582423c10c9e83387a96d00a69ba3d11ee47b7b5

-----Decoded View---------------
Arg [0] : _admin (address): 0xc333a03e8040cad31993e02615fd1b3f88447d95
Arg [1] : _minDistributionPeriod (uint256): 86400
Arg [2] : _farmToken (address): 0xf9c6e3c123f0494a4447100bd7dbd536f43cc33a
Arg [3] : _rainToken (address): 0x582423c10c9e83387a96d00a69ba3d11ee47b7b5

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000c333a03e8040cad31993e02615fd1b3f88447d95
Arg [1] : 0000000000000000000000000000000000000000000000000000000000015180
Arg [2] : 000000000000000000000000f9c6e3c123f0494a4447100bd7dbd536f43cc33a
Arg [3] : 000000000000000000000000582423c10c9e83387a96d00a69ba3d11ee47b7b5


Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Validator ID :
0 FTM

Amount Staked
0

Amount Delegated
0

Staking Total
0

Staking Start Epoch
0

Staking Start Time
0

Proof of Importance
0

Origination Score
0

Validation Score
0

Active
0

Online
0

Downtime
0 s
Address Amount claimed Rewards Created On Epoch Created On
Block Uncle Number Difficulty Gas Used Reward
Loading
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.