/api/coins/join
GETJoin multiple smaller denomination coins into a single larger denomination coin.
Current Implementation Status: This endpoint currently validates the target denomination parameter but does not perform the actual coin joining operation. Full implementation is pending integration with cmd_join_coins() to execute the RAIDA Join protocol (0x095d).
Current Behavior: Returns success with validated denomination and value. Coins remain unchanged in wallet.
Planned Implementation: Will automatically select optimal combination of smaller coins, communicate with all 25 RAIDA servers, destroy source coins, and create a single joined coin with new serial number.
Description
The /api/coins/join endpoint will consolidate multiple smaller denomination coins into a single larger denomination coin. This operation is useful for simplifying wallet management and reducing the total number of coins while maintaining the same value.
When fully implemented, the system will:
- Select multiple coins from the Bank folder with a total value equal to the target denomination
- Request an available serial number from RAIDA for the joined coin
- Send a Join (0x095d) request to all 25 RAIDA servers with source coin details
- RAIDA destroys the source coins and creates a single joined coin
- Download the joined coin with new Authenticity Numbers (ANs)
- Save the joined coin to the Bank folder
This endpoint will be perfect for:
- Wallet consolidation: Reduce the number of individual coins
- Denomination management: Create specific denominations for payments
- Balance simplification: Convert many small coins into fewer large ones
- Transaction preparation: Create exact denominations needed for transfers
Protocol Details:
- Command Code: 0x095d (Group 0x09, Command 0x5d)
- Operation Type: Atomic multi-coin destruction and single-coin creation
- Requirements: All 25 RAIDA servers must agree to the join operation
- Source Coins: Automatically destroyed upon successful join
- Target Coin: Created with new serial number from RAIDA pool
- Total Value: Sum of source coins must exactly equal target denomination
Parameters
This endpoint requires one query parameter:
| Parameter | Type | Required | Description |
|---|---|---|---|
denomination |
integer | Yes | Target denomination code to join into (0-10). See denomination reference table below. |
Denomination Reference
Valid denomination codes and their corresponding CloudCoin values:
Code | Value | Common Join Examples
-----|--------------|------------------------------------
0 | 1 | 5× 0.1 → 1, or 2× 0.25 + 2× 0.1 + 2× 0.05 → 1
1 | 5 | 5× 1 → 5
2 | 25 | 5× 5 → 25
3 | 100 | 4× 25 → 100
4 | 250 | 10× 25 → 250, or 2× 100 + 2× 25 → 250
5 | 1,000 | 4× 250 → 1,000, or 10× 100 → 1,000
6 | 5,000 | 2× 1,000 + 2× 1,000 + 1,000 → 5,000
7 | 25,000 | 5× 5,000 → 25,000
8 | 100,000 | 4× 25,000 → 100,000
9 | 250,000 | 10× 25,000 → 250,000
10 | 1,000,000 | 4× 250,000 → 1,000,000
When fully implemented, the system will automatically select the optimal combination of source coins:
- Exact Match Priority: Prefers combinations that exactly match the target (e.g., 4× 25 for 100)
- Minimum Coins: Minimizes the number of source coins used
- Denomination Balance: Avoids leaving odd or difficult-to-use denominations
- Value Precision: Ensures total source value exactly equals target denomination
Response
Returns a JSON object with join operation status and details.
Response Properties (Current Implementation)
Future Response Properties (When Fully Implemented)
Example Success Response (Current Implementation)
{
"status": "success",
"operation": "coins-join",
"message": "Join coins endpoint - parameter-based implementation pending",
"wallet": "Default",
"target_denomination": 5,
"target_value": 1000,
"note": "System will join smaller coins to create this denomination - needs cmd_join_coins() integration"
}
Example Success Response (Future Implementation)
{
"status": "success",
"operation": "coins-join",
"message": "Successfully joined 4 coins into 1 coin of denomination 1000",
"wallet": "Default",
"target_denomination": 5,
"target_value": 1000,
"source_coins": [
{
"serial_number": 12345,
"denomination": 4,
"value": 250
},
{
"serial_number": 12346,
"denomination": 4,
"value": 250
},
{
"serial_number": 12347,
"denomination": 4,
"value": 250
},
{
"serial_number": 12348,
"denomination": 4,
"value": 250
}
],
"source_count": 4,
"joined_coin": {
"serial_number": 89012,
"denomination": 5,
"value": 1000,
"file_path": "Bank/1000.CloudCoin.1.89012.stack"
},
"raida_results": {
"total_raidas": 25,
"success_count": 25,
"fail_count": 0,
"error_count": 0
},
"pown_string": "ppppppppppppppppppppppppp",
"authenticity_status": "authentic"
}
Example Error Response (Missing Parameter)
{
"status": "error",
"operation": "coins-join",
"message": "Missing required parameter: denomination"
}
Example Error Response (Invalid Denomination)
{
"status": "error",
"operation": "coins-join",
"message": "Invalid denomination value: 15. Must be between 0 and 10"
}
Example Error Response (No Active Wallet)
{
"status": "error",
"operation": "coins-join",
"message": "No active wallet. Please select a wallet first."
}
Example Error Response (Insufficient Coins - Future Implementation)
{
"status": "error",
"operation": "coins-join",
"message": "Insufficient coins to join into denomination 1000. Need total value of 1000, but only have 750 in available coins."
}
HTTP Status Codes
| Status Code | Description |
|---|---|
200 OK |
Parameter validation successful (current), or join operation completed successfully (future). |
400 Bad Request |
Missing or invalid 'denomination' parameter, or no active wallet. |
500 Internal Server Error |
Server error during join operation (future implementation). |
Join Operation Details (Future Implementation)
Step-by-Step Process
- Coin Selection: System scans Bank folder and selects optimal combination of coins whose total value equals the target denomination.
- Serial Number Request: Queries RAIDA for an available serial number to assign to the joined coin.
- Join Request Construction: Builds RAIDA Join (0x095d) request packet containing:
- Source coin serial numbers, denominations, and ANs
- Target denomination code
- New serial number for joined coin
- Multi-threaded RAIDA Communication: Sends join request to all 25 RAIDA servers in parallel using thread pool (~1-2 second execution time).
- Response Collection: Collects responses from all RAIDAs and builds POWN string (p=pass, f=fail, e=error, n=no reply).
- Authenticity Check: Requires 13+ RAIDAs to respond with 'pass' for successful join.
- Coin Creation: If successful, downloads joined coin with new ANs from RAIDA and saves to Bank folder.
- Source Coin Cleanup: Removes source coins from Bank folder (they are now destroyed on RAIDA).
- Transaction Receipt: Generates receipt file in Receipts folder with join details.
Atomic Operation Guarantee
The join operation is atomic across all 25 RAIDA servers:
- If 13+ RAIDAs succeed → All source coins destroyed, joined coin created
- If <13 RAIDAs succeed → Operation fails, source coins remain unchanged
- No partial state: Either complete success or complete rollback
Coin Selection Strategy
The system will automatically select the best combination of source coins:
Target: 1000 (denomination code 5)
Option 1 (Preferred - Exact Match):
4× 250 = 1000 ✓ (Minimal coins)
Option 2:
10× 100 = 1000 ✓ (More coins, less optimal)
Option 3:
2× 250 + 5× 100 = 1000 ✓ (Mixed denominations)
Option 4:
1× 250 + 3× 100 + 15× 25 + 5× 5 = 1000 ✓ (Many coins, least optimal)
Selection Priority:
1. Fewest source coins
2. Largest denominations first
3. Avoid leaving odd remainders
Performance Characteristics
| Operation | Time (Sequential) | Time (Multi-threaded) |
|---|---|---|
| Serial Number Request | ~25 seconds | ~1-2 seconds |
| Join Request (0x095d) | ~25 seconds | ~1-2 seconds |
| Download New ANs | ~25 seconds | ~1-2 seconds |
| Total | ~75 seconds | ~3-6 seconds |
Examples
JavaScript (fetch)
const API_HOST = 'http://localhost:8080';
async function joinCoins(targetDenomination) {
try {
const response = await fetch(
`${API_HOST}/api/coins/join?denomination=${targetDenomination}`
);
const result = await response.json();
if (result.status === 'success') {
console.log('Join Operation (Parameter Validation):');
console.log(`Target Denomination: ${result.target_denomination}`);
console.log(`Target Value: ${result.target_value}`);
console.log(`Wallet: ${result.wallet}`);
console.log(`Note: ${result.note}`);
// Future implementation will include:
// console.log(`Source Coins: ${result.source_count}`);
// console.log(`Joined Coin SN: ${result.joined_coin.serial_number}`);
// console.log(`POWN String: ${result.pown_string}`);
// console.log(`Status: ${result.authenticity_status}`);
} else {
console.error('Join failed:', result.message);
}
} catch (error) {
console.error('Error joining coins:', error);
}
}
// Join 4× 250 coins into 1× 1000 coin (denomination code 5)
joinCoins(5);
// Join 4× 25 coins into 1× 100 coin (denomination code 3)
joinCoins(3);
// Denomination reference map
const DENOMINATIONS = {
0: 1,
1: 5,
2: 25,
3: 100,
4: 250,
5: 1000,
6: 5000,
7: 25000,
8: 100000,
9: 250000,
10: 1000000
};
function getDenominationCode(value) {
return Object.keys(DENOMINATIONS).find(
key => DENOMINATIONS[key] === value
);
}
// Example: Join into 1000 coin
const code = getDenominationCode(1000); // Returns "5"
joinCoins(parseInt(code));
cURL
# Join coins into 1000 denomination (code 5)
curl -X GET "http://localhost:8080/api/coins/join?denomination=5"
# Join coins into 100 denomination (code 3)
curl -X GET "http://localhost:8080/api/coins/join?denomination=3"
# Join coins into 25000 denomination (code 7)
curl -X GET "http://localhost:8080/api/coins/join?denomination=7"
# Pretty-print JSON response with jq
curl -X GET "http://localhost:8080/api/coins/join?denomination=5" | jq .
# Check for errors
curl -X GET "http://localhost:8080/api/coins/join?denomination=99" | jq .
Go
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
const ApiHost = "http://localhost:8080"
type SourceCoin struct {
SerialNumber int `json:"serial_number"`
Denomination int `json:"denomination"`
Value int `json:"value"`
}
type JoinedCoin struct {
SerialNumber int `json:"serial_number"`
Denomination int `json:"denomination"`
Value int `json:"value"`
FilePath string `json:"file_path"`
}
type RaidaResults struct {
TotalRaidas int `json:"total_raidas"`
SuccessCount int `json:"success_count"`
FailCount int `json:"fail_count"`
ErrorCount int `json:"error_count"`
}
type JoinResponse struct {
Status string `json:"status"`
Operation string `json:"operation"`
Message string `json:"message"`
Wallet string `json:"wallet"`
TargetDenomination int `json:"target_denomination"`
TargetValue int `json:"target_value"`
Note string `json:"note"`
// Future implementation fields:
SourceCoins []SourceCoin `json:"source_coins,omitempty"`
SourceCount int `json:"source_count,omitempty"`
JoinedCoin *JoinedCoin `json:"joined_coin,omitempty"`
RaidaResults *RaidaResults `json:"raida_results,omitempty"`
PownString string `json:"pown_string,omitempty"`
AuthenticityStatus string `json:"authenticity_status,omitempty"`
}
// Denomination value reference
var DenominationValues = map[int]int{
0: 1,
1: 5,
2: 25,
3: 100,
4: 250,
5: 1000,
6: 5000,
7: 25000,
8: 100000,
9: 250000,
10: 1000000,
}
func joinCoins(targetDenomination int) (*JoinResponse, error) {
url := fmt.Sprintf("%s/api/coins/join?denomination=%d",
ApiHost, targetDenomination)
resp, err := http.Get(url)
if err != nil {
return nil, fmt.Errorf("request failed: %v", err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response: %v", err)
}
var result JoinResponse
if err := json.Unmarshal(body, &result); err != nil {
return nil, fmt.Errorf("failed to parse JSON: %v", err)
}
return &result, nil
}
func main() {
// Join into 1000 denomination (code 5)
result, err := joinCoins(5)
if err != nil {
panic(err)
}
if result.Status == "success" {
fmt.Println("Join Operation (Parameter Validation):")
fmt.Printf("Target Denomination: %d\n", result.TargetDenomination)
fmt.Printf("Target Value: %d\n", result.TargetValue)
fmt.Printf("Wallet: %s\n", result.Wallet)
fmt.Printf("Note: %s\n", result.Note)
// Future implementation will include:
// fmt.Printf("Source Coins: %d\n", result.SourceCount)
// fmt.Printf("Joined Coin SN: %d\n", result.JoinedCoin.SerialNumber)
// fmt.Printf("POWN String: %s\n", result.PownString)
// fmt.Printf("Status: %s\n", result.AuthenticityStatus)
} else {
fmt.Printf("Join failed: %s\n", result.Message)
}
// Example: Join different denominations
denominations := []int{3, 5, 7} // 100, 1000, 25000
for _, denom := range denominations {
result, err := joinCoins(denom)
if err != nil {
fmt.Printf("Error for denomination %d: %v\n", denom, err)
continue
}
value := DenominationValues[denom]
fmt.Printf("Validated join into %d (value: %d)\n", denom, value)
}
}
Join vs Break Operations
Understanding the difference between joining and breaking coins:
| Aspect | Join (0x095d) | Break (0x095c) |
|---|---|---|
| Operation | Many coins → One coin | One coin → Many coins |
| Direction | Smaller → Larger denomination | Larger → Smaller denominations |
| Use Case | Consolidate wallet, reduce coin count | Make change, prepare exact payments |
| Example | 4× 25 → 1× 100 | 1× 100 → 4× 25 |
| Source Coins | Multiple (2-100+ coins) | Single coin |
| Result Coins | Single coin | Multiple coins |
| Value Conservation | Sum of sources = Joined coin | Source coin = Sum of result coins |
| RAIDA Protocol | Command 0x095d | Command 0x095c |
Use Join when you want to:
- Reduce the total number of coins in your wallet
- Consolidate many small denominations into fewer large ones
- Simplify wallet management
- Prepare for large transactions
Use Break when you want to:
- Create exact change for payments
- Split a large coin into multiple smaller denominations
- Prepare coins for distribution to multiple recipients
- Increase denomination flexibility
Related Endpoints
/api/coins/break
Break a single large denomination coin into multiple smaller denomination coins. Opposite of join operation.
/api/wallet/balance
Check current wallet balance and available denominations before joining coins.
/api/wallet/show-coins
View detailed list of all coins in Bank folder, including denominations available for joining.
/api/coins/detect
Authenticate coins with RAIDA before joining to ensure all source coins are valid.
Implementation Roadmap
Current Implementation (Parameter Validation Only):
- ✅ Parameter parsing and validation
- ✅ Denomination code verification (0-10)
- ✅ Target value calculation
- ✅ Active wallet check
- ✅ Error response formatting
Pending Implementation:
- ❌ Integration with
cmd_join_coins()in C backend - ❌ Coin selection algorithm (optimal combination finder)
- ❌ RAIDA serial number request (find available SN)
- ❌ RAIDA Join (0x095d) protocol execution
- ❌ Multi-threaded RAIDA communication (25 parallel requests)
- ❌ POWN string collection and authenticity check (13+ passes required)
- ❌ New coin download with ANs from RAIDA
- ❌ Source coin cleanup (remove from Bank folder)
- ❌ Joined coin save to Bank folder
- ❌ Transaction receipt generation
Dependencies:
raida_thread_pool_t- Multi-threaded RAIDA executionwallet.h- Coin file I/O and Bank folder managementtransactions.h- Receipt generationraida.h- RAIDA protocol implementation (0x095d)