Untitled
unknown
plain_text
a year ago
9.2 kB
6
Indexable
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract ProductSupplyChain {
address public admin;
struct Product {
string productId; // Using string for product ID
string productName;
string manufacturerId; // Using string for manufacturer ID
string details; // Compressed details
uint256 quantity;
uint256 quality;
bool isConfirmed;
bool isSold;
bool isReturned;
string scratchCode; // Store the scratch code
}
mapping(string => Product) public products; // Using string keys
mapping(address => bool) public manufacturers;
mapping(address => bool) public retailers;
mapping(address => bool) public wholesalers;
event ProductProduced(string indexed productId, string productName, string manufacturerId, string details);
event ProductVerified(string indexed productId, uint256 quantity, uint256 quality, bool isConfirmed);
event ProductSold(string indexed productId, address indexed buyer);
event ProductReturned(string indexed productId);
event ProductAuthenticity(string indexed productId, bool isAuthentic);
event ScratchCodeGenerated(string indexed productId, string scratchCode);
constructor() {
admin = msg.sender;
}
modifier onlyAdmin() {
require(msg.sender == admin, "Only admin can perform this action");
_;
}
modifier onlyManufacturer() {
require(manufacturers[msg.sender], "Only manufacturers can perform this action");
_;
}
modifier onlyWholesaler() {
require(wholesalers[msg.sender], "Only wholesalers can perform this action");
_;
}
modifier onlyRetailer() {
require(retailers[msg.sender], "Only retailers can perform this action");
_;
}
function produceProduct(
string memory _productId,
string memory _productName,
string memory _manufacturerId,
string memory _manufactureDate,
string memory _expirationDate,
string memory _batchNumber
) public onlyManufacturer {
require(bytes(products[_productId].productId).length == 0, "Product with the same productId already exists");
string memory details = string(abi.encodePacked(_manufactureDate, "|", _expirationDate, "|", _batchNumber));
products[_productId] = Product(_productId, _productName, _manufacturerId, details, 0, 0, false, false, false, "");
emit ProductProduced(_productId, _productName, _manufacturerId, details);
}
function verifyProduct(string memory _productId, uint256 _quantity, uint256 _quality) public onlyManufacturer {
require(bytes(products[_productId].productId).length != 0, "Product with the given productId does not exist");
Product storage product = products[_productId];
product.quantity = _quantity;
product.quality = _quality;
product.isConfirmed = true; // Confirming the product on-chain
// Generate a random scratch code
product.scratchCode = generateRandomScratchCode(_productId);
emit ProductVerified(_productId, _quantity, _quality, true);
emit ScratchCodeGenerated(_productId, product.scratchCode);
}
function sellProduct(string memory _productId) public {
require(bytes(products[_productId].productId).length != 0, "Product with the given productId does not exist");
require(products[_productId].isConfirmed, "Product has not been confirmed by the manufacturer");
require(!products[_productId].isSold, "Product has already been sold");
if (manufacturers[msg.sender]) {
// Manufacturer selling to wholesaler or retailer
products[_productId].isSold = true;
} else if (wholesalers[msg.sender] || retailers[msg.sender]) {
// Wholesaler or retailer selling to customer or another wholesaler/retailer
products[_productId].isSold = true;
} else {
revert("Only manufacturers, wholesalers, or retailers can sell products");
}
emit ProductSold(_productId, msg.sender);
}
function buyProduct(string memory _productId) public {
require(bytes(products[_productId].productId).length != 0, "Product with the given productId does not exist");
require(products[_productId].isSold, "Product has not been sold yet");
products[_productId].isSold = true;
emit ProductSold(_productId, msg.sender);
}
function returnProduct(string memory _productId) public {
require(bytes(products[_productId].productId).length != 0, "Product with the given productId does not exist");
require(products[_productId].isSold, "Product has not been sold yet");
products[_productId].isSold = false;
products[_productId].isReturned = true;
emit ProductReturned(_productId);
}
function checkAuthenticity(string memory _productId) public view returns (bool, bool) {
if (bytes(products[_productId].productId).length == 0) {
return (false, false);
}
return (products[_productId].isConfirmed, true);
}
function addManufacturer(address _manufacturer) public onlyAdmin {
require(!manufacturers[_manufacturer], "Manufacturer already exists");
manufacturers[_manufacturer] = true;
}
function addRetailer(address _retailer) public onlyAdmin {
require(!retailers[_retailer], "Retailer already exists");
retailers[_retailer] = true;
}
function addWholesaler(address _wholesaler) public onlyAdmin {
require(!wholesalers[_wholesaler], "Wholesaler already exists");
wholesalers[_wholesaler] = true;
}
function getScratchCode(string memory _productId) public view returns (string memory) {
require(bytes(products[_productId].productId).length != 0, "Product with the given productId does not exist");
require(products[_productId].isSold, "Product has not been sold yet");
return products[_productId].scratchCode;
}
function isReturned(string memory _productId) public view returns (bool) {
require(bytes(products[_productId].productId).length != 0, "Product with the given productId does not exist");
return products[_productId].isReturned;
}
function decodeDetails(string memory details) public pure returns (string memory, string memory, string memory) {
bytes memory detailsBytes = bytes(details);
uint delimiterCount = 0;
uint lastDelimiterIndex = 0;
uint[] memory delimiterIndices = new uint[](2);
for (uint i = 0; i < detailsBytes.length; i++) {
if (detailsBytes[i] == '|') {
delimiterIndices[delimiterCount] = i;
delimiterCount++;
lastDelimiterIndex = i;
}
}
require(delimiterCount == 2, "Invalid details format");
string memory manufactureDate = new string(delimiterIndices[0]);
string memory expirationDate = new string(delimiterIndices[1] - delimiterIndices[0] - 1);
string memory batchNumber = new string(detailsBytes.length - lastDelimiterIndex - 1);
for (uint i = 0; i < delimiterIndices[0]; i++) {
bytes(manufactureDate)[i] = detailsBytes[i];
}
for (uint i = delimiterIndices[0] + 1; i < delimiterIndices[1]; i++) {
bytes(expirationDate)[i - delimiterIndices[0] - 1] = detailsBytes[i];
}
for (uint i = delimiterIndices[1] + 1; i < detailsBytes.length; i++) {
bytes(batchNumber)[i - delimiterIndices[1] - 1] = detailsBytes[i];
}
return (manufactureDate, expirationDate, batchNumber);
}
function generateRandomScratchCode(string memory _productId) internal view returns (string memory) {
bytes32 randomHash = keccak256(abi.encodePacked(block.timestamp, _productId, block.difficulty));
return toString(randomHash);
}
function toString(bytes32 _bytes32) internal pure returns (string memory) {
bytes memory bytesArray = new bytes(64);
for (uint256 i = 0; i < 32; i++) {
bytesArray[i*2] = _toHexChar(uint8(_bytes32[i]) / 16);
bytesArray[i*2 + 1] = _toHexChar(uint8(_bytes32[i]) % 16);
}
return string(bytesArray);
}
function _toHexChar(uint8 _char) internal pure returns (bytes1) {
if (_char < 10) {
return bytes1(_char + 0x30);
} else {
return bytes1(_char + 0x57);
}
}
function verifyScratchCode(string memory _productId, string memory _scratchCode) public view returns (bool) {
require(bytes(products[_productId].productId).length != 0, "Product with the given productId does not exist");
Product memory product = products[_productId];
return keccak256(abi.encodePacked(product.scratchCode)) == keccak256(abi.encodePacked(_scratchCode));
}
}
Editor is loading...
Leave a Comment