/api/transactions/locker/put-no-sum

GET

Upload CloudCoins from your wallet to a RAIDA locker using per-coin authentication. Each coin is individually verified by the RAIDA, providing per-coin pass/fail results.

Description

The /api/transactions/locker/put-no-sum endpoint uploads CloudCoins from your wallet to the RAIDA cloud locker system using per-coin authentication. Unlike the standard locker upload which uses an XOR checksum, this endpoint authenticates each coin individually with its Authenticity Number (AN), giving per-coin pass/fail results.

Per-Coin Authentication

This endpoint uses RAIDA command 0x0850 (cmd_store). Each coin is individually authenticated — the RAIDA checks each coin's AN and returns a per-coin bitmask showing which coins passed and which failed. Only coins achieving 13+ RAIDA confirmations are moved to the Locker folder.

The endpoint performs a multi-phase operation:

  1. Coin Selection: Selects coins from Bank and Fracked folders using greedy selection (largest denominations first). Auto make-change if exact amount cannot be met.
  2. RAIDA Store: Sends per-coin POWN-format packets to all 25 RAIDAs in parallel via TCP. Each coin carries its AN and a per-RAIDA derived locker code as the PAN.
  3. Per-Coin Consensus: Each RAIDA returns a bitmask indicating which coins passed. Coins with 13+ RAIDA passes are considered accepted.
  4. File Management: Only accepted coins are moved to the Locker folder. Failed coins remain in Bank/Fracked.
Security Warning

The locker_key parameter is essentially a password. Anyone with this key can download the coins from the locker. Keep it secret and share it securely with the intended recipient only.

Comparison with Locker Upload

Feature Locker Upload (0x0852) Locker Put No-Sum (0x0850)
Authentication XOR checksum of all ANs (all-or-nothing) Per-coin AN verification (individual results)
Bytes per coin 5 (DN + SN only) 37 (DN + SN + AN + PAN)
Failure granularity All coins fail if any AN is wrong Only bad coins fail; good coins still accepted
Transport TCP, unencrypted TCP, unencrypted
Best for Trusted coins, smaller batches Mixed-quality coins, when per-coin results matter

Parameters

This endpoint requires both locker_key and amount.

Query Parameters

Parameter Type Required Description
locker_key string Yes Any string of characters (e.g., "ABC-1234"). This becomes the password to access the locker.
amount integer Yes Upload coins totaling this many whole CloudCoin units. Uses greedy selection (largest denominations first) with auto make-change.
wallet_path string No Full path to the wallet directory containing the coins. If omitted, uses the default wallet.
wallet string No Wallet name (alternative to wallet_path). Looks up wallet in standard locations.

Locker Key Format

The locker_key can be any string. We recommend a format like "ABC-1234" for easy sharing, but any characters work.

Example locker_key values:

CUP-1974
MySecret2025
ABC-DEFG-1234
gift-for-alice

Important: The same locker_key always accesses the same locker. Keep your locker_key secret and share it securely with the intended recipient only. Anyone with the locker_key can download the coins.

RAIDA Protocol Details

This endpoint uses the RAIDA Store command (0x0850) with per-coin POWN-style authentication.

Command Code

0x0850 (Command Group: 0x08 = Locker, Command: 0x50 = Store / Put No-Sum)

Request Body Format

N x [DN(1 byte) + SN(4 bytes) + AN(16 bytes) + PAN(16 bytes)]

Body size = N x 37 bytes, where N is the number of coins. Each coin carries:

  • DN (1 byte): Denomination code
  • SN (4 bytes): Serial number, big-endian
  • AN (16 bytes): Authenticity Number for this specific RAIDA
  • PAN (16 bytes): Per-RAIDA derived locker code (same for all coins in the batch)

PAN Derivation

The PAN is not a random value. It is the per-RAIDA locker code derived from the locker key:

locker_code[raida_id] = MD5(str(raida_id) + parts[0] + "-" + parts[1])
locker_code[12..15] = 0xFFFFFFFF

The same locker code is used as PAN for every coin in the batch on a given RAIDA.

Response Status Codes

  • 241 (ALL_PASS): All coins accepted by this RAIDA
  • 242 (ALL_FAIL): No coins accepted by this RAIDA
  • 243 (MIXED): Some coins passed, some failed. Response body contains a bitmask (1 bit per coin, LSB-first)

Bitmask Format (Status 243)

The response body is a bitmask with 1 bit per coin, packed LSB-first:

bit = (body[i / 8] >> (i % 8)) & 1
// 1 = coin accepted, 0 = coin rejected

Consensus Requirement

