@riocrypto/common-server 1.0.2878 → 1.0.2879

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/build/clients/cluster-client.d.ts +36 -0
  2. package/build/clients/cluster-client.js +31 -1
  3. package/build/helpers/get-custom-rio-bank-account.d.ts +10 -0
  4. package/build/helpers/get-custom-rio-bank-account.js +37 -0
  5. package/build/helpers/get-processor.d.ts +7 -4
  6. package/build/helpers/get-processor.js +72 -55
  7. package/build/helpers/get-tax-rate.js +1 -0
  8. package/build/helpers/payin-destinations.d.ts +37 -0
  9. package/build/helpers/payin-destinations.js +286 -0
  10. package/build/helpers/payin-verification.d.ts +30 -0
  11. package/build/helpers/payin-verification.js +162 -0
  12. package/build/helpers/processor-enablement.d.ts +19 -0
  13. package/build/helpers/processor-enablement.js +87 -0
  14. package/build/helpers/record-observed-processor-readiness.d.ts +10 -0
  15. package/build/helpers/record-observed-processor-readiness.js +65 -0
  16. package/build/helpers/resolve-processor.d.ts +18 -0
  17. package/build/helpers/resolve-processor.js +122 -0
  18. package/build/index.d.ts +10 -0
  19. package/build/index.js +10 -0
  20. package/build/middlewares/get-order.js +1 -0
  21. package/build/models/bank-account-verification.d.ts +2 -2
  22. package/build/models/bulk-bank-payment.js +3 -0
  23. package/build/models/fintoc-deposit-CLABE.d.ts +28 -0
  24. package/build/models/fintoc-deposit-CLABE.js +56 -0
  25. package/build/models/fintoc-mxn-withdrawal.d.ts +51 -0
  26. package/build/models/fintoc-mxn-withdrawal.js +88 -0
  27. package/build/models/fireblocks-vault.d.ts +8 -0
  28. package/build/models/fireblocks-vault.js +8 -0
  29. package/build/models/internal-balances.d.ts +3 -0
  30. package/build/models/internal-balances.js +3 -0
  31. package/build/models/payment-address-verification.d.ts +49 -0
  32. package/build/models/payment-address-verification.js +77 -0
  33. package/build/models/processor-readiness.d.ts +44 -0
  34. package/build/models/processor-readiness.js +90 -0
  35. package/build/models/rio-bank-account.d.ts +3 -1
  36. package/build/models/rio-bank-account.js +3 -0
  37. package/build/models/rio-settings.d.ts +3 -11
  38. package/build/models/rio-settings.js +1 -2
  39. package/package.json +2 -2
