Skip to content

Commit

Permalink
done thank you jesus
Browse files Browse the repository at this point in the history
  • Loading branch information
georgegoldman committed Nov 1, 2024
1 parent 65c6d14 commit 734ae45
Show file tree
Hide file tree
Showing 8 changed files with 294 additions and 68 deletions.
2 changes: 1 addition & 1 deletion lib/openzeppelin-contracts
19 changes: 0 additions & 19 deletions script/Counter.s.sol

This file was deleted.

14 changes: 0 additions & 14 deletions src/Counter.sol

This file was deleted.

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


contract CollaborativeNFTOwnership {
struct Contributor {
uint256 shares; // Share percentage (e.g., 100 = 100%)
bool exists; // You can add more fields if necessary
}

mapping(address => Contributor) public contributors;
address[] public contributorAddresses;
uint256 public totalShares;
address public owner; // Owner on Lisk

event NFTPurchased(address indexed buyer, uint256 totalPaid, uint256 tokenId);
event SharesAssigned(address indexed contributor, uint256 shares);
event PaymentDistributed(address indexed contributor, uint256 amount);

modifier onlyOwner(){
require(msg.sender == owner, "not owner");
_;
}

constructor() {
totalShares = 100; // Total shares represent 100% ownership
owner = msg.sender;
}

// Assign shares to each contributor based on collaboration percentage
function assignShares(address[] memory _contributors, uint256[] memory _shares) external onlyOwner {
require(_contributors.length == _shares.length, "Contributors and shares length mismatch");

for (uint256 i = 0; i < _contributors.length; i++) {
address contributor = _contributors[i];
uint256 share = _shares[i];
require(share > 0, "Shares must be greater than zero");
require(!contributors[contributor].exists, "Contributor already exists");

contributors[contributor] = Contributor(share, true);
contributorAddresses.push(contributor);

emit SharesAssigned(contributor, share);
}
}

// Function to purchase the NFT, triggering payment distribution and ownership transfer event
function buyNFT(uint256 tokenId) external payable {
require(msg.value > 0, "Payment is required to buy NFT");

// Distribute payment based on shares
uint256 totalPayment = msg.value;

for (uint256 i = 0; i < contributorAddresses.length; i++) {
address contributor = contributorAddresses[i];
uint256 contributorShare = (contributors[contributor].shares * totalPayment) / totalShares;
(bool success, ) = contributor.call{value: contributorShare}("");
require(success, "Payment to contributor failed");

emit PaymentDistributed(contributor, contributorShare);
}

// Emit NFT purchase event for bridge to trigger ownership update on Lisk
emit NFTPurchased(msg.sender, totalPayment, tokenId);
}
}
52 changes: 42 additions & 10 deletions src/NFT.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,49 @@ pragma solidity ^0.8.23;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

