Skip to content

Address Management

Comprehensive guide to managing blockchain addresses in PayIn's address pool system.

Overview

PayIn's Address Pool is a sophisticated address management system that pre-generates and dynamically allocates blockchain addresses for payment processing. This approach enables:

  • Instant Address Assignment: No need to generate addresses on-demand
  • Address Reusability: Efficient recycling with cooldown protection
  • Multi-Chain Support: Unified management across EVM, Tron, and Solana
  • Security: Proper key management and address isolation
  • Scalability: Handle high-volume payment operations

Why Address Pool?

Traditional payment systems generate addresses on-demand, causing delays. PayIn's address pool pre-generates addresses, enabling instant payment address assignment and improving user experience.

Address Pool Concept

How It Works

┌─────────────────────────────────────────────────────────────┐
│                      Address Pool System                    │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌──────────────┐  Allocate  ┌──────────────┐             │
│  │  Available   │  ────────→  │  Allocated   │             │
│  │  Addresses   │             │  (Order)     │             │
│  │              │             │              │             │
│  │  1000 addrs  │  ←────────  │  50 addrs    │             │
│  └──────────────┘   Release   └──────────────┘             │
│        ↑                                                    │
│        │                                                    │
│        │ After cooldown                                     │
│        │                                                    │
│  ┌──────────────┐             ┌──────────────┐             │
│  │  Cooldown    │             │    Bound     │             │
│  │  (30 min)    │             │  (Deposit)   │             │
│  │              │             │              │             │
│  │  100 addrs   │             │  200 addrs   │             │
│  └──────────────┘             └──────────────┘             │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Key Concepts:

  1. Pre-Generation: Addresses are generated in bulk before being needed
  2. Dynamic Allocation: Addresses are assigned on-demand from the pool
  3. State Management: Addresses transition through defined states
  4. Automatic Recycling: Order addresses return to the pool after completion
  5. Cooldown Protection: Prevents immediate reuse for privacy and security

Address States

PayIn manages addresses through four states:

StateDescriptionUsed ForReturns to Pool
availableReady for allocationWaiting in poolN/A
allocatedTemporarily assignedActive ordersYes (after completion)
boundPermanently assignedUser depositsOptional (manual unbind)
cooldownRecently releasedTemporary holdYes (after 30 min)
State Transition Diagram
               allocate                complete/expire
  available  ─────────→  allocated  ──────────────→  cooldown
      ↑                                                   │
      │                                                   │
      └───────────────── after 30 min ────────────────────┘

               bind                      unbind
  available  ─────────→   bound    ─────────────→  cooldown
      ↑                                                   │
      │                                                   │
      └───────────────── after 30 min ────────────────────┘

Why Cooldown Matters

Cooldown Period (default: 30 minutes) provides:

  1. Privacy Protection: Prevents linking different orders to the same address immediately
  2. Settlement Window: Allows time for blockchain finalization
  3. User Confidence: Avoids confusion from address reuse
  4. Monitoring Cleanup: Ensures monitoring tasks complete properly

Configurable Cooldown

The cooldown period can be adjusted per organization via the address_pool.cooldown_minutes configuration parameter.

Address Management Modes

PayIn supports two address management approaches to fit different security models and operational preferences.

Comparison Table

FeatureHD Wallet ModeSelf-Managed Mode
Key ManagementUser controls mnemonicUser controls private keys
Address GenerationPayIn CLI toolUser's own tools
TraceabilityFull (derivation index)Limited
BackupSingle mnemonicEach key separately
ToolingPayIn provides toolsUser provides tools
Recommended ForMost usersAdvanced users
Security ResponsibilityUser (mnemonic)User (all keys)

Recommendation

We strongly recommend HD Wallet Mode for most use cases. It provides better traceability, easier backup, and full tooling support from PayIn.

HD Wallet Mode uses BIP44 hierarchical deterministic wallet standard to derive addresses from a single master seed (mnemonic phrase).

Advantages:

  • Single Backup: One 12/24-word mnemonic backs up unlimited addresses
  • Deterministic: Can regenerate any address with mnemonic + derivation index
  • Full Traceability: Track which addresses belong to your wallet
  • PayIn Tooling: Complete CLI tool support for generation and verification
  • Standards-Based: Uses industry-standard BIP44 paths

How It Works:

  1. Generate a BIP39 mnemonic phrase (12 or 24 words)
  2. Use PayIn Address Tool to derive addresses from the mnemonic
  3. Export addresses to CSV (includes derivation index)
  4. Import CSV to PayIn via Admin UI
  5. PayIn assigns addresses from the pool

Derivation Paths:

EVM Chains:    m/44'/60'/0'/0/{index}   (Ethereum, Polygon, etc.)
Tron Chain:    m/44'/195'/0'/0/{index}
Solana Chain:  m/44'/501'/{index}'/0'   (Hardened derivation)

Solana Limitations

