Skip to content
Open
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
5 changes: 5 additions & 0 deletions .changeset/tidy-selection-fails.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@fleet-sdk/core": patch
---

fix(core): throw InsufficientInputs when a token target cannot be reached because no selected input holds the token, instead of crashing with "Empty array." or a TypeError on empty selections
24 changes: 24 additions & 0 deletions packages/core/src/builder/selector/boxSelector.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,30 @@ describe("Validations", () => {
}).toThrow(InsufficientInputs);
});

it("Should fail if tokens target is unreached and no input holds the token", () => {
const tokenId = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
const selector = new BoxSelector(regularBoxes);

let error: unknown;
try {
selector.select({ tokens: [{ tokenId, amount: 100n }] });
} catch (e) {
error = e;
}

expect(error).toBeInstanceOf(InsufficientInputs);
expect((error as InsufficientInputs).unreached.tokens).toEqual([{ tokenId, amount: 100n }]);
});

it("Should fail if tokens target is unreached and there are no inputs at all", () => {
const tokenId = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
const selector = new BoxSelector([]);

expect(() => {
selector.select({ tokens: [{ tokenId, amount: 100n }] });
}).toThrow(InsufficientInputs);
});

it("Should fail if any target is unreached", () => {
const tokenId = "0cd8c9f416e5b1ca9f986a7f10a84191dfb85941619e49e53c0dc30ebf83324b";
const selector = new BoxSelector(regularBoxes);
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/builder/selector/boxSelector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export class BoxSelector<T extends Box<bigint>> {
let inclusion = this._ensureInclusionBoxIds;

// if the target has a token that is being minted, then the first input should be included
if (target.tokens?.some((x) => x.tokenId === unselected[0].boxId)) {
if (some(unselected) && target.tokens?.some((x) => x.tokenId === unselected[0].boxId)) {
inclusion = new Set(this._ensureInclusionBoxIds).add(unselected[0].boxId);
}

Expand Down Expand Up @@ -139,7 +139,7 @@ export class BoxSelector<T extends Box<bigint>> {
for (const tokenTarget of target.tokens) {
const totalSelected = utxoSum(inputs, tokenTarget.tokenId);
if (tokenTarget.amount && tokenTarget.amount > totalSelected) {
if (tokenTarget.tokenId === first(inputs).boxId) {
if (some(inputs) && tokenTarget.tokenId === first(inputs).boxId) {
// if the token is the same as the first input, then it is being minted
continue;
}
Expand Down