// SPDX-License-Identifier: MIT pragma solidity ^0.8.21; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; // Interface for the external Oracle service interface IOracleService { function getChatGPTPrediction(string calldata destination) external returns (string memory); } // External reputation system contract interface ExternalReputationSystem { function getUserReputation(address _user) external view returns (uint256); function updateReputation(address _user, uint256 _reputationImpact) external; } contract NCapp is Ownable, ReentrancyGuard { IERC20 public navisToken; IOracleService public oracleService; ExternalReputationSystem public externalReputationSystem; enum ShipmentStatus { Created, Accepted, InTransit, Delivered, Completed } struct Shipment { uint trackingNumber; ShipmentStatus status; address dispatcher; address courier; address packageReceiver; string paymentForm; string destination; string uniquePasscode; string wazeRoute; string[] alternativeRoutes; uint expirationTimestamp; uint256 reputationImpact; bool isBulky; bool multipleShipments; uint256 reward; } struct Warehouse { address dispatcher; uint256 availableSpace; uint256 usedSpace; uint256 rewardPool; } mapping(uint => Shipment) public shipments; mapping(address => uint[]) public receiverShipments; mapping(address => Warehouse) public warehouses; uint public totalShipments; uint public totalWarehouses; event ShipmentCreated(uint indexed trackingNumber, address indexed dispatcher); event ShipmentAccepted(uint indexed trackingNumber, address indexed courier); event ShipmentInTransit(uint indexed trackingNumber); event ShipmentDelivered(uint indexed trackingNumber); event ShipmentCompleted(uint indexed trackingNumber); event WarehouseCreated(address indexed dispatcher, uint256 availableSpace, uint256 rewardPool); event LoadPicked(uint indexed trackingNumber, address indexed courier); event RewardsDistributed(address indexed dispatcher, address indexed courier, uint256 amount); event ReputationUpdated(address indexed user, uint256 oldReputation, uint256 newReputation); modifier onlyDispatcher() { require(msg.sender == owner(), "Only dispatcher can perform this action"); _; } modifier onlyCourier(uint _trackingNumber) { require(shipments[_trackingNumber].courier == msg.sender, "Only courier can perform this action"); _; } modifier onlyPackageReceiver(uint _trackingNumber) { require(shipments[_trackingNumber].packageReceiver == msg.sender, "Only package receiver can perform this action"); _; } modifier onlyBeforeExpiration(uint _trackingNumber) { require(block.timestamp < shipments[_trackingNumber].expirationTimestamp, "Shipment has expired"); _; } modifier onlyExternalReputationSystem() { require(msg.sender == address(externalReputationSystem), "Only external reputation system can perform this action"); _; } constructor(address _navisToken, address _oracleService, address _externalReputationSystem) { navisToken = IERC20(_navisToken); oracleService = IOracleService(_oracleService); externalReputationSystem = ExternalReputationSystem(_externalReputationSystem); } function createWarehouse(uint256 _availableSpace, uint256 _rewardPool) external onlyDispatcher { totalWarehouses++; warehouses[msg.sender] = Warehouse({ dispatcher: msg.sender, availableSpace: _availableSpace, usedSpace: 0, rewardPool: _rewardPool }); emit WarehouseCreated(msg.sender, _availableSpace, _rewardPool); } function createShipment( address _packageReceiver, string memory _paymentForm, string memory _destination, bool _isBulky, bool _multipleShipments, uint256 _reward ) external onlyDispatcher { require(_multipleShipments || _reward == 0, "Invalid reward configuration"); totalShipments++; shipments[totalShipments] = Shipment({ trackingNumber: totalShipments, status: ShipmentStatus.Created, dispatcher: msg.sender, courier: address(0), packageReceiver: _packageReceiver, paymentForm: _paymentForm, destination: _destination, uniquePasscode: "", wazeRoute: "", expirationTimestamp: 0, reputationImpact: 0, isBulky: _isBulky, multipleShipments: _multipleShipments, reward: _reward }); if (_multipleShipments) { receiverShipments[_packageReceiver].push(totalShipments); } emit ShipmentCreated(totalShipments, msg.sender); } function acceptShipment(uint _trackingNumber) external onlyCourier(_trackingNumber) { Shipment storage shipment = shipments[_trackingNumber]; require(shipment.status == ShipmentStatus.Created, "Shipment must be in Created state"); if (shipment.multipleShipments) { require(receiverShipments[shipment.packageReceiver].length > 1, "Cannot accept single shipment in multiple shipments mode"); } shipment.status = ShipmentStatus.Accepted; shipment.courier = msg.sender; shipment.expirationTimestamp = block.timestamp + 1 weeks; // Set expiration time to 1 week emit ShipmentAccepted(_trackingNumber, msg.sender); } function startShipment(uint _trackingNumber, string memory _uniquePasscode, string memory _wazeRoute, string[] memory _alternativeRoutes) external onlyCourier(_trackingNumber) onlyBeforeExpiration(_trackingNumber) { Shipment storage shipment = shipments[_trackingNumber]; require(shipment.status == ShipmentStatus.Accepted, "Shipment must be in Accepted state"); shipment.status = ShipmentStatus.InTransit; shipment.uniquePasscode = _uniquePasscode; shipment.wazeRoute = _wazeRoute; shipment.alternativeRoutes = _alternativeRoutes; emit ShipmentInTransit(_trackingNumber); } function completeShipment(uint _trackingNumber) external onlyCourier(_trackingNumber) onlyBeforeExpiration(_trackingNumber) { Shipment storage shipment = shipments[_trackingNumber]; require(shipment.status == ShipmentStatus.InTransit, "Shipment must be in InTransit state"); shipment.status = ShipmentStatus.Completed; // Update reputation for the courier updateReputation(shipment.courier, shipment.reputationImpact); // Distribute rewards to dispatcher and courier distributeRewards(shipment.dispatcher, shipment.courier, shipment.reward); emit ShipmentCompleted(_trackingNumber); } function deliverShipment(uint _trackingNumber) external onlyPackageReceiver(_trackingNumber) { Shipment storage shipment = shipments[_trackingNumber]; require(shipment.status == ShipmentStatus.Completed, "Shipment must be in Completed state"); // Update reputation for the courier updateReputation(shipment.courier, shipment.reputationImpact); // Distribute rewards to dispatcher and courier distributeRewards(shipment.dispatcher, shipment.courier, shipment.reward); emit ShipmentDelivered(_trackingNumber); } function claimReward(uint _trackingNumber) external onlyCourier(_trackingNumber) { Shipment storage shipment = shipments[_trackingNumber]; require(shipment.status == ShipmentStatus.Completed, "Shipment must be in Completed state"); // Distribute rewards to dispatcher and courier distributeRewards(shipment.dispatcher, shipment.courier, shipment.reward); } function pickLoad(uint _trackingNumber) external onlyCourier(_trackingNumber) { Shipment storage shipment = shipments[_trackingNumber]; require(shipment.status == ShipmentStatus.Accepted, "Shipment must be in Accepted state"); // Update reputation for the courier updateReputation(shipment.courier, shipment.reputationImpact); // Distribute rewards to dispatcher and courier distributeRewards(shipment.dispatcher, shipment.courier, shipment.reward); emit LoadPicked(_trackingNumber, msg.sender); } function distributeRewards(address _dispatcher, address _courier, uint256 _reward) internal { uint256 dispatcherReward = (_reward * 80) / 100; // 80% for dispatcher uint256 courierReward = (_reward * 20) / 100; // 20% for courier // Update reputation for the dispatcher updateReputation(_dispatcher, courierReward); // Distribute rewards navisToken.transfer(_dispatcher, dispatcherReward); navisToken.transfer(_courier, courierReward); emit RewardsDistributed(_dispatcher, _courier, _reward); } function getReceiverShipments(address _receiver) external view returns (uint[] memory) { return receiverShipments[_receiver]; } // Function to set the external reputation system address function setExternalReputationSystem(address _externalReputationSystem) external onlyOwner { externalReputationSystem = ExternalReputationSystem(_externalReputationSystem); } // Function to update user reputation function updateReputation(address _user, uint256 _reputationImpact) internal onlyExternalReputationSystem { require(_reputationImpact != 0, "Invalid reputation impact"); // Get the old reputation uint256 oldReputation = externalReputationSystem.getUserReputation(_user); // Update the reputation externalReputationSystem.updateReputation(_user, _reputationImpact); // Get the new reputation uint256 newReputation = externalReputationSystem.getUserReputation(_user); // Emit an event to log the reputation update emit ReputationUpdated(_user, oldReputation, newReputation); } // Function to perform some specific action function someSpecificAction() external onlyOracleService { // Implement the specific action logic here } // Modifier for some specific condition modifier onlyIfSomeCondition() { // Implement the condition logic here require(someCondition, "Some condition not met"); _; } // Function to perform another specific action function anotherSpecificAction() external onlyIfSomeCondition { // Implement the action logic here } }