Overview
Starkzap supports Troves strategies through wallet.troves().
Troves combines off-chain strategy discovery with on-chain execution:
- 📊 Discover strategies - Fetch the currently available Troves strategies and protocol-level stats
- 🧾 Inspect positions - Read the wallet’s share balance and the current underlying asset amounts for a strategy
- 💸 Deposit - Build and execute the Troves deposit flow from typed
Amount inputs
- 📤 Withdraw - Build and execute the Troves withdraw flow with the same typed API
- 📦 Batch with other actions - Compose Troves deposits or withdrawals inside
wallet.tx()
Troves uses the Troves HTTP API to discover strategies and build the required calls, then executes those calls through the connected Starknet wallet.
Configuration
Troves is available from the wallet:
import { StarkZap } from "starkzap";
const sdk = new StarkZap({ network: "mainnet" });
const wallet = await sdk.connectWallet({
account: { signer, accountClass },
});
const troves = wallet.troves();
By default, Troves is mainnet-only. If the wallet is not on Starknet Mainnet, wallet.troves() throws unless you explicitly override the API base:
const troves = wallet.troves({
apiBase: "https://your-custom-troves-backend.example.com",
timeoutMs: 15000,
});
Use apiBase only when you intentionally want to point the SDK at a custom Troves-compatible backend.
Discovering strategies
Fetch the current strategy catalog:
const { strategies, lastUpdated } = await wallet.troves().getStrategies();
console.log("Updated at:", lastUpdated);
for (const strategy of strategies) {
console.log(strategy.id, strategy.name);
console.log("APY:", strategy.apy);
console.log("TVL (USD):", strategy.tvlUsd);
console.log(
"Deposit tokens:",
strategy.depositTokens.map((token) => token.symbol).join(", ")
);
}
You can force a fresh fetch instead of using the default cached endpoint:
const data = await wallet.troves().getStrategies({ noCache: true });
Strategy shape
interface TrovesStrategyAPIResult {
id: string;
name: string;
apy: number | string;
apySplit: {
baseApy: number;
rewardsApy: number;
};
depositTokens: TrovesDepositToken[];
leverage: number;
contracts: TrovesContract[];
tvlUsd: number;
status: { number: number; value: string };
liveStatus?: string;
isAudited: boolean;
isRetired: boolean;
assets: string[];
protocols: string[];
}
Protocol-level stats
const stats = await wallet.troves().getStats();
console.log(stats.tvl);
console.log(stats.lastUpdated);
Querying a position
Read the wallet’s position in a strategy by id:
const position = await wallet.troves().getPosition("ekubo_cl_strketh");
if (position) {
console.log("Shares:", position.shares);
position.amounts.forEach((amount) => {
console.log(amount.toFormatted());
});
}
getPosition() returns null when the wallet holds no shares, or when the strategy does not expose a readable vault contract for this flow.
Position shape
interface TrovesPosition {
strategyId: string;
vaultAddress: Address;
shares: bigint;
amounts: Amount[];
}
For single-asset strategies, amounts contains one Amount. For dual-asset strategies, it contains two entries in the same order as the strategy’s depositTokens.
Depositing
Deposit into a Troves strategy with typed Amount inputs:
const tx = await wallet.troves().deposit({
strategyId: "ekubo_cl_strketh",
amount: Amount.parse("10", STRK),
});
await tx.wait();
Dual-asset strategies can provide amount2:
const tx = await wallet.troves().deposit({
strategyId: "some_dual_asset_strategy",
amount: Amount.parse("10", TOKEN_A),
amount2: Amount.parse("0.5", TOKEN_B),
});
await tx.wait();
With execution options:
const tx = await wallet.troves().deposit(
{
strategyId: "ekubo_cl_strketh",
amount: Amount.parse("10", STRK),
},
{ feeMode: { type: "paymaster" } }
);
await tx.wait();
Withdrawing
Withdraw from a Troves strategy using the same typed shape:
const tx = await wallet.troves().withdraw({
strategyId: "ekubo_cl_strketh",
amount: Amount.parse("5", STRK),
});
await tx.wait();
For dual-asset strategies:
const tx = await wallet.troves().withdraw({
strategyId: "some_dual_asset_strategy",
amount: Amount.parse("5", TOKEN_A),
amount2: Amount.parse("0.25", TOKEN_B),
});
await tx.wait();
Using the transaction builder
Troves can be composed into a larger atomic transaction through the tx builder:
const tx = await wallet
.tx()
.trovesDeposit({
strategyId: "ekubo_cl_strketh",
amount: Amount.parse("10", STRK),
})
.transfer(STRK, [{ to: recipient, amount: Amount.parse("1", STRK) }])
.send();
await tx.wait();
Withdraw through the builder:
const tx = await wallet
.tx()
.trovesWithdraw({
strategyId: "ekubo_cl_strketh",
amount: Amount.parse("5", STRK),
})
.send();
await tx.wait();
Low-level call preparation
If you need to inspect or batch Troves calls manually, use the populate helpers:
const depositCalls = await wallet.troves().populateDeposit({
strategyId: "ekubo_cl_strketh",
amount: Amount.parse("10", STRK),
});
const withdrawCalls = await wallet.troves().populateWithdraw({
strategyId: "ekubo_cl_strketh",
amount: Amount.parse("5", STRK),
});
These return Starknet Call[] values without executing them.
Best Practices
- Use
getStrategies() to drive the strategy picker instead of hard-coding ids.
- Treat Troves as mainnet-only unless you are explicitly using a custom compatible backend.
- Use typed
Amount values from the strategy’s deposit tokens to avoid decimals mismatches.
- Prefer
wallet.tx().trovesDeposit(...) and wallet.tx().trovesWithdraw(...) when Troves actions should be atomic with other wallet operations.
- Expect some strategies to return
apy as a string label rather than a numeric yield; use apySplit when you need structured numeric values.
Next Steps