Skip to content

Commit

Permalink
Merge pull request #1 from treenteq/feature/CurrentSetup
Browse files Browse the repository at this point in the history
Feature/CurrentSetup
  • Loading branch information
VanshSahay authored Feb 12, 2025
2 parents c132e87 + 0c8dc77 commit f10bb58
Show file tree
Hide file tree
Showing 10 changed files with 661 additions and 63 deletions.
7 changes: 1 addition & 6 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,12 @@ jobs:
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly
version: stable

- name: Show Forge version
run: |
forge --version
- name: Run Forge fmt
run: |
forge fmt --check
id: fmt

- name: Run Forge build
run: |
forge build --sizes
Expand Down
71 changes: 71 additions & 0 deletions broadcast/DeployDataset.s.sol/84532/run-1739234491.json

Large diffs are not rendered by default.

71 changes: 71 additions & 0 deletions broadcast/DeployDataset.s.sol/84532/run-latest.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
src = "src"
out = "out"
libs = ["lib"]
remappings = ["@openzeppelin/=lib/openzeppelin-contracts/"]

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
19 changes: 0 additions & 19 deletions script/Counter.s.sol

This file was deleted.

28 changes: 28 additions & 0 deletions script/DeployDataset.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

import {Script} from "forge-std/Script.sol";
import {DatasetToken} from "../src/DeployDataset.sol";

contract DeployDatasetScript is Script {
function setUp() public {}

function run() public {
// Retrieve the private key from environment variable
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");

// Start broadcasting transactions
vm.startBroadcast(deployerPrivateKey);

// Deploy the contract
// Parameters:
// 1. Base URI for metadata (e.g., IPFS gateway URL)
// 2. Initial owner address (msg.sender in this case)
new DatasetToken(
"https://api.example.com/metadata/", // Replace with your actual metadata URI NOTE: Discuss with Rahul on how we were setting this up
vm.addr(deployerPrivateKey) // Set deployer as initial owner
);

vm.stopBroadcast();
}
}
14 changes: 0 additions & 14 deletions src/Counter.sol

This file was deleted.

282 changes: 282 additions & 0 deletions src/DeployDataset.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,282 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

