Skip to content

Commit

Permalink
feat: return metadata with bonding price and price deprecation
Browse files Browse the repository at this point in the history
  • Loading branch information
VanshSahay committed Feb 13, 2025
1 parent d2036c9 commit 9ca6bc4
Show file tree
Hide file tree
Showing 6 changed files with 791 additions and 149 deletions.
197 changes: 197 additions & 0 deletions broadcast/DeployBondingCurve.s.sol/84532/run-1739480875.json

Large diffs are not rendered by default.

148 changes: 74 additions & 74 deletions broadcast/DeployBondingCurve.s.sol/84532/run-latest.json

Large diffs are not rendered by default.

61 changes: 50 additions & 11 deletions src/DatasetBondingCurve.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity ^0.8.18;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {DatasetToken} from "./DeployDataset.sol";
import {console2} from "forge-std/console2.sol";

contract DatasetBondingCurve is Ownable {
using Math for uint256;
Expand All @@ -14,11 +15,17 @@ contract DatasetBondingCurve is Ownable {
// Bonding curve parameters
uint256 public constant PRICE_MULTIPLIER = 1.5 ether; // 1.5x increase per token
uint256 public constant DENOMINATOR = 1 ether;
uint256 public constant WEEK = 7 days;
uint256 public constant DEPRECIATION_RATE = 0.9 ether; // 10% decrease per week of no purchases

// Mapping to store initial prices for each token
mapping(uint256 => uint256) public tokenInitialPrices;
// Mapping to store the number of purchases for each token
mapping(uint256 => uint256) public tokenPurchaseCount;
// Mapping to store the last purchase timestamp for each token
mapping(uint256 => uint256) public lastPurchaseTimestamp;
// Mapping to store the current base price for each token (after depreciation)
mapping(uint256 => uint256) public currentBasePrices;

event PriceCalculated(uint256 indexed tokenId, uint256 price);
event InitialPriceSet(uint256 indexed tokenId, uint256 initialPrice);
Expand Down Expand Up @@ -48,22 +55,28 @@ contract DatasetBondingCurve is Ownable {
require(tokenInitialPrices[tokenId] == 0, "Initial price already set");

tokenInitialPrices[tokenId] = initialPrice;
currentBasePrices[tokenId] = initialPrice;
lastPurchaseTimestamp[tokenId] = block.timestamp;
emit InitialPriceSet(tokenId, initialPrice);
}

/**
* @dev Calculate the price for a specific token based on its bonding curve
* Price = initialPrice * (PRICE_MULTIPLIER ^ purchaseCount)
* Price = currentBasePrice * (DEPRECIATION_RATE ^ weeksSinceLastPurchase)
*/
function calculatePrice(uint256 tokenId) public returns (uint256) {
require(tokenInitialPrices[tokenId] > 0, "Token initial price not set");

uint256 price = tokenInitialPrices[tokenId];
uint256 purchases = tokenPurchaseCount[tokenId];
uint256 price = currentBasePrices[tokenId];

// Apply multiplier based on number of purchases
for (uint256 i = 0; i < purchases; i++) {
price = (price * PRICE_MULTIPLIER) / DENOMINATOR;
// Calculate weeks since last purchase
uint256 timeSinceLastPurchase = block.timestamp -
lastPurchaseTimestamp[tokenId];
uint256 weeksSinceLastPurchase = timeSinceLastPurchase / WEEK;

// Apply depreciation based on weeks without purchases
for (uint256 i = 0; i < weeksSinceLastPurchase; i++) {
price = (price * DEPRECIATION_RATE) / DENOMINATOR;
}

emit PriceCalculated(tokenId, price);
Expand All @@ -76,12 +89,25 @@ contract DatasetBondingCurve is Ownable {
function getCurrentPrice(uint256 tokenId) external view returns (uint256) {
require(tokenInitialPrices[tokenId] > 0, "Token initial price not set");

uint256 price = tokenInitialPrices[tokenId];
uint256 purchases = tokenPurchaseCount[tokenId];
uint256 price = currentBasePrices[tokenId];
console2.log("Base price:", price);

// Calculate weeks since last purchase
uint256 timeSinceLastPurchase = block.timestamp -
lastPurchaseTimestamp[tokenId];
uint256 weeksSinceLastPurchase = timeSinceLastPurchase / WEEK;
console2.log("Weeks since last purchase:", weeksSinceLastPurchase);
console2.log("Time since last purchase:", timeSinceLastPurchase);
console2.log("Current timestamp:", block.timestamp);
console2.log(
"Last purchase timestamp:",
lastPurchaseTimestamp[tokenId]
);

// Apply multiplier based on number of purchases
for (uint256 i = 0; i < purchases; i++) {
price = (price * PRICE_MULTIPLIER) / DENOMINATOR;
// Apply depreciation based on weeks without purchases
for (uint256 i = 0; i < weeksSinceLastPurchase; i++) {
price = (price * DEPRECIATION_RATE) / DENOMINATOR;
console2.log("Price after depreciation step:", price);
}

return price;
Expand All @@ -98,6 +124,19 @@ contract DatasetBondingCurve is Ownable {
);
require(tokenInitialPrices[tokenId] > 0, "Token initial price not set");

// Get the current price (with depreciation)
uint256 currentPrice = calculatePrice(tokenId);

// Set the base price to the current price
currentBasePrices[tokenId] = currentPrice;

// Calculate the new price for the next purchase (1.5x)
currentBasePrices[tokenId] =
(currentBasePrices[tokenId] * PRICE_MULTIPLIER) /
DENOMINATOR;

// Reset the last purchase timestamp
lastPurchaseTimestamp[tokenId] = block.timestamp;
tokenPurchaseCount[tokenId]++;
}

Expand Down
96 changes: 69 additions & 27 deletions src/DeployDataset.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ contract DatasetToken is ERC1155, Ownable, ReentrancyGuard {
string description;
string contentHash;
string ipfsHash; // IPFS hash for the dataset file
uint256 price; // Price in wei
string[] tags; // Array of tags for the dataset
OwnershipShare[] owners; // Array of owners with their ownership percentages
uint256 price; // Current price from bonding curve (not stored, dynamically fetched)
}

// Mapping token ID to dataset metadata
mapping(uint256 => DatasetMetadata) public tokenMetadata;
mapping(uint256 => DatasetMetadata) private _tokenMetadata;

// Mapping from token ID to whether it's listed for sale
mapping(uint256 => bool) public isListed;
Expand Down Expand Up @@ -122,19 +122,18 @@ contract DatasetToken is ERC1155, Ownable, ReentrancyGuard {
uint256 tokenId = _currentTokenId++;

// Store metadata
tokenMetadata[tokenId].name = name;
tokenMetadata[tokenId].description = description;
tokenMetadata[tokenId].contentHash = contentHash;
tokenMetadata[tokenId].ipfsHash = ipfsHash;
tokenMetadata[tokenId].price = initialPrice;
tokenMetadata[tokenId].tags = tags;
_tokenMetadata[tokenId].name = name;
_tokenMetadata[tokenId].description = description;
_tokenMetadata[tokenId].contentHash = contentHash;
_tokenMetadata[tokenId].ipfsHash = ipfsHash;
_tokenMetadata[tokenId].tags = tags;

// Initialize bonding curve for this token
bondingCurve.setInitialPrice(tokenId, initialPrice);

// Store ownership information
for (uint256 i = 0; i < owners.length; i++) {
tokenMetadata[tokenId].owners.push(owners[i]);
_tokenMetadata[tokenId].owners.push(owners[i]);
_mint(owners[i].owner, tokenId, 1, "");
}

Expand Down Expand Up @@ -173,7 +172,7 @@ contract DatasetToken is ERC1155, Ownable, ReentrancyGuard {
uint256 currentPrice = bondingCurve.getCurrentPrice(tokenId);
require(msg.value == currentPrice, "Incorrect payment amount");

DatasetMetadata storage metadata = tokenMetadata[tokenId];
DatasetMetadata storage metadata = _tokenMetadata[tokenId];
uint256 totalAmount = msg.value;

// Transfer ownership shares and payments
Expand Down Expand Up @@ -222,7 +221,7 @@ contract DatasetToken is ERC1155, Ownable, ReentrancyGuard {
function getTokenTags(
uint256 tokenId
) external view returns (string[] memory) {
return tokenMetadata[tokenId].tags;
return _tokenMetadata[tokenId].tags;
}

/**
Expand All @@ -231,27 +230,71 @@ contract DatasetToken is ERC1155, Ownable, ReentrancyGuard {
function getTokenOwners(
uint256 tokenId
) external view returns (OwnershipShare[] memory) {
return tokenMetadata[tokenId].owners;
return _tokenMetadata[tokenId].owners;
}

/**
* @dev Update the price of a dataset
* @dev Get the current price of a dataset from the bonding curve
* @param tokenId The ID of the token
* @param newPrice The new price in wei
* @return The current price in wei
*/
function updatePrice(uint256 tokenId, uint256 newPrice) external {
require(newPrice > 0, "Price must be greater than 0");
require(
tokenMetadata[tokenId].owners.length > 0,
"Dataset has no owners"
);
require(
msg.sender == tokenMetadata[tokenId].owners[0].owner,
"Only primary owner can update price"
function getCurrentPrice(uint256 tokenId) public view returns (uint256) {
require(address(bondingCurve) != address(0), "Bonding curve not set");
return bondingCurve.getCurrentPrice(tokenId);
}

/**
* @dev Get dataset metadata including current price
*/
function getDatasetMetadata(
uint256 tokenId
)
external
view
returns (
string memory name,
string memory description,
string memory contentHash,
string memory ipfsHash,
uint256 currentPrice,
string[] memory tags
)
{
DatasetMetadata storage metadata = _tokenMetadata[tokenId];
return (
metadata.name,
metadata.description,
metadata.contentHash,
metadata.ipfsHash,
getCurrentPrice(tokenId),
metadata.tags
);
}

tokenMetadata[tokenId].price = newPrice;
emit PriceUpdated(tokenId, newPrice);
/**
* @dev Get all dataset metadata for all tokens
* @return allMetadata An array of all dataset metadata including current prices
*/
function getAllDatasetMetadata()
external
view
returns (DatasetMetadata[] memory allMetadata)
{
uint256 totalTokens = _currentTokenId;
allMetadata = new DatasetMetadata[](totalTokens);

for (uint256 i = 0; i < totalTokens; i++) {
DatasetMetadata storage metadata = _tokenMetadata[i];
allMetadata[i].name = metadata.name;
allMetadata[i].description = metadata.description;
allMetadata[i].contentHash = metadata.contentHash;
allMetadata[i].ipfsHash = metadata.ipfsHash;
allMetadata[i].tags = metadata.tags;
allMetadata[i].owners = metadata.owners;
allMetadata[i].price = getCurrentPrice(i);
}

return allMetadata;
}

/**
Expand Down Expand Up @@ -289,7 +332,6 @@ contract DatasetToken is ERC1155, Ownable, ReentrancyGuard {

/**
* @dev Get the IPFS hash for a purchased dataset
* @param tokenId The ID of the token
*/
function getDatasetIPFSHash(
uint256 tokenId
Expand All @@ -298,6 +340,6 @@ contract DatasetToken is ERC1155, Ownable, ReentrancyGuard {
balanceOf(msg.sender, tokenId) > 0,
"Caller does not own this dataset"
);
return tokenMetadata[tokenId].ipfsHash;
return _tokenMetadata[tokenId].ipfsHash;
}
}
Loading

0 comments on commit 9ca6bc4

Please sign in to comment.