@riocrypto/common-server 1.0.2922 → 1.0.2925

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.
@@ -48,6 +48,7 @@ class CoincoverClient {
48
48
  [common_1.Crypto.USDCPolygon]: "usd-coin",
49
49
  [common_1.Crypto.USDCStellar]: "usd-coin",
50
50
  [common_1.Crypto.USDCBase]: "usd-coin",
51
+ [common_1.Crypto.USDCArc]: "usd-coin",
51
52
  [common_1.Crypto.USDCSolana]: "usd-coin",
52
53
  [common_1.Crypto.USDCPolygonBridged]: "usd-coin",
53
54
  [common_1.Crypto.USDCTempoBridged]: "usd-coin",
@@ -238,6 +238,7 @@ class FireblocksClient {
238
238
  common_1.Crypto.USDCBase,
239
239
  common_1.Crypto.USDCPolygonBridged,
240
240
  common_1.Crypto.USDCTempoBridged,
241
+ common_1.Crypto.USDCArc,
241
242
  common_1.Crypto.USDCSolana,
242
243
  common_1.Crypto.USDTEthereum,
243
244
  common_1.Crypto.USDTPolygon,
@@ -0,0 +1,4 @@
1
+ import { Crypto } from "@riocrypto/common";
2
+ import { Mongoose } from "mongoose";
3
+ export declare const getLaunchedCryptos: (mongoose: Mongoose) => Promise<Crypto[]>;
4
+ export declare const assertCryptoLaunched: (mongoose: Mongoose, crypto?: Crypto | string | null) => Promise<void>;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.assertCryptoLaunched = exports.getLaunchedCryptos = void 0;
13
+ const common_1 = require("@riocrypto/common");
14
+ const rio_settings_1 = require("../models/rio-settings");
15
+ const getLaunchedCryptos = (mongoose) => __awaiter(void 0, void 0, void 0, function* () {
16
+ var _a;
17
+ const RioSettings = (0, rio_settings_1.buildRioSettings)(mongoose);
18
+ const rioSettings = yield RioSettings.findOne().select("launchedCryptos");
19
+ return (_a = rioSettings === null || rioSettings === void 0 ? void 0 : rioSettings.launchedCryptos) !== null && _a !== void 0 ? _a : [];
20
+ });
21
+ exports.getLaunchedCryptos = getLaunchedCryptos;
22
+ // Rejects a customer-facing request for a crypto that is still behind the
23
+ // launch switch. Cryptos outside PRELAUNCH_CRYPTOS never touch the database.
24
+ const assertCryptoLaunched = (mongoose, crypto) => __awaiter(void 0, void 0, void 0, function* () {
25
+ if (!crypto || !(0, common_1.isPrelaunchCrypto)(crypto)) {
26
+ return;
27
+ }
28
+ const launchedCryptos = yield (0, exports.getLaunchedCryptos)(mongoose);
29
+ if (!(0, common_1.isCryptoLaunched)(crypto, launchedCryptos)) {
30
+ throw new common_1.CryptoNotLaunchedError(crypto);
31
+ }
32
+ });
33
+ exports.assertCryptoLaunched = assertCryptoLaunched;
@@ -19,6 +19,9 @@ const getNetworkFees = (crypto, conversionRateToUSD) => {
19
19
  else if (crypto === common_1.Crypto.USDCTempoBridged) {
20
20
  withdrawFeeInUSD = 0.01;
21
21
  }
22
+ else if (crypto === common_1.Crypto.USDCArc) {
23
+ withdrawFeeInUSD = 0.01;
24
+ }
22
25
  else if (crypto === common_1.Crypto.USDCBase || crypto === common_1.Crypto.EURCBase) {
23
26
  withdrawFeeInUSD = 0.01;
24
27
  }
@@ -24,7 +24,12 @@ const pickByShare = (candidates, position) => {
24
24
  // from the configured split.
25
25
  //
26
26
  // A percentage divides volume between the rails that are actually available to
27
- // the customer; it is not a switch. A rail left at zero, left out of the rule, or
27
+ // the customer; it is not a switch. On a scheduled corridor the percentages are
28
+ // whichever window covers the current minute where that corridor banks, so the
29
+ // same order placed two hours later can be divided differently. Everything below
30
+ // that point is indifferent to where the shares came from.
31
+ //
32
+ // A rail left at zero, left out of the rule, or
28
33
  // belonging to a corridor with no rule at all still takes their orders when it is
29
34
  // the only one available to them, which is why the candidate set comes from the
30
35
  // corridor rather than from the rule. What keeps an order away from a rail is the
@@ -96,6 +101,11 @@ const resolveProcessor = ({ country, fiat, purpose, routingConfig, excludedProce
96
101
  // ruleless until an admin first saves one - as is any corridor whose shares
97
102
  // were all cleared, since the settings page stores that as no rule at all.
98
103
  const rule = getRule(routingConfig, country, fiat, purpose);
104
+ // The split in force at this instant, which on a scheduled corridor depends on
105
+ // what time it is where the corridor banks. Resolved from `decidedAt` so the
106
+ // shares, the window and the timestamp recorded on the decision can never end
107
+ // up describing different minutes.
108
+ const { percentages: configuredPercentages, matchedWindow } = (0, common_1.resolveProcessorRoutingPercentages)(rule, country, fiat, purpose, decidedAt);
99
109
  // Starts from the corridor's rails rather than from the rails the rule names,
100
110
  // because a percentage decides how volume is divided between the rails a
101
111
  // customer can use - it is not what makes a rail usable. Also drops any share
@@ -139,11 +149,21 @@ const resolveProcessor = ({ country, fiat, purpose, routingConfig, excludedProce
139
149
  const candidates = enablementOverridden
140
150
  ? eligible
141
151
  : eligible.filter((processor) => !disabled.includes(processor) && !gatedUnset.includes(processor));
142
- // What was filtered, carried by every decision below. Kept in one place so a
143
- // branch cannot quietly stop reporting one of them, since these sets are the
144
- // whole reason a decision can still be explained weeks later.
145
- const filtered = Object.assign({ corridor, excluded: excludedProcessors, disabled,
146
- unset }, (enablementOverridden ? { enablementOverridden: true } : {}));
152
+ // What was filtered and which window the shares came from, carried by every
153
+ // decision below. Kept in one place so a branch cannot quietly stop reporting
154
+ // one of them, since this is the whole reason a decision can still be explained
155
+ // weeks later. The window is recorded even on the refusals, because "the
156
+ // afternoon window gave Fintoc everything and this customer has Fintoc off" is
157
+ // the shape of the question that gets asked.
158
+ const filtered = Object.assign(Object.assign({ corridor, excluded: excludedProcessors, disabled,
159
+ unset }, (enablementOverridden ? { enablementOverridden: true } : {})), (matchedWindow
160
+ ? {
161
+ window: {
162
+ startMinute: matchedWindow.startMinute,
163
+ endMinute: matchedWindow.endMinute,
164
+ },
165
+ }
166
+ : {}));
147
167
  if (!candidates.length) {
148
168
  return Object.assign(Object.assign({
149
169
  // Told apart because they are different conversations. One customer turned
@@ -155,13 +175,10 @@ const resolveProcessor = ({ country, fiat, purpose, routingConfig, excludedProce
155
175
  : common_1.RoutingDecisionReason.NoEnabledCandidate }, filtered), { decidedAt });
156
176
  }
157
177
  const shares = candidates
158
- .map((processor) => {
159
- var _a;
160
- return ({
161
- processor,
162
- percentage: Number((_a = rule === null || rule === void 0 ? void 0 : rule.percentages) === null || _a === void 0 ? void 0 : _a[processor]) || 0,
163
- });
164
- })
178
+ .map((processor) => ({
179
+ processor,
180
+ percentage: Number(configuredPercentages[processor]) || 0,
181
+ }))
165
182
  .filter((candidate) => candidate.percentage > 0);
166
183
  const percentages = Object.fromEntries(shares.map((share) => [share.processor, share.percentage]));
167
184
  // None of the rails this customer can use carries a share - or no rule is
package/build/index.d.ts CHANGED
@@ -187,6 +187,7 @@ export * from "./helpers/get-exchange-rates-with-markups";
187
187
  export * from "./helpers/get-order-from-static-reference";
188
188
  export * from "./helpers/get-bulk-bank-payment-from-static-reference";
189
189
  export * from "./helpers/is-after-hours";
190
+ export * from "./helpers/assert-crypto-launched";
190
191
  export * from "./helpers/interpolate-forward-curve-rate";
191
192
  export * from "./helpers/find-user-tier-forward-curve-rate";
192
193
  export * from "./helpers/resolve-forward-curve-rate";
package/build/index.js CHANGED
@@ -203,6 +203,7 @@ __exportStar(require("./helpers/get-exchange-rates-with-markups"), exports);
203
203
  __exportStar(require("./helpers/get-order-from-static-reference"), exports);
204
204
  __exportStar(require("./helpers/get-bulk-bank-payment-from-static-reference"), exports);
205
205
  __exportStar(require("./helpers/is-after-hours"), exports);
206
+ __exportStar(require("./helpers/assert-crypto-launched"), exports);
206
207
  __exportStar(require("./helpers/interpolate-forward-curve-rate"), exports);
207
208
  __exportStar(require("./helpers/find-user-tier-forward-curve-rate"), exports);
208
209
  __exportStar(require("./helpers/resolve-forward-curve-rate"), exports);
@@ -97,6 +97,7 @@ interface RioSettingsAttrs {
97
97
  };
98
98
  };
99
99
  };
100
+ launchedCryptos?: Crypto[];
100
101
  }
101
102
  interface RioSettingsDoc extends mongoose.Document {
102
103
  platformFee: number;
@@ -194,6 +195,7 @@ interface RioSettingsDoc extends mongoose.Document {
194
195
  };
195
196
  };
196
197
  };
198
+ launchedCryptos?: Crypto[];
197
199
  }
198
200
  interface RioSettingsModel extends mongoose.Model<RioSettingsDoc> {
199
201
  build(attrs: RioSettingsAttrs): HydratedDocument<RioSettingsDoc>;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.buildRioSettings = void 0;
4
+ const common_1 = require("@riocrypto/common");
4
5
  const buildRioSettings = (mongoose) => {
5
6
  // if model is already defined, return it
6
7
  if (mongoose.models.RioSettings) {
@@ -86,6 +87,10 @@ const buildRioSettings = (mongoose) => {
86
87
  isMaintenanceModeActive: {
87
88
  type: Object,
88
89
  },
90
+ launchedCryptos: {
91
+ type: [String],
92
+ enum: Object.values(common_1.Crypto),
93
+ },
89
94
  }, {
90
95
  toJSON: {
91
96
  transform(doc, ret) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riocrypto/common-server",
3
- "version": "1.0.2922",
3
+ "version": "1.0.2925",
4
4
  "description": "",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",
@@ -28,7 +28,7 @@
28
28
  "@google-cloud/secret-manager": "^5.6.0",
29
29
  "@google-cloud/storage": "^7.19.0",
30
30
  "@hyperdx/node-opentelemetry": "^0.10.3",
31
- "@riocrypto/common": "1.0.2720",
31
+ "@riocrypto/common": "1.0.2726",
32
32
  "@slack/web-api": "^7.15.0",
33
33
  "@types/express": "^4.17.25",
34
34
  "axios": "1.18.1",