@kestrelfi/lyc-sdk 1.0.1 → 1.0.3
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/README.md +32 -0
- package/dist/carry-XU3WUD22.mjs +20 -0
- package/dist/carry-XU3WUD22.mjs.map +1 -0
- package/dist/chunk-2T23QQCX.mjs +3707 -0
- package/dist/chunk-2T23QQCX.mjs.map +1 -0
- package/dist/chunk-GOW6CARW.mjs +3969 -0
- package/dist/chunk-GOW6CARW.mjs.map +1 -0
- package/dist/chunk-ZPXXY3QV.mjs +9330 -0
- package/dist/chunk-ZPXXY3QV.mjs.map +1 -0
- package/dist/{sdks/long-yield-carry/src/idl/long_yield_carry.d.ts → core-DP6wfpME.d.mts} +3242 -84
- package/dist/core-DP6wfpME.d.ts +10485 -0
- package/dist/core.d.mts +8 -0
- package/dist/core.d.ts +8 -0
- package/dist/core.js +12348 -0
- package/dist/core.js.map +1 -0
- package/dist/core.mjs +72 -0
- package/dist/core.mjs.map +1 -0
- package/dist/index.d.mts +2537 -0
- package/dist/index.d.ts +2537 -0
- package/dist/index.js +23884 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +5898 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +56 -10
- package/.env.example +0 -11
- package/dist/sdks/long-yield-carry/scripts/asyncBurn.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/asyncBurn.js +0 -117
- package/dist/sdks/long-yield-carry/scripts/burnToken.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/burnToken.js +0 -98
- package/dist/sdks/long-yield-carry/scripts/claimIncentives.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/claimIncentives.js +0 -108
- package/dist/sdks/long-yield-carry/scripts/closeCpiPlans.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/closeCpiPlans.js +0 -93
- package/dist/sdks/long-yield-carry/scripts/collectInterest.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/collectInterest.js +0 -164
- package/dist/sdks/long-yield-carry/scripts/collectProtocolFees.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/collectProtocolFees.js +0 -120
- package/dist/sdks/long-yield-carry/scripts/computeOptimalAllocations.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/computeOptimalAllocations.js +0 -84
- package/dist/sdks/long-yield-carry/scripts/createToken.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/createToken.js +0 -76
- package/dist/sdks/long-yield-carry/scripts/createTokenLendingPosition.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/createTokenLendingPosition.js +0 -157
- package/dist/sdks/long-yield-carry/scripts/createYieldingBank.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/createYieldingBank.js +0 -69
- package/dist/sdks/long-yield-carry/scripts/decreaseCarryPositions.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/decreaseCarryPositions.js +0 -247
- package/dist/sdks/long-yield-carry/scripts/depositUnlentCollateral.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/depositUnlentCollateral.js +0 -90
- package/dist/sdks/long-yield-carry/scripts/emergency/deleverageAll.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/emergency/deleverageAll.js +0 -202
- package/dist/sdks/long-yield-carry/scripts/emergency/triggerCircuitBreaker.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/emergency/triggerCircuitBreaker.js +0 -68
- package/dist/sdks/long-yield-carry/scripts/env.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/env.js +0 -8
- package/dist/sdks/long-yield-carry/scripts/findTxs.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/findTxs.js +0 -143
- package/dist/sdks/long-yield-carry/scripts/increaseCarryPositions.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/increaseCarryPositions.js +0 -112
- package/dist/sdks/long-yield-carry/scripts/inspect/format.d.ts +0 -13
- package/dist/sdks/long-yield-carry/scripts/inspect/format.js +0 -363
- package/dist/sdks/long-yield-carry/scripts/inspect.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/inspect.js +0 -108
- package/dist/sdks/long-yield-carry/scripts/localUtils.d.ts +0 -53
- package/dist/sdks/long-yield-carry/scripts/localUtils.js +0 -191
- package/dist/sdks/long-yield-carry/scripts/mintToken.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/mintToken.js +0 -103
- package/dist/sdks/long-yield-carry/scripts/processAsyncBurns.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/processAsyncBurns.js +0 -76
- package/dist/sdks/long-yield-carry/scripts/rebalanceToken.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/rebalanceToken.js +0 -210
- package/dist/sdks/long-yield-carry/scripts/rebalanceYieldingBank.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/rebalanceYieldingBank.js +0 -149
- package/dist/sdks/long-yield-carry/scripts/recollateralizeLoss.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/recollateralizeLoss.js +0 -64
- package/dist/sdks/long-yield-carry/scripts/refresh.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/refresh.js +0 -101
- package/dist/sdks/long-yield-carry/scripts/updateFees.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/updateFees.js +0 -369
- package/dist/sdks/long-yield-carry/scripts/updateGeneralLut.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/updateGeneralLut.js +0 -27
- package/dist/sdks/long-yield-carry/scripts/updateLendingPositionConfig.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/updateLendingPositionConfig.js +0 -127
- package/dist/sdks/long-yield-carry/scripts/updateTokenLuts.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/updateTokenLuts.js +0 -27
- package/dist/sdks/long-yield-carry/scripts/updateTokenMetadata.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/updateTokenMetadata.js +0 -194
- package/dist/sdks/long-yield-carry/scripts/updateYieldingBankConfig.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/updateYieldingBankConfig.js +0 -84
- package/dist/sdks/long-yield-carry/scripts/withdrawUnlentCollateral.d.ts +0 -1
- package/dist/sdks/long-yield-carry/scripts/withdrawUnlentCollateral.js +0 -140
- package/dist/sdks/long-yield-carry/src/client/account.d.ts +0 -152
- package/dist/sdks/long-yield-carry/src/client/account.js +0 -349
- package/dist/sdks/long-yield-carry/src/client/builders/args.d.ts +0 -299
- package/dist/sdks/long-yield-carry/src/client/builders/args.js +0 -2
- package/dist/sdks/long-yield-carry/src/client/builders/asyncBurnBuilder.d.ts +0 -20
- package/dist/sdks/long-yield-carry/src/client/builders/asyncBurnBuilder.js +0 -212
- package/dist/sdks/long-yield-carry/src/client/builders/base.d.ts +0 -77
- package/dist/sdks/long-yield-carry/src/client/builders/base.js +0 -191
- package/dist/sdks/long-yield-carry/src/client/builders/burnTokenBuilder.d.ts +0 -18
- package/dist/sdks/long-yield-carry/src/client/builders/burnTokenBuilder.js +0 -165
- package/dist/sdks/long-yield-carry/src/client/builders/claimIncentivesBuilder.d.ts +0 -9
- package/dist/sdks/long-yield-carry/src/client/builders/claimIncentivesBuilder.js +0 -135
- package/dist/sdks/long-yield-carry/src/client/builders/collectFeesBuilder.d.ts +0 -14
- package/dist/sdks/long-yield-carry/src/client/builders/collectFeesBuilder.js +0 -50
- package/dist/sdks/long-yield-carry/src/client/builders/collectInterestBuilder.d.ts +0 -8
- package/dist/sdks/long-yield-carry/src/client/builders/collectInterestBuilder.js +0 -86
- package/dist/sdks/long-yield-carry/src/client/builders/createCpiPlanBuilder.d.ts +0 -6
- package/dist/sdks/long-yield-carry/src/client/builders/createCpiPlanBuilder.js +0 -22
- package/dist/sdks/long-yield-carry/src/client/builders/createTokenBuilder.d.ts +0 -7
- package/dist/sdks/long-yield-carry/src/client/builders/createTokenBuilder.js +0 -64
- package/dist/sdks/long-yield-carry/src/client/builders/createTokenLendingPositionBuilder.d.ts +0 -10
- package/dist/sdks/long-yield-carry/src/client/builders/createTokenLendingPositionBuilder.js +0 -138
- package/dist/sdks/long-yield-carry/src/client/builders/createYieldingBankAllocationBuilder.d.ts +0 -7
- package/dist/sdks/long-yield-carry/src/client/builders/createYieldingBankAllocationBuilder.js +0 -29
- package/dist/sdks/long-yield-carry/src/client/builders/createYieldingBankBuilder.d.ts +0 -7
- package/dist/sdks/long-yield-carry/src/client/builders/createYieldingBankBuilder.js +0 -39
- package/dist/sdks/long-yield-carry/src/client/builders/decreaseCarryPositionBuilder.d.ts +0 -30
- package/dist/sdks/long-yield-carry/src/client/builders/decreaseCarryPositionBuilder.js +0 -99
- package/dist/sdks/long-yield-carry/src/client/builders/depositUnlentCollateralBuilder.d.ts +0 -8
- package/dist/sdks/long-yield-carry/src/client/builders/depositUnlentCollateralBuilder.js +0 -64
- package/dist/sdks/long-yield-carry/src/client/builders/increaseCarryPositionBuilder.d.ts +0 -8
- package/dist/sdks/long-yield-carry/src/client/builders/increaseCarryPositionBuilder.js +0 -73
- package/dist/sdks/long-yield-carry/src/client/builders/index.d.ts +0 -28
- package/dist/sdks/long-yield-carry/src/client/builders/index.js +0 -62
- package/dist/sdks/long-yield-carry/src/client/builders/mintTokenBuilder.d.ts +0 -8
- package/dist/sdks/long-yield-carry/src/client/builders/mintTokenBuilder.js +0 -95
- package/dist/sdks/long-yield-carry/src/client/builders/rebalanceTokenBuilder.d.ts +0 -11
- package/dist/sdks/long-yield-carry/src/client/builders/rebalanceTokenBuilder.js +0 -255
- package/dist/sdks/long-yield-carry/src/client/builders/rebalanceYieldingBankBuilder.d.ts +0 -8
- package/dist/sdks/long-yield-carry/src/client/builders/rebalanceYieldingBankBuilder.js +0 -75
- package/dist/sdks/long-yield-carry/src/client/builders/recollateralizeLossBuilder.d.ts +0 -12
- package/dist/sdks/long-yield-carry/src/client/builders/recollateralizeLossBuilder.js +0 -220
- package/dist/sdks/long-yield-carry/src/client/builders/refreshTokenStateBuilder.d.ts +0 -9
- package/dist/sdks/long-yield-carry/src/client/builders/refreshTokenStateBuilder.js +0 -112
- package/dist/sdks/long-yield-carry/src/client/builders/refreshTokensBuilder.d.ts +0 -9
- package/dist/sdks/long-yield-carry/src/client/builders/refreshTokensBuilder.js +0 -59
- package/dist/sdks/long-yield-carry/src/client/builders/refreshYieldingBankBuilder.d.ts +0 -8
- package/dist/sdks/long-yield-carry/src/client/builders/refreshYieldingBankBuilder.js +0 -29
- package/dist/sdks/long-yield-carry/src/client/builders/resetTokenBurnRateLimitBuilder.d.ts +0 -7
- package/dist/sdks/long-yield-carry/src/client/builders/resetTokenBurnRateLimitBuilder.js +0 -19
- package/dist/sdks/long-yield-carry/src/client/builders/setTokenCircuitBreakerBuilder.d.ts +0 -11
- package/dist/sdks/long-yield-carry/src/client/builders/setTokenCircuitBreakerBuilder.js +0 -31
- package/dist/sdks/long-yield-carry/src/client/builders/setYieldingBankCircuitBreakerBuilder.d.ts +0 -8
- package/dist/sdks/long-yield-carry/src/client/builders/setYieldingBankCircuitBreakerBuilder.js +0 -28
- package/dist/sdks/long-yield-carry/src/client/builders/updateLendingPositionConfigBuilder.d.ts +0 -10
- package/dist/sdks/long-yield-carry/src/client/builders/updateLendingPositionConfigBuilder.js +0 -30
- package/dist/sdks/long-yield-carry/src/client/builders/updateTokenConfigurationBuilder.d.ts +0 -11
- package/dist/sdks/long-yield-carry/src/client/builders/updateTokenConfigurationBuilder.js +0 -47
- package/dist/sdks/long-yield-carry/src/client/builders/updateTokenMetadataBuilder.d.ts +0 -7
- package/dist/sdks/long-yield-carry/src/client/builders/updateTokenMetadataBuilder.js +0 -24
- package/dist/sdks/long-yield-carry/src/client/builders/updateYieldingBankConfigBuilder.d.ts +0 -10
- package/dist/sdks/long-yield-carry/src/client/builders/updateYieldingBankConfigBuilder.js +0 -31
- package/dist/sdks/long-yield-carry/src/client/builders/utils.d.ts +0 -4
- package/dist/sdks/long-yield-carry/src/client/builders/utils.js +0 -20
- package/dist/sdks/long-yield-carry/src/client/client.d.ts +0 -115
- package/dist/sdks/long-yield-carry/src/client/client.js +0 -166
- package/dist/sdks/long-yield-carry/src/client/externalLiquidityResolver.d.ts +0 -13
- package/dist/sdks/long-yield-carry/src/client/externalLiquidityResolver.js +0 -34
- package/dist/sdks/long-yield-carry/src/client/index.d.ts +0 -10
- package/dist/sdks/long-yield-carry/src/client/index.js +0 -33
- package/dist/sdks/long-yield-carry/src/client/lendingPlatformClients.d.ts +0 -19
- package/dist/sdks/long-yield-carry/src/client/lendingPlatformClients.js +0 -33
- package/dist/sdks/long-yield-carry/src/client/pda.d.ts +0 -33
- package/dist/sdks/long-yield-carry/src/client/pda.js +0 -79
- package/dist/sdks/long-yield-carry/src/client/plans/collectInterest.d.ts +0 -24
- package/dist/sdks/long-yield-carry/src/client/plans/collectInterest.js +0 -150
- package/dist/sdks/long-yield-carry/src/client/plans/decreaseCarryPosition.d.ts +0 -12
- package/dist/sdks/long-yield-carry/src/client/plans/decreaseCarryPosition.js +0 -140
- package/dist/sdks/long-yield-carry/src/client/routes/collectInterest.d.ts +0 -13
- package/dist/sdks/long-yield-carry/src/client/routes/collectInterest.js +0 -39
- package/dist/sdks/long-yield-carry/src/client/transaction.d.ts +0 -41
- package/dist/sdks/long-yield-carry/src/client/transaction.js +0 -55
- package/dist/sdks/long-yield-carry/src/client/types/builders.d.ts +0 -18
- package/dist/sdks/long-yield-carry/src/client/types/builders.js +0 -2
- package/dist/sdks/long-yield-carry/src/client/types/enums.d.ts +0 -22
- package/dist/sdks/long-yield-carry/src/client/types/enums.js +0 -48
- package/dist/sdks/long-yield-carry/src/client/types/general.d.ts +0 -98
- package/dist/sdks/long-yield-carry/src/client/types/general.js +0 -2
- package/dist/sdks/long-yield-carry/src/client/types/index.d.ts +0 -6
- package/dist/sdks/long-yield-carry/src/client/types/index.js +0 -22
- package/dist/sdks/long-yield-carry/src/client/types/ix.d.ts +0 -352
- package/dist/sdks/long-yield-carry/src/client/types/ix.js +0 -2
- package/dist/sdks/long-yield-carry/src/client/types/planTypes/collectInterest.d.ts +0 -91
- package/dist/sdks/long-yield-carry/src/client/types/planTypes/collectInterest.js +0 -2
- package/dist/sdks/long-yield-carry/src/client/types/planTypes/common.d.ts +0 -28
- package/dist/sdks/long-yield-carry/src/client/types/planTypes/common.js +0 -2
- package/dist/sdks/long-yield-carry/src/client/types/planTypes/decreaseCarryPosition.d.ts +0 -128
- package/dist/sdks/long-yield-carry/src/client/types/planTypes/decreaseCarryPosition.js +0 -2
- package/dist/sdks/long-yield-carry/src/client/types/planTypes/index.d.ts +0 -3
- package/dist/sdks/long-yield-carry/src/client/types/planTypes/index.js +0 -19
- package/dist/sdks/long-yield-carry/src/client/types/tx.d.ts +0 -339
- package/dist/sdks/long-yield-carry/src/client/types/tx.js +0 -2
- package/dist/sdks/long-yield-carry/src/constants/configs/allocations.d.ts +0 -3
- package/dist/sdks/long-yield-carry/src/constants/configs/allocations.js +0 -23
- package/dist/sdks/long-yield-carry/src/constants/configs/carryTradePresets.d.ts +0 -58
- package/dist/sdks/long-yield-carry/src/constants/configs/carryTradePresets.js +0 -116
- package/dist/sdks/long-yield-carry/src/constants/configs/index.d.ts +0 -2
- package/dist/sdks/long-yield-carry/src/constants/configs/index.js +0 -18
- package/dist/sdks/long-yield-carry/src/constants/general.d.ts +0 -70
- package/dist/sdks/long-yield-carry/src/constants/general.js +0 -107
- package/dist/sdks/long-yield-carry/src/constants/index.d.ts +0 -3
- package/dist/sdks/long-yield-carry/src/constants/index.js +0 -19
- package/dist/sdks/long-yield-carry/src/constants/lycTokenMetadata.d.ts +0 -36
- package/dist/sdks/long-yield-carry/src/constants/lycTokenMetadata.js +0 -41
- package/dist/sdks/long-yield-carry/src/decoders/decodeTransaction.d.ts +0 -86
- package/dist/sdks/long-yield-carry/src/decoders/decodeTransaction.js +0 -230
- package/dist/sdks/long-yield-carry/src/decoders/discriminators.d.ts +0 -8
- package/dist/sdks/long-yield-carry/src/decoders/discriminators.js +0 -11
- package/dist/sdks/long-yield-carry/src/decoders/idlAccounts.d.ts +0 -29
- package/dist/sdks/long-yield-carry/src/decoders/idlAccounts.js +0 -57
- package/dist/sdks/long-yield-carry/src/decoders/index.d.ts +0 -6
- package/dist/sdks/long-yield-carry/src/decoders/index.js +0 -14
- package/dist/sdks/long-yield-carry/src/decoders/innerCpis.d.ts +0 -68
- package/dist/sdks/long-yield-carry/src/decoders/innerCpis.js +0 -225
- package/dist/sdks/long-yield-carry/src/decoders/lycInstructionNames.d.ts +0 -6
- package/dist/sdks/long-yield-carry/src/decoders/lycInstructionNames.js +0 -73
- package/dist/sdks/long-yield-carry/src/decoders/programIds.d.ts +0 -4
- package/dist/sdks/long-yield-carry/src/decoders/programIds.js +0 -11
- package/dist/sdks/long-yield-carry/src/decoders/solana.d.ts +0 -7
- package/dist/sdks/long-yield-carry/src/decoders/solana.js +0 -30
- package/dist/sdks/long-yield-carry/src/decoders/transactionPayload.d.ts +0 -41
- package/dist/sdks/long-yield-carry/src/decoders/transactionPayload.js +0 -6
- package/dist/sdks/long-yield-carry/src/decoders/types.d.ts +0 -58
- package/dist/sdks/long-yield-carry/src/decoders/types.js +0 -2
- package/dist/sdks/long-yield-carry/src/errors.d.ts +0 -69
- package/dist/sdks/long-yield-carry/src/errors.js +0 -183
- package/dist/sdks/long-yield-carry/src/idl/long_yield_carry.js +0 -7323
- package/dist/sdks/long-yield-carry/src/index.d.ts +0 -10
- package/dist/sdks/long-yield-carry/src/index.js +0 -25
- package/dist/sdks/long-yield-carry/src/metrics/index.d.ts +0 -1
- package/dist/sdks/long-yield-carry/src/metrics/index.js +0 -17
- package/dist/sdks/long-yield-carry/src/metrics/protocolMetrics.d.ts +0 -276
- package/dist/sdks/long-yield-carry/src/metrics/protocolMetrics.js +0 -547
- package/dist/sdks/long-yield-carry/src/models/index.d.ts +0 -3
- package/dist/sdks/long-yield-carry/src/models/index.js +0 -7
- package/dist/sdks/long-yield-carry/src/models/lycToken.d.ts +0 -156
- package/dist/sdks/long-yield-carry/src/models/lycToken.js +0 -288
- package/dist/sdks/long-yield-carry/src/models/yieldingBank.d.ts +0 -52
- package/dist/sdks/long-yield-carry/src/models/yieldingBank.js +0 -109
- package/dist/sdks/long-yield-carry/src/services/allocation/allocationService.d.ts +0 -106
- package/dist/sdks/long-yield-carry/src/services/allocation/allocationService.js +0 -589
- package/dist/sdks/long-yield-carry/src/services/allocation/index.d.ts +0 -2
- package/dist/sdks/long-yield-carry/src/services/allocation/index.js +0 -18
- package/dist/sdks/long-yield-carry/src/services/allocation/types.d.ts +0 -25
- package/dist/sdks/long-yield-carry/src/services/allocation/types.js +0 -2
- package/dist/sdks/long-yield-carry/src/services/carry/carryAllocationConfig.d.ts +0 -103
- package/dist/sdks/long-yield-carry/src/services/carry/carryAllocationConfig.js +0 -146
- package/dist/sdks/long-yield-carry/src/services/carry/index.d.ts +0 -2
- package/dist/sdks/long-yield-carry/src/services/carry/index.js +0 -18
- package/dist/sdks/long-yield-carry/src/services/carry/lycLendingPositionManager.d.ts +0 -39
- package/dist/sdks/long-yield-carry/src/services/carry/lycLendingPositionManager.js +0 -100
- package/dist/sdks/long-yield-carry/src/services/index.d.ts +0 -5
- package/dist/sdks/long-yield-carry/src/services/index.js +0 -21
- package/dist/sdks/long-yield-carry/src/services/lendingPosition/index.d.ts +0 -2
- package/dist/sdks/long-yield-carry/src/services/lendingPosition/index.js +0 -5
- package/dist/sdks/long-yield-carry/src/services/lendingPosition/lendingPositionService.d.ts +0 -88
- package/dist/sdks/long-yield-carry/src/services/lendingPosition/lendingPositionService.js +0 -229
- package/dist/sdks/long-yield-carry/src/services/rebalance/index.d.ts +0 -2
- package/dist/sdks/long-yield-carry/src/services/rebalance/index.js +0 -18
- package/dist/sdks/long-yield-carry/src/services/rebalance/token/index.d.ts +0 -1
- package/dist/sdks/long-yield-carry/src/services/rebalance/token/index.js +0 -17
- package/dist/sdks/long-yield-carry/src/services/rebalance/token/tokenRebalanceService.d.ts +0 -51
- package/dist/sdks/long-yield-carry/src/services/rebalance/token/tokenRebalanceService.js +0 -99
- package/dist/sdks/long-yield-carry/src/services/rebalance/yieldingBank/index.d.ts +0 -3
- package/dist/sdks/long-yield-carry/src/services/rebalance/yieldingBank/index.js +0 -21
- package/dist/sdks/long-yield-carry/src/services/rebalance/yieldingBank/planner.d.ts +0 -68
- package/dist/sdks/long-yield-carry/src/services/rebalance/yieldingBank/planner.js +0 -181
- package/dist/sdks/long-yield-carry/src/services/rebalance/yieldingBank/strategy.d.ts +0 -26
- package/dist/sdks/long-yield-carry/src/services/rebalance/yieldingBank/strategy.js +0 -26
- package/dist/sdks/long-yield-carry/src/services/rebalance/yieldingBank/types.d.ts +0 -40
- package/dist/sdks/long-yield-carry/src/services/rebalance/yieldingBank/types.js +0 -2
- package/dist/sdks/long-yield-carry/src/services/redemption/index.d.ts +0 -2
- package/dist/sdks/long-yield-carry/src/services/redemption/index.js +0 -5
- package/dist/sdks/long-yield-carry/src/services/redemption/redemptionService.d.ts +0 -139
- package/dist/sdks/long-yield-carry/src/services/redemption/redemptionService.js +0 -532
- package/dist/sdks/long-yield-carry/src/types/enriched.d.ts +0 -168
- package/dist/sdks/long-yield-carry/src/types/enriched.js +0 -2
- package/dist/sdks/long-yield-carry/src/types/index.d.ts +0 -1
- package/dist/sdks/long-yield-carry/src/types/index.js +0 -17
- package/dist/sdks/long-yield-carry/src/utils/cache.d.ts +0 -4
- package/dist/sdks/long-yield-carry/src/utils/cache.js +0 -10
- package/dist/sdks/long-yield-carry/src/utils/data.d.ts +0 -12
- package/dist/sdks/long-yield-carry/src/utils/data.js +0 -59
- package/dist/sdks/long-yield-carry/src/utils/enrichment.d.ts +0 -5
- package/dist/sdks/long-yield-carry/src/utils/enrichment.js +0 -244
- package/dist/sdks/long-yield-carry/src/utils/feeDripMetrics.d.ts +0 -36
- package/dist/sdks/long-yield-carry/src/utils/feeDripMetrics.js +0 -93
- package/dist/sdks/long-yield-carry/src/utils/general.d.ts +0 -28
- package/dist/sdks/long-yield-carry/src/utils/general.js +0 -47
- package/dist/sdks/long-yield-carry/src/utils/index.d.ts +0 -13
- package/dist/sdks/long-yield-carry/src/utils/index.js +0 -29
- package/dist/sdks/long-yield-carry/src/utils/ix.d.ts +0 -83
- package/dist/sdks/long-yield-carry/src/utils/ix.js +0 -165
- package/dist/sdks/long-yield-carry/src/utils/lendingPosition.d.ts +0 -68
- package/dist/sdks/long-yield-carry/src/utils/lendingPosition.js +0 -105
- package/dist/sdks/long-yield-carry/src/utils/lookupTables.d.ts +0 -55
- package/dist/sdks/long-yield-carry/src/utils/lookupTables.js +0 -216
- package/dist/sdks/long-yield-carry/src/utils/lycData.d.ts +0 -66
- package/dist/sdks/long-yield-carry/src/utils/lycData.js +0 -211
- package/dist/sdks/long-yield-carry/src/utils/timelock.d.ts +0 -19
- package/dist/sdks/long-yield-carry/src/utils/timelock.js +0 -37
- package/dist/sdks/long-yield-carry/src/utils/tokenFeeMath.d.ts +0 -11
- package/dist/sdks/long-yield-carry/src/utils/tokenFeeMath.js +0 -24
- package/dist/sdks/long-yield-carry/src/utils/transactions.d.ts +0 -20
- package/dist/sdks/long-yield-carry/src/utils/transactions.js +0 -72
- package/dist/sdks/long-yield-carry/src/utils/yieldingBank.d.ts +0 -24
- package/dist/sdks/long-yield-carry/src/utils/yieldingBank.js +0 -36
- package/dist/shared/common/src/constants/accountMetas.d.ts +0 -3
- package/dist/shared/common/src/constants/accountMetas.js +0 -9
- package/dist/shared/common/src/constants/general.d.ts +0 -21
- package/dist/shared/common/src/constants/general.js +0 -30
- package/dist/shared/common/src/constants/generated/cpi.d.ts +0 -23
- package/dist/shared/common/src/constants/generated/cpi.js +0 -28
- package/dist/shared/common/src/constants/generated/index.d.ts +0 -1
- package/dist/shared/common/src/constants/generated/index.js +0 -17
- package/dist/shared/common/src/constants/index.d.ts +0 -3
- package/dist/shared/common/src/constants/index.js +0 -19
- package/dist/shared/common/src/index.d.ts +0 -4
- package/dist/shared/common/src/index.js +0 -20
- package/dist/shared/common/src/services/baseAccountClient.d.ts +0 -22
- package/dist/shared/common/src/services/baseAccountClient.js +0 -38
- package/dist/shared/common/src/services/baseIxBuilderService.d.ts +0 -27
- package/dist/shared/common/src/services/baseIxBuilderService.js +0 -48
- package/dist/shared/common/src/services/dataCache.d.ts +0 -41
- package/dist/shared/common/src/services/dataCache.js +0 -130
- package/dist/shared/common/src/services/index.d.ts +0 -8
- package/dist/shared/common/src/services/index.js +0 -24
- package/dist/shared/common/src/services/lutManager.d.ts +0 -31
- package/dist/shared/common/src/services/lutManager.js +0 -133
- package/dist/shared/common/src/services/mints/defaults.d.ts +0 -2
- package/dist/shared/common/src/services/mints/defaults.js +0 -152
- package/dist/shared/common/src/services/mints/index.d.ts +0 -4
- package/dist/shared/common/src/services/mints/index.js +0 -20
- package/dist/shared/common/src/services/mints/registry.d.ts +0 -70
- package/dist/shared/common/src/services/mints/registry.js +0 -117
- package/dist/shared/common/src/services/mints/symbols.d.ts +0 -6
- package/dist/shared/common/src/services/mints/symbols.js +0 -13
- package/dist/shared/common/src/services/mints/types.d.ts +0 -30
- package/dist/shared/common/src/services/mints/types.js +0 -2
- package/dist/shared/common/src/services/swap/index.d.ts +0 -4
- package/dist/shared/common/src/services/swap/index.js +0 -20
- package/dist/shared/common/src/services/swap/routableSwapClient.d.ts +0 -36
- package/dist/shared/common/src/services/swap/routableSwapClient.js +0 -2
- package/dist/shared/common/src/services/swap/swapClientBase.d.ts +0 -45
- package/dist/shared/common/src/services/swap/swapClientBase.js +0 -2
- package/dist/shared/common/src/services/swap/swapRouting.d.ts +0 -13
- package/dist/shared/common/src/services/swap/swapRouting.js +0 -28
- package/dist/shared/common/src/services/swap/types.d.ts +0 -77
- package/dist/shared/common/src/services/swap/types.js +0 -2
- package/dist/shared/common/src/services/token/index.d.ts +0 -2
- package/dist/shared/common/src/services/token/index.js +0 -18
- package/dist/shared/common/src/services/token/tokenProtocolClientBase.d.ts +0 -51
- package/dist/shared/common/src/services/token/tokenProtocolClientBase.js +0 -2
- package/dist/shared/common/src/services/token/types.d.ts +0 -19
- package/dist/shared/common/src/services/token/types.js +0 -2
- package/dist/shared/common/src/services/transactionSender.d.ts +0 -24
- package/dist/shared/common/src/services/transactionSender.js +0 -30
- package/dist/shared/common/src/types/cpi.d.ts +0 -34
- package/dist/shared/common/src/types/cpi.js +0 -8
- package/dist/shared/common/src/types/enums.d.ts +0 -59
- package/dist/shared/common/src/types/enums.js +0 -122
- package/dist/shared/common/src/types/general.d.ts +0 -38
- package/dist/shared/common/src/types/general.js +0 -2
- package/dist/shared/common/src/types/index.d.ts +0 -4
- package/dist/shared/common/src/types/index.js +0 -20
- package/dist/shared/common/src/types/solana.d.ts +0 -24
- package/dist/shared/common/src/types/solana.js +0 -2
- package/dist/shared/common/src/utils/accounts/index.d.ts +0 -5
- package/dist/shared/common/src/utils/accounts/index.js +0 -21
- package/dist/shared/common/src/utils/accounts/meta.d.ts +0 -21
- package/dist/shared/common/src/utils/accounts/meta.js +0 -27
- package/dist/shared/common/src/utils/accounts/pda.d.ts +0 -2
- package/dist/shared/common/src/utils/accounts/pda.js +0 -17
- package/dist/shared/common/src/utils/accounts/roles.d.ts +0 -26
- package/dist/shared/common/src/utils/accounts/roles.js +0 -54
- package/dist/shared/common/src/utils/accounts/rpc.d.ts +0 -8
- package/dist/shared/common/src/utils/accounts/rpc.js +0 -30
- package/dist/shared/common/src/utils/accounts/splBalances.d.ts +0 -15
- package/dist/shared/common/src/utils/accounts/splBalances.js +0 -52
- package/dist/shared/common/src/utils/anchor.d.ts +0 -17
- package/dist/shared/common/src/utils/anchor.js +0 -29
- package/dist/shared/common/src/utils/asyncConcurrency.d.ts +0 -5
- package/dist/shared/common/src/utils/asyncConcurrency.js +0 -28
- package/dist/shared/common/src/utils/compat.d.ts +0 -46
- package/dist/shared/common/src/utils/compat.js +0 -72
- package/dist/shared/common/src/utils/cpi/args.d.ts +0 -69
- package/dist/shared/common/src/utils/cpi/args.js +0 -100
- package/dist/shared/common/src/utils/cpi/index.d.ts +0 -2
- package/dist/shared/common/src/utils/cpi/index.js +0 -18
- package/dist/shared/common/src/utils/cpi/refs.d.ts +0 -122
- package/dist/shared/common/src/utils/cpi/refs.js +0 -234
- package/dist/shared/common/src/utils/data.d.ts +0 -20
- package/dist/shared/common/src/utils/data.js +0 -27
- package/dist/shared/common/src/utils/general.d.ts +0 -24
- package/dist/shared/common/src/utils/general.js +0 -95
- package/dist/shared/common/src/utils/index.d.ts +0 -22
- package/dist/shared/common/src/utils/index.js +0 -38
- package/dist/shared/common/src/utils/instruction.d.ts +0 -74
- package/dist/shared/common/src/utils/instruction.js +0 -147
- package/dist/shared/common/src/utils/jito.d.ts +0 -113
- package/dist/shared/common/src/utils/jito.js +0 -178
- package/dist/shared/common/src/utils/json.d.ts +0 -5
- package/dist/shared/common/src/utils/json.js +0 -25
- package/dist/shared/common/src/utils/jsonRpcFetch.d.ts +0 -21
- package/dist/shared/common/src/utils/jsonRpcFetch.js +0 -134
- package/dist/shared/common/src/utils/metadata.d.ts +0 -107
- package/dist/shared/common/src/utils/metadata.js +0 -194
- package/dist/shared/common/src/utils/numbers.d.ts +0 -72
- package/dist/shared/common/src/utils/numbers.js +0 -193
- package/dist/shared/common/src/utils/priorityFee.d.ts +0 -18
- package/dist/shared/common/src/utils/priorityFee.js +0 -63
- package/dist/shared/common/src/utils/retry.d.ts +0 -20
- package/dist/shared/common/src/utils/retry.js +0 -69
- package/dist/shared/common/src/utils/rpc.d.ts +0 -40
- package/dist/shared/common/src/utils/rpc.js +0 -130
- package/dist/shared/common/src/utils/solana.d.ts +0 -23
- package/dist/shared/common/src/utils/solana.js +0 -61
- package/dist/shared/common/src/utils/timeSeries.d.ts +0 -18
- package/dist/shared/common/src/utils/timeSeries.js +0 -40
- package/dist/shared/common/src/utils/token.d.ts +0 -33
- package/dist/shared/common/src/utils/token.js +0 -82
- package/dist/shared/common/src/utils/transaction.d.ts +0 -154
- package/dist/shared/common/src/utils/transaction.js +0 -585
- package/dist/shared/common/src/utils/transactionSplitter.d.ts +0 -85
- package/dist/shared/common/src/utils/transactionSplitter.js +0 -127
- package/dist/shared/common/src/utils/txAccountCoverage.d.ts +0 -49
- package/dist/shared/common/src/utils/txAccountCoverage.js +0 -122
- package/dist/shared/jupiter-helpers/src/api.d.ts +0 -59
- package/dist/shared/jupiter-helpers/src/api.js +0 -130
- package/dist/shared/jupiter-helpers/src/client.d.ts +0 -79
- package/dist/shared/jupiter-helpers/src/client.js +0 -173
- package/dist/shared/jupiter-helpers/src/constants.d.ts +0 -35
- package/dist/shared/jupiter-helpers/src/constants.js +0 -38
- package/dist/shared/jupiter-helpers/src/extract.d.ts +0 -30
- package/dist/shared/jupiter-helpers/src/extract.js +0 -57
- package/dist/shared/jupiter-helpers/src/index.d.ts +0 -5
- package/dist/shared/jupiter-helpers/src/index.js +0 -21
- package/dist/shared/jupiter-helpers/src/routePreInstructions.d.ts +0 -19
- package/dist/shared/jupiter-helpers/src/routePreInstructions.js +0 -61
- package/dist/shared/jupiter-helpers/src/sizeExactInForMinOutput.d.ts +0 -70
- package/dist/shared/jupiter-helpers/src/sizeExactInForMinOutput.js +0 -95
- package/dist/shared/jupiter-helpers/src/types.d.ts +0 -66
- package/dist/shared/jupiter-helpers/src/types.js +0 -2
- package/dist/shared/lending-platforms/src/constants/cache.d.ts +0 -8
- package/dist/shared/lending-platforms/src/constants/cache.js +0 -11
- package/dist/shared/lending-platforms/src/constants/index.d.ts +0 -3
- package/dist/shared/lending-platforms/src/constants/index.js +0 -19
- package/dist/shared/lending-platforms/src/constants/kamino.d.ts +0 -7
- package/dist/shared/lending-platforms/src/constants/kamino.js +0 -83
- package/dist/shared/lending-platforms/src/constants/lendingPosition.d.ts +0 -7
- package/dist/shared/lending-platforms/src/constants/lendingPosition.js +0 -10
- package/dist/shared/lending-platforms/src/data/accounts/index.d.ts +0 -2
- package/dist/shared/lending-platforms/src/data/accounts/index.js +0 -18
- package/dist/shared/lending-platforms/src/data/accounts/kamino.d.ts +0 -42
- package/dist/shared/lending-platforms/src/data/accounts/kamino.js +0 -104
- package/dist/shared/lending-platforms/src/data/accounts/lpAccountsBase.d.ts +0 -7
- package/dist/shared/lending-platforms/src/data/accounts/lpAccountsBase.js +0 -9
- package/dist/shared/lending-platforms/src/data/incentive/incentiveBase.d.ts +0 -35
- package/dist/shared/lending-platforms/src/data/incentive/incentiveBase.js +0 -26
- package/dist/shared/lending-platforms/src/data/incentive/index.d.ts +0 -2
- package/dist/shared/lending-platforms/src/data/incentive/index.js +0 -18
- package/dist/shared/lending-platforms/src/data/incentive/kamino.d.ts +0 -55
- package/dist/shared/lending-platforms/src/data/incentive/kamino.js +0 -101
- package/dist/shared/lending-platforms/src/data/index.d.ts +0 -6
- package/dist/shared/lending-platforms/src/data/index.js +0 -22
- package/dist/shared/lending-platforms/src/data/instructions/index.d.ts +0 -3
- package/dist/shared/lending-platforms/src/data/instructions/index.js +0 -19
- package/dist/shared/lending-platforms/src/data/instructions/kamino.d.ts +0 -55
- package/dist/shared/lending-platforms/src/data/instructions/kamino.js +0 -630
- package/dist/shared/lending-platforms/src/data/instructions/lpInstructionsBase.d.ts +0 -175
- package/dist/shared/lending-platforms/src/data/instructions/lpInstructionsBase.js +0 -192
- package/dist/shared/lending-platforms/src/data/instructions/types.d.ts +0 -7
- package/dist/shared/lending-platforms/src/data/instructions/types.js +0 -2
- package/dist/shared/lending-platforms/src/data/platform/index.d.ts +0 -2
- package/dist/shared/lending-platforms/src/data/platform/index.js +0 -18
- package/dist/shared/lending-platforms/src/data/platform/kamino.d.ts +0 -59
- package/dist/shared/lending-platforms/src/data/platform/kamino.js +0 -206
- package/dist/shared/lending-platforms/src/data/platform/lpDataBase.d.ts +0 -35
- package/dist/shared/lending-platforms/src/data/platform/lpDataBase.js +0 -31
- package/dist/shared/lending-platforms/src/data/reserve/index.d.ts +0 -2
- package/dist/shared/lending-platforms/src/data/reserve/index.js +0 -18
- package/dist/shared/lending-platforms/src/data/reserve/kamino.d.ts +0 -45
- package/dist/shared/lending-platforms/src/data/reserve/kamino.js +0 -141
- package/dist/shared/lending-platforms/src/data/reserve/reserveBase.d.ts +0 -114
- package/dist/shared/lending-platforms/src/data/reserve/reserveBase.js +0 -125
- package/dist/shared/lending-platforms/src/data/userPosition/index.d.ts +0 -2
- package/dist/shared/lending-platforms/src/data/userPosition/index.js +0 -18
- package/dist/shared/lending-platforms/src/data/userPosition/kamino.d.ts +0 -15
- package/dist/shared/lending-platforms/src/data/userPosition/kamino.js +0 -45
- package/dist/shared/lending-platforms/src/data/userPosition/userPositionBase.d.ts +0 -50
- package/dist/shared/lending-platforms/src/data/userPosition/userPositionBase.js +0 -63
- package/dist/shared/lending-platforms/src/index.d.ts +0 -5
- package/dist/shared/lending-platforms/src/index.js +0 -21
- package/dist/shared/lending-platforms/src/services/client/index.d.ts +0 -2
- package/dist/shared/lending-platforms/src/services/client/index.js +0 -18
- package/dist/shared/lending-platforms/src/services/client/kamino.d.ts +0 -53
- package/dist/shared/lending-platforms/src/services/client/kamino.js +0 -142
- package/dist/shared/lending-platforms/src/services/client/lpClientBase.d.ts +0 -66
- package/dist/shared/lending-platforms/src/services/client/lpClientBase.js +0 -19
- package/dist/shared/lending-platforms/src/services/flashLoan/flashLoanBase.d.ts +0 -49
- package/dist/shared/lending-platforms/src/services/flashLoan/flashLoanBase.js +0 -16
- package/dist/shared/lending-platforms/src/services/flashLoan/index.d.ts +0 -2
- package/dist/shared/lending-platforms/src/services/flashLoan/index.js +0 -18
- package/dist/shared/lending-platforms/src/services/flashLoan/kamino.d.ts +0 -11
- package/dist/shared/lending-platforms/src/services/flashLoan/kamino.js +0 -85
- package/dist/shared/lending-platforms/src/services/index.d.ts +0 -5
- package/dist/shared/lending-platforms/src/services/index.js +0 -21
- package/dist/shared/lending-platforms/src/services/lendingPosition/index.d.ts +0 -2
- package/dist/shared/lending-platforms/src/services/lendingPosition/index.js +0 -18
- package/dist/shared/lending-platforms/src/services/lendingPosition/lendingPositionManager.d.ts +0 -117
- package/dist/shared/lending-platforms/src/services/lendingPosition/lendingPositionManager.js +0 -342
- package/dist/shared/lending-platforms/src/services/lendingPosition/types.d.ts +0 -40
- package/dist/shared/lending-platforms/src/services/lendingPosition/types.js +0 -2
- package/dist/shared/lending-platforms/src/services/leverage/index.d.ts +0 -2
- package/dist/shared/lending-platforms/src/services/leverage/index.js +0 -18
- package/dist/shared/lending-platforms/src/services/leverage/leverageService.d.ts +0 -104
- package/dist/shared/lending-platforms/src/services/leverage/leverageService.js +0 -437
- package/dist/shared/lending-platforms/src/services/leverage/types.d.ts +0 -261
- package/dist/shared/lending-platforms/src/services/leverage/types.js +0 -2
- package/dist/shared/lending-platforms/src/services/reservesManager.d.ts +0 -53
- package/dist/shared/lending-platforms/src/services/reservesManager.js +0 -112
- package/dist/shared/lending-platforms/src/types/general.d.ts +0 -37
- package/dist/shared/lending-platforms/src/types/general.js +0 -8
- package/dist/shared/lending-platforms/src/types/index.d.ts +0 -2
- package/dist/shared/lending-platforms/src/types/index.js +0 -18
- package/dist/shared/lending-platforms/src/types/kamino.d.ts +0 -10
- package/dist/shared/lending-platforms/src/types/kamino.js +0 -2
- package/dist/shared/lending-platforms/src/utils/accounts.d.ts +0 -16
- package/dist/shared/lending-platforms/src/utils/accounts.js +0 -36
- package/dist/shared/lending-platforms/src/utils/cache.d.ts +0 -3
- package/dist/shared/lending-platforms/src/utils/cache.js +0 -11
- package/dist/shared/lending-platforms/src/utils/index.d.ts +0 -6
- package/dist/shared/lending-platforms/src/utils/index.js +0 -22
- package/dist/shared/lending-platforms/src/utils/kamino.d.ts +0 -87
- package/dist/shared/lending-platforms/src/utils/kamino.js +0 -190
- package/dist/shared/lending-platforms/src/utils/lendingPlatform.d.ts +0 -6
- package/dist/shared/lending-platforms/src/utils/lendingPlatform.js +0 -16
- package/dist/shared/lending-platforms/src/utils/math.d.ts +0 -47
- package/dist/shared/lending-platforms/src/utils/math.js +0 -123
- package/dist/shared/lending-platforms/src/utils/scope.d.ts +0 -38
- package/dist/shared/lending-platforms/src/utils/scope.js +0 -144
- package/dist/shared/oracle-service/src/constants/index.d.ts +0 -3
- package/dist/shared/oracle-service/src/constants/index.js +0 -19
- package/dist/shared/oracle-service/src/constants/pyth.d.ts +0 -7
- package/dist/shared/oracle-service/src/constants/pyth.js +0 -71
- package/dist/shared/oracle-service/src/constants/splStake.d.ts +0 -2
- package/dist/shared/oracle-service/src/constants/splStake.js +0 -6
- package/dist/shared/oracle-service/src/constants/switchboard.d.ts +0 -7
- package/dist/shared/oracle-service/src/constants/switchboard.js +0 -10
- package/dist/shared/oracle-service/src/feeds/custom.d.ts +0 -30
- package/dist/shared/oracle-service/src/feeds/custom.js +0 -56
- package/dist/shared/oracle-service/src/feeds/jupiter.d.ts +0 -7
- package/dist/shared/oracle-service/src/feeds/jupiter.js +0 -43
- package/dist/shared/oracle-service/src/feeds/priceBase.d.ts +0 -13
- package/dist/shared/oracle-service/src/feeds/priceBase.js +0 -25
- package/dist/shared/oracle-service/src/feeds/pyth.d.ts +0 -8
- package/dist/shared/oracle-service/src/feeds/pyth.js +0 -59
- package/dist/shared/oracle-service/src/feeds/splStake.d.ts +0 -26
- package/dist/shared/oracle-service/src/feeds/splStake.js +0 -99
- package/dist/shared/oracle-service/src/feeds/switchboard.d.ts +0 -6
- package/dist/shared/oracle-service/src/feeds/switchboard.js +0 -11
- package/dist/shared/oracle-service/src/index.d.ts +0 -5
- package/dist/shared/oracle-service/src/index.js +0 -26
- package/dist/shared/oracle-service/src/oracle.d.ts +0 -22
- package/dist/shared/oracle-service/src/oracle.js +0 -104
- package/dist/shared/oracle-service/src/types.d.ts +0 -4
- package/dist/shared/oracle-service/src/types.js +0 -2
- package/dist/shared/oracle-service/src/utils/general.d.ts +0 -20
- package/dist/shared/oracle-service/src/utils/general.js +0 -65
- package/dist/shared/oracle-service/src/utils/index.d.ts +0 -1
- package/dist/shared/oracle-service/src/utils/index.js +0 -17
- package/dist/shared/perena-helpers/src/accounts.d.ts +0 -7
- package/dist/shared/perena-helpers/src/accounts.js +0 -12
- package/dist/shared/perena-helpers/src/client.d.ts +0 -299
- package/dist/shared/perena-helpers/src/client.js +0 -680
- package/dist/shared/perena-helpers/src/constants.d.ts +0 -5
- package/dist/shared/perena-helpers/src/constants.js +0 -8
- package/dist/shared/perena-helpers/src/cpi/burn.d.ts +0 -27
- package/dist/shared/perena-helpers/src/cpi/burn.js +0 -22
- package/dist/shared/perena-helpers/src/cpi/index.d.ts +0 -3
- package/dist/shared/perena-helpers/src/cpi/index.js +0 -19
- package/dist/shared/perena-helpers/src/cpi/mint.d.ts +0 -27
- package/dist/shared/perena-helpers/src/cpi/mint.js +0 -22
- package/dist/shared/perena-helpers/src/cpi/requestUnstake.d.ts +0 -19
- package/dist/shared/perena-helpers/src/cpi/requestUnstake.js +0 -16
- package/dist/shared/perena-helpers/src/index.d.ts +0 -5
- package/dist/shared/perena-helpers/src/index.js +0 -21
- package/dist/shared/perena-helpers/src/utils.d.ts +0 -9
- package/dist/shared/perena-helpers/src/utils.js +0 -54
- package/dist/shared/swap-aggregator/src/aggSwapClient.d.ts +0 -71
- package/dist/shared/swap-aggregator/src/aggSwapClient.js +0 -103
- package/dist/shared/swap-aggregator/src/index.d.ts +0 -1
- package/dist/shared/swap-aggregator/src/index.js +0 -17
- package/docs/launchingToken.md +0 -57
- package/scripts/asyncBurn.ts +0 -155
- package/scripts/burnToken.ts +0 -120
- package/scripts/claimIncentives.ts +0 -125
- package/scripts/closeCpiPlans.ts +0 -113
- package/scripts/collectInterest.ts +0 -194
- package/scripts/collectProtocolFees.ts +0 -144
- package/scripts/computeOptimalAllocations.ts +0 -117
- package/scripts/createToken.ts +0 -100
- package/scripts/createTokenLendingPosition.ts +0 -204
- package/scripts/createYieldingBank.ts +0 -91
- package/scripts/decreaseCarryPositions.ts +0 -359
- package/scripts/depositUnlentCollateral.ts +0 -106
- package/scripts/emergency/deleverageAll.ts +0 -287
- package/scripts/emergency/triggerCircuitBreaker.ts +0 -87
- package/scripts/env.ts +0 -4
- package/scripts/findTxs.ts +0 -169
- package/scripts/increaseCarryPositions.ts +0 -134
- package/scripts/inspect/format.ts +0 -576
- package/scripts/inspect.ts +0 -147
- package/scripts/localUtils.ts +0 -249
- package/scripts/mintToken.ts +0 -126
- package/scripts/processAsyncBurns.ts +0 -89
- package/scripts/rebalanceToken.ts +0 -269
- package/scripts/rebalanceYieldingBank.ts +0 -183
- package/scripts/recollateralizeLoss.ts +0 -79
- package/scripts/refresh.ts +0 -156
- package/scripts/updateFees.ts +0 -486
- package/scripts/updateGeneralLut.ts +0 -36
- package/scripts/updateLendingPositionConfig.ts +0 -172
- package/scripts/updateTokenLuts.ts +0 -36
- package/scripts/updateTokenMetadata.ts +0 -199
- package/scripts/updateYieldingBankConfig.ts +0 -100
- package/scripts/withdrawUnlentCollateral.ts +0 -178
- package/src/client/account.ts +0 -503
- package/src/client/builders/args.ts +0 -381
- package/src/client/builders/asyncBurnBuilder.ts +0 -305
- package/src/client/builders/base.ts +0 -303
- package/src/client/builders/burnTokenBuilder.ts +0 -258
- package/src/client/builders/claimIncentivesBuilder.ts +0 -211
- package/src/client/builders/collectFeesBuilder.ts +0 -52
- package/src/client/builders/collectInterestBuilder.ts +0 -165
- package/src/client/builders/createCpiPlanBuilder.ts +0 -21
- package/src/client/builders/createTokenBuilder.ts +0 -73
- package/src/client/builders/createTokenLendingPositionBuilder.ts +0 -219
- package/src/client/builders/createYieldingBankAllocationBuilder.ts +0 -32
- package/src/client/builders/createYieldingBankBuilder.ts +0 -39
- package/src/client/builders/decreaseCarryPositionBuilder.ts +0 -162
- package/src/client/builders/depositUnlentCollateralBuilder.ts +0 -95
- package/src/client/builders/increaseCarryPositionBuilder.ts +0 -105
- package/src/client/builders/index.ts +0 -37
- package/src/client/builders/mintTokenBuilder.ts +0 -137
- package/src/client/builders/rebalanceTokenBuilder.ts +0 -356
- package/src/client/builders/rebalanceYieldingBankBuilder.ts +0 -109
- package/src/client/builders/recollateralizeLossBuilder.ts +0 -367
- package/src/client/builders/refreshTokenStateBuilder.ts +0 -153
- package/src/client/builders/refreshTokensBuilder.ts +0 -82
- package/src/client/builders/refreshYieldingBankBuilder.ts +0 -42
- package/src/client/builders/resetTokenBurnRateLimitBuilder.ts +0 -21
- package/src/client/builders/setTokenCircuitBreakerBuilder.ts +0 -40
- package/src/client/builders/setYieldingBankCircuitBreakerBuilder.ts +0 -37
- package/src/client/builders/updateLendingPositionConfigBuilder.ts +0 -33
- package/src/client/builders/updateTokenConfigurationBuilder.ts +0 -50
- package/src/client/builders/updateTokenMetadataBuilder.ts +0 -24
- package/src/client/builders/updateYieldingBankConfigBuilder.ts +0 -32
- package/src/client/builders/utils.ts +0 -26
- package/src/client/client.ts +0 -264
- package/src/client/externalLiquidityResolver.ts +0 -54
- package/src/client/index.ts +0 -20
- package/src/client/lendingPlatformClients.ts +0 -50
- package/src/client/pda.ts +0 -102
- package/src/client/plans/collectInterest.ts +0 -207
- package/src/client/plans/decreaseCarryPosition.ts +0 -226
- package/src/client/routes/collectInterest.ts +0 -56
- package/src/client/transaction.ts +0 -106
- package/src/client/types/builders.ts +0 -19
- package/src/client/types/enums.ts +0 -47
- package/src/client/types/general.ts +0 -117
- package/src/client/types/index.ts +0 -6
- package/src/client/types/ix.ts +0 -452
- package/src/client/types/planTypes/collectInterest.ts +0 -97
- package/src/client/types/planTypes/common.ts +0 -31
- package/src/client/types/planTypes/decreaseCarryPosition.ts +0 -134
- package/src/client/types/planTypes/index.ts +0 -3
- package/src/client/types/tx.ts +0 -409
- package/src/constants/configs/allocations.ts +0 -30
- package/src/constants/configs/carryTradePresets.ts +0 -164
- package/src/constants/configs/index.ts +0 -2
- package/src/constants/general.ts +0 -141
- package/src/constants/index.ts +0 -3
- package/src/constants/lycTokenMetadata.ts +0 -52
- package/src/decoders/decodeTransaction.ts +0 -319
- package/src/decoders/discriminators.ts +0 -10
- package/src/decoders/idlAccounts.ts +0 -75
- package/src/decoders/index.ts +0 -15
- package/src/decoders/innerCpis.ts +0 -262
- package/src/decoders/lycInstructionNames.ts +0 -73
- package/src/decoders/programIds.ts +0 -12
- package/src/decoders/solana.ts +0 -25
- package/src/decoders/transactionPayload.ts +0 -41
- package/src/decoders/types.ts +0 -60
- package/src/errors.ts +0 -195
- package/src/idl/long_yield_carry.ts +0 -14648
- package/src/index.ts +0 -10
- package/src/metrics/index.ts +0 -1
- package/src/metrics/protocolMetrics.ts +0 -976
- package/src/models/index.ts +0 -9
- package/src/models/lycToken.ts +0 -380
- package/src/models/yieldingBank.ts +0 -127
- package/src/services/allocation/allocationService.ts +0 -823
- package/src/services/allocation/index.ts +0 -2
- package/src/services/allocation/types.ts +0 -27
- package/src/services/carry/carryAllocationConfig.ts +0 -266
- package/src/services/carry/index.ts +0 -2
- package/src/services/carry/lycLendingPositionManager.ts +0 -167
- package/src/services/index.ts +0 -5
- package/src/services/lendingPosition/index.ts +0 -5
- package/src/services/lendingPosition/lendingPositionService.ts +0 -328
- package/src/services/rebalance/index.ts +0 -2
- package/src/services/rebalance/token/index.ts +0 -1
- package/src/services/rebalance/token/tokenRebalanceService.ts +0 -142
- package/src/services/rebalance/yieldingBank/index.ts +0 -3
- package/src/services/rebalance/yieldingBank/planner.ts +0 -215
- package/src/services/rebalance/yieldingBank/strategy.ts +0 -41
- package/src/services/rebalance/yieldingBank/types.ts +0 -41
- package/src/services/redemption/index.ts +0 -9
- package/src/services/redemption/redemptionService.ts +0 -758
- package/src/types/enriched.ts +0 -187
- package/src/types/index.ts +0 -1
- package/src/utils/cache.ts +0 -12
- package/src/utils/data.ts +0 -65
- package/src/utils/enrichment.ts +0 -330
- package/src/utils/feeDripMetrics.ts +0 -146
- package/src/utils/general.ts +0 -54
- package/src/utils/index.ts +0 -13
- package/src/utils/ix.ts +0 -227
- package/src/utils/lendingPosition.ts +0 -221
- package/src/utils/lookupTables.ts +0 -309
- package/src/utils/lycData.ts +0 -321
- package/src/utils/timelock.ts +0 -63
- package/src/utils/tokenFeeMath.ts +0 -25
- package/src/utils/transactions.ts +0 -109
- package/src/utils/yieldingBank.ts +0 -38
- package/tsconfig.json +0 -11
|
@@ -0,0 +1,3969 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CpiTypes,
|
|
3
|
+
DAYS_PER_YEAR,
|
|
4
|
+
DEFAULT_PUBLIC_KEY,
|
|
5
|
+
DataCache,
|
|
6
|
+
ENVIRONMENT,
|
|
7
|
+
IX_SYSVAR_META,
|
|
8
|
+
LOCALNET_URL,
|
|
9
|
+
PRICE_STALENESS_SECONDS,
|
|
10
|
+
RENT_SYSVAR_META,
|
|
11
|
+
SYSTEM_PROGRAM_META,
|
|
12
|
+
U64_MAX_BN,
|
|
13
|
+
accountExists,
|
|
14
|
+
applyFeeCeil,
|
|
15
|
+
createRpcWithFailover,
|
|
16
|
+
createSignerFromAddress,
|
|
17
|
+
currentUnixSeconds,
|
|
18
|
+
dedupeOrderedAddresses,
|
|
19
|
+
fetchWithRetry,
|
|
20
|
+
fromUiAmount,
|
|
21
|
+
fromWeb3Pk,
|
|
22
|
+
getAtaAddress,
|
|
23
|
+
getCreateAtaIxIfNeeded,
|
|
24
|
+
getRpcUrl,
|
|
25
|
+
getSlot,
|
|
26
|
+
mints,
|
|
27
|
+
numToU64Bytes,
|
|
28
|
+
oracle,
|
|
29
|
+
sum,
|
|
30
|
+
toCustomAccountMeta,
|
|
31
|
+
toUiAmount
|
|
32
|
+
} from "./chunk-2T23QQCX.mjs";
|
|
33
|
+
|
|
34
|
+
// ../../shared/lending-platforms/src/services/client/kamino.ts
|
|
35
|
+
import { Obligation } from "@kamino-finance/klend-sdk";
|
|
36
|
+
|
|
37
|
+
// ../../shared/lending-platforms/src/services/client/lpClientBase.ts
|
|
38
|
+
var LendingPlatformClientBase = class {
|
|
39
|
+
constructor(rpcUrl, rpcUrls = [rpcUrl]) {
|
|
40
|
+
this.rpc = createRpcWithFailover(rpcUrls);
|
|
41
|
+
}
|
|
42
|
+
applyPostSuccessCacheInvalidations(invalidations) {
|
|
43
|
+
this.ix.applyPostSuccessCacheInvalidations(invalidations);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// ../../shared/lending-platforms/src/data/platform/kamino.ts
|
|
48
|
+
import {
|
|
49
|
+
KaminoMarket,
|
|
50
|
+
DEFAULT_RECENT_SLOT_DURATION_MS,
|
|
51
|
+
PROGRAM_ID as PROGRAM_ID2,
|
|
52
|
+
DEFAULT_PUBLIC_KEY as DEFAULT_PUBLIC_KEY2
|
|
53
|
+
} from "@kamino-finance/klend-sdk";
|
|
54
|
+
import { Scope as Scope2 } from "@kamino-finance/scope-sdk";
|
|
55
|
+
import { Farms } from "@kamino-finance/farms-sdk";
|
|
56
|
+
|
|
57
|
+
// ../../shared/lending-platforms/src/constants/cache.ts
|
|
58
|
+
var LENDING_PLATFORM_DATA_CACHE_CATEGORY_POOL = "pool";
|
|
59
|
+
var LENDING_PLATFORM_DATA_CACHE_CATEGORY_RESERVE = "reserve";
|
|
60
|
+
var LENDING_PLATFORM_DATA_CACHE_CATEGORY_USER_ACCOUNT = "userAccount";
|
|
61
|
+
|
|
62
|
+
// ../../shared/lending-platforms/src/data/platform/lpDataBase.ts
|
|
63
|
+
var LendingPlatformData = class {
|
|
64
|
+
constructor(rpcUrl, cacheTtlConfig, rpcUrls = [rpcUrl]) {
|
|
65
|
+
this.poolCatKey = LENDING_PLATFORM_DATA_CACHE_CATEGORY_POOL;
|
|
66
|
+
this.reserveCatKey = LENDING_PLATFORM_DATA_CACHE_CATEGORY_RESERVE;
|
|
67
|
+
this.userAccountCatKey = LENDING_PLATFORM_DATA_CACHE_CATEGORY_USER_ACCOUNT;
|
|
68
|
+
this.rpc = createRpcWithFailover(rpcUrls);
|
|
69
|
+
this.cache = new DataCache(cacheTtlConfig);
|
|
70
|
+
}
|
|
71
|
+
clearCache() {
|
|
72
|
+
this.cache.clearAllCache();
|
|
73
|
+
}
|
|
74
|
+
clearCacheEntry(category, id) {
|
|
75
|
+
this.cache.clearCacheEntry(category, id);
|
|
76
|
+
}
|
|
77
|
+
/** Returns the current slot, cached to reduce RPC calls */
|
|
78
|
+
async getSlot() {
|
|
79
|
+
const { data } = await this.cache.getDataOrThrow(
|
|
80
|
+
async () => await getSlot(this.rpc),
|
|
81
|
+
"slot",
|
|
82
|
+
"slot"
|
|
83
|
+
);
|
|
84
|
+
return data;
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// ../../shared/lending-platforms/src/constants/kamino.ts
|
|
89
|
+
import { address } from "@solana/kit";
|
|
90
|
+
var KAMINO_FARMS_PROGRAM_ID = address("FarmsPZpWu9i7Kky8tPN37rs2TpmMrAZrC7S7vJa91Hr");
|
|
91
|
+
var KAMINO_SCOPE_PROGRAM_ID = address("HFn8GnPADiny6XqUoWE8uRPPxb29ikn4yTuPa9MF2fWJ");
|
|
92
|
+
var KAMINO_MAIN_MARKET = address("7u3HeHxYDLhnCoErrtycNokbQYbWGzLs6JSDqGAv5PfF");
|
|
93
|
+
var SOL_RESERVE = address("d4A2prbA2whesmvHaL88BH6Ewn5N4bTSU2Ze8P6Bc4Q");
|
|
94
|
+
var USDC_RESERVE = address("D6q6wuQSrifJKZYpR1M8R4YawnLDtDsMmWM1NbBmgJ59");
|
|
95
|
+
var KAMINO_ACCOUNTS = {
|
|
96
|
+
[KAMINO_MAIN_MARKET]: [
|
|
97
|
+
{
|
|
98
|
+
address: SOL_RESERVE,
|
|
99
|
+
mintSymbol: "SOL"
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
address: address("37Jk2zkz23vkAYBT66HM2gaqJuNg2nYLsCreQAVt5MWK"),
|
|
103
|
+
mintSymbol: "cbBTC"
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
address: address("febGYTnFX4GbSGoFHFeJXUHgNaK53fB23uDins9Jp1E"),
|
|
107
|
+
mintSymbol: "wETH"
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
address: address("DGQZWCY17gGtBUgdaFs1VreJWsodkjFxndPsskwFKGpp"),
|
|
111
|
+
mintSymbol: "JupSOL"
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
address: address("CkgQnPbuHHwSv2mNdAKH79TKSqC6jsyttK9yh4MPH6z3"),
|
|
115
|
+
mintSymbol: "dfdvSOL"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
address: USDC_RESERVE,
|
|
119
|
+
mintSymbol: "USDC"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
address: address("2gc9Dm1eB6UgVYFBUN9bWks6Kes9PbWSaPaa9DqyvEiN"),
|
|
123
|
+
mintSymbol: "PYUSD"
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
address: address("ApQkX32ULJUzszZDe986aobLDLMNDoGQK8tRm6oD6SsA"),
|
|
127
|
+
mintSymbol: "CASH"
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
address: address("ESCkPWKHmgNE7Msf77n9yzqJd5kQVWWGy3o5Mgxhvavp"),
|
|
131
|
+
mintSymbol: "USDG"
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
address: address("BHUi32TrEsfN2U821G4FprKrR4hTeK4LCWtA3BFetuqA"),
|
|
135
|
+
mintSymbol: "USDS"
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
address: address("H3t6qZ1JkguCNTi9uzVKqQ7dvt2cum4XiXWom6Gn5e5S"),
|
|
139
|
+
mintSymbol: "USDT"
|
|
140
|
+
}
|
|
141
|
+
],
|
|
142
|
+
/// xStocks Market
|
|
143
|
+
[address("5wJeMrUYECGq41fxRESKALVcHnNX26TAWy4W98yULsua")]: [
|
|
144
|
+
{
|
|
145
|
+
address: address("2jerdAXR8r2B6z3P7P6VgSiePQX7wqcpbEqdDbm8mgeB"),
|
|
146
|
+
mintSymbol: "QQQx"
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
address: address("UvXjBuC7YZYaGB9Rn1PpBD1GySmjzunXgE8Zev9ua8d"),
|
|
150
|
+
mintSymbol: "SPYx"
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
address: address("97zoywd8mPZsGTg8q1wdD2Wgkdrs2tqusp1Qqcxbyj7E"),
|
|
154
|
+
mintSymbol: "USDC"
|
|
155
|
+
}
|
|
156
|
+
]
|
|
157
|
+
// Bitcoin Market
|
|
158
|
+
// [address("GMqmFygF5iSm5nkckYU6tieggFcR42SyjkkhK5rswFRs")]: [
|
|
159
|
+
// {
|
|
160
|
+
// address: address("2Xd86oYAuhiKtQMVJBuWvJYxrSippreb46PmehGszpPQ"),
|
|
161
|
+
// mintSymbol: "wBTC"
|
|
162
|
+
// },
|
|
163
|
+
// {
|
|
164
|
+
// address: address("9FRZvAsjDJ6WM8BJ2S45h9PoDCLAq8DNY9zZDX7MyGzT"),
|
|
165
|
+
// mintSymbol: "USDC"
|
|
166
|
+
// }
|
|
167
|
+
// ]
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
// ../../shared/lending-platforms/src/constants/lendingPosition.ts
|
|
171
|
+
var MAX_LENDING_POSITION_UPPER_UTIL_BPS = 10500;
|
|
172
|
+
|
|
173
|
+
// ../../shared/lending-platforms/src/utils/accounts.ts
|
|
174
|
+
function getEligiblePools(mintSymbol) {
|
|
175
|
+
const needle = mintSymbol.toUpperCase();
|
|
176
|
+
const pools = [];
|
|
177
|
+
for (const pool of Object.keys(KAMINO_ACCOUNTS)) {
|
|
178
|
+
const reserves = KAMINO_ACCOUNTS[pool];
|
|
179
|
+
if (reserves.some((r) => r.mintSymbol.toUpperCase() === needle)) {
|
|
180
|
+
pools.push(pool);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return pools;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// ../../shared/lending-platforms/src/utils/cache.ts
|
|
187
|
+
function getLendingUserAccountCacheInvalidation(userAccount) {
|
|
188
|
+
return {
|
|
189
|
+
client: "kamino",
|
|
190
|
+
category: LENDING_PLATFORM_DATA_CACHE_CATEGORY_USER_ACCOUNT,
|
|
191
|
+
id: userAccount
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// ../../shared/lending-platforms/src/utils/kamino.ts
|
|
196
|
+
import {
|
|
197
|
+
calculateCurrentRewardPerToken,
|
|
198
|
+
SECONDS_IN_A_DAY
|
|
199
|
+
} from "@kamino-finance/farms-sdk";
|
|
200
|
+
import { BN } from "@anchor-lang/core";
|
|
201
|
+
import { LendingMarket, PROGRAM_ID } from "@kamino-finance/klend-sdk";
|
|
202
|
+
import Decimal from "decimal.js";
|
|
203
|
+
async function fetchExtraFarms() {
|
|
204
|
+
const cdnRes = await fetchWithRetry("https://cdn.kamino.finance/resources.json");
|
|
205
|
+
const allResources = await cdnRes.json();
|
|
206
|
+
return allResources["mainnet-beta"]["extraFarms"];
|
|
207
|
+
}
|
|
208
|
+
function calculateRewardAPY(reserveMint, rewardInfo, totalStakedRaw, stakedTokenDecimals, exchangeRate, rewardMintPrice, requiresPairReserve) {
|
|
209
|
+
let totalStaked = new Decimal(toUiAmount(BigInt(totalStakedRaw), stakedTokenDecimals));
|
|
210
|
+
if (!requiresPairReserve) {
|
|
211
|
+
totalStaked = totalStaked.div(exchangeRate);
|
|
212
|
+
}
|
|
213
|
+
if (totalStaked.isZero()) return 0;
|
|
214
|
+
const rewardPerTokenPerSecond = calculateCurrentRewardPerToken(
|
|
215
|
+
rewardInfo,
|
|
216
|
+
new Decimal(currentUnixSeconds())
|
|
217
|
+
);
|
|
218
|
+
if (!rewardPerTokenPerSecond) return 0;
|
|
219
|
+
const divisor = new Decimal(10).pow(new Decimal(rewardInfo.rewardsPerSecondDecimals.toString())).mul(new Decimal(10).pow(new Decimal(rewardInfo.token.decimals.toString())));
|
|
220
|
+
const adjustedRewardPerToken = new Decimal(rewardPerTokenPerSecond).div(divisor);
|
|
221
|
+
let dailyRewards = adjustedRewardPerToken.mul(SECONDS_IN_A_DAY);
|
|
222
|
+
if (mints.get(rewardInfo.token.mint)?.assetType !== "Stablecoin" && rewardInfo.token.mint !== reserveMint) {
|
|
223
|
+
dailyRewards = dailyRewards.mul(new Decimal(rewardMintPrice));
|
|
224
|
+
}
|
|
225
|
+
const dailyRate = dailyRewards.div(totalStaked);
|
|
226
|
+
const apy = Decimal.pow(dailyRate.plus(1), DAYS_PER_YEAR).minus(1);
|
|
227
|
+
return apy.toNumber();
|
|
228
|
+
}
|
|
229
|
+
function liquidityToCollateral(reserveData, liquidityBaseUnits) {
|
|
230
|
+
const exchangeRate = reserveData.rawData.getEstimatedCollateralExchangeRate(reserveData.slot, 0).toNumber();
|
|
231
|
+
return Math.floor(liquidityBaseUnits * exchangeRate);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// ../../shared/lending-platforms/src/utils/math.ts
|
|
235
|
+
function clampUnitInterval(x) {
|
|
236
|
+
if (x <= 0) return 0;
|
|
237
|
+
if (x >= 1) return 1;
|
|
238
|
+
return x;
|
|
239
|
+
}
|
|
240
|
+
function assertLtv(ltv) {
|
|
241
|
+
if (!(ltv > 0) || ltv > 1) {
|
|
242
|
+
throw new RangeError("ltv must be in (0, 1] (e.g. 0.8 for 80% max LTV)");
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
function assertLiquidationThreshold(t) {
|
|
246
|
+
if (!(t > 0) || t > 1) {
|
|
247
|
+
throw new RangeError("liquidationThreshold must be in (0, 1] (e.g. 0.85)");
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
function maxLtvUtilBeforeCollUsdMultiplierInternal(params) {
|
|
251
|
+
const {
|
|
252
|
+
collateralUsdMultiplier: mult,
|
|
253
|
+
ltv,
|
|
254
|
+
liquidationThreshold,
|
|
255
|
+
targetMaxBorrowUtilizationAfter = 1
|
|
256
|
+
} = params;
|
|
257
|
+
assertLtv(ltv);
|
|
258
|
+
if (!(mult > 0)) {
|
|
259
|
+
throw new RangeError("collateralUsdMultiplier must be positive");
|
|
260
|
+
}
|
|
261
|
+
if (liquidationThreshold !== void 0) {
|
|
262
|
+
assertLiquidationThreshold(liquidationThreshold);
|
|
263
|
+
return clampUnitInterval(mult * liquidationThreshold / ltv);
|
|
264
|
+
}
|
|
265
|
+
if (!(targetMaxBorrowUtilizationAfter > 0) || targetMaxBorrowUtilizationAfter > 1) {
|
|
266
|
+
throw new RangeError(
|
|
267
|
+
"targetMaxBorrowUtilizationAfter must be in (0, 1] (1 = 100% of borrow limit)"
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
return clampUnitInterval(mult * targetMaxBorrowUtilizationAfter);
|
|
271
|
+
}
|
|
272
|
+
function maxLtvUtilBeforeCollDrawdown(params) {
|
|
273
|
+
if (!(params.drawdownPercent >= 0)) {
|
|
274
|
+
throw new RangeError("drawdownPercent must be non-negative (e.g. 30 for a 30% drop)");
|
|
275
|
+
}
|
|
276
|
+
const collateralUsdMultiplier = 1 - params.drawdownPercent / 100;
|
|
277
|
+
if (!(collateralUsdMultiplier > 0)) {
|
|
278
|
+
throw new RangeError(
|
|
279
|
+
"drawdownPercent must be less than 100 so collateral USD remains positive"
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
return maxLtvUtilBeforeCollUsdMultiplierInternal({
|
|
283
|
+
collateralUsdMultiplier,
|
|
284
|
+
ltv: params.ltv,
|
|
285
|
+
targetMaxBorrowUtilizationAfter: params.targetMaxBorrowUtilizationAfter,
|
|
286
|
+
liquidationThreshold: params.liquidationThreshold
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
function ltvUtilAfterCollateralPricePctChg(currentLtvUtilization, collateralPricePctChg) {
|
|
290
|
+
if (!(currentLtvUtilization >= 0) || currentLtvUtilization > 1) {
|
|
291
|
+
throw new RangeError("currentLtvUtilization must be in [0, 1]");
|
|
292
|
+
}
|
|
293
|
+
const mult = 1 + collateralPricePctChg / 100;
|
|
294
|
+
if (!(mult > 0)) {
|
|
295
|
+
throw new RangeError(
|
|
296
|
+
"collateralPricePctChg must be greater than -100 so collateral USD stays positive"
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
return currentLtvUtilization / mult;
|
|
300
|
+
}
|
|
301
|
+
function ltvUtilDeltaBelowTargForRallyPct(targetLtvUtilization, rallyPercentPositive) {
|
|
302
|
+
if (!(targetLtvUtilization > 0) || targetLtvUtilization > 1) {
|
|
303
|
+
throw new RangeError("targetLtvUtilization must be in (0, 1]");
|
|
304
|
+
}
|
|
305
|
+
if (!Number.isFinite(rallyPercentPositive) || rallyPercentPositive <= 0) {
|
|
306
|
+
throw new RangeError("rallyPercentPositive must be finite and positive");
|
|
307
|
+
}
|
|
308
|
+
const after = ltvUtilAfterCollateralPricePctChg(targetLtvUtilization, rallyPercentPositive);
|
|
309
|
+
return targetLtvUtilization - after;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// ../../shared/lending-platforms/src/utils/scope.ts
|
|
313
|
+
import { Scope } from "@kamino-finance/scope-sdk";
|
|
314
|
+
var ORACLE_TYPE_MOST_RECENT_OF = 28;
|
|
315
|
+
var ORACLE_TYPE_CAPPED_FLOORED = 33;
|
|
316
|
+
var MOST_RECENT_OF_UNUSED = 512;
|
|
317
|
+
function collectTokenDependencies(token, mappings, result, depth = 0) {
|
|
318
|
+
if (result.has(token) || depth > 5) return;
|
|
319
|
+
const isValidDep = (dep2) => dep2 !== void 0 && dep2 !== token && dep2 < mappings.priceInfoAccounts.length && mappings.priceInfoAccounts[dep2] !== DEFAULT_PUBLIC_KEY;
|
|
320
|
+
const recurse = (dep2) => collectTokenDependencies(dep2, mappings, result, depth + 1);
|
|
321
|
+
if (mappings.priceTypes[token] === ORACLE_TYPE_MOST_RECENT_OF) {
|
|
322
|
+
const raw = mappings.generic[token];
|
|
323
|
+
if (raw?.length >= 8) {
|
|
324
|
+
for (let i = 0; i < 4; i++) {
|
|
325
|
+
const src = raw[i * 2] | raw[i * 2 + 1] << 8;
|
|
326
|
+
if (src !== MOST_RECENT_OF_UNUSED && isValidDep(src)) {
|
|
327
|
+
recurse(src);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
} else if (mappings.priceTypes[token] === ORACLE_TYPE_CAPPED_FLOORED) {
|
|
332
|
+
const raw = mappings.generic[token];
|
|
333
|
+
if (raw?.length >= 7) {
|
|
334
|
+
const sourceEntry = raw[0] | raw[1] << 8;
|
|
335
|
+
if (isValidDep(sourceEntry)) recurse(sourceEntry);
|
|
336
|
+
if (raw[2] === 1) {
|
|
337
|
+
const capEntry = raw[3] | raw[4] << 8;
|
|
338
|
+
if (isValidDep(capEntry)) recurse(capEntry);
|
|
339
|
+
}
|
|
340
|
+
const floorOffset = raw[2] === 1 ? 5 : 3;
|
|
341
|
+
if (raw[floorOffset] === 1) {
|
|
342
|
+
const floorEntry = raw[floorOffset + 1] | raw[floorOffset + 2] << 8;
|
|
343
|
+
if (isValidDep(floorEntry)) recurse(floorEntry);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
const dep = mappings.refPrice[token];
|
|
348
|
+
if (isValidDep(dep)) {
|
|
349
|
+
recurse(dep);
|
|
350
|
+
}
|
|
351
|
+
result.add(token);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// ../../shared/lending-platforms/src/data/platform/kamino.ts
|
|
355
|
+
import Decimal2 from "decimal.js";
|
|
356
|
+
var KaminoData = class extends LendingPlatformData {
|
|
357
|
+
constructor(rpcUrl, cacheConfig, rpcUrls = [rpcUrl]) {
|
|
358
|
+
const ttlConfig = {
|
|
359
|
+
defaultTtlMs: 9e4,
|
|
360
|
+
categoryTtlMs: {
|
|
361
|
+
...cacheConfig?.categoryTtlMs,
|
|
362
|
+
markets: 6e4 * 5,
|
|
363
|
+
farms: 6e4 * 5,
|
|
364
|
+
extraFarms: Number.MAX_SAFE_INTEGER,
|
|
365
|
+
scopeOraclePrices: 3e4,
|
|
366
|
+
scopeConfig: 6e4 * 5
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
super(rpcUrl, ttlConfig, rpcUrls);
|
|
370
|
+
this.farms = new Farms(this.rpc, KAMINO_FARMS_PROGRAM_ID);
|
|
371
|
+
this.scope = new Scope2("mainnet-beta", this.rpc);
|
|
372
|
+
}
|
|
373
|
+
platform() {
|
|
374
|
+
return 0 /* Kamino */;
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Warms the market cache for the requested pools. Single-pool calls reuse the
|
|
378
|
+
* normal lazy fetch path; multi-pool calls use Kamino's batched loader.
|
|
379
|
+
*/
|
|
380
|
+
async load(pools) {
|
|
381
|
+
if (pools.length === 0) return;
|
|
382
|
+
if (pools.length === 1) {
|
|
383
|
+
await this.fetchMarket(pools[0]);
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
const { data: markets, fromCache } = await this.cache.getDataBatch(
|
|
387
|
+
async () => {
|
|
388
|
+
const marketsData = await KaminoMarket.loadMultiple(
|
|
389
|
+
this.rpc,
|
|
390
|
+
pools,
|
|
391
|
+
DEFAULT_RECENT_SLOT_DURATION_MS,
|
|
392
|
+
PROGRAM_ID2,
|
|
393
|
+
true
|
|
394
|
+
);
|
|
395
|
+
return pools.map((pool) => marketsData.get(pool) ?? null);
|
|
396
|
+
},
|
|
397
|
+
this.poolCatKey,
|
|
398
|
+
pools
|
|
399
|
+
);
|
|
400
|
+
if (!fromCache) {
|
|
401
|
+
await Promise.all(markets.map(async (market) => await market.loadReserves()));
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
/** Fetches a market by address, loading from cache if available */
|
|
405
|
+
async fetchMarket(market) {
|
|
406
|
+
const { data, fromCache } = await this.cache.getDataOrThrow(
|
|
407
|
+
async () => await KaminoMarket.load(
|
|
408
|
+
this.rpc,
|
|
409
|
+
market,
|
|
410
|
+
DEFAULT_RECENT_SLOT_DURATION_MS,
|
|
411
|
+
PROGRAM_ID2,
|
|
412
|
+
true
|
|
413
|
+
),
|
|
414
|
+
this.poolCatKey,
|
|
415
|
+
market
|
|
416
|
+
);
|
|
417
|
+
if (!fromCache) {
|
|
418
|
+
await data.loadReserves();
|
|
419
|
+
}
|
|
420
|
+
return data;
|
|
421
|
+
}
|
|
422
|
+
/** Fetches all oracle prices for assets in the specified market */
|
|
423
|
+
async fetchPrices(pool) {
|
|
424
|
+
const market = await this.fetchMarket(pool);
|
|
425
|
+
const { data } = await this.cache.getDataOrThrow(
|
|
426
|
+
async () => await market.getAllPrices(),
|
|
427
|
+
"prices",
|
|
428
|
+
"queryAll"
|
|
429
|
+
);
|
|
430
|
+
return data;
|
|
431
|
+
}
|
|
432
|
+
/** Fetches an obligation (user position) by address */
|
|
433
|
+
async fetchObligation(market, obligation) {
|
|
434
|
+
const { data } = await this.cache.getData(
|
|
435
|
+
async () => await market.getObligationByAddress(obligation),
|
|
436
|
+
this.userAccountCatKey,
|
|
437
|
+
obligation,
|
|
438
|
+
{ cacheNull: false }
|
|
439
|
+
);
|
|
440
|
+
return data;
|
|
441
|
+
}
|
|
442
|
+
/** Batch fetches farm states by their addresses */
|
|
443
|
+
async fetchFarms(farms) {
|
|
444
|
+
const { data } = await this.cache.getDataBatch(
|
|
445
|
+
async () => (await this.farms.getAllFarmStatesByPubkeys(farms)).map((x) => x.farmState),
|
|
446
|
+
"userFarms",
|
|
447
|
+
farms
|
|
448
|
+
);
|
|
449
|
+
return data;
|
|
450
|
+
}
|
|
451
|
+
async fetchExtraFarms() {
|
|
452
|
+
const { data } = await this.cache.getDataOrThrow(
|
|
453
|
+
async () => await fetchExtraFarms(),
|
|
454
|
+
"extraFarms",
|
|
455
|
+
"mainnet-beta"
|
|
456
|
+
);
|
|
457
|
+
return data;
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Collects all farm incentives for a reserve, including both standard
|
|
461
|
+
* collateral/debt farms and extra paired farms from Kamino CDN config.
|
|
462
|
+
*/
|
|
463
|
+
async fetchFarmsForReserve(pool, reserve) {
|
|
464
|
+
const market = await this.fetchMarket(pool);
|
|
465
|
+
const reserveData = market.getReserveByAddress(reserve);
|
|
466
|
+
if (!reserveData) {
|
|
467
|
+
throw new Error(`Unable to find reserve ${reserve}`);
|
|
468
|
+
}
|
|
469
|
+
const farms = [];
|
|
470
|
+
const farmCollateral = reserveData.state.farmCollateral;
|
|
471
|
+
const farmDebt = reserveData.state.farmDebt;
|
|
472
|
+
if (farmCollateral && farmCollateral !== DEFAULT_PUBLIC_KEY2) {
|
|
473
|
+
farms.push({ address: farmCollateral, isDebtFarm: false });
|
|
474
|
+
}
|
|
475
|
+
if (farmDebt && farmDebt !== DEFAULT_PUBLIC_KEY2) {
|
|
476
|
+
farms.push({ address: farmDebt, isDebtFarm: true });
|
|
477
|
+
}
|
|
478
|
+
const extraFarmsData = (await this.fetchExtraFarms()).filter(
|
|
479
|
+
(x) => x.collReserve === reserve || x.debtReserve === reserve
|
|
480
|
+
);
|
|
481
|
+
const extraFarmEntries = extraFarmsData.map((x) => ({
|
|
482
|
+
address: x.farm,
|
|
483
|
+
isDebtFarm: x.debtReserve === reserve
|
|
484
|
+
}));
|
|
485
|
+
const allFarmEntries = [...farms, ...extraFarmEntries];
|
|
486
|
+
const allFarmAddresses = allFarmEntries.map((f) => f.address);
|
|
487
|
+
if (!allFarmAddresses.length) {
|
|
488
|
+
return [];
|
|
489
|
+
}
|
|
490
|
+
const farmStates = await this.fetchFarms(allFarmAddresses);
|
|
491
|
+
const result = [];
|
|
492
|
+
farmStates.forEach((farmState, i) => {
|
|
493
|
+
const farmEntry = allFarmEntries[i];
|
|
494
|
+
const isExtraFarm = i >= farms.length;
|
|
495
|
+
const extraFarmIndex = i - farms.length;
|
|
496
|
+
farmState.rewardInfos.forEach((rewardInfo, rewardIndex) => {
|
|
497
|
+
if (rewardInfo.rewardsVault === DEFAULT_PUBLIC_KEY2) {
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
result.push({
|
|
501
|
+
data: {
|
|
502
|
+
key: farmEntry.address,
|
|
503
|
+
farmState
|
|
504
|
+
},
|
|
505
|
+
rewardIndex,
|
|
506
|
+
requiresPairReserve: isExtraFarm ? extraFarmsData[extraFarmIndex].debtReserve : void 0,
|
|
507
|
+
isDebtFarm: farmEntry.isDebtFarm
|
|
508
|
+
});
|
|
509
|
+
});
|
|
510
|
+
});
|
|
511
|
+
return result;
|
|
512
|
+
}
|
|
513
|
+
async fetchUserActiveIncentives(user, specificFarm) {
|
|
514
|
+
let { data } = await this.cache.getDataOrThrow(
|
|
515
|
+
async () => {
|
|
516
|
+
return Array.from(
|
|
517
|
+
(await this.farms.getAllFarmsForUserMultiState(user, new Decimal2(currentUnixSeconds()))).values()
|
|
518
|
+
).flat();
|
|
519
|
+
},
|
|
520
|
+
"userFarms",
|
|
521
|
+
user
|
|
522
|
+
);
|
|
523
|
+
if (specificFarm) {
|
|
524
|
+
data = data.filter((x) => x.farm === specificFarm);
|
|
525
|
+
}
|
|
526
|
+
return data;
|
|
527
|
+
}
|
|
528
|
+
async maybeFetchUserPositionInPool(pool, userPosition) {
|
|
529
|
+
const market = await this.fetchMarket(pool);
|
|
530
|
+
const obligation = await this.fetchObligation(market, userPosition);
|
|
531
|
+
return obligation ? KaminoUserPositionData.loadData(obligation) : null;
|
|
532
|
+
}
|
|
533
|
+
async fetchUserPositionsInPool(pool, userPositions) {
|
|
534
|
+
const market = await this.fetchMarket(pool);
|
|
535
|
+
const { data } = await this.cache.getDataBatch(
|
|
536
|
+
async () => await market.getMultipleObligationsByAddress(userPositions),
|
|
537
|
+
this.userAccountCatKey,
|
|
538
|
+
userPositions
|
|
539
|
+
);
|
|
540
|
+
return data.map((obligation) => KaminoUserPositionData.loadData(obligation));
|
|
541
|
+
}
|
|
542
|
+
async fetchAllUserPositionsForUserInPool(pool, user) {
|
|
543
|
+
const market = await this.fetchMarket(pool);
|
|
544
|
+
const { data } = await this.cache.getDataOrThrow(
|
|
545
|
+
async () => await market.getAllUserObligations(user, "confirmed"),
|
|
546
|
+
"obligationsBatch",
|
|
547
|
+
user
|
|
548
|
+
);
|
|
549
|
+
return data.map((obligation) => KaminoUserPositionData.loadData(obligation));
|
|
550
|
+
}
|
|
551
|
+
async fetchReserve(pool, reserve) {
|
|
552
|
+
const market = await this.fetchMarket(pool);
|
|
553
|
+
const reserveData = market.getReserveByAddress(reserve);
|
|
554
|
+
if (!reserveData) {
|
|
555
|
+
throw new Error(`Unable to find reserve ${reserve}`);
|
|
556
|
+
}
|
|
557
|
+
return this.mapReserve(market, reserveData);
|
|
558
|
+
}
|
|
559
|
+
async fetchReserveByMint(pool, mint) {
|
|
560
|
+
const market = await this.fetchMarket(pool);
|
|
561
|
+
const reserveData = market.getReserveByMint(mint);
|
|
562
|
+
if (!reserveData) {
|
|
563
|
+
throw new Error(`Unable to find reserve by mint ${mint}`);
|
|
564
|
+
}
|
|
565
|
+
return this.mapReserve(market, reserveData);
|
|
566
|
+
}
|
|
567
|
+
async mapReserve(market, reserve) {
|
|
568
|
+
return KaminoReserveData.loadData(
|
|
569
|
+
market,
|
|
570
|
+
reserve,
|
|
571
|
+
await this.fetchFarmsForReserve(market.address, reserve.address),
|
|
572
|
+
await this.fetchPrices(market.address),
|
|
573
|
+
await this.getSlot()
|
|
574
|
+
);
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* Fetches and caches the Scope OraclePrices account for a given price feed.
|
|
578
|
+
* @returns The deserialized OraclePrices, or null if the account doesn't exist
|
|
579
|
+
*/
|
|
580
|
+
async fetchScopeOraclePrices(priceFeed) {
|
|
581
|
+
const { data } = await this.cache.getData(
|
|
582
|
+
async () => await this.scope.getSingleOraclePrices({ prices: priceFeed }),
|
|
583
|
+
"scopeOraclePrices",
|
|
584
|
+
priceFeed
|
|
585
|
+
);
|
|
586
|
+
return data;
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* Resolves and caches the Scope Configuration account address for a given OraclePrices account.
|
|
590
|
+
* The first call per price feed does a getProgramAccounts lookup; subsequent calls use cache.
|
|
591
|
+
*/
|
|
592
|
+
async fetchScopeConfigAddress(priceFeed) {
|
|
593
|
+
const { data } = await this.cache.getDataOrThrow(
|
|
594
|
+
async () => {
|
|
595
|
+
const [configAddr] = await this.scope.getSingleFeedConfiguration({
|
|
596
|
+
prices: priceFeed
|
|
597
|
+
});
|
|
598
|
+
return configAddr;
|
|
599
|
+
},
|
|
600
|
+
"scopeConfig",
|
|
601
|
+
priceFeed
|
|
602
|
+
);
|
|
603
|
+
return data;
|
|
604
|
+
}
|
|
605
|
+
};
|
|
606
|
+
|
|
607
|
+
// ../../shared/lending-platforms/src/data/reserve/kamino.ts
|
|
608
|
+
import {
|
|
609
|
+
isNotNullPubkey
|
|
610
|
+
} from "@kamino-finance/klend-sdk";
|
|
611
|
+
import Decimal4 from "decimal.js";
|
|
612
|
+
|
|
613
|
+
// ../../shared/lending-platforms/src/data/incentive/incentiveBase.ts
|
|
614
|
+
var TokenIncentiveBase = class {
|
|
615
|
+
constructor(address4, config) {
|
|
616
|
+
this.address = address4;
|
|
617
|
+
this.config = config;
|
|
618
|
+
}
|
|
619
|
+
};
|
|
620
|
+
|
|
621
|
+
// ../../shared/lending-platforms/src/data/incentive/kamino.ts
|
|
622
|
+
import Decimal3 from "decimal.js";
|
|
623
|
+
import { BN as BN2 } from "@anchor-lang/core";
|
|
624
|
+
import {
|
|
625
|
+
calculateCurrentRewardPerToken as calculateCurrentRewardPerToken2
|
|
626
|
+
} from "@kamino-finance/farms-sdk";
|
|
627
|
+
var KaminoIncentiveData = class _KaminoIncentiveData extends TokenIncentiveBase {
|
|
628
|
+
/**
|
|
629
|
+
* Creates a KaminoIncentiveData instance from farm and reserve data.
|
|
630
|
+
* Determines the incentive type and calculates current exchange rates.
|
|
631
|
+
*/
|
|
632
|
+
static loadData(args, reserve, prices, slot) {
|
|
633
|
+
const {
|
|
634
|
+
data: { key, farmState },
|
|
635
|
+
rewardIndex,
|
|
636
|
+
requiresPairReserve,
|
|
637
|
+
isDebtFarm
|
|
638
|
+
} = args;
|
|
639
|
+
const rewardInfo = farmState.rewardInfos[rewardIndex];
|
|
640
|
+
const data = new _KaminoIncentiveData(key, {
|
|
641
|
+
rewardMint: rewardInfo.token.mint,
|
|
642
|
+
incentiveType: isDebtFarm ? "Borrowing" /* BorrowingOnly */ : requiresPairReserve ? "Pair" /* Pair */ : "Lending" /* LendingOnly */,
|
|
643
|
+
requiresPairReserve
|
|
644
|
+
});
|
|
645
|
+
data.rawReserve = reserve;
|
|
646
|
+
data.rawFarm = farmState;
|
|
647
|
+
data.rewardInfo = farmState.rewardInfos[rewardIndex];
|
|
648
|
+
data.isDebtFarm = isDebtFarm;
|
|
649
|
+
const collateralExchangeRate = reserve.getEstimatedCollateralExchangeRate(slot, 0).toNumber();
|
|
650
|
+
const debtExchangeRate = reserve.getEstimatedCumulativeBorrowRate(slot, 0).toNumber();
|
|
651
|
+
data.exchangeRate = isDebtFarm ? debtExchangeRate : collateralExchangeRate;
|
|
652
|
+
const rewardMint = rewardInfo.token.mint;
|
|
653
|
+
const scope = prices.scope.spot[rewardMint];
|
|
654
|
+
const pyth = prices.pyth.spot[rewardMint];
|
|
655
|
+
const swb = prices.switchboard.spot[rewardMint];
|
|
656
|
+
data.rewardMintPrice = scope ? scope.price.toNumber() : pyth ? pyth.price.toNumber() : swb ? swb.price.toNumber() : 0;
|
|
657
|
+
return data;
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* Checks if the incentive is currently active.
|
|
661
|
+
* An incentive is active if rewards are available, the schedule has started,
|
|
662
|
+
* and there is a non-zero emission rate.
|
|
663
|
+
*/
|
|
664
|
+
active() {
|
|
665
|
+
const rewardsAvailable = this.rewardInfo.rewardsAvailable.gtn(0);
|
|
666
|
+
const hasStarted = this.rewardInfo.rewardScheduleCurve.points[0].tsStart.toNumber() < currentUnixSeconds();
|
|
667
|
+
const rewardPerTokenPerSecond = calculateCurrentRewardPerToken2(
|
|
668
|
+
this.rewardInfo,
|
|
669
|
+
new Decimal3(currentUnixSeconds())
|
|
670
|
+
);
|
|
671
|
+
return rewardsAvailable && hasStarted && rewardPerTokenPerSecond > 0;
|
|
672
|
+
}
|
|
673
|
+
/** Calculates the current APY based on total staked amount and reward emission rate */
|
|
674
|
+
apy() {
|
|
675
|
+
const { totalStaked, stakedTokenDecimals } = this.getStakedTokenData();
|
|
676
|
+
return calculateRewardAPY(
|
|
677
|
+
this.rawReserve.getLiquidityMint(),
|
|
678
|
+
this.rewardInfo,
|
|
679
|
+
totalStaked.toString(),
|
|
680
|
+
stakedTokenDecimals,
|
|
681
|
+
this.exchangeRate,
|
|
682
|
+
this.rewardMintPrice,
|
|
683
|
+
Boolean(this.config.requiresPairReserve)
|
|
684
|
+
);
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* Simulates the APY after a hypothetical position change.
|
|
688
|
+
* Useful for calculating expected rewards before executing a transaction.
|
|
689
|
+
*/
|
|
690
|
+
simulateNewAPY(args) {
|
|
691
|
+
const changeInUnderlying = this.isDebtFarm ? args.debtChange ?? 0 : args.collateralChange ?? 0;
|
|
692
|
+
if (changeInUnderlying === 0) {
|
|
693
|
+
return this.apy();
|
|
694
|
+
}
|
|
695
|
+
const { totalStaked, stakedTokenDecimals } = this.getStakedTokenData();
|
|
696
|
+
const changeInShares = changeInUnderlying / this.exchangeRate;
|
|
697
|
+
const changeInSharesRaw = new BN2(
|
|
698
|
+
Math.round(changeInShares * Math.pow(10, stakedTokenDecimals))
|
|
699
|
+
);
|
|
700
|
+
const newTotalStakedRaw = new BN2(totalStaked.toString()).add(changeInSharesRaw);
|
|
701
|
+
return calculateRewardAPY(
|
|
702
|
+
this.rawReserve.getLiquidityMint(),
|
|
703
|
+
this.rewardInfo,
|
|
704
|
+
newTotalStakedRaw.toString(),
|
|
705
|
+
stakedTokenDecimals,
|
|
706
|
+
this.exchangeRate,
|
|
707
|
+
this.rewardMintPrice,
|
|
708
|
+
Boolean(this.config.requiresPairReserve)
|
|
709
|
+
);
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* Returns staking metrics for APY calculation.
|
|
713
|
+
* Falls back to reserve decimals if farm token decimals are not set.
|
|
714
|
+
*/
|
|
715
|
+
getStakedTokenData() {
|
|
716
|
+
return {
|
|
717
|
+
totalStaked: this.rawFarm.totalStakedAmount,
|
|
718
|
+
stakedTokenDecimals: this.rawFarm.token.decimals.toNumber() || (this.config.requiresPairReserve ? 6 : this.rawReserve.getMintDecimals())
|
|
719
|
+
};
|
|
720
|
+
}
|
|
721
|
+
};
|
|
722
|
+
|
|
723
|
+
// ../../shared/lending-platforms/src/data/reserve/reserveBase.ts
|
|
724
|
+
var ReserveBase = class {
|
|
725
|
+
constructor(address4, mint, config, deposits, borrows, state, incentives) {
|
|
726
|
+
this.address = address4;
|
|
727
|
+
this.mint = mint;
|
|
728
|
+
this.config = config;
|
|
729
|
+
this.deposits = deposits;
|
|
730
|
+
this.borrows = borrows;
|
|
731
|
+
this.state = state;
|
|
732
|
+
this.incentives = incentives;
|
|
733
|
+
this.createdAt = Date.now();
|
|
734
|
+
}
|
|
735
|
+
normalizeLtvPct(ltvPct) {
|
|
736
|
+
return ltvPct <= 1 ? ltvPct : ltvPct / 100;
|
|
737
|
+
}
|
|
738
|
+
/** Returns the cached price, or undefined if stale */
|
|
739
|
+
get mintPrice() {
|
|
740
|
+
if (this.mint.price === void 0) {
|
|
741
|
+
return void 0;
|
|
742
|
+
}
|
|
743
|
+
const ageMs = Date.now() - this.createdAt;
|
|
744
|
+
if (ageMs > PRICE_STALENESS_SECONDS * 1e3) {
|
|
745
|
+
return void 0;
|
|
746
|
+
}
|
|
747
|
+
return this.mint.price;
|
|
748
|
+
}
|
|
749
|
+
/** Returns the cached EMA price, or undefined if stale/missing */
|
|
750
|
+
get mintEmaPrice() {
|
|
751
|
+
if (this.mint.emaPrice === void 0) {
|
|
752
|
+
return void 0;
|
|
753
|
+
}
|
|
754
|
+
const ageMs = Date.now() - this.createdAt;
|
|
755
|
+
if (ageMs > PRICE_STALENESS_SECONDS * 1e3) {
|
|
756
|
+
return void 0;
|
|
757
|
+
}
|
|
758
|
+
return this.mint.emaPrice;
|
|
759
|
+
}
|
|
760
|
+
/**
|
|
761
|
+
* Returns the reserve LTV in decimal form, where `0.5 = 50%`.
|
|
762
|
+
*/
|
|
763
|
+
get ltvPct() {
|
|
764
|
+
return this.normalizeLtvPct(this.config.ltvPct);
|
|
765
|
+
}
|
|
766
|
+
/**
|
|
767
|
+
* Returns e-mode configs with `ltvPct` normalized to decimal form, where
|
|
768
|
+
* `0.5 = 50%`.
|
|
769
|
+
*/
|
|
770
|
+
get emodes() {
|
|
771
|
+
return this.config.emodes?.map((emode) => ({
|
|
772
|
+
...emode,
|
|
773
|
+
ltvPct: this.normalizeLtvPct(emode.ltvPct)
|
|
774
|
+
}));
|
|
775
|
+
}
|
|
776
|
+
utilizationRatePct() {
|
|
777
|
+
return this.state.utilizationRatePct;
|
|
778
|
+
}
|
|
779
|
+
/** Returns borrowable liquidity, accounting for both available balance and borrow limits, in UI amount (e.g. 1.234) */
|
|
780
|
+
liquidityAvailable() {
|
|
781
|
+
return Math.min(this.state.availableLiquidity, this.borrows.limit - this.borrows.totalAmount);
|
|
782
|
+
}
|
|
783
|
+
/**
|
|
784
|
+
* Returns the total supply APY including base rate and eligible supply-side
|
|
785
|
+
* incentives (types `LendingOnly` and `Pair`). Borrow-side incentives are
|
|
786
|
+
* excluded here — they reward borrowers, not lenders.
|
|
787
|
+
* @param usingDebtReserve - When specified, includes paired incentives requiring this debt reserve
|
|
788
|
+
*/
|
|
789
|
+
supplyAPY(usingDebtReserve) {
|
|
790
|
+
return this.deposits.apy + this.sumEligibleIncentivesAPY("supply", usingDebtReserve);
|
|
791
|
+
}
|
|
792
|
+
/**
|
|
793
|
+
* Returns the effective borrow APY (base rate minus eligible borrow-side
|
|
794
|
+
* incentive rebates, i.e. `BorrowingOnly`). Lender-side incentives are
|
|
795
|
+
* excluded — they are paid to lenders and do not offset borrower cost.
|
|
796
|
+
* @param usingSupplyReserve - When specified, includes paired incentives requiring this collateral
|
|
797
|
+
*/
|
|
798
|
+
borrowAPY(usingSupplyReserve) {
|
|
799
|
+
return this.borrows.apy - this.sumEligibleIncentivesAPY("borrow", usingSupplyReserve);
|
|
800
|
+
}
|
|
801
|
+
/** Sums APY from incentives eligible for the given side and paired reserve */
|
|
802
|
+
sumEligibleIncentivesAPY(side, usingPairReserve) {
|
|
803
|
+
return sum(this.getEligibleIncentives(side, usingPairReserve).map((x) => x.apy()));
|
|
804
|
+
}
|
|
805
|
+
/** Sums the new simulated APY from incentives eligible for the given side and paired reserve */
|
|
806
|
+
simulateNewEligbleIncentivesAPY(args, side, usingPairReserve) {
|
|
807
|
+
return sum(
|
|
808
|
+
this.getEligibleIncentives(side, usingPairReserve).map((x) => x.simulateNewAPY(args))
|
|
809
|
+
);
|
|
810
|
+
}
|
|
811
|
+
/**
|
|
812
|
+
* Filters incentives eligible for the given side (supply vs borrow) and
|
|
813
|
+
* paired reserve.
|
|
814
|
+
*
|
|
815
|
+
* Side filter:
|
|
816
|
+
* - `supply`: `LendingOnly` and `Pair` (collateral-farm incentives,
|
|
817
|
+
* optionally gated on a specific debt reserve).
|
|
818
|
+
* - `borrow`: `BorrowingOnly` (debt-farm incentives, optionally gated on a
|
|
819
|
+
* specific collateral reserve via `requiresPairReserve`).
|
|
820
|
+
*
|
|
821
|
+
* Pair filter: incentives with `requiresPairReserve` only apply when that
|
|
822
|
+
* reserve matches the caller's pair.
|
|
823
|
+
*/
|
|
824
|
+
getEligibleIncentives(side, usingPairReserve) {
|
|
825
|
+
return (this.incentives ?? []).filter((x) => {
|
|
826
|
+
const sideMatches = side === "borrow" ? x.config.incentiveType === "Borrowing" /* BorrowingOnly */ : x.config.incentiveType !== "Borrowing" /* BorrowingOnly */;
|
|
827
|
+
if (!sideMatches) return false;
|
|
828
|
+
return !x.config.requiresPairReserve || x.config.requiresPairReserve === usingPairReserve;
|
|
829
|
+
});
|
|
830
|
+
}
|
|
831
|
+
canDeposit(amount) {
|
|
832
|
+
return amount <= this.deposits.limit;
|
|
833
|
+
}
|
|
834
|
+
canBorrow(amount) {
|
|
835
|
+
return amount <= this.borrows.limit;
|
|
836
|
+
}
|
|
837
|
+
};
|
|
838
|
+
|
|
839
|
+
// ../../shared/lending-platforms/src/data/reserve/kamino.ts
|
|
840
|
+
var KaminoReserveData = class _KaminoReserveData extends ReserveBase {
|
|
841
|
+
/**
|
|
842
|
+
* Creates a KaminoReserveData instance from raw SDK types.
|
|
843
|
+
* Extracts and normalizes configuration, rates, limits, and incentives.
|
|
844
|
+
*/
|
|
845
|
+
static loadData(market, reserve, reserveFarms, prices, slot) {
|
|
846
|
+
const stats = reserve.stats;
|
|
847
|
+
const state = reserve.state;
|
|
848
|
+
const config = state.config;
|
|
849
|
+
const mintDecimals = reserve.getMintDecimals();
|
|
850
|
+
const price = reserve.getOracleMarketPrice().toNumber();
|
|
851
|
+
const allElevationGroups = config.elevationGroups.map((id) => market.getElevationGroup(id)).filter(
|
|
852
|
+
(group) => group !== void 0 && group.debtReserve !== reserve.address && group.maxReservesAsCollateral === 1
|
|
853
|
+
);
|
|
854
|
+
const data = new _KaminoReserveData(
|
|
855
|
+
reserve.address,
|
|
856
|
+
{
|
|
857
|
+
mint: reserve.getLiquidityMint(),
|
|
858
|
+
mintDecimals,
|
|
859
|
+
mintTokenProgram: reserve.getLiquidityTokenProgram(),
|
|
860
|
+
price
|
|
861
|
+
},
|
|
862
|
+
{
|
|
863
|
+
ltvPct: stats.loanToValue,
|
|
864
|
+
liquidationThresholdPct: stats.liquidationThreshold,
|
|
865
|
+
borrowFeePct: reserve.getBorrowFee().toNumber(),
|
|
866
|
+
flashLoanFeePct: reserve.getFlashLoanFee().toNumber(),
|
|
867
|
+
emodes: allElevationGroups.map((x) => ({
|
|
868
|
+
id: x.id,
|
|
869
|
+
debtReserve: x.debtReserve,
|
|
870
|
+
ltvPct: x.ltvPct,
|
|
871
|
+
liquidationThresholdPct: x.liquidationThresholdPct
|
|
872
|
+
}))
|
|
873
|
+
},
|
|
874
|
+
{
|
|
875
|
+
totalAmount: reserve.getDepositTvl().toNumber() / price,
|
|
876
|
+
limit: toUiAmount(config.depositLimit, mintDecimals),
|
|
877
|
+
apy: reserve.totalSupplyAPY(slot)
|
|
878
|
+
},
|
|
879
|
+
{
|
|
880
|
+
totalAmount: reserve.getBorrowTvl().toNumber() / price,
|
|
881
|
+
limit: toUiAmount(config.borrowLimit, mintDecimals),
|
|
882
|
+
apy: reserve.totalBorrowAPY(slot)
|
|
883
|
+
},
|
|
884
|
+
{
|
|
885
|
+
utilizationRatePct: reserve.calculateUtilizationRatio(),
|
|
886
|
+
availableLiquidity: toUiAmount(
|
|
887
|
+
BigInt(reserve.getLiquidityAvailableAmount().toFixed(0)),
|
|
888
|
+
mintDecimals
|
|
889
|
+
)
|
|
890
|
+
},
|
|
891
|
+
reserveFarms.map((x) => KaminoIncentiveData.loadData(x, reserve, prices, slot)).filter((x) => x.active() || [state.farmCollateral, state.farmDebt].includes(x.address))
|
|
892
|
+
);
|
|
893
|
+
data.rawData = reserve;
|
|
894
|
+
data.slot = slot;
|
|
895
|
+
return data;
|
|
896
|
+
}
|
|
897
|
+
/** Checks if TWAP price validation is enabled for this reserve */
|
|
898
|
+
isTwapEnabled() {
|
|
899
|
+
return this.rawData.state.config.tokenInfo.maxTwapDivergenceBps.toNumber() > 0;
|
|
900
|
+
}
|
|
901
|
+
/**
|
|
902
|
+
* Determines if the reserve's on-chain price data is stale and needs refreshing.
|
|
903
|
+
*/
|
|
904
|
+
requiresRefresh() {
|
|
905
|
+
return true;
|
|
906
|
+
}
|
|
907
|
+
/**
|
|
908
|
+
* Returns all configured oracle account addresses for this reserve.
|
|
909
|
+
* Only includes accounts that are actually enabled.
|
|
910
|
+
*/
|
|
911
|
+
getOracleAccounts() {
|
|
912
|
+
const tokenInfo = this.rawData.state.config.tokenInfo;
|
|
913
|
+
const pythAccount = tokenInfo.pythConfiguration.price;
|
|
914
|
+
const switchboardPrice = tokenInfo.switchboardConfiguration.priceAggregator;
|
|
915
|
+
const switchboardTwap = tokenInfo.switchboardConfiguration.twapAggregator;
|
|
916
|
+
const scope = tokenInfo.scopeConfiguration.priceFeed;
|
|
917
|
+
const pythEnabled = isNotNullPubkey(pythAccount);
|
|
918
|
+
const switchboardEnabled = isNotNullPubkey(switchboardPrice);
|
|
919
|
+
const switchboardTwapEnabled = switchboardEnabled && this.isTwapEnabled() && isNotNullPubkey(switchboardTwap);
|
|
920
|
+
const scopeEnabled = isNotNullPubkey(scope);
|
|
921
|
+
return {
|
|
922
|
+
pythPrice: pythEnabled ? pythAccount : void 0,
|
|
923
|
+
switchboardPrice: switchboardEnabled ? switchboardPrice : void 0,
|
|
924
|
+
switchboardTwap: switchboardTwapEnabled ? switchboardTwap : void 0,
|
|
925
|
+
scope: scopeEnabled ? scope : void 0
|
|
926
|
+
};
|
|
927
|
+
}
|
|
928
|
+
/**
|
|
929
|
+
* Simulates the supply APY after a position balance change.
|
|
930
|
+
* Uses the SDK's calcSimulatedSupplyAPR which accounts for utilization changes.
|
|
931
|
+
*/
|
|
932
|
+
simulateNewSupplyAPY(args, usingDebtReserve) {
|
|
933
|
+
const collateralChange = args.collateralChange ?? 0;
|
|
934
|
+
if (!collateralChange) {
|
|
935
|
+
return this.supplyAPY(usingDebtReserve);
|
|
936
|
+
}
|
|
937
|
+
const simulatedAPR = this.rawData.calcSimulatedSupplyAPR(
|
|
938
|
+
new Decimal4(fromUiAmount(collateralChange, this.mint.mintDecimals).toNumber()),
|
|
939
|
+
collateralChange > 0 ? "deposit" : "withdraw",
|
|
940
|
+
this.slot,
|
|
941
|
+
0
|
|
942
|
+
);
|
|
943
|
+
return simulatedAPR + this.simulateNewEligbleIncentivesAPY(args, "supply", usingDebtReserve);
|
|
944
|
+
}
|
|
945
|
+
/**
|
|
946
|
+
* Simulates the borrow APY after a position balance change.
|
|
947
|
+
* Uses the SDK's calcSimulatedBorrowAPR which accounts for utilization changes.
|
|
948
|
+
*/
|
|
949
|
+
simulateNewBorrowAPY(args, usingSupplyReserve) {
|
|
950
|
+
const debtChange = args.debtChange ?? 0;
|
|
951
|
+
if (!debtChange) {
|
|
952
|
+
return this.borrowAPY(usingSupplyReserve);
|
|
953
|
+
}
|
|
954
|
+
const simulatedAPR = this.rawData.calcSimulatedBorrowAPR(
|
|
955
|
+
new Decimal4(fromUiAmount(debtChange, this.mint.mintDecimals).toNumber()),
|
|
956
|
+
debtChange > 0 ? "borrow" : "repay",
|
|
957
|
+
this.slot,
|
|
958
|
+
0
|
|
959
|
+
);
|
|
960
|
+
return simulatedAPR - this.simulateNewEligbleIncentivesAPY(args, "borrow", usingSupplyReserve);
|
|
961
|
+
}
|
|
962
|
+
canWithdraw(amount) {
|
|
963
|
+
const capCapacity = this.rawData.getDepositWithdrawalCapCapacity();
|
|
964
|
+
const capCurrent = this.rawData.getDepositWithdrawalCapCurrent(this.slot);
|
|
965
|
+
return this.hasCapacity(amount, capCapacity, capCurrent);
|
|
966
|
+
}
|
|
967
|
+
canBorrow(amount) {
|
|
968
|
+
const capCapacity = this.rawData.getDebtWithdrawalCapCapacity();
|
|
969
|
+
const capCurrent = this.rawData.getDebtWithdrawalCapCurrent(this.slot);
|
|
970
|
+
return amount <= this.borrows.limit && this.hasCapacity(amount, capCapacity, capCurrent);
|
|
971
|
+
}
|
|
972
|
+
hasCapacity(amount, capCapacity, capCurrent) {
|
|
973
|
+
if (!capCapacity.isZero()) {
|
|
974
|
+
const remainingCap = toUiAmount(
|
|
975
|
+
BigInt(capCapacity.minus(capCurrent).toFixed(0)),
|
|
976
|
+
this.mint.mintDecimals
|
|
977
|
+
);
|
|
978
|
+
if (amount > remainingCap) {
|
|
979
|
+
return false;
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
return true;
|
|
983
|
+
}
|
|
984
|
+
};
|
|
985
|
+
|
|
986
|
+
// ../../shared/lending-platforms/src/data/userPosition/kamino.ts
|
|
987
|
+
import { BN as BN4 } from "@anchor-lang/core";
|
|
988
|
+
|
|
989
|
+
// ../../shared/lending-platforms/src/data/userPosition/userPositionBase.ts
|
|
990
|
+
import { BN as BN3 } from "@anchor-lang/core";
|
|
991
|
+
var UserPositionBase = class {
|
|
992
|
+
constructor(address4, utilizationRate, deposits, borrows, ltv, liquidationThreshold, borrowLimitUsd) {
|
|
993
|
+
this.address = address4;
|
|
994
|
+
this.utilizationRate = utilizationRate;
|
|
995
|
+
this.deposits = deposits;
|
|
996
|
+
this.borrows = borrows;
|
|
997
|
+
this.ltv = ltv;
|
|
998
|
+
this.liquidationThreshold = liquidationThreshold;
|
|
999
|
+
this.borrowLimitUsd = borrowLimitUsd;
|
|
1000
|
+
}
|
|
1001
|
+
/** Aggregate borrowed USD for headroom; prefers per-borrow breakdown when present. */
|
|
1002
|
+
userPositionBorrowedValueUsd() {
|
|
1003
|
+
const fromBorrows = this.borrows.reduce((sum2, borrow) => sum2 + borrow.valueUsd, 0);
|
|
1004
|
+
if (fromBorrows > 0) {
|
|
1005
|
+
return fromBorrows;
|
|
1006
|
+
}
|
|
1007
|
+
if (this.borrowLimitUsd !== void 0 && this.utilizationRate > 0) {
|
|
1008
|
+
return this.borrowLimitUsd * this.utilizationRate;
|
|
1009
|
+
}
|
|
1010
|
+
return 0;
|
|
1011
|
+
}
|
|
1012
|
+
/**
|
|
1013
|
+
* Max additional debt UI amount before the platform rejects the borrow.
|
|
1014
|
+
* Uses obligation `borrowLimitUsd − borrowedUsd`, floored to base units with a
|
|
1015
|
+
* one-unit buffer so simulation-time refresh cannot overshoot. Returns `undefined`
|
|
1016
|
+
* when `borrowLimitUsd` was not set by the platform loader.
|
|
1017
|
+
*/
|
|
1018
|
+
getMaxAdditionalBorrowUiAmount(debtPriceUsd, debtDecimals) {
|
|
1019
|
+
if (this.borrowLimitUsd === void 0) {
|
|
1020
|
+
return void 0;
|
|
1021
|
+
}
|
|
1022
|
+
const borrowedValueUsd = this.userPositionBorrowedValueUsd();
|
|
1023
|
+
const headroomUsd = Math.max(0, this.borrowLimitUsd - borrowedValueUsd);
|
|
1024
|
+
if (headroomUsd <= 0 || !(debtPriceUsd > 0)) {
|
|
1025
|
+
return 0;
|
|
1026
|
+
}
|
|
1027
|
+
const headroomUi = headroomUsd / debtPriceUsd;
|
|
1028
|
+
const maxBaseUnits = fromUiAmount(headroomUi, debtDecimals);
|
|
1029
|
+
const safeBaseUnits = BN3.max(maxBaseUnits.subn(1), new BN3(0));
|
|
1030
|
+
return toUiAmount(safeBaseUnits, debtDecimals);
|
|
1031
|
+
}
|
|
1032
|
+
};
|
|
1033
|
+
|
|
1034
|
+
// ../../shared/lending-platforms/src/data/userPosition/kamino.ts
|
|
1035
|
+
var KaminoUserPositionData = class _KaminoUserPositionData extends UserPositionBase {
|
|
1036
|
+
/** Creates a KaminoUserPositionData from a raw KaminoObligation */
|
|
1037
|
+
static loadData(obligation) {
|
|
1038
|
+
const deposits = [];
|
|
1039
|
+
obligation.deposits.forEach((deposit, mint) => {
|
|
1040
|
+
deposits.push({
|
|
1041
|
+
reserve: deposit.reserveAddress,
|
|
1042
|
+
mint,
|
|
1043
|
+
amount: new BN4(deposit.amount.toFixed(0)),
|
|
1044
|
+
valueUsd: deposit.marketValueRefreshed.toNumber()
|
|
1045
|
+
});
|
|
1046
|
+
});
|
|
1047
|
+
const borrows = [];
|
|
1048
|
+
obligation.borrows.forEach((borrow, mint) => {
|
|
1049
|
+
borrows.push({
|
|
1050
|
+
reserve: borrow.reserveAddress,
|
|
1051
|
+
mint,
|
|
1052
|
+
amount: new BN4(borrow.amount.toFixed(0)),
|
|
1053
|
+
valueUsd: borrow.marketValueRefreshed.toNumber()
|
|
1054
|
+
});
|
|
1055
|
+
});
|
|
1056
|
+
const borrowedValueUsd = obligation.refreshedStats.userTotalBorrow.toNumber();
|
|
1057
|
+
const borrowLimitUsd = obligation.refreshedStats.borrowLimit.toNumber();
|
|
1058
|
+
const utilizationRate = borrowLimitUsd > 0 ? borrowedValueUsd / borrowLimitUsd : 0;
|
|
1059
|
+
const data = new _KaminoUserPositionData(
|
|
1060
|
+
obligation.obligationAddress,
|
|
1061
|
+
utilizationRate,
|
|
1062
|
+
deposits,
|
|
1063
|
+
borrows,
|
|
1064
|
+
void 0,
|
|
1065
|
+
void 0,
|
|
1066
|
+
borrowLimitUsd
|
|
1067
|
+
);
|
|
1068
|
+
data.rawData = obligation;
|
|
1069
|
+
return data;
|
|
1070
|
+
}
|
|
1071
|
+
/**
|
|
1072
|
+
* Determines if the obligation needs a refresh_obligation instruction.
|
|
1073
|
+
*/
|
|
1074
|
+
requiresRefresh() {
|
|
1075
|
+
return true;
|
|
1076
|
+
}
|
|
1077
|
+
};
|
|
1078
|
+
|
|
1079
|
+
// ../../shared/lending-platforms/src/data/instructions/kamino.ts
|
|
1080
|
+
import { BN as BN5 } from "@anchor-lang/core";
|
|
1081
|
+
import { address as address2, getAddressEncoder } from "@solana/kit";
|
|
1082
|
+
import { Scope as Scope3 } from "@kamino-finance/scope-sdk";
|
|
1083
|
+
import {
|
|
1084
|
+
DEFAULT_PUBLIC_KEY as DEFAULT_PUBLIC_KEY3,
|
|
1085
|
+
lendingMarketAuthPda,
|
|
1086
|
+
PROGRAM_ID as PROGRAM_ID3,
|
|
1087
|
+
userMetadataPda as userMetadataPda2,
|
|
1088
|
+
VanillaObligation as VanillaObligation2
|
|
1089
|
+
} from "@kamino-finance/klend-sdk";
|
|
1090
|
+
|
|
1091
|
+
// ../../shared/lending-platforms/src/data/instructions/lpInstructionsBase.ts
|
|
1092
|
+
var LpInstructionsBase = class {
|
|
1093
|
+
constructor(rpc, rpcUrl, data, accounts) {
|
|
1094
|
+
/** Tracks which reserves (and their pools/roles) are involved in each transaction */
|
|
1095
|
+
this.txReserves = /* @__PURE__ */ new Map();
|
|
1096
|
+
/**
|
|
1097
|
+
* Per-txId per-obligation set of debt reserves that the caller has flagged
|
|
1098
|
+
* as being fully repaid earlier in the same transaction. Subsequent
|
|
1099
|
+
* `RefreshObligation` builds for that obligation must NOT include these
|
|
1100
|
+
* reserves in the borrow accounts list — by execution time the borrow row
|
|
1101
|
+
* has been removed from the obligation, and Kamino's `handler_refresh_obligation`
|
|
1102
|
+
* checks the passed account count against the live obligation state and
|
|
1103
|
+
* fails with `InvalidAccountInput` (klend error 6006) on a mismatch.
|
|
1104
|
+
*
|
|
1105
|
+
* Set via {@link markObligationDebtCleared}, read via {@link getTxObligationClearedDebt}.
|
|
1106
|
+
*/
|
|
1107
|
+
this.txClearedDebt = /* @__PURE__ */ new Map();
|
|
1108
|
+
this.rpc = rpc;
|
|
1109
|
+
this.rpcUrl = rpcUrl;
|
|
1110
|
+
this.data = data;
|
|
1111
|
+
this.accounts = accounts;
|
|
1112
|
+
}
|
|
1113
|
+
emptyAccountMeta() {
|
|
1114
|
+
return toCustomAccountMeta(this.programId);
|
|
1115
|
+
}
|
|
1116
|
+
clearCacheEntry(category, id) {
|
|
1117
|
+
this.data.clearCacheEntry(category, id);
|
|
1118
|
+
}
|
|
1119
|
+
getCacheInvalidation(invalidation) {
|
|
1120
|
+
return {
|
|
1121
|
+
client: "kamino",
|
|
1122
|
+
...invalidation
|
|
1123
|
+
};
|
|
1124
|
+
}
|
|
1125
|
+
applyPostSuccessCacheInvalidations(invalidations) {
|
|
1126
|
+
for (const invalidation of invalidations) {
|
|
1127
|
+
if (invalidation.client !== "kamino") {
|
|
1128
|
+
continue;
|
|
1129
|
+
}
|
|
1130
|
+
this.clearCacheEntry(invalidation.category, invalidation.id);
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
getCpiData(cpiType, accounts, data, programId, postSuccessCacheInvalidations) {
|
|
1134
|
+
return {
|
|
1135
|
+
programId: programId ?? this.programId,
|
|
1136
|
+
cpiType,
|
|
1137
|
+
data,
|
|
1138
|
+
accounts,
|
|
1139
|
+
lookupTables: [this.lookupTable],
|
|
1140
|
+
postSuccessCacheInvalidations
|
|
1141
|
+
};
|
|
1142
|
+
}
|
|
1143
|
+
createSplitOperationCpiData(prerequisiteCpis, cpis) {
|
|
1144
|
+
return {
|
|
1145
|
+
prerequisiteCpis,
|
|
1146
|
+
cpis,
|
|
1147
|
+
allCpis: [...prerequisiteCpis, ...cpis]
|
|
1148
|
+
};
|
|
1149
|
+
}
|
|
1150
|
+
buildLendingOperationCpiBundle(cpiData) {
|
|
1151
|
+
return {
|
|
1152
|
+
prerequisiteCpis: cpiData.prerequisiteCpis,
|
|
1153
|
+
cpis: cpiData.cpis,
|
|
1154
|
+
allCpis: [...cpiData.prerequisiteCpis, ...cpiData.cpis],
|
|
1155
|
+
postSuccessCacheInvalidations: [...cpiData.prerequisiteCpis, ...cpiData.cpis].flatMap(
|
|
1156
|
+
(cpi) => cpi.postSuccessCacheInvalidations ?? []
|
|
1157
|
+
)
|
|
1158
|
+
};
|
|
1159
|
+
}
|
|
1160
|
+
async getInitAndDepositCpiBundle(params, userAccountId) {
|
|
1161
|
+
return this.buildLendingOperationCpiBundle(
|
|
1162
|
+
await this.getInitAndDepositCpiData(params, userAccountId)
|
|
1163
|
+
);
|
|
1164
|
+
}
|
|
1165
|
+
async getInitBorrowPositionCpiBundle(params, collReserve) {
|
|
1166
|
+
return this.buildLendingOperationCpiBundle(
|
|
1167
|
+
await this.getInitBorrowPositionCpiData(params, collReserve)
|
|
1168
|
+
);
|
|
1169
|
+
}
|
|
1170
|
+
async getDepositCpiBundle(params) {
|
|
1171
|
+
return this.buildLendingOperationCpiBundle(await this.getDepositCpiData(params));
|
|
1172
|
+
}
|
|
1173
|
+
async getWithdrawCpiBundle(params) {
|
|
1174
|
+
return this.buildLendingOperationCpiBundle(await this.getWithdrawCpiData(params));
|
|
1175
|
+
}
|
|
1176
|
+
async getBorrowCpiBundle(params) {
|
|
1177
|
+
return this.buildLendingOperationCpiBundle(await this.getBorrowCpiData(params));
|
|
1178
|
+
}
|
|
1179
|
+
async getRepayCpiBundle(params) {
|
|
1180
|
+
return this.buildLendingOperationCpiBundle(await this.getRepayCpiData(params));
|
|
1181
|
+
}
|
|
1182
|
+
/**
|
|
1183
|
+
* Registers a reserve as being used in a transaction.
|
|
1184
|
+
* When userAccount and role are provided, also tracks the collateral/debt role
|
|
1185
|
+
* for that specific user account.
|
|
1186
|
+
*/
|
|
1187
|
+
registerTxReserve(txId, pool, reserve, userAccount, role) {
|
|
1188
|
+
if (!this.txReserves.has(txId)) {
|
|
1189
|
+
this.txReserves.set(txId, /* @__PURE__ */ new Map());
|
|
1190
|
+
}
|
|
1191
|
+
const txMap = this.txReserves.get(txId);
|
|
1192
|
+
if (!txMap.has(reserve)) {
|
|
1193
|
+
txMap.set(reserve, { pool, userAccounts: /* @__PURE__ */ new Map() });
|
|
1194
|
+
}
|
|
1195
|
+
if (userAccount && role) {
|
|
1196
|
+
const entry = txMap.get(reserve);
|
|
1197
|
+
if (!entry.userAccounts.has(userAccount)) {
|
|
1198
|
+
entry.userAccounts.set(userAccount, /* @__PURE__ */ new Set());
|
|
1199
|
+
}
|
|
1200
|
+
entry.userAccounts.get(userAccount).add(role);
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
/**
|
|
1204
|
+
* Returns the collateral and debt reserves registered in the tx cache
|
|
1205
|
+
* for a specific user account (obligation).
|
|
1206
|
+
*/
|
|
1207
|
+
getTxUserAccountReserves(txId, userAccount) {
|
|
1208
|
+
const collateral = [];
|
|
1209
|
+
const debt = [];
|
|
1210
|
+
const txMap = this.txReserves.get(txId);
|
|
1211
|
+
if (!txMap) return { collateral, debt };
|
|
1212
|
+
for (const [reserve, info] of txMap) {
|
|
1213
|
+
const roles = info.userAccounts.get(userAccount);
|
|
1214
|
+
if (roles?.has("collateral")) collateral.push(reserve);
|
|
1215
|
+
if (roles?.has("debt")) debt.push(reserve);
|
|
1216
|
+
}
|
|
1217
|
+
return { collateral, debt };
|
|
1218
|
+
}
|
|
1219
|
+
/**
|
|
1220
|
+
* Mark that `reserve` will be fully repaid for `userAccount` earlier in the
|
|
1221
|
+
* `txId` flow, so subsequent obligation-refresh builders drop it from the
|
|
1222
|
+
* borrow accounts they emit. Call after building a "repay all" CPI; it has
|
|
1223
|
+
* no effect on the repay itself.
|
|
1224
|
+
*/
|
|
1225
|
+
markObligationDebtCleared(txId, userAccount, reserve) {
|
|
1226
|
+
if (!this.txClearedDebt.has(txId)) {
|
|
1227
|
+
this.txClearedDebt.set(txId, /* @__PURE__ */ new Map());
|
|
1228
|
+
}
|
|
1229
|
+
const obligationMap = this.txClearedDebt.get(txId);
|
|
1230
|
+
if (!obligationMap.has(userAccount)) {
|
|
1231
|
+
obligationMap.set(userAccount, /* @__PURE__ */ new Set());
|
|
1232
|
+
}
|
|
1233
|
+
obligationMap.get(userAccount).add(reserve);
|
|
1234
|
+
}
|
|
1235
|
+
/** Returns the set of debt reserves marked cleared for `(txId, userAccount)`. */
|
|
1236
|
+
getTxObligationClearedDebt(txId, userAccount) {
|
|
1237
|
+
return this.txClearedDebt.get(txId)?.get(userAccount) ?? /* @__PURE__ */ new Set();
|
|
1238
|
+
}
|
|
1239
|
+
/**
|
|
1240
|
+
* Clears the transaction cache for a given transaction or all transactions.
|
|
1241
|
+
* Call after finishing building a transaction to free memory.
|
|
1242
|
+
*/
|
|
1243
|
+
clearTransactionCache(txId) {
|
|
1244
|
+
if (txId) {
|
|
1245
|
+
this.txReserves.delete(txId);
|
|
1246
|
+
this.txClearedDebt.delete(txId);
|
|
1247
|
+
} else {
|
|
1248
|
+
this.txReserves.clear();
|
|
1249
|
+
this.txClearedDebt.clear();
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
/**
|
|
1253
|
+
* Returns prerequisite CPIs needed before reading refreshed account state for
|
|
1254
|
+
* a batch of lending positions outside a normal deposit/withdraw/borrow/repay
|
|
1255
|
+
* flow.
|
|
1256
|
+
*/
|
|
1257
|
+
async getPrerequisiteCpisForRefresh(_targets) {
|
|
1258
|
+
return [];
|
|
1259
|
+
}
|
|
1260
|
+
/**
|
|
1261
|
+
* Returns CPI data for initializing a lending position end-to-end: the user
|
|
1262
|
+
* account itself plus any per-reserve accessory accounts (e.g. Kamino
|
|
1263
|
+
* obligation farm user states for the collateral and debt reserves). Called
|
|
1264
|
+
* at position-creation time so subsequent deposit/borrow flows don't need
|
|
1265
|
+
* to init these inline.
|
|
1266
|
+
*
|
|
1267
|
+
* Default: delegates to {@link getInitUserAccountCpiData}. Platforms with
|
|
1268
|
+
* per-reserve accessory accounts override this to add their inits.
|
|
1269
|
+
*/
|
|
1270
|
+
async getInitLendingPositionCpiData(params) {
|
|
1271
|
+
return this.getInitUserAccountCpiData(
|
|
1272
|
+
params.pool,
|
|
1273
|
+
params.user,
|
|
1274
|
+
params.payer,
|
|
1275
|
+
params.userAccountId
|
|
1276
|
+
);
|
|
1277
|
+
}
|
|
1278
|
+
};
|
|
1279
|
+
|
|
1280
|
+
// ../../shared/lending-platforms/src/data/instructions/kamino.ts
|
|
1281
|
+
import { TOKEN_PROGRAM_ADDRESS } from "@solana-program/token";
|
|
1282
|
+
import { getTreasuryVaultPDA } from "@kamino-finance/farms-sdk";
|
|
1283
|
+
var KaminoInstructions = class extends LpInstructionsBase {
|
|
1284
|
+
constructor(rpc, rpcUrl, data, accounts) {
|
|
1285
|
+
super(rpc, rpcUrl, data, accounts);
|
|
1286
|
+
this.programId = PROGRAM_ID3;
|
|
1287
|
+
this.lookupTable = address2("bzdjSeDDPEdsGpK73oevQ87x4Sm6QRsnzupPLQEaFFN");
|
|
1288
|
+
}
|
|
1289
|
+
clearTransactionCache(txId) {
|
|
1290
|
+
super.clearTransactionCache(txId);
|
|
1291
|
+
}
|
|
1292
|
+
// ================ CPI Data ================
|
|
1293
|
+
getUserAccountCacheInvalidations(userAccount) {
|
|
1294
|
+
return [
|
|
1295
|
+
this.getCacheInvalidation({
|
|
1296
|
+
category: this.data.userAccountCatKey,
|
|
1297
|
+
id: userAccount
|
|
1298
|
+
})
|
|
1299
|
+
];
|
|
1300
|
+
}
|
|
1301
|
+
async getInitUserMetadataCpiData(user, payer, userLookupTable) {
|
|
1302
|
+
const [userMetadataAddress] = await userMetadataPda2(user, this.programId);
|
|
1303
|
+
if (await accountExists(this.rpc, userMetadataAddress)) return;
|
|
1304
|
+
return this.getCpiData(
|
|
1305
|
+
CpiTypes.K_INIT_USER_METADATA,
|
|
1306
|
+
[
|
|
1307
|
+
toCustomAccountMeta(user, false, void 0, true),
|
|
1308
|
+
toCustomAccountMeta(payer, true, void 0, true),
|
|
1309
|
+
toCustomAccountMeta(userMetadataAddress, true),
|
|
1310
|
+
this.emptyAccountMeta(),
|
|
1311
|
+
RENT_SYSVAR_META,
|
|
1312
|
+
SYSTEM_PROGRAM_META
|
|
1313
|
+
],
|
|
1314
|
+
new Uint8Array(getAddressEncoder().encode(userLookupTable ?? DEFAULT_PUBLIC_KEY3))
|
|
1315
|
+
);
|
|
1316
|
+
}
|
|
1317
|
+
async getInitLendingPositionCpiData(params) {
|
|
1318
|
+
const userInit = await this.getInitUserAccountCpiData(
|
|
1319
|
+
params.pool,
|
|
1320
|
+
params.user,
|
|
1321
|
+
params.payer,
|
|
1322
|
+
params.userAccountId
|
|
1323
|
+
);
|
|
1324
|
+
const obligation = await this.accounts.getUserAccountAddress(
|
|
1325
|
+
params.pool,
|
|
1326
|
+
params.user,
|
|
1327
|
+
params.userAccountId
|
|
1328
|
+
);
|
|
1329
|
+
const farmCpis = [];
|
|
1330
|
+
const farmTargets = [
|
|
1331
|
+
[params.collateralReserve, "collateral"],
|
|
1332
|
+
[params.debtReserve, "debt"]
|
|
1333
|
+
];
|
|
1334
|
+
for (const [reserve, mode] of farmTargets) {
|
|
1335
|
+
const reserveData = await this.data.fetchReserve(params.pool, reserve);
|
|
1336
|
+
const reserveFarm = mode === "collateral" ? reserveData.rawData.state.farmCollateral : reserveData.rawData.state.farmDebt;
|
|
1337
|
+
if (!reserveFarm || reserveFarm === DEFAULT_PUBLIC_KEY3) continue;
|
|
1338
|
+
const farmAccounts = await this.accounts.getFarmAccounts(
|
|
1339
|
+
params.pool,
|
|
1340
|
+
reserve,
|
|
1341
|
+
obligation,
|
|
1342
|
+
mode
|
|
1343
|
+
);
|
|
1344
|
+
if (await accountExists(this.rpc, farmAccounts.userFarm.address)) continue;
|
|
1345
|
+
farmCpis.push(
|
|
1346
|
+
await this.getInitObligationFarmsForReserveCpiData(
|
|
1347
|
+
params.user,
|
|
1348
|
+
params.payer,
|
|
1349
|
+
obligation,
|
|
1350
|
+
params.pool,
|
|
1351
|
+
reserve,
|
|
1352
|
+
mode
|
|
1353
|
+
)
|
|
1354
|
+
);
|
|
1355
|
+
}
|
|
1356
|
+
return this.createSplitOperationCpiData(userInit.prerequisiteCpis, [
|
|
1357
|
+
...userInit.cpis,
|
|
1358
|
+
...farmCpis
|
|
1359
|
+
]);
|
|
1360
|
+
}
|
|
1361
|
+
async getInitUserAccountCpiData(pool, user, payer, id, userLookupTable) {
|
|
1362
|
+
const market = await this.data.fetchMarket(pool);
|
|
1363
|
+
const obligationPda = await this.accounts.getUserAccountAddress(pool, user, id);
|
|
1364
|
+
const userMetadataAddress = await this.accounts.getUserMetadataAddress(user);
|
|
1365
|
+
const tag = VanillaObligation2.tag;
|
|
1366
|
+
const initMetadataCpi = await this.getInitUserMetadataCpiData(user, payer, userLookupTable);
|
|
1367
|
+
const obligationAlreadyInit = await accountExists(this.rpc, obligationPda);
|
|
1368
|
+
return this.createSplitOperationCpiData(
|
|
1369
|
+
[],
|
|
1370
|
+
[
|
|
1371
|
+
...initMetadataCpi ? [initMetadataCpi] : [],
|
|
1372
|
+
...obligationAlreadyInit ? [] : [
|
|
1373
|
+
this.getCpiData(
|
|
1374
|
+
CpiTypes.K_INIT_OBLIGATION,
|
|
1375
|
+
[
|
|
1376
|
+
toCustomAccountMeta(user),
|
|
1377
|
+
toCustomAccountMeta(payer, true),
|
|
1378
|
+
toCustomAccountMeta(obligationPda, true),
|
|
1379
|
+
toCustomAccountMeta(market.address),
|
|
1380
|
+
toCustomAccountMeta(DEFAULT_PUBLIC_KEY3),
|
|
1381
|
+
toCustomAccountMeta(DEFAULT_PUBLIC_KEY3),
|
|
1382
|
+
toCustomAccountMeta(userMetadataAddress),
|
|
1383
|
+
RENT_SYSVAR_META,
|
|
1384
|
+
SYSTEM_PROGRAM_META
|
|
1385
|
+
],
|
|
1386
|
+
new Uint8Array([tag, id])
|
|
1387
|
+
)
|
|
1388
|
+
]
|
|
1389
|
+
]
|
|
1390
|
+
);
|
|
1391
|
+
}
|
|
1392
|
+
async getInitObligationFarmsForReserveCpiData(user, payer, obligation, pool, reserve, farmMode) {
|
|
1393
|
+
const farmAccounts = await this.accounts.getFarmAccounts(pool, reserve, obligation, farmMode);
|
|
1394
|
+
return this.getCpiData(
|
|
1395
|
+
CpiTypes.K_INIT_USER_FARM,
|
|
1396
|
+
[
|
|
1397
|
+
toCustomAccountMeta(payer, true),
|
|
1398
|
+
toCustomAccountMeta(user),
|
|
1399
|
+
toCustomAccountMeta(obligation, true),
|
|
1400
|
+
toCustomAccountMeta((await lendingMarketAuthPda(pool))[0]),
|
|
1401
|
+
toCustomAccountMeta(reserve, true),
|
|
1402
|
+
farmAccounts.farm,
|
|
1403
|
+
farmAccounts.userFarm,
|
|
1404
|
+
toCustomAccountMeta(pool),
|
|
1405
|
+
toCustomAccountMeta(KAMINO_FARMS_PROGRAM_ID),
|
|
1406
|
+
RENT_SYSVAR_META,
|
|
1407
|
+
SYSTEM_PROGRAM_META
|
|
1408
|
+
],
|
|
1409
|
+
new Uint8Array([farmMode === "collateral" ? 0 : 1])
|
|
1410
|
+
);
|
|
1411
|
+
}
|
|
1412
|
+
/**
|
|
1413
|
+
* Returns CPI accounts for refreshing a reserve's state.
|
|
1414
|
+
* Includes the market, reserve, and all configured oracle accounts.
|
|
1415
|
+
*/
|
|
1416
|
+
async getRefreshReserveCpiData(pool, reserve) {
|
|
1417
|
+
const reserveData = await this.data.fetchReserve(pool, reserve);
|
|
1418
|
+
const oracleAccounts = reserveData.getOracleAccounts();
|
|
1419
|
+
return this.getCpiData(
|
|
1420
|
+
CpiTypes.K_REFRESH_RESERVE,
|
|
1421
|
+
[
|
|
1422
|
+
toCustomAccountMeta(reserve, true),
|
|
1423
|
+
toCustomAccountMeta(pool),
|
|
1424
|
+
...Object.values(oracleAccounts).map(
|
|
1425
|
+
(x) => x === void 0 ? this.emptyAccountMeta() : toCustomAccountMeta(x)
|
|
1426
|
+
)
|
|
1427
|
+
],
|
|
1428
|
+
new Uint8Array()
|
|
1429
|
+
);
|
|
1430
|
+
}
|
|
1431
|
+
async getRefreshObligationCpiData(txId, pool, obligation) {
|
|
1432
|
+
const obligationData = await this.data.maybeFetchUserPositionInPool(pool, obligation);
|
|
1433
|
+
const cached = this.getTxUserAccountReserves(txId, obligation);
|
|
1434
|
+
const cleared = this.getTxObligationClearedDebt(txId, obligation);
|
|
1435
|
+
const collateralReserves = [
|
|
1436
|
+
.../* @__PURE__ */ new Set([...obligationData?.deposits.map((x) => x.reserve) ?? [], ...cached.collateral])
|
|
1437
|
+
];
|
|
1438
|
+
const debtReserves = [
|
|
1439
|
+
.../* @__PURE__ */ new Set([...obligationData?.borrows.map((x) => x.reserve) ?? [], ...cached.debt])
|
|
1440
|
+
].filter((r) => !cleared.has(r));
|
|
1441
|
+
return this.getCpiData(
|
|
1442
|
+
CpiTypes.K_REFRESH_OBLIGATION,
|
|
1443
|
+
[
|
|
1444
|
+
toCustomAccountMeta(pool),
|
|
1445
|
+
toCustomAccountMeta(obligation, true),
|
|
1446
|
+
...collateralReserves.map((x) => toCustomAccountMeta(x)),
|
|
1447
|
+
...debtReserves.map((x) => toCustomAccountMeta(x))
|
|
1448
|
+
],
|
|
1449
|
+
new Uint8Array()
|
|
1450
|
+
);
|
|
1451
|
+
}
|
|
1452
|
+
getRefreshObligationCpiDataFromReserves({
|
|
1453
|
+
pool,
|
|
1454
|
+
userAccount,
|
|
1455
|
+
collateralReserves,
|
|
1456
|
+
debtReserves
|
|
1457
|
+
}) {
|
|
1458
|
+
return this.getCpiData(
|
|
1459
|
+
CpiTypes.K_REFRESH_OBLIGATION,
|
|
1460
|
+
[
|
|
1461
|
+
toCustomAccountMeta(pool),
|
|
1462
|
+
toCustomAccountMeta(userAccount, true),
|
|
1463
|
+
...dedupeOrderedAddresses(collateralReserves).map((x) => toCustomAccountMeta(x)),
|
|
1464
|
+
...dedupeOrderedAddresses(debtReserves).map((x) => toCustomAccountMeta(x))
|
|
1465
|
+
],
|
|
1466
|
+
new Uint8Array()
|
|
1467
|
+
);
|
|
1468
|
+
}
|
|
1469
|
+
async getPrerequisiteCpisForRefresh(targets) {
|
|
1470
|
+
const reserveRefreshes = [];
|
|
1471
|
+
const seenReserveRefreshes = /* @__PURE__ */ new Set();
|
|
1472
|
+
const obligationRefreshes = /* @__PURE__ */ new Map();
|
|
1473
|
+
for (const target of targets) {
|
|
1474
|
+
for (const reserve of dedupeOrderedAddresses([
|
|
1475
|
+
...target.collateralReserves,
|
|
1476
|
+
...target.debtReserves
|
|
1477
|
+
])) {
|
|
1478
|
+
const reserveRefreshKey = `${target.pool}:${reserve}`;
|
|
1479
|
+
if (seenReserveRefreshes.has(reserveRefreshKey)) {
|
|
1480
|
+
continue;
|
|
1481
|
+
}
|
|
1482
|
+
seenReserveRefreshes.add(reserveRefreshKey);
|
|
1483
|
+
reserveRefreshes.push({ pool: target.pool, reserve });
|
|
1484
|
+
}
|
|
1485
|
+
if (target.userAccount === DEFAULT_PUBLIC_KEY3) {
|
|
1486
|
+
continue;
|
|
1487
|
+
}
|
|
1488
|
+
const obligationKey = `${target.pool}:${target.userAccount}`;
|
|
1489
|
+
if (obligationRefreshes.has(obligationKey)) {
|
|
1490
|
+
continue;
|
|
1491
|
+
}
|
|
1492
|
+
obligationRefreshes.set(obligationKey, {
|
|
1493
|
+
pool: target.pool,
|
|
1494
|
+
userAccount: target.userAccount,
|
|
1495
|
+
collateralReserves: dedupeOrderedAddresses(target.collateralReserves),
|
|
1496
|
+
debtReserves: dedupeOrderedAddresses(target.debtReserves)
|
|
1497
|
+
});
|
|
1498
|
+
}
|
|
1499
|
+
const prerequisiteCpis = [];
|
|
1500
|
+
for (const { pool, reserve } of reserveRefreshes) {
|
|
1501
|
+
prerequisiteCpis.push(await this.getRefreshReserveCpiData(pool, reserve));
|
|
1502
|
+
}
|
|
1503
|
+
for (const obligationRefresh of obligationRefreshes.values()) {
|
|
1504
|
+
let obligationData = null;
|
|
1505
|
+
try {
|
|
1506
|
+
obligationData = await this.data.maybeFetchUserPositionInPool(
|
|
1507
|
+
obligationRefresh.pool,
|
|
1508
|
+
obligationRefresh.userAccount
|
|
1509
|
+
);
|
|
1510
|
+
} catch {
|
|
1511
|
+
obligationData = null;
|
|
1512
|
+
}
|
|
1513
|
+
if (!obligationData) {
|
|
1514
|
+
continue;
|
|
1515
|
+
}
|
|
1516
|
+
prerequisiteCpis.push(
|
|
1517
|
+
this.getRefreshObligationCpiDataFromReserves({
|
|
1518
|
+
pool: obligationRefresh.pool,
|
|
1519
|
+
userAccount: obligationRefresh.userAccount,
|
|
1520
|
+
collateralReserves: obligationData.deposits.map((deposit) => deposit.reserve),
|
|
1521
|
+
debtReserves: obligationData.borrows.map((borrow) => borrow.reserve)
|
|
1522
|
+
})
|
|
1523
|
+
);
|
|
1524
|
+
}
|
|
1525
|
+
return prerequisiteCpis;
|
|
1526
|
+
}
|
|
1527
|
+
async getRefreshUserFarmCpiData(signer, pool, reserve, obligation, userFarm, farm, mode) {
|
|
1528
|
+
const details = await this.accounts.reserveInteractionDetails(
|
|
1529
|
+
signer,
|
|
1530
|
+
pool,
|
|
1531
|
+
reserve,
|
|
1532
|
+
obligation
|
|
1533
|
+
);
|
|
1534
|
+
return this.getCpiData(
|
|
1535
|
+
CpiTypes.K_REFRESH_USER_FARM,
|
|
1536
|
+
[
|
|
1537
|
+
details.signer,
|
|
1538
|
+
details.obligation,
|
|
1539
|
+
details.lendingMarketAuthority,
|
|
1540
|
+
details.reserve,
|
|
1541
|
+
toCustomAccountMeta(farm, true),
|
|
1542
|
+
toCustomAccountMeta(userFarm, true),
|
|
1543
|
+
details.lendingMarket,
|
|
1544
|
+
details.farmsProgram,
|
|
1545
|
+
RENT_SYSVAR_META,
|
|
1546
|
+
SYSTEM_PROGRAM_META
|
|
1547
|
+
],
|
|
1548
|
+
new Uint8Array([mode === "collateral" ? 0 : 1])
|
|
1549
|
+
);
|
|
1550
|
+
}
|
|
1551
|
+
/**
|
|
1552
|
+
* Checks if refresh CPIs are needed for the given reserve and obligation.
|
|
1553
|
+
* Also registers all involved reserves in the txReserves cache for getPreInstructions.
|
|
1554
|
+
*
|
|
1555
|
+
* The instruction `reserve` (collateral vs debt) is also listed on the obligation;
|
|
1556
|
+
* `dedupeOrderedAddresses` ensures one RefreshReserve CPI per reserve pubkey.
|
|
1557
|
+
*/
|
|
1558
|
+
async getRefreshCpisIfNeeded(txId, pool, reserve, obligation) {
|
|
1559
|
+
const cpis = [];
|
|
1560
|
+
const cached = this.getTxUserAccountReserves(txId, obligation);
|
|
1561
|
+
const refreshReserve = async (reserveAddr) => {
|
|
1562
|
+
cpis.push(await this.getRefreshReserveCpiData(pool, reserveAddr));
|
|
1563
|
+
this.registerTxReserve(txId, pool, reserveAddr);
|
|
1564
|
+
};
|
|
1565
|
+
const obligationData = await this.data.maybeFetchUserPositionInPool(pool, obligation);
|
|
1566
|
+
if (obligationData) {
|
|
1567
|
+
const needsFullObligationRefresh = obligationData.requiresRefresh() || cached.collateral.length > 0 || cached.debt.length > 0;
|
|
1568
|
+
if (needsFullObligationRefresh) {
|
|
1569
|
+
const additional = [
|
|
1570
|
+
...obligationData.deposits.map((d) => d.reserve),
|
|
1571
|
+
...obligationData.borrows.map((b) => b.reserve),
|
|
1572
|
+
...cached.collateral,
|
|
1573
|
+
...cached.debt
|
|
1574
|
+
];
|
|
1575
|
+
for (const addr of dedupeOrderedAddresses([reserve, ...additional])) {
|
|
1576
|
+
await refreshReserve(addr);
|
|
1577
|
+
}
|
|
1578
|
+
cpis.push(await this.getRefreshObligationCpiData(txId, pool, obligation));
|
|
1579
|
+
} else {
|
|
1580
|
+
await refreshReserve(reserve);
|
|
1581
|
+
}
|
|
1582
|
+
} else {
|
|
1583
|
+
const additional = [.../* @__PURE__ */ new Set([...cached.collateral, ...cached.debt])];
|
|
1584
|
+
for (const addr of dedupeOrderedAddresses([reserve, ...additional])) {
|
|
1585
|
+
await refreshReserve(addr);
|
|
1586
|
+
}
|
|
1587
|
+
cpis.push(await this.getRefreshObligationCpiData(txId, pool, obligation));
|
|
1588
|
+
}
|
|
1589
|
+
return cpis;
|
|
1590
|
+
}
|
|
1591
|
+
async getPreInstructions(txId) {
|
|
1592
|
+
const reserveEntries = this.txReserves.get(txId);
|
|
1593
|
+
if (!reserveEntries) return [];
|
|
1594
|
+
const SCOPE_CHAIN_END = 65535;
|
|
1595
|
+
const scopeFeeds = /* @__PURE__ */ new Map();
|
|
1596
|
+
if (reserveEntries) {
|
|
1597
|
+
for (const [reserve, { pool }] of reserveEntries) {
|
|
1598
|
+
const reserveData = await this.data.fetchReserve(pool, reserve);
|
|
1599
|
+
if (!reserveData.requiresRefresh()) continue;
|
|
1600
|
+
const scopeFeed = reserveData.getOracleAccounts().scope;
|
|
1601
|
+
if (!scopeFeed) continue;
|
|
1602
|
+
if (!scopeFeeds.has(scopeFeed)) {
|
|
1603
|
+
scopeFeeds.set(scopeFeed, /* @__PURE__ */ new Set());
|
|
1604
|
+
}
|
|
1605
|
+
const tokens2 = scopeFeeds.get(scopeFeed);
|
|
1606
|
+
const { priceChain, twapChain } = reserveData.rawData.state.config.tokenInfo.scopeConfiguration;
|
|
1607
|
+
for (const chain of [priceChain, twapChain]) {
|
|
1608
|
+
for (const index of chain) {
|
|
1609
|
+
if (index === SCOPE_CHAIN_END) break;
|
|
1610
|
+
tokens2.add(index);
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
const configTokens = /* @__PURE__ */ new Map();
|
|
1616
|
+
for (const [feed, chainTokens2] of scopeFeeds) {
|
|
1617
|
+
const configAddr2 = await this.data.fetchScopeConfigAddress(feed);
|
|
1618
|
+
if (!configTokens.has(configAddr2)) {
|
|
1619
|
+
configTokens.set(configAddr2, /* @__PURE__ */ new Set());
|
|
1620
|
+
}
|
|
1621
|
+
const merged = configTokens.get(configAddr2);
|
|
1622
|
+
for (const t of chainTokens2) merged.add(t);
|
|
1623
|
+
}
|
|
1624
|
+
const scope = new Scope3("mainnet-beta", this.rpc);
|
|
1625
|
+
const isLocalnet = this.rpcUrl === LOCALNET_URL;
|
|
1626
|
+
const [firstEntry] = configTokens;
|
|
1627
|
+
if (!firstEntry) return [];
|
|
1628
|
+
const [configAddr, chainTokens] = firstEntry;
|
|
1629
|
+
let tokens;
|
|
1630
|
+
if (isLocalnet) {
|
|
1631
|
+
const mappings = await scope.getOracleMappings({ config: address2(configAddr) });
|
|
1632
|
+
const allTokens = /* @__PURE__ */ new Set();
|
|
1633
|
+
for (const token of chainTokens) {
|
|
1634
|
+
collectTokenDependencies(token, mappings, allTokens);
|
|
1635
|
+
}
|
|
1636
|
+
tokens = [...allTokens];
|
|
1637
|
+
} else {
|
|
1638
|
+
tokens = [...chainTokens];
|
|
1639
|
+
}
|
|
1640
|
+
const ix = await scope.refreshPriceListIx({ config: address2(configAddr) }, tokens);
|
|
1641
|
+
return ix ? [ix] : [];
|
|
1642
|
+
}
|
|
1643
|
+
async getClaimIncentiveCpiData(user, payer, pool, reserve, obligation, farm, userFarm, mint) {
|
|
1644
|
+
const tokenProgram = mints.get(mint)?.tokenProgram ?? TOKEN_PROGRAM_ADDRESS;
|
|
1645
|
+
const reserveData = await this.data.fetchReserve(pool, reserve);
|
|
1646
|
+
const [farmState] = await this.data.fetchFarms([farm]);
|
|
1647
|
+
const rewardIndex = farmState.rewardInfos.findIndex((r) => r.token.mint === mint);
|
|
1648
|
+
if (rewardIndex === -1) {
|
|
1649
|
+
throw new Error(`Reward mint ${mint} not found on farm ${farm}`);
|
|
1650
|
+
}
|
|
1651
|
+
const rewardInfo = farmState.rewardInfos[rewardIndex];
|
|
1652
|
+
const treasuryVault = await getTreasuryVaultPDA(
|
|
1653
|
+
KAMINO_FARMS_PROGRAM_ID,
|
|
1654
|
+
farmState.globalConfig,
|
|
1655
|
+
mint
|
|
1656
|
+
);
|
|
1657
|
+
const scopePrices = farmState.scopePrices === DEFAULT_PUBLIC_KEY3 ? KAMINO_FARMS_PROGRAM_ID : farmState.scopePrices;
|
|
1658
|
+
const mode = reserveData.rawData.state.farmCollateral === farm ? "collateral" : reserveData.rawData.state.farmDebt === farm ? "debt" : void 0;
|
|
1659
|
+
const refreshIx = mode ? await this.getRefreshUserFarmCpiData(user, pool, reserve, obligation, userFarm, farm, mode) : void 0;
|
|
1660
|
+
return [
|
|
1661
|
+
...refreshIx ? [refreshIx] : [],
|
|
1662
|
+
this.getCpiData(
|
|
1663
|
+
CpiTypes.K_HARVEST_REWARD,
|
|
1664
|
+
[
|
|
1665
|
+
toCustomAccountMeta(user, true),
|
|
1666
|
+
toCustomAccountMeta(userFarm, true),
|
|
1667
|
+
toCustomAccountMeta(farm, true),
|
|
1668
|
+
toCustomAccountMeta(farmState.globalConfig),
|
|
1669
|
+
toCustomAccountMeta(mint),
|
|
1670
|
+
toCustomAccountMeta(await getAtaAddress(mint, user, tokenProgram), true, {
|
|
1671
|
+
owner: user,
|
|
1672
|
+
mint,
|
|
1673
|
+
tokenProgram
|
|
1674
|
+
}),
|
|
1675
|
+
toCustomAccountMeta(rewardInfo.rewardsVault, true),
|
|
1676
|
+
toCustomAccountMeta(treasuryVault, true),
|
|
1677
|
+
toCustomAccountMeta(farmState.farmVaultsAuthority),
|
|
1678
|
+
toCustomAccountMeta(scopePrices),
|
|
1679
|
+
toCustomAccountMeta(tokenProgram)
|
|
1680
|
+
],
|
|
1681
|
+
numToU64Bytes(rewardIndex),
|
|
1682
|
+
KAMINO_FARMS_PROGRAM_ID
|
|
1683
|
+
)
|
|
1684
|
+
];
|
|
1685
|
+
}
|
|
1686
|
+
async getRequestElevationGroupCpiData(elevationGroup, user, obligation, pool, txId) {
|
|
1687
|
+
const obligationData = await this.data.maybeFetchUserPositionInPool(pool, obligation);
|
|
1688
|
+
const cached = this.getTxUserAccountReserves(txId, obligation);
|
|
1689
|
+
const cleared = this.getTxObligationClearedDebt(txId, obligation);
|
|
1690
|
+
const collateralReserves = [
|
|
1691
|
+
.../* @__PURE__ */ new Set([...obligationData?.deposits.map((x) => x.reserve) ?? [], ...cached.collateral])
|
|
1692
|
+
];
|
|
1693
|
+
const debtReserves = [
|
|
1694
|
+
.../* @__PURE__ */ new Set([...obligationData?.borrows.map((x) => x.reserve) ?? [], ...cached.debt])
|
|
1695
|
+
].filter((r) => !cleared.has(r));
|
|
1696
|
+
return this.getCpiData(
|
|
1697
|
+
CpiTypes.K_REQUEST_ELEVATION_GROUP,
|
|
1698
|
+
[
|
|
1699
|
+
toCustomAccountMeta(user),
|
|
1700
|
+
toCustomAccountMeta(obligation, true),
|
|
1701
|
+
toCustomAccountMeta(pool),
|
|
1702
|
+
...collateralReserves.map((x) => toCustomAccountMeta(x, true)),
|
|
1703
|
+
...debtReserves.map((x) => toCustomAccountMeta(x, true))
|
|
1704
|
+
],
|
|
1705
|
+
new Uint8Array([elevationGroup])
|
|
1706
|
+
);
|
|
1707
|
+
}
|
|
1708
|
+
async getInitAndDepositCpiData(params, userAccountId) {
|
|
1709
|
+
const initCpis = [];
|
|
1710
|
+
if (!await accountExists(this.rpc, params.userAccount)) {
|
|
1711
|
+
initCpis.push(
|
|
1712
|
+
...(await this.getInitUserAccountCpiData(
|
|
1713
|
+
params.pool,
|
|
1714
|
+
params.user,
|
|
1715
|
+
params.payer,
|
|
1716
|
+
userAccountId
|
|
1717
|
+
)).allCpis,
|
|
1718
|
+
await this.getRefreshObligationCpiData(params.txId, params.pool, params.userAccount)
|
|
1719
|
+
);
|
|
1720
|
+
}
|
|
1721
|
+
const reserveData = await this.data.fetchReserve(params.pool, params.reserve);
|
|
1722
|
+
const farmCollateral = reserveData.rawData.state.farmCollateral;
|
|
1723
|
+
if (farmCollateral && farmCollateral !== DEFAULT_PUBLIC_KEY3) {
|
|
1724
|
+
const farmAccounts = await this.accounts.getFarmAccounts(
|
|
1725
|
+
params.pool,
|
|
1726
|
+
params.reserve,
|
|
1727
|
+
params.userAccount,
|
|
1728
|
+
"collateral"
|
|
1729
|
+
);
|
|
1730
|
+
if (!await accountExists(this.rpc, farmAccounts.userFarm.address)) {
|
|
1731
|
+
initCpis.push(
|
|
1732
|
+
await this.getInitObligationFarmsForReserveCpiData(
|
|
1733
|
+
params.user,
|
|
1734
|
+
params.payer,
|
|
1735
|
+
params.userAccount,
|
|
1736
|
+
params.pool,
|
|
1737
|
+
params.reserve,
|
|
1738
|
+
"collateral"
|
|
1739
|
+
)
|
|
1740
|
+
);
|
|
1741
|
+
}
|
|
1742
|
+
}
|
|
1743
|
+
const depositCpis = await this.getDepositCpiData(params);
|
|
1744
|
+
return this.createSplitOperationCpiData(
|
|
1745
|
+
[...initCpis, ...depositCpis.prerequisiteCpis],
|
|
1746
|
+
depositCpis.cpis
|
|
1747
|
+
);
|
|
1748
|
+
}
|
|
1749
|
+
async getInitBorrowPositionCpiData(params, collReserve) {
|
|
1750
|
+
const initCpis = [];
|
|
1751
|
+
const reserveData = await this.data.fetchReserve(params.pool, params.reserve);
|
|
1752
|
+
const farmDebt = reserveData.rawData.state.farmDebt;
|
|
1753
|
+
if (farmDebt && farmDebt !== DEFAULT_PUBLIC_KEY3) {
|
|
1754
|
+
const farmAccounts = await this.accounts.getFarmAccounts(
|
|
1755
|
+
params.pool,
|
|
1756
|
+
params.reserve,
|
|
1757
|
+
params.userAccount,
|
|
1758
|
+
"debt"
|
|
1759
|
+
);
|
|
1760
|
+
if (!await accountExists(this.rpc, farmAccounts.userFarm.address)) {
|
|
1761
|
+
initCpis.push(
|
|
1762
|
+
await this.getInitObligationFarmsForReserveCpiData(
|
|
1763
|
+
params.user,
|
|
1764
|
+
params.payer,
|
|
1765
|
+
params.userAccount,
|
|
1766
|
+
params.pool,
|
|
1767
|
+
params.reserve,
|
|
1768
|
+
"debt"
|
|
1769
|
+
)
|
|
1770
|
+
);
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1773
|
+
const debtReserveData = await this.data.fetchReserve(params.pool, params.reserve);
|
|
1774
|
+
const market = await this.data.fetchMarket(params.pool);
|
|
1775
|
+
const requestedBorrowBaseUnits = params.baseUnitAmount && params.baseUnitAmount !== "all" ? params.baseUnitAmount : typeof params.uiAmount === "number" ? new BN5(Math.floor(params.uiAmount * Math.pow(10, debtReserveData.mint.mintDecimals))) : void 0;
|
|
1776
|
+
const collReserveData = await this.data.fetchReserve(params.pool, collReserve);
|
|
1777
|
+
const availableElevationGroups = collReserveData.config.emodes?.filter(
|
|
1778
|
+
(x) => x.debtReserve === params.reserve
|
|
1779
|
+
);
|
|
1780
|
+
if (availableElevationGroups?.length) {
|
|
1781
|
+
const sortedGroups = [...availableElevationGroups].filter((g) => g.id !== void 0).sort((a, b) => b.ltvPct - a.ltvPct);
|
|
1782
|
+
let selectedGroup;
|
|
1783
|
+
for (const group of sortedGroups) {
|
|
1784
|
+
const [available] = debtReserveData.rawData.getLiquidityAvailableForDebtReserveGivenCaps(
|
|
1785
|
+
market,
|
|
1786
|
+
[group.id],
|
|
1787
|
+
[collReserve]
|
|
1788
|
+
);
|
|
1789
|
+
const hasCapacity = requestedBorrowBaseUnits ? available.gte(requestedBorrowBaseUnits.toString()) : available.gt(0);
|
|
1790
|
+
if (hasCapacity) {
|
|
1791
|
+
selectedGroup = group.id;
|
|
1792
|
+
break;
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
if (selectedGroup !== void 0) {
|
|
1796
|
+
initCpis.push(
|
|
1797
|
+
...await this.getRefreshCpisIfNeeded(
|
|
1798
|
+
params.txId,
|
|
1799
|
+
params.pool,
|
|
1800
|
+
collReserve,
|
|
1801
|
+
params.userAccount
|
|
1802
|
+
)
|
|
1803
|
+
);
|
|
1804
|
+
initCpis.push(
|
|
1805
|
+
await this.getRequestElevationGroupCpiData(
|
|
1806
|
+
selectedGroup,
|
|
1807
|
+
params.user,
|
|
1808
|
+
params.userAccount,
|
|
1809
|
+
params.pool,
|
|
1810
|
+
params.txId
|
|
1811
|
+
)
|
|
1812
|
+
);
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
const borrowCpis = await this.getBorrowCpiData(params);
|
|
1816
|
+
return this.createSplitOperationCpiData(
|
|
1817
|
+
[...initCpis, ...borrowCpis.prerequisiteCpis],
|
|
1818
|
+
borrowCpis.cpis
|
|
1819
|
+
);
|
|
1820
|
+
}
|
|
1821
|
+
async getDepositCpiData(params) {
|
|
1822
|
+
const refreshCpis = await this.getRefreshCpisIfNeeded(
|
|
1823
|
+
params.txId,
|
|
1824
|
+
params.pool,
|
|
1825
|
+
params.reserve,
|
|
1826
|
+
params.userAccount
|
|
1827
|
+
);
|
|
1828
|
+
const details = await this.accounts.reserveInteractionDetails(
|
|
1829
|
+
params.user,
|
|
1830
|
+
params.pool,
|
|
1831
|
+
params.reserve,
|
|
1832
|
+
params.userAccount,
|
|
1833
|
+
typeof params.uiAmount === "number" ? params.uiAmount : void 0,
|
|
1834
|
+
params.baseUnitAmount instanceof BN5 ? params.baseUnitAmount : void 0
|
|
1835
|
+
);
|
|
1836
|
+
const farms = await this.accounts.getFarmAccounts(
|
|
1837
|
+
params.pool,
|
|
1838
|
+
params.reserve,
|
|
1839
|
+
params.userAccount,
|
|
1840
|
+
"collateral"
|
|
1841
|
+
);
|
|
1842
|
+
this.registerTxReserve(
|
|
1843
|
+
params.txId,
|
|
1844
|
+
params.pool,
|
|
1845
|
+
params.reserve,
|
|
1846
|
+
params.userAccount,
|
|
1847
|
+
"collateral"
|
|
1848
|
+
);
|
|
1849
|
+
return this.createSplitOperationCpiData(refreshCpis, [
|
|
1850
|
+
this.getCpiData(
|
|
1851
|
+
CpiTypes.K_DEPOSIT,
|
|
1852
|
+
[
|
|
1853
|
+
details.signer,
|
|
1854
|
+
details.obligation,
|
|
1855
|
+
details.lendingMarket,
|
|
1856
|
+
details.lendingMarketAuthority,
|
|
1857
|
+
details.reserve,
|
|
1858
|
+
details.reserveLiquidityMint,
|
|
1859
|
+
details.reserveLiquiditySupply,
|
|
1860
|
+
details.reserveCollateralMint,
|
|
1861
|
+
details.reserveCollateralSupply,
|
|
1862
|
+
details.userLiquidityTa,
|
|
1863
|
+
this.emptyAccountMeta(),
|
|
1864
|
+
details.collateralMintTokenProgram,
|
|
1865
|
+
details.liquidityMintTokenProgram,
|
|
1866
|
+
IX_SYSVAR_META,
|
|
1867
|
+
farms.userFarm,
|
|
1868
|
+
farms.farm,
|
|
1869
|
+
details.farmsProgram
|
|
1870
|
+
],
|
|
1871
|
+
details.baseUnitAmount ? numToU64Bytes(details.baseUnitAmount) : void 0,
|
|
1872
|
+
void 0,
|
|
1873
|
+
this.getUserAccountCacheInvalidations(params.userAccount)
|
|
1874
|
+
)
|
|
1875
|
+
]);
|
|
1876
|
+
}
|
|
1877
|
+
async getWithdrawCpiData(params) {
|
|
1878
|
+
const refreshCpis = await this.getRefreshCpisIfNeeded(
|
|
1879
|
+
params.txId,
|
|
1880
|
+
params.pool,
|
|
1881
|
+
params.reserve,
|
|
1882
|
+
params.userAccount
|
|
1883
|
+
);
|
|
1884
|
+
const withdrawAll = params.uiAmount === "all" || params.baseUnitAmount === "all";
|
|
1885
|
+
const details = await this.accounts.reserveInteractionDetails(
|
|
1886
|
+
params.user,
|
|
1887
|
+
params.pool,
|
|
1888
|
+
params.reserve,
|
|
1889
|
+
params.userAccount,
|
|
1890
|
+
typeof params.uiAmount === "number" ? params.uiAmount : void 0,
|
|
1891
|
+
params.baseUnitAmount instanceof BN5 ? params.baseUnitAmount : void 0
|
|
1892
|
+
);
|
|
1893
|
+
const farms = await this.accounts.getFarmAccounts(
|
|
1894
|
+
params.pool,
|
|
1895
|
+
params.reserve,
|
|
1896
|
+
params.userAccount,
|
|
1897
|
+
"collateral"
|
|
1898
|
+
);
|
|
1899
|
+
let collateralBytes;
|
|
1900
|
+
if (withdrawAll) {
|
|
1901
|
+
collateralBytes = numToU64Bytes(U64_MAX_BN);
|
|
1902
|
+
} else if (details.baseUnitAmount) {
|
|
1903
|
+
const reserveData = await this.data.fetchReserve(params.pool, params.reserve);
|
|
1904
|
+
const collateralAmount = liquidityToCollateral(reserveData, details.baseUnitAmount.toNumber()) + 1;
|
|
1905
|
+
collateralBytes = numToU64Bytes(collateralAmount);
|
|
1906
|
+
}
|
|
1907
|
+
this.registerTxReserve(
|
|
1908
|
+
params.txId,
|
|
1909
|
+
params.pool,
|
|
1910
|
+
params.reserve,
|
|
1911
|
+
params.userAccount,
|
|
1912
|
+
"collateral"
|
|
1913
|
+
);
|
|
1914
|
+
return this.createSplitOperationCpiData(refreshCpis, [
|
|
1915
|
+
this.getCpiData(
|
|
1916
|
+
CpiTypes.K_WITHDRAW,
|
|
1917
|
+
[
|
|
1918
|
+
details.signer,
|
|
1919
|
+
details.obligation,
|
|
1920
|
+
details.lendingMarket,
|
|
1921
|
+
details.lendingMarketAuthority,
|
|
1922
|
+
details.reserve,
|
|
1923
|
+
details.reserveLiquidityMint,
|
|
1924
|
+
details.reserveCollateralSupply,
|
|
1925
|
+
details.reserveCollateralMint,
|
|
1926
|
+
details.reserveLiquiditySupply,
|
|
1927
|
+
details.userLiquidityTa,
|
|
1928
|
+
this.emptyAccountMeta(),
|
|
1929
|
+
details.collateralMintTokenProgram,
|
|
1930
|
+
details.liquidityMintTokenProgram,
|
|
1931
|
+
IX_SYSVAR_META,
|
|
1932
|
+
farms.userFarm,
|
|
1933
|
+
farms.farm,
|
|
1934
|
+
details.farmsProgram
|
|
1935
|
+
],
|
|
1936
|
+
collateralBytes,
|
|
1937
|
+
void 0,
|
|
1938
|
+
this.getUserAccountCacheInvalidations(params.userAccount)
|
|
1939
|
+
)
|
|
1940
|
+
]);
|
|
1941
|
+
}
|
|
1942
|
+
async getBorrowCpiData(params) {
|
|
1943
|
+
const refreshCpis = await this.getRefreshCpisIfNeeded(
|
|
1944
|
+
params.txId,
|
|
1945
|
+
params.pool,
|
|
1946
|
+
params.reserve,
|
|
1947
|
+
params.userAccount
|
|
1948
|
+
);
|
|
1949
|
+
const details = await this.accounts.reserveInteractionDetails(
|
|
1950
|
+
params.user,
|
|
1951
|
+
params.pool,
|
|
1952
|
+
params.reserve,
|
|
1953
|
+
params.userAccount,
|
|
1954
|
+
typeof params.uiAmount === "number" ? params.uiAmount : void 0
|
|
1955
|
+
);
|
|
1956
|
+
const farms = await this.accounts.getFarmAccounts(
|
|
1957
|
+
params.pool,
|
|
1958
|
+
params.reserve,
|
|
1959
|
+
params.userAccount,
|
|
1960
|
+
"debt"
|
|
1961
|
+
);
|
|
1962
|
+
this.registerTxReserve(params.txId, params.pool, params.reserve, params.userAccount, "debt");
|
|
1963
|
+
return this.createSplitOperationCpiData(refreshCpis, [
|
|
1964
|
+
this.getCpiData(
|
|
1965
|
+
CpiTypes.K_BORROW,
|
|
1966
|
+
[
|
|
1967
|
+
details.signer,
|
|
1968
|
+
details.obligation,
|
|
1969
|
+
details.lendingMarket,
|
|
1970
|
+
details.lendingMarketAuthority,
|
|
1971
|
+
details.reserve,
|
|
1972
|
+
details.reserveLiquidityMint,
|
|
1973
|
+
details.reserveLiquiditySupply,
|
|
1974
|
+
details.reserveFeeVault,
|
|
1975
|
+
details.userLiquidityTa,
|
|
1976
|
+
this.emptyAccountMeta(),
|
|
1977
|
+
details.liquidityMintTokenProgram,
|
|
1978
|
+
IX_SYSVAR_META,
|
|
1979
|
+
farms.userFarm,
|
|
1980
|
+
farms.farm,
|
|
1981
|
+
details.farmsProgram
|
|
1982
|
+
],
|
|
1983
|
+
details.baseUnitAmount ? numToU64Bytes(details.baseUnitAmount) : void 0,
|
|
1984
|
+
void 0,
|
|
1985
|
+
this.getUserAccountCacheInvalidations(params.userAccount)
|
|
1986
|
+
)
|
|
1987
|
+
]);
|
|
1988
|
+
}
|
|
1989
|
+
async getRepayCpiData(params) {
|
|
1990
|
+
this.registerTxReserve(params.txId, params.pool, params.reserve, params.userAccount, "debt");
|
|
1991
|
+
const refreshCpis = await this.getRefreshCpisIfNeeded(
|
|
1992
|
+
params.txId,
|
|
1993
|
+
params.pool,
|
|
1994
|
+
params.reserve,
|
|
1995
|
+
params.userAccount
|
|
1996
|
+
);
|
|
1997
|
+
const details = await this.accounts.reserveInteractionDetails(
|
|
1998
|
+
params.user,
|
|
1999
|
+
params.pool,
|
|
2000
|
+
params.reserve,
|
|
2001
|
+
params.userAccount,
|
|
2002
|
+
typeof params.uiAmount === "number" ? params.uiAmount : void 0
|
|
2003
|
+
);
|
|
2004
|
+
const farms = await this.accounts.getFarmAccounts(
|
|
2005
|
+
params.pool,
|
|
2006
|
+
params.reserve,
|
|
2007
|
+
params.userAccount,
|
|
2008
|
+
"debt"
|
|
2009
|
+
);
|
|
2010
|
+
const repayAmountBytes = params.full ? numToU64Bytes(U64_MAX_BN) : params.baseUnitAmount instanceof BN5 ? numToU64Bytes(params.baseUnitAmount) : details.baseUnitAmount ? numToU64Bytes(details.baseUnitAmount) : void 0;
|
|
2011
|
+
return this.createSplitOperationCpiData(refreshCpis, [
|
|
2012
|
+
this.getCpiData(
|
|
2013
|
+
CpiTypes.K_REPAY,
|
|
2014
|
+
[
|
|
2015
|
+
details.signer,
|
|
2016
|
+
details.obligation,
|
|
2017
|
+
details.lendingMarket,
|
|
2018
|
+
details.reserve,
|
|
2019
|
+
details.reserveLiquidityMint,
|
|
2020
|
+
details.reserveLiquiditySupply,
|
|
2021
|
+
details.userLiquidityTa,
|
|
2022
|
+
details.liquidityMintTokenProgram,
|
|
2023
|
+
IX_SYSVAR_META,
|
|
2024
|
+
farms.userFarm,
|
|
2025
|
+
farms.farm,
|
|
2026
|
+
details.lendingMarketAuthority,
|
|
2027
|
+
details.farmsProgram
|
|
2028
|
+
],
|
|
2029
|
+
repayAmountBytes,
|
|
2030
|
+
void 0,
|
|
2031
|
+
this.getUserAccountCacheInvalidations(params.userAccount)
|
|
2032
|
+
)
|
|
2033
|
+
]);
|
|
2034
|
+
}
|
|
2035
|
+
};
|
|
2036
|
+
|
|
2037
|
+
// ../../shared/lending-platforms/src/data/accounts/kamino.ts
|
|
2038
|
+
import {
|
|
2039
|
+
DEFAULT_PUBLIC_KEY as DEFAULT_PUBLIC_KEY4,
|
|
2040
|
+
lendingMarketAuthPda as lendingMarketAuthPda2,
|
|
2041
|
+
obligationFarmStatePda,
|
|
2042
|
+
PROGRAM_ID as PROGRAM_ID4,
|
|
2043
|
+
userMetadataPda as userMetadataPda3,
|
|
2044
|
+
VanillaObligation as VanillaObligation3
|
|
2045
|
+
} from "@kamino-finance/klend-sdk";
|
|
2046
|
+
import { TOKEN_PROGRAM_ADDRESS as TOKEN_PROGRAM_ADDRESS2 } from "@solana-program/token";
|
|
2047
|
+
|
|
2048
|
+
// ../../shared/lending-platforms/src/data/accounts/lpAccountsBase.ts
|
|
2049
|
+
var LpAccountsBase = class {
|
|
2050
|
+
constructor(data) {
|
|
2051
|
+
this.data = data;
|
|
2052
|
+
}
|
|
2053
|
+
};
|
|
2054
|
+
|
|
2055
|
+
// ../../shared/lending-platforms/src/data/accounts/kamino.ts
|
|
2056
|
+
var KaminoAccounts = class extends LpAccountsBase {
|
|
2057
|
+
async getUserAccountAddress(pool, user, id) {
|
|
2058
|
+
const market = await this.data.fetchMarket(pool);
|
|
2059
|
+
const obligationType = new VanillaObligation3(market.programId, id);
|
|
2060
|
+
return await obligationType.toPda(pool, user);
|
|
2061
|
+
}
|
|
2062
|
+
async getUserMetadataAddress(user) {
|
|
2063
|
+
return (await userMetadataPda3(user, PROGRAM_ID4))[0];
|
|
2064
|
+
}
|
|
2065
|
+
/**
|
|
2066
|
+
* Gets the obligation farm accounts for a reserve.
|
|
2067
|
+
*/
|
|
2068
|
+
async getFarmAccounts(pool, reserve, obligation, farmMode) {
|
|
2069
|
+
const emptyFarms = {
|
|
2070
|
+
userFarm: toCustomAccountMeta(PROGRAM_ID4),
|
|
2071
|
+
farm: toCustomAccountMeta(PROGRAM_ID4)
|
|
2072
|
+
};
|
|
2073
|
+
const reserveData = await this.data.fetchReserve(pool, reserve);
|
|
2074
|
+
if (!reserveData) {
|
|
2075
|
+
return emptyFarms;
|
|
2076
|
+
}
|
|
2077
|
+
const farmAddress = farmMode === "collateral" ? reserveData.rawData.state.farmCollateral : reserveData.rawData.state.farmDebt;
|
|
2078
|
+
if (!farmAddress || farmAddress === DEFAULT_PUBLIC_KEY4) {
|
|
2079
|
+
return emptyFarms;
|
|
2080
|
+
}
|
|
2081
|
+
const obligationFarmUserState = await obligationFarmStatePda(farmAddress, obligation);
|
|
2082
|
+
return {
|
|
2083
|
+
userFarm: toCustomAccountMeta(obligationFarmUserState, true),
|
|
2084
|
+
farm: toCustomAccountMeta(farmAddress, true)
|
|
2085
|
+
};
|
|
2086
|
+
}
|
|
2087
|
+
/**
|
|
2088
|
+
* Returns the obligationFarmUserState PDA addresses for all active farms
|
|
2089
|
+
* (collateral and debt) on a reserve. The farm addresses themselves live on
|
|
2090
|
+
* the Kamino LUTs; only the user-specific state needs the per-token LUT.
|
|
2091
|
+
*/
|
|
2092
|
+
async getUserFarmAddresses(pool, reserve, obligation) {
|
|
2093
|
+
const addresses = [];
|
|
2094
|
+
for (const mode of ["collateral", "debt"]) {
|
|
2095
|
+
const { farm, userFarm } = await this.getFarmAccounts(pool, reserve, obligation, mode);
|
|
2096
|
+
if (farm.address !== PROGRAM_ID4) {
|
|
2097
|
+
addresses.push(userFarm.address);
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
return addresses;
|
|
2101
|
+
}
|
|
2102
|
+
/**
|
|
2103
|
+
* Get all relevant account metas needed for interacting with the Kamino lending market.
|
|
2104
|
+
*/
|
|
2105
|
+
async reserveInteractionDetails(user, pool, reserve, obligation, amount, baseUnitAmountOverride) {
|
|
2106
|
+
const reserveData = await this.data.fetchReserve(pool, reserve);
|
|
2107
|
+
const liquidityMint = reserveData.mint.mint;
|
|
2108
|
+
const liquidityMintTokenProgram = reserveData.mint.mintTokenProgram;
|
|
2109
|
+
const collateralMint = reserveData.rawData.state.collateral.mintPubkey;
|
|
2110
|
+
const collateralMintTokenProgram = TOKEN_PROGRAM_ADDRESS2;
|
|
2111
|
+
const userLiquidityTaSeeds = {
|
|
2112
|
+
mint: liquidityMint,
|
|
2113
|
+
owner: user,
|
|
2114
|
+
tokenProgram: liquidityMintTokenProgram
|
|
2115
|
+
};
|
|
2116
|
+
const userLiquidityTa = await getAtaAddress(liquidityMint, user, liquidityMintTokenProgram);
|
|
2117
|
+
const userCollateralTaSeeds = {
|
|
2118
|
+
mint: collateralMint,
|
|
2119
|
+
owner: user,
|
|
2120
|
+
tokenProgram: collateralMintTokenProgram
|
|
2121
|
+
};
|
|
2122
|
+
const userCollateralTa = await getAtaAddress(collateralMint, user, collateralMintTokenProgram);
|
|
2123
|
+
const reserveLiquiditySupply = reserveData.rawData.state.liquidity.supplyVault;
|
|
2124
|
+
const reserveCollateralSupply = reserveData.rawData.state.collateral.supplyVault;
|
|
2125
|
+
return {
|
|
2126
|
+
baseUnitAmount: baseUnitAmountOverride !== void 0 ? baseUnitAmountOverride : amount !== void 0 ? fromUiAmount(amount, reserveData.mint.mintDecimals) : void 0,
|
|
2127
|
+
signer: toCustomAccountMeta(user, true),
|
|
2128
|
+
obligation: obligation ? toCustomAccountMeta(obligation, true) : void 0,
|
|
2129
|
+
reserve: toCustomAccountMeta(reserve, true),
|
|
2130
|
+
reserveFeeVault: toCustomAccountMeta(reserveData.rawData.state.liquidity.feeVault, true),
|
|
2131
|
+
reserveLiquidityMint: toCustomAccountMeta(liquidityMint),
|
|
2132
|
+
reserveLiquiditySupply: toCustomAccountMeta(reserveLiquiditySupply, true),
|
|
2133
|
+
reserveCollateralMint: toCustomAccountMeta(collateralMint, true),
|
|
2134
|
+
reserveCollateralSupply: toCustomAccountMeta(reserveCollateralSupply, true),
|
|
2135
|
+
lendingMarket: toCustomAccountMeta(pool),
|
|
2136
|
+
lendingMarketAuthority: toCustomAccountMeta((await lendingMarketAuthPda2(pool))[0]),
|
|
2137
|
+
userLiquidityTa: toCustomAccountMeta(userLiquidityTa, true, userLiquidityTaSeeds),
|
|
2138
|
+
userCollateralTa: toCustomAccountMeta(userCollateralTa, true, userCollateralTaSeeds),
|
|
2139
|
+
liquidityMintTokenProgram: toCustomAccountMeta(liquidityMintTokenProgram),
|
|
2140
|
+
collateralMintTokenProgram: toCustomAccountMeta(collateralMintTokenProgram),
|
|
2141
|
+
farmsProgram: toCustomAccountMeta(KAMINO_FARMS_PROGRAM_ID)
|
|
2142
|
+
};
|
|
2143
|
+
}
|
|
2144
|
+
};
|
|
2145
|
+
|
|
2146
|
+
// ../../shared/lending-platforms/src/services/flashLoan/kamino.ts
|
|
2147
|
+
import { BN as BN6 } from "@anchor-lang/core";
|
|
2148
|
+
import Decimal5 from "decimal.js";
|
|
2149
|
+
import { none } from "@solana/kit";
|
|
2150
|
+
import {
|
|
2151
|
+
getBorrowFlashLoanInstruction,
|
|
2152
|
+
getRepayFlashLoanInstruction,
|
|
2153
|
+
lendingMarketAuthPda as lendingMarketAuthPda3,
|
|
2154
|
+
PROGRAM_ID as PROGRAM_ID5
|
|
2155
|
+
} from "@kamino-finance/klend-sdk";
|
|
2156
|
+
|
|
2157
|
+
// ../../shared/lending-platforms/src/services/flashLoan/flashLoanBase.ts
|
|
2158
|
+
var FlashLoanBase = class {
|
|
2159
|
+
constructor(data) {
|
|
2160
|
+
this.data = data;
|
|
2161
|
+
}
|
|
2162
|
+
};
|
|
2163
|
+
|
|
2164
|
+
// ../../shared/lending-platforms/src/services/flashLoan/kamino.ts
|
|
2165
|
+
function stripAccountSigners(ix) {
|
|
2166
|
+
if (!ix.accounts) return ix;
|
|
2167
|
+
return {
|
|
2168
|
+
...ix,
|
|
2169
|
+
accounts: ix.accounts.map((account) => {
|
|
2170
|
+
if (!("signer" in account)) return account;
|
|
2171
|
+
const { signer: _signer, ...rest } = account;
|
|
2172
|
+
return rest;
|
|
2173
|
+
})
|
|
2174
|
+
};
|
|
2175
|
+
}
|
|
2176
|
+
var KaminoFlashLoan = class extends FlashLoanBase {
|
|
2177
|
+
async getFlashBorrowIx(params) {
|
|
2178
|
+
const { reserve, lendingMarketAuthority, destinationAta } = await this.resolveSharedAccounts(params);
|
|
2179
|
+
return stripAccountSigners(
|
|
2180
|
+
getBorrowFlashLoanInstruction({
|
|
2181
|
+
userTransferAuthority: createSignerFromAddress(params.user),
|
|
2182
|
+
lendingMarketAuthority,
|
|
2183
|
+
lendingMarketAddress: params.pool,
|
|
2184
|
+
reserve: reserve.rawData,
|
|
2185
|
+
amountLamports: new Decimal5(params.amountBaseUnits.toString()),
|
|
2186
|
+
destinationAta,
|
|
2187
|
+
referrerAccount: none(),
|
|
2188
|
+
referrerTokenState: none(),
|
|
2189
|
+
programId: PROGRAM_ID5
|
|
2190
|
+
})
|
|
2191
|
+
);
|
|
2192
|
+
}
|
|
2193
|
+
async getAvailableFlashBorrowAmount(pool, reserve) {
|
|
2194
|
+
const reserveData = await this.data.fetchReserve(pool, reserve);
|
|
2195
|
+
return new BN6(reserveData.rawData.getLiquidityAvailableAmount().toFixed(0));
|
|
2196
|
+
}
|
|
2197
|
+
async getFlashLoanFeeRate(pool, reserve) {
|
|
2198
|
+
const reserveData = await this.data.fetchReserve(pool, reserve);
|
|
2199
|
+
return reserveData.config.flashLoanFeePct;
|
|
2200
|
+
}
|
|
2201
|
+
async getFlashRepayIx(params) {
|
|
2202
|
+
const { reserve, lendingMarketAuthority, destinationAta } = await this.resolveSharedAccounts(params);
|
|
2203
|
+
return stripAccountSigners(
|
|
2204
|
+
getRepayFlashLoanInstruction({
|
|
2205
|
+
borrowIxIndex: params.borrowIxIndex,
|
|
2206
|
+
userTransferAuthority: createSignerFromAddress(params.user),
|
|
2207
|
+
lendingMarketAuthority,
|
|
2208
|
+
lendingMarketAddress: params.pool,
|
|
2209
|
+
reserve: reserve.rawData,
|
|
2210
|
+
amountLamports: new Decimal5(params.amountBaseUnits.toString()),
|
|
2211
|
+
userSourceLiquidity: params.userSourceLiquidity ?? destinationAta,
|
|
2212
|
+
referrerAccount: none(),
|
|
2213
|
+
referrerTokenState: none(),
|
|
2214
|
+
programId: PROGRAM_ID5
|
|
2215
|
+
})
|
|
2216
|
+
);
|
|
2217
|
+
}
|
|
2218
|
+
async resolveSharedAccounts(params) {
|
|
2219
|
+
const reserve = await this.data.fetchReserve(params.pool, params.reserve);
|
|
2220
|
+
const [lendingMarketAuthority] = await lendingMarketAuthPda3(params.pool);
|
|
2221
|
+
const liquidityMint = reserve.mint.mint;
|
|
2222
|
+
const tokenProgram = mints.get(liquidityMint)?.tokenProgram;
|
|
2223
|
+
if (!tokenProgram) {
|
|
2224
|
+
throw new Error(`Unsupported liquidity mint for flash loan: ${liquidityMint}`);
|
|
2225
|
+
}
|
|
2226
|
+
const destinationAta = params.destinationAta ?? await getAtaAddress(liquidityMint, params.user, tokenProgram);
|
|
2227
|
+
return { reserve, lendingMarketAuthority, destinationAta };
|
|
2228
|
+
}
|
|
2229
|
+
};
|
|
2230
|
+
|
|
2231
|
+
// ../../shared/lending-platforms/src/services/client/kamino.ts
|
|
2232
|
+
var KaminoClient = class extends LendingPlatformClientBase {
|
|
2233
|
+
constructor(rpcUrl = getRpcUrl(ENVIRONMENT), rpcUrls = [rpcUrl]) {
|
|
2234
|
+
super(rpcUrl, rpcUrls);
|
|
2235
|
+
this.data = new KaminoData(rpcUrl, void 0, rpcUrls);
|
|
2236
|
+
this.accounts = new KaminoAccounts(this.data);
|
|
2237
|
+
this.ix = new KaminoInstructions(this.rpc, rpcUrl, this.data, this.accounts);
|
|
2238
|
+
}
|
|
2239
|
+
async refreshData(pools) {
|
|
2240
|
+
this.data.clearCache();
|
|
2241
|
+
await this.data.load(pools);
|
|
2242
|
+
}
|
|
2243
|
+
getFlashLoan() {
|
|
2244
|
+
return new KaminoFlashLoan(this.data);
|
|
2245
|
+
}
|
|
2246
|
+
/**
|
|
2247
|
+
* Kamino's `RepayObligationLiquidityV2` interprets `u64::MAX` as "repay
|
|
2248
|
+
* the obligation's full debt for this reserve" — letting the on-chain
|
|
2249
|
+
* handler clear interest-accrual dust between the off-chain quote and
|
|
2250
|
+
* settlement. The flash-borrow over-borrows by a slippage buffer to fund
|
|
2251
|
+
* this; the post-repay surplus is swept into the yielding bank.
|
|
2252
|
+
*/
|
|
2253
|
+
getRepayAllSentinel() {
|
|
2254
|
+
return U64_MAX_BN;
|
|
2255
|
+
}
|
|
2256
|
+
async getAvailableUserAccountId(pool, user, excludeUserAccounts = []) {
|
|
2257
|
+
const positions = await this.data.fetchAllUserPositionsForUserInPool(pool, user);
|
|
2258
|
+
const positionsByAddress = new Map(positions.map((position) => [position.address, position]));
|
|
2259
|
+
const excludeSet = new Set(excludeUserAccounts);
|
|
2260
|
+
for (let userAccountId = 0; ; userAccountId++) {
|
|
2261
|
+
const userAccount = await this.accounts.getUserAccountAddress(pool, user, userAccountId);
|
|
2262
|
+
if (excludeSet.has(userAccount)) {
|
|
2263
|
+
continue;
|
|
2264
|
+
}
|
|
2265
|
+
const existingPosition = positionsByAddress.get(userAccount);
|
|
2266
|
+
if (!existingPosition || this.isInactiveUserAccount(existingPosition)) {
|
|
2267
|
+
return userAccountId;
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2271
|
+
/**
|
|
2272
|
+
* Returns claimable rewards across all kamino farms tied to this obligation:
|
|
2273
|
+
*
|
|
2274
|
+
* - **Obligation farms** (klend reserve `farmCollateral`/`farmDebt`):
|
|
2275
|
+
* UserState.owner = obligation owner (the lyc-token PDA),
|
|
2276
|
+
* UserState.delegatee = the obligation itself.
|
|
2277
|
+
* - **Direct/extra farms** (e.g. paired-reserve incentives): the lyc-token
|
|
2278
|
+
* PDA stakes directly in the farms program.
|
|
2279
|
+
* UserState.owner = UserState.delegatee = lyc-token PDA.
|
|
2280
|
+
*
|
|
2281
|
+
* The farms SDK filters UserStates by memcmp against `owner` (offset 48),
|
|
2282
|
+
* so we query by the obligation's owner and then accept any UserState whose
|
|
2283
|
+
* `delegatee` is either the obligation or the owner itself. In both cases
|
|
2284
|
+
* `userFarm.userStateAddress` is the correct UserState account for the
|
|
2285
|
+
* `HarvestReward` CPI; deriving via `obligationFarmStatePda` would be wrong
|
|
2286
|
+
* for direct farms (different seed scheme).
|
|
2287
|
+
*/
|
|
2288
|
+
async getOutstandingIncentives(userAccount, minUiAmount = 0, log) {
|
|
2289
|
+
const obligationOwner = await this.fetchObligationOwner(userAccount);
|
|
2290
|
+
if (!obligationOwner) {
|
|
2291
|
+
log?.(` [getOutstandingIncentives] no obligation owner found for ${userAccount}`);
|
|
2292
|
+
return [];
|
|
2293
|
+
}
|
|
2294
|
+
const allOwnerFarms = await this.data.fetchUserActiveIncentives(obligationOwner);
|
|
2295
|
+
log?.(
|
|
2296
|
+
` [getOutstandingIncentives] found ${allOwnerFarms.length} farm(s) owned by ${obligationOwner.slice(0, 6)}\u2026`
|
|
2297
|
+
);
|
|
2298
|
+
const userFarms = allOwnerFarms.filter(
|
|
2299
|
+
(uf) => uf.userState.delegatee === userAccount || uf.userState.delegatee === obligationOwner
|
|
2300
|
+
);
|
|
2301
|
+
const filteredOut = allOwnerFarms.length - userFarms.length;
|
|
2302
|
+
if (filteredOut > 0) {
|
|
2303
|
+
log?.(
|
|
2304
|
+
` [getOutstandingIncentives] ${filteredOut} farm(s) skipped \u2014 delegatee matched neither userAccount (${userAccount.slice(0, 6)}\u2026) nor owner`
|
|
2305
|
+
);
|
|
2306
|
+
}
|
|
2307
|
+
if (userFarms.length === 0) {
|
|
2308
|
+
log?.(` [getOutstandingIncentives] no matching farms for userAccount`);
|
|
2309
|
+
return [];
|
|
2310
|
+
}
|
|
2311
|
+
const farmStates = await this.data.fetchFarms(userFarms.map((uf) => uf.farm));
|
|
2312
|
+
const decimalsByFarmAndMint = /* @__PURE__ */ new Map();
|
|
2313
|
+
farmStates.forEach((farmState, i) => {
|
|
2314
|
+
const farm = userFarms[i].farm;
|
|
2315
|
+
for (const rewardInfo of farmState.rewardInfos) {
|
|
2316
|
+
decimalsByFarmAndMint.set(
|
|
2317
|
+
`${farm}:${rewardInfo.token.mint}`,
|
|
2318
|
+
rewardInfo.token.decimals.toNumber()
|
|
2319
|
+
);
|
|
2320
|
+
}
|
|
2321
|
+
});
|
|
2322
|
+
const incentives = [];
|
|
2323
|
+
for (const userFarm of userFarms) {
|
|
2324
|
+
log?.(
|
|
2325
|
+
` [getOutstandingIncentives] farm ${userFarm.farm.slice(0, 6)}\u2026 userFarm ${userFarm.userStateAddress.slice(0, 6)}\u2026 delegatee ${userFarm.userState.delegatee.slice(0, 6)}\u2026 ${userFarm.pendingRewards.length} pending reward(s)`
|
|
2326
|
+
);
|
|
2327
|
+
for (const reward of userFarm.pendingRewards) {
|
|
2328
|
+
const amount = reward.cumulatedPendingRewards.toNumber();
|
|
2329
|
+
const decimals = decimalsByFarmAndMint.get(`${userFarm.farm}:${reward.rewardTokenMint}`) ?? 0;
|
|
2330
|
+
const uiAmount = amount / 10 ** decimals;
|
|
2331
|
+
if (amount <= 0) {
|
|
2332
|
+
log?.(` reward ${reward.rewardTokenMint.slice(0, 6)}\u2026 \u2014 skipped (amount=0)`);
|
|
2333
|
+
continue;
|
|
2334
|
+
}
|
|
2335
|
+
if (uiAmount < minUiAmount) {
|
|
2336
|
+
log?.(
|
|
2337
|
+
` reward ${reward.rewardTokenMint.slice(0, 6)}\u2026 \u2014 skipped (uiAmount=${uiAmount.toFixed(4)} < minUiAmount=${minUiAmount})`
|
|
2338
|
+
);
|
|
2339
|
+
continue;
|
|
2340
|
+
}
|
|
2341
|
+
log?.(
|
|
2342
|
+
` reward ${reward.rewardTokenMint.slice(0, 6)}\u2026 \u2014 claimable uiAmount=${uiAmount.toFixed(4)}`
|
|
2343
|
+
);
|
|
2344
|
+
incentives.push({
|
|
2345
|
+
mint: reward.rewardTokenMint,
|
|
2346
|
+
amount,
|
|
2347
|
+
decimals,
|
|
2348
|
+
uiAmount,
|
|
2349
|
+
claimAccounts: {
|
|
2350
|
+
farm: userFarm.farm,
|
|
2351
|
+
userFarm: userFarm.userStateAddress
|
|
2352
|
+
}
|
|
2353
|
+
});
|
|
2354
|
+
}
|
|
2355
|
+
}
|
|
2356
|
+
return incentives;
|
|
2357
|
+
}
|
|
2358
|
+
/**
|
|
2359
|
+
* Reads the klend obligation account and returns its `owner` field (the
|
|
2360
|
+
* authority that opened the obligation — for LYC this is the lyc-token PDA).
|
|
2361
|
+
* Returns null when the account doesn't exist on-chain (stale protocolUserAcc).
|
|
2362
|
+
*/
|
|
2363
|
+
async fetchObligationOwner(userAccount) {
|
|
2364
|
+
const obligation = await Obligation.fetch(this.rpc, userAccount);
|
|
2365
|
+
return obligation ? obligation.owner : null;
|
|
2366
|
+
}
|
|
2367
|
+
isInactiveUserAccount(position) {
|
|
2368
|
+
return [...position.deposits, ...position.borrows].every((entry) => entry.amount.isZero());
|
|
2369
|
+
}
|
|
2370
|
+
};
|
|
2371
|
+
|
|
2372
|
+
// ../../shared/lending-platforms/src/services/leverage/leverageService.ts
|
|
2373
|
+
import { BN as BN8 } from "@anchor-lang/core";
|
|
2374
|
+
|
|
2375
|
+
// ../../shared/jupiter-helpers/src/constants.ts
|
|
2376
|
+
import { address as address3 } from "@solana/kit";
|
|
2377
|
+
var JUPITER_V6_PROGRAM_ID = address3(
|
|
2378
|
+
"JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4"
|
|
2379
|
+
);
|
|
2380
|
+
var JUPITER_API_URL = "https://lite-api.jup.ag";
|
|
2381
|
+
var DEFAULT_SLIPPAGE_BPS = 500;
|
|
2382
|
+
var LOCAL_TEST_MAX_ACCOUNTS = 20;
|
|
2383
|
+
var LOCAL_TEST_EXCLUDED_DEXES = ["GoonFi", "HumidiFi", "TesseraV", "1DEX", "Aquifer"];
|
|
2384
|
+
var ALWAYS_EXCLUDED_DEXES = ["Riptide"];
|
|
2385
|
+
|
|
2386
|
+
// ../../shared/jupiter-helpers/src/api.ts
|
|
2387
|
+
import { getBase64Encoder, getTransactionDecoder } from "@solana/kit";
|
|
2388
|
+
import { createJupiterApiClient } from "@jup-ag/api";
|
|
2389
|
+
async function getJupiterQuote(params) {
|
|
2390
|
+
const jupiterApi = createJupiterApiClient({ basePath: JUPITER_API_URL });
|
|
2391
|
+
const amount = typeof params.amount === "bigint" ? Number(params.amount) : params.amount;
|
|
2392
|
+
const request = {
|
|
2393
|
+
inputMint: params.inputMint,
|
|
2394
|
+
outputMint: params.outputMint,
|
|
2395
|
+
amount,
|
|
2396
|
+
slippageBps: params.slippageBps ?? DEFAULT_SLIPPAGE_BPS,
|
|
2397
|
+
swapMode: params.swapMode,
|
|
2398
|
+
maxAccounts: params.maxAccounts,
|
|
2399
|
+
dexes: params.dexes,
|
|
2400
|
+
// When `dexes` is set it acts as a whitelist and `excludeDexes` is irrelevant.
|
|
2401
|
+
// Otherwise the caller's exclusions are merged with the global list.
|
|
2402
|
+
excludeDexes: params.dexes ? void 0 : [.../* @__PURE__ */ new Set([...ALWAYS_EXCLUDED_DEXES, ...params.excludeDexes ?? []])],
|
|
2403
|
+
onlyDirectRoutes: params.onlyDirectRoutes
|
|
2404
|
+
};
|
|
2405
|
+
try {
|
|
2406
|
+
return await jupiterApi.quoteGet(request);
|
|
2407
|
+
} catch (err) {
|
|
2408
|
+
throw await enrichJupiterHttpError(err, request);
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2411
|
+
async function enrichJupiterHttpError(err, request) {
|
|
2412
|
+
if (!(err instanceof Error) || !("response" in err)) {
|
|
2413
|
+
return err instanceof Error ? err : new Error(String(err));
|
|
2414
|
+
}
|
|
2415
|
+
const res = err.response;
|
|
2416
|
+
if (!res || res.ok || typeof res.text !== "function") {
|
|
2417
|
+
return err;
|
|
2418
|
+
}
|
|
2419
|
+
let body = "";
|
|
2420
|
+
try {
|
|
2421
|
+
body = (await res.text()).slice(0, 2e3);
|
|
2422
|
+
} catch {
|
|
2423
|
+
body = "<failed to read response body>";
|
|
2424
|
+
}
|
|
2425
|
+
return new Error(
|
|
2426
|
+
`Jupiter quoteGet http=${res.status} ${res.statusText} request=${JSON.stringify(request)} body=${body} (was: ${err.message})`
|
|
2427
|
+
);
|
|
2428
|
+
}
|
|
2429
|
+
async function buildJupiterSwapTransaction(params) {
|
|
2430
|
+
const jupiterApi = createJupiterApiClient({ basePath: JUPITER_API_URL });
|
|
2431
|
+
const swapResult = await jupiterApi.swapPost({
|
|
2432
|
+
swapRequest: {
|
|
2433
|
+
quoteResponse: params.quote,
|
|
2434
|
+
userPublicKey: params.userPublicKey,
|
|
2435
|
+
wrapAndUnwrapSol: params.wrapAndUnwrapSol ?? false,
|
|
2436
|
+
// Default false for CPI
|
|
2437
|
+
dynamicComputeUnitLimit: params.dynamicComputeUnitLimit ?? true
|
|
2438
|
+
}
|
|
2439
|
+
});
|
|
2440
|
+
const base64Encoder = getBase64Encoder();
|
|
2441
|
+
const transactionBytes = base64Encoder.encode(swapResult.swapTransaction);
|
|
2442
|
+
const transactionDecoder = getTransactionDecoder();
|
|
2443
|
+
return transactionDecoder.decode(transactionBytes);
|
|
2444
|
+
}
|
|
2445
|
+
|
|
2446
|
+
// ../../shared/jupiter-helpers/src/extract.ts
|
|
2447
|
+
import {
|
|
2448
|
+
decompileTransactionMessageFetchingLookupTables,
|
|
2449
|
+
getCompiledTransactionMessageDecoder
|
|
2450
|
+
} from "@solana/kit";
|
|
2451
|
+
async function extractJupiterInstruction(transaction, rpc, jupiterProgramId = JUPITER_V6_PROGRAM_ID) {
|
|
2452
|
+
const messageDecoder = getCompiledTransactionMessageDecoder();
|
|
2453
|
+
const compiledMessage = messageDecoder.decode(transaction.messageBytes);
|
|
2454
|
+
const lookupTables = ("addressTableLookups" in compiledMessage ? compiledMessage.addressTableLookups ?? [] : []).map((lookup) => lookup.lookupTableAddress);
|
|
2455
|
+
const decompiledMessage = await decompileTransactionMessageFetchingLookupTables(
|
|
2456
|
+
compiledMessage,
|
|
2457
|
+
rpc
|
|
2458
|
+
);
|
|
2459
|
+
const jupiterIx = decompiledMessage.instructions.find(
|
|
2460
|
+
(ix) => ix.programAddress === jupiterProgramId
|
|
2461
|
+
);
|
|
2462
|
+
if (!jupiterIx) {
|
|
2463
|
+
throw new Error("Jupiter instruction not found in transaction");
|
|
2464
|
+
}
|
|
2465
|
+
const accounts = (jupiterIx.accounts ?? []).map(
|
|
2466
|
+
(account) => ({
|
|
2467
|
+
address: account.address,
|
|
2468
|
+
role: account.role
|
|
2469
|
+
})
|
|
2470
|
+
);
|
|
2471
|
+
return {
|
|
2472
|
+
data: new Uint8Array(jupiterIx.data ?? []),
|
|
2473
|
+
accounts,
|
|
2474
|
+
lookupTables
|
|
2475
|
+
};
|
|
2476
|
+
}
|
|
2477
|
+
|
|
2478
|
+
// ../../shared/jupiter-helpers/src/routePreInstructions.ts
|
|
2479
|
+
async function getJupiterRoutePreInstructions(rpc, quote, user, payer) {
|
|
2480
|
+
const intermediate = /* @__PURE__ */ new Set();
|
|
2481
|
+
for (const step of quote.routePlan ?? []) {
|
|
2482
|
+
intermediate.add(step.swapInfo.inputMint);
|
|
2483
|
+
intermediate.add(step.swapInfo.outputMint);
|
|
2484
|
+
}
|
|
2485
|
+
intermediate.delete(quote.inputMint);
|
|
2486
|
+
intermediate.delete(quote.outputMint);
|
|
2487
|
+
if (!intermediate.size) {
|
|
2488
|
+
return { instructions: [], postSuccessCacheInvalidations: [] };
|
|
2489
|
+
}
|
|
2490
|
+
const tokenProgramByMint = /* @__PURE__ */ new Map();
|
|
2491
|
+
const unknown = [];
|
|
2492
|
+
for (const mint of intermediate) {
|
|
2493
|
+
const info = mints.get(mint);
|
|
2494
|
+
if (info) {
|
|
2495
|
+
tokenProgramByMint.set(mint, info.tokenProgram);
|
|
2496
|
+
} else {
|
|
2497
|
+
unknown.push(mint);
|
|
2498
|
+
}
|
|
2499
|
+
}
|
|
2500
|
+
if (unknown.length) {
|
|
2501
|
+
const resp = await rpc.getMultipleAccounts(unknown, { encoding: "base64" }).send();
|
|
2502
|
+
for (let i = 0; i < unknown.length; i += 1) {
|
|
2503
|
+
const acct = resp.value[i];
|
|
2504
|
+
if (!acct) {
|
|
2505
|
+
throw new Error(
|
|
2506
|
+
`getJupiterRoutePreInstructions: route mint ${unknown[i]} not found on-chain`
|
|
2507
|
+
);
|
|
2508
|
+
}
|
|
2509
|
+
tokenProgramByMint.set(unknown[i], acct.owner);
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
2512
|
+
const instructions = [];
|
|
2513
|
+
const postSuccessCacheInvalidations = [];
|
|
2514
|
+
for (const mint of intermediate) {
|
|
2515
|
+
const tokenProgram = tokenProgramByMint.get(mint);
|
|
2516
|
+
const result = await getCreateAtaIxIfNeeded(rpc, payer, mint, user, tokenProgram);
|
|
2517
|
+
if (result.instruction) {
|
|
2518
|
+
instructions.push(result.instruction);
|
|
2519
|
+
postSuccessCacheInvalidations.push(...result.postSuccessCacheInvalidations);
|
|
2520
|
+
}
|
|
2521
|
+
}
|
|
2522
|
+
return { instructions, postSuccessCacheInvalidations };
|
|
2523
|
+
}
|
|
2524
|
+
|
|
2525
|
+
// ../../shared/jupiter-helpers/src/client.ts
|
|
2526
|
+
var JupiterSwapClient = class {
|
|
2527
|
+
/**
|
|
2528
|
+
* Creates a new Jupiter swap client.
|
|
2529
|
+
*
|
|
2530
|
+
* @param rpc - Solana RPC client for resolving address lookup tables
|
|
2531
|
+
* @param config - Optional default quote policy applied to every Jupiter quote
|
|
2532
|
+
*/
|
|
2533
|
+
constructor(rpc, config = {}) {
|
|
2534
|
+
this.rpc = rpc;
|
|
2535
|
+
this.config = config;
|
|
2536
|
+
/**
|
|
2537
|
+
* Empty lists mean any route for aggregate routing (Jupiter quotes arbitrary
|
|
2538
|
+
* pairs via the API).
|
|
2539
|
+
*/
|
|
2540
|
+
this.inputMints = [];
|
|
2541
|
+
this.outputMints = [];
|
|
2542
|
+
this.routeAnchorMints = [];
|
|
2543
|
+
}
|
|
2544
|
+
/**
|
|
2545
|
+
* Get a swap quote from Jupiter.
|
|
2546
|
+
*
|
|
2547
|
+
* @param params - Quote parameters
|
|
2548
|
+
* @returns Normalized swap quote with Jupiter's QuoteResponse as rawQuote
|
|
2549
|
+
*/
|
|
2550
|
+
async getQuote(params) {
|
|
2551
|
+
const excludeDexes = params.excludeDexes?.length ? [.../* @__PURE__ */ new Set([...this.config.quoteDefaults?.excludeDexes ?? [], ...params.excludeDexes])] : void 0;
|
|
2552
|
+
const rawQuote = await getJupiterQuote({
|
|
2553
|
+
...this.config.quoteDefaults ?? {},
|
|
2554
|
+
inputMint: params.inputMint,
|
|
2555
|
+
outputMint: params.outputMint,
|
|
2556
|
+
amount: params.amount,
|
|
2557
|
+
slippageBps: params.slippageBps,
|
|
2558
|
+
...params.maxAccounts !== void 0 ? { maxAccounts: params.maxAccounts } : {},
|
|
2559
|
+
...params.onlyDirectRoutes !== void 0 ? { onlyDirectRoutes: params.onlyDirectRoutes } : {},
|
|
2560
|
+
...excludeDexes ? { excludeDexes } : {}
|
|
2561
|
+
});
|
|
2562
|
+
return {
|
|
2563
|
+
inputMint: params.inputMint,
|
|
2564
|
+
outputMint: params.outputMint,
|
|
2565
|
+
inputAmount: BigInt(rawQuote.inAmount),
|
|
2566
|
+
outputAmount: BigInt(rawQuote.outAmount),
|
|
2567
|
+
priceImpactPct: Number(rawQuote.priceImpactPct ?? 0),
|
|
2568
|
+
rawQuote
|
|
2569
|
+
};
|
|
2570
|
+
}
|
|
2571
|
+
/**
|
|
2572
|
+
* Use Jupiter `ExactOut` quoting: desired output is `minOutputAmount`; reject if implied
|
|
2573
|
+
* input exceeds `maxInputAmount`.
|
|
2574
|
+
*/
|
|
2575
|
+
async getQuoteCoveringMinOutput(params) {
|
|
2576
|
+
const need = params.minOutputAmount;
|
|
2577
|
+
if (need <= BigInt(0)) {
|
|
2578
|
+
throw new Error("getQuoteCoveringMinOutput: minOutputAmount must be positive");
|
|
2579
|
+
}
|
|
2580
|
+
const maxIn = params.maxInputAmount;
|
|
2581
|
+
if (maxIn <= BigInt(0)) {
|
|
2582
|
+
throw new Error("getQuoteCoveringMinOutput: maxInputAmount must be positive");
|
|
2583
|
+
}
|
|
2584
|
+
if (need > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
2585
|
+
throw new Error("getQuoteCoveringMinOutput: minOutputAmount exceeds Number.MAX_SAFE_INTEGER");
|
|
2586
|
+
}
|
|
2587
|
+
const rawQuote = await getJupiterQuote({
|
|
2588
|
+
...this.config.quoteDefaults ?? {},
|
|
2589
|
+
inputMint: params.inputMint,
|
|
2590
|
+
outputMint: params.outputMint,
|
|
2591
|
+
amount: Number(need),
|
|
2592
|
+
slippageBps: params.slippageBps,
|
|
2593
|
+
swapMode: "ExactOut"
|
|
2594
|
+
});
|
|
2595
|
+
const inAmt = BigInt(rawQuote.inAmount);
|
|
2596
|
+
const outAmt = BigInt(rawQuote.outAmount);
|
|
2597
|
+
if (inAmt > maxIn) {
|
|
2598
|
+
throw new Error(
|
|
2599
|
+
"Jupiter getQuoteCoveringMinOutput: exact-out route needs more input than maxInputAmount"
|
|
2600
|
+
);
|
|
2601
|
+
}
|
|
2602
|
+
if (outAmt < need) {
|
|
2603
|
+
throw new Error("Jupiter getQuoteCoveringMinOutput: quoted output is below minOutputAmount");
|
|
2604
|
+
}
|
|
2605
|
+
return {
|
|
2606
|
+
inputMint: params.inputMint,
|
|
2607
|
+
outputMint: params.outputMint,
|
|
2608
|
+
inputAmount: inAmt,
|
|
2609
|
+
outputAmount: outAmt,
|
|
2610
|
+
priceImpactPct: Number(rawQuote.priceImpactPct ?? 0),
|
|
2611
|
+
rawQuote
|
|
2612
|
+
};
|
|
2613
|
+
}
|
|
2614
|
+
/**
|
|
2615
|
+
* Build Jupiter swap instruction for CPI.
|
|
2616
|
+
*
|
|
2617
|
+
* This fetches a swap transaction from Jupiter API, decompiles it,
|
|
2618
|
+
* and extracts the instruction data and accounts needed for CPI.
|
|
2619
|
+
*
|
|
2620
|
+
* @param quote - Quote from getQuote()
|
|
2621
|
+
* @param userPublicKey - Address executing the swap (typically a PDA)
|
|
2622
|
+
* @param options - Swap options
|
|
2623
|
+
* @returns Instruction data, accounts, and Jupiter program ID
|
|
2624
|
+
*/
|
|
2625
|
+
async getSwapCpiData(quote, userPublicKey, options) {
|
|
2626
|
+
const transaction = await buildJupiterSwapTransaction({
|
|
2627
|
+
quote: quote.rawQuote,
|
|
2628
|
+
userPublicKey,
|
|
2629
|
+
wrapAndUnwrapSol: options?.wrapAndUnwrapSol ?? false
|
|
2630
|
+
});
|
|
2631
|
+
const { data, accounts, lookupTables } = await extractJupiterInstruction(transaction, this.rpc);
|
|
2632
|
+
let preInstructions;
|
|
2633
|
+
let preInvalidations;
|
|
2634
|
+
if (options?.payer) {
|
|
2635
|
+
const result = await getJupiterRoutePreInstructions(
|
|
2636
|
+
this.rpc,
|
|
2637
|
+
quote.rawQuote,
|
|
2638
|
+
userPublicKey,
|
|
2639
|
+
options.payer
|
|
2640
|
+
);
|
|
2641
|
+
if (result.instructions.length) {
|
|
2642
|
+
preInstructions = result.instructions;
|
|
2643
|
+
preInvalidations = result.postSuccessCacheInvalidations;
|
|
2644
|
+
}
|
|
2645
|
+
}
|
|
2646
|
+
return {
|
|
2647
|
+
cpiType: CpiTypes.JUPITER_SWAP,
|
|
2648
|
+
data,
|
|
2649
|
+
accounts,
|
|
2650
|
+
programId: JUPITER_V6_PROGRAM_ID,
|
|
2651
|
+
lookupTables,
|
|
2652
|
+
...preInstructions ? { preInstructions } : {},
|
|
2653
|
+
...preInvalidations ? { postSuccessCacheInvalidations: preInvalidations } : {}
|
|
2654
|
+
};
|
|
2655
|
+
}
|
|
2656
|
+
};
|
|
2657
|
+
|
|
2658
|
+
// ../../shared/jupiter-helpers/src/sizeExactInForMinOutput.ts
|
|
2659
|
+
var ExactInQuoteExceedsMaxInputError = class extends Error {
|
|
2660
|
+
constructor(inputAmount, maxInputAmount) {
|
|
2661
|
+
super(
|
|
2662
|
+
`sizeExactInForMinOutput: sized input (${inputAmount}) exceeds maxInputAmount (${maxInputAmount})`
|
|
2663
|
+
);
|
|
2664
|
+
this.inputAmount = inputAmount;
|
|
2665
|
+
this.maxInputAmount = maxInputAmount;
|
|
2666
|
+
this.name = "ExactInQuoteExceedsMaxInputError";
|
|
2667
|
+
}
|
|
2668
|
+
};
|
|
2669
|
+
async function sizeExactInForMinOutput(swap, params) {
|
|
2670
|
+
const {
|
|
2671
|
+
inputMint,
|
|
2672
|
+
outputMint,
|
|
2673
|
+
minOutputAmount,
|
|
2674
|
+
maxInputAmount,
|
|
2675
|
+
slippageBps,
|
|
2676
|
+
safetyBufferBps = 0,
|
|
2677
|
+
onlyDirectRoutes,
|
|
2678
|
+
maxAccounts,
|
|
2679
|
+
excludeDexes
|
|
2680
|
+
} = params;
|
|
2681
|
+
if (minOutputAmount <= 0n) {
|
|
2682
|
+
throw new Error("sizeExactInForMinOutput: minOutputAmount must be positive");
|
|
2683
|
+
}
|
|
2684
|
+
if (maxInputAmount <= 0n) {
|
|
2685
|
+
throw new Error("sizeExactInForMinOutput: maxInputAmount must be positive");
|
|
2686
|
+
}
|
|
2687
|
+
if (slippageBps < 0 || slippageBps >= 1e4) {
|
|
2688
|
+
throw new Error("sizeExactInForMinOutput: slippageBps must be in [0, 10000)");
|
|
2689
|
+
}
|
|
2690
|
+
if (safetyBufferBps < 0) {
|
|
2691
|
+
throw new Error("sizeExactInForMinOutput: safetyBufferBps must be non-negative");
|
|
2692
|
+
}
|
|
2693
|
+
if (minOutputAmount > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
2694
|
+
throw new Error("sizeExactInForMinOutput: minOutputAmount exceeds Number.MAX_SAFE_INTEGER");
|
|
2695
|
+
}
|
|
2696
|
+
const probeQuote = await swap.getQuote({
|
|
2697
|
+
inputMint,
|
|
2698
|
+
outputMint,
|
|
2699
|
+
amount: Number(minOutputAmount),
|
|
2700
|
+
slippageBps,
|
|
2701
|
+
onlyDirectRoutes,
|
|
2702
|
+
maxAccounts,
|
|
2703
|
+
excludeDexes
|
|
2704
|
+
});
|
|
2705
|
+
if (probeQuote.outputAmount <= 0n || probeQuote.inputAmount <= 0n) {
|
|
2706
|
+
throw new Error("sizeExactInForMinOutput: probe quote returned non-positive amounts");
|
|
2707
|
+
}
|
|
2708
|
+
const slippageBpsBig = BigInt(slippageBps);
|
|
2709
|
+
const safetyBpsBig = BigInt(safetyBufferBps);
|
|
2710
|
+
const sizingNumer = minOutputAmount * probeQuote.inputAmount * (10000n + safetyBpsBig);
|
|
2711
|
+
const sizingDenom = probeQuote.outputAmount * (10000n - slippageBpsBig);
|
|
2712
|
+
const inputAmount = (sizingNumer + sizingDenom - 1n) / sizingDenom;
|
|
2713
|
+
if (inputAmount > maxInputAmount) {
|
|
2714
|
+
throw new ExactInQuoteExceedsMaxInputError(inputAmount, maxInputAmount);
|
|
2715
|
+
}
|
|
2716
|
+
if (inputAmount > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
2717
|
+
throw new Error("sizeExactInForMinOutput: sized input exceeds Number.MAX_SAFE_INTEGER");
|
|
2718
|
+
}
|
|
2719
|
+
const quote = await swap.getQuote({
|
|
2720
|
+
inputMint,
|
|
2721
|
+
outputMint,
|
|
2722
|
+
amount: Number(inputAmount),
|
|
2723
|
+
slippageBps,
|
|
2724
|
+
onlyDirectRoutes,
|
|
2725
|
+
maxAccounts,
|
|
2726
|
+
excludeDexes
|
|
2727
|
+
});
|
|
2728
|
+
const worstCaseOutputAmount = quote.outputAmount * (10000n - slippageBpsBig) / 10000n;
|
|
2729
|
+
if (worstCaseOutputAmount < minOutputAmount) {
|
|
2730
|
+
throw new Error(
|
|
2731
|
+
`sizeExactInForMinOutput: real-quote worst-case output (${worstCaseOutputAmount}) does not cover minOutputAmount (${minOutputAmount}) \u2014 likely price impact at sized input diverged from probe spot rate; raise safetyBufferBps`
|
|
2732
|
+
);
|
|
2733
|
+
}
|
|
2734
|
+
return { quote, inputAmount, worstCaseOutputAmount };
|
|
2735
|
+
}
|
|
2736
|
+
|
|
2737
|
+
// ../../shared/lending-platforms/src/services/lendingPosition/lendingPositionManager.ts
|
|
2738
|
+
import { BN as BN7 } from "@anchor-lang/core";
|
|
2739
|
+
|
|
2740
|
+
// ../../shared/lending-platforms/src/services/reservesManager.ts
|
|
2741
|
+
var ReservesManager = class {
|
|
2742
|
+
constructor(supplyReserve, debtReserve, environment) {
|
|
2743
|
+
this.supplyReserve = supplyReserve;
|
|
2744
|
+
this.debtReserve = debtReserve;
|
|
2745
|
+
this.environment = environment;
|
|
2746
|
+
this.cache = new DataCache();
|
|
2747
|
+
}
|
|
2748
|
+
/** Max LTV ratio (0-1), using e-mode override when the pair qualifies */
|
|
2749
|
+
get maxLtv() {
|
|
2750
|
+
const emode = this.supplyReserve.emodes?.find(
|
|
2751
|
+
(e) => e.debtReserve === this.debtReserve.address
|
|
2752
|
+
);
|
|
2753
|
+
return emode?.ltvPct ?? this.supplyReserve.ltvPct;
|
|
2754
|
+
}
|
|
2755
|
+
/**
|
|
2756
|
+
* Returns supply and debt token prices.
|
|
2757
|
+
* Uses reserve-embedded prices when available, otherwise fetches from oracle and caches the result.
|
|
2758
|
+
*/
|
|
2759
|
+
async prices() {
|
|
2760
|
+
const { data } = await this.cache.getDataOrThrow(
|
|
2761
|
+
async () => {
|
|
2762
|
+
const supplyRealtimePrice = this.supplyReserve.mintPrice;
|
|
2763
|
+
const debtRealtimePrice = this.debtReserve.mintPrice;
|
|
2764
|
+
const supplyEmaPrice = this.supplyReserve.mintEmaPrice;
|
|
2765
|
+
const debtEmaPrice = this.debtReserve.mintEmaPrice;
|
|
2766
|
+
const realtimeMintsToFetch = [
|
|
2767
|
+
...supplyRealtimePrice === void 0 ? [this.supplyReserve.mint.mint] : [],
|
|
2768
|
+
...debtRealtimePrice === void 0 ? [this.debtReserve.mint.mint] : []
|
|
2769
|
+
];
|
|
2770
|
+
const emaMintsToFetch = [
|
|
2771
|
+
...supplyEmaPrice === void 0 ? [this.supplyReserve.mint.mint] : [],
|
|
2772
|
+
...debtEmaPrice === void 0 ? [this.debtReserve.mint.mint] : []
|
|
2773
|
+
];
|
|
2774
|
+
const [realtime, ema] = await Promise.all([
|
|
2775
|
+
realtimeMintsToFetch.length ? oracle.fetchPrices(realtimeMintsToFetch, "realtime", void 0, this.environment) : {},
|
|
2776
|
+
emaMintsToFetch.length ? oracle.fetchPrices(emaMintsToFetch, "ema", void 0, this.environment) : {}
|
|
2777
|
+
]);
|
|
2778
|
+
return {
|
|
2779
|
+
supply: {
|
|
2780
|
+
realtimePrice: supplyRealtimePrice ?? realtime[this.supplyReserve.mint.mint],
|
|
2781
|
+
emaPrice: supplyEmaPrice ?? ema[this.supplyReserve.mint.mint]
|
|
2782
|
+
},
|
|
2783
|
+
debt: {
|
|
2784
|
+
realtimePrice: debtRealtimePrice ?? realtime[this.debtReserve.mint.mint],
|
|
2785
|
+
emaPrice: debtEmaPrice ?? ema[this.debtReserve.mint.mint]
|
|
2786
|
+
}
|
|
2787
|
+
};
|
|
2788
|
+
},
|
|
2789
|
+
"prices",
|
|
2790
|
+
`${this.supplyReserve.mint.mint}:${this.debtReserve.mint.mint}`
|
|
2791
|
+
);
|
|
2792
|
+
return data;
|
|
2793
|
+
}
|
|
2794
|
+
/**
|
|
2795
|
+
* Net APY for the lending & borrowing position.
|
|
2796
|
+
* Accounts for eligible incentives based on the paired reserve relationship.
|
|
2797
|
+
*/
|
|
2798
|
+
get netAPY() {
|
|
2799
|
+
return this.supplyReserve.supplyAPY(this.debtReserve.address) - this.debtReserve.borrowAPY();
|
|
2800
|
+
}
|
|
2801
|
+
/**
|
|
2802
|
+
* Simulates net APY after hypothetical position changes.
|
|
2803
|
+
* Accounts for eligible incentives based on the paired reserve relationship.
|
|
2804
|
+
*/
|
|
2805
|
+
simulateNetAPY(args) {
|
|
2806
|
+
return this.supplyReserve.simulateNewSupplyAPY(
|
|
2807
|
+
args.find((x) => Boolean(x.collateralChange)) ?? { collateralChange: 0 },
|
|
2808
|
+
this.debtReserve.address
|
|
2809
|
+
) - this.debtReserve.simulateNewBorrowAPY(
|
|
2810
|
+
args.find((x) => Boolean(x.debtChange)) ?? { debtChange: 0 }
|
|
2811
|
+
);
|
|
2812
|
+
}
|
|
2813
|
+
/** Current LTV utilization rate in basis points (0-10000) given USD position values */
|
|
2814
|
+
calcLtvUtilizationRateBps(supplyUsd, debtUsd) {
|
|
2815
|
+
if (supplyUsd <= 0) return 0;
|
|
2816
|
+
return debtUsd / (supplyUsd * this.maxLtv) * 1e4;
|
|
2817
|
+
}
|
|
2818
|
+
/**
|
|
2819
|
+
* Calculates the USD debt adjustment needed to reach a target LTV utilization rate.
|
|
2820
|
+
* Positive result = boost (increase leverage), negative = deleverage.
|
|
2821
|
+
*/
|
|
2822
|
+
async calcDebtAdjustmentUsd(uiSupplyAmount, uiDebtAmount, targetLtvUtilizationRateBps, options = {}) {
|
|
2823
|
+
const { supply: supplyPrice, debt: debtPrice } = await this.prices();
|
|
2824
|
+
let supplyUsd = uiSupplyAmount * supplyPrice.realtimePrice;
|
|
2825
|
+
let debtUsd = uiDebtAmount * debtPrice.realtimePrice;
|
|
2826
|
+
const maxLtv = this.maxLtv;
|
|
2827
|
+
const targetUtilizationRate = targetLtvUtilizationRateBps / 1e4;
|
|
2828
|
+
const flFee = this.debtReserve.config.flashLoanFeePct / 100;
|
|
2829
|
+
const lpBorrowFee = this.debtReserve.config.borrowFeePct / 100;
|
|
2830
|
+
const positionChangeMode = options.positionChangeMode ?? "levered";
|
|
2831
|
+
const currentLtvUtilizationRate = supplyUsd > 0 ? debtUsd / (supplyUsd * maxLtv) : 0;
|
|
2832
|
+
const isBoost = currentLtvUtilizationRate < targetUtilizationRate;
|
|
2833
|
+
if (isBoost) {
|
|
2834
|
+
supplyUsd = uiSupplyAmount * (supplyPrice.emaPrice ?? supplyPrice.realtimePrice);
|
|
2835
|
+
debtUsd = uiDebtAmount * (debtPrice.emaPrice ?? debtPrice.realtimePrice);
|
|
2836
|
+
}
|
|
2837
|
+
if (positionChangeMode === "debtOnly") {
|
|
2838
|
+
const targetDebtDeltaUsd = targetUtilizationRate * maxLtv * supplyUsd - debtUsd;
|
|
2839
|
+
return isBoost ? targetDebtDeltaUsd / (1 + lpBorrowFee) : targetDebtDeltaUsd;
|
|
2840
|
+
}
|
|
2841
|
+
return isBoost ? (targetUtilizationRate * maxLtv * supplyUsd - debtUsd) / (1 + lpBorrowFee + flFee - targetUtilizationRate * maxLtv) : (targetUtilizationRate * maxLtv * supplyUsd - debtUsd) / (1 - targetUtilizationRate * maxLtv * (1 + flFee));
|
|
2842
|
+
}
|
|
2843
|
+
};
|
|
2844
|
+
|
|
2845
|
+
// ../../shared/lending-platforms/src/services/lendingPosition/lendingPositionManager.ts
|
|
2846
|
+
var LendingPositionManager = class {
|
|
2847
|
+
constructor(lpData, pool, userAccount, collateralReserve, debtReserve, environment) {
|
|
2848
|
+
this.lpData = lpData;
|
|
2849
|
+
this.pool = pool;
|
|
2850
|
+
this.userAccount = userAccount;
|
|
2851
|
+
this.reservesManager = new ReservesManager(collateralReserve, debtReserve, environment);
|
|
2852
|
+
}
|
|
2853
|
+
/**
|
|
2854
|
+
* Calculates the UI debt amount change needed to reach the target LTV utilization
|
|
2855
|
+
* rate. Positive values indicate borrowing; negative values indicate repaying.
|
|
2856
|
+
*/
|
|
2857
|
+
async calcDebtChangeAmount(targetUtilizationRateBps) {
|
|
2858
|
+
const state = await this.getPositionState("realtime");
|
|
2859
|
+
if (!state) return 0;
|
|
2860
|
+
return this.calcDebtChangeAmountFromState(state, targetUtilizationRateBps);
|
|
2861
|
+
}
|
|
2862
|
+
/**
|
|
2863
|
+
* Fetch current supply and debt position amounts in UI units.
|
|
2864
|
+
*/
|
|
2865
|
+
async getLendingPositionAmounts() {
|
|
2866
|
+
const state = await this.getPositionState("realtime");
|
|
2867
|
+
if (!state) return { supplyUiAmount: 0, debtUiAmount: 0 };
|
|
2868
|
+
const supplyPrice = state.prices.supply.realtimePrice;
|
|
2869
|
+
const debtPrice = state.prices.debt.realtimePrice;
|
|
2870
|
+
return {
|
|
2871
|
+
supplyUiAmount: supplyPrice > 0 ? state.supplyUsd / supplyPrice : 0,
|
|
2872
|
+
debtUiAmount: debtPrice > 0 ? state.debtUsd / debtPrice : 0
|
|
2873
|
+
};
|
|
2874
|
+
}
|
|
2875
|
+
/**
|
|
2876
|
+
* Calculates the utilization rate the source position must reach before a
|
|
2877
|
+
* collateral withdrawal so that, after the withdrawal, the position lands at
|
|
2878
|
+
* the desired target utilization rate.
|
|
2879
|
+
*
|
|
2880
|
+
* Units:
|
|
2881
|
+
* - current supply USD = supplied collateral before withdrawal
|
|
2882
|
+
* - withdrawn USD = collateral requested for the rebalance move
|
|
2883
|
+
* - post-withdraw target = desired utilization after collateral leaves the LP
|
|
2884
|
+
*
|
|
2885
|
+
* Formula:
|
|
2886
|
+
* pre_withdraw_target = post_withdraw_target * (current_supply - withdrawn) / current_supply
|
|
2887
|
+
*
|
|
2888
|
+
* The result is floored to stay conservatively at or below the requested
|
|
2889
|
+
* post-withdraw target once integer basis-point rounding is applied.
|
|
2890
|
+
*/
|
|
2891
|
+
async calcPreWithdrawalTargetUtilizationRateBps(withdrawUiCollateralAmount, postWithdrawalTargetUtilizationRateBps) {
|
|
2892
|
+
const state = await this.getPositionState("realtime");
|
|
2893
|
+
if (!state) return 0;
|
|
2894
|
+
return this.calcPreWithdrawalTargetUtilizationRateBpsFromState(
|
|
2895
|
+
state,
|
|
2896
|
+
withdrawUiCollateralAmount,
|
|
2897
|
+
postWithdrawalTargetUtilizationRateBps
|
|
2898
|
+
);
|
|
2899
|
+
}
|
|
2900
|
+
/**
|
|
2901
|
+
* Calculates the UI debt amount change needed before a collateral withdrawal
|
|
2902
|
+
* so that the position lands at the desired utilization rate after the
|
|
2903
|
+
* withdrawal completes.
|
|
2904
|
+
*/
|
|
2905
|
+
async calcDebtChangeAmountForCollateralWithdrawal(withdrawUiCollateralAmount, postWithdrawalTargetUtilizationRateBps) {
|
|
2906
|
+
const state = await this.getPositionState("realtime");
|
|
2907
|
+
if (!state) return 0;
|
|
2908
|
+
const preWithdrawalTargetUtilizationRateBps = this.calcPreWithdrawalTargetUtilizationRateBpsFromState(
|
|
2909
|
+
state,
|
|
2910
|
+
withdrawUiCollateralAmount,
|
|
2911
|
+
postWithdrawalTargetUtilizationRateBps
|
|
2912
|
+
);
|
|
2913
|
+
return this.calcDebtChangeAmountFromState(state, preWithdrawalTargetUtilizationRateBps);
|
|
2914
|
+
}
|
|
2915
|
+
/**
|
|
2916
|
+
* Calculates the utilization rate after withdrawing collateral while leaving
|
|
2917
|
+
* debt unchanged.
|
|
2918
|
+
*/
|
|
2919
|
+
async calcPostWithdrawalUtilizationRateBps(withdrawUiCollateralAmount) {
|
|
2920
|
+
const state = await this.getPositionState("realtime");
|
|
2921
|
+
if (!state) return 0;
|
|
2922
|
+
return this.calcPostWithdrawalUtilizationRateBpsFromState(state, withdrawUiCollateralAmount);
|
|
2923
|
+
}
|
|
2924
|
+
/**
|
|
2925
|
+
* For burn-token liquidity management: checks that a withdrawal of
|
|
2926
|
+
* `collateralWithdrawalUiAmount` (collateral mint UI units) leaves strictly
|
|
2927
|
+
* positive supplied collateral, matching the pre-withdraw math used in
|
|
2928
|
+
* {@link calcPreWithdrawalTargetUtilizationRateBps}.
|
|
2929
|
+
*
|
|
2930
|
+
* Returns realtime LTV utilization in basis points when eligible; null when the
|
|
2931
|
+
* obligation is missing, has no supply, prices are invalid, or the withdrawal
|
|
2932
|
+
* would consume the full (or more than the full) collateral position.
|
|
2933
|
+
*/
|
|
2934
|
+
async getBurnUnwindEligibility(collateralWithdrawalUiAmount) {
|
|
2935
|
+
if (!(collateralWithdrawalUiAmount > 0)) {
|
|
2936
|
+
return null;
|
|
2937
|
+
}
|
|
2938
|
+
const state = await this.getPositionState("realtime");
|
|
2939
|
+
if (!state) {
|
|
2940
|
+
return null;
|
|
2941
|
+
}
|
|
2942
|
+
const collateralPrice = state.prices.supply.realtimePrice;
|
|
2943
|
+
if (!(collateralPrice > 0)) {
|
|
2944
|
+
return null;
|
|
2945
|
+
}
|
|
2946
|
+
const withdrawnCollateralUsd = collateralWithdrawalUiAmount * collateralPrice;
|
|
2947
|
+
if (!(withdrawnCollateralUsd < state.supplyUsd)) {
|
|
2948
|
+
return null;
|
|
2949
|
+
}
|
|
2950
|
+
const utilizationRateBps = this.reservesManager.calcLtvUtilizationRateBps(
|
|
2951
|
+
state.supplyUsd,
|
|
2952
|
+
state.debtUsd
|
|
2953
|
+
);
|
|
2954
|
+
return { utilizationRateBps };
|
|
2955
|
+
}
|
|
2956
|
+
/**
|
|
2957
|
+
* Returns the collateral price levels that would place the position exactly on
|
|
2958
|
+
* its lower and upper utilization trigger bands.
|
|
2959
|
+
*
|
|
2960
|
+
* The lower-band trigger uses EMA pricing (to mirror boost-trigger semantics),
|
|
2961
|
+
* while the upper-band trigger uses realtime pricing (to mirror unwind-trigger
|
|
2962
|
+
* semantics).
|
|
2963
|
+
*/
|
|
2964
|
+
async getCollateralPriceTriggerBand(params) {
|
|
2965
|
+
const [lower, upper] = await Promise.all([
|
|
2966
|
+
this.getCollateralPriceTriggerLevel("ema", params.lowerTargetUtilizationRateBps),
|
|
2967
|
+
this.getCollateralPriceTriggerLevel("realtime", params.upperTargetUtilizationRateBps)
|
|
2968
|
+
]);
|
|
2969
|
+
return { lower, upper };
|
|
2970
|
+
}
|
|
2971
|
+
async getUtilizationRatesBps() {
|
|
2972
|
+
const [realtimeState, emaState] = await Promise.all([
|
|
2973
|
+
this.getPositionState("realtime"),
|
|
2974
|
+
this.getPositionState("ema")
|
|
2975
|
+
]);
|
|
2976
|
+
if (!realtimeState || !emaState) {
|
|
2977
|
+
return null;
|
|
2978
|
+
}
|
|
2979
|
+
return {
|
|
2980
|
+
realtime: this.reservesManager.calcLtvUtilizationRateBps(
|
|
2981
|
+
realtimeState.supplyUsd,
|
|
2982
|
+
realtimeState.debtUsd
|
|
2983
|
+
),
|
|
2984
|
+
ema: this.reservesManager.calcLtvUtilizationRateBps(emaState.supplyUsd, emaState.debtUsd)
|
|
2985
|
+
};
|
|
2986
|
+
}
|
|
2987
|
+
async getUtilizationPrices() {
|
|
2988
|
+
const [realtimeState, emaState] = await Promise.all([
|
|
2989
|
+
this.getPositionState("realtime"),
|
|
2990
|
+
this.getPositionState("ema")
|
|
2991
|
+
]);
|
|
2992
|
+
if (!realtimeState || !emaState) {
|
|
2993
|
+
return null;
|
|
2994
|
+
}
|
|
2995
|
+
return {
|
|
2996
|
+
realtime: {
|
|
2997
|
+
collateral: this.selectPrice(realtimeState.prices.supply, "realtime"),
|
|
2998
|
+
debt: this.selectPrice(realtimeState.prices.debt, "realtime")
|
|
2999
|
+
},
|
|
3000
|
+
ema: {
|
|
3001
|
+
collateral: this.selectPrice(emaState.prices.supply, "ema"),
|
|
3002
|
+
debt: this.selectPrice(emaState.prices.debt, "ema")
|
|
3003
|
+
}
|
|
3004
|
+
};
|
|
3005
|
+
}
|
|
3006
|
+
async getInspectMetrics(params) {
|
|
3007
|
+
const [utilizationRateBps, utilizationPrices, triggerBand] = await Promise.all([
|
|
3008
|
+
this.getUtilizationRatesBps(),
|
|
3009
|
+
this.getUtilizationPrices(),
|
|
3010
|
+
this.getCollateralPriceTriggerBand(params)
|
|
3011
|
+
]);
|
|
3012
|
+
if (!utilizationRateBps || !utilizationPrices) {
|
|
3013
|
+
return null;
|
|
3014
|
+
}
|
|
3015
|
+
return { utilizationRateBps, utilizationPrices, triggerBand };
|
|
3016
|
+
}
|
|
3017
|
+
async getPositionState(mode) {
|
|
3018
|
+
const position = await this.lpData.maybeFetchUserPositionInPool(this.pool, this.userAccount);
|
|
3019
|
+
if (!position) return null;
|
|
3020
|
+
const prices = await this.reservesManager.prices();
|
|
3021
|
+
const { supplyUsd, debtUsd } = this.calcPositionSupplyDebtUsd(position, prices, mode);
|
|
3022
|
+
return { prices, supplyUsd, debtUsd };
|
|
3023
|
+
}
|
|
3024
|
+
calcPositionSupplyDebtUsd(position, prices, mode) {
|
|
3025
|
+
const { supplyReserve, debtReserve } = this.reservesManager;
|
|
3026
|
+
const deposit = position.deposits.find((d) => d.reserve === supplyReserve.address);
|
|
3027
|
+
const borrow = position.borrows.find((b) => b.reserve === debtReserve.address);
|
|
3028
|
+
const supplyAmount = deposit ? toUiAmount(deposit.amount, supplyReserve.mint.mintDecimals) : 0;
|
|
3029
|
+
const debtAmount = borrow ? toUiAmount(borrow.amount, debtReserve.mint.mintDecimals) : 0;
|
|
3030
|
+
return {
|
|
3031
|
+
supplyUsd: supplyAmount * this.selectPrice(prices.supply, mode).value,
|
|
3032
|
+
debtUsd: debtAmount * this.selectPrice(prices.debt, mode).value
|
|
3033
|
+
};
|
|
3034
|
+
}
|
|
3035
|
+
selectPrice(price, mode) {
|
|
3036
|
+
if (mode === "realtime") {
|
|
3037
|
+
return { value: price.realtimePrice, source: "realtime" };
|
|
3038
|
+
}
|
|
3039
|
+
if (price.emaPrice != null) {
|
|
3040
|
+
return { value: price.emaPrice, source: "ema" };
|
|
3041
|
+
}
|
|
3042
|
+
return { value: price.realtimePrice, source: "ema_fallback_realtime" };
|
|
3043
|
+
}
|
|
3044
|
+
async getCollateralPriceTriggerLevel(mode, targetUtilizationRateBps) {
|
|
3045
|
+
this.assertValidTriggerBandUtilizationRateBps(
|
|
3046
|
+
targetUtilizationRateBps,
|
|
3047
|
+
"targetUtilizationRateBps"
|
|
3048
|
+
);
|
|
3049
|
+
if (targetUtilizationRateBps === 0) {
|
|
3050
|
+
return void 0;
|
|
3051
|
+
}
|
|
3052
|
+
const state = await this.getPositionState(mode);
|
|
3053
|
+
if (!state) {
|
|
3054
|
+
return void 0;
|
|
3055
|
+
}
|
|
3056
|
+
const currentCollateralPrice = mode === "ema" ? state.prices.supply.emaPrice ?? state.prices.supply.realtimePrice : state.prices.supply.realtimePrice;
|
|
3057
|
+
if (currentCollateralPrice <= 0 || state.debtUsd < 0 || this.reservesManager.maxLtv <= 0) {
|
|
3058
|
+
return void 0;
|
|
3059
|
+
}
|
|
3060
|
+
const uiSupplyAmount = state.supplyUsd / currentCollateralPrice;
|
|
3061
|
+
if (uiSupplyAmount <= 0) {
|
|
3062
|
+
return void 0;
|
|
3063
|
+
}
|
|
3064
|
+
const triggerCollateralPrice = this.calcCollateralPriceForTargetUtilization(
|
|
3065
|
+
state.debtUsd,
|
|
3066
|
+
uiSupplyAmount,
|
|
3067
|
+
targetUtilizationRateBps
|
|
3068
|
+
);
|
|
3069
|
+
if (!Number.isFinite(triggerCollateralPrice) || triggerCollateralPrice < 0) {
|
|
3070
|
+
return void 0;
|
|
3071
|
+
}
|
|
3072
|
+
return {
|
|
3073
|
+
currentCollateralPrice,
|
|
3074
|
+
triggerCollateralPrice,
|
|
3075
|
+
targetUtilizationRateBps,
|
|
3076
|
+
priceMode: mode,
|
|
3077
|
+
priceChangePct: (triggerCollateralPrice - currentCollateralPrice) / currentCollateralPrice * 100
|
|
3078
|
+
};
|
|
3079
|
+
}
|
|
3080
|
+
/**
|
|
3081
|
+
* Solve for collateral price at a target utilization:
|
|
3082
|
+
* utilization = debtUsd / (collateralAmount * collateralPrice * maxLtv).
|
|
3083
|
+
*/
|
|
3084
|
+
calcCollateralPriceForTargetUtilization(debtUsd, uiSupplyAmount, targetUtilizationRateBps) {
|
|
3085
|
+
const targetUtilizationRate = targetUtilizationRateBps / 1e4;
|
|
3086
|
+
return debtUsd / (uiSupplyAmount * this.reservesManager.maxLtv * targetUtilizationRate);
|
|
3087
|
+
}
|
|
3088
|
+
async calcDebtChangeAmountFromState(state, targetUtilizationRateBps) {
|
|
3089
|
+
this.assertValidUtilizationRateBps(targetUtilizationRateBps, "targetUtilizationRateBps");
|
|
3090
|
+
if (state.prices.debt.realtimePrice <= 0) {
|
|
3091
|
+
throw new Error("Debt reserve realtime price must be positive");
|
|
3092
|
+
}
|
|
3093
|
+
if (state.prices.supply.realtimePrice <= 0) {
|
|
3094
|
+
throw new Error("Collateral reserve realtime price must be positive");
|
|
3095
|
+
}
|
|
3096
|
+
const debtAdjustmentUsd = await this.reservesManager.calcDebtAdjustmentUsd(
|
|
3097
|
+
state.supplyUsd / state.prices.supply.realtimePrice,
|
|
3098
|
+
state.debtUsd / state.prices.debt.realtimePrice,
|
|
3099
|
+
targetUtilizationRateBps,
|
|
3100
|
+
{ positionChangeMode: "debtOnly" }
|
|
3101
|
+
);
|
|
3102
|
+
const debtChangeUiAmount = debtAdjustmentUsd / state.prices.debt.realtimePrice;
|
|
3103
|
+
const debtDecimals = this.reservesManager.debtReserve.mint.mintDecimals;
|
|
3104
|
+
let quantizedUiAmount = this.quantizeDebtChangeUiAmount(debtChangeUiAmount, debtDecimals);
|
|
3105
|
+
if (quantizedUiAmount > 0) {
|
|
3106
|
+
quantizedUiAmount = await this.capPositiveBorrowToProtocolHeadroom(quantizedUiAmount, state);
|
|
3107
|
+
}
|
|
3108
|
+
return debtChangeUiAmount < 0 ? -quantizedUiAmount : quantizedUiAmount;
|
|
3109
|
+
}
|
|
3110
|
+
/**
|
|
3111
|
+
* Quantize to the debt mint's base-unit precision. Borrows floor; repays round
|
|
3112
|
+
* away from zero so deleveraging does not undershoot.
|
|
3113
|
+
*/
|
|
3114
|
+
quantizeDebtChangeUiAmount(debtChangeUiAmount, debtDecimals) {
|
|
3115
|
+
if (debtChangeUiAmount === 0) return 0;
|
|
3116
|
+
const absUi = Math.abs(debtChangeUiAmount);
|
|
3117
|
+
if (debtChangeUiAmount > 0) {
|
|
3118
|
+
if (!(absUi > 0)) return 0;
|
|
3119
|
+
const flooredBaseUnits = new BN7(Math.floor(absUi * Math.pow(10, debtDecimals)));
|
|
3120
|
+
return toUiAmount(flooredBaseUnits, debtDecimals);
|
|
3121
|
+
}
|
|
3122
|
+
const roundedAmount = fromUiAmount(absUi, debtDecimals);
|
|
3123
|
+
let repayUi = toUiAmount(roundedAmount, debtDecimals);
|
|
3124
|
+
if (repayUi < absUi) {
|
|
3125
|
+
repayUi = toUiAmount(roundedAmount.addn(1), debtDecimals);
|
|
3126
|
+
}
|
|
3127
|
+
return repayUi;
|
|
3128
|
+
}
|
|
3129
|
+
/** Cap positive borrows to obligation headroom when the platform exposes it. */
|
|
3130
|
+
async capPositiveBorrowToProtocolHeadroom(requestedUiAmount, state) {
|
|
3131
|
+
const debtDecimals = this.reservesManager.debtReserve.mint.mintDecimals;
|
|
3132
|
+
const position = await this.lpData.maybeFetchUserPositionInPool(this.pool, this.userAccount);
|
|
3133
|
+
if (!position) {
|
|
3134
|
+
return requestedUiAmount;
|
|
3135
|
+
}
|
|
3136
|
+
const maxUi = position.getMaxAdditionalBorrowUiAmount(
|
|
3137
|
+
state.prices.debt.realtimePrice,
|
|
3138
|
+
debtDecimals
|
|
3139
|
+
);
|
|
3140
|
+
if (maxUi === void 0) {
|
|
3141
|
+
return requestedUiAmount;
|
|
3142
|
+
}
|
|
3143
|
+
return Math.min(requestedUiAmount, maxUi);
|
|
3144
|
+
}
|
|
3145
|
+
calcPreWithdrawalTargetUtilizationRateBpsFromState(state, withdrawUiCollateralAmount, postWithdrawalTargetUtilizationRateBps) {
|
|
3146
|
+
if (withdrawUiCollateralAmount <= 0) {
|
|
3147
|
+
throw new Error("withdrawUiCollateralAmount must be greater than zero");
|
|
3148
|
+
}
|
|
3149
|
+
this.assertValidUtilizationRateBps(
|
|
3150
|
+
postWithdrawalTargetUtilizationRateBps,
|
|
3151
|
+
"postWithdrawalTargetUtilizationRateBps"
|
|
3152
|
+
);
|
|
3153
|
+
const collateralPrice = state.prices.supply.realtimePrice;
|
|
3154
|
+
if (collateralPrice <= 0) {
|
|
3155
|
+
throw new Error("Collateral reserve realtime price must be positive");
|
|
3156
|
+
}
|
|
3157
|
+
const withdrawnCollateralUsd = withdrawUiCollateralAmount * collateralPrice;
|
|
3158
|
+
if (withdrawnCollateralUsd >= state.supplyUsd) {
|
|
3159
|
+
throw new Error("withdrawUiCollateralAmount exceeds the current supplied collateral");
|
|
3160
|
+
}
|
|
3161
|
+
const preWithdrawalTargetUtilizationRateBps = Math.floor(
|
|
3162
|
+
postWithdrawalTargetUtilizationRateBps * (state.supplyUsd - withdrawnCollateralUsd) / state.supplyUsd
|
|
3163
|
+
);
|
|
3164
|
+
return Math.max(
|
|
3165
|
+
0,
|
|
3166
|
+
Math.min(postWithdrawalTargetUtilizationRateBps, preWithdrawalTargetUtilizationRateBps)
|
|
3167
|
+
);
|
|
3168
|
+
}
|
|
3169
|
+
calcPostWithdrawalUtilizationRateBpsFromState(state, withdrawUiCollateralAmount) {
|
|
3170
|
+
if (withdrawUiCollateralAmount <= 0) {
|
|
3171
|
+
throw new Error("withdrawUiCollateralAmount must be greater than zero");
|
|
3172
|
+
}
|
|
3173
|
+
const collateralPrice = state.prices.supply.realtimePrice;
|
|
3174
|
+
if (collateralPrice <= 0) {
|
|
3175
|
+
throw new Error("Collateral reserve realtime price must be positive");
|
|
3176
|
+
}
|
|
3177
|
+
const withdrawnCollateralUsd = withdrawUiCollateralAmount * collateralPrice;
|
|
3178
|
+
if (withdrawnCollateralUsd >= state.supplyUsd) {
|
|
3179
|
+
throw new Error("withdrawUiCollateralAmount exceeds the current supplied collateral");
|
|
3180
|
+
}
|
|
3181
|
+
return this.reservesManager.calcLtvUtilizationRateBps(
|
|
3182
|
+
state.supplyUsd - withdrawnCollateralUsd,
|
|
3183
|
+
state.debtUsd
|
|
3184
|
+
);
|
|
3185
|
+
}
|
|
3186
|
+
assertValidUtilizationRateBps(value, field) {
|
|
3187
|
+
if (!Number.isFinite(value) || value < 0 || value > 1e4) {
|
|
3188
|
+
throw new Error(`${field} must be between 0 and 10000`);
|
|
3189
|
+
}
|
|
3190
|
+
}
|
|
3191
|
+
/**
|
|
3192
|
+
* Unwind/boost trigger bands may exceed 100% LTV utilization (up to 10_500 bps
|
|
3193
|
+
* on-chain). Debt-sizing paths still use {@link assertValidUtilizationRateBps}.
|
|
3194
|
+
*/
|
|
3195
|
+
assertValidTriggerBandUtilizationRateBps(value, field) {
|
|
3196
|
+
if (!Number.isFinite(value) || value < 0 || value > MAX_LENDING_POSITION_UPPER_UTIL_BPS) {
|
|
3197
|
+
throw new Error(`${field} must be between 0 and ${MAX_LENDING_POSITION_UPPER_UTIL_BPS}`);
|
|
3198
|
+
}
|
|
3199
|
+
}
|
|
3200
|
+
};
|
|
3201
|
+
|
|
3202
|
+
// ../../shared/lending-platforms/src/services/leverage/leverageService.ts
|
|
3203
|
+
var DECREASE_LEVERAGE_SWAP_BUFFER_BPS = 5;
|
|
3204
|
+
var DECREASE_LEVERAGE_SWAP_SLIPPAGE_BPS = 40;
|
|
3205
|
+
var DECREASE_LEVERAGE_SWAP_MAX_ACCOUNTS = 30;
|
|
3206
|
+
var FLASH_REBALANCE_SWAP_MAX_ACCOUNTS = 25;
|
|
3207
|
+
var FlashRebalanceSwapCostExceededError = class extends Error {
|
|
3208
|
+
constructor(reason, executionCostBps, marketBasisBps, limitBps, inputAmount, outputAmount) {
|
|
3209
|
+
super(
|
|
3210
|
+
`LeverageService.buildFlashRebalance: swap ${reason} exceeds ${limitBps} bps (execution cost ${executionCostBps.toFixed(2)} bps, market basis ${marketBasisBps.toFixed(2)} bps, in=${inputAmount} out=${outputAmount})`
|
|
3211
|
+
);
|
|
3212
|
+
this.reason = reason;
|
|
3213
|
+
this.executionCostBps = executionCostBps;
|
|
3214
|
+
this.marketBasisBps = marketBasisBps;
|
|
3215
|
+
this.limitBps = limitBps;
|
|
3216
|
+
this.inputAmount = inputAmount;
|
|
3217
|
+
this.outputAmount = outputAmount;
|
|
3218
|
+
this.name = "FlashRebalanceSwapCostExceededError";
|
|
3219
|
+
}
|
|
3220
|
+
};
|
|
3221
|
+
var LeverageService = class {
|
|
3222
|
+
/**
|
|
3223
|
+
* Calculate the borrow amount needed to reach the target utilization rate,
|
|
3224
|
+
* then build the borrow CPIs.
|
|
3225
|
+
*/
|
|
3226
|
+
static async buildIncreaseLeverage(ctx, params) {
|
|
3227
|
+
const reserves = new ReservesManager(ctx.supplyReserve, ctx.debtReserve, ctx.environment);
|
|
3228
|
+
const mode = params.mode ?? "debtOnly";
|
|
3229
|
+
const debtAdjustmentUsd = await reserves.calcDebtAdjustmentUsd(
|
|
3230
|
+
params.currentSupplyUiAmount,
|
|
3231
|
+
params.currentDebtUiAmount,
|
|
3232
|
+
params.targetUtilizationRateBps,
|
|
3233
|
+
{ positionChangeMode: mode }
|
|
3234
|
+
);
|
|
3235
|
+
const prices = await reserves.prices();
|
|
3236
|
+
const borrowUiAmount = Math.abs(debtAdjustmentUsd / prices.debt.realtimePrice);
|
|
3237
|
+
const borrowBaseUnits = fromUiAmount(borrowUiAmount, ctx.debtReserve.mint.mintDecimals);
|
|
3238
|
+
const { prerequisiteCpis, cpis, postSuccessCacheInvalidations } = await ctx.lendingIx.getBorrowCpiBundle({
|
|
3239
|
+
user: ctx.user,
|
|
3240
|
+
payer: ctx.payer,
|
|
3241
|
+
pool: ctx.pool,
|
|
3242
|
+
reserve: ctx.debtReserve.address,
|
|
3243
|
+
userAccount: ctx.userAccount,
|
|
3244
|
+
uiAmount: borrowUiAmount,
|
|
3245
|
+
txId: ctx.txId
|
|
3246
|
+
});
|
|
3247
|
+
const preInstructions = await ctx.lendingIx.getPreInstructions(ctx.txId);
|
|
3248
|
+
return {
|
|
3249
|
+
borrowUiAmount,
|
|
3250
|
+
borrowBaseUnits,
|
|
3251
|
+
prerequisiteCpis,
|
|
3252
|
+
borrowCpis: cpis,
|
|
3253
|
+
preInstructions,
|
|
3254
|
+
postSuccessCacheInvalidations
|
|
3255
|
+
};
|
|
3256
|
+
}
|
|
3257
|
+
/**
|
|
3258
|
+
* Calculate the repay amount needed to reach the target utilization rate,
|
|
3259
|
+
* build the repay CPIs, and assemble CPI groups with an optional swap
|
|
3260
|
+
* prepended when the caller's debt-token balance is insufficient.
|
|
3261
|
+
*
|
|
3262
|
+
* The returned `repayUiAmount` is always non-negative. When the position is
|
|
3263
|
+
* already at or below the target, the amount is zero and the CPI list is
|
|
3264
|
+
* sized for a zero repay.
|
|
3265
|
+
*/
|
|
3266
|
+
static async buildDecreaseLeverage(ctx, params) {
|
|
3267
|
+
const reserves = new ReservesManager(ctx.supplyReserve, ctx.debtReserve, ctx.environment);
|
|
3268
|
+
const mode = params.mode ?? "debtOnly";
|
|
3269
|
+
const debtAdjustmentUsd = await reserves.calcDebtAdjustmentUsd(
|
|
3270
|
+
params.currentSupplyUiAmount,
|
|
3271
|
+
params.currentDebtUiAmount,
|
|
3272
|
+
params.targetUtilizationRateBps,
|
|
3273
|
+
{ positionChangeMode: mode }
|
|
3274
|
+
);
|
|
3275
|
+
const prices = await reserves.prices();
|
|
3276
|
+
const debtDecimals = ctx.debtReserve.mint.mintDecimals;
|
|
3277
|
+
const repayUiAmount = Math.abs(debtAdjustmentUsd / prices.debt.realtimePrice);
|
|
3278
|
+
const calculatedRepayBaseUnits = fromUiAmount(repayUiAmount, debtDecimals);
|
|
3279
|
+
const repayBaseUnits = params.repayBaseUnitsOverride ?? calculatedRepayBaseUnits;
|
|
3280
|
+
const { prerequisiteCpis, cpis } = await ctx.lendingIx.getRepayCpiData({
|
|
3281
|
+
user: ctx.user,
|
|
3282
|
+
payer: ctx.payer,
|
|
3283
|
+
pool: ctx.pool,
|
|
3284
|
+
reserve: ctx.debtReserve.address,
|
|
3285
|
+
userAccount: ctx.userAccount,
|
|
3286
|
+
txId: ctx.txId,
|
|
3287
|
+
...params.repayBaseUnitsOverride ? { baseUnitAmount: repayBaseUnits } : {}
|
|
3288
|
+
});
|
|
3289
|
+
const preInstructions = await ctx.lendingIx.getPreInstructions(ctx.txId);
|
|
3290
|
+
const swapRequired = params.swapContext !== void 0;
|
|
3291
|
+
const assembledCpis = await this.assembleDecreaseLeverageCpis(
|
|
3292
|
+
repayBaseUnits,
|
|
3293
|
+
cpis,
|
|
3294
|
+
params.swapContext
|
|
3295
|
+
);
|
|
3296
|
+
return {
|
|
3297
|
+
repayUiAmount,
|
|
3298
|
+
repayBaseUnits,
|
|
3299
|
+
prerequisiteCpis,
|
|
3300
|
+
repayCpis: cpis,
|
|
3301
|
+
cpiDataGroups: assembledCpis.cpiDataGroups,
|
|
3302
|
+
swapRequired,
|
|
3303
|
+
preInstructions: [...preInstructions, ...assembledCpis.preInstructions]
|
|
3304
|
+
};
|
|
3305
|
+
}
|
|
3306
|
+
/**
|
|
3307
|
+
* Assemble repay CPI groups, prepending a swap group whenever the bank is
|
|
3308
|
+
* configured to source the debt mint via a swap. The on-chain handler
|
|
3309
|
+
* decides whether to actually invoke the swap (via `perform_swap`) based on
|
|
3310
|
+
* runtime balances; building it unconditionally keeps the tx resilient when
|
|
3311
|
+
* the bank's debt-token balance changes between build and send.
|
|
3312
|
+
*/
|
|
3313
|
+
static async assembleDecreaseLeverageCpis(repayBaseUnits, repayCpis, swapContext) {
|
|
3314
|
+
if (!swapContext) {
|
|
3315
|
+
return { cpiDataGroups: [repayCpis], preInstructions: [] };
|
|
3316
|
+
}
|
|
3317
|
+
const swapCpiData = await this.quoteDebtTopUpSwap(swapContext, repayBaseUnits);
|
|
3318
|
+
return {
|
|
3319
|
+
cpiDataGroups: [[swapCpiData], repayCpis],
|
|
3320
|
+
preInstructions: swapCpiData.preInstructions ?? []
|
|
3321
|
+
};
|
|
3322
|
+
}
|
|
3323
|
+
/**
|
|
3324
|
+
* Quote a swap that converts a source asset into the debt mint,
|
|
3325
|
+
* covering at least `shortfall` base units.
|
|
3326
|
+
*/
|
|
3327
|
+
static async quoteDebtTopUpSwap(ctx, shortfall) {
|
|
3328
|
+
const need = BigInt(shortfall.toString());
|
|
3329
|
+
if (need <= 0n) {
|
|
3330
|
+
throw new Error("LeverageService.quoteDebtTopUpSwap: shortfall must be positive");
|
|
3331
|
+
}
|
|
3332
|
+
if (ctx.sourceBalanceBaseUnits <= 0n) {
|
|
3333
|
+
throw new Error("LeverageService.quoteDebtTopUpSwap: source balance is zero");
|
|
3334
|
+
}
|
|
3335
|
+
const { quote } = await sizeExactInForMinOutput(ctx.swap, {
|
|
3336
|
+
inputMint: ctx.sourceMint,
|
|
3337
|
+
outputMint: ctx.debtMint,
|
|
3338
|
+
minOutputAmount: need,
|
|
3339
|
+
maxInputAmount: ctx.sourceBalanceBaseUnits,
|
|
3340
|
+
slippageBps: ctx.slippageBps ?? DECREASE_LEVERAGE_SWAP_SLIPPAGE_BPS,
|
|
3341
|
+
safetyBufferBps: DECREASE_LEVERAGE_SWAP_BUFFER_BPS,
|
|
3342
|
+
maxAccounts: DECREASE_LEVERAGE_SWAP_MAX_ACCOUNTS,
|
|
3343
|
+
excludeDexes: ctx.excludeDexes
|
|
3344
|
+
});
|
|
3345
|
+
return ctx.swap.getSwapCpiData(quote, ctx.swapTarget, { payer: ctx.payer });
|
|
3346
|
+
}
|
|
3347
|
+
/**
|
|
3348
|
+
* Build a flash-loan-wrapped rebalance that moves collateral between two
|
|
3349
|
+
* lending positions without decreasing any carry positions.
|
|
3350
|
+
*
|
|
3351
|
+
* The flow assembled here (inside a single transaction):
|
|
3352
|
+
* 1. Top-level: flash-borrow source debt mint into the user's ATA.
|
|
3353
|
+
* 2. CPI: repay flash-borrowed amount on source → frees collateral.
|
|
3354
|
+
* 3. CPI: withdraw `collateralUiAmount` from source.
|
|
3355
|
+
* 4. CPI: deposit that collateral on destination.
|
|
3356
|
+
* 5. CPI: borrow destination debt mint (sized slightly above the swap
|
|
3357
|
+
* input needed to produce the flash repay, so post-slippage output
|
|
3358
|
+
* still covers it).
|
|
3359
|
+
* 6. CPI: exact-in swap destination debt → source debt; the entire borrow
|
|
3360
|
+
* is consumed and worst-case output is at least the flash repay amount.
|
|
3361
|
+
* 7. Top-level: flash-repay source debt mint.
|
|
3362
|
+
*
|
|
3363
|
+
* The exact-in over-borrow leaves a small **source-debt** excess in the
|
|
3364
|
+
* token PDA's ATA after the swap; the on-chain handler sweeps this excess
|
|
3365
|
+
* into the yielding bank before the top-level flash repay so exactly
|
|
3366
|
+
* `flashRepayAmountBaseUnits` remains for the repay.
|
|
3367
|
+
*/
|
|
3368
|
+
static async buildFlashRebalance(ctx, params) {
|
|
3369
|
+
if (ctx.source.debtReserve.mint.mint === ctx.destination.debtReserve.mint.mint) {
|
|
3370
|
+
throw new Error(
|
|
3371
|
+
"LeverageService.buildFlashRebalance: source and destination debt mints must differ"
|
|
3372
|
+
);
|
|
3373
|
+
}
|
|
3374
|
+
const sourceDebtMint = ctx.source.debtReserve.address;
|
|
3375
|
+
const sourceDebtLiqMint = ctx.source.debtReserve.mint.mint;
|
|
3376
|
+
const sourceDebtDecimals = ctx.source.debtReserve.mint.mintDecimals;
|
|
3377
|
+
const destDebtLiqMint = ctx.destination.debtReserve.mint.mint;
|
|
3378
|
+
const destDebtDecimals = ctx.destination.debtReserve.mint.mintDecimals;
|
|
3379
|
+
const sourceRepayBaseUnits = await this.calcSourceRepayForWithdraw(ctx, params);
|
|
3380
|
+
if (sourceRepayBaseUnits.lten(0)) {
|
|
3381
|
+
throw new Error(
|
|
3382
|
+
"LeverageService.buildFlashRebalance: source repay amount must be positive \u2014 use the simple rebalance path when no flash loan is needed"
|
|
3383
|
+
);
|
|
3384
|
+
}
|
|
3385
|
+
const sourceRepayUiAmount = toUiAmount(sourceRepayBaseUnits, sourceDebtDecimals);
|
|
3386
|
+
const flashFeeRate = await ctx.flashLoan.getFlashLoanFeeRate(ctx.source.pool, sourceDebtMint);
|
|
3387
|
+
const SOURCE_REPAY_OVERBORROW_BPS = 5n;
|
|
3388
|
+
const sourceRepayBigInt = BigInt(sourceRepayBaseUnits.toString());
|
|
3389
|
+
const flashBorrowBigInt = params.withdrawAll ? sourceRepayBigInt + sourceRepayBigInt * SOURCE_REPAY_OVERBORROW_BPS / 10000n : sourceRepayBigInt;
|
|
3390
|
+
const flashFeeBigInt = applyFeeCeil(flashBorrowBigInt, flashFeeRate);
|
|
3391
|
+
const flashRepayBigInt = flashBorrowBigInt + flashFeeBigInt;
|
|
3392
|
+
const flashBorrowAmountBaseUnits = new BN8(flashBorrowBigInt.toString());
|
|
3393
|
+
const flashFeeBaseUnits = new BN8(flashFeeBigInt.toString());
|
|
3394
|
+
const flashRepayAmountBaseUnits = new BN8(flashRepayBigInt.toString());
|
|
3395
|
+
const reserveBorrowCapacityBaseUnits = BigInt(
|
|
3396
|
+
fromUiAmount(
|
|
3397
|
+
ctx.destination.debtReserve.borrows.limit - ctx.destination.debtReserve.borrows.totalAmount,
|
|
3398
|
+
destDebtDecimals
|
|
3399
|
+
).toString()
|
|
3400
|
+
);
|
|
3401
|
+
const utilizationBorrowCapacityBaseUnits = await this.calcDestinationBorrowCapacityForDeposit(
|
|
3402
|
+
ctx,
|
|
3403
|
+
{ ...params, collateralUiAmount: 0 }
|
|
3404
|
+
);
|
|
3405
|
+
const maxDestinationBorrowBaseUnits = [
|
|
3406
|
+
params.maxDestinationBorrowBaseUnits,
|
|
3407
|
+
reserveBorrowCapacityBaseUnits,
|
|
3408
|
+
utilizationBorrowCapacityBaseUnits
|
|
3409
|
+
].filter((amount) => amount !== void 0).reduce((min, amount) => amount < min ? amount : min);
|
|
3410
|
+
if (maxDestinationBorrowBaseUnits <= 0n) {
|
|
3411
|
+
throw new Error(
|
|
3412
|
+
"LeverageService.buildFlashRebalance: destination reserve has no available borrow capacity"
|
|
3413
|
+
);
|
|
3414
|
+
}
|
|
3415
|
+
const { quote: swapQuote } = await sizeExactInForMinOutput(ctx.swap, {
|
|
3416
|
+
inputMint: destDebtLiqMint,
|
|
3417
|
+
outputMint: sourceDebtLiqMint,
|
|
3418
|
+
minOutputAmount: flashRepayBigInt,
|
|
3419
|
+
maxInputAmount: maxDestinationBorrowBaseUnits,
|
|
3420
|
+
slippageBps: params.swapSlippageBps ?? 15,
|
|
3421
|
+
safetyBufferBps: params.swapBufferBps ?? 5,
|
|
3422
|
+
maxAccounts: FLASH_REBALANCE_SWAP_MAX_ACCOUNTS
|
|
3423
|
+
});
|
|
3424
|
+
if (params.maxSwapCostBps !== void 0 || params.maxMarketBasisBps !== void 0) {
|
|
3425
|
+
const [sourcePrices, destPrices] = await Promise.all([
|
|
3426
|
+
new ReservesManager(
|
|
3427
|
+
ctx.source.supplyReserve,
|
|
3428
|
+
ctx.source.debtReserve,
|
|
3429
|
+
ctx.environment
|
|
3430
|
+
).prices(),
|
|
3431
|
+
new ReservesManager(
|
|
3432
|
+
ctx.destination.supplyReserve,
|
|
3433
|
+
ctx.destination.debtReserve,
|
|
3434
|
+
ctx.environment
|
|
3435
|
+
).prices()
|
|
3436
|
+
]);
|
|
3437
|
+
const fairOutPerIn = destPrices.debt.realtimePrice / sourcePrices.debt.realtimePrice;
|
|
3438
|
+
if (!Number.isFinite(fairOutPerIn) || fairOutPerIn <= 0) {
|
|
3439
|
+
throw new Error(
|
|
3440
|
+
`LeverageService.buildFlashRebalance: invalid oracle prices for swap cost check (source=${sourcePrices.debt.realtimePrice} dest=${destPrices.debt.realtimePrice})`
|
|
3441
|
+
);
|
|
3442
|
+
}
|
|
3443
|
+
const inUi = Number(swapQuote.inputAmount) / Math.pow(10, destDebtDecimals);
|
|
3444
|
+
const outUi = Number(swapQuote.outputAmount) / Math.pow(10, sourceDebtDecimals);
|
|
3445
|
+
const executionCostBps = (1 - outUi / inUi / fairOutPerIn) * 1e4;
|
|
3446
|
+
const marketBasisBps = (1 - fairOutPerIn) * 1e4;
|
|
3447
|
+
if (params.maxSwapCostBps !== void 0 && executionCostBps > params.maxSwapCostBps) {
|
|
3448
|
+
throw new FlashRebalanceSwapCostExceededError(
|
|
3449
|
+
"execution-cost",
|
|
3450
|
+
executionCostBps,
|
|
3451
|
+
marketBasisBps,
|
|
3452
|
+
params.maxSwapCostBps,
|
|
3453
|
+
swapQuote.inputAmount,
|
|
3454
|
+
swapQuote.outputAmount
|
|
3455
|
+
);
|
|
3456
|
+
}
|
|
3457
|
+
if (params.maxMarketBasisBps !== void 0 && Math.abs(marketBasisBps) > params.maxMarketBasisBps) {
|
|
3458
|
+
throw new FlashRebalanceSwapCostExceededError(
|
|
3459
|
+
"market-basis",
|
|
3460
|
+
executionCostBps,
|
|
3461
|
+
marketBasisBps,
|
|
3462
|
+
params.maxMarketBasisBps,
|
|
3463
|
+
swapQuote.inputAmount,
|
|
3464
|
+
swapQuote.outputAmount
|
|
3465
|
+
);
|
|
3466
|
+
}
|
|
3467
|
+
}
|
|
3468
|
+
const swapCpi = await ctx.swap.getSwapCpiData(swapQuote, ctx.user, { payer: ctx.payer });
|
|
3469
|
+
const destinationBorrowBaseUnits = new BN8(swapQuote.inputAmount.toString());
|
|
3470
|
+
const destinationBorrowUiAmount = toUiAmount(destinationBorrowBaseUnits, destDebtDecimals);
|
|
3471
|
+
const sourceRepay = await ctx.source.lendingIx.getRepayCpiData({
|
|
3472
|
+
user: ctx.user,
|
|
3473
|
+
payer: ctx.payer,
|
|
3474
|
+
pool: ctx.source.pool,
|
|
3475
|
+
reserve: sourceDebtMint,
|
|
3476
|
+
userAccount: ctx.source.userAccount,
|
|
3477
|
+
txId: ctx.txId
|
|
3478
|
+
});
|
|
3479
|
+
if (params.withdrawAll) {
|
|
3480
|
+
ctx.source.lendingIx.markObligationDebtCleared(
|
|
3481
|
+
ctx.txId,
|
|
3482
|
+
ctx.source.userAccount,
|
|
3483
|
+
sourceDebtMint
|
|
3484
|
+
);
|
|
3485
|
+
}
|
|
3486
|
+
const destBorrow = await ctx.destination.lendingIx.getInitBorrowPositionCpiBundle(
|
|
3487
|
+
{
|
|
3488
|
+
user: ctx.user,
|
|
3489
|
+
payer: ctx.payer,
|
|
3490
|
+
pool: ctx.destination.pool,
|
|
3491
|
+
reserve: ctx.destination.debtReserve.address,
|
|
3492
|
+
userAccount: ctx.destination.userAccount,
|
|
3493
|
+
uiAmount: destinationBorrowUiAmount,
|
|
3494
|
+
txId: ctx.txId
|
|
3495
|
+
},
|
|
3496
|
+
ctx.destination.supplyReserve.address
|
|
3497
|
+
);
|
|
3498
|
+
const userSourceDebtAta = await getAtaAddress(
|
|
3499
|
+
sourceDebtLiqMint,
|
|
3500
|
+
ctx.user,
|
|
3501
|
+
ctx.source.debtReserve.mint.mintTokenProgram
|
|
3502
|
+
);
|
|
3503
|
+
const flashBorrowIx = await ctx.flashLoan.getFlashBorrowIx({
|
|
3504
|
+
user: ctx.payer,
|
|
3505
|
+
pool: ctx.source.pool,
|
|
3506
|
+
reserve: sourceDebtMint,
|
|
3507
|
+
amountBaseUnits: flashBorrowAmountBaseUnits,
|
|
3508
|
+
destinationAta: userSourceDebtAta
|
|
3509
|
+
});
|
|
3510
|
+
const sourceIx = ctx.source.lendingIx;
|
|
3511
|
+
const destIx = ctx.destination.lendingIx;
|
|
3512
|
+
const sourcePreInstructions = await sourceIx.getPreInstructions(ctx.txId);
|
|
3513
|
+
const lendingPreInstructions = sourceIx === destIx ? sourcePreInstructions : [...sourcePreInstructions, ...await destIx.getPreInstructions(ctx.txId)];
|
|
3514
|
+
const swapPreInstructions = swapCpi.preInstructions ?? [];
|
|
3515
|
+
const preInstructions = [...lendingPreInstructions, ...swapPreInstructions];
|
|
3516
|
+
const postSuccessCacheInvalidations = [
|
|
3517
|
+
...destBorrow.postSuccessCacheInvalidations,
|
|
3518
|
+
...swapCpi.postSuccessCacheInvalidations ?? []
|
|
3519
|
+
];
|
|
3520
|
+
return {
|
|
3521
|
+
flashBorrowAmountBaseUnits,
|
|
3522
|
+
flashRepayAmountBaseUnits,
|
|
3523
|
+
flashFeeBaseUnits,
|
|
3524
|
+
sourceRepayUiAmount,
|
|
3525
|
+
destinationBorrowUiAmount,
|
|
3526
|
+
flashBorrowIx,
|
|
3527
|
+
sourceRepayCpis: [...sourceRepay.prerequisiteCpis, ...sourceRepay.cpis],
|
|
3528
|
+
destinationBorrowCpis: [...destBorrow.prerequisiteCpis, ...destBorrow.cpis],
|
|
3529
|
+
swapCpis: [swapCpi],
|
|
3530
|
+
preInstructions,
|
|
3531
|
+
postSuccessCacheInvalidations
|
|
3532
|
+
};
|
|
3533
|
+
}
|
|
3534
|
+
/**
|
|
3535
|
+
* Build the top-level flash-repay instruction for a previously-built flash
|
|
3536
|
+
* rebalance, given the final transaction index of its `flashBorrowIx`.
|
|
3537
|
+
*
|
|
3538
|
+
* Split from {@link buildFlashRebalance} because `borrowIxIndex` depends on
|
|
3539
|
+
* the caller's full tx layout (pre-instructions + heap frame + ATA creations
|
|
3540
|
+
* + flash-borrow position), which in turn depends on the ATA list derived
|
|
3541
|
+
* from the plan's `remainingAccounts` — a chicken-and-egg the caller resolves
|
|
3542
|
+
* by assembling the preamble before calling this.
|
|
3543
|
+
*/
|
|
3544
|
+
static async buildFlashRepayIx(ctx, plan, borrowIxIndex) {
|
|
3545
|
+
const userSourceDebtAta = await getAtaAddress(
|
|
3546
|
+
ctx.source.debtReserve.mint.mint,
|
|
3547
|
+
ctx.user,
|
|
3548
|
+
ctx.source.debtReserve.mint.mintTokenProgram
|
|
3549
|
+
);
|
|
3550
|
+
return ctx.flashLoan.getFlashRepayIx({
|
|
3551
|
+
user: ctx.payer,
|
|
3552
|
+
pool: ctx.source.pool,
|
|
3553
|
+
reserve: ctx.source.debtReserve.address,
|
|
3554
|
+
amountBaseUnits: plan.flashBorrowAmountBaseUnits,
|
|
3555
|
+
borrowIxIndex,
|
|
3556
|
+
userSourceLiquidity: userSourceDebtAta
|
|
3557
|
+
});
|
|
3558
|
+
}
|
|
3559
|
+
static async calcSourceRepayForWithdraw(ctx, params) {
|
|
3560
|
+
const manager = new LendingPositionManager(
|
|
3561
|
+
ctx.source.lendingIx.data,
|
|
3562
|
+
ctx.source.pool,
|
|
3563
|
+
ctx.source.userAccount,
|
|
3564
|
+
ctx.source.supplyReserve,
|
|
3565
|
+
ctx.source.debtReserve,
|
|
3566
|
+
ctx.environment
|
|
3567
|
+
);
|
|
3568
|
+
if (params.withdrawAll) {
|
|
3569
|
+
const { debtUiAmount } = await manager.getLendingPositionAmounts();
|
|
3570
|
+
return fromUiAmount(debtUiAmount, ctx.source.debtReserve.mint.mintDecimals);
|
|
3571
|
+
}
|
|
3572
|
+
const debtChangeUi = await manager.calcDebtChangeAmountForCollateralWithdrawal(
|
|
3573
|
+
params.collateralUiAmount,
|
|
3574
|
+
params.sourceTargetUtilizationRateBps
|
|
3575
|
+
);
|
|
3576
|
+
const repayUi = Math.max(0, -debtChangeUi);
|
|
3577
|
+
return fromUiAmount(repayUi, ctx.source.debtReserve.mint.mintDecimals);
|
|
3578
|
+
}
|
|
3579
|
+
static async calcDestinationBorrowCapacityForDeposit(ctx, params) {
|
|
3580
|
+
if (params.destinationMaxUtilizationRateBps === void 0) {
|
|
3581
|
+
return void 0;
|
|
3582
|
+
}
|
|
3583
|
+
const manager = new LendingPositionManager(
|
|
3584
|
+
ctx.destination.lendingIx.data,
|
|
3585
|
+
ctx.destination.pool,
|
|
3586
|
+
ctx.destination.userAccount,
|
|
3587
|
+
ctx.destination.supplyReserve,
|
|
3588
|
+
ctx.destination.debtReserve,
|
|
3589
|
+
ctx.environment
|
|
3590
|
+
);
|
|
3591
|
+
const current = await manager.getLendingPositionAmounts();
|
|
3592
|
+
const reserves = new ReservesManager(
|
|
3593
|
+
ctx.destination.supplyReserve,
|
|
3594
|
+
ctx.destination.debtReserve,
|
|
3595
|
+
ctx.environment
|
|
3596
|
+
);
|
|
3597
|
+
const debtAdjustmentUsd = await reserves.calcDebtAdjustmentUsd(
|
|
3598
|
+
current.supplyUiAmount + params.collateralUiAmount,
|
|
3599
|
+
current.debtUiAmount,
|
|
3600
|
+
params.destinationMaxUtilizationRateBps,
|
|
3601
|
+
{ positionChangeMode: "debtOnly" }
|
|
3602
|
+
);
|
|
3603
|
+
const prices = await reserves.prices();
|
|
3604
|
+
if (debtAdjustmentUsd <= 0) {
|
|
3605
|
+
return 0n;
|
|
3606
|
+
}
|
|
3607
|
+
const debtUiAmount = debtAdjustmentUsd / prices.debt.realtimePrice;
|
|
3608
|
+
return BigInt(
|
|
3609
|
+
fromUiAmount(debtUiAmount, ctx.destination.debtReserve.mint.mintDecimals).toString()
|
|
3610
|
+
);
|
|
3611
|
+
}
|
|
3612
|
+
};
|
|
3613
|
+
|
|
3614
|
+
// src/constants/configs/carryTradePresets.ts
|
|
3615
|
+
var VOLATILITY_REGIMES = ["lowVol", "highVol"];
|
|
3616
|
+
function isVolatilityRegime(s) {
|
|
3617
|
+
return VOLATILITY_REGIMES.includes(s);
|
|
3618
|
+
}
|
|
3619
|
+
var STOCK_INDEX_PRESETS = {
|
|
3620
|
+
lowVol: {
|
|
3621
|
+
drawdownPctFromTargetToLiq: 8,
|
|
3622
|
+
drawdownPctFromUnwindToLiq: 5,
|
|
3623
|
+
maxPriceChangeUpPercent: 2
|
|
3624
|
+
},
|
|
3625
|
+
highVol: {
|
|
3626
|
+
drawdownPctFromTargetToLiq: 11,
|
|
3627
|
+
drawdownPctFromUnwindToLiq: 7,
|
|
3628
|
+
maxPriceChangeUpPercent: 3
|
|
3629
|
+
}
|
|
3630
|
+
};
|
|
3631
|
+
var BTC_CARRY_PRESETS = {
|
|
3632
|
+
lowVol: {
|
|
3633
|
+
drawdownPctFromTargetToLiq: 12,
|
|
3634
|
+
drawdownPctFromUnwindToLiq: 8,
|
|
3635
|
+
maxPriceChangeUpPercent: 6
|
|
3636
|
+
},
|
|
3637
|
+
highVol: {
|
|
3638
|
+
drawdownPctFromTargetToLiq: 14,
|
|
3639
|
+
drawdownPctFromUnwindToLiq: 10,
|
|
3640
|
+
maxPriceChangeUpPercent: 8
|
|
3641
|
+
}
|
|
3642
|
+
};
|
|
3643
|
+
var ETH_CARRY_PRESETS = {
|
|
3644
|
+
lowVol: {
|
|
3645
|
+
drawdownPctFromTargetToLiq: 14,
|
|
3646
|
+
drawdownPctFromUnwindToLiq: 10,
|
|
3647
|
+
maxPriceChangeUpPercent: 7
|
|
3648
|
+
},
|
|
3649
|
+
highVol: {
|
|
3650
|
+
drawdownPctFromTargetToLiq: 17,
|
|
3651
|
+
drawdownPctFromUnwindToLiq: 12,
|
|
3652
|
+
maxPriceChangeUpPercent: 10
|
|
3653
|
+
}
|
|
3654
|
+
};
|
|
3655
|
+
var SOL_CARRY_PRESETS = {
|
|
3656
|
+
lowVol: {
|
|
3657
|
+
drawdownPctFromTargetToLiq: 16,
|
|
3658
|
+
drawdownPctFromUnwindToLiq: 12,
|
|
3659
|
+
maxPriceChangeUpPercent: 8
|
|
3660
|
+
},
|
|
3661
|
+
highVol: {
|
|
3662
|
+
drawdownPctFromTargetToLiq: 19,
|
|
3663
|
+
drawdownPctFromUnwindToLiq: 14,
|
|
3664
|
+
maxPriceChangeUpPercent: 11
|
|
3665
|
+
}
|
|
3666
|
+
};
|
|
3667
|
+
var LST_CARRY_PRESETS = {
|
|
3668
|
+
lowVol: {
|
|
3669
|
+
drawdownPctFromTargetToLiq: 19,
|
|
3670
|
+
drawdownPctFromUnwindToLiq: 10,
|
|
3671
|
+
maxPriceChangeUpPercent: 8
|
|
3672
|
+
},
|
|
3673
|
+
highVol: {
|
|
3674
|
+
drawdownPctFromTargetToLiq: 22,
|
|
3675
|
+
drawdownPctFromUnwindToLiq: 12,
|
|
3676
|
+
maxPriceChangeUpPercent: 11
|
|
3677
|
+
}
|
|
3678
|
+
};
|
|
3679
|
+
var LARGE_CAP_ALT_CARRY_PRESETS = {
|
|
3680
|
+
lowVol: {
|
|
3681
|
+
drawdownPctFromTargetToLiq: 22,
|
|
3682
|
+
drawdownPctFromUnwindToLiq: 16,
|
|
3683
|
+
maxPriceChangeUpPercent: 8
|
|
3684
|
+
},
|
|
3685
|
+
highVol: {
|
|
3686
|
+
drawdownPctFromTargetToLiq: 25,
|
|
3687
|
+
drawdownPctFromUnwindToLiq: 18,
|
|
3688
|
+
maxPriceChangeUpPercent: 10
|
|
3689
|
+
}
|
|
3690
|
+
};
|
|
3691
|
+
var SMALL_CAP_ALT_CARRY_PRESETS = {
|
|
3692
|
+
lowVol: {
|
|
3693
|
+
drawdownPctFromTargetToLiq: 26,
|
|
3694
|
+
drawdownPctFromUnwindToLiq: 22,
|
|
3695
|
+
maxPriceChangeUpPercent: 10
|
|
3696
|
+
},
|
|
3697
|
+
highVol: {
|
|
3698
|
+
drawdownPctFromTargetToLiq: 29,
|
|
3699
|
+
drawdownPctFromUnwindToLiq: 24,
|
|
3700
|
+
maxPriceChangeUpPercent: 12
|
|
3701
|
+
}
|
|
3702
|
+
};
|
|
3703
|
+
var ASSET_PRESETS = {
|
|
3704
|
+
WBTC: { presets: BTC_CARRY_PRESETS, defaultRegime: "lowVol" },
|
|
3705
|
+
CBBTC: { presets: BTC_CARRY_PRESETS, defaultRegime: "lowVol" },
|
|
3706
|
+
WETH: { presets: ETH_CARRY_PRESETS, defaultRegime: "lowVol" },
|
|
3707
|
+
SOL: { presets: SOL_CARRY_PRESETS, defaultRegime: "lowVol" },
|
|
3708
|
+
JUPSOL: { presets: LST_CARRY_PRESETS, defaultRegime: "lowVol" },
|
|
3709
|
+
JITOSOL: { presets: LST_CARRY_PRESETS, defaultRegime: "lowVol" },
|
|
3710
|
+
DFDVSOL: { presets: LST_CARRY_PRESETS, defaultRegime: "lowVol" },
|
|
3711
|
+
SPYX: { presets: STOCK_INDEX_PRESETS, defaultRegime: "lowVol" },
|
|
3712
|
+
QQQX: { presets: STOCK_INDEX_PRESETS, defaultRegime: "lowVol" },
|
|
3713
|
+
LARGE_CAP: { presets: LARGE_CAP_ALT_CARRY_PRESETS, defaultRegime: "lowVol" },
|
|
3714
|
+
SMALL_CAP: { presets: SMALL_CAP_ALT_CARRY_PRESETS, defaultRegime: "highVol" }
|
|
3715
|
+
};
|
|
3716
|
+
function resolvePresets(collateralSymbol) {
|
|
3717
|
+
return ASSET_PRESETS[collateralSymbol.toUpperCase()];
|
|
3718
|
+
}
|
|
3719
|
+
|
|
3720
|
+
// src/services/carry/carryAllocationConfig.ts
|
|
3721
|
+
var MAX_TARGET_UTILIZATION_RATE_BPS = 1e4;
|
|
3722
|
+
var MAX_LENDING_POSITION_UPPER_UTIL_BPS2 = 10500;
|
|
3723
|
+
var MIN_DEVIATION_ABOVE_TARGET_UTIL_BPS = 200;
|
|
3724
|
+
function clampLendingPositionConfigBps(config) {
|
|
3725
|
+
let { targetUtilizationRateBps, maxDeviationAboveTargetUtilBps, maxDeviationBelowTargetUtilBps } = config;
|
|
3726
|
+
if (!Number.isInteger(targetUtilizationRateBps) || targetUtilizationRateBps <= 0) {
|
|
3727
|
+
throw new Error("targetUtilizationRateBps must be a positive integer");
|
|
3728
|
+
}
|
|
3729
|
+
for (const [name, v] of [
|
|
3730
|
+
["maxDeviationAboveTargetUtilBps", maxDeviationAboveTargetUtilBps],
|
|
3731
|
+
["maxDeviationBelowTargetUtilBps", maxDeviationBelowTargetUtilBps]
|
|
3732
|
+
]) {
|
|
3733
|
+
if (!Number.isInteger(v) || v < 0) {
|
|
3734
|
+
throw new Error(`${name} must be a non-negative integer`);
|
|
3735
|
+
}
|
|
3736
|
+
}
|
|
3737
|
+
targetUtilizationRateBps = Math.min(targetUtilizationRateBps, MAX_TARGET_UTILIZATION_RATE_BPS);
|
|
3738
|
+
maxDeviationAboveTargetUtilBps = Math.min(
|
|
3739
|
+
maxDeviationAboveTargetUtilBps,
|
|
3740
|
+
MAX_LENDING_POSITION_UPPER_UTIL_BPS2 - targetUtilizationRateBps
|
|
3741
|
+
);
|
|
3742
|
+
if (targetUtilizationRateBps <= maxDeviationBelowTargetUtilBps) {
|
|
3743
|
+
throw new Error("targetUtilizationRateBps must be greater than maxDeviationBelowTargetUtilBps");
|
|
3744
|
+
}
|
|
3745
|
+
return {
|
|
3746
|
+
targetUtilizationRateBps,
|
|
3747
|
+
maxDeviationAboveTargetUtilBps,
|
|
3748
|
+
maxDeviationBelowTargetUtilBps
|
|
3749
|
+
};
|
|
3750
|
+
}
|
|
3751
|
+
function computeCarryLendingAllocationConfig(params) {
|
|
3752
|
+
const {
|
|
3753
|
+
drawdownPctFromTargetToLiq,
|
|
3754
|
+
drawdownPctFromUnwindToLiq,
|
|
3755
|
+
maxPriceChangeUpPercent,
|
|
3756
|
+
maxLtv,
|
|
3757
|
+
liquidationThreshold
|
|
3758
|
+
} = params;
|
|
3759
|
+
if (!Number.isFinite(drawdownPctFromTargetToLiq) || drawdownPctFromTargetToLiq <= 0 || drawdownPctFromTargetToLiq >= 100) {
|
|
3760
|
+
throw new RangeError("drawdownPctFromTargetToLiq must be in (0, 100)");
|
|
3761
|
+
}
|
|
3762
|
+
if (!Number.isFinite(drawdownPctFromUnwindToLiq) || drawdownPctFromUnwindToLiq < 0 || drawdownPctFromUnwindToLiq >= 100) {
|
|
3763
|
+
throw new RangeError("drawdownPctFromUnwindToLiq must be in [0, 100)");
|
|
3764
|
+
}
|
|
3765
|
+
if (drawdownPctFromUnwindToLiq >= drawdownPctFromTargetToLiq) {
|
|
3766
|
+
throw new RangeError(
|
|
3767
|
+
"drawdownPctFromUnwindToLiq must be less than drawdownPctFromTargetToLiq (unwind trigger is closer to liquidation than target)"
|
|
3768
|
+
);
|
|
3769
|
+
}
|
|
3770
|
+
if (!Number.isFinite(maxPriceChangeUpPercent) || maxPriceChangeUpPercent <= 0) {
|
|
3771
|
+
throw new RangeError("maxPriceChangeUpPercent must be finite and positive");
|
|
3772
|
+
}
|
|
3773
|
+
const targetDecimal = maxLtvUtilBeforeCollDrawdown({
|
|
3774
|
+
drawdownPercent: drawdownPctFromTargetToLiq,
|
|
3775
|
+
ltv: maxLtv,
|
|
3776
|
+
liquidationThreshold
|
|
3777
|
+
});
|
|
3778
|
+
let targetUtilizationRateBps = Math.min(
|
|
3779
|
+
Math.floor(targetDecimal * 1e4),
|
|
3780
|
+
MAX_TARGET_UTILIZATION_RATE_BPS
|
|
3781
|
+
);
|
|
3782
|
+
if (targetUtilizationRateBps <= 0) {
|
|
3783
|
+
throw new RangeError(
|
|
3784
|
+
"Computed target utilization rounds to zero; reduce drawdownPctFromTargetToLiq or check maxLtv / liquidationThreshold"
|
|
3785
|
+
);
|
|
3786
|
+
}
|
|
3787
|
+
const unwindTriggerDecimal = maxLtvUtilBeforeCollDrawdown({
|
|
3788
|
+
drawdownPercent: drawdownPctFromUnwindToLiq,
|
|
3789
|
+
ltv: maxLtv,
|
|
3790
|
+
liquidationThreshold
|
|
3791
|
+
});
|
|
3792
|
+
const unwindTriggerBps = Math.floor(unwindTriggerDecimal * 1e4);
|
|
3793
|
+
let maxDeviationAboveTargetUtilBps = Math.min(
|
|
3794
|
+
unwindTriggerBps - targetUtilizationRateBps,
|
|
3795
|
+
MAX_LENDING_POSITION_UPPER_UTIL_BPS2 - targetUtilizationRateBps
|
|
3796
|
+
);
|
|
3797
|
+
if (maxDeviationAboveTargetUtilBps < MIN_DEVIATION_ABOVE_TARGET_UTIL_BPS) {
|
|
3798
|
+
maxDeviationAboveTargetUtilBps = MIN_DEVIATION_ABOVE_TARGET_UTIL_BPS;
|
|
3799
|
+
targetUtilizationRateBps = Math.min(
|
|
3800
|
+
targetUtilizationRateBps,
|
|
3801
|
+
MAX_LENDING_POSITION_UPPER_UTIL_BPS2 - MIN_DEVIATION_ABOVE_TARGET_UTIL_BPS
|
|
3802
|
+
);
|
|
3803
|
+
}
|
|
3804
|
+
const t = targetUtilizationRateBps / 1e4;
|
|
3805
|
+
const maxBelowDecimal = ltvUtilDeltaBelowTargForRallyPct(t, maxPriceChangeUpPercent);
|
|
3806
|
+
const maxDeviationBelowTargetUtilBps = Math.floor(maxBelowDecimal * 1e4);
|
|
3807
|
+
return clampLendingPositionConfigBps({
|
|
3808
|
+
targetUtilizationRateBps,
|
|
3809
|
+
maxDeviationAboveTargetUtilBps,
|
|
3810
|
+
maxDeviationBelowTargetUtilBps
|
|
3811
|
+
});
|
|
3812
|
+
}
|
|
3813
|
+
function computeConfigForCollateral(args) {
|
|
3814
|
+
const { collateralMint, collateralReserve, debtReserve } = args;
|
|
3815
|
+
const mintInfo = mints.get(collateralMint);
|
|
3816
|
+
const symbol = mintInfo?.symbol ?? String(collateralMint);
|
|
3817
|
+
const entry = resolvePresets(symbol);
|
|
3818
|
+
if (!entry) {
|
|
3819
|
+
throw new Error(
|
|
3820
|
+
`computeConfigForCollateral: no carry preset found for collateral "${symbol}" (${collateralMint})`
|
|
3821
|
+
);
|
|
3822
|
+
}
|
|
3823
|
+
const regime = args.regime ?? entry.defaultRegime;
|
|
3824
|
+
const preset = entry.presets[regime];
|
|
3825
|
+
const rm = new ReservesManager(collateralReserve, debtReserve);
|
|
3826
|
+
const pct = collateralReserve.config.liquidationThresholdPct;
|
|
3827
|
+
const liquidationThreshold = pct <= 1 ? pct : pct / 100;
|
|
3828
|
+
return computeCarryLendingAllocationConfig({
|
|
3829
|
+
...preset,
|
|
3830
|
+
maxLtv: rm.maxLtv,
|
|
3831
|
+
liquidationThreshold
|
|
3832
|
+
});
|
|
3833
|
+
}
|
|
3834
|
+
|
|
3835
|
+
// src/services/carry/lycLendingPositionManager.ts
|
|
3836
|
+
var LycLendingPositionManager = class _LycLendingPositionManager extends LendingPositionManager {
|
|
3837
|
+
constructor(lpData, lendingPosition, collateralReserve, debtReserve, environment) {
|
|
3838
|
+
super(
|
|
3839
|
+
lpData,
|
|
3840
|
+
fromWeb3Pk(lendingPosition.pool),
|
|
3841
|
+
fromWeb3Pk(lendingPosition.protocolUserAcc),
|
|
3842
|
+
collateralReserve,
|
|
3843
|
+
debtReserve,
|
|
3844
|
+
environment
|
|
3845
|
+
);
|
|
3846
|
+
this.lendingPosition = lendingPosition;
|
|
3847
|
+
}
|
|
3848
|
+
static async create(lpData, lendingPosition, environment) {
|
|
3849
|
+
const pool = fromWeb3Pk(lendingPosition.pool);
|
|
3850
|
+
const [collateralReserve, debtReserve] = await Promise.all([
|
|
3851
|
+
lpData.fetchReserve(pool, fromWeb3Pk(lendingPosition.collateralReserve)),
|
|
3852
|
+
lpData.fetchReserve(pool, fromWeb3Pk(lendingPosition.debtReserve))
|
|
3853
|
+
]);
|
|
3854
|
+
if (!collateralReserve || !debtReserve) {
|
|
3855
|
+
throw new Error("Failed to fetch reserves");
|
|
3856
|
+
}
|
|
3857
|
+
return new _LycLendingPositionManager(
|
|
3858
|
+
lpData,
|
|
3859
|
+
lendingPosition,
|
|
3860
|
+
collateralReserve,
|
|
3861
|
+
debtReserve,
|
|
3862
|
+
environment
|
|
3863
|
+
);
|
|
3864
|
+
}
|
|
3865
|
+
/**
|
|
3866
|
+
* Derives `targetUtilizationRateBps` and carry trigger deviations from drawdown-to-liquidation
|
|
3867
|
+
* buffers and a rally percentage, using this pair's {@link ReservesManager.maxLtv} and the
|
|
3868
|
+
* collateral reserve's **base** `liquidationThresholdPct` (normalized to a decimal).
|
|
3869
|
+
*
|
|
3870
|
+
* For custom `maxLtv` / `liquidationThreshold` (e.g. e-mode liquidation threshold), call
|
|
3871
|
+
* {@link computeCarryLendingAllocationConfig} directly.
|
|
3872
|
+
*/
|
|
3873
|
+
getLendingAllocationConfigFromPriceBands(params) {
|
|
3874
|
+
const pct = this.reservesManager.supplyReserve.config.liquidationThresholdPct;
|
|
3875
|
+
const liquidationThreshold = pct <= 1 ? pct : pct / 100;
|
|
3876
|
+
return computeCarryLendingAllocationConfig({
|
|
3877
|
+
...params,
|
|
3878
|
+
maxLtv: this.reservesManager.maxLtv,
|
|
3879
|
+
liquidationThreshold
|
|
3880
|
+
});
|
|
3881
|
+
}
|
|
3882
|
+
/**
|
|
3883
|
+
* Returns true when the current LTV utilization (valued at EMA prices) has
|
|
3884
|
+
* fallen far enough below the target that the position should be boosted.
|
|
3885
|
+
*/
|
|
3886
|
+
async shouldIncreaseCarryPosition() {
|
|
3887
|
+
const state = await this.getPositionState("ema");
|
|
3888
|
+
if (!state) return false;
|
|
3889
|
+
const { supplyUsd, debtUsd } = state;
|
|
3890
|
+
if (supplyUsd <= 0) return false;
|
|
3891
|
+
const currentUtilBps = this.reservesManager.calcLtvUtilizationRateBps(supplyUsd, debtUsd);
|
|
3892
|
+
return currentUtilBps <= this.lendingPosition.config.targetUtilizationRateBps - this.lendingPosition.config.maxDeviationBelowTargetUtilBps;
|
|
3893
|
+
}
|
|
3894
|
+
/**
|
|
3895
|
+
* Returns true when the current LTV utilization (valued at realtime prices) has
|
|
3896
|
+
* risen far enough above the target that the position should be unwound.
|
|
3897
|
+
*/
|
|
3898
|
+
async shouldDecreaseCarryPosition() {
|
|
3899
|
+
const state = await this.getPositionState("realtime");
|
|
3900
|
+
if (!state) return false;
|
|
3901
|
+
const { supplyUsd, debtUsd } = state;
|
|
3902
|
+
const currentUtilBps = this.reservesManager.calcLtvUtilizationRateBps(supplyUsd, debtUsd);
|
|
3903
|
+
return currentUtilBps >= this.lendingPosition.config.targetUtilizationRateBps + this.lendingPosition.config.maxDeviationAboveTargetUtilBps;
|
|
3904
|
+
}
|
|
3905
|
+
async calcDebtChangeAmount(targetUtilizationRateBps = this.lendingPosition.config.targetUtilizationRateBps) {
|
|
3906
|
+
return super.calcDebtChangeAmount(targetUtilizationRateBps);
|
|
3907
|
+
}
|
|
3908
|
+
async calcPreWithdrawalTargetUtilizationRateBps(withdrawUiCollateralAmount, postWithdrawalTargetUtilizationRateBps = this.lendingPosition.config.targetUtilizationRateBps) {
|
|
3909
|
+
return super.calcPreWithdrawalTargetUtilizationRateBps(
|
|
3910
|
+
withdrawUiCollateralAmount,
|
|
3911
|
+
postWithdrawalTargetUtilizationRateBps
|
|
3912
|
+
);
|
|
3913
|
+
}
|
|
3914
|
+
async calcDebtChangeAmountForCollateralWithdrawal(withdrawUiCollateralAmount, postWithdrawalTargetUtilizationRateBps = this.lendingPosition.config.targetUtilizationRateBps) {
|
|
3915
|
+
return super.calcDebtChangeAmountForCollateralWithdrawal(
|
|
3916
|
+
withdrawUiCollateralAmount,
|
|
3917
|
+
postWithdrawalTargetUtilizationRateBps
|
|
3918
|
+
);
|
|
3919
|
+
}
|
|
3920
|
+
async getCollateralPriceTriggerBand() {
|
|
3921
|
+
return super.getCollateralPriceTriggerBand(this.configTriggerBandBps());
|
|
3922
|
+
}
|
|
3923
|
+
async getInspectMetrics() {
|
|
3924
|
+
return super.getInspectMetrics(this.configTriggerBandBps());
|
|
3925
|
+
}
|
|
3926
|
+
configTriggerBandBps() {
|
|
3927
|
+
const {
|
|
3928
|
+
targetUtilizationRateBps,
|
|
3929
|
+
maxDeviationBelowTargetUtilBps,
|
|
3930
|
+
maxDeviationAboveTargetUtilBps
|
|
3931
|
+
} = this.lendingPosition.config;
|
|
3932
|
+
return {
|
|
3933
|
+
lowerTargetUtilizationRateBps: targetUtilizationRateBps - maxDeviationBelowTargetUtilBps,
|
|
3934
|
+
upperTargetUtilizationRateBps: targetUtilizationRateBps + maxDeviationAboveTargetUtilBps
|
|
3935
|
+
};
|
|
3936
|
+
}
|
|
3937
|
+
};
|
|
3938
|
+
|
|
3939
|
+
export {
|
|
3940
|
+
KAMINO_MAIN_MARKET,
|
|
3941
|
+
getEligiblePools,
|
|
3942
|
+
getLendingUserAccountCacheInvalidation,
|
|
3943
|
+
KaminoClient,
|
|
3944
|
+
LOCAL_TEST_MAX_ACCOUNTS,
|
|
3945
|
+
LOCAL_TEST_EXCLUDED_DEXES,
|
|
3946
|
+
JupiterSwapClient,
|
|
3947
|
+
ExactInQuoteExceedsMaxInputError,
|
|
3948
|
+
FlashRebalanceSwapCostExceededError,
|
|
3949
|
+
LeverageService,
|
|
3950
|
+
VOLATILITY_REGIMES,
|
|
3951
|
+
isVolatilityRegime,
|
|
3952
|
+
STOCK_INDEX_PRESETS,
|
|
3953
|
+
BTC_CARRY_PRESETS,
|
|
3954
|
+
ETH_CARRY_PRESETS,
|
|
3955
|
+
SOL_CARRY_PRESETS,
|
|
3956
|
+
LST_CARRY_PRESETS,
|
|
3957
|
+
LARGE_CAP_ALT_CARRY_PRESETS,
|
|
3958
|
+
SMALL_CAP_ALT_CARRY_PRESETS,
|
|
3959
|
+
ASSET_PRESETS,
|
|
3960
|
+
resolvePresets,
|
|
3961
|
+
MAX_TARGET_UTILIZATION_RATE_BPS,
|
|
3962
|
+
MAX_LENDING_POSITION_UPPER_UTIL_BPS2 as MAX_LENDING_POSITION_UPPER_UTIL_BPS,
|
|
3963
|
+
MIN_DEVIATION_ABOVE_TARGET_UTIL_BPS,
|
|
3964
|
+
clampLendingPositionConfigBps,
|
|
3965
|
+
computeCarryLendingAllocationConfig,
|
|
3966
|
+
computeConfigForCollateral,
|
|
3967
|
+
LycLendingPositionManager
|
|
3968
|
+
};
|
|
3969
|
+
//# sourceMappingURL=chunk-GOW6CARW.mjs.map
|