Inventory Management Smart Contract
What it does:
Tracks inventory levels, manages stock in/out transactions, and provides real-time, auditable records of goods across warehouses or stores.
Why it matters:
Reduces human error, prevents stock discrepancies, increases supply chain efficiency, and enables transparent auditing for stakeholders.
How it works:
-
Warehouses, suppliers, and stores are registered on-chain
-
Each product or SKU is recorded with quantity, location, and metadata
-
Stock additions, removals, or transfers are logged immutably
-
Alerts can be triggered for low stock or overstock situations
-
Smart contracts maintain historical records for auditing and reporting
-
Integrates with Supply Chain Traceability, logistics, and automated reordering systems
-
Public dashboards allow visibility into inventory levels and movement
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/access/Ownable.sol";
/**
* @title InventoryManagement
* @author Nam
* @notice Manages inventory on-chain with stock tracking and auditing
*/
contract InventoryManagement is Ownable {
struct Product {
string name;
string metadataURI;
uint256 totalQuantity;
bool exists;
}
struct StockEvent {
uint256 timestamp;
address operator;
int256 quantityChange;
string note;
}
mapping(uint256 => Product) public products; // productId => Product
mapping(uint256 => StockEvent[]) public productEvents; // productId => events
mapping(address => bool) public operators;
uint256 public productCount;
// -------------------- EVENTS --------------------
event ProductRegistered(uint256 indexed productId, string name, uint256 quantity);
event StockUpdated(uint256 indexed productId, int256 quantityChange, string note, address operator);
event OperatorApproved(address operator);
// -------------------- OPERATOR MANAGEMENT --------------------
function approveOperator(address _operator) external onlyOwner {
operators[_operator] = true;
emit OperatorApproved(_operator);
}
function revokeOperator(address _operator) external onlyOwner {
operators[_operator] = false;
}
modifier onlyOperator() {
require(operators[msg.sender], "Not an authorized operator");
_;
}
// -------------------- PRODUCT MANAGEMENT --------------------
function registerProduct(string calldata _name, string calldata _metadataURI, uint256 _initialQuantity) external onlyOperator {
productCount += 1;
products[productCount] = Product({
name: _name,
metadataURI: _metadataURI,
totalQuantity: _initialQuantity,
exists: true
});
productEvents[productCount].push(StockEvent({
timestamp: block.timestamp,
operator: msg.sender,
quantityChange: int256(_initialQuantity),
note: "Initial stock"
}));
emit ProductRegistered(productCount, _name, _initialQuantity);
}
// -------------------- STOCK MANAGEMENT --------------------
function updateStock(uint256 _productId, int256 _quantityChange, string calldata _note) external onlyOperator {
require(products[_productId].exists, "Product does not exist");
int256 newQuantity = int256(products[_productId].totalQuantity) + _quantityChange;
require(newQuantity >= 0, "Stock cannot be negative");
products[_productId].totalQuantity = uint256(newQuantity);
productEvents[_productId].push(StockEvent({
timestamp: block.timestamp,
operator: msg.sender,
quantityChange: _quantityChange,
note: _note
}));
emit StockUpdated(_productId, _quantityChange, _note, msg.sender);
}
// -------------------- VIEW FUNCTIONS --------------------
function getProductEvents(uint256 _productId) external view returns (StockEvent[] memory) {
return productEvents[_productId];
}
function getProductQuantity(uint256 _productId) external view returns (uint256) {
require(products[_productId].exists, "Product does not exist");
return products[_productId].totalQuantity;
}
}