Skip to content

Commit

Permalink
feat(core): allow placing outputs at specific index
Browse files Browse the repository at this point in the history
  • Loading branch information
capt-nemo429 committed Dec 10, 2022
1 parent 821ebcc commit c5f0347
Show file tree
Hide file tree
Showing 9 changed files with 136 additions and 7 deletions.
1 change: 1 addition & 0 deletions jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export default {
testPathIgnorePatterns: ["/node_modules/", "/dist/", "/coverage/"],
collectCoverage: false,
testEnvironment: "node",
maxWorkers: 1, // this limit is being used to circumvent this issue https://github.com/facebook/jest/issues/11617
preset: "ts-jest",
roots: ["./packages"]
};
2 changes: 1 addition & 1 deletion packages/common/jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export default {
functions: "100"
}
},
// maxWorkers: 1, // this limit is being used to circumvent this issue https://github.com/facebook/jest/issues/11617
maxWorkers: 1, // this limit is being used to circumvent this issue https://github.com/facebook/jest/issues/11617
preset: "ts-jest",
roots: ["./src"]
};
2 changes: 1 addition & 1 deletion packages/core/jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export default {
functions: "100"
}
},
// maxWorkers: 1, // this limit is being used to circumvent this issue https://github.com/facebook/jest/issues/11617
maxWorkers: 1, // this limit is being used to circumvent this issue https://github.com/facebook/jest/issues/11617
preset: "ts-jest",
roots: ["./src"]
};
21 changes: 21 additions & 0 deletions packages/core/src/builder/transactionBuilder.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,27 @@ describe("basic construction", () => {
expect(builder.dataInputs).toHaveLength(0);
});

it("Should place outputs at specific index", () => {
const firstOutput = new OutputBuilder(SAFE_MIN_BOX_VALUE, a1.address, height);
const secondOutput = new OutputBuilder(SAFE_MIN_BOX_VALUE * 2n, a1.address, height);

const builder = new TransactionBuilder(height)
.from(regularBoxesMock)
.to([firstOutput, secondOutput]);

expect(builder.outputs.at(0)).toBe(firstOutput);
expect(builder.outputs.at(1)).toBe(secondOutput);

const placedOutput = new OutputBuilder(SAFE_MIN_BOX_VALUE * 3n, a2.address, height);

builder.and.to(placedOutput, { index: 1 });
expect(builder.outputs.length).toBe(3);

expect(builder.outputs.at(0)).toBe(firstOutput); // should remain unchanged
expect(builder.outputs.at(1)).toBe(placedOutput); // should be placed at index = 1
expect(builder.outputs.at(2)).toBe(secondOutput); // should be moved to third place
});

