- 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
68 lines
2.5 KiB
Solidity
68 lines
2.5 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 {UniversalCCIPBridge} from "../../contracts/bridge/UniversalCCIPBridge.sol";
|
|
import {UniversalCCIPFlashBridgeAdapter} from "../../contracts/flash/UniversalCCIPFlashBridgeAdapter.sol";
|
|
|
|
/// @dev Minimal stand-in for `UniversalCCIPBridge.bridge` (pulls token, records op).
|
|
contract FlashBridgeAdapterTestMock {
|
|
event BridgeCalled(address token, uint256 amount, uint64 dest, address recipient, bytes32 assetType, bool pmm, bool vault);
|
|
|
|
function bridge(UniversalCCIPBridge.BridgeOperation calldata op) external payable returns (bytes32) {
|
|
IERC20(op.token).transferFrom(msg.sender, address(this), op.amount);
|
|
emit BridgeCalled(
|
|
op.token, op.amount, op.destinationChain, op.recipient, op.assetType, op.usePMM, op.useVault
|
|
);
|
|
return keccak256(abi.encodePacked("mock", op.token, op.amount));
|
|
}
|
|
|
|
receive() external payable {}
|
|
}
|
|
|
|
contract MockMintERC20 is ERC20 {
|
|
constructor() ERC20("A", "A") {}
|
|
|
|
function mint(address to, uint256 v) external {
|
|
_mint(to, v);
|
|
}
|
|
}
|
|
|
|
contract UniversalCCIPFlashBridgeAdapterTest is Test {
|
|
FlashBridgeAdapterTestMock internal uni;
|
|
UniversalCCIPFlashBridgeAdapter internal adapter;
|
|
MockMintERC20 internal token;
|
|
|
|
address internal alice = address(0xA11CE);
|
|
|
|
function setUp() public {
|
|
uni = new FlashBridgeAdapterTestMock();
|
|
adapter = new UniversalCCIPFlashBridgeAdapter(address(uni));
|
|
token = new MockMintERC20();
|
|
token.mint(alice, 500e18);
|
|
vm.deal(alice, 10 ether);
|
|
}
|
|
|
|
function test_adapter_pullsAndCallsBridge_emptyExtraData() public {
|
|
vm.startPrank(alice);
|
|
token.approve(address(adapter), 100e18);
|
|
bytes32 mid = adapter.bridgeTokensFrom{value: 1 wei}(address(token), 100e18, 7, address(0xBEEF), "");
|
|
vm.stopPrank();
|
|
|
|
assertTrue(mid != bytes32(0));
|
|
assertEq(token.balanceOf(address(uni)), 100e18);
|
|
}
|
|
|
|
function test_adapter_decodesExtraData() public {
|
|
bytes memory extra = abi.encode(bytes32(uint256(1)), true, false, bytes("p"), bytes("v"));
|
|
vm.startPrank(alice);
|
|
token.approve(address(adapter), 50e18);
|
|
adapter.bridgeTokensFrom(address(token), 50e18, 99, address(0xCAFE), extra);
|
|
vm.stopPrank();
|
|
|
|
assertEq(token.balanceOf(address(uni)), 50e18);
|
|
}
|
|
}
|