contract NFT is ERC721 {

contract SecureNFTMinter is ERC721 {
uint256 public currentTokenId;
mapping(uint256 => string) private _tokenURIs;
address public bridgeAddress; // Address of the bridge contract on Lisk

modifier onlyOwner(){
require(bridgeAddress == address(this), "must be the contract");
_;
}

constructor(string memory name, string memory symbol) ERC721(name, symbol) {
bridgeAddress = address(this);
}

// Function to mint an NFT, accessible to anyone
function mintNFT(address to, string memory newTokenURI) external returns (uint256) {
uint256 tokenId = ++currentTokenId;
_safeMint(to, tokenId);
_setTokenURI(tokenId, newTokenURI); // Set the CID as the token URI
return tokenId;
}

// Internal function to set the token URI (CID)
function _setTokenURI(uint256 tokenId, string memory newTokenURI) internal {
_tokenURIs[tokenId] = newTokenURI;
}

// Override tokenURI function to return the IPFS URI
function tokenURI(uint256 tokenId) public view override returns (string memory) {
return string(abi.encodePacked("ipfs://", _tokenURIs[tokenId]));
}

// Function to set the bridge address (only the contract owner can do this)
function setBridgeAddress(address _bridgeAddress) external onlyOwner {
bridgeAddress = _bridgeAddress;
}

// The following will create an ERC721 Token called Lisk.
constructor() ERC721("Lisk", "LSK") {}
// Function to transfer ownership of an NFT, restricted to the bridge contract
function transferNFT(uint256 tokenId, address newOwner) external {
require(msg.sender == bridgeAddress, "Only the bridge can transfer ownership");
// require(_exists(tokenId), "Token does not exist");

// mint function
function mint(address recipient) public payable returns (uint256) {
uint256 newItemId = ++currentTokenId;
_safeMint(recipient, newItemId);
return newItemId;
address currentOwner = ownerOf(tokenId);
_transfer(currentOwner, newOwner, tokenId); // Transfer ownership to the new owner
}
}
}
24 changes: 0 additions & 24 deletions test/Counter.t.sol

This file was deleted.

117 changes: 117 additions & 0 deletions test/FractionalNFT.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// SPDX-License-Identifier: SEE LICENSE IN LICENSE
pragma solidity ^0.8.23;

import {Test, console} from "forge-std/Test.sol";
import "forge-std/Script.sol";
import {CollaborativeNFTOwnership} from "../src/FractionalNFT.sol";

contract CollaborativeNFTOwnershipTest is Test {
CollaborativeNFTOwnership nftContract;
address owner = address(this);
address contributor1 = address(0x123);
address contributor2 = address(0x456);

function setUp() public {
// Deploy the contract
nftContract = new CollaborativeNFTOwnership();
}

function testAssignShares() public {
// Initialize test data
address[] memory contributors = new address[](2);
contributors[0] = contributor1;
contributors[1] = contributor2;

uint256[] memory shares = new uint256[](2);
shares[0] = 60;
shares[1] = 40;

// Assign shares
nftContract.assignShares(contributors, shares);

// Check if shares were assigned correctly
(uint256 contributor1Shares, bool exists1) = nftContract.contributors(contributor1);
(uint256 contributor2Shares, bool exists2) = nftContract.contributors(contributor2);

assertTrue(exists1, "Contributor1 should exist");
assertTrue(exists2, "Contributor2 should exist");
assertEq(contributor1Shares, 60, "Contributor1 should have 60 shares");
assertEq(contributor2Shares, 40, "Contributor2 should have 40 shares");
}

function testAssignSharesOnlyOwner() public {
// Simulate a non-owner trying to assign shares
vm.prank(address(0x789));
address[] memory contributors = new address[](2);
contributors[0] = contributor1;
contributors[1] = contributor2;
uint256[] memory shares = new uint256[](2);
shares[0] = 60;
shares[1] = 40;

// Expect the transaction to revert due to onlyOwner modifier
vm.expectRevert("not owner");
nftContract.assignShares(contributors, shares);
}

function testBuyNFTAndDistributePayments() public {
// Assign shares to contributors
uint256[] memory shares = new uint256[](2);
shares[0] = 60;
shares[1] = 40;

// Start tracking balance for contributors
uint256 initialBalanceContributor1 = contributor1.balance;
uint256 initialBalanceContributor2 = contributor2.balance;

// Buy NFT and pay 1 ether
uint256 tokenId = 1;
vm.deal(address(this), 1 ether); // Fund the buyer
nftContract.buyNFT{value: 1 ether}(tokenId);

// Calculate expected payments
uint256 expectedPaymentContributor1 = (60 * 1 ether) / 100;
uint256 expectedPaymentContributor2 = (40 * 1 ether) / 100;

// Verify balances after payment distribution
assertEq(contributor1.balance, initialBalanceContributor1 + expectedPaymentContributor1, "Contributor1 should receive 60%");
assertEq(contributor2.balance, initialBalanceContributor2 + expectedPaymentContributor2, "Contributor2 should receive 40%");
}

function testBuyNFTNoPaymentShouldFail() public {
uint256 tokenId = 1;

// Expect the transaction to revert due to zero payment
vm.expectRevert("Payment is required to buy NFT");
nftContract.buyNFT(tokenId);
}

function testDoubleAssignSharesFails() public {
// Assign shares to contributors
address[] memory contributors = new address[](2);
contributors[0] = contributor1;
contributors[1] = contributor2;
uint256[] memory shares = new uint256[](2);
shares[0] = 60;
shares[1] = 40;
nftContract.assignShares(contributors, shares);

// Attempt to assign shares to the same contributor again should fail
vm.expectRevert("Contributor already exists");
nftContract.assignShares(contributors, shares);
}

function testAssignSharesInvalidLengthShouldFail() public {
// Set up mismatched lengths for contributors and shares
address[] memory contributors = new address[](2);
contributors[0] = contributor1;
contributors[1] = contributor2;
uint256[] memory shares = new uint256[](2);
shares[0] = 60;
shares[1] = 40;

// Expect the transaction to revert due to length mismatch
vm.expectRevert("Contributors and shares length mismatch");
nftContract.assignShares(contributors, shares);
}
}
68 changes: 68 additions & 0 deletions test/NFT.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import {Test, console} from "forge-std/Test.sol";
import {SecureNFTMinter} from "../src/NFT.sol";

contract SecureNFTMinterTest is Test {
SecureNFTMinter nftMinter;
address owner = address(0x1);
address bridge = address(0x2);
address user1 = address(0x3);
address user2 = address(0x4);

function setUp() public {
vm.prank(owner);
nftMinter = new SecureNFTMinter("TestNFT", "TNFT");
}

function testMintNFT() public {
// Mint an NFT for user1
vm.prank(user1);
uint256 tokenId = nftMinter.mintNFT(user1, "QmExampleHash123");

// Check that the tokenId incremented correctly and ownership is set
assertEq(nftMinter.ownerOf(tokenId), user1);
assertEq(nftMinter.tokenURI(tokenId), "ipfs://QmExampleHash123");
}

function testSetBridgeAddress() public {
// Set the bridge address as the owner
vm.prank(owner);
nftMinter.setBridgeAddress(bridge);

// Verify the bridge address was set
assertEq(nftMinter.bridgeAddress(), bridge);
}

function testTransferNFTByBridge() public {
// Mint an NFT for user1
vm.prank(user1);
uint256 tokenId = nftMinter.mintNFT(user1, "QmExampleHash123");

// Set the bridge address
vm.prank(owner);
nftMinter.setBridgeAddress(bridge);

// Attempt transfer by bridge to user2
vm.prank(bridge);
nftMinter.transferNFT(tokenId, user2);

// Verify the new ownership
assertEq(nftMinter.ownerOf(tokenId), user2);
}

function testFailTransferNFTByNonBridge() public {
// Mint an NFT for user1
vm.prank(user1);
uint256 tokenId = nftMinter.mintNFT(user1, "QmExampleHash123");

// Set the bridge address
vm.prank(owner);
nftMinter.setBridgeAddress(bridge);

// Attempt transfer by non-bridge address (should fail)
vm.prank(user1);
nftMinter.transferNFT(tokenId, user2); // This should revert
}
}

0 comments on commit 734ae45

Please sign in to comment.