Skip to content
Lattice

AggregatorExecAdapterLib

Git Source

Title: AggregatorExecAdapterLib

Authors: David Dada <daveproxy80@gmail.com> (https://github.com/dadadave80), Modified from LI.FI (https://github.com/lifinance/contracts)

Logic + ERC-7201 storage for the generic swap/bridge EXECUTION adapter. execute forwards off-chain-built calldata to an admin-allow-listed (aggregator, selector) pair, making an ARBITRARY external call from a fund-holding diamond — so the entire design is confused-deputy prevention.

SECURITY MODEL (why each step exists):

  • Allow-list: bytes4(callData) is the selector the aggregator dispatches on, so gating _allowedCall[aggregator][selector] gates exactly what the aggregator will do. address(0) and address(this) can never be allow-listed (the latter would let crafted calldata re-enter privileged facets — the classic confused-deputy on a diamond).
  • Fund isolation: funds are pulled from msg.sender (never the diamond balance) and the aggregator is granted an EXACT, immediately-reset approval. Balance snapshots taken BEFORE the pull/call make every sweep DELTA-based, so a pre-existing standing balance of any token (or native) is provably untouched: crafted calldata cannot route the diamond's OTHER holdings out.
  • Approval hygiene: the input allowance is reset to 0 after every call (no standing grant to drain).
  • Leftover sweep: unspent input (delta above the standing balance), the output-token delta, and any unspent native are all returned to msg.sender, so the diamond nets zero from the call. COMPOSITION INVARIANT (the delta-sweep protects ONLY input/output/native): this adapter itself never leaves a standing ERC-20 allowance to any aggregator (it resets to 0 on every call), so it is safe standalone. But if a DIFFERENT facet composed into the same diamond leaves a live allowance to an allow-listed aggregator for some third token Z the diamond also holds, crafted calldata could swap that Z out (its proceeds swept as the output delta). Integrators MUST NOT grant standing allowances to any address that is (or may become) an allow-listed aggregator; a composability CI guard asserting zero standing aggregator allowances is the recommended enforcement. Reuses the shared safe-transfer / force-approve helpers (BridgeFungibleLib.pullExact, AdapterBaseLib.forceApprove/transferHonest/balanceOfSelf); no bespoke ERC-20 plumbing.

Functions

aggregatorExecAdapterStorage

function aggregatorExecAdapterStorage() internal pure returns (AggregatorExecAdapterStorage storage $);

Returns

NameTypeDescription
$AggregatorExecAdapterStorage

__AggregatorExecAdapter_init

Registers the IAggregatorExecAdapter ERC-165 id. Called inside the diamond initializing window.

function __AggregatorExecAdapter_init() internal;

registerInterface

Writes true to the ERC-165 map slot for IAggregatorExecAdapter.

function registerInterface() internal;

isAllowedCall

function isAllowedCall(address aggregator, bytes4 selector) internal view returns (bool);

Parameters

NameTypeDescription
aggregatoraddress
selectorbytes4

Returns

NameTypeDescription
<none>bool

setAllowedCall

Toggles allow-listing of the (aggregator, selector) pair. Admin only. address(0) and address(this) are rejected — the diamond must NEVER be able to call ITSELF through this adapter.

function setAllowedCall(address aggregator, bytes4 selector, bool allowed) internal;

Parameters

NameTypeDescription
aggregatoraddress
selectorbytes4
allowedbool

execute

Forwards callData to an allow-listed (aggregator, bytes4(callData)) under strict CEI, pulling amount of inputToken from msg.sender, approving EXACTLY that amount, then resetting the approval to 0 and sweeping every leftover (unspent input, output delta, unspent native) back to the caller. See AggregatorExecAdapterLib security model for why each step is present.

function execute(
        address aggregator,
        address inputToken,
        uint256 amount,
        address outputToken,
        bytes calldata callData
    ) internal returns (bytes memory ret);

Parameters

NameTypeDescription
aggregatoraddress
inputTokenaddress
amountuint256
outputTokenaddress
callDatabytes

Returns

NameTypeDescription
retbytes