diff --git a/package.json b/package.json index 79f5a6753..91f1c9ea5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@interlay/interbtc-api", - "version": "2.2.3", + "version": "2.2.4", "description": "JavaScript library to interact with interBTC", "main": "build/src/index.js", "typings": "build/src/index.d.ts", diff --git a/src/parachain/redeem.ts b/src/parachain/redeem.ts index 7fff4a37e..fb624c796 100644 --- a/src/parachain/redeem.ts +++ b/src/parachain/redeem.ts @@ -12,7 +12,7 @@ import { InterbtcPrimitivesRedeemRedeemRequest, } from "@polkadot/types/lookup"; -import { VaultsAPI } from "./vaults"; +import { NO_LIQUIDATION_VAULT_FOUND_REJECTION, VaultsAPI } from "./vaults"; import { decodeBtcAddress, decodeFixedPointType, @@ -27,7 +27,7 @@ import { allocateAmountsToVaults } from "../utils/issueRedeem"; import { ElectrsAPI } from "../external"; import { TransactionAPI } from "./transaction"; import { OracleAPI } from "./oracle"; -import { CollateralCurrencyExt, ExtrinsicData, Redeem, WrappedCurrency } from "../types"; +import { CollateralCurrencyExt, ExtrinsicData, Redeem, SystemVaultExt, WrappedCurrency } from "../types"; import { SystemAPI } from "./system"; /** @@ -332,7 +332,15 @@ export class DefaultRedeemAPI implements RedeemAPI { } async getMaxBurnableTokens(collateralCurrency: CollateralCurrencyExt): Promise> { - const liquidationVault = await this.vaultsAPI.getLiquidationVault(collateralCurrency); + const liquidationVault: SystemVaultExt | null = await this.vaultsAPI.getLiquidationVault(collateralCurrency) + // method rejects if no vault was found, wrap as null + .catch((reason) => (reason === NO_LIQUIDATION_VAULT_FOUND_REJECTION) ? null : Promise.reject(reason)); + + if (liquidationVault === null) { + // no liquidation vault exists, therefore, no burnable tokens) + return BitcoinAmount.zero(); + } + // This should never be below 0, but still... const burnableTokens = liquidationVault.issuedTokens.sub(liquidationVault.toBeRedeemedTokens); if (burnableTokens.lte(BitcoinAmount.zero())) { diff --git a/src/parachain/vaults.ts b/src/parachain/vaults.ts index ed91e1ded..6505272df 100644 --- a/src/parachain/vaults.ts +++ b/src/parachain/vaults.ts @@ -410,6 +410,8 @@ export interface VaultsAPI { ): Promise; } +export const NO_LIQUIDATION_VAULT_FOUND_REJECTION = "No liquidation vault found"; + export class DefaultVaultsAPI implements VaultsAPI { constructor( private api: ApiPromise, @@ -657,8 +659,9 @@ export class DefaultVaultsAPI implements VaultsAPI { const vaultCurrencyPair = newVaultCurrencyPair(this.api, collateralCurrency, this.wrappedCurrency); const liquidationVault = await this.api.query.vaultRegistry.liquidationVault(vaultCurrencyPair); if (!liquidationVault.isSome) { - return Promise.reject("System vault could not be fetched"); + return Promise.reject(NO_LIQUIDATION_VAULT_FOUND_REJECTION); } + return await parseSystemVault( this.api, liquidationVault.value as VaultRegistrySystemVault, diff --git a/test/unit/parachain/redeem.test.ts b/test/unit/parachain/redeem.test.ts index b6d2927b7..70ad7ac84 100644 --- a/test/unit/parachain/redeem.test.ts +++ b/test/unit/parachain/redeem.test.ts @@ -4,6 +4,7 @@ import { DefaultRedeemAPI, DefaultVaultsAPI, VaultsAPI } from "../../../src"; import { newMonetaryAmount } from "../../../src/utils"; import { ExchangeRate, KBtc, Kintsugi } from "@interlay/monetary-js"; import Big from "big.js"; +import { NO_LIQUIDATION_VAULT_FOUND_REJECTION } from "../../../src/parachain/vaults"; describe("DefaultRedeemAPI", () => { let redeemApi: DefaultRedeemAPI; @@ -95,4 +96,26 @@ describe("DefaultRedeemAPI", () => { ); }); }); + + describe("getMaxBurnableTokens", () => { + afterEach(() => { + sinon.restore(); + sinon.reset(); + }); + + it("should return zero if getLiquidationVault rejects with no liquidation vault message", async () => { + // stub internal call to return no liquidation vault + stubbedVaultsApi.getLiquidationVault.withArgs(sinon.match.any).returns(Promise.reject(NO_LIQUIDATION_VAULT_FOUND_REJECTION)); + + const actualValue = await redeemApi.getMaxBurnableTokens(Kintsugi); + expect(actualValue.toBig().toNumber()).to.be.eq(0); + }); + + it("should propagate rejection if getLiquidationVault rejects with other message", async () => { + // stub internal call to return no liquidation vault + stubbedVaultsApi.getLiquidationVault.withArgs(sinon.match.any).returns(Promise.reject("foobar happened here")); + + await expect(redeemApi.getMaxBurnableTokens(Kintsugi)).to.be.rejectedWith("foobar happened here"); + }); + }); });