The Store contract is a decentralized marketplace smart contract that enables merchants to sell products, manage inventory, handle discounts, and process purchases with built-in refund mechanisms. The contract implements a time-locked fund release system for security and includes comprehensive merchant management.
Contract Details:
- License: MIT
- Solidity Version: ^0.8.28
- Author: Pynex
- Inheritance: OpenZeppelin Ownable
- Add, update, and delete products
- Inventory tracking
- Price management
- Creator verification
- Merchant registration and verification
- Sales tracking
- Performance analytics
- Create discount tickets for specific users
- Percentage-based discounts
- Usage tracking and validation
- Individual and batch purchases
- Discount application
- Purchase statistics
- User balance tracking
- Time-locked fund release (20 hours default)
- Withdrawal system with fees
- Refund mechanism
- Fund blocking during transactions
- Time-delayed fund release
- Owner override for emergency fund release
struct Product {
uint price; // Price per unit
string productName; // Product name
uint amount; // Available quantity
uint id; // Unique product identifier
address creator; // Merchant who created the product
}
struct DiscountTicket {
uint discount; // Discount percentage (1-100)
uint amount; // Quantity eligible for discount
uint id; // Product ID
address user; // User who can use this ticket
}
Userpurchase
: buyer → product_id → amount purchasedpurchaseStatistics
: product_id → total quantity soldisMecrchant
: merchant address → is merchant booleanamountOfSales
: merchant → total sales amountuserBalance
: user → balance amountareUsersFundsBlocked
: user → funds blocked statusFundsBlocked
: user → amount of blocked fundsunlockTime
: user → timestamp when funds unlockdiscountTicketForUser
: user → array of discount tickets
merchants
: List of all registered merchantsproducts
: List of all productsdiscountTickets
: Internal discount tickets array
delayTime
: 20 hours (fund release delay)
event Purchase(address buyer, uint id, uint quantity, address creator, uint price);
Emitted when a purchase is made.
event Refund(address buyer, uint id, uint amount, address creator, uint price);
Emitted when a refund is processed.
- Access: Owner only
- Purpose: Add a new merchant to the platform
- Requirements: Merchant must not already exist
- Access: Owner only
- Purpose: Emergency fund release for users
- Requirements: User must have blocked funds
- Access: Merchants only
- Purpose: Add a new product to the store
- Requirements: Product ID must be unique
- Parameters:
_price
: Price per unit_productName
: Product name_amount
: Initial quantity_id
: Unique product identifier
- Access: Product creator only
- Purpose: Update product price
- Requirements: Caller must be the product creator
- Access: Product creator only
- Purpose: Update product quantity
- Requirements: Caller must be the product creator
- Access: Product creator only
- Purpose: Remove product from store
- Requirements: Product must exist, caller must be creator
- Access: Merchants only
- Purpose: Create discount ticket for specific user
- Requirements:
- Product must exist
- Discount between 1-100%
- Caller must be product creator
- Valid user address
- Access: Public payable
- Purpose: Deposit ETH to user balance
- Requirements: Must send ETH with transaction
- Access: Public
- Purpose: Purchase a single product
- Parameters:
_id
: Product ID_quantity
: Quantity to purchase_useDiscount
: 0 = no discount, 1 = use discount
- Requirements:
- Sufficient product quantity
- Sufficient user balance
- Valid discount ticket (if using discount)
- Access: Public
- Purpose: Purchase multiple products in one transaction
- Requirements:
- Array lengths must match
- Sufficient quantities and balance for all products
- Valid discount tickets (if using discounts)
- Access: Public
- Purpose: Refund a previous purchase
- Requirements:
- Must have purchased the product
- Sufficient purchase amount to refund
- Valid product ID
- Access: Public payable
- Purpose: Withdraw funds from user balance
- Requirements:
- Sufficient balance
- Sufficient contract balance
- Fee: 5% fee deducted, sent to contract owner
- Access: Public
- Purpose: Update blocked funds status and release if time passed
- Effect: Automatically releases funds if delay time has passed
- Returns: Array of all products
- Requirements: Products must exist
- Returns: Specific product by ID
- Requirements: Product must exist
- Returns: Array of all merchant addresses
- Requirements: Merchants must exist
- Returns: Caller's current balance
- Returns: User's blocked funds amount
- Returns: Product price
- Returns: Available product quantity
- Returns: Product creator address
- Returns: Discount percentage for user and product
- Returns: Discounted quantity available to user
- Returns: Array of user's discount tickets
- Returns: Product ID with highest sales
- Returns: Merchant address with highest sales
The contract includes comprehensive error handling with custom errors:
uAreNotAnOwner()
: Caller is not the ownermerchantAlreadyAdded()
: Merchant already existsuAreNotAMerchant()
: Caller is not a merchantnotEnoughFunds()
: Insufficient fundsProductsDoesNotExist()
: No products availableincorrectAmount()
: Invalid amount specifieddiscountCantBeMoreThen100()
: Discount exceeds 100%yourFundsBlocked()
: User funds are blockedidAlreadyExist()
: Product ID already existsidDoesNotExist()
: Product ID not foundnotEnoughProductsToBuy()
: Insufficient product quantityarraysMismatch()
: Array parameters don't matchincorrectDeposit()
: Invalid deposit amount
- Funds are locked for 20 hours after purchase/refund
- Prevents immediate fund extraction
- Owner can override in emergencies
- Owner-only functions for critical operations
- Merchant verification system
- Creator-only product management
- Comprehensive parameter validation
- Array length matching for batch operations
- Discount percentage limits (1-100%)
- Uses internal functions for critical operations
- State changes before external calls
- Proper fund management
// Must be called by a registered merchant
store.addProduct(1000, "Gaming Laptop", 10, 1);
// Deposit funds first
store.depositBalance{value: 1 ether}();
// Purchase without discount
store.buyProduct(1, 2, 0);
// Purchase with discount (if available)
store.buyProduct(1, 1, 1);
uint[] memory ids = [1, 2, 3];
uint[] memory quantities = [1, 2, 1];
uint[] memory useDiscounts = [0, 1, 0];
store.batchBuy(ids, quantities, useDiscounts);
// 20% discount for 5 units of product 1 for specific user
store.addDiscountTicket(20, 1, 5, userAddress);
- Withdrawal Fee: 5% of withdrawn amount
- Fee Recipient: Contract owner
- No fees on: Deposits, purchases, refunds
- Fund Release Delay: 20 hours after purchase/refund
- Override Authority: Contract owner can release funds early
- Automatic Release: Users can call
updateBlockedFunds()
after delay