账户
0xde...ab50
0xDE...Ab50

0xDE...Ab50

$500
此合同的源代码已经过验证!
合同元数据
编译器
0.7.4+commit.3f05b770
语言
Solidity
合同源代码
文件 1 的 11:Context.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}
合同源代码
文件 2 的 11:DegensFarm.sol
// SPDX-License-Identifier: MIT
// Degen'$ Farm: Collectible NFT game (https://degens.farm)
pragma solidity ^0.7.4;
pragma experimental ABIEncoderV2;

import "./DegensFarmBase.sol";

contract DegenFarm is DegenFarmBase {

    uint8   constant public CREATURE_TYPE_COUNT= 20;  // how much creatures types may be used
    uint256 constant public FARMING_DURATION   = 168 hours;
    uint256 constant public TOOL_UNSTAKE_DELAY = 1 weeks;
    uint16  constant public NORMIE_COUNT_IN_TYPE = 100;
    uint16  constant public CHAD_COUNT_IN_TYPE = 20;
    uint16  constant public MAX_LANDS = 2500;

    constructor (
        address _land,
        address _creatures,
        address _inventory,
        address _bagstoken,
        address _dungtoken,
        IEggs _eggs
    )
        DegenFarmBase(_land, _creatures, _inventory, _bagstoken, _dungtoken, _eggs)
    {
        require(CREATURE_TYPE_COUNT <= CREATURE_TYPE_COUNT_MAX, "CREATURE_TYPE_COUNT is greater than CREATURE_TYPE_COUNT_MAX");

        // Mainnet amulet addresses
        amulets[0]  = 0xD533a949740bb3306d119CC777fa900bA034cd52; // Cow    $CRV
        amulets[1]  = 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984; // Horse  $UNI
        amulets[2]  = 0xfA5047c9c78B8877af97BDcb85Db743fD7313d4a; // Rabbit $ROOK
        amulets[3]  = 0xDADA00A9C23390112D08a1377cc59f7d03D9df55; // Chicken $DUNG
        amulets[4]  = 0x6B3595068778DD592e39A122f4f5a5cF09C90fE2; // Pig    $SUSHI
        amulets[5]  = 0x0D8775F648430679A709E98d2b0Cb6250d2887EF; // Cat    $BAT
        amulets[6]  = 0x3472A5A71965499acd81997a54BBA8D852C6E53d; // Dog	$BADGER
        amulets[7]  = 0x0d438F3b5175Bebc262bF23753C1E53d03432bDE; // Goose	$WNXM
        amulets[8]  = 0x3155BA85D5F96b2d030a4966AF206230e46849cb; // Goat	$RUNE
        amulets[9]  = 0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9; // Sheep	$AAVE
        amulets[10] = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F; // Snake	$SNX
        amulets[11] = 0x967da4048cD07aB37855c090aAF366e4ce1b9F48; // Fish	$OCEAN
        amulets[12] = 0x0F5D2fB29fb7d3CFeE444a200298f468908cC942; // Frog	$MANA
        amulets[13] = 0x514910771AF9Ca656af840dff83E8264EcF986CA; // Worm	$LINK
        amulets[14] = 0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32; // Lama	$LDO
        amulets[15] = 0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C; // Mouse	$BNT
        amulets[16] = 0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2; // Camel	$MKR
        amulets[17] = 0x111111111117dC0aa78b770fA6A738034120C302; // Donkey	$1INCH
        amulets[18] = 0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e; // Bee	$YFI
        amulets[19] = 0xc00e94Cb662C3520282E6f5717214004A7f26888; // Duck	$COMP
    }

    function getCreatureTypeCount() override internal view returns (uint16) {
        return CREATURE_TYPE_COUNT;
    }

    function getFarmingDuration() override internal view returns (uint) {
        return FARMING_DURATION;
    }

    function getNormieCountInType() override internal view returns (uint16) {
        return NORMIE_COUNT_IN_TYPE;
    }

    function getChadCountInType() override internal view returns (uint16) {
        return CHAD_COUNT_IN_TYPE;
    }

    function getMaxLands() override internal view returns (uint16) {
        return MAX_LANDS;
    }

    function getToolUnstakeDelay() override internal view returns (uint) {
        return TOOL_UNSTAKE_DELAY;
    }

}
合同源代码
文件 3 的 11:DegensFarmBase.sol
// SPDX-License-Identifier: MIT
// Degen'$ Farm: Collectible NFT game (https://degens.farm)
pragma solidity ^0.7.4;
pragma experimental ABIEncoderV2;

import "./IERC20.sol";
import "./IERC1155.sol";
import "./ERC1155Receiver.sol";
import "./IERC721.sol";
import "./Ownable.sol";

interface IEggs is IERC721 {
    function mint(address to, uint256 tokenId) external;
    function burn(uint256 tokenId) external;
    function getUsersTokens(address _owner) external view returns (uint256[] memory);
}

interface ICreatures is IERC721 {
    function mint(
        address to, 
        uint256 tokenId, 
        uint8 _animalType,
        uint8 _rarity,
        uint32 index
        ) external;

    function getTypeAndRarity(uint256 _tokenId) external view returns(uint8, uint8);
    function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
}

interface ILand is IERC721 {
    function mint(
        address to, 
        uint256 tokenId,
        uint randomSeed
    ) external;
    function burn(uint256 tokenId) external;
}

interface IDung is IERC20 {
    function mint(
        address to, 
        uint256 amount 
    ) external;
}

interface IInventory is IERC1155 {
     function getToolBoost(uint8 _item) external view returns (uint16);
}

interface IAmuletPriceProvider {
     function getLastPrice(address _amulet) external view returns (uint256);
}

