@ember-finance/sdk 2.18.0 → 2.20.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.
@@ -0,0 +1,13 @@
1
+ import { VaultsApi } from "../api/v2/index.js";
2
+ /**
3
+ * The generated vaults client, on the fetch adapter so this module keeps one
4
+ * transport in the browser and in Node.
5
+ */
6
+ export declare function vaultsApi(baseUrl: string): VaultsApi;
7
+ /** Status and Retry-After of a failed call, or undefined when no response came back. */
8
+ export declare function httpFailure(error: unknown): {
9
+ status: number;
10
+ retryAfter?: string;
11
+ } | undefined;
12
+ /** True for a transport failure (no response), which is worth retrying. */
13
+ export declare function isNetworkError(error: unknown): boolean;
@@ -0,0 +1,26 @@
1
+ import axios from "axios";
2
+ import { Configuration, VaultsApi } from "../api/v2/index.js";
3
+ /**
4
+ * The generated vaults client, on the fetch adapter so this module keeps one
5
+ * transport in the browser and in Node.
6
+ */
7
+ export function vaultsApi(baseUrl) {
8
+ return new VaultsApi(new Configuration({
9
+ basePath: baseUrl.replace(/\/$/, ""),
10
+ baseOptions: { adapter: "fetch" }
11
+ }));
12
+ }
13
+ /** Status and Retry-After of a failed call, or undefined when no response came back. */
14
+ export function httpFailure(error) {
15
+ if (!axios.isAxiosError(error) || !error.response)
16
+ return undefined;
17
+ const retryAfter = error.response.headers?.["retry-after"];
18
+ return {
19
+ status: error.response.status,
20
+ retryAfter: typeof retryAfter === "string" ? retryAfter : undefined
21
+ };
22
+ }
23
+ /** True for a transport failure (no response), which is worth retrying. */
24
+ export function isNetworkError(error) {
25
+ return axios.isAxiosError(error) && !error.response && !axios.isCancel(error);
26
+ }
@@ -10,7 +10,6 @@ export interface HttpPointerSourceOptions {
10
10
  env?: PlatformEnv;
11
11
  /** Overrides `env` entirely. For a local deployment, or a proxy. */
12
12
  baseUrl?: string;
13
- path?: string;
14
13
  /** How long a coin's rows may be reused, in milliseconds. Default 30s. */
15
14
  cacheMs?: number;
16
15
  }
@@ -1,5 +1,6 @@
1
1
  import { environmentConfig } from "../common/constants.js";
2
- import { isAbortError, isTransientStatus, retryAfterMs } from "./batch.js";
2
+ import { httpFailure, isNetworkError, vaultsApi } from "./api.js";
3
+ import { isTransientStatus, retryAfterMs } from "./batch.js";
3
4
  import { coinTypesMatch, normalizeCoinType } from "./sui.js";
4
5
  /**
5
6
  * Pointers held in memory. Useful for tests, and for pinning a known venue set
@@ -33,7 +34,7 @@ export function httpPointerSource(options = {}) {
33
34
  // makes, not to cache across a session: pointers change when a venue is
34
35
  // added, and a long window would keep a new one invisible.
35
36
  const baseUrl = options.baseUrl ?? environmentConfig[options.env ?? "prod"].apiHost;
36
- const path = options.path ?? "/api/v2/vaults/placements";
37
+ const api = vaultsApi(baseUrl);
37
38
  const cacheMs = options.cacheMs ?? 30000;
38
39
  /**
39
40
  * One request for every coin. The endpoint answers with the whole registry
@@ -59,12 +60,7 @@ export function httpPointerSource(options = {}) {
59
60
  inFlight.set(key, { at: Date.now(), rows });
60
61
  return rows;
61
62
  };
62
- const request = (coin) => {
63
- const url = new URL(`${baseUrl.replace(/\/$/, "")}${path}`);
64
- if (coin !== undefined)
65
- url.searchParams.set("coin", coin);
66
- return fetchPlacements(url.toString());
67
- };
63
+ const request = (coin) => fetchPlacements(api, coin);
68
64
  const rowsFor = async (coin) => {
69
65
  if (Date.now() >= perCoinUntil) {
70
66
  try {
@@ -139,34 +135,31 @@ const FALLBACK_RECHECK_MS = 5 * 60000;
139
135
  * Retries transient failures. Every vault's venues now ride on this one
140
136
  * request, and callers keep a failed discover rather than retrying it.
141
137
  */