contract DatasetToken is ERC1155, Ownable, ReentrancyGuard {
// Token ID counter
uint256 private _currentTokenId;

struct OwnershipShare {
address owner;
uint256 percentage; // Percentage multiplied by 100 (e.g., 33.33% = 3333)
}

struct DatasetMetadata {
string name;
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
}

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

// Mapping from token ID to whether it's listed for sale
mapping(uint256 => bool) public isListed;

// Mapping from tag to token IDs
mapping(string => uint256[]) private _tagToTokenIds;

// Events
event DatasetTokenMinted(
address[] owners,
uint256[] percentages,
uint256 indexed tokenId,
string name,
string contentHash,
string ipfsHash,
uint256 price,
string[] tags
);

event DatasetPurchased(
uint256 indexed tokenId,
address indexed buyer,
address[] sellers,
uint256[] amounts
);

event PriceUpdated(uint256 indexed tokenId, uint256 newPrice);

/**
* @dev Constructor to initialize the contract.
* @param uri The base URI for metadata.
* @param initialOwner The address of the initial owner.
*/
constructor(
string memory uri,
address initialOwner
) ERC1155(uri) Ownable(initialOwner) {}

/**
* @dev Validate ownership percentages add up to 10000 (100%)
*/
function validateOwnershipShares(
OwnershipShare[] memory shares
) internal pure {
uint256 totalPercentage;
for (uint256 i = 0; i < shares.length; i++) {
require(
shares[i].percentage > 0,
"Percentage must be greater than 0"
);
require(shares[i].owner != address(0), "Invalid owner address");
totalPercentage += shares[i].percentage;
}
require(totalPercentage == 10000, "Total percentage must equal 100%");
}

/**
* @dev Mint a new dataset token with multiple owners
*/
function mintDatasetToken(
OwnershipShare[] memory owners,
string memory name,
string memory description,
string memory contentHash,
string memory ipfsHash,
uint256 price,
string[] memory tags
) external onlyOwner {
require(bytes(contentHash).length > 0, "Content hash is required");
require(bytes(ipfsHash).length > 0, "IPFS hash is required");
require(price > 0, "Price must be greater than 0");
require(owners.length > 0, "At least one owner required");
require(tags.length > 0, "At least one tag required");

validateOwnershipShares(owners);

uint256 tokenId = _currentTokenId++;

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

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

// Index tags
for (uint256 i = 0; i < tags.length; i++) {
_tagToTokenIds[tags[i]].push(tokenId);
}

isListed[tokenId] = true;

// Prepare arrays for event
address[] memory ownerAddresses = new address[](owners.length);
uint256[] memory percentages = new uint256[](owners.length);
for (uint256 i = 0; i < owners.length; i++) {
ownerAddresses[i] = owners[i].owner;
percentages[i] = owners[i].percentage;
}

emit DatasetTokenMinted(
ownerAddresses,
percentages,
tokenId,
name,
contentHash,
ipfsHash,
price,
tags
);
}

/**
* @dev Purchase a dataset token
*/
function purchaseDataset(uint256 tokenId) external payable nonReentrant {
require(isListed[tokenId], "Dataset is not listed for sale");
require(
msg.value == tokenMetadata[tokenId].price,
"Incorrect payment amount"
);

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

// Transfer ownership shares and payments
for (uint256 i = 0; i < metadata.owners.length; i++) {
address owner = metadata.owners[i].owner;
require(balanceOf(owner, tokenId) > 0, "Owner has no tokens");

// Calculate owner's share of the payment
uint256 ownerShare = (totalAmount * metadata.owners[i].percentage) /
10000;

// Transfer token
_safeTransferFrom(owner, msg.sender, tokenId, 1, "");

// Transfer payment
(bool success, ) = owner.call{value: ownerShare}("");
require(success, "Payment transfer failed");
}

// Prepare arrays for event
address[] memory sellers = new address[](metadata.owners.length);
uint256[] memory amounts = new uint256[](metadata.owners.length);
for (uint256 i = 0; i < metadata.owners.length; i++) {
sellers[i] = metadata.owners[i].owner;
amounts[i] = (totalAmount * metadata.owners[i].percentage) / 10000;
}

emit DatasetPurchased(tokenId, msg.sender, sellers, amounts);
}

/**
* @dev Get token IDs by tag
*/
function getTokensByTag(
string memory tag
) external view returns (uint256[] memory) {
return _tagToTokenIds[tag];
}

/**
* @dev Get all tags for a token
*/
function getTokenTags(
uint256 tokenId
) external view returns (string[] memory) {
return tokenMetadata[tokenId].tags;
}

/**
* @dev Get ownership shares for a token
*/
function getTokenOwners(
uint256 tokenId
) external view returns (OwnershipShare[] memory) {
return tokenMetadata[tokenId].owners;
}

/**
* @dev Update the price of a dataset
* @param tokenId The ID of the token
* @param newPrice The new 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"
);

tokenMetadata[tokenId].price = newPrice;
emit PriceUpdated(tokenId, newPrice);
}

/**
* @dev Get the total number of tokens minted
*/
function getTotalTokens() public view returns (uint256) {
return _currentTokenId;
}

/**
* @dev Get all token IDs owned by an address
* @param owner The address to check
*/
function getTokensByOwner(
address owner
) public view returns (uint256[] memory) {
uint256[] memory ownedTokens = new uint256[](_currentTokenId);
uint256 ownedCount = 0;

for (uint256 i = 0; i < _currentTokenId; i++) {
if (balanceOf(owner, i) > 0) {
ownedTokens[ownedCount] = i;
ownedCount++;
}
}

// Resize array to actual owned count
uint256[] memory result = new uint256[](ownedCount);
for (uint256 i = 0; i < ownedCount; i++) {
result[i] = ownedTokens[i];
}

return result;
}

/**
* @dev Get the IPFS hash for a purchased dataset
* @param tokenId The ID of the token
*/
function getDatasetIPFSHash(
uint256 tokenId
) external view returns (string memory) {
require(
balanceOf(msg.sender, tokenId) > 0,
"Caller does not own this dataset"
);
return tokenMetadata[tokenId].ipfsHash;
}
}
24 changes: 0 additions & 24 deletions test/Counter.t.sol

This file was deleted.

Loading

0 comments on commit f10bb58

Please sign in to comment.