interface IOperatorManage {
    function addOperator(address _newOperator) external;    
    function removeOperator(address _oldOperator) external;
    function withdrawERC20(IERC20 _tokenContract, address _admin) external;
    function setSigner(address _newSigner) external;
}

abstract contract DegenFarmBase is ERC1155Receiver, Ownable {
    enum AnimalType {
        Cow, Horse, Rabbit, Chicken, Pig, Cat, Dog, Goose, Goat, Sheep,
        Snake, Fish, Frog, Worm, Lama, Mouse, Camel, Donkey, Bee, Duck,
        GenesisEgg // 20
    }
    enum Rarity {
        Normie, // 0
        Chad,   // 1
        Degen,  // 2
        Unique // 3
    }
    enum   Result     {Fail,   Dung,  Chad, Degen}
    
    // External contract addresses used with this farm
    struct AddressRegistry {
        address land;
        address creatures;
        address inventory;
        address bagstoken;
        address dungtoken;
    }

    // Degens Farm data for creature type
    struct CreaturesCount {
        uint16 totalNormie;
        uint16 leftNormie;
        uint16 totalChad;
        uint16 leftChadToDiscover;
        uint16 totalDegen;
        uint16 leftDegenToDiscover;
        uint16 chadFarmAttempts;
        uint16 degenFarmAttempts;
    }

    // Land count record
    struct LandCount {
        uint16 total;
        uint16 left;
    }
 
    // Record represent one farming act
    struct FarmRecord {
        uint256   creatureId;
        uint256   landId;
        uint256   harvestTime;
        uint256   amuletsPrice1;
        uint256   amuletsPrice2;
        Result    harvest;
        uint256   harvestId; // new NFT tokenId
        bool[COMMON_AMULET_COUNT]   commonAmuletInitialHold;
    }

    // Bonus for better harvest
    struct Bonus {
        uint256 commonAmuletHold;  // common amulet hold
        uint256 creatureAmuletBullTrend;
        uint256 inventoryHold;
        uint256 creatureAmuletBalance;
    }

    uint8   constant public CREATURE_TYPE_COUNT_MAX = 20;  //how much creatures types may be used

    // Creature probability multiplier, scaled with 100. 3.00  - 300, 3.05 - 305 etc
    uint32  constant public CREATURE_P_MULT = 230;
    uint16  public MAX_ALL_NORMIES    = getCreatureTypeCount() * getNormieCountInType();
    uint256 constant public NFT_ID_MULTIPLIER  = 10000;     //must be set more then all Normies count
    uint256 constant public FARM_DUNG_AMOUNT   = 250e33;      //per one harvest
    uint256 constant public BONUS_POINTS_AMULET_HOLD       = 10;
    uint256 constant public COMMON_AMULET_COUNT       = 2;
    uint256 constant public TOOL_TYPE_COUNT = 6;

    // Common Amulet addresses
    address[COMMON_AMULET_COUNT] public COMMON_AMULETS = [
        0x126c121f99e1E211dF2e5f8De2d96Fa36647c855, // $DEGEN token
        0xa0246c9032bC3A600820415aE600c6388619A14D  // $FARM token
    ];

    bool    public REVEAL_ENABLED  = false;
    bool    public FARMING_ENABLED = false;
    address public priceProvider;
    IEggs   public eggs;
    
    address[CREATURE_TYPE_COUNT_MAX] public amulets; // amulets by creature type
    AddressRegistry                  public farm;
    LandCount                        public landCount;

    mapping(address => uint256) public maxAmuletBalances;

    // mapping from user to his(her) staked tools
    // Index of uint256[6] represent tool NFT itemID
    mapping(address => uint256[TOOL_TYPE_COUNT]) public userStakedTools;


    uint16 public allNormiesesLeft;
    CreaturesCount[CREATURE_TYPE_COUNT_MAX] public creaturesBorn;
    FarmRecord[] public farming;
    mapping(uint => uint) public parents;

    event Reveal(address _farmer, uint256 indexed _tokenId, bool _isCreature, uint8 _animalType);
    event Harvest(
        uint256 indexed _eggId, 
        address farmer, 
        uint8   result,
        uint256 baseChance,
        uint256 commonAmuletHold,
        uint256 amuletBullTrend,
        uint256 inventoryHold,
        uint256 amuletMaxBalance,
        uint256 resultChance
    );
    event Stake(address owner, uint8 innventory);
    event UnStake(address owner, uint8 innventory);
    
    constructor (
        address _land, 
        address _creatures,
        address _inventory,
        address _bagstoken,
        address _dungtoken,
        IEggs _eggs
    )
    {
        farm.land      = _land;
        farm.creatures = _creatures;
        farm.inventory = _inventory;
        farm.bagstoken = _bagstoken;
        farm.dungtoken = _dungtoken;
        
        // Index of creaturesBorn in this initial setting  
        // must NOT exceed CREATURE_TYPE_COUNT
        for (uint i = 0; i < getCreatureTypeCount(); i++) {
            creaturesBorn[i] = CreaturesCount(
                getNormieCountInType(), // totalNormie;
                getNormieCountInType(), // leftNormie;
                getChadCountInType(),   // totalChad;
                getChadCountInType(),   // leftChadToDiscover;
                1,                      // totalDegen;
                1,                      // leftDegenToDiscover;
                0, // chadFarmAttempts;
                0);  // degenFarmAttempts;
        }

        landCount        = LandCount(getMaxLands(), getMaxLands());
        allNormiesesLeft = MAX_ALL_NORMIES;
        eggs = _eggs;
    }

    function reveal(uint count) external {
        require(_isRevelEnabled(), "Please wait for reveal enabled.");
        require(count > 0, "Count must be positive");
        require(count <= 8, "Count must less than 9"); // random limit
        require(
            IERC20(farm.bagstoken).allowance(msg.sender, address(this)) >= count*1,
            "Please approve your BAGS token to this contract."
        );
        require(
            IERC20(farm.bagstoken).transferFrom(msg.sender, address(this), count*1)
        );
        uint randomSeed = uint(keccak256(abi.encodePacked(block.timestamp, msg.sender)));
        // random seed for 8 reveals (8x32=256)
        for (uint i = 0; i < count; i++) {
            _reveal(randomSeed);
            randomSeed = randomSeed / 0x100000000; // shift right 32 bits
        }
    }

    /**
     * @dev Start farming process. New NFT - Egg will minted for user 
     * @param _creatureId - NFT tokenId, caller must be owner of this token
     * @param _landId -- NFT tokenId, caller must be owner of this token
     */
    function farmDeploy(uint256 _creatureId, uint256 _landId) external {
        require(FARMING_ENABLED == true, "Chief Farmer not enable yet");
        require(ICreatures(farm.creatures).ownerOf(_creatureId) == msg.sender, 
            "Need to be Creature Owner"
        );
        require(ILand(farm.land).ownerOf(_landId) == msg.sender,
            "Need to be Land Owner"
        );
        (uint8 crType, uint8 crRarity) = ICreatures(farm.creatures).getTypeAndRarity(_creatureId);
        require((DegenFarmBase.Rarity)(crRarity) == Rarity.Normie ||
            (DegenFarmBase.Rarity)(crRarity) == Rarity.Chad,
            "Can farm only Normie and Chad");
        // Check that farming available yet
        if (crRarity == 0) {
            require(creaturesBorn[crType].leftChadToDiscover > 0, "No more chads left");
        } else {
            require(creaturesBorn[crType].leftDegenToDiscover > 0, "No more Degen left");
        }

        // Save deploy record
        farming.push(
            FarmRecord({
                creatureId:    _creatureId,
                landId:        _landId,
                harvestTime:   block.timestamp + getFarmingDuration(),
                amuletsPrice1: _getExistingAmuletsPrices(amulets[crType]),
                amuletsPrice2: 0,
                harvest:       Result.Fail,
                harvestId:     0, 
                commonAmuletInitialHold: _getCommonAmuletsHoldState(msg.sender) //save initial hold state
            })
        );

        // Let's mint Egg.
        eggs.mint(
            msg.sender,         // farmer
            farming.length - 1  // tokenId
        );
        // STAKE LAND and Creatures
        ILand(farm.land).transferFrom(msg.sender, address(this), _landId);
        ICreatures(farm.creatures).transferFrom(msg.sender, address(this), _creatureId);
    }

    /**
     * @dev Finish farming process. Egg NFT will be  burn 
     * @param _deployId - NFT tokenId, caller must be owner of this token
     */
    function harvest(uint256 _deployId) external {

        require(eggs.ownerOf(_deployId) == msg.sender, "This is NOT YOUR EGG");
        
        FarmRecord storage f = farming[_deployId];
        require(f.harvestTime <= block.timestamp, "To early for harvest");
        // Lets Calculate Dung/CHAD-DEGEN chance
        Result farmingResult;
        Bonus memory bonus;
        // 1. BaseChance
        (uint8 crType, uint8 crRarity) = ICreatures(farm.creatures).getTypeAndRarity(
            f.creatureId
        );
        uint256 baseChance;
        if (crRarity == 0) {
            // Try farm CHAD. So if there is no CHADs any more we must return assets
            if (creaturesBorn[crType].leftChadToDiscover == 0) {
                _endFarming(_deployId, Result.Fail);
                return;
            }
            baseChance = 100 * creaturesBorn[crType].totalChad / creaturesBorn[crType].totalNormie; // by default 20%
            // Decrease appropriate farm ATTEMPTS COUNT
            creaturesBorn[crType].chadFarmAttempts += 1;
        } else {
            // Try farm DEGEN. So if there is no DEGENSs any more we must return assets
            if (creaturesBorn[crType].leftDegenToDiscover == 0) {
                _endFarming(_deployId, Result.Fail);
                return;
            }
            baseChance = 100 * creaturesBorn[crType].totalDegen / creaturesBorn[crType].totalChad; // by default 5%
            // Decrease appropriate farm ATTEMPTS COUNT
            creaturesBorn[crType].degenFarmAttempts += 1;
        }
        //////////////////////////////////////////////
        //   2. Bonus for common amulet token ***HOLD*** - commonAmuletHold
        //////////////////////////////////////////////
  
        // Get current hold stae
        for (uint8 i = 0; i < COMMON_AMULETS.length; i ++){
            if (f.commonAmuletInitialHold[i] &&  _getCommonAmuletsHoldState(msg.sender)[i]) {
                bonus.commonAmuletHold = BONUS_POINTS_AMULET_HOLD;
            }
        }
        //////////////////////////////////////////////
        //   3. Bonus for creatures amulets BULLs trend  - creatureAmuletBullTrend
        //   4. Bonus for creatures amulets balance      - creatureAmuletBalance
        //////////////////////////////////////////////
        uint256 prices2 = 0;
        prices2 = _getExistingAmuletsPrices(amulets[crType]);
        if (f.amuletsPrice1 > 0 && prices2 > 0 && prices2 > f.amuletsPrice1){
            bonus.creatureAmuletBullTrend =
                (prices2 - f.amuletsPrice1) * 100 / f.amuletsPrice1;
        }
        //Lets check max Balance, because
        //bonus.amuletHold = userAmuletBalance/maxAmuletBalances*BONUS_POINTS_AMULET_HOLD
        _checkAndSaveMaxAmuletPrice(amulets[crType]);
        if (maxAmuletBalances[amulets[crType]] > 0) {
            bonus.creatureAmuletBalance =
                IERC20(amulets[crType]).balanceOf(msg.sender) * 100 //100 used for scale
                / maxAmuletBalances[amulets[crType]] * BONUS_POINTS_AMULET_HOLD /100;
        }
        f.amuletsPrice2 = prices2;    

        ////////////////////////////////////////////// 
        //5. Bonus for inventory 
        //////////////////////////////////////////////
        bonus.inventoryHold = 0;
        if (userStakedTools[msg.sender].length > 0) { 
           for (uint8 i=0; i < userStakedTools[msg.sender].length; i++) {
               if (userStakedTools[msg.sender][i] > 0) {
                   bonus.inventoryHold = bonus.inventoryHold + IInventory(farm.inventory).getToolBoost(i);
               }
           }
        }  
        //////////////////////////////////////////////

        uint256 allBonus = bonus.commonAmuletHold 
            + bonus.creatureAmuletBullTrend 
            + bonus.creatureAmuletBalance
            + bonus.inventoryHold;

        if (allBonus > 100) {
            allBonus = 100; // limit bonus to 100%
        }

        uint32[] memory choiceWeight = new uint32[](2);
        choiceWeight[0] = uint32(baseChance * (100 + allBonus)); // chance of born new chad/degen
        choiceWeight[1] = uint32(10000 - choiceWeight[0]); // receive DUNG

        if (_getWeightedChoice(choiceWeight) == 0) {
            f.harvestId = (crRarity + 1) * NFT_ID_MULTIPLIER + _deployId;
            // Mint new chad/degen

            uint32 index;
            // Decrease appropriate CREATURE COUNT
            if (crRarity + 1 == uint8(Rarity.Chad)) {
                index = creaturesBorn[crType].totalChad - creaturesBorn[crType].leftChadToDiscover + 1;
                creaturesBorn[crType].leftChadToDiscover -= 1;
                farmingResult = Result.Chad;
            } else if (crRarity + 1 == uint8(Rarity.Degen)) {
                index = creaturesBorn[crType].totalDegen - creaturesBorn[crType].leftDegenToDiscover + 1;
                creaturesBorn[crType].leftDegenToDiscover -= 1;
                farmingResult = Result.Degen;
            }

            uint newCreatureId = (crRarity + 1) * NFT_ID_MULTIPLIER + _deployId;
            ICreatures(farm.creatures).mint(
                msg.sender,
                newCreatureId, // new iD
                crType, // AnimalType
                crRarity + 1,
                index // index
            );
            parents[newCreatureId] = f.creatureId;
        } else {
            // Mint new dung
            IDung(farm.dungtoken).mint(msg.sender, FARM_DUNG_AMOUNT);
            farmingResult = Result.Dung;
        }
        
        // BURN Land
        ILand(farm.land).burn(f.landId);
        _endFarming(_deployId, farmingResult);
        emit Harvest(
            _deployId, 
            msg.sender, 
            uint8(farmingResult),
            baseChance,
            bonus.commonAmuletHold,
            bonus.creatureAmuletBullTrend,
            bonus.inventoryHold,
            bonus.creatureAmuletBalance,
            choiceWeight[0]
        );
    }

    /**
     * @dev Stake one inventory item 
     * @param _itemId - NFT tokenId, caller must be owner of this token
     */
    function stakeOneTool(uint8 _itemId) external {
        _stakeOneTool(_itemId);
         emit Stake(msg.sender, _itemId);
    }

    /**
     * @dev UnStake one inventory item 
     * @param _itemId - NFT tokenId
     */
    function unstakeOneTool(uint8 _itemId) external {
        _unstakeOneTool(_itemId);
        emit UnStake(msg.sender, _itemId);
    }

    /////////////////////////////////////////////////////
    ////    Admin functions                       ///////
    /////////////////////////////////////////////////////
    function setOneCommonAmulet(uint8 _index, address _token) external onlyOwner {
        COMMON_AMULETS[_index] = _token;
    }

    function setAmuletForOneCreature(uint8 _index, address _token) external onlyOwner {
        amulets[_index] = _token;
    }

    function setAmulets(address[] calldata _tokens) external onlyOwner {
        for (uint i = 0; i < _tokens.length; i++) {
            amulets[i] = _tokens[i];
        }
    }

    function setPriceProvider(address _priceProvider) external onlyOwner {
        priceProvider = _priceProvider;
    }

    function enableReveal(bool _isEnabled) external onlyOwner {
        REVEAL_ENABLED = _isEnabled;
    }

    function enableFarming(bool _isEnabled) external onlyOwner {
        FARMING_ENABLED = _isEnabled;
    }

    ////////////////////////////////////////
    /// Proxy for NFT Operators mamnage   //
    ////////////////////////////////////////
    function addOperator(address _contract, address newOperator) external onlyOwner {
        IOperatorManage(_contract).addOperator(newOperator);
    }

    function removeOperator(address _contract, address oldOperator) external onlyOwner {
        IOperatorManage(_contract).removeOperator(oldOperator);
    }
 
    function reclaimToken(address _contract, IERC20 anyTokens, address _admin) external onlyOwner {
        IOperatorManage(_contract).withdrawERC20(anyTokens, _admin);
    }

    function setSigner(address _contract, address _newSigner) external onlyOwner {
        IOperatorManage(_contract).setSigner(_newSigner);
    }

    ////////////////////////////////////////////////////////

    function getCreatureAmulets(uint8 _creatureType) external view returns (address) {
        return _getCreatureAmulets(_creatureType);
    }

    function _getCreatureAmulets(uint8 _creatureType) internal view returns (address) {
        return amulets[_creatureType];
    } 

    function getCreatureStat(uint8 _creatureType) 
        external 
        view 
        returns (
            uint16, 
            uint16, 
            uint16, 
            uint16, 
            uint16, 
            uint16,
            uint16,
            uint16 
        )
    {
        CreaturesCount storage stat = creaturesBorn[_creatureType];
        return (
            stat.totalNormie, 
            stat.leftNormie, 
            stat.totalChad, 
            stat.leftChadToDiscover, 
            stat.totalDegen, 
            stat.leftDegenToDiscover,
            stat.chadFarmAttempts,
            stat.degenFarmAttempts
        );
    }

    function getWeightedChoice(uint32[] memory _weights) external view returns (uint8){
        return _getWeightedChoice(_weights);
    }

    function _getWeightedChoice(uint32[] memory _weights) internal view returns (uint8){
        uint randomSeed = uint(keccak256(abi.encodePacked(block.timestamp, msg.sender)));
        return _getWeightedChoice2(_weights, randomSeed);
    }

    function getFarmingById(uint256 _farmingId) external view returns (FarmRecord memory) {
        return farming[_farmingId];
    }

    function getOneAmuletPrice(address _token) external view returns (uint256) {
        return _getOneAmuletPrice(_token);
    }

    
    ///////////////////////////////////////////////
    ///  Internals                          ///////                   
    ///////////////////////////////////////////////
    /**
     * @dev Save farming results in storage and mint
     * appropriate token (NFT, ERC20 or None)
    */
    function _endFarming(uint256 _deployId, Result  _res) internal {
        FarmRecord storage f = farming[_deployId];
        f.harvest = _res;
        // unstake creature
        ICreatures(farm.creatures).transferFrom(address(this), msg.sender, f.creatureId);
        eggs.burn(_deployId); // Burn EGG

        if (_res ==  Result.Fail) {
            //unstake land (if staked)
            if (ILand(farm.land).ownerOf(f.landId) == address(this)){
               ILand(farm.land).transferFrom(address(this), msg.sender, f.landId);
            }
            emit Harvest(
                _deployId, 
                msg.sender, 
                uint8(_res),
                0, //baseChance
                0, //bonus.commonAmuletHold
                0, //bonus.creatureAmuletBullTrend,
                0, //bonus.inventoryHold 
                0,  // bonus.creatureAmuletBalance
                0
            );   
        }
    }

    function _stakeOneTool(uint8 _itemId) internal {
        require(IInventory(farm.inventory).balanceOf(msg.sender, _itemId) >= 1,
            "You must own this tool for stake!"
        );
        // Before stake  we need two checks.
        // 1. Removed
        // 2. Cant`t stake one tool more than one item
        require(userStakedTools[msg.sender][_itemId] == 0, "Tool is already staked");

        // stake
        IInventory(farm.inventory).safeTransferFrom(
            msg.sender, 
            address(this), 
            _itemId, 
            1, 
            bytes('0')
        );
        userStakedTools[msg.sender][_itemId] = block.timestamp;
    }

    function _unstakeOneTool(uint8 _itemId) internal {
        require(userStakedTools[msg.sender][_itemId] > 0, "This tool is not staked yet");
        require(block.timestamp - userStakedTools[msg.sender][_itemId] >= getToolUnstakeDelay(),
            "Cant unstake earlier than a week"
        );
        userStakedTools[msg.sender][_itemId] = 0;
        IInventory(farm.inventory).safeTransferFrom(
            address(this), 
            msg.sender, 
            _itemId, 
            1, 
            bytes('0')
        );

    }

    function _checkAndSaveMaxAmuletPrice(address _amulet) internal {
        if (IERC20(_amulet).balanceOf(msg.sender)
                > maxAmuletBalances[_amulet]
            ) 
            {
              maxAmuletBalances[_amulet] 
              = IERC20(_amulet).balanceOf(msg.sender);
            }
    }

    function _getCommonAmuletsHoldState(address _farmer) internal view returns (bool[COMMON_AMULET_COUNT] memory) {
        
        // If token balance =0 - set false
        bool[COMMON_AMULET_COUNT] memory res;
        for (uint8 i = 0; i < COMMON_AMULETS.length; i++){
            if (IERC20(COMMON_AMULETS[i]).balanceOf(_farmer) > 0){
                res[i] = true;    
            } else {
            // Set to zero if token balance is 0   
                res[i] = false;
            }
        }
        return res;
    }

    function _getExistingAmuletsPrices(address _token) 
        internal 
        view 
        returns (uint256) 
    {
        if (IERC20(_token).balanceOf(msg.sender) > 0){
            return _getOneAmuletPrice(_token);    
        } else {
        // Set to zero if token balance is 0   
            return 0;
        }    
    }

    function _getOneAmuletPrice(address _token) internal view returns (uint256) {
        return IAmuletPriceProvider(priceProvider).getLastPrice(_token);
    }

    function _isRevelEnabled() internal view returns (bool) {
        return REVEAL_ENABLED;
    }

    function _reveal(uint randomSeed) internal {
        require ((landCount.left + allNormiesesLeft) > 0, "Sorry, no more reveal!");
        //1. Lets choose Land OR Creature, %
        //So we have two possible results. 1 - Land, 0 - Creature.
        // sum of weights = 100, lets define weigth for Creature
        uint32[] memory choiceWeight = new uint32[](2);
        choiceWeight[0] = uint32(allNormiesesLeft) * CREATURE_P_MULT;
        choiceWeight[1] = uint32(landCount.left) * 100;
        uint8 choice = uint8(_getWeightedChoice2(choiceWeight, randomSeed));
        randomSeed /= 0x10000; // shift right 16 bits
        //Check that choice can be executed
        if (choice != 0 && landCount.left == 0) {
            //There are no more Lands. So we need change choice
            choice = 0;
        }

        if (choice == 0) { // create creature
            uint32[] memory choiceWeight0 = new uint32[](getCreatureTypeCount());
            //2. Ok, Creature will  be born. But what kind of?
            for (uint8 i = 0; i < getCreatureTypeCount(); i ++) {
                choiceWeight0[i] = uint32(creaturesBorn[i].leftNormie);
            }
            choice = uint8(_getWeightedChoice2(choiceWeight0, randomSeed));
            ICreatures(farm.creatures).mint(
                msg.sender, 
                MAX_ALL_NORMIES - allNormiesesLeft,
                choice, //AnimalType
                0,
                creaturesBorn[choice].totalNormie - creaturesBorn[choice].leftNormie + 1 // index
            );
            emit Reveal(msg.sender, MAX_ALL_NORMIES - allNormiesesLeft, true, choice);
            allNormiesesLeft -= 1;
            creaturesBorn[choice].leftNormie -= 1;
        } else { // create land
            ILand(farm.land).mint(
                msg.sender, 
                getMaxLands() - landCount.left,
                randomSeed
            );
            emit Reveal(msg.sender, getMaxLands() - landCount.left , false, 0);
            landCount.left -= 1; 
        }
    }

    function _getWeightedChoice2(uint32[] memory _weights, uint randomSeed) internal view returns (uint8){
        uint256 sum_of_weights = 0;
        for (uint8 index = 0; index < _weights.length; index++) {
            sum_of_weights += _weights[index];
        }
        uint256 rnd = randomSeed % sum_of_weights;
        for (uint8 kindex = 0; kindex < _weights.length; kindex++) {
            if (rnd < _weights[kindex]) {
                return kindex;
            }
            rnd -= _weights[kindex];
        }
        return 0;
    }

    /**
        @dev Handles the receipt of a single ERC1155 token type. This function is
        called at the end of a `safeTransferFrom` after the balance has been updated.
        To accept the transfer, this must return
        `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
        (i.e. 0xf23a6e61, or its own function selector).
        @param operator The address which initiated the transfer (i.e. msg.sender)
        @param from The address which previously owned the token
        @param id The ID of the token being transferred
        @param value The amount of tokens being transferred
        @param data Additional data with no specified format
        @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
    */
    function onERC1155Received(
        address operator,
        address from,
        uint256 id,
        uint256 value,
        bytes calldata data
    )
        external
        override
        returns(bytes4)
    {
        return bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"));  
    }    

    /**
        @dev Handles the receipt of a multiple ERC1155 token types. This function
        is called at the end of a `safeBatchTransferFrom` after the balances have
        been updated. To accept the transfer(s), this must return
        `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
        (i.e. 0xbc197c81, or its own function selector).
        @param operator The address which initiated the batch transfer (i.e. msg.sender)
        @param from The address which previously owned the token
        @param ids An array containing ids of each token being transferred (order and length must match values array)
        @param values An array containing amounts of each token being transferred (order and length must match ids array)
        @param data Additional data with no specified format
        @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
    */
    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    )
        external
        override
        returns(bytes4)
    {
        return bytes4(keccak256("onERC1155BatchReceived(address,address,uint256,uint256,bytes)"));  
    }

    function getCreatureTypeCount() virtual internal view returns (uint16);

    function getFarmingDuration() virtual internal view returns (uint);

    function getToolUnstakeDelay() virtual internal view returns (uint);

    function getNormieCountInType() virtual internal view returns (uint16);

    function getChadCountInType() virtual internal view returns (uint16);

    function getMaxLands() virtual internal view returns (uint16);

    function getUsersTokens(address _owner) external view returns (uint256[] memory) {
        return eggs.getUsersTokens(_owner);
    }

    /**
     * @dev Returns creatures owned by owner and that can be used for farming.this
     * Some creatures types and rarity are limited to farm because all chad/degens
     * was already discovered.
     * @param _owner - creatures owner
     */
    function getFarmingAllowedCreatures(address _owner) external view returns (uint256[] memory) {
        uint256 n = ICreatures(farm.creatures).balanceOf(_owner);

        uint256[] memory result = new uint256[](n);
        uint256 count = 0;

        for (uint16 i = 0; i < n; i++) {
            uint creatureId = ICreatures(farm.creatures).tokenOfOwnerByIndex(_owner, i);
            if (isFarmingAllowedForCreature(creatureId)) {
                result[count] = creatureId;
                count++;
            }
        }
        uint256[] memory result2 = new uint256[](count);
        for (uint16 i = 0; i < count; i++) {
            result2[i] = result[i];
        }
        return result2;
    }

    function getFarmingAllowedCreaturesWithRarity(address _owner, uint8 wantRarity) external view returns (uint256[] memory) {
        uint256 n = ICreatures(farm.creatures).balanceOf(_owner);

        uint256[] memory result = new uint256[](n);
        uint256 count = 0;

        for (uint16 i = 0; i < n; i++) {
            uint creatureId = ICreatures(farm.creatures).tokenOfOwnerByIndex(_owner, i);
            (uint8 _, uint8 rarity) = ICreatures(farm.creatures).getTypeAndRarity(creatureId);
            if (rarity == wantRarity && isFarmingAllowedForCreature(creatureId)) {
                result[count] = creatureId;
                count++;
            }
        }
        uint256[] memory result2 = new uint256[](count);
        for (uint16 i = 0; i < count; i++) {
            result2[i] = result[i];
        }
        return result2;
    }

    function isFarmingAllowedForCreature(uint creatureId) public view returns (bool) {
        (uint8 _type, uint8 rarity) = ICreatures(farm.creatures).getTypeAndRarity(creatureId);

        if ((DegenFarmBase.Rarity)(rarity) == Rarity.Normie) {
            return creaturesBorn[_type].leftChadToDiscover > 0;
        }
        if ((DegenFarmBase.Rarity)(rarity) == Rarity.Chad) {
            return creaturesBorn[_type].leftDegenToDiscover > 0;
        }
        return false;
    }
}
合同源代码
文件 4 的 11:ERC1155Receiver.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "./IERC1155Receiver.sol";
import "./ERC165.sol";

