diff --git a/ts-client/src/dlmm/error.ts b/ts-client/src/dlmm/error.ts index 42d86da4..4fbb1371 100644 --- a/ts-client/src/dlmm/error.ts +++ b/ts-client/src/dlmm/error.ts @@ -6,57 +6,299 @@ type Codes = (typeof IDL.errors)[number]["code"]; // ProgramError error parser export class DLMMError extends Error { - public errorCode: number; - public errorName: string; - public errorMessage: string; + public errorCode: number; + public errorName: string; + public errorMessage: string; - constructor(error: object | Codes) { - let _errorCode = 0; - let _errorName = "Something went wrong"; - let _errorMessage = "Something went wrong"; + constructor(error: object | Codes) { + let _errorCode = 0; + let _errorName = "Something went wrong"; + let _errorMessage = "Something went wrong"; - if (error instanceof Error) { - const anchorError = AnchorError.parse( - JSON.parse(JSON.stringify(error)).logs as string[] - ); + if (error instanceof Error) { + const anchorError = AnchorError.parse( + JSON.parse(JSON.stringify(error)).logs as string[] + ); - if ( - anchorError?.program.toBase58() === LBCLMM_PROGRAM_IDS["mainnet-beta"] - ) { - _errorCode = anchorError.error.errorCode.number; - _errorName = anchorError.error.errorCode.code; - _errorMessage = anchorError.error.errorMessage; - } - } else { - const idlError = IDL.errors.find((err) => err.code === error); + if ( + anchorError?.program.toBase58() === LBCLMM_PROGRAM_IDS["mainnet-beta"] + ) { + _errorCode = anchorError.error.errorCode.number; + _errorName = anchorError.error.errorCode.code; + _errorMessage = anchorError.error.errorMessage; + } + } else { + const idlError = IDL.errors.find((err) => err.code === error); - if (idlError) { - _errorCode = idlError.code; - _errorName = idlError.name; - _errorMessage = idlError.msg; - } - } + if (idlError) { + _errorCode = idlError.code; + _errorName = idlError.name; + _errorMessage = idlError.msg; + } + } - super(_errorMessage); + super(_errorMessage); - this.errorCode = _errorCode; - this.errorName = _errorName; - this.errorMessage = _errorMessage; - } + this.errorCode = _errorCode; + this.errorName = _errorName; + this.errorMessage = _errorMessage; + } } // SDK error -type ErrorName = - | "SWAP_QUOTE_INSUFFICIENT_LIQUIDITY" - | "INVALID_MAX_EXTRA_BIN_ARRAYS"; +type ErrorName = | "SWAP_QUOTE_INSUFFICIENT_LIQUIDITY" | "INVALID_MAX_EXTRA_BIN_ARRAYS"; export class DlmmSdkError extends Error { - name: ErrorName; - message: string; - - constructor(name: ErrorName, message: string) { - super(); - this.name = name; - this.message = message; - } + name: ErrorName; + message: string; + + constructor(name: ErrorName, message: string) { + super(); + this.name = name; + this.message = message; + } +} + +export class PoolExistsError extends Error { + message: string; + + constructor(message: string="This pool already exists") { + super(); + this.message = message; + } +} + +export class LBPairAccountNotFound extends Error { + message: string; + + constructor(account: string|null=null, message: string|null=null) { + super(); + if (typeof account === "string") { + this.message = `LB Pair account ${account} not found` + } + else if (message !== null) { + this.message = message; + } + + else { + this.message = "LB Pair account was not found" + } + } +} + +export class LBPairStateNotFound extends Error { + message: string; + + constructor(account: string|null=null, message: string|null=null) { + super(); + if (typeof account === "string") { + this.message = `LB Pair ${account} state not found` + } + else if (message !== null) { + this.message = message; + } + + else { + this.message = "LB Pair state was not found" + } + } +} + +export class NoMintForLBPair extends Error { + message: string; + + constructor(account: string|null=null, message: string|null=null) { + super(); + if (typeof account === "string") { + this.message = `Mint account for LB Pair ${account} not found` + } + else if (message !== null) { + this.message = message; + } + + else { + this.message = "Mint account for LB Pair not found" + } + } +} + +export class NoReserveForLBPair extends Error { + message: string; + + constructor(account: string|null=null, message: string|null=null) { + super(); + if (typeof account === "string") { + this.message = `Reserve account for LB Pair ${account} not found` + } + else if (message !== null) { + this.message = message; + } + + else { + this.message = "Reserve account for LB Pair not found" + } + } +} + +export class BinArrayAccountNotFound extends Error { + message: string; + + constructor(account: string|null=null, message: string|null=null) { + super(); + if (typeof account === "string") { + this.message = `Bin Array account ${account} not found` + } + else if (message !== null) { + this.message = message; + } + + else { + this.message = "Bin Array account not found" + } + } +} + +export class ClockAccountNotFound extends Error { + message: string; + + constructor(message: string="Clock account not found") { + super(); + this.message = message; + } +} + +export class ErrorFetchingActiveBin extends Error { + message: string; + + constructor(message: string="Error fetching active bin") { + super(); + this.message = message; + } +} + +export class ErrorFetchingPositions extends Error { + message: string; + + constructor(message: string="Error fetching positions") { + super(); + this.message = message; + } +} + +export class PositionAccountNotFound extends Error { + message: string; + + constructor(account: string|null=null, message: string|null=null) { + super(); + if (typeof account === "string") { + this.message = `Position account ${account} not found` + } + else if (message !== null) { + this.message = message; + } + + else { + this.message = "Position account not found" + } + } +} + +export class PositionOutOfRange extends Error { + message: string; + + constructor(max_bin: number|null=null, message: string|null=null) { + super(); + if (typeof max_bin === "number") { + this.message = `Position must be within a range of 1 to ${max_bin} bins.` + } + else if (message !== null) { + this.message = message; + } + + else { + this.message = "Position is out of range" + } + } +} + +export class ZeroLiquidityBinsError extends Error { + message: string; + + constructor(message: string="No liquidity to add: Cannot add liquidity to zero bins") { + super(); + this.message = message; + } +} + +export class IllegalBinConfiguration extends Error { + message: string; + + constructor(message: string="You have an illegal bin configuration. Please check that your bin IDs are in the correct order.") { + super(); + this.message = message; + } +} + +export class CannotRemoveZeroLiquidity extends Error { + message: string; + + constructor(message: string="No liquidity to remove") { + super(); + this.message = message; + } +} + +export class CannotClaimZeroRewards extends Error { + message: string; + + constructor(message: string="No LM reward to claim") { + super(); + this.message = message; + } +} + +export class CannotClaimZeroFees extends Error { + message: string; + + constructor(message: string="No fee to claim") { + super(); + this.message = message; + } +} + +export class PriceOutOfRange extends Error { + message: string; + + constructor(message: string="Your min/max price is out of range of the current price") { + super(); + this.message = message; + } +} + +export class PriceRangeTooSmall extends Error { + message: string; + + constructor(message: string="Price range too small") { + super(); + this.message = message; + } +} + +export class SyncError extends Error { + message: string; + + constructor(message: string="Unable to sync with market price due to bin with liquidity between current and " + + "market price bin") { + super(); + this.message = message; + } +} + +export class DiscontinuousBinId extends Error { + message: string; + + constructor(message: string="Bin IDs must be continuous") { + super(); + this.message = message; + } } diff --git a/ts-client/src/dlmm/index.ts b/ts-client/src/dlmm/index.ts index 607d7267..2587afb3 100644 --- a/ts-client/src/dlmm/index.ts +++ b/ts-client/src/dlmm/index.ts @@ -50,7 +50,14 @@ import { TOKEN_ACCOUNT_FEE_BN, U64_MAX, } from "./constants"; -import { DlmmSdkError } from "./error"; +import { + BinArrayAccountNotFound, CannotClaimZeroFees, CannotClaimZeroRewards, CannotRemoveZeroLiquidity, + ClockAccountNotFound, DiscontinuousBinId, DlmmSdkError, + ErrorFetchingActiveBin, ErrorFetchingPositions, + IllegalBinConfiguration, LBPairAccountNotFound, LBPairStateNotFound, NoMintForLBPair, + NoReserveForLBPair, PoolExistsError, PositionAccountNotFound, PositionOutOfRange, + PriceOutOfRange, PriceRangeTooSmall, SyncError, ZeroLiquidityBinsError +} from "./error"; import { Opt, binIdToBinArrayIndex, @@ -390,7 +397,7 @@ export class DLMM { const lbPairAccountInfoBuffer = accountsInfo[0]?.data; if (!lbPairAccountInfoBuffer) - throw new Error(`LB Pair account ${dlmm.toBase58()} not found`); + throw new LBPairAccountNotFound(dlmm.toBase58()); // Pass const lbPairAccInfo = decodeAccount( program, @@ -410,7 +417,7 @@ export class DLMM { } const clockAccountInfoBuffer = accountsInfo[2]?.data; - if (!clockAccountInfoBuffer) throw new Error(`Clock account not found`); + if (!clockAccountInfoBuffer) throw new ClockAccountNotFound(); const clock = ClockLayout.decode(clockAccountInfoBuffer) as Clock; accountsToFetch = [ @@ -590,7 +597,7 @@ export class DLMM { const clockAccount = accountsInfo.pop(); const clockAccountInfoBuffer = clockAccount?.data; - if (!clockAccountInfoBuffer) throw new Error(`Clock account not found`); + if (!clockAccountInfoBuffer) throw new ClockAccountNotFound(); const clock = ClockLayout.decode(clockAccountInfoBuffer) as Clock; const lbPairArraysMap = new Map(); @@ -598,7 +605,7 @@ export class DLMM { const lbPairPubKey = dlmmList[i]; const lbPairAccountInfoBuffer = accountsInfo[i]?.data; if (!lbPairAccountInfoBuffer) - throw new Error(`LB Pair account ${lbPairPubKey.toBase58()} not found`); + throw new LBPairAccountNotFound(lbPairPubKey.toBase58()); const lbPairAccInfo = decodeAccount( program, "lbPair", @@ -702,7 +709,7 @@ export class DLMM { const lbClmmImpl = dlmmList.map((lbPair, index) => { const lbPairState = lbPairArraysMap.get(lbPair.toBase58()); if (!lbPairState) - throw new Error(`LB Pair ${lbPair.toBase58()} state not found`); + throw new LBPairStateNotFound(lbPair.toBase58()); const binArrayBitmapExtensionState = binArrayBitMapExtensionsMap.get( lbPair.toBase58() @@ -743,9 +750,9 @@ export class DLMM { accountsInfo[offsetToRewardMintAccountInfos + index * 2 + 1]; if (!reserveXAccountInfo || !reserveYAccountInfo) - throw new Error( - `Reserve account for LB Pair ${lbPair.toBase58()} not found` - ); + throw new NoReserveForLBPair( + lbPair.toBase58() + ); const reserveXBalance = AccountLayout.decode(reserveXAccountInfo.data); const reserveYBalance = AccountLayout.decode(reserveYAccountInfo.data); @@ -942,7 +949,7 @@ export class DLMM { const lbPairPubkey = lbPairKeys[i - binArrayPubkeyArrayV2.length]; const lbPairAccInfoBufferV2 = binArraysAccInfo[i]; if (!lbPairAccInfoBufferV2) - throw new Error(`LB Pair account ${lbPairPubkey.toBase58()} not found`); + throw new LBPairAccountNotFound(lbPairPubkey.toBase58()); const lbPairAccInfo = decodeAccount( program, "lbPair", @@ -988,9 +995,8 @@ export class DLMM { const reserveYAccount = accountInfos[index + 1]; if (!reserveXAccount || !reserveYAccount) - throw new Error( - `Reserve account for LB Pair ${lbPair.toBase58()} not found` - ); + throw new NoReserveForLBPair(lbPair.toBase58() + ); const reserveAccX = AccountLayout.decode(reserveXAccount.data); const reserveAccY = AccountLayout.decode(reserveYAccount.data); @@ -1003,9 +1009,7 @@ export class DLMM { const mintXAccount = accountInfos[index + 2]; const mintYAccount = accountInfos[index + 3]; if (!mintXAccount || !mintYAccount) - throw new Error( - `Mint account for LB Pair ${lbPair.toBase58()} not found` - ); + throw new NoMintForLBPair(lbPair.toBase58()); const mintX = unpackMint( reserveAccX.mint, @@ -1231,9 +1235,7 @@ export class DLMM { const binArrayPubkey = binArrayPubkeyArrayV2[i]; const binArrayAccBufferV2 = binArraysAccInfo[i]; if (!binArrayAccBufferV2) - throw new Error( - `Bin Array account ${binArrayPubkey.toBase58()} not found` - ); + throw new BinArrayAccountNotFound(binArrayPubkey.toBase58()); const binArrayAccInfo = decodeAccount( this.program, "binArray", @@ -1520,7 +1522,7 @@ export class DLMM { ); if (existsPool) { - throw new Error("Pool already exists"); + throw new PoolExistsError(); } const [lbPair] = deriveLbPair2( @@ -1617,7 +1619,7 @@ export class DLMM { ); if (existsPool) { - throw new Error("Pool already exists"); + throw new PoolExistsError(); } const [lbPair] = deriveLbPairWithPresetParamWithIndexKey( @@ -2231,7 +2233,7 @@ export class DLMM { const [activeBin, positionsV2] = promiseResults; if (!activeBin) { - throw new Error("Error fetching active bin"); + throw new ErrorFetchingActiveBin(); } if (!userPubKey) { @@ -2248,7 +2250,7 @@ export class DLMM { ]; if (!positions) { - throw new Error("Error fetching positions"); + throw new ErrorFetchingPositions(); } const binArrayPubkeySetV2 = new Set(); @@ -2289,7 +2291,7 @@ export class DLMM { } if (!lbPairAccInfo) - throw new Error(`LB Pair account ${this.pubkey.toBase58()} not found`); + throw new LBPairAccountNotFound(this.pubkey.toBase58()); const clock: Clock = ClockLayout.decode(clockAccInfo.data); @@ -2503,9 +2505,7 @@ export class DLMM { await this.program.provider.connection.getAccountInfo(positionPubKey); if (!positionAccountInfo) { - throw new Error( - `Position account ${positionPubKey.toBase58()} not found` - ); + throw new PositionAccountNotFound(positionPubKey.toBase58()); } let position: IPosition = wrapPosition( @@ -3146,9 +3146,7 @@ export class DLMM { : MAX_ACTIVE_BIN_SLIPPAGE; if (upperBinId >= lowerBinId + DEFAULT_BIN_PER_POSITION.toNumber()) { - throw new Error( - `Position must be within a range of 1 to ${DEFAULT_BIN_PER_POSITION.toNumber()} bins.` - ); + throw new PositionOutOfRange(DEFAULT_BIN_PER_POSITION.toNumber()); } const preInstructions: Array = []; @@ -3275,7 +3273,7 @@ export class DLMM { ); if (binLiquidityDist.length === 0) { - throw new Error("No liquidity to add"); + throw new ZeroLiquidityBinsError(); } const liquidityParams: LiquidityParameterByWeight = { @@ -3623,11 +3621,11 @@ export class DLMM { this.processXYAmountDistribution(xYAmountDistribution); if (lowerBinId < positionAccount.lowerBinId) - throw new Error( + throw new IllegalBinConfiguration( `Lower Bin ID (${lowerBinId}) lower than Position Lower Bin Id (${positionAccount.lowerBinId})` ); if (upperBinId > positionAccount.upperBinId) - throw new Error( + throw new IllegalBinConfiguration( `Upper Bin ID (${upperBinId}) higher than Position Upper Bin Id (${positionAccount.upperBinId})` ); @@ -3660,7 +3658,7 @@ export class DLMM { ); if (binLiquidityDist.length === 0) { - throw new Error("No liquidity to add"); + throw new ZeroLiquidityBinsError(); } const lowerBinArrayIndex = binIdToBinArrayIndex( @@ -3926,7 +3924,7 @@ export class DLMM { }); if (binIdsWithLiquidity.length == 0) { - throw new Error("No liquidity to remove"); + throw new CannotRemoveZeroLiquidity(); } const lowerBinIdWithLiquidity = binIdsWithLiquidity[0].binId.toNumber(); @@ -5090,7 +5088,7 @@ export class DLMM { position: LbPosition; }): Promise { if (isPositionNoReward(position.positionData)) { - throw new Error("No LM reward to claim"); + throw new CannotClaimZeroRewards(); } const claimTransactions = await this.createClaimBuildMethod({ @@ -5142,7 +5140,7 @@ export class DLMM { if ( positions.every((position) => isPositionNoReward(position.positionData)) ) { - throw new Error("No LM reward to claim"); + throw new CannotClaimZeroRewards(); } const claimAllTxs = ( @@ -5247,7 +5245,7 @@ export class DLMM { position: LbPosition; }): Promise { if (isPositionNoFee(position.positionData)) { - throw new Error("No fee to claim"); + throw new CannotClaimZeroFees(); } const claimFeeTxs = await this.createClaimSwapFeeMethod({ @@ -5294,7 +5292,7 @@ export class DLMM { positions: LbPosition[]; }): Promise { if (positions.every((position) => isPositionNoFee(position.positionData))) { - throw new Error("No fee to claim"); + throw new CannotClaimZeroFees(); } const claimAllTxs = ( @@ -5364,7 +5362,7 @@ export class DLMM { isPositionNoFee(position.positionData) && isPositionNoReward(position.positionData) ) { - throw new Error("No fee/reward to claim"); + throw new CannotClaimZeroRewards("No fee/reward to claim"); } const claimAllSwapFeeTxs = await this.createClaimSwapFeeMethod({ @@ -5457,11 +5455,11 @@ export class DLMM { ); if (minBinId.toNumber() < this.lbPair.activeId) { - throw new Error("minPrice < current pair price"); + throw new PriceOutOfRange("minPrice < current pair price"); } if (minBinId.toNumber() >= maxBinId.toNumber()) { - throw new Error("Price range too small"); + throw new PriceRangeTooSmall(); } // Generate amount for each bin @@ -6422,9 +6420,7 @@ export class DLMM { const activeBinId = activeBin.binId; if (!this.canSyncWithMarketPrice(marketPrice, activeBinId)) { - throw new Error( - "Unable to sync with market price due to bin with liquidity between current and market price bin" - ); + throw new SyncError(); } const fromBinArrayIndex = binIdToBinArrayIndex(new BN(activeBinId)); @@ -7712,7 +7708,7 @@ export class DLMM { binIds.push(binAndAmount.binId); if (currentBinId && binAndAmount.binId !== currentBinId + 1) { - throw new Error("Discontinuous Bin ID"); + throw new DiscontinuousBinId(); } else { currentBinId = binAndAmount.binId; }