@@ -0,0 +1,18 @@
1
+ import { Country, Fiat, Processor, ProcessorRoutingConfig, ProcessorRoutingPurpose } from "@riocrypto/common";
2
+ export interface ResolveProcessorParams {
3
+ country: Country;
4
+ fiat: Fiat;
5
+ purpose: ProcessorRoutingPurpose;
6
+ routingConfig?: ProcessorRoutingConfig;
7
+ excludedProcessors?: Processor[];
8
+ disabledProcessors?: Processor[];
9
+ customRioBankAccount?: {
10
+ processor?: Processor;
11
+ };
12
+ randomSeed?: number;
13
+ }
14
+ export interface ResolveProcessorResult {
15
+ processor?: Processor;
16
+ reason: "customRioBankAccount" | "customRioBankAccountWithoutRail" | "split" | "onlyCandidate" | "enabledRailWithoutShare" | "noRuleConfigured" | "noEligibleCandidate" | "noEnabledCandidate";
17
+ }
18
+ export declare const resolveProcessor: ({ country, fiat, purpose, routingConfig, excludedProcessors, disabledProcessors, customRioBankAccount, randomSeed, }: ResolveProcessorParams) => ResolveProcessorResult;
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveProcessor = void 0;
4
+ const common_1 = require("@riocrypto/common");
5
+ const getRule = (config, country, fiat, purpose) => { var _a, _b; return (_b = (_a = config === null || config === void 0 ? void 0 : config[country]) === null || _a === void 0 ? void 0 : _a[fiat]) === null || _b === void 0 ? void 0 : _b[purpose]; };
6
+ // Renormalizes over the candidates it is given rather than assuming they still
7
+ // add up to 100, which is what lets a rail drop out - excluded by environment, or
8
+ // switched off by the customer - and have its share absorbed proportionally by
9
+ // the rest.
10
+ const pickByShare = (candidates, position) => {
11
+ const total = candidates.reduce((acc, c) => acc + c.percentage, 0);
12
+ let cursor = position * total;
13
+ for (const candidate of candidates) {
14
+ cursor -= candidate.percentage;
15
+ if (cursor < 0) {
16
+ return candidate.processor;
17
+ }
18
+ }
19
+ // Floating point can leave the cursor a hair above zero on the last step.
20
+ return candidates[candidates.length - 1].processor;
21
+ };
22
+ // Chooses the payment processor for a buy, a sell or a bank account verification
23
+ // from the configured split.
24
+ //
25
+ // A percentage divides volume between the rails that are actually available to
26
+ // the customer; it is not a switch. A rail left at zero, or left out of the rule
27
+ // altogether, still takes their orders when it is the only one they have left
28
+ // enabled, which is why the candidate set comes from the corridor rather than
29
+ // from the rule. Switching a rail off is the only way to keep an order away from
30
+ // it.
31
+ //
32
+ // Does no IO of its own - the routing config and the user's readiness are passed
33
+ // in - and the only nondeterminism is the per-order roll, which a caller can
34
+ // pin down by supplying randomSeed. Because the roll happens once, the answer
35
+ // belongs to the record that stores it: anything that needs to know which rail
36
+ // an existing order uses reads it off the order rather than calling again.
37
+ //
38
+ // Only handles rails that participate in a split. Structural routing that is not
39
+ // a commercial choice - Binance RFQ, COP, USD in the US or Mexico - stays in
40
+ // getProcessor and never reaches here.
41
+ const resolveProcessor = ({ country, fiat, purpose, routingConfig, excludedProcessors, disabledProcessors, customRioBankAccount, randomSeed, }) => {
42
+ const isEligible = (processor) => !(excludedProcessors === null || excludedProcessors === void 0 ? void 0 : excludedProcessors.includes(processor));
43
+ // A rail the customer has switched off for this direction is worthless whatever
44
+ // share it carries: on a buy they cannot send money to it, on a sell their bank
45
+ // will not accept the credit. Applies to every rail, verifiable or not - a bank
46
+ // can refuse a wire from Bancrea as easily as a SPEI transfer from Fintoc.
47
+ //
48
+ // Verifications are exempt because they are ours to place against an account the
49
+ // customer gave us, not a rail they have to accept.
50
+ const isUsable = (processor) => purpose === common_1.ProcessorRoutingPurpose.BankAccountVerification ||
51
+ !(disabledProcessors === null || disabledProcessors === void 0 ? void 0 : disabledProcessors.includes(processor));
52
+ // A custom Rio bank account outranks everything on buys, because it is where
53
+ // the money physically goes: `getBankDetails` returns it in place of the
54
+ // rail's own destination. Routing the order to a different processor would
55
+ // leave the order's processor and the account the payin lands in disagreeing,
56
+ // which breaks deposit matching, payout retry and the readiness gate at once.
57
+ // Sells and verifications never touch it - both are outbound.
58
+ if (customRioBankAccount && purpose === common_1.ProcessorRoutingPurpose.Buy) {
59
+ const { processor } = customRioBankAccount;
60
+ // Accounts predating the processor field have an unknown rail. Guessing
61
+ // would reintroduce the very mismatch this is here to prevent, so hand back
62
+ // to the structural path and leave these users exactly as they were until an
63
+ // admin records which rail the account belongs to.
64
+ if (!processor) {
65
+ return { reason: "customRioBankAccountWithoutRail" };
66
+ }
67
+ // Deliberately fail closed rather than fall through to the split. The payin
68
+ // destination is fixed, so if that rail cannot be used here the only honest
69
+ // options are to refuse the order or to keep sending payins to a provider we
70
+ // have stopped watching.
71
+ if (!isEligible(processor)) {
72
+ return { reason: "noEligibleCandidate" };
73
+ }
74
+ return { processor, reason: "customRioBankAccount" };
75
+ }
76
+ const rule = getRule(routingConfig, country, fiat, purpose);
77
+ if (!rule) {
78
+ return { reason: "noRuleConfigured" };
79
+ }
80
+ // Starts from the corridor's rails rather than from the rails the rule names,
81
+ // because a percentage decides how volume is divided between the rails a
82
+ // customer can use - it is not what makes a rail usable. Also drops any share
83
+ // stored against a rail this purpose does not serve, which nothing dispatches.
84
+ const corridorProcessors = (0, common_1.getProcessorsForCorridor)(country, fiat, purpose);
85
+ const eligible = corridorProcessors.filter(isEligible);
86
+ if (!eligible.length) {
87
+ return { reason: "noEligibleCandidate" };
88
+ }
89
+ const candidates = eligible.filter(isUsable);
90
+ if (!candidates.length) {
91
+ return { reason: "noEnabledCandidate" };
92
+ }
93
+ const shares = candidates
94
+ .map((processor) => ({
95
+ processor,
96
+ percentage: Number(rule.percentages[processor]) || 0,
97
+ }))
98
+ .filter((candidate) => candidate.percentage > 0);
99
+ // None of the rails this customer can use carries a share, so there is no split
100
+ // to draw from. Refusing the order would read a zero as "never use this rail",
101
+ // when all it says is where volume goes while there is somewhere else to send
102
+ // it. Prefers the corridor default and otherwise the corridor's own order, so
103
+ // the rail a customer in this position gets is predictable rather than rolled.
104
+ if (!shares.length) {
105
+ const fallback = (0, common_1.getDefaultProcessor)(country, fiat, purpose, excludedProcessors);
106
+ return {
107
+ processor: fallback && candidates.includes(fallback) ? fallback : candidates[0],
108
+ reason: "enabledRailWithoutShare",
109
+ };
110
+ }
111
+ if (shares.length === 1) {
112
+ return { processor: shares[0].processor, reason: "onlyCandidate" };
113
+ }
114
+ // Rolled per order, so the realized share converges on the configured
115
+ // percentages by order count. Nothing is persisted here: a caller that needs
116
+ // the same answer twice passes back the seed it used.
117
+ return {
118
+ processor: pickByShare(shares, randomSeed !== null && randomSeed !== void 0 ? randomSeed : Math.random()),
119
+ reason: "split",
120
+ };
121
+ };
122
+ exports.resolveProcessor = resolveProcessor;
package/build/index.d.ts CHANGED
@@ -87,6 +87,10 @@ export * from "./models/admin-auth-dashboard-settings";
87
87
  export * from "./models/STP-mxn-withdrawal";
