docs: add comprehensive exchange integration guide
- Document network overview and confirmation requirements - Provide node setup instructions with Docker - Explain address generation for hot/cold wallets - Detail deposit monitoring via WebSocket and polling - Document withdrawal transaction building - Explain hybrid signature format (Ed25519 + Dilithium3) - Include complete API reference - Add security recommendations for exchange operations - Document testnet environment for testing
This commit is contained in:
parent
4a2825f516
commit
960c25eb8a
1 changed files with 532 additions and 0 deletions
532
docs/EXCHANGE_INTEGRATION.md
Normal file
532
docs/EXCHANGE_INTEGRATION.md
Normal file
|
|
@ -0,0 +1,532 @@
|
||||||
|
# Synor Exchange Integration Guide
|
||||||
|
|
||||||
|
This document provides technical specifications for cryptocurrency exchanges to integrate Synor (SYNOR) deposits, withdrawals, and trading.
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
1. [Network Overview](#network-overview)
|
||||||
|
2. [Node Setup](#node-setup)
|
||||||
|
3. [Address Generation](#address-generation)
|
||||||
|
4. [Deposits](#deposits)
|
||||||
|
5. [Withdrawals](#withdrawals)
|
||||||
|
6. [Transaction Format](#transaction-format)
|
||||||
|
7. [API Reference](#api-reference)
|
||||||
|
8. [Security Considerations](#security-considerations)
|
||||||
|
9. [Test Environment](#test-environment)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Network Overview
|
||||||
|
|
||||||
|
### Basic Information
|
||||||
|
|
||||||
|
| Property | Value |
|
||||||
|
|----------|-------|
|
||||||
|
| **Name** | Synor |
|
||||||
|
| **Symbol** | SYNOR |
|
||||||
|
| **Decimals** | 8 |
|
||||||
|
| **Smallest Unit** | soma (1 SYNOR = 10^8 somas) |
|
||||||
|
| **Block Time** | ~10 seconds (DAG-based) |
|
||||||
|
| **Consensus** | DAG-based PoW with SPECTRE ordering |
|
||||||
|
| **Signature Scheme** | Hybrid Ed25519 + Dilithium3 (post-quantum) |
|
||||||
|
|
||||||
|
### Network Types
|
||||||
|
|
||||||
|
| Network | Address Prefix | Use Case |
|
||||||
|
|---------|---------------|----------|
|
||||||
|
| Mainnet | `synor1` | Production |
|
||||||
|
| Testnet | `tsynor1` | Testing |
|
||||||
|
|
||||||
|
### Confirmation Requirements
|
||||||
|
|
||||||
|
| Amount | Recommended Confirmations |
|
||||||
|
|--------|---------------------------|
|
||||||
|
| < 100 SYNOR | 10 confirmations |
|
||||||
|
| 100-10,000 SYNOR | 50 confirmations |
|
||||||
|
| > 10,000 SYNOR | 100 confirmations |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Node Setup
|
||||||
|
|
||||||
|
### Hardware Requirements
|
||||||
|
|
||||||
|
**Minimum:**
|
||||||
|
- CPU: 4 cores
|
||||||
|
- RAM: 8 GB
|
||||||
|
- Storage: 100 GB SSD
|
||||||
|
- Network: 100 Mbps
|
||||||
|
|
||||||
|
**Recommended (Exchange):**
|
||||||
|
- CPU: 8+ cores
|
||||||
|
- RAM: 32 GB
|
||||||
|
- Storage: 500 GB NVMe SSD
|
||||||
|
- Network: 1 Gbps
|
||||||
|
|
||||||
|
### Docker Deployment
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# docker-compose.yml
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
synor-node:
|
||||||
|
image: synor/synord:latest
|
||||||
|
container_name: synor-exchange-node
|
||||||
|
restart: always
|
||||||
|
command:
|
||||||
|
- "run"
|
||||||
|
- "--p2p-port=16511"
|
||||||
|
- "--rpc-host=0.0.0.0"
|
||||||
|
- "--rpc-port=16110"
|
||||||
|
- "--ws-port=16111"
|
||||||
|
- "--seeds=seed1.synor.cc:16511,seed2.synor.cc:16511"
|
||||||
|
ports:
|
||||||
|
- "16511:16511" # P2P (public)
|
||||||
|
- "127.0.0.1:16110:16110" # RPC (internal only)
|
||||||
|
- "127.0.0.1:16111:16111" # WebSocket (internal only)
|
||||||
|
volumes:
|
||||||
|
- synor-data:/data/synor
|
||||||
|
environment:
|
||||||
|
- RUST_LOG=info
|
||||||
|
- SYNOR_NETWORK=mainnet
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
synor-data:
|
||||||
|
```
|
||||||
|
|
||||||
|
### Node Health Check
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check sync status
|
||||||
|
curl -X POST http://localhost:16110 \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"jsonrpc":"2.0","method":"synor_getSyncStatus","params":[],"id":1}'
|
||||||
|
|
||||||
|
# Response when synced:
|
||||||
|
# {"result":{"synced":true,"currentBlock":1234567,"highestBlock":1234567}}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Address Generation
|
||||||
|
|
||||||
|
### Address Format
|
||||||
|
|
||||||
|
Synor addresses use Bech32m encoding:
|
||||||
|
|
||||||
|
```
|
||||||
|
synor1qz232pysw8kezv2f4qxnhdufrlx5cmq78522mpuf8x5qlxu6j8sgcp05get
|
||||||
|
└────┘└──────────────────────────────────────────────────────────┘
|
||||||
|
HRP Base32-encoded payload
|
||||||
|
```
|
||||||
|
|
||||||
|
- **HRP (Human Readable Part):** `synor1` (mainnet) or `tsynor1` (testnet)
|
||||||
|
- **Payload:** 32-byte Blake3 hash of the hybrid public key
|
||||||
|
- **Checksum:** Bech32m checksum (6 characters)
|
||||||
|
|
||||||
|
### Generating Addresses
|
||||||
|
|
||||||
|
#### Using the CLI
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Generate new address
|
||||||
|
synor-cli wallet new
|
||||||
|
|
||||||
|
# Derive address from mnemonic
|
||||||
|
synor-cli wallet recover --mnemonic "your 24 word phrase..."
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Using the SDK (Rust)
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use synor_crypto::{generate_keypair, public_key_to_address, Network};
|
||||||
|
|
||||||
|
// Generate new keypair
|
||||||
|
let keypair = generate_keypair();
|
||||||
|
|
||||||
|
// Get address
|
||||||
|
let address = public_key_to_address(&keypair.public_key, Network::Mainnet);
|
||||||
|
// Returns: "synor1qz232pysw8kezv2f4qxnhdufrlx5cmq78522mpuf8x5qlxu6j8sgcp05get"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Using the SDK (JavaScript)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { createWallet, publicKeyToAddress } from '@synor/sdk';
|
||||||
|
|
||||||
|
// Generate wallet from mnemonic
|
||||||
|
const mnemonic = generateMnemonic(24);
|
||||||
|
const wallet = await createWallet(mnemonic, '', 'mainnet');
|
||||||
|
|
||||||
|
console.log(wallet.address);
|
||||||
|
// "synor1qz232pysw8kezv2f4qxnhdufrlx5cmq78522mpuf8x5qlxu6j8sgcp05get"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Address Validation
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Validate address format
|
||||||
|
function isValidSynorAddress(address) {
|
||||||
|
const mainnetRegex = /^synor1[a-z0-9]{58}$/;
|
||||||
|
const testnetRegex = /^tsynor1[a-z0-9]{59}$/;
|
||||||
|
return mainnetRegex.test(address) || testnetRegex.test(address);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Deposits
|
||||||
|
|
||||||
|
### Recommended Flow
|
||||||
|
|
||||||
|
1. **Generate unique deposit address per user**
|
||||||
|
2. **Monitor address via WebSocket or polling**
|
||||||
|
3. **Wait for required confirmations**
|
||||||
|
4. **Credit user account**
|
||||||
|
|
||||||
|
### Monitoring Deposits
|
||||||
|
|
||||||
|
#### WebSocket Subscription
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const ws = new WebSocket('ws://localhost:16111');
|
||||||
|
|
||||||
|
ws.onopen = () => {
|
||||||
|
// Subscribe to address transactions
|
||||||
|
ws.send(JSON.stringify({
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
method: 'synor_subscribeAddress',
|
||||||
|
params: ['synor1qz232...'],
|
||||||
|
id: 1
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onmessage = (event) => {
|
||||||
|
const msg = JSON.parse(event.data);
|
||||||
|
if (msg.method === 'synor_addressNotification') {
|
||||||
|
const { txId, amount, confirmations } = msg.params;
|
||||||
|
console.log(`Deposit: ${amount} SYNOR (${confirmations} confirms)`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Polling Method
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
async function checkDeposits(address, lastCheckedBlock) {
|
||||||
|
const response = await rpc('synor_getAddressTransactions', [
|
||||||
|
address,
|
||||||
|
{ fromBlock: lastCheckedBlock, limit: 100 }
|
||||||
|
]);
|
||||||
|
|
||||||
|
for (const tx of response.transactions) {
|
||||||
|
if (tx.type === 'receive' && tx.confirmations >= REQUIRED_CONFIRMS) {
|
||||||
|
await creditUser(address, tx.amount, tx.txId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.currentBlock;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Deposit Transaction Example
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"txId": "a1b2c3d4e5f6...",
|
||||||
|
"type": "receive",
|
||||||
|
"amount": "100.00000000",
|
||||||
|
"from": "synor1sender...",
|
||||||
|
"to": "synor1exchange...",
|
||||||
|
"confirmations": 50,
|
||||||
|
"blockHash": "block1234...",
|
||||||
|
"timestamp": 1704067200
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Withdrawals
|
||||||
|
|
||||||
|
### Recommended Flow
|
||||||
|
|
||||||
|
1. **Validate withdrawal address**
|
||||||
|
2. **Check exchange hot wallet balance**
|
||||||
|
3. **Build and sign transaction**
|
||||||
|
4. **Broadcast transaction**
|
||||||
|
5. **Monitor confirmation status**
|
||||||
|
6. **Update user withdrawal status**
|
||||||
|
|
||||||
|
### Building a Withdrawal Transaction
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { createSendTransactionHybrid, serializeTransaction } from '@synor/sdk';
|
||||||
|
|
||||||
|
async function processWithdrawal(toAddress, amount, wallet) {
|
||||||
|
// Build signed transaction
|
||||||
|
const tx = await createSendTransactionHybrid(
|
||||||
|
wallet.address, // From: exchange hot wallet
|
||||||
|
toAddress, // To: user's address
|
||||||
|
amount, // Amount in SYNOR (e.g., "100.5")
|
||||||
|
wallet // Contains seed, keypair, dilithiumPublicKey
|
||||||
|
);
|
||||||
|
|
||||||
|
// Broadcast
|
||||||
|
const result = await rpc('synor_sendRawTransaction', [
|
||||||
|
serializeTransaction(tx)
|
||||||
|
]);
|
||||||
|
|
||||||
|
return result.txId;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### UTXO Consolidation
|
||||||
|
|
||||||
|
For high-volume exchanges, periodically consolidate small UTXOs:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
async function consolidateUtxos(wallet) {
|
||||||
|
const utxos = await rpc('synor_getUtxos', [wallet.address]);
|
||||||
|
|
||||||
|
// Only consolidate if many small UTXOs
|
||||||
|
if (utxos.length < 100) return;
|
||||||
|
|
||||||
|
// Filter small UTXOs (< 1 SYNOR)
|
||||||
|
const smallUtxos = utxos.filter(u => parseFloat(u.amount) < 1);
|
||||||
|
|
||||||
|
if (smallUtxos.length < 50) return;
|
||||||
|
|
||||||
|
// Build consolidation transaction (send to self)
|
||||||
|
// ... transaction building code
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Fee Estimation
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
async function estimateFee(fromAddress, toAddress, amount) {
|
||||||
|
const result = await rpc('synor_estimateFee', [{
|
||||||
|
from: fromAddress,
|
||||||
|
to: toAddress,
|
||||||
|
amount: amount
|
||||||
|
}]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
fee: result.fee, // e.g., "0.00001000"
|
||||||
|
feePerByte: result.feePerByte,
|
||||||
|
estimatedSize: result.size // Larger for hybrid signatures
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Transaction Format
|
||||||
|
|
||||||
|
### Hybrid Signatures
|
||||||
|
|
||||||
|
Synor uses **hybrid signatures** combining:
|
||||||
|
|
||||||
|
1. **Ed25519** (64 bytes) - Classical elliptic curve
|
||||||
|
2. **Dilithium3/ML-DSA-65** (~3.3 KB) - Post-quantum lattice-based
|
||||||
|
|
||||||
|
Both signatures must verify for a transaction to be valid.
|
||||||
|
|
||||||
|
### Transaction Structure
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"previousTxId": "abc123...",
|
||||||
|
"outputIndex": 0,
|
||||||
|
"signature": "ed25519_sig_hex",
|
||||||
|
"hybridSignature": {
|
||||||
|
"ed25519": "64_bytes_hex",
|
||||||
|
"dilithium": "3293_bytes_hex"
|
||||||
|
},
|
||||||
|
"publicKey": "ed25519_pubkey_32_bytes",
|
||||||
|
"dilithiumPublicKey": "dilithium_pubkey_1952_bytes"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"address": "synor1recipient...",
|
||||||
|
"amount": "10000000000" // 100 SYNOR in somas
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"lockTime": 0,
|
||||||
|
"isHybrid": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Transaction Size
|
||||||
|
|
||||||
|
Due to Dilithium signatures, Synor transactions are larger than Bitcoin:
|
||||||
|
|
||||||
|
| Component | Size (bytes) |
|
||||||
|
|-----------|-------------|
|
||||||
|
| Base transaction | ~50 |
|
||||||
|
| Per input (hybrid) | ~5,500 |
|
||||||
|
| Per output | ~40 |
|
||||||
|
|
||||||
|
**Example:** 2 inputs, 2 outputs ≈ 11,180 bytes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## API Reference
|
||||||
|
|
||||||
|
### JSON-RPC Endpoint
|
||||||
|
|
||||||
|
- **HTTP:** `http://localhost:16110`
|
||||||
|
- **WebSocket:** `ws://localhost:16111`
|
||||||
|
|
||||||
|
### Common Methods
|
||||||
|
|
||||||
|
#### synor_getBlockCount
|
||||||
|
```json
|
||||||
|
{"jsonrpc":"2.0","method":"synor_getBlockCount","params":[],"id":1}
|
||||||
|
// Response: {"result": 1234567}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### synor_getBalance
|
||||||
|
```json
|
||||||
|
{"jsonrpc":"2.0","method":"synor_getBalance","params":["synor1..."],"id":1}
|
||||||
|
// Response: {"result": {"confirmed": "1000.50000000", "pending": "10.00000000"}}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### synor_getUtxos
|
||||||
|
```json
|
||||||
|
{"jsonrpc":"2.0","method":"synor_getUtxos","params":["synor1..."],"id":1}
|
||||||
|
// Response: {"result": [{"txId": "...", "outputIndex": 0, "amount": "100.00000000"}]}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### synor_sendRawTransaction
|
||||||
|
```json
|
||||||
|
{"jsonrpc":"2.0","method":"synor_sendRawTransaction","params":["serialized_tx"],"id":1}
|
||||||
|
// Response: {"result": {"txId": "abc123..."}}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### synor_getTransaction
|
||||||
|
```json
|
||||||
|
{"jsonrpc":"2.0","method":"synor_getTransaction","params":["txId"],"id":1}
|
||||||
|
// Response: {"result": {"txId": "...", "confirmations": 50, ...}}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### synor_getAddressTransactions
|
||||||
|
```json
|
||||||
|
{"jsonrpc":"2.0","method":"synor_getAddressTransactions","params":["synor1...", 100],"id":1}
|
||||||
|
// Response: {"result": [{"txId": "...", "type": "receive", ...}]}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Security Considerations
|
||||||
|
|
||||||
|
### Hot/Cold Wallet Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────┐
|
||||||
|
│ Cold Storage │
|
||||||
|
│ (Offline HSM) │
|
||||||
|
│ 95% of funds │
|
||||||
|
└────────┬────────┘
|
||||||
|
│ Manual
|
||||||
|
│ Transfer
|
||||||
|
┌────────▼────────┐
|
||||||
|
│ Warm Wallet │
|
||||||
|
│ (Limited online) │
|
||||||
|
│ 4% of funds │
|
||||||
|
└────────┬────────┘
|
||||||
|
│ Automated
|
||||||
|
│ Threshold
|
||||||
|
┌────────▼────────┐
|
||||||
|
│ Hot Wallet │
|
||||||
|
│ (Always online) │
|
||||||
|
│ 1% of funds │
|
||||||
|
└─────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### Recommended Security Measures
|
||||||
|
|
||||||
|
1. **Multi-signature wallets** for hot wallet (2-of-3 minimum)
|
||||||
|
2. **Rate limiting** on withdrawals (per-user and global)
|
||||||
|
3. **Withdrawal address whitelisting** with cool-down period
|
||||||
|
4. **Monitoring** for unusual patterns
|
||||||
|
5. **Key rotation** schedule (quarterly for hot wallet keys)
|
||||||
|
6. **Audit logging** of all wallet operations
|
||||||
|
|
||||||
|
### Post-Quantum Security
|
||||||
|
|
||||||
|
Synor's hybrid signature scheme provides:
|
||||||
|
|
||||||
|
- **Current security:** Ed25519 against classical attacks
|
||||||
|
- **Future security:** Dilithium3 against quantum attacks
|
||||||
|
- **Defense in depth:** Both must be compromised to forge signatures
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Test Environment
|
||||||
|
|
||||||
|
### Testnet Information
|
||||||
|
|
||||||
|
| Property | Value |
|
||||||
|
|----------|-------|
|
||||||
|
| Network Name | Synor Testnet |
|
||||||
|
| Address Prefix | `tsynor1` |
|
||||||
|
| RPC Endpoint | `https://testnet-rpc.synor.cc` |
|
||||||
|
| WebSocket | `wss://testnet-ws.synor.cc` |
|
||||||
|
| Faucet | `https://faucet.synor.cc` |
|
||||||
|
| Explorer | `https://testnet.explorer.synor.cc` |
|
||||||
|
|
||||||
|
### Getting Test Tokens
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Request testnet tokens via faucet API
|
||||||
|
curl -X POST https://faucet.synor.cc/request \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"address": "tsynor1your_testnet_address..."}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Running Local Testnet
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Clone repository
|
||||||
|
git clone https://github.com/synor/synor.git
|
||||||
|
cd synor
|
||||||
|
|
||||||
|
# Start local testnet with Docker
|
||||||
|
docker compose -f docker-compose.testnet.yml up -d
|
||||||
|
|
||||||
|
# Access local RPC
|
||||||
|
curl http://localhost:17110 ...
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
### Integration Support
|
||||||
|
|
||||||
|
- **Email:** integration@synor.cc
|
||||||
|
- **Telegram:** @SynorExchangeSupport
|
||||||
|
- **Documentation:** https://docs.synor.cc/exchange
|
||||||
|
|
||||||
|
### API Status
|
||||||
|
|
||||||
|
- **Status Page:** https://status.synor.cc
|
||||||
|
- **Maintenance Notifications:** Subscribe at status page
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
|
||||||
|
| Version | Date | Changes |
|
||||||
|
|---------|------|---------|
|
||||||
|
| 1.0 | 2026-01 | Initial release |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Last updated: January 2026*
|
||||||
Loading…
Add table
Reference in a new issue