@0dotxyz/p0-ts-sdk 2.5.3 → 2.5.5-alpha.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/dist/index.cjs +577 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +170 -4
- package/dist/index.d.ts +170 -4
- package/dist/index.js +575 -3
- package/dist/index.js.map +1 -1
- package/dist/instructions.d.cts +1 -1
- package/dist/instructions.d.ts +1 -1
- package/dist/{types-Bv7AjHar.d.ts → types-D1QBbDkU.d.ts} +4 -1
- package/dist/{types-f-ZjRBYz.d.cts → types-DrxdJJIi.d.cts} +4 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -128,6 +128,9 @@ var TransactionBuildingErrorCode = /* @__PURE__ */ ((TransactionBuildingErrorCod
|
|
|
128
128
|
TransactionBuildingErrorCode2["JUPLEND_STATE_NOT_FOUND"] = "JUPLEND_STATE_NOT_FOUND";
|
|
129
129
|
TransactionBuildingErrorCode2["SWITCHBOARD_FEED_UPDATE_FAILED"] = "SWITCHBOARD_FEED_UPDATE_FAILED";
|
|
130
130
|
TransactionBuildingErrorCode2["SWAP_QUOTE_FAILED"] = "SWAP_QUOTE_FAILED";
|
|
131
|
+
TransactionBuildingErrorCode2["TRANSFER_POSITIONS_INVALID_SELECTION"] = "TRANSFER_POSITIONS_INVALID_SELECTION";
|
|
132
|
+
TransactionBuildingErrorCode2["TRANSFER_POSITIONS_UNSUPPORTED_BANK"] = "TRANSFER_POSITIONS_UNSUPPORTED_BANK";
|
|
133
|
+
TransactionBuildingErrorCode2["TRANSFER_POSITIONS_UNSPLITTABLE"] = "TRANSFER_POSITIONS_UNSPLITTABLE";
|
|
131
134
|
return TransactionBuildingErrorCode2;
|
|
132
135
|
})(TransactionBuildingErrorCode || {});
|
|
133
136
|
var TransactionBuildingError = class _TransactionBuildingError extends Error {
|
|
@@ -224,6 +227,40 @@ var TransactionBuildingError = class _TransactionBuildingError extends Error {
|
|
|
224
227
|
{ provider, inputMint, outputMint, reason }
|
|
225
228
|
);
|
|
226
229
|
}
|
|
230
|
+
/**
|
|
231
|
+
* The requested set of positions to transfer is invalid (inactive bank on the source,
|
|
232
|
+
* destination overlap, capacity/slot conflict, group/authority mismatch, etc.).
|
|
233
|
+
*/
|
|
234
|
+
static transferPositionsInvalidSelection(reason, bankAddresses) {
|
|
235
|
+
return new _TransactionBuildingError(
|
|
236
|
+
"TRANSFER_POSITIONS_INVALID_SELECTION" /* TRANSFER_POSITIONS_INVALID_SELECTION */,
|
|
237
|
+
`Invalid transfer-positions selection: ${reason}`,
|
|
238
|
+
{ reason, bankAddresses }
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* A selected position lives in a bank whose asset tag is not supported by transfer-positions
|
|
243
|
+
* (v1 supports DEFAULT and STAKED only).
|
|
244
|
+
*/
|
|
245
|
+
static transferPositionsUnsupportedBank(bankAddress, assetTag, bankSymbol) {
|
|
246
|
+
return new _TransactionBuildingError(
|
|
247
|
+
"TRANSFER_POSITIONS_UNSUPPORTED_BANK" /* TRANSFER_POSITIONS_UNSUPPORTED_BANK */,
|
|
248
|
+
`Bank ${bankSymbol ?? bankAddress} (asset tag ${assetTag}) is not supported by transfer-positions`,
|
|
249
|
+
{ bankAddress, assetTag, bankSymbol }
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* The built transfer transaction exceeds the v0 size / account-lock limits even at the position
|
|
254
|
+
* cap (most likely several integration positions whose reserve accounts overflow the 64-lock cap).
|
|
255
|
+
* Retry with fewer positions in the selection.
|
|
256
|
+
*/
|
|
257
|
+
static transferPositionsUnsplittable(reason, sizeBytes, accountCount) {
|
|
258
|
+
return new _TransactionBuildingError(
|
|
259
|
+
"TRANSFER_POSITIONS_UNSPLITTABLE" /* TRANSFER_POSITIONS_UNSPLITTABLE */,
|
|
260
|
+
`Transfer does not fit one transaction: ${reason}`,
|
|
261
|
+
{ reason, sizeBytes, accountCount }
|
|
262
|
+
);
|
|
263
|
+
}
|
|
227
264
|
/**
|
|
228
265
|
* Generic escape hatch for custom errors
|
|
229
266
|
*/
|
|
@@ -19903,6 +19940,7 @@ var EmodeFlags = /* @__PURE__ */ ((EmodeFlags3) => {
|
|
|
19903
19940
|
var EmodeTag = /* @__PURE__ */ ((EmodeTag3) => {
|
|
19904
19941
|
EmodeTag3[EmodeTag3["UNSET"] = 0] = "UNSET";
|
|
19905
19942
|
EmodeTag3[EmodeTag3["SOL"] = 501] = "SOL";
|
|
19943
|
+
EmodeTag3[EmodeTag3["SOL_T2"] = 502] = "SOL_T2";
|
|
19906
19944
|
EmodeTag3[EmodeTag3["LST_T1"] = 1571] = "LST_T1";
|
|
19907
19945
|
EmodeTag3[EmodeTag3["LST_T2"] = 1572] = "LST_T2";
|
|
19908
19946
|
EmodeTag3[EmodeTag3["LST_PT"] = 15787] = "LST_PT";
|
|
@@ -19911,6 +19949,8 @@ var EmodeTag = /* @__PURE__ */ ((EmodeTag3) => {
|
|
|
19911
19949
|
EmodeTag3[EmodeTag3["STABLE_T2"] = 57482] = "STABLE_T2";
|
|
19912
19950
|
EmodeTag3[EmodeTag3["BTC_T1"] = 871] = "BTC_T1";
|
|
19913
19951
|
EmodeTag3[EmodeTag3["BTC_T2"] = 872] = "BTC_T2";
|
|
19952
|
+
EmodeTag3[EmodeTag3["HYUSD"] = 47050] = "HYUSD";
|
|
19953
|
+
EmodeTag3[EmodeTag3["PT_HYUSD"] = 8747] = "PT_HYUSD";
|
|
19914
19954
|
return EmodeTag3;
|
|
19915
19955
|
})(EmodeTag || {});
|
|
19916
19956
|
var EmodeImpactStatus = /* @__PURE__ */ ((EmodeImpactStatus3) => {
|
|
@@ -21734,6 +21774,8 @@ function parseEmodeTag(emodeTagRaw) {
|
|
|
21734
21774
|
switch (emodeTagRaw) {
|
|
21735
21775
|
case 501:
|
|
21736
21776
|
return 501 /* SOL */;
|
|
21777
|
+
case 502:
|
|
21778
|
+
return 502 /* SOL_T2 */;
|
|
21737
21779
|
case 1571:
|
|
21738
21780
|
return 1571 /* LST_T1 */;
|
|
21739
21781
|
case 1572:
|
|
@@ -21750,6 +21792,10 @@ function parseEmodeTag(emodeTagRaw) {
|
|
|
21750
21792
|
return 871 /* BTC_T1 */;
|
|
21751
21793
|
case 872:
|
|
21752
21794
|
return 872 /* BTC_T2 */;
|
|
21795
|
+
case 47050:
|
|
21796
|
+
return 47050 /* HYUSD */;
|
|
21797
|
+
case 8747:
|
|
21798
|
+
return 8747 /* PT_HYUSD */;
|
|
21753
21799
|
case 0:
|
|
21754
21800
|
default:
|
|
21755
21801
|
return 0 /* UNSET */;
|
|
@@ -69425,6 +69471,23 @@ var MarginfiAccount = class _MarginfiAccount {
|
|
|
69425
69471
|
}
|
|
69426
69472
|
});
|
|
69427
69473
|
}
|
|
69474
|
+
/**
|
|
69475
|
+
* Atomically move a selected set of positions from this account to a destination account
|
|
69476
|
+
* (same authority, same group) using flashloans, auto-splitting across transactions as needed.
|
|
69477
|
+
*
|
|
69478
|
+
* @see {@link makeTransferPositionsTx} for detailed implementation
|
|
69479
|
+
*/
|
|
69480
|
+
async makeTransferPositionsTx(params) {
|
|
69481
|
+
return makeTransferPositionsTx({
|
|
69482
|
+
...params,
|
|
69483
|
+
marginfiAccount: this,
|
|
69484
|
+
overrideInferAccounts: {
|
|
69485
|
+
authority: this.authority,
|
|
69486
|
+
group: this.group,
|
|
69487
|
+
...params.overrideInferAccounts
|
|
69488
|
+
}
|
|
69489
|
+
});
|
|
69490
|
+
}
|
|
69428
69491
|
/**
|
|
69429
69492
|
* Creates a transaction to repay debt using collateral.
|
|
69430
69493
|
*
|
|
@@ -69884,6 +69947,485 @@ async function composeBridgedSwap(params) {
|
|
|
69884
69947
|
if (!transactions) return null;
|
|
69885
69948
|
return { transactions, firstLegQuote: firstLeg.quoteResponse, secondLegQuote: secondLeg.quoteResponse };
|
|
69886
69949
|
}
|
|
69950
|
+
var MAX_BALANCES = 16;
|
|
69951
|
+
var DEFAULT_MAX_TRANSFER_POSITIONS = 5;
|
|
69952
|
+
var DEFAULT_BORROW_PADDING_BPS = 10;
|
|
69953
|
+
var CU_IXS = () => [
|
|
69954
|
+
web3_js.ComputeBudgetProgram.setComputeUnitLimit({ units: 14e5 }),
|
|
69955
|
+
web3_js.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 })
|
|
69956
|
+
];
|
|
69957
|
+
function requireBank(bankMap, address) {
|
|
69958
|
+
const bank = bankMap.get(address.toBase58());
|
|
69959
|
+
if (!bank) {
|
|
69960
|
+
throw TransactionBuildingError.transferPositionsInvalidSelection(
|
|
69961
|
+
`bank ${address.toBase58()} not found`,
|
|
69962
|
+
[address.toBase58()]
|
|
69963
|
+
);
|
|
69964
|
+
}
|
|
69965
|
+
return bank;
|
|
69966
|
+
}
|
|
69967
|
+
function requireTokenProgram(tokenProgramsByBank, address) {
|
|
69968
|
+
const tp = tokenProgramsByBank.get(address.toBase58());
|
|
69969
|
+
if (!tp) {
|
|
69970
|
+
throw TransactionBuildingError.transferPositionsInvalidSelection(
|
|
69971
|
+
`token program for bank ${address.toBase58()} not provided`,
|
|
69972
|
+
[address.toBase58()]
|
|
69973
|
+
);
|
|
69974
|
+
}
|
|
69975
|
+
return tp;
|
|
69976
|
+
}
|
|
69977
|
+
function classifyAndValidate(params) {
|
|
69978
|
+
const {
|
|
69979
|
+
marginfiAccount: accountA,
|
|
69980
|
+
destinationAccount: accountB,
|
|
69981
|
+
bankAddresses,
|
|
69982
|
+
bankMap,
|
|
69983
|
+
tokenProgramsByBank,
|
|
69984
|
+
assetShareValueMultiplierByBank
|
|
69985
|
+
} = params;
|
|
69986
|
+
const maxPositions = params.maxPositions ?? DEFAULT_MAX_TRANSFER_POSITIONS;
|
|
69987
|
+
if (bankAddresses.length === 0) {
|
|
69988
|
+
throw TransactionBuildingError.transferPositionsInvalidSelection("no positions selected", []);
|
|
69989
|
+
}
|
|
69990
|
+
if (bankAddresses.length > maxPositions) {
|
|
69991
|
+
throw TransactionBuildingError.transferPositionsInvalidSelection(
|
|
69992
|
+
`cannot transfer ${bankAddresses.length} positions in one transaction (max ${maxPositions}); select fewer and transfer in batches`,
|
|
69993
|
+
bankAddresses.map((b) => b.toBase58())
|
|
69994
|
+
);
|
|
69995
|
+
}
|
|
69996
|
+
const activeBalancesA = accountA.balances.filter((b) => b.active);
|
|
69997
|
+
const positions = [];
|
|
69998
|
+
for (const bankAddress of bankAddresses) {
|
|
69999
|
+
const bank = requireBank(bankMap, bankAddress);
|
|
70000
|
+
const tokenProgram = requireTokenProgram(tokenProgramsByBank, bankAddress);
|
|
70001
|
+
const balance = activeBalancesA.find((b) => b.bankPk.equals(bankAddress));
|
|
70002
|
+
if (!balance) {
|
|
70003
|
+
throw TransactionBuildingError.transferPositionsInvalidSelection(
|
|
70004
|
+
`source account has no active position in bank ${bankAddress.toBase58()}`,
|
|
70005
|
+
[bankAddress.toBase58()]
|
|
70006
|
+
);
|
|
70007
|
+
}
|
|
70008
|
+
const side = balance.assetShares.gt(0) ? "collateral" : "debt";
|
|
70009
|
+
const multiplier = assetShareValueMultiplierByBank.get(bankAddress.toBase58());
|
|
70010
|
+
const qty = computeQuantityUi(balance, bank, multiplier);
|
|
70011
|
+
positions.push({
|
|
70012
|
+
bankAddress,
|
|
70013
|
+
side,
|
|
70014
|
+
uiAmount: side === "collateral" ? qty.assets : qty.liabilities,
|
|
70015
|
+
bank,
|
|
70016
|
+
tokenProgram
|
|
70017
|
+
});
|
|
70018
|
+
}
|
|
70019
|
+
const isolatedDebts = positions.filter(
|
|
70020
|
+
(p) => p.side === "debt" && p.bank.config.riskTier === "Isolated" /* Isolated */
|
|
70021
|
+
);
|
|
70022
|
+
if (isolatedDebts.length > 0) {
|
|
70023
|
+
const otherDebts = positions.filter((p) => p.side === "debt").length > 1;
|
|
70024
|
+
const destHasLiabilities = (accountB?.balances ?? []).some(
|
|
70025
|
+
(b) => b.active && b.liabilityShares.gt(0)
|
|
70026
|
+
);
|
|
70027
|
+
if (isolatedDebts.length > 1 || otherDebts || destHasLiabilities) {
|
|
70028
|
+
throw TransactionBuildingError.transferPositionsInvalidSelection(
|
|
70029
|
+
"an isolated-tier debt can only be transferred as the destination account's sole liability",
|
|
70030
|
+
isolatedDebts.map((p) => p.bankAddress.toBase58())
|
|
70031
|
+
);
|
|
70032
|
+
}
|
|
70033
|
+
}
|
|
70034
|
+
if (accountB) {
|
|
70035
|
+
if (!accountB.group.equals(accountA.group)) {
|
|
70036
|
+
throw TransactionBuildingError.transferPositionsInvalidSelection(
|
|
70037
|
+
"destination account is in a different group",
|
|
70038
|
+
[accountB.address.toBase58()]
|
|
70039
|
+
);
|
|
70040
|
+
}
|
|
70041
|
+
if (!accountB.authority.equals(accountA.authority)) {
|
|
70042
|
+
throw TransactionBuildingError.transferPositionsInvalidSelection(
|
|
70043
|
+
"destination account has a different authority",
|
|
70044
|
+
[accountB.address.toBase58()]
|
|
70045
|
+
);
|
|
70046
|
+
}
|
|
70047
|
+
const overlap = positions.filter(
|
|
70048
|
+
(p) => accountB.balances.some((b) => b.active && b.bankPk.equals(p.bankAddress))
|
|
70049
|
+
);
|
|
70050
|
+
if (overlap.length > 0) {
|
|
70051
|
+
throw TransactionBuildingError.transferPositionsInvalidSelection(
|
|
70052
|
+
"destination account already holds a position in a transferred bank",
|
|
70053
|
+
overlap.map((p) => p.bankAddress.toBase58())
|
|
70054
|
+
);
|
|
70055
|
+
}
|
|
70056
|
+
const activeCountB = accountB.balances.filter((b) => b.active).length;
|
|
70057
|
+
if (activeCountB + positions.length > MAX_BALANCES) {
|
|
70058
|
+
throw TransactionBuildingError.transferPositionsInvalidSelection(
|
|
70059
|
+
`destination account cannot hold ${activeCountB + positions.length} positions (max ${MAX_BALANCES})`,
|
|
70060
|
+
positions.map((p) => p.bankAddress.toBase58())
|
|
70061
|
+
);
|
|
70062
|
+
}
|
|
70063
|
+
}
|
|
70064
|
+
return positions;
|
|
70065
|
+
}
|
|
70066
|
+
function buildIntegrationRefreshIxs(args) {
|
|
70067
|
+
const { accountA, destinationAccount, positions, bankMap, bankMetadataMap } = args;
|
|
70068
|
+
const transferredKaminoPks = positions.filter((p) => p.bank.config.assetTag === 3 /* KAMINO */).map((p) => p.bankAddress);
|
|
70069
|
+
const transferredJupPks = positions.filter((p) => p.bank.config.assetTag === 6 /* JUPLEND */).map((p) => p.bankAddress);
|
|
70070
|
+
const ixs = [];
|
|
70071
|
+
ixs.push(
|
|
70072
|
+
...makeRefreshKaminoBanksIxs(accountA, bankMap, transferredKaminoPks, bankMetadataMap).instructions
|
|
70073
|
+
);
|
|
70074
|
+
if (destinationAccount) {
|
|
70075
|
+
ixs.push(
|
|
70076
|
+
...makeRefreshKaminoBanksIxs(destinationAccount, bankMap, [], bankMetadataMap).instructions
|
|
70077
|
+
);
|
|
70078
|
+
}
|
|
70079
|
+
ixs.push(
|
|
70080
|
+
...makeUpdateJupLendRateIxs(accountA, bankMap, transferredJupPks, bankMetadataMap).instructions
|
|
70081
|
+
);
|
|
70082
|
+
if (destinationAccount) {
|
|
70083
|
+
ixs.push(
|
|
70084
|
+
...makeUpdateJupLendRateIxs(destinationAccount, bankMap, transferredJupPks, bankMetadataMap).instructions
|
|
70085
|
+
);
|
|
70086
|
+
}
|
|
70087
|
+
return ixs;
|
|
70088
|
+
}
|
|
70089
|
+
function dedupeBanks(banks) {
|
|
70090
|
+
const seen = /* @__PURE__ */ new Map();
|
|
70091
|
+
for (const bank of banks) seen.set(bank.address.toBase58(), bank);
|
|
70092
|
+
return [...seen.values()];
|
|
70093
|
+
}
|
|
70094
|
+
async function buildCollateralLegIxs(ctx, position, isSync, observationBanksOverride) {
|
|
70095
|
+
const { bank, tokenProgram, uiAmount } = position;
|
|
70096
|
+
const tag = bank.config.assetTag;
|
|
70097
|
+
const key = bank.address.toBase58();
|
|
70098
|
+
if (tag === 3 /* KAMINO */) {
|
|
70099
|
+
const reserve = ctx.bankMetadataMap[key]?.kaminoStates?.reserveState;
|
|
70100
|
+
if (!reserve) {
|
|
70101
|
+
throw TransactionBuildingError.transferPositionsInvalidSelection(
|
|
70102
|
+
`kamino reserve state missing for bank ${key} (populate bankMetadataMap.kaminoStates)`,
|
|
70103
|
+
[key]
|
|
70104
|
+
);
|
|
70105
|
+
}
|
|
70106
|
+
const multiplier = ctx.assetShareValueMultiplierByBank.get(key) ?? new BigNumber3.BigNumber(1);
|
|
70107
|
+
const cTokenAmount = uiAmount.div(multiplier);
|
|
70108
|
+
const withdraw2 = await makeKaminoWithdrawIx3({
|
|
70109
|
+
program: ctx.program,
|
|
70110
|
+
bank,
|
|
70111
|
+
bankMap: ctx.bankMap,
|
|
70112
|
+
tokenProgram,
|
|
70113
|
+
cTokenAmount,
|
|
70114
|
+
marginfiAccount: ctx.accountA,
|
|
70115
|
+
authority: ctx.accountA.authority,
|
|
70116
|
+
reserve,
|
|
70117
|
+
bankMetadataMap: ctx.bankMetadataMap,
|
|
70118
|
+
withdrawAll: true,
|
|
70119
|
+
isSync,
|
|
70120
|
+
opts: {
|
|
70121
|
+
createAtas: false,
|
|
70122
|
+
wrapAndUnwrapSol: false,
|
|
70123
|
+
overrideInferAccounts: ctx.overrideInferAccounts,
|
|
70124
|
+
observationBanksOverride
|
|
70125
|
+
}
|
|
70126
|
+
});
|
|
70127
|
+
const deposit2 = await makeKaminoDepositIx3({
|
|
70128
|
+
program: ctx.program,
|
|
70129
|
+
bank,
|
|
70130
|
+
tokenProgram,
|
|
70131
|
+
amount: uiAmount,
|
|
70132
|
+
accountAddress: ctx.accountB.address,
|
|
70133
|
+
authority: ctx.accountA.authority,
|
|
70134
|
+
group: ctx.accountB.group,
|
|
70135
|
+
reserve,
|
|
70136
|
+
isSync,
|
|
70137
|
+
opts: { wrapAndUnwrapSol: false, overrideInferAccounts: ctx.overrideInferAccounts }
|
|
70138
|
+
});
|
|
70139
|
+
return { withdrawIxs: withdraw2.instructions, depositIxs: deposit2.instructions };
|
|
70140
|
+
}
|
|
70141
|
+
if (tag === 6 /* JUPLEND */) {
|
|
70142
|
+
const jupLendingState = ctx.bankMetadataMap[key]?.jupLendStates?.jupLendingState;
|
|
70143
|
+
if (!jupLendingState) {
|
|
70144
|
+
throw TransactionBuildingError.transferPositionsInvalidSelection(
|
|
70145
|
+
`juplend lending state missing for bank ${key} (populate bankMetadataMap.jupLendStates)`,
|
|
70146
|
+
[key]
|
|
70147
|
+
);
|
|
70148
|
+
}
|
|
70149
|
+
const withdraw2 = await makeJuplendWithdrawIx2({
|
|
70150
|
+
program: ctx.program,
|
|
70151
|
+
bank,
|
|
70152
|
+
bankMap: ctx.bankMap,
|
|
70153
|
+
tokenProgram,
|
|
70154
|
+
amount: uiAmount,
|
|
70155
|
+
marginfiAccount: ctx.accountA,
|
|
70156
|
+
authority: ctx.accountA.authority,
|
|
70157
|
+
jupLendingState,
|
|
70158
|
+
bankMetadataMap: ctx.bankMetadataMap,
|
|
70159
|
+
withdrawAll: true,
|
|
70160
|
+
opts: {
|
|
70161
|
+
createAtas: false,
|
|
70162
|
+
wrapAndUnwrapSol: false,
|
|
70163
|
+
overrideInferAccounts: ctx.overrideInferAccounts,
|
|
70164
|
+
observationBanksOverride
|
|
70165
|
+
}
|
|
70166
|
+
});
|
|
70167
|
+
const deposit2 = await makeJuplendDepositIx2({
|
|
70168
|
+
program: ctx.program,
|
|
70169
|
+
bank,
|
|
70170
|
+
tokenProgram,
|
|
70171
|
+
amount: uiAmount,
|
|
70172
|
+
accountAddress: ctx.accountB.address,
|
|
70173
|
+
authority: ctx.accountA.authority,
|
|
70174
|
+
group: ctx.accountB.group,
|
|
70175
|
+
isSync,
|
|
70176
|
+
opts: { wrapAndUnwrapSol: false, overrideInferAccounts: ctx.overrideInferAccounts }
|
|
70177
|
+
});
|
|
70178
|
+
return { withdrawIxs: withdraw2.instructions, depositIxs: deposit2.instructions };
|
|
70179
|
+
}
|
|
70180
|
+
if (tag !== 0 /* DEFAULT */ && tag !== 1 /* SOL */ && tag !== 2 /* STAKED */) {
|
|
70181
|
+
throw TransactionBuildingError.transferPositionsUnsupportedBank(key, tag, bank.tokenSymbol);
|
|
70182
|
+
}
|
|
70183
|
+
const withdraw = await makeWithdrawIx3({
|
|
70184
|
+
program: ctx.program,
|
|
70185
|
+
bank,
|
|
70186
|
+
bankMap: ctx.bankMap,
|
|
70187
|
+
tokenProgram,
|
|
70188
|
+
amount: uiAmount,
|
|
70189
|
+
marginfiAccount: ctx.accountA,
|
|
70190
|
+
authority: ctx.accountA.authority,
|
|
70191
|
+
withdrawAll: true,
|
|
70192
|
+
bankMetadataMap: ctx.bankMetadataMap,
|
|
70193
|
+
isSync,
|
|
70194
|
+
opts: {
|
|
70195
|
+
createAtas: false,
|
|
70196
|
+
wrapAndUnwrapSol: false,
|
|
70197
|
+
overrideInferAccounts: ctx.overrideInferAccounts,
|
|
70198
|
+
observationBanksOverride
|
|
70199
|
+
}
|
|
70200
|
+
});
|
|
70201
|
+
const deposit = await makeDepositIx3({
|
|
70202
|
+
program: ctx.program,
|
|
70203
|
+
bank,
|
|
70204
|
+
tokenProgram,
|
|
70205
|
+
amount: uiAmount,
|
|
70206
|
+
accountAddress: ctx.accountB.address,
|
|
70207
|
+
authority: ctx.accountA.authority,
|
|
70208
|
+
group: ctx.accountB.group,
|
|
70209
|
+
isSync,
|
|
70210
|
+
opts: { wrapAndUnwrapSol: false, overrideInferAccounts: ctx.overrideInferAccounts }
|
|
70211
|
+
});
|
|
70212
|
+
return { withdrawIxs: withdraw.instructions, depositIxs: deposit.instructions };
|
|
70213
|
+
}
|
|
70214
|
+
async function buildInnerIxs(ctx, positions, isSync) {
|
|
70215
|
+
const collateral = positions.filter((p) => p.side === "collateral");
|
|
70216
|
+
const debts = positions.filter((p) => p.side === "debt");
|
|
70217
|
+
const collateralBanks = collateral.map((p) => p.bank);
|
|
70218
|
+
const withdrawIxs = [];
|
|
70219
|
+
const depositIxs = [];
|
|
70220
|
+
const borrowIxs = [];
|
|
70221
|
+
const repayIxs = [];
|
|
70222
|
+
for (const position of collateral) {
|
|
70223
|
+
const observationBanksOverride = ctx.groupRateLimiterEnabled ? computeHealthAccountMetas([], true, [position.bank]) : [];
|
|
70224
|
+
const legs = await buildCollateralLegIxs(ctx, position, isSync, observationBanksOverride);
|
|
70225
|
+
withdrawIxs.push(...legs.withdrawIxs);
|
|
70226
|
+
depositIxs.push(...legs.depositIxs);
|
|
70227
|
+
}
|
|
70228
|
+
const borrowedSoFar = [];
|
|
70229
|
+
for (const position of debts) {
|
|
70230
|
+
const { bank, tokenProgram } = position;
|
|
70231
|
+
borrowedSoFar.push(bank);
|
|
70232
|
+
const activeBanks = dedupeBanks([
|
|
70233
|
+
...ctx.destPreexistingBanks,
|
|
70234
|
+
...collateralBanks,
|
|
70235
|
+
...borrowedSoFar
|
|
70236
|
+
]);
|
|
70237
|
+
const observationBanksOverride = computeHealthAccountMetas(activeBanks);
|
|
70238
|
+
const borrowUi = position.uiAmount.times(1 + ctx.borrowPaddingBps / 1e4);
|
|
70239
|
+
const borrow = await makeBorrowIx3({
|
|
70240
|
+
program: ctx.program,
|
|
70241
|
+
bank,
|
|
70242
|
+
bankMap: ctx.bankMap,
|
|
70243
|
+
tokenProgram,
|
|
70244
|
+
amount: borrowUi,
|
|
70245
|
+
marginfiAccount: ctx.accountB,
|
|
70246
|
+
authority: ctx.accountA.authority,
|
|
70247
|
+
isSync,
|
|
70248
|
+
opts: {
|
|
70249
|
+
createAtas: false,
|
|
70250
|
+
wrapAndUnwrapSol: false,
|
|
70251
|
+
overrideInferAccounts: ctx.overrideInferAccounts,
|
|
70252
|
+
observationBanksOverride
|
|
70253
|
+
}
|
|
70254
|
+
});
|
|
70255
|
+
borrowIxs.push(...borrow.instructions);
|
|
70256
|
+
const repay = await makeRepayIx3({
|
|
70257
|
+
program: ctx.program,
|
|
70258
|
+
bank,
|
|
70259
|
+
tokenProgram,
|
|
70260
|
+
amount: position.uiAmount,
|
|
70261
|
+
accountAddress: ctx.accountA.address,
|
|
70262
|
+
authority: ctx.accountA.authority,
|
|
70263
|
+
repayAll: true,
|
|
70264
|
+
isSync,
|
|
70265
|
+
opts: {
|
|
70266
|
+
wrapAndUnwrapSol: false,
|
|
70267
|
+
overrideInferAccounts: ctx.overrideInferAccounts
|
|
70268
|
+
}
|
|
70269
|
+
});
|
|
70270
|
+
repayIxs.push(...repay.instructions);
|
|
70271
|
+
}
|
|
70272
|
+
return [...CU_IXS(), ...withdrawIxs, ...depositIxs, ...borrowIxs, ...repayIxs];
|
|
70273
|
+
}
|
|
70274
|
+
async function buildTransferFlashloanTx(args) {
|
|
70275
|
+
const { program, accountA, projectedActiveBanksA, innerIxs, preIxs, blockhash, luts } = args;
|
|
70276
|
+
const endIndex = preIxs.length + innerIxs.length + 1;
|
|
70277
|
+
const begin = await makeBeginFlashLoanIx3(program, accountA.address, endIndex, accountA.authority);
|
|
70278
|
+
const end = await makeEndFlashLoanIx3(
|
|
70279
|
+
program,
|
|
70280
|
+
accountA.address,
|
|
70281
|
+
projectedActiveBanksA,
|
|
70282
|
+
accountA.authority
|
|
70283
|
+
);
|
|
70284
|
+
const message = new web3_js.TransactionMessage({
|
|
70285
|
+
payerKey: accountA.authority,
|
|
70286
|
+
recentBlockhash: blockhash,
|
|
70287
|
+
instructions: [...preIxs, ...begin.instructions, ...innerIxs, ...end.instructions]
|
|
70288
|
+
}).compileToV0Message(luts);
|
|
70289
|
+
return addTransactionMetadata(new web3_js.VersionedTransaction(message), {
|
|
70290
|
+
addressLookupTables: luts,
|
|
70291
|
+
type: "FLASHLOAN" /* FLASHLOAN */
|
|
70292
|
+
});
|
|
70293
|
+
}
|
|
70294
|
+
function destPreexistingBanksOf(account, bankMap) {
|
|
70295
|
+
if (!account) return [];
|
|
70296
|
+
return dedupeBanks(
|
|
70297
|
+
account.balances.filter((b) => b.active).map((b) => bankMap.get(b.bankPk.toBase58())).filter((b) => Boolean(b))
|
|
70298
|
+
);
|
|
70299
|
+
}
|
|
70300
|
+
async function makeTransferPositionsTx(params) {
|
|
70301
|
+
const {
|
|
70302
|
+
program,
|
|
70303
|
+
connection,
|
|
70304
|
+
marginfiAccount: accountA,
|
|
70305
|
+
bankMap,
|
|
70306
|
+
bankMetadataMap,
|
|
70307
|
+
oraclePrices,
|
|
70308
|
+
assetShareValueMultiplierByBank,
|
|
70309
|
+
addressLookupTableAccounts,
|
|
70310
|
+
crossbarUrl,
|
|
70311
|
+
overrideInferAccounts
|
|
70312
|
+
} = params;
|
|
70313
|
+
const luts = addressLookupTableAccounts ?? [];
|
|
70314
|
+
const borrowPaddingBps = params.borrowPaddingBps ?? DEFAULT_BORROW_PADDING_BPS;
|
|
70315
|
+
const groupRateLimiterEnabled = params.groupRateLimiterEnabled ?? false;
|
|
70316
|
+
const positions = classifyAndValidate(params);
|
|
70317
|
+
let accountB = params.destinationAccount;
|
|
70318
|
+
let createIx;
|
|
70319
|
+
if (!accountB) {
|
|
70320
|
+
const accountIndex = params.createDestinationOpts?.accountIndex ?? await findRandomAvailableAccountIndex(
|
|
70321
|
+
connection,
|
|
70322
|
+
program.programId,
|
|
70323
|
+
accountA.group,
|
|
70324
|
+
accountA.authority
|
|
70325
|
+
);
|
|
70326
|
+
const created = await makeCreateAccountIxWithProjection({
|
|
70327
|
+
program,
|
|
70328
|
+
authority: accountA.authority,
|
|
70329
|
+
group: accountA.group,
|
|
70330
|
+
accountIndex,
|
|
70331
|
+
thirdPartyId: params.createDestinationOpts?.thirdPartyId
|
|
70332
|
+
});
|
|
70333
|
+
accountB = created.account;
|
|
70334
|
+
createIx = created.ix;
|
|
70335
|
+
}
|
|
70336
|
+
const ctx = {
|
|
70337
|
+
program,
|
|
70338
|
+
accountA,
|
|
70339
|
+
accountB,
|
|
70340
|
+
bankMap,
|
|
70341
|
+
bankMetadataMap,
|
|
70342
|
+
assetShareValueMultiplierByBank,
|
|
70343
|
+
borrowPaddingBps,
|
|
70344
|
+
groupRateLimiterEnabled,
|
|
70345
|
+
overrideInferAccounts,
|
|
70346
|
+
destPreexistingBanks: destPreexistingBanksOf(params.destinationAccount, bankMap)
|
|
70347
|
+
};
|
|
70348
|
+
const innerIxs = await buildInnerIxs(ctx, positions, false);
|
|
70349
|
+
const transferred = new Set(positions.map((p) => p.bankAddress.toBase58()));
|
|
70350
|
+
const projectedActiveBanksA = dedupeBanks(
|
|
70351
|
+
accountA.balances.filter((b) => b.active && !transferred.has(b.bankPk.toBase58())).map((b) => requireBank(bankMap, b.bankPk))
|
|
70352
|
+
);
|
|
70353
|
+
const blockhash = (await connection.getLatestBlockhash("confirmed")).blockhash;
|
|
70354
|
+
const preIxs = createIx ? [createIx] : [];
|
|
70355
|
+
const flashloanTx = await buildTransferFlashloanTx({
|
|
70356
|
+
program,
|
|
70357
|
+
accountA,
|
|
70358
|
+
projectedActiveBanksA,
|
|
70359
|
+
innerIxs,
|
|
70360
|
+
preIxs,
|
|
70361
|
+
blockhash,
|
|
70362
|
+
luts
|
|
70363
|
+
});
|
|
70364
|
+
const size = getTxSize(flashloanTx);
|
|
70365
|
+
const keys = getTotalAccountKeys(flashloanTx);
|
|
70366
|
+
if (size > MAX_TX_SIZE || keys > MAX_ACCOUNT_LOCKS) {
|
|
70367
|
+
throw TransactionBuildingError.transferPositionsUnsplittable(
|
|
70368
|
+
`built transaction exceeds size limits (${size} bytes, ${keys} accounts); transfer fewer positions`,
|
|
70369
|
+
size,
|
|
70370
|
+
keys
|
|
70371
|
+
);
|
|
70372
|
+
}
|
|
70373
|
+
const setupIxs = await makeSetupIx({
|
|
70374
|
+
connection,
|
|
70375
|
+
authority: accountA.authority,
|
|
70376
|
+
tokens: positions.map((p) => ({ mint: p.bank.mint, tokenProgram: p.tokenProgram }))
|
|
70377
|
+
});
|
|
70378
|
+
const refreshIxs = buildIntegrationRefreshIxs({
|
|
70379
|
+
accountA,
|
|
70380
|
+
destinationAccount: params.destinationAccount,
|
|
70381
|
+
positions,
|
|
70382
|
+
bankMap,
|
|
70383
|
+
bankMetadataMap
|
|
70384
|
+
});
|
|
70385
|
+
const additionalTxs = [];
|
|
70386
|
+
const preludeIxs = [...setupIxs, ...refreshIxs];
|
|
70387
|
+
if (preludeIxs.length > 0) {
|
|
70388
|
+
const txs = splitInstructionsToFitTransactions([], preludeIxs, {
|
|
70389
|
+
blockhash,
|
|
70390
|
+
payerKey: accountA.authority,
|
|
70391
|
+
luts
|
|
70392
|
+
});
|
|
70393
|
+
additionalTxs.push(
|
|
70394
|
+
...txs.map(
|
|
70395
|
+
(tx) => addTransactionMetadata(tx, { type: "CREATE_ATA" /* CREATE_ATA */, addressLookupTables: luts })
|
|
70396
|
+
)
|
|
70397
|
+
);
|
|
70398
|
+
}
|
|
70399
|
+
const { instructions: updateFeedIxs, luts: feedLuts } = await makeSmartCrankSwbFeedIx({
|
|
70400
|
+
marginfiAccount: accountA,
|
|
70401
|
+
bankMap,
|
|
70402
|
+
oraclePrices,
|
|
70403
|
+
assetShareValueMultiplierByBank,
|
|
70404
|
+
instructions: innerIxs,
|
|
70405
|
+
program,
|
|
70406
|
+
connection,
|
|
70407
|
+
crossbarUrl
|
|
70408
|
+
});
|
|
70409
|
+
if (updateFeedIxs.length > 0) {
|
|
70410
|
+
const message = new web3_js.TransactionMessage({
|
|
70411
|
+
payerKey: accountA.authority,
|
|
70412
|
+
recentBlockhash: blockhash,
|
|
70413
|
+
instructions: updateFeedIxs
|
|
70414
|
+
}).compileToV0Message(feedLuts);
|
|
70415
|
+
additionalTxs.push(
|
|
70416
|
+
addTransactionMetadata(new web3_js.VersionedTransaction(message), {
|
|
70417
|
+
addressLookupTables: feedLuts,
|
|
70418
|
+
type: "CRANK" /* CRANK */
|
|
70419
|
+
})
|
|
70420
|
+
);
|
|
70421
|
+
}
|
|
70422
|
+
const transactions = [...additionalTxs, flashloanTx];
|
|
70423
|
+
return {
|
|
70424
|
+
transactions,
|
|
70425
|
+
actionTxIndex: additionalTxs.length,
|
|
70426
|
+
destinationAccount: accountB
|
|
70427
|
+
};
|
|
70428
|
+
}
|
|
69887
70429
|
|
|
69888
70430
|
// src/services/account/services/account-simulation.service.ts
|
|
69889
70431
|
async function simulateAccountHealthCacheWithFallback(params) {
|
|
@@ -70293,7 +70835,7 @@ var GROUP_OFFSET = 8;
|
|
|
70293
70835
|
var BALANCES_OFFSET = 72;
|
|
70294
70836
|
var BALANCE_SIZE = 104;
|
|
70295
70837
|
var BANK_PK_OFFSET_IN_BALANCE = 1;
|
|
70296
|
-
var
|
|
70838
|
+
var MAX_BALANCES2 = 16;
|
|
70297
70839
|
var scanBankSlots = async (program, group, bank, options) => {
|
|
70298
70840
|
const connection = program.provider.connection;
|
|
70299
70841
|
const programId = program.programId;
|
|
@@ -70301,7 +70843,7 @@ var scanBankSlots = async (program, group, bank, options) => {
|
|
|
70301
70843
|
const groupBytes = group.toBase58();
|
|
70302
70844
|
const bankBytes = bank.toBase58();
|
|
70303
70845
|
const slotOffsets = Array.from(
|
|
70304
|
-
{ length:
|
|
70846
|
+
{ length: MAX_BALANCES2 },
|
|
70305
70847
|
(_, n) => BALANCES_OFFSET + BANK_PK_OFFSET_IN_BALANCE + n * BALANCE_SIZE
|
|
70306
70848
|
);
|
|
70307
70849
|
const scanSlot = (offset) => {
|
|
@@ -74332,6 +74874,36 @@ var MarginfiAccountWrapper = class {
|
|
|
74332
74874
|
};
|
|
74333
74875
|
return this.account.makeLoopTx(fullParams);
|
|
74334
74876
|
}
|
|
74877
|
+
/**
|
|
74878
|
+
* Atomically move a selected set of positions from this account to a destination account with
|
|
74879
|
+
* auto-injected client data.
|
|
74880
|
+
*
|
|
74881
|
+
* Auto-injects: program, connection, marginfiAccount, bankMap, oraclePrices, bankMetadataMap,
|
|
74882
|
+
* assetShareValueMultiplierByBank, addressLookupTables, tokenProgramsByBank, groupRateLimiterEnabled.
|
|
74883
|
+
*/
|
|
74884
|
+
async makeTransferPositionsTx(params) {
|
|
74885
|
+
const tokenProgramsByBank = /* @__PURE__ */ new Map();
|
|
74886
|
+
for (const bankAddress of params.bankAddresses) {
|
|
74887
|
+
const bank = this.client.bankMap.get(bankAddress.toBase58());
|
|
74888
|
+
if (!bank) throw new Error(`Bank ${bankAddress.toBase58()} not found`);
|
|
74889
|
+
const mintData = await this.getMintDataFromBank(bank);
|
|
74890
|
+
tokenProgramsByBank.set(bankAddress.toBase58(), mintData.tokenProgram);
|
|
74891
|
+
}
|
|
74892
|
+
const fullParams = {
|
|
74893
|
+
...params,
|
|
74894
|
+
program: this.client.program,
|
|
74895
|
+
connection: this.client.program.provider.connection,
|
|
74896
|
+
marginfiAccount: this.account,
|
|
74897
|
+
bankMap: this.client.bankMap,
|
|
74898
|
+
oraclePrices: this.client.oraclePriceByBank,
|
|
74899
|
+
bankMetadataMap: this.client.bankIntegrationMap,
|
|
74900
|
+
assetShareValueMultiplierByBank: this.client.assetShareValueMultiplierByBank,
|
|
74901
|
+
addressLookupTableAccounts: this.client.addressLookupTables,
|
|
74902
|
+
tokenProgramsByBank,
|
|
74903
|
+
groupRateLimiterEnabled: isGroupRateLimiterEnabled(this.client.group.rateLimiter)
|
|
74904
|
+
};
|
|
74905
|
+
return this.account.makeTransferPositionsTx(fullParams);
|
|
74906
|
+
}
|
|
74335
74907
|
/**
|
|
74336
74908
|
* Creates a repay with collateral transaction with auto-injected client data.
|
|
74337
74909
|
*
|
|
@@ -75276,6 +75848,7 @@ exports.bankRateLimiterRawToDto = bankRateLimiterRawToDto;
|
|
|
75276
75848
|
exports.bankRawToDto = bankRawToDto;
|
|
75277
75849
|
exports.bigNumberToWrappedI80F48 = bigNumberToWrappedI80F48;
|
|
75278
75850
|
exports.bpsToPercentile = bpsToPercentile;
|
|
75851
|
+
exports.buildCollateralLegIxs = buildCollateralLegIxs;
|
|
75279
75852
|
exports.calculateApyFromInterest = calculateApyFromInterest;
|
|
75280
75853
|
exports.calculateInterestFromApy = calculateInterestFromApy;
|
|
75281
75854
|
exports.capConfidenceInterval = capConfidenceInterval;
|
|
@@ -75287,6 +75860,7 @@ exports.checkTitanFeeAccount = checkTitanFeeAccount;
|
|
|
75287
75860
|
exports.chunkedGetRawMultipleAccountInfoOrdered = chunkedGetRawMultipleAccountInfoOrdered;
|
|
75288
75861
|
exports.chunkedGetRawMultipleAccountInfoOrderedWithNulls = chunkedGetRawMultipleAccountInfoOrderedWithNulls;
|
|
75289
75862
|
exports.chunkedGetRawMultipleAccountInfos = chunkedGetRawMultipleAccountInfos;
|
|
75863
|
+
exports.classifyAndValidate = classifyAndValidate;
|
|
75290
75864
|
exports.compileFlashloanPrecheck = compileFlashloanPrecheck;
|
|
75291
75865
|
exports.composeBridgedSwap = composeBridgedSwap;
|
|
75292
75866
|
exports.composeRemainingAccounts = composeRemainingAccounts;
|
|
@@ -75521,6 +76095,7 @@ exports.makeSetupIx = makeSetupIx;
|
|
|
75521
76095
|
exports.makeSmartCrankSwbFeedIx = makeSmartCrankSwbFeedIx;
|
|
75522
76096
|
exports.makeSwapCollateralTx = makeSwapCollateralTx;
|
|
75523
76097
|
exports.makeSwapDebtTx = makeSwapDebtTx;
|
|
76098
|
+
exports.makeTransferPositionsTx = makeTransferPositionsTx;
|
|
75524
76099
|
exports.makeTxPriorityIx = makeTxPriorityIx;
|
|
75525
76100
|
exports.makeUnwrapSolIx = makeUnwrapSolIx;
|
|
75526
76101
|
exports.makeUpdateDriftMarketIxs = makeUpdateDriftMarketIxs;
|