Skip to content

Commit d43b8e7

Browse files
authored
Merge pull request #3392 from DFXswiss/develop
Release: develop -> main
2 parents d180d52 + 5331fcf commit d43b8e7

14 files changed

Lines changed: 218 additions & 148 deletions

File tree

src/integration/blockchain/icp/dto/icp.dto.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export interface IcpTransferQueryResult {
1212
transfers: IcpTransfer[];
1313
lastBlockIndex: number;
1414
chainLength: number;
15+
rawTransactionCount: number;
1516
}
1617

1718
// --- Candid query_blocks response types (ICP native ledger) ---

src/integration/blockchain/icp/icp-client.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ export class InternetComputerClient extends BlockchainClient {
188188
lastIndex = start - 1;
189189
}
190190

191-
return { transfers, lastBlockIndex: lastIndex, chainLength };
191+
return { transfers, lastBlockIndex: lastIndex, chainLength, rawTransactionCount: response.blocks.length };
192192
}
193193

194194
private mapBlockToTransfer(block: CandidBlock, index: number): IcpTransfer | undefined {
@@ -277,9 +277,23 @@ export class InternetComputerClient extends BlockchainClient {
277277
if (transfer) transfers.push(transfer);
278278
}
279279

280-
const lastIndex = response.transactions.length > 0 ? firstIndex + response.transactions.length - 1 : start - 1;
280+
let lastIndex: number;
281281

282-
return { transfers, lastBlockIndex: lastIndex, chainLength: Number(response.log_length) };
282+
if (response.transactions.length > 0) {
283+
lastIndex = firstIndex + response.transactions.length - 1;
284+
} else if (firstIndex > start) {
285+
lastIndex = firstIndex - 1;
286+
this.logger.info(`Skipping archived ICRC blocks ${start}-${lastIndex}, next query starts at ${firstIndex}`);
287+
} else {
288+
lastIndex = start - 1;
289+
}
290+
291+
return {
292+
transfers,
293+
lastBlockIndex: lastIndex,
294+
chainLength: Number(response.log_length),
295+
rawTransactionCount: response.transactions.length,
296+
};
283297
}
284298