Solana uses Ed25519 cryptography with hardened derivation (SLIP-0010), which means:

  • ❌ Cannot derive child addresses from master public key
  • ✅ Address generation requires full mnemonic
  • ✅ Addresses are still tracked via derivation index
  • ✅ Fully compatible with PayIn's address pool

This is a fundamental cryptographic property of Ed25519, not a limitation of PayIn.

Self-Managed Mode

Self-Managed Mode allows you to import addresses generated by your own tools or wallets.

Advantages:

  • Full Control: Use your preferred wallet software
  • Flexibility: Import addresses from any source
  • Custom Workflows: Integrate with existing key management
  • No Derivation: Not tied to any specific derivation scheme

Considerations:

  • ⚠️ Manual Backup: Must backup each address/key separately
  • ⚠️ Limited Traceability: PayIn doesn't know address relationships
  • ⚠️ Your Responsibility: Must ensure addresses are valid and secure

How It Works:

  1. Generate addresses using your wallet software
  2. Export to CSV format
  3. Import CSV to PayIn via Admin UI or API
  4. PayIn assigns addresses from the pool

CSV Format:

csv
address,protocol,derivation_index,master_public_key
0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0,evm,,
TYASr5UV6HEcXatwdFQfmLVUqQQQMUxHLS,tron,,

Optional Fields

For self-managed addresses, derivation_index and master_public_key are optional. Leave them empty if not applicable.

HD Wallet Address Generation

This section covers the complete workflow for generating addresses in HD Wallet Mode using PayIn's official tools.

Prerequisites

  1. Secure Environment: Use an offline computer or air-gapped system for maximum security
  2. Node.js: Version 18 or higher
  3. PayIn Address Tool: Official CLI tool
  4. Secure Storage: Physical location for mnemonic backup (safe, vault, etc.)

Step 1: Install Address Tool

bash
# Navigate to PayIn repository
cd payin/apps/address-tool

# Install dependencies
npm install

# Build the tool
npm run build

Global Installation

For easier access, you can install globally:

bash
npm install -g @payin/address-tool

Then run with: payin-address-tool

Step 2: Generate Mnemonic

Start the tool and choose to generate a new mnemonic:

bash
npm start

Interactive Flow:

? Select an action: Generate New Addresses
? Select protocol: EVM (Ethereum, Polygon, etc.)
? Do you have an existing mnemonic? No, generate new mnemonic

🔐 Your Mnemonic Phrase (WRITE THIS DOWN IMMEDIATELY!):

    witch collapse practice feed shame open despair creek road again ice least

⚠️  WARNING:
   - Write down this mnemonic on paper
   - Store it in a secure, offline location
   - Anyone with this phrase can access your funds
   - This tool does NOT save it for you

? Have you written down the mnemonic? (yes/no): yes

Security Checklist:

  • ✅ Write mnemonic on paper (not digitally)
  • ✅ Double-check each word is correct
  • ✅ Store in secure location (safe, safety deposit box)
  • ✅ Consider creating multiple backups in separate locations
  • ❌ NEVER save to computer, phone, or cloud storage
  • ❌ NEVER take a photo of the mnemonic
  • ❌ NEVER share with anyone

Step 3: Generate Addresses

Configure address generation parameters:

? Starting derivation index: 0
? How many addresses to generate: 1000

Generating addresses...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% | 1000/1000

✅ Generated 1000 addresses successfully!

Protocol: evm
Derivation Path: m/44'/60'/0'/0/{index}
Range: 0 - 999

Generation Tips:

  • Batch Size: Generate 1000-5000 addresses per batch
  • Starting Index: Use 0 for first batch, then 1000, 2000, etc.
  • Multiple Protocols: Generate separately for EVM, Tron, and Solana

Step 4: Export to CSV

? Export to CSV? Yes
? Output file name: evm-addresses-2025-01-20

Exporting to CSV...
✅ Exported to: output/evm-addresses-2025-01-20-full.csv

CSV Format: Full (HD Wallet Mode)
Columns: address, derivation_index, protocol, master_public_key
Rows: 1000

CSV Content Example:

csv
address,derivation_index,protocol,master_public_key
0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0,0,evm,xpub6CUGRUonZSQ4TWUJKy...
0x5AEDA56215b167893e80B4fE645BA6d5Bab767DE,1,evm,xpub6CUGRUonZSQ4TWUJKy...
0x9FF4e4b8a0451F7c8F7a1D8c1C6b5C2d3E4f5A6B,2,evm,xpub6CUGRUonZSQ4TWUJKy...

CSV File Security

The CSV file contains your extended public key (xpub), which allows anyone to:

  • View all your addresses
  • Track your payment history
  • Derive future addresses (EVM/Tron only)

Do NOT:

  • Share CSV files publicly
  • Upload to untrusted systems
  • Commit to version control

Store CSV files securely and only upload to trusted PayIn instances.

