This repository has been archived by the owner on Nov 15, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d8e093b
commit 819a8a6
Showing
5 changed files
with
467 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
|
||
|
||
|
||
} |
Oops, something went wrong.