Hello Pendlefrens and Anteans! As you may have heard, as of today Pendle has deployed and staked 6 different Ante Tests for the Pendle protocol. We’re all excited about our partnership and what it means for the future of decentralized trust in Web3. For those who may be wondering how the Pendle Ante Tests work, this post is intended to be a quick overview of the tests and their mechanics.
Pendle allows users to deposit a yield-bearing token (e.g. the SushiSwap USDC/ETH LP) and split it into an ownership token (OT) and future yield token (YT) representing the principal and future yield components of the underlying asset value over a given period of time. The yield tokens can be purchased, sold, traded, or staked in various liquidity pools in order to earn incentives, and yield is distributed to holders of the YT until expiry.
Ante is a trust protocol that enables Ante Tests: Smart Tests for Smart Contracts that programmatically check and provide financial guarantees around a protocol’s key assumptions in real time. Responsible project teams like Pendle explicitly put “skin in the game” by staking crypto behind their Ante Tests (which anyone can also challenge or stake) to boost Pendle’s “Decentralized Trust Score” (check it out here). In turn, developers can reference Ante to build more safely on top of Pendle, and users can more explicitly see community trust in Pendle real-time.
In case you want to follow along, we are looking at ante-community-tests/contracts/pendle, commit 14ce1a83fca96eabb10bed0dde02db55dcb499ae
on 2022-03-09.
Four of the Ante Tests cover Pendle’s forge contracts, which govern the critical process of splitting underlying yield tokens into their OT and YT components. The remaining two tests cover Pendle’s markets. Each of the six Pendle Ante Tests has its own Ante Pool. As the tests and pools are composable, in the future, one could potentially write a “wrapper” Ante Test/Pool that would act as a test aggregator for Pendle’s tests.
This is a pretty straightforward test that checks whether the Pendle yield token holder address owns enough aUSDC to exchange 1:1 for all aUSDC OTs, i.e. the forge never mints more OTs than can be redeemed. If Pendle is ever unable to pay out redeemed OTs, that means the protocol is insolvent, so this is a critical invariant to check!
As written, the test checks this condition for the current aUSDC OT (expiring 2022–12–29) and fails if it does not meet this condition.
AntePendleAaveForgeTest.sol, lines 39–41
Note that the test implements a 1% margin of error to account for any very minor precision issues that could arise.
Note that the OT contract that this Ante Test checks is fixed, meaning that at some point if a new aUSDC OT contract were to be deployed (e.g. for 2023 expiry), this Ante Test would not automatically check that contract. In order to check any new OT contracts, a new version of this Ante Test would need to be deployed and liquidity potentially migrated over to the new test.
A note on test “updatability”: When writing tests that iterate over a set of contracts that may update or expire over time, it can sometimes be beneficial to add functions within the test to allow the addition of additional contracts, or to reference a list of contracts held by another contract that can be updated when new contracts are added. This must be balanced with the increased attack surface area this creates for the test itself; if relying on a privileged role to update contracts, this could be seen as reducing decentralization and potentially allows a malicious protocol team to prevent a test from failing, while allowing anyone to add a contract (even with checks to make sure a valid OT contract is added) could potentially be exploited by providing a malicious contract to the test. Philosophically speaking, it could be seen as unfair for a test to change tested contracts after people have already made the decision to stake/challenge the test, even if they can withdraw their capital. In light of these considerations, the Pendle and Ante teams decided not to implement the ability to add additional contracts in any of the Pendle Ante Tests covered in this post.
This is similar in structure to the Pendle Aave Forge Test, with additional complexity due to the fact that we are dealing with LP tokens so we need to calculate an exchange rate for redemption.
AntePendleSushiPEPForgeTest.sol, lines 43–53
In this case, the exchange rate is determined using the following equation:
which is then used to compare the supply of OT against LP. Note that the test implements a 1% margin of error to account for minor fluctuations in exchange rate that can occur when more LPs are minted for the fee.
Similar to the Pendle Sushi PEP Forge Test, this checks that the yield token holder holds enough underlying token to cover OT redemption.
The only difference here is that the LP balance must be pulled through MasterChef (ETH/USDC is an incentivized pool on SushiSwap so the yield token holder needs to stake to MasterChef in order to get rewards).
// Getting LP balance for PENDLE/ETH LP
uint256 lpBal = IERC20(yieldToken).balanceOf(yieldTokenHolder);// Getting LP balance for ETH/USDC LP
uint256 lpBal = IMasterChef(masterChef).userInfo(pid, yieldTokenHolder).amount;
This test covers the solvency of the Compound cDAI forge — with this, the 4 non-expired major Pendle markets on Ethereum are tested for solvency. Talk about covering your bases! 💪
One thing we’re excited about with this test is that it represents the first live Ante Test that doesn’t only use external view functions to check whether the test passes. This has always been an intended capability of the Ante Test design — testing certain failure conditions may require some manipulation of state outside the Ante Test — but the tests to date had not required it.
AntePendleCompoundForgeTest.sol, lines 49–53
In this case, the exchangeRateCurrent()
function updates the accrued interest when called, which can result in a state change.
The second group of Pendle Ante Tests test the functions of the Pendle AMM implementation across their different markets. These both currently test 6 different markets (that use the 4 forges tested above).
From the Pendle AMM documentation, we see that the weights of the YT and the underlying token are set to 0.5 and 0.5 at the start of the market period, with the YT weight decreasing and underlying token weight increasing by the same amount over time until market expiry.
This test tests two characteristics that we should expect to see during proper AMM function given the above:
AntePendleMarketWeightTest.sol, lines 31–44
Note that the test ignores a market if it has entered the frozen period — at that point, the weights start to suffer from mathematical precision errors so the Pendle market stops shifting weights and trading.
The last Pendle Ante Test checks the same 6 markets to verify that the market’s assumptions about its internal token balances are correct, i.e. the market holds enough YT and underlying token in the actual token contracts to cover the amount of each the Pendle market has stored in internal state. A failure could indicate that the AMM got rugged, for example.
AntePendleMarketBalanceTest.sol, lines 28–46
Note that this test also excludes expired markets, but for a different reason: the getReserves()
function has a known bug after the market has expired.
We all know DeFi can be a dangerous place. Smart contracts can be opaque to your average DeFi user, and bad actors abound. Ante helps make code risk explicit by allowing for real-time financial guarantees around specific smart contract commitments. This helps you make more informed decisions about which protocols you might want to use. Responsible protocol teams like Pendle are helping pave the way for a safer Web3 future!
If you would like to learn more about how Ante could be useful for your protocol team, please reach out to us at hello@ante.finance, read the docs at docs.ante.finance, or follow the team on Twitter and join our Discord for more Web3 security discussions!