Each coin is evaluated independently. A coin is considered accepted if 13 or more out of 25 RAIDAs report it as passed.

Response

Returns a JSON object with per-coin results showing exactly which coins were accepted and which failed.

Example: Success (All Coins Accepted)

{
  "status": "success",
  "operation": "locker_put_no_sum",
  "amount_requested": 500,
  "coins_sent": 3,
  "coins_accepted": 3,
  "coins_moved": 3,
  "value_accepted": 500,
  "locker_key": "CUP-1974",
  "raida_responded": 25,
  "coin_results": [
    {
      "serial_number": 1234567,
      "denomination": 100,
      "raida_pass": 25,
      "accepted": true
    },
    {
      "serial_number": 2345678,
      "denomination": 100,
      "raida_pass": 24,
      "accepted": true
    },
    {
      "serial_number": 3456789,
      "denomination": 100,
      "raida_pass": 100,
      "accepted": true
    }
  ],
  "task_id": "a1b2c3d4"
}

Example: Partial Success (Mixed Results)

{
  "status": "success",
  "operation": "locker_put_no_sum",
  "amount_requested": 200,
  "coins_sent": 3,
  "coins_accepted": 2,
  "coins_moved": 2,
  "value_accepted": 110,
  "locker_key": "MY-LOCKER",
  "raida_responded": 25,
  "coin_results": [
    {
      "serial_number": 1111111,
      "denomination": 100,
      "raida_pass": 24,
      "accepted": true
    },
    {
      "serial_number": 2222222,
      "denomination": 10,
      "raida_pass": 25,
      "accepted": true
    },
    {
      "serial_number": 3333333,
      "denomination": 100,
      "raida_pass": 3,
      "accepted": false
    }
  ],
  "task_id": "e5f6g7h8"
}

Response Properties

status string
"success" if at least one coin was accepted, "error" otherwise.
operation string
Always "locker_put_no_sum".
amount_requested integer
The amount of CloudCoins requested to upload.
coins_sent integer
Total number of coins sent to the RAIDA.
coins_accepted integer
Number of coins that achieved 13+ RAIDA consensus (accepted into locker).
coins_moved integer
Number of coins successfully moved to the Locker folder.
value_accepted integer
Total value of accepted coins in whole CloudCoin units.
locker_key string
The locker key used for the upload.
raida_responded integer
Number of RAIDAs that responded successfully (out of 25).
coin_results array
Per-coin breakdown. Each object contains serial_number, denomination, raida_pass (number of RAIDAs that accepted this coin), and accepted (true if 13+ passes).
task_id string
Transaction ID for tracking in wallet transaction log.

Error Responses

The endpoint returns appropriate HTTP status codes with JSON error messages.

HTTP 400 - Bad Request

  • Missing or empty locker_key parameter
  • Missing amount parameter
  • Invalid amount (must be greater than 0)
  • Cannot make exact change for requested amount
  • Invalid wallet path

HTTP 500 - Internal Server Error

  • Put failed - no coins accepted by RAIDA consensus
  • Insufficient RAIDA responses (fewer than 13 RAIDAs responded)
  • Transport not initialized

Example Error Response

{
  "status": "error",
  "operation": "locker_put_no_sum",
  "message": "Put failed - no coins accepted by RAIDA consensus",
  "locker_key": "MY-KEY",
  "raida_responded": 25,
  "coins_sent": 3,
  "coins_accepted": 0
}

Examples

cURL

# Upload 500 CloudCoins to locker with per-coin authentication
curl "http://localhost:8080/api/transactions/locker/put-no-sum?locker_key=CUP-1974&amount=500"

# Upload 100 CloudCoins from a specific wallet
curl "http://localhost:8080/api/transactions/locker/put-no-sum?locker_key=GIFT-CODE&amount=100&wallet_path=/path/to/wallet"

# Upload 1 CloudCoin (small test)
curl "http://localhost:8080/api/transactions/locker/put-no-sum?locker_key=TEST-KEY&amount=1"

# Upload using a named wallet
curl "http://localhost:8080/api/transactions/locker/put-no-sum?locker_key=ABC-1234&amount=50&wallet=MyWallet"

JavaScript (fetch)

const API_HOST = 'http://localhost:8080';

