Overview
ThePolygon_SpokePool is deployed on Polygon PoS (formerly Matic). It implements Polygon’s unique FxPortal cross-chain messaging system and integrates with the custom PolygonTokenBridger contract due to special constraints in Polygon’s native bridge.
Contract: contracts/Polygon_SpokePool.sol
Key Characteristics
- FxPortal messaging: Uses Polygon’s FxChild contract for cross-chain admin verification
- Custom token bridger: Uses
PolygonTokenBridgerinstead of direct bridge calls - Delegatecall validation: Admin functions executed via delegatecall from
processMessageFromRoot() - CCTP support: Integrates Circle CCTP for USDC transfers
- OFT support: Supports LayerZero OFT tokens
- Native token wrapping: Handles MATIC→WMATIC conversions
- EOA-only restrictions: Enforces EOA callers for certain functions to prevent griefing
Inheritance
- Implements
IFxMessageProcessorto receive FxPortal messages - Inherits base
SpokePoolfunctionality - Inherits
CircleCCTPAdapterfor USDC bridging
Constructor
_wrappedNativeTokenAddress: Address of WMATIC on Polygon_depositQuoteTimeBuffer: Max age for deposit quote timestamps_fillDeadlineBuffer: Max future offset for fill deadlines_l2Usdc: Circle USDC address on Polygon (or 0x0 to disable CCTP)_cctpTokenMessenger: Circle TokenMessenger contract for CCTP bridging_oftDstEid: LayerZero endpoint ID for OFT messaging_oftFeeCap: Maximum fee for OFT transfers
Initialization
_initialDepositId: Starting deposit nonce_polygonTokenBridger: Address of PolygonTokenBridger contract_crossDomainAdmin: L1 HubPool address_withdrawalRecipient: Address receiving bridged tokens on L1 (typically HubPool)_fxChild: Address of Polygon’s FxChild contract
Admin Verification
_requireAdminSender()
processMessageFromRoot() flow, validated by the callValidated flag.
FxPortal Message Processing
- HubPool on L1 sends message via FxPortal
- FxChild on Polygon calls
processMessageFromRoot()on this contract - Validates
msg.sender == fxChildandrootMessageSender == crossDomainAdmin - Uses delegatecall to execute the admin function on
thiscontract - The delegatecalled function checks
callValidated == truein itsonlyAdminmodifier
validateInternalCalls Modifier
callValidated flag to allow admin functions to pass _requireAdminSender() check.
Token Bridging
_bridgeTokensToHubPool()
- CCTP for USDC: Uses Circle’s Cross-Chain Transfer Protocol
- LayerZero OFT: For tokens with configured OFT messengers
- PolygonTokenBridger: Default mechanism for standard ERC20s
PolygonTokenBridger
Why needed: Polygon’s bridge has special constraints:- Complex token mapping system
- Requires specific burn/lock patterns
- Special handling for native MATIC vs WMATIC
- The
PolygonTokenBridgercontract encapsulates this complexity
MATIC Handling
Native Token Wrapping
_preExecuteLeafHook()
Multicall Protection
_validateMulticallData()
- No nested multicalls
- Cannot mix
executeRelayerRefundLeaf()with other function calls - Can multicall multiple
executeRelayerRefundLeaf()calls together - Can multicall other public functions together (but not with execute functions)
EOA Enforcement
executeRelayerRefundLeaf() Override
executeRelayerRefundLeaf() with other calls that could produce excessive logs, which would cause the L2→L1 message to fail.
Checks:
msg.sender != tx.origin: Rejects calls from contractsmsg.sender.code.length > 0: Rejects EIP-7702 delegated wallets
Admin Functions
setFxChild()
setPolygonTokenBridger()
State Variables
Events
Errors
Unique Features
- FxPortal integration: Unique cross-chain messaging system specific to Polygon
- Delegatecall pattern: Admin functions executed via delegatecall for validation
- PolygonTokenBridger: Custom contract to handle Polygon bridge complexity
- MATIC wrapping: Explicit wrapping needed due to Polygon’s bridging behavior
- Griefing protection: EOA enforcement and multicall restrictions to prevent L2→L1 message failures
- Multi-bridge support: CCTP, OFT, and native Polygon bridge
Architecture Notes
- HubPool sends messages via FxPortal’s StateSender on L1
- FxChild contract on Polygon receives and forwards messages
- Admin calls go through
processMessageFromRoot()→ delegatecall → actual function - The
callValidatedflag ensures functions are only callable via this flow - Token bridging is delegated to PolygonTokenBridger to handle Polygon-specific requirements
- Special care taken to prevent excessive log production in L2→L1 messages
Related Contracts
- SpokePool - Base contract
- Polygon Adapter - L1→L2 message relay via FxPortal from HubPool
- PolygonTokenBridger - Token bridging helper (see source code)