BaseBase
0x7d...d15f
Fungi

Fungi

FUNGI

Token
Capitalización de Mercado
$1.00
 
Precio
2%
¡El código fuente de este contrato está verificado!
Metadatos del Contrato
Compilador
0.8.25+commit.b61c2a91
Idioma
Solidity
Código Fuente del Contrato
Archivo 1 de 9: Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @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 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) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}
Código Fuente del Contrato
Archivo 2 de 9: Erc20.sol
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "@openzeppelin/contracts/utils/Context.sol";

contract ERC20 is Context, IERC20, IERC20Metadata {
    mapping(address => uint256) internal _balances;

    mapping(address => mapping(address => uint256)) private _allowances;

    uint256 internal _totalSupply;
    uint8 internal constant _decimals = 9;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the default value returned by this function, unless
     * it's overridden.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public pure returns (uint8) {
        return _decimals;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(
        address account
    ) public view virtual override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(
        address owner,
        address spender
    ) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(
        address spender,
        uint256 amount
    ) public virtual override returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `amount`.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, amount);
        _transfer(from, to, amount);
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(
        address spender,
        uint256 addedValue
    ) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, allowance(owner, spender) + addedValue);
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(
        address spender,
        uint256 subtractedValue
    ) public virtual returns (bool) {
        address owner = _msgSender();
        uint256 currentAllowance = allowance(owner, spender);
        require(
            currentAllowance >= subtractedValue,
            "ERC20: decreased allowance below zero"
        );
        unchecked {
            _approve(owner, spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    /**
     * @dev Moves `amount` of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     */
    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {
        require(from != address(0), "ERC20: transfer from the zero address");

        uint256 fromBalance = _balances[from];
        require(
            fromBalance >= amount,
            "ERC20: transfer amount exceeds balance"
        );
        unchecked {
            _balances[from] = fromBalance - amount;
            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
            // decrementing then incrementing.
            _balances[to] += amount;
        }

        emit Transfer(from, to, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _totalSupply += amount;
        unchecked {
            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
            _balances[account] += amount;
        }
        emit Transfer(address(0), account, amount);
    }

    /**
     * @dev Erases `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
            // Overflow not possible: amount <= accountBalance <= totalSupply.
            _totalSupply -= amount;
        }

        emit Transfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
     *
     * Does not update the allowance amount in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Might emit an {Approval} event.
     */
    function _spendAllowance(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            require(
                currentAllowance >= amount,
                "ERC20: insufficient allowance"
            );
            unchecked {
                _approve(owner, spender, currentAllowance - amount);
            }
        }
    }
}
Código Fuente del Contrato
Archivo 3 de 9: Fungi.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "./Erc20.sol";
import "./PoolCreatableErc20i.sol";
import "../Generator.sol";

library ExtraSeedLibrary {
    function extra(address account) internal pure returns (uint256) {
        return uint(keccak256(abi.encode(account)));
    }

    function seed_data(
        address account,
        uint seed
    ) internal pure returns (SeedData memory) {
        return SeedData(seed, extra(account));
    }
}

abstract contract Mushrooms is PoolCreatableErc20i {
    using ExtraSeedLibrary for address;
    mapping(address owner => uint) _counts;
    mapping(address owner => mapping(uint index => SeedData seed_data)) _ownedTokens;
    mapping(address owner => mapping(uint tokenId => uint)) _ownedTokensIndex;
    mapping(address owner => mapping(uint => bool)) _owns;
    mapping(address owner => SeedData seed_data) _spores;
    mapping(uint index => address user) _holderList;
    mapping(address user => uint index) _holderListIndexes;
    uint _mushroomsTotalCount;
    uint _holdersCount;
    uint _sporesTotalCount;

    event OnMushroomTransfer(
        address indexed from,
        address indexed to,
        SeedData seed_data
    );
    event OnSporesGrow(address indexed holder, SeedData seed_data);
    event OnSporesShrink(address indexed holder, SeedData seed_data);

    constructor() PoolCreatableErc20i("Fungi", "FUNGI", msg.sender) {}

    modifier holder_calculate(address acc1, address acc2) {
        bool before1 = _isHolder(acc1);
        bool before2 = _isHolder(acc2);
        _;
        bool after1 = _isHolder(acc1);
        bool after2 = _isHolder(acc2);
        if (!before1 && after1) _addHolder(acc1);
        if (before1 && !after1) _removeHolder(acc1);
        if (!before2 && after2) _addHolder(acc2);
        if (before2 && !after2) _removeHolder(acc2);
    }

    function _isHolder(address account) private view returns (bool) {
        if (
            account == address(this) ||
            account == _pool ||
            account == address(0)
        ) return false;

        return (_spores[account].seed + this.mushroomCount(account)) > 0;
    }

    function trySeedTransfer(
        address from,
        address to,
        uint amount
    ) internal holder_calculate(from, to) {
        if (from == address(this)) return;
        uint seed = amount / (10 ** decimals());

        if (seed > 0 && from != _pool && to != _pool) {
            // transfer growing mushroom
            if (_spores[from].seed == seed) {
                SeedData memory data = _spores[from];
                _removeSeedCount(from, seed);
                _addTokenToOwnerEnumeration(to, data);
                emit OnMushroomTransfer(from, to, data);
                return;
            }

            // transfer collected mushroom
            if (_owns[from][seed] && !_owns[to][seed]) {
                SeedData memory data = _ownedTokens[from][
                    _ownedTokensIndex[from][seed]
                ];
                _removeTokenFromOwnerEnumeration(from, seed);
                _addTokenToOwnerEnumeration(to, data);
                emit OnMushroomTransfer(from, to, data);
                return;
            }
        }

        // transfer spores
        uint lastBalanceFromSeed = _balances[from] / (10 ** decimals());
        uint newBalanceFromSeed = (_balances[from] - amount) /
            (10 ** decimals());
        _removeSeedCount(from, lastBalanceFromSeed - newBalanceFromSeed);
        _addSeedCount(to, seed);
    }

    function _addHolder(address account) private {
        _holderList[_holdersCount] = account;
        _holderListIndexes[account] = _holdersCount;
        ++_holdersCount;
    }

    function _removeHolder(address account) private {
        if (_holdersCount == 0) return;
        --_holdersCount;
        uint removingIndex = _holderListIndexes[account];
        _holderList[removingIndex] = _holderList[_holdersCount];
        delete _holderList[_holdersCount];
        delete _holderListIndexes[account];
    }

    function getHolderByIndex(uint index) public view returns (address) {
        return _holderList[index];
    }

    function getHoldersList(
        uint startIndex,
        uint count
    ) public view returns (address[] memory) {
        address[] memory holders = new address[](count);
        for (uint i = 0; i < count; ++i)
            holders[i] = getHolderByIndex(startIndex + i);
        return holders;
    }

    function _addSeedCount(address account, uint seed) private {
        if (seed == 0) return;
        if (account == _pool) return;
        SeedData memory last = _spores[account];

        _spores[account].seed += seed;
        _spores[account].extra = account.extra();

        if (last.seed == 0 && _spores[account].seed > 0) ++_sporesTotalCount;

        emit OnSporesGrow(account, _spores[account]);
    }

    function _removeSeedCount(address account, uint seed) private {
        if (seed == 0) return;
        if (account == _pool) return;
        SeedData memory lastSpores = _spores[account];
        if (_spores[account].seed >= seed) {
            _spores[account].seed -= seed;
            if (lastSpores.seed > 0 && _spores[account].seed == 0)
                --_sporesTotalCount;
            emit OnSporesShrink(account, _spores[account]);
            return;
        }
        uint seedRemains = seed - _spores[account].seed;
        _spores[account].seed = 0;

        // remove mushrooms
        uint count = _counts[account];
        uint removed;
        for (uint i = 0; i < count && removed < seedRemains; ++i) {
            removed += _removeFirstTokenFromOwner(account);
        }

        if (removed > seedRemains)
            _spores[account].seed += removed - seedRemains;
        if (lastSpores.seed > 0 && _spores[account].seed == 0)
            --_sporesTotalCount;
        emit OnSporesShrink(account, _spores[account]);
    }

    function _addTokenToOwnerEnumeration(
        address to,
        SeedData memory data
    ) private {
        if (to == _pool) return;
        ++_counts[to];
        ++_mushroomsTotalCount;
        uint length = _counts[to] - 1;
        _ownedTokens[to][length] = data;
        _ownedTokensIndex[to][data.seed] = length;
        _owns[to][data.seed] = true;
    }

    function _removeTokenFromOwnerEnumeration(address from, uint seed) private {
        if (from == _pool) return;
        --_counts[from];
        --_mushroomsTotalCount;
        _owns[from][seed] = false;
        uint lastTokenIndex = _counts[from];
        uint tokenIndex = _ownedTokensIndex[from][seed];
        SeedData memory data = _ownedTokens[from][tokenIndex];

        // When the token to delete is the last token, the swap operation is unnecessary
        if (tokenIndex != lastTokenIndex) {
            SeedData memory lastTokenId = _ownedTokens[from][lastTokenIndex];

            _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
            _ownedTokensIndex[from][lastTokenId.seed] = tokenIndex; // Update the moved token's index
        }

        delete _ownedTokensIndex[from][data.seed];
        delete _ownedTokens[from][lastTokenIndex];
    }

    function _removeFirstTokenFromOwner(address owner) private returns (uint) {
        uint count = _counts[owner];
        if (count == 0) return 0;
        uint seed = _ownedTokens[owner][0].seed;
        _removeTokenFromOwnerEnumeration(owner, seed);
        return seed;
    }

    function isOwnerOf(address owner, uint seed) external view returns (bool) {
        return _owns[owner][seed];
    }

    function sporesDegree(
        address owner
    ) external view returns (SeedData memory data) {
        return _spores[owner];
    }

    function mushroomCount(address owner) external view returns (uint) {
        return _counts[owner];
    }

    function mushroomOfOwnerByIndex(
        address owner,
        uint index
    ) external view returns (SeedData memory data) {
        return _ownedTokens[owner][index];
    }

    function mushroomsTotalCount() external view returns (uint) {
        return _mushroomsTotalCount;
    }

    function holdersCount() external view returns (uint) {
        return _holdersCount;
    }

    function sporesTotalCount() external view returns (uint) {
        return _sporesTotalCount;
    }
}

contract Fungi is Mushrooms, Generator, ReentrancyGuard {
    uint constant _startTotalSupply = 210e6 * (10 ** _decimals);
    uint constant _startMaxBuyCount = (_startTotalSupply * 5) / 10000;
    uint constant _addMaxBuyPercentPerSec = 5; // 100%=_addMaxBuyPrecesion add 0.005%/second
    uint constant _addMaxBuyPrecesion = 100000;

    constructor() {
        _mint(msg.sender, _startTotalSupply);
    }

    modifier maxBuyLimit(uint256 amount) {
        require(amount <= maxBuy(), "max buy limit");
        _;
    }

    function maxBuy() public view returns (uint256) {
        if (!isStarted()) return _startTotalSupply;
        uint256 count = _startMaxBuyCount +
            (_startTotalSupply *
                (block.timestamp - _startTime) *
                _addMaxBuyPercentPerSec) /
            _addMaxBuyPrecesion;
        if (count > _startTotalSupply) count = _startTotalSupply;
        return count;
    }

    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal override {
        if (isStarted()) {
            trySeedTransfer(from, to, amount);
        } else {
            require(from == _owner || to == _owner, "not started");
        }

        // allow burning
        if (to == address(0)) {
            _burn(from, amount);
            return;
        }

        // system transfers
        if (from == address(this)) {
            super._transfer(from, to, amount);
            return;
        }

        if (_feeLocked) {
            super._transfer(from, to, amount);
            return;
        } else {
            if (from == _pool) {
                buy(to, amount);
                return;
            }
        }

        super._transfer(from, to, amount);
    }

    function buy(
        address to,
        uint256 amount
    ) private maxBuyLimit(amount) lockFee {
        super._transfer(_pool, to, amount);
    }

    function burnCount() public view returns (uint256) {
        return _startTotalSupply - totalSupply();
    }
}
Código Fuente del Contrato
Archivo 4 de 9: Generator.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "./lib/Ownable.sol";

uint constant levelsCount = 5;
uint constant bcgroundsCount = 6;
uint constant groundsCount = 2;
uint8 constant pixelsCount = 24;
uint constant seedLevel1 = 21000;
uint constant seedLevel2 = 525000;
uint constant seedLevel3 = 1050000;
uint constant seedLevel4 = 1575000;
uint constant seedLevel5 = 2100000;

struct MushroomData {
    uint lvl;
    string background;
    uint ground;
    string groundColor;
    uint stem;
    string stemColor;
    uint cap;
    string capColor;
    bool hasDots;
    string dotsColor;
}

struct Rect {
    uint8 x;
    uint8 y;
    uint8 width;
    uint8 height;
}

struct FileData {
    uint lvl;
    uint file;
    Rect[] rects;
}

struct ColorsData {
    string[] lvl0;
    string[] lvl1;
    string[] lvl2;
    string[] lvl3;
    string[] lvl4;
}

struct SeedData {
    uint seed;
    uint extra;
}

struct Rand {
    uint seed;
    uint nonce;
    uint extra;
}

library RandLib {
    function next(Rand memory rnd) internal pure returns (uint) {
        return
            uint(
                keccak256(
                    abi.encodePacked(rnd.seed + rnd.nonce++ - 1, rnd.extra)
                )
            );
    }

    function lvl(Rand memory rnd) internal pure returns (uint) {
        if (rnd.seed < seedLevel1) return 0;
        if (rnd.seed < seedLevel2) return 1;
        if (rnd.seed < seedLevel3) return 2;
        if (rnd.seed < seedLevel4) return 3;
        if (rnd.seed < seedLevel5) return 4;
        return 5;
    }

    function random(
        string[] memory data,
        Rand memory rnd
    ) internal pure returns (string memory) {
        return data[randomIndex(data, rnd)];
    }

    function randomIndex(
        string[] memory data,
        Rand memory rnd
    ) internal pure returns (uint) {
        return next(rnd) % data.length;
    }
}

library LayersLib {
    function setLayers(
        mapping(uint => mapping(uint => Rect[])) storage rects,
        FileData[] calldata data
    ) internal {
        for (uint i = 0; i < data.length; ++i) {
            setFile(rects, data[i]);
        }
    }

    function setFile(
        mapping(uint => mapping(uint => Rect[])) storage rects,
        FileData calldata input
    ) internal {
        Rect[] storage storageFile = rects[input.lvl][input.file];
        for (uint i = 0; i < input.rects.length; ++i) {
            storageFile.push(input.rects[i]);
        }
    }

    function getLvl(
        mapping(uint => mapping(uint => Rect[])) storage rects,
        uint lvl
    ) internal view returns (mapping(uint => Rect[]) storage) {
        return rects[lvl];
    }

    function to_lvl_1(uint l) internal pure returns (uint) {
        if (l > 0) --l;
        return l;
    }
}

library Converter {
    function toString(uint value) internal pure returns (string memory) {
        if (value == 0) {
            return "0";
        }
        uint temp = value;
        uint digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }
}

library RectLib {
    using RectLib for Rect;
    using RandLib for Rand;
    using RandLib for string[];
    using Converter for uint8;

    function toSvg(
        Rect memory r,
        string memory color
    ) internal pure returns (string memory) {
        return
            string(
                abi.encodePacked(
                    "<rect x='",
                    r.x.toString(),
                    "' y='",
                    r.y.toString(),
                    "' width='",
                    r.width.toString(),
                    "' height='",
                    r.height.toString(),
                    "' fill='",
                    color,
                    "'/>"
                )
            );
    }

    function toSvg(
        Rect[] storage rects,
        string[] storage colors,
        Rand memory rnd
    ) internal view returns (string memory) {
        string memory res;
        for (uint i = 0; i < rects.length; ++i) {
            res = string(
                abi.encodePacked(res, rects[i].toSvg(colors.random(rnd)))
            );
        }
        return res;
    }

    function toSvg(
        Rect[] storage rects,
        string memory color
    ) internal view returns (string memory) {
        string memory res;
        for (uint i = 0; i < rects.length; ++i) {
            res = string(abi.encodePacked(res, rects[i].toSvg(color)));
        }
        return res;
    }
}

contract Generator is Ownable {
    using LayersLib for mapping(uint => mapping(uint => Rect[]));
    using LayersLib for mapping(uint => string[]);
    using LayersLib for uint;
    using RectLib for Rect;
    using RectLib for Rect[];
    using RandLib for Rand;
    using RandLib for string[];
    using Converter for uint;

    uint8 spores_count = 7;
    uint8[levelsCount] stemLevelCounts = [5, 5, 5, 6, 10];
    uint8[levelsCount] capLevelCounts = [5, 7, 10, 10, 10];
    uint8[levelsCount] dotLevelCounts = [5, 7, 10, 10, 10];

    mapping(uint => Rect[]) spores;
    mapping(uint => mapping(uint => Rect[])) stems;
    mapping(uint => mapping(uint => Rect[])) caps;
    mapping(uint => mapping(uint => Rect[])) dots;
    mapping(uint => Rect[]) grounds;

    string[] private backgroundColors0 = [
        "#000000",
        "#493114",
        "#1d772f",
        "#38166a",
        "#db4161",
        "#7c288a",
        "#4141ff",
        "#ff61b2",
        "#8f3bc2",
        "#a2a2a2",
        "#bfca87",
        "#92dcba",
        "#a2fff3",
        "#fddad5"
    ];

    string[] private backgroundColors1 = [
        "#453879",
        "#184b5b",
        "#447f60",
        "#e35100",
        "#ff7930",
        "#e43b44",
        "#eedc59",
        "#f279ca",
        "#4deae9",
        "#ffdba2",
        "#a2baff",
        "#ca90ff"
    ];

    string[] private backgroundColors2 = [
        "#231b32",
        "#3f1164",
        "#28426a",
        "#9a2079",
        "#d45e4e",
        "#79dfac",
        "#1fabe0",
        "#e8a2bf",
        "#849be4",
        "#e3b2ff"
    ];

    string[] private backgroundColors3 = [
        "#291970",
        "#413c5d",
        "#a44c4c",
        "#f8972a",
        "#a271ff",
        "#4192c3",
        "#5182ff",
        "#ffb2a7"
    ];

    string[] private backgroundColors4 = [
        "#0f0c45",
        "#560e43",
        "#b21030",
        "#ff6e69",
        "#534fed",
        "#7cb8ff"
    ];

    string[] private groundColors0 = [
        "#000000",
        "#1d730e",
        "#525050",
        "#b21030",
        "#ff7930",
        "#925f4f",
        "#db4161",
        "#9aeb00",
        "#d8cc33",
        "#2800ba",
        "#f361ff",
        "#4192c3",
        "#d0c598",
        "#f4c09a",
        "#e3b2ff"
    ];

    string[] private groundColors1 = [
        "#020104",
        "#493114",
        "#74254d",
        "#453879",
        "#306141",
        "#83376e",
        "#e59220",
        "#7377a0",
        "#30b7c0",
        "#86b4bb",
        "#ffa9a9",
        "#f7e2c5"
    ];

    string[] private groundColors2 = [
        "#495900",
        "#395844",
        "#d47642",
        "#719767",
        "#8a8a00",
        "#806a9c",
        "#a2a2a2",
        "#86d48e",
        "#c3e88d",
        "#c3b2ff"
    ];

    string[] private groundColors3 = [
        "#253d2d",
        "#515130",
        "#384f7a",
        "#49a269",
        "#b18b57",
        "#fff392",
        "#b4edcd",
        "#ffffff"
    ];

    string[] private groundColors4 = [
        "#663a13",
        "#137d5a",
        "#974700",
        "#49aa10",
        "#99ba5a",
        "#ade151"
    ];

    string[] private mushroomColors0 = [
        "#000000",
        "#1d730e",
        "#525050",
        "#b21030",
        "#ff7930",
        "#925f4f",
        "#db4161",
        "#9aeb00",
        "#d8cc33",
        "#2800ba",
        "#f361ff",
        "#4192c3",
        "#d0c598",
        "#f4c09a",
        "#e3b2ff"
    ];

    string[] private mushroomColors1 = [
        "#020104",
        "#493114",
        "#74254d",
        "#453879",
        "#306141",
        "#83376e",
        "#e59220",
        "#7377a0",
        "#30b7c0",
        "#86b4bb",
        "#ffa9a9",
        "#f7e2c5"
    ];

    string[] private mushroomColors2 = [
        "#495900",
        "#395844",
        "#d47642",
        "#719767",
        "#8a8a00",
        "#806a9c",
        "#a2a2a2",
        "#86d48e",
        "#c3e88d",
        "#c3b2ff"
    ];

    string[] private mushroomColors3 = [
        "#253d2d",
        "#515130",
        "#384f7a",
        "#49a269",
        "#b18b57",
        "#fff392",
        "#b4edcd",
        "#ffffff"
    ];

    string[] private mushroomColors4 = [
        "#663a13",
        "#137d5a",
        "#974700",
        "#49aa10",
        "#99ba5a",
        "#ade151"
    ];

    constructor() {
        grounds[0].push(Rect(0, 17, 24, 7));
        grounds[1].push(Rect(0, 17, 24, 8));
        grounds[1].push(Rect(0, 17, 24, 1));
        grounds[1].push(Rect(0, 18, 24, 1));
    }

    function backgroundColors(
        uint index
    ) private view returns (string[] storage) {
        if (index == 0) return backgroundColors0;
        if (index == 1) return backgroundColors1;
        if (index == 2) return backgroundColors2;
        if (index == 3) return backgroundColors3;
        if (index == 4) return backgroundColors4;
        return backgroundColors0;
    }

    function groundColors(uint index) private view returns (string[] storage) {
        if (index == 0) return groundColors0;
        if (index == 1) return groundColors1;
        if (index == 2) return groundColors2;
        if (index == 3) return groundColors3;
        if (index == 4) return groundColors4;
        return groundColors0;
    }

    function mushroomColors(
        uint index
    ) private view returns (string[] storage) {
        if (index == 0) return mushroomColors0;
        if (index == 1) return mushroomColors1;
        if (index == 2) return mushroomColors2;
        if (index == 3) return mushroomColors3;
        if (index == 4) return mushroomColors4;
        return mushroomColors0;
    }

    function setSpores(FileData[] calldata data) external onlyOwner {
        for (uint i = 0; i < data.length; ++i) {
            FileData memory file = data[i];
            Rect[] storage storageFile = spores[file.file];
            for (uint j = 0; j < file.rects.length; ++j) {
                storageFile.push(file.rects[j]);
            }
        }
    }

    function setStems(FileData[] calldata data) external onlyOwner {
        stems.setLayers(data);
    }

    function setCaps(FileData[] calldata data) external onlyOwner {
        caps.setLayers(data);
    }

    function setDots(FileData[] calldata data) external onlyOwner {
        dots.setLayers(data);
    }

    function toString(uint value) private pure returns (string memory) {
        if (value == 0) {
            return "0";
        }
        uint temp = value;
        uint digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    function setBcGround(
        MushroomData memory data,
        Rand memory rnd
    ) private view {
        data.background = backgroundColors(rnd.lvl().to_lvl_1()).random(rnd);
    }

    function setGround(MushroomData memory data, Rand memory rnd) private view {
        data.ground = rnd.next() % groundsCount;
        data.groundColor = groundColors(rnd.lvl().to_lvl_1()).random(rnd);
    }

    function setSpores(MushroomData memory data, Rand memory rnd) private view {
        data.stem = rnd.next() % spores_count;
        data.stemColor = mushroomColors(rnd.lvl().to_lvl_1()).random(rnd);
    }

    function setStem(MushroomData memory data, Rand memory rnd) private view {
        data.stem = rnd.next() % stemLevelCounts[rnd.lvl().to_lvl_1()];
        data.stemColor = mushroomColors(rnd.lvl().to_lvl_1()).random(rnd);
    }

    function setCap(MushroomData memory data, Rand memory rnd) private view {
        data.cap = rnd.next() % capLevelCounts[rnd.lvl().to_lvl_1()];
        data.capColor = mushroomColors(rnd.lvl().to_lvl_1()).random(rnd);
        data.hasDots = rnd.next() % 4 == 0;
        if (data.hasDots) {
            data.dotsColor = mushroomColors(rnd.lvl().to_lvl_1()).random(rnd);
        }
    }

    function getMushroom(
        SeedData calldata seed_data
    ) external view returns (MushroomData memory) {
        Rand memory rnd = Rand(seed_data.seed, 0, seed_data.extra);
        MushroomData memory data;
        data.lvl = rnd.lvl();
        setBcGround(data, rnd);
        setGround(data, rnd);
        if (data.lvl == 0) {
            setSpores(data, rnd);
        } else {
            setStem(data, rnd);
            setCap(data, rnd);
        }
        return data;
    }

    function getSvg(
        SeedData calldata seed_data
    ) external view returns (string memory) {
        return toSvg(this.getMushroom(seed_data));
    }

    function getMeta(
        SeedData calldata seed_data
    ) external view returns (string memory) {
        MushroomData memory data = this.getMushroom(seed_data);
        bytes memory lvl = abi.encodePacked('"level":', data.lvl.toString());
        bytes memory background = abi.encodePacked(
            ',"background":"',
            data.background,
            '"'
        );
        bytes memory ground = abi.encodePacked(
            ',"groundColor":"',
            data.groundColor,
            '"'
        );
        bytes memory stem = abi.encodePacked(
            ',"stem":',
            data.stem.toString(),
            ',"stemColor":"',
            data.stemColor,
            '"'
        );
        bytes memory cap = abi.encodePacked(
            ',"cap":',
            data.cap.toString(),
            ',"capColor":"',
            data.capColor,
            '"'
        );
        bytes memory capDots = abi.encodePacked(
            ',"hasDots":',
            data.hasDots ? "true" : "false",
            ',"dotsColor":"',
            data.dotsColor,
            '"'
        );

        return
            string(
                abi.encodePacked(
                    "{",
                    lvl,
                    background,
                    ground,
                    stem,
                    cap,
                    capDots,
                    "}"
                )
            );
    }

    function toSvg(
        MushroomData memory data
    ) private view returns (string memory) {
        bytes memory svgStart = abi.encodePacked(
            "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0",
            " ",
            toString(pixelsCount),
            " ",
            toString(pixelsCount),
            "'>"
        );

        if (data.lvl == 0) {
            return
                string(
                    abi.encodePacked(
                        svgStart,
                        backgroundSvg(data),
                        groundSvg(data),
                        stemSvg(data),
                        "</svg>"
                    )
                );
        } else {
            return
                string(
                    abi.encodePacked(
                        svgStart,
                        backgroundSvg(data),
                        groundSvg(data),
                        stemSvg(data),
                        capSvg(data),
                        "</svg>"
                    )
                );
        }
    }

    function backgroundSvg(
        MushroomData memory data
    ) private pure returns (string memory) {
        Rect memory r = Rect(0, 0, pixelsCount, pixelsCount);
        return r.toSvg(data.background);
    }

    function groundSvg(
        MushroomData memory data
    ) private view returns (string memory) {
        return grounds[data.ground].toSvg(data.groundColor);
    }

    function stemSvg(
        MushroomData memory data
    ) private view returns (string memory) {
        if (data.lvl == 0) return spores[data.stem].toSvg(data.stemColor);
        return stems[data.lvl.to_lvl_1()][data.stem].toSvg(data.stemColor);
    }

    function capSvg(
        MushroomData memory data
    ) private view returns (string memory) {
        string memory cap = caps[data.lvl.to_lvl_1()][data.cap].toSvg(
            data.capColor
        );
        if (data.hasDots) {
            string memory dotsSvg = dots[data.lvl.to_lvl_1()][data.cap].toSvg(
                data.dotsColor
            );
            return string(abi.encodePacked(cap, dotsSvg));
        } else {
            return string(cap);
        }
    }
}
Código Fuente del Contrato
Archivo 5 de 9: IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}
Código Fuente del Contrato
Archivo 6 de 9: IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}
Código Fuente del Contrato
Archivo 7 de 9: Ownable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract Ownable {
    address _owner;

    event RenounceOwnership();

    constructor() {
        _owner = msg.sender;
    }

    modifier onlyOwner() {
        require(_owner == msg.sender, "only owner");
        _;
    }

    function owner() external view virtual returns (address) {
        return _owner;
    }

    function ownerRenounce() public onlyOwner {
        _owner = address(0);
        emit RenounceOwnership();
    }

    function transferOwnership(address newOwner) external onlyOwner {
        _owner = newOwner;
    }
}
Código Fuente del Contrato
Archivo 8 de 9: PoolCreatableErc20i.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

import "./Erc20.sol";

abstract contract PoolCreatableErc20i is ERC20 {
    address internal _pool;
    uint256 internal _startTime;
    bool internal _feeLocked;
    address immutable _pairCreator;

    constructor(
        string memory name_,
        string memory symbol_,
        address pairCreator
    ) ERC20(name_, symbol_) {
        _pairCreator = pairCreator;
    }

    modifier lockFee() {
        _feeLocked = true;
        _;
        _feeLocked = false;
    }

    function launch(address poolAddress) external payable {
        require(msg.sender == _pairCreator);
        require(!isStarted());
        _pool = poolAddress;
        _startTime = block.timestamp;
    }

    function isStarted() internal view returns (bool) {
        return _pool != address(0);
    }

    function pool() external view returns (address) {
        return _pool;
    }
}
Código Fuente del Contrato
Archivo 9 de 9: ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    uint256 private _status;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    constructor() {
        _status = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        _status = ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == ENTERED;
    }
}
Configuraciones
{
  "compilationTarget": {
    "contracts/token/Fungi.sol": "Fungi"
  },
  "evmVersion": "paris",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "remappings": []
}
ABI
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"components":[{"internalType":"uint256","name":"seed","type":"uint256"},{"internalType":"uint256","name":"extra","type":"uint256"}],"indexed":false,"internalType":"struct SeedData","name":"seed_data","type":"tuple"}],"name":"OnMushroomTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"holder","type":"address"},{"components":[{"internalType":"uint256","name":"seed","type":"uint256"},{"internalType":"uint256","name":"extra","type":"uint256"}],"indexed":false,"internalType":"struct SeedData","name":"seed_data","type":"tuple"}],"name":"OnSporesGrow","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"holder","type":"address"},{"components":[{"internalType":"uint256","name":"seed","type":"uint256"},{"internalType":"uint256","name":"extra","type":"uint256"}],"indexed":false,"internalType":"struct SeedData","name":"seed_data","type":"tuple"}],"name":"OnSporesShrink","type":"event"},{"anonymous":false,"inputs":[],"name":"RenounceOwnership","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"burnCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getHolderByIndex","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"startIndex","type":"uint256"},{"internalType":"uint256","name":"count","type":"uint256"}],"name":"getHoldersList","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"seed","type":"uint256"},{"internalType":"uint256","name":"extra","type":"uint256"}],"internalType":"struct SeedData","name":"seed_data","type":"tuple"}],"name":"getMeta","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"seed","type":"uint256"},{"internalType":"uint256","name":"extra","type":"uint256"}],"internalType":"struct SeedData","name":"seed_data","type":"tuple"}],"name":"getMushroom","outputs":[{"components":[{"internalType":"uint256","name":"lvl","type":"uint256"},{"internalType":"string","name":"background","type":"string"},{"internalType":"uint256","name":"ground","type":"uint256"},{"internalType":"string","name":"groundColor","type":"string"},{"internalType":"uint256","name":"stem","type":"uint256"},{"internalType":"string","name":"stemColor","type":"string"},{"internalType":"uint256","name":"cap","type":"uint256"},{"internalType":"string","name":"capColor","type":"string"},{"internalType":"bool","name":"hasDots","type":"bool"},{"internalType":"string","name":"dotsColor","type":"string"}],"internalType":"struct MushroomData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"seed","type":"uint256"},{"internalType":"uint256","name":"extra","type":"uint256"}],"internalType":"struct SeedData","name":"seed_data","type":"tuple"}],"name":"getSvg","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"holdersCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"seed","type":"uint256"}],"name":"isOwnerOf","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"poolAddress","type":"address"}],"name":"launch","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"maxBuy","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"mushroomCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"mushroomOfOwnerByIndex","outputs":[{"components":[{"internalType":"uint256","name":"seed","type":"uint256"},{"internalType":"uint256","name":"extra","type":"uint256"}],"internalType":"struct SeedData","name":"data","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mushroomsTotalCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ownerRenounce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"lvl","type":"uint256"},{"internalType":"uint256","name":"file","type":"uint256"},{"components":[{"internalType":"uint8","name":"x","type":"uint8"},{"internalType":"uint8","name":"y","type":"uint8"},{"internalType":"uint8","name":"width","type":"uint8"},{"internalType":"uint8","name":"height","type":"uint8"}],"internalType":"struct Rect[]","name":"rects","type":"tuple[]"}],"internalType":"struct FileData[]","name":"data","type":"tuple[]"}],"name":"setCaps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"lvl","type":"uint256"},{"internalType":"uint256","name":"file","type":"uint256"},{"components":[{"internalType":"uint8","name":"x","type":"uint8"},{"internalType":"uint8","name":"y","type":"uint8"},{"internalType":"uint8","name":"width","type":"uint8"},{"internalType":"uint8","name":"height","type":"uint8"}],"internalType":"struct Rect[]","name":"rects","type":"tuple[]"}],"internalType":"struct FileData[]","name":"data","type":"tuple[]"}],"name":"setDots","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"lvl","type":"uint256"},{"internalType":"uint256","name":"file","type":"uint256"},{"components":[{"internalType":"uint8","name":"x","type":"uint8"},{"internalType":"uint8","name":"y","type":"uint8"},{"internalType":"uint8","name":"width","type":"uint8"},{"internalType":"uint8","name":"height","type":"uint8"}],"internalType":"struct Rect[]","name":"rects","type":"tuple[]"}],"internalType":"struct FileData[]","name":"data","type":"tuple[]"}],"name":"setSpores","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"lvl","type":"uint256"},{"internalType":"uint256","name":"file","type":"uint256"},{"components":[{"internalType":"uint8","name":"x","type":"uint8"},{"internalType":"uint8","name":"y","type":"uint8"},{"internalType":"uint8","name":"width","type":"uint8"},{"internalType":"uint8","name":"height","type":"uint8"}],"internalType":"struct Rect[]","name":"rects","type":"tuple[]"}],"internalType":"struct FileData[]","name":"data","type":"tuple[]"}],"name":"setStems","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"sporesDegree","outputs":[{"components":[{"internalType":"uint256","name":"seed","type":"uint256"},{"internalType":"uint256","name":"extra","type":"uint256"}],"internalType":"struct SeedData","name":"data","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sporesTotalCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]