-
-
Save OdionOseiwe/219693dc6ac0f6b8c3af3a42a89ee782 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| // SPDX-License-Identifier: MIT | |
| pragma solidity ^0.8.10; | |
| import "../dependencies/@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; | |
| import "../dependencies/@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; | |
| import "../dependencies/@openzeppelin/contracts-upgradeable/utils/structs/EnumerableSetUpgradeable.sol"; | |
| import "../dependencies/@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; | |
| import "../dependencies/interfaces/IACMTCT.sol"; | |
| import "../dependencies/ELEPHANT.sol"; | |
| error NotSeller(); | |
| error NotListed(); | |
| error InvalidPrice(); | |
| error BidTooLow(); | |
| error AuctionEnded(); | |
| error NoActiveBid(); | |
| interface IACMROI { | |
| function getUserDcaPower(uint256 userId) external view returns (uint256); | |
| } | |
| contract ReefMarketplace is Initializable, OwnableUpgradeable { | |
| using EnumerableSetUpgradeable for EnumerableSetUpgradeable.UintSet; | |
| enum ETFType { MacroETF, MicroETF, IndexETF} | |
| struct Listing { | |
| address seller; | |
| uint256 tokenId; | |
| uint256 price; | |
| uint256 categoryId; | |
| uint256 timestamp; | |
| uint256 user; | |
| address cPlanChlzAddress; | |
| bool cPlanFractionalization; | |
| bool cPlanDCATokenChoose; | |
| string[] dcaTokenSym; | |
| address[] dcaTokenAdd; | |
| uint256[] dcaTokensPercent; | |
| uint256 roiDate; | |
| uint256 roiArrears; | |
| bool active; | |
| } | |
| struct Bid { | |
| address bidder; | |
| uint256 amount; | |
| bool active; | |
| } | |
| struct FractionalRequest { | |
| uint requestId; | |
| address requester; | |
| uint ticketId; | |
| uint quantity; | |
| uint pricePerUnit; | |
| uint totalValue; | |
| bool isFulfilled; | |
| } | |
| struct CounterOffer { | |
| address owner; | |
| uint256 price; | |
| uint256 quantity; | |
| bool active; | |
| } | |
| mapping(uint => FractionalRequest) public fractionalRequests; | |
| mapping(uint => CounterOffer[]) public counterOffers; | |
| uint public nextRequestId; | |
| struct MacroETF { | |
| uint256 tokenId; | |
| uint256 price; // Price of the ETF | |
| uint256 totalSupply; | |
| uint256 fractionalValue; | |
| } | |
| struct MicroETF { | |
| uint256 tokenId; | |
| uint256 price; | |
| uint256 totalSupply; | |
| } | |
| struct IndexETF { | |
| uint256 tokenId; | |
| uint256 price; | |
| uint256 totalSupply; | |
| } | |
| struct Auction { | |
| address seller; | |
| uint256 tokenId; | |
| uint256 reservePrice; | |
| uint256 highestBid; | |
| address highestBidder; | |
| uint256 endTime; | |
| bool active; | |
| ETFType etfType; | |
| Bid[] allBids; | |
| } | |
| struct Trader { | |
| address traderAddress; | |
| uint256[] ownedETFs; | |
| uint256[] transactionHistory; | |
| uint256[] wishlist; | |
| } | |
| mapping(address => Trader) public traders; | |
| event Listed( uint256 indexed tokenId, address indexed seller, uint256 price); | |
| event Purchased(uint256 indexed tokenId, address indexed buyer, uint256 price); | |
| event BidCancelled(uint256 indexed tokenId, address indexed bidder); | |
| event AcceptedBid( uint256 indexed tokenId, address indexed bidder, uint256 amount); | |
| event ClaimTicketProcessed( uint256 tokenId, uint256 user, uint256 categoryId, uint256 price, uint256 timestamp, address cPlanChlzAddress, bool cPlanFractionalization, bool cPlanDCATokenChoose, string[] dcaTokenSym, address[] dcaTokenAdd, uint256[] dcaTokensPercent, uint256 roiDate, uint256 roiArrears); | |
| event FractionalRequestSubmitted( uint requestId, address requester, uint ticketId, uint quantity, uint pricePerUnit, uint totalValue); | |
| event FractalRequestApproved(uint requestId, address approver, uint timestamp); | |
| event FractalRequestRejected( uint requestId, address rejecter, uint timestamp); | |
| event AuctionCreated(uint256 indexed tokenId, address indexed seller, uint256 reservePrice, ETFType etfType, uint256 endTime ); | |
| event AuctionBidPlaced( uint256 indexed tokenId, address indexed bidder, uint256 amount); | |
| event TraderFollowed(address indexed follower, address indexed followee); | |
| event CounterOfferMade( uint requestId, address owner, uint price, uint quantity); | |
| event FetchedHistoricalDCA( uint256 indexed user, uint256 indexed ticketIndex, string[] dcaTokenSymbols, address[] dcaTokenAddresses, uint[] dcaTokenPercentages); | |
| event FetchedTradingData( uint256 indexed user, uint256 indexed ticketIndex, uint256 tradingVolume, uint256 tradingPrice); | |
| event OfferMade(uint256 indexed tokenId, address indexed offerer, uint256 price, uint256 quantity, string etfType); | |
| event OfferNotification( address indexed user, uint256 indexed tokenId, string etfType, string message); | |
| event OfferApproved(uint indexed requestId); | |
| event OfferPurchased( uint indexed requestId, address buyer, uint price, uint quantity); | |
| event BidPaymentConfirmed(uint256 bidAmount, address recipientAddress, uint256 taxAmount, address taxRevenueVaultAddress ); | |
| address public Usdt; | |
| IACMTCT public ACMTCT; // ACMTCT contract address | |
| IACMTCT public acmtctContract; | |
| IACMROI public acmRoiContractAddress; | |
| mapping(uint256 => Listing) public listings; | |
| mapping(uint256 => Bid) public bids; | |
| EnumerableSetUpgradeable.UintSet private activeListings; | |
| mapping(uint256 => Bid) private acceptedBids; | |
| mapping(uint256 => MacroETF) public macroETFs; | |
| mapping(uint256 => Auction) public auctions; | |
| mapping(uint256 => IndexETF) public indexETFs; | |
| mapping(uint256 => MicroETF) public microETFs; | |
| mapping(address => address[]) public followers; | |
| mapping(address => uint256[]) public traderListings; | |
| uint256 public transactionFee; | |
| address public admin; | |
| event TransactionFeeUpdated(uint256 newFee); | |
| address public taxRevenueVaultAddress; | |
| uint256 public taxRevenueVaultPercentage; | |
| modifier onlyAdmin() { | |
| require(msg.sender == admin, "Only admin can call this function"); | |
| _; | |
| } | |
| modifier onlySeller(uint256 _tokenId) { | |
| if (listings[_tokenId].seller != msg.sender) { | |
| revert NotSeller(); | |
| } | |
| _; | |
| } | |
| function initialize( | |
| address _Usdt, address _acmTCT, address _acmRoiContractAddress, address _taxRevenueVaultAddress, uint256 _taxRevenueVaultPercentage) external initializer { | |
| __Ownable_init(); Usdt = _Usdt; ACMTCT = ACMTCT; | |
| acmtctContract = IACMTCT(_acmTCT); | |
| acmRoiContractAddress = IACMROI(_acmRoiContractAddress); | |
| admin = msg.sender; | |
| taxRevenueVaultAddress = _taxRevenueVaultAddress; | |
| taxRevenueVaultPercentage = _taxRevenueVaultPercentage; | |
| } | |
| // Function to handle new TCT creation | |
| function handleNewTCTCreation( uint256 user, uint256 ticketIndex, uint256 categoryId, uint256 tokenId, uint256 timestamp) external { | |
| require(msg.sender == address(acmtctContract), "Unauthorized"); | |
| // Retrieve token details from ACMTCT contract | |
| IACMTCT.TokenClaimTicket memory ticket = acmtctContract.getClaimTicketDetails(user, ticketIndex); | |
| // List the token with additional details | |
| autoListTCT(tokenId, ticket.cPlanValue); | |
| // Emit an event to signal the processing of the claim ticket | |
| emit ClaimTicketProcessed( | |
| tokenId, user, categoryId, ticket.cPlanValue, timestamp, ticket.cPlanChlzAddress, ticket.cPlanFractionalization, ticket.cPlanDCATokenChoose, ticket.dcaTokenSym, ticket.dcaTokenAdd, ticket.dcaTokensPercent, ticket.roiDate, ticket.roiArrears); | |
| } | |
| function autoListTCT(uint256 _tokenId, uint256 _price) internal { | |
| require(!listings[_tokenId].active, "Already listed"); | |
| IACMTCT.TokenClaimTicket memory ticket = acmtctContract.getClaimTicketDetails(0, _tokenId); | |
| listings[_tokenId] = Listing({seller: ERC721Upgradeable(Usdt).ownerOf(_tokenId), tokenId: _tokenId, price: _price, categoryId: ticket.categoryId, timestamp: ticket.timestamp, user: ticket.user, cPlanChlzAddress: ticket.cPlanChlzAddress, cPlanFractionalization: ticket.cPlanFractionalization, cPlanDCATokenChoose: ticket.cPlanDCATokenChoose, dcaTokenSym: ticket.dcaTokenSym, dcaTokenAdd: ticket.dcaTokenAdd, dcaTokensPercent: ticket.dcaTokensPercent, roiDate: ticket.roiDate, roiArrears: ticket.roiArrears, active: true | |
| }); | |
| activeListings.add(_tokenId); | |
| emit Listed(_tokenId, listings[_tokenId].seller, _price); | |
| } | |
| function placeTCTBid(uint256 _tokenId, uint256 _bidAmount) external { | |
| // Ensure the token is listed and active | |
| require(listings[_tokenId].active, "Not listed"); | |
| // Ensure bid amount is greater than 0 | |
| require(_bidAmount > 0, "Bid amount must be greater than zero"); | |
| // Store the new bid | |
| bids[_tokenId] = Bid({ | |
| bidder: msg.sender, | |
| amount: _bidAmount, | |
| active: true | |
| }); | |
| // Emit an event for the new bid | |
| emit AuctionBidPlaced(_tokenId, msg.sender, _bidAmount); | |
| } | |
| function acceptTCTBid(uint256 _tokenId) external onlySeller(_tokenId) { | |
| Bid storage acceptedBid = bids[_tokenId]; | |
| require(acceptedBid.active, "No active bid"); | |
| address seller = listings[_tokenId].seller; | |
| uint256 totalAmount = acceptedBid.amount; | |
| uint256 taxRevenueVaultAmount = (totalAmount * taxRevenueVaultPercentage) / 100; | |
| uint256 sellerAmount = totalAmount - taxRevenueVaultPercentage; | |
| // Transfer the token to the highest bidder | |
| ERC721Upgradeable(Usdt).safeTransferFrom(seller, acceptedBid.bidder, _tokenId); | |
| // Transfer the funds to the tax revenue vault and seller | |
| payable(taxRevenueVaultAddress).transfer(taxRevenueVaultAmount); | |
| payable(seller).transfer(sellerAmount); | |
| // Mark the bid as inactive | |
| acceptedBid.active = false; | |
| // Emit events | |
| emit AcceptedBid(_tokenId, acceptedBid.bidder, acceptedBid.amount); | |
| emit Purchased(_tokenId, acceptedBid.bidder, acceptedBid.amount); | |
| } | |
| function getUserDcaPower(uint256 userId) external view returns (uint256) { | |
| return acmRoiContractAddress.getUserDcaPower(userId); | |
| } | |
| function setTransactionFee(uint256 _transactionFee) external onlyAdmin { | |
| require(_transactionFee <= 100, "Fee must be a percentage (0-100)"); | |
| transactionFee = _transactionFee; | |
| emit TransactionFeeUpdated(_transactionFee); | |
| } | |
| function purchaseChilz(uint256 _tokenId) external payable { | |
| require(listings[_tokenId].active, "Not listed"); | |
| require(msg.value == listings[_tokenId].price, "Incorrect price"); | |
| address seller = listings[_tokenId].seller; | |
| uint256 fee = msg.value*(transactionFee)/(100); | |
| uint256 sellerProceeds = msg.value-(fee); | |
| ERC721Upgradeable(Usdt).safeTransferFrom(seller, msg.sender, _tokenId); | |
| delete listings[_tokenId]; | |
| activeListings.remove(_tokenId); | |
| payable(seller).transfer(sellerProceeds); | |
| payable(admin).transfer(fee); | |
| emit Purchased(_tokenId, msg.sender, msg.value); | |
| } | |
| // Urgent sales of assets | |
| function createAuction( uint256 _tokenId, ETFType _etfType, uint256 _reservePrice, uint256 _duration) external { | |
| require(ERC721Upgradeable(Usdt).ownerOf(_tokenId) == msg.sender, "Not the owner"); | |
| require(_duration > 0, "Duration must be greater than zero"); | |
| Auction storage auction = auctions[_tokenId]; | |
| auction.seller = msg.sender; | |
| auction.tokenId = _tokenId; | |
| auction.reservePrice = _reservePrice; | |
| auction.highestBid = 0; | |
| auction.highestBidder = address(0); | |
| auction.endTime = block.timestamp + _duration; | |
| auction.active = true; | |
| auction.etfType = _etfType; | |
| // Initialize an empty array of bids in memory | |
| Bid[] memory emptyBids; | |
| // Copy the empty array to storage | |
| copyBidsToStorage(emptyBids, _tokenId); | |
| emit AuctionCreated(_tokenId, msg.sender, _reservePrice, _etfType, auction.endTime); | |
| } | |
| function placeAuctionBid(uint256 _tokenId, uint256 _bidAmount) external { | |
| Auction storage auction = auctions[_tokenId]; | |
| if (!auction.active) { | |
| revert AuctionEnded(); | |
| } | |
| if (block.timestamp >= auction.endTime) { | |
| revert AuctionEnded(); | |
| } | |
| // Store the bid | |
| auction.allBids.push(Bid({ bidder: msg.sender, amount: _bidAmount, active: true})); | |
| emit AuctionBidPlaced(_tokenId, msg.sender, _bidAmount); | |
| } | |
| function acceptBid(uint256 _tokenId) external onlySeller(_tokenId) { | |
| Listing storage listing = listings[_tokenId]; | |
| require(listing.active, "Not listed"); | |
| Auction storage auction = auctions[_tokenId]; | |
| require(auction.allBids.length > 0, "No bids available"); | |
| // Find the highest bid | |
| uint256 highestBidAmount = 0; | |
| address highestBidder; | |
| uint256 highestBidIndex; | |
| for (uint256 i = 0; i < auction.allBids.length; i++) { | |
| if (auction.allBids[i].amount > highestBidAmount) { | |
| highestBidAmount = auction.allBids[i].amount; | |
| highestBidder = auction.allBids[i].bidder; | |
| highestBidIndex = i; | |
| } | |
| } | |
| // Mark the highest bid as accepted | |
| acceptedBids[_tokenId] = auction.allBids[highestBidIndex]; | |
| acceptedBids[_tokenId].active = true; | |
| emit AcceptedBid(_tokenId, highestBidder, highestBidAmount); | |
| } | |
| // Function to confirm bid payment | |
| function confirmAuctionBidPayment(uint256 bidAmount, address payable recipientAddress) external { | |
| // Calculate tax amount to deduct | |
| uint256 taxAmount = (bidAmount * taxRevenueVaultPercentage) / 100; // Assuming taxRevenueVaultAmount is in percentage | |
| // Deduct tax from bid amount | |
| uint256 amountAfterTax = bidAmount - taxAmount; | |
| // Transfer bid amount minus tax to recipient | |
| recipientAddress.transfer(amountAfterTax); | |
| // Transfer tax amount to tax revenue vault address | |
| payable(taxRevenueVaultAddress).transfer(taxAmount); | |
| // Emit event or perform other actions as needed | |
| emit BidPaymentConfirmed(bidAmount, recipientAddress, taxAmount, taxRevenueVaultAddress); | |
| } | |
| function getActiveListingsCount() external view returns (uint256) { | |
| return activeListings.length(); | |
| } | |
| function getActiveListingByIndex( uint256 index) external view returns (uint256 tokenId, address seller, uint256 price) { | |
| require(index < activeListings.length(), "Index out of bounds"); | |
| tokenId = activeListings.at(index); | |
| Listing storage listing = listings[tokenId]; | |
| return (tokenId, listing.seller, listing.price); | |
| } | |
| function getAcceptedBid( | |
| uint256 _tokenId) external view returns (Bid memory) { | |
| require(acceptedBids[_tokenId].active, "No accepted bid"); | |
| return acceptedBids[_tokenId]; | |
| } | |
| function submitFractalRequest( address _requester, uint _ticketId, uint _quantity, uint _pricePerUnit, uint _totalValue | |
| ) external { uint requestId = nextRequestId++; | |
| fractionalRequests[requestId] = FractionalRequest({ requestId: requestId, requester: _requester, ticketId: _ticketId, quantity: _quantity, pricePerUnit: _pricePerUnit, totalValue: _totalValue, | |
| isFulfilled: false | |
| }); | |
| emit FractionalRequestSubmitted( requestId, _requester, _ticketId, _quantity, _pricePerUnit, _totalValue); | |
| } | |
| function approveFractalRequest(uint _requestId) external { | |
| require( !fractionalRequests[_requestId].isFulfilled, "Request already fulfilled"); | |
| fractionalRequests[_requestId].isFulfilled = true; | |
| emit FractalRequestApproved(_requestId, msg.sender, block.timestamp); | |
| } | |
| function rejectFractalRequest(uint _requestId) external { | |
| require( !fractionalRequests[_requestId].isFulfilled, "Request already fulfilled"); | |
| fractionalRequests[_requestId].isFulfilled = true; | |
| emit FractalRequestRejected(_requestId, msg.sender, block.timestamp); | |
| } | |
| function getFractalRequest( uint _requestId ) external view | |
| returns ( address requester, uint ticketId, uint quantity, uint pricePerUnit, uint totalValue, bool isFulfilled) | |
| { | |
| FractionalRequest storage request = fractionalRequests[_requestId]; | |
| return ( request.requester, request.ticketId, request.quantity, request.pricePerUnit, request.totalValue, request.isFulfilled); | |
| } | |
| function purchaseMacroETF( uint256 _tokenId, uint256 _quantity) external payable { MacroETF storage macroETF = macroETFs[_tokenId]; | |
| require(macroETF.tokenId > 0, "ETF not listed"); | |
| require( msg.value >= macroETF.price*(_quantity), "Insufficient funds" ); | |
| require( _quantity > 0 && _quantity <= macroETF.totalSupply, "Invalid quantity"); | |
| ERC721Upgradeable(Usdt).safeTransferFrom(owner(), msg.sender, _tokenId); | |
| macroETF.totalSupply = macroETF.totalSupply-(_quantity); | |
| emit Purchased(_tokenId, msg.sender, macroETF.price*(_quantity)); | |
| } | |
| function purchaseMicroETF(uint256 _tokenId, uint256 _quantity) external payable { | |
| MicroETF storage microETF = microETFs[_tokenId]; | |
| require(microETF.tokenId > 0, "MicroETF not listed"); | |
| require(msg.value >= microETF.price*(_quantity), "Insufficient funds"); | |
| require(_quantity > 0 && _quantity <= microETF.totalSupply, "Invalid quantity"); | |
| ERC721Upgradeable(Usdt).safeTransferFrom(owner(), msg.sender, _tokenId); | |
| microETF.totalSupply = microETF.totalSupply-(_quantity); | |
| emit Purchased(_tokenId, msg.sender, microETF.price*(_quantity)); | |
| } | |
| function purchaseIndexETF( uint256 _tokenId, uint256 _quantity) external payable { | |
| IndexETF storage indexETF = indexETFs[_tokenId]; | |
| require(indexETF.tokenId > 0, "IndexETF not listed"); | |
| require( msg.value >= indexETF.price*(_quantity), "Insufficient funds"); | |
| require( _quantity > 0 && _quantity <= indexETF.totalSupply, "Invalid quantity"); | |
| ERC721Upgradeable(Usdt).safeTransferFrom(owner(), msg.sender, _tokenId); | |
| indexETF.totalSupply = indexETF.totalSupply-(_quantity); | |
| emit Purchased(_tokenId, msg.sender, indexETF.price*(_quantity)); | |
| } | |
| function followTrader(address _trader) external { | |
| require(_trader != msg.sender, "Cannot follow yourself"); | |
| followers[_trader].push(msg.sender); | |
| emit TraderFollowed(msg.sender, _trader); | |
| } | |
| function getFollowers( address _trader) external view returns (address[] memory) { | |
| return followers[_trader]; | |
| } | |
| function searchListings( | |
| uint256 _minPrice, | |
| uint256 _maxPrice, | |
| uint256 _categoryId, | |
| bool _fractionalization, | |
| bool _dcaTokenChoose) external view returns (uint256[] memory) { | |
| uint256 resultCount = 0; | |
| uint256[] memory result = new uint256[](activeListings.length()); | |
| for (uint256 i = 0; i < activeListings.length(); i++) { | |
| uint256 tokenId = activeListings.at(i); | |
| Listing storage listing = listings[tokenId]; | |
| if ( | |
| listing.price >= _minPrice && | |
| listing.price <= _maxPrice && | |
| listing.categoryId == _categoryId && | |
| listing.cPlanFractionalization == _fractionalization && | |
| listing.cPlanDCATokenChoose == _dcaTokenChoose | |
| ) { | |
| result[resultCount] = tokenId; | |
| resultCount++; | |
| } | |
| } | |
| uint256[] memory filteredResults = new uint256[](resultCount); | |
| for (uint256 i = 0; i < resultCount; i++) { | |
| filteredResults[i] = result[i]; | |
| } | |
| return filteredResults; | |
| } | |
| function shareListing(uint256 _tokenId, address _recipient) external { | |
| require(listings[_tokenId].active, "Listing not active"); | |
| ERC721Upgradeable(Usdt).safeTransferFrom( | |
| listings[_tokenId].seller, _recipient, _tokenId); | |
| } | |
| struct ETF { | |
| uint256 tokenId; | |
| uint256 totalSupply; | |
| //Todo | |
| } | |
| struct Offer { | |
| address offerer; | |
| uint256 price; | |
| uint256 quantity; | |
| bool active; | |
| } | |
| mapping(uint256 => ETF) public iETFs; | |
| mapping(uint256 => Offer[]) public macroETFOffers; | |
| mapping(uint256 => Offer[]) public microETFOffers; | |
| mapping(uint256 => Offer[]) public iETFOffers; | |
| mapping(address => mapping(uint256 => bool)) public offerNotifications; | |
| // Function to submit counter offer | |
| function submitCounterOffer( uint _requestId, uint _price, uint _quantity) external onlyOwner { | |
| require( fractionalRequests[_requestId].isFulfilled == false, "Request already fulfilled"); | |
| counterOffers[_requestId].push( | |
| CounterOffer({ owner: msg.sender, price: _price, quantity: _quantity, active: true}) | |
| ); | |
| emit CounterOfferMade(_requestId, msg.sender, _price, _quantity); | |
| } | |
| // Function to get counter offers | |
| function getCounterOffers( uint _requestId) external view returns (CounterOffer[] memory) { | |
| return counterOffers[_requestId]; | |
| } | |
| // Function to make offer on any ETF | |
| function makeOffer( uint256 _tokenId, uint256 _price, uint256 _quantity, string memory _etfType) external { | |
| if (keccak256(abi.encodePacked(_etfType)) == keccak256(abi.encodePacked("MacroETF"))) { | |
| require(macroETFs[_tokenId].tokenId > 0, "MacroETF not listed"); | |
| require( _quantity > 0 && _quantity <= macroETFs[_tokenId].totalSupply, "Invalid quantity"); | |
| macroETFOffers[_tokenId].push( | |
| Offer({offerer: msg.sender, price: _price, quantity: _quantity, active: true}) | |
| ); | |
| } else if (keccak256(abi.encodePacked(_etfType)) == keccak256(abi.encodePacked("MicroETF"))) { | |
| require(microETFs[_tokenId].tokenId > 0, "MicroETF not listed"); | |
| require( _quantity > 0 && _quantity <= microETFs[_tokenId].totalSupply, "Invalid quantity"); | |
| microETFOffers[_tokenId].push( | |
| Offer({ offerer: msg.sender, price: _price, quantity: _quantity, active: true}) | |
| ); | |
| } else if (keccak256(abi.encodePacked(_etfType)) == keccak256(abi.encodePacked("iETF"))) { | |
| require(iETFs[_tokenId].tokenId > 0, "iETF not listed"); | |
| require( _quantity > 0 && _quantity <= iETFs[_tokenId].totalSupply, "Invalid quantity"); | |
| iETFOffers[_tokenId].push( | |
| Offer({offerer: msg.sender, price: _price, quantity: _quantity, active: true}) | |
| ); | |
| } else { | |
| revert("Invalid ETF type"); | |
| } | |
| emit OfferMade(_tokenId, msg.sender, _price, _quantity, _etfType); | |
| notifyUsers(_tokenId, _etfType); | |
| } | |
| // Function to get offers on ETFs with filtering and sorting | |
| function getOffers( uint256 _tokenId, uint256 _minPrice, uint256 _maxPrice, bool _sortByPrice, string memory _etfType) external view returns (Offer[] memory) { | |
| Offer[] storage offers; | |
| if (keccak256(abi.encodePacked(_etfType)) == keccak256(abi.encodePacked("MacroETF"))) { | |
| offers = macroETFOffers[_tokenId]; | |
| } else if (keccak256(abi.encodePacked(_etfType)) == keccak256(abi.encodePacked("MicroETF"))) { | |
| offers = microETFOffers[_tokenId]; | |
| } else if (keccak256(abi.encodePacked(_etfType)) == keccak256(abi.encodePacked("iETF"))) { | |
| offers = iETFOffers[_tokenId]; | |
| } else { | |
| revert("Invalid ETF type"); | |
| } | |
| Offer[] memory filteredOffers = new Offer[](offers.length); | |
| uint256 count = 0; | |
| for (uint256 i = 0; i < offers.length; i++) { | |
| if ( | |
| offers[i].active && | |
| offers[i].price >= _minPrice && | |
| offers[i].price <= _maxPrice | |
| ) { | |
| filteredOffers[count] = offers[i]; | |
| count++; | |
| } | |
| } | |
| Offer[] memory result = new Offer[](count); | |
| for (uint256 i = 0; i < count; i++) { | |
| result[i] = filteredOffers[i]; | |
| } | |
| if (_sortByPrice) { | |
| // Sort result by price (ascending) | |
| for (uint256 i = 0; i < result.length; i++) { | |
| for (uint256 j = i + 1; j < result.length; j++) { | |
| if (result[i].price > result[j].price) { | |
| Offer memory temp = result[i]; | |
| result[i] = result[j]; | |
| result[j] = temp; | |
| } | |
| } | |
| } | |
| } | |
| return result; | |
| } | |
| // Function to sort offers by price in ascending order | |
| function sortOffersByPriceAscending( Offer[] memory offers ) internal pure returns (Offer[] memory) { | |
| // Bubble sort algorithm | |
| for (uint256 i = 0; i < offers.length; i++) { | |
| for (uint256 j = i + 1; j < offers.length; j++) { | |
| if (offers[i].price > offers[j].price) { | |
| // Swap offers[i] with offers[j] | |
| Offer memory temp = offers[i]; | |
| offers[i] = offers[j]; | |
| offers[j] = temp; | |
| } | |
| } | |
| } | |
| return offers; | |
| } | |
| // Functions to subscribe and unsubscribe from offer notifications | |
| function subscribeToOfferNotifications(uint256 _tokenId) external { | |
| offerNotifications[msg.sender][_tokenId] = true; | |
| } | |
| function unsubscribeFromOfferNotifications(uint256 _tokenId) external { | |
| offerNotifications[msg.sender][_tokenId] = false; | |
| } | |
| // Function to get all offers for a specific MacroETF | |
| function getAllMacroETFOffers( uint256 _tokenId) external view returns (Offer[] memory) { | |
| return macroETFOffers[_tokenId]; | |
| } | |
| // Function to get all offers for a specific MicroETF | |
| function getAllMicroETFOffers( uint256 _tokenId) external view returns (Offer[] memory) { | |
| return microETFOffers[_tokenId]; | |
| } | |
| // Function to get all offers for a specific iETF | |
| function getAlliETFOffers( uint256 _tokenId) external view returns (Offer[] memory) { | |
| return iETFOffers[_tokenId]; | |
| } | |
| // Function to notify users about a new offer | |
| function notifyUsers(uint256 _tokenId, string memory _etfType) internal { | |
| address[] memory _followers; | |
| if ( | |
| keccak256(abi.encodePacked((_etfType))) == | |
| keccak256(abi.encodePacked(("MacroETF"))) | |
| ) { | |
| _followers = followers[address(this)]; | |
| } else if ( | |
| keccak256(abi.encodePacked((_etfType))) == | |
| keccak256(abi.encodePacked(("MicroETF"))) | |
| ) { | |
| _followers = followers[address(this)]; | |
| } else if ( | |
| keccak256(abi.encodePacked((_etfType))) == | |
| keccak256(abi.encodePacked(("iETF"))) | |
| ) { | |
| _followers = followers[address(this)]; | |
| } | |
| for (uint256 i = 0; i < _followers.length; i++) { | |
| if (!offerNotifications[_followers[i]][_tokenId]) { | |
| offerNotifications[_followers[i]][_tokenId] = true; | |
| emit OfferNotification( | |
| _followers[i], | |
| _tokenId, | |
| _etfType, | |
| "New offer available" | |
| ); | |
| } | |
| } | |
| } | |
| function fetchHistoricalDCA(uint256 _user, uint256 _ticketIndex) external { | |
| // Fetch claim ticket details from ACMTCT contract | |
| IACMTCT.TokenClaimTicket memory ticket = acmtctContract | |
| .getClaimTicketDetails(_user, _ticketIndex); | |
| emit FetchedHistoricalDCA( | |
| _user, | |
| _ticketIndex, | |
| ticket.dcaTokenSym, | |
| ticket.dcaTokenAdd, | |
| ticket.dcaTokensPercent | |
| ); | |
| } | |
| function fetchTradingData(uint256 _user, uint256 _ticketIndex) external { | |
| // Fetch claim ticket details from ACMTCT contract | |
| IACMTCT.TokenClaimTicket memory ticket = acmtctContract | |
| .getClaimTicketDetails(_user, _ticketIndex); | |
| uint256 tradingVolume = ticket.cPlanValue; | |
| uint256 tradingPrice = ticket.roiArrears; | |
| emit FetchedTradingData( | |
| _user, | |
| _ticketIndex, | |
| tradingVolume, | |
| tradingPrice | |
| ); | |
| } | |
| // Function to add an ETF to a user's owned list | |
| function addToOwnedETFs(address _user, uint256 _tokenId) external { | |
| traders[_user].ownedETFs.push(_tokenId); | |
| } | |
| // Function to add a transaction to a user's history | |
| function addToTransactionHistory( address _user, uint256 _transactionId) external { | |
| traders[_user].transactionHistory.push(_transactionId); | |
| } | |
| // Function to add an ETF to a user's wishlist | |
| function addToWishlist(address _user, uint256 _tokenId) external { | |
| traders[_user].wishlist.push(_tokenId); | |
| } | |
| // Function to retrieve a user's profile | |
| function getTraderProfile( address _user) external view | |
| returns ( uint256[] memory ownedETFs, uint256[] memory transactionHistory, uint256[] memory wishlist) | |
| { | |
| Trader storage trader = traders[_user]; | |
| return (trader.ownedETFs, trader.transactionHistory, trader.wishlist); | |
| } | |
| // Function to clear notifications for a user | |
| function clearNotifications(uint256 _tokenId) external { | |
| require( | |
| offerNotifications[msg.sender][_tokenId], | |
| "No notifications to clear" | |
| ); | |
| offerNotifications[msg.sender][_tokenId] = false; | |
| } | |
| function purchaseApprovedOffer(uint _requestId) external payable { | |
| require( | |
| fractionalRequests[_requestId].isFulfilled, | |
| "Offer is not approved" | |
| ); | |
| CounterOffer[] storage offers = counterOffers[_requestId]; | |
| bool found = false; | |
| uint offerIndex; | |
| for (uint i = 0; i < offers.length; i++) { | |
| if (offers[i].active) { | |
| found = true; | |
| offerIndex = i; | |
| break; | |
| } | |
| } | |
| require(found, "No active offer found"); | |
| CounterOffer memory approvedOffer = offers[offerIndex]; | |
| require(msg.value == approvedOffer.price, "Incorrect payment amount"); | |
| offers[offerIndex].active = false; | |
| emit OfferPurchased( | |
| _requestId, | |
| approvedOffer.owner, | |
| approvedOffer.price, | |
| approvedOffer.quantity | |
| ); | |
| } | |
| function copyBidsToStorage(Bid[] memory bidsArray, uint256 tokenId) internal { | |
| Auction storage auction = auctions[tokenId]; | |
| for (uint256 i = 0; i < bidsArray.length; i++) { | |
| auction.allBids.push(bidsArray[i]); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment