@waterx/sdk 4.3.2 → 5.0.0
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/.claude/skills/waterx-sdk-integration/SKILL.md +225 -0
- package/README.md +216 -45
- package/SKILLS.md +34 -0
- package/dist/cjs/src/account/config.d.ts +3 -5
- package/dist/cjs/src/account/funding/wormhole.d.ts +1 -2
- package/dist/cjs/src/account/funding/wormhole.js +1 -2
- package/dist/cjs/src/generated/waterx_rule/waterx_rule.d.ts +140 -7
- package/dist/cjs/src/generated/waterx_rule/waterx_rule.js +163 -8
- package/dist/cjs/src/oracle/aggregate.d.ts +49 -62
- package/dist/cjs/src/oracle/aggregate.js +208 -164
- package/dist/cjs/src/oracle/config.d.ts +38 -51
- package/dist/cjs/src/oracle/config.js +1 -1
- package/dist/cjs/src/oracle/host.d.ts +14 -19
- package/dist/cjs/src/oracle/host.js +3 -3
- package/dist/cjs/src/oracle/index.d.ts +25 -16
- package/dist/cjs/src/oracle/index.js +87 -69
- package/dist/cjs/src/oracle/price-update-rule.d.ts +104 -66
- package/dist/cjs/src/oracle/price-update-rule.js +24 -16
- package/dist/cjs/src/oracle/pyth-pro-history.d.ts +36 -0
- package/dist/cjs/src/oracle/pyth-pro-history.js +41 -0
- package/dist/cjs/src/oracle/read-plane.d.ts +35 -53
- package/dist/cjs/src/oracle/read-plane.js +26 -48
- package/dist/cjs/src/oracle/read-prices.d.ts +105 -0
- package/dist/cjs/src/oracle/read-prices.js +162 -0
- package/dist/cjs/src/oracle/rule-registry.d.ts +12 -12
- package/dist/cjs/src/oracle/rule-registry.js +12 -14
- package/dist/cjs/src/oracle/rules/pyth-lazer-rule.d.ts +24 -3
- package/dist/cjs/src/oracle/rules/pyth-lazer-rule.js +40 -20
- package/dist/cjs/src/oracle/rules/waterx-rule.d.ts +271 -57
- package/dist/cjs/src/oracle/rules/waterx-rule.js +743 -144
- package/dist/cjs/src/oracle/schedule.d.ts +109 -0
- package/dist/cjs/src/oracle/schedule.js +991 -0
- package/dist/cjs/src/oracle/source-list.d.ts +31 -27
- package/dist/cjs/src/oracle/source-list.js +43 -45
- package/dist/cjs/src/oracle/symbol-catalog.d.ts +54 -0
- package/dist/cjs/src/oracle/symbol-catalog.js +69 -0
- package/dist/cjs/src/oracle/update-fetch.d.ts +11 -15
- package/dist/cjs/src/oracle/update-fetch.js +12 -19
- package/dist/cjs/src/oracle/validate.d.ts +105 -0
- package/dist/cjs/src/oracle/validate.js +185 -0
- package/dist/cjs/src/oracle/weight-coverage.d.ts +79 -0
- package/dist/cjs/src/oracle/weight-coverage.js +173 -0
- package/dist/cjs/src/perp/client.d.ts +40 -55
- package/dist/cjs/src/perp/client.js +44 -17
- package/dist/cjs/src/perp/config-view.d.ts +5 -14
- package/dist/cjs/src/perp/config-view.js +5 -16
- package/dist/cjs/src/perp/config.d.ts +3 -3
- package/dist/cjs/src/perp/config.js +11 -13
- package/dist/cjs/src/perp/index.d.ts +4 -6
- package/dist/cjs/src/perp/index.js +43 -18
- package/dist/cjs/src/perp/tx-builders/common.d.ts +86 -48
- package/dist/cjs/src/perp/tx-builders/common.js +115 -47
- package/dist/cjs/src/perp/tx-builders/wlp.d.ts +3 -14
- package/dist/cjs/src/perp/tx-builders/wlp.js +6 -35
- package/dist/cjs/src/perp/tx-builders.d.ts +6 -5
- package/dist/cjs/src/perp/tx-builders.js +16 -10
- package/dist/cjs/src/unified-client.d.ts +9 -35
- package/dist/cjs/src/unified-client.js +3 -4
- package/dist/cjs/src/utils/config.d.ts +0 -8
- package/dist/cjs/src/utils/config.js +5 -13
- package/dist/src/account/config.d.ts +3 -5
- package/dist/src/account/funding/wormhole.d.ts +1 -2
- package/dist/src/account/funding/wormhole.js +1 -2
- package/dist/src/generated/waterx_rule/waterx_rule.d.ts +140 -7
- package/dist/src/generated/waterx_rule/waterx_rule.js +151 -7
- package/dist/src/oracle/aggregate.d.ts +49 -62
- package/dist/src/oracle/aggregate.js +209 -164
- package/dist/src/oracle/config.d.ts +38 -51
- package/dist/src/oracle/config.js +1 -1
- package/dist/src/oracle/host.d.ts +14 -19
- package/dist/src/oracle/host.js +3 -3
- package/dist/src/oracle/index.d.ts +25 -16
- package/dist/src/oracle/index.js +61 -54
- package/dist/src/oracle/price-update-rule.d.ts +104 -66
- package/dist/src/oracle/price-update-rule.js +23 -16
- package/dist/src/oracle/pyth-pro-history.d.ts +36 -0
- package/dist/src/oracle/pyth-pro-history.js +38 -0
- package/dist/src/oracle/read-plane.d.ts +35 -53
- package/dist/src/oracle/read-plane.js +25 -47
- package/dist/src/oracle/read-prices.d.ts +105 -0
- package/dist/src/oracle/read-prices.js +156 -0
- package/dist/src/oracle/rule-registry.d.ts +12 -12
- package/dist/src/oracle/rule-registry.js +12 -14
- package/dist/src/oracle/rules/pyth-lazer-rule.d.ts +24 -3
- package/dist/src/oracle/rules/pyth-lazer-rule.js +39 -20
- package/dist/src/oracle/rules/waterx-rule.d.ts +271 -57
- package/dist/src/oracle/rules/waterx-rule.js +735 -144
- package/dist/src/oracle/schedule.d.ts +109 -0
- package/dist/src/oracle/schedule.js +985 -0
- package/dist/src/oracle/source-list.d.ts +31 -27
- package/dist/src/oracle/source-list.js +42 -43
- package/dist/src/oracle/symbol-catalog.d.ts +54 -0
- package/dist/src/oracle/symbol-catalog.js +65 -0
- package/dist/src/oracle/update-fetch.d.ts +11 -15
- package/dist/src/oracle/update-fetch.js +12 -18
- package/dist/src/oracle/validate.d.ts +105 -0
- package/dist/src/oracle/validate.js +177 -0
- package/dist/src/oracle/weight-coverage.d.ts +79 -0
- package/dist/src/oracle/weight-coverage.js +166 -0
- package/dist/src/perp/client.d.ts +40 -55
- package/dist/src/perp/client.js +45 -18
- package/dist/src/perp/config-view.d.ts +5 -14
- package/dist/src/perp/config-view.js +5 -16
- package/dist/src/perp/config.d.ts +3 -3
- package/dist/src/perp/config.js +11 -13
- package/dist/src/perp/index.d.ts +4 -6
- package/dist/src/perp/index.js +17 -5
- package/dist/src/perp/tx-builders/common.d.ts +86 -48
- package/dist/src/perp/tx-builders/common.js +114 -48
- package/dist/src/perp/tx-builders/wlp.d.ts +3 -14
- package/dist/src/perp/tx-builders/wlp.js +6 -35
- package/dist/src/perp/tx-builders.d.ts +6 -5
- package/dist/src/perp/tx-builders.js +15 -6
- package/dist/src/unified-client.d.ts +9 -35
- package/dist/src/unified-client.js +3 -4
- package/dist/src/utils/config.d.ts +0 -8
- package/dist/src/utils/config.js +5 -12
- package/package.json +8 -2
- package/dist/cjs/src/generated/pyth_sponsor_rule/deps/sui/balance.d.ts +0 -12
- package/dist/cjs/src/generated/pyth_sponsor_rule/deps/sui/balance.js +0 -17
- package/dist/cjs/src/generated/pyth_sponsor_rule/pyth_sponsor_rule.d.ts +0 -68
- package/dist/cjs/src/generated/pyth_sponsor_rule/pyth_sponsor_rule.js +0 -113
- package/dist/cjs/src/generated/waterx_pyth_rule/deps/sui/vec_map.d.ts +0 -36
- package/dist/cjs/src/generated/waterx_pyth_rule/deps/sui/vec_map.js +0 -31
- package/dist/cjs/src/generated/waterx_pyth_rule/pyth_rule.d.ts +0 -192
- package/dist/cjs/src/generated/waterx_pyth_rule/pyth_rule.js +0 -214
- package/dist/cjs/src/oracle/pyth.d.ts +0 -227
- package/dist/cjs/src/oracle/pyth.js +0 -652
- package/dist/cjs/src/oracle/rules/pyth-core-rule.d.ts +0 -15
- package/dist/cjs/src/oracle/rules/pyth-core-rule.js +0 -100
- package/dist/cjs/src/oracle/rules/pyth-rule.d.ts +0 -11
- package/dist/cjs/src/oracle/rules/pyth-rule.js +0 -29
- package/dist/cjs/src/oracle/rules/sponsor.d.ts +0 -32
- package/dist/cjs/src/oracle/rules/sponsor.js +0 -56
- package/dist/src/generated/pyth_sponsor_rule/deps/sui/balance.d.ts +0 -12
- package/dist/src/generated/pyth_sponsor_rule/deps/sui/balance.js +0 -14
- package/dist/src/generated/pyth_sponsor_rule/pyth_sponsor_rule.d.ts +0 -68
- package/dist/src/generated/pyth_sponsor_rule/pyth_sponsor_rule.js +0 -73
- package/dist/src/generated/waterx_pyth_rule/deps/sui/vec_map.d.ts +0 -36
- package/dist/src/generated/waterx_pyth_rule/deps/sui/vec_map.js +0 -27
- package/dist/src/generated/waterx_pyth_rule/pyth_rule.d.ts +0 -192
- package/dist/src/generated/waterx_pyth_rule/pyth_rule.js +0 -170
- package/dist/src/oracle/pyth.d.ts +0 -227
- package/dist/src/oracle/pyth.js +0 -638
- package/dist/src/oracle/rules/pyth-core-rule.d.ts +0 -15
- package/dist/src/oracle/rules/pyth-core-rule.js +0 -97
- package/dist/src/oracle/rules/pyth-rule.d.ts +0 -11
- package/dist/src/oracle/rules/pyth-rule.js +0 -26
- package/dist/src/oracle/rules/sponsor.d.ts +0 -32
- package/dist/src/oracle/rules/sponsor.js +0 -52
|
@@ -19,27 +19,18 @@ export declare class PerpConfigView {
|
|
|
19
19
|
getMarket(ticker: string): import("./config.ts").WaterxPerpMarketEntry;
|
|
20
20
|
/** `waterx_oracle.aggregators[ticker]`, throws if unknown. */
|
|
21
21
|
getAggregator(ticker: string): string;
|
|
22
|
-
/** `pyth_rule.feeds[ticker]`, throws if unknown. */
|
|
23
|
-
getPythFeed(ticker: string): {
|
|
24
|
-
feed_id: string;
|
|
25
|
-
price_info_object: string;
|
|
26
|
-
};
|
|
27
22
|
/**
|
|
28
23
|
* True when `ticker` is priced by `constant_rule` (a constant pin,
|
|
29
|
-
* e.g. `USDCUSD → $1`) rather than
|
|
30
|
-
* `constant_rule::feed` and need no
|
|
24
|
+
* e.g. `USDCUSD → $1`) rather than a live source. Such tickers are fed via
|
|
25
|
+
* `constant_rule::feed` and need no source update leg; see
|
|
26
|
+
* {@link refreshOraclePrices}.
|
|
31
27
|
*
|
|
32
28
|
* All-or-nothing, mirroring {@link getSupraRule} and the keeper: only routes a
|
|
33
29
|
* ticker to the constant rule when the rule is FULLY wired (`published_at` +
|
|
34
30
|
* `config` present). A half-populated block — a `feeds` entry listed before the
|
|
35
31
|
* rule is deployed, a realistic mid-rollout state — would otherwise make this
|
|
36
|
-
* true while {@link aggregateTicker} throws, aborting the whole price-refresh
|
|
37
|
-
* instead of
|
|
38
|
-
*
|
|
39
|
-
* Whether a constant ticker is *also* Pyth-fed (the dual-feed transition state)
|
|
40
|
-
* or constant-only is not a separate flag — it falls out of whether the ticker
|
|
41
|
-
* still has a `pyth_rule.feeds` entry. {@link aggregateTicker} feeds each rule the
|
|
42
|
-
* ticker is configured for, so no `isDualFeed` / `isConstantOnly` predicate is needed.
|
|
32
|
+
* true while {@link aggregateTicker} throws, aborting the whole price-refresh
|
|
33
|
+
* PTB instead of leaving the ticker to its live sources.
|
|
43
34
|
*/
|
|
44
35
|
isConstantTicker(ticker: string): boolean;
|
|
45
36
|
/**
|
|
@@ -39,29 +39,18 @@ export class PerpConfigView {
|
|
|
39
39
|
throw new Error(`No aggregator listed for ticker: ${ticker}`);
|
|
40
40
|
return a;
|
|
41
41
|
}
|
|
42
|
-
/** `pyth_rule.feeds[ticker]`, throws if unknown. */
|
|
43
|
-
getPythFeed(ticker) {
|
|
44
|
-
const f = ownEntry(this.config.packages.pyth_rule?.feeds, ticker);
|
|
45
|
-
if (!f)
|
|
46
|
-
throw new Error(`No pyth feed listed for ticker: ${ticker}`);
|
|
47
|
-
return f;
|
|
48
|
-
}
|
|
49
42
|
/**
|
|
50
43
|
* True when `ticker` is priced by `constant_rule` (a constant pin,
|
|
51
|
-
* e.g. `USDCUSD → $1`) rather than
|
|
52
|
-
* `constant_rule::feed` and need no
|
|
44
|
+
* e.g. `USDCUSD → $1`) rather than a live source. Such tickers are fed via
|
|
45
|
+
* `constant_rule::feed` and need no source update leg; see
|
|
46
|
+
* {@link refreshOraclePrices}.
|
|
53
47
|
*
|
|
54
48
|
* All-or-nothing, mirroring {@link getSupraRule} and the keeper: only routes a
|
|
55
49
|
* ticker to the constant rule when the rule is FULLY wired (`published_at` +
|
|
56
50
|
* `config` present). A half-populated block — a `feeds` entry listed before the
|
|
57
51
|
* rule is deployed, a realistic mid-rollout state — would otherwise make this
|
|
58
|
-
* true while {@link aggregateTicker} throws, aborting the whole price-refresh
|
|
59
|
-
* instead of
|
|
60
|
-
*
|
|
61
|
-
* Whether a constant ticker is *also* Pyth-fed (the dual-feed transition state)
|
|
62
|
-
* or constant-only is not a separate flag — it falls out of whether the ticker
|
|
63
|
-
* still has a `pyth_rule.feeds` entry. {@link aggregateTicker} feeds each rule the
|
|
64
|
-
* ticker is configured for, so no `isDualFeed` / `isConstantOnly` predicate is needed.
|
|
52
|
+
* true while {@link aggregateTicker} throws, aborting the whole price-refresh
|
|
53
|
+
* PTB instead of leaving the ticker to its live sources.
|
|
65
54
|
*/
|
|
66
55
|
isConstantTicker(ticker) {
|
|
67
56
|
const c = this.config.packages.constant_rule;
|
|
@@ -5,15 +5,15 @@
|
|
|
5
5
|
* The schema mirrors the canonical JSON layout one-to-one (each package
|
|
6
6
|
* groups its own object IDs + per-ticker maps). External chain infra is
|
|
7
7
|
* **not** in the JSON — each oracle source owns its own per-network table
|
|
8
|
-
* (`
|
|
9
|
-
* `oracle/rules/
|
|
8
|
+
* (`LAZER_INFRA` in `oracle/rules/pyth-lazer-rule.ts`, `WATERX_INFRA` in
|
|
9
|
+
* `oracle/rules/waterx-rule.ts`); Wormhole bridge infra lives in
|
|
10
10
|
* `WORMHOLE_DEFAULTS` below.
|
|
11
11
|
*/
|
|
12
12
|
import type { AccountPackages, BasePackageEntry, WormholeInfraConfig } from "../account/config.ts";
|
|
13
13
|
import type { OraclePackages } from "../oracle/config.ts";
|
|
14
14
|
import type { Network } from "./constants.ts";
|
|
15
15
|
export type { AccountConfig, AccountPackages, BasePackageEntry, NativeCustodyAsset, NativeCustodyPackage, WaterxCreditPackage, WaterxReferralPackage, WithdrawalQueuePackage, WormholeBridgePackage, WormholeInfraConfig, WxaAccountPackage, } from "../account/config.ts";
|
|
16
|
-
export type { ConstantFeedEntry, OracleConfig, OraclePackages, PythAccessConfig, PythFetchPolicy, PythLazerRulePackage,
|
|
16
|
+
export type { ConstantFeedEntry, OracleConfig, OraclePackages, PythAccessConfig, PythFetchPolicy, PythLazerRulePackage, SupraFeedEntry, SupraRulePackage, WaterxConstantRulePackage, WaterxAccessConfig, WaterxOraclePackage, WaterxRulePackage, } from "../oracle/config.ts";
|
|
17
17
|
export interface WaterxPerpMarketEntry {
|
|
18
18
|
market: string;
|
|
19
19
|
config: string;
|
package/dist/src/perp/config.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* The schema mirrors the canonical JSON layout one-to-one (each package
|
|
6
6
|
* groups its own object IDs + per-ticker maps). External chain infra is
|
|
7
7
|
* **not** in the JSON — each oracle source owns its own per-network table
|
|
8
|
-
* (`
|
|
9
|
-
* `oracle/rules/
|
|
8
|
+
* (`LAZER_INFRA` in `oracle/rules/pyth-lazer-rule.ts`, `WATERX_INFRA` in
|
|
9
|
+
* `oracle/rules/waterx-rule.ts`); Wormhole bridge infra lives in
|
|
10
10
|
* `WORMHOLE_DEFAULTS` below.
|
|
11
11
|
*/
|
|
12
12
|
import { fetchWithPolicy, rethrowExhaustedFetch } from "../oracle/update-fetch.js";
|
|
@@ -14,14 +14,12 @@ import { fetchWithPolicy, rethrowExhaustedFetch } from "../oracle/update-fetch.j
|
|
|
14
14
|
// Wormhole — external chain infra, defaults by network
|
|
15
15
|
// ============================================================================
|
|
16
16
|
//
|
|
17
|
-
// Oracle-source infra lives with each source (`
|
|
18
|
-
// `oracle/
|
|
19
|
-
// `client.pyth` is the caller-supplied access
|
|
20
|
-
// re-exported at the top of this file).
|
|
17
|
+
// Oracle-source infra lives with each source (`LAZER_INFRA` in
|
|
18
|
+
// `oracle/rules/pyth-lazer-rule.ts`, `WATERX_INFRA` in
|
|
19
|
+
// `oracle/rules/waterx-rule.ts`); `client.pyth` is the caller-supplied access
|
|
20
|
+
// slice only (`PythAccessConfig`, re-exported at the top of this file).
|
|
21
21
|
// `WormholeInfraConfig` is defined in `account/config.ts` (funding base) and
|
|
22
|
-
// re-exported at the top of this file.
|
|
23
|
-
// Wormhole `State` object Pyth uses (kept in sync with
|
|
24
|
-
// `PYTH_CORE_INFRA[*].wormhole_state_id`).
|
|
22
|
+
// re-exported at the top of this file.
|
|
25
23
|
export const WORMHOLE_DEFAULTS = {
|
|
26
24
|
MAINNET: {
|
|
27
25
|
state_id: "0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c",
|
|
@@ -141,15 +139,15 @@ function validateConfig(cfg, expected, url) {
|
|
|
141
139
|
};
|
|
142
140
|
// Validate by deployment kind. A perp config must carry the perp set; a
|
|
143
141
|
// credit config the credit set. `waterx_account` is common to both.
|
|
144
|
-
//
|
|
145
|
-
//
|
|
146
|
-
//
|
|
142
|
+
// NO oracle-rule package is required by presence — which rules run is the
|
|
143
|
+
// client's derived fed set, never a hand-declared list (and
|
|
144
|
+
// `pyth_rule`, once required here, was retired in 5.0.0 — a config may
|
|
145
|
+
// carry or omit its block freely).
|
|
147
146
|
const isPerp = "waterx_perp" in cfg.packages;
|
|
148
147
|
const isCredit = "waterx_credit" in cfg.packages || "wormhole_bridge" in cfg.packages;
|
|
149
148
|
const required = isPerp
|
|
150
149
|
? [
|
|
151
150
|
"bucket_framework",
|
|
152
|
-
"pyth_rule",
|
|
153
151
|
"waterx_account",
|
|
154
152
|
"waterx_oracle",
|
|
155
153
|
"waterx_perp",
|
package/dist/src/perp/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export { PerpClient } from "./client.ts";
|
|
2
2
|
export type { CreateClientOptions } from "./client.ts";
|
|
3
3
|
export { WORMHOLE_DEFAULTS, clearConfigCache, loadConfig } from "./config.ts";
|
|
4
|
-
export type { BasePackageEntry, ConstantFeedEntry, WaterxReferralPackage, LoadConfigOptions, NativeCustodyAsset, NativeCustodyPackage, PythAccessConfig, PythFetchPolicy, PythLazerRulePackage,
|
|
4
|
+
export type { BasePackageEntry, ConstantFeedEntry, WaterxReferralPackage, LoadConfigOptions, NativeCustodyAsset, NativeCustodyPackage, PythAccessConfig, PythFetchPolicy, PythLazerRulePackage, SupraFeedEntry, SupraRulePackage, TestnetFaucetPackage, WaterXConfig, WaterXPackages, WaterxCreditPackage, WaterxOraclePackage, WaterxPerpMarketEntry, WaterxPerpPackage, WaterxStakingPackage, WithdrawalQueuePackage, WlpPackage, WormholeBridgePackage, WormholeInfraConfig, WxaAccountPackage, } from "./config.ts";
|
|
5
5
|
export { ACTION_ADD_PRE_ORDER, ACTION_CANCEL_ORDER, ACTION_CANCEL_PRE_ORDER, ACTION_CLOSE_POSITION, ACTION_DECREASE_POSITION, ACTION_DEPOSIT_COLLATERAL, ACTION_INCREASE_POSITION, ACTION_LIQUIDATE, ACTION_OPEN_POSITION, ACTION_PLACE_ORDER, ACTION_UPDATE_ORDER, ACTION_WITHDRAW_COLLATERAL, BPS_SCALE, DOUBLE_SCALE, DRY_RUN_SENDER, FLOAT_SCALE, ORDER_LIMIT_BUY, ORDER_LIMIT_SELL, ORDER_STOP_BUY, ORDER_STOP_SELL, ORDER_TAG_WILDCARD, PERM_ALL, PERM_ALL_TRADING, PERM_CANCEL_ORDER, PERM_CLOSE_POSITION, PERM_DECREASE_POSITION, PERM_DEPOSIT_COLLATERAL, PERM_INCREASE_POSITION, PERM_MINT_WLP, PERM_OPEN_POSITION, PERM_PLACE_ORDER, PERM_REDEEM_WLP, PERM_WITHDRAW_COLLATERAL, STAKING_PERM_DEPOSIT_STAKE, STAKING_PERM_REDEEM_STAKE, STAKING_PERM_CLAIM_REWARD, STAKING_PERM_ALL, MS_PER_MINUTE, MS_PER_HOUR, MS_PER_YEAR, SUI_DECIMALS, WLP_DECIMALS, COLLATERAL_DECIMALS, TOKEN_DECIMALS, } from "./constants.ts";
|
|
6
6
|
export type { Network } from "./constants.ts";
|
|
7
|
-
export { getMarketTickers
|
|
7
|
+
export { getMarketTickers } from "../utils/config.ts";
|
|
8
8
|
export { annualizedApyFromRatio, annualizeFundingRate, calcBorrowRate, calcBorrowRateAccrual, calcDynamicFeeBps, calcEffectiveCollateralUsd, calcEstLiqPrice, calcEstLiqPriceRaw, calcFee, calcFundingFeeUsd, calcFundingRate, calcImpactFeeRate, calcLeverage, calcMaxReducibleCollateralUsd, calcNotional, calcPositionBorrowFee, calcRealLiqNetCostUsd, calcTokenUtilizationBps, calcTotalTradingFeeRate, calcUnrealizedPnl, calcViewEstLiqFeesUsd, calcWlpIncentiveApy, calcWlpMintOut, calcWlpPrice, calcWlpRedeemOut, decodeFundingIndexDelta, rawPrice, } from "../utils/math.ts";
|
|
9
9
|
export type { ExactDecimalUsd, LiqFeeBundle, RawPriceInput } from "../utils/math.ts";
|
|
10
10
|
export { formatFundingInterval } from "../utils/format.ts";
|
|
@@ -13,8 +13,8 @@ export type { EstLiqPriceViewOpts } from "./liq-view.ts";
|
|
|
13
13
|
export * from "./user/index.ts";
|
|
14
14
|
export * from "./tx-builders.ts";
|
|
15
15
|
export * from "./fetch.ts";
|
|
16
|
-
export { FetchPolicyError, LazerApiKeyMissingError,
|
|
17
|
-
export type { FetchPolicy,
|
|
16
|
+
export { FetchPolicyError, LazerApiKeyMissingError, LazerNotEntitledError, OracleTickerUnservedError, OracleWeightCoverageError, OracleWeightUnreadableError, OracleSourceNotImplementedError, aggregateTicker, aggregateTickerWithConstant, ORACLE_SOURCES, assertOracleWeightCoverage, assertOracleWriteCoverage, fetchPythProHistory, fetchPythSymbolCatalog, fetchWaterxSignedLeaves, fetchWaterxSignedUpdate, fetchWaterxUpdateData, getMarketStatus, isFreshWaterxEntry, deriveOracleSources, missingOracleCredentials, parsePythSchedule, PythScheduleParseError, pullWaterxQuotes, readLazerPrices, readPlanTickers, readQuoteCenterPrices, refreshOraclePrices, resolveOracleReadPlan, resolveOracleRule, servableTickers, WATERX_MAX_PRICE_AGE_MS, waterxEnvelopeOf, waterxLeavesOf, parseSignedLeaves, MERKLE_ROOT_INTENT, waterxQuoteCenterEndpoint, } from "../oracle/index.ts";
|
|
17
|
+
export type { FetchPolicy, HolidayDate, MarketStatusResult, OracleCredentialKind, OraclePriceEntry, OracleRefreshSummary, OracleReadPlan, OracleSource, ParsedPythSchedule, PythSymbolRecord, TradingHours, TradingSession, UpdateDataProvider, WaterxBatchItem, WaterxEnvelopePayload, WaterxLeafPayload, WaterxSignedEnvelope, WaterxSignedLeaf, WaterxUpdatePayload, } from "../oracle/index.ts";
|
|
18
18
|
export { fetchDepositVaa, fetchVaa, listBridgeWithdrawalVaas, listVaasByEmitter, padEvmEmitter, toWormholescanEmitter, vaaBase64ToBytes, vaaBase64ToHex, vaaBytesToBase64, waitForVaa, } from "../account/funding/wormhole.ts";
|
|
19
19
|
export type { VaaListItem, VaaResponse, WormholescanOptions } from "../account/funding/wormhole.ts";
|
|
20
20
|
export { AccountData as AccountDataBcs, GlobalConfigData as GlobalConfigDataBcs, MarketData as MarketDataBcs, OrderData as OrderDataBcs, PoolData as PoolDataBcs, PositionData as PositionDataBcs, RedeemRequestData as RedeemRequestDataBcs, TokenPoolData as TokenPoolDataBcs, } from "../generated/waterx_perp_view/view.ts";
|
|
@@ -27,8 +27,6 @@ export * as viewCalls from "../generated/waterx_perp_view/view.ts";
|
|
|
27
27
|
export * as wxaAccountCalls from "../generated/waterx_account/account.ts";
|
|
28
28
|
export * as stakingCalls from "../generated/waterx_staking/waterx_staking.ts";
|
|
29
29
|
export * as oracleCalls from "../generated/waterx_oracle/oracle.ts";
|
|
30
|
-
export * as pythRuleCalls from "../generated/waterx_pyth_rule/pyth_rule.ts";
|
|
31
|
-
export * as pythSponsorRuleCalls from "../generated/pyth_sponsor_rule/pyth_sponsor_rule.ts";
|
|
32
30
|
export * as referralCalls from "../generated/waterx_referral/referral_table.ts";
|
|
33
31
|
export * as nativeCustodyCalls from "../generated/native_custody/custody_vault.ts";
|
|
34
32
|
export * as withdrawalQueueCalls from "../generated/withdrawal_queue/withdrawal_queue.ts";
|
package/dist/src/perp/index.js
CHANGED
|
@@ -4,7 +4,7 @@ export { WORMHOLE_DEFAULTS, clearConfigCache, loadConfig } from "./config.js";
|
|
|
4
4
|
// ======== Constants & enums ========
|
|
5
5
|
export { ACTION_ADD_PRE_ORDER, ACTION_CANCEL_ORDER, ACTION_CANCEL_PRE_ORDER, ACTION_CLOSE_POSITION, ACTION_DECREASE_POSITION, ACTION_DEPOSIT_COLLATERAL, ACTION_INCREASE_POSITION, ACTION_LIQUIDATE, ACTION_OPEN_POSITION, ACTION_PLACE_ORDER, ACTION_UPDATE_ORDER, ACTION_WITHDRAW_COLLATERAL, BPS_SCALE, DOUBLE_SCALE, DRY_RUN_SENDER, FLOAT_SCALE, ORDER_LIMIT_BUY, ORDER_LIMIT_SELL, ORDER_STOP_BUY, ORDER_STOP_SELL, ORDER_TAG_WILDCARD, PERM_ALL, PERM_ALL_TRADING, PERM_CANCEL_ORDER, PERM_CLOSE_POSITION, PERM_DECREASE_POSITION, PERM_DEPOSIT_COLLATERAL, PERM_INCREASE_POSITION, PERM_MINT_WLP, PERM_OPEN_POSITION, PERM_PLACE_ORDER, PERM_REDEEM_WLP, PERM_WITHDRAW_COLLATERAL, STAKING_PERM_DEPOSIT_STAKE, STAKING_PERM_REDEEM_STAKE, STAKING_PERM_CLAIM_REWARD, STAKING_PERM_ALL, MS_PER_MINUTE, MS_PER_HOUR, MS_PER_YEAR, SUI_DECIMALS, WLP_DECIMALS, COLLATERAL_DECIMALS, TOKEN_DECIMALS, } from "./constants.js";
|
|
6
6
|
// ======== Utilities ========
|
|
7
|
-
export { getMarketTickers
|
|
7
|
+
export { getMarketTickers } from "../utils/config.js";
|
|
8
8
|
export { annualizedApyFromRatio, annualizeFundingRate, calcBorrowRate, calcBorrowRateAccrual, calcDynamicFeeBps, calcEffectiveCollateralUsd, calcEstLiqPrice, calcEstLiqPriceRaw, calcFee, calcFundingFeeUsd, calcFundingRate, calcImpactFeeRate, calcLeverage, calcMaxReducibleCollateralUsd, calcNotional, calcPositionBorrowFee, calcRealLiqNetCostUsd, calcTokenUtilizationBps, calcTotalTradingFeeRate, calcUnrealizedPnl, calcViewEstLiqFeesUsd, calcWlpIncentiveApy, calcWlpMintOut, calcWlpPrice, calcWlpRedeemOut, decodeFundingIndexDelta, rawPrice, } from "../utils/math.js";
|
|
9
9
|
export { formatFundingInterval } from "../utils/format.js";
|
|
10
10
|
export { calcEstLiqPriceRawFromView } from "./liq-view.js";
|
|
@@ -14,8 +14,22 @@ export * from "./user/index.js";
|
|
|
14
14
|
export * from "./tx-builders.js";
|
|
15
15
|
// ======== Read-only queries ========
|
|
16
16
|
export * from "./fetch.js";
|
|
17
|
-
// ======== Oracle utilities (
|
|
18
|
-
export { FetchPolicyError, LazerApiKeyMissingError,
|
|
17
|
+
// ======== Oracle utilities (sources + rule aggregation + read planes) ========
|
|
18
|
+
export { FetchPolicyError, LazerApiKeyMissingError, LazerNotEntitledError, OracleTickerUnservedError, OracleWeightCoverageError, OracleWeightUnreadableError, OracleSourceNotImplementedError, aggregateTicker, aggregateTickerWithConstant, ORACLE_SOURCES, assertOracleWeightCoverage, assertOracleWriteCoverage, fetchPythProHistory, fetchPythSymbolCatalog, fetchWaterxSignedLeaves, fetchWaterxSignedUpdate, fetchWaterxUpdateData, getMarketStatus, isFreshWaterxEntry, deriveOracleSources, missingOracleCredentials, parsePythSchedule, PythScheduleParseError,
|
|
19
|
+
// THE quote-center route ladder (leaves-first, envelope only where there is
|
|
20
|
+
// no leaf route). Both SDK planes go through it, so a consumer running its
|
|
21
|
+
// own prefetch reaches for the same one rather than re-deriving the ladder.
|
|
22
|
+
pullWaterxQuotes, readLazerPrices, readPlanTickers, readQuoteCenterPrices, refreshOraclePrices, resolveOracleReadPlan, resolveOracleRule,
|
|
23
|
+
// `refreshOraclePrices`' OWN acceptance predicate. Consumers filtering a
|
|
24
|
+
// ticker list before a build must use this rather than re-deriving "some
|
|
25
|
+
// listed source carries it", or they drift from what the build accepts.
|
|
26
|
+
servableTickers, WATERX_MAX_PRICE_AGE_MS, waterxEnvelopeOf,
|
|
27
|
+
// Leaves are the DEFAULT waterx wire shape, so their accessor + parser belong
|
|
28
|
+
// on the same surface as `waterxEnvelopeOf` (and on the root, which re-exports
|
|
29
|
+
// this file). A prefetch cache written against the envelope-only surface would
|
|
30
|
+
// otherwise get `null` from its only accessor on the normal path and have to
|
|
31
|
+
// discover `@waterx/sdk/oracle` to fix it.
|
|
32
|
+
waterxLeavesOf, parseSignedLeaves, MERKLE_ROOT_INTENT, waterxQuoteCenterEndpoint, } from "../oracle/index.js";
|
|
19
33
|
// ======== Wormhole / Wormholescan utilities (credit bridge) ========
|
|
20
34
|
export { fetchDepositVaa, fetchVaa, listBridgeWithdrawalVaas, listVaasByEmitter, padEvmEmitter, toWormholescanEmitter, vaaBase64ToBytes, vaaBase64ToHex, vaaBytesToBase64, waitForVaa, } from "../account/funding/wormhole.js";
|
|
21
35
|
// ======== Generated BCS types (sui-ts-codegen) ========
|
|
@@ -30,8 +44,6 @@ export * as viewCalls from "../generated/waterx_perp_view/view.js";
|
|
|
30
44
|
export * as wxaAccountCalls from "../generated/waterx_account/account.js";
|
|
31
45
|
export * as stakingCalls from "../generated/waterx_staking/waterx_staking.js";
|
|
32
46
|
export * as oracleCalls from "../generated/waterx_oracle/oracle.js";
|
|
33
|
-
export * as pythRuleCalls from "../generated/waterx_pyth_rule/pyth_rule.js";
|
|
34
|
-
export * as pythSponsorRuleCalls from "../generated/pyth_sponsor_rule/pyth_sponsor_rule.js";
|
|
35
47
|
export * as referralCalls from "../generated/waterx_referral/referral_table.js";
|
|
36
48
|
export * as nativeCustodyCalls from "../generated/native_custody/custody_vault.js";
|
|
37
49
|
export * as withdrawalQueueCalls from "../generated/withdrawal_queue/withdrawal_queue.js";
|
|
@@ -1,44 +1,58 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared scaffolding for the high-level perp `build*Tx` composers:
|
|
3
3
|
* `CommonBuildOpts`, the new-or-reuse PTB helper, the WLP pool-oracle refresh,
|
|
4
|
-
* and the request+execute envelope (optional
|
|
4
|
+
* and the request+execute envelope (optional pre-sweep).
|
|
5
5
|
*/
|
|
6
6
|
import { Transaction, type TransactionArgument } from "@mysten/sui/transactions";
|
|
7
|
-
import {
|
|
7
|
+
import { type OracleRefreshSummary, type UpdateDataProvider } from "../../oracle/index.ts";
|
|
8
8
|
import type { PerpClient } from "../client.ts";
|
|
9
9
|
export interface CommonBuildOpts {
|
|
10
10
|
/** Append to an existing PTB instead of creating a new one. */
|
|
11
11
|
tx?: Transaction;
|
|
12
|
-
/** Skip oracle refresh entirely (caller manages freshness). Default: false. */
|
|
13
|
-
skipOraclePriceRefresh?: boolean;
|
|
14
|
-
/** Share a `PythCache` across builders to avoid redundant pyth_state reads. */
|
|
15
|
-
pythCache?: PythCache;
|
|
16
12
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
13
|
+
* Skip oracle refresh entirely (caller manages freshness). Default: false.
|
|
14
|
+
*
|
|
15
|
+
* This is the SHARED-REFRESH composition lever: a caller batching several
|
|
16
|
+
* builders into one PTB refreshes once, up front, then passes the same `tx`
|
|
17
|
+
* to each builder with this flag set —
|
|
18
|
+
*
|
|
19
|
+
* const tx = new Transaction();
|
|
20
|
+
* await refreshOraclePrices(tx, client.perp, allTickers);
|
|
21
|
+
* await buildIncreasePositionTx(client.perp, { ...a, tx, skipOraclePriceRefresh: true });
|
|
22
|
+
* await buildPlaceOrderTx(client.perp, { ...b, tx, skipOraclePriceRefresh: true });
|
|
23
|
+
*
|
|
24
|
+
* — one refresh covering `allTickers` (every builder's market + collateral
|
|
25
|
+
* tickers + the WLP pool tokens) instead of N. This is not just a gas
|
|
26
|
+
* saving: under `waterx_rule` a repeated per-builder refresh would submit
|
|
27
|
+
* the same signed timestamp twice per symbol in one PTB, paying full
|
|
28
|
+
* verification for an on-chain abstain (the F-014 per-symbol replay
|
|
29
|
+
* high-water mark).
|
|
30
|
+
*
|
|
31
|
+
* Sharing one fetched waterx snapshot across CONCURRENT builds is safe on
|
|
32
|
+
* these paths: every builder here feeds through `collect_*`, where a
|
|
33
|
+
* replayed per-symbol timestamp ABSTAINS rather than aborting — the chain
|
|
34
|
+
* already holds a price at least that fresh. `EReplayedSignature` is raised
|
|
35
|
+
* only by the single-rule `feed_*` entries, which no `build*Tx` uses. The
|
|
36
|
+
* cost of sharing is a contribution that does not count, not a failed
|
|
37
|
+
* transaction.
|
|
27
38
|
*/
|
|
28
|
-
|
|
39
|
+
skipOraclePriceRefresh?: boolean;
|
|
29
40
|
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* `
|
|
41
|
+
* Build even when a ticker this action depends on could not be refreshed.
|
|
42
|
+
*
|
|
43
|
+
* `refreshOraclePrices` SKIPS tickers no listed source serves (it is a broad
|
|
44
|
+
* primitive — losing 29 tickers because the 30th is unconfigured is the wrong
|
|
45
|
+
* trade). The composers then fail closed on the subset their specific action
|
|
46
|
+
* actually depends on. This opts out of that check, building against whatever
|
|
47
|
+
* price the chain already holds.
|
|
48
|
+
*
|
|
49
|
+
* Rarely correct. The on-chain guards do NOT cover for it: `mint_wlp` sizes
|
|
50
|
+
* the payout off `pool.tvl_usd`, and `assert_prices_fresh` only compares each
|
|
51
|
+
* token's `last_price_refresh_timestamp` against
|
|
52
|
+
* `price_refresh_threshold_ms` — so a pool asset last refreshed by SOMEONE
|
|
53
|
+
* ELSE minutes ago passes, and the mint is valued off that stale price.
|
|
40
54
|
*/
|
|
41
|
-
|
|
55
|
+
allowUnrefreshedPrices?: boolean;
|
|
42
56
|
/**
|
|
43
57
|
* Pre-sweep parked backing assets (USDC, USDsui, …) at the wxa account's
|
|
44
58
|
* address into USD credit, plus any CREDIT coins/funds at the address into
|
|
@@ -73,36 +87,63 @@ interface RequestParams {
|
|
|
73
87
|
lpType?: string;
|
|
74
88
|
}
|
|
75
89
|
export declare function newTx(opts?: CommonBuildOpts): Transaction;
|
|
90
|
+
/**
|
|
91
|
+
* Fail the build when a ticker THIS action depends on went unrefreshed.
|
|
92
|
+
*
|
|
93
|
+
* The split of responsibility: `refreshOraclePrices` skips (it cannot know
|
|
94
|
+
* which of its tickers were load-bearing), the composer asserts (it does).
|
|
95
|
+
*/
|
|
96
|
+
export declare function assertTickersRefreshed(client: PerpClient, summary: OracleRefreshSummary, required: string[], opts: CommonBuildOpts | undefined,
|
|
97
|
+
/** Appended to the error, to say why THESE tickers were load-bearing. */
|
|
98
|
+
why?: string): void;
|
|
99
|
+
/**
|
|
100
|
+
* Fail the build when ANY WLP pool asset went unpriced — stricter than
|
|
101
|
+
* {@link assertTickersRefreshed}, and deliberately so.
|
|
102
|
+
*
|
|
103
|
+
* `mint_wlp` / `settle_redeem` take `&WlpAum` and size the payout against the
|
|
104
|
+
* pool's WHOLE `tvl_usd`, so a stale price on any pool asset mis-values the
|
|
105
|
+
* trade — not just a stale price on the deposit ticker.
|
|
106
|
+
*
|
|
107
|
+
* Nothing on chain catches the gap. Two paths, neither of which fails:
|
|
108
|
+
* - the asset IS bumped: `update_token_value` calls `oracle::get_price`,
|
|
109
|
+
* which aborts `EStalePrice` unless this PTB aggregated it — loud, safe;
|
|
110
|
+
* - the asset is NOT bumped (it was skipped, so no leg was emitted): its
|
|
111
|
+
* `last_price_refresh_timestamp` keeps whatever a previous transaction
|
|
112
|
+
* left, and `assert_prices_fresh` only asks that it be within
|
|
113
|
+
* `price_refresh_threshold_ms`. A recent-enough stale price PASSES.
|
|
114
|
+
*
|
|
115
|
+
* So the silent case is exactly the skipped one, and the build is the only
|
|
116
|
+
* place it can be caught.
|
|
117
|
+
*/
|
|
118
|
+
export declare function assertWlpPoolRefreshed(client: PerpClient, summary: OracleRefreshSummary, opts: CommonBuildOpts | undefined): void;
|
|
76
119
|
/**
|
|
77
120
|
* Refresh every WLP pool-token oracle (+ caller-supplied extra tickers) and
|
|
78
121
|
* bump each pool token's `last_price_refresh_timestamp` so the pool's
|
|
79
122
|
* `assert_prices_fresh` passes when the next `mint_wlp` / `request_redeem` /
|
|
80
123
|
* trading `execute` runs in the same PTB.
|
|
124
|
+
*
|
|
125
|
+
* Fails closed via {@link assertWlpPoolRefreshed} — see there for why a gap is
|
|
126
|
+
* otherwise silent rather than an on-chain abort.
|
|
81
127
|
*/
|
|
82
|
-
export declare function refreshWlpPoolOracles(tx: Transaction, client: PerpClient, extraTickers: string[],
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
feeSource?: OracleFeeSource;
|
|
128
|
+
export declare function refreshWlpPoolOracles(tx: Transaction, client: PerpClient, extraTickers: string[],
|
|
129
|
+
/** The build's options — `lpType`, plus `allowUnrefreshedPrices` / `updateDataProvider`. */
|
|
130
|
+
opts: CommonBuildOpts & {
|
|
86
131
|
lpType?: string;
|
|
87
|
-
|
|
88
|
-
}): Promise<void>;
|
|
132
|
+
}): Promise<OracleRefreshSummary>;
|
|
89
133
|
/**
|
|
90
|
-
* Build the *Request + execute envelope
|
|
134
|
+
* Build the *Request + execute envelope:
|
|
91
135
|
*
|
|
92
136
|
* [maybeConsolidate(tx)]
|
|
93
|
-
*
|
|
94
|
-
* refreshOraclePrices(..., feeSource?)
|
|
137
|
+
* refreshOraclePrices(...)
|
|
95
138
|
* req = buildRequest()
|
|
96
|
-
* [sponsor.reimburse(fund, req)]
|
|
97
139
|
* trading::execute(req)
|
|
98
140
|
*
|
|
99
141
|
* Accepted ordering caveat: `maybeConsolidate` runs FIRST and can itself
|
|
100
|
-
* append PTB commands (the consolidation sweep) before the
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
* `
|
|
104
|
-
*
|
|
105
|
-
* discard-tx-on-throw contract every `build*Tx` composer already has for
|
|
142
|
+
* append PTB commands (the consolidation sweep) before the refresh's own
|
|
143
|
+
* pre-checks run — so a throw out of `refreshOraclePrices` here is NOT the
|
|
144
|
+
* "zero commands appended" guarantee it gives its own callers (see its
|
|
145
|
+
* docblock in `aggregate.ts`); `tx` can already carry the sweep. This is the
|
|
146
|
+
* same discard-tx-on-throw contract every `build*Tx` composer already has for
|
|
106
147
|
* mid-build on-chain-read failures — not a new hole. It matters only for a
|
|
107
148
|
* caller that passed in their OWN `opts.tx` (reusing one `Transaction`
|
|
108
149
|
* across builder calls, e.g. to compose several actions in one PTB); such a
|
|
@@ -111,10 +152,7 @@ export declare function refreshWlpPoolOracles(tx: Transaction, client: PerpClien
|
|
|
111
152
|
*/
|
|
112
153
|
export declare function wrapRequestAndExecute(client: PerpClient, tx: Transaction, req: RequestParams & {
|
|
113
154
|
accountId: string;
|
|
114
|
-
}, collateralTicker: string, opts: CommonBuildOpts | undefined, buildRequest: (
|
|
115
|
-
fund: TransactionArgument;
|
|
116
|
-
packageId: string;
|
|
117
|
-
}) => TransactionArgument): Promise<void>;
|
|
155
|
+
}, collateralTicker: string, opts: CommonBuildOpts | undefined, buildRequest: () => TransactionArgument): Promise<void>;
|
|
118
156
|
/** Run the async sweep iff `consolidateToUsd !== false`. */
|
|
119
157
|
export declare function maybeConsolidate(client: PerpClient, tx: Transaction, accountId: string, opts: CommonBuildOpts | undefined): Promise<void>;
|
|
120
158
|
export {};
|
|
@@ -1,52 +1,141 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared scaffolding for the high-level perp `build*Tx` composers:
|
|
3
3
|
* `CommonBuildOpts`, the new-or-reuse PTB helper, the WLP pool-oracle refresh,
|
|
4
|
-
* and the request+execute envelope (optional
|
|
4
|
+
* and the request+execute envelope (optional pre-sweep).
|
|
5
5
|
*/
|
|
6
6
|
import { Transaction } from "@mysten/sui/transactions";
|
|
7
7
|
import { appendConsolidateForSpend } from "../../account/funding/consolidate.js";
|
|
8
|
-
import {
|
|
9
|
-
import { getCollateralAssets } from "../../utils/config.js";
|
|
8
|
+
import { OracleTickerUnservedError, partitionServableTickers, refreshOraclePrices, } from "../../oracle/index.js";
|
|
10
9
|
import { executeTrading } from "../user/trading.js";
|
|
11
10
|
import { updateTokenValue } from "../user/wlp.js";
|
|
12
11
|
export function newTx(opts) {
|
|
13
12
|
return opts?.tx ?? new Transaction();
|
|
14
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Fail the build when a ticker THIS action depends on went unrefreshed.
|
|
16
|
+
*
|
|
17
|
+
* The split of responsibility: `refreshOraclePrices` skips (it cannot know
|
|
18
|
+
* which of its tickers were load-bearing), the composer asserts (it does).
|
|
19
|
+
*/
|
|
20
|
+
export function assertTickersRefreshed(client, summary, required, opts,
|
|
21
|
+
/** Appended to the error, to say why THESE tickers were load-bearing. */
|
|
22
|
+
why) {
|
|
23
|
+
if (opts?.allowUnrefreshedPrices)
|
|
24
|
+
return;
|
|
25
|
+
const skipped = new Set(summary.skipped);
|
|
26
|
+
const unserved = [...new Set(required)].filter((ticker) => skipped.has(ticker));
|
|
27
|
+
if (unserved.length > 0) {
|
|
28
|
+
throw new OracleTickerUnservedError(unserved, client.oracleSources, why);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Fail the build when ANY WLP pool asset went unpriced — stricter than
|
|
33
|
+
* {@link assertTickersRefreshed}, and deliberately so.
|
|
34
|
+
*
|
|
35
|
+
* `mint_wlp` / `settle_redeem` take `&WlpAum` and size the payout against the
|
|
36
|
+
* pool's WHOLE `tvl_usd`, so a stale price on any pool asset mis-values the
|
|
37
|
+
* trade — not just a stale price on the deposit ticker.
|
|
38
|
+
*
|
|
39
|
+
* Nothing on chain catches the gap. Two paths, neither of which fails:
|
|
40
|
+
* - the asset IS bumped: `update_token_value` calls `oracle::get_price`,
|
|
41
|
+
* which aborts `EStalePrice` unless this PTB aggregated it — loud, safe;
|
|
42
|
+
* - the asset is NOT bumped (it was skipped, so no leg was emitted): its
|
|
43
|
+
* `last_price_refresh_timestamp` keeps whatever a previous transaction
|
|
44
|
+
* left, and `assert_prices_fresh` only asks that it be within
|
|
45
|
+
* `price_refresh_threshold_ms`. A recent-enough stale price PASSES.
|
|
46
|
+
*
|
|
47
|
+
* So the silent case is exactly the skipped one, and the build is the only
|
|
48
|
+
* place it can be caught.
|
|
49
|
+
*/
|
|
50
|
+
export function assertWlpPoolRefreshed(client, summary, opts) {
|
|
51
|
+
// Every pool asset is required — that IS the WLP-specific part. The general
|
|
52
|
+
// assert does the rest; there is no second class of fault to detect, because
|
|
53
|
+
// `refreshWlpPoolOracles` requests the whole pool, so anything this client
|
|
54
|
+
// cannot price is necessarily in `summary.skipped` already.
|
|
55
|
+
assertTickersRefreshed(client, summary, Object.keys(client.config.packages.wlp?.pool_tokens ?? {}), opts, "They are WLP pool assets, and mint/redeem values the WHOLE pool. ");
|
|
56
|
+
}
|
|
15
57
|
/**
|
|
16
58
|
* Refresh every WLP pool-token oracle (+ caller-supplied extra tickers) and
|
|
17
59
|
* bump each pool token's `last_price_refresh_timestamp` so the pool's
|
|
18
60
|
* `assert_prices_fresh` passes when the next `mint_wlp` / `request_redeem` /
|
|
19
61
|
* trading `execute` runs in the same PTB.
|
|
62
|
+
*
|
|
63
|
+
* Fails closed via {@link assertWlpPoolRefreshed} — see there for why a gap is
|
|
64
|
+
* otherwise silent rather than an on-chain abort.
|
|
20
65
|
*/
|
|
21
|
-
export async function refreshWlpPoolOracles(tx, client, extraTickers,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
66
|
+
export async function refreshWlpPoolOracles(tx, client, extraTickers,
|
|
67
|
+
/** The build's options — `lpType`, plus `allowUnrefreshedPrices` / `updateDataProvider`. */
|
|
68
|
+
opts) {
|
|
69
|
+
// EVERY pool asset is requested, not a pre-filtered subset. Filtering here
|
|
70
|
+
// was the bug: a token the fed set cannot price was dropped from BOTH the
|
|
71
|
+
// refresh and the bump, so nothing on chain objected (see
|
|
72
|
+
// `assertWlpPoolRefreshed` for why `assert_prices_fresh` lets that through)
|
|
73
|
+
// and the mint was valued off a stale price. Ask for all of them, fail the
|
|
74
|
+
// build on any gap, then bump.
|
|
75
|
+
const poolTokens = client.config.packages.wlp?.pool_tokens ?? {};
|
|
76
|
+
// `refreshOraclePrices` dedupes its own input, so a plain concat is enough.
|
|
77
|
+
const oracleTickers = [...extraTickers, ...Object.keys(poolTokens)];
|
|
78
|
+
// Fail closed BEFORE the fetch, on EVERYTHING this build depends on.
|
|
79
|
+
//
|
|
80
|
+
// `refreshOraclePrices` no longer throws on an unservable ticker (it skips
|
|
81
|
+
// and reports), so nothing is gained by waiting for it — and waiting costs
|
|
82
|
+
// the full off-chain fetch plus every collector/aggregate moveCall appended
|
|
83
|
+
// to a caller-supplied `tx`, all discarded on the throw. The predicate is
|
|
84
|
+
// pure config, so the pre-flight answer is identical to the summary's, free.
|
|
85
|
+
//
|
|
86
|
+
// Two required sets, each with its own explanation: `extraTickers` are the
|
|
87
|
+
// caller's action-critical ones (the traded market + its collateral, or a
|
|
88
|
+
// WLP deposit ticker), and the pool is required wholesale because mint and
|
|
89
|
+
// redeem value the WHOLE pool.
|
|
90
|
+
const planned = plannedSummary(client, oracleTickers);
|
|
91
|
+
assertTickersRefreshed(client, planned, extraTickers, opts);
|
|
92
|
+
assertWlpPoolRefreshed(client, planned, opts);
|
|
93
|
+
const summary = await refreshOraclePrices(tx, client, oracleTickers, {
|
|
27
94
|
updateDataProvider: opts.updateDataProvider,
|
|
28
95
|
});
|
|
29
|
-
|
|
96
|
+
// Bump only what was actually AGGREGATED, not every pool entry.
|
|
97
|
+
//
|
|
98
|
+
// `update_token_value` calls `oracle::get_price`, which aborts `EStalePrice`
|
|
99
|
+
// unless this PTB aggregated that ticker. Normally the asserts above
|
|
100
|
+
// guarantee it — but `allowUnrefreshedPrices` skips them by design, and
|
|
101
|
+
// bumping a skipped asset then produced a transaction guaranteed to abort,
|
|
102
|
+
// which made the escape hatch unusable on exactly the deployments that need
|
|
103
|
+
// it. Driving the loop off the summary makes the opt-out mean what it says:
|
|
104
|
+
// build with whatever prices the chain already holds, and touch nothing else.
|
|
105
|
+
const aggregated = new Set(summary.refreshed);
|
|
106
|
+
for (const [ticker, tokenType] of Object.entries(poolTokens)) {
|
|
107
|
+
if (!aggregated.has(ticker))
|
|
108
|
+
continue;
|
|
30
109
|
updateTokenValue(client, tx, { tokenType, lpType: opts.lpType });
|
|
31
110
|
}
|
|
111
|
+
return summary;
|
|
32
112
|
}
|
|
33
113
|
/**
|
|
34
|
-
*
|
|
114
|
+
* What {@link refreshOraclePrices} WOULD report for `tickers`, computed from
|
|
115
|
+
* config alone.
|
|
116
|
+
*
|
|
117
|
+
* Same predicate, same partition — so a pre-flight assert cannot disagree with
|
|
118
|
+
* the summary the refresh later returns, and a build destined to fail can fail
|
|
119
|
+
* before spending a network round trip or mutating the caller's transaction.
|
|
120
|
+
*/
|
|
121
|
+
function plannedSummary(client, tickers) {
|
|
122
|
+
const { servable, unservable } = partitionServableTickers(client, tickers);
|
|
123
|
+
return { refreshed: servable, skipped: unservable };
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Build the *Request + execute envelope:
|
|
35
127
|
*
|
|
36
128
|
* [maybeConsolidate(tx)]
|
|
37
|
-
*
|
|
38
|
-
* refreshOraclePrices(..., feeSource?)
|
|
129
|
+
* refreshOraclePrices(...)
|
|
39
130
|
* req = buildRequest()
|
|
40
|
-
* [sponsor.reimburse(fund, req)]
|
|
41
131
|
* trading::execute(req)
|
|
42
132
|
*
|
|
43
133
|
* Accepted ordering caveat: `maybeConsolidate` runs FIRST and can itself
|
|
44
|
-
* append PTB commands (the consolidation sweep) before the
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* `
|
|
48
|
-
*
|
|
49
|
-
* discard-tx-on-throw contract every `build*Tx` composer already has for
|
|
134
|
+
* append PTB commands (the consolidation sweep) before the refresh's own
|
|
135
|
+
* pre-checks run — so a throw out of `refreshOraclePrices` here is NOT the
|
|
136
|
+
* "zero commands appended" guarantee it gives its own callers (see its
|
|
137
|
+
* docblock in `aggregate.ts`); `tx` can already carry the sweep. This is the
|
|
138
|
+
* same discard-tx-on-throw contract every `build*Tx` composer already has for
|
|
50
139
|
* mid-build on-chain-read failures — not a new hole. It matters only for a
|
|
51
140
|
* caller that passed in their OWN `opts.tx` (reusing one `Transaction`
|
|
52
141
|
* across builder calls, e.g. to compose several actions in one PTB); such a
|
|
@@ -55,39 +144,16 @@ export async function refreshWlpPoolOracles(tx, client, extraTickers, opts) {
|
|
|
55
144
|
*/
|
|
56
145
|
export async function wrapRequestAndExecute(client, tx, req, collateralTicker, opts, buildRequest) {
|
|
57
146
|
await maybeConsolidate(client, tx, req.accountId, opts);
|
|
58
|
-
// Fee source + witness attachment is config-driven, not a caller flag: the
|
|
59
|
-
// sponsor fund is opened (and later reimbursed) whenever this client's
|
|
60
|
-
// config has `pyth_sponsor_rule` deployed — regardless of the deprecated
|
|
61
|
-
// `useSponsor` flag (see its JSDoc). `allowGasFee` is the only caller lever
|
|
62
|
-
// left, and it only matters when config has NO sponsor rule to open (see
|
|
63
|
-
// `OracleFeeSourceUnavailable` in `oracle/pyth.ts`).
|
|
64
|
-
//
|
|
65
|
-
// `feeSource` is resolved HERE, once, from that same decision — sponsor
|
|
66
|
-
// beats gas structurally because this is the only branch that ever sees
|
|
67
|
-
// both candidates; everything downstream (`refreshWlpPoolOracles` →
|
|
68
|
-
// `refreshOraclePrices` → `BuildUpdateOpts` → `PythCoreRule` →
|
|
69
|
-
// `buildPythPriceUpdateCalls`) just carries the single resolved value.
|
|
70
|
-
let sponsorFund;
|
|
71
|
-
if (client.config.packages.pyth_sponsor_rule) {
|
|
72
|
-
sponsorFund = openPythSponsorFund(tx, client);
|
|
73
|
-
}
|
|
74
|
-
const feeSource = sponsorFund
|
|
75
|
-
? { kind: "sponsor", ...sponsorFund }
|
|
76
|
-
: opts?.allowGasFee
|
|
77
|
-
? { kind: "gas" }
|
|
78
|
-
: undefined;
|
|
79
147
|
if (!opts?.skipOraclePriceRefresh) {
|
|
148
|
+
// The action-critical pair for a trade — the market being traded and the
|
|
149
|
+
// collateral it is margined in — is passed as the extras, which
|
|
150
|
+
// `refreshWlpPoolOracles` fails closed on before it fetches anything.
|
|
80
151
|
await refreshWlpPoolOracles(tx, client, [req.ticker, collateralTicker], {
|
|
81
|
-
|
|
82
|
-
feeSource,
|
|
152
|
+
...opts,
|
|
83
153
|
lpType: req.lpType,
|
|
84
|
-
updateDataProvider: opts?.updateDataProvider,
|
|
85
154
|
});
|
|
86
155
|
}
|
|
87
|
-
const tradingReq = buildRequest(
|
|
88
|
-
if (sponsorFund) {
|
|
89
|
-
reimbursePythSponsor(tx, client, sponsorFund.fund, tradingReq, req.collateralType);
|
|
90
|
-
}
|
|
156
|
+
const tradingReq = buildRequest();
|
|
91
157
|
executeTrading(client, tx, {
|
|
92
158
|
ticker: req.ticker,
|
|
93
159
|
collateralType: req.collateralType,
|