Skip to content

Instantly share code, notes, and snippets.

@OdionOseiwe
Forked from max-clinch/market.sol
Created July 1, 2024 10:27
Show Gist options
  • Select an option

  • Save OdionOseiwe/219693dc6ac0f6b8c3af3a42a89ee782 to your computer and use it in GitHub Desktop.

Select an option

Save OdionOseiwe/219693dc6ac0f6b8c3af3a42a89ee782 to your computer and use it in GitHub Desktop.
// 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