Step 5: Verify Addresses (Optional)

Verify that an address belongs to your wallet:

bash
npm start
? Select an action: Verify Address Ownership
? Select protocol: EVM
? Do you have an existing mnemonic? Yes, use existing

? Enter your mnemonic phrase: [enter your 12/24 words]

? Enter address to verify: 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0
? Search range (max derivation index): 1000

Searching for address...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100%

✅ ADDRESS FOUND!

Address: 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0
Derivation Index: 0
Derivation Path: m/44'/60'/0'/0/0

Verification Use Cases:

  • Confirm an address belongs to your wallet
  • Find the derivation index of a known address
  • Audit imported addresses
  • Recover address information

Importing Addresses to PayIn

After generating addresses, import them into PayIn's address pool via the Admin UI or API.

The Admin UI provides a user-friendly interface for importing addresses with validation.

Step-by-Step:

  1. Login to PayIn Admin

  2. Navigate to Address Pool

    • Click "Address Pool" in the sidebar
    • You'll see current pool statistics
  3. Start Import

    • Click "Import Addresses" button
    • Import dialog opens
  4. Select Import Mode

    ○ HD Wallet Import (Recommended)
    ○ Self-Managed Import
    • Choose HD Wallet Import if your CSV includes derivation_index and master_public_key
    • Choose Self-Managed Import for addresses from external wallets
  5. Upload CSV File

    • Click "Choose File" or drag-and-drop
    • Select your exported CSV file
    • Wait for file validation
  6. Review and Confirm

    Import Summary:
    - Protocol: EVM
    - Total Addresses: 1000
    - Derivation Range: 0 - 999
    - Master Public Key: xpub6CUG...
    
    ✓ All addresses are valid
    ✓ No duplicates found
    ✓ Format validation passed
  7. Start Import

    • Click "Import"
    • Progress bar shows import status
    • Receive confirmation when complete

Duplicate Handling

PayIn automatically skips duplicate addresses during import. If an address already exists in the pool, it won't be imported again.

Import via API

For automation or programmatic imports, use the Address Pool API.

Endpoint: POST /api/v1/address-pool/import

Authentication: Requires API Key with admin or owner role

Request:

typescript
import fs from 'fs';

const csvContent = fs.readFileSync('evm-addresses-2025-01-20-full.csv', 'utf8');