88
88
  export * from "./models/STP-deposit-CLABE";
89
89
  export * from "./models/STP-settings";
90
+ export * from "./models/fintoc-mxn-withdrawal";
91
+ export * from "./models/fintoc-deposit-CLABE";
92
+ export * from "./models/processor-readiness";
93
+ export * from "./models/payment-address-verification";
90
94
  export * from "./models/alfin-virtual-cci";
91
95
  export * from "./models/alfin-settings";
92
96
  export * from "./models/alfin-withdrawal";
@@ -175,6 +179,12 @@ export * from "./helpers/generate-idempotency-key-from-order";
175
179
  export * from "./helpers/generate-idempotency-key-from-bulk-payout";
176
180
  export * from "./helpers/get-is-fireblocks-signature-valid";
177
181
  export * from "./helpers/get-processor";
182
+ export * from "./helpers/resolve-processor";
183
+ export * from "./helpers/get-custom-rio-bank-account";
184
+ export * from "./helpers/payin-destinations";
185
+ export * from "./helpers/payin-verification";
186
+ export * from "./helpers/processor-enablement";
187
+ export * from "./helpers/record-observed-processor-readiness";
178
188
  export * from "./helpers/get-bulk-payment-from-reference";
179
189
  export * from "./helpers/extract-error-message";
