Skip to content

feat(contracts): Foundry workspace + CharonLiquidator skeleton#36

Merged
obchain merged 6 commits intomainfrom
feat/11-foundry-skeleton
Apr 24, 2026
Merged

feat(contracts): Foundry workspace + CharonLiquidator skeleton#36
obchain merged 6 commits intomainfrom
feat/11-foundry-skeleton

Conversation

@obchain
Copy link
Copy Markdown
Owner

@obchain obchain commented Apr 21, 2026

Closes #12

Lays the on-chain foundation. Contract shape and storage layout are fixed by this commit so the Rust tx builder and fork tests can target stable signatures; actual liquidation + flash-loan + swap logic is the next PR.

  • contracts/ Foundry workspace, forge-std pinned via submodule
  • foundry.toml — solc 0.8.24, optimizer 1M runs, 100-char fmt, BSC RPC + etherscan endpoints driven from ${BNB_HTTP_URL} / ${BSCSCAN_API_KEY}
  • src/CharonLiquidator.sol:
    • executeLiquidation(LiquidationParams) entrypoint, onlyOwner
    • executeOperation(...) Aave V3 callback, gated by msg.sender == AAVE_POOL AND initiator == address(this)
    • Both stub bodies revert with explicit "not yet implemented" so any accidental skeleton deploy fails loud
    • rescue(token, to, amount) fully implemented as a safety hatch (handles native BNB + ERC-20, checks transfer return value)
    • LiquidationExecuted + Rescued events
    • Immutables: owner, AAVE_POOL, SWAP_ROUTER (zero-address guarded)
  • src/interfaces/: minimal IFlashLoanSimpleReceiver, IERC20, IAaveV3Pool, IVToken — no external libs
  • Skipped: Balancer receiveFlashLoan (not on BSC), IComet/IMorpho (out of v0.1 scope)

forge build clean, forge fmt --check clean.

Depends on #11 (feat/10-chainlink-pricecache).

…#11)

Lays the on-chain foundation. The contract shape and the storage
layout are fixed by this commit so the Rust tx builder (#14) and the
fork tests (#22) can target stable signatures; the actual liquidation
+ flash-loan + swap logic is the next commit (#12).

- `contracts/` Foundry workspace, `forge-std` pinned via submodule
- `foundry.toml` — solc 0.8.24, optimizer 1M runs, 100-char fmt,
  BSC RPC + etherscan endpoints driven from `${BNB_HTTP_URL}` /
  `${BSCSCAN_API_KEY}` so fork tests run against mainnet state
- `src/CharonLiquidator.sol`:
    - `executeLiquidation(LiquidationParams)` entrypoint, `onlyOwner`
    - `executeOperation(...)` Aave V3 callback, gated by
      `msg.sender == AAVE_POOL` AND `initiator == address(this)`
    - both stub bodies revert with explicit "not yet implemented"
      so any accidental skeleton deploy fails loud before touching
      funds
    - `rescue(token, to, amount)` fully implemented as a safety hatch
      (handles native BNB and ERC-20, checks transfer return value)
    - `LiquidationExecuted` + `Rescued` events
    - immutables: owner, AAVE_POOL, SWAP_ROUTER (zero-address guarded)
- `src/interfaces/`: minimal IFlashLoanSimpleReceiver, IERC20,
  IAaveV3Pool, IVToken stubs — no external libs, all defined inline
- Skipped: Balancer `receiveFlashLoan` callback (not on BSC),
  IComet/IMorpho (out of v0.1 scope)

`forge build` clean, `forge fmt --check` clean.
obchain added 5 commits April 23, 2026 12:38
drop the floating `^0.8.24` caret across CharonLiquidator.sol and the
four inline interfaces. pins deployed-bytecode producing solc to a
single known version and removes risk of a future 0.8.x patch release
subtly changing codegen, optimizer behaviour or metadata hash.

closes #113
BNB Chain has not adopted the Shanghai hard fork and rejects the
PUSH0 opcode. solc >= 0.8.20 emits PUSH0 by default, so contracts
compiled with the prior config would revert on first touch when
deployed to BSC. pinning the target to paris keeps our bytecode
compatible with the live chain until BSC enables Shanghai.

closes #114
the forge-std submodule is already pinned by gitlink to commit
2999b6563e1f07971a09d48b82f3fac910d72a05 (v1.15.0 + 15) in the
parent repo's index, but .gitmodules carried no explanation. add
comments recording the pin, noting the absence of `branch =` is
deliberate (so `git submodule update` tracks the recorded commit,
not a moving tip), and warning against `--remote` in CI.

closes #115
remove the open `receive() external payable { }` hatch on
CharonLiquidator so misrouted or griefing bnb transfers now revert
instead of silently accumulating. v0.1 does not handle the vBNB
native market; when it is added, a sender-gated receive() will be
introduced. existing rescue(address(0), ...) still recovers bnb
credited via selfdestruct.

switch the native-bnb branch of rescue() from `payable(to).transfer`
to `payable(to).call{value: amount}("")` with a checked success
return. the 2300-gas stipend of `transfer`/`send` is insufficient
post-EIP-1884 for gnosis safe and other smart-wallet recipients,
which would otherwise trap funds. erc-20 path is unchanged.

closes #117
step-11 requires a passing forge test suite. add one that covers
the shape of the deployed skeleton without any fork dependency:

- constructor zero-address guards and owner/immutable binding
- onlyOwner on executeLiquidation and rescue
- per-field input validation inside executeLiquidation (seven
  require branches reached before the skeleton's final revert)
- executeOperation `!pool` and `!initiator` security gates
- rescue() erc-20 and native-bnb happy paths, zero-recipient and
  zero-amount reverts, plus the post-#117 `call`-based bnb path
  against a gas-hungry contract recipient that would reject a
  2300-gas `transfer` stipend
- post-#117 no-receive policy: direct bnb sends must revert

uses only forge-std and two in-file mocks (MockERC20,
GasHungryReceiver); pinned at solidity 0.8.24. fork-based end-to-end
coverage remains tracked under issue #22.

closes #116
@obchain obchain changed the base branch from feat/10-chainlink-pricecache to main April 24, 2026 10:40
@obchain obchain merged commit 4c3ad92 into main Apr 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[contracts] Foundry workspace + CharonLiquidator.sol skeleton

1 participant