// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.24; import {Test} from "forge-std/Test.sol"; import {SettlementEscrow} from "../src/SettlementEscrow.sol"; import {SettlementRouter} from "../src/adapters/SettlementRouter.sol"; import {MockERC20} from "./mocks/Mocks.sol"; contract MockResolvedMarket { mapping(uint256 => uint8) public optionWinner; mapping(bytes32 => uint256) claimables; bool public disputed; bool public appealed; uint256 public baseTokenDecimals = 1e6; function setWinner(uint256 o, uint8 side) external { optionWinner[o] = side; } function setClaimable(address u, uint256 o, uint256 amt) external { claimables[keccak256(abi.encodePacked(u, o))] = amt; } function setDisputed(bool d) external { disputed = d; } function getClaimableAmount(address u, uint256 o) external view returns (uint256) { return claimables[keccak256(abi.encodePacked(u, o))]; } function optionClaimed(uint256, address) external pure returns (bool) { return false; } function isOptionDisputed(uint256) external view returns (bool) { return disputed; } function isOptionAppealed(uint256) external view returns (bool) { return appealed; } } contract SettlementRouterTest is Test { SettlementEscrow escrow; SettlementRouter router; MockERC20 usdt; MockERC20 usdc; MockResolvedMarket market; address timelock = makeAddr("timelock"); address winner = makeAddr("winner"); function setUp() public { usdt = new MockERC20("USDT", "USDT", 6); usdc = new MockERC20("USDC", "USDC", 6); escrow = new SettlementEscrow(address(usdt), address(usdc)); router = new SettlementRouter(address(escrow), timelock); market = new MockResolvedMarket(); escrow.setup(makeAddr("reserve")); escrow.addAdapter(address(router)); escrow.finalize(); usdt.mint(address(escrow), 1_000_000e6); // pre-funded escrow vm.prank(timelock); router.registerMarket(address(market)); } function test_settle_paysWinnerFromEscrow() public { market.setWinner(1, 1); market.setClaimable(winner, 1, 5_000e6); router.settle(address(market), 1, winner); assertEq(usdt.balanceOf(winner), 5_000e6); } function test_settle_doublePayBlocked() public { market.setWinner(1, 1); market.setClaimable(winner, 1, 5_000e6); router.settle(address(market), 1, winner); vm.expectRevert(SettlementRouter.AlreadySettled.selector); router.settle(address(market), 1, winner); } function test_settle_unresolvedReverts() public { market.setClaimable(winner, 1, 5_000e6); vm.expectRevert(SettlementRouter.NotResolved.selector); router.settle(address(market), 1, winner); } function test_settle_disputedReverts() public { market.setWinner(1, 1); market.setClaimable(winner, 1, 5_000e6); market.setDisputed(true); vm.expectRevert(SettlementRouter.UnderDispute.selector); router.settle(address(market), 1, winner); } function test_settle_unregisteredMarketReverts() public { MockResolvedMarket rogue = new MockResolvedMarket(); rogue.setWinner(1, 1); rogue.setClaimable(winner, 1, 5_000e6); vm.expectRevert(SettlementRouter.MarketNotRegistered.selector); router.settle(address(rogue), 1, winner); } function test_settle_zeroClaimReverts() public { market.setWinner(1, 1); vm.expectRevert(SettlementRouter.NothingClaimable.selector); router.settle(address(market), 1, winner); } }