180
190
  export * from "./helpers/get-exchange-rates-with-markups";
package/build/index.js CHANGED
@@ -103,6 +103,10 @@ __exportStar(require("./models/admin-auth-dashboard-settings"), exports);
103
103
  __exportStar(require("./models/STP-mxn-withdrawal"), exports);
104
104
  __exportStar(require("./models/STP-deposit-CLABE"), exports);
105
105
  __exportStar(require("./models/STP-settings"), exports);
106
+ __exportStar(require("./models/fintoc-mxn-withdrawal"), exports);
107
+ __exportStar(require("./models/fintoc-deposit-CLABE"), exports);
108
+ __exportStar(require("./models/processor-readiness"), exports);
109
+ __exportStar(require("./models/payment-address-verification"), exports);
106
110
  __exportStar(require("./models/alfin-virtual-cci"), exports);
107
111
  __exportStar(require("./models/alfin-settings"), exports);
108
112
  __exportStar(require("./models/alfin-withdrawal"), exports);
@@ -191,6 +195,12 @@ __exportStar(require("./helpers/generate-idempotency-key-from-order"), exports);
191
195
  __exportStar(require("./helpers/generate-idempotency-key-from-bulk-payout"), exports);
192
196
  __exportStar(require("./helpers/get-is-fireblocks-signature-valid"), exports);
193
197
  __exportStar(require("./helpers/get-processor"), exports);
198
+ __exportStar(require("./helpers/resolve-processor"), exports);
199
+ __exportStar(require("./helpers/get-custom-rio-bank-account"), exports);
200
+ __exportStar(require("./helpers/payin-destinations"), exports);
201
+ __exportStar(require("./helpers/payin-verification"), exports);
202
+ __exportStar(require("./helpers/processor-enablement"), exports);
203
+ __exportStar(require("./helpers/record-observed-processor-readiness"), exports);
194
204
  __exportStar(require("./helpers/get-bulk-payment-from-reference"), exports);
195
205
  __exportStar(require("./helpers/extract-error-message"), exports);
196
206
  __exportStar(require("./helpers/get-exchange-rates-with-markups"), exports);
@@ -39,6 +39,7 @@ const getOrder = (req, res, next, mongoose, onlyBankOrders) => __awaiter(void 0,
39
39
  common_1.Processor.SPID,
40
40
  common_1.Processor.SPEI_NVIO,
41
41
  common_1.Processor.SPEI_STP,
42
+ common_1.Processor.SPEI_FINTOC,
42
43
  ].includes(order.processor)) {
43
44
  req.order = order;
44
45
  }
