Reference

Trading router

Trading deploys one canonical factory and one canonical router. The router handles entry and liquidity operations, share-transfer exits and complete-set redemption, and permit-assisted LP removal.

Entrypoints

TwoWayConstantProductRouter(factory) fixes the only eligible factory. All user mutations enforce a deadline and a reentrancy guard. The router's receiver callbacks accept only the active pool's canonical share token and universe IDs. receive() accepts ETH only during redemption and only from the expected SecurityPool or its canonical portfolio settlement engine.

The payable entrypoints require nonzero msg.value (ETH input is zero). Every entrypoint requires a recipient that is neither zero nor the router (Invalid recipient) and block.timestamp ≤ deadline (Deadline expired); those that take a pair require it to be the factory's canonical pair for its SecurityPool (Unrecognized pair, Noncanonical pair). The three liquidity entrypoints that take ETH return LiquidityResult: pair, completeSetShares, yesUsed, noUsed, yesReturned, noReturned, invalidInsurance, and liquidity.

Every successful share-custody operation, including the receive-based operations below, asserts that the router's Invalid, Yes, and No balances equal their starting values, preserving pre-existing forced shares.

Exits and complete-set redemption by share transfer

The router has no exitPosition or redeemCompleteSet entrypoint. Users exit and redeem by calling the ShareToken's safeBatchTransferFrom with themselves as both caller and owner, the router as recipient, and an encoded request in the data field. No setApprovalForAll is required. The request is the ABI-encoded ReceiveRequest struct with fields in this order: version (must equal CALLBACK_VERSION, currently 1), operation (0 ExitPosition, 1 RedeemCompleteSet), shareToken, securityPool, pair, universeId, questionId, invalidTokenId, yesTokenId, noTokenId, longOutcome, completeSetShares, maxLongSharesIn, minEthOut, payoutRecipient, refundRecipient, and deadline. encodeReceiveRequest produces it. The router accepts only owner-initiated top-level transfers (operator == from); internal pair callbacks are distinguished from top-level user callbacks.

Both operations require completeSetShares > 0, a payoutRecipient and a refundRecipient that are neither zero nor the router, and canonical pool, share-token, universe, question and outcome IDs. An insured exit requires the factory's canonical pair. Complete-set redemption permits a zero pair; a supplied nonzero pair must still be canonical. A child with no trading pair can therefore redeem directly through this transfer route.

Both operations measure the ETH and native REP produced by redemption and forward exactly those deltas to the payout recipient. ETH must meet minEthOut, and at least one asset must be positive. A REP-only basket therefore accepts a zero ETH minimum. Pre-existing ETH and REP in the router are excluded from the payout; minEthOut protects only the ETH component.

For LP removal through the router, Safes and integrations without signature support may use ordinary exact allowances instead of a permit. The first-party UI calls the pair directly and needs no router allowance.