Skip to main content

Quickstart

This page walks through the most common flows with @magma-protocol/sdk. If you have not installed the package yet, see Installation.

import { MagmaClient } from '@magma-protocol/sdk';

const magma = new MagmaClient();

All read flows below work with the default public client. The backing flow requires an authenticated client.

Browse the narrative feed

narratives.feed() returns a normalized, paginated response. Filter and sort through NarrativeFeedParams:

const { narratives, total, page, has_more } = await magma.narratives.feed({
filter: 'active',
sort: 'top_score',
limit: 20,
});

console.log(`${total} narratives (page ${page})`);
for (const n of narratives) {
console.log(n.title, '·', n.score, '·', n.total_backed_sol, 'SOL');
}
Tolerant pagination

The backend root feed currently returns only { narratives }. The SDK fills in total, page, and has_more so you always get a stable shape — total falls back to the returned count and has_more defaults to false.

Fetch a single narrative

const narrative = await magma.narratives.get('<NARRATIVE_ID>');
console.log(narrative.title, narrative.status, narrative.deadline_at);

The SDK unwraps the backend's { narrative: {...} } envelope and returns the Narrative directly.

Read conviction

A wallet's conviction profile includes its tier, score, accuracy, and per-category stats:

const profile = await magma.users.getConvictionProfile('<WALLET>');

console.log('Tier:', profile.conviction_tier); // e.g. 'volcanic'
console.log('Score:', profile.conviction_score); // e.g. 847
console.log('Accuracy:', profile.accuracy_pct, '%');
console.log('Yield multiplier:', profile.yield_multiplier);

To read a wallet's Eruption Streak (which drives part of the yield multiplier):

const streak = await magma.users.getStreak('<WALLET>');
console.log('Streak:', streak.current_streak, '·', streak.streak_tier);

Submit a backing

Backing is a two-step flow: prepare and sign the Solana transaction with the user's wallet, then submit the signature so MAGMA records the position and routes principal into yield. This requires an authenticated client.

import { MagmaClient, MagmaError } from '@magma-protocol/sdk';

const magma = new MagmaClient({
authToken: privyJwtToken,
walletAddress: userWalletAddress,
});

try {
// 1 — Prepare the unsigned transaction (gasless via Kora if configured)
const { transaction, gasless } = await magma.narratives.prepareMint({
narrative_id: '<NARRATIVE_ID>',
backer_wallet: userWalletAddress,
amount_sol: 0.5,
});

// 2 — Sign with the user's wallet (Privy / Mobile Wallet Adapter)
const signedTx = await wallet.signTransaction(transaction);

// 3 — Record the backing on the backend
const result = await magma.narratives.back('<NARRATIVE_ID>', {
sol_amount: 0.5,
token_address: 'SOL',
tx_signature: signedTx.signature,
});

console.log('Success:', result.success);
console.log('Backing row:', result.backing.id, '· epoch', result.backing.epoch_number);
console.log('Combined yield multiplier:', result.backing.combined_yield_multiplier);

// `yield` is populated only when SOL was routed into Kamino, else null
if (result.yield) {
console.log('Yield active:', result.yield.active, '· est. APY', result.yield.estimatedApy);
}
} catch (err) {
if (err instanceof MagmaError) {
console.error(`[${err.status}] ${err.code}: ${err.message}`);
}
}

back() returns the full BackingResponse{ success, backing, yield } — where backing is the complete narrative_backings row written by the backend and yield is the Kamino deposit result (or null). See the client reference for the full shape.

Money-moving calls don't auto-retry

The SDK only retries idempotent GET requests. prepareMint, back, and challenge are POST calls and never auto-retry, so a network blip can't double-submit a transaction. See Error handling.

Read DeFi APYs and supported tokens

Live yield rates across all sources (Kamino, Save, Jito, Marinade, Jupiter, Meteora, Guardian, P0):

const { sources } = await magma.defi.getApys();

For a flattened, per-protocol token list — protocol key, label, supported token, live APY, and availability — use getTokens():

const { tokens } = await magma.defi.getTokens();

for (const t of tokens) {
console.log(
t.protocol, // e.g. 'kamino'
t.label, // e.g. 'Kamino Lend'
t.token, // e.g. 'SOL/USDC'
t.apy, // live APY (percent), if available
t.testnet_available, // available on the current devnet deployment?
t.coming_at // when it goes live if not yet, else null
);
}
Derived from /v1/defi/apys

There is no standalone tokens endpoint. getTokens() derives the list by joining the protocols metadata and the apys map from the same /v1/defi/apys response.

Pull the leaderboard

const { leaders } = await magma.leaderboard.get({
sort: 'score',
limit: 50,
});

leaders.forEach(l =>
console.log(`#${l.rank}`, l.wallet, '·', l.score, '·', l.tier),
);

For the streak-based leaderboard:

const { leaders } = await magma.leaderboard.getStreaks();

Read the current epoch

The Echo Pool epoch (via the nova resource):

const epoch = await magma.nova.getEpoch();
console.log(
`Epoch ${epoch.epoch_number}:`,
epoch.echo_pool_sol, 'SOL ·',
epoch.days_remaining, 'days left ·',
epoch.total_tickets, 'tickets',
);

Where to go next