Skip to content

Commit

Permalink
Merge pull request #637 from bvotteler/fix-max-burnable-tokens-return…
Browse files Browse the repository at this point in the history
…-zero

Fix: Return zero max burnable tokens when no liquidation vault exists
  • Loading branch information
bvotteler authored May 23, 2023
2 parents 80fbfb7 + b057649 commit a629d9a
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 5 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
14 changes: 11 additions & 3 deletions src/parachain/redeem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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";

/**
Expand Down Expand Up @@ -332,7 +332,15 @@ export class DefaultRedeemAPI implements RedeemAPI {
}

async getMaxBurnableTokens(collateralCurrency: CollateralCurrencyExt): Promise<MonetaryAmount<WrappedCurrency>> {
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())) {
Expand Down
5 changes: 4 additions & 1 deletion src/parachain/vaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,8 @@ export interface VaultsAPI {
): Promise<Big | undefined>;
}

export const NO_LIQUIDATION_VAULT_FOUND_REJECTION = "No liquidation vault found";

export class DefaultVaultsAPI implements VaultsAPI {
constructor(
private api: ApiPromise,
Expand Down Expand Up @@ -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,
Expand Down
23 changes: 23 additions & 0 deletions test/unit/parachain/redeem.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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");
});
});
});

0 comments on commit a629d9a

Please sign in to comment.