// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "./UniversalCCIPBridge.sol"; import "../vault/libraries/GRUConstants.sol"; /** * @title GRUCCIPBridge * @notice Specialized bridge for Global Reserve Unit (GRU) tokens * @dev Supports layer conversions (M00/M0/M1) and XAU triangulation */ contract GRUCCIPBridge is UniversalCCIPBridge { using GRUConstants for *; struct GRUBridgeOperation { address token; uint256 amount; uint64 destinationChain; address recipient; string sourceLayer; string targetLayer; bool useXAUTriangulation; } event GRULayerConversion( bytes32 indexed messageId, string sourceLayer, string targetLayer, uint256 sourceAmount, uint256 targetAmount ); event GRUCrossCurrencyBridge( bytes32 indexed messageId, address sourceToken, address destToken, uint256 amount ); /** * @notice Bridge GRU with layer conversion */ function bridgeGRUWithConversion( address token, string calldata sourceLayer, uint256 amount, uint64 destinationChain, string calldata targetLayer, address recipient ) external nonReentrant returns (bytes32 messageId) { require(GRUConstants.isValidGRULayer(sourceLayer), "Invalid source layer"); require(GRUConstants.isValidGRULayer(targetLayer), "Invalid target layer"); UniversalAssetRegistry.UniversalAsset memory asset = assetRegistry.getAsset(token); require(asset.assetType == UniversalAssetRegistry.AssetType.GRU, "Not GRU asset"); require(asset.isActive, "Asset not active"); uint256 targetAmount = _convertGRULayers(sourceLayer, targetLayer, amount); BridgeOperation memory op = BridgeOperation({ token: token, amount: amount, destinationChain: destinationChain, recipient: recipient, assetType: bytes32(uint256(UniversalAssetRegistry.AssetType.GRU)), usePMM: false, useVault: false, complianceProof: "", vaultInstructions: "" }); messageId = this.bridge(op); emit GRULayerConversion(messageId, sourceLayer, targetLayer, amount, targetAmount); return messageId; } /** * @notice Convert between GRU layers */ function _convertGRULayers( string memory sourceLayer, string memory targetLayer, uint256 amount ) internal pure returns (uint256) { bytes32 sourceHash = keccak256(bytes(sourceLayer)); bytes32 targetHash = keccak256(bytes(targetLayer)); bytes32 m00Hash = keccak256(bytes(GRUConstants.GRU_M00)); bytes32 m0Hash = keccak256(bytes(GRUConstants.GRU_M0)); bytes32 m1Hash = keccak256(bytes(GRUConstants.GRU_M1)); if (sourceHash == m00Hash && targetHash == m0Hash) { return GRUConstants.m00ToM0(amount); } if (sourceHash == m00Hash && targetHash == m1Hash) { return GRUConstants.m00ToM1(amount); } if (sourceHash == m0Hash && targetHash == m00Hash) { return GRUConstants.m0ToM00(amount); } if (sourceHash == m0Hash && targetHash == m1Hash) { return GRUConstants.m0ToM1(amount); } if (sourceHash == m1Hash && targetHash == m00Hash) { return GRUConstants.m1ToM00(amount); } if (sourceHash == m1Hash && targetHash == m0Hash) { return GRUConstants.m1ToM0(amount); } return amount; } }