ETH Price: $3,334.08 (-0.44%)
 

Overview

ETH Balance

0.0087 ETH

Eth Value

$29.01 (@ $3,334.08/ETH)

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Safe Transfer Fr...151611262022-07-17 16:08:36898 days ago1658074116IN
0x6c20F86f...078B4d27c
0 ETH0.0017207246.57289627
Safe Transfer Fr...151611232022-07-17 16:08:01898 days ago1658074081IN
0x6c20F86f...078B4d27c
0 ETH0.0027870947.3616718
Set Approval For...148210202022-05-22 3:02:32955 days ago1653188552IN
0x6c20F86f...078B4d27c
0 ETH0.0003944414.65844519
Set Approval For...147108072022-05-04 11:59:27972 days ago1651665567IN
0x6c20F86f...078B4d27c
0 ETH0.0022404945.89199071
Set Approval For...146560912022-04-25 21:09:30981 days ago1650920970IN
0x6c20F86f...078B4d27c
0 ETH0.0045769593.74980219
Safe Transfer Fr...146451702022-04-24 3:50:56983 days ago1650772256IN
0x6c20F86f...078B4d27c
0 ETH0.0015011327.77462064
Safe Transfer Fr...145913592022-04-15 17:43:33991 days ago1650044613IN
0x6c20F86f...078B4d27c
0 ETH0.0022272437.84811061
Set Approval For...145816002022-04-14 5:11:41993 days ago1649913101IN
0x6c20F86f...078B4d27c
0 ETH0.0020851142.70940458
Set Approval For...145600572022-04-10 20:20:43996 days ago1649622043IN
0x6c20F86f...078B4d27c
0 ETH0.002331747.76026095
Set Approval For...145425352022-04-08 2:41:01999 days ago1649385661IN
0x6c20F86f...078B4d27c
0 ETH0.0029551460.5301649
Set Approval For...145410762022-04-07 21:03:39999 days ago1649365419IN
0x6c20F86f...078B4d27c
0 ETH0.0025279851.78059446
Safe Transfer Fr...145394782022-04-07 15:14:13999 days ago1649344453IN
0x6c20F86f...078B4d27c
0 ETH0.01675871284.78446443
Set Approval For...145195012022-04-04 12:19:511002 days ago1649074791IN
0x6c20F86f...078B4d27c
0 ETH0.0023167147.4533278
Set Approval For...145175452022-04-04 5:07:271003 days ago1649048847IN
0x6c20F86f...078B4d27c
0 ETH0.0029940861.32782289
Set Approval For...145170942022-04-04 3:21:331003 days ago1649042493IN
0x6c20F86f...078B4d27c
0 ETH0.002159944.24139678
Set Approval For...145168832022-04-04 2:30:551003 days ago1649039455IN
0x6c20F86f...078B4d27c
0 ETH0.001080346.60885589
Set Approval For...145162762022-04-04 0:07:211003 days ago1649030841IN
0x6c20F86f...078B4d27c
0 ETH0.0028135257.62938631
Set Approval For...145151352022-04-03 19:54:261003 days ago1649015666IN
0x6c20F86f...078B4d27c
0 ETH0.0025850952.95056236
Set Approval For...145145912022-04-03 17:53:381003 days ago1649008418IN
0x6c20F86f...078B4d27c
0 ETH0.0016802947.95491393
Set Approval For...145144522022-04-03 17:22:111003 days ago1649006531IN
0x6c20F86f...078B4d27c
0 ETH0.0024410550
Set Approval For...145102472022-04-03 1:34:241004 days ago1648949664IN
0x6c20F86f...078B4d27c
0 ETH0.002708255.47211653
Safe Transfer Fr...145096352022-04-02 23:17:441004 days ago1648941464IN
0x6c20F86f...078B4d27c
0 ETH0.0024845342.2201833
Safe Transfer Fr...145096162022-04-02 23:14:511004 days ago1648941291IN
0x6c20F86f...078B4d27c
0 ETH0.0028027147.62709581
Safe Transfer Fr...145096122022-04-02 23:13:421004 days ago1648941222IN
0x6c20F86f...078B4d27c
0 ETH0.0024732642.02874867
Safe Transfer Fr...145096092022-04-02 23:13:231004 days ago1648941203IN
0x6c20F86f...078B4d27c
0 ETH0.0024896742.30765943
View all transactions

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block
From
To
145072782022-04-02 14:32:081004 days ago1648909928  Contract Creation0 ETH
Loading...
Loading