it("Should set change address by base58 encoded address", () => {
const builder = new TransactionBuilder(height).from(regularBoxesMock).sendChangeTo(a1.address);

Expand Down
15 changes: 12 additions & 3 deletions packages/core/src/builder/transactionBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,13 @@ import {
} from "@fleet-sdk/common";
import { InvalidInput, MalformedTransaction, NotAllowedTokenBurning } from "../errors";
import { NonStandardizedMinting } from "../errors/nonStandardizedMinting";
import { ErgoAddress, InputsCollection, OutputsCollection, TokensCollection } from "../models";
import {
AddOutputOptions,
ErgoAddress,
InputsCollection,
OutputsCollection,
TokensCollection
} from "../models";
import { OutputBuilder, SAFE_MIN_BOX_VALUE } from "./outputBuilder";
import { BoxSelector } from "./selector";
import { TransactionBuilderSettings } from "./transactionBuilderSettings";
Expand Down Expand Up @@ -117,8 +123,11 @@ export class TransactionBuilder {
return this;
}

public to(outputs: OutputBuilder[] | OutputBuilder): TransactionBuilder {
this._outputs.add(outputs);
public to(
outputs: OutputBuilder[] | OutputBuilder,
options?: AddOutputOptions
): TransactionBuilder {
this._outputs.add(outputs, options);

return this;
}
Expand Down
18 changes: 18 additions & 0 deletions packages/core/src/models/collections/collection.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,24 @@ describe("collection base", () => {
expect(collection).toHaveLength(numbers.length); // push on previous line should not affect internal array.
});

it("Should get items by index", () => {
const collection = new MockCollection();
collection.add(numbers);

for (let i = 0; i < numbers.length; i++) {
expect(collection.at(i)).toEqual(numbers[i]);
}
});

it("Should fail when trying to get item out of index range", () => {
const collection = new MockCollection();
collection.add(numbers);

expect(() => {
collection.at(collection.length + 1);
}).toThrow(RangeError);
});

it("Should iterate correctly for all items", () => {
const collection = new MockCollection();
expect(collection.isEmpty).toBeTruthy();
Expand Down
8 changes: 8 additions & 0 deletions packages/core/src/models/collections/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ export abstract class Collection<InternalType, ExternalType> implements Iterable
return this.length === 0;
}

public at(index: number): InternalType {
if (this._isIndexOutOfBounds(index)) {
throw new RangeError(`Index '${index}' is out of range.`);
}

return this._items[index];
}

public add(items: ExternalType[] | ExternalType): number {
return this._addOneOrMore(items);
}
Expand Down
51 changes: 51 additions & 0 deletions packages/core/src/models/collections/outputsCollection.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,57 @@ describe("outputs collection", () => {
expect(first(collection.toArray())).toBe(output);
});

it("Should add a single item at a specific index", () => {
const first = new OutputBuilder(SAFE_MIN_BOX_VALUE, address, height);
const second = new OutputBuilder(SAFE_MIN_BOX_VALUE * 2n, address, height);

const collection = new OutputsCollection([first, second]);
expect(collection.at(0)).toBe(first);
expect(collection.at(1)).toBe(second);

const placedOutput = new OutputBuilder(SAFE_MIN_BOX_VALUE * 3n, address, height);
const newLen = collection.add(placedOutput, { index: 1 });
expect(newLen).toBe(3);

expect(collection.at(0)).toBe(first); // should remain unchanged
expect(collection.at(1)).toBe(placedOutput); // should be placed at index = 1
expect(collection.at(2)).toBe(second); // should be moved to third place
});

it("Should append items at a specific index", () => {
const first = new OutputBuilder(SAFE_MIN_BOX_VALUE, address, height);
const second = new OutputBuilder(SAFE_MIN_BOX_VALUE * 2n, address, height);

const collection = new OutputsCollection([first, second]);
expect(collection.at(0)).toBe(first);
expect(collection.at(1)).toBe(second);

const fistPlacedOutput = new OutputBuilder(SAFE_MIN_BOX_VALUE * 3n, address, height);
const secondPlacedOutput = new OutputBuilder(SAFE_MIN_BOX_VALUE * 4n, address, height);
const newLen = collection.add([fistPlacedOutput, secondPlacedOutput], { index: 1 });
expect(newLen).toBe(4);

expect(collection.at(0)).toBe(first); // should remain unchanged

expect(collection.at(1)).toBe(fistPlacedOutput); // should be placed at index = 1
expect(collection.at(2)).toBe(secondPlacedOutput); // should be placed at index = 2

expect(collection.at(3)).toBe(second); // should be moved to third place
});

it("Should fail when trying to add out of range", () => {
const collection = new OutputsCollection([
new OutputBuilder(SAFE_MIN_BOX_VALUE, address, height),
new OutputBuilder(SAFE_MIN_BOX_VALUE * 2n, address, height)
]);

const placedOutput = new OutputBuilder(SAFE_MIN_BOX_VALUE * 3n, address, height);

expect(() => {
collection.add(placedOutput, { index: 5 /* out of range value */ });
}).toThrow(RangeError);
});

it("Should append items", () => {
const collection = new OutputsCollection();

Expand Down
25 changes: 23 additions & 2 deletions packages/core/src/models/collections/outputsCollection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { SelectionTarget } from "../../builder/selector/boxSelector";
import { NotFoundError } from "../../errors";
import { Collection } from "./collection";

export type AddOutputOptions = { index: number };

export class OutputsCollection extends Collection<OutputBuilder, OutputBuilder> {
constructor(outputs?: OutputBuilder | OutputBuilder[]) {
super();
Expand All @@ -13,12 +15,31 @@ export class OutputsCollection extends Collection<OutputBuilder, OutputBuilder>
}
}

protected override _addOne(outputBuilder: OutputBuilder): number {
this._items.push(outputBuilder);
protected override _addOne(output: OutputBuilder, options?: AddOutputOptions): number {
if (isDefined(options) && isDefined(options.index)) {
if (this._isIndexOutOfBounds(options.index)) {
throw new RangeError(`Index '${options.index}' is out of range.`);
}

this._items.splice(options.index, 0, output);
} else {
this._items.push(output);
}

return this._items.length;
}

public override add(
outputs: OutputBuilder | OutputBuilder[],
options?: AddOutputOptions
): number {
if (Array.isArray(outputs) && isDefined(options) && isDefined(options.index)) {
return this._addOneOrMore(outputs.reverse(), options);
}

return this._addOneOrMore(outputs, options);
}

public remove(output: OutputBuilder): number;
public remove(index: number): number;
public remove(outputs: OutputBuilder | number): number {
Expand Down

0 comments on commit c5f0347

Please sign in to comment.