Sable Trident
The Trident vault executes a 3-loop recursive staking strategy using Endur and Vesu to amplify base staking APY by ~3x.
Risk Level: 3 (Medium)
Strategy: 3x loop: WBTC → Endur → xWBTC → Vesu supply → borrow WBTC → repeat
Strategy Overview
Loop 1: WBTC → Endur → xWBTC → Vesu collateral → borrow WBTC (70% LTV)
Loop 2: Borrowed WBTC → Endur → xWBTC → Vesu collateral → borrow WBTC
Loop 3: Borrowed WBTC → Endur → xWBTC → Vesu collateral (no final borrow)
Result: 3x exposure to Endur staking APY via recursive leverage
How It Works
- Deposit WBTC into Endur → receive xWBTC liquid staking shares
- Supply xWBTC to Vesu Re7 xBTC pool as collateral
- Borrow WBTC against xWBTC collateral (70% LTV)
- Repeat steps 1-3 two more times
Final position: ~3.4x WBTC value in xWBTC staking for same initial deposit.
Yield Sources
| Source | Type | Amplification |
|---|
| Endur Staking APY | Base yield | 3x (three staked positions) |
| xWBTC Appreciation | Capital gain | 3x exposure to xWBTC/WBTC ratio |
| BTCFi STRK Rewards | Incentive | On all Vesu collateral |
Example: If Endur base APY = 5%, Trident effective APY ≈ 15% (minus borrow cost, which is offset by BTCFi rewards).
Risk Profile
- Moderate leverage: 3x loop creates ~2.4x net leverage
- Liquidation risk: If xWBTC/WBTC ratio drops sharply, Vesu positions could be liquidated
- Borrow cost: WBTC borrow APY reduces net yield (but BTCFi rewards cover this)
- Unwinding complexity: Requires iterative deleverage or flash loan
Contract Architecture
File: trident.cairo (~700 LOC)
Deployed: 0x058aadc9db62700de03d89a7c8f2952851d94e75f854cc6a340ef92d00cd3fb8
Core Components
Recursive Loop
Flash Loan Unwind
Minimum Deposit
Trident executes 3 staking loops on every deposit:fn _deploy_to_strategy(ref self: ContractState, amount: u256) {
let num_loops: u8 = 3;
let mut remaining_wbtc = amount;
let mut total_xwbtc_added: u256 = 0;
let mut total_wbtc_borrowed: u256 = 0;
let mut i: u8 = 0;
while i < num_loops {
// 1. Stake WBTC -> Endur -> xWBTC
wbtc.approve(endur_addr, remaining_wbtc);
let xwbtc_shares = endur.deposit(remaining_wbtc, this);
total_xwbtc_added += xwbtc_shares;
// 2. Supply xWBTC to Vesu as collateral
xwbtc_token.approve(vesu_addr, xwbtc_shares);
vesu.modify_position(/* deposit collateral */);
// 3. Borrow WBTC from Vesu (70% LTV)
let borrow_amount = (remaining_wbtc * 70) / 100;
if borrow_amount == 0 { break; }
vesu.modify_position(/* borrow WBTC */);
total_wbtc_borrowed += borrow_amount;
// 4. Use borrowed WBTC for next loop
remaining_wbtc = borrow_amount;
i += 1;
};
}
From trident.cairo:823 Withdrawals use a Vesu flash loan to atomically unwind all 3 loops:fn on_flash_loan(
ref self: ContractState,
sender: ContractAddress,
asset: ContractAddress, // WBTC
amount: u256, // Full debt amount
data: Span<felt252>,
) {
// Step 1: Repay ALL USDC debt atomically
// (Actually WBTC debt, not USDC — see implementation)
vesu.modify_position(ModifyPositionParams {
collateral: Amount { /* withdraw ALL xWBTC */ },
debt: Amount { /* repay ALL WBTC debt */ },
});
// Step 2: Swap ALL xWBTC -> WBTC via AVNU (Ekubo pool)
let xwbtc_balance = xwbtc_token.balance_of(this);
avnu.multi_route_swap(
endur_addr, xwbtc_balance, wbtc_addr,
0, min_amount_out, this, 0, Zero::zero(), routes,
);
// Step 3: Approve WBTC for flash loan repayment
wbtc.approve(vesu_addr, amount);
// Position fully closed, all xWBTC converted to idle WBTC
self.total_debt_borrowed.write(0);
self.vesu_collateral.write(0);
self.leverage_loops.write(0);
}
From trident.cairo:325 Trident enforces a minimum deposit to ensure all 3 loops complete:fn _min_deposit_for_loops(self: @ContractState, num_loops: u8) -> u256 {
let min_debt = self._vesu_debt_dust_min();
if min_debt == 0 { return 0; }
// Smallest borrow at loop N is amount * 0.7^N
// Must be >= debt dust min
// Formula: ceil(min_debt * 10^N / 7^N)
let mut pow7: u256 = 1;
let mut pow10: u256 = 1;
let mut j: u8 = 0;
while j < num_loops {
pow7 = pow7 * 7;
pow10 = pow10 * 10;
j += 1;
};
(min_debt * pow10 + pow7 - 1) / pow7
}
From trident.cairo:806For 3 loops: min_deposit ≈ 2.9× Vesu dust threshold (~$30 for WBTC)
Key Functions
User Functions
Deposit WBTC and receive yvBTC-TRI sharesParameters:
assets (u256): Amount of WBTC to deposit (must be ≥ min_deposit)
receiver (ContractAddress): Address to receive vault shares
Returns: u256 — Number of shares mintedAuto-executes 3-loop strategy:
- Loop 1: 100% WBTC → 70% borrow
- Loop 2: 70% WBTC → 49% borrow
- Loop 3: 49% WBTC → no borrow
Final: ~2.19x WBTC staked, ~1.19x WBTC debt
Burn shares and withdraw WBTC (flash loan unwind)Parameters:
assets (u256): Amount of WBTC to withdraw
receiver (ContractAddress): Address to receive WBTC
owner (ContractAddress): Share owner
Returns: u256 — Number of shares burnedAutomatic Flash Loan Unwind:
- Flash borrows full WBTC debt from Vesu
- Repays debt + withdraws all xWBTC collateral
- Swaps xWBTC → WBTC via AVNU (hardcoded Ekubo route)
- Repays flash loan from swap proceeds
- User receives remaining WBTC
Tolerance: Accepts up to 0.5% slippage due to xWBTC swap conversion rounding.
Curator Functions
Manually execute N staking loops (for idle WBTC)Parameters:
wbtc_amount (u256): WBTC to deploy
num_loops (u8): Number of loops (1-10)
fn execute_staking_loop(ref self: ContractState, wbtc_amount: u256, num_loops: u8)
Implementation at trident.cairo:412
Iteratively unwind N loops (repay debt → withdraw collateral → unstake)Parameters:
loops_to_unwind (u8): Number of loops to reverse
fn deleverage(ref self: ContractState, loops_to_unwind: u8)
Implementation at trident.cairo:497Endur Queue: If Endur has liquidity, unstakes xWBTC immediately. Otherwise, xWBTC remains idle.
Atomically close all positions via flash loanParameters:
min_amount_out (u256): Minimum WBTC from xWBTC swap (slippage protection)
routes (Array<Route>): AVNU swap routes (xWBTC → WBTC)
fn flash_unwind(ref self: ContractState, min_amount_out: u256, routes: Array<Route>)
Implementation at trident.cairo:630Used internally by _ensure_idle_balance during withdrawals.
Integration with External Protocols
Endur xWBTC Vault
Address: endur_vault (constructor parameter)
Trident stakes WBTC 3 times via Endur’s ERC-4626 vault:
let endur = IERC4626Dispatcher { contract_address: endur_addr };
let xwbtc_shares = endur.deposit(wbtc_amount, vault_address);
Vesu Re7 xBTC Pool
Pool ID: 0x03a8416bf20d036df5b1cf3447630a2e1cb04685f6b0c3a70ed7fb1473548ecf
Trident uses this pool for:
- Collateral: xWBTC shares
- Debt: WBTC borrowed at 70% LTV
vesu.modify_position(ModifyPositionParams {
collateral_asset: endur_addr, // xWBTC
debt_asset: wbtc_addr, // WBTC
user: vault_address,
collateral: Amount { /* xWBTC shares, positive = deposit */ },
debt: Amount { /* WBTC amount, positive = borrow */ },
});
AVNU xWBTC/WBTC Swap
For flash loan unwind, Trident swaps all xWBTC → WBTC via Ekubo (hardcoded route):
let swap_params: Array<felt252> = array![
wbtc_felt, // token0 (WBTC < xWBTC by address)
endur_felt, // token1 (xWBTC)
0x68db8bac710cb4000000000000000, // fee 0.01%
0xc8, // tick_spacing = 200
0x0, // extension
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, // sqrt_ratio_limit (max)
];
From trident.cairo:920
Example Usage
Depositing WBTC
import { Contract } from 'starknet'
const tridentVault = new Contract(tridentABI, tridentAddress, account)
const wbtc = new Contract(erc20ABI, wbtcAddress, account)
// Check minimum deposit
const minDeposit = await tridentVault.min_deposit()
console.log('Min deposit:', minDeposit / 1e8, 'WBTC')
// Deposit (auto-executes 3-loop strategy)
const amount = 20_000_000n // 0.2 WBTC
await wbtc.approve(tridentAddress, amount)
await tridentVault.deposit(amount, account.address)
// Check yvBTC-TRI balance
const shares = await tridentVault.balance_of(account.address)
Checking Leverage Stats
// Strategy info: (collateral, debt, loops, paused)
const [xwbtcCollateral, wbtcDebt, numLoops, paused] = await tridentVault.get_strategy_info()
console.log('xWBTC collateral:', xwbtcCollateral / 1e8)
console.log('WBTC debt:', wbtcDebt / 1e8)
console.log('Leverage loops:', numLoops)
// Convert xWBTC collateral to WBTC equivalent
const endurVault = new Contract(erc4626ABI, endurAddress, provider)
const wbtcValue = await endurVault.convert_to_assets(xwbtcCollateral)
console.log('Total WBTC staked value:', wbtcValue / 1e8)
// Net exposure
const netExposure = wbtcValue - wbtcDebt
console.log('Net WBTC exposure:', netExposure / 1e8)
Withdrawing WBTC
// Get max withdrawable
const maxWithdraw = await tridentVault.max_withdraw(account.address)
// Withdraw (triggers flash loan unwind)
await tridentVault.withdraw(maxWithdraw, account.address, account.address)
// Flash loan automatically:
// 1. Borrows full WBTC debt from Vesu (zero fee)
// 2. Repays debt + withdraws all xWBTC
// 3. Swaps xWBTC -> WBTC via AVNU
// 4. Repays flash loan
// 5. Sends remaining WBTC to user
Security Considerations
Risks
- Liquidation Risk: If xWBTC/WBTC ratio drops >30%, Vesu positions could be liquidated
- Flash Loan Dependency: Withdrawals require Vesu flash loans to work
- Swap Slippage: Large withdrawals may face xWBTC/WBTC swap slippage on Ekubo
- Endur Protocol Risk: All positions depend on Endur’s xWBTC mechanism
- Vesu Pool Risk: Smart contract vulnerabilities in Re7 xBTC pool
Risk Mitigation
- Conservative LTV: 70% LTV leaves 30% buffer before liquidation
- xWBTC backing: Endur’s 1:1 WBTC backing mechanism keeps xWBTC stable
- Flash loan safety: Trident only initiates flash loans (Vesu can’t call
on_flash_loan directly)
- Tolerance buffer: Withdrawals accept up to 0.5% slippage to handle rounding
- Pause mechanism: Owner can halt deposits if issues arise
Health Factor Monitoring
// Monitor health factor manually
const vesuPool = new Contract(vesuPoolABI, vesuPoolAddress, provider)
const [position, collValue, debtValue] = await vesuPool.position(
endurAddress, // collateral_asset (xWBTC)
wbtcAddress, // debt_asset
tridentAddress // user (vault)
)
// Health factor = (collateral * LT) / debt
// LT (liquidation threshold) ≈ 75% for Vesu Re7 xBTC
const healthFactor = (collValue * 75n) / (debtValue * 100n)
console.log('Health factor:', Number(healthFactor) / 100)
// Safe: health > 1.5
// Caution: health 1.0-1.5
// Danger: health < 1.0 (liquidation risk)
Additional Resources