Untitled
unknown
plain_text
a year ago
9.2 kB
4
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