Skip to content
This repository has been archived by the owner on Nov 15, 2024. It is now read-only.

Commit

Permalink
refix#lostchanges#contracts
Browse files Browse the repository at this point in the history
  • Loading branch information
0xJonaseb11 committed Oct 26, 2024
1 parent d8e093b commit 819a8a6
Show file tree
Hide file tree
Showing 5 changed files with 467 additions and 0 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ yarn hardhat:test

### Frontend section

# The client comes with the Scaffold-eth2 tool and it is built with Nextjs
# Once everything is clearly set, run
yarn install
yarn start
# here the frontend should display commonly on http://localhost:3000

## With deployment, I recommend vercel for development option - In initial state


```

Expand Down
89 changes: 89 additions & 0 deletions packages/hardhat/contracts/DataRegistry.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
* @title DataRegistry
* @author: @0xJonaseb11
* @notice: Stores the log of all txns and supply chain events
* @dev Provides a way to aufit and verify the integrity of the supply chain!
* @dev Could utilize merkle trees or similar methods for efficient amd verifiable data storage
*/

// imports
import { AccessControl } from "@openzeppelin/contracts/access/AccessControl.sol";

contract DataRegistry is AccessControl{
// states for tracking events
uint256 public eventCounter;
mapping(uint256 => EventLog) public events;
mapping(uint256 => uint256[]) public batchEventIds;


// roles for access control
bytes32 public constant AUDITOR_ROLE = keccak256("AUDITOR_ROLE");
bytes32 public constant SUPPLY_CHAIN_ROLE = keccak256("SUPPLY_CHAIN_ROLE");

// structre to store each event log
struct EventLog {
uint256 batchId;
address triggeredBy;
string eventType; // "StatusUpdated", "OwnershipTransfer", "Certification"
string details;
uint256 timestamp;
}

// events
event EventRecorded(uint256 indexed eventId, uint256 indexed batchId, string eventType, string details);

// contract constructor
constructor() {
// set up roles
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
}

// errors - customly

// business logic

// setters - cores
function recordEvent(uint256 _batchId, string memory _eventType, string memory _details) public onlyRole(SUPPLY_CHAIN_ROLE) {
// assign unique eventId
eventCounter++;

// record event in the mapping
events[eventCounter] = EventLog({
batchId: _batchId,
triggeredBy: msg.sender,
eventType: _eventType,
details: _details,
timestamp: block.timestamp
});
// map the event to the batch ID
batchEventIds[_batchId].push(eventCounter);
// Log event to the blockchain after recording
emit EventRecorded(eventCounter, _batchId, _eventType, _details);
}

// getters - execute
function getBatchEvents(uint256 _batchId) public view returns(EventLog[] memory) {
uint256[] memory eventIds = batchEventIds[_batchId];
EventLog[] memory batchEvents = new EventLog[](eventIds.length);

//loop through events to retrieve events by their ids
for (uint256 i = 0; i < eventIds.length; i++) {
batchEvents[i] = events[eventIds[i]];
}
return batchEvents;
}

// get event details
function getEventDetails(uint256 _eventId) public view returns(EventLog memory) {
require(events[_eventId].timestamp != 0, "Event Doesn't Exist!!");
return events[_eventId];
}

// Audit batches
function auditBatch(uint256 _batchId) public view onlyRole(AUDITOR_ROLE) returns(EventLog[] memory) {
return getBatchEvents(_batchId);
}
}
126 changes: 126 additions & 0 deletions packages/hardhat/contracts/MineralToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
* @title MineralToken
* @author: @0xJonaseb11
* @notice A utility token(NFT) for digital certification of minerals
* @dev Could represent a batch of minerals, each token tracking a certain quantity or type of mineral
* @dev Integrates with the Supplychain.sol for transferring mineral ownership
*/

// imports
import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import { AccessControl } from "@openzeppelin/contracts/access/AccessControl.sol";
import { Counters } from "@openzeppelin/contracts/utils/Counters.sol";

contract MineralToken is ERC721, AccessControl {
// states
// mappings to track token existence
mapping(uint256 => bool) private tokenExists;
// mappings to store batch details
mapping(uint256 => MineralBatch) public mineralBatches;
mapping(uint256 => bool) public verifiedBatches;
using Counters for Counters.Counter;

Counters.Counter private _tokenIds;
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
bytes32 public constant TRANSFER_ROLE = keccak256("TRANSFER_ROLE");

// struct for mineral batch
struct MineralBatch {
uint256 batchId;
string origin;
string purity;
string metadataURI;
uint256 timestamp;
bool isCertified;
}

// events
event MineralMinted(uint256 indexed tokenId, string origin, string purity, string metadataURI);
event MineralVerified(uint256 indexed tokenId, bool isCertified);

// contract constructor
constructor() ERC721("MineralToken", "MTK") {
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(MINTER_ROLE, msg.sender);
}

// mint mineral
function mintMineral(string memory _origin, string memory _purity, string memory _metadataURI) public onlyRole(MINTER_ROLE) returns (uint256) {
_tokenIds.increment();
uint256 newBatchId = _tokenIds.current();

// mint the new token representing the mineral batch
_mint(msg.sender, newBatchId);
// mark the token as existing
tokenExists[newBatchId] = true;

// store batch details
mineralBatches[newBatchId] = MineralBatch({
batchId: newBatchId,
origin: _origin,
purity: _purity,
metadataURI: _metadataURI,
timestamp: block.timestamp,
isCertified: false
});

// log event to blockchain after minting mineral token
emit MineralMinted(newBatchId, _origin, _purity, _metadataURI);
// return targeted batchId(uint256)
return newBatchId;
}

// verification of mineral batch
function verifyBatch(uint256 _tokenId) public onlyRole(DEFAULT_ADMIN_ROLE) {
_requireOwned(_tokenId); // Checks ownership and existence

MineralBatch storage batch = mineralBatches[_tokenId];
batch.isCertified = true;
verifiedBatches[_tokenId] = true;

// log event to blockchain after verification of mineral batch
emit MineralVerified(_tokenId, true);
}

// retrieve batch details
function getBatchDetails(uint256 _tokenId) public view returns (MineralBatch memory) {
_requireOwned(_tokenId); // Checks ownership and existence
return mineralBatches[_tokenId];
}

// transfer mineral
function transferMineral(address to, uint256 _tokenId) public onlyRole(TRANSFER_ROLE) {
_requireOwned(_tokenId); // Checks ownership and existence
require(verifiedBatches[_tokenId], "Batch Isn't Verified!!"); // only allow transfer of verified mineral batches

_transfer(msg.sender, to, _tokenId);
}

/**
* @dev Custom `_exists` function to check if a token exists
*/
function _exists(uint256 tokenId) internal view returns (bool) {
return tokenExists[tokenId];
}

/**
* @dev supportsInterface function to resolve overriding issue
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, AccessControl) returns (bool) {
return super.supportsInterface(interfaceId);
}

/**
* @dev `_requireOwned` function to check token ownership and existence
* @notice This checks if the token exists and returns the owner's address
*/
function _requireOwned(uint256 tokenId) internal view override returns (address) {
address owner = _ownerOf(tokenId);
require(owner == msg.sender, "Caller is not the owner of this token");
return owner; // return owner's address
}

}
143 changes: 143 additions & 0 deletions packages/hardhat/contracts/Participants.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
* contractName Participants
* @author: 0xJonaseb11
* @notice Defines various paarticipants (miers, refiners, shippers, buyers, etc
* @dev Each participants will have roles and permissions to perform specific actions!
* @notice Uses AccessControl for role management
*/

// imports
import { AccessControl } from "@openzeppelin/contracts/access/AccessControl.sol";

contract Partcipants is AccessControl{
// states
mapping(address => Participant) public participants;
address[] public participantList;

// participant roles
bytes32 public constant MINER_ROLE = keccak256("MINER_ROLE");
bytes32 public constant REFINER_ROLE = keccak256("REFINER_ROLE");
bytes32 public constant TRANSPORTER_ROLE = keccak256("TRANSPORTER_ROLE");
bytes32 public constant AUDITOR_ROLE = keccak256("AUDITOR_ROLE");
bytes32 public constant INSPECTOR_ROLE = keccak256("INSPECTOR_ROLE");

// struct to hold participants details
struct Participant {
address participantAddress;
string name;
string location;
string role;
bool isActive;
uint256 dateRegistered;
}

// events
event ParticipantRegistered(address indexed participant, string role, string name);
event ParticipantStatusUpdated(address indexed participant, bool isActive);
event ParticipantRoleUpdated(address indexed participant, string newRole);

// contract constructor
constructor () {
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
}




// errors

// business logic

// setters - cores
// Partipant registration
function registerParticipant(address _participantAddress, string memory _name, string memory _location, string memory _role) public onlyRole(DEFAULT_ADMIN_ROLE) {
require(participants[_participantAddress].participantAddress == address(0), "Participant Already Registered!!");

// Assign role based on _role input
bytes32 roleHash = keccak256(abi.encodePacked(_role));
// validate role by hash
require(
roleHash == MINER_ROLE || roleHash == REFINER_ROLE || roleHash == TRANSPORTER_ROLE || roleHash == AUDITOR_ROLE || roleHash == INSPECTOR_ROLE ,
"INVALID ROLE"
);

// Register the participant and grant role
participants[_participantAddress] = Participant({
participantAddress: _participantAddress,
name: _name,
location: _location,
role: _role,
isActive: true,
dateRegistered: block.timestamp
});
// add the registered participant to the list
participantList.push(_participantAddress);

// setup role to recently added participant
_grantRole(roleHash, _participantAddress);
emit ParticipantRegistered(_participantAddress, _role, _name);
}

// Update participant status
function updateParticipantStatus(address _participantAddress, bool _isActive) public onlyRole(DEFAULT_ADMIN_ROLE) {
require(participants[_participantAddress].participantAddress != address(0), "Participant you're trying to update is not Registered!!");

// set status after condition is met
participants[_participantAddress].isActive = _isActive;
// log event to blockchain for successful status update
emit ParticipantStatusUpdated(_participantAddress, _isActive);
}

// update role
function updateRole(address _participantAddress, string memory _newRole) public onlyRole(DEFAULT_ADMIN_ROLE) {
require(participants[_participantAddress].participantAddress != address(0), "Participant is Not Registered");

// remove old role
bytes32 oldRoleHash = keccak256(abi.encodePacked(participants[_participantAddress].role));
_revokeRole(oldRoleHash, _participantAddress);

// assign new role
bytes32 newRoleHash = keccak256(abi.encodePacked(_newRole));
_grantRole(newRoleHash, _participantAddress);
participants[_participantAddress].role = _newRole;

// log event to blockchain after updating role
emit ParticipantRoleUpdated(_participantAddress, _newRole);
}


// getters - execute

// handle getting participants by Role
function getParticipantsByRole(string memory _role) public view returns (Participant[] memory) {
bytes32 roleHash = keccak256(abi.encodePacked(_role));
uint256 count;

// count participants with the specified role
for (uint256 i = 0; i < participantList.length; i++) {
if (hasRole(roleHash, participantList[i])) {
count++;
}
}

// collect participants with the specified role
Participant[] memory roleParticipants = new Participant[](count);
uint256 index = 0;

// loop through roles to retrieve participants
for (uint256 i = 0; i < participantList.length; i++) {
if (hasRole(roleHash, participantList[i])) {
roleParticipants[index] = participants[participantList[i]];
index++;
}

}
return roleParticipants;
}



}
Loading

0 comments on commit 819a8a6

Please sign in to comment.