feat(executor): transaction builder + eth_call simulator#41
Merged
Conversation
New `charon-executor` crate. Two modules — both deliberately small, both passive (no broadcast / no signing of arbitrary inputs / no state held beyond config). Pipeline glue (#15) wires them together. builder.rs — `TxBuilder`: - `encode_calldata(opp, params)` — packs the protocol-specific `LiquidationParams::Venus` plus underlying-token addresses from the `LiquidationOpportunity` into the on-chain `CharonLiquidationParams` struct (lockstep with the Solidity source) and ABI-encodes the outer `executeLiquidation(...)` call via `alloy::sol!` + `SolCall::abi_encode` - `build_tx(provider, calldata, max_fee, priority_fee, gas_limit)` — assembles an EIP-1559 `TransactionRequest`, fetching the latest nonce for the bot signer - `sign(tx)` — signs via `EthereumWallet`, returns raw EIP-2718 envelope bytes ready for `eth_sendRawTransaction` or a Flashbots bundle. **Does not broadcast.** - Test pins selector against `executeLiquidationCall::SELECTOR` (catches accidental drift between Rust + Solidity struct shapes) simulation.rs — `Simulator`: - `simulate(provider, calldata)` — `eth_call` against latest block. Ok = caller may broadcast; Err = revert reason logged at WARN, caller drops the opportunity. Zero gas spent. Constants pinned: `PROTOCOL_VENUS = 3` matches the Solidity constant. `CharonLiquidationParams` field order/types must match `contracts/src/CharonLiquidator.sol` exactly — the selector test will fail if either side drifts.
This was referenced Apr 23, 2026
Closed
Closed
Closed
[executor] charon-executor still missing from workspace members — fourth consecutive PR flagged
#199
Closed
Closed
Closed
Closed
Closed
Closed
obchain
added a commit
that referenced
this pull request
Apr 23, 2026
…able the swap leg hard-coded `fee: 3000` (0.30 %). that tier does not exist or has near-zero liquidity for several Venus-collateral pairs on PCS V3: BTCB/USDT sits in the 0.05 % (500) pool, ETH/USDT in the 0.01 % (100) pool, XVS/WBNB in the 1 % (10000) pool. routing those through the 0.30 % pool would revert on `SPL` or eat unbounded slippage. add `uint24 swapPoolFee` to LiquidationParams, validate non-zero in executeLiquidation, and pass it to ExactInputSingleParams.fee. the off-chain opportunity router now selects the deepest pool per pair. abi layout note: this extends LiquidationParams with a new tail field. the companion Rust `LiquidationParams` builder in the charon-executor crate (not yet present on this branch — lands with PR #41) must mirror the added field. closes #122
- Redact PrivateKeySigner in TxBuilder Debug to avoid leaking the k256 scalar into logs (#158). - Pull nonce from the pending block tag so queued tx don't collide with newly built ones; TODO flags NonceManager in PR #43 (#159). - Reject build_tx calls where priority tip exceeds max fee per gas before any RPC round-trip (#160). - Require an explicit gas_limit on Simulator::simulate so the simulation burns the same gas ceiling as the real broadcast (#161). - Add Simulator::from_builder so the simulated sender is always the builder's hot wallet (onlyOwner alignment), plus debug_assert on non-zero sender (#162). - Replace anyhow on the public lib surface with BuilderError and SimulationError thiserror enums (#163). - Pin PROTOCOL_VENUS to the Solidity constant with an ABI-level unit test and line-number comment referencing CharonLiquidator.sol:49 (#164). - Adopt workspace lints (unsafe_code=forbid, arithmetic_side_effects, cast_possible_truncation, unwrap_used) and opt charon-executor in via [lints] workspace = true (#165). - Decode revert payload in Simulator::simulate into a 4-byte selector plus full hex body so logs are greppable cross-protocol (#166). - Add #[ignore]d fork tests covering the happy path and the onlyOwner adversarial path to pin the sim gate's safety invariant (#167). Closes #158 Closes #159 Closes #160 Closes #161 Closes #162 Closes #163 Closes #164 Closes #165 Closes #166 Closes #167
…der-and-sim # Conflicts: # Cargo.toml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #15
New
charon-executorcrate. Two modules, both small and passive (no broadcast, no signing of arbitrary inputs, no state held beyond config). Pipeline glue wires them together in a later PR.builder.rs—TxBuilder:encode_calldata(opp, params)— packsLiquidationParams::Venus+ underlying-token addresses from the opportunity into the on-chainCharonLiquidationParamsstruct (lockstep with Solidity) and ABI-encodes the outerexecuteLiquidation(...)call viaalloy::sol!+SolCall::abi_encodebuild_tx(provider, calldata, max_fee, priority_fee, gas_limit)— assembles EIP-1559TransactionRequest, fetches the latest nonce for the bot signersign(tx)— signs viaEthereumWallet, returns raw EIP-2718 envelope bytes. Does not broadcast.executeLiquidationCall::SELECTOR(catches accidental drift between Rust + Solidity struct shapes)simulation.rs—Simulator:simulate(provider, calldata)—eth_callagainst latest block.Ok= caller may broadcast;Err= revert reason logged at WARN, caller drops the opportunity. Zero gas spent.Constants pinned:
PROTOCOL_VENUS = 3matches Solidity constant.CharonLiquidationParamsfield order/types must matchcontracts/src/CharonLiquidator.solexactly — selector test fails if either side drifts.Depends on
feat/15-profit-calc-and-queue.