The Router serves as the entry point for users interacting with the protocol. It is organized as multiple
Action[...] contracts that contain various types of logic. While reviewing all the functions in these contracts would be excessive for this article, it’s useful to examine a specific user scenario and trace the involved functions. So…
Imagine a scenario where Alice expects a significant increase in stETH yield due to upcoming protocol changes. She decides to acquire YT tokens to capitalize on this potential upside.
She starts by using the
swapExactTokenForYt() function, approving a certain amount of WETH and providing the market address, token input details (WETH, amount, etc.), the minimum YT output (to account for slippage), and other parameters (some of which will be described later). First, the function
checks if an approximation can be used — a kind of optimization which we will discuss later. Alice
mints SY tokens "wrapping" the underlying tokens
into their "SY" version.
The next step involves
swapping these SY tokens for YT tokens using the
_swapExactSyForYt() function, which is complex internally. During this swap (SY to YT tokens), Pendle first attempts to fill limit order, though this is not relevant in Alice’s case (we don't plan to discuss limit orders, as it will distract us from the main mechanics).
Alice then
calculates the amount of YT tokens she will receive via the
approxSwapExactSyForYtV2() function, which is particularly noteworthy. This function uses a numerical approximation to compute the optimal amount of YT tokens that should result from swapping a specified amount of SY tokens.
An optimization comes into play
here. If a smart contract uses an iterative algorithm for approximation, optimization, or searching, the user can assist it externally (e.g., from an off-chain dApp) by providing suggested starting values for the algorithm. These hints can accelerate the calculation process. This technique is not new, as seen in Liquity V2 (
article) in the
getAppoxHint() function for a linked list. In this case, the
ApproxParams provided by the user help to calculate the optimal YT token amount.
[NOTE] This "user-provided hints" approach is not fully foolproof and may become ineffective if other transactions change the contract state during calculations, leading to gas inefficiencies or even resulting in griefing attacks. In Pendle, this is mitigated by the imbalance protection in the pool, which prevents abrupt changes in token exchange rates.If no external approx parameters are provided, the function
uses min/max values from the current market.
Next, the function begins a
loop, estimating the amount of PT that needs to be involved to efficiently convert the exact SY input into YT tokens. Because PT and YT tokens must be minted in equal amounts but have different prices, an approximation algorithm determines the
optimal PT amount required to maximize the YT output for the given SY input, within an acceptable error range. This establishes how much SY tokens are necessary to achieve the target YT amount.
Finally, it’s time to
redeem the SY tokens, extracting only the YT tokens since Alice only needs the YT tokens she has paid for. An interesting aspect arises here: the
receiver is the YT token contract (not
receiver). This is explained by the following sequence of actions during the swap:
- Start with some initial SY (PT + YT).
- "Flash-borrow" PT tokens needed to reach the target YT amount.
- Buy additional SY tokens using the borrowed PT tokens from the market.
- Combine the initial and "partially borrowed" SY tokens.
- Mint PT + YT tokens from this combined SY amount.
- Use the PT tokens to repay the flash loan.
- Retain the YT tokens as the final output.
Although the process appears complex, the result is simple: Alice ends up with YT tokens (tradeable in the AMM) acquired using the underlying asset. For reverse swaps, YT tokens can be exchanged for other assets using the
swapExactYtForToken() function.
Pendle routers also include similar functions for swaps involving PT tokens:
swapExactTokenForPt(),
swapExactSyForPt(),
swapExactPtForToken(), and
swapExactPtForSy(). All of these functions rely on SY tokens as intermediate assets.