-
Notifications
You must be signed in to change notification settings - Fork 0
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
0 parents
commit b314120
Showing
3 changed files
with
376 additions
and
0 deletions.
There are no files selected for viewing
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,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); | ||
} | ||
} |
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,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 | ||
); | ||
} | ||
} |
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,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; | ||
} | ||
} |