Exchanger Limits and Verification System

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1 servicesAll 1306 services
Exchanger Limits and Verification System
Medium
~3-5 business days
FAQ
Blockchain Development Services
Blockchain Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1214
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    823

Exchanger Limits and Verification System Development

A limits system is not just numbers in a database. It is a compliance tool that balances between usability (user wants to exchange immediately) and regulatory requirements (AML requires knowing the client at amounts above threshold). Proper limits architecture reduces KYC abandonment and remains compliant.

Limit Structure by Verification Level

interface LimitTier {
  daily: number;      // USD equivalent
  monthly: number;
  perTransaction: number;
  fiatsAllowed: boolean;
  cryptoWithdrawalLimit: number;
  requiresKYC: KYCLevel;
}

const LIMIT_TIERS: Record<string, LimitTier> = {
  ANONYMOUS: {
    daily: 500,
    monthly: 1000,
    perTransaction: 500,
    fiatsAllowed: false,
    cryptoWithdrawalLimit: 500,
    requiresKYC: KYCLevel.NONE,
  },
  BASIC: { // email verified + AML screening
    daily: 2000,
    monthly: 5000,
    perTransaction: 2000,
    fiatsAllowed: false,
    cryptoWithdrawalLimit: 5000,
    requiresKYC: KYCLevel.EMAIL,
  },
  VERIFIED: { // full KYC
    daily: 50000,
    monthly: 200000,
    perTransaction: 25000,
    fiatsAllowed: true,
    cryptoWithdrawalLimit: -1, // unlimited
    requiresKYC: KYCLevel.FULL,
  },
};

Rolling Window Limits

Fixed daily windows (00:00-23:59) create bad UX: user cannot exchange at 23:50 what was planned because limit resets in 10 minutes. Rolling window is better:

class LimitChecker {
  async checkAndConsumeLimits(
    userId: string,
    amount: number,
    currency: string
  ): Promise<LimitCheckResult> {
    const tier = await this.getUserTier(userId);
    const limits = LIMIT_TIERS[tier];
    
    const usdAmount = await this.toUSD(amount, currency);
    
    // Single transaction check
    if (usdAmount > limits.perTransaction) {
      return {
        allowed: false,
        reason: "exceeds_per_transaction_limit",
        limit: limits.perTransaction,
        upgradeRequired: tier !== "VERIFIED",
      };
    }
    
    // Rolling 24h window
    const usage24h = await this.getUsage(userId, 24 * 60 * 60 * 1000);
    if (usage24h + usdAmount > limits.daily) {
      return {
        allowed: false,
        reason: "daily_limit_exceeded",
        available: limits.daily - usage24h,
        resetsIn: await this.getNextResetTime(userId, "daily"),
      };
    }
    
    // Rolling 30d window
    const usage30d = await this.getUsage(userId, 30 * 24 * 60 * 60 * 1000);
    if (usage30d + usdAmount > limits.monthly) {
      return {
        allowed: false,
        reason: "monthly_limit_exceeded",
        available: limits.monthly - usage30d,
      };
    }
    
    // If all ok — reserve (idempotency via Redis)
    await this.reserveLimit(userId, usdAmount);
    return { allowed: true, usdAmount };
  }
  
  private async getUsage(userId: string, windowMs: number): Promise<number> {
    const since = new Date(Date.now() - windowMs);
    return this.db.sumTransactions(userId, since);
  }
}

AML Threshold Amounts and Automatic Checks

const AML_THRESHOLDS = {
  ENHANCED_SCREENING: 1000,    // USD — additional AML screening
  KYC_REQUIRED: 1000,          // requires basic KYC
  FULL_KYC_REQUIRED: 3000,     // requires full KYC
  SAR_REVIEW: 10000,           // manual review by compliance officer
  CTR_REPORT: 10000,           // Currency Transaction Report (in some jurisdictions)
};

async function preTransactionChecks(tx: ExchangeTransaction): Promise<CheckResult> {
  // Automatic requirement escalation when thresholds reached
  if (tx.usdAmount >= AML_THRESHOLDS.FULL_KYC_REQUIRED) {
    const kycStatus = await getKYCStatus(tx.userId);
    if (kycStatus < KYCLevel.FULL) {
      return {
        action: "REQUIRE_KYC",
        requiredLevel: KYCLevel.FULL,
        message: "For amounts above $3,000, verification is required",
      };
    }
  }
  
  // Screening at amounts above $1,000
  if (tx.usdAmount >= AML_THRESHOLDS.ENHANCED_SCREENING) {
    const screenResult = await screenWallet(tx.destinationAddress, tx.asset);
    if (screenResult.blocked) {
      return { action: "BLOCK", reason: screenResult.reason };
    }
  }
  
  return { action: "ALLOW" };
}

Source of Funds Verification

For amounts above enhanced due diligence threshold — Source of Funds form:

interface SourceOfFunds {
  source: "employment" | "business" | "investments" | "inheritance" | "other";
  description: string;
  estimatedMonthlyVolume: number;
  supportingDocuments: string[]; // IPFS hashes or S3 URLs
}

async function collectSourceOfFunds(userId: string, amount: number): Promise<boolean> {
  if (amount < SOF_THRESHOLD) return true;
  
  const existingSOF = await db.getSourceOfFunds(userId);
  
  // SOF valid if filled and not expired (re-collection once per year)
  if (existingSOF && !isExpired(existingSOF, 365)) return true;
  
  // Request SOF through UI
  await triggerSOFCollection(userId, { requiredFor: "transaction", amount });
  return false;
}

Limits system with rolling windows, AML thresholds and SOF collection — 2-3 weeks development.