@gearbox-protocol/sdk 14.12.0-next.80 → 14.12.0-next.82
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/dist/cjs/model/filters.js +0 -4
- package/dist/cjs/model/filters.schema.js +10 -1
- package/dist/cjs/model/index.js +11 -0
- package/dist/cjs/model/liquidations.js +1 -1
- package/dist/cjs/model/liquidations.schema.js +1 -1
- package/dist/cjs/model/opportunities.js +1 -1
- package/dist/cjs/model/opportunities.schema.js +6 -13
- package/dist/cjs/model/positions.js +1 -1
- package/dist/cjs/model/positions.schema.js +33 -1
- package/dist/cjs/model/response.js +1 -0
- package/dist/cjs/model/response.schema.js +64 -0
- package/dist/cjs/new-sdk/AbstractNamespace.js +46 -128
- package/dist/cjs/new-sdk/GearboxSDK.js +55 -42
- package/dist/cjs/new-sdk/errors/AllSourcesFailedError.js +20 -0
- package/dist/cjs/new-sdk/errors/MissingSourceError.js +25 -0
- package/dist/cjs/new-sdk/errors/NoSourceServedError.js +20 -0
- package/dist/cjs/new-sdk/errors/SourceChainMismatchError.js +34 -0
- package/dist/cjs/new-sdk/errors/SourceUnavailableError.js +25 -0
- package/dist/cjs/new-sdk/errors/assertSameChains.js +12 -0
- package/dist/cjs/new-sdk/errors/everyChainFailed.js +11 -0
- package/dist/cjs/new-sdk/errors/index.js +15 -0
- package/dist/cjs/new-sdk/index.js +23 -3
- package/dist/cjs/new-sdk/opportunities/OpportunitiesNamespace.js +37 -89
- package/dist/cjs/new-sdk/positions/PositionsNamespace.js +27 -94
- package/dist/cjs/new-sdk/types.js +0 -21
- package/dist/cjs/new-sdk/utils/filterResponse.js +21 -0
- package/dist/cjs/new-sdk/utils/index.js +6 -0
- package/dist/cjs/new-sdk/utils/mergeChains.js +81 -0
- package/dist/cjs/new-sdk/utils/types.js +1 -0
- package/dist/cjs/offchain/AbstractOffchainNamespace.js +42 -65
- package/dist/cjs/offchain/GearboxAPI.js +12 -8
- package/dist/cjs/offchain/errors/OffchainInvalidJsonError.js +19 -0
- package/dist/cjs/offchain/errors/OffchainNotConfiguredError.js +20 -0
- package/dist/cjs/offchain/errors/OffchainNotImplementedError.js +19 -0
- package/dist/cjs/offchain/errors/OffchainRequestFailedError.js +24 -0
- package/dist/cjs/offchain/errors/OffchainStatusError.js +20 -0
- package/dist/cjs/offchain/errors/OffchainTransportError.js +31 -0
- package/dist/cjs/offchain/errors/OffchainValidationError.js +26 -0
- package/dist/cjs/offchain/errors/backendMessage.js +28 -0
- package/dist/cjs/offchain/errors/errorCause.js +12 -0
- package/dist/cjs/offchain/errors/index.js +21 -0
- package/dist/cjs/offchain/errors/readResponseBody.js +15 -0
- package/dist/cjs/offchain/index.js +22 -5
- package/dist/cjs/offchain/opportunities/OffchainOpportunities.js +6 -3
- package/dist/cjs/offchain/positions/OffchainPositions.js +15 -21
- package/dist/cjs/offchain/types.js +0 -75
- package/dist/cjs/sdk/MultichainSDK.js +1 -1
- package/dist/cjs/sdk/OnchainSDK.js +1 -1
- package/dist/cjs/sdk/accounts/credit-account-compressor/CreditAccountCompressor.js +6 -6
- package/dist/cjs/sdk/accounts/liquidations/LiquidationsService.js +26 -20
- package/dist/cjs/sdk/accounts/liquidations/MultichainLiquidationsService.js +38 -14
- package/dist/cjs/sdk/accounts/withdrawal-compressor/AbstractWithdrawalCompressorContract.js +7 -5
- package/dist/cjs/sdk/accounts/withdrawal-compressor/WithdrawalCompressorV313Contract.js +3 -2
- package/dist/cjs/sdk/base/MultichainConstruct.js +73 -34
- package/dist/cjs/sdk/chain/chains.js +11 -0
- package/dist/cjs/sdk/chain/index.js +1 -0
- package/dist/cjs/sdk/core/index.js +1 -1
- package/dist/cjs/sdk/index.js +2 -1
- package/dist/cjs/sdk/market/rwa/RWARegistry.js +4 -2
- package/dist/cjs/sdk/opportunities/MultichainOpportunitiesService.js +18 -32
- package/dist/cjs/sdk/opportunities/OpportunitiesService.js +1 -4
- package/dist/cjs/sdk/pools/PoolService.js +2 -1
- package/dist/cjs/sdk/positions/MultichainPositionsService.js +6 -29
- package/dist/cjs/sdk/positions/PositionsService.js +12 -6
- package/dist/esm/dev/AccountOpener.js +1 -1
- package/dist/esm/dev/withdrawalUtils.js +1 -1
- package/dist/esm/model/filters.js +0 -4
- package/dist/esm/model/filters.schema.js +10 -2
- package/dist/esm/model/index.js +5 -3
- package/dist/esm/model/liquidations.js +1 -1
- package/dist/esm/model/liquidations.schema.js +1 -1
- package/dist/esm/model/opportunities.js +1 -1
- package/dist/esm/model/opportunities.schema.js +4 -11
- package/dist/esm/model/positions.js +1 -1
- package/dist/esm/model/positions.schema.js +33 -3
- package/dist/esm/model/response.js +1 -0
- package/dist/esm/model/response.schema.js +58 -0
- package/dist/esm/new-sdk/AbstractNamespace.js +46 -128
- package/dist/esm/new-sdk/GearboxSDK.js +55 -42
- package/dist/esm/new-sdk/errors/AllSourcesFailedError.js +19 -0
- package/dist/esm/new-sdk/errors/MissingSourceError.js +24 -0
- package/dist/esm/new-sdk/errors/NoSourceServedError.js +19 -0
- package/dist/esm/new-sdk/errors/SourceChainMismatchError.js +33 -0
- package/dist/esm/new-sdk/errors/SourceUnavailableError.js +24 -0
- package/dist/esm/new-sdk/errors/assertSameChains.js +11 -0
- package/dist/esm/new-sdk/errors/everyChainFailed.js +10 -0
- package/dist/esm/new-sdk/errors/index.js +8 -0
- package/dist/esm/new-sdk/index.js +13 -3
- package/dist/esm/new-sdk/opportunities/OpportunitiesNamespace.js +38 -90
- package/dist/esm/new-sdk/positions/PositionsNamespace.js +28 -95
- package/dist/esm/new-sdk/types.js +1 -21
- package/dist/esm/new-sdk/utils/filterResponse.js +20 -0
- package/dist/esm/new-sdk/utils/index.js +3 -1
- package/dist/esm/new-sdk/utils/mergeChains.js +78 -0
- package/dist/esm/new-sdk/utils/types.js +1 -0
- package/dist/esm/offchain/AbstractOffchainNamespace.js +41 -64
- package/dist/esm/offchain/GearboxAPI.js +12 -8
- package/dist/esm/offchain/errors/OffchainInvalidJsonError.js +18 -0
- package/dist/esm/offchain/errors/OffchainNotConfiguredError.js +19 -0
- package/dist/esm/offchain/errors/OffchainNotImplementedError.js +18 -0
- package/dist/esm/offchain/errors/OffchainRequestFailedError.js +23 -0
- package/dist/esm/offchain/errors/OffchainStatusError.js +19 -0
- package/dist/esm/offchain/errors/OffchainTransportError.js +30 -0
- package/dist/esm/offchain/errors/OffchainValidationError.js +25 -0
- package/dist/esm/offchain/errors/backendMessage.js +27 -0
- package/dist/esm/offchain/errors/errorCause.js +11 -0
- package/dist/esm/offchain/errors/index.js +11 -0
- package/dist/esm/offchain/errors/readResponseBody.js +14 -0
- package/dist/esm/offchain/index.js +13 -2
- package/dist/esm/offchain/opportunities/OffchainOpportunities.js +6 -3
- package/dist/esm/offchain/positions/OffchainPositions.js +15 -21
- package/dist/esm/offchain/types.js +1 -72
- package/dist/esm/plugins/adapters/contracts/ERC4626AdapterContract.js +1 -1
- package/dist/esm/preview/simulate/simulatePoolOperation.js +1 -1
- package/dist/esm/preview/trace/extractTransfers.js +1 -1
- package/dist/esm/sdk/MultichainSDK.js +1 -1
- package/dist/esm/sdk/OnchainSDK.js +1 -1
- package/dist/esm/sdk/accounts/CreditAccountsServiceV310.js +2 -2
- package/dist/esm/sdk/accounts/credit-account-compressor/CreditAccountCompressor.js +6 -6
- package/dist/esm/sdk/accounts/liquidations/LiquidationsService.js +27 -21
- package/dist/esm/sdk/accounts/liquidations/MultichainLiquidationsService.js +38 -14
- package/dist/esm/sdk/accounts/withdrawal-compressor/AbstractWithdrawalCompressorContract.js +7 -5
- package/dist/esm/sdk/accounts/withdrawal-compressor/RedemptionLoggerV310Contract.js +1 -1
- package/dist/esm/sdk/accounts/withdrawal-compressor/WithdrawalCompressorV310Contract.js +1 -1
- package/dist/esm/sdk/accounts/withdrawal-compressor/WithdrawalCompressorV311Contract.js +1 -1
- package/dist/esm/sdk/accounts/withdrawal-compressor/WithdrawalCompressorV313Contract.js +4 -3
- package/dist/esm/sdk/base/MultichainConstruct.js +73 -34
- package/dist/esm/sdk/base/TokensMeta.js +2 -2
- package/dist/esm/sdk/chain/chains.js +11 -1
- package/dist/esm/sdk/chain/detectNetwork.js +1 -1
- package/dist/esm/sdk/chain/index.js +2 -2
- package/dist/esm/sdk/core/createAddressProvider.js +1 -1
- package/dist/esm/sdk/core/index.js +1 -1
- package/dist/esm/sdk/index.js +3 -3
- package/dist/esm/sdk/market/credit/CreditFacadeV310BaseContract.js +1 -1
- package/dist/esm/sdk/market/pool/PoolV310Contract.js +1 -1
- package/dist/esm/sdk/market/rwa/RWARegistry.js +4 -2
- package/dist/esm/sdk/market/zapper/IETHZapperContract.js +1 -1
- package/dist/esm/sdk/market/zapper/ZapperContract.js +1 -1
- package/dist/esm/sdk/opportunities/MultichainOpportunitiesService.js +18 -32
- package/dist/esm/sdk/opportunities/OpportunitiesService.js +1 -4
- package/dist/esm/sdk/pools/PoolService.js +3 -2
- package/dist/esm/sdk/positions/MultichainPositionsService.js +6 -29
- package/dist/esm/sdk/positions/PositionsService.js +12 -6
- package/dist/esm/sdk/utils/viem/simulateWithPriceUpdates.js +1 -1
- package/dist/types/model/filters.d.ts +9 -3
- package/dist/types/model/filters.schema.d.ts +7 -1
- package/dist/types/model/index.d.ts +7 -5
- package/dist/types/model/liquidations.d.ts +2 -6
- package/dist/types/model/liquidations.schema.d.ts +1 -1
- package/dist/types/model/opportunities.d.ts +3 -7
- package/dist/types/model/opportunities.schema.d.ts +2 -2
- package/dist/types/model/positions.d.ts +2 -6
- package/dist/types/model/positions.schema.d.ts +32 -2
- package/dist/types/model/response.d.ts +105 -0
- package/dist/types/model/response.schema.d.ts +98 -0
- package/dist/types/new-sdk/AbstractNamespace.d.ts +33 -98
- package/dist/types/new-sdk/GearboxSDK.d.ts +10 -25
- package/dist/types/new-sdk/errors/AllSourcesFailedError.d.ts +11 -0
- package/dist/types/new-sdk/errors/MissingSourceError.d.ts +23 -0
- package/dist/types/new-sdk/errors/NoSourceServedError.d.ts +17 -0
- package/dist/types/new-sdk/errors/SourceChainMismatchError.d.ts +35 -0
- package/dist/types/new-sdk/errors/SourceUnavailableError.d.ts +22 -0
- package/dist/types/new-sdk/errors/assertSameChains.d.ts +11 -0
- package/dist/types/new-sdk/errors/everyChainFailed.d.ts +10 -0
- package/dist/types/new-sdk/errors/index.d.ts +8 -0
- package/dist/types/new-sdk/index.d.ts +17 -6
- package/dist/types/new-sdk/opportunities/OpportunitiesNamespace.d.ts +19 -40
- package/dist/types/new-sdk/opportunities/index.d.ts +2 -2
- package/dist/types/new-sdk/opportunities/types.d.ts +80 -26
- package/dist/types/new-sdk/positions/PositionsNamespace.d.ts +17 -38
- package/dist/types/new-sdk/positions/index.d.ts +2 -2
- package/dist/types/new-sdk/positions/types.d.ts +74 -24
- package/dist/types/new-sdk/types.d.ts +24 -77
- package/dist/types/new-sdk/utils/filterResponse.d.ts +16 -0
- package/dist/types/new-sdk/utils/history.d.ts +6 -36
- package/dist/types/new-sdk/utils/index.d.ts +5 -2
- package/dist/types/new-sdk/utils/mergeChains.d.ts +20 -0
- package/dist/types/new-sdk/utils/types.d.ts +11 -0
- package/dist/types/offchain/AbstractOffchainNamespace.d.ts +21 -28
- package/dist/types/offchain/GearboxAPI.d.ts +13 -9
- package/dist/types/offchain/errors/OffchainInvalidJsonError.d.ts +16 -0
- package/dist/types/offchain/errors/OffchainNotConfiguredError.d.ts +16 -0
- package/dist/types/offchain/errors/OffchainNotImplementedError.d.ts +15 -0
- package/dist/types/offchain/errors/OffchainRequestFailedError.d.ts +12 -0
- package/dist/types/offchain/errors/OffchainStatusError.d.ts +16 -0
- package/dist/types/offchain/errors/OffchainTransportError.d.ts +43 -0
- package/dist/types/offchain/errors/OffchainValidationError.d.ts +21 -0
- package/dist/types/offchain/errors/backendMessage.d.ts +9 -0
- package/dist/types/offchain/errors/errorCause.d.ts +22 -0
- package/dist/types/offchain/errors/index.d.ts +11 -0
- package/dist/types/offchain/errors/readResponseBody.d.ts +8 -0
- package/dist/types/offchain/index.d.ts +13 -2
- package/dist/types/offchain/opportunities/OffchainOpportunities.d.ts +9 -8
- package/dist/types/offchain/positions/OffchainPositions.d.ts +9 -15
- package/dist/types/offchain/types.d.ts +7 -88
- package/dist/types/sdk/accounts/credit-account-compressor/types.d.ts +4 -0
- package/dist/types/sdk/accounts/index.d.ts +3 -3
- package/dist/types/sdk/accounts/liquidations/LiquidationsService.d.ts +2 -2
- package/dist/types/sdk/accounts/liquidations/MultichainLiquidationsService.d.ts +15 -14
- package/dist/types/sdk/accounts/liquidations/index.d.ts +2 -2
- package/dist/types/sdk/accounts/liquidations/types.d.ts +32 -16
- package/dist/types/sdk/accounts/withdrawal-compressor/AbstractWithdrawalCompressorContract.d.ts +4 -4
- package/dist/types/sdk/accounts/withdrawal-compressor/WithdrawalCompressorV313Contract.d.ts +2 -2
- package/dist/types/sdk/accounts/withdrawal-compressor/index.d.ts +2 -2
- package/dist/types/sdk/accounts/withdrawal-compressor/types.d.ts +26 -4
- package/dist/types/sdk/base/MultichainConstruct.d.ts +63 -14
- package/dist/types/sdk/base/index.d.ts +2 -2
- package/dist/types/sdk/chain/chains.d.ts +10 -2
- package/dist/types/sdk/chain/index.d.ts +2 -2
- package/dist/types/sdk/index.d.ts +7 -7
- package/dist/types/sdk/market/MarketSuite.d.ts +1 -1
- package/dist/types/sdk/market/rwa/RWARegistry.d.ts +2 -1
- package/dist/types/sdk/opportunities/MultichainOpportunitiesService.d.ts +13 -16
- package/dist/types/sdk/pools/types.d.ts +4 -0
- package/dist/types/sdk/positions/MultichainPositionsService.d.ts +2 -12
- package/dist/types/sdk/positions/index.d.ts +2 -2
- package/dist/types/sdk/positions/types.d.ts +14 -5
- package/dist/types/sdk/types/index.d.ts +2 -2
- package/dist/types/sdk/types/multichain.d.ts +16 -36
- package/package.json +1 -1
|
@@ -1,9 +1,19 @@
|
|
|
1
|
-
import { AllSourcesFailedError } from "./
|
|
1
|
+
import { AllSourcesFailedError } from "./errors/AllSourcesFailedError.js";
|
|
2
|
+
import { SourceChainMismatchError } from "./errors/SourceChainMismatchError.js";
|
|
3
|
+
import { assertSameChains } from "./errors/assertSameChains.js";
|
|
4
|
+
import { everyChainFailed } from "./errors/everyChainFailed.js";
|
|
5
|
+
import { MissingSourceError } from "./errors/MissingSourceError.js";
|
|
6
|
+
import { NoSourceServedError } from "./errors/NoSourceServedError.js";
|
|
7
|
+
import { SourceUnavailableError } from "./errors/SourceUnavailableError.js";
|
|
8
|
+
import "./errors/index.js";
|
|
2
9
|
import { AbstractNamespace } from "./AbstractNamespace.js";
|
|
10
|
+
import { filterResponse } from "./utils/filterResponse.js";
|
|
11
|
+
import { DEFAULT_MAX_OFFCHAIN_LAG, mergeChainList, mergeChainOne } from "./utils/mergeChains.js";
|
|
12
|
+
import "./utils/index.js";
|
|
3
13
|
import { OpportunitiesNamespace } from "./opportunities/OpportunitiesNamespace.js";
|
|
4
14
|
import "./opportunities/index.js";
|
|
5
15
|
import { PositionsNamespace } from "./positions/PositionsNamespace.js";
|
|
6
16
|
import "./positions/index.js";
|
|
7
17
|
import { GearboxSDK } from "./GearboxSDK.js";
|
|
8
|
-
import "./
|
|
9
|
-
export { AbstractNamespace, AllSourcesFailedError, GearboxSDK, OpportunitiesNamespace, PositionsNamespace };
|
|
18
|
+
import "./types.js";
|
|
19
|
+
export { AbstractNamespace, AllSourcesFailedError, DEFAULT_MAX_OFFCHAIN_LAG, GearboxSDK, MissingSourceError, NoSourceServedError, OpportunitiesNamespace, PositionsNamespace, SourceChainMismatchError, SourceUnavailableError, assertSameChains, everyChainFailed, filterResponse, mergeChainList, mergeChainOne };
|
|
@@ -1,120 +1,68 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { matchesOpportunityFilter } from "../../model/opportunities.js";
|
|
2
2
|
import "../../model/index.js";
|
|
3
3
|
import { AbstractNamespace } from "../AbstractNamespace.js";
|
|
4
|
+
import { filterResponse } from "../utils/filterResponse.js";
|
|
5
|
+
import { mergeChainList, mergeChainOne } from "../utils/mergeChains.js";
|
|
6
|
+
import "../utils/index.js";
|
|
4
7
|
//#region src/new-sdk/opportunities/OpportunitiesNamespace.ts
|
|
5
8
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* Empty of on-chain conflicts today — every yield group here is off-chain only,
|
|
9
|
-
* so onchain-first would already yield the backend's value. It is written out
|
|
10
|
-
* anyway so that adding an on-chain estimate of one of them is a deliberate
|
|
11
|
-
* change to this list rather than a silent regression.
|
|
12
|
-
**/
|
|
13
|
-
const OFFCHAIN_OWNED_FIELDS = /* @__PURE__ */ new Set(["supplyApy", "collateralApy"]);
|
|
14
|
-
/**
|
|
15
|
-
* The `opportunities` namespace of the combined SDK.
|
|
16
|
-
*
|
|
17
|
-
* A stateless router over the two sources, see {@link AbstractNamespace} for
|
|
18
|
-
* the routing itself. What is specific to opportunities is the reads below and
|
|
19
|
-
* the merge policy at the bottom of the class.
|
|
20
|
-
*
|
|
21
|
-
* The class implements the methods of every mode; {@link GearboxSDK} exposes it
|
|
22
|
-
* as its mode's slice of {@link OpportunitiesByMode}, so calling a method the
|
|
23
|
-
* mode does not have is a compile error rather than a runtime one.
|
|
9
|
+
* The `opportunities` namespace of a {@link GearboxSDK}, see
|
|
10
|
+
* {@link OpportunitiesByMode} for what each mode offers.
|
|
24
11
|
**/
|
|
25
12
|
var OpportunitiesNamespace = class extends AbstractNamespace {
|
|
26
|
-
|
|
27
|
-
|
|
13
|
+
/**
|
|
14
|
+
* {@inheritDoc OpportunitiesBase.merge}
|
|
15
|
+
**/
|
|
16
|
+
merge = {
|
|
17
|
+
list: (onchain, offchain) => mergeChainList(onchain, offchain, this.maxOffchainLagSeconds),
|
|
18
|
+
pool: (onchain, offchain) => mergeChainOne(onchain, offchain, this.maxOffchainLagSeconds),
|
|
19
|
+
strategy: (onchain, offchain) => mergeChainOne(onchain, offchain, this.maxOffchainLagSeconds)
|
|
20
|
+
};
|
|
21
|
+
constructor(onchain, offchain, options) {
|
|
22
|
+
super("Opportunities", onchain?.opportunities, offchain?.opportunities, options);
|
|
28
23
|
}
|
|
29
24
|
/**
|
|
30
25
|
* {@inheritDoc OpportunitiesBase.list}
|
|
31
26
|
**/
|
|
32
27
|
async list(filter) {
|
|
33
|
-
return this.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
};
|
|
39
|
-
}, (api) => api.opportunities.list(filter));
|
|
28
|
+
return this.merged("list opportunities", {
|
|
29
|
+
fromChain: (source) => source.list(filter),
|
|
30
|
+
fromBackend: (source) => source.list(filter),
|
|
31
|
+
merge: this.merge.list
|
|
32
|
+
});
|
|
40
33
|
}
|
|
41
34
|
/**
|
|
42
35
|
* {@inheritDoc OpportunitiesBase.getPool}
|
|
43
36
|
**/
|
|
44
37
|
async getPool(key) {
|
|
45
|
-
return this.
|
|
38
|
+
return this.merged("get pool opportunity", {
|
|
39
|
+
fromChain: (source) => source.getPool(key),
|
|
40
|
+
fromBackend: (source) => source.getPool(key),
|
|
41
|
+
merge: this.merge.pool
|
|
42
|
+
});
|
|
46
43
|
}
|
|
47
44
|
/**
|
|
48
45
|
* {@inheritDoc OpportunitiesBase.getStrategy}
|
|
49
46
|
**/
|
|
50
47
|
async getStrategy(key) {
|
|
51
|
-
return this.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
48
|
+
return this.merged("get strategy opportunity", {
|
|
49
|
+
fromChain: (source) => source.getStrategy(key),
|
|
50
|
+
fromBackend: (source) => source.getStrategy(key),
|
|
51
|
+
merge: this.merge.strategy
|
|
52
|
+
});
|
|
55
53
|
}
|
|
56
54
|
/**
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* The metric a caller may name is gated by the reader's type, so the kind of
|
|
60
|
-
* the key is not re-checked here.
|
|
55
|
+
* {@inheritDoc OpportunitiesBase.filter}
|
|
61
56
|
**/
|
|
62
|
-
|
|
63
|
-
|
|
57
|
+
filter(response, filter) {
|
|
58
|
+
return filterResponse(response, filter, matchesOpportunityFilter);
|
|
59
|
+
}
|
|
60
|
+
history(key) {
|
|
61
|
+
return { chart: (metric, range) => this.offchain.getHistory({
|
|
64
62
|
opportunity: key,
|
|
65
63
|
range,
|
|
66
64
|
metric
|
|
67
|
-
})
|
|
68
|
-
metric,
|
|
69
|
-
points: [],
|
|
70
|
-
metadata: {}
|
|
71
|
-
});
|
|
72
|
-
return {
|
|
73
|
-
data: result.points,
|
|
74
|
-
metadata: {
|
|
75
|
-
...result.metadata,
|
|
76
|
-
source: meta
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Merges the two versions of one opportunity.
|
|
82
|
-
*
|
|
83
|
-
* The chain wins every field it fills; the backend fills the rest and owns
|
|
84
|
-
* {@link OFFCHAIN_OWNED_FIELDS}.
|
|
85
|
-
*
|
|
86
|
-
* The rule is onchain-first, field-wise, and never deeper than one level: a
|
|
87
|
-
* group like `totalSupply` or `supplyApy` is taken whole from one source, so
|
|
88
|
-
* a row never mixes an on-chain token amount with a backend dollar value
|
|
89
|
-
* derived from a different block.
|
|
90
|
-
**/
|
|
91
|
-
mergeOne(onchain, offchain) {
|
|
92
|
-
const merged = { ...onchain };
|
|
93
|
-
for (const [field, value] of Object.entries(offchain)) {
|
|
94
|
-
if (value === void 0) continue;
|
|
95
|
-
if (OFFCHAIN_OWNED_FIELDS.has(field) || merged[field] === void 0) merged[field] = value;
|
|
96
|
-
}
|
|
97
|
-
return merged;
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Unions the two lists by canonical opportunity id.
|
|
101
|
-
*
|
|
102
|
-
* Rows present in both are merged by {@link OpportunitiesNamespace.mergeOne}.
|
|
103
|
-
* Rows only the backend knows are appended: a chain the SDK does not cover,
|
|
104
|
-
* or a market it has not loaded, is a reason to show more rather than fewer
|
|
105
|
-
* opportunities.
|
|
106
|
-
**/
|
|
107
|
-
mergeList(onchain, offchain) {
|
|
108
|
-
const byId = /* @__PURE__ */ new Map();
|
|
109
|
-
for (const row of onchain) byId.set(opportunityId(row), row);
|
|
110
|
-
const extra = [];
|
|
111
|
-
for (const row of offchain) {
|
|
112
|
-
const id = opportunityId(row);
|
|
113
|
-
const existing = byId.get(id);
|
|
114
|
-
if (existing) byId.set(id, this.mergeOne(existing, row));
|
|
115
|
-
else extra.push(row);
|
|
116
|
-
}
|
|
117
|
-
return [...byId.values(), ...extra];
|
|
65
|
+
}) };
|
|
118
66
|
}
|
|
119
67
|
};
|
|
120
68
|
//#endregion
|
|
@@ -1,117 +1,50 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { matchesPositionFilter } from "../../model/positions.js";
|
|
2
2
|
import "../../model/index.js";
|
|
3
3
|
import { AbstractNamespace } from "../AbstractNamespace.js";
|
|
4
|
+
import { filterResponse } from "../utils/filterResponse.js";
|
|
5
|
+
import { mergeChainList } from "../utils/mergeChains.js";
|
|
6
|
+
import "../utils/index.js";
|
|
4
7
|
//#region src/new-sdk/positions/PositionsNamespace.ts
|
|
5
8
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* The yield and PnL groups are derived from a position's history and from
|
|
9
|
-
* incentive programs, neither of which the chain has. `targetCollateral` is
|
|
10
|
-
* there for a subtler reason: the read model defines it as the collateral the
|
|
11
|
-
* position was opened into, which only the backend can know, while the chain
|
|
12
|
-
* approximates it with the dominant collateral held right now.
|
|
13
|
-
**/
|
|
14
|
-
const OFFCHAIN_OWNED_FIELDS = /* @__PURE__ */ new Set([
|
|
15
|
-
"apy",
|
|
16
|
-
"netApy",
|
|
17
|
-
"pnl",
|
|
18
|
-
"targetCollateral"
|
|
19
|
-
]);
|
|
20
|
-
/**
|
|
21
|
-
* The `positions` namespace of the combined SDK.
|
|
22
|
-
*
|
|
23
|
-
* A stateless router over the two sources, see {@link AbstractNamespace} for the
|
|
24
|
-
* routing itself. What is specific to positions is the reads below and the merge
|
|
25
|
-
* policy at the bottom of the class.
|
|
26
|
-
*
|
|
27
|
-
* The class implements the methods of every mode; {@link GearboxSDK} exposes it
|
|
28
|
-
* as its mode's slice of {@link PositionsByMode}, so calling a method the mode
|
|
29
|
-
* does not have is a compile error rather than a runtime one.
|
|
9
|
+
* The `positions` namespace of a {@link GearboxSDK}, see
|
|
10
|
+
* {@link PositionsByMode} for what each mode offers.
|
|
30
11
|
**/
|
|
31
12
|
var PositionsNamespace = class extends AbstractNamespace {
|
|
32
|
-
|
|
33
|
-
|
|
13
|
+
/**
|
|
14
|
+
* {@inheritDoc PositionsBase.merge}
|
|
15
|
+
**/
|
|
16
|
+
merge = { list: (onchain, offchain) => mergeChainList(onchain, offchain, this.maxOffchainLagSeconds) };
|
|
17
|
+
constructor(onchain, offchain, options) {
|
|
18
|
+
super("Positions", onchain?.positions, offchain?.positions, options);
|
|
34
19
|
}
|
|
35
20
|
/**
|
|
36
21
|
* {@inheritDoc PositionsBase.list}
|
|
37
22
|
**/
|
|
38
23
|
async list(wallet, filter) {
|
|
39
|
-
return this.
|
|
40
|
-
|
|
24
|
+
return this.merged("list positions", {
|
|
25
|
+
fromChain: (source) => source.list({
|
|
41
26
|
wallet,
|
|
42
27
|
filter
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
history(key) {
|
|
51
|
-
return { chart: (metric, range) => this.#chart(key, metric, range) };
|
|
28
|
+
}),
|
|
29
|
+
fromBackend: (source) => source.list({
|
|
30
|
+
wallet,
|
|
31
|
+
filter
|
|
32
|
+
}),
|
|
33
|
+
merge: this.merge.list
|
|
34
|
+
});
|
|
52
35
|
}
|
|
53
36
|
/**
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
* The metric a caller may name is gated by the reader's type, so the kind of
|
|
57
|
-
* the key is not re-checked here.
|
|
37
|
+
* {@inheritDoc PositionsBase.filter}
|
|
58
38
|
**/
|
|
59
|
-
|
|
60
|
-
|
|
39
|
+
filter(response, filter) {
|
|
40
|
+
return filterResponse(response, filter, matchesPositionFilter);
|
|
41
|
+
}
|
|
42
|
+
history(key) {
|
|
43
|
+
return { chart: (metric, range) => this.offchain.getHistory({
|
|
61
44
|
position: key,
|
|
62
45
|
range,
|
|
63
46
|
metric
|
|
64
|
-
})
|
|
65
|
-
metric,
|
|
66
|
-
points: [],
|
|
67
|
-
metadata: {}
|
|
68
|
-
});
|
|
69
|
-
return {
|
|
70
|
-
data: result.points,
|
|
71
|
-
metadata: {
|
|
72
|
-
...result.metadata,
|
|
73
|
-
source: meta
|
|
74
|
-
}
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Merges the two versions of one position.
|
|
79
|
-
*
|
|
80
|
-
* The chain wins every field it fills; the backend fills the rest and owns
|
|
81
|
-
* {@link OFFCHAIN_OWNED_FIELDS}.
|
|
82
|
-
*
|
|
83
|
-
* The rule is onchain-first, field-wise, and never deeper than one level: a
|
|
84
|
-
* group like `totalValue` or `apy` is taken whole from one source, so a row
|
|
85
|
-
* never mixes an on-chain token amount with a backend dollar value derived
|
|
86
|
-
* from a different block.
|
|
87
|
-
**/
|
|
88
|
-
mergeOne(onchain, offchain) {
|
|
89
|
-
const merged = { ...onchain };
|
|
90
|
-
for (const [field, value] of Object.entries(offchain)) {
|
|
91
|
-
if (value === void 0) continue;
|
|
92
|
-
if (OFFCHAIN_OWNED_FIELDS.has(field) || merged[field] === void 0) merged[field] = value;
|
|
93
|
-
}
|
|
94
|
-
return merged;
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* Unions the two lists by canonical position id.
|
|
98
|
-
*
|
|
99
|
-
* Rows present in both are merged by {@link PositionsNamespace.mergeOne}.
|
|
100
|
-
* Rows only the backend knows are appended: a chain the SDK does not cover,
|
|
101
|
-
* or a market it has not loaded, must not hide a position the wallet actually
|
|
102
|
-
* holds.
|
|
103
|
-
**/
|
|
104
|
-
mergeList(onchain, offchain) {
|
|
105
|
-
const byId = /* @__PURE__ */ new Map();
|
|
106
|
-
for (const row of onchain) byId.set(positionId(row), row);
|
|
107
|
-
const extra = [];
|
|
108
|
-
for (const row of offchain) {
|
|
109
|
-
const id = positionId(row);
|
|
110
|
-
const existing = byId.get(id);
|
|
111
|
-
if (existing) byId.set(id, this.mergeOne(existing, row));
|
|
112
|
-
else extra.push(row);
|
|
113
|
-
}
|
|
114
|
-
return [...byId.values(), ...extra];
|
|
47
|
+
}) };
|
|
115
48
|
}
|
|
116
49
|
};
|
|
117
50
|
//#endregion
|
|
@@ -1,21 +1 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* Thrown when a read had sources to ask and none of them answered.
|
|
4
|
-
*
|
|
5
|
-
* A read that partially succeeded never throws: it returns what it has and
|
|
6
|
-
* reports the rest in {@link SourceMeta}.
|
|
7
|
-
**/
|
|
8
|
-
var AllSourcesFailedError = class extends Error {
|
|
9
|
-
/**
|
|
10
|
-
* Outcome of every source the failed read asked.
|
|
11
|
-
**/
|
|
12
|
-
meta;
|
|
13
|
-
constructor(action, meta) {
|
|
14
|
-
const reasons = [...meta.chains.filter((c) => c.status === "error").map((c) => `${c.network}: ${c.error}`), ...meta.offchain?.status === "error" ? [`offchain: ${meta.offchain.error}`] : []];
|
|
15
|
-
super(`cannot ${action}, every source failed (${reasons.join("; ")})`);
|
|
16
|
-
this.name = "AllSourcesFailedError";
|
|
17
|
-
this.meta = meta;
|
|
18
|
-
}
|
|
19
|
-
};
|
|
20
|
-
//#endregion
|
|
21
|
-
export { AllSourcesFailedError };
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//#region src/new-sdk/utils/filterResponse.ts
|
|
2
|
+
/**
|
|
3
|
+
* Narrows an already-read list, rows and metadata alike. `undefined` passes
|
|
4
|
+
* through, so a read still in flight stays that way.
|
|
5
|
+
*
|
|
6
|
+
* @typeParam T - Row type.
|
|
7
|
+
* @typeParam F - Filter type.
|
|
8
|
+
* @param matches - Whether one row satisfies the filter, e.g.
|
|
9
|
+
* `matchesOpportunityFilter`.
|
|
10
|
+
**/
|
|
11
|
+
function filterResponse(response, filter, matches) {
|
|
12
|
+
if (!response) return;
|
|
13
|
+
const chainIds = filter?.chainIds;
|
|
14
|
+
return {
|
|
15
|
+
data: response.data.filter((row) => matches(row, filter)),
|
|
16
|
+
meta: { chains: chainIds ? response.meta.chains.filter((chain) => chainIds.includes(chain.chainId)) : response.meta.chains }
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { filterResponse };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { NoSourceServedError } from "../errors/NoSourceServedError.js";
|
|
2
|
+
import "../errors/index.js";
|
|
3
|
+
//#region src/new-sdk/utils/mergeChains.ts
|
|
4
|
+
/**
|
|
5
|
+
* How many seconds the backend may lag the chain and still be used.
|
|
6
|
+
**/
|
|
7
|
+
const DEFAULT_MAX_OFFCHAIN_LAG = 120;
|
|
8
|
+
/**
|
|
9
|
+
* Merges two lists chain by chain: a chain is served by the backend when it is
|
|
10
|
+
* within `maxLagSeconds` of the chain, by the chain otherwise, and reported as
|
|
11
|
+
* an error when neither source succeeded.
|
|
12
|
+
**/
|
|
13
|
+
function mergeChainList(onchain, offchain, maxLagSeconds = 120) {
|
|
14
|
+
if (!onchain && !offchain) return;
|
|
15
|
+
const fromOnchain = /* @__PURE__ */ new Map();
|
|
16
|
+
for (const chain of onchain?.meta.chains ?? []) fromOnchain.set(chain.chainId, chain);
|
|
17
|
+
const fromOffchain = /* @__PURE__ */ new Map();
|
|
18
|
+
for (const chain of offchain?.meta.chains ?? []) fromOffchain.set(chain.chainId, chain);
|
|
19
|
+
const data = [];
|
|
20
|
+
const chains = [];
|
|
21
|
+
for (const chainId of /* @__PURE__ */ new Set([...fromOnchain.keys(), ...fromOffchain.keys()])) {
|
|
22
|
+
const onchainMeta = fromOnchain.get(chainId);
|
|
23
|
+
const offchainMeta = fromOffchain.get(chainId);
|
|
24
|
+
const winner = pickSource(onchainMeta, offchainMeta, maxLagSeconds);
|
|
25
|
+
if (winner === "onchain" && onchain && onchainMeta) {
|
|
26
|
+
data.push(...onchain.data.filter((row) => row.chainId === chainId));
|
|
27
|
+
chains.push(onchainMeta);
|
|
28
|
+
} else if (winner === "offchain" && offchain && offchainMeta) {
|
|
29
|
+
data.push(...offchain.data.filter((row) => row.chainId === chainId));
|
|
30
|
+
chains.push(offchainMeta);
|
|
31
|
+
} else chains.push(failedChain(chainId, onchainMeta, offchainMeta));
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
data,
|
|
35
|
+
meta: { chains }
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Merges two versions of one entity under the same freshness rule as
|
|
40
|
+
* {@link mergeChainList}, returning the winning response whole.
|
|
41
|
+
**/
|
|
42
|
+
function mergeChainOne(onchain, offchain, maxLagSeconds = 120) {
|
|
43
|
+
switch (pickSource(onchain?.meta.chains[0], offchain?.meta.chains[0], maxLagSeconds)) {
|
|
44
|
+
case "onchain": return onchain;
|
|
45
|
+
case "offchain": return offchain;
|
|
46
|
+
default: return;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Which side serves one chain, or `undefined` when neither can.
|
|
51
|
+
**/
|
|
52
|
+
function pickSource(onchain, offchain, maxLagSeconds) {
|
|
53
|
+
const onchainOk = onchain?.status === "success" ? onchain : void 0;
|
|
54
|
+
const offchainOk = offchain?.status === "success" ? offchain : void 0;
|
|
55
|
+
if (onchainOk && offchainOk) return isFresh(onchainOk, offchainOk, maxLagSeconds) ? "offchain" : "onchain";
|
|
56
|
+
if (onchainOk) return "onchain";
|
|
57
|
+
if (offchainOk) return "offchain";
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Whether the backend is close enough behind the chain to be preferred.
|
|
61
|
+
**/
|
|
62
|
+
function isFresh(onchain, offchain, maxLagSeconds) {
|
|
63
|
+
return offchain.timestamp >= onchain.timestamp - maxLagSeconds;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Metadata for a chain neither source served.
|
|
67
|
+
**/
|
|
68
|
+
function failedChain(chainId, onchain, offchain) {
|
|
69
|
+
if (!onchain || !offchain) return onchain ?? offchain;
|
|
70
|
+
const reasons = [onchain, offchain].map((chain) => chain.status === "error" ? chain.error : void 0).filter((reason) => !!reason);
|
|
71
|
+
return {
|
|
72
|
+
chainId,
|
|
73
|
+
status: "error",
|
|
74
|
+
error: reasons.length === 1 ? reasons[0] : new NoSourceServedError(chainId, reasons)
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
//#endregion
|
|
78
|
+
export { DEFAULT_MAX_OFFCHAIN_LAG, mergeChainList, mergeChainOne };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,25 +1,30 @@
|
|
|
1
1
|
import { historySeriesSchema } from "../model/history.schema.js";
|
|
2
|
-
import {
|
|
2
|
+
import { responseSchema } from "../model/response.schema.js";
|
|
3
|
+
import { OffchainInvalidJsonError } from "./errors/OffchainInvalidJsonError.js";
|
|
4
|
+
import { OffchainNotConfiguredError } from "./errors/OffchainNotConfiguredError.js";
|
|
5
|
+
import { OffchainRequestFailedError } from "./errors/OffchainRequestFailedError.js";
|
|
6
|
+
import { OffchainStatusError } from "./errors/OffchainStatusError.js";
|
|
7
|
+
import { OffchainValidationError } from "./errors/OffchainValidationError.js";
|
|
8
|
+
import { readResponseBody } from "./errors/readResponseBody.js";
|
|
9
|
+
import "./errors/index.js";
|
|
3
10
|
import { z } from "zod/v4";
|
|
4
11
|
//#region src/offchain/AbstractOffchainNamespace.ts
|
|
5
12
|
const DEFAULT_TIMEOUT = 3e4;
|
|
6
13
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* A namespace is a set of routes: it knows which path answers which read and
|
|
10
|
-
* which schema describes the payload. Everything under that — where the
|
|
11
|
-
* backend is, how long a request may take, how a failure is reported and how a
|
|
12
|
-
* response becomes read model values — lives here, so a namespace holds
|
|
14
|
+
* Base class of every {@link GearboxAPI} namespace: issues the requests,
|
|
15
|
+
* decodes the responses and reports the failures, so that a namespace holds
|
|
13
16
|
* nothing but its routes.
|
|
14
17
|
**/
|
|
15
18
|
var AbstractOffchainNamespace = class {
|
|
16
19
|
logger;
|
|
17
20
|
#baseUrl;
|
|
21
|
+
#chainIds;
|
|
18
22
|
#timeout;
|
|
19
23
|
constructor(name, options) {
|
|
20
|
-
this.#baseUrl = options
|
|
21
|
-
this.#
|
|
22
|
-
this
|
|
24
|
+
this.#baseUrl = options.baseUrl?.replace(/\/+$/, "");
|
|
25
|
+
this.#chainIds = [...options.chainIds];
|
|
26
|
+
this.#timeout = options.timeout ?? DEFAULT_TIMEOUT;
|
|
27
|
+
this.logger = options.logger?.child?.({ name }) ?? options.logger;
|
|
23
28
|
}
|
|
24
29
|
/**
|
|
25
30
|
* Base URL every read of this namespace is issued against.
|
|
@@ -28,36 +33,39 @@ var AbstractOffchainNamespace = class {
|
|
|
28
33
|
return this.#baseUrl;
|
|
29
34
|
}
|
|
30
35
|
/**
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
* Chains one read covers: the configured ones, narrowed by the filter when it
|
|
37
|
+
* names any. A filter naming a chain this client does not cover narrows
|
|
38
|
+
* nothing.
|
|
39
|
+
**/
|
|
40
|
+
scopedChainIds(filter) {
|
|
41
|
+
const wanted = filter?.chainIds;
|
|
42
|
+
return wanted ? this.#chainIds.filter((chainId) => wanted.includes(chainId)) : [...this.#chainIds];
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Reads one endpoint and decodes its payload. Timeouts, non-2xx answers and
|
|
46
|
+
* schema skew throw, since none of them is a {@link DataResponse}.
|
|
36
47
|
**/
|
|
37
48
|
async get(request) {
|
|
38
49
|
const url = this.#url(request.path, request.query);
|
|
39
|
-
this.logger?.debug(`reading ${url}`);
|
|
40
50
|
const payload = await this.#fetchJson(url);
|
|
41
|
-
const parsed = request.schema.safeParse(payload);
|
|
51
|
+
const parsed = responseSchema(request.schema).safeParse(payload);
|
|
42
52
|
if (!parsed.success) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}, "offchain response does not match the read model");
|
|
47
|
-
throw new OffchainValidationError(url, parsed.error.issues);
|
|
53
|
+
const error = new OffchainValidationError(url, parsed.error);
|
|
54
|
+
this.logger?.error(error, "offchain response does not match the read model");
|
|
55
|
+
throw error;
|
|
48
56
|
}
|
|
57
|
+
const { data, meta } = parsed.data;
|
|
49
58
|
return {
|
|
50
|
-
|
|
51
|
-
meta: {
|
|
59
|
+
data,
|
|
60
|
+
meta: { chains: meta.chains.map((chain) => ({
|
|
61
|
+
...chain,
|
|
62
|
+
source: "offchain"
|
|
63
|
+
})) }
|
|
52
64
|
};
|
|
53
65
|
}
|
|
54
66
|
/**
|
|
55
|
-
* Reads one historical series.
|
|
56
|
-
*
|
|
57
|
-
* The requested metric is pinned in the schema, which is what upholds the
|
|
58
|
-
* `HistorySeries<M>` a caller gets back: a response carrying a different
|
|
59
|
-
* metric is version skew and fails validation like any other mismatch,
|
|
60
|
-
* rather than being cast into the requested shape.
|
|
67
|
+
* Reads one historical series. A response carrying a metric other than the
|
|
68
|
+
* requested one fails validation.
|
|
61
69
|
**/
|
|
62
70
|
async readHistory(request) {
|
|
63
71
|
return this.get({
|
|
@@ -86,46 +94,15 @@ var AbstractOffchainNamespace = class {
|
|
|
86
94
|
signal: AbortSignal.timeout(this.#timeout)
|
|
87
95
|
});
|
|
88
96
|
} catch (error) {
|
|
89
|
-
throw new
|
|
97
|
+
throw new OffchainRequestFailedError(url, error);
|
|
90
98
|
}
|
|
91
|
-
if (!response.ok) throw new
|
|
99
|
+
if (!response.ok) throw new OffchainStatusError(url, response.status, await readResponseBody(response));
|
|
92
100
|
try {
|
|
93
101
|
return await response.json();
|
|
94
102
|
} catch (error) {
|
|
95
|
-
throw new
|
|
103
|
+
throw new OffchainInvalidJsonError(url, response.status, error);
|
|
96
104
|
}
|
|
97
105
|
}
|
|
98
106
|
};
|
|
99
|
-
/**
|
|
100
|
-
* Why a non-2xx response failed, in the backend's own words when it said.
|
|
101
|
-
**/
|
|
102
|
-
async function failureReason(response) {
|
|
103
|
-
const status = `the backend answered ${response.status}`;
|
|
104
|
-
let body;
|
|
105
|
-
try {
|
|
106
|
-
body = await response.text();
|
|
107
|
-
} catch {
|
|
108
|
-
return status;
|
|
109
|
-
}
|
|
110
|
-
const message = backendMessage(body) ?? body.trim();
|
|
111
|
-
return message ? `${status}: ${truncate(message)}` : status;
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* The `message` of a Gearbox backend error body, or nothing when the body is
|
|
115
|
-
* not one.
|
|
116
|
-
**/
|
|
117
|
-
function backendMessage(body) {
|
|
118
|
-
try {
|
|
119
|
-
const parsed = JSON.parse(body);
|
|
120
|
-
if (typeof parsed === "object" && parsed !== null && "message" in parsed && typeof parsed.message === "string") return parsed.message;
|
|
121
|
-
} catch {}
|
|
122
|
-
}
|
|
123
|
-
function describe(error) {
|
|
124
|
-
if (error instanceof Error) return error.name === "TimeoutError" ? "the request timed out" : error.message;
|
|
125
|
-
return String(error);
|
|
126
|
-
}
|
|
127
|
-
function truncate(text) {
|
|
128
|
-
return text.length > 200 ? `${text.slice(0, 200)}…` : text;
|
|
129
|
-
}
|
|
130
107
|
//#endregion
|
|
131
108
|
export { AbstractOffchainNamespace };
|
|
@@ -10,18 +10,21 @@ import "./positions/index.js";
|
|
|
10
10
|
* call reads the same way against either source:
|
|
11
11
|
*
|
|
12
12
|
* ```ts
|
|
13
|
-
* const api = new GearboxAPI({
|
|
14
|
-
*
|
|
13
|
+
* const api = new GearboxAPI({
|
|
14
|
+
* baseUrl: "https://api.gearbox.fi",
|
|
15
|
+
* chainIds: [1, 42161],
|
|
16
|
+
* });
|
|
17
|
+
* const { data } = await api.opportunities.list({ kind: "strategy" });
|
|
15
18
|
* ```
|
|
16
19
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* transport and schema validation.
|
|
20
|
-
*
|
|
21
|
-
* The transport is not implemented yet; see {@link OffchainOpportunities} and
|
|
22
|
-
* {@link OffchainPositions} for what each stubbed endpoint currently answers.
|
|
20
|
+
* Every read is scoped to {@link GearboxAPIOptions.chainIds}, so a client only
|
|
21
|
+
* ever sees the chains it was built for even though the backend knows more.
|
|
23
22
|
**/
|
|
24
23
|
var GearboxAPI = class {
|
|
24
|
+
/**
|
|
25
|
+
* Chains every read of this client is scoped to.
|
|
26
|
+
**/
|
|
27
|
+
chainIds;
|
|
25
28
|
/**
|
|
26
29
|
* Namespace for pool and strategy opportunities.
|
|
27
30
|
**/
|
|
@@ -31,6 +34,7 @@ var GearboxAPI = class {
|
|
|
31
34
|
**/
|
|
32
35
|
positions;
|
|
33
36
|
constructor(options) {
|
|
37
|
+
this.chainIds = [...options.chainIds];
|
|
34
38
|
this.opportunities = new OffchainOpportunities(options);
|
|
35
39
|
this.positions = new OffchainPositions(options);
|
|
36
40
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { OffchainTransportError } from "./OffchainTransportError.js";
|
|
2
|
+
//#region src/offchain/errors/OffchainInvalidJsonError.ts
|
|
3
|
+
/**
|
|
4
|
+
* Thrown when the backend answered in the 2xx range with a body that is not
|
|
5
|
+
* JSON, so there is nothing to validate against the read model.
|
|
6
|
+
**/
|
|
7
|
+
var OffchainInvalidJsonError = class extends OffchainTransportError {
|
|
8
|
+
name = "OffchainInvalidJsonError";
|
|
9
|
+
constructor(url, status, cause) {
|
|
10
|
+
super("The Gearbox backend answered with a body that is not JSON.", {
|
|
11
|
+
url,
|
|
12
|
+
status,
|
|
13
|
+
cause
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
//#endregion
|
|
18
|
+
export { OffchainInvalidJsonError };
|