diff --git a/Asset-Tokenization.sol b/Asset-Tokenization.sol new file mode 100644 index 0000000..7270f69 --- /dev/null +++ b/Asset-Tokenization.sol @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; + +contract AssetTokenization is ERC1155, Ownable { + uint256 public currentTokenID = 0; + + enum AssetScope { Global, Regional, Local } + + struct AssetMetadata { + string name; + string description; + string assetType; + string location; + uint256 valuation; + uint256 createdAt; + address createdBy; + AssetScope scope; + } + + mapping(uint256 => AssetMetadata) public assetMetadata; + mapping(address => mapping(uint256 => uint256)) public lockedBalance; + + event TokensBurned(address indexed burner, uint256 indexed tokenID, uint256 amount); + event TokensTransferred(address indexed from, address indexed to, uint256 indexed tokenID, uint256 amount, bytes data); + event BatchMinted(address indexed minter, uint256[] tokenIDs, uint256[] amounts, AssetMetadata[] metadatas); + event TokensLocked(address indexed locker, uint256 indexed tokenID, uint256 amount, uint256 unlockTimestamp); + event TokensUnlocked(address indexed locker, uint256 indexed tokenID, uint256 amount); + + constructor(string memory uri) ERC1155(uri) Ownable(0x7e2eD6241f395E32c2fcEdCE0829e0506cbCFc79) {} + + function identifyAssetScope(uint8 scopeValue) internal pure returns (AssetScope) { + require(scopeValue >= uint8(AssetScope.Global) && scopeValue <= uint8(AssetScope.Local), "Invalid scope value"); + return AssetScope(scopeValue); + } + + function verifyAssetOwner(address account, uint256 tokenID) public view returns (bool) { + return balanceOf(account, tokenID) > 0; + } + + function verifyKYC() internal pure returns (bool) { + // Call Oracle API for KYC verification + // Implement your KYC verification logic here + // For demonstration purposes, returning true + return true; + } + + function mintAsset(address account, uint256 amount, bytes memory data, AssetMetadata memory metadata) public onlyOwner { + require(verifyKYC(), "Account is not KYC verified"); + assetMetadata[currentTokenID] = metadata; + _mint(account, currentTokenID, amount, data); + uint256[] memory tokenIDs = new uint256[](1); + uint256[] memory amountsArray = new uint256[](1); + AssetMetadata[] memory metadatasArray = new AssetMetadata[](1); + tokenIDs[0] = currentTokenID; + amountsArray[0] = amount; + metadatasArray[0] = metadata; + emit BatchMinted(account, tokenIDs, amountsArray, metadatasArray); + currentTokenID++; + } + + function batchMintAsset(address[] memory accounts, uint256[] memory amounts, bytes[] memory data, AssetMetadata[] memory metadatas) public onlyOwner { + require(accounts.length == amounts.length && accounts.length == data.length && accounts.length == metadatas.length, "Array lengths must match"); + uint256[] memory tokenIDs = new uint256[](accounts.length); + for (uint256 i = 0; i < accounts.length; i++) { + assetMetadata[currentTokenID] = metadatas[i]; + _mint(accounts[i], currentTokenID, amounts[i], data[i]); + tokenIDs[i] = currentTokenID; + currentTokenID++; + } + emit BatchMinted(msg.sender, tokenIDs, amounts, metadatas); + } + + function burn(uint256 tokenID, uint256 amount) public { + _burn(msg.sender, tokenID, amount); + emit TokensBurned(msg.sender, tokenID, amount); + } + + function transferTokens(address from, address to, uint256 tokenID, uint256 amount, bytes memory data) public { + require(from == msg.sender || isApprovedForAll(from, msg.sender), "Sender is not approved to transfer tokens"); + require(balanceOf(from, tokenID) >= amount, "Insufficient token balance"); + safeTransferFrom(from, to, tokenID, amount, data); + emit TokensTransferred(from, to, tokenID, amount, data); + } + + function lockTokens(uint256 tokenID, uint256 amount, uint256 unlockTimestamp) public { + require(unlockTimestamp > block.timestamp, "Unlock timestamp must be in the future"); + require(balanceOf(msg.sender, tokenID) >= amount, "Insufficient token balance"); + lockedBalance[msg.sender][tokenID] += amount; + emit TokensLocked(msg.sender, tokenID, amount, unlockTimestamp); + } + + function unlockTokens(uint256 tokenID, uint256 amount) public { + require(lockedBalance[msg.sender][tokenID] >= amount, "Insufficient locked token balance"); + lockedBalance[msg.sender][tokenID] -= amount; + _mint(msg.sender, tokenID, amount, ""); + emit TokensUnlocked(msg.sender, tokenID, amount); + } +} diff --git a/DaoVoting.sol b/DaoVoting.sol new file mode 100644 index 0000000..4b19647 --- /dev/null +++ b/DaoVoting.sol @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; + +contract FractionalNFTWithVoting is ERC1155, Ownable { + struct Fraction { + uint256 tokenId; + uint256 amount; + uint256 totalSupply; + address owner; + mapping(address => uint256) votes; + } + + enum GovernanceModel { SimpleMajority, Supermajority, Consensus } + + struct Proposal { + string title; + string description; + string[] options; + uint deadline; + bool votingStarted; + mapping(address => bool) hasVoted; + mapping(string => uint) votes; + } + + mapping(uint256 => Fraction) public fractions; + mapping(uint256 => uint256) public tokenIdToFractionId; + uint256 public fractionCounter; + address public factory; + uint256 public decisionThreshold; + mapping(uint256 => Proposal) public proposals; + uint256 public proposalCount; + + event FractionCreated(uint256 indexed tokenId, uint256 indexed fractionId, uint256 amount); + event FractionTransferred(uint256 indexed fractionId, address indexed from, address indexed to, uint256 amount); + event VoteCasted(uint256 indexed fractionId, address indexed voter, bool vote); + event ProposalCreated(uint proposalId, string title); + event VotingStarted(uint proposalId, uint deadline); + event VoteRecorded(uint proposalId, string option, address voter); + + constructor(address _factory, uint256 _decisionThreshold) ERC1155("") { + factory = _factory; + decisionThreshold = _decisionThreshold; + } + + function createFraction(uint256 _tokenId, uint256 _amount) external { + require(msg.sender == factory, "Only factory can create fractions"); + require(_amount > 0, "Amount must be greater than zero"); + require(fractions[fractionCounter].totalSupply == 0, "Fraction already exists for this token"); + + fractions[fractionCounter] = Fraction({ + tokenId: _tokenId, + amount: _amount, + totalSupply: _amount, + owner: msg.sender + }); + + tokenIdToFractionId[_tokenId] = fractionCounter; + _mint(msg.sender, fractionCounter, _amount, ""); + + emit FractionCreated(_tokenId, fractionCounter, _amount); + fractionCounter++; + } + + function transferFraction(address _to, uint256 _fractionId, uint256 _amount) external { + require(fractions[_fractionId].owner == msg.sender, "You don't own this fraction"); + require(_to != address(0), "Invalid address"); + require(_amount > 0 && _amount <= balanceOf(msg.sender, _fractionId), "Invalid amount"); + + _safeTransferFrom(msg.sender, _to, _fractionId, _amount, ""); + fractions[_fractionId].amount -= _amount; + + emit FractionTransferred(_fractionId, msg.sender, _to, _amount); + } + + function castVote(uint256 _fractionId, bool _vote) external { + require(fractions[_fractionId].owner != address(0), "Fraction does not exist"); + require(balanceOf(msg.sender, _fractionId) > 0, "You don't own any fraction of this NFT"); + + fractions[_fractionId].votes[msg.sender] = _vote ? 1 : 0; + + emit VoteCasted(_fractionId, msg.sender, _vote); + } + + function calculateDecision(uint256 _fractionId, GovernanceModel _model) external view returns (bool) { + require(fractions[_fractionId].owner != address(0), "Fraction does not exist"); + + uint256 totalVotes = 0; + uint256 totalSupply = fractions[_fractionId].totalSupply; + + // Count votes by iterating over all token holders + for (uint256 i = 0; i < fractionCounter; i++) { + address owner = fractions[i].owner; + if (fractions[_fractionId].votes[owner] == 1) { + totalVotes++; + } + } + + if (_model == GovernanceModel.SimpleMajority) { + return totalVotes > (totalSupply / 2); + } else if (_model == GovernanceModel.Supermajority) { + return totalVotes >= ((totalSupply * 2) / 3); + } else if (_model == GovernanceModel.Consensus) { + return totalVotes == totalSupply; + } + + return false; + } + + function createProposal( + string memory _title, + string memory _description, + string[] memory _options + ) public returns (uint) { + proposalCount++; + Proposal storage proposal = proposals[proposalCount]; + proposal.title = _title; + proposal.description = _description; + proposal.options = _options; + emit ProposalCreated(proposalCount, _title); + return proposalCount; + } + + function startVoting(uint _proposalId, uint _duration) public { + Proposal storage proposal = proposals[_proposalId]; + require(!proposal.votingStarted, "Voting already started"); + proposal.votingStarted = true; + proposal.deadline = block.timestamp + _duration; + emit VotingStarted(_proposalId, proposal.deadline); + } + + function vote(uint _proposalId, string memory _option) public { + Proposal storage proposal = proposals[_proposalId]; + require(block.timestamp < proposal.deadline, "Voting has ended"); + require(!proposal.hasVoted[msg.sender], "You have already voted"); + + proposal.votes[_option]++; + proposal.hasVoted[msg.sender] = true; + emit VoteRecorded(_proposalId, _option, msg.sender); + } + + function getVotes(uint _proposalId, string memory _option) public view returns (uint) { + Proposal storage proposal = proposals[_proposalId]; + return proposal.votes[_option]; + } + + function getProposal(uint _proposalId) public view returns ( + string memory title, + string memory description, + string[] memory options, + uint deadline, + bool votingStarted, + uint[] memory voteCounts + ) { + Proposal storage proposal = proposals[_proposalId]; + voteCounts = new uint[](proposal.options.length); + for (uint i = 0; i < proposal.options.length; i++) { + voteCounts[i] = proposal.votes[proposal.options[i]]; + } + return ( + proposal.title, + proposal.description, + proposal.options, + proposal.deadline, + proposal.votingStarted, + voteCounts + ); + } +} \ No newline at end of file diff --git a/fractional-NFT.sol b/fractional-NFT.sol new file mode 100644 index 0000000..5f90f85 --- /dev/null +++ b/fractional-NFT.sol @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; +import "@openzeppelin/contracts/utils/Counters.sol"; + +contract DAOVoting is ERC1155, Ownable { + using Counters for Counters.Counter; + + uint256 public currentTokenID = 0; + uint256 public constant TOTAL_SHARES = 1000000; + + struct Proposal { + string description; + uint256 deadline; + uint256 votingStart; + mapping(address => bool) hasVoted; + uint256 yesVotes; + uint256 noVotes; + bool finalized; + } + + mapping(uint256 => Proposal) public proposals; + + Counters.Counter private proposalCounter; + + event ProposalCreated(uint256 indexed tokenID, string description, uint256 deadline); + event VotingStarted(uint256 indexed tokenID, uint256 votingStart); + event VoteSubmitted(uint256 indexed proposalID, address indexed voter, bool choice); + event ProposalFinalized(uint256 indexed proposalID, uint256 yesVotes, uint256 noVotes); + + constructor(string memory uri) ERC1155(uri) Ownable(0x7e2eD6241f395E32c2fcEdCE0829e0506cbCFc79) { + // Fractionalize the NFT "borderlesspower.dao" into 1,000,000 shares + _mint(msg.sender, currentTokenID, TOTAL_SHARES, ""); + currentTokenID++; + } + + function fractionalize(uint256 tokenID, uint256 amount) public onlyOwner { + require(balanceOf(msg.sender, tokenID) >= amount, "Insufficient token balance to fractionalize"); + _mint(msg.sender, tokenID, amount, ""); + } + + function distributeFractionalShares(uint256 tokenID, address[] memory recipients, uint256[] memory amounts) public onlyOwner { + require(recipients.length == amounts.length, "Recipients and amounts arrays must have the same length"); + for (uint256 i = 0; i < recipients.length; i++) { + _mint(recipients[i], tokenID, amounts[i], ""); + } + } + + function createProposal(string memory description, uint256 deadline) public onlyOwner { + require(deadline > block.timestamp, "Deadline should be in the future"); + uint256 proposalID = proposalCounter.current(); + proposals[proposalID].description = description; + proposals[proposalID].deadline = deadline; + emit ProposalCreated(proposalID, description, deadline); + _mint(msg.sender, proposalID, 1, ""); + proposalCounter.increment(); + } + + function startVoting(uint256 proposalID, uint256 votingStart) public onlyOwner { + require(votingStart < proposals[proposalID].deadline, "Voting start time must be before the proposal deadline"); + proposals[proposalID].votingStart = votingStart; + emit VotingStarted(proposalID, votingStart); + } + + function submitVote(uint256 proposalID, bool choice) public { + Proposal storage proposal = proposals[proposalID]; + require(proposal.votingStart > 0 && block.timestamp >= proposal.votingStart && block.timestamp <= proposal.deadline, "Voting period has not started or has ended"); + require(!proposal.hasVoted[msg.sender], "You have already voted for this proposal"); + proposal.hasVoted[msg.sender] = true; + if (choice) { + proposal.yesVotes++; + } else { + proposal.noVotes++; + } + emit VoteSubmitted(proposalID, msg.sender, choice); + } + + function finalizeProposal(uint256 proposalID) public onlyOwner { + Proposal storage proposal = proposals[proposalID]; + require(block.timestamp > proposal.deadline, "Voting period has not ended"); + require(!proposal.finalized, "Proposal has already been finalized"); + proposal.finalized = true; + emit ProposalFinalized(proposalID, proposal.yesVotes, proposal.noVotes); + } + + function getVotingHistory(uint256 proposalID) public view returns (uint256 yesVotes, uint256 noVotes, bool finalized) { + Proposal storage proposal = proposals[proposalID]; + return (proposal.yesVotes, proposal.noVotes, proposal.finalized); + } + + function getCurrentProposalID() public view returns (uint256) { + return proposalCounter.current(); + } + + function getCurrentTimestamp() public view returns (uint256) { + return block.timestamp; + } + + function getRandomNumber(uint256 range) public view returns (uint256) { + return uint256(keccak256(abi.encodePacked(block.timestamp, blockhash(block.number - 1), range))) % range; + } +}