Skip to main content

Overview

Selling gold converts gold tokens back to USDC. The flow mirrors buying:
  1. Get an estimate for the USDC you’ll receive
  2. Create a sell transaction
  3. Sign and submit the transaction
There are two sell types:
  • User sale — sells gold from a specific user’s account
  • Partner sale — sells gold from the partner’s PDA (reserves/treasury)
All trading endpoints require an API key with PARTNER_EXECUTIVE_AUTHORITY scope.

Step 1: Get a Sell Estimate

Calculate how much USDC you’ll receive for a given amount of gold.
curl -X POST https://oro-tradebook-devnet.up.railway.app/api/trading/estimate/sell \
  -H "Content-Type: application/json" \
  -H "x-api-key: your-api-key" \
  -d '{
    "goldAmount": 0.5
  }'
{
  "success": true,
  "data": {
    "goldAmount": 0.5,
    "estimatedUsdcAmount": 2543.10,
    "goldPricePerOunce": 5086.2,
    "timestamp": "2024-01-15T10:30:00.000Z"
  }
}
Use the estimatedUsdcAmount value to set your minimumUsdcAmount in the next step.

Step 2: Create a Sell Transaction

User Sale

Sell gold from a specific user’s account. The flow differs based on your partner type.
User sale transactions are Versioned Transactions (V0). Use VersionedTransaction from @solana/web3.js for signing.

Custodial

For custodial partners, only the executive authority signs. The co_sign and userAsFeePayer parameters are ignored.
curl -X POST https://oro-tradebook-devnet.up.railway.app/api/trading/sales/user \
  -H "Content-Type: application/json" \
  -H "x-api-key: your-api-key" \
  -d '{
    "userId": "user-id",
    "goldAmount": 0.1,
    "minimumUsdcAmount": 480
  }'

Self-Custody

For self-custody partners, the user must sign (and optionally the executive authority co-signs).
curl -X POST https://oro-tradebook-devnet.up.railway.app/api/trading/sales/user \
  -H "Content-Type: application/json" \
  -H "x-api-key: your-api-key" \
  -d '{
    "userId": "user-id",
    "goldAmount": 0.1,
    "minimumUsdcAmount": 480,
    "co_sign": false,
    "userAsFeePayer": true
  }'
Both return:
{
  "success": true,
  "data": {
    "sellId": "uuid-sale-id",
    "goldAmount": 0.1,
    "quoteUsdcAmount": 508.62,
    "minimumUsdcAmount": 480,
    "quotedGoldPrice": 5086.2,
    "status": "pending_signature",
    "transaction": {
      "serializedTx": "base64-encoded-transaction",
      "signingInstructions": {
        "walletType": "user_wallet",
        "signers": ["UserWalletAddress"],
        "expiresAt": "2024-01-15T10:35:00.000Z"
      }
    },
    "createdAt": "2024-01-15T10:30:00.000Z"
  }
}

Partner Sale

Sell gold from the partner’s PDA (reserves). This is a Legacy Transaction signed only by the executive authority.
Partner sales deduct gold from the partner PDA and deposit USDC to the PDA. The partner must have sufficient gold balance.
curl -X POST https://oro-tradebook-devnet.up.railway.app/api/trading/sales/partner \
  -H "Content-Type: application/json" \
  -H "x-api-key: your-api-key" \
  -d '{
    "goldAmount": 1.0,
    "minimumUsdcAmount": 4800
  }'
{
  "success": true,
  "data": {
    "sellId": "uuid-sale-id",
    "goldAmount": 1.0,
    "quoteUsdcAmount": 5086.20,
    "minimumUsdcAmount": 4800,
    "quotedGoldPrice": 5086.2,
    "status": "pending_signature",
    "transaction": {
      "serializedTx": "base64-encoded-transaction",
      "signingInstructions": {
        "walletType": "PARTNER_AUTHORITY",
        "signers": ["ExecutiveAuthorityAddress"],
        "expiresAt": "2024-01-15T10:35:00.000Z"
      }
    },
    "createdAt": "2024-01-15T10:30:00.000Z"
  }
}

Step 3: Sign and Submit

Who signs user sales:
Partner TypeSigners Required
CustodialExecutive authority only
Self-Custody (co_sign: false, userAsFeePayer: true)User wallet only
Self-Custody (all other combinations)User wallet + Executive authority
The code below is a simplified reference. In practice, the user signs on the client side and the partner’s executive authority signs on the backend before submitting the transaction.

Signing a Versioned Transaction (V0) — User Sales

import { Keypair, VersionedTransaction, Connection } from "@solana/web3.js";

const connection = new Connection("https://api.devnet.solana.com");

// Deserialize the versioned transaction
const serializedTx = "base64-encoded-transaction"; // from response.data.transaction.serializedTx
const transaction = VersionedTransaction.deserialize(
  Buffer.from(serializedTx, "base64")
);

// Sign with required wallet(s) — see table above
const userKeypair = Keypair.fromSecretKey(/* user's secret key bytes */);
const executiveAuthority = Keypair.fromSecretKey(/* executive authority key bytes */);
transaction.sign([userKeypair, executiveAuthority]);

// Send to Solana
const txId = await connection.sendTransaction(transaction);

console.log("Transaction ID:", txId);

Signing a Legacy Transaction — Partner Sales

Partner sales are signed only by the executive authority.
import { Keypair, Transaction, Connection, sendAndConfirmTransaction } from "@solana/web3.js";

const connection = new Connection("https://api.devnet.solana.com");

const serializedTx = "base64-encoded-transaction"; // from response.data.transaction.serializedTx
const transaction = Transaction.from(Buffer.from(serializedTx, "base64"));

// Only executive authority signs partner sales
const executiveAuthority = Keypair.fromSecretKey(/* your secret key bytes */);

// Sign and send to Solana
const txId = await sendAndConfirmTransaction(connection, transaction, [executiveAuthority]);

console.log("Transaction ID:", txId);
If you prefer not to send the transaction yourself, you can use the POST /api/transactions/submit endpoint instead. Just pass the base64-encoded signed transaction and the API will send it to the network for you.

Slippage Protection

Setting minimumUsdcAmount too close to the estimate may cause transactions to fail during volatile markets. Setting it too low means you accept larger price drops.
The minimumUsdcAmount parameter protects against receiving less USDC than expected:
  • If the actual USDC received would be less than minimumUsdcAmount, the on-chain program rejects the transaction
  • Set it to the estimatedUsdcAmount value minus a buffer (e.g., 5–10%) to account for price fluctuations
minimumUsdcAmount = estimatedUsdcAmount * 0.95  // 5% slippage tolerance

Next Steps

To manage your treasury and partner settings, proceed to Withdrawals & Partner Management.