Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fee error types #110

Merged
merged 2 commits into from
Jan 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
184 changes: 135 additions & 49 deletions src/fees.test.ts
Original file line number Diff line number Diff line change
@@ -1,93 +1,179 @@
import BigNumber from "bignumber.js";

import { FeeValidationError } from "./types";
import {
validateFeeRate,
validateFee,
estimateMultisigTransactionFee,
estimateMultisigTransactionFeeRate,
checkFeeError,
checkFeeRateError,
} from "./fees";
import { P2SH } from "./p2sh";
import { P2SH_P2WSH } from "./p2sh_p2wsh";
import { P2WSH } from "./p2wsh";

describe("fees", () => {
describe("validateFeeRate", () => {
it("should return an error message for an unparseable fee rate", () => {
it("should return an error and message for an unparseable fee rate", () => {
BigNumber.DEBUG = true;
expect(validateFeeRate(null)).toMatch(/invalid fee rate/i);
const feeRateSatsPerVbyte = null;
expect(checkFeeRateError(feeRateSatsPerVbyte)).toBe(
FeeValidationError.INVALID_FEE_RATE
);
expect(validateFeeRate(feeRateSatsPerVbyte)).toMatch(/invalid fee rate/i);
BigNumber.DEBUG = false;
});

it("should return an error message for an unparseable fee rate", () => {
expect(validateFeeRate("foo")).toMatch(/invalid fee rate/i);
it("should return an error and message for an unparseable fee rate", () => {
const feeRateSatsPerVbyte = "foo";
expect(checkFeeRateError(feeRateSatsPerVbyte)).toBe(
FeeValidationError.INVALID_FEE_RATE
);
expect(validateFeeRate(feeRateSatsPerVbyte)).toMatch(/invalid fee rate/i);
});

it("should return an error message for a negative fee rate", () => {
expect(validateFeeRate(-1)).toMatch(/cannot be negative/i);
it("should return an error and message for a negative fee rate", () => {
const feeRateSatsPerVbyte = -1;
expect(checkFeeRateError(feeRateSatsPerVbyte)).toBe(
FeeValidationError.FEE_RATE_CANNOT_BE_NEGATIVE
);
expect(validateFeeRate(feeRateSatsPerVbyte)).toMatch(
/cannot be negative/i
);
});

it("should return an empty string for a zero fee rate", () => {
expect(validateFeeRate(0)).toBe("");
const feeRateSatsPerVbyte = 0;
expect(checkFeeRateError(feeRateSatsPerVbyte)).toBe(null);
expect(validateFeeRate(feeRateSatsPerVbyte)).toBe("");
});

it("should return an error message when the fee rate is too high", () => {
expect(validateFeeRate(10000)).toMatch(/too high/i);
it("should return an error and message when the fee rate is too high", () => {
const feeRateSatsPerVbyte = 10000;
expect(checkFeeRateError(feeRateSatsPerVbyte)).toBe(
FeeValidationError.FEE_RATE_TOO_HIGH
);
expect(validateFeeRate(feeRateSatsPerVbyte)).toMatch(/too high/i);
});

it("return an empty string for an acceptable fee rate", () => {
expect(validateFeeRate(100)).toBe("");
it("return an empty string and no error for an acceptable fee rate", () => {
const feeRateSatsPerVbyte = 100;
expect(checkFeeRateError(feeRateSatsPerVbyte)).toBe(null);
expect(validateFeeRate(feeRateSatsPerVbyte)).toBe("");
});
});

describe("validateFee", () => {
it("should return an error message for an unparseable fee", () => {
it("should return an error and message for an unparseable fee", () => {
// If BigNumber.DEBUG is set true then an error will be thrown if this BigNumber constructor receives an invalid value
// see https://mikemcl.github.io/bignumber.js/#debug
BigNumber.DEBUG = true;
expect(validateFee(null, 1000000)).toMatch(/invalid fee/i);
const feeSats = null;
const inputsTotalSats = 1000000;
expect(checkFeeError(feeSats, inputsTotalSats)).toBe(
FeeValidationError.INVALID_FEE
);
expect(validateFee(feeSats, inputsTotalSats)).toMatch(/invalid fee/i);
BigNumber.DEBUG = false;
});

it("should return an error message for an unparseable inputTotalSats", () => {
it("should return an error and message for an unparseable inputTotalSats", () => {
BigNumber.DEBUG = true;
expect(validateFee(10000, null)).toMatch(/invalid total input amount/i);
const feeSats = 10000;
const inputsTotalSats = null;
expect(checkFeeError(feeSats, inputsTotalSats)).toBe(
FeeValidationError.INVALID_INPUT_AMOUNT
);
expect(validateFee(feeSats, inputsTotalSats)).toMatch(
/invalid total input amount/i
);
BigNumber.DEBUG = false;
});

it("should return an error message for an unparseable fee", () => {
expect(validateFee("foo", 1000000)).toMatch(/invalid fee/i);
});

it("should return an error message for an unparseable total input amount", () => {
expect(validateFee(10000, "foo")).toMatch(/invalid total input amount/i);
});

it("should return an error message for a negative fee", () => {
expect(validateFee(-1, 1000000)).toMatch(/cannot be negative/i);
});

it("should return an error message for a negative total input amount", () => {
expect(validateFee(10000, -1)).toMatch(/must be positive/i);
});

it("should return an error message for a zero total linput amount", () => {
expect(validateFee(10000, 0)).toMatch(/must be positive/i);
});

it("should return an empty string for a zero fee", () => {
expect(validateFee(0, 1000000)).toBe("");
});

it("should return an error message when the fee is too high", () => {
expect(validateFee(2500001, 10000000)).toMatch(/too high/i);
});

it("should return an error message when the fee higher than the total input amount", () => {
expect(validateFee(100001, 100000)).toMatch(/too high/i);
});

it("should return an empty string for an acceptable fee", () => {
expect(validateFee(10000, 1000000)).toBe("");
it("should return an error and message for an unparseable fee", () => {
const feeSats = "foo";
const inputsTotalSats = 1000000;
expect(checkFeeError(feeSats, inputsTotalSats)).toBe(
FeeValidationError.INVALID_FEE
);
expect(validateFee(feeSats, inputsTotalSats)).toMatch(/invalid fee/i);
});

it("should return an error and message for an unparseable total input amount", () => {
const feeSats = 10000;
const inputsTotalSats = "foo";
expect(checkFeeError(feeSats, inputsTotalSats)).toBe(
FeeValidationError.INVALID_INPUT_AMOUNT
);
expect(validateFee(feeSats, inputsTotalSats)).toMatch(
/invalid total input amount/i
);
});

it("should return an error and message for a negative fee", () => {
const feeSats = -1;
const inputsTotalSats = 1000000;
expect(checkFeeError(feeSats, inputsTotalSats)).toBe(
FeeValidationError.FEE_CANNOT_BE_NEGATIVE
);
expect(validateFee(feeSats, inputsTotalSats)).toMatch(
/cannot be negative/i
);
});

it("should return an error and message for a negative total input amount", () => {
const feeSats = 10000;
const inputsTotalSats = -1;
expect(checkFeeError(feeSats, inputsTotalSats)).toBe(
FeeValidationError.INPUT_AMOUNT_MUST_BE_POSITIVE
);
expect(validateFee(feeSats, inputsTotalSats)).toMatch(
/must be positive/i
);
});

it("should return an error and message for a zero total linput amount", () => {
const feeSats = 10000;
const inputsTotalSats = 0;
expect(checkFeeError(feeSats, inputsTotalSats)).toBe(
FeeValidationError.INPUT_AMOUNT_MUST_BE_POSITIVE
);
expect(validateFee(feeSats, inputsTotalSats)).toMatch(
/must be positive/i
);
});

it("should return an empty string and not error for a zero fee", () => {
const feeSats = 0;
const inputsTotalSats = 1000000;
expect(checkFeeError(feeSats, inputsTotalSats)).toBe(null);
expect(validateFee(feeSats, inputsTotalSats)).toBe("");
});

it("should return an error and message when the fee is too high", () => {
const feeSats = 2500001;
const inputsTotalSats = 10000000;
expect(checkFeeError(feeSats, inputsTotalSats)).toBe(
FeeValidationError.FEE_TOO_HIGH
);
expect(validateFee(feeSats, inputsTotalSats)).toMatch(/too high/i);
});

it("should return an error and message when the fee higher than the total input amount", () => {
const feeSats = 100001;
const inputsTotalSats = 100000;
expect(checkFeeError(feeSats, inputsTotalSats)).toBe(
FeeValidationError.FEE_TOO_HIGH
);
expect(validateFee(feeSats, inputsTotalSats)).toMatch(/too high/i);
});

it("should return an empty string and no error for an acceptable fee", () => {
const feeSats = 10000;
const inputsTotalSats = 1000000;
expect(checkFeeError(feeSats, inputsTotalSats)).toBe(null);
expect(validateFee(feeSats, inputsTotalSats)).toBe("");
});
});

Expand Down
Loading