@ember-finance/sdk 2.33.0 → 2.34.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.
@@ -62,6 +62,12 @@ export declare class SuiAtomicLiquidityReader {
62
62
  private readTableValue;
63
63
  /** Rate value (1e9) of any vault object (ALV or source EmberVault). */
64
64
  private rateValue;
65
+ /**
66
+ * Platform fee a collection would settle at `atMs` (epoch ms), in collateral base units.
67
+ * @param vaultId The id of the atomic vault
68
+ * @param atMs Time to project the fee to
69
+ */
70
+ getPlatformFeeDue(vaultId: string, atMs: bigint): Promise<bigint>;
65
71
  /** Per-source-share EmberShare config from the `ember_share_configs` table. */
66
72
  getEmberShareConfig(vaultId: string, sourceVaultId: string): Promise<{
67
73
  whitelisted: boolean;
@@ -131,6 +131,27 @@ export class SuiAtomicLiquidityReader {
131
131
  const fields = unwrapMoveFields(res.object?.json);
132
132
  return toBig(unwrapMoveFields(fields?.rate)?.value);
133
133
  }
134
+ /**
135
+ * Platform fee a collection would settle at `atMs` (epoch ms), in collateral base units.
136
+ * @param vaultId The id of the atomic vault
137
+ * @param atMs Time to project the fee to
138
+ */
139
+ async getPlatformFeeDue(vaultId, atMs) {
140
+ // collect_platform_fee charges the time since last_charged_at before settling:
141
+ // accrued + tvl' * fee_percentage * elapsed_ms / 31_536_000e12, where tvl' is
142
+ // TVL (div(total_shares, rate)) net of the already-accrued fee.
143
+ const fields = await this.vaultFields(vaultId);
144
+ const fee = unwrapMoveFields(fields.fee) ?? {};
145
+ const accrued = toBig(fee.accrued);
146
+ const lastChargedAt = toBig(fee.last_charged_at);
147
+ const feePercentage = toBig(fields.fee_percentage);
148
+ if (atMs <= lastChargedAt || feePercentage === 0n)
149
+ return accrued;
150
+ const tvl = divFloor(toBig(fields.total_shares), toBig(unwrapMoveFields(fields.rate)?.value));
151
+ const base = tvl > accrued ? tvl - accrued : 0n;
152
+ return (accrued +
153
+ (base * feePercentage * (atMs - lastChargedAt)) / 31536000000000000000n);
154
+ }
134
155
  /** Per-source-share EmberShare config from the `ember_share_configs` table. */
135
156
  async getEmberShareConfig(vaultId, sourceVaultId) {
136
157
  const fields = await this.vaultFields(vaultId);
@@ -139,7 +139,8 @@ export declare class OperatorCalls extends OnChainCalls {
139
139
  */
140
140
  atomicProcessWithdrawalRequestsUpToTimestamp(vaultId: string, timestamp: NumStr, options?: IVaultOptionalParams & SuiTransactionBlockResponseOptions): Promise<OnChainCallResponse>;
141
141
  /**
142
- * Collect the platform fee of an atomic vault
142
+ * Collect the platform fee of an atomic vault. On a strategy vault, pulls any
143
+ * shortfall from the strategy first, in the same transaction.
143
144
  * @param vaultId The id of the atomic vault
144
145
  * @param loss The reported loss amount
145
146
  * @param options Optional tx execution params
@@ -252,7 +252,8 @@ export class OperatorCalls extends OnChainCalls {
252
252
  return this.execCall(txb, options);
253
253
  }
254
254
  /**
255
- * Collect the platform fee of an atomic vault
255
+ * Collect the platform fee of an atomic vault. On a strategy vault, pulls any
256
+ * shortfall from the strategy first, in the same transaction.
256
257
  * @param vaultId The id of the atomic vault
257
258
  * @param loss The reported loss amount
258
259
  * @param options Optional tx execution params
@@ -260,6 +261,24 @@ export class OperatorCalls extends OnChainCalls {
260
261
  */
261
262
  async atomicCollectPlatformFee(vaultId, loss, options) {
262
263
  const txb = options?.txBlock || new TransactionBlock();
264
+ // Unlike EVM's collectPlatformFee, the Sui collection pays from idle balance only
265
+ // and aborts when it is short, so the strategy is drawn on first. The fee keeps
266
+ // accruing until the tx lands, so it is projected a few minutes ahead; whatever
267
+ // is pulled beyond the payout stays idle in the vault.
268
+ const reader = new SuiAtomicLiquidityReader(this.suiClient);
269
+ const target = await reader.getStrategyTarget(vaultId);
270
+ if (target.strategy === "suilend") {
271
+ const landsBy = BigInt(Date.now() + 10 * 60 * 1000);
272
+ const due = await reader.getPlatformFeeDue(vaultId, landsBy);
273
+ const payout = due > BigInt(loss) ? due - BigInt(loss) : 0n;
274
+ const shortfall = payout - target.idleCollateral;
275
+ if (shortfall > 0n) {
276
+ const withdraw = isSuiCoinType(target.collateralType)
277
+ ? this.txBuilder.atomicWithdrawFromSuilendStrategySui.bind(this.txBuilder)
278
+ : this.txBuilder.atomicWithdrawFromSuilendStrategy.bind(this.txBuilder);
279
+ withdraw(vaultId, target.suilendPoolType, target.suilendMarketId, shortfall.toString(), { ...options, txBlock: txb });
280
+ }
281
+ }
263
282
  this.txBuilder.atomicCollectPlatformFee(vaultId, loss, {
264
283
  ...options,
265
284
  txBlock: txb
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.33.0",
4
+ "version": "2.34.0",
5
5
  "type": "module",
6
6
  "module": "./dist/index.js",
7
7
  "main": "./dist/index.js",