285299
private mapIcrcTransaction(tx: CandidIcrcTransaction, index: number, decimals: number): IcpTransfer | undefined {

src/subdomains/core/history/mappers/transaction-dto.mapper.ts

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ export class TransactionRequestExtended extends TransactionRequest {
4545
export class TransactionDtoMapper {
4646
// BuyCrypto
4747
static mapBuyCryptoTransaction(buyCrypto: BuyCryptoExtended): TransactionDto {
48+
const inputAsset = isAsset(buyCrypto.inputAssetEntity) ? buyCrypto.inputAssetEntity : null;
49+
const outputAsset = buyCrypto.outputAsset;
50+
4851
const dto: TransactionDto = {
4952
id: buyCrypto.transaction.id,
5053
uid: buyCrypto.transaction.uid,
@@ -54,14 +57,18 @@ export class TransactionDtoMapper {
5457
inputAmount: Util.roundReadable(buyCrypto.inputAmount, amountType(buyCrypto.inputAssetEntity)),
5558
inputAsset: buyCrypto.inputAssetEntity.name,
5659
inputAssetId: buyCrypto.inputAssetEntity.id,
60+
inputChainId: inputAsset?.chainId ?? null,
5761
inputBlockchain: buyCrypto.cryptoInput?.asset.blockchain,
62+
inputEvmChainId: inputAsset?.evmChainId ?? null,
5863
inputPaymentMethod: buyCrypto.paymentMethodIn,
5964
...(buyCrypto.outputAmount ? buyCrypto.exchangeRate : null),
6065
outputAmount:
6166
buyCrypto.outputAmount != null ? Util.roundReadable(buyCrypto.outputAmount, AmountType.ASSET) : null,
6267
outputAsset: buyCrypto.outputAsset?.name,
6368
outputAssetId: buyCrypto.outputAsset?.id,
69+
outputChainId: outputAsset?.chainId ?? null,
6470
outputBlockchain: buyCrypto.outputAsset?.blockchain,
71+
outputEvmChainId: outputAsset?.evmChainId ?? null,
6572
outputPaymentMethod: CryptoPaymentMethod.CRYPTO,
6673
priceSteps: buyCrypto.priceStepsObject,
6774
feeAmount: buyCrypto.totalFeeAmount
@@ -76,6 +83,7 @@ export class TransactionDtoMapper {
7683
inputTxUrl: buyCrypto?.cryptoInput
7784
? txExplorerUrl(buyCrypto.cryptoInput.asset.blockchain, buyCrypto.cryptoInput.inTxId)
7885
: null,
86+
depositAddress: buyCrypto.cryptoInput?.address?.address ?? null,
7987
outputTxId: buyCrypto.txId,
8088
outputTxUrl: buyCrypto.txId ? txExplorerUrl(buyCrypto.outputAsset?.blockchain, buyCrypto.txId) : null,
8189
outputDate: buyCrypto.outputDate,
@@ -122,6 +130,8 @@ export class TransactionDtoMapper {
122130

123131
// BuyFiat
124132
static mapBuyFiatTransaction(buyFiat: BuyFiatExtended): TransactionDto {
133+
const inputAsset = isAsset(buyFiat.inputAssetEntity) ? buyFiat.inputAssetEntity : null;
134+
125135
const dto: TransactionDto = {
126136
id: buyFiat.transaction.id,
127137
uid: buyFiat.transaction.uid,
@@ -131,13 +141,17 @@ export class TransactionDtoMapper {
131141
inputAmount: Util.roundReadable(buyFiat.inputAmount, amountType(buyFiat.inputAssetEntity)),
132142
inputAsset: buyFiat.inputAssetEntity.name,
133143
inputAssetId: buyFiat.inputAssetEntity.id,
144+
inputChainId: inputAsset?.chainId ?? null,
134145
inputBlockchain: buyFiat.cryptoInput?.asset.blockchain,
146+
inputEvmChainId: inputAsset?.evmChainId ?? null,
135147
inputPaymentMethod: CryptoPaymentMethod.CRYPTO,
136148
...(buyFiat.outputAmount ? buyFiat.exchangeRate : null),
137149
outputAmount: buyFiat.outputAmount != null ? Util.roundReadable(buyFiat.outputAmount, AmountType.FIAT) : null,
138150
outputAsset: buyFiat.outputAsset?.name,
139151
outputAssetId: buyFiat.outputAsset?.id,
152+
outputChainId: null,
140153
outputBlockchain: null,
154+
outputEvmChainId: null,
141155
outputPaymentMethod: FiatPaymentMethod.BANK,
142156
outputDate: buyFiat.outputDate,
143157
priceSteps: buyFiat.priceStepsObject,
@@ -153,6 +167,7 @@ export class TransactionDtoMapper {
153167
inputTxUrl: buyFiat?.cryptoInput
154168
? txExplorerUrl(buyFiat.cryptoInput.asset.blockchain, buyFiat.cryptoInput.inTxId)
155169
: null,
170+
depositAddress: buyFiat.cryptoInput?.address?.address ?? null,
156171
outputTxId: buyFiat.bankTx?.remittanceInfo ?? null,
157172
outputTxUrl: null,
158173
chargebackAmount: buyFiat.chargebackAmount,
@@ -186,6 +201,8 @@ export class TransactionDtoMapper {
186201
// Waiting TxRequest
187202
static mapTxRequestTransaction(txRequest: TransactionRequestExtended): TransactionDto {
188203
const fees = TransactionDtoMapper.mapFees(txRequest);
204+
const sourceAsset = isAsset(txRequest.sourceAssetEntity) ? txRequest.sourceAssetEntity : null;
205+
const targetAsset = isAsset(txRequest.targetAssetEntity) ? txRequest.targetAssetEntity : null;
189206

190207
const dto: TransactionDto = {
191208
id: null,
@@ -195,19 +212,24 @@ export class TransactionDtoMapper {
195212
inputAmount: Util.roundReadable(txRequest.amount, amountType(txRequest.sourceAssetEntity)),
196213
inputAsset: txRequest.sourceAssetEntity.name,
197214
inputAssetId: txRequest.sourceAssetEntity.id,
198-
inputBlockchain: isAsset(txRequest.sourceAssetEntity) ? txRequest.sourceAssetEntity.blockchain : null,
215+
inputChainId: sourceAsset?.chainId ?? null,
216+
inputBlockchain: sourceAsset?.blockchain ?? null,
217+
inputEvmChainId: sourceAsset?.evmChainId ?? null,
199218
inputPaymentMethod: txRequest.sourcePaymentMethod,
200219
outputAmount: null,
201220
outputAsset: txRequest.targetAssetEntity?.name,
202221
outputAssetId: txRequest.targetAssetEntity?.id,
203-
outputBlockchain: isAsset(txRequest.targetAssetEntity) ? txRequest.targetAssetEntity?.blockchain : null,
222+
outputChainId: targetAsset?.chainId ?? null,
223+
outputBlockchain: targetAsset?.blockchain ?? null,
224+
outputEvmChainId: targetAsset?.evmChainId ?? null,
204225
outputPaymentMethod: txRequest.targetPaymentMethod,
205226
priceSteps: null,
206227
feeAmount: fees?.total,
207228
feeAsset: fees?.total ? txRequest.sourceAssetEntity.name : null,
208229
fees,
209230
inputTxId: null,
210231
inputTxUrl: null,
232+
depositAddress: null,
211233
outputTxId: null,
212234
outputTxUrl: null,
213235
outputDate: null,
@@ -247,7 +269,9 @@ export class TransactionDtoMapper {
247269
inputAmount: null,
248270
inputAsset: null,
249271
inputAssetId: null,
272+
inputChainId: null,
250273
inputBlockchain: null,
274+
inputEvmChainId: null,
251275
inputPaymentMethod: null,
252276
exchangeRate: null,
253277
rate: null,
@@ -257,7 +281,9 @@ export class TransactionDtoMapper {
257281
: null,
258282
outputAsset: refReward.outputAsset.name,
259283
outputAssetId: refReward.outputAsset?.id,
284+
outputChainId: refReward.outputAsset?.chainId ?? null,
260285
outputBlockchain: refReward.targetBlockchain,
286+
outputEvmChainId: refReward.outputAsset?.evmChainId ?? null,
261287
outputPaymentMethod: CryptoPaymentMethod.CRYPTO,
262288
outputDate: refReward.outputDate,
263289
priceSteps: null,
@@ -266,6 +292,7 @@ export class TransactionDtoMapper {
266292
fees: null,
267293
inputTxId: null,
268294
inputTxUrl: null,
295+
depositAddress: null,
269296
outputTxId: refReward.txId,
270297
outputTxUrl: refReward.txId ? txExplorerUrl(refReward.targetBlockchain, refReward.txId) : null,
271298
chargebackAmount: undefined,

src/subdomains/generic/kyc/controllers/kyc.controller.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import {
4343
KycBeneficialData,
4444
KycChangeAddressData,
4545
KycChangeNameData,
46+
KycChangePhoneData,
4647
KycContactData,
4748
KycFileData,
4849
KycLegalEntityData,
@@ -266,6 +267,17 @@ export class KycController {
266267
return this.kycService.updateNameChangeData(code, +id, data);
267268
}
268269

270+
@Put('data/phone/:id')
271+
@ApiOkResponse({ type: KycStepBase })
272+
@ApiUnauthorizedResponse(MergedResponse)
273+
async updatePhoneChangeData(
274+
@Headers(CodeHeaderName) code: string,
275+
@Param('id') id: string,
276+
@Body() data: KycChangePhoneData,
277+
): Promise<KycStepBase> {
278+
return this.kycService.updatePhoneChangeData(code, +id, data);
279+
}
280+
269281
@Put('data/confirmation/:id')
270282
@ApiOkResponse({ type: KycStepBase })
271283
@ApiUnauthorizedResponse(MergedResponse)

src/subdomains/generic/kyc/dto/input/kyc-data.dto.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,15 @@ export class KycChangeNameData {
114114
lastName: string;
115115
}
116116

117+
export class KycChangePhoneData {
118+
@ApiProperty({ description: 'New phone number' })
119+
@IsNotEmpty()
120+
@IsString()
121+
@Transform(DfxPhoneTransform)
122+
@IsDfxPhone()
123+
phone: string;
124+
}
125+
117126
export class KycPersonalData {
118127
@ApiProperty({ enum: AccountType })
119128
@IsNotEmpty()

src/subdomains/generic/kyc/entities/kyc-step.entity.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ export class KycStep extends IEntity {
135135
return { url: `${apiUrl}/data/payment/${this.id}`, type: UrlType.API };
136136

137137
case KycStepName.PHONE_CHANGE:
138-
return { url: '', type: UrlType.NONE };
138+
return { url: `${apiUrl}/data/phone/${this.id}`, type: UrlType.API };
139139

140140
case KycStepName.ADDRESS_CHANGE:
141141
return { url: `${apiUrl}/data/address/${this.id}`, type: UrlType.API };

src/subdomains/generic/kyc/services/kyc.service.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import {
5151
KycBeneficialData,
5252
KycChangeAddressData,
5353
KycChangeNameData,
54+
KycChangePhoneData,
5455
KycContactData,
5556
KycFileData,
5657
KycLegalEntityData,
@@ -772,6 +773,19 @@ export class KycService {
772773
});
773774
}
774775

776+
async updatePhoneChangeData(kycHash: string, stepId: number, data: KycChangePhoneData): Promise<KycStepBase> {
777+
const user = await this.getUser(kycHash);
778+
const kycStep = user.getPendingStepOrThrow(stepId);
779+
780+
await this.userDataService.updatePhone(user, data.phone, false);
781+
782+
await this.kycStepRepo.update(...kycStep.complete({ phone: data.phone }));
783+
await this.createStepLog(user, kycStep);
784+
await this.updateProgress(user, false);
785+
786+
return KycStepMapper.toStepBase(kycStep);
787+
}
788+
775789
async getFinancialData(kycHash: string, ip: string, stepId: number, lang?: string): Promise<KycFinancialOutData> {
776790
const user = await this.getUser(kycHash);
777791
const kycStep = user.getPendingStepOrThrow(stepId);

src/subdomains/generic/user/models/user-data/user-data.service.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,7 @@ export class UserDataService {
754754
}
755755

756756
// --- PHONE UPDATE --- //
757-
async updatePhone(userData: UserData, phone: string): Promise<void> {
757+
async updatePhone(userData: UserData, phone: string, createStep = true): Promise<void> {
758758
if (userData.kycLevel !== KycLevel.LEVEL_0 && !phone)
759759
throw new BadRequestException('KYC already started, user data deletion not allowed');
760760

@@ -784,10 +784,12 @@ export class UserDataService {
784784
}
785785

786786
// create KYC step
787-
await this.kycService.createCustomKycStep(userData, KycStepName.PHONE_CHANGE, ReviewStatus.COMPLETED, {
788-
phone,
789-
previousPhone,
790-
});
787+
if (createStep) {
788+
await this.kycService.createCustomKycStep(userData, KycStepName.PHONE_CHANGE, ReviewStatus.COMPLETED, {
789+
phone,
790+
previousPhone,
791+
});
792+
}
791793
}
792794

793795
// --- ADDRESS UPDATE --- //

src/subdomains/generic/user/services/webhook/dto/payment-webhook.dto.ts

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
1+
import { ApiProperty } from '@nestjs/swagger';
22
import { TransactionDetailDto } from 'src/subdomains/supporting/payment/dto/transaction.dto';
33
import { WebhookDto, WebhookType } from './webhook.dto';
44

@@ -21,21 +21,6 @@ export enum PaymentWebhookState {
2121
export class PaymentWebhookData extends TransactionDetailDto {
2222
@ApiProperty()
2323
dfxReference: number;
24-
25-
@ApiPropertyOptional({ description: 'Source token contract address' })
26-
sourceChainId?: string;
27-
28-
@ApiPropertyOptional({ description: 'Destination token contract address' })
29-
destinationChainId?: string;
30-
31-
@ApiPropertyOptional({ description: 'Source EVM chain ID (e.g. 1, 56, 137)' })
32-
sourceEvmChainId?: number;
33-
34-
@ApiPropertyOptional({ description: 'Destination EVM chain ID (e.g. 1, 56, 137)' })
35-
destinationEvmChainId?: number;
36-
37-
@ApiPropertyOptional({ description: 'Deposit address for crypto inputs' })
38-
depositAddress?: string;
3924
}
4025

4126
export class PaymentWebhookDto extends WebhookDto<PaymentWebhookData> {

src/subdomains/generic/user/services/webhook/mapper/webhook-data.mapper.ts

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { Asset } from 'src/shared/models/asset/asset.entity';
21
import { CountryDtoMapper } from 'src/shared/models/country/dto/country-dto.mapper';
32
import {
43
BuyCryptoExtended,
@@ -33,57 +32,30 @@ export class WebhookDataMapper {
3332
}
3433

3534
static mapCryptoFiatData(payment: BuyFiatExtended): PaymentWebhookData {
36-
const inputAsset = payment.inputAssetEntity as Asset;
37-
3835
return {
3936
...TransactionDtoMapper.mapBuyFiatTransactionDetail(payment),
4037
dfxReference: payment.id,
41-
sourceChainId: inputAsset.chainId,
42-
destinationChainId: null,
43-
sourceEvmChainId: inputAsset.evmChainId ?? null,
44-
destinationEvmChainId: null,
45-
depositAddress: payment.cryptoInput?.address?.address ?? null,
4638
};
4739
}
4840

4941
static mapFiatFiatData(payment: BuyFiatExtended): PaymentWebhookData {
5042
return {
5143
...TransactionDtoMapper.mapBuyFiatTransactionDetail(payment),
5244
dfxReference: payment.id,
53-
sourceChainId: null,
54-
destinationChainId: null,
55-
sourceEvmChainId: null,
56-
destinationEvmChainId: null,
57-
depositAddress: null,
5845
};
5946
}
6047

6148
static mapCryptoCryptoData(payment: BuyCryptoExtended): PaymentWebhookData {
62-
const inputAsset = payment.inputAssetEntity as Asset;
63-
const outputAsset = payment.outputAsset;
64-
6549
return {
6650
...TransactionDtoMapper.mapBuyCryptoTransactionDetail(payment),
6751
dfxReference: payment.id,
68-
sourceChainId: inputAsset.chainId,
69-
destinationChainId: outputAsset?.chainId ?? null,
70-
sourceEvmChainId: inputAsset.evmChainId ?? null,
71-
destinationEvmChainId: outputAsset?.evmChainId ?? null,
72-
depositAddress: payment.cryptoInput?.address?.address ?? null,
7352
};
7453
}
7554

7655
static mapFiatCryptoData(payment: BuyCryptoExtended): PaymentWebhookData {
77-
const outputAsset = payment.outputAsset;
78-
7956
return {
8057
...TransactionDtoMapper.mapBuyCryptoTransactionDetail(payment),
8158
dfxReference: payment.id,
82-
sourceChainId: null,
83-
destinationChainId: outputAsset?.chainId ?? null,
84-
sourceEvmChainId: null,
85-
destinationEvmChainId: outputAsset?.evmChainId ?? null,
86-
depositAddress: null,
8759
};
8860
}
8961

0 commit comments

Comments
 (0)