/**
 * @dev _Available since v3.1._
 */
abstract contract ERC1155Receiver is ERC165, IERC1155Receiver {
    constructor() internal {
        _registerInterface(
            ERC1155Receiver(address(0)).onERC1155Received.selector ^
            ERC1155Receiver(address(0)).onERC1155BatchReceived.selector
        );
    }
}
合同源代码
文件 5 的 11:ERC165.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts may inherit from this and call {_registerInterface} to declare
 * their support of an interface.
 */
abstract contract ERC165 is IERC165 {
    /*
     * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
     */
    bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;

    /**
     * @dev Mapping of interface ids to whether or not it's supported.
     */
    mapping(bytes4 => bool) private _supportedInterfaces;

    constructor () internal {
        // Derived contracts need only register support for their own interfaces,
        // we register support for ERC165 itself here
        _registerInterface(_INTERFACE_ID_ERC165);
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     *
     * Time complexity O(1), guaranteed to always use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return _supportedInterfaces[interfaceId];
    }

    /**
     * @dev Registers the contract as an implementer of the interface defined by
     * `interfaceId`. Support of the actual ERC165 interface is automatic and
     * registering its interface id is not required.
     *
     * See {IERC165-supportsInterface}.
     *
     * Requirements:
     *
     * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).
     */
    function _registerInterface(bytes4 interfaceId) internal virtual {
        require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
        _supportedInterfaces[interfaceId] = true;
    }
}
合同源代码
文件 6 的 11:IERC1155.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