const response = await fetch('https://testnet.payin.com/api/v1/address-pool/import', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${process.env.PAYIN_API_KEY}`
  },
  body: JSON.stringify({
    protocol: 'evm',
    mode: 'hd_wallet', // or 'self_managed'
    addresses: csvContent
  })
});

const result = await response.json();
console.log('Import result:', result);

Response:

json
{
  "success": true,
  "imported": 1000,
  "skipped": 0,
  "errors": [],
  "summary": {
    "protocol": "evm",
    "mode": "hd_wallet",
    "derivation_range": {
      "start": 0,
      "end": 999
    },
    "master_public_key": "xpub6CUGRUonZSQ4TWUJKy..."
  }
}

Error Response (400 Bad Request):

json
{
  "success": false,
  "error": "Validation failed",
  "details": [
    {
      "line": 42,
      "address": "0xinvalid",
      "error": "Invalid EVM address format"
    }
  ]
}

Python Example:

python
import requests

with open('evm-addresses-2025-01-20-full.csv', 'r') as f:
    csv_content = f.read()

response = requests.post(
    'https://testnet.payin.com/api/v1/address-pool/import',
    headers={
        'Content-Type': 'application/json',
        'Authorization': f'Bearer {os.getenv("PAYIN_API_KEY")}'
    },
    json={
        'protocol': 'evm',
        'mode': 'hd_wallet',
        'addresses': csv_content
    }
)

result = response.json()
print(f"Imported: {result['imported']} addresses")

Batch Import Strategy

For large address pools (10,000+ addresses), use batch imports:

Strategy:

  1. Generate in Batches: Create CSV files with 1000-5000 addresses each
  2. Sequential Import: Import batches sequentially to avoid timeout
  3. Verify After Each: Check pool statistics after each batch
  4. Track Progress: Maintain a log of imported batches

Example Batch Workflow:

bash
# Batch 1: Addresses 0-999
npm start
# Generate: start=0, count=1000
# Export: evm-batch-1.csv

# Batch 2: Addresses 1000-1999
npm start
# Generate: start=1000, count=1000
# Export: evm-batch-2.csv

# Batch 3: Addresses 2000-2999
npm start
# Generate: start=2000, count=1000
# Export: evm-batch-3.csv

# Import each batch via Admin UI

Address Lifecycle Management

Understanding how addresses move through different states helps you manage the pool effectively.

Order Payment Lifecycle

Scenario: User creates an order to pay 100 USDT

Step 1: Order Creation
─────────────────────────────────────────────────────────────
POST /api/v1/orders
{
  "orderReference": "ORDER-2025-001",
  "amount": "100",
  "currency": "USDT",
  "chainId": "ethereum-sepolia"
}

↓ PayIn allocates address from pool

Response:
{
  "orderId": "ord_abc123",
  "paymentAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0",
  "status": "pending"
}

Address State: available → allocated
Step 2: User Pays
─────────────────────────────────────────────────────────────
User sends 100 USDT to 0x742d35...

↓ PayIn monitor detects transaction
↓ Waits for confirmations (default: 3 blocks)
↓ Order completes

Webhook Event: order.completed

Address State: allocated (still held)
Step 3: Address Release
─────────────────────────────────────────────────────────────
After order completion, PayIn automatically:
1. Releases address from order
2. Sets cooldown period (30 minutes)
3. Address enters cooldown state

Address State: allocated → cooldown
Step 4: Return to Pool
─────────────────────────────────────────────────────────────
After cooldown expires (30 minutes):
- Address becomes available again
- Can be allocated to new orders
- Prioritized by LRU (least recently used)

Address State: cooldown → available

Timeline:

Order Created ────→ Payment Sent ────→ Order Completed ────→ Cooldown Expires
     ↓                    ↓                    ↓                     ↓
  allocated          allocated             cooldown              available
     0s               ~3 min              ~3 min 30s            ~33 min 30s

Deposit Address Lifecycle

Scenario: User wants a permanent deposit address

Step 1: Address Binding
─────────────────────────────────────────────────────────────
POST /api/v1/deposits/references
{
  "depositReference": "user_alice_123",
  "currency": "USDT",
  "chainId": "polygon-amoy"
}

↓ PayIn allocates and binds address

Response:
{
  "depositReference": "user_alice_123",
  "address": "0x9FF4e4b8a0451F7c8F7a1D8c1C6b5C2d3E4f5A6B",
  "protocol": "evm"
}

Address State: available → bound
Step 2: Multiple Deposits
─────────────────────────────────────────────────────────────
User can deposit multiple times to the same address:

Deposit 1: 50 USDT  → Creates deposit record
Deposit 2: 100 USDT → Creates another deposit record
Deposit 3: 25 USDT  → Creates another deposit record

Each deposit:
- Triggers webhook: deposit.pending → deposit.confirmed
- Records amount and transaction
- Address remains bound

Address State: bound (permanent)
Step 3: Address Unbinding (Optional)
─────────────────────────────────────────────────────────────
If user closes account or stops using service:

DELETE /api/v1/deposits/references/user_alice_123

↓ PayIn unbinds address
↓ Sets cooldown period (30 minutes)

Address State: bound → cooldown → available

Timeline:

Binding ────→ Deposit 1 ────→ Deposit 2 ────→ ... ────→ Unbind ────→ Cooldown ────→ Available
   ↓             ↓                ↓                           ↓            ↓              ↓
 bound         bound            bound                     cooldown      cooldown      available
   0s           Hours           Days                       ~0s         ~30 min        ~30 min

LRU Allocation Strategy

PayIn uses Least Recently Used (LRU) algorithm to allocate addresses efficiently.

Allocation Priority:

sql
-- 1. NEW ADDRESSES (never used)
WHERE recycled_at IS NULL
ORDER BY created_at ASC

-- 2. RECYCLED ADDRESSES (used before, cooled down)
WHERE recycled_at IS NOT NULL
  AND cooldown_until <= NOW()
ORDER BY recycled_at ASC

Why LRU?

  1. Fairness: All addresses get equal usage over time
  2. Privacy: Maximizes time between reuses
  3. Distribution: Prevents hot addresses
  4. Monitoring: Ensures old monitoring tasks clean up

Example Allocation Sequence:

Pool State:
- Address A: recycled_at = NULL (new)
- Address B: recycled_at = 2025-01-20 10:00 (used 2 hours ago)
- Address C: recycled_at = 2025-01-20 11:30 (used 30 min ago)
- Address D: recycled_at = NULL (new)

Allocation Order:
1. Address A (new address, created first)
2. Address D (new address, created second)
3. Address B (recycled, oldest)
4. Address C (recycled, newest)

Address Pool Monitoring

Monitor your address pool health to ensure smooth payment operations.

Pool Status API

Get real-time pool statistics:

Endpoint: GET /api/v1/address-pool/status

Request:

typescript
const response = await fetch('https://testnet.payin.com/api/v1/address-pool/status', {
  headers: {
    'Authorization': `Bearer ${process.env.PAYIN_API_KEY}`
  }
});

const status = await response.json();
console.log('Pool Status:', status);

Response:

json
{
  "evm": {
    "total": 5000,
    "available": 4200,
    "allocated": 500,
    "bound": 250,
    "coolingDown": 50
  },
  "tron": {
    "total": 2000,
    "available": 1800,
    "allocated": 150,
    "bound": 40,
    "coolingDown": 10
  },
  "solana": {
    "total": 1000,
    "available": 950,
    "allocated": 30,
    "bound": 15,
    "coolingDown": 5
  }
}

Admin UI Dashboard

The Admin UI provides visual pool monitoring:

  1. Navigate to Address Pool

    • See real-time statistics
    • View address allocation chart
  2. Pool Health Indicators

    EVM Address Pool                          ● Healthy
    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    Total:        5,000 addresses
    Available:    4,200 (84%)  ▓▓▓▓▓▓▓▓░░
    Allocated:      500 (10%)  ▓▓░░░░░░░░
    Bound:          250 ( 5%)  ▓░░░░░░░░░
    Cooldown:        50 ( 1%)  ░░░░░░░░░░
  3. Low Inventory Warning

    ⚠️ WARNING: Low Address Inventory
    
    EVM pool has only 120 available addresses (2.4%)
    
    Recommended actions:
    1. Generate more addresses immediately
    2. Import new batch to pool
    3. Review address allocation rate

Monitoring Metrics

Key Metrics to Track:

MetricDescriptionHealthy RangeAction Threshold
Available %Percentage of available addresses> 50%< 20%
Allocation RateAddresses allocated per hourVariesTrending up sharply
Cooldown %Percentage in cooldown< 5%> 10%
Bound GrowthRate of deposit bindingVariesUnexpected spike

Low Inventory Alerts

Configure alerts to notify you when pool inventory is low.

Admin UI Configuration:

  1. Navigate to Settings → Address Pool

  2. Set Alert Thresholds:

    Low Inventory Alert:
    ┌─────────────────────────────────┐
    │ EVM:    [200] addresses         │
    │ Tron:   [100] addresses         │
    │ Solana: [50]  addresses         │
    └─────────────────────────────────┘
    
    Notification Methods:
    ☑ Email
    ☑ Webhook
    ☐ SMS
  3. Test Alert:

    • Click "Send Test Alert"
    • Verify you receive notification

Email Alert Example:

Subject: [PayIn Alert] Low Address Pool Inventory

Dear PayIn User,

Your EVM address pool is running low:

Current Status:
- Available: 180 addresses (3.6%)
- Total Pool: 5,000 addresses
- Threshold: 200 addresses (4%)

Recommended Actions:
1. Generate 1,000+ new addresses using PayIn Address Tool
2. Import addresses via Admin UI
3. Review allocation patterns

View Details: https://testnet.payin.com/address-pool


PayIn Alert System

Webhook Alert Payload:

json
{
  "type": "alert.address_pool_low",
  "timestamp": "2025-01-20T15:30:00Z",
  "data": {
    "protocol": "evm",
    "available": 180,
    "total": 5000,
    "percentage": 3.6,
    "threshold": 200
  }
}

Proactive Pool Management

Best Practices:

  1. Monitor Daily: Check pool status at least once per day
  2. Maintain Buffer: Keep 50%+ addresses available
  3. Batch Generation: Generate 1000+ addresses per batch
  4. Predictive Scaling: Monitor allocation trends, add addresses proactively
  5. Protocol Balance: Ensure adequate addresses for each protocol

Monitoring Script Example:

typescript
// check-pool-health.ts
import { PayInClient } from '@payin/sdk';

const client = new PayInClient({
  apiKey: process.env.PAYIN_API_KEY,
  baseUrl: 'https://testnet.payin.com'
});

async function checkPoolHealth() {
  const status = await client.addressPool.getStatus();

  for (const [protocol, stats] of Object.entries(status)) {
    const availablePercent = (stats.available / stats.total) * 100;

    if (availablePercent < 20) {
      console.error(`❌ CRITICAL: ${protocol} pool at ${availablePercent.toFixed(1)}%`);
      // Send alert
    } else if (availablePercent < 50) {
      console.warn(`⚠️  WARNING: ${protocol} pool at ${availablePercent.toFixed(1)}%`);
      // Consider generating more
    } else {
      console.log(`✅ OK: ${protocol} pool at ${availablePercent.toFixed(1)}%`);
    }
  }
}

// Run every hour
setInterval(checkPoolHealth, 60 * 60 * 1000);
checkPoolHealth();

Cron Job Setup:

bash
# Add to crontab (runs every 4 hours)
0 */4 * * * cd /path/to/scripts && node check-pool-health.js

Self-Managed Address Import

For users who prefer to manage their own keys and addresses outside of the HD wallet system.

Preparing Self-Managed Addresses

Step 1: Generate Addresses

Use your preferred wallet software:

bash
# Using ethers.js (EVM)
import { Wallet } from 'ethers';

const addresses = [];
for (let i = 0; i < 1000; i++) {
  const wallet = Wallet.createRandom();
  addresses.push({
    address: wallet.address,
    privateKey: wallet.privateKey // Store securely, don't include in CSV!
  });
}

# Save private keys securely (encrypted file, hardware wallet, etc.)
# Export only addresses to CSV
bash
# Using TronWeb (Tron)
import TronWeb from 'tronweb';

const addresses = [];
for (let i = 0; i < 1000; i++) {
  const account = await TronWeb.createAccount();
  addresses.push({
    address: account.address.base58,
    privateKey: account.privateKey // Store securely!
  });
}

Step 2: Create CSV File

Format for self-managed addresses:

csv
address,protocol,derivation_index,master_public_key
0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0,evm,,
0x5AEDA56215b167893e80B4fE645BA6d5Bab767DE,evm,,
0x9FF4e4b8a0451F7c8F7a1D8c1C6b5C2d3E4f5A6B,evm,,
TYASr5UV6HEcXatwdFQfmLVUqQQQMUxHLS,tron,,
TPJRnELdwXLWVvokPJyT3CHPF4YPKVkrSU,tron,,

Key Points:

  • Leave derivation_index and master_public_key empty
  • Include only public addresses (never private keys!)
  • One address per line
  • Protocol must be evm, tron, or solana

Step 3: Validate Addresses

Before import, validate addresses locally:

typescript
// validate-addresses.ts
import { isAddress } from 'ethers';
import fs from 'fs';
import csv from 'csv-parse/sync';

const content = fs.readFileSync('self-managed-addresses.csv', 'utf8');
const records = csv.parse(content, { columns: true });

let errors = 0;
for (const [index, record] of records.entries()) {
  if (record.protocol === 'evm' && !isAddress(record.address)) {
    console.error(`Line ${index + 2}: Invalid EVM address: ${record.address}`);
    errors++;
  }
  // Add validation for Tron and Solana addresses
}

if (errors === 0) {
  console.log('✅ All addresses are valid');
} else {
  console.error(`❌ Found ${errors} invalid addresses`);
  process.exit(1);
}

Import Process

Via Admin UI:

  1. Navigate to Address Pool → Import Addresses
  2. Select "Self-Managed Import"
  3. Upload CSV file
  4. Review import summary
  5. Confirm import

Via API:

typescript
const csvContent = fs.readFileSync('self-managed-addresses.csv', 'utf8');

const response = await fetch('https://testnet.payin.com/api/v1/address-pool/import', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${process.env.PAYIN_API_KEY}`
  },
  body: JSON.stringify({
    protocol: 'evm',
    mode: 'self_managed',
    addresses: csvContent
  })
});

