// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "forge-std/Test.sol"; import "../../src/RailTriggerRegistry.sol"; import "../../src/interfaces/IRailTriggerRegistry.sol"; import "../../src/libraries/RailTypes.sol"; contract RailTriggerRegistryTest is Test { RailTriggerRegistry public registry; address public admin; address public railOperator; address public railAdapter; address public token; function setUp() public { admin = address(0x1); railOperator = address(0x2); railAdapter = address(0x3); token = address(0x100); registry = new RailTriggerRegistry(admin); vm.startPrank(admin); registry.grantRole(registry.RAIL_OPERATOR_ROLE(), railOperator); registry.grantRole(registry.RAIL_ADAPTER_ROLE(), railAdapter); vm.stopPrank(); } function test_createTrigger() public { IRailTriggerRegistry.Trigger memory t = IRailTriggerRegistry.Trigger({ id: 0, rail: RailTypes.Rail.SWIFT, msgType: keccak256("pacs.008"), accountRefId: keccak256("account1"), walletRefId: bytes32(0), token: token, amount: 1000, currencyCode: keccak256("USD"), instructionId: keccak256("instruction1"), state: RailTypes.State.CREATED, createdAt: 0, updatedAt: 0 }); vm.expectEmit(true, true, false, true); emit IRailTriggerRegistry.TriggerCreated( 0, uint8(RailTypes.Rail.SWIFT), keccak256("pacs.008"), keccak256("instruction1"), keccak256("account1"), token, 1000 ); vm.prank(railOperator); uint256 id = registry.createTrigger(t); assertEq(id, 0); IRailTriggerRegistry.Trigger memory retrieved = registry.getTrigger(id); assertEq(uint8(retrieved.rail), uint8(RailTypes.Rail.SWIFT)); assertEq(retrieved.msgType, keccak256("pacs.008")); assertEq(retrieved.amount, 1000); assertEq(uint8(retrieved.state), uint8(RailTypes.State.CREATED)); } function test_createTrigger_duplicateInstructionId() public { IRailTriggerRegistry.Trigger memory t = IRailTriggerRegistry.Trigger({ id: 0, rail: RailTypes.Rail.SWIFT, msgType: keccak256("pacs.008"), accountRefId: keccak256("account1"), walletRefId: bytes32(0), token: token, amount: 1000, currencyCode: keccak256("USD"), instructionId: keccak256("instruction1"), state: RailTypes.State.CREATED, createdAt: 0, updatedAt: 0 }); vm.prank(railOperator); registry.createTrigger(t); vm.prank(railOperator); vm.expectRevert("RailTriggerRegistry: duplicate instructionId"); registry.createTrigger(t); } function test_updateState() public { IRailTriggerRegistry.Trigger memory t = IRailTriggerRegistry.Trigger({ id: 0, rail: RailTypes.Rail.SWIFT, msgType: keccak256("pacs.008"), accountRefId: keccak256("account1"), walletRefId: bytes32(0), token: token, amount: 1000, currencyCode: keccak256("USD"), instructionId: keccak256("instruction1"), state: RailTypes.State.CREATED, createdAt: 0, updatedAt: 0 }); vm.prank(railOperator); uint256 id = registry.createTrigger(t); vm.expectEmit(true, false, false, true); emit IRailTriggerRegistry.TriggerStateUpdated(id, uint8(RailTypes.State.CREATED), uint8(RailTypes.State.VALIDATED), bytes32(0)); vm.prank(railAdapter); registry.updateState(id, RailTypes.State.VALIDATED, bytes32(0)); IRailTriggerRegistry.Trigger memory retrieved = registry.getTrigger(id); assertEq(uint8(retrieved.state), uint8(RailTypes.State.VALIDATED)); } function test_updateState_invalidTransition() public { IRailTriggerRegistry.Trigger memory t = IRailTriggerRegistry.Trigger({ id: 0, rail: RailTypes.Rail.SWIFT, msgType: keccak256("pacs.008"), accountRefId: keccak256("account1"), walletRefId: bytes32(0), token: token, amount: 1000, currencyCode: keccak256("USD"), instructionId: keccak256("instruction1"), state: RailTypes.State.CREATED, createdAt: 0, updatedAt: 0 }); vm.prank(railOperator); uint256 id = registry.createTrigger(t); vm.prank(railAdapter); vm.expectRevert("RailTriggerRegistry: invalid state transition"); registry.updateState(id, RailTypes.State.SETTLED, bytes32(0)); } function test_instructionIdExists() public { IRailTriggerRegistry.Trigger memory t = IRailTriggerRegistry.Trigger({ id: 0, rail: RailTypes.Rail.SWIFT, msgType: keccak256("pacs.008"), accountRefId: keccak256("account1"), walletRefId: bytes32(0), token: token, amount: 1000, currencyCode: keccak256("USD"), instructionId: keccak256("instruction1"), state: RailTypes.State.CREATED, createdAt: 0, updatedAt: 0 }); assertFalse(registry.instructionIdExists(keccak256("instruction1"))); vm.prank(railOperator); registry.createTrigger(t); assertTrue(registry.instructionIdExists(keccak256("instruction1"))); } }