Contract Functions
Token Exchange
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");
}
}
function sell(address ipId) public {
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 && creatorFeeSent, "Failed to send ether");
if (protocolFee > 0) {
(bool protocolFeeSent, ) = payable(owner()).call{ value: protocolFee }("");
require(protocolFeeSent, "Failed to send protocol fee");
}
}
Remix
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);
}
Price Curve
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;
}
Last updated