Skip to content
Lattice

StargateBridgeAdapterLib

Git Source

Title: StargateBridgeAdapterLib

Authors: David Dada <daveproxy80@gmail.com> (https://github.com/dadadave80), Modified from Stargate (https://github.com/stargate-protocol/stargate-v2)

Logic + ERC-7201 storage for the Stargate v2 POOLED-LIQUIDITY token-bridge adapter (the third token rail: neither burn/mint CCTP nor intent Across). Outbound sendToken pulls exactly amountLD from the caller, force-approves the token's registered pool for exactly that amount, dispatches a TAXI-mode OFT send, resets the allowance to 0, then sweeps any un-debited dust back to the caller (pools truncate amountLD to shared decimals, so amountSentLD may be LESS than what was pulled — the diamond nets zero).

TRUST MODEL / SCOPE: Stargate pools hold unified liquidity; the DESTINATION pool is the LayerZero receiver that credits the recipient — no Lattice inbound surface exists (outbound-only for plain transfers; never routed through OpenBridge, no receiveId). DEFERRED (documented, deliberate): composeMsg/lzCompose destination hooks and BUS mode (non-empty oftCmd; issue #77 Q11) — every send here is a taxi (empty oftCmd); native-ETH pools (StargatePoolNative), whose msg.value mixes fee + amount — v1 is ERC-20 ONLY and msg.value is the LayerZero fee EXCLUSIVELY. REFUND SAFETY: refundAddress is ALWAYS msg.sender — excess LayerZero fee refunds go to the USER, never the diamond (same stranding class as the Across depositor). Reuses the shared safe-transfer / force-approve helpers (BridgeFungibleLib.pullExact, AdapterBaseLib.forceApprove); no bespoke ERC-20 plumbing.

Functions

stargateBridgeAdapterStorage

function stargateBridgeAdapterStorage() internal pure returns (StargateBridgeAdapterStorage storage $);

Returns

NameTypeDescription
$StargateBridgeAdapterStorage

__StargateBridgeAdapter_init

Registers the IStargateBridgeAdapter ERC-165 id. Called inside the diamond initializing window. No protocol wiring happens at init — Stargate is per-token pools, all admin-registered (registerStargateEid/registerPool) after deploy.

function __StargateBridgeAdapter_init() internal;

registerInterface

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

function registerInterface() internal;

stargateEidOf

function stargateEidOf(uint256 chainId) internal view returns (uint32);

Parameters

NameTypeDescription
chainIduint256

Returns

NameTypeDescription
<none>uint32

stargateChainIdOf

function stargateChainIdOf(uint32 eid) internal view returns (uint256);

Parameters

NameTypeDescription
eiduint32

Returns

NameTypeDescription
<none>uint256

poolOf

function poolOf(address token) internal view returns (address);

Parameters

NameTypeDescription
tokenaddress

Returns

NameTypeDescription
<none>address

quoteSendFee

Quotes the LayerZero native fee of p, building the IDENTICAL SendParam (same _buildSendParam builder, same checks) the sendToken path dispatches — quote and send can never drift.

function quoteSendFee(IStargateBridgeAdapter.SendTokenParams calldata p) internal view returns (uint256 nativeFee);

Parameters

NameTypeDescription
pIStargateBridgeAdapter.SendTokenParams

Returns

NameTypeDescription
nativeFeeuint256

registerStargateEid

Registers an EVM chainId ↔ LayerZero eid equivalence (both directions). FAIL-LOUD identity admin: an already-mapped chainId OR eid reverts — identities are never remapped. chainId 0 and eid 0 are rejected (0 is each map's unset sentinel). Admin only.

Stargate rides LayerZero, so this eid equals the LayerZero adapter's eid for the same chain — recorded in this adapter's OWN map (adapters never share hot-path storage).

function registerStargateEid(uint256 chainId, uint32 eid) internal;

Parameters

NameTypeDescription
chainIduint256
eiduint32

registerPool

Registers token's LOCAL Stargate pool. FAIL-LOUD identity per token (StargateTokenAlreadyRegistered — a pool upgrade cannot re-point a token entry in v1; deliberate YAGNI) and FAIL-CLOSED: IStargate(pool).token() must equal token (StargatePoolTokenMismatch) — a mis-registered pool would burn user approvals against the wrong asset. Admin only.

ERC-20 pools ONLY in v1: a StargatePoolNative reports token() == address(0) and is rejected by the cross-check against the non-zero token argument.

function registerPool(address token, address pool) internal;

Parameters

NameTypeDescription
tokenaddress
pooladdress

sendToken

Sends p.amountLD of p.token (pulled from msg.sender) through its registered Stargate pool toward the ERC-7930 p.recipient on p.destinationChainId. Strict CEI under the reentrancy guard: checks + fee precheck, pull exactly amountLD, approve the pool for exactly amountLD, send (taxi), reset the allowance to 0, sweep un-debited dust back to the caller.

FEE PRECHECK (mirrors the Hyperlane sibling): quoteSend(...).nativeFee is compared against msg.value BEFORE any funds move — a shortfall reverts StargateInsufficientFee instead of bubbling an opaque pool revert after the pull. msg.value is then forwarded WHOLE as the MessagingFee.nativeFee with refundAddress = msg.sender, so any excess refunds to the USER, never the diamond (REFUND-CRITICAL — same stranding class as the Across depositor). DUST-CRITICAL: the pool debits oftReceipt.amountSentLD, which may be LESS than amountLD (shared-decimal truncation) — the exact leftover (balance now - snapshot) is transferred back to msg.sender, so the diamond nets zero even for dusty amounts.

function sendToken(IStargateBridgeAdapter.SendTokenParams calldata p)
        internal
        returns (bytes32 guid, uint256 amountSentLD, uint256 amountReceivedLD);

Parameters

NameTypeDescription
pIStargateBridgeAdapter.SendTokenParams

Returns

NameTypeDescription
guidbytes32
amountSentLDuint256
amountReceivedLDuint256

_buildSendParam

Validates p and builds the TAXI-mode SendParam both the quote and send paths use: empty extraOptions (pool default executor options), empty composeMsg (no lzCompose hook) and empty oftCmd (taxi — bus mode deferred, issue #77 Q11).

Check order: pool registered, non-zero amount, non-zero minAmount (mandatory slippage floor — pools charge fees so output < input; 0 would mean unlimited slippage), not same-chain, eid registered, then the ERC-7930 recipient parse + fail-closed eip-155 cross-check.

function _buildSendParam(IStargateBridgeAdapter.SendTokenParams calldata p)
        private
        view
        returns (address pool, SendParam memory sendParam);

Parameters

NameTypeDescription
pIStargateBridgeAdapter.SendTokenParams

Returns

NameTypeDescription
pooladdress
sendParamSendParam

_callPool

The pool call lives in its own frame (returns collapse the two receipts into scalars) — stack relief for sendToken under the legacy codegen pipeline. Forwards msg.value WHOLE as the native fee; refundAddress = msg.sender (REFUND-CRITICAL, see sendToken). The returned bus Ticket is ignored: taxi-mode sends always return an empty one.

function _callPool(address pool, SendParam memory sendParam)
        private
        returns (bytes32 guid, uint256 amountSentLD, uint256 amountReceivedLD);

Parameters

NameTypeDescription
pooladdress
sendParamSendParam

Returns

NameTypeDescription
guidbytes32
amountSentLDuint256
amountReceivedLDuint256

_parseAndCheckRecipient

Parses the ERC-7930 recipient (canonical widths enforced; reverts on empty/oversized/short-EVM address fields) and fail-closed cross-checks a declared eip-155 chain reference against destinationChainId (reverts StargateDestinationMismatch — mirrors the Across sibling). For non-EVM chainTypes no cross-check is possible; the bytes32 is trusted as caller-supplied.

function _parseAndCheckRecipient(bytes calldata recipientBytes, uint256 destinationChainId)
        private
        pure
        returns (bytes32 recipient);

Parameters

NameTypeDescription
recipientBytesbytes
destinationChainIduint256

Returns

NameTypeDescription
recipientbytes32

_chainIdFromReference

Right-aligns an ERC-7930 chain-reference (<= 32 bytes, big-endian) into a uint256 chainId.

For eip-155 chains the reference IS the chainId. Reverts StargateChainReferenceTooLong if > 32 bytes.

function _chainIdFromReference(bytes memory ref) private pure returns (uint256 chainId);

Parameters

NameTypeDescription
refbytes

Returns

NameTypeDescription
chainIduint256