@riocrypto/common-server 1.0.2878 → 1.0.2880

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 +76 -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 +128 -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" | "noEligibleCandidate" | "noEnabledCandidate";
17
+ }
18
+ export declare const resolveProcessor: ({ country, fiat, purpose, routingConfig, excludedProcessors, disabledProcessors, customRioBankAccount, randomSeed, }: ResolveProcessorParams) => ResolveProcessorResult;
@@ -0,0 +1,128 @@
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, left out of the rule, or
27
+ // belonging to a corridor with no rule at all still takes their orders when it is
28
+ // the only one they have left enabled, which is why the candidate set comes from
29
+ // the corridor rather than from the rule. Switching a rail off is the only way to
30
+ // keep an order away from 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
+ // An absent rule is read as every rail at zero rather than as a reason to stop.
77
+ // Bailing out here would hand the decision to the structural default, which
78
+ // knows nothing about which rails the customer accepts, and every corridor is
79
+ // ruleless until an admin first saves one - as is any corridor whose shares
80
+ // were all cleared, since the settings page stores that as no rule at all.
81
+ const rule = getRule(routingConfig, country, fiat, purpose);
82
+ // Starts from the corridor's rails rather than from the rails the rule names,
83
+ // because a percentage decides how volume is divided between the rails a
84
+ // customer can use - it is not what makes a rail usable. Also drops any share
85
+ // stored against a rail this purpose does not serve, which nothing dispatches.
86
+ const corridorProcessors = (0, common_1.getProcessorsForCorridor)(country, fiat, purpose);
87
+ const eligible = corridorProcessors.filter(isEligible);
88
+ if (!eligible.length) {
89
+ return { reason: "noEligibleCandidate" };
90
+ }
91
+ const candidates = eligible.filter(isUsable);
92
+ if (!candidates.length) {
93
+ return { reason: "noEnabledCandidate" };
94
+ }
95
+ const shares = candidates
96
+ .map((processor) => {
97
+ var _a;
98
+ return ({
99
+ processor,
100
+ percentage: Number((_a = rule === null || rule === void 0 ? void 0 : rule.percentages) === null || _a === void 0 ? void 0 : _a[processor]) || 0,
101
+ });
102
+ })
103
+ .filter((candidate) => candidate.percentage > 0);
104
+ // None of the rails this customer can use carries a share - or no rule is
105
+ // configured at all - so there is no split to draw from. Refusing the order
106
+ // would read a zero as "never use this rail", when all it says is where volume
107
+ // goes while there is somewhere else to send it. Prefers the corridor default
108
+ // and otherwise the corridor's own order, so the rail a customer in this
109
+ // position gets is predictable rather than rolled.
110
+ if (!shares.length) {
111
+ const fallback = (0, common_1.getDefaultProcessor)(country, fiat, purpose, excludedProcessors);
112
+ return {
113
+ processor: fallback && candidates.includes(fallback) ? fallback : candidates[0],
114
+ reason: "enabledRailWithoutShare",
115
+ };
116
+ }
117
+ if (shares.length === 1) {
118
+ return { processor: shares[0].processor, reason: "onlyCandidate" };
119
+ }
120
+ // Rolled per order, so the realized share converges on the configured
121
+ // percentages by order count. Nothing is persisted here: a caller that needs
122
+ // the same answer twice passes back the seed it used.
123
+ return {
124
+ processor: pickByShare(shares, randomSeed !== null && randomSeed !== void 0 ? randomSeed : Math.random()),
125
+ reason: "split",
126
+ };
127
+ };
128
+ 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;