const result = await response.json();
console.log(`Imported ${result.imported} self-managed addresses`);

Security Considerations

Self-Managed Mode Responsibilities:

  1. Private Key Management

    • Store private keys securely (hardware wallet, encrypted storage)
    • Never include private keys in CSV imports
    • Implement key rotation strategy
    • Backup keys in multiple secure locations
  2. Address Tracking

    • Maintain your own mapping of addresses to keys
    • Document address generation method
    • Track which addresses are imported to PayIn
  3. Recovery Planning

    • Document key recovery procedures
    • Test recovery process regularly
    • Ensure successors can access keys if needed

Critical: Private Key Security

PayIn NEVER asks for or stores your private keys. If someone asks for your private keys claiming to be from PayIn, it's a scam. Only import public addresses to PayIn.

Best Practices

For HD Wallet Mode

Security Best Practices:

  1. Mnemonic Storage

    • ✅ Write on paper, store in safe/vault
    • ✅ Create multiple backups in separate locations
    • ✅ Use metal backup plates for fire/water resistance
    • ✅ Consider Shamir's Secret Sharing for enterprise
    • ❌ Never store digitally (computer, phone, cloud)
    • ❌ Never take photos
    • ❌ Never share with anyone
  2. Generation Environment

    • ✅ Use offline/air-gapped computer for generation
    • ✅ Verify tool integrity (checksum, signature)
    • ✅ Disconnect network during generation
    • ❌ Don't generate on shared/public computers
  3. Verification

    • ✅ Verify first few addresses after import
    • ✅ Test small payment before production use
    • ✅ Document derivation paths used

