Quickstart
This guide walks you through creating an account and earning yield on Compound — the most common integration flow. By the end, you’ll have a working sub-account earning USDC yield on Base.
Prerequisites
- A Legend Prime Account with a query key (contact us to get set up)
- An EOA private key (for signing transactions)
1. Install the SDK
npm install legend-prime viem
2. Initialize the client
import { LegendPrime } from "legend-prime";
const client = new LegendPrime({
queryKey: process.env.LEGEND_QUERY_KEY,
});
3. Create a sub-account
Each sub-account has its own on-chain wallet. You provide the signer’s Ethereum address — the private key stays with you.
curl -X POST https://prime-api.legend.xyz/accounts \
-H "Authorization: Bearer $LEGEND_QUERY_KEY" \
-H "Content-Type: application/json" \
-d '{
"signer_type": "eoa",
"signer_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18"
}'
Response:
{
"external_id": "acc_2o0yiljtp378",
"signer_type": "eoa",
"signer_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18",
"legend_wallet_address": "0xc40897f38bc3d4e4d17f9daf46d2a13b4c47642f",
"created_at": "2025-06-15T10:30:00Z"
}
The legend_wallet_address is the sub-account’s on-chain wallet. Fund this address with USDC before proceeding.
4. Create an earn plan
A plan describes what you want to do. Legend generates the on-chain transaction details and returns an EIP-712 digest for signing.
curl -X POST https://prime-api.legend.xyz/accounts/acc_2o0yiljtp378/plan/earn \
-H "Authorization: Bearer $LEGEND_QUERY_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount": "1000000",
"asset": "USDC",
"network": "base",
"protocol": "compound"
}'
Response:
{
"plan_id": "pln_71mcui082png",
"chart": {
"quark_operation_actions": [...],
"eip712_data": {
"digest": "0x8a3f...b7c2",
"domain_separator": "0x...",
"hash_struct": "0x..."
}
},
"expires_at": "2025-06-15T10:32:00Z"
}
Plans expire after 2 minutes. Sign and execute before expires_at or create a new plan.
5. Sign the plan
The signer approves the plan by signing the EIP-712 digest. This proves they authorize the on-chain transaction.
import { privateKeyToAccount } from "viem/accounts";
const signer = privateKeyToAccount(process.env.SIGNER_PRIVATE_KEY as `0x${string}`);
const digest = plan.chart.eip712_data.digest;
const signature = await signer.sign({ hash: digest });
6. Execute the plan
Send the signature back to Legend. This triggers the on-chain transaction.
curl -X POST https://prime-api.legend.xyz/accounts/acc_2o0yiljtp378/plan/execute \
-H "Authorization: Bearer $LEGEND_QUERY_KEY" \
-H "Content-Type: application/json" \
-d '{
"plan_id": "pln_71mcui082png",
"signature": "0x1a2b3c..."
}'
Response:
{
"plan_id": "pln_71mcui082png",
"quark_intent_id": 42,
"status": "executing"
}
7. Verify the result
Poll the activities endpoint to confirm the transaction landed.
curl https://prime-api.legend.xyz/accounts/acc_2o0yiljtp378/activities \
-H "Authorization: Bearer $LEGEND_QUERY_KEY"
Response:
{
"activities": [
{
"id": 1,
"activity_type": "quark_operation_executed",
"activity_status": "pending",
"activity_metadata": [
{
"action_type": "COMET_SUPPLY",
"asset_symbol": "USDC",
"amount": "1000000",
"chain_id": "8453"
}
],
"occurred_at": "2025-06-15T10:30:15Z"
}
]
}
For real-time updates instead of polling, use the events endpoint with poll=true for long-polling.
Full example
Here’s the complete flow in one script:
import { LegendPrime } from "legend-prime";
import { privateKeyToAccount } from "viem/accounts";
const client = new LegendPrime({
queryKey: process.env.LEGEND_QUERY_KEY,
});
// 1. Create account
const account = await client.accounts.create({
signerType: "eoa",
signerAddress: "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18",
});
// 2. Create earn plan
const plan = await client.plan.earn(account.external_id, {
amount: "1000000",
asset: "USDC",
network: "base",
protocol: "compound",
});
// 3. Sign
const signer = privateKeyToAccount(process.env.SIGNER_PRIVATE_KEY as `0x${string}`);
const signature = await signer.sign({
hash: plan.chart.eip712_data.digest,
});
// 4. Execute
const result = await client.plan.execute(account.external_id, {
planId: plan.plan_id,
signature,
});
console.log(`Executing: ${result.plan_id}`);
// 5. Poll for confirmation
for (let i = 0; i < 30; i++) {
const { activities } = await client.accounts.activities(account.external_id);
if (activities.length > 0) {
console.log(`Done: ${activities[0].activity_type}`);
break;
}
await new Promise((r) => setTimeout(r, 2000));
}
Next steps