@ember-finance/sdk 2.25.0 → 2.26.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.
|
@@ -2,6 +2,18 @@ import { BaseClient as SuiClient } from "@mysten/sui/client";
|
|
|
2
2
|
import { FeeMultiplierTier, InstantWithdrawQuote } from "../../atomic/instant-withdraw.js";
|
|
3
3
|
/** Strategy an atomic vault's idle collateral can be supplied to. */
|
|
4
4
|
export type SuiAtomicStrategy = "none" | "suilend";
|
|
5
|
+
/** An atomic vault's strategy and, for Suilend, the market it supplies to. */
|
|
6
|
+
export interface SuiAtomicStrategyTarget {
|
|
7
|
+
strategy: SuiAtomicStrategy;
|
|
8
|
+
/** The vault's collateral coin type (`T`). */
|
|
9
|
+
collateralType: string;
|
|
10
|
+
/** Collateral held in the vault, in base units. */
|
|
11
|
+
idleCollateral: bigint;
|
|
12
|
+
/** Suilend only: the LendingMarket object id. */
|
|
13
|
+
suilendMarketId?: string;
|
|
14
|
+
/** Suilend only: the market's pool type (`P`). */
|
|
15
|
+
suilendPoolType?: string;
|
|
16
|
+
}
|
|
5
17
|
/**
|
|
6
18
|
* Read-only views + instant-withdraw quotes for the Sui Atomic Liquidity Vault (BET-4111).
|
|
7
19
|
*
|
|
@@ -42,6 +54,15 @@ export declare class SuiAtomicLiquidityReader {
|
|
|
42
54
|
} | null>;
|
|
43
55
|
/** Caller's ALV (non-transferable) share balance from the `shares` table. */
|
|
44
56
|
shareOf(vaultId: string, account: string): Promise<bigint>;
|
|
57
|
+
/**
|
|
58
|
+
* The strategy an atomic vault is on, and for Suilend the market it supplies to.
|
|
59
|
+
* Plain object reads, no simulation.
|
|
60
|
+
* @param vaultId Object id of the atomic vault
|
|
61
|
+
* @returns The strategy, the vault's collateral coin type and idle collateral, and
|
|
62
|
+
* for Suilend the market id and its pool type (`P`)
|
|
63
|
+
*/
|
|
64
|
+
getStrategyTarget(vaultId: string): Promise<SuiAtomicStrategyTarget>;
|
|
65
|
+
private readStrategyTarget;
|
|
45
66
|
/**
|
|
46
67
|
* Where an atomic vault's collateral sits: idle in the vault, or supplied to its
|
|
47
68
|
* strategy.
|
|
@@ -112,14 +112,18 @@ export class SuiAtomicLiquidityReader {
|
|
|
112
112
|
return toBig(await this.readTableValue(tableId, "address", account));
|
|
113
113
|
}
|
|
114
114
|
/**
|
|
115
|
-
*
|
|
116
|
-
*
|
|
115
|
+
* The strategy an atomic vault is on, and for Suilend the market it supplies to.
|
|
116
|
+
* Plain object reads, no simulation.
|
|
117
117
|
* @param vaultId Object id of the atomic vault
|
|
118
|
-
* @returns The
|
|
119
|
-
*
|
|
120
|
-
* the strategy is Suilend.
|
|
118
|
+
* @returns The strategy, the vault's collateral coin type and idle collateral, and
|
|
119
|
+
* for Suilend the market id and its pool type (`P`)
|
|
121
120
|
*/
|
|
122
|
-
async
|
|
121
|
+
async getStrategyTarget(vaultId) {
|
|
122
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
123
|
+
const { packageId, ...target } = await this.readStrategyTarget(vaultId);
|
|
124
|
+
return target;
|
|
125
|
+
}
|
|
126
|
+
async readStrategyTarget(vaultId) {
|
|
123
127
|
const res = await this.suiClient.core.getObject({
|
|
124
128
|
objectId: vaultId,
|
|
125
129
|
include: { json: true }
|
|
@@ -131,16 +135,14 @@ export class SuiAtomicLiquidityReader {
|
|
|
131
135
|
if (!strategy) {
|
|
132
136
|
throw new Error(`Unknown strategy kind ${fields.strategy_kind} on ${vaultId}`);
|
|
133
137
|
}
|
|
138
|
+
const vaultType = res.object.type;
|
|
139
|
+
// The package that defines the vault type is the one with the views.
|
|
140
|
+
const packageId = vaultType.split("::")[0];
|
|
141
|
+
const collateralType = vaultType.slice(vaultType.indexOf("<") + 1, -1);
|
|
134
142
|
const idleCollateral = toBig(fields.balance);
|
|
135
143
|
if (strategy === "none") {
|
|
136
|
-
return { strategy, idleCollateral,
|
|
144
|
+
return { strategy, collateralType, idleCollateral, packageId };
|
|
137
145
|
}
|
|
138
|
-
// The vault's type names the package that defines it, which is the one with
|
|
139
|
-
// the views. The position is valued by Suilend against the reserve's current
|
|
140
|
-
// interest, so it is simulated rather than read from fields.
|
|
141
|
-
const vaultType = res.object.type;
|
|
142
|
-
const collateralType = vaultType.slice(vaultType.indexOf("<") + 1, -1);
|
|
143
|
-
const packageId = vaultType.split("::")[0];
|
|
144
146
|
const marketField = await this.suiClient.core.getDynamicField({
|
|
145
147
|
parentId: vaultId,
|
|
146
148
|
name: {
|
|
@@ -154,13 +156,41 @@ export class SuiAtomicLiquidityReader {
|
|
|
154
156
|
const suilendMarketId = bcs.Address.parse(marketField.dynamicField.value.bcs);
|
|
155
157
|
const market = await this.suiClient.core.getObject({ objectId: suilendMarketId });
|
|
156
158
|
const marketType = market.object.type;
|
|
157
|
-
|
|
159
|
+
return {
|
|
160
|
+
strategy,
|
|
161
|
+
collateralType,
|
|
162
|
+
idleCollateral,
|
|
163
|
+
packageId,
|
|
164
|
+
suilendMarketId,
|
|
165
|
+
suilendPoolType: marketType.slice(marketType.indexOf("<") + 1, -1)
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Where an atomic vault's collateral sits: idle in the vault, or supplied to its
|
|
170
|
+
* strategy.
|
|
171
|
+
* @param vaultId Object id of the atomic vault
|
|
172
|
+
* @returns The active strategy, idle collateral and strategy assets, in collateral
|
|
173
|
+
* base units. `suilendMarketId` and `suilendPoolType` (the market's `P`) are set when
|
|
174
|
+
* the strategy is Suilend.
|
|
175
|
+
*/
|
|
176
|
+
async getStrategyState(vaultId) {
|
|
177
|
+
const target = await this.readStrategyTarget(vaultId);
|
|
178
|
+
const { strategy, idleCollateral, suilendMarketId, suilendPoolType, packageId } = target;
|
|
179
|
+
if (strategy === "none") {
|
|
180
|
+
return { strategy, idleCollateral, strategyAssets: 0n };
|
|
181
|
+
}
|
|
182
|
+
// Suilend values the position against the reserve's current interest, so it is
|
|
183
|
+
// simulated rather than read from fields.
|
|
158
184
|
const tx = new Transaction();
|
|
159
185
|
tx.setSender(SUI_ZERO_ADDRESS);
|
|
160
186
|
tx.moveCall({
|
|
161
187
|
target: `${packageId}::atomic_liquidity_vault::get_suilend_strategy_assets`,
|
|
162
|
-
typeArguments: [collateralType,
|
|
163
|
-
arguments: [
|
|
188
|
+
typeArguments: [target.collateralType, suilendPoolType],
|
|
189
|
+
arguments: [
|
|
190
|
+
tx.object(vaultId),
|
|
191
|
+
tx.object(suilendMarketId),
|
|
192
|
+
tx.object.clock()
|
|
193
|
+
]
|
|
164
194
|
});
|
|
165
195
|
const sim = await this.suiClient.core.simulateTransaction({
|
|
166
196
|
transaction: tx,
|
|
@@ -176,7 +206,7 @@ export class SuiAtomicLiquidityReader {
|
|
|
176
206
|
idleCollateral,
|
|
177
207
|
strategyAssets: BigInt(bcs.u64().parse(returned)),
|
|
178
208
|
suilendMarketId,
|
|
179
|
-
suilendPoolType
|
|
209
|
+
suilendPoolType
|
|
180
210
|
};
|
|
181
211
|
}
|
|
182
212
|
/**
|
|
@@ -87,7 +87,8 @@ export declare class UserCalls extends OnChainCalls {
|
|
|
87
87
|
*/
|
|
88
88
|
atomicCancelPendingWithdrawalRequest(vaultId: string, sequenceNumber: NumStr, options?: IVaultOptionalParams & SuiTransactionBlockResponseOptions): Promise<OnChainCallResponse>;
|
|
89
89
|
/**
|
|
90
|
-
* Instantly withdraw collateral from an atomic liquidity vault
|
|
90
|
+
* Instantly withdraw collateral from an atomic liquidity vault. Routes to the
|
|
91
|
+
* entry point for the vault's current strategy.
|
|
91
92
|
* @param vaultId The id of the atomic vault
|
|
92
93
|
* @param shares The number of shares to withdraw
|
|
93
94
|
* @param options Optional tx execution params
|
|
@@ -109,7 +110,8 @@ export declare class UserCalls extends OnChainCalls {
|
|
|
109
110
|
receiver?: SuiAddress;
|
|
110
111
|
} & SuiTransactionBlockResponseOptions): Promise<OnChainCallResponse>;
|
|
111
112
|
/**
|
|
112
|
-
* Swap ember shares (source vault receipt coin) into an atomic vault
|
|
113
|
+
* Swap ember shares (source vault receipt coin) into an atomic vault. Routes to the
|
|
114
|
+
* entry point for the vault's current strategy.
|
|
113
115
|
* @param vaultId The id of the atomic vault
|
|
114
116
|
* @param sourceReceiptType The receipt coin type of the source vault (R)
|
|
115
117
|
* @param sourceVaultId Object id of the source Vault<T, R>
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { OnChainCalls } from "./onchain-calls.js";
|
|
2
2
|
import { TransactionBlock, bigNumber, CoinUtils, SUI_NATIVE_BASE } from "@firefly-exchange/library-sui";
|
|
3
3
|
import { Vault } from "./vault.js";
|
|
4
|
+
import { SuiAtomicLiquidityReader } from "./atomic-liquidity.js";
|
|
5
|
+
const isSuiCoinType = (coinType) => {
|
|
6
|
+
const [address, module, name] = coinType.split("::");
|
|
7
|
+
return module === "sui" && name === "SUI" && /^0x0*2$/.test(address);
|
|
8
|
+
};
|
|
4
9
|
export class UserCalls extends OnChainCalls {
|
|
5
10
|
constructor(_network, _suiClient, _deployment, _signer, _walletAddress, _isUIWallet) {
|
|
6
11
|
super(_network, _suiClient, _deployment, _signer, _walletAddress, _isUIWallet);
|
|
@@ -186,7 +191,8 @@ export class UserCalls extends OnChainCalls {
|
|
|
186
191
|
return this.execCall(txb, options);
|
|
187
192
|
}
|
|
188
193
|
/**
|
|
189
|
-
* Instantly withdraw collateral from an atomic liquidity vault
|
|
194
|
+
* Instantly withdraw collateral from an atomic liquidity vault. Routes to the
|
|
195
|
+
* entry point for the vault's current strategy.
|
|
190
196
|
* @param vaultId The id of the atomic vault
|
|
191
197
|
* @param shares The number of shares to withdraw
|
|
192
198
|
* @param options Optional tx execution params
|
|
@@ -194,10 +200,20 @@ export class UserCalls extends OnChainCalls {
|
|
|
194
200
|
*/
|
|
195
201
|
async atomicInstantWithdraw(vaultId, shares, options) {
|
|
196
202
|
const txb = options?.txBlock || new TransactionBlock();
|
|
197
|
-
this.
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
203
|
+
const target = await new SuiAtomicLiquidityReader(this.suiClient).getStrategyTarget(vaultId);
|
|
204
|
+
// The plain entry point asserts the vault has no strategy (EStrategyMismatch);
|
|
205
|
+
// a strategy vault must be called with its market so liquidity can be pulled.
|
|
206
|
+
if (target.strategy === "suilend") {
|
|
207
|
+
if (isSuiCoinType(target.collateralType)) {
|
|
208
|
+
this.txBuilder.atomicInstantWithdrawWithSuilendSui(vaultId, target.suilendPoolType, target.suilendMarketId, shares, options?.receiver ?? this.walletAddress, { ...options, txBlock: txb });
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
this.txBuilder.atomicInstantWithdrawWithSuilend(vaultId, target.suilendPoolType, target.suilendMarketId, shares, options?.receiver ?? null, { ...options, txBlock: txb });
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
this.txBuilder.atomicInstantWithdraw(vaultId, shares, options?.receiver ?? null, { ...options, txBlock: txb });
|
|
216
|
+
}
|
|
201
217
|
return this.execCall(txb, options);
|
|
202
218
|
}
|
|
203
219
|
/**
|
|
@@ -215,7 +231,8 @@ export class UserCalls extends OnChainCalls {
|
|
|
215
231
|
return this.execCall(txb, options);
|
|
216
232
|
}
|
|
217
233
|
/**
|
|
218
|
-
* Swap ember shares (source vault receipt coin) into an atomic vault
|
|
234
|
+
* Swap ember shares (source vault receipt coin) into an atomic vault. Routes to the
|
|
235
|
+
* entry point for the vault's current strategy.
|
|
219
236
|
* @param vaultId The id of the atomic vault
|
|
220
237
|
* @param sourceReceiptType The receipt coin type of the source vault (R)
|
|
221
238
|
* @param sourceVaultId Object id of the source Vault<T, R>
|
|
@@ -242,7 +259,20 @@ export class UserCalls extends OnChainCalls {
|
|
|
242
259
|
[split, merged] = await CoinUtils.validateCoinBalance(this.suiClient, txb, bigNumber(amount).toFixed(0), coinId);
|
|
243
260
|
coinId = split;
|
|
244
261
|
}
|
|
245
|
-
|
|
262
|
+
const target = await new SuiAtomicLiquidityReader(this.suiClient).getStrategyTarget(vaultId);
|
|
263
|
+
// The plain entry point asserts the vault has no strategy (EStrategyMismatch);
|
|
264
|
+
// a strategy vault must be called with its market so liquidity can be pulled.
|
|
265
|
+
if (target.strategy === "suilend") {
|
|
266
|
+
if (isSuiCoinType(target.collateralType)) {
|
|
267
|
+
this.txBuilder.atomicSwapEmberSharesWithSuilendSui(vaultId, sourceReceiptType, target.suilendPoolType, sourceVaultId, target.suilendMarketId, coinId, options?.receiver ?? this.walletAddress, minNetOut, { ...options, txBlock: txb });
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
this.txBuilder.atomicSwapEmberSharesWithSuilend(vaultId, sourceReceiptType, target.suilendPoolType, sourceVaultId, target.suilendMarketId, coinId, options?.receiver ?? null, minNetOut, { ...options, txBlock: txb });
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
this.txBuilder.atomicSwapEmberShares(vaultId, sourceReceiptType, sourceVaultId, coinId, options?.receiver ?? null, minNetOut, { ...options, txBlock: txb });
|
|
275
|
+
}
|
|
246
276
|
if (merged) {
|
|
247
277
|
txb.transferObjects([merged], this.walletAddress);
|
|
248
278
|
}
|