# Contract Functions

## Token Exchange

{% code overflow="wrap" %}

```solidity
function buy(address ipId) public payable {
        require(checkListed(ipId), "IP is not listed");
        uint256 price = getBuyPrice(ipId);
        (uint256 creatorFee, uint256 protocolFee, uint256 totalFee) = _calcTradingFees(price);
        uint256 priceAfterFee = price + totalFee;
        require(msg.value >= priceAfterFee, "Insufficient payment");
        uint256 assetId = ipIdToAssetId[ipId];
        totalSupply[assetId] += 1;
        poolLiquidity[assetId] += price;
        _mint(msg.sender, assetId, 1, "");
        emit Trade(TradeType.Buy, ipId, assetId, msg.sender, 1, price, creatorFee);
        (bool creatorFeeSent, ) = payable(storyHelper.getIpOwner(ipId)).call{ value: creatorFee }("");
        require(creatorFeeSent, "Failed to send creator fee");
        if (protocolFee > 0) {
            (bool protocolFeeSent, ) = payable(owner()).call{ value: protocolFee }("");
            require(protocolFeeSent, "Failed to send protocol fee");
        }


        if (msg.value > priceAfterFee) {
            (bool refunded, ) = payable(msg.sender).call{ value: msg.value - priceAfterFee }("");
            require(refunded, "Failed to refund excess payment");
        }
    }
```

{% endcode %}

<pre class="language-solidity" data-overflow="wrap"><code class="lang-solidity"><strong>function sell(address ipId) public {
</strong>        require(checkListed(ipId), "IP is not listed");
        uint256 assetId = ipIdToAssetId[ipId];
        require(balanceOf(msg.sender, assetId) >= 1, "Insufficient balance");
        uint256 supply = totalSupply[assetId];
        require(supply - 1 >= PREMINT, "Supply not allowed below premint amount");
        uint256 price = getSellPrice(ipId);
        (uint256 creatorFee, uint256 protocolFee, uint256 totalFee) = _calcTradingFees(price);
        _burn(msg.sender, assetId, 1);
        totalSupply[assetId] = supply - 1;
        poolLiquidity[assetId] -= price;
        emit Trade(TradeType.Sell, ipId, assetId, msg.sender, 1, price, creatorFee);
        (bool sent, ) = payable(msg.sender).call{ value: price - totalFee }("");
        (bool creatorFeeSent, ) = payable(storyHelper.getIpOwner(ipId)).call{ value: creatorFee }("");
        require(sent &#x26;&#x26; creatorFeeSent, "Failed to send ether");
        if (protocolFee > 0) {
            (bool protocolFeeSent, ) = payable(owner()).call{ value: protocolFee }("");
            require(protocolFeeSent, "Failed to send protocol fee");
        }
    }
</code></pre>

## Remix

{% code overflow="wrap" %}

```solidity
function remix(
        address parentIpId,
        address licenseTemplate,
        uint256 licenseTermsId
    ) public returns (address childIpId) {
        require(checkListed(parentIpId), "IP is not listed");
        require(
            storyHelper.hasIpAttachedLicenseTerm(parentIpId, licenseTemplate, licenseTermsId),
            "IP does not have the license"
        );
        require(!storyHelper.isDisputed(parentIpId), "IP is disputed");
        uint256 parentAssetId = ipIdToAssetId[parentIpId];
        require(balanceOf(msg.sender, parentAssetId) >= PREMINT, "Insufficient balance");
        // Register childIP
        uint256 tokenId = remixingNFT.mint(address(this), storyHelper.getIpUri(parentIpId));
        childIpId = storyHelper.ipAssetRegistry().register(block.chainid, address(remixingNFT), tokenId);
        // Calc minting fee
        (address policy, , uint256 mintingLicenseFee, address currencyToken) = ILicenseTemplate(licenseTemplate)
            .getRoyaltyPolicy(licenseTermsId);
        uint256 configFee = storyHelper.getLicensingConfigFee(parentIpId, childIpId, licenseTemplate, licenseTermsId);
        if (configFee > 0) {
            mintingLicenseFee = configFee;
        }


        if (mintingLicenseFee > 0) {
            IERC20(currencyToken).transferFrom(msg.sender, address(this), mintingLicenseFee);
            IERC20(currencyToken).approve(policy, mintingLicenseFee);
        }
        // Mint derivative
        {
            address[] memory _parents = new address[](1);
            _parents[0] = parentIpId;
            uint256[] memory _lids = new uint256[](1);
            _lids[0] = licenseTermsId;
            storyHelper.licensingModule().registerDerivative(childIpId, _parents, _lids, licenseTemplate, "");
        }
        // Burn parent key
        uint256 sellPrice = getSellPrice(parentIpId);
        _burn(msg.sender, parentAssetId, 1);
        totalSupply[parentAssetId] -= 1;
        poolLiquidity[parentAssetId] -= sellPrice;
        emit Remix(parentIpId, childIpId, msg.sender, licenseTemplate, licenseTermsId, sellPrice, 0);
        uint256 childAssetId = _register(childIpId);
        emit List(childIpId, childAssetId, msg.sender);
        poolLiquidity[childAssetId] += sellPrice;
        remixFloorPrice[childIpId] = sellPrice;
        emit Trade(TradeType.Mint, childIpId, childAssetId, msg.sender, PREMINT, sellPrice, 0);
        remixingNFT.transferFrom(address(this), msg.sender, tokenId);
    }

```

{% endcode %}

## Price Curve

{% code overflow="wrap" fullWidth="false" %}

```solidity
function curve(uint256 x) public view returns (uint256) {
        int128 supply = ABDKMath64x64.fromUInt(x);
        int128 z = ABDKMath64x64.div(ABDKMath64x64.sub(supply, MEAN), STD);
        int128 a = ABDKMath64x64.abs(z);
        int128 t = ABDKMath64x64.inv(ABDKMath64x64.add(FP_ONE, ABDKMath64x64.mul(a, FP_P)));
        int128 w1 = 0;
        {
            int128 b4_add_t_mul_b5 = ABDKMath64x64.add(FP_MAGIC_NUMBER4, ABDKMath64x64.mul(t, FP_MAGIC_NUMBER5));
            int128 b3_add_t_mul_prev = ABDKMath64x64.add(FP_MAGIC_NUMBER3, ABDKMath64x64.mul(t, b4_add_t_mul_b5));
            int128 b2_add_t_mul_prev = ABDKMath64x64.add(FP_MAGIC_NUMBER2, ABDKMath64x64.mul(t, b3_add_t_mul_prev));
            int128 b1_add_t_mul_prev = ABDKMath64x64.add(FP_MAGIC_NUMBER1, ABDKMath64x64.mul(t, b2_add_t_mul_prev));
            w1 = ABDKMath64x64.mul(t, b1_add_t_mul_prev);
        }
        int128 expasqr = ABDKMath64x64.exp(ABDKMath64x64.neg(ABDKMath64x64.div(ABDKMath64x64.pow(a, 2), FP_TWO)));
        int128 tmp = ABDKMath64x64.mul(ABDKMath64x64.mul(INV_SQRT2PI, expasqr), w1);
        int128 w = ABDKMath64x64.sub(FP_ONE, tmp);
        uint256 price = ABDKMath64x64.mulu(w, BASE_PERCISION);
        if (z < 0) {
            return BASE_PERCISION - price;
        }
        return price;
    }

```

{% endcode %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://57blocks-1.gitbook.io/dolphin_hackathon/contract-functions.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
