re-use the same kyc function from withdrawal for deposits

This commit is contained in:
Sebastian 2023-01-17 15:59:30 -03:00
parent eeea3e62a0
commit 2c14a180c1
No known key found for this signature in database
GPG Key ID: BE4FF68352439FC1
3 changed files with 77 additions and 50 deletions

View File

@ -1361,7 +1361,8 @@ export type WgInfo =
| WgInfoBankPeerPush
| WgInfoBankRecoup;
export interface WithdrawalKycPendingInfo {
export type KycUserType = "individual" | "business";
export interface KycPendingInfo {
paytoHash: string;
requirementRow: number;
}
@ -1380,7 +1381,7 @@ export interface WithdrawalGroupRecord {
wgInfo: WgInfo;
kycPending?: WithdrawalKycPendingInfo;
kycPending?: KycPendingInfo;
/**
* Secret seed used to derive planchets.

View File

@ -21,6 +21,7 @@ import {
AbsoluteTime,
AmountJson,
Amounts,
bytesToString,
CancellationToken,
canonicalJson,
codecForDepositSuccess,
@ -35,6 +36,7 @@ import {
ExchangeDepositRequest,
GetFeeForDepositRequest,
getRandomBytes,
hashTruncate32,
hashWire,
HttpStatusCode,
Logger,
@ -44,6 +46,7 @@ import {
PrepareDepositRequest,
PrepareDepositResponse,
RefreshReason,
stringToBytes,
TalerErrorCode,
TalerProtocolTimestamp,
TrackDepositGroupRequest,
@ -59,6 +62,7 @@ import {
TransactionStatus,
} from "../db.js";
import { TalerError } from "../errors.js";
import { checkKycStatus } from "../index.js";
import { InternalWalletState } from "../internal-wallet-state.js";
import { readSuccessResponseJsonOrThrow } from "../util/http.js";
import { OperationAttemptResult } from "../util/retries.js";
@ -151,7 +155,28 @@ export async function processDepositGroup(
if (depositGroup.transactionPerCoin[i] !== TransactionStatus.Wired) {
const track = await trackDepositPermission(ws, depositGroup, perm);
updatedTxStatus = txStatusFromTrack(track);
if (track.type === "accepted") {
if (!track.kyc_ok && track.requirement_row !== undefined) {
updatedTxStatus = TransactionStatus.KycRequired;
const { requirement_row: requirementRow } = track;
const paytoHash = encodeCrock(
hashTruncate32(stringToBytes(depositGroup.wire.payto_uri + "\0")),
);
await checkKycStatus(
ws,
perm.exchange_url,
{ paytoHash, requirementRow },
"individual",
);
} else {
updatedTxStatus = TransactionStatus.Accepted;
}
} else if (track.type === "wired") {
updatedTxStatus = TransactionStatus.Wired;
} else {
updatedTxStatus = TransactionStatus.Unknown;
}
}
if (updatedTxStatus !== undefined || updatedDeposit !== undefined) {
@ -199,19 +224,6 @@ export async function processDepositGroup(
return OperationAttemptResult.finishedEmpty();
}
function txStatusFromTrack(t: TrackTransaction): TransactionStatus {
if (t.type === "accepted") {
if (!t.kyc_ok && t.requirement_row !== undefined) {
return TransactionStatus.KycRequired;
}
return TransactionStatus.Accepted;
}
if (t.type === "wired") {
return TransactionStatus.Wired;
}
return TransactionStatus.Unknown;
}
export async function trackDepositGroup(
ws: InternalWalletState,
req: TrackDepositGroupRequest,

View File

@ -26,7 +26,6 @@ import {
AmountJson,
AmountLike,
Amounts,
AmountString,
BankWithdrawDetails,
CancellationToken,
canonicalizeBaseUrl,
@ -70,13 +69,14 @@ import {
CoinSourceType,
DenominationRecord,
DenominationVerificationStatus,
KycPendingInfo,
KycUserType,
PlanchetRecord,
PlanchetStatus,
WalletStoresV1,
WgInfo,
WithdrawalGroupRecord,
WithdrawalGroupStatus,
WithdrawalKycPendingInfo,
WithdrawalRecordType,
} from "../db.js";
import {
@ -86,7 +86,6 @@ import {
} from "../errors.js";
import { InternalWalletState } from "../internal-wallet-state.js";
import {
getExchangeTosStatus,
makeCoinAvailable,
makeExchangeListItem,
runOperationWithErrorReporting,
@ -927,7 +926,7 @@ async function queryReserve(
);
reserveUrl.searchParams.set("timeout_ms", "30000");
logger.info(`querying reserve status via ${reserveUrl}`);
logger.info(`querying reserve status via ${reserveUrl.href}`);
const resp = await ws.http.get(reserveUrl.href, {
timeout: getReserveRequestTimeout(withdrawalGroup),
@ -1165,9 +1164,9 @@ export async function processWithdrawalGroup(
let numFinished = 0;
let numKycRequired = 0;
let finishedForFirstTime = false;
let errorsPerCoin: Record<number, TalerErrorDetail> = {};
const errorsPerCoin: Record<number, TalerErrorDetail> = {};
let res = await ws.db
const res = await ws.db
.mktx((x) => [x.coins, x.withdrawalGroups, x.planchets])
.runReadWrite(async (tx) => {
const wg = await tx.withdrawalGroups.get(withdrawalGroupId);
@ -1210,39 +1209,22 @@ export async function processWithdrawalGroup(
if (numKycRequired > 0) {
if (kycInfo) {
const url = new URL(
`kyc-check/${kycInfo.requirementRow}/${kycInfo.paytoHash}/individual`,
await checkKycStatus(
ws,
withdrawalGroup.exchangeBaseUrl,
kycInfo,
"individual",
);
logger.info(`kyc url ${url.href}`);
const kycStatusReq = await ws.http.fetch(url.href, {
method: "GET",
});
logger.warn("kyc requested, but already fulfilled");
if (kycStatusReq.status === HttpStatusCode.Ok) {
return {
type: OperationAttemptResultType.Pending,
result: undefined,
};
} else if (kycStatusReq.status === HttpStatusCode.Accepted) {
const kycStatus = await kycStatusReq.json();
logger.info(`kyc status: ${j2s(kycStatus)}`);
throw TalerError.fromDetail(
TalerErrorCode.WALLET_WITHDRAWAL_KYC_REQUIRED,
{
kycUrl: kycStatus.kyc_url,
},
`KYC check required for withdrawal`,
);
} else {
throw Error(
`unexpected response from kyc-check (${kycStatusReq.status})`,
);
}
return {
type: OperationAttemptResultType.Pending,
result: undefined,
};
} else {
throw TalerError.fromDetail(
TalerErrorCode.WALLET_WITHDRAWAL_KYC_REQUIRED,
{},
{
//FIXME we can't rise KYC error here since we don't have the url
} as any,
`KYC check required for withdrawal (not yet implemented in wallet-core)`,
);
}
@ -1270,6 +1252,38 @@ export async function processWithdrawalGroup(
};
}
export async function checkKycStatus(
ws: InternalWalletState,
exchangeUrl: string,
kycInfo: KycPendingInfo,
userType: KycUserType,
): Promise<void> {
const url = new URL(
`kyc-check/${kycInfo.requirementRow}/${kycInfo.paytoHash}/${userType}`,
exchangeUrl,
);
logger.info(`kyc url ${url.href}`);
const kycStatusReq = await ws.http.fetch(url.href, {
method: "GET",
});
logger.warn("kyc requested, but already fulfilled");
if (kycStatusReq.status === HttpStatusCode.Ok) {
return;
} else if (kycStatusReq.status === HttpStatusCode.Accepted) {
const kycStatus = await kycStatusReq.json();
logger.info(`kyc status: ${j2s(kycStatus)}`);
throw TalerError.fromDetail(
TalerErrorCode.WALLET_WITHDRAWAL_KYC_REQUIRED,
{
kycUrl: kycStatus.kyc_url,
},
`KYC check required for withdrawal`,
);
} else {
throw Error(`unexpected response from kyc-check (${kycStatusReq.status})`);
}
}
const AGE_MASK_GROUPS = "8:10:12:14:16:18"
.split(":")
.map((n) => parseInt(n, 10));