// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts/access/AccessControl.sol"; contract DBIS_ParticipantRegistry is AccessControl { bytes32 public constant PARTICIPANT_ADMIN_ROLE = keccak256("PARTICIPANT_ADMIN"); enum EntityType { BANK, MSB, CUSTODIAN, TRUSTEE, OPERATOR, AUDITOR } enum Status { ACTIVE, SUSPENDED, REVOKED } struct Participant { bytes32 participantId; string legalName; string jurisdiction; EntityType entityType; Status status; bytes32[] policyTags; address[] operationalWallets; } mapping(bytes32 => Participant) private _participants; mapping(bytes32 => uint8) private _participantStatus; mapping(address => bytes32) private _walletToParticipant; event ParticipantRegistered(bytes32 indexed participantId, string legalName, string jurisdiction, uint8 entityType); event ParticipantStatusChanged(bytes32 indexed participantId, uint8 status); event OperationalWalletAdded(bytes32 indexed participantId, address wallet); event OperationalWalletRemoved(bytes32 indexed participantId, address wallet); constructor(address admin) { _grantRole(DEFAULT_ADMIN_ROLE, admin); _grantRole(PARTICIPANT_ADMIN_ROLE, admin); } function registerParticipant(Participant calldata p) external onlyRole(PARTICIPANT_ADMIN_ROLE) { require(p.participantId != bytes32(0), "DBIS: zero participantId"); require(_participants[p.participantId].participantId == bytes32(0), "DBIS: already registered"); _participants[p.participantId] = Participant({ participantId: p.participantId, legalName: p.legalName, jurisdiction: p.jurisdiction, entityType: p.entityType, status: p.status, policyTags: p.policyTags, operationalWallets: p.operationalWallets }); _participantStatus[p.participantId] = uint8(p.status); _linkWalletsToParticipant(p.participantId, p.operationalWallets); emit ParticipantRegistered(p.participantId, p.legalName, p.jurisdiction, uint8(p.entityType)); } function setParticipantStatus(bytes32 participantId, Status s) external onlyRole(PARTICIPANT_ADMIN_ROLE) { require(_participants[participantId].participantId != bytes32(0), "DBIS: unknown participant"); _participants[participantId].status = s; _participantStatus[participantId] = uint8(s); emit ParticipantStatusChanged(participantId, uint8(s)); } function addOperationalWallet(bytes32 participantId, address wallet) external onlyRole(PARTICIPANT_ADMIN_ROLE) { require(_participants[participantId].participantId != bytes32(0), "DBIS: unknown participant"); require(wallet != address(0), "DBIS: zero wallet"); _participants[participantId].operationalWallets.push(wallet); _walletToParticipant[wallet] = participantId; emit OperationalWalletAdded(participantId, wallet); } function removeOperationalWallet(bytes32 participantId, address wallet) external onlyRole(PARTICIPANT_ADMIN_ROLE) { require(_participants[participantId].participantId != bytes32(0), "DBIS: unknown participant"); address[] storage wallets = _participants[participantId].operationalWallets; for (uint256 i = 0; i < wallets.length; i++) { if (wallets[i] == wallet) { wallets[i] = wallets[wallets.length - 1]; wallets.pop(); if (_walletToParticipant[wallet] == participantId) delete _walletToParticipant[wallet]; emit OperationalWalletRemoved(participantId, wallet); return; } } revert("DBIS: wallet not found"); } function isOperationalWallet(address wallet) external view returns (bool) { bytes32 pid = _walletToParticipant[wallet]; if (pid == bytes32(0)) return false; return _participantStatus[pid] == uint8(Status.ACTIVE); } function getParticipantByWallet(address wallet) external view returns (bytes32 participantId) { return _walletToParticipant[wallet]; } function getParticipantStatus(bytes32 participantId) external view returns (Status) { return _participants[participantId].status; } function getParticipant(bytes32 participantId) external view returns (Participant memory) { return _participants[participantId]; } function _linkWalletsToParticipant(bytes32 participantId, address[] calldata wallets) private { for (uint256 i = 0; i < wallets.length; i++) { if (wallets[i] != address(0)) _walletToParticipant[wallets[i]] = participantId; } } }