import "./IERC165.sol";

/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 *
 * _Available since v3.1._
 */
interface IERC1155 is IERC165 {
    /**
     * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    /**
     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
     * transfers.
     */
    event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values);

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /**
     * @dev Returns the amount of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data) external;
}
合同源代码
文件 7 的 11:IERC1155Receiver.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "./IERC165.sol";

/**
 * _Available since v3.1._
 */
interface IERC1155Receiver is IERC165 {

    /**
        @dev Handles the receipt of a single ERC1155 token type. This function is
        called at the end of a `safeTransferFrom` after the balance has been updated.
        To accept the transfer, this must return
        `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
        (i.e. 0xf23a6e61, or its own function selector).
        @param operator The address which initiated the transfer (i.e. msg.sender)
        @param from The address which previously owned the token
        @param id The ID of the token being transferred
        @param value The amount of tokens being transferred
        @param data Additional data with no specified format
        @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
    */
    function onERC1155Received(
        address operator,
        address from,
        uint256 id,
        uint256 value,
        bytes calldata data
    )
        external
        returns(bytes4);

    /**
        @dev Handles the receipt of a multiple ERC1155 token types. This function
        is called at the end of a `safeBatchTransferFrom` after the balances have
        been updated. To accept the transfer(s), this must return
        `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
        (i.e. 0xbc197c81, or its own function selector).
        @param operator The address which initiated the batch transfer (i.e. msg.sender)
        @param from The address which previously owned the token
        @param ids An array containing ids of each token being transferred (order and length must match values array)
        @param values An array containing amounts of each token being transferred (order and length must match ids array)
        @param data Additional data with no specified format
        @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
    */
    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    )
        external
        returns(bytes4);
}
合同源代码
文件 8 的 11:IERC165.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
合同源代码
文件 9 的 11:IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <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);
}
合同源代码
文件 10 的 11:IERC721.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

