YieldCoin
Automated crosschain stablecoin yield optimizer
Created on 19th June 2025
•
YieldCoin
Automated crosschain stablecoin yield optimizer
The problem YieldCoin solves
There have been numerous times where I have held stablecoins in a wallet, on various chains, and wanted to “put them to work” to earn yield, instead of just sitting there. I end up struggling to find the time to keep up with the best (and safe) opportunities to position my stablecoins (whilst retaining full control and liquidity), then withdrawing, bridging and depositing again. This process is time consuming, burdensome, and boring.
Chainlink’s Automation, Functions, and CCIP components can be combined into the “Contract Level Yield” infrastructure, or “YieldCoin”, to abstract this process away - giving users the simplest possible experience to consistently and securely earn the highest yield on their stablecoins without any manual input.
How does it work?
- Users deposit their stablecoins from their chain of choice
- Deposited stablecoins are allocated to highest yield generating strategy protocol (Aave, Compound, etc.)
- Depositors receive YieldCoin in exchange, representing their share of the system's total value
- Chainlink services periodically check for the chain and protocol with the highest APY for stablecoins, automatically rebalancing the total value in the system to the optimal position.
Please see the README for details on the architecture, Chainlink integrations, deployment, testing, testnet transactions, future developments roadmap, and more.
If running the unit tests, please see this note.
Challenges I ran into
Share Mint Calculation Bug
This was the most significant challenge and went unresolved whilst prioritizing an eligible submission.
The invariant testing revealed cases where the amount of YieldCoin minted in exchange for USDC deposits was significantly less than it should have been, breaking a key invariant of the system:
users must always be able to withdraw their deposit
(minus fees when implemented).I thought the issue was mitigated with something like dead shares inflation attack mitigation because the invariant tests were then passing.
The issue came up again during formal verification with Certora. Even though initial admin shares were minted, Certora revealed scenarios where a depositor was not receiving enough YieldCoin to withdraw their deposit - bad!
22nd - Unresolved because an eligible submission was priority.
24th - There was a problem with the share mint amount calculation in ParentPeer::_calculateMintAmount. That problem was the TVL being passed included the deposit amount. Both of these values are required to calculate the amount to mint. The fix to this was to subtract the amount from TVL.
The invariant discussed above is now fixed.
26th - The root cause of this issue was a helper function in the abstract YieldPeer contract. The function deposited an amount to the active strategy, and returned the TVL. The order of operations for these was incorrect. TVL was being read after the deposit, which was wrong. This took time to fix because there was also a single instance of the same operation being done, outside the function.
This article goes into further detail.
Burning small amounts of shares (YieldCoin), worth less than the lowest possible value of USDC (6 decimals) resulted in reverts
If a user attempted to withdraw USDC by burning an amount of shares/YieldCoin worth less than the lowest possible value of USDC (6 decimals), solidity would calculate the amount of USDC to withdraw as 0. This caused reverts when the smart contracts attempted to withdraw 0 from strategy protocols and transfer it to the withdrawer.
To mitigate this, the current approach is a bit of a compromise, but if someone tries to withdraw less than the lowest possible value of USDC, they receive nothing in exchange for burning their shares. This of course is not ideal, and is considered a known issue, however it is unexpected that a user will attempt to withdraw such an insignificant amount, and doing so would benefit all other YieldCoin holders. Most importantly, this mitigation means the system doesn't revert/experience any weird DoS.
It is mitigated, but further research will be conducted on this. An option being explored is enforcing a minimum share burn amount, but the crosschain nature of some withdraw paths makes this tricky to enforce at the contract level.
USDC chainlink-local fork
The current chainlink-local ccip simulator is amazing, but unfortunately doesn’t have support for USDC - the stablecoin with the most lanes on CCIP.
To fully test the system on forked mainnets, additional functionality in the CCIPLocalSimulatorFork was required to get past the additional CCTP checks for USDC. CCTP is Circle’s crosschain infrastructure for USDC that works alongside CCIP onchain.
Ultimately the additional functionality required was the monitoring for a CCTP event and pranking the CCTP attesters.
The full answer to "Challenges I ran into" would not fit into this submission page. Please see here in the README for more info.
Tracks Applied (4)
Onchain Finance
Cross-Chain Solutions
AWS Credits for all Hackathon winners and runner ups
AWS
Avalanche Track
Avalanche