142
- async function fetchPlacements(url) {
138
+ async function fetchPlacements(api, coin) {
143
139
  for (let attempt = 1;; attempt++) {
144
140
  let waitMs;
145
141
  try {
146
- const response = await fetch(url, {
147
- headers: { Accept: "application/json" }
148
- });
149
- if (response.ok) {
150
- const body = (await response.json());
151
- return body.placements ?? [];
152
- }
153
- if (!isTransientStatus(response.status) || attempt >= FETCH_ATTEMPTS) {
154
- throw new PointerSourceError(response.status);
155
- }
156
- waitMs = retryAfterMs(response.headers?.get("retry-after"));
157
- // Retrying before the server asked would only add to the load it
158
- // is shedding and fail again.
159
- if (waitMs !== undefined && waitMs > RETRY_MAX_MS) {
160
- throw new PointerSourceError(response.status);
161
- }
142
+ const { data } = await api.getCoinPlacements(coin);
143
+ return data.placements ?? [];
162
144
  }
163
145
  catch (error) {
164
- // fetch rejects only on network failure; retry that, not our own
165
- // errors or an abort.
166
- if (error instanceof PointerSourceError ||
167
- isAbortError(error) ||
168
- attempt >= FETCH_ATTEMPTS) {
169
- throw error;
146
+ const failure = httpFailure(error);
147
+ if (!failure) {
148
+ // Only a transport failure is worth retrying, not an abort or a
149
+ // bug of our own.
150
+ if (!isNetworkError(error) || attempt >= FETCH_ATTEMPTS)
151
+ throw error;
152
+ }
153
+ else {
154
+ if (!isTransientStatus(failure.status) || attempt >= FETCH_ATTEMPTS) {
155
+ throw new PointerSourceError(failure.status);
156
+ }
157
+ waitMs = retryAfterMs(failure.retryAfter);
158
+ // Retrying before the server asked would only add to the load it
159
+ // is shedding and fail again.
160
+ if (waitMs !== undefined && waitMs > RETRY_MAX_MS) {
161
+ throw new PointerSourceError(failure.status);
162
+ }
170
163
  }
171
164
  }
172
165
  const backoff = Math.min(RETRY_BASE_MS * 2 ** (attempt - 1), RETRY_MAX_MS);
@@ -1,4 +1,5 @@
1
1
  import { environmentConfig } from "../common/constants.js";
2
+ import { httpFailure, vaultsApi } from "./api.js";
2
3
  /**
3
4
  * Resolves a vault to the receipt coins it issues, from the vaults API.
4
5
  *
@@ -6,14 +7,17 @@ import { environmentConfig } from "../common/constants.js";
6
7
  * each, so this returns one entry per chain rather than assuming a single coin.
7
8
  */
8
9
  export function httpVaultCoinsResolver(options = {}) {
9
- const baseUrl = (options.baseUrl ?? environmentConfig[options.env ?? "prod"].apiHost).replace(/\/$/, "");
10
- const get = async (path) => {
11
- const response = await fetch(`${baseUrl}${path}`, {
12
- headers: { Accept: "application/json" }
13
- });
14
- if (!response.ok)
15
- throw new Error(`vaults api ${response.status} for ${path}`);
16
- return (await response.json());
10
+ const api = vaultsApi(options.baseUrl ?? environmentConfig[options.env ?? "prod"].apiHost);
11
+ const get = async (path, call) => {
12
+ try {
13
+ return (await call()).data;
14
+ }
15
+ catch (error) {
16
+ const failure = httpFailure(error);
17
+ if (failure)
18
+ throw new Error(`vaults api ${failure.status} for ${path}`);
19
+ throw error;
20
+ }
17
21
  };
18
22
  // The chain catalogue is what carries the EVM network id. Without it an EVM
19
23
  // coin has no chainId, and every read for it fails rather than returning a
@@ -22,7 +26,7 @@ export function httpVaultCoinsResolver(options = {}) {
22
26
  const chainRefs = () => {
23
27
  if (chains)
24
28
  return chains;
25
- chains = get("/api/v2/vaults/supported-chains").then(supported => {
29
+ chains = get("/api/v2/vaults/supported-chains", () => api.getSupportedChains()).then(supported => {
26
30
  const byIdentifier = new Map();
27
31
  for (const chain of supported) {
28
32
  if (!chain.identifier)
@@ -51,10 +55,10 @@ export function httpVaultCoinsResolver(options = {}) {
51
55
  return {
52
56
  async coinsForVault(vaultId) {
53
57
  const [vaults, catalogue] = await Promise.all([
54
- get(`/api/v2/vaults?vaultId=${encodeURIComponent(vaultId)}`),
58
+ get(`/api/v2/vaults?vaultId=${vaultId}`, () => api.getVaults(vaultId)),
55
59
  chainRefs()
56
60
  ]);
57
- const list = Array.isArray(vaults) ? vaults : [vaults];
61
+ const list = vaults;
58
62
  const vault = list.find(v => v.id === vaultId) ?? list[0];
59
63
  if (!vault)
60
64
  throw new Error(`vault ${vaultId} not found`);
@@ -70,6 +70,20 @@ export interface IVaultOptionalParams extends ITxBuilderOptionalParams {
70
70
  dryRun?: boolean;
71
71
  returnTxb?: boolean;
72
72
  }
73
+ /**
74
+ * Operations that can be paused individually on a vault.
75
+ *
76
+ * The values are the exact `vector<u8>` the Move entry points compare against
77
+ * (`OP_DEPOSITS` and friends in `vault.move`), shared by the regular and atomic
78
+ * vault flavours. Note `privileged_operations` is snake_case here and
79
+ * `privilegedOperations` in EVM's `VaultPauseOperation` — consumers serving both
80
+ * chains have to map, which is why this enum exists rather than a bare string.
81
+ */
82
+ export declare enum SuiVaultPauseOperation {
83
+ Deposits = "deposits",
84
+ Withdrawals = "withdrawals",
85
+ PrivilegedOperations = "privileged_operations"
86
+ }
73
87
  /** `version` and the protocol-wide pause flag from the shared ProtocolConfig. */
74
88
  export interface IProtocolConfigState {
75
89
  /** The package VERSION the protocol currently accepts, as a decimal string. */
@@ -1 +1,15 @@
1
- export {};
1
+ /**
2
+ * Operations that can be paused individually on a vault.
3
+ *
4
+ * The values are the exact `vector<u8>` the Move entry points compare against
5
+ * (`OP_DEPOSITS` and friends in `vault.move`), shared by the regular and atomic
6
+ * vault flavours. Note `privileged_operations` is snake_case here and
7
+ * `privilegedOperations` in EVM's `VaultPauseOperation` — consumers serving both
8
+ * chains have to map, which is why this enum exists rather than a bare string.
9
+ */
10
+ export var SuiVaultPauseOperation;
11
+ (function (SuiVaultPauseOperation) {
12
+ SuiVaultPauseOperation["Deposits"] = "deposits";
13
+ SuiVaultPauseOperation["Withdrawals"] = "withdrawals";
14
+ SuiVaultPauseOperation["PrivilegedOperations"] = "privileged_operations";
15
+ })(SuiVaultPauseOperation || (SuiVaultPauseOperation = {}));
@@ -1,5 +1,5 @@
1
1
  import { SuiDeploymentParser } from "../utils/index.js";
2
- import { ISuiDeployment, ITxBuilderOptionalParams } from "../interfaces/index.js";
2
+ import { ISuiDeployment, ITxBuilderOptionalParams, SuiVaultPauseOperation } from "../interfaces/index.js";
3
3
  import { Address, NumStr, TransactionBlock } from "@firefly-exchange/library-sui";
4
4
  export declare class TxBuilder {
5
5
  parser: SuiDeploymentParser;
@@ -45,6 +45,32 @@ export declare class TxBuilder {
45
45
  * @returns TransactionBlock
46
46
  */
47
47
  setGuardian(newGuardian: Address, options?: ITxBuilderOptionalParams): TransactionBlock;
48
+ /**
49
+ * Guardian fast-path to pause / unpause one operation on a regular vault.
50
+ * Callable directly by the guardian address — no AdminCap.
51
+ *
52
+ * Per-operation, unlike the AdminCap-gated {@link updateVaultPausedStatus},
53
+ * which flips the vault's single legacy `paused` flag. On chain the effective
54
+ * answer is `vault.paused || <this operation's flag>`, so clearing an
55
+ * operation here does not un-pause a vault the admin stopped wholesale.
56
+ * @param vaultId Id of the vault
57
+ * @param operation Operation to pause or resume
58
+ * @param paused True to pause, false to resume
59
+ * @param options Optional tx building params; `packageId` routes through a retired package
60
+ * @returns TransactionBlock
61
+ */
62
+ guardianSetVaultPausedStatus(vaultId: string, operation: SuiVaultPauseOperation, paused: boolean, options?: ITxBuilderOptionalParams): TransactionBlock;
63
+ /**
64
+ * Guardian fast-path to pause / unpause one operation on an atomic liquidity
65
+ * vault. Same vocabulary as the regular-vault variant; separate entry point
66
+ * because the vault type differs and takes only the collateral type.
67
+ * @param vaultId Id of the atomic vault
68
+ * @param operation Operation to pause or resume
69
+ * @param paused True to pause, false to resume
70
+ * @param options Optional tx building params; `packageId` routes through a retired package
71
+ * @returns TransactionBlock
72
+ */
73
+ atomicGuardianSetPauseStatus(vaultId: string, operation: SuiVaultPauseOperation, paused: boolean, options?: ITxBuilderOptionalParams): TransactionBlock;
48
74
  /**
49
75
  * Asserts `ProtocolConfig.version` equals the VERSION compiled into the target
50
76
  * package, aborting EUnsupportedPackage (1000) otherwise.
@@ -94,6 +94,69 @@ export class TxBuilder {
94
94
  txb.setSenderIfNotSet(options.sender);
95
95
  return txb;
96
96
  }
97
+ /**
98
+ * Guardian fast-path to pause / unpause one operation on a regular vault.
99
+ * Callable directly by the guardian address — no AdminCap.
100
+ *
101
+ * Per-operation, unlike the AdminCap-gated {@link updateVaultPausedStatus},
102
+ * which flips the vault's single legacy `paused` flag. On chain the effective
103
+ * answer is `vault.paused || <this operation's flag>`, so clearing an
104
+ * operation here does not un-pause a vault the admin stopped wholesale.
105
+ * @param vaultId Id of the vault
106
+ * @param operation Operation to pause or resume
107
+ * @param paused True to pause, false to resume
108
+ * @param options Optional tx building params; `packageId` routes through a retired package
109
+ * @returns TransactionBlock
110
+ */
111
+ guardianSetVaultPausedStatus(vaultId, operation, paused, options) {
112
+ const txb = options?.txBlock || new TransactionBlock();
113
+ txb.moveCall({
114
+ arguments: [
115
+ txb.object(vaultId),
116
+ txb.object(this.parser.getProtocolConfig()),
117
+ txb.pure.vector("u8", Array.from(Buffer.from(operation, "utf8"))),
118
+ txb.pure.bool(paused)
119
+ ],
120
+ typeArguments: [
121
+ this.parser.getDepositCoinType(vaultId),
122
+ this.parser.getReceiptCoinType(vaultId)
123
+ ],
124
+ target: `${this.targetPackageId(options)}::gateway::guardian_set_vault_paused_status`
125
+ });
126
+ if (options?.gasBudget)
127
+ txb.setGasBudget(options.gasBudget);
128
+ if (options?.sender)
129
+ txb.setSenderIfNotSet(options.sender);
130
+ return txb;
131
+ }
132
+ /**
133
+ * Guardian fast-path to pause / unpause one operation on an atomic liquidity
134
+ * vault. Same vocabulary as the regular-vault variant; separate entry point
135
+ * because the vault type differs and takes only the collateral type.
136
+ * @param vaultId Id of the atomic vault
137
+ * @param operation Operation to pause or resume
138
+ * @param paused True to pause, false to resume
139
+ * @param options Optional tx building params; `packageId` routes through a retired package
140
+ * @returns TransactionBlock
141
+ */
142
+ atomicGuardianSetPauseStatus(vaultId, operation, paused, options) {
143
+ const txb = options?.txBlock || new TransactionBlock();
144
+ txb.moveCall({
145
+ arguments: [
146
+ txb.object(vaultId),
147
+ txb.object(this.parser.getProtocolConfig()),
148
+ txb.pure.vector("u8", Array.from(Buffer.from(operation, "utf8"))),
149
+ txb.pure.bool(paused)
150
+ ],
151
+ typeArguments: [this.parser.getAtomicCollateralType(vaultId)],
152
+ target: `${this.targetPackageId(options)}::gateway::atomic_guardian_set_pause_status`
153
+ });
154
+ if (options?.gasBudget)
155
+ txb.setGasBudget(options.gasBudget);
156
+ if (options?.sender)
157
+ txb.setSenderIfNotSet(options.sender);
158
+ return txb;
159
+ }
97
160
  /**
98
161
  * Asserts `ProtocolConfig.version` equals the VERSION compiled into the target
99
162
  * package, aborting EUnsupportedPackage (1000) otherwise.
@@ -1,6 +1,6 @@
1
1
  import { BaseClient as SuiClient } from "@mysten/sui/client";
2
2
  import { OnChainCalls } from "./onchain-calls.js";
3
- import { ISuiDeployment, IVaultOptionalParams } from "../interfaces/index.js";
3
+ import { ISuiDeployment, IVaultOptionalParams, SuiVaultPauseOperation } from "../interfaces/index.js";
4
4
  import { NumStr } from "@firefly-exchange/library-sui";
5
5
  import { OnChainCallResponse, Signer, SuiAddress, SuiTransactionBlockResponseOptions } from "@firefly-exchange/library-sui";
6
6
  export declare class VaultAdminCalls extends OnChainCalls {
@@ -46,6 +46,34 @@ export declare class VaultAdminCalls extends OnChainCalls {
46
46
  * @returns OnChainCallResponse
47
47
  */
48
48
  updateVaultPausedStatus(vaultId: string, paused: boolean, options?: IVaultOptionalParams & SuiTransactionBlockResponseOptions): Promise<OnChainCallResponse>;
49
+ /**
50
+ * Guardian fast-path to pause / unpause one operation on a regular vault.
51
+ * Needs no AdminCap — the signer must be the address `set_guardian` recorded.
52
+ *
53
+ * Per-operation, unlike {@link updateVaultPausedStatus}, which flips the
54
+ * vault's single legacy `paused` flag. The chain reads
55
+ * `vault.paused || <operation flag>`, so resuming an operation here does not
56
+ * revive a vault the admin paused wholesale.
57
+ *
58
+ * Version-gated like every guarded call: pass `options.packageId` to route
59
+ * through a retired package while an upgrade is half-applied.
60
+ * @param vaultId The id of the vault
61
+ * @param operation The operation to pause or resume
62
+ * @param paused True to pause, false to resume
63
+ * @param options Optional tx execution params
64
+ * @returns OnChainCallResponse
65
+ */
66
+ guardianSetVaultPausedStatus(vaultId: string, operation: SuiVaultPauseOperation, paused: boolean, options?: IVaultOptionalParams & SuiTransactionBlockResponseOptions): Promise<OnChainCallResponse>;
67
+ /**
68
+ * Guardian fast-path to pause / unpause one operation on an atomic liquidity
69
+ * vault. Same vocabulary as the regular-vault variant.
70
+ * @param vaultId The id of the atomic vault
71
+ * @param operation The operation to pause or resume
72
+ * @param paused True to pause, false to resume
73
+ * @param options Optional tx execution params
74
+ * @returns OnChainCallResponse
75
+ */
76
+ atomicGuardianSetPauseStatus(vaultId: string, operation: SuiVaultPauseOperation, paused: boolean, options?: IVaultOptionalParams & SuiTransactionBlockResponseOptions): Promise<OnChainCallResponse>;
49
77
  /**
50
78
  * Update vault rate update interval
51
79
  * @param vaultId The id of the vault to update the rate update interval for
@@ -80,6 +80,48 @@ export class VaultAdminCalls extends OnChainCalls {
80
80
  });
81
81
  return this.execCall(txb, options);
82
82
  }
83
+ /**
84
+ * Guardian fast-path to pause / unpause one operation on a regular vault.
85
+ * Needs no AdminCap — the signer must be the address `set_guardian` recorded.
86
+ *
87
+ * Per-operation, unlike {@link updateVaultPausedStatus}, which flips the
88
+ * vault's single legacy `paused` flag. The chain reads
89
+ * `vault.paused || <operation flag>`, so resuming an operation here does not
90
+ * revive a vault the admin paused wholesale.
91
+ *
92
+ * Version-gated like every guarded call: pass `options.packageId` to route
93
+ * through a retired package while an upgrade is half-applied.
94
+ * @param vaultId The id of the vault
95
+ * @param operation The operation to pause or resume
96
+ * @param paused True to pause, false to resume
97
+ * @param options Optional tx execution params
98
+ * @returns OnChainCallResponse
99
+ */
100
+ async guardianSetVaultPausedStatus(vaultId, operation, paused, options) {
101
+ const txb = options?.txBlock || new TransactionBlock();
102
+ this.txBuilder.guardianSetVaultPausedStatus(vaultId, operation, paused, {
103
+ ...options,
104
+ txBlock: txb
105
+ });
106
+ return this.execCall(txb, options);
107
+ }
108
+ /**
109
+ * Guardian fast-path to pause / unpause one operation on an atomic liquidity
110
+ * vault. Same vocabulary as the regular-vault variant.
111
+ * @param vaultId The id of the atomic vault
112
+ * @param operation The operation to pause or resume
113
+ * @param paused True to pause, false to resume
114
+ * @param options Optional tx execution params
115
+ * @returns OnChainCallResponse
116
+ */
117
+ async atomicGuardianSetPauseStatus(vaultId, operation, paused, options) {
118
+ const txb = options?.txBlock || new TransactionBlock();
119
+ this.txBuilder.atomicGuardianSetPauseStatus(vaultId, operation, paused, {
120
+ ...options,
121
+ txBlock: txb
122
+ });
123
+ return this.execCall(txb, options);
124
+ }
83
125
  /**
84
126
  * Update vault rate update interval
85
127
  * @param vaultId The id of the vault to update the rate update interval for
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ember-finance/sdk",
3
3
  "description": "Ember Protocol SDK",
4
- "version": "2.18.0",
4
+ "version": "2.20.0",
5
5
  "type": "module",
6
6
  "module": "./dist/index.js",
7
7
  "main": "./dist/index.js",