import "./IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);

    /**
      * @dev Safely transfers `tokenId` token from `from` to `to`.
      *
      * Requirements:
      *
      * - `from` cannot be the zero address.
      * - `to` cannot be the zero address.
      * - `tokenId` token must exist and be owned by `from`.
      * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
      * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
      *
      * Emits a {Transfer} event.
      */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
}
合同源代码
文件 11 的 11:Ownable.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

import "./Context.sol";
/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () internal {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}
设置
{
  "compilationTarget": {
    "DegensFarm.sol": "DegenFarm"
  },
  "evmVersion": "istanbul",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "remappings": []
}
ABI
[{"inputs":[{"internalType":"address","name":"_land","type":"address"},{"internalType":"address","name":"_creatures","type":"address"},{"internalType":"address","name":"_inventory","type":"address"},{"internalType":"address","name":"_bagstoken","type":"address"},{"internalType":"address","name":"_dungtoken","type":"address"},{"internalType":"contract IEggs","name":"_eggs","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_eggId","type":"uint256"},{"indexed":false,"internalType":"address","name":"farmer","type":"address"},{"indexed":false,"internalType":"uint8","name":"result","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"baseChance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"commonAmuletHold","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amuletBullTrend","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"inventoryHold","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amuletMaxBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"resultChance","type":"uint256"}],"name":"Harvest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_farmer","type":"address"},{"indexed":true,"internalType":"uint256","name":"_tokenId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"_isCreature","type":"bool"},{"indexed":false,"internalType":"uint8","name":"_animalType","type":"uint8"}],"name":"Reveal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint8","name":"innventory","type":"uint8"}],"name":"Stake","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint8","name":"innventory","type":"uint8"}],"name":"UnStake","type":"event"},{"inputs":[],"name":"BONUS_POINTS_AMULET_HOLD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CHAD_COUNT_IN_TYPE","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"COMMON_AMULETS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"COMMON_AMULET_COUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CREATURE_P_MULT","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CREATURE_TYPE_COUNT","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CREATURE_TYPE_COUNT_MAX","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FARMING_DURATION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FARMING_ENABLED","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FARM_DUNG_AMOUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_ALL_NORMIES","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_LANDS","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NFT_ID_MULTIPLIER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NORMIE_COUNT_IN_TYPE","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REVEAL_ENABLED","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOOL_TYPE_COUNT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOOL_UNSTAKE_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_contract","type":"address"},{"internalType":"address","name":"newOperator","type":"address"}],"name":"addOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"allNormiesesLeft","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"amulets","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"creaturesBorn","outputs":[{"internalType":"uint16","name":"totalNormie","type":"uint16"},{"internalType":"uint16","name":"leftNormie","type":"uint16"},{"internalType":"uint16","name":"totalChad","type":"uint16"},{"internalType":"uint16","name":"leftChadToDiscover","type":"uint16"},{"internalType":"uint16","name":"totalDegen","type":"uint16"},{"internalType":"uint16","name":"leftDegenToDiscover","type":"uint16"},{"internalType":"uint16","name":"chadFarmAttempts","type":"uint16"},{"internalType":"uint16","name":"degenFarmAttempts","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eggs","outputs":[{"internalType":"contract IEggs","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_isEnabled","type":"bool"}],"name":"enableFarming","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isEnabled","type":"bool"}],"name":"enableReveal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"farm","outputs":[{"internalType":"address","name":"land","type":"address"},{"internalType":"address","name":"creatures","type":"address"},{"internalType":"address","name":"inventory","type":"address"},{"internalType":"address","name":"bagstoken","type":"address"},{"internalType":"address","name":"dungtoken","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_creatureId","type":"uint256"},{"internalType":"uint256","name":"_landId","type":"uint256"}],"name":"farmDeploy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"farming","outputs":[{"internalType":"uint256","name":"creatureId","type":"uint256"},{"internalType":"uint256","name":"landId","type":"uint256"},{"internalType":"uint256","name":"harvestTime","type":"uint256"},{"internalType":"uint256","name":"amuletsPrice1","type":"uint256"},{"internalType":"uint256","name":"amuletsPrice2","type":"uint256"},{"internalType":"enum DegenFarmBase.Result","name":"harvest","type":"uint8"},{"internalType":"uint256","name":"harvestId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"_creatureType","type":"uint8"}],"name":"getCreatureAmulets","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"_creatureType","type":"uint8"}],"name":"getCreatureStat","outputs":[{"internalType":"uint16","name":"","type":"uint16"},{"internalType":"uint16","name":"","type":"uint16"},{"internalType":"uint16","name":"","type":"uint16"},{"internalType":"uint16","name":"","type":"uint16"},{"internalType":"uint16","name":"","type":"uint16"},{"internalType":"uint16","name":"","type":"uint16"},{"internalType":"uint16","name":"","type":"uint16"},{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getFarmingAllowedCreatures","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"uint8","name":"wantRarity","type":"uint8"}],"name":"getFarmingAllowedCreaturesWithRarity","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_farmingId","type":"uint256"}],"name":"getFarmingById","outputs":[{"components":[{"internalType":"uint256","name":"creatureId","type":"uint256"},{"internalType":"uint256","name":"landId","type":"uint256"},{"internalType":"uint256","name":"harvestTime","type":"uint256"},{"internalType":"uint256","name":"amuletsPrice1","type":"uint256"},{"internalType":"uint256","name":"amuletsPrice2","type":"uint256"},{"internalType":"enum DegenFarmBase.Result","name":"harvest","type":"uint8"},{"internalType":"uint256","name":"harvestId","type":"uint256"},{"internalType":"bool[2]","name":"commonAmuletInitialHold","type":"bool[2]"}],"internalType":"struct DegenFarmBase.FarmRecord","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getOneAmuletPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"getUsersTokens","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32[]","name":"_weights","type":"uint32[]"}],"name":"getWeightedChoice","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_deployId","type":"uint256"}],"name":"harvest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"creatureId","type":"uint256"}],"name":"isFarmingAllowedForCreature","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"landCount","outputs":[{"internalType":"uint16","name":"total","type":"uint16"},{"internalType":"uint16","name":"left","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxAmuletBalances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"parents","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceProvider","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_contract","type":"address"},{"internalType":"contract IERC20","name":"anyTokens","type":"address"},{"internalType":"address","name":"_admin","type":"address"}],"name":"reclaimToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_contract","type":"address"},{"internalType":"address","name":"oldOperator","type":"address"}],"name":"removeOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"count","type":"uint256"}],"name":"reveal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_index","type":"uint8"},{"internalType":"address","name":"_token","type":"address"}],"name":"setAmuletForOneCreature","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_tokens","type":"address[]"}],"name":"setAmulets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_index","type":"uint8"},{"internalType":"address","name":"_token","type":"address"}],"name":"setOneCommonAmulet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_priceProvider","type":"address"}],"name":"setPriceProvider","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_contract","type":"address"},{"internalType":"address","name":"_newSigner","type":"address"}],"name":"setSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_itemId","type":"uint8"}],"name":"stakeOneTool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_itemId","type":"uint8"}],"name":"unstakeOneTool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userStakedTools","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]