@riocrypto/common-server 1.0.2842 → 1.0.2844

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.
@@ -91,6 +91,8 @@ declare class BitsoClient {
91
91
  createCryptoWithdrawal(amount: number, crypto: Crypto, address: string): Promise<Object>;
92
92
  getDepositByHash(hash: string): Promise<Object>;
93
93
  getDepositByConcepto(concepto: string): Promise<Object>;
94
+ listFundings(limit?: number): Promise<any[]>;
95
+ listWithdrawals(limit?: number): Promise<any[]>;
94
96
  signRequest(requestConfig: AxiosRequestConfig): AxiosRequestConfig;
95
97
  }
96
98
  export declare const buildBitsoClient: () => Promise<BitsoClient>;
@@ -482,6 +482,44 @@ class BitsoClient {
482
482
  return data.payload.find((deposit) => deposit.details.concepto === concepto);
483
483
  });
484
484
  }
485
+ // List recent fundings (deposits) so callers can import exchange-native
486
+ // deposits done directly on Bitso. Bitso caps `limit` at 100 per page.
487
+ listFundings(limit = 100) {
488
+ return __awaiter(this, void 0, void 0, function* () {
489
+ const requestConfig = {
490
+ method: "GET",
491
+ url: `${this.baseUrl}/api/v3/fundings/?limit=${limit}`,
492
+ headers: {
493
+ "Content-Type": "application/json",
494
+ },
495
+ };
496
+ const signedRequestConfig = this.signRequest(requestConfig);
497
+ const { data } = yield this.axiosClient(signedRequestConfig);
498
+ if (!data.success) {
499
+ throw new Error("Error listing Bitso fundings");
500
+ }
501
+ return data.payload;
502
+ });
503
+ }
504
+ // List recent withdrawals so callers can import exchange-native withdrawals
505
+ // done directly on Bitso. Bitso caps `limit` at 100 per page.
506
+ listWithdrawals(limit = 100) {
507
+ return __awaiter(this, void 0, void 0, function* () {
508
+ const requestConfig = {
509
+ method: "GET",
510
+ url: `${this.baseUrl}/api/v3/withdrawals/?limit=${limit}`,
511
+ headers: {
512
+ "Content-Type": "application/json",
513
+ },
514
+ };
515
+ const signedRequestConfig = this.signRequest(requestConfig);
516
+ const { data } = yield this.axiosClient(signedRequestConfig);
517
+ if (!data.success) {
518
+ throw new Error("Error listing Bitso withdrawals");
519
+ }
520
+ return data.payload;
521
+ });
522
+ }
485
523
  signRequest(requestConfig) {
486
524
  var _a;
487
525
  const url = new URL(requestConfig.url || "");
@@ -180,7 +180,7 @@ declare class ClusterClient {
180
180
  stopExternalTradingAlgorithm(id: string): Promise<ExternalTradingAlgorithm>;
181
181
  getExternalTradingAlgorithm(id: string): Promise<ExternalTradingAlgorithm>;
182
182
  getExternalTrade(id: string): Promise<ExternalTrade>;
183
- placeExternalTrade({ provider, type, originCurrency, destinationCurrency, requestedOriginAmount, requestedDestinationAmount, limitPrice, twoWaySettlementDateOffset, arbitrageSessionId, fxTradeId, timeInForce, valueDate, }: {
183
+ placeExternalTrade({ provider, type, originCurrency, destinationCurrency, requestedOriginAmount, requestedDestinationAmount, limitPrice, twoWaySettlementDateOffset, arbitrageSessionId, fxTradeId, internalTradeId, timeInForce, valueDate, }: {
184
184
  provider: ExternalTradingProvider;
185
185
  type: ExternalTradeType;
186
186
  originCurrency: Crypto | Fiat;
@@ -191,6 +191,7 @@ declare class ClusterClient {
191
191
  twoWaySettlementDateOffset?: number;
192
192
  arbitrageSessionId?: string;
193
193
  fxTradeId?: string;
194
+ internalTradeId?: string;
194
195
  timeInForce?: "day" | "gtc" | "ioc" | "fok";
195
196
  valueDate?: string;
196
197
  }): Promise<ExternalTrade>;
@@ -654,7 +654,7 @@ class ClusterClient {
654
654
  return response.data;
655
655
  });
656
656
  }
657
- placeExternalTrade({ provider, type, originCurrency, destinationCurrency, requestedOriginAmount, requestedDestinationAmount, limitPrice, twoWaySettlementDateOffset, arbitrageSessionId, fxTradeId, timeInForce, valueDate, }) {
657
+ placeExternalTrade({ provider, type, originCurrency, destinationCurrency, requestedOriginAmount, requestedDestinationAmount, limitPrice, twoWaySettlementDateOffset, arbitrageSessionId, fxTradeId, internalTradeId, timeInForce, valueDate, }) {
658
658
  return __awaiter(this, void 0, void 0, function* () {
659
659
  const response = yield this.axios.post(`${this.baseUrl}/api/trading/external/trades`, {
660
660
  provider,
@@ -667,6 +667,7 @@ class ClusterClient {
667
667
  twoWaySettlementDateOffset,
668
668
  arbitrageSessionId,
669
669
  fxTradeId,
670
+ internalTradeId,
670
671
  timeInForce,
671
672
  valueDate,
672
673
  }, {
@@ -57,6 +57,9 @@ class CoincoverClient {
57
57
  [common_1.Crypto.SOL]: "solana",
58
58
  [common_1.Crypto.XLM]: "stellar",
59
59
  [common_1.Crypto.POL]: "matic-network",
60
+ // Synthetic catch-all for unmapped assets seen on imported treasury
61
+ // movements; it has no CoinGecko id and is never priced.
62
+ [common_1.Crypto.Other]: "",
60
63
  };
61
64
  this.axiosClient = (0, axios_with_logging_1.buildAxiosWithLogging)();
62
65
  }
@@ -51,6 +51,12 @@ declare class FireblocksClient {
51
51
  getSingularExchangeCryptoBalance(id: string, usdType: "usdc" | "usdt"): Promise<number>;
52
52
  getExchangeFiatBalance(): Promise<number>;
53
53
  getTransactions(vaultId: string, crypto: Crypto, nextPage?: string): Promise<any>;
54
+ listVaultTransactions(params: {
55
+ vaultId: string;
56
+ direction: "incoming" | "outgoing";
57
+ afterMs: number;
58
+ status?: string;
59
+ }): Promise<TransactionResponse[]>;
54
60
  getDepositAddress(vaultId: string, crypto: Crypto): Promise<string>;
55
61
  createVault(userId: string, name: string, type: "transactional", number?: number): Promise<string>;
56
62
  createWallet(vaultId: string, crypto: Crypto): Promise<{
@@ -356,6 +356,45 @@ class FireblocksClient {
356
356
  return transactionData;
357
357
  });
358
358
  }
359
+ // Lists a vault's transactions in one direction (incoming = deposits to the
360
+ // vault, outgoing = withdrawals from the vault) created at/after `afterMs`
361
+ // (unix ms). Pages through all results. Used by the treasury import cron to
362
+ // detect movements performed directly in Fireblocks (not initiated by Rio).
363
+ //
364
+ // Note the SDK paging quirk (fireblocks-sdk-js#268): when a page filter is
365
+ // provided it takes priority over the next-page path, so we pass the filter
366
+ // only on the first request and the path on subsequent requests.
367
+ listVaultTransactions(params) {
368
+ var _a;
369
+ return __awaiter(this, void 0, void 0, function* () {
370
+ const { vaultId, direction, afterMs, status } = params;
371
+ const filter = {
372
+ after: String(Math.floor(afterMs)),
373
+ orderBy: "createdAt",
374
+ limit: 200,
375
+ };
376
+ if (direction === "incoming") {
377
+ filter.destId = vaultId;
378
+ }
379
+ else {
380
+ filter.sourceId = vaultId;
381
+ }
382
+ if (status) {
383
+ filter.status = status;
384
+ }
385
+ const results = [];
386
+ let nextPage;
387
+ let pagesFetched = 0;
388
+ const MAX_PAGES = 20;
389
+ do {
390
+ const response = yield this.fireblocks.getTransactionsWithPageInfo(nextPage ? undefined : filter, nextPage);
391
+ results.push(...(response.transactions || []));
392
+ nextPage = ((_a = response.pageDetails) === null || _a === void 0 ? void 0 : _a.nextPage) || undefined;
393
+ pagesFetched += 1;
394
+ } while (nextPage && pagesFetched < MAX_PAGES);
395
+ return results;
396
+ });
397
+ }
359
398
  getDepositAddress(vaultId, crypto) {
360
399
  return __awaiter(this, void 0, void 0, function* () {
361
400
  let addresses = yield this.fireblocks.getDepositAddresses(vaultId, crypto);
@@ -0,0 +1,78 @@
1
+ import { RioEnv } from "@riocrypto/common";
2
+ export declare const KRAKEN_ASSET_USD = "ZUSD";
3
+ export interface KrakenDepositMethod {
4
+ method: string;
5
+ limit: string | boolean;
6
+ fee?: string;
7
+ "gen-address"?: boolean;
8
+ "address-setup-fee"?: string;
9
+ }
10
+ export interface KrakenDepositAddress {
11
+ address: string;
12
+ expiretm: string;
13
+ new?: boolean;
14
+ tag?: string;
15
+ memo?: string;
16
+ }
17
+ export interface KrakenFundingStatus {
18
+ method: string;
19
+ aclass: string;
20
+ asset: string;
21
+ refid: string;
22
+ txid: string;
23
+ info: string;
24
+ amount: string;
25
+ fee: string;
26
+ time: number;
27
+ status: string;
28
+ "status-prop"?: string;
29
+ }
30
+ export interface KrakenWithdrawInfo {
31
+ method: string;
32
+ limit: string;
33
+ amount: string;
34
+ fee: string;
35
+ }
36
+ export interface KrakenLedgerEntry {
37
+ refid: string;
38
+ time: number;
39
+ type: string;
40
+ subtype: string;
41
+ aclass: string;
42
+ asset: string;
43
+ amount: string;
44
+ fee: string;
45
+ balance: string;
46
+ }
47
+ declare class KrakenClient {
48
+ private apiKey;
49
+ private env;
50
+ private axiosClient;
51
+ private decodedSecret;
52
+ private lastNonce;
53
+ private requestQueue;
54
+ private restBaseUrl;
55
+ constructor(apiKey: string, apiSecret: string, env: RioEnv);
56
+ private assertFundingAllowed;
57
+ private nextNonce;
58
+ private sign;
59
+ private privatePost;
60
+ private executePrivatePost;
61
+ getBalance(asset: string): Promise<number>;
62
+ getAllBalances(assets: string[]): Promise<Record<string, number>>;
63
+ getDepositMethods(asset: string): Promise<KrakenDepositMethod[]>;
64
+ getDepositAddresses(asset: string, method: string, isNew?: boolean): Promise<KrakenDepositAddress[]>;
65
+ getDepositStatus(asset: string, method?: string): Promise<KrakenFundingStatus[]>;
66
+ getWithdrawInfo(asset: string, key: string, amount: number): Promise<KrakenWithdrawInfo>;
67
+ withdraw(asset: string, key: string, amount: number): Promise<string>;
68
+ getWithdrawStatus(asset: string, method?: string): Promise<KrakenFundingStatus[]>;
69
+ getWithdrawStatusByRefid(asset: string, refid: string): Promise<KrakenFundingStatus | undefined>;
70
+ getDepositByTxId(asset: string, txid: string): Promise<KrakenFundingStatus | undefined>;
71
+ getLedgers(params?: {
72
+ type?: string;
73
+ asset?: string;
74
+ start?: number;
75
+ }): Promise<Record<string, KrakenLedgerEntry>>;
76
+ }
77
+ export declare const buildKrakenClient: () => Promise<KrakenClient>;
78
+ export type { KrakenClient };
@@ -0,0 +1,253 @@
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
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.buildKrakenClient = exports.KRAKEN_ASSET_USD = void 0;
16
+ const crypto_1 = __importDefault(require("crypto"));
17
+ const common_1 = require("@riocrypto/common");
18
+ const axios_with_logging_1 = require("./axios-with-logging");
19
+ const secret_manager_client_1 = require("./secret-manager-client");
20
+ // Kraken REST hosts. There is no public Kraken spot testnet, but institutional
21
+ // clients get a separate UAT environment. The host is selected purely from
22
+ // RIO_ENV: only production talks to the live account; every other environment
23
+ // points at the UAT host so it can never move funds on the real account.
24
+ const KRAKEN_PROD_REST_BASE_URL = "https://api.kraken.com";
25
+ const KRAKEN_UAT_REST_BASE_URL = "https://api.uat.kraken.com";
26
+ const getKrakenRestBaseUrl = (env) => env === common_1.RioEnv.Production
27
+ ? KRAKEN_PROD_REST_BASE_URL
28
+ : KRAKEN_UAT_REST_BASE_URL;
29
+ // Kraken Balance keys. Fiat USD is `ZUSD`; the stablecoins use their ticker.
30
+ exports.KRAKEN_ASSET_USD = "ZUSD";
31
+ class KrakenClient {
32
+ constructor(apiKey, apiSecret, env) {
33
+ this.apiKey = apiKey;
34
+ this.env = env;
35
+ // Kraken nonces must strictly increase per key. We keep a monotonic floor so
36
+ // two calls in the same millisecond can't produce a decreasing nonce.
37
+ this.lastNonce = 0;
38
+ // Serialization queue for private requests. Even with strictly increasing
39
+ // nonces, concurrent private requests can arrive at Kraken out of order,
40
+ // which Kraken rejects as `EAPI:Invalid nonce`. Chaining every private
41
+ // request through this promise guarantees one in-flight request at a time so
42
+ // nonces always arrive in order.
43
+ this.requestQueue = Promise.resolve();
44
+ this.decodedSecret = Buffer.from(apiSecret, "base64");
45
+ this.axiosClient = (0, axios_with_logging_1.buildAxiosWithLogging)();
46
+ this.restBaseUrl = getKrakenRestBaseUrl(env);
47
+ }
48
+ // Fail-closed guard: a non-production environment must never move funds
49
+ // against the LIVE Kraken host. The host is derived from RIO_ENV, so this
50
+ // also catches an unknown/unset RIO_ENV resolving to the live host.
51
+ assertFundingAllowed() {
52
+ const isLiveHost = this.restBaseUrl === KRAKEN_PROD_REST_BASE_URL;
53
+ if (this.env !== common_1.RioEnv.Production && isLiveHost) {
54
+ throw new Error("Refusing to move Kraken funds: a non-production environment is pointed at the live Kraken host.");
55
+ }
56
+ }
57
+ nextNonce() {
58
+ const now = Date.now();
59
+ const nonce = now > this.lastNonce ? now : this.lastNonce + 1;
60
+ this.lastNonce = nonce;
61
+ return nonce;
62
+ }
63
+ sign(path, nonce, postData) {
64
+ // API-Sign = base64( HMAC-SHA512( path + SHA256(nonce + postData),
65
+ // base64decode(secret) ) )
66
+ const sha256 = crypto_1.default
67
+ .createHash("sha256")
68
+ .update(nonce + postData)
69
+ .digest();
70
+ const message = Buffer.concat([Buffer.from(path, "utf8"), sha256]);
71
+ return crypto_1.default
72
+ .createHmac("sha512", this.decodedSecret)
73
+ .update(message)
74
+ .digest("base64");
75
+ }
76
+ privatePost(method, params = {}) {
77
+ return __awaiter(this, void 0, void 0, function* () {
78
+ // Queue behind any in-flight private request so nonces reach Kraken in
79
+ // strictly increasing order. The queue must survive individual failures,
80
+ // hence the `.catch` on the stored promise (the caller still sees the
81
+ // original rejection via `run`).
82
+ const run = this.requestQueue.then(() => this.executePrivatePost(method, params));
83
+ this.requestQueue = run.catch(() => undefined);
84
+ return run;
85
+ });
86
+ }
87
+ executePrivatePost(method, params = {}) {
88
+ return __awaiter(this, void 0, void 0, function* () {
89
+ const path = `/0/private/${method}`;
90
+ const nonce = this.nextNonce();
91
+ const form = new URLSearchParams();
92
+ form.set("nonce", String(nonce));
93
+ for (const [key, value] of Object.entries(params)) {
94
+ if (value !== undefined && value !== null) {
95
+ form.set(key, String(value));
96
+ }
97
+ }
98
+ const postData = form.toString();
99
+ const signature = this.sign(path, nonce, postData);
100
+ const { data } = yield this.axiosClient.post(`${this.restBaseUrl}${path}`, postData, {
101
+ headers: {
102
+ "API-Key": this.apiKey,
103
+ "API-Sign": signature,
104
+ "Content-Type": "application/x-www-form-urlencoded",
105
+ },
106
+ });
107
+ // Kraken returns HTTP 200 with errors inside an `error` array.
108
+ if ((data === null || data === void 0 ? void 0 : data.error) && data.error.length > 0) {
109
+ throw new Error(`Kraken API error: ${data.error.join(", ")}`);
110
+ }
111
+ return data.result;
112
+ });
113
+ }
114
+ // ----- Balances -----
115
+ getBalance(asset) {
116
+ return __awaiter(this, void 0, void 0, function* () {
117
+ const balances = yield this.privatePost("Balance", {});
118
+ const value = balances[asset];
119
+ return value ? parseFloat(value) : 0;
120
+ });
121
+ }
122
+ getAllBalances(assets) {
123
+ return __awaiter(this, void 0, void 0, function* () {
124
+ const balances = yield this.privatePost("Balance", {});
125
+ const result = {};
126
+ for (const asset of assets) {
127
+ result[asset] = balances[asset] ? parseFloat(balances[asset]) : 0;
128
+ }
129
+ return result;
130
+ });
131
+ }
132
+ // ----- Deposits -----
133
+ getDepositMethods(asset) {
134
+ return __awaiter(this, void 0, void 0, function* () {
135
+ return this.privatePost("DepositMethods", { asset });
136
+ });
137
+ }
138
+ // Retrieve (or generate) deposit addresses for an asset + method. `method`
139
+ // must exactly match one of the values returned by DepositMethods.
140
+ getDepositAddresses(asset, method, isNew = false) {
141
+ return __awaiter(this, void 0, void 0, function* () {
142
+ return this.privatePost("DepositAddresses", {
143
+ asset,
144
+ method,
145
+ new: isNew ? true : undefined,
146
+ });
147
+ });
148
+ }
149
+ getDepositStatus(asset, method) {
150
+ return __awaiter(this, void 0, void 0, function* () {
151
+ return this.privatePost("DepositStatus", {
152
+ asset,
153
+ method,
154
+ });
155
+ });
156
+ }
157
+ // ----- Withdrawals -----
158
+ getWithdrawInfo(asset, key, amount) {
159
+ return __awaiter(this, void 0, void 0, function* () {
160
+ return this.privatePost("WithdrawInfo", {
161
+ asset,
162
+ key,
163
+ amount,
164
+ });
165
+ });
166
+ }
167
+ // Withdraw to a pre-configured, account-whitelisted address referenced by
168
+ // `key` (Kraken does not allow withdrawing to an arbitrary address via API).
169
+ // Returns Kraken's withdrawal reference id (refid).
170
+ withdraw(asset, key, amount) {
171
+ return __awaiter(this, void 0, void 0, function* () {
172
+ this.assertFundingAllowed();
173
+ const result = yield this.privatePost("Withdraw", {
174
+ asset,
175
+ key,
176
+ amount,
177
+ });
178
+ if (!(result === null || result === void 0 ? void 0 : result.refid)) {
179
+ throw new Error("Kraken Withdraw returned no refid");
180
+ }
181
+ return result.refid;
182
+ });
183
+ }
184
+ getWithdrawStatus(asset, method) {
185
+ return __awaiter(this, void 0, void 0, function* () {
186
+ return this.privatePost("WithdrawStatus", {
187
+ asset,
188
+ method,
189
+ });
190
+ });
191
+ }
192
+ getWithdrawStatusByRefid(asset, refid) {
193
+ return __awaiter(this, void 0, void 0, function* () {
194
+ const statuses = yield this.getWithdrawStatus(asset);
195
+ return statuses.find((s) => s.refid === refid);
196
+ });
197
+ }
198
+ getDepositByTxId(asset, txid) {
199
+ return __awaiter(this, void 0, void 0, function* () {
200
+ const statuses = yield this.getDepositStatus(asset);
201
+ return statuses.find((s) => s.txid === txid);
202
+ });
203
+ }
204
+ // ----- Ledgers -----
205
+ // Returns the ledger entries (keyed by ledger id) for the given filters.
206
+ // This is the authoritative source for fiat deposits/withdrawals, which do
207
+ // not appear in DepositStatus/WithdrawStatus. `start` is a unix timestamp in
208
+ // seconds; Kraken returns the most recent entries (max 50 per page) at or
209
+ // after it.
210
+ getLedgers(params = {}) {
211
+ var _a;
212
+ return __awaiter(this, void 0, void 0, function* () {
213
+ const result = yield this.privatePost("Ledgers", {
214
+ type: params.type,
215
+ asset: params.asset,
216
+ start: params.start,
217
+ });
218
+ return (_a = result === null || result === void 0 ? void 0 : result.ledger) !== null && _a !== void 0 ? _a : {};
219
+ });
220
+ }
221
+ }
222
+ // Cache a single client per process so the monotonic nonce floor is effective
223
+ // process-wide; building a fresh client per call would reset it and risk
224
+ // `EAPI:Invalid nonce`.
225
+ let krakenClient = null;
226
+ let krakenClientPromise = null;
227
+ const buildKrakenClient = () => __awaiter(void 0, void 0, void 0, function* () {
228
+ if (krakenClient) {
229
+ return krakenClient;
230
+ }
231
+ if (!krakenClientPromise) {
232
+ krakenClientPromise = (() => __awaiter(void 0, void 0, void 0, function* () {
233
+ const KRAKEN_API_KEY = yield secret_manager_client_1.secretManagerClient.getSecretValue("KRAKEN_API_KEY");
234
+ if (!KRAKEN_API_KEY) {
235
+ throw new common_1.SecretManagerError();
236
+ }
237
+ const KRAKEN_API_SECRET = yield secret_manager_client_1.secretManagerClient.getSecretValue("KRAKEN_API_SECRET");
238
+ if (!KRAKEN_API_SECRET) {
239
+ throw new common_1.SecretManagerError();
240
+ }
241
+ krakenClient = new KrakenClient(KRAKEN_API_KEY, KRAKEN_API_SECRET, process.env.RIO_ENV);
242
+ return krakenClient;
243
+ }))();
244
+ }
245
+ try {
246
+ return yield krakenClientPromise;
247
+ }
248
+ catch (err) {
249
+ krakenClientPromise = null;
250
+ throw err;
251
+ }
252
+ });
253
+ exports.buildKrakenClient = buildKrakenClient;
package/build/index.d.ts CHANGED
@@ -148,6 +148,7 @@ export * from "./clients/circle-client";
148
148
  export * from "./clients/coincover-client";
149
149
  export * from "./clients/google-sheets-api-client";
150
150
  export * from "./clients/binance-client";
151
+ export * from "./clients/kraken-client";
151
152
  export * from "./helpers/get-user-helper";
152
153
  export * from "./helpers/get-processor-fees";
153
154
  export * from "./helpers/get-network-fees";
package/build/index.js CHANGED
@@ -164,6 +164,7 @@ __exportStar(require("./clients/circle-client"), exports);
164
164
  __exportStar(require("./clients/coincover-client"), exports);
165
165
  __exportStar(require("./clients/google-sheets-api-client"), exports);
166
166
  __exportStar(require("./clients/binance-client"), exports);
167
+ __exportStar(require("./clients/kraken-client"), exports);
167
168
  __exportStar(require("./helpers/get-user-helper"), exports);
168
169
  __exportStar(require("./helpers/get-processor-fees"), exports);
169
170
  __exportStar(require("./helpers/get-network-fees"), exports);
@@ -19,6 +19,8 @@ interface ExternalTradeAttrs {
19
19
  associatedMidmarketPrice?: number;
20
20
  status: ExternalTradeStatus;
21
21
  fxTradeId?: string;
22
+ internalTradeId?: string;
23
+ coinbaseConversionId?: string;
22
24
  providerOptions?: {
23
25
  emarkets?: {
24
26
  settlementType?: EmarketsSettlementType;
@@ -60,6 +62,8 @@ interface ExternalTradeDoc extends Document {
60
62
  associatedMidmarketPrice?: number;
61
63
  status: ExternalTradeStatus;
62
64
  fxTradeId?: string;
65
+ internalTradeId?: string;
66
+ coinbaseConversionId?: string;
63
67
  providerOptions?: {
64
68
  emarkets?: {
65
69
  settlementType?: EmarketsSettlementType;
@@ -32,6 +32,12 @@ const buildExternalTrade = (mongoose) => {
32
32
  fxTradeId: {
33
33
  type: String,
34
34
  },
35
+ internalTradeId: {
36
+ type: String,
37
+ },
38
+ coinbaseConversionId: {
39
+ type: String,
40
+ },
35
41
  provider: {
36
42
  type: String,
37
43
  required: true,
@@ -28,6 +28,9 @@ interface InternalBalancesDoc extends mongoose.Document {
28
28
  binance: {
29
29
  [key in Fiat & Crypto]: number;
30
30
  };
31
+ kraken: {
32
+ [key in Fiat & Crypto]: number;
33
+ };
31
34
  brex: {
32
35
  [key in Fiat & Crypto]: number;
33
36
  };
@@ -20,6 +20,9 @@ const buildInternalBalances = (mongoose) => {
20
20
  [common_1.TreasuryProvider.Binance]: {
21
21
  type: Object,
22
22
  },
23
+ [common_1.TreasuryProvider.Kraken]: {
24
+ type: Object,
25
+ },
23
26
  [common_1.TreasuryProvider.Brex]: {
24
27
  type: Object,
25
28
  },
@@ -19,6 +19,7 @@ interface InternalTradeAttrs {
19
19
  amountFilled?: number;
20
20
  limitPrice?: number;
21
21
  coinbaseConversionId?: string;
22
+ externalTradeId?: string;
22
23
  }
23
24
  interface InternalTradeDoc extends mongoose.Document {
24
25
  id: string;
@@ -40,6 +41,7 @@ interface InternalTradeDoc extends mongoose.Document {
40
41
  amountFilled?: number;
41
42
  limitPrice?: number;
42
43
  coinbaseConversionId?: string;
44
+ externalTradeId?: string;
43
45
  }
44
46
  interface InternalTradeModel extends mongoose.Model<InternalTradeDoc> {
45
47
  build(attrs: InternalTradeAttrs): HydratedDocument<InternalTradeDoc>;
@@ -67,6 +67,9 @@ const buildInternalTrade = (mongoose) => {
67
67
  coinbaseConversionId: {
68
68
  type: String,
69
69
  },
70
+ externalTradeId: {
71
+ type: String,
72
+ },
70
73
  }, {
71
74
  toJSON: {
72
75
  transform(doc, ret) {
@@ -1,5 +1,5 @@
1
1
  import mongoose, { HydratedDocument } from "mongoose";
2
- import { InternalTransferType, TreasuryProvider, Fiat, Crypto, InternalTransferOriginStatus, InternalTransferDestinationStatus } from "@riocrypto/common";
2
+ import { InternalTransferType, TreasuryProvider, Fiat, Crypto, InternalTransferOriginStatus, InternalTransferDestinationStatus, OtherProviderMetadata } from "@riocrypto/common";
3
3
  interface InternalTransferAttrs {
4
4
  createdAt: Date;
5
5
  adminId?: string;
@@ -8,6 +8,8 @@ interface InternalTransferAttrs {
8
8
  transferType: InternalTransferType;
9
9
  amount: number;
10
10
  currency: Fiat | Crypto;
11
+ otherCurrencyCode?: string;
12
+ isImported?: boolean;
11
13
  blockchainTxId?: string;
12
14
  reference?: string;
13
15
  SPEITrackingNumber?: string;
@@ -17,14 +19,18 @@ interface InternalTransferAttrs {
17
19
  providerId?: string;
18
20
  amountSent?: number;
19
21
  status: InternalTransferOriginStatus;
22
+ otherStatus?: string;
23
+ otherProviderMetadata?: OtherProviderMetadata;
20
24
  };
21
25
  destination: {
22
26
  provider: TreasuryProvider;
23
27
  providerId?: string;
24
28
  amountReceived?: number;
25
29
  status: InternalTransferDestinationStatus;
30
+ otherStatus?: string;
26
31
  notifyWhenCredited?: boolean;
27
32
  notifyWhenCompleted?: boolean;
33
+ otherProviderMetadata?: OtherProviderMetadata;
28
34
  };
29
35
  }
30
36
  interface InternalTransferDoc extends mongoose.Document {
@@ -34,6 +40,8 @@ interface InternalTransferDoc extends mongoose.Document {
34
40
  liquiditySourcingPlanId?: string;
35
41
  createdAt: Date;
36
42
  transferType: InternalTransferType;
43
+ otherCurrencyCode?: string;
44
+ isImported?: boolean;
37
45
  blockchainTxId?: string;
38
46
  reference?: string;
39
47
  SPEITrackingNumber?: string;
@@ -43,14 +51,18 @@ interface InternalTransferDoc extends mongoose.Document {
43
51
  providerId?: string;
44
52
  amountSent?: number;
45
53
  status: InternalTransferOriginStatus;
54
+ otherStatus?: string;
55
+ otherProviderMetadata?: OtherProviderMetadata;
46
56
  };
47
57
  destination: {
48
58
  provider: TreasuryProvider;
49
59
  providerId?: string;
50
60
  amountReceived?: number;
51
61
  status: InternalTransferDestinationStatus;
62
+ otherStatus?: string;
52
63
  notifyWhenCredited?: boolean;
53
64
  notifyWhenCompleted?: boolean;
65
+ otherProviderMetadata?: OtherProviderMetadata;
54
66
  };
55
67
  amount: number;
56
68
  currency: Fiat | Crypto;
@@ -26,6 +26,13 @@ const buildInternalTransfer = (mongoose) => {
26
26
  enum: Object.values(common_1.InternalTransferType),
27
27
  required: true,
28
28
  },
29
+ otherCurrencyCode: {
30
+ type: String,
31
+ },
32
+ isImported: {
33
+ type: Boolean,
34
+ default: false,
35
+ },
29
36
  blockchainTxId: {
30
37
  type: String,
31
38
  },
@@ -55,6 +62,16 @@ const buildInternalTransfer = (mongoose) => {
55
62
  enum: Object.values(common_1.InternalTransferOriginStatus),
56
63
  required: true,
57
64
  },
65
+ otherStatus: {
66
+ type: String,
67
+ },
68
+ otherProviderMetadata: {
69
+ blockchainAddress: { type: String },
70
+ memo: { type: String },
71
+ bankAccountInfo: { type: String },
72
+ bankName: { type: String },
73
+ label: { type: String },
74
+ },
58
75
  },
59
76
  destination: {
60
77
  provider: {
@@ -73,6 +90,9 @@ const buildInternalTransfer = (mongoose) => {
73
90
  enum: Object.values(common_1.InternalTransferDestinationStatus),
74
91
  required: true,
75
92
  },
93
+ otherStatus: {
94
+ type: String,
95
+ },
76
96
  notifyWhenCredited: {
77
97
  type: Boolean,
78
98
  default: false,
@@ -81,6 +101,13 @@ const buildInternalTransfer = (mongoose) => {
81
101
  type: Boolean,
82
102
  default: false,
83
103
  },
104
+ otherProviderMetadata: {
105
+ blockchainAddress: { type: String },
106
+ memo: { type: String },
107
+ bankAccountInfo: { type: String },
108
+ bankName: { type: String },
109
+ label: { type: String },
110
+ },
84
111
  },
85
112
  amount: {
86
113
  type: Number,
@@ -99,6 +126,16 @@ const buildInternalTransfer = (mongoose) => {
99
126
  },
100
127
  },
101
128
  });
129
+ // Indexes to support dedup lookups when importing exchange-native activity.
130
+ InternalTransferSchema.index({
131
+ "origin.provider": 1,
132
+ "origin.providerId": 1,
133
+ });
134
+ InternalTransferSchema.index({
135
+ "destination.provider": 1,
136
+ "destination.providerId": 1,
137
+ });
138
+ InternalTransferSchema.index({ blockchainTxId: 1 });
102
139
  InternalTransferSchema.statics.build = (attrs) => {
103
140
  return new InternalTransfer(attrs);
104
141
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riocrypto/common-server",
3
- "version": "1.0.2842",
3
+ "version": "1.0.2844",
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.2643",
31
+ "@riocrypto/common": "1.0.2649",
32
32
  "@slack/web-api": "^7.15.0",
33
33
  "@types/express": "^4.17.25",
34
34
  "axios": "1.16.0",