Minimal Proxy Contract for 0x7546923ddb50b284c09a936e0f8ecd36c52bf4d2

Contract Name:
Club

Compiler Version
v0.8.11+commit.d7f03943

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity)

Decompile Bytecode Similar Contracts
/**
 *Submitted for verification at Etherscan.io on 2022-02-10
*/

// SPDX-License-Identifier: MIT
// File: tokens/erc1155/ERC1155.sol


pragma solidity ^0.8.4;

/// @notice Minimalist and gas efficient standard ERC1155 implementation.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC1155.sol)
abstract contract ERC1155 {
    /*///////////////////////////////////////////////////////////////
                                EVENTS
    //////////////////////////////////////////////////////////////*/

    event TransferSingle(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256 id,
        uint256 amount
    );

    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] amounts
    );

    event ApprovalForAll(
        address indexed owner,
        address indexed operator,
        bool approved
    );

    event URI(string value, uint256 indexed id);

    /*///////////////////////////////////////////////////////////////
                            ERC1155 STORAGE
    //////////////////////////////////////////////////////////////*/

    mapping(address => mapping(uint256 => uint256)) public balanceOf;

    mapping(address => mapping(address => bool)) public isApprovedForAll;

    /*///////////////////////////////////////////////////////////////
                             METADATA LOGIC
    //////////////////////////////////////////////////////////////*/

    function uri(uint256 id) public view virtual returns (string memory);

    /*///////////////////////////////////////////////////////////////
                             ERC1155 LOGIC
    //////////////////////////////////////////////////////////////*/

    function setApprovalForAll(address operator, bool approved) public virtual {
        isApprovedForAll[msg.sender][operator] = approved;

        emit ApprovalForAll(msg.sender, operator, approved);
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) public virtual {
        require(
            msg.sender == from || isApprovedForAll[from][msg.sender],
            "NOT_AUTHORIZED"
        );

        balanceOf[from][id] -= amount;
        balanceOf[to][id] += amount;

        emit TransferSingle(msg.sender, from, to, id, amount);

        require(
            to.code.length == 0
                ? to != address(0)
                : ERC1155TokenReceiver(to).onERC1155Received(
                    msg.sender,
                    from,
                    id,
                    amount,
                    data
                ) == ERC1155TokenReceiver.onERC1155Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) public virtual {
        uint256 idsLength = ids.length; // Saves MLOADs.

        require(idsLength == amounts.length, "LENGTH_MISMATCH");

        require(
            msg.sender == from || isApprovedForAll[from][msg.sender],
            "NOT_AUTHORIZED"
        );

        for (uint256 i = 0; i < idsLength; ) {
            uint256 id = ids[i];
            uint256 amount = amounts[i];

            balanceOf[from][id] -= amount;
            balanceOf[to][id] += amount;

            // An array can't have a total length
            // larger than the max uint256 value.
            unchecked {
                i++;
            }
        }

        emit TransferBatch(msg.sender, from, to, ids, amounts);

        require(
            to.code.length == 0
                ? to != address(0)
                : ERC1155TokenReceiver(to).onERC1155BatchReceived(
                    msg.sender,
                    from,
                    ids,
                    amounts,
                    data
                ) == ERC1155TokenReceiver.onERC1155BatchReceived.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function balanceOfBatch(address[] memory owners, uint256[] memory ids)
        public
        view
        virtual
        returns (uint256[] memory balances)
    {
        uint256 ownersLength = owners.length; // Saves MLOADs.

        require(ownersLength == ids.length, "LENGTH_MISMATCH");

        balances = new uint256[](owners.length);

        // Unchecked because the only math done is incrementing
        // the array index counter which cannot possibly overflow.
        unchecked {
            for (uint256 i = 0; i < ownersLength; i++) {
                balances[i] = balanceOf[owners[i]][ids[i]];
            }
        }
    }

    /*///////////////////////////////////////////////////////////////
                              ERC165 LOGIC
    //////////////////////////////////////////////////////////////*/

    function supportsInterface(bytes4 interfaceId)
        public
        pure
        virtual
        returns (bool)
    {
        return
            interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
            interfaceId == 0xd9b67a26 || // ERC165 Interface ID for ERC1155
            interfaceId == 0x0e89341c; // ERC165 Interface ID for ERC1155MetadataURI
    }

    /*///////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) internal {
        balanceOf[to][id] += amount;

        emit TransferSingle(msg.sender, address(0), to, id, amount);

        require(
            to.code.length == 0
                ? to != address(0)
                : ERC1155TokenReceiver(to).onERC1155Received(
                    msg.sender,
                    address(0),
                    id,
                    amount,
                    data
                ) == ERC1155TokenReceiver.onERC1155Received.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function _batchMint(
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal {
        uint256 idsLength = ids.length; // Saves MLOADs.

        require(idsLength == amounts.length, "LENGTH_MISMATCH");

        for (uint256 i = 0; i < idsLength; ) {
            balanceOf[to][ids[i]] += amounts[i];

            // An array can't have a total length
            // larger than the max uint256 value.
            unchecked {
                i++;
            }
        }

        emit TransferBatch(msg.sender, address(0), to, ids, amounts);

        require(
            to.code.length == 0
                ? to != address(0)
                : ERC1155TokenReceiver(to).onERC1155BatchReceived(
                    msg.sender,
                    address(0),
                    ids,
                    amounts,
                    data
                ) == ERC1155TokenReceiver.onERC1155BatchReceived.selector,
            "UNSAFE_RECIPIENT"
        );
    }

    function _batchBurn(
        address from,
        uint256[] memory ids,
        uint256[] memory amounts
    ) internal {
        uint256 idsLength = ids.length; // Saves MLOADs.

        require(idsLength == amounts.length, "LENGTH_MISMATCH");

        for (uint256 i = 0; i < idsLength; ) {
            balanceOf[from][ids[i]] -= amounts[i];

            // An array can't have a total length
            // larger than the max uint256 value.
            unchecked {
                i++;
            }
        }

        emit TransferBatch(msg.sender, from, address(0), ids, amounts);
    }

    function _burn(
        address from,
        uint256 id,
        uint256 amount
    ) internal {
        balanceOf[from][id] -= amount;

        emit TransferSingle(msg.sender, from, address(0), id, amount);
    }
}

/// @notice A generic interface for a contract which properly accepts ERC1155 tokens.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC1155.sol)
interface ERC1155TokenReceiver {
    function onERC1155Received(
        address operator,
        address from,
        uint256 id,
        uint256 amount,
        bytes calldata data
    ) external returns (bytes4);

    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) external returns (bytes4);
}

// File: @openzeppelin/contracts/utils/math/SafeMath.sol


// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)

pragma solidity ^0.8.0;

// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
 * now has built in overflow checking.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a / b;
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}

// File: @openzeppelin/contracts/utils/Counters.sol


// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)

pragma solidity ^0.8.0;

/**
 * @title Counters
 * @author Matt Condon (@shrugs)
 * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
 * of elements in a mapping, issuing ERC721 ids, or counting request ids.
 *
 * Include with `using Counters for Counters.Counter;`
 */
library Counters {
    struct Counter {
        // This variable should never be directly accessed by users of the library: interactions must be restricted to
        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
        // this feature: see https://github.com/ethereum/solidity/issues/4637
        uint256 _value; // default: 0
    }

    function current(Counter storage counter) internal view returns (uint256) {
        return counter._value;
    }

    function increment(Counter storage counter) internal {
        unchecked {
            counter._value += 1;
        }
    }

    function decrement(Counter storage counter) internal {
        uint256 value = counter._value;
        require(value > 0, "Counter: decrement overflow");
        unchecked {
            counter._value = value - 1;
        }
    }

    function reset(Counter storage counter) internal {
        counter._value = 0;
    }
}

// File: Club.sol


pragma solidity ^0.8.4;




contract Club is ERC1155 {
    using Counters for Counters.Counter;
    using SafeMath for uint256;

    string public name;
    string public symbol;
    string public docs;
    address public safeAddress;
    address public referralAddress;
    address internal coterieAddress;
    uint256 public maxMembers;

    Counters.Counter public memberCounter;
    Counters.Counter public tokenCounter;

    mapping(address => bool) public members;
    mapping(uint256 => Token) public tokens;

    bool internal locked;

    struct Token {
        uint256 mintPrice;
        uint256 startTime;
        uint256 endTime;
        string ipfsCID;
        uint256 maximum;
        uint256 minted;
        uint256 maxAmount;
        bool exists;
    }

    event Minted(address who, uint256 tokenIndex, uint256 amount);
    event Withdrew(uint256 amountSentToSafe, uint256 percentageFee);
    event Kicked(address who);
    event Joined(address who);

    error UnknownToken();
    error AlreadyInitialized();
    error NotEnoughFunds();
    error NotMember();

    modifier onlySafe() {
        require(
            msg.sender == safeAddress,
            "Only the safe can call this function"
        );
        _;
    }

    modifier onlyCoterie() {
        require(
            msg.sender == coterieAddress,
            "Only coterie can call this function"
        );
        _;
    }

    modifier onTime(uint256 startTime, uint256 endTime) {
        require(startTime < endTime, "Start time must be before end time");
        require(startTime > 0 && endTime > 0, "Time window cannot be 0");
        _;
    }

    modifier inMemberLimits(uint256 _maxMembers, string memory _docs) {
        if (bytes(_docs).length == 0) {
            require(_maxMembers > 0, "Max members must be greater than 0");
            require(_maxMembers <= 100, "Max members must be less than 100");
        } else {
            require(_maxMembers > 0, "Max members must be greater than 0");
        }
        _;
    }

    function _kick(address to) internal {
        if (!members[to]) revert NotMember();

        for (uint256 i = 0; i < tokenCounter.current(); i++) {
            if (balanceOf[to][i] > 0) {
                balanceOf[to][i] = 0;
            }
        }

        memberCounter.decrement();
        members[to] = false;

        emit Kicked(to);
    }

    function _getTokenValues(address to) internal view returns (uint256) {
        if (!members[to]) revert NotMember();

        uint256 total = 0;

        for (uint256 i = 0; i < tokenCounter.current(); i++) {
            if (balanceOf[to][i] > 0) {
                total = total.add(balanceOf[to][i].mul(tokens[i].mintPrice));
            }
        }

        return total;
    }

    function _addMember(address to) internal {
        require(!members[to], "Member already exists");

        members[to] = true;
        memberCounter.increment();

        emit Joined(to);
    }

    function setCoterieAddress(address _coterieAddress) external onlyCoterie {
        coterieAddress = _coterieAddress;
    }

    function init(
        string memory _clubName,
        string memory _tokenSymbol,
        string memory _docs,
        uint256 _maxMembers,
        address _safeAddress,
        address _referralAddress
    ) external inMemberLimits(_maxMembers, _docs) {
        if (safeAddress != address(0)) revert AlreadyInitialized();
        require(
            _safeAddress != _referralAddress,
            "Safe address cannot be the same as referral address"
        );

        name = _clubName;
        symbol = _tokenSymbol;
        docs = _docs;
        safeAddress = _safeAddress;
        referralAddress = _referralAddress;
        maxMembers = _maxMembers;
        coterieAddress = 0x7c5252031d236d5A17db832Fc8367e6850a3b4FB;
    }

    function createFundingRound(
        uint256 mintPrice,
        uint256 startTime,
        uint256 endTime,
        uint256 maximum,
        uint256 maxAmount,
        string memory ipfsCID
    ) external onlySafe onTime(startTime, endTime) {
        Token storage token = tokens[tokenCounter.current()];
        token.mintPrice = mintPrice;
        token.startTime = startTime;
        token.endTime = endTime;
        token.ipfsCID = ipfsCID;
        token.maximum = maximum;
        token.minted = 0;
        token.maxAmount = maxAmount;
        token.exists = true;

        tokenCounter.increment();
    }

    function editFundingRound(
        uint256 id,
        uint256 mintPrice,
        uint256 startTime,
        uint256 endTime
    ) external onlySafe onTime(startTime, endTime) {
        if (!tokens[id].exists) revert UnknownToken();

        tokens[id].mintPrice = mintPrice;
        tokens[id].startTime = startTime;
        tokens[id].endTime = endTime;
    }

    function editTokenMintMaximum(uint256 id, uint256 maximum)
        external
        onlySafe
    {
        if (!tokens[id].exists) revert UnknownToken();

        tokens[id].maximum = maximum;
    }

    function editTokenMaxAmount(uint256 id, uint256 maxAmount)
        external
        onlySafe
    {
        if (!tokens[id].exists) revert UnknownToken();

        tokens[id].maxAmount = maxAmount;
    }

    function editTokenIPFS(uint256 id, string memory ipfsCID)
        external
        onlySafe
    {
        if (!tokens[id].exists) revert UnknownToken();

        tokens[id].ipfsCID = ipfsCID;
    }

    function editMaximumMembers(uint256 _maxMembers)
        external
        onlySafe
        inMemberLimits(_maxMembers, docs)
    {
        maxMembers = _maxMembers;
    }

    function mint(uint256 tokenIndex, uint256 amount) external payable {
        if (!tokens[tokenIndex].exists) revert UnknownToken();
        if (tokens[tokenIndex].maxAmount > 0) {
            require(
                amount <=
                    tokens[tokenIndex].maxAmount.sub(
                        balanceOf[msg.sender][tokenIndex]
                    ),
                "Cannot mint over max amount"
            );
        }
        require(amount > 0, "Amount must be greater than 0");
        require(
            block.timestamp > tokens[tokenIndex].startTime &&
                block.timestamp < tokens[tokenIndex].endTime,
            "time window closed"
        );
        if (msg.value < amount.mul(tokens[tokenIndex].mintPrice))
            revert NotEnoughFunds();
        if (tokens[tokenIndex].maximum > 0) {
            require(
                tokens[tokenIndex].minted.add(amount) <=
                    tokens[tokenIndex].maximum,
                "Maximum amount of tokens minted"
            );
        }

        if (!members[msg.sender]) {
            if (memberCounter.current() >= maxMembers) revert("Club is full");
            members[msg.sender] = true;
            memberCounter.increment();

            emit Joined(msg.sender);
        }

        _mint(msg.sender, tokenIndex, amount, "");
        tokens[tokenIndex].minted = tokens[tokenIndex].minted.add(amount);

        emit Minted(msg.sender, tokenIndex, amount);
    }

    function withdraw() external onlySafe {
        require(safeAddress != address(0), "Club not initialized");
        require(address(this).balance > 0, "No funds to withdraw");

        uint256 balance = address(this).balance;
        uint256 rate = 500;

        if (balance >= 50 ether && balance < 85 ether) {
            rate = 425;
        } else if (balance >= 85 ether && balance < 100 ether) {
            rate = 385;
        } else if (balance >= 100 ether && balance < 250 ether) {
            rate = 325;
        } else if (balance >= 250 ether && balance < 500 ether) {
            rate = 250;
        } else if (balance >= 500 ether) {
            rate = 200;
        }

        uint256 coterieFee = address(this).balance.mul(rate).div(10000);
        uint256 referralFee = 0;

        if (referralAddress != address(0)) {
            referralFee = coterieFee.div(10);
            (bool referralSuccess, ) = referralAddress.call{value: referralFee}(
                ""
            );
            if (!referralSuccess) {
                revert("referral address failed to receive funds");
            }
        }

        (bool coterieSuccess, ) = coterieAddress.call{
            value: coterieFee.sub(referralFee)
        }("");
        if (!coterieSuccess) {
            revert("Coterie address failed to receive funds");
        }

        uint256 amountSentToSafe = address(this).balance;

        (bool safeSuccess, ) = safeAddress.call{value: amountSentToSafe}("");
        if (!safeSuccess) {
            revert("Safe address failed to receive funds");
        }

        emit Withdrew(amountSentToSafe, rate);
    }

    function kick(address to) external payable onlySafe {
        uint256 totalEtherToReturn = _getTokenValues(to);

        if (msg.value < totalEtherToReturn) revert NotEnoughFunds();

        _kick(to);

        (bool success, ) = to.call{value: totalEtherToReturn}("");
        if (!success) {
            revert("Failed to send funds to kicked member");
        }
    }

    function kickMultiple(address[] calldata to) external payable onlySafe {
        require(to.length > 0, "No members to kick");
        require(
            to.length <= memberCounter.current(),
            "Too many addresses provided"
        );
        require(msg.value > 0, "No ether was sent");

        int256 balance = int256(msg.value);

        for (uint256 i = 0; i < to.length; i++) {
            uint256 etherToReturn = _getTokenValues(to[i]);
            balance = balance - int256(etherToReturn);

            if (balance < 0) revert NotEnoughFunds();

            _kick(to[i]);

            (bool success, ) = to[i].call{value: etherToReturn}("");
            if (!success) {
                revert("Failed to send funds to kicked member");
            }
        }
    }

    function addMember(address to) public onlySafe {
        require(memberCounter.current() < maxMembers, "Club is full");

        _addMember(to);
    }

    function addMembers(address[] calldata to) external onlySafe {
        require(to.length > 0, "No members to add");
        require(
            to.length.add(memberCounter.current()) <= maxMembers,
            "Too many addresses provided"
        );

        for (uint256 i = 0; i < to.length; i++) {
            _addMember(to[i]);
        }
    }

    function uri(uint256 id) public view override returns (string memory) {
        if (!tokens[id].exists) revert UnknownToken();

        return string(abi.encodePacked("ipfs://", tokens[id].ipfsCID));
    }
}

Contract ABI

[{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"NotEnoughFunds","type":"error"},{"inputs":[],"name":"NotMember","type":"error"},{"inputs":[],"name":"UnknownToken","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"who","type":"address"}],"name":"Joined","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"who","type":"address"}],"name":"Kicked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"who","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Minted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"URI","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amountSentToSafe","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"percentageFee","type":"uint256"}],"name":"Withdrew","type":"event"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"addMember","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"to","type":"address[]"}],"name":"addMembers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"owners","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"balances","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"mintPrice","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"uint256","name":"maximum","type":"uint256"},{"internalType":"uint256","name":"maxAmount","type":"uint256"},{"internalType":"string","name":"ipfsCID","type":"string"}],"name":"createFundingRound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"docs","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"mintPrice","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"}],"name":"editFundingRound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxMembers","type":"uint256"}],"name":"editMaximumMembers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"string","name":"ipfsCID","type":"string"}],"name":"editTokenIPFS","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"maxAmount","type":"uint256"}],"name":"editTokenMaxAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"maximum","type":"uint256"}],"name":"editTokenMintMaximum","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_clubName","type":"string"},{"internalType":"string","name":"_tokenSymbol","type":"string"},{"internalType":"string","name":"_docs","type":"string"},{"internalType":"uint256","name":"_maxMembers","type":"uint256"},{"internalType":"address","name":"_safeAddress","type":"address"},{"internalType":"address","name":"_referralAddress","type":"address"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"kick","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"to","type":"address[]"}],"name":"kickMultiple","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"maxMembers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"memberCounter","outputs":[{"internalType":"uint256","name":"_value","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"members","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenIndex","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"referralAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"safeAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_coterieAddress","type":"address"}],"name":"setCoterieAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenCounter","outputs":[{"internalType":"uint256","name":"_value","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokens","outputs":[{"internalType":"uint256","name":"mintPrice","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"},{"internalType":"string","name":"ipfsCID","type":"string"},{"internalType":"uint256","name":"maximum","type":"uint256"},{"internalType":"uint256","name":"minted","type":"uint256"},{"internalType":"uint256","name":"maxAmount","type":"uint256"},{"internalType":"bool","name":"exists","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.