Operational Best Practices:

  1. Batch Management

    • Generate addresses in batches (1000-5000)
    • Track derivation ranges (0-999, 1000-1999, etc.)
    • Document batch imports with dates
    • Maintain batch generation logs
  2. Pool Sizing

    • Maintain 50%+ available addresses
    • Generate new batches proactively
    • Monitor allocation rate trends
    • Scale before running low
  3. Traceability

    • Keep records of all imports (batch files, dates)
    • Document master public keys
    • Track derivation index ranges
    • Audit pool regularly

For Self-Managed Mode

Key Management:

  1. Private Key Security

    • Use hardware wallets when possible
    • Encrypt private key storage
    • Implement access controls
    • Regular security audits
  2. Address Generation

    • Use reputable wallet software
    • Verify address formats before import
    • Check for duplicates
    • Document generation method
  3. Backup Strategy

    • Multiple secure backups
    • Geographic distribution
    • Regular backup verification
    • Documented recovery procedures

Import Best Practices:

  1. Validation

    • Validate all addresses before import
    • Check for format errors
    • Verify no duplicates
    • Test small batch first
  2. Documentation

    • Maintain address-to-key mapping
    • Document import dates and batches
    • Track which addresses are in PayIn
    • Record any address rotation

General Best Practices

Pool Management:

  1. Monitoring

    • Check pool status daily
    • Set up low inventory alerts
    • Monitor allocation patterns
    • Track cooldown rates
  2. Maintenance

    • Regular pool audits
    • Review address states
    • Clean up stale bindings
    • Update cooldown configuration as needed
  3. Scaling

    • Monitor business growth
    • Scale proactively
    • Plan for peak periods
    • Maintain adequate buffer

