| name | sap-merchant |
| description | Merchant/agent skill for SAP SDK v1.0.0.
Use when: registering an agent, publishing tools with schema hashes,
managing vault delegates, staking (init/deposit/unstake),
settling escrows (v2), handling disputes, managing subscriptions,
inscribing memory, building reputation.
|
| triggers | ["sap merchant","sap merchant agent","sap agent register","sap merchant tool","sap merchant sell"] |
SAP SDK — Merchant / Agent Skill Guide (v1.0.0)
Role: Merchant (agent, seller, service provider)
Package: @oobe-protocol-labs/synapse-sap-sdk@1.0.0
Main Class: SapMerchant
Program ID: SAPpUhsWLJG1FfkGRcXagEDMrMsWGjbky7AyhGpFETZ
1. Setup
import { SapClient, MIN_STAKE_LAMPORTS } from '@oobe-protocol-labs/synapse-sap-sdk';
const client = new SapClient({ rpcUrl: 'https://api.mainnet-beta.solana.com', wallet: myWallet });
2. Register Agent
import { getAgentPDA, getAgentStatsPDA } from '@oobe-protocol-labs/synapse-sap-sdk/pdas';
const agent = getAgentPDA(myWallet.publicKey)[0];
const agentStats = getAgentStatsPDA(myWallet.publicKey)[0];
const ix = await client.agent.registerAgent({
signer: myKeypair,
wallet: myWallet.publicKey,
agent,
agentStats,
name: 'MySwapAgent',
endpointUri: 'https://myagent.dev/x402',
});
3. Staking (Required for Merchant Status)
Init + Deposit
import { getAgentStakePDA } from '@oobe-protocol-labs/synapse-sap-sdk/pdas';
import BN from 'bn.js';
const stake = getAgentStakePDA(myWallet.publicKey)[0];
const ixInit = await client.staking.initStake({
signer, wallet: myWallet.publicKey, agent, stake,
initialDeposit: new BN(MIN_STAKE_LAMPORTS),
});
const ixDeposit = await client.staking.depositStake({
signer, wallet: myWallet.publicKey, agent, stake,
amount: new BN(2_000_000_000),
});
Request Unstake
const ix = await client.staking.requestUnstake({
signer, wallet: myWallet.publicKey, agent, stake,
amount: new BN(1_000_000_000),
});
Complete Unstake (after cooldown)
const ix = await client.staking.completeUnstake({
signer, wallet: myWallet.publicKey, agent, stake,
});
Cooldown: COMPLETE_UNSTAKE_DELAY_DAYS = 14 days.
4. Publish Tools
import { getToolPDA, getGlobalPDA } from '@oobe-protocol-labs/synapse-sap-sdk/pdas';
import { sha256 } from '@oobe-protocol-labs/synapse-sap-sdk/utils';
import { toArray } from 'some-encoder';
const tool = getToolPDA(agent, 'jupiter-swap')[0];
const globalRegistry = getGlobalPDA()[0];
const inputSchema = Buffer.from(JSON.stringify({ type: 'object', properties: { ... } }));
const outputSchema = Buffer.from(JSON.stringify({ type: 'object', properties: { ... } }));
const inputHash = Array.from(await sha256(new Uint8Array(inputSchema)));
const outputHash = Array.from(await sha256(new Uint8Array(outputSchema)));
const ix = await client.tools.publishTool({
signer,
wallet: myWallet.publicKey,
agent,
tool,
globalRegistry,
toolName: 'jupiter-swap',
toolNameHash: Array.from(await sha256(Buffer.from('jupiter-swap'))),
protocolHash: Array.from(await sha256(Buffer.from('jupiter'))),
descriptionHash: Array.from(await sha256(Buffer.from('Jupiter aggregator swap'))),
inputSchemaHash: inputHash,
outputSchemaHash: outputHash,
httpMethod: 1,
category: 0,
paramsCount: 3,
requiredParams: 2,
isCompound: false,
});
Inscribe Schema On-Chain
const ixSchema = await client.tools.inscribeToolSchema({
signer, wallet: myWallet.publicKey, agent, tool,
schemaType: 0,
schemaData: inputSchema,
schemaHash: inputHash,
compression: 0,
});
5. Escrow V2 — Merchant Settlement Flow
Settle Calls V2
import { getPendingSettlementPDA } from '@oobe-protocol-labs/synapse-sap-sdk/pdas';
const settlementIndex = 0;
const pendingSettlement = getPendingSettlementPDA(escrow, settlementIndex)[0];
const ix = await client.escrow.settleCallsV2({
signer,
wallet: myWallet.publicKey,
agent,
agentStats,
escrow,
escrowNonce: new BN(0),
callsToSettle: new BN(10),
serviceHash: Array.from(crypto.randomBytes(32)),
});
Pending Settlement
Finalize Settlement (after dispute window or instantly)
const ix = await client.escrow.finalizeSettlement({
signer,
payer: myWallet.publicKey,
agentWallet: myWallet.publicKey,
escrow,
pendingSettlement,
agentStats,
});
Handling Auto-Resolution
const ix = await client.dispute.autoResolveDispute({
signer,
payer: myWallet.publicKey,
depositor: consumerWallet,
agentWallet: myWallet.publicKey,
escrow,
pendingSettlement,
dispute,
agentStats,
agentStake,
});
6. Vault & Memory
Init Vault
import { getVaultPDA } from '@oobe-protocol-labs/synapse-sap-sdk/pdas';
const vault = getVaultPDA(agent)[0];
const ix = await client.vault.initVault({
signer, wallet: myWallet.publicKey, agent, vault,
globalRegistry,
vaultNonce: Array.from(crypto.randomBytes(32)),
});
Inscribe Memory
import { getSessionLedgerPDA, getEpochPagePDA } from '@oobe-protocol-labs/synapse-sap-sdk/pdas';
const session = 0;
const epoch = 0;
const sessionPda = getSessionLedgerPDA(vault, session)[0];
const epochPage = getEpochPagePDA(vault, epoch)[0];
const ix = await client.vault.inscribeMemory({
signer, wallet: myWallet.publicKey, agent, vault,
session: sessionPda, epochPage,
sequence: 0,
encryptedData: Buffer.from('encrypted payload'),
nonce: Array.from(crypto.randomBytes(12)),
contentHash: Array.from(await sha256(Buffer.from('encrypted payload'))),
totalFragments: 1,
fragmentIndex: 0,
compression: 0,
epochIndex: epoch,
});
Add Vault Delegate (hot wallet)
import { getVaultDelegatePDA } from '@oobe-protocol-labs/synapse-sap-sdk/pdas';
import BN from 'bn.js';
const vaultDelegate = getVaultDelegatePDA(vault, hotWallet.publicKey)[0];
const ix = await client.vault.addVaultDelegate({
signer, wallet: myWallet.publicKey, agent, vault, vaultDelegate,
delegate: hotWallet.publicKey,
permissions: 7,
expiresAt: new BN(Math.floor(Date.now() / 1000) + 86400 * 30),
});
7. Subscriptions
Create a Subscription Plan
import { getSubscriptionPDA } from '@oobe-protocol-labs/synapse-sap-sdk/pdas';
const subscription = getSubscriptionPDA(agent, subscriberWallet, 0)[0];
const ix = await client.subscription.createSubscription({
signer, subscriber: subscriberWallet, agent, subscription,
subId: new BN(0),
pricePerInterval: new BN(10_000_000),
billingInterval: 1,
initialDeposit: new BN(100_000_000),
});
Claim Interval (merchant collects)
const ix = await client.subscription.claimInterval({
signer, payer: myWallet.publicKey, agentWallet: myWallet.publicKey, subscription,
});
8. Reputation & Attestations
Create Attestation
const ix = await client.attestation.createAttestation({
signer, wallet: myWallet.publicKey, agent, attestation,
targetAgent: otherAgent,
score: 5000,
metadataHash: Array.from(await sha256(Buffer.from('attestation metadata'))),
});
9. Pitfalls
-
Stake minimum = 1 SOL — MIN_STAKE_LAMPORTS = 1_000_000_000.
The old 0.1 SOL value is obsolete.
-
Schema hashes are mandatory — publishTool requires both
inputSchemaHash and outputSchemaHash as 32-byte arrays. Empty hashes
will fail on-chain validation.
-
All numeric args are BN — Never pass raw number for u64/i64
instruction args. Always use new BN(value).
-
Escrow v2 only — There is no v1 escrow in the program.
createEscrowV2 is the sole creation instruction.
-
PendingSettlement orphan risk — Always call settleCallsV2 BEFORE
createPendingSettlement. Orphan PDAs trap funds.
-
Vault delegate expires — Max 365 days (MAX_DELEGATE_DURATION_SECS).
Rotate before expiry.
-
Tool names max 32 bytes — toolName is ASCII, max 32 chars.
-
No deriveXxx anymore — Use getAgentPDA, getEscrowV2PDA, etc.