-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
65c6d14
commit 734ae45
Showing
8 changed files
with
294 additions
and
68 deletions.
There are no files selected for viewing
Submodule openzeppelin-contracts
updated
122 files
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} |