Files
smom-dbis-138/test/flash/CrossChainFlashBorrower.t.sol
defiQUG 76aa419320 feat: bridges, PMM, flash workflow, token-aggregation, and deployment docs
- CCIP/trustless bridge contracts, GRU tokens, DEX/PMM tests, reserve vault.
- Token-aggregation service routes, planner, chain config, relay env templates.
- Config snapshots and multi-chain deployment markdown updates.
- gitignore services/btc-intake/dist/ (tsc output); do not track dist.

Run forge build && forge test before deploy (large solc graph).

Made-with: Cursor
2026-04-07 23:40:52 -07:00

80 lines
3.0 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Test} from "forge-std/Test.sol";
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC3156FlashBorrower} from "@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol";
import {SimpleERC3156FlashVault} from "../../contracts/flash/SimpleERC3156FlashVault.sol";
import {CrossChainFlashBorrower} from "../../contracts/flash/CrossChainFlashBorrower.sol";
import {ICrossChainFlashBridge} from "../../contracts/flash/interfaces/ICrossChainFlashBridge.sol";
contract MockCrossChainBridge is ICrossChainFlashBridge {
event BridgeCalled(address token, uint256 amount, uint64 dest, address recipient, bytes extra, uint256 value);
function bridgeTokensFrom(
address token,
uint256 amount,
uint64 destinationChainSelector,
address recipientOnDestination,
bytes calldata extraData
) external payable override returns (bytes32 messageId) {
IERC20(token).transferFrom(msg.sender, address(this), amount);
emit BridgeCalled(token, amount, destinationChainSelector, recipientOnDestination, extraData, msg.value);
messageId = keccak256(abi.encodePacked(block.number, token, amount));
}
}
contract MockERC20Mint is ERC20 {
constructor() ERC20("T", "T") {}
function mint(address to, uint256 v) external {
_mint(to, v);
}
}
contract CrossChainFlashBorrowerTest is Test {
SimpleERC3156FlashVault internal vault;
MockERC20Mint internal token;
MockCrossChainBridge internal bridge;
CrossChainFlashBorrower internal borrower;
address internal owner = address(0xA11);
address internal user = address(0xB22);
function setUp() public {
vm.startPrank(owner);
vault = new SimpleERC3156FlashVault(owner, 5);
token = new MockERC20Mint();
token.mint(address(vault), 1_000_000e18);
vault.setTokenSupported(address(token), true);
vm.stopPrank();
bridge = new MockCrossChainBridge();
borrower = new CrossChainFlashBorrower(address(vault));
}
function test_flashBridge_out_repaysFromPrefund() public {
uint256 amount = 40_000e18;
uint256 fee = vault.flashFee(address(token), amount);
uint256 bridgeAmount = amount;
token.mint(address(borrower), bridgeAmount + fee);
CrossChainFlashBorrower.CrossChainFlashParams memory p = CrossChainFlashBorrower.CrossChainFlashParams({
bridge: address(bridge),
bridgeAmount: bridgeAmount,
destinationChainSelector: 123,
recipientOnDestination: address(0xbeef),
bridgeExtraData: hex"abcd",
nativeBridgeFee: 0
});
vm.prank(user);
vault.flashLoan(IERC3156FlashBorrower(address(borrower)), address(token), amount, abi.encode(p));
assertEq(token.balanceOf(address(bridge)), bridgeAmount);
assertEq(vault.totalFeesCollected(address(token)), fee);
}
}