@@ -6,8 +6,25 @@ import {PolymerCCTPFacet} from "lifi/Facets/PolymerCCTPFacet.sol";
66import {IPolymerCCTPFacet} from "lifi/Interfaces/IPolymerCCTP.sol " ;
77import {PolymerCCTPData} from "lifi/Interfaces/IPolymerCCTP.sol " ;
88import {ILiFi} from "lifi/Interfaces/ILiFi.sol " ;
9+ import {LibSwap} from "lifi/Libraries/LibSwap.sol " ;
10+ import {LibAllowList} from "lifi/Libraries/LibAllowList.sol " ;
911import {ERC20 } from "solmate/tokens/ERC20.sol " ;
10- import {InvalidReceiver, InvalidAmount, InvalidSendingToken} from "src/Errors/GenericErrors.sol " ;
12+ import {InvalidReceiver, InvalidAmount} from "src/Errors/GenericErrors.sol " ;
13+
14+ // Test version with allowlist management
15+ contract TestPolymerCCTPFacet is PolymerCCTPFacet {
16+ constructor (address _tokenMessenger , address _usdc , address _polymerFeeReceiver )
17+ PolymerCCTPFacet (_tokenMessenger, _usdc, _polymerFeeReceiver)
18+ {}
19+
20+ function addDex (address _dex ) external {
21+ LibAllowList.addAllowedContract (_dex);
22+ }
23+
24+ function setFunctionApprovalBySignature (bytes4 _signature ) external {
25+ LibAllowList.addAllowedSelector (_signature);
26+ }
27+ }
1128
1229// Mock TokenMessenger
1330contract MockTokenMessenger {
@@ -37,8 +54,25 @@ contract MockUSDC is ERC20 {
3754 }
3855}
3956
57+ // Mock token for swap testing
58+ contract MockToken is ERC20 {
59+ constructor (string memory name , string memory symbol , uint8 decimals ) ERC20 (name, symbol, decimals) {}
60+
61+ function mint (address to , uint256 amount ) external {
62+ _mint (to, amount);
63+ }
64+ }
65+
66+ // Mock DEX for swapping
67+ contract MockDEX {
68+ function swap (address tokenIn , address tokenOut , uint256 amountIn , uint256 amountOut ) external {
69+ ERC20 (tokenIn).transferFrom (msg .sender , address (this ), amountIn);
70+ ERC20 (tokenOut).transfer (msg .sender , amountOut);
71+ }
72+ }
73+
4074contract PolymerCCTPFacetTest is Test {
41- PolymerCCTPFacet public facet;
75+ TestPolymerCCTPFacet public facet;
4276 MockTokenMessenger public tokenMessenger;
4377 MockUSDC public usdc;
4478
@@ -52,7 +86,7 @@ contract PolymerCCTPFacetTest is Test {
5286 tokenMessenger = new MockTokenMessenger ();
5387
5488 // Deploy facet
55- facet = new PolymerCCTPFacet (address (tokenMessenger), address (usdc), feeReceiver);
89+ facet = new TestPolymerCCTPFacet (address (tokenMessenger), address (usdc), feeReceiver);
5690
5791 // Mint USDC to user
5892 usdc.mint (user, 1_000_000e6 ); // 1M USDC
@@ -207,9 +241,80 @@ contract PolymerCCTPFacetTest is Test {
207241 vm.startPrank (user);
208242 wrongToken.approve (address (facet), bridgeData.minAmount);
209243
210- vm.expectRevert (InvalidSendingToken. selector );
244+ vm.expectRevert ( abi.encodeWithSelector (IPolymerCCTPFacet.InvalidSendingAsset. selector , address (wrongToken), address (usdc)) );
211245 facet.startBridgeTokensViaPolymerCCTP (bridgeData, polymerData);
212246
213247 vm.stopPrank ();
214248 }
249+
250+ function test_CanSwapAndBridgeViaPolymerCCTP () public {
251+ // Deploy mock token and DEX
252+ MockToken dai = new MockToken ("DAI " , "DAI " , 18 );
253+ MockDEX dex = new MockDEX ();
254+
255+ // Add DEX to allowlist
256+ facet.addDex (address (dex));
257+ facet.setFunctionApprovalBySignature (MockDEX.swap.selector );
258+
259+ // Setup: User has DAI, wants to swap to USDC and bridge
260+ uint256 daiAmount = 100_000e18 ; // 100k DAI
261+ uint256 usdcAmount = 100_000e6 ; // 100k USDC (after swap)
262+ uint256 polymerFee = 100e6 ; // 100 USDC fee
263+ uint256 amountAfterFee = usdcAmount - polymerFee;
264+
265+ // Mint DAI to user and USDC to DEX
266+ dai.mint (user, daiAmount);
267+ usdc.mint (address (dex), usdcAmount);
268+
269+ ILiFi.BridgeData memory bridgeData = ILiFi.BridgeData ({
270+ transactionId: bytes32 (uint256 (1 )),
271+ bridge: "polymercctp " ,
272+ integrator: "test " ,
273+ referrer: address (0 ),
274+ sendingAssetId: address (usdc),
275+ receiver: receiver,
276+ minAmount: usdcAmount,
277+ destinationChainId: 81457 , // Blast
278+ hasSourceSwaps: true ,
279+ hasDestinationCall: false
280+ });
281+
282+ // Create swap data
283+ LibSwap.SwapData[] memory swapData = new LibSwap.SwapData [](1 );
284+ swapData[0 ] = LibSwap.SwapData ({
285+ callTo: address (dex),
286+ approveTo: address (dex),
287+ sendingAssetId: address (dai),
288+ receivingAssetId: address (usdc),
289+ fromAmount: daiAmount,
290+ callData: abi.encodeWithSelector (MockDEX.swap.selector , address (dai), address (usdc), daiAmount, usdcAmount),
291+ requiresDeposit: true
292+ });
293+
294+ PolymerCCTPData memory polymerData = PolymerCCTPData ({
295+ polymerTokenFee: polymerFee, maxCCTPFee: 0 , nonEvmAddress: bytes32 (0 ), minFinalityThreshold: 0
296+ });
297+
298+ vm.startPrank (user);
299+
300+ // Approve facet to spend DAI
301+ dai.approve (address (facet), daiAmount);
302+
303+ // Execute swap and bridge
304+ facet.swapAndStartBridgeTokensViaPolymerCCTP (bridgeData, swapData, polymerData);
305+
306+ vm.stopPrank ();
307+
308+ // Verify fee receiver got the fee
309+ assertEq (usdc.balanceOf (feeReceiver), polymerFee);
310+
311+ // Verify token messenger got the bridge amount minus fee
312+ assertEq (usdc.balanceOf (address (tokenMessenger)), amountAfterFee);
313+
314+ // Verify user's DAI balance decreased
315+ assertEq (dai.balanceOf (user), 0 );
316+
317+ // Verify DEX has the DAI
318+ assertEq (dai.balanceOf (address (dex)), daiAmount);
319+ }
215320}
0 commit comments