// Upload coins to locker with per-coin authentication
async function lockerPutNoSum(lockerKey, amount, walletPath = null) {
    let url = `${API_HOST}/api/transactions/locker/put-no-sum?` +
              `locker_key=${encodeURIComponent(lockerKey)}&` +
              `amount=${amount}`;

    if (walletPath) {
        url += `&wallet_path=${encodeURIComponent(walletPath)}`;
    }

    const response = await fetch(url);
    const result = await response.json();

    if (result.status === 'success') {
        console.log(`Accepted ${result.coins_accepted}/${result.coins_sent} coins`);
        console.log(`Value accepted: ${result.value_accepted} CC`);

        // Check per-coin results
        for (const coin of result.coin_results) {
            const status = coin.accepted ? 'ACCEPTED' : 'REJECTED';
            console.log(`  SN ${coin.serial_number} (${coin.denomination} CC): ` +
                        `${coin.raida_pass}/25 RAIDA - ${status}`);
        }
    } else {
        console.error('Put failed:', result.message);
    }
    return result;
}

// Examples:
// Upload 500 CloudCoins
lockerPutNoSum('CUP-1974', 500);

// Upload 100 CloudCoins from specific wallet
lockerPutNoSum('GIFT-CODE', 100, 'E:/Wallets/MyWallet');

// Upload 1 CloudCoin (test)
lockerPutNoSum('TEST-KEY', 1);

Go

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "net/url"
)

const ApiHost = "http://localhost:8080"

type CoinResult struct {
    SerialNumber int     `json:"serial_number"`
    Denomination float64 `json:"denomination"`
    RaidaPass    int     `json:"raida_pass"`
    Accepted     bool    `json:"accepted"`
}

type LockerPutNoSumResponse struct {
    Status         string       `json:"status"`
    Operation      string       `json:"operation"`
    AmountReq      int          `json:"amount_requested"`
    CoinsSent      int          `json:"coins_sent"`
    CoinsAccepted  int          `json:"coins_accepted"`
    CoinsMoved     int          `json:"coins_moved"`
    ValueAccepted  int          `json:"value_accepted"`
    LockerKey      string       `json:"locker_key"`
    RaidaResponded int          `json:"raida_responded"`
    CoinResults    []CoinResult `json:"coin_results"`
    TaskID         string       `json:"task_id"`
    Message        string       `json:"message,omitempty"`
}

func lockerPutNoSum(lockerKey string, amount int, walletPath string) (*LockerPutNoSumResponse, error) {
    params := url.Values{}
    params.Add("locker_key", lockerKey)
    params.Add("amount", fmt.Sprintf("%d", amount))
    if walletPath != "" {
        params.Add("wallet_path", walletPath)
    }

    fullURL := fmt.Sprintf("%s/api/transactions/locker/put-no-sum?%s",
                           ApiHost, params.Encode())

    resp, err := http.Get(fullURL)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    body, _ := ioutil.ReadAll(resp.Body)
    var result LockerPutNoSumResponse
    json.Unmarshal(body, &result)
    return &result, nil
}

func main() {
    result, err := lockerPutNoSum("CUP-1974", 500, "")
    if err != nil {
        fmt.Printf("Error: %v\n", err)
        return
    }

    fmt.Printf("Status: %s\n", result.Status)
    fmt.Printf("Coins: %d sent, %d accepted\n",
               result.CoinsSent, result.CoinsAccepted)
    fmt.Printf("Value accepted: %d CC\n", result.ValueAccepted)

    // Print per-coin results
    for _, coin := range result.CoinResults {
        status := "REJECTED"
        if coin.Accepted {
            status = "ACCEPTED"
        }
        fmt.Printf("  SN %d (%g CC): %d/25 RAIDA - %s\n",
                    coin.SerialNumber, coin.Denomination,
                    coin.RaidaPass, status)
    }
}

Related Endpoints

/api/transactions/locker/upload

Upload coins using XOR-sum verification (all-or-nothing authentication). Faster for trusted coins.

/api/locker/peek

View the contents of a locker without downloading the coins. Check what's inside before downloading.

/api/transactions/locker/download

Download coins from a locker to your wallet using the locker key.

Implementation Notes

Best Practices
  • Test First: Use amount=1 when testing to minimize risk
  • Check Balance: Ensure wallet has coins before uploading
  • Review Results: Always check the coin_results array to see which coins were accepted
  • Handle Partial Success: If coins_accepted < coins_sent, failed coins remain in the wallet and may need frack-fix
  • Secure Keys: Use memorable but unpredictable locker keys
  • Share Safely: Only share locker keys through secure channels
Common Issues
  • Low raida_pass count: Coin's ANs may be out of sync with the RAIDA. Run frack-fix on the wallet first.
  • 0 coins accepted: All coins may be counterfeit or have corrupted ANs. Check coin details.
  • Partial acceptance: Some coins passed, others failed. Failed coins stay in Bank/Fracked. The accepted value (not the requested amount) is logged in the transaction.
  • Insufficient change: If exact change can't be made after 3 auto-break attempts, the request fails with HTTP 400.