账户
0x42...953d
0x42...953D

0x42...953D

$500
此合同的源代码已经过验证!
合同元数据
编译器
0.8.20+commit.a1b79de6
语言
Solidity
合同源代码
文件 1 的 1:TimeBasedExperience.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;
    }
}

// File: timebasedexperience.sol


pragma solidity ^0.8.20;


contract TimeBasedExperience is ReentrancyGuard {
    struct SharesTradedEvent {
        address from;
        uint256 shares;
        bool isBuy;
        uint256 totalCost;
        uint256 feeToApp;
        uint256 feeToCreator;
        uint256 feeToShareholders;
        uint256 feeToReferrer;
        address experienceCreator;
        uint256 totalSupplyExperience;
        address referrerAddress;
    }

    struct SharesRedeemedEvent {
        address from;
        uint256 shares;
        uint256 totalCost;
        uint256 feeToApp;
        uint256 feeToCreator;
        uint256 feeToShareholders;
        uint256 feeToReferrer;
        address experienceCreator;
        uint256 totalSupplyExperience;
        address referrerAddress;
    }

    struct Experience {
        uint256 totalShares; // Total shares outstanding
        mapping(address => uint256) sharesOwned;
        address creator;
        uint256 fundsCollected;
        uint256 minRedemptionPrice;
        address ref;
    }

    // Experience ID => Experience
    mapping(address => Experience) public experiences;

    // Address => Allowed to transfer
    mapping(address => bool) public allowedToTransfer;

    // Address => Has an experience, to prevent multiple experiences per user
    mapping(address => bool) public hasAnExperience;

    uint256 private constant BASE_PRICE = 0.0001 ether;
    uint256 private constant A = 0.000000015 ether;
    uint256 private constant B = 0.000025 ether;
    uint256 private constant C = 0.0005 ether;

    /// @notice Fee percentages in case of the chosen experience was not referred by someone
    /// @dev Buys/sells
    uint256 public constant appFeePercentage_WithoutRef = 17500000000; // 1.75% fee to the application
    uint256 public constant creatorFeePercentage_WithoutRef = 20000000000; // 2% fee to the creator
    uint256 public constant shareholdersFeePercentage_WithoutRef = 2500000000; // .25% fee to other shareholders

    /// @notice Fee percentages in case of the chosen experience was referred by someone
    /// @dev Buys/sells
    uint256 public constant appFeePercentage_WithRef = 15500000000; // 1.55% fee to the application
    uint256 public constant creatorFeePercentage_WithRef = 21000000000; // 2.1% fee to the creator
    uint256 public constant shareholdersFeePercentage_WithRef = 2500000000; // .25% fee to other shareholders
    uint256 public constant refFeePercentage = 1000000000; // .1% fee to the referrer

    /// @notice Fee percentages in case of redeeming shares without a referrer
    uint256 public constant appFeePercentage_Redeem_WithoutRef = 40000000000; // 4% fee to the application
    uint256 public constant creatorFeePercentage_Redeem_WithoutRef = 940000000000; // 94% fee to the creator
    uint256 public constant shareholdersFeePercentage_Redeem_WithoutRef = 20000000000; // 2% fee to other shareholders

    /// @notice Fee percentages in case of redeeming shares with a referrer
    uint256 public constant appFeePercentage_Redeem_WithRef = 25000000000; // 2.5% fee to the application
    uint256 public constant creatorFeePercentage_Redeem_WithRef = 950000000000; // 95% fee to the creator
    uint256 public constant shareholdersFeePercentage_Redeem_WithRef = 20000000000; // 2% fee to other shareholders
    uint256 public constant refFeePercentage_Redeem = 5000000000; // .5% fee to the referrer

    uint256 public constant minSharesToRedeem = 15; // Minimum shares to redeem

    uint256 private constant _BASIS_POINTS = 1e12;

    address private immutable _owner;

    bool private _paused;

    event SharesCreated(address creator, address referrer);
    event SharesTransferred(address from, address to, uint256 shares);
    event SharesTraded(SharesTradedEvent event_);
    event SharesRedeemed(SharesRedeemedEvent event_);

    error NotEnoughEthSent();
    error NotEnoughSharesOwned();
    error AtLeastOneShare();
    error InsufficientBalance();
    error LessThanMinimumRedemptionPrice();
    error LessThanMinShare();

    constructor() {
        _owner = msg.sender;
    }

    /**
     * @notice Buy minutes in an experience
     * @param creatorAddress creator of the experience
     * @param _minutes How many minutes to buy
     */
    function buyShares(address creatorAddress, uint256 _minutes) public payable isPaused {
        SharesTradedEvent memory _event;

        Experience storage experience = experiences[creatorAddress];

        // Check if experience exists
        if (experience.creator == address(0)) {
            revert("Experience does not exist");
        }

        uint256 cost = calculateTotalCost(_minutes, experience.totalShares);

        experience.totalShares += _minutes;
        experience.sharesOwned[msg.sender] += _minutes;

        address ref_ = experience.ref;

        uint256 appFee;
        uint256 creatorFee;
        uint256 shareholdersFee;

        uint256 refFee;
        if (ref_ != address(0)) {
            appFee = (cost * appFeePercentage_WithRef) / _BASIS_POINTS;
            refFee = (cost * refFeePercentage) / _BASIS_POINTS;
            creatorFee = (cost * creatorFeePercentage_WithRef) / _BASIS_POINTS;
            shareholdersFee = (cost * shareholdersFeePercentage_WithRef) / _BASIS_POINTS;

            payable(ref_).transfer(refFee);
        } else {
            appFee = (cost * appFeePercentage_WithoutRef) / _BASIS_POINTS;
            creatorFee = (cost * creatorFeePercentage_WithoutRef) / _BASIS_POINTS;
            shareholdersFee = (cost * shareholdersFeePercentage_WithoutRef) / _BASIS_POINTS;
        }

        if (msg.value < (cost + appFee + creatorFee + shareholdersFee + refFee)) {
            revert NotEnoughEthSent();
        }

        payable(owner()).transfer(appFee);

        payable(experiences[creatorAddress].creator).transfer(creatorFee);

        experience.fundsCollected += shareholdersFee;

        _event = SharesTradedEvent({
            from: msg.sender,
            shares: _minutes,
            isBuy: true,
            totalCost: cost,
            feeToApp: appFee,
            feeToCreator: creatorFee,
            feeToShareholders: shareholdersFee,
            feeToReferrer: refFee,
            experienceCreator: experience.creator,
            totalSupplyExperience: experience.totalShares,
            referrerAddress: ref_
        });

        emit SharesTraded(_event);
    }

    /**
     * @notice Get the cost of a buy or amount of eth to receive for a sell, including fees
     * @param creatorAddress Creator of the experience
     * @param _minutes Amount of minutes to buy or sell
     * @param isBuy True for buy, false for sell
     */
    function totalCostWithFees(address creatorAddress, uint256 _minutes, bool isBuy) external view returns (uint256) {
        Experience storage experience = experiences[creatorAddress];
        uint256 shares = isBuy ? experience.totalShares : experience.totalShares - _minutes;
        uint256 cost = calculateTotalCost(_minutes, shares);

        address ref_ = experience.ref;

        uint256 appFee;
        uint256 creatorFee;
        uint256 shareholdersFee;

        uint256 refFee;
        if (ref_ != address(0)) {
            appFee = (cost * appFeePercentage_WithRef) / _BASIS_POINTS;
            refFee = (cost * refFeePercentage) / _BASIS_POINTS;
            creatorFee = creatorFee = (cost * creatorFeePercentage_WithRef) / _BASIS_POINTS;
            shareholdersFee = (cost * shareholdersFeePercentage_WithRef) / _BASIS_POINTS;
        } else {
            appFee = (cost * appFeePercentage_WithoutRef) / _BASIS_POINTS;
            creatorFee = (cost * creatorFeePercentage_WithoutRef) / _BASIS_POINTS;
            shareholdersFee = (cost * shareholdersFeePercentage_WithoutRef) / _BASIS_POINTS;
        }

        if (isBuy) {
            return cost + appFee + creatorFee + shareholdersFee + refFee;
        } else {
            return cost - appFee - creatorFee - shareholdersFee - refFee;
        }
    }

    /**
     * @notice Sell minutes in an experience in the bonding curve
     * @param creatorAddress Creator of the experience
     * @param _minutes Amount of minutes to sell
     */
    function sellShares(address creatorAddress, uint256 _minutes) public isPaused nonReentrant {
        SharesTradedEvent memory _event;

        Experience storage experience = experiences[creatorAddress];

        if (experience.sharesOwned[msg.sender] < _minutes) {
            revert NotEnoughSharesOwned();
        }

        if (experience.totalShares <= _minutes) {
            revert AtLeastOneShare();
        }

        uint256 currentPrice = calculateTotalCost(_minutes, experience.totalShares - _minutes);

        address ref_ = experience.ref;

        uint256 appFee;
        uint256 creatorFee;
        uint256 shareholdersFee;

        uint256 refFee;
        if (ref_ != address(0)) {
            refFee = (currentPrice * refFeePercentage) / _BASIS_POINTS;
            appFee = (currentPrice * appFeePercentage_WithRef) / _BASIS_POINTS;
            creatorFee = (currentPrice * creatorFeePercentage_WithRef) / _BASIS_POINTS;
            shareholdersFee = (currentPrice * shareholdersFeePercentage_WithRef) / _BASIS_POINTS;

            payable(ref_).transfer(refFee);
        } else {
            appFee = (currentPrice * appFeePercentage_WithoutRef) / _BASIS_POINTS;
            creatorFee = (currentPrice * creatorFeePercentage_WithoutRef) / _BASIS_POINTS;
            shareholdersFee = (currentPrice * shareholdersFeePercentage_WithoutRef) / _BASIS_POINTS;
        }

        uint256 reimbursement = currentPrice - appFee - creatorFee - shareholdersFee - refFee;

        if (address(this).balance < reimbursement) {
            revert InsufficientBalance();
        }

        payable(owner()).transfer(appFee);

        payable(experiences[creatorAddress].creator).transfer(creatorFee);

        experience.fundsCollected += shareholdersFee;

        experience.sharesOwned[msg.sender] -= _minutes;
        experience.totalShares -= _minutes;

        payable(msg.sender).transfer(reimbursement);

        _event = SharesTradedEvent(
            msg.sender,
            _minutes,
            false,
            currentPrice,
            appFee,
            creatorFee,
            shareholdersFee,
            refFee,
            experience.creator,
            experience.totalShares,
            ref_
        );

        emit SharesTraded(_event);
    }

    /**
     * @notice Redeem minutes for an experience. You need to redeem at least 15 shares for a meeting
     * @param creatorAddress Address of the experience creator
     * @param shares Amount of minutes
     */
    function redeemShares(address creatorAddress, uint256 shares) public isPaused nonReentrant {
        _redeemShares(creatorAddress, shares, msg.sender);
    }

    function redeemSharesAllowed(address creatorAddress, uint256 shares, address from) public isPaused nonReentrant {
        require(allowedToTransfer[msg.sender], "Not allowed to transfer");
        _redeemShares(creatorAddress, shares, from);
    }

    /**
     * @notice Redeem minutes for an experience. You need to redeem at least 15 shares for a meeting
     * @param creatorAddress Address of the experience creator
     * @param shares Amount of minutes
     */
    function _redeemShares(address creatorAddress, uint256 shares, address from) private isPaused {
        Experience storage experience = experiences[creatorAddress];

        uint256 currentPrice = calculateTotalCost(shares, experience.totalShares - shares);

        bool isAllowedContract = allowedToTransfer[msg.sender];

        if (experience.sharesOwned[msg.sender] < shares) {
            revert NotEnoughSharesOwned();
        }

        if (shares < minSharesToRedeem && !isAllowedContract) {
            revert LessThanMinShare();
        }

        // Check if there will be at least one share after redemption
        if (experience.totalShares <= shares) {
            revert AtLeastOneShare();
        }

        if (getCurrentFloorPrice(creatorAddress) < experience.minRedemptionPrice && !isAllowedContract) {
            revert LessThanMinimumRedemptionPrice();
        }

        address ref_ = experience.ref;

        uint256 appFee;
        uint256 creatorFee;
        uint256 shareholdersFee;

        uint256 refFee;
        if (ref_ != address(0)) {
            refFee = (currentPrice * refFeePercentage_Redeem) / _BASIS_POINTS;
            appFee = (currentPrice * appFeePercentage_Redeem_WithRef) / _BASIS_POINTS;
            creatorFee = (currentPrice * creatorFeePercentage_Redeem_WithRef) / _BASIS_POINTS;
            shareholdersFee = (currentPrice * shareholdersFeePercentage_Redeem_WithRef) / _BASIS_POINTS;

            payable(ref_).transfer(refFee);
        } else {
            appFee = (currentPrice * appFeePercentage_Redeem_WithoutRef) / _BASIS_POINTS;
            creatorFee = (currentPrice * creatorFeePercentage_Redeem_WithoutRef) / _BASIS_POINTS;
            shareholdersFee = (currentPrice * shareholdersFeePercentage_Redeem_WithoutRef) / _BASIS_POINTS;
        }

        payable(owner()).transfer(appFee);
        payable(experiences[creatorAddress].creator).transfer(creatorFee);

        experiences[creatorAddress].fundsCollected += shareholdersFee;

        experience.sharesOwned[msg.sender] -= shares;
        experience.totalShares -= shares;

        SharesRedeemedEvent memory _event = SharesRedeemedEvent(
            from,
            shares,
            currentPrice,
            appFee,
            creatorFee,
            shareholdersFee,
            refFee,
            experience.creator,
            experience.totalShares,
            ref_
        );

        emit SharesRedeemed(_event);
    }

    /**
     * @notice Transfer minutes to another address
     * @param creatorAddress Creator of the experience
     * @param from Owner of the minutes
     * @param to New owner of the minutes
     * @param shares Amount of minutes to transfer
     * @dev Used only by internal contracts, not meant for public use
     */
    function transferShare(address creatorAddress, address from, address to, uint256 shares) public {
        require(allowedToTransfer[msg.sender], "Not allowed to transfer");

        Experience storage experience = experiences[creatorAddress];

        if (experience.sharesOwned[from] < shares) {
            revert NotEnoughSharesOwned();
        }

        experience.sharesOwned[from] -= shares;
        experience.sharesOwned[to] += shares;

        emit SharesTransferred(from, to, shares);
    }

    function experienceExists(address creatorAddress) public view returns (bool) {
        return experiences[creatorAddress].creator != address(0);
    }

    /**
     * @notice Get the current floor price for a creator
     * @param creatorAddress Creator of the experience
     */
    function getCurrentFloorPrice(address creatorAddress) public view returns (uint256) {
        uint256 totalShares = experiences[creatorAddress].totalShares;

        return BASE_PRICE + A * totalShares ** 2 + B * totalShares + C;
    }

    /**
     * @notice Create a new experience settings minumum price and referral address
     * @param minPrice Minimum minute price to allow redemptions
     * @param _ref Referral address that will receive a fee
     */
    function createExperience(uint256 minPrice, address _ref) external isPaused returns (address) {
        // Make sure its the user's first experience
        require(!hasAnExperience[msg.sender], "User already has an experience");
        require(_ref != msg.sender, "Cannot refer yourself");

        Experience storage newExperience_ = experiences[msg.sender];

        newExperience_.totalShares = 1;
        newExperience_.creator = msg.sender;
        newExperience_.fundsCollected = 0;
        newExperience_.minRedemptionPrice = minPrice;
        newExperience_.sharesOwned[msg.sender] = 1;
        newExperience_.ref = _ref;

        hasAnExperience[msg.sender] = true;

        emit SharesCreated(msg.sender, _ref);

        return msg.sender;
    }

    /**
     * @notice Update the minimum redemption price for an experience
     * @param creatorAddress Creator of the experience
     * @param minPrice Minimum minute price to allow redemptions
     */
    function updateMinRedemptionPrice(address creatorAddress, uint256 minPrice) external {
        require(msg.sender == experiences[creatorAddress].creator, "Only creator can update");
        experiences[creatorAddress].minRedemptionPrice = minPrice;
    }

    /**
     * @notice Get the total cost of buying minutes in an experience without fees, `totalCostWithFees` will give more precise results since it includes fees
     * @param numShares Number of minutes to buy
     * @param totalSupply Total supply of minutes
     */
    function calculateTotalCost(uint256 numShares, uint256 totalSupply) public pure returns (uint256) {
        uint256 initialShares = totalSupply;

        uint256 finalShares = initialShares + numShares - 1;

        uint256 sumSquares = (finalShares * (finalShares + 1) * (2 * finalShares + 1) / 6)
            - ((initialShares - 1) * initialShares * (2 * (initialShares - 1) + 1) / 6);

        uint256 sumFirstN = (finalShares * (finalShares + 1) / 2) - ((initialShares - 1) * initialShares / 2);

        uint256 totalCost = (BASE_PRICE * numShares) + (A * sumSquares) + (B * sumFirstN) + (C * numShares);

        return totalCost;
    }

    function getBalanceOfShares(address creatorAddress, address user) public view returns (uint256) {
        return experiences[creatorAddress].sharesOwned[user];
    }

    /**
     * @notice Retrieve funds collected by the creator
     */
    function retrieveShareHolderFunds() external {
        Experience storage experience = experiences[msg.sender];

        uint256 collected = experience.fundsCollected;

        require(msg.sender == experience.creator, "Only creator can retrieve funds");
        require(collected > 0, "No funds to retrieve");

        experience.fundsCollected = 0;

        payable(msg.sender).transfer(collected);
    }

    function updateAllowedToTransfer(address _address, bool _allowed) public {
        require(msg.sender == _owner, "Only owner can update");
        allowedToTransfer[_address] = _allowed;
    }

    function updatePaused(bool _paused_) external {
        require(msg.sender == _owner, "Only owner can update");
        _paused = _paused_;
    }

    function paused() public view returns (bool) {
        return _paused;
    }

    modifier isPaused() {
        require(!_paused, "Contract is paused");
        _;
    }

    function owner() public view returns (address) {
        return _owner;
    }
}
设置
{
  "compilationTarget": {
    "TimeBasedExperience.sol": "TimeBasedExperience"
  },
  "evmVersion": "shanghai",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "optimizer": {
    "enabled": false,
    "runs": 200
  },
  "remappings": []
}
ABI
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AtLeastOneShare","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"LessThanMinShare","type":"error"},{"inputs":[],"name":"LessThanMinimumRedemptionPrice","type":"error"},{"inputs":[],"name":"NotEnoughEthSent","type":"error"},{"inputs":[],"name":"NotEnoughSharesOwned","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"creator","type":"address"},{"indexed":false,"internalType":"address","name":"referrer","type":"address"}],"name":"SharesCreated","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"totalCost","type":"uint256"},{"internalType":"uint256","name":"feeToApp","type":"uint256"},{"internalType":"uint256","name":"feeToCreator","type":"uint256"},{"internalType":"uint256","name":"feeToShareholders","type":"uint256"},{"internalType":"uint256","name":"feeToReferrer","type":"uint256"},{"internalType":"address","name":"experienceCreator","type":"address"},{"internalType":"uint256","name":"totalSupplyExperience","type":"uint256"},{"internalType":"address","name":"referrerAddress","type":"address"}],"indexed":false,"internalType":"struct TimeBasedExperience.SharesRedeemedEvent","name":"event_","type":"tuple"}],"name":"SharesRedeemed","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"bool","name":"isBuy","type":"bool"},{"internalType":"uint256","name":"totalCost","type":"uint256"},{"internalType":"uint256","name":"feeToApp","type":"uint256"},{"internalType":"uint256","name":"feeToCreator","type":"uint256"},{"internalType":"uint256","name":"feeToShareholders","type":"uint256"},{"internalType":"uint256","name":"feeToReferrer","type":"uint256"},{"internalType":"address","name":"experienceCreator","type":"address"},{"internalType":"uint256","name":"totalSupplyExperience","type":"uint256"},{"internalType":"address","name":"referrerAddress","type":"address"}],"indexed":false,"internalType":"struct TimeBasedExperience.SharesTradedEvent","name":"event_","type":"tuple"}],"name":"SharesTraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"SharesTransferred","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"allowedToTransfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"appFeePercentage_Redeem_WithRef","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"appFeePercentage_Redeem_WithoutRef","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"appFeePercentage_WithRef","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"appFeePercentage_WithoutRef","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creatorAddress","type":"address"},{"internalType":"uint256","name":"_minutes","type":"uint256"}],"name":"buyShares","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"numShares","type":"uint256"},{"internalType":"uint256","name":"totalSupply","type":"uint256"}],"name":"calculateTotalCost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"minPrice","type":"uint256"},{"internalType":"address","name":"_ref","type":"address"}],"name":"createExperience","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"creatorFeePercentage_Redeem_WithRef","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"creatorFeePercentage_Redeem_WithoutRef","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"creatorFeePercentage_WithRef","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"creatorFeePercentage_WithoutRef","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creatorAddress","type":"address"}],"name":"experienceExists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"experiences","outputs":[{"internalType":"uint256","name":"totalShares","type":"uint256"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"uint256","name":"fundsCollected","type":"uint256"},{"internalType":"uint256","name":"minRedemptionPrice","type":"uint256"},{"internalType":"address","name":"ref","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creatorAddress","type":"address"},{"internalType":"address","name":"user","type":"address"}],"name":"getBalanceOfShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creatorAddress","type":"address"}],"name":"getCurrentFloorPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"hasAnExperience","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minSharesToRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creatorAddress","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"redeemShares","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"creatorAddress","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"from","type":"address"}],"name":"redeemSharesAllowed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"refFeePercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"refFeePercentage_Redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"retrieveShareHolderFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"creatorAddress","type":"address"},{"internalType":"uint256","name":"_minutes","type":"uint256"}],"name":"sellShares","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"shareholdersFeePercentage_Redeem_WithRef","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"shareholdersFeePercentage_Redeem_WithoutRef","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"shareholdersFeePercentage_WithRef","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"shareholdersFeePercentage_WithoutRef","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creatorAddress","type":"address"},{"internalType":"uint256","name":"_minutes","type":"uint256"},{"internalType":"bool","name":"isBuy","type":"bool"}],"name":"totalCostWithFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creatorAddress","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"transferShare","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"bool","name":"_allowed","type":"bool"}],"name":"updateAllowedToTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"creatorAddress","type":"address"},{"internalType":"uint256","name":"minPrice","type":"uint256"}],"name":"updateMinRedemptionPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_paused_","type":"bool"}],"name":"updatePaused","outputs":[],"stateMutability":"nonpayable","type":"function"}]