Skip to content

Commit d06a5a8

Browse files
committed
feat(realunit): adjust KYC level requirements based on amount (#2771)
- KYC Level 20 is now sufficient for amounts up to 1000 CHF - KYC Level 50 is still required for amounts above 1000 CHF - EUR amounts are converted to CHF for the limit check - Uses existing Config.tradingLimits.monthlyDefaultWoKyc threshold
1 parent b4b852e commit d06a5a8

2 files changed

Lines changed: 27 additions & 9 deletions

File tree

src/subdomains/supporting/realunit/dto/realunit.dto.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
22
import { Type } from 'class-transformer';
3-
import { IsEnum, IsNumber, IsOptional, IsString } from 'class-validator';
3+
import { IsEnum, IsNumber, IsOptional, IsPositive, IsString } from 'class-validator';
44
import { FeeDto } from 'src/subdomains/supporting/payment/dto/fee.dto';
55
import { QuoteError } from 'src/subdomains/supporting/payment/dto/transaction-helper/quote-error.enum';
66
import { PriceStep } from 'src/subdomains/supporting/pricing/domain/entities/price';
@@ -272,6 +272,7 @@ export enum RealUnitBuyCurrency {
272272
export class RealUnitBuyDto {
273273
@ApiProperty({ description: 'Amount in fiat currency' })
274274
@IsNumber()
275+
@IsPositive()
275276
@Type(() => Number)
276277
amount: number;
277278

src/subdomains/supporting/realunit/realunit.service.ts

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -199,9 +199,23 @@ export class RealUnitService {
199199
const userData = user.userData;
200200
const currencyName = dto.currency ?? 'CHF';
201201

202-
// 1. KYC Level 50 required for RealUnit
203-
if (userData.kycLevel < KycLevel.LEVEL_50) {
204-
throw new BadRequestException('KYC Level 50 required for RealUnit');
202+
// 1. KYC Level check - Level 20 for amounts <= 1000 CHF, Level 50 for higher amounts
203+
const currency = await this.fiatService.getFiatByName(currencyName);
204+
const amountChf =
205+
currencyName === 'CHF'
206+
? dto.amount
207+
: (await this.pricingService.getPrice(currency, PriceCurrency.CHF, PriceValidity.ANY)).convert(dto.amount);
208+
209+
const maxAmountForLevel20 = Config.tradingLimits.monthlyDefaultWoKyc;
210+
const requiresLevel50 = amountChf > maxAmountForLevel20;
211+
const requiredLevel = requiresLevel50 ? KycLevel.LEVEL_50 : KycLevel.LEVEL_20;
212+
213+
if (userData.kycLevel < requiredLevel) {
214+
throw new BadRequestException(
215+
requiresLevel50
216+
? `KYC Level 50 required for amounts above ${maxAmountForLevel20} CHF`
217+
: 'KYC Level 20 required for RealUnit',
218+
);
205219
}
206220

207221
// 2. Registration required
@@ -214,10 +228,7 @@ export class RealUnitService {
214228
const realuAsset = await this.getRealuAsset();
215229
const buy = await this.buyService.createBuy(user, user.address, { asset: realuAsset }, true);
216230

217-
// 4. Get currency
218-
const currency = await this.fiatService.getFiatByName(currencyName);
219-
220-
// 5. Call BuyService to get payment info (handles fees, rates, IBAN creation, QR codes, etc.)
231+
// 4. Call BuyService to get payment info (handles fees, rates, IBAN creation, QR codes, etc.)
221232
const buyPaymentInfo = await this.buyService.toPaymentInfoDto(user.id, buy, {
222233
amount: dto.amount,
223234
targetAmount: undefined,
@@ -227,7 +238,7 @@ export class RealUnitService {
227238
exactPrice: false,
228239
});
229240

230-
// 6. Override recipient info with RealUnit company address
241+
// 5. Override recipient info with RealUnit company address
231242
const { bank: realunitBank } = GetConfig().blockchain.realunit;
232243
const response: RealUnitPaymentInfoDto = {
233244
id: buyPaymentInfo.id,
@@ -523,6 +534,12 @@ export class RealUnitService {
523534
});
524535

525536
await this.kycService.saveKycStepUpdate(kycStep.complete());
537+
538+
// Set KYC Level 20 if not already higher (same as NATIONALITY_DATA step)
539+
if (kycStep.userData.kycLevel < KycLevel.LEVEL_20) {
540+
await this.userDataService.updateUserDataInternal(kycStep.userData, { kycLevel: KycLevel.LEVEL_20 });
541+
}
542+
526543
return true;
527544
} catch (error) {
528545
const message = error?.response?.data ? JSON.stringify(error.response.data) : error?.message || error;

0 commit comments

Comments
 (0)