@xchainjs/xchain-aggregator 2.3.2 → 2.3.3
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.
- package/lib/const.d.ts +1 -1
- package/lib/index.esm.js +421 -108
- package/lib/index.js +420 -107
- package/lib/protocols/oneclick/api.d.ts +8 -0
- package/lib/protocols/oneclick/index.d.ts +1 -0
- package/lib/protocols/oneclick/oneclickProtocol.d.ts +19 -0
- package/lib/protocols/oneclick/types.d.ts +41 -0
- package/lib/protocols/oneclick/utils.d.ts +11 -0
- package/lib/types.d.ts +6 -1
- package/package.json +16 -16
package/lib/index.esm.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Network } from '@xchainjs/xchain-client';
|
|
2
|
-
import { CachedValue, isSynthAsset, isTradeAsset, CryptoAmount, baseAmount, isSecuredAsset, assetToString, eqAsset, assetFromStringEx,
|
|
2
|
+
import { CachedValue, isSynthAsset, isTradeAsset, CryptoAmount, baseAmount, isSecuredAsset, assetToString, eqAsset, assetFromStringEx, isTokenAsset, assetFromString } from '@xchainjs/xchain-util';
|
|
3
3
|
import { SwapSDK } from '@chainflip/sdk/swap';
|
|
4
4
|
import { assetUSDC, ThorchainCache, Thornode, ThorchainQuery } from '@xchainjs/xchain-thorchain-query';
|
|
5
5
|
import { AssetCacao, MAYAChain } from '@xchainjs/xchain-mayachain';
|
|
@@ -40,7 +40,7 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
|
|
|
40
40
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
-
const SupportedProtocols = ['Thorchain', 'Mayachain', 'Chainflip'];
|
|
43
|
+
const SupportedProtocols = ['Thorchain', 'Mayachain', 'Chainflip', 'OneClick'];
|
|
44
44
|
const DEFAULT_CONFIG = {
|
|
45
45
|
protocols: SupportedProtocols,
|
|
46
46
|
network: Network.Mainnet,
|
|
@@ -571,16 +571,16 @@ const G = getGlobal();
|
|
|
571
571
|
const FormDataCtor = typeof G.FormData !== 'undefined' ? G.FormData : undefined;
|
|
572
572
|
|
|
573
573
|
const isFormData = (thing) => {
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
574
|
+
if (!thing) return false;
|
|
575
|
+
if (FormDataCtor && thing instanceof FormDataCtor) return true;
|
|
576
|
+
// Reject plain objects inheriting directly from Object.prototype so prototype-pollution gadgets can't spoof FormData (GHSA-6chq-wfr3-2hj9).
|
|
577
|
+
const proto = getPrototypeOf(thing);
|
|
578
|
+
if (!proto || proto === Object.prototype) return false;
|
|
579
|
+
if (!isFunction$1(thing.append)) return false;
|
|
580
|
+
const kind = kindOf(thing);
|
|
581
|
+
return kind === 'formdata' ||
|
|
582
|
+
// detect form-data instance
|
|
583
|
+
(kind === 'object' && isFunction$1(thing.toString) && thing.toString() === '[object FormData]');
|
|
584
584
|
};
|
|
585
585
|
|
|
586
586
|
/**
|
|
@@ -1247,40 +1247,40 @@ let AxiosError$1 = class AxiosError extends Error {
|
|
|
1247
1247
|
return axiosError;
|
|
1248
1248
|
}
|
|
1249
1249
|
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
}
|
|
1250
|
+
/**
|
|
1251
|
+
* Create an Error with the specified message, config, error code, request and response.
|
|
1252
|
+
*
|
|
1253
|
+
* @param {string} message The error message.
|
|
1254
|
+
* @param {string} [code] The error code (for example, 'ECONNABORTED').
|
|
1255
|
+
* @param {Object} [config] The config.
|
|
1256
|
+
* @param {Object} [request] The request.
|
|
1257
|
+
* @param {Object} [response] The response.
|
|
1258
|
+
*
|
|
1259
|
+
* @returns {Error} The created error.
|
|
1260
|
+
*/
|
|
1261
|
+
constructor(message, code, config, request, response) {
|
|
1262
|
+
super(message);
|
|
1263
|
+
|
|
1264
|
+
// Make message enumerable to maintain backward compatibility
|
|
1265
|
+
// The native Error constructor sets message as non-enumerable,
|
|
1266
|
+
// but axios < v1.13.3 had it as enumerable
|
|
1267
|
+
Object.defineProperty(this, 'message', {
|
|
1268
|
+
value: message,
|
|
1269
|
+
enumerable: true,
|
|
1270
|
+
writable: true,
|
|
1271
|
+
configurable: true,
|
|
1272
|
+
});
|
|
1273
|
+
|
|
1274
|
+
this.name = 'AxiosError';
|
|
1275
|
+
this.isAxiosError = true;
|
|
1276
|
+
code && (this.code = code);
|
|
1277
|
+
config && (this.config = config);
|
|
1278
|
+
request && (this.request = request);
|
|
1279
|
+
if (response) {
|
|
1280
|
+
this.response = response;
|
|
1281
|
+
this.status = response.status;
|
|
1283
1282
|
}
|
|
1283
|
+
}
|
|
1284
1284
|
|
|
1285
1285
|
toJSON() {
|
|
1286
1286
|
return {
|
|
@@ -1316,6 +1316,7 @@ AxiosError$1.ERR_BAD_REQUEST = 'ERR_BAD_REQUEST';
|
|
|
1316
1316
|
AxiosError$1.ERR_CANCELED = 'ERR_CANCELED';
|
|
1317
1317
|
AxiosError$1.ERR_NOT_SUPPORT = 'ERR_NOT_SUPPORT';
|
|
1318
1318
|
AxiosError$1.ERR_INVALID_URL = 'ERR_INVALID_URL';
|
|
1319
|
+
AxiosError$1.ERR_FORM_DATA_DEPTH_EXCEEDED = 'ERR_FORM_DATA_DEPTH_EXCEEDED';
|
|
1319
1320
|
|
|
1320
1321
|
// eslint-disable-next-line strict
|
|
1321
1322
|
var httpAdapter = null;
|
|
@@ -1430,6 +1431,7 @@ function toFormData$1(obj, formData, options) {
|
|
|
1430
1431
|
const dots = options.dots;
|
|
1431
1432
|
const indexes = options.indexes;
|
|
1432
1433
|
const _Blob = options.Blob || (typeof Blob !== 'undefined' && Blob);
|
|
1434
|
+
const maxDepth = options.maxDepth === undefined ? 100 : options.maxDepth;
|
|
1433
1435
|
const useBlob = _Blob && utils$1.isSpecCompliantForm(formData);
|
|
1434
1436
|
|
|
1435
1437
|
if (!utils$1.isFunction(visitor)) {
|
|
@@ -1522,9 +1524,16 @@ function toFormData$1(obj, formData, options) {
|
|
|
1522
1524
|
isVisitable,
|
|
1523
1525
|
});
|
|
1524
1526
|
|
|
1525
|
-
function build(value, path) {
|
|
1527
|
+
function build(value, path, depth = 0) {
|
|
1526
1528
|
if (utils$1.isUndefined(value)) return;
|
|
1527
1529
|
|
|
1530
|
+
if (depth > maxDepth) {
|
|
1531
|
+
throw new AxiosError$1(
|
|
1532
|
+
'Object is too deeply nested (' + depth + ' levels). Max depth: ' + maxDepth,
|
|
1533
|
+
AxiosError$1.ERR_FORM_DATA_DEPTH_EXCEEDED
|
|
1534
|
+
);
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1528
1537
|
if (stack.indexOf(value) !== -1) {
|
|
1529
1538
|
throw Error('Circular reference detected in ' + path.join('.'));
|
|
1530
1539
|
}
|
|
@@ -1537,7 +1546,7 @@ function toFormData$1(obj, formData, options) {
|
|
|
1537
1546
|
visitor.call(formData, el, utils$1.isString(key) ? key.trim() : key, path, exposedHelpers);
|
|
1538
1547
|
|
|
1539
1548
|
if (result === true) {
|
|
1540
|
-
build(el, path ? path.concat(key) : [key]);
|
|
1549
|
+
build(el, path ? path.concat(key) : [key], depth + 1);
|
|
1541
1550
|
}
|
|
1542
1551
|
});
|
|
1543
1552
|
|
|
@@ -1569,9 +1578,8 @@ function encode$1(str) {
|
|
|
1569
1578
|
')': '%29',
|
|
1570
1579
|
'~': '%7E',
|
|
1571
1580
|
'%20': '+',
|
|
1572
|
-
'%00': '\x00',
|
|
1573
1581
|
};
|
|
1574
|
-
return encodeURIComponent(str).replace(/[!'()~]|%20
|
|
1582
|
+
return encodeURIComponent(str).replace(/[!'()~]|%20/g, function replacer(match) {
|
|
1575
1583
|
return charMap[match];
|
|
1576
1584
|
});
|
|
1577
1585
|
}
|
|
@@ -1891,7 +1899,9 @@ function formDataToJSON(formData) {
|
|
|
1891
1899
|
|
|
1892
1900
|
if (isLast) {
|
|
1893
1901
|
if (utils$1.hasOwnProp(target, name)) {
|
|
1894
|
-
target[name] =
|
|
1902
|
+
target[name] = utils$1.isArray(target[name])
|
|
1903
|
+
? target[name].concat(value)
|
|
1904
|
+
: [target[name], value];
|
|
1895
1905
|
} else {
|
|
1896
1906
|
target[name] = value;
|
|
1897
1907
|
}
|
|
@@ -1925,6 +1935,8 @@ function formDataToJSON(formData) {
|
|
|
1925
1935
|
return null;
|
|
1926
1936
|
}
|
|
1927
1937
|
|
|
1938
|
+
const own = (obj, key) => (obj != null && utils$1.hasOwnProp(obj, key) ? obj[key] : undefined);
|
|
1939
|
+
|
|
1928
1940
|
/**
|
|
1929
1941
|
* It takes a string, tries to parse it, and if it fails, it returns the stringified version
|
|
1930
1942
|
* of the input
|
|
@@ -1992,20 +2004,22 @@ const defaults = {
|
|
|
1992
2004
|
let isFileList;
|
|
1993
2005
|
|
|
1994
2006
|
if (isObjectPayload) {
|
|
2007
|
+
const formSerializer = own(this, 'formSerializer');
|
|
1995
2008
|
if (contentType.indexOf('application/x-www-form-urlencoded') > -1) {
|
|
1996
|
-
return toURLEncodedForm(data,
|
|
2009
|
+
return toURLEncodedForm(data, formSerializer).toString();
|
|
1997
2010
|
}
|
|
1998
2011
|
|
|
1999
2012
|
if (
|
|
2000
2013
|
(isFileList = utils$1.isFileList(data)) ||
|
|
2001
2014
|
contentType.indexOf('multipart/form-data') > -1
|
|
2002
2015
|
) {
|
|
2003
|
-
const
|
|
2016
|
+
const env = own(this, 'env');
|
|
2017
|
+
const _FormData = env && env.FormData;
|
|
2004
2018
|
|
|
2005
2019
|
return toFormData$1(
|
|
2006
2020
|
isFileList ? { 'files[]': data } : data,
|
|
2007
2021
|
_FormData && new _FormData(),
|
|
2008
|
-
|
|
2022
|
+
formSerializer
|
|
2009
2023
|
);
|
|
2010
2024
|
}
|
|
2011
2025
|
}
|
|
@@ -2021,9 +2035,10 @@ const defaults = {
|
|
|
2021
2035
|
|
|
2022
2036
|
transformResponse: [
|
|
2023
2037
|
function transformResponse(data) {
|
|
2024
|
-
const transitional = this
|
|
2038
|
+
const transitional = own(this, 'transitional') || defaults.transitional;
|
|
2025
2039
|
const forcedJSONParsing = transitional && transitional.forcedJSONParsing;
|
|
2026
|
-
const
|
|
2040
|
+
const responseType = own(this, 'responseType');
|
|
2041
|
+
const JSONRequested = responseType === 'json';
|
|
2027
2042
|
|
|
2028
2043
|
if (utils$1.isResponse(data) || utils$1.isReadableStream(data)) {
|
|
2029
2044
|
return data;
|
|
@@ -2032,17 +2047,17 @@ const defaults = {
|
|
|
2032
2047
|
if (
|
|
2033
2048
|
data &&
|
|
2034
2049
|
utils$1.isString(data) &&
|
|
2035
|
-
((forcedJSONParsing && !
|
|
2050
|
+
((forcedJSONParsing && !responseType) || JSONRequested)
|
|
2036
2051
|
) {
|
|
2037
2052
|
const silentJSONParsing = transitional && transitional.silentJSONParsing;
|
|
2038
2053
|
const strictJSONParsing = !silentJSONParsing && JSONRequested;
|
|
2039
2054
|
|
|
2040
2055
|
try {
|
|
2041
|
-
return JSON.parse(data, this
|
|
2056
|
+
return JSON.parse(data, own(this, 'parseReviver'));
|
|
2042
2057
|
} catch (e) {
|
|
2043
2058
|
if (strictJSONParsing) {
|
|
2044
2059
|
if (e.name === 'SyntaxError') {
|
|
2045
|
-
throw AxiosError$1.from(e, AxiosError$1.ERR_BAD_RESPONSE, this, null, this
|
|
2060
|
+
throw AxiosError$1.from(e, AxiosError$1.ERR_BAD_RESPONSE, this, null, own(this, 'response'));
|
|
2046
2061
|
}
|
|
2047
2062
|
throw e;
|
|
2048
2063
|
}
|
|
@@ -2154,41 +2169,41 @@ var parseHeaders = (rawHeaders) => {
|
|
|
2154
2169
|
|
|
2155
2170
|
const $internals = Symbol('internals');
|
|
2156
2171
|
|
|
2157
|
-
const
|
|
2158
|
-
|
|
2159
|
-
function assertValidHeaderValue(value, header) {
|
|
2160
|
-
if (value === false || value == null) {
|
|
2161
|
-
return;
|
|
2162
|
-
}
|
|
2172
|
+
const INVALID_HEADER_VALUE_CHARS_RE = /[^\x09\x20-\x7E\x80-\xFF]/g;
|
|
2163
2173
|
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
}
|
|
2174
|
+
function trimSPorHTAB(str) {
|
|
2175
|
+
let start = 0;
|
|
2176
|
+
let end = str.length;
|
|
2168
2177
|
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
}
|
|
2172
|
-
}
|
|
2178
|
+
while (start < end) {
|
|
2179
|
+
const code = str.charCodeAt(start);
|
|
2173
2180
|
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
}
|
|
2181
|
+
if (code !== 0x09 && code !== 0x20) {
|
|
2182
|
+
break;
|
|
2183
|
+
}
|
|
2177
2184
|
|
|
2178
|
-
|
|
2179
|
-
|
|
2185
|
+
start += 1;
|
|
2186
|
+
}
|
|
2180
2187
|
|
|
2181
|
-
while (end >
|
|
2182
|
-
const
|
|
2188
|
+
while (end > start) {
|
|
2189
|
+
const code = str.charCodeAt(end - 1);
|
|
2183
2190
|
|
|
2184
|
-
if (
|
|
2191
|
+
if (code !== 0x09 && code !== 0x20) {
|
|
2185
2192
|
break;
|
|
2186
2193
|
}
|
|
2187
2194
|
|
|
2188
2195
|
end -= 1;
|
|
2189
2196
|
}
|
|
2190
2197
|
|
|
2191
|
-
return end === str.length ? str : str.slice(
|
|
2198
|
+
return start === 0 && end === str.length ? str : str.slice(start, end);
|
|
2199
|
+
}
|
|
2200
|
+
|
|
2201
|
+
function normalizeHeader(header) {
|
|
2202
|
+
return header && String(header).trim().toLowerCase();
|
|
2203
|
+
}
|
|
2204
|
+
|
|
2205
|
+
function sanitizeHeaderValue(str) {
|
|
2206
|
+
return trimSPorHTAB(str.replace(INVALID_HEADER_VALUE_CHARS_RE, ''));
|
|
2192
2207
|
}
|
|
2193
2208
|
|
|
2194
2209
|
function normalizeValue(value) {
|
|
@@ -2196,7 +2211,7 @@ function normalizeValue(value) {
|
|
|
2196
2211
|
return value;
|
|
2197
2212
|
}
|
|
2198
2213
|
|
|
2199
|
-
return utils$1.isArray(value) ? value.map(normalizeValue) :
|
|
2214
|
+
return utils$1.isArray(value) ? value.map(normalizeValue) : sanitizeHeaderValue(String(value));
|
|
2200
2215
|
}
|
|
2201
2216
|
|
|
2202
2217
|
function parseTokens(str) {
|
|
@@ -2278,7 +2293,6 @@ let AxiosHeaders$1 = class AxiosHeaders {
|
|
|
2278
2293
|
_rewrite === true ||
|
|
2279
2294
|
(_rewrite === undefined && self[key] !== false)
|
|
2280
2295
|
) {
|
|
2281
|
-
assertValidHeaderValue(_value, _header);
|
|
2282
2296
|
self[key || _header] = normalizeValue(_value);
|
|
2283
2297
|
}
|
|
2284
2298
|
}
|
|
@@ -2701,13 +2715,13 @@ const progressEventReducer = (listener, isDownloadStream, freq = 3) => {
|
|
|
2701
2715
|
const _speedometer = speedometer(50, 250);
|
|
2702
2716
|
|
|
2703
2717
|
return throttle((e) => {
|
|
2704
|
-
const
|
|
2718
|
+
const rawLoaded = e.loaded;
|
|
2705
2719
|
const total = e.lengthComputable ? e.total : undefined;
|
|
2706
|
-
const
|
|
2720
|
+
const loaded = total != null ? Math.min(rawLoaded, total) : rawLoaded;
|
|
2721
|
+
const progressBytes = Math.max(0, loaded - bytesNotified);
|
|
2707
2722
|
const rate = _speedometer(progressBytes);
|
|
2708
|
-
const inRange = loaded <= total;
|
|
2709
2723
|
|
|
2710
|
-
bytesNotified = loaded;
|
|
2724
|
+
bytesNotified = Math.max(bytesNotified, loaded);
|
|
2711
2725
|
|
|
2712
2726
|
const data = {
|
|
2713
2727
|
loaded,
|
|
@@ -2715,7 +2729,7 @@ const progressEventReducer = (listener, isDownloadStream, freq = 3) => {
|
|
|
2715
2729
|
progress: total ? loaded / total : undefined,
|
|
2716
2730
|
bytes: progressBytes,
|
|
2717
2731
|
rate: rate ? rate : undefined,
|
|
2718
|
-
estimated: rate && total
|
|
2732
|
+
estimated: rate && total ? (total - loaded) / rate : undefined,
|
|
2719
2733
|
event: e,
|
|
2720
2734
|
lengthComputable: total != null,
|
|
2721
2735
|
[isDownloadStream ? 'download' : 'upload']: true,
|
|
@@ -2849,7 +2863,7 @@ function combineURLs(baseURL, relativeURL) {
|
|
|
2849
2863
|
*/
|
|
2850
2864
|
function buildFullPath(baseURL, requestedURL, allowAbsoluteUrls) {
|
|
2851
2865
|
let isRelativeUrl = !isAbsoluteURL(requestedURL);
|
|
2852
|
-
if (baseURL && (isRelativeUrl || allowAbsoluteUrls
|
|
2866
|
+
if (baseURL && (isRelativeUrl || allowAbsoluteUrls === false)) {
|
|
2853
2867
|
return combineURLs(baseURL, requestedURL);
|
|
2854
2868
|
}
|
|
2855
2869
|
return requestedURL;
|
|
@@ -2869,7 +2883,18 @@ const headersToObject = (thing) => (thing instanceof AxiosHeaders$1 ? { ...thing
|
|
|
2869
2883
|
function mergeConfig$1(config1, config2) {
|
|
2870
2884
|
// eslint-disable-next-line no-param-reassign
|
|
2871
2885
|
config2 = config2 || {};
|
|
2872
|
-
|
|
2886
|
+
|
|
2887
|
+
// Use a null-prototype object so that downstream reads such as `config.auth`
|
|
2888
|
+
// or `config.baseURL` cannot inherit polluted values from Object.prototype
|
|
2889
|
+
// (see GHSA-q8qp-cvcw-x6jj). `hasOwnProperty` is restored as a non-enumerable
|
|
2890
|
+
// own slot to preserve ergonomics for user code that relies on it.
|
|
2891
|
+
const config = Object.create(null);
|
|
2892
|
+
Object.defineProperty(config, 'hasOwnProperty', {
|
|
2893
|
+
value: Object.prototype.hasOwnProperty,
|
|
2894
|
+
enumerable: false,
|
|
2895
|
+
writable: true,
|
|
2896
|
+
configurable: true,
|
|
2897
|
+
});
|
|
2873
2898
|
|
|
2874
2899
|
function getMergedValue(target, source, prop, caseless) {
|
|
2875
2900
|
if (utils$1.isPlainObject(target) && utils$1.isPlainObject(source)) {
|
|
@@ -2908,9 +2933,9 @@ function mergeConfig$1(config1, config2) {
|
|
|
2908
2933
|
|
|
2909
2934
|
// eslint-disable-next-line consistent-return
|
|
2910
2935
|
function mergeDirectKeys(a, b, prop) {
|
|
2911
|
-
if (prop
|
|
2936
|
+
if (utils$1.hasOwnProp(config2, prop)) {
|
|
2912
2937
|
return getMergedValue(a, b);
|
|
2913
|
-
} else if (prop
|
|
2938
|
+
} else if (utils$1.hasOwnProp(config1, prop)) {
|
|
2914
2939
|
return getMergedValue(undefined, a);
|
|
2915
2940
|
}
|
|
2916
2941
|
}
|
|
@@ -2942,6 +2967,7 @@ function mergeConfig$1(config1, config2) {
|
|
|
2942
2967
|
httpsAgent: defaultToConfig2,
|
|
2943
2968
|
cancelToken: defaultToConfig2,
|
|
2944
2969
|
socketPath: defaultToConfig2,
|
|
2970
|
+
allowedSocketPaths: defaultToConfig2,
|
|
2945
2971
|
responseEncoding: defaultToConfig2,
|
|
2946
2972
|
validateStatus: mergeDirectKeys,
|
|
2947
2973
|
headers: (a, b, prop) =>
|
|
@@ -2951,7 +2977,9 @@ function mergeConfig$1(config1, config2) {
|
|
|
2951
2977
|
utils$1.forEach(Object.keys({ ...config1, ...config2 }), function computeConfigValue(prop) {
|
|
2952
2978
|
if (prop === '__proto__' || prop === 'constructor' || prop === 'prototype') return;
|
|
2953
2979
|
const merge = utils$1.hasOwnProp(mergeMap, prop) ? mergeMap[prop] : mergeDeepProperties;
|
|
2954
|
-
const
|
|
2980
|
+
const a = utils$1.hasOwnProp(config1, prop) ? config1[prop] : undefined;
|
|
2981
|
+
const b = utils$1.hasOwnProp(config2, prop) ? config2[prop] : undefined;
|
|
2982
|
+
const configValue = merge(a, b, prop);
|
|
2955
2983
|
(utils$1.isUndefined(configValue) && merge !== mergeDirectKeys) || (config[prop] = configValue);
|
|
2956
2984
|
});
|
|
2957
2985
|
|
|
@@ -2961,12 +2989,24 @@ function mergeConfig$1(config1, config2) {
|
|
|
2961
2989
|
var resolveConfig = (config) => {
|
|
2962
2990
|
const newConfig = mergeConfig$1({}, config);
|
|
2963
2991
|
|
|
2964
|
-
|
|
2992
|
+
// Read only own properties to prevent prototype pollution gadgets
|
|
2993
|
+
// (e.g. Object.prototype.baseURL = 'https://evil.com'). See GHSA-q8qp-cvcw-x6jj.
|
|
2994
|
+
const own = (key) => (utils$1.hasOwnProp(newConfig, key) ? newConfig[key] : undefined);
|
|
2995
|
+
|
|
2996
|
+
const data = own('data');
|
|
2997
|
+
let withXSRFToken = own('withXSRFToken');
|
|
2998
|
+
const xsrfHeaderName = own('xsrfHeaderName');
|
|
2999
|
+
const xsrfCookieName = own('xsrfCookieName');
|
|
3000
|
+
let headers = own('headers');
|
|
3001
|
+
const auth = own('auth');
|
|
3002
|
+
const baseURL = own('baseURL');
|
|
3003
|
+
const allowAbsoluteUrls = own('allowAbsoluteUrls');
|
|
3004
|
+
const url = own('url');
|
|
2965
3005
|
|
|
2966
3006
|
newConfig.headers = headers = AxiosHeaders$1.from(headers);
|
|
2967
3007
|
|
|
2968
3008
|
newConfig.url = buildURL(
|
|
2969
|
-
buildFullPath(
|
|
3009
|
+
buildFullPath(baseURL, url, allowAbsoluteUrls),
|
|
2970
3010
|
config.params,
|
|
2971
3011
|
config.paramsSerializer
|
|
2972
3012
|
);
|
|
@@ -3005,10 +3045,18 @@ var resolveConfig = (config) => {
|
|
|
3005
3045
|
// Specifically not if we're in a web worker, or react-native.
|
|
3006
3046
|
|
|
3007
3047
|
if (platform.hasStandardBrowserEnv) {
|
|
3008
|
-
|
|
3048
|
+
if (utils$1.isFunction(withXSRFToken)) {
|
|
3049
|
+
withXSRFToken = withXSRFToken(newConfig);
|
|
3050
|
+
}
|
|
3051
|
+
|
|
3052
|
+
// Strict boolean check — prevents proto-pollution gadgets (e.g. Object.prototype.withXSRFToken = 1)
|
|
3053
|
+
// and misconfigurations (e.g. "false") from short-circuiting the same-origin check and leaking
|
|
3054
|
+
// the XSRF token cross-origin. See GHSA-xx6v-rp6x-q39c.
|
|
3055
|
+
const shouldSendXSRF =
|
|
3056
|
+
withXSRFToken === true ||
|
|
3057
|
+
(withXSRFToken == null && isURLSameOrigin(newConfig.url));
|
|
3009
3058
|
|
|
3010
|
-
if (
|
|
3011
|
-
// Add xsrf header
|
|
3059
|
+
if (shouldSendXSRF) {
|
|
3012
3060
|
const xsrfValue = xsrfHeaderName && xsrfCookieName && cookies.read(xsrfCookieName);
|
|
3013
3061
|
|
|
3014
3062
|
if (xsrfValue) {
|
|
@@ -3427,18 +3475,20 @@ const factory = (env) => {
|
|
|
3427
3475
|
test(() => {
|
|
3428
3476
|
let duplexAccessed = false;
|
|
3429
3477
|
|
|
3430
|
-
const
|
|
3431
|
-
|
|
3432
|
-
const hasContentType = new Request(platform.origin, {
|
|
3433
|
-
body,
|
|
3478
|
+
const request = new Request(platform.origin, {
|
|
3479
|
+
body: new ReadableStream$1(),
|
|
3434
3480
|
method: 'POST',
|
|
3435
3481
|
get duplex() {
|
|
3436
3482
|
duplexAccessed = true;
|
|
3437
3483
|
return 'half';
|
|
3438
3484
|
},
|
|
3439
|
-
})
|
|
3485
|
+
});
|
|
3486
|
+
|
|
3487
|
+
const hasContentType = request.headers.has('Content-Type');
|
|
3440
3488
|
|
|
3441
|
-
body
|
|
3489
|
+
if (request.body != null) {
|
|
3490
|
+
request.body.cancel();
|
|
3491
|
+
}
|
|
3442
3492
|
|
|
3443
3493
|
return duplexAccessed && !hasContentType;
|
|
3444
3494
|
});
|
|
@@ -3582,6 +3632,19 @@ const factory = (env) => {
|
|
|
3582
3632
|
// see https://github.com/cloudflare/workerd/issues/902
|
|
3583
3633
|
const isCredentialsSupported = isRequestSupported && 'credentials' in Request.prototype;
|
|
3584
3634
|
|
|
3635
|
+
// If data is FormData and Content-Type is multipart/form-data without boundary,
|
|
3636
|
+
// delete it so fetch can set it correctly with the boundary
|
|
3637
|
+
if (utils$1.isFormData(data)) {
|
|
3638
|
+
const contentType = headers.getContentType();
|
|
3639
|
+
if (
|
|
3640
|
+
contentType &&
|
|
3641
|
+
/^multipart\/form-data/i.test(contentType) &&
|
|
3642
|
+
!/boundary=/i.test(contentType)
|
|
3643
|
+
) {
|
|
3644
|
+
headers.delete('content-type');
|
|
3645
|
+
}
|
|
3646
|
+
}
|
|
3647
|
+
|
|
3585
3648
|
const resolvedOptions = {
|
|
3586
3649
|
...fetchOptions,
|
|
3587
3650
|
signal: composedSignal,
|
|
@@ -3890,7 +3953,7 @@ function dispatchRequest(config) {
|
|
|
3890
3953
|
);
|
|
3891
3954
|
}
|
|
3892
3955
|
|
|
3893
|
-
const VERSION$1 = "1.15.
|
|
3956
|
+
const VERSION$1 = "1.15.2";
|
|
3894
3957
|
|
|
3895
3958
|
const validators$1 = {};
|
|
3896
3959
|
|
|
@@ -3975,7 +4038,9 @@ function assertOptions(options, schema, allowUnknown) {
|
|
|
3975
4038
|
let i = keys.length;
|
|
3976
4039
|
while (i-- > 0) {
|
|
3977
4040
|
const opt = keys[i];
|
|
3978
|
-
|
|
4041
|
+
// Use hasOwnProperty so a polluted Object.prototype.<opt> cannot supply
|
|
4042
|
+
// a non-function validator and cause a TypeError. See GHSA-q8qp-cvcw-x6jj.
|
|
4043
|
+
const validator = Object.prototype.hasOwnProperty.call(schema, opt) ? schema[opt] : undefined;
|
|
3979
4044
|
if (validator) {
|
|
3980
4045
|
const value = options[opt];
|
|
3981
4046
|
const result = value === undefined || validator(value, opt, options);
|
|
@@ -7678,10 +7743,255 @@ class MayachainProtocol {
|
|
|
7678
7743
|
}
|
|
7679
7744
|
}
|
|
7680
7745
|
|
|
7746
|
+
const BASE_URL = 'https://1click.chaindefuser.com';
|
|
7747
|
+
class OneClickApi {
|
|
7748
|
+
constructor(apiKey) {
|
|
7749
|
+
this.headers = { 'Content-Type': 'application/json' };
|
|
7750
|
+
if (apiKey) {
|
|
7751
|
+
this.headers['Authorization'] = `Bearer ${apiKey}`;
|
|
7752
|
+
}
|
|
7753
|
+
}
|
|
7754
|
+
getTokens() {
|
|
7755
|
+
return __awaiter$4(this, void 0, void 0, function* () {
|
|
7756
|
+
const resp = yield fetch(`${BASE_URL}/v0/tokens`, { headers: this.headers });
|
|
7757
|
+
if (!resp.ok)
|
|
7758
|
+
throw new Error(`1Click getTokens failed: ${resp.status}`);
|
|
7759
|
+
return resp.json();
|
|
7760
|
+
});
|
|
7761
|
+
}
|
|
7762
|
+
getQuote(params) {
|
|
7763
|
+
return __awaiter$4(this, void 0, void 0, function* () {
|
|
7764
|
+
const resp = yield fetch(`${BASE_URL}/v0/quote`, {
|
|
7765
|
+
method: 'POST',
|
|
7766
|
+
headers: this.headers,
|
|
7767
|
+
body: JSON.stringify(params),
|
|
7768
|
+
});
|
|
7769
|
+
if (!resp.ok)
|
|
7770
|
+
throw new Error(`1Click getQuote failed: ${resp.status}`);
|
|
7771
|
+
return resp.json();
|
|
7772
|
+
});
|
|
7773
|
+
}
|
|
7774
|
+
submitDeposit(txHash, depositAddress) {
|
|
7775
|
+
return __awaiter$4(this, void 0, void 0, function* () {
|
|
7776
|
+
yield fetch(`${BASE_URL}/v0/deposit/submit`, {
|
|
7777
|
+
method: 'POST',
|
|
7778
|
+
headers: this.headers,
|
|
7779
|
+
body: JSON.stringify({ txHash, depositAddress }),
|
|
7780
|
+
}).catch(() => {
|
|
7781
|
+
// Fire-and-forget
|
|
7782
|
+
});
|
|
7783
|
+
});
|
|
7784
|
+
}
|
|
7785
|
+
}
|
|
7786
|
+
|
|
7787
|
+
const X_TO_ONECLICK = {
|
|
7788
|
+
BTC: 'btc',
|
|
7789
|
+
ETH: 'eth',
|
|
7790
|
+
ARB: 'arb',
|
|
7791
|
+
AVAX: 'avax',
|
|
7792
|
+
BSC: 'bsc',
|
|
7793
|
+
SOL: 'sol',
|
|
7794
|
+
DOGE: 'doge',
|
|
7795
|
+
DASH: 'dash',
|
|
7796
|
+
LTC: 'ltc',
|
|
7797
|
+
BCH: 'bch',
|
|
7798
|
+
XRP: 'xrp',
|
|
7799
|
+
ADA: 'cardano',
|
|
7800
|
+
SUI: 'sui',
|
|
7801
|
+
};
|
|
7802
|
+
const ONECLICK_TO_X = Object.fromEntries(Object.entries(X_TO_ONECLICK).map(([k, v]) => [v, k]));
|
|
7803
|
+
const xChainToOneClickBlockchain = (chain) => {
|
|
7804
|
+
var _a;
|
|
7805
|
+
return (_a = X_TO_ONECLICK[chain]) !== null && _a !== void 0 ? _a : null;
|
|
7806
|
+
};
|
|
7807
|
+
const oneClickBlockchainToXChain = (blockchain) => {
|
|
7808
|
+
var _a;
|
|
7809
|
+
return (_a = ONECLICK_TO_X[blockchain]) !== null && _a !== void 0 ? _a : null;
|
|
7810
|
+
};
|
|
7811
|
+
const findOneClickToken = (asset, tokens) => {
|
|
7812
|
+
if (isSynthAsset(asset) || isTradeAsset(asset) || isSecuredAsset(asset))
|
|
7813
|
+
return undefined;
|
|
7814
|
+
const blockchain = xChainToOneClickBlockchain(asset.chain);
|
|
7815
|
+
if (!blockchain)
|
|
7816
|
+
return undefined;
|
|
7817
|
+
return tokens.find((token) => {
|
|
7818
|
+
if (token.blockchain !== blockchain)
|
|
7819
|
+
return false;
|
|
7820
|
+
if (isTokenAsset(asset)) {
|
|
7821
|
+
// Match by contract address (case-insensitive)
|
|
7822
|
+
const assetContract = asset.symbol.includes('-') ? asset.symbol.split('-')[1] : undefined;
|
|
7823
|
+
return assetContract && token.contractAddress
|
|
7824
|
+
? token.contractAddress.toLowerCase() === assetContract.toLowerCase()
|
|
7825
|
+
: false;
|
|
7826
|
+
}
|
|
7827
|
+
// Native asset: match by symbol, ensure no contract address on token
|
|
7828
|
+
return token.symbol.toUpperCase() === asset.symbol.toUpperCase() && !token.contractAddress;
|
|
7829
|
+
});
|
|
7830
|
+
};
|
|
7831
|
+
|
|
7832
|
+
class OneClickProtocol {
|
|
7833
|
+
constructor(configuration) {
|
|
7834
|
+
this.name = 'OneClick';
|
|
7835
|
+
this.api = new OneClickApi(configuration === null || configuration === void 0 ? void 0 : configuration.oneClickApiKey);
|
|
7836
|
+
this.wallet = configuration === null || configuration === void 0 ? void 0 : configuration.wallet;
|
|
7837
|
+
this.affiliateAddress = configuration === null || configuration === void 0 ? void 0 : configuration.affiliateAddress;
|
|
7838
|
+
this.affiliateBps = configuration === null || configuration === void 0 ? void 0 : configuration.affiliateBps;
|
|
7839
|
+
this.tokensCache = new CachedValue(() => this.api.getTokens(), 24 * 60 * 60 * 1000);
|
|
7840
|
+
}
|
|
7841
|
+
approveRouterToSpend(_params) {
|
|
7842
|
+
return __awaiter$4(this, void 0, void 0, function* () {
|
|
7843
|
+
throw new Error('Not implemented');
|
|
7844
|
+
});
|
|
7845
|
+
}
|
|
7846
|
+
shouldBeApproved(_params) {
|
|
7847
|
+
return __awaiter$4(this, void 0, void 0, function* () {
|
|
7848
|
+
return false;
|
|
7849
|
+
});
|
|
7850
|
+
}
|
|
7851
|
+
isAssetSupported(asset) {
|
|
7852
|
+
return __awaiter$4(this, void 0, void 0, function* () {
|
|
7853
|
+
if (isSynthAsset(asset) || isTradeAsset(asset) || isSecuredAsset(asset))
|
|
7854
|
+
return false;
|
|
7855
|
+
const tokens = yield this.tokensCache.getValue();
|
|
7856
|
+
return findOneClickToken(asset, tokens) !== undefined;
|
|
7857
|
+
});
|
|
7858
|
+
}
|
|
7859
|
+
getSupportedChains() {
|
|
7860
|
+
return __awaiter$4(this, void 0, void 0, function* () {
|
|
7861
|
+
const tokens = yield this.tokensCache.getValue();
|
|
7862
|
+
const chains = new Set();
|
|
7863
|
+
for (const token of tokens) {
|
|
7864
|
+
const chain = oneClickBlockchainToXChain(token.blockchain);
|
|
7865
|
+
if (chain)
|
|
7866
|
+
chains.add(chain);
|
|
7867
|
+
}
|
|
7868
|
+
return Array.from(chains);
|
|
7869
|
+
});
|
|
7870
|
+
}
|
|
7871
|
+
estimateSwap(params) {
|
|
7872
|
+
return __awaiter$4(this, void 0, void 0, function* () {
|
|
7873
|
+
var _a, _b, _c;
|
|
7874
|
+
const tokens = yield this.tokensCache.getValue();
|
|
7875
|
+
const srcToken = findOneClickToken(params.fromAsset, tokens);
|
|
7876
|
+
const destToken = findOneClickToken(params.destinationAsset, tokens);
|
|
7877
|
+
if (!srcToken || !destToken) {
|
|
7878
|
+
return this.errorQuote(params, srcToken ? 'Destination asset not supported' : 'Source asset not supported');
|
|
7879
|
+
}
|
|
7880
|
+
try {
|
|
7881
|
+
const isDry = !(params.fromAddress && params.destinationAddress);
|
|
7882
|
+
const deadline = new Date(Date.now() + 10 * 60 * 1000).toISOString();
|
|
7883
|
+
const appFees = this.affiliateAddress && this.affiliateBps
|
|
7884
|
+
? [{ recipient: this.affiliateAddress, fee: this.affiliateBps }]
|
|
7885
|
+
: undefined;
|
|
7886
|
+
const resp = yield this.api.getQuote({
|
|
7887
|
+
dry: isDry,
|
|
7888
|
+
swapType: 'EXACT_INPUT',
|
|
7889
|
+
depositType: 'ORIGIN_CHAIN',
|
|
7890
|
+
recipientType: 'DESTINATION_CHAIN',
|
|
7891
|
+
refundType: 'ORIGIN_CHAIN',
|
|
7892
|
+
originAsset: srcToken.assetId,
|
|
7893
|
+
destinationAsset: destToken.assetId,
|
|
7894
|
+
amount: params.amount.baseAmount.amount().toString(),
|
|
7895
|
+
refundTo: params.fromAddress || '',
|
|
7896
|
+
recipient: params.destinationAddress || '',
|
|
7897
|
+
slippageTolerance: (_a = params.toleranceBps) !== null && _a !== void 0 ? _a : 100,
|
|
7898
|
+
deadline,
|
|
7899
|
+
appFees,
|
|
7900
|
+
});
|
|
7901
|
+
if (resp.error || resp.message) {
|
|
7902
|
+
return this.errorQuote(params, resp.error || resp.message || 'Unknown error');
|
|
7903
|
+
}
|
|
7904
|
+
const quote = resp.quote;
|
|
7905
|
+
const toAddress = (_b = quote.depositAddress) !== null && _b !== void 0 ? _b : '';
|
|
7906
|
+
return {
|
|
7907
|
+
protocol: this.name,
|
|
7908
|
+
toAddress,
|
|
7909
|
+
memo: '',
|
|
7910
|
+
expectedAmount: new CryptoAmount(baseAmount(quote.amountOut, destToken.decimals), params.destinationAsset),
|
|
7911
|
+
dustThreshold: new CryptoAmount(baseAmount(0), params.fromAsset),
|
|
7912
|
+
totalSwapSeconds: (_c = quote.timeEstimate) !== null && _c !== void 0 ? _c : 0,
|
|
7913
|
+
maxStreamingQuantity: undefined,
|
|
7914
|
+
canSwap: toAddress !== '',
|
|
7915
|
+
warning: '',
|
|
7916
|
+
errors: [],
|
|
7917
|
+
slipBasisPoints: 0,
|
|
7918
|
+
fees: {
|
|
7919
|
+
asset: params.fromAsset,
|
|
7920
|
+
affiliateFee: new CryptoAmount(baseAmount(0), params.fromAsset),
|
|
7921
|
+
outboundFee: new CryptoAmount(baseAmount(0), params.destinationAsset),
|
|
7922
|
+
},
|
|
7923
|
+
};
|
|
7924
|
+
}
|
|
7925
|
+
catch (e) {
|
|
7926
|
+
return this.errorQuote(params, e instanceof Error ? e.message : 'Unknown error');
|
|
7927
|
+
}
|
|
7928
|
+
});
|
|
7929
|
+
}
|
|
7930
|
+
doSwap(params) {
|
|
7931
|
+
return __awaiter$4(this, void 0, void 0, function* () {
|
|
7932
|
+
const quoteSwap = yield this.estimateSwap(params);
|
|
7933
|
+
if (!quoteSwap.canSwap) {
|
|
7934
|
+
throw new Error(`Can not make swap. ${quoteSwap.errors.join('\n')}`);
|
|
7935
|
+
}
|
|
7936
|
+
if (!this.wallet)
|
|
7937
|
+
throw new Error('Wallet not configured. Can not do swap');
|
|
7938
|
+
const hash = yield this.wallet.transfer({
|
|
7939
|
+
recipient: quoteSwap.toAddress,
|
|
7940
|
+
amount: params.amount.baseAmount,
|
|
7941
|
+
asset: params.fromAsset,
|
|
7942
|
+
memo: quoteSwap.memo,
|
|
7943
|
+
});
|
|
7944
|
+
// Funds are already on the wire. Awaiting submitDeposit lets callers distinguish
|
|
7945
|
+
// "deposit registered, swap will settle" from "registration silently failed, swap will
|
|
7946
|
+
// never settle" — surface the failure with the broadcast hash so it can be retried.
|
|
7947
|
+
try {
|
|
7948
|
+
yield this.api.submitDeposit(hash, quoteSwap.toAddress);
|
|
7949
|
+
}
|
|
7950
|
+
catch (e) {
|
|
7951
|
+
throw new Error(`1Click deposit tx ${hash} was broadcast, but submitDeposit failed: ${e instanceof Error ? e.message : 'unknown error'}`);
|
|
7952
|
+
}
|
|
7953
|
+
// Explorer URL is best-effort; the hash is what callers actually need for tracking.
|
|
7954
|
+
let url = '';
|
|
7955
|
+
try {
|
|
7956
|
+
url = yield this.wallet.getExplorerTxUrl(params.fromAsset.chain, hash);
|
|
7957
|
+
}
|
|
7958
|
+
catch (_a) {
|
|
7959
|
+
// swallow: explorer URL lookup must not reject a successful swap
|
|
7960
|
+
}
|
|
7961
|
+
return { hash, url };
|
|
7962
|
+
});
|
|
7963
|
+
}
|
|
7964
|
+
getSwapHistory(_params) {
|
|
7965
|
+
return __awaiter$4(this, void 0, void 0, function* () {
|
|
7966
|
+
return { count: 0, swaps: [] };
|
|
7967
|
+
});
|
|
7968
|
+
}
|
|
7969
|
+
errorQuote(params, error) {
|
|
7970
|
+
return {
|
|
7971
|
+
protocol: this.name,
|
|
7972
|
+
toAddress: '',
|
|
7973
|
+
memo: '',
|
|
7974
|
+
expectedAmount: new CryptoAmount(baseAmount(0), params.destinationAsset),
|
|
7975
|
+
dustThreshold: new CryptoAmount(baseAmount(0), params.fromAsset),
|
|
7976
|
+
totalSwapSeconds: 0,
|
|
7977
|
+
maxStreamingQuantity: undefined,
|
|
7978
|
+
canSwap: false,
|
|
7979
|
+
warning: '',
|
|
7980
|
+
errors: [error],
|
|
7981
|
+
slipBasisPoints: 0,
|
|
7982
|
+
fees: {
|
|
7983
|
+
asset: params.fromAsset,
|
|
7984
|
+
affiliateFee: new CryptoAmount(baseAmount(0), params.fromAsset),
|
|
7985
|
+
outboundFee: new CryptoAmount(baseAmount(0), params.destinationAsset),
|
|
7986
|
+
},
|
|
7987
|
+
};
|
|
7988
|
+
}
|
|
7989
|
+
}
|
|
7990
|
+
|
|
7681
7991
|
/**
|
|
7682
7992
|
* The base URL for the Midgard API endpoint.
|
|
7683
7993
|
*/
|
|
7684
|
-
const MIDGARD_API_URL = 'https://
|
|
7994
|
+
const MIDGARD_API_URL = 'https://midgard.thorchain.network/';
|
|
7685
7995
|
|
|
7686
7996
|
/******************************************************************************
|
|
7687
7997
|
Copyright (c) Microsoft Corporation.
|
|
@@ -10510,7 +10820,7 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
|
|
|
10510
10820
|
const defaultMidgardConfig = {
|
|
10511
10821
|
mainnet: {
|
|
10512
10822
|
apiRetries: 3,
|
|
10513
|
-
midgardBaseUrls: ['https://gateway.liquify.com/chain/thorchain_midgard'],
|
|
10823
|
+
midgardBaseUrls: ['https://midgard.thorchain.network', 'https://gateway.liquify.com/chain/thorchain_midgard'],
|
|
10514
10824
|
},
|
|
10515
10825
|
stagenet: {
|
|
10516
10826
|
apiRetries: 3,
|
|
@@ -11063,6 +11373,7 @@ const getProtocolConfig = (name, configuration) => {
|
|
|
11063
11373
|
network: configuration.network,
|
|
11064
11374
|
affiliateBrokers: configuration.affiliateBrokers,
|
|
11065
11375
|
brokerUrl: configuration.brokerUrl,
|
|
11376
|
+
oneClickApiKey: configuration.oneClickApiKey,
|
|
11066
11377
|
};
|
|
11067
11378
|
};
|
|
11068
11379
|
class ProtocolFactory {
|
|
@@ -11075,6 +11386,8 @@ class ProtocolFactory {
|
|
|
11075
11386
|
return new MayachainProtocol(protocolConfig);
|
|
11076
11387
|
case 'Chainflip':
|
|
11077
11388
|
return new ChainflipProtocol(protocolConfig);
|
|
11389
|
+
case 'OneClick':
|
|
11390
|
+
return new OneClickProtocol(protocolConfig);
|
|
11078
11391
|
}
|
|
11079
11392
|
}
|
|
11080
11393
|
}
|