@@ -6,7 +6,7 @@ interface BankAccountVerificationAttrs {
6
6
  bankAccountId: string;
7
7
  status: BankAccountVerificationStatus;
8
8
  amount: number;
9
- provider?: Processor.SPEI_STP | Processor.SPEI_NVIO | Processor.Alfin;
9
+ provider?: Processor.SPEI_STP | Processor.SPEI_NVIO | Processor.Alfin | Processor.SPEI_FINTOC;
10
10
  providerWithdrawalId?: string;
11
11
  SPEITrackingNumber?: string;
12
12
  CEPLink?: string;
@@ -21,7 +21,7 @@ interface BankAccountVerificationDoc extends Document {
21
21
  bankAccountId: string;
22
22
  status: BankAccountVerificationStatus;
23
23
  amount: number;
24
- provider?: Processor.SPEI_STP | Processor.SPEI_NVIO | Processor.Alfin;
24
+ provider?: Processor.SPEI_STP | Processor.SPEI_NVIO | Processor.Alfin | Processor.SPEI_FINTOC;
25
25
  providerWithdrawalId?: string;
26
26
  SPEITrackingNumber?: string;
27
27
  CEPLink?: string;
@@ -48,6 +48,9 @@ const buildBulkBankPayment = (mongoose) => {
48
48
  bankAddress: {
49
49
  type: String,
50
50
  },
51
+ accountNumber: {
52
+ type: String,
53
+ },
51
54
  status: {
52
55
  type: String,
53
56
  required: true,
@@ -0,0 +1,28 @@
1
+ import { Mongoose, Model, Document, HydratedDocument } from "mongoose";
2
+ interface FintocDepositCLABEAttrs {
3
+ createdAt: Date;
4
+ userId: string;
5
+ CLABE: string;
6
+ fintocAccountNumberId?: string;
7
+ processedFintocEventIds?: string[];
8
+ orderId?: string;
9
+ metadata?: Record<string, string>;
10
+ disabled?: boolean;
11
+ disabledAt?: Date;
12
+ }
13
+ interface FintocDepositCLABEDoc extends Document {
14
+ createdAt: Date;
15
+ userId: string;
16
+ CLABE: string;
17
+ fintocAccountNumberId?: string;
18
+ processedFintocEventIds?: string[];
19
+ orderId?: string;
20
+ metadata?: Record<string, string>;
21
+ disabled?: boolean;
22
+ disabledAt?: Date;
23
+ }
24
+ interface FintocDepositCLABEModel extends Model<FintocDepositCLABEDoc> {
25
+ build(attrs: FintocDepositCLABEAttrs): HydratedDocument<FintocDepositCLABEDoc>;
26
+ }
27
+ declare const buildFintocDepositCLABE: (mongoose: Mongoose) => FintocDepositCLABEModel;
28
+ export { buildFintocDepositCLABE, FintocDepositCLABEDoc, FintocDepositCLABEAttrs, };
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildFintocDepositCLABE = void 0;
4
+ const buildFintocDepositCLABE = (mongoose) => {
5
+ if (mongoose.models.FintocDepositCLABE) {
6
+ return mongoose.model("FintocDepositCLABE");
7
+ }
8
+ const FintocDepositCLABESchema = new mongoose.Schema({
9
+ userId: {
10
+ type: String,
11
+ },
12
+ CLABE: {
13
+ type: String,
14
+ },
15
+ fintocAccountNumberId: {
16
+ type: String,
17
+ },
18
+ processedFintocEventIds: {
19
+ type: [String],
20
+ default: [],
21
+ },
22
+ orderId: {
23
+ type: String,
24
+ index: { unique: true, sparse: true },
25
+ },
26
+ metadata: {
27
+ type: mongoose.Schema.Types.Mixed,
28
+ },
29
+ disabled: {
30
+ type: Boolean,
31
+ default: false,
32
+ },
33
+ disabledAt: {
34
+ type: mongoose.Schema.Types.Date,
35
+ },
36
+ createdAt: {
37
+ type: mongoose.Schema.Types.Date,
38
+ required: true,
39
+ },
40
+ }, {
41
+ toJSON: {
42
+ transform(doc, ret) {
43
+ ret.id = ret._id.valueOf();
44
+ delete ret._id;
45
+ delete ret.__v;
46
+ },
47
+ },
48
+ });
49
+ FintocDepositCLABESchema.index({ userId: 1 }, { unique: true });
50
+ FintocDepositCLABESchema.statics.build = (attrs) => {
51
+ return new FintocDepositCLABE(attrs);
52
+ };
53
+ const FintocDepositCLABE = mongoose.model("FintocDepositCLABE", FintocDepositCLABESchema);
54
+ return FintocDepositCLABE;
55
+ };
56
+ exports.buildFintocDepositCLABE = buildFintocDepositCLABE;
@@ -0,0 +1,51 @@
1
+ import { FintocMXNWithdrawalStatus } from "@riocrypto/common";
2
+ import { Mongoose, Model, Document, HydratedDocument } from "mongoose";
3
+ interface FintocMXNWithdrawalAttrs {
4
+ createdAt: Date;
5
+ type: "transaction" | "bankAccountVerification" | "liquidityOrder" | "internalTransfer";
6
+ orderId?: string;
7
+ numberOfParts?: number;
8
+ partsCompleted?: number;
9
+ bankAccountVerificationId?: string;
10
+ bulkBankPayoutId?: string;
11
+ internalTransferId?: string;
12
+ withdrawalIdempotencyKey?: string;
13
+ FintocWithdrawals: {
14
+ uuid: string;
15
+ fintocTransferId?: string;
16
+ trackingKey?: string;
17
+ idempotencyKey?: string;
18
+ partNumber: number;
19
+ amount: number;
20
+ reference: string;
21
+ status: FintocMXNWithdrawalStatus;
22
+ }[];
23
+ orderVersion?: number;
24
+ }
25
+ interface FintocMXNWithdrawalDoc extends Document {
26
+ createdAt: Date;
27
+ type: "transaction" | "bankAccountVerification" | "liquidityOrder" | "internalTransfer";
28
+ orderId?: string;
29
+ bankAccountVerificationId?: string;
30
+ numberOfParts?: number;
31
+ bulkBankPayoutId?: string;
32
+ internalTransferId?: string;
33
+ withdrawalIdempotencyKey?: string;
34
+ partsCompleted?: number;
35
+ orderVersion?: number;
36
+ FintocWithdrawals: {
37
+ uuid: string;
38
+ fintocTransferId?: string;
39
+ trackingKey?: string;
40
+ idempotencyKey?: string;
41
+ partNumber: number;
42
+ amount: number;
43
+ status: FintocMXNWithdrawalStatus;
44
+ reference: string;
45
+ }[];
46
+ }
47
+ interface FintocMXNWithdrawalModel extends Model<FintocMXNWithdrawalDoc> {
48
+ build(attrs: FintocMXNWithdrawalAttrs): HydratedDocument<FintocMXNWithdrawalDoc>;
49
+ }
50
+ declare const buildFintocMXNWithdrawal: (mongoose: Mongoose) => FintocMXNWithdrawalModel;
51
+ export { buildFintocMXNWithdrawal, FintocMXNWithdrawalDoc, FintocMXNWithdrawalAttrs, };
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildFintocMXNWithdrawal = void 0;
4
+ const common_1 = require("@riocrypto/common");
5
+ const buildFintocMXNWithdrawal = (mongoose) => {
6
+ if (mongoose.models.FintocMXNWithdrawal) {
7
+ return mongoose.model("FintocMXNWithdrawal");
8
+ }
9
+ const FintocMXNWithdrawalSchema = new mongoose.Schema({
10
+ orderId: {
11
+ type: String,
12
+ index: { unique: true, sparse: true },
13
+ },
14
+ bankAccountVerificationId: {
15
+ type: String,
16
+ index: { unique: true, sparse: true },
17
+ },
18
+ internalTransferId: {
19
+ type: String,
20
+ index: { unique: true, sparse: true },
21
+ },
22
+ withdrawalIdempotencyKey: {
23
+ type: String,
24
+ index: { unique: true, sparse: true },
25
+ },
26
+ bulkBankPayoutId: {
27
+ type: String,
28
+ index: { unique: true, sparse: true },
29
+ },
30
+ numberOfParts: {
31
+ type: Number,
32
+ },
33
+ partsCompleted: {
34
+ type: Number,
35
+ },
36
+ type: {
37
+ type: String,
38
+ required: true,
39
+ },
40
+ createdAt: {
41
+ type: mongoose.Schema.Types.Date,
42
+ required: true,
43
+ },
44
+ FintocWithdrawals: {
45
+ type: [
46
+ {
47
+ uuid: String,
48
+ fintocTransferId: String,
49
+ trackingKey: String,
50
+ idempotencyKey: String,
51
+ amount: Number,
52
+ status: {
53
+ type: String,
54
+ enum: Object.values(common_1.FintocMXNWithdrawalStatus),
55
+ },
56
+ partNumber: Number,
57
+ reference: String,
58
+ },
59
+ ],
60
+ },
61
+ orderVersion: {
62
+ type: Number,
63
+ },
64
+ }, {
65
+ toJSON: {
66
+ transform(doc, ret) {
67
+ ret.id = ret._id.valueOf();
68
+ delete ret._id;
69
+ delete ret.__v;
70
+ if (ret.FintocWithdrawals && Array.isArray(ret.FintocWithdrawals)) {
71
+ ret.FintocWithdrawals = ret.FintocWithdrawals.map((withdrawal) => {
72
+ if (withdrawal._id) {
73
+ withdrawal.id = withdrawal._id.valueOf();
74
+ delete withdrawal._id;
75
+ }
76
+ return withdrawal;
77
+ });
78
+ }
79
+ },
80
+ },
81
+ });
82
+ FintocMXNWithdrawalSchema.statics.build = (attrs) => {
83
+ return new FintocMXNWithdrawal(attrs);
84
+ };
85
+ const FintocMXNWithdrawal = mongoose.model("FintocMXNWithdrawal", FintocMXNWithdrawalSchema);
86
+ return FintocMXNWithdrawal;
87
+ };
88
+ exports.buildFintocMXNWithdrawal = buildFintocMXNWithdrawal;
@@ -18,6 +18,10 @@ interface FireblocksVaultAttrs {
18
18
  bulkCryptoPaymentId: string;
19
19
  crypto: Crypto;
20
20
  }[];
21
+ activePaymentAddressVerifications?: {
22
+ verificationId: string;
23
+ crypto: Crypto;
24
+ }[];
21
25
  }
22
26
  interface FireblocksVaultDoc extends mongoose.Document {
23
27
  userId: string;
@@ -37,6 +41,10 @@ interface FireblocksVaultDoc extends mongoose.Document {
37
41
  bulkCryptoPaymentId: string;
38
42
  crypto: Crypto;
39
43
  }[];
44
+ activePaymentAddressVerifications?: {
45
+ verificationId: string;
46
+ crypto: Crypto;
47
+ }[];
40
48
  }
41
49
  interface FireblocksVaultModel extends mongoose.Model<FireblocksVaultDoc> {
42
50
  build(attrs: FireblocksVaultAttrs): HydratedDocument<FireblocksVaultDoc>;
@@ -38,6 +38,14 @@ const buildFireblocksVault = (mongoose) => {
38
38
  },
39
39
  ],
40
40
  },
41
+ activePaymentAddressVerifications: {
42
+ type: [
43
+ {
44
+ verificationId: String,
45
+ crypto: String,
46
+ },
47
+ ],
48
+ },
41
49
  }, {
42
50
  toJSON: {
43
51
  transform(doc, ret) {
@@ -46,6 +46,9 @@ interface InternalBalancesDoc extends mongoose.Document {
46
46
  STP: {
47
47
  [key in Fiat & Crypto]: number;
48
48
  };
49
+ fintoc: {
50
+ [key in Fiat & Crypto]: number;
51
+ };
49
52
  alfin: {
50
53
  [key in Fiat & Crypto]: number;
51
54
  };
@@ -71,6 +71,9 @@ const buildInternalBalances = (mongoose) => {
71
71
  [common_1.TreasuryProvider.Alfin]: {
72
72
  type: Object,
73
73
  },
74
+ [common_1.TreasuryProvider.Fintoc]: {
75
+ type: Object,
76
+ },
74
77
  }, {
75
78
  toJSON: {
76
79
  transform(doc, ret) {
@@ -0,0 +1,49 @@
1
+ import { Crypto, ProcessorReadinessStatus, ProcessorReadinessVerificationMethod } from "@riocrypto/common";
2
+ import { Mongoose, Model, Document, HydratedDocument } from "mongoose";
3
+ interface PaymentAddressVerificationAttrs {
4
+ createdAt: Date;
5
+ userId: string;
6
+ crypto: Crypto;
7
+ fireblocksVaultId: string;
8
+ address: string;
9
+ memo?: string;
10
+ status: ProcessorReadinessStatus;
11
+ testAmount?: number;
12
+ observedTransfer?: {
13
+ amount: number;
14
+ blockchainTxId?: string;
15
+ fireblocksTransferId?: string;
16
+ originBlockchainAddress?: string;
17
+ receivedAt: Date;
18
+ };
19
+ verifiedAt?: Date;
20
+ verifiedVia?: ProcessorReadinessVerificationMethod;
21
+ verifiedByAdminId?: string;
22
+ verificationNote?: string;
23
+ }
24
+ interface PaymentAddressVerificationDoc extends Document {
25
+ createdAt: Date;
26
+ userId: string;
27
+ crypto: Crypto;
28
+ fireblocksVaultId: string;
29
+ address: string;
30
+ memo?: string;
31
+ status: ProcessorReadinessStatus;
32
+ testAmount?: number;
33
+ observedTransfer?: {
34
+ amount: number;
35
+ blockchainTxId?: string;
36
+ fireblocksTransferId?: string;
37
+ originBlockchainAddress?: string;
38
+ receivedAt: Date;
39
+ };
40
+ verifiedAt?: Date;
41
+ verifiedVia?: ProcessorReadinessVerificationMethod;
42
+ verifiedByAdminId?: string;
43
+ verificationNote?: string;
44
+ }
45
+ interface PaymentAddressVerificationModel extends Model<PaymentAddressVerificationDoc> {
46
+ build(attrs: PaymentAddressVerificationAttrs): HydratedDocument<PaymentAddressVerificationDoc>;
47
+ }
48
+ declare const buildPaymentAddressVerification: (mongoose: Mongoose) => PaymentAddressVerificationModel;
49
+ export { buildPaymentAddressVerification, PaymentAddressVerificationDoc, PaymentAddressVerificationAttrs, };
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildPaymentAddressVerification = void 0;
4
+ // What we have proven about one crypto address a user pays us at. See the
5
+ // PaymentAddressVerification type in common for why this exists and why it is
6
+ // keyed by vault rather than by address.
7
+ const buildPaymentAddressVerification = (mongoose) => {
8
+ if (mongoose.models.PaymentAddressVerification) {
9
+ return mongoose.model("PaymentAddressVerification");
10
+ }
11
+ const PaymentAddressVerificationSchema = new mongoose.Schema({
12
+ userId: {
13
+ type: String,
14
+ required: true,
15
+ },
16
+ crypto: {
17
+ type: String,
18
+ required: true,
19
+ },
20
+ fireblocksVaultId: {
21
+ type: String,
22
+ required: true,
23
+ },
24
+ address: {
25
+ type: String,
26
+ required: true,
27
+ },
28
+ memo: {
29
+ type: String,
30
+ },
31
+ status: {
32
+ type: String,
33
+ required: true,
34
+ },
35
+ testAmount: {
36
+ type: Number,
37
+ },
38
+ observedTransfer: {
39
+ type: Object,
40
+ },
41
+ verifiedAt: {
42
+ type: mongoose.Schema.Types.Date,
43
+ },
44
+ verifiedVia: {
45
+ type: String,
46
+ },
47
+ verifiedByAdminId: {
48
+ type: String,
49
+ },
50
+ verificationNote: {
51
+ type: String,
52
+ },
53
+ createdAt: {
54
+ type: mongoose.Schema.Types.Date,
55
+ required: true,
56
+ },
57
+ }, {
58
+ toJSON: {
59
+ transform(doc, ret) {
60
+ ret.id = ret._id.valueOf();
61
+ delete ret._id;
62
+ delete ret.__v;
63
+ },
64
+ },
65
+ });
66
+ // One record per address, where an address is a vault and an asset. Unique
67
+ // because the inbound webhook and a customer starting a test can arrive at the
68
+ // same moment, and two records disagreeing about status would let a test
69
+ // deposit match a row that nobody is looking at.
70
+ PaymentAddressVerificationSchema.index({ userId: 1, crypto: 1, fireblocksVaultId: 1 }, { unique: true });
71
+ PaymentAddressVerificationSchema.statics.build = (attrs) => {
72
+ return new PaymentAddressVerification(attrs);
73
+ };
74
+ const PaymentAddressVerification = mongoose.model("PaymentAddressVerification", PaymentAddressVerificationSchema);
75
+ return PaymentAddressVerification;
76
+ };
77
+ exports.buildPaymentAddressVerification = buildPaymentAddressVerification;