LayerX Forge Std Integration, Test Mocks, and Solidity Test Support
Vendored Forge Standard Library, test mock contracts (MockERC20, MockUSDT, MockWrappedNative, MockPECORRouter, ReentrantToken), and Solidity test fixtures for the LayerX contract suite.
Overview
The LayerX contract test suite uses vendored forge-std (v1.16.1) under lib/ for tests only. Production src/ has zero external imports. The test/mocks/ directory provides concrete mock contracts to simulate ERC-20 behavior, USDT-style approval rules, wrapped native flows, router execution, and reentrancy attacks.
Forge Std Configuration
Source: layerx/contracts/foundry.toml
| Key | Value | Effect |
|---|---|---|
libs | ["lib"] | Resolves forge-std from lib/ |
fs_permissions | read ./out | Allows test file reads |
The vendored forge-std package.json declares version 1.16.1.
Test Harness
forge-std/src/Test.sol is the abstract base contract combining TestBase, StdAssertions, StdChains, StdCheats, StdInvariant, and StdUtils. LayerX tests inherit from Test to access:
vm.deal/vm.prank/vm.startPrankfor address impersonationvm.expectRevertwithstdErrorselectorsassertEq/assertTrue/assertGtfor assertionsvm.loadfor direct storage readsconsole2.logfor decoded Forge trace logging
Test Mock Contracts
MockERC20
Source: layerx/contracts/test/mocks/MockERC20.sol
Standard, well-behaved ERC-20 test token.
| Constructor | Type | Description |
|---|---|---|
n | string | Token name |
s | string | Token symbol |
d | uint8 | Decimals |
Methods: mint(to, amount), transfer, approve, transferFrom (unlimited allowance when type(uint256).max).
MockUSDT
Source: layerx/contracts/test/mocks/MockUSDT.sol
Models non-standard USDT behavior:
transferandtransferFromreturnvoid(no boolean)approverequires resetting allowance to zero before setting a new non-zero value
Used to exercise SafeERC20.forceApprove and the no-boolean-return wrapper.
MockWrappedNative
Source: layerx/contracts/test/mocks/MockWrappedNative.sol
WETH-style wrapper inheriting MockERC20 ("Wrapped PAX", "WPAX9", 18 decimals). Methods: deposit() (accepts native value), withdraw(amount) (sends native value back).
MockPECORRouter
Source: layerx/contracts/test/mocks/MockPECORRouter.sol
Test DEX router for swap-based deposits.
| Property | Type | Description |
|---|---|---|
usdl | IERC20 | Immutable USDL payout asset |
rateE18 | mapping(address => uint256) | Per-token conversion rate (scaled by 1e18) |
Methods:
setRate(tokenIn, rate)- set conversion rateswapBestRoute(tokenIn, tokenOut, amountIn, amountOutMin, deadline)- execute swap (requires USDL astokenOut)getBestQuote(tokenIn, tokenOut, amountIn)- read-only quote
Formula: out = amountIn * rateE18[tokenIn] / 1e18
ReentrantToken
Source: layerx/contracts/test/mocks/ReentrantToken.sol
Malicious token that attempts reentry during transferFrom. Inherits MockERC20 ("Reentrant", "RE", 6 decimals).
| Property | Type | Description |
|---|---|---|
target | address | Call target for reentry |
payload | bytes | Calldata for reentry |
armed | bool | Single-shot guard |
reentryAttempted | bool | Whether callback was attempted |
reentrySucceeded | bool | Whether callback succeeded |
Methods:
arm(target, payload)- enable one-shot reentry attempttransferFrom- when armed, clears arm, records attempt, callstarget.call(payload), then continues with normal transfer
Used to prove that vault entrypoints are protected by nonReentrant.
Solidity Test Files
SettlementAnchor.t.sol
Tests: writer can anchor and root is visible via rootOf; non-writers rejected; same batch id cannot be recorded twice; zero roots rejected; governor can rotate writer.
SafeERC20.t.sol
Tests with a harness contract exposing library functions: standard transfers succeed; USDT-style no-boolean tokens accepted; forceApprove handles reset-to-zero; calling into non-contract address reverts.
LayerXVault.t.sol
Tests: direct USDL deposits mint 1:1; swap deposits enforce slippage/deadline; native deposits wrap and swap; settlement is idempotent/capped/reserve-bounded; force-exit covers initiate/challenge/finalize with epoch checks; pause/unpause obey access rules; governance is two-step; reentrancy guard blocks malicious tokens; exit-delay bounds enforced.
PaymentChannel.t.sol (Deus)
Tests: fund and payout, close and refund, availableWei accounting.
Fixture Files
| File | Purpose |
|---|---|
lib/forge-std/test/fixtures/test.json | JSON fixture with scalar + nested data |
lib/forge-std/test/fixtures/test.toml | TOML mirror of JSON fixture |
lib/forge-std/test/fixtures/config.toml | Chain-scoped config with typed subtables |
lib/forge-std/test/fixtures/broadcast.log.json | Full broadcast record for parsing tests |
Test Execution Pattern
1. Developer writes Solidity test inheriting Test
2. Test deploys mock contracts (MockERC20, MockUSDT, MockWrappedNative, MockPECORRouter, ReentrantToken)
3. Test calls vault/anchor methods with controlled mock state
4. Test asserts with assertEq / vm.expectRevert / vm.load
5. forge test --match-path test/ContractName.t.sol
