Files
smom-dbis-138/contracts/emoney/ISO20022Router.sol
defiQUG 1fb7266469 Add Oracle Aggregator and CCIP Integration
- Introduced Aggregator.sol for Chainlink-compatible oracle functionality, including round-based updates and access control.
- Added OracleWithCCIP.sol to extend Aggregator with CCIP cross-chain messaging capabilities.
- Created .gitmodules to include OpenZeppelin contracts as a submodule.
- Developed a comprehensive deployment guide in NEXT_STEPS_COMPLETE_GUIDE.md for Phase 2 and smart contract deployment.
- Implemented Vite configuration for the orchestration portal, supporting both Vue and React frameworks.
- Added server-side logic for the Multi-Cloud Orchestration Portal, including API endpoints for environment management and monitoring.
- Created scripts for resource import and usage validation across non-US regions.
- Added tests for CCIP error handling and integration to ensure robust functionality.
- Included various new files and directories for the orchestration portal and deployment scripts.
2025-12-12 14:57:48 -08:00

140 lines
5.9 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/access/AccessControl.sol";
import "./interfaces/IISO20022Router.sol";
import "./interfaces/IRailTriggerRegistry.sol";
import "./libraries/RailTypes.sol";
import "./libraries/ISO20022Types.sol";
/**
* @title ISO20022Router
* @notice Normalizes ISO-20022 messages into canonical on-chain format
* @dev Creates triggers in RailTriggerRegistry for both inbound and outbound messages
*/
contract ISO20022Router is IISO20022Router, AccessControl {
bytes32 public constant RAIL_OPERATOR_ROLE = keccak256("RAIL_OPERATOR_ROLE");
IRailTriggerRegistry public immutable triggerRegistry;
mapping(bytes32 => uint256) private _triggerIdByInstructionId; // instructionId => triggerId
/**
* @notice Initializes the router with registry address
* @param admin Address that will receive DEFAULT_ADMIN_ROLE
* @param triggerRegistry_ Address of RailTriggerRegistry contract
*/
constructor(address admin, address triggerRegistry_) {
_grantRole(DEFAULT_ADMIN_ROLE, admin);
require(triggerRegistry_ != address(0), "ISO20022Router: zero triggerRegistry");
triggerRegistry = IRailTriggerRegistry(triggerRegistry_);
}
/**
* @notice Submits an inbound ISO-20022 message (rail confirmation/notification)
* @dev Requires RAIL_OPERATOR_ROLE. Creates a trigger in CREATED state.
* @param m Canonical message struct
* @return triggerId The created trigger ID
*/
function submitInbound(
CanonicalMessage calldata m
) external override onlyRole(RAIL_OPERATOR_ROLE) returns (uint256 triggerId) {
require(m.msgType != bytes32(0), "ISO20022Router: zero msgType");
require(m.instructionId != bytes32(0), "ISO20022Router: zero instructionId");
require(m.accountRefId != bytes32(0), "ISO20022Router: zero accountRefId");
require(m.token != address(0), "ISO20022Router: zero token");
require(m.amount > 0, "ISO20022Router: zero amount");
// Determine rail from message type (simplified - in production, this would be more sophisticated)
RailTypes.Rail rail = _determineRailFromMessageType(m.msgType);
// Create trigger
IRailTriggerRegistry.Trigger memory trigger = IRailTriggerRegistry.Trigger({
id: 0, // Will be assigned by registry
rail: rail,
msgType: m.msgType,
accountRefId: m.accountRefId,
walletRefId: bytes32(0), // Will be resolved by orchestrator if needed
token: m.token,
amount: m.amount,
currencyCode: m.currencyCode,
instructionId: m.instructionId,
state: RailTypes.State.CREATED,
createdAt: 0, // Will be set by registry
updatedAt: 0 // Will be set by registry
});
triggerId = triggerRegistry.createTrigger(trigger);
_triggerIdByInstructionId[m.instructionId] = triggerId;
emit InboundSubmitted(triggerId, m.msgType, m.instructionId, m.accountRefId);
}
/**
* @notice Submits an outbound ISO-20022 message (rail initiation)
* @dev Requires RAIL_OPERATOR_ROLE. Creates a trigger in CREATED state.
* @param m Canonical message struct
* @return triggerId The created trigger ID
*/
function submitOutbound(
CanonicalMessage calldata m
) external override onlyRole(RAIL_OPERATOR_ROLE) returns (uint256 triggerId) {
require(m.msgType != bytes32(0), "ISO20022Router: zero msgType");
require(m.instructionId != bytes32(0), "ISO20022Router: zero instructionId");
require(m.accountRefId != bytes32(0), "ISO20022Router: zero accountRefId");
require(m.token != address(0), "ISO20022Router: zero token");
require(m.amount > 0, "ISO20022Router: zero amount");
// Determine rail from message type
RailTypes.Rail rail = _determineRailFromMessageType(m.msgType);
// Create trigger
IRailTriggerRegistry.Trigger memory trigger = IRailTriggerRegistry.Trigger({
id: 0, // Will be assigned by registry
rail: rail,
msgType: m.msgType,
accountRefId: m.accountRefId,
walletRefId: bytes32(0), // Will be resolved by orchestrator if needed
token: m.token,
amount: m.amount,
currencyCode: m.currencyCode,
instructionId: m.instructionId,
state: RailTypes.State.CREATED,
createdAt: 0, // Will be set by registry
updatedAt: 0 // Will be set by registry
});
triggerId = triggerRegistry.createTrigger(trigger);
_triggerIdByInstructionId[m.instructionId] = triggerId;
emit OutboundSubmitted(triggerId, m.msgType, m.instructionId, m.accountRefId);
}
/**
* @notice Returns the trigger ID for a given instruction ID
* @param instructionId The instruction ID
* @return The trigger ID (0 if not found)
*/
function getTriggerIdByInstructionId(bytes32 instructionId) external view override returns (uint256) {
return _triggerIdByInstructionId[instructionId];
}
/**
* @notice Determines the rail type from an ISO-20022 message type
* @dev Simplified implementation - in production, this would use a mapping table
* @param msgType The message type
* @return The rail type
*/
function _determineRailFromMessageType(bytes32 msgType) internal pure returns (RailTypes.Rail) {
// This is a simplified implementation
// In production, you would have a mapping table or more sophisticated logic
// For now, we'll use a default based on message family
if (msgType == ISO20022Types.PAIN_001 || msgType == ISO20022Types.PACS_008) {
// These are commonly used across rails, default to SWIFT
return RailTypes.Rail.SWIFT;
}
// Default to SWIFT for unknown types
return RailTypes.Rail.SWIFT;
}
}