Security:

  1. Access Control

    • Limit who can import addresses
    • Use API keys with appropriate permissions
    • Audit import activities
    • Monitor unauthorized access attempts
  2. Address Privacy

    • Don't reuse addresses unnecessarily
    • Respect cooldown periods
    • Consider unbinding unused deposit addresses
    • Rotate address pools periodically

Operational:

  1. Testing

    • Test address allocation on testnet first
    • Verify import process works correctly
    • Test pool exhaustion scenarios
    • Practice emergency procedures
  2. Documentation

    • Document your address management process
    • Keep import logs
    • Maintain runbooks for common tasks
    • Train team members

Security Considerations

Mnemonic Security

Critical: Your mnemonic phrase is the master key to all addresses generated from it.

Threat Model:

ThreatImpactMitigation
Physical TheftAttacker gains full accessMultiple secure locations, split storage
Digital ExposureMalware/hacking accessNever store digitally, offline generation
Social EngineeringTricked into revealingEducation, verification procedures
Loss/DestructionPermanent loss of accessMultiple backups, metal plates

Defense in Depth:

Layer 1: Offline Generation
- Generate on air-gapped computer
- Use verified, open-source tools
- Disconnect network during generation

Layer 2: Physical Security
- Store in safe/vault
- Multiple geographic locations
- Fire/water resistant containers

Layer 3: Access Control
- Limit who knows where mnemonic is stored
- Multi-person access requirements (for enterprises)
- Regular security reviews

Layer 4: Backup Strategy
- Multiple copies
- Different formats (paper, metal)
- Different locations
- Regular verification

Address Validation

Import Validation:

PayIn performs comprehensive validation during address import:

  1. Format Validation

    • EVM: Checksummed address format (0x + 40 hex chars)
    • Tron: Base58 format starting with 'T'
    • Solana: Base58 format (32-44 chars)
  2. Duplicate Detection

    • Checks against existing pool addresses
    • Prevents duplicate imports
    • Validates within CSV file
  3. Protocol Consistency

    • Ensures address matches specified protocol
    • Detects format mismatches
    • Validates derivation data consistency

Blacklist Checking:

Future Feature

PayIn is planning to add support for address blacklist checking against known malicious addresses. This will help prevent importing compromised addresses.

For now, implement your own blacklist checking:

typescript
// check-blacklist.ts
import fs from 'fs';
import csv from 'csv-parse/sync';

// Load blacklist from public sources
const blacklist = new Set([
  '0x...',  // Known scam addresses
  // Add more
]);

const addresses = csv.parse(
  fs.readFileSync('addresses.csv', 'utf8'),
  { columns: true }
);

for (const record of addresses) {
  if (blacklist.has(record.address.toLowerCase())) {
    console.error(`❌ Blacklisted address found: ${record.address}`);
    process.exit(1);
  }
}

console.log('✅ No blacklisted addresses found');

Import Verification

After importing addresses, verify the import was successful:

Verification Steps:

  1. Check Pool Statistics

    typescript
    const status = await client.addressPool.getStatus();
    console.log(`Total EVM addresses: ${status.evm.total}`);
    // Should match expected count
  2. Spot Check Addresses

    typescript
    // Verify random addresses from your import exist in pool
    const response = await client.addressPool.listAddresses({
      protocol: 'evm',
      page: 1,
      pageSize: 10
    });
    
    // Check if addresses from your CSV appear
  3. Test Allocation

    typescript
    // Create a test order to verify allocation works
    const order = await client.orders.create({
      orderReference: 'TEST-VERIFICATION',
      amount: '1',
      currency: 'USDT',
      chainId: 'ethereum-sepolia'
    });
    
    // Verify allocated address is from your imported set
    console.log(`Allocated address: ${order.paymentAddress}`);

Audit Logging

PayIn maintains comprehensive audit logs for address pool operations:

Logged Events:

  • Address imports (who, when, how many)
  • Address allocations (order/deposit)
  • Address releases
  • Address bindings/unbindings
  • Pool configuration changes

