Browser Wallet Flow
This guide covers collecting feedback in browser-based apps where the user's wallet (Phantom, Solflare, Backpack) signs the feedback. This is a two-step flow: the frontend prepares the feedback, the user signs it, and a server-side signer submits it on-chain.
Prerequisites
- A browser wallet adapter (e.g.,
@solana/wallet-adapter) - A server-side signer with SOL for transaction fees
- See Getting Started for SDK installation
How It Works
- Frontend calls
prepareFeedback()- builds a SIWS message for the user to sign - User's wallet signs the message (no SOL needed from the user)
- Server calls
submitPreparedFeedback()with the user's signature - pays for the transaction
This separation means your users never need SOL - your server covers transaction costs.
Frontend: Prepare and Sign
typescript
import { SatiAgent0 } from "@cascade-fyi/sati-agent0-sdk";
// Initialize with TransactionSender (browser wallet adapter)
const sdk = new SatiAgent0({
network: "mainnet",
transactionSender: walletAdapter,
});
// Step 1: Prepare the feedback (builds the SIWS message)
const prepared = await sdk.prepareFeedback(
agentId,
85, // value (0-100)
"quality", // tag1
"speed", // tag2
);
// Step 2: User signs with their wallet
const walletSignature = await wallet.signMessage(prepared.messageBytes);
// Step 3: Send to your server
await fetch("/api/submit-feedback", {
method: "POST",
body: JSON.stringify({
prepared,
signature: Array.from(walletSignature),
}),
});Server: Submit On-Chain
typescript
import { SatiAgent0 } from "@cascade-fyi/sati-agent0-sdk";
// Server SDK with a KeyPairSigner (pays for transactions)
const sdk = new SatiAgent0({
network: "mainnet",
signer: serverSigner,
});
// Submit the wallet-signed feedback
const handle = await sdk.submitPreparedFeedback(
prepared,
new Uint8Array(signatureFromClient),
);
const { result: feedback } = await handle.waitMined();
console.log(handle.hash); // transaction signatureWith Typed Outcomes
For workflows that need structured outcomes:
typescript
import { Outcome } from "@cascade-fyi/sati-agent0-sdk";
const prepared = await sdk.prepareFeedback(
agentId,
85,
"quality",
"speed",
{
endpoint: "https://api.example.com",
text: "Excellent response",
outcome: Outcome.Positive,
taskRef: interactionHashBytes, // deterministic 32-byte reference
},
);Error Handling
typescript
import {
SatiError,
AgentNotFoundError,
ReadOnlyError,
SignerRequiredError,
} from "@cascade-fyi/sati-agent0-sdk";
try {
await sdk.submitPreparedFeedback(prepared, walletSignature);
} catch (err) {
if (err instanceof AgentNotFoundError) {
// Agent was deregistered between prepare and submit
} else if (err instanceof SignerRequiredError) {
// Server SDK missing KeyPairSigner
}
}Next Steps
- Agent Marketplace - full server-side integration
- API Reference: sati-sdk prepareFeedback - sati-sdk method signature
- API Reference: sati-agent0-sdk prepareFeedback - agent0-compatible wrapper