Accessing Audit Logs:

typescript
const logs = await client.addressPool.getAuditLogs({
  startDate: '2025-01-20',
  endDate: '2025-01-21',
  eventType: 'import'
});

for (const log of logs.entries) {
  console.log(`${log.timestamp}: ${log.eventType} by ${log.user} - ${log.count} addresses`);
}

Troubleshooting

Common Issues

1. Import Failed: "Invalid address format"

Cause: Address doesn't match the expected format for the protocol.

Solution:

bash
# Validate EVM addresses
import { isAddress } from 'ethers';
console.log(isAddress('0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0')); // true

# Ensure addresses are checksummed
import { getAddress } from 'ethers';
const checksummed = getAddress('0x742d35cc6634c0532925a3b844bc9e7595f0beb0');
console.log(checksummed); // 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb0

2. Import Failed: "Duplicate addresses found"

Cause: Addresses already exist in the pool or appear multiple times in CSV.

Solution:

typescript
// Check for duplicates in CSV
const addresses = records.map(r => r.address.toLowerCase());
const unique = new Set(addresses);
if (addresses.length !== unique.size) {
  console.error('CSV contains duplicate addresses');
}

// Check against existing pool
const existing = await client.addressPool.checkAddresses(addresses);
console.log(`${existing.duplicates.length} addresses already in pool`);

3. "No available addresses in pool"

Cause: All addresses are allocated, bound, or in cooldown.

Solution:

  1. Check Pool Status:

    typescript
    const status = await client.addressPool.getStatus();
    console.log(status);
  2. Generate and Import More Addresses (immediate fix)

  3. Review Allocation Pattern (long-term fix):

    • Are orders expiring properly?
    • Are addresses being released?
    • Is cooldown period too long?
    • Is allocation rate higher than expected?

4. Address Tool: "Invalid mnemonic phrase"

Cause: Mnemonic has typos, wrong word count, or invalid words.

Solution:

bash
# Verify mnemonic word count (12 or 24)
echo "your mnemonic words here" | wc -w

# Check for typos in words (use BIP39 word list)

# Common mistakes:
# - Extra spaces between words
# - Wrong word order
# - Words not in BIP39 list

5. Verification: "Address not found in wallet"

Cause: Address doesn't belong to the mnemonic, or search range is too small.

Solution:

bash
# Increase search range
? Search range: 5000  # Instead of default 1000

# Verify you're using correct:
# - Mnemonic phrase
# - Protocol (EVM vs Tron vs Solana)
# - Derivation path

6. Low Pool Performance

Cause: Too many addresses in cooldown, frequent allocation/release cycles.

Solution:

  1. Increase Pool Size: More addresses = better performance
  2. Adjust Cooldown: Reduce if not needed for your use case
    typescript
    await client.config.update({
      'address_pool.cooldown_minutes': 15  // Reduce from 30 to 15
    });
  3. Review Allocation Strategy: Are you creating too many short-lived orders?

Getting Help

If you encounter issues not covered here:

  1. Check API Logs:

    • Review error responses
    • Check HTTP status codes
    • Look for detailed error messages
  2. Admin UI Diagnostics:

    • Navigate to Address Pool
    • Check "Pool Health" tab
    • Review recent activity logs
  3. Contact Support:

    • Email: support@payin.com
    • Include: pool statistics, error messages, CSV sample
    • Specify: protocol, import mode, environment (testnet/mainnet)
  4. Community:

Next Steps

Now that you understand address management, explore these related topics:

Essential Reading

API References

Advanced Topics

Tools

Summary

Key Takeaways:

Address Pool enables instant payment address assignment and efficient reuse

HD Wallet Mode (recommended) uses BIP44 standard with full tooling support

Self-Managed Mode provides flexibility for advanced users

LRU Allocation ensures fair distribution and privacy protection

Cooldown Period (30 min) protects privacy and allows settlement

Monitoring is critical - maintain 50%+ available addresses

Security requires proper mnemonic storage and validation

Quick Reference:

TaskTool/MethodTime Required
Generate 1000 addressesPayIn Address Tool~2 minutes
Import addressesAdmin UI or API~1 minute
Check pool statusAdmin UI or APIInstant
Allocate addressAutomatic (API call)< 100ms
Release addressAutomatic (order completion)< 100ms

Production Checklist:

  • [ ] Mnemonic generated and securely stored (multiple backups)
  • [ ] Addresses generated for all needed protocols (EVM, Tron, Solana)
  • [ ] Addresses imported to PayIn (verified via pool status)
  • [ ] Low inventory alerts configured
  • [ ] Pool monitoring set up (daily checks or automated)
  • [ ] Team trained on address generation process
  • [ ] Emergency procedures documented
  • [ ] Backup generation capability established

You're now ready to manage addresses efficiently for your PayIn payment infrastructure!

Released under the MIT License.