diff --git a/test/unit/operation.test.ts b/test/unit/operation.test.ts new file mode 100644 index 00000000..a6f09b7a --- /dev/null +++ b/test/unit/operation.test.ts @@ -0,0 +1,164 @@ +import { describe, it, expect } from "vitest"; +import { Operation } from "../../src/operation.js"; +import xdr from "../../src/xdr.js"; + +describe("Operation._checkUnsignedIntValue()", () => { + it("returns correct values for valid inputs", () => { + const cases: Array<{ + value: number | string | undefined; + expected: number | undefined; + }> = [ + { value: 0, expected: 0 }, + { value: 10, expected: 10 }, + { value: "0", expected: 0 }, + { value: "10", expected: 10 }, + { value: undefined, expected: undefined }, + ]; + + for (const { value, expected } of cases) { + expect(Operation._checkUnsignedIntValue("field", value)).toBe(expected); + } + }); + + it("throws for invalid values", () => { + const invalids: unknown[] = [ + {}, + [], + "", + "test", + "0.5", + "-10", + "-10.5", + "Infinity", + Infinity, + "Nan", + NaN, + ]; + + for (const value of invalids) { + expect(() => + Operation._checkUnsignedIntValue("field", value as number), + ).toThrow(); + } + }); + + it("applies isValidFunction when provided", () => { + const lessThan10 = (v: number) => v < 10; + + expect( + Operation._checkUnsignedIntValue("field", undefined, lessThan10), + ).toBe(undefined); + + expect(Operation._checkUnsignedIntValue("field", 8, lessThan10)).toBe(8); + expect(Operation._checkUnsignedIntValue("field", "8", lessThan10)).toBe(8); + + expect(() => + Operation._checkUnsignedIntValue("field", 12, lessThan10), + ).toThrow(); + expect(() => + Operation._checkUnsignedIntValue("field", "12", lessThan10), + ).toThrow(); + }); +}); + +describe("Operation.isValidAmount()", () => { + it("returns true for valid amounts", () => { + const valid = ["10", "0.10", "0.1234567", "922337203685.4775807"]; + for (const amount of valid) { + expect(Operation.isValidAmount(amount)).toBe(true); + } + }); + + it("returns false for invalid amounts", () => { + const invalid: unknown[] = [ + 100, + 100.5, + "", + "test", + "0", + "-10", + "-10.5", + "0.12345678", + "922337203685.4775808", + "Infinity", + Infinity, + "Nan", + NaN, + ]; + for (const amount of invalid) { + expect(Operation.isValidAmount(amount as string)).toBe(false); + } + }); + + it("allows 0 only when allowZero is true", () => { + expect(Operation.isValidAmount("0")).toBe(false); + expect(Operation.isValidAmount("0", true)).toBe(true); + }); +}); + +describe("Operation._fromXDRAmount()", () => { + it("correctly parses XDR amounts", () => { + expect(Operation._fromXDRAmount(xdr.Int64.fromString("1"))).toBe( + "0.0000001", + ); + expect(Operation._fromXDRAmount(xdr.Int64.fromString("10000000"))).toBe( + "1.0000000", + ); + expect(Operation._fromXDRAmount(xdr.Int64.fromString("10000000000"))).toBe( + "1000.0000000", + ); + expect( + Operation._fromXDRAmount(xdr.Int64.fromString("1000000000000000000")), + ).toBe("100000000000.0000000"); + }); +}); + +describe("Operation._toXDRAmount()", () => { + it("correctly converts string amounts to XDR Int64", () => { + expect(Operation._toXDRAmount("0.0000001").toString()).toBe("1"); + expect(Operation._toXDRAmount("1.0000000").toString()).toBe("10000000"); + expect(Operation._toXDRAmount("1000.0000000").toString()).toBe( + "10000000000", + ); + expect(Operation._toXDRAmount("100000000000.0000000").toString()).toBe( + "1000000000000000000", + ); + }); +}); + +describe("Operation._fromXDRPrice()", () => { + it("converts an XDR Price to a decimal string", () => { + expect(Operation._fromXDRPrice(new xdr.Price({ n: 1, d: 2 }))).toBe("0.5"); + expect(Operation._fromXDRPrice(new xdr.Price({ n: 11, d: 10 }))).toBe( + "1.1", + ); + expect(Operation._fromXDRPrice(new xdr.Price({ n: 1, d: 1 }))).toBe("1"); + }); +}); + +describe("Operation._toXDRPrice()", () => { + it("converts a string price to XDR", () => { + const price = Operation._toXDRPrice("0.5"); + expect(price.n() / price.d()).toBeCloseTo(0.5); + }); + + it("converts a number price to XDR", () => { + const price = Operation._toXDRPrice(1.5); + expect(price.n() / price.d()).toBeCloseTo(1.5); + }); + + it("converts a {n, d} fraction to XDR", () => { + const price = Operation._toXDRPrice({ n: 11, d: 10 }); + expect(price.n()).toBe(11); + expect(price.d()).toBe(10); + }); + + it("throws for a negative price", () => { + expect(() => Operation._toXDRPrice({ n: -1, d: 10 })).toThrow( + /price must be positive/, + ); + expect(() => Operation._toXDRPrice({ n: 1, d: -10 })).toThrow( + /price must be positive/, + ); + }); +}); diff --git a/test/unit/operations/bump_sequence.test.ts b/test/unit/operations/bump_sequence.test.ts new file mode 100644 index 00000000..a8d04945 --- /dev/null +++ b/test/unit/operations/bump_sequence.test.ts @@ -0,0 +1,42 @@ +import { describe, it, expect } from "vitest"; +import { Operation } from "../../../src/operation.js"; +import xdr from "../../../src/xdr.js"; + +describe("Operation.bumpSequence()", () => { + it("creates a bumpSequence operation", () => { + const opts = { bumpTo: "77833036561510299" }; + const op = Operation.bumpSequence(opts); + const xdrHex = op.toXDR("hex"); + const operation = xdr.Operation.fromXDR(xdrHex, "hex"); + const obj = Operation.fromXDRObject(operation); + + expect(obj.type).toBe("bumpSequence"); + if (obj.type !== "bumpSequence") throw new Error("unexpected type"); + + expect(obj.bumpTo).toBe(opts.bumpTo); + }); + + it("fails when bumpTo is not a string", () => { + expect(() => + // @ts-expect-error: intentionally passing non-string to test runtime validation + Operation.bumpSequence({ bumpTo: 1000 }), + ).toThrow(/bumpTo must be a string/); + }); + + it("fails when bumpTo is not a stringified number", () => { + expect(() => Operation.bumpSequence({ bumpTo: "not-a-number" })).toThrow( + /bumpTo must be a stringified number/, + ); + }); + + it("preserves an optional source account", () => { + const source = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ"; + const op = Operation.bumpSequence({ bumpTo: "100", source }); + const obj = Operation.fromXDRObject( + xdr.Operation.fromXDR(op.toXDR("hex"), "hex"), + ); + + if (obj.type !== "bumpSequence") throw new Error("unexpected type"); + expect(obj.source).toBe(source); + }); +}); diff --git a/test/unit/operations/change_trust.test.ts b/test/unit/operations/change_trust.test.ts new file mode 100644 index 00000000..fb7bbde5 --- /dev/null +++ b/test/unit/operations/change_trust.test.ts @@ -0,0 +1,119 @@ +import { describe, it, expect } from "vitest"; +import { Operation } from "../../../src/operation.js"; +import { Asset } from "../../../src/asset.js"; +import { LiquidityPoolAsset } from "../../../src/liquidity_pool_asset.js"; +import { LiquidityPoolFeeV18 } from "../../../src/get_liquidity_pool_id.js"; +import xdr from "../../../src/xdr.js"; + +const usd = new Asset( + "USD", + "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7", +); + +const lpAsset = new LiquidityPoolAsset( + new Asset("ARST", "GBBM6BKZPEHWYO3E3YKREDPQXMS4VK35YLNU7NFBRI26RAN7GI5POFBB"), + new Asset("USD", "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7"), + LiquidityPoolFeeV18, +); + +describe("Operation.changeTrust()", () => { + it("creates a changeTrustOp with Asset using default limit (MAX_INT64)", () => { + const op = Operation.changeTrust({ asset: usd }); + const xdrHex = op.toXDR("hex"); + const operation = xdr.Operation.fromXDR(xdrHex, "hex"); + const obj = Operation.fromXDRObject(operation); + + expect(obj.type).toBe("changeTrust"); + if (obj.type !== "changeTrust") throw new Error("unexpected type"); + + expect(obj.line).toEqual(usd); + expect( + (operation.body().value() as xdr.ChangeTrustOp).limit().toString(), + ).toBe("9223372036854775807"); + expect(obj.limit).toBe("922337203685.4775807"); + }); + + it("creates a changeTrustOp with Asset and explicit limit", () => { + const op = Operation.changeTrust({ asset: usd, limit: "50.0000000" }); + const xdrHex = op.toXDR("hex"); + const operation = xdr.Operation.fromXDR(xdrHex, "hex"); + const obj = Operation.fromXDRObject(operation); + + expect(obj.type).toBe("changeTrust"); + if (obj.type !== "changeTrust") throw new Error("unexpected type"); + + expect(obj.line).toEqual(usd); + expect( + (operation.body().value() as xdr.ChangeTrustOp).limit().toString(), + ).toBe("500000000"); + expect(obj.limit).toBe("50.0000000"); + }); + + it("creates a changeTrustOp with LiquidityPoolAsset using default limit (MAX_INT64)", () => { + const op = Operation.changeTrust({ asset: lpAsset }); + expect(op).toBeInstanceOf(xdr.Operation); + + const xdrOp = xdr.Operation.fromXDR(op.toXDR("hex"), "hex"); + const obj = Operation.fromXDRObject(xdrOp); + + expect(obj.type).toBe("changeTrust"); + if (obj.type !== "changeTrust") throw new Error("unexpected type"); + + expect(obj.line).toEqual(lpAsset); + expect( + (xdrOp.body().value() as xdr.ChangeTrustOp).limit().toString(), + ).toBe("9223372036854775807"); + expect(obj.limit).toBe("922337203685.4775807"); + }); + + it("deletes an Asset trustline by setting limit to 0", () => { + const op = Operation.changeTrust({ asset: usd, limit: "0.0000000" }); + const obj = Operation.fromXDRObject( + xdr.Operation.fromXDR(op.toXDR("hex"), "hex"), + ); + + expect(obj.type).toBe("changeTrust"); + if (obj.type !== "changeTrust") throw new Error("unexpected type"); + + expect(obj.line).toEqual(usd); + expect(obj.limit).toBe("0.0000000"); + }); + + it("deletes a LiquidityPoolAsset trustline by setting limit to 0", () => { + const op = Operation.changeTrust({ asset: lpAsset, limit: "0.0000000" }); + const obj = Operation.fromXDRObject( + xdr.Operation.fromXDR(op.toXDR("hex"), "hex"), + ); + + expect(obj.type).toBe("changeTrust"); + if (obj.type !== "changeTrust") throw new Error("unexpected type"); + + expect(obj.line).toEqual(lpAsset); + expect(obj.limit).toBe("0.0000000"); + }); + + it("throws TypeError for a non-string limit", () => { + expect(() => + // @ts-expect-error: intentionally passing non-string limit to test runtime validation + Operation.changeTrust({ asset: usd, limit: 0 }), + ).toThrow(TypeError); + }); + + it("throws TypeError for an invalid asset type", () => { + expect(() => + // @ts-expect-error: intentionally passing invalid asset to test runtime validation + Operation.changeTrust({ asset: "not-an-asset" }), + ).toThrow(TypeError); + }); + + it("preserves an optional source account", () => { + const source = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ"; + const op = Operation.changeTrust({ asset: usd, source }); + const obj = Operation.fromXDRObject( + xdr.Operation.fromXDR(op.toXDR("hex"), "hex"), + ); + + if (obj.type !== "changeTrust") throw new Error("unexpected type"); + expect(obj.source).toBe(source); + }); +}); diff --git a/test/unit/operations/claim_claimable_balance.test.ts b/test/unit/operations/claim_claimable_balance.test.ts new file mode 100644 index 00000000..342e2418 --- /dev/null +++ b/test/unit/operations/claim_claimable_balance.test.ts @@ -0,0 +1,46 @@ +import { describe, it, expect } from "vitest"; +import { Operation } from "../../../src/operation.js"; +import xdr from "../../../src/xdr.js"; + +const balanceId = + "00000000da0d57da7d4850e7fc10d2a9d0ebc731f7afb40574c03395b17d49149b91f5be"; + +describe("Operation.claimClaimableBalance()", () => { + it("creates a claimClaimableBalanceOp", () => { + const op = Operation.claimClaimableBalance({ balanceId }); + const xdrHex = op.toXDR("hex"); + const operation = xdr.Operation.fromXDR(xdrHex, "hex"); + const obj = Operation.fromXDRObject(operation); + + expect(obj.type).toBe("claimClaimableBalance"); + if (obj.type !== "claimClaimableBalance") + throw new Error("unexpected type"); + + expect(obj.balanceId).toBe(balanceId); + }); + + it("throws when balanceId is not present", () => { + expect(() => + // @ts-expect-error: intentionally omitting required field to test runtime validation + Operation.claimClaimableBalance({}), + ).toThrow(/must provide a valid claimable balance id/); + }); + + it("throws for an invalid balanceId", () => { + expect(() => + Operation.claimClaimableBalance({ balanceId: "badc0ffee" }), + ).toThrow(/must provide a valid claimable balance id/); + }); + + it("preserves an optional source account", () => { + const source = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ"; + const op = Operation.claimClaimableBalance({ balanceId, source }); + const obj = Operation.fromXDRObject( + xdr.Operation.fromXDR(op.toXDR("hex"), "hex"), + ); + + if (obj.type !== "claimClaimableBalance") + throw new Error("unexpected type"); + expect(obj.source).toBe(source); + }); +}); diff --git a/test/unit/operations/classic_ops_test.js b/test/unit/operations/classic_ops_test.js deleted file mode 100644 index e53c1dbb..00000000 --- a/test/unit/operations/classic_ops_test.js +++ /dev/null @@ -1,1678 +0,0 @@ -import BigNumber from "bignumber.js"; - -const { encodeMuxedAccountToAddress, encodeMuxedAccount } = StellarBase; - -describe("Operation", function () { - describe(".pathPaymentStrictSend()", function () { - it("creates a pathPaymentStrictSendOp", function () { - var sendAsset = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - var sendAmount = "3.0070000"; - var destination = - "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ"; - var destAsset = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - var destMin = "3.1415000"; - var path = [ - new StellarBase.Asset( - "USD", - "GBBM6BKZPEHWYO3E3YKREDPQXMS4VK35YLNU7NFBRI26RAN7GI5POFBB" - ), - new StellarBase.Asset( - "EUR", - "GDTNXRLOJD2YEBPKK7KCMR7J33AAG5VZXHAJTHIG736D6LVEFLLLKPDL" - ) - ]; - let op = StellarBase.Operation.pathPaymentStrictSend({ - sendAsset, - sendAmount, - destination, - destAsset, - destMin, - path - }); - var xdr = op.toXDR("hex"); - var operation = StellarBase.xdr.Operation.fromXDR( - Buffer.from(xdr, "hex") - ); - var obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("pathPaymentStrictSend"); - expect(obj.sendAsset.equals(sendAsset)).to.be.true; - expect(operation.body().value().sendAmount().toString()).to.be.equal( - "30070000" - ); - expect(obj.sendAmount).to.be.equal(sendAmount); - expect(obj.destination).to.be.equal(destination); - expect(obj.destAsset.equals(destAsset)).to.be.true; - expect(operation.body().value().destMin().toString()).to.be.equal( - "31415000" - ); - expect(obj.destMin).to.be.equal(destMin); - expect(obj.path[0].getCode()).to.be.equal("USD"); - expect(obj.path[0].getIssuer()).to.be.equal( - "GBBM6BKZPEHWYO3E3YKREDPQXMS4VK35YLNU7NFBRI26RAN7GI5POFBB" - ); - expect(obj.path[1].getCode()).to.be.equal("EUR"); - expect(obj.path[1].getIssuer()).to.be.equal( - "GDTNXRLOJD2YEBPKK7KCMR7J33AAG5VZXHAJTHIG736D6LVEFLLLKPDL" - ); - }); - - const base = "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ"; - const source = encodeMuxedAccountToAddress(encodeMuxedAccount(base, "1")); - const destination = encodeMuxedAccountToAddress( - encodeMuxedAccount(base, "2") - ); - - let opts = { source, destination }; - opts.sendAsset = opts.destAsset = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.destMin = "3.1415000"; - opts.sendAmount = "3.0070000"; - opts.path = [ - new StellarBase.Asset( - "USD", - "GBBM6BKZPEHWYO3E3YKREDPQXMS4VK35YLNU7NFBRI26RAN7GI5POFBB" - ) - ]; - - it("supports muxed accounts", function () { - const packed = StellarBase.Operation.pathPaymentStrictSend(opts); - - // Ensure we can convert to and from the raw XDR: - expect(() => { - StellarBase.xdr.Operation.fromXDR(packed.toXDR("raw"), "raw"); - StellarBase.xdr.Operation.fromXDR(packed.toXDR("hex"), "hex"); - }).to.not.throw(); - - const unpacked = StellarBase.Operation.fromXDRObject(packed); - expect(unpacked.type).to.equal("pathPaymentStrictSend"); - expect(unpacked.source).to.equal(opts.source); - expect(unpacked.destination).to.equal(opts.destination); - }); - - it("fails to create path payment operation with an invalid destination address", function () { - let opts = { - destination: "GCEZW", - sendAmount: "20", - destMin: "50", - sendAsset: StellarBase.Asset.native(), - destAsset: new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ) - }; - expect(() => StellarBase.Operation.pathPaymentStrictSend(opts)).to.throw( - /destination is invalid/ - ); - }); - - it("fails to create path payment operation with an invalid sendAmount", function () { - let opts = { - destination: "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ", - sendAmount: 20, - destMin: "50", - sendAsset: StellarBase.Asset.native(), - destAsset: new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ) - }; - expect(() => StellarBase.Operation.pathPaymentStrictSend(opts)).to.throw( - /sendAmount argument must be of type String/ - ); - }); - - it("fails to create path payment operation with an invalid destMin", function () { - let opts = { - destination: "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ", - sendAmount: "20", - destMin: 50, - sendAsset: StellarBase.Asset.native(), - destAsset: new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ) - }; - expect(() => StellarBase.Operation.pathPaymentStrictSend(opts)).to.throw( - /destMin argument must be of type String/ - ); - }); - }); - - describe(".changeTrust()", function () { - it("creates a changeTrustOp with Asset", function () { - let asset = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - let op = StellarBase.Operation.changeTrust({ asset }); - var xdr = op.toXDR("hex"); - var operation = StellarBase.xdr.Operation.fromXDR( - Buffer.from(xdr, "hex") - ); - var obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("changeTrust"); - expect(obj.line).to.be.deep.equal(asset); - expect(operation.body().value().limit().toString()).to.be.equal( - "9223372036854775807" - ); // MAX_INT64 - expect(obj.limit).to.be.equal("922337203685.4775807"); - }); - - it("creates a changeTrustOp with Asset and limit", function () { - let asset = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - let op = StellarBase.Operation.changeTrust({ - asset, - limit: "50.0000000" - }); - var xdr = op.toXDR("hex"); - var operation = StellarBase.xdr.Operation.fromXDR( - Buffer.from(xdr, "hex") - ); - var obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("changeTrust"); - expect(obj.line).to.be.deep.equal(asset); - expect(operation.body().value().limit().toString()).to.be.equal( - "500000000" - ); - expect(obj.limit).to.be.equal("50.0000000"); - }); - - it("creates a changeTrustOp to a liquidity pool", function () { - const assetA = new StellarBase.Asset( - "ARST", - "GBBM6BKZPEHWYO3E3YKREDPQXMS4VK35YLNU7NFBRI26RAN7GI5POFBB" - ); - const assetB = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - const fee = StellarBase.LiquidityPoolFeeV18; - const asset = new StellarBase.LiquidityPoolAsset(assetA, assetB, fee); - const op = StellarBase.Operation.changeTrust({ asset }); - expect(op).to.be.instanceof(StellarBase.xdr.Operation); - - const opXdr = op.toXDR("hex"); - const opXdrObj = StellarBase.xdr.Operation.fromXDR(opXdr, "hex"); - const operation = StellarBase.Operation.fromXDRObject(opXdrObj); - - expect(operation.type).to.be.equal("changeTrust"); - expect(operation.line).to.be.deep.equal(asset); - expect(opXdrObj.body().value().limit().toString()).to.be.equal( - "9223372036854775807" - ); // MAX_INT64 - expect(operation.limit).to.be.equal("922337203685.4775807"); - }); - - it("deletes an Asset trustline", function () { - let asset = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - let op = StellarBase.Operation.changeTrust({ - asset: asset, - limit: "0.0000000" - }); - var xdr = op.toXDR("hex"); - var operation = StellarBase.xdr.Operation.fromXDR( - Buffer.from(xdr, "hex") - ); - var obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("changeTrust"); - expect(obj.line).to.be.deep.equal(asset); - expect(obj.limit).to.be.equal("0.0000000"); - }); - - it("deletes a LiquidityPoolAsset trustline", function () { - const assetA = new StellarBase.Asset( - "ARST", - "GBBM6BKZPEHWYO3E3YKREDPQXMS4VK35YLNU7NFBRI26RAN7GI5POFBB" - ); - const assetB = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - const fee = StellarBase.LiquidityPoolFeeV18; - const asset = new StellarBase.LiquidityPoolAsset(assetA, assetB, fee); - let op = StellarBase.Operation.changeTrust({ - asset, - limit: "0.0000000" - }); - var xdr = op.toXDR("hex"); - var operation = StellarBase.xdr.Operation.fromXDR( - Buffer.from(xdr, "hex") - ); - var obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("changeTrust"); - expect(obj.line).to.be.deep.equal(asset); - expect(obj.limit).to.be.equal("0.0000000"); - }); - - it("throws TypeError for incorrect limit argument", function () { - let asset = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - let changeTrust = () => - StellarBase.Operation.changeTrust({ asset: asset, limit: 0 }); - expect(changeTrust).to.throw(TypeError); - }); - }); - - describe(".manageSellOffer", function () { - it("creates a manageSellOfferOp (string price)", function () { - var opts = {}; - opts.selling = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.buying = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.amount = "3.1234560"; - opts.price = "8.141592"; - opts.offerId = "1"; - let op = StellarBase.Operation.manageSellOffer(opts); - var xdr = op.toXDR("hex"); - var operation = StellarBase.xdr.Operation.fromXDR( - Buffer.from(xdr, "hex") - ); - var obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("manageSellOffer"); - expect(obj.selling.equals(opts.selling)).to.be.true; - expect(obj.buying.equals(opts.buying)).to.be.true; - expect(operation.body().value().amount().toString()).to.be.equal( - "31234560" - ); - expect(obj.amount).to.be.equal(opts.amount); - expect(obj.price).to.be.equal(opts.price); - expect(obj.offerId).to.be.equal(opts.offerId); - }); - - it("creates a manageSellOfferOp (price fraction)", function () { - var opts = {}; - opts.selling = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.buying = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.amount = "3.123456"; - opts.price = { - n: 11, - d: 10 - }; - opts.offerId = "1"; - let op = StellarBase.Operation.manageSellOffer(opts); - var xdr = op.toXDR("hex"); - var operation = StellarBase.xdr.Operation.fromXDR( - Buffer.from(xdr, "hex") - ); - var obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.price).to.be.equal( - new BigNumber(opts.price.n).div(opts.price.d).toString() - ); - }); - - it("creates an invalid manageSellOfferOp (price fraction)", function () { - var opts = {}; - opts.selling = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.buying = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.amount = "3.123456"; - opts.price = { - n: 11, - d: -1 - }; - opts.offerId = "1"; - expect(() => StellarBase.Operation.manageSellOffer(opts)).to.throw( - /price must be positive/ - ); - }); - - it("creates a manageSellOfferOp (number price)", function () { - var opts = {}; - opts.selling = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.buying = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.amount = "3.123456"; - opts.price = 3.07; - opts.offerId = "1"; - let op = StellarBase.Operation.manageSellOffer(opts); - var xdr = op.toXDR("hex"); - var operation = StellarBase.xdr.Operation.fromXDR( - Buffer.from(xdr, "hex") - ); - var obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("manageSellOffer"); - expect(obj.price).to.be.equal(opts.price.toString()); - }); - - it("creates a manageSellOfferOp (BigNumber price)", function () { - var opts = {}; - opts.selling = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.buying = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.amount = "3.123456"; - opts.price = new BigNumber(5).dividedBy(4); - opts.offerId = "1"; - let op = StellarBase.Operation.manageSellOffer(opts); - var xdr = op.toXDR("hex"); - var operation = StellarBase.xdr.Operation.fromXDR( - Buffer.from(xdr, "hex") - ); - var obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("manageSellOffer"); - expect(obj.price).to.be.equal("1.25"); - }); - - it("creates a manageSellOfferOp with no offerId", function () { - var opts = {}; - opts.selling = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.buying = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.amount = "1000.0000000"; - opts.price = "3.141592"; - let op = StellarBase.Operation.manageSellOffer(opts); - var xdr = op.toXDR("hex"); - var operation = StellarBase.xdr.Operation.fromXDR( - Buffer.from(xdr, "hex") - ); - var obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("manageSellOffer"); - expect(obj.selling.equals(opts.selling)).to.be.true; - expect(obj.buying.equals(opts.buying)).to.be.true; - expect(operation.body().value().amount().toString()).to.be.equal( - "10000000000" - ); - expect(obj.amount).to.be.equal(opts.amount); - expect(obj.price).to.be.equal(opts.price); - expect(obj.offerId).to.be.equal("0"); // 0=create a new offer, otherwise edit an existing offer - }); - - it("cancels offer", function () { - var opts = {}; - opts.selling = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.buying = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.amount = "0.0000000"; - opts.price = "3.141592"; - opts.offerId = "1"; - let op = StellarBase.Operation.manageSellOffer(opts); - var xdr = op.toXDR("hex"); - var operation = StellarBase.xdr.Operation.fromXDR( - Buffer.from(xdr, "hex") - ); - var obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("manageSellOffer"); - expect(obj.selling.equals(opts.selling)).to.be.true; - expect(obj.buying.equals(opts.buying)).to.be.true; - expect(operation.body().value().amount().toString()).to.be.equal("0"); - expect(obj.amount).to.be.equal(opts.amount); - expect(obj.price).to.be.equal(opts.price); - expect(obj.offerId).to.be.equal("1"); // 0=create a new offer, otherwise edit an existing offer - }); - - it("fails to create manageSellOffer operation with an invalid amount", function () { - let opts = { - amount: 20, - price: "10", - selling: new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ), - buying: new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ) - }; - expect(() => StellarBase.Operation.manageSellOffer(opts)).to.throw( - /amount argument must be of type String/ - ); - }); - - it("fails to create manageSellOffer operation with missing price", function () { - let opts = { - amount: "20", - selling: new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ), - buying: new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ) - }; - expect(() => StellarBase.Operation.manageSellOffer(opts)).to.throw( - /price argument is required/ - ); - }); - - it("fails to create manageSellOffer operation with negative price", function () { - let opts = { - amount: "20", - price: "-1", - selling: new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ), - buying: new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ) - }; - expect(() => StellarBase.Operation.manageSellOffer(opts)).to.throw( - /price must be positive/ - ); - }); - - it("fails to create manageSellOffer operation with invalid price", function () { - let opts = { - amount: "20", - price: "test", - selling: new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ), - buying: new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ) - }; - expect(() => StellarBase.Operation.manageSellOffer(opts)).to.throw( - /not a number/i - ); - }); - }); - - describe(".manageBuyOffer", function () { - it("creates a manageBuyOfferOp (string price)", function () { - var opts = {}; - opts.selling = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.buying = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.buyAmount = "3.1234560"; - opts.price = "8.141592"; - opts.offerId = "1"; - let op = StellarBase.Operation.manageBuyOffer(opts); - var xdr = op.toXDR("hex"); - var operation = StellarBase.xdr.Operation.fromXDR( - Buffer.from(xdr, "hex") - ); - var obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("manageBuyOffer"); - expect(obj.selling.equals(opts.selling)).to.be.true; - expect(obj.buying.equals(opts.buying)).to.be.true; - expect(operation.body().value().buyAmount().toString()).to.be.equal( - "31234560" - ); - expect(obj.buyAmount).to.be.equal(opts.buyAmount); - expect(obj.price).to.be.equal(opts.price); - expect(obj.offerId).to.be.equal(opts.offerId); - }); - - it("creates a manageBuyOfferOp (price fraction)", function () { - var opts = {}; - opts.selling = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.buying = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.buyAmount = "3.123456"; - opts.price = { - n: 11, - d: 10 - }; - opts.offerId = "1"; - let op = StellarBase.Operation.manageBuyOffer(opts); - var xdr = op.toXDR("hex"); - var operation = StellarBase.xdr.Operation.fromXDR( - Buffer.from(xdr, "hex") - ); - var obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.price).to.be.equal( - new BigNumber(opts.price.n).div(opts.price.d).toString() - ); - }); - - it("creates an invalid manageBuyOfferOp (price fraction)", function () { - var opts = {}; - opts.selling = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.buying = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.buyAmount = "3.123456"; - opts.price = { - n: 11, - d: -1 - }; - opts.offerId = "1"; - expect(() => StellarBase.Operation.manageBuyOffer(opts)).to.throw( - /price must be positive/ - ); - }); - - it("creates a manageBuyOfferOp (number price)", function () { - var opts = {}; - opts.selling = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.buying = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.buyAmount = "3.123456"; - opts.price = 3.07; - opts.offerId = "1"; - let op = StellarBase.Operation.manageBuyOffer(opts); - var xdr = op.toXDR("hex"); - var operation = StellarBase.xdr.Operation.fromXDR( - Buffer.from(xdr, "hex") - ); - var obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("manageBuyOffer"); - expect(obj.price).to.be.equal(opts.price.toString()); - }); - - it("creates a manageBuyOfferOp (BigNumber price)", function () { - var opts = {}; - opts.selling = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.buying = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.buyAmount = "3.123456"; - opts.price = new BigNumber(5).dividedBy(4); - opts.offerId = "1"; - let op = StellarBase.Operation.manageBuyOffer(opts); - var xdr = op.toXDR("hex"); - var operation = StellarBase.xdr.Operation.fromXDR( - Buffer.from(xdr, "hex") - ); - var obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("manageBuyOffer"); - expect(obj.price).to.be.equal("1.25"); - }); - - it("creates a manageBuyOfferOp with no offerId", function () { - var opts = {}; - opts.selling = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.buying = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.buyAmount = "1000.0000000"; - opts.price = "3.141592"; - let op = StellarBase.Operation.manageBuyOffer(opts); - var xdr = op.toXDR("hex"); - var operation = StellarBase.xdr.Operation.fromXDR( - Buffer.from(xdr, "hex") - ); - var obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("manageBuyOffer"); - expect(obj.selling.equals(opts.selling)).to.be.true; - expect(obj.buying.equals(opts.buying)).to.be.true; - expect(operation.body().value().buyAmount().toString()).to.be.equal( - "10000000000" - ); - expect(obj.buyAmount).to.be.equal(opts.buyAmount); - expect(obj.price).to.be.equal(opts.price); - expect(obj.offerId).to.be.equal("0"); // 0=create a new offer, otherwise edit an existing offer - }); - - it("cancels offer", function () { - var opts = {}; - opts.selling = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.buying = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.buyAmount = "0.0000000"; - opts.price = "3.141592"; - opts.offerId = "1"; - let op = StellarBase.Operation.manageBuyOffer(opts); - var xdr = op.toXDR("hex"); - var operation = StellarBase.xdr.Operation.fromXDR( - Buffer.from(xdr, "hex") - ); - var obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("manageBuyOffer"); - expect(obj.selling.equals(opts.selling)).to.be.true; - expect(obj.buying.equals(opts.buying)).to.be.true; - expect(operation.body().value().buyAmount().toString()).to.be.equal("0"); - expect(obj.buyAmount).to.be.equal(opts.buyAmount); - expect(obj.price).to.be.equal(opts.price); - expect(obj.offerId).to.be.equal("1"); // 0=create a new offer, otherwise edit an existing offer - }); - - it("fails to create manageBuyOffer operation with an invalid amount", function () { - let opts = { - buyAmount: 20, - price: "10", - selling: new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ), - buying: new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ) - }; - expect(() => StellarBase.Operation.manageBuyOffer(opts)).to.throw( - /buyAmount argument must be of type String/ - ); - }); - - it("fails to create manageBuyOffer operation with missing price", function () { - let opts = { - buyAmount: "20", - selling: new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ), - buying: new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ) - }; - expect(() => StellarBase.Operation.manageBuyOffer(opts)).to.throw( - /price argument is required/ - ); - }); - - it("fails to create manageBuyOffer operation with negative price", function () { - let opts = { - buyAmount: "20", - price: "-1", - selling: new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ), - buying: new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ) - }; - expect(() => StellarBase.Operation.manageBuyOffer(opts)).to.throw( - /price must be positive/ - ); - }); - - it("fails to create manageBuyOffer operation with invalid price", function () { - let opts = { - buyAmount: "20", - price: "test", - selling: new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ), - buying: new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ) - }; - expect(() => StellarBase.Operation.manageBuyOffer(opts)).to.throw( - /not a number/i - ); - }); - }); - - describe(".createPassiveSellOffer", function () { - it("creates a createPassiveSellOfferOp (string price)", function () { - var opts = {}; - opts.selling = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.buying = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.amount = "11.2782700"; - opts.price = "3.07"; - let op = StellarBase.Operation.createPassiveSellOffer(opts); - var xdr = op.toXDR("hex"); - var operation = StellarBase.xdr.Operation.fromXDR( - Buffer.from(xdr, "hex") - ); - var obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("createPassiveSellOffer"); - expect(obj.selling.equals(opts.selling)).to.be.true; - expect(obj.buying.equals(opts.buying)).to.be.true; - expect(operation.body().value().amount().toString()).to.be.equal( - "112782700" - ); - expect(obj.amount).to.be.equal(opts.amount); - expect(obj.price).to.be.equal(opts.price); - }); - - it("creates a createPassiveSellOfferOp (number price)", function () { - var opts = {}; - opts.selling = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.buying = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.amount = "11.2782700"; - opts.price = 3.07; - let op = StellarBase.Operation.createPassiveSellOffer(opts); - var xdr = op.toXDR("hex"); - var operation = StellarBase.xdr.Operation.fromXDR( - Buffer.from(xdr, "hex") - ); - var obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("createPassiveSellOffer"); - expect(obj.selling.equals(opts.selling)).to.be.true; - expect(obj.buying.equals(opts.buying)).to.be.true; - expect(operation.body().value().amount().toString()).to.be.equal( - "112782700" - ); - expect(obj.amount).to.be.equal(opts.amount); - expect(obj.price).to.be.equal(opts.price.toString()); - }); - - it("creates a createPassiveSellOfferOp (BigNumber price)", function () { - var opts = {}; - opts.selling = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.buying = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - opts.amount = "11.2782700"; - opts.price = new BigNumber(5).dividedBy(4); - let op = StellarBase.Operation.createPassiveSellOffer(opts); - var xdr = op.toXDR("hex"); - var operation = StellarBase.xdr.Operation.fromXDR( - Buffer.from(xdr, "hex") - ); - var obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("createPassiveSellOffer"); - expect(obj.selling.equals(opts.selling)).to.be.true; - expect(obj.buying.equals(opts.buying)).to.be.true; - expect(operation.body().value().amount().toString()).to.be.equal( - "112782700" - ); - expect(obj.amount).to.be.equal(opts.amount); - expect(obj.price).to.be.equal("1.25"); - }); - - it("fails to create createPassiveSellOffer operation with an invalid amount", function () { - let opts = { - amount: 20, - price: "10", - selling: new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ), - buying: new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ) - }; - expect(() => StellarBase.Operation.createPassiveSellOffer(opts)).to.throw( - /amount argument must be of type String/ - ); - }); - - it("fails to create createPassiveSellOffer operation with missing price", function () { - let opts = { - amount: "20", - selling: new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ), - buying: new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ) - }; - expect(() => StellarBase.Operation.createPassiveSellOffer(opts)).to.throw( - /price argument is required/ - ); - }); - - it("fails to create createPassiveSellOffer operation with negative price", function () { - let opts = { - amount: "20", - price: "-2", - selling: new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ), - buying: new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ) - }; - expect(() => StellarBase.Operation.createPassiveSellOffer(opts)).to.throw( - /price must be positive/ - ); - }); - }); - - describe(".bumpSequence", function () { - it("creates a bumpSequence", function () { - var opts = { - bumpTo: "77833036561510299" - }; - let op = StellarBase.Operation.bumpSequence(opts); - var xdr = op.toXDR("hex"); - var operation = StellarBase.xdr.Operation.fromXDR( - Buffer.from(xdr, "hex") - ); - var obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("bumpSequence"); - expect(obj.bumpTo).to.be.equal(opts.bumpTo); - }); - - it("fails when `bumpTo` is not string", function () { - expect(() => - StellarBase.Operation.bumpSequence({ bumpTo: 1000 }) - ).to.throw(); - }); - }); - - describe("._checkUnsignedIntValue()", function () { - it("returns true for valid values", function () { - let values = [ - { value: 0, expected: 0 }, - { value: 10, expected: 10 }, - { value: "0", expected: 0 }, - { value: "10", expected: 10 }, - { value: undefined, expected: undefined } - ]; - - for (var i in values) { - let { value, expected } = values[i]; - expect( - StellarBase.Operation._checkUnsignedIntValue(value, value) - ).to.be.equal(expected); - } - }); - - it("throws error for invalid values", function () { - let values = [ - {}, - [], - "", // empty string - "test", // string not representing a number - "0.5", - "-10", - "-10.5", - "Infinity", - Infinity, - "Nan", - NaN - ]; - - for (var i in values) { - let value = values[i]; - expect(() => - StellarBase.Operation._checkUnsignedIntValue(value, value) - ).to.throw(); - } - }); - - it("return correct values when isValidFunction is set", function () { - expect( - StellarBase.Operation._checkUnsignedIntValue( - "test", - undefined, - (value) => value < 10 - ) - ).to.equal(undefined); - - expect( - StellarBase.Operation._checkUnsignedIntValue( - "test", - 8, - (value) => value < 10 - ) - ).to.equal(8); - expect( - StellarBase.Operation._checkUnsignedIntValue( - "test", - "8", - (value) => value < 10 - ) - ).to.equal(8); - - expect(() => { - StellarBase.Operation._checkUnsignedIntValue( - "test", - 12, - (value) => value < 10 - ); - }).to.throw(); - expect(() => { - StellarBase.Operation._checkUnsignedIntValue( - "test", - "12", - (value) => value < 10 - ); - }).to.throw(); - }); - }); - - describe("createClaimableBalance()", function () { - it("creates a CreateClaimableBalanceOp", function () { - const asset = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - const amount = "100.0000000"; - const claimants = [ - new StellarBase.Claimant( - "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ" - ) - ]; - - const op = StellarBase.Operation.createClaimableBalance({ - asset, - amount, - claimants - }); - var xdr = op.toXDR("hex"); - var operation = StellarBase.xdr.Operation.fromXDR( - Buffer.from(xdr, "hex") - ); - var obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("createClaimableBalance"); - expect(obj.asset.toString()).to.equal(asset.toString()); - expect(obj.amount).to.be.equal(amount); - expect(obj.claimants).to.have.lengthOf(1); - expect(obj.claimants[0].toXDRObject().toXDR("hex")).to.equal( - claimants[0].toXDRObject().toXDR("hex") - ); - }); - it("throws an error when asset is not present", function () { - const amount = "100.0000000"; - const claimants = [ - new StellarBase.Claimant( - "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ" - ) - ]; - - const attrs = { - amount, - claimants - }; - - expect(() => - StellarBase.Operation.createClaimableBalance(attrs) - ).to.throw( - /must provide an asset for create claimable balance operation/ - ); - }); - it("throws an error when amount is not present", function () { - const asset = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - const claimants = [ - new StellarBase.Claimant( - "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ" - ) - ]; - - const attrs = { - asset, - claimants - }; - - expect(() => - StellarBase.Operation.createClaimableBalance(attrs) - ).to.throw( - /amount argument must be of type String, represent a positive number and have at most 7 digits after the decimal/ - ); - }); - it("throws an error when claimants is empty or not present", function () { - const asset = new StellarBase.Asset( - "USD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - const amount = "100.0000"; - - const attrs = { - asset, - amount - }; - - expect(() => - StellarBase.Operation.createClaimableBalance(attrs) - ).to.throw(/must provide at least one claimant/); - - attrs.claimants = []; - expect(() => - StellarBase.Operation.createClaimableBalance(attrs) - ).to.throw(/must provide at least one claimant/); - }); - }); - - describe("claimClaimableBalance()", function () { - it("creates a claimClaimableBalanceOp", function () { - const balanceId = - "00000000da0d57da7d4850e7fc10d2a9d0ebc731f7afb40574c03395b17d49149b91f5be"; - - const op = StellarBase.Operation.claimClaimableBalance({ balanceId }); - var xdr = op.toXDR("hex"); - var operation = StellarBase.xdr.Operation.fromXDR( - Buffer.from(xdr, "hex") - ); - var obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("claimClaimableBalance"); - expect(obj.balanceId).to.equal(balanceId); - }); - it("throws an error when balanceId is not present", function () { - expect(() => StellarBase.Operation.claimClaimableBalance({})).to.throw( - /must provide a valid claimable balance id/ - ); - }); - it("throws an error for invalid balanceIds", function () { - expect(() => - StellarBase.Operation.claimClaimableBalance({ - balanceId: "badc0ffee" - }) - ).to.throw(/must provide a valid claimable balance id/); - }); - }); - - describe("clawbackClaimableBalance()", function () { - it("creates a clawbackClaimableBalanceOp", function () { - const balanceId = - "00000000da0d57da7d4850e7fc10d2a9d0ebc731f7afb40574c03395b17d49149b91f5be"; - - const op = StellarBase.Operation.clawbackClaimableBalance({ - balanceId: balanceId - }); - var xdr = op.toXDR("hex"); - var operation = StellarBase.xdr.Operation.fromXDR( - Buffer.from(xdr, "hex") - ); - var obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("clawbackClaimableBalance"); - expect(obj.balanceId).to.equal(balanceId); - }); - it("throws an error when balanceId is not present", function () { - expect(() => StellarBase.Operation.clawbackClaimableBalance({})).to.throw( - /must provide a valid claimable balance id/ - ); - }); - it("throws an error for invalid balanceIds", function () { - expect(() => - StellarBase.Operation.clawbackClaimableBalance({ - balanceId: "badc0ffee" - }) - ).to.throw(/must provide a valid claimable balance id/); - }); - }); - - describe("revokeAccountSponsorship()", function () { - it("creates a revokeAccountSponsorshipOp", function () { - const account = - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7"; - const op = StellarBase.Operation.revokeAccountSponsorship({ - account - }); - var xdr = op.toXDR("hex"); - - var operation = StellarBase.xdr.Operation.fromXDR(xdr, "hex"); - expect(operation.body().switch().name).to.equal("revokeSponsorship"); - var obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("revokeAccountSponsorship"); - expect(obj.account).to.be.equal(account); - }); - it("throws an error when account is invalid", function () { - expect(() => StellarBase.Operation.revokeAccountSponsorship({})).to.throw( - /account is invalid/ - ); - expect(() => - StellarBase.Operation.revokeAccountSponsorship({ - account: "GBAD" - }) - ).to.throw(/account is invalid/); - }); - }); - - describe("revokeTrustlineSponsorship()", function () { - it("creates a revokeTrustlineSponsorship", function () { - const account = - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7"; - var asset = new StellarBase.Asset( - "USDUSD", - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - ); - const op = StellarBase.Operation.revokeTrustlineSponsorship({ - account, - asset - }); - var xdr = op.toXDR("hex"); - - var operation = StellarBase.xdr.Operation.fromXDR(xdr, "hex"); - expect(operation.body().switch().name).to.equal("revokeSponsorship"); - var obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("revokeTrustlineSponsorship"); - }); - it("creates a revokeTrustlineSponsorship for a liquidity pool", function () { - const account = - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7"; - const asset = new StellarBase.LiquidityPoolId( - "dd7b1ab831c273310ddbec6f97870aa83c2fbd78ce22aded37ecbf4f3380fac7" - ); - const op = StellarBase.Operation.revokeTrustlineSponsorship({ - account, - asset - }); - const xdr = op.toXDR("hex"); - - const operation = StellarBase.xdr.Operation.fromXDR(xdr, "hex"); - expect(operation.body().switch().name).to.equal("revokeSponsorship"); - const obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("revokeTrustlineSponsorship"); - }); - it("throws an error when account is invalid", function () { - expect(() => - StellarBase.Operation.revokeTrustlineSponsorship({}) - ).to.throw(/account is invalid/); - expect(() => - StellarBase.Operation.revokeTrustlineSponsorship({ - account: "GBAD" - }) - ).to.throw(/account is invalid/); - }); - it("throws an error when asset is invalid", function () { - expect(() => - StellarBase.Operation.revokeTrustlineSponsorship({ - account: "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - }) - ).to.throw(/asset must be an Asset or LiquidityPoolId/); - }); - }); - - describe("revokeOfferSponsorship()", function () { - it("creates a revokeOfferSponsorship", function () { - const seller = "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7"; - var offerId = "1234"; - const op = StellarBase.Operation.revokeOfferSponsorship({ - seller, - offerId - }); - var xdr = op.toXDR("hex"); - - var operation = StellarBase.xdr.Operation.fromXDR(xdr, "hex"); - expect(operation.body().switch().name).to.equal("revokeSponsorship"); - var obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("revokeOfferSponsorship"); - expect(obj.seller).to.be.equal(seller); - expect(obj.offerId).to.be.equal(offerId); - }); - it("throws an error when seller is invalid", function () { - expect(() => StellarBase.Operation.revokeOfferSponsorship({})).to.throw( - /seller is invalid/ - ); - expect(() => - StellarBase.Operation.revokeOfferSponsorship({ - seller: "GBAD" - }) - ).to.throw(/seller is invalid/); - }); - it("throws an error when asset offerId is not included", function () { - expect(() => - StellarBase.Operation.revokeOfferSponsorship({ - seller: "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - }) - ).to.throw(/offerId is invalid/); - }); - }); - - describe("revokeDataSponsorship()", function () { - it("creates a revokeDataSponsorship", function () { - const account = - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7"; - var name = "foo"; - const op = StellarBase.Operation.revokeDataSponsorship({ - account, - name - }); - var xdr = op.toXDR("hex"); - - var operation = StellarBase.xdr.Operation.fromXDR(xdr, "hex"); - expect(operation.body().switch().name).to.equal("revokeSponsorship"); - var obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("revokeDataSponsorship"); - expect(obj.account).to.be.equal(account); - expect(obj.name).to.be.equal(name); - }); - it("throws an error when account is invalid", function () { - expect(() => StellarBase.Operation.revokeDataSponsorship({})).to.throw( - /account is invalid/ - ); - expect(() => - StellarBase.Operation.revokeDataSponsorship({ - account: "GBAD" - }) - ).to.throw(/account is invalid/); - }); - it("throws an error when data name is not included", function () { - expect(() => - StellarBase.Operation.revokeDataSponsorship({ - account: "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - }) - ).to.throw(/name must be a string, up to 64 characters/); - }); - }); - - describe("revokeClaimableBalanceSponsorship()", function () { - it("creates a revokeClaimableBalanceSponsorship", function () { - const balanceId = - "00000000da0d57da7d4850e7fc10d2a9d0ebc731f7afb40574c03395b17d49149b91f5be"; - const op = StellarBase.Operation.revokeClaimableBalanceSponsorship({ - balanceId - }); - var xdr = op.toXDR("hex"); - - var operation = StellarBase.xdr.Operation.fromXDR(xdr, "hex"); - expect(operation.body().switch().name).to.equal("revokeSponsorship"); - var obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("revokeClaimableBalanceSponsorship"); - expect(obj.balanceId).to.be.equal(balanceId); - }); - it("throws an error when balanceId is invalid", function () { - expect(() => - StellarBase.Operation.revokeClaimableBalanceSponsorship({}) - ).to.throw(/balanceId is invalid/); - }); - }); - - describe("revokeLiquidityPoolSponsorship()", function () { - it("creates a revokeLiquidityPoolSponsorship", function () { - const liquidityPoolId = - "dd7b1ab831c273310ddbec6f97870aa83c2fbd78ce22aded37ecbf4f3380fac7"; - const op = StellarBase.Operation.revokeLiquidityPoolSponsorship({ - liquidityPoolId - }); - const xdr = op.toXDR("hex"); - - const operation = StellarBase.xdr.Operation.fromXDR(xdr, "hex"); - expect(operation.body().switch().name).to.equal("revokeSponsorship"); - - const obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("revokeLiquidityPoolSponsorship"); - expect(obj.liquidityPoolId).to.be.equal(liquidityPoolId); - }); - - it("throws an error when liquidityPoolId is invalid", function () { - expect(() => - StellarBase.Operation.revokeLiquidityPoolSponsorship({}) - ).to.throw(/liquidityPoolId is invalid/); - }); - }); - - describe("revokeSignerSponsorship()", function () { - it("creates a revokeSignerSponsorship", function () { - const account = - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7"; - let signer = { - ed25519PublicKey: - "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7" - }; - let op = StellarBase.Operation.revokeSignerSponsorship({ - account, - signer - }); - let xdr = op.toXDR("hex"); - - let operation = StellarBase.xdr.Operation.fromXDR(xdr, "hex"); - expect(operation.body().switch().name).to.equal("revokeSponsorship"); - let obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("revokeSignerSponsorship"); - expect(obj.account).to.be.equal(account); - expect(obj.signer.ed25519PublicKey).to.be.equal(signer.ed25519PublicKey); - - // preAuthTx signer - signer = { - preAuthTx: StellarBase.hash("Tx hash").toString("hex") - }; - op = StellarBase.Operation.revokeSignerSponsorship({ - account, - signer - }); - operation = StellarBase.xdr.Operation.fromXDR(op.toXDR("hex"), "hex"); - obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("revokeSignerSponsorship"); - expect(obj.account).to.be.equal(account); - expect(obj.signer.preAuthTx).to.be.equal(signer.preAuthTx); - - // sha256Hash signer - signer = { - sha256Hash: StellarBase.hash("Hash Preimage").toString("hex") - }; - op = StellarBase.Operation.revokeSignerSponsorship({ - account, - signer - }); - operation = StellarBase.xdr.Operation.fromXDR(op.toXDR("hex"), "hex"); - obj = StellarBase.Operation.fromXDRObject(operation); - expect(obj.type).to.be.equal("revokeSignerSponsorship"); - expect(obj.account).to.be.equal(account); - expect(obj.signer.sha256Hash).to.be.equal(signer.sha256Hash); - }); - it("throws an error when account is invalid", function () { - const signer = { - ed25519PublicKey: - "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ" - }; - expect(() => - StellarBase.Operation.revokeSignerSponsorship({ - signer - }) - ).to.throw(/account is invalid/); - }); - }); - - describe("liquidityPoolDeposit()", function () { - it("throws an error if a required parameter is missing", function () { - expect(() => StellarBase.Operation.liquidityPoolDeposit()).to.throw( - /liquidityPoolId argument is required/ - ); - - let opts = {}; - expect(() => StellarBase.Operation.liquidityPoolDeposit(opts)).to.throw( - /liquidityPoolId argument is required/ - ); - - opts.liquidityPoolId = - "dd7b1ab831c273310ddbec6f97870aa83c2fbd78ce22aded37ecbf4f3380fac7"; - expect(() => StellarBase.Operation.liquidityPoolDeposit(opts)).to.throw( - /maxAmountA argument must be of type String, represent a positive number and have at most 7 digits after the decimal/ - ); - - opts.maxAmountA = "10"; - expect(() => StellarBase.Operation.liquidityPoolDeposit(opts)).to.throw( - /maxAmountB argument must be of type String, represent a positive number and have at most 7 digits after the decimal/ - ); - - opts.maxAmountB = "20"; - expect(() => StellarBase.Operation.liquidityPoolDeposit(opts)).to.throw( - /minPrice argument is required/ - ); - - opts.minPrice = "0.45"; - expect(() => StellarBase.Operation.liquidityPoolDeposit(opts)).to.throw( - /maxPrice argument is required/ - ); - - opts.maxPrice = "0.55"; - expect(() => - StellarBase.Operation.liquidityPoolDeposit(opts) - ).to.not.throw(); - }); - - it("throws an error if prices are negative", function () { - const opts = { - liquidityPoolId: - "dd7b1ab831c273310ddbec6f97870aa83c2fbd78ce22aded37ecbf4f3380fac7", - maxAmountA: "10.0000000", - maxAmountB: "20.0000000", - minPrice: "-0.45", - maxPrice: "0.55" - }; - expect(() => StellarBase.Operation.liquidityPoolDeposit(opts)).to.throw( - /price must be positive/ - ); - }); - - it("creates a liquidityPoolDeposit (string prices)", function () { - const opts = { - liquidityPoolId: - "dd7b1ab831c273310ddbec6f97870aa83c2fbd78ce22aded37ecbf4f3380fac7", - maxAmountA: "10.0000000", - maxAmountB: "20.0000000", - minPrice: "0.45", - maxPrice: "0.55" - }; - const op = StellarBase.Operation.liquidityPoolDeposit(opts); - const xdr = op.toXDR("hex"); - - const xdrObj = StellarBase.xdr.Operation.fromXDR(Buffer.from(xdr, "hex")); - expect(xdrObj.body().switch().name).to.equal("liquidityPoolDeposit"); - expect(xdrObj.body().value().maxAmountA().toString()).to.equal( - "100000000" - ); - expect(xdrObj.body().value().maxAmountB().toString()).to.equal( - "200000000" - ); - - const operation = StellarBase.Operation.fromXDRObject(xdrObj); - expect(operation.type).to.be.equal("liquidityPoolDeposit"); - expect(operation.liquidityPoolId).to.be.equals(opts.liquidityPoolId); - expect(operation.maxAmountA).to.be.equals(opts.maxAmountA); - expect(operation.maxAmountB).to.be.equals(opts.maxAmountB); - expect(operation.minPrice).to.be.equals(opts.minPrice); - expect(operation.maxPrice).to.be.equals(opts.maxPrice); - }); - - it("creates a liquidityPoolDeposit (fraction prices)", function () { - const opts = { - liquidityPoolId: - "dd7b1ab831c273310ddbec6f97870aa83c2fbd78ce22aded37ecbf4f3380fac7", - maxAmountA: "10.0000000", - maxAmountB: "20.0000000", - minPrice: { - n: 9, - d: 20 - }, - maxPrice: { - n: 11, - d: 20 - } - }; - const op = StellarBase.Operation.liquidityPoolDeposit(opts); - const xdr = op.toXDR("hex"); - - const xdrObj = StellarBase.xdr.Operation.fromXDR(Buffer.from(xdr, "hex")); - expect(xdrObj.body().switch().name).to.equal("liquidityPoolDeposit"); - expect(xdrObj.body().value().maxAmountA().toString()).to.equal( - "100000000" - ); - expect(xdrObj.body().value().maxAmountB().toString()).to.equal( - "200000000" - ); - - const operation = StellarBase.Operation.fromXDRObject(xdrObj); - expect(operation.type).to.be.equal("liquidityPoolDeposit"); - expect(operation.liquidityPoolId).to.be.equals(opts.liquidityPoolId); - expect(operation.maxAmountA).to.be.equals(opts.maxAmountA); - expect(operation.maxAmountB).to.be.equals(opts.maxAmountB); - expect(operation.minPrice).to.be.equals( - new BigNumber(opts.minPrice.n).div(opts.minPrice.d).toString() - ); - expect(operation.maxPrice).to.be.equals( - new BigNumber(opts.maxPrice.n).div(opts.maxPrice.d).toString() - ); - }); - - it("creates a liquidityPoolDeposit (number prices)", function () { - const opts = { - liquidityPoolId: - "dd7b1ab831c273310ddbec6f97870aa83c2fbd78ce22aded37ecbf4f3380fac7", - maxAmountA: "10.0000000", - maxAmountB: "20.0000000", - minPrice: 0.45, - maxPrice: 0.55 - }; - const op = StellarBase.Operation.liquidityPoolDeposit(opts); - const xdr = op.toXDR("hex"); - - const xdrObj = StellarBase.xdr.Operation.fromXDR(Buffer.from(xdr, "hex")); - expect(xdrObj.body().switch().name).to.equal("liquidityPoolDeposit"); - expect(xdrObj.body().value().maxAmountA().toString()).to.equal( - "100000000" - ); - expect(xdrObj.body().value().maxAmountB().toString()).to.equal( - "200000000" - ); - - const operation = StellarBase.Operation.fromXDRObject(xdrObj); - expect(operation.type).to.be.equal("liquidityPoolDeposit"); - expect(operation.liquidityPoolId).to.be.equals(opts.liquidityPoolId); - expect(operation.maxAmountA).to.be.equals(opts.maxAmountA); - expect(operation.maxAmountB).to.be.equals(opts.maxAmountB); - expect(operation.minPrice).to.be.equals(opts.minPrice.toString()); - expect(operation.maxPrice).to.be.equals(opts.maxPrice.toString()); - }); - - it("creates a liquidityPoolDeposit (BigNumber prices)", function () { - const opts = { - liquidityPoolId: - "dd7b1ab831c273310ddbec6f97870aa83c2fbd78ce22aded37ecbf4f3380fac7", - maxAmountA: "10.0000000", - maxAmountB: "20.0000000", - minPrice: new BigNumber(9).dividedBy(20), - maxPrice: new BigNumber(11).dividedBy(20) - }; - const op = StellarBase.Operation.liquidityPoolDeposit(opts); - const xdr = op.toXDR("hex"); - - const xdrObj = StellarBase.xdr.Operation.fromXDR(Buffer.from(xdr, "hex")); - expect(xdrObj.body().switch().name).to.equal("liquidityPoolDeposit"); - expect(xdrObj.body().value().maxAmountA().toString()).to.equal( - "100000000" - ); - expect(xdrObj.body().value().maxAmountB().toString()).to.equal( - "200000000" - ); - - const operation = StellarBase.Operation.fromXDRObject(xdrObj); - expect(operation.type).to.be.equal("liquidityPoolDeposit"); - expect(operation.liquidityPoolId).to.be.equals(opts.liquidityPoolId); - expect(operation.maxAmountA).to.be.equals(opts.maxAmountA); - expect(operation.maxAmountB).to.be.equals(opts.maxAmountB); - expect(operation.minPrice).to.be.equals(opts.minPrice.toString()); - expect(operation.maxPrice).to.be.equals(opts.maxPrice.toString()); - }); - }); - - describe(".isValidAmount()", function () { - it("returns true for valid amounts", function () { - let amounts = [ - "10", - "0.10", - "0.1234567", - "922337203685.4775807" // MAX - ]; - - for (var i in amounts) { - expect(StellarBase.Operation.isValidAmount(amounts[i])).to.be.true; - } - }); - - it("returns false for invalid amounts", function () { - let amounts = [ - 100, // integer - 100.5, // float - "", // empty string - "test", // string not representing a number - "0", - "-10", - "-10.5", - "0.12345678", - "922337203685.4775808", // Overflow - "Infinity", - Infinity, - "Nan", - NaN - ]; - - for (var i in amounts) { - expect(StellarBase.Operation.isValidAmount(amounts[i])).to.be.false; - } - }); - - it("allows 0 only if allowZero argument is set to true", function () { - expect(StellarBase.Operation.isValidAmount("0")).to.be.false; - expect(StellarBase.Operation.isValidAmount("0", true)).to.be.true; - }); - }); - - describe("._fromXDRAmount()", function () { - it("correctly parses the amount", function () { - expect(StellarBase.Operation._fromXDRAmount(1)).to.be.equal("0.0000001"); - expect(StellarBase.Operation._fromXDRAmount(10000000)).to.be.equal( - "1.0000000" - ); - expect(StellarBase.Operation._fromXDRAmount(10000000000)).to.be.equal( - "1000.0000000" - ); - expect( - StellarBase.Operation._fromXDRAmount(1000000000000000000) - ).to.be.equal("100000000000.0000000"); - }); - }); -}); diff --git a/test/unit/operations/clawback_claimable_balance.test.ts b/test/unit/operations/clawback_claimable_balance.test.ts new file mode 100644 index 00000000..b42efcd7 --- /dev/null +++ b/test/unit/operations/clawback_claimable_balance.test.ts @@ -0,0 +1,46 @@ +import { describe, it, expect } from "vitest"; +import { Operation } from "../../../src/operation.js"; +import xdr from "../../../src/xdr.js"; + +const balanceId = + "00000000da0d57da7d4850e7fc10d2a9d0ebc731f7afb40574c03395b17d49149b91f5be"; + +describe("Operation.clawbackClaimableBalance()", () => { + it("creates a clawbackClaimableBalanceOp", () => { + const op = Operation.clawbackClaimableBalance({ balanceId }); + const xdrHex = op.toXDR("hex"); + const operation = xdr.Operation.fromXDR(xdrHex, "hex"); + const obj = Operation.fromXDRObject(operation); + + expect(obj.type).toBe("clawbackClaimableBalance"); + if (obj.type !== "clawbackClaimableBalance") + throw new Error("unexpected type"); + + expect(obj.balanceId).toBe(balanceId); + }); + + it("throws when balanceId is not present", () => { + expect(() => + // @ts-expect-error: intentionally omitting required field to test runtime validation + Operation.clawbackClaimableBalance({}), + ).toThrow(/must provide a valid claimable balance id/); + }); + + it("throws for an invalid balanceId", () => { + expect(() => + Operation.clawbackClaimableBalance({ balanceId: "badc0ffee" }), + ).toThrow(/must provide a valid claimable balance id/); + }); + + it("preserves an optional source account", () => { + const source = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ"; + const op = Operation.clawbackClaimableBalance({ balanceId, source }); + const obj = Operation.fromXDRObject( + xdr.Operation.fromXDR(op.toXDR("hex"), "hex"), + ); + + if (obj.type !== "clawbackClaimableBalance") + throw new Error("unexpected type"); + expect(obj.source).toBe(source); + }); +}); diff --git a/test/unit/operations/create_claimable_balance.test.ts b/test/unit/operations/create_claimable_balance.test.ts new file mode 100644 index 00000000..cd309e3c --- /dev/null +++ b/test/unit/operations/create_claimable_balance.test.ts @@ -0,0 +1,91 @@ +import { describe, it, expect } from "vitest"; +import { Operation } from "../../../src/operation.js"; +import { Asset } from "../../../src/asset.js"; +import { Claimant } from "../../../src/claimant.js"; +import xdr from "../../../src/xdr.js"; + +const asset = new Asset( + "USD", + "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7", +); +const amount = "100.0000000"; +const claimants = [ + new Claimant("GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ"), +]; + +describe("Operation.createClaimableBalance()", () => { + it("creates a createClaimableBalanceOp", () => { + const op = Operation.createClaimableBalance({ asset, amount, claimants }); + const xdrHex = op.toXDR("hex"); + const operation = xdr.Operation.fromXDR(xdrHex, "hex"); + const obj = Operation.fromXDRObject(operation); + + expect(obj.type).toBe("createClaimableBalance"); + + if (obj.type !== "createClaimableBalance") + throw new Error("unexpected type"); + + expect(obj.asset.toString()).toBe(asset.toString()); + expect(obj.amount).toBe(amount); + expect(obj.claimants).toHaveLength(1); + + const firstClaimant = obj.claimants[0]; + if (firstClaimant === undefined) throw new Error("missing claimant"); + + const expectedClaimant = claimants[0]; + if (expectedClaimant === undefined) + throw new Error("missing fixture claimant"); + + expect(firstClaimant.toXDRObject().toXDR("hex")).toBe( + expectedClaimant.toXDRObject().toXDR("hex"), + ); + }); + + it("throws when asset is not provided", () => { + expect(() => + // @ts-expect-error: intentionally omitting required field to test runtime validation + Operation.createClaimableBalance({ amount, claimants }), + ).toThrow(/must provide an asset for create claimable balance operation/); + }); + + it("throws when amount is not provided", () => { + expect(() => + // @ts-expect-error: intentionally omitting required field to test runtime validation + Operation.createClaimableBalance({ asset, claimants }), + ).toThrow( + /amount argument must be of type String, represent a positive number and have at most 7 digits after the decimal/, + ); + }); + + it("throws when claimants is not provided", () => { + expect(() => + // @ts-expect-error: intentionally omitting required field to test runtime validation + Operation.createClaimableBalance({ asset, amount }), + ).toThrow(/must provide at least one claimant/); + }); + + it("throws when claimants is an empty array", () => { + expect(() => + Operation.createClaimableBalance({ asset, amount, claimants: [] }), + ).toThrow(/must provide at least one claimant/); + }); + + it("preserves an optional source account", () => { + const source = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ"; + const op = Operation.createClaimableBalance({ + asset, + amount, + claimants, + source, + }); + + const obj = Operation.fromXDRObject( + xdr.Operation.fromXDR(op.toXDR("hex"), "hex"), + ); + + if (obj.type !== "createClaimableBalance") + throw new Error("unexpected type"); + + expect(obj.source).toBe(source); + }); +}); diff --git a/test/unit/operations/create_passive_sell_offer.test.ts b/test/unit/operations/create_passive_sell_offer.test.ts new file mode 100644 index 00000000..ce1e596b --- /dev/null +++ b/test/unit/operations/create_passive_sell_offer.test.ts @@ -0,0 +1,141 @@ +import { describe, it, expect } from "vitest"; +import BigNumber from "bignumber.js"; +import { Operation } from "../../../src/operation.js"; +import { Asset } from "../../../src/asset.js"; +import xdr from "../../../src/xdr.js"; + +const selling = new Asset( + "USD", + "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7", +); +const buying = new Asset( + "USD", + "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7", +); +const amount = "11.2782700"; + +describe("Operation.createPassiveSellOffer()", () => { + it("creates a createPassiveSellOfferOp with string price", () => { + const price = "3.07"; + const op = Operation.createPassiveSellOffer({ + selling, + buying, + amount, + price, + }); + const xdrHex = op.toXDR("hex"); + const operation = xdr.Operation.fromXDR(xdrHex, "hex"); + const obj = Operation.fromXDRObject(operation); + + expect(obj.type).toBe("createPassiveSellOffer"); + if (obj.type !== "createPassiveSellOffer") + throw new Error("unexpected type"); + + expect(obj.selling.equals(selling)).toBe(true); + expect(obj.buying.equals(buying)).toBe(true); + expect( + (operation.body().value() as xdr.CreatePassiveSellOfferOp) + .amount() + .toString(), + ).toBe("112782700"); + expect(obj.amount).toBe(amount); + expect(obj.price).toBe(price); + }); + + it("creates a createPassiveSellOfferOp with number price", () => { + const price = 3.07; + const op = Operation.createPassiveSellOffer({ + selling, + buying, + amount, + price, + }); + const obj = Operation.fromXDRObject( + xdr.Operation.fromXDR(op.toXDR("hex"), "hex"), + ); + + expect(obj.type).toBe("createPassiveSellOffer"); + if (obj.type !== "createPassiveSellOffer") + throw new Error("unexpected type"); + + expect(obj.selling.equals(selling)).toBe(true); + expect(obj.buying.equals(buying)).toBe(true); + expect(obj.amount).toBe(amount); + expect(obj.price).toBe(price.toString()); + }); + + it("creates a createPassiveSellOfferOp with BigNumber price", () => { + const price = new BigNumber(5).dividedBy(4); + const op = Operation.createPassiveSellOffer({ + selling, + buying, + amount, + price, + }); + const obj = Operation.fromXDRObject( + xdr.Operation.fromXDR(op.toXDR("hex"), "hex"), + ); + + expect(obj.type).toBe("createPassiveSellOffer"); + if (obj.type !== "createPassiveSellOffer") + throw new Error("unexpected type"); + + expect(obj.selling.equals(selling)).toBe(true); + expect(obj.buying.equals(buying)).toBe(true); + expect(obj.amount).toBe(amount); + expect(obj.price).toBe("1.25"); + }); + + it("fails with an invalid amount", () => { + expect(() => + Operation.createPassiveSellOffer({ + selling, + buying, + // @ts-expect-error: intentionally passing non-string amount to test runtime validation + amount: 20, + price: "10", + }), + ).toThrow(/amount argument must be of type String/); + }); + + it("fails with a missing price", () => { + expect(() => + Operation.createPassiveSellOffer({ + selling, + buying, + amount: "20", + // @ts-expect-error: intentionally omitting required field to test runtime validation + price: undefined, + }), + ).toThrow(/price argument is required/); + }); + + it("fails with a negative price", () => { + expect(() => + Operation.createPassiveSellOffer({ + selling, + buying, + amount: "20", + price: "-2", + }), + ).toThrow(/price must be positive/); + }); + + it("preserves an optional source account", () => { + const source = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ"; + const op = Operation.createPassiveSellOffer({ + selling, + buying, + amount, + price: "3.07", + source, + }); + const obj = Operation.fromXDRObject( + xdr.Operation.fromXDR(op.toXDR("hex"), "hex"), + ); + + if (obj.type !== "createPassiveSellOffer") + throw new Error("unexpected type"); + expect(obj.source).toBe(source); + }); +}); diff --git a/test/unit/operations/liquidity_pool_deposit.test.ts b/test/unit/operations/liquidity_pool_deposit.test.ts new file mode 100644 index 00000000..9c3d3f29 --- /dev/null +++ b/test/unit/operations/liquidity_pool_deposit.test.ts @@ -0,0 +1,204 @@ +import { describe, it, expect } from "vitest"; +import BigNumber from "bignumber.js"; +import { Operation } from "../../../src/operation.js"; +import xdr from "../../../src/xdr.js"; + +const liquidityPoolId = + "dd7b1ab831c273310ddbec6f97870aa83c2fbd78ce22aded37ecbf4f3380fac7"; +const maxAmountA = "10.0000000"; +const maxAmountB = "20.0000000"; + +describe("Operation.liquidityPoolDeposit()", () => { + it("fails without liquidityPoolId", () => { + expect(() => Operation.liquidityPoolDeposit()).toThrow( + /liquidityPoolId argument is required/, + ); + + expect(() => + // @ts-expect-error: intentionally passing empty opts to test runtime validation + Operation.liquidityPoolDeposit({}), + ).toThrow(/liquidityPoolId argument is required/); + }); + + it("fails without maxAmountA", () => { + expect(() => + Operation.liquidityPoolDeposit({ + liquidityPoolId, + // @ts-expect-error: intentionally omitting required field to test runtime validation + maxAmountA: undefined, + maxAmountB, + minPrice: "0.45", + maxPrice: "0.55", + }), + ).toThrow( + /maxAmountA argument must be of type String, represent a positive number and have at most 7 digits after the decimal/, + ); + }); + + it("fails without maxAmountB", () => { + expect(() => + Operation.liquidityPoolDeposit({ + liquidityPoolId, + maxAmountA, + // @ts-expect-error: intentionally omitting required field to test runtime validation + maxAmountB: undefined, + minPrice: "0.45", + maxPrice: "0.55", + }), + ).toThrow( + /maxAmountB argument must be of type String, represent a positive number and have at most 7 digits after the decimal/, + ); + }); + + it("fails without minPrice", () => { + expect(() => + Operation.liquidityPoolDeposit({ + liquidityPoolId, + maxAmountA, + maxAmountB, + // @ts-expect-error: intentionally omitting required field to test runtime validation + minPrice: undefined, + maxPrice: "0.55", + }), + ).toThrow(/minPrice argument is required/); + }); + + it("fails without maxPrice", () => { + expect(() => + Operation.liquidityPoolDeposit({ + liquidityPoolId, + maxAmountA, + maxAmountB, + minPrice: "0.45", + // @ts-expect-error: intentionally omitting required field to test runtime validation + maxPrice: undefined, + }), + ).toThrow(/maxPrice argument is required/); + }); + + it("fails with a negative price", () => { + expect(() => + Operation.liquidityPoolDeposit({ + liquidityPoolId, + maxAmountA, + maxAmountB, + minPrice: "-0.45", + maxPrice: "0.55", + }), + ).toThrow(/price must be positive/); + }); + + it("creates a liquidityPoolDeposit with string prices", () => { + const opts = { + liquidityPoolId, + maxAmountA, + maxAmountB, + minPrice: "0.45", + maxPrice: "0.55", + }; + const op = Operation.liquidityPoolDeposit(opts); + const xdrHex = op.toXDR("hex"); + const xdrOp = xdr.Operation.fromXDR(xdrHex, "hex"); + const body = xdrOp.body().value() as xdr.LiquidityPoolDepositOp; + + expect(body.maxAmountA().toString()).toBe("100000000"); + expect(body.maxAmountB().toString()).toBe("200000000"); + + const obj = Operation.fromXDRObject(xdrOp); + expect(obj.type).toBe("liquidityPoolDeposit"); + if (obj.type !== "liquidityPoolDeposit") throw new Error("unexpected type"); + + expect(obj.liquidityPoolId).toBe(liquidityPoolId); + expect(obj.maxAmountA).toBe(maxAmountA); + expect(obj.maxAmountB).toBe(maxAmountB); + expect(obj.minPrice).toBe("0.45"); + expect(obj.maxPrice).toBe("0.55"); + }); + + it("creates a liquidityPoolDeposit with fraction prices", () => { + const opts = { + liquidityPoolId, + maxAmountA, + maxAmountB, + minPrice: { n: 9, d: 20 }, + maxPrice: { n: 11, d: 20 }, + }; + const op = Operation.liquidityPoolDeposit(opts); + const obj = Operation.fromXDRObject( + xdr.Operation.fromXDR(op.toXDR("hex"), "hex"), + ); + + expect(obj.type).toBe("liquidityPoolDeposit"); + if (obj.type !== "liquidityPoolDeposit") throw new Error("unexpected type"); + + expect(obj.liquidityPoolId).toBe(liquidityPoolId); + expect(obj.maxAmountA).toBe(maxAmountA); + expect(obj.maxAmountB).toBe(maxAmountB); + expect(obj.minPrice).toBe(new BigNumber(9).div(20).toString()); + expect(obj.maxPrice).toBe(new BigNumber(11).div(20).toString()); + }); + + it("creates a liquidityPoolDeposit with number prices", () => { + const opts = { + liquidityPoolId, + maxAmountA, + maxAmountB, + minPrice: 0.45, + maxPrice: 0.55, + }; + const op = Operation.liquidityPoolDeposit(opts); + const obj = Operation.fromXDRObject( + xdr.Operation.fromXDR(op.toXDR("hex"), "hex"), + ); + + expect(obj.type).toBe("liquidityPoolDeposit"); + if (obj.type !== "liquidityPoolDeposit") throw new Error("unexpected type"); + + expect(obj.liquidityPoolId).toBe(liquidityPoolId); + expect(obj.maxAmountA).toBe(maxAmountA); + expect(obj.maxAmountB).toBe(maxAmountB); + expect(obj.minPrice).toBe((0.45).toString()); + expect(obj.maxPrice).toBe((0.55).toString()); + }); + + it("creates a liquidityPoolDeposit with BigNumber prices", () => { + const opts = { + liquidityPoolId, + maxAmountA, + maxAmountB, + minPrice: new BigNumber(9).dividedBy(20), + maxPrice: new BigNumber(11).dividedBy(20), + }; + const op = Operation.liquidityPoolDeposit(opts); + const obj = Operation.fromXDRObject( + xdr.Operation.fromXDR(op.toXDR("hex"), "hex"), + ); + + expect(obj.type).toBe("liquidityPoolDeposit"); + if (obj.type !== "liquidityPoolDeposit") throw new Error("unexpected type"); + + expect(obj.liquidityPoolId).toBe(liquidityPoolId); + expect(obj.maxAmountA).toBe(maxAmountA); + expect(obj.maxAmountB).toBe(maxAmountB); + expect(obj.minPrice).toBe(new BigNumber(9).dividedBy(20).toString()); + expect(obj.maxPrice).toBe(new BigNumber(11).dividedBy(20).toString()); + }); + + it("preserves an optional source account", () => { + const source = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ"; + const op = Operation.liquidityPoolDeposit({ + liquidityPoolId, + maxAmountA, + maxAmountB, + minPrice: "0.45", + maxPrice: "0.55", + source, + }); + const obj = Operation.fromXDRObject( + xdr.Operation.fromXDR(op.toXDR("hex"), "hex"), + ); + + if (obj.type !== "liquidityPoolDeposit") throw new Error("unexpected type"); + expect(obj.source).toBe(source); + }); +}); diff --git a/test/unit/operations/manage_buy_offer.test.ts b/test/unit/operations/manage_buy_offer.test.ts new file mode 100644 index 00000000..0cc356f9 --- /dev/null +++ b/test/unit/operations/manage_buy_offer.test.ts @@ -0,0 +1,221 @@ +import { describe, it, expect } from "vitest"; +import BigNumber from "bignumber.js"; +import { Operation } from "../../../src/operation.js"; +import { Asset } from "../../../src/asset.js"; +import xdr from "../../../src/xdr.js"; + +const selling = new Asset( + "USD", + "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7", +); +const buying = new Asset( + "USD", + "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7", +); + +describe("Operation.manageBuyOffer()", () => { + it("creates a manageBuyOfferOp with string price", () => { + const opts = { + selling, + buying, + buyAmount: "3.1234560", + price: "8.141592", + offerId: "1", + }; + const op = Operation.manageBuyOffer(opts); + const xdrHex = op.toXDR("hex"); + const operation = xdr.Operation.fromXDR(xdrHex, "hex"); + const obj = Operation.fromXDRObject(operation); + + expect(obj.type).toBe("manageBuyOffer"); + if (obj.type !== "manageBuyOffer") throw new Error("unexpected type"); + + expect(obj.selling.equals(selling)).toBe(true); + expect(obj.buying.equals(buying)).toBe(true); + expect( + (operation.body().value() as xdr.ManageBuyOfferOp).buyAmount().toString(), + ).toBe("31234560"); + expect(obj.buyAmount).toBe(opts.buyAmount); + expect(obj.price).toBe(opts.price); + expect(obj.offerId).toBe(opts.offerId); + }); + + it("creates a manageBuyOfferOp with fraction price", () => { + const opts = { + selling, + buying, + buyAmount: "3.123456", + price: { n: 11, d: 10 }, + offerId: "1", + }; + const op = Operation.manageBuyOffer(opts); + const obj = Operation.fromXDRObject( + xdr.Operation.fromXDR(op.toXDR("hex"), "hex"), + ); + + expect(obj.type).toBe("manageBuyOffer"); + if (obj.type !== "manageBuyOffer") throw new Error("unexpected type"); + expect(obj.price).toBe(new BigNumber(11).div(10).toString()); + }); + + it("fails with a negative fraction price", () => { + expect(() => + Operation.manageBuyOffer({ + selling, + buying, + buyAmount: "3.123456", + price: { n: 11, d: -1 }, + offerId: "1", + }), + ).toThrow(/price must be positive/); + }); + + it("creates a manageBuyOfferOp with number price", () => { + const opts = { + selling, + buying, + buyAmount: "3.123456", + price: 3.07, + offerId: "1", + }; + const op = Operation.manageBuyOffer(opts); + const obj = Operation.fromXDRObject( + xdr.Operation.fromXDR(op.toXDR("hex"), "hex"), + ); + + expect(obj.type).toBe("manageBuyOffer"); + if (obj.type !== "manageBuyOffer") throw new Error("unexpected type"); + expect(obj.price).toBe((3.07).toString()); + }); + + it("creates a manageBuyOfferOp with BigNumber price", () => { + const opts = { + selling, + buying, + buyAmount: "3.123456", + price: new BigNumber(5).dividedBy(4), + offerId: "1", + }; + const op = Operation.manageBuyOffer(opts); + const obj = Operation.fromXDRObject( + xdr.Operation.fromXDR(op.toXDR("hex"), "hex"), + ); + + expect(obj.type).toBe("manageBuyOffer"); + if (obj.type !== "manageBuyOffer") throw new Error("unexpected type"); + expect(obj.price).toBe("1.25"); + }); + + it("defaults offerId to '0' when not provided", () => { + const opts = { + selling, + buying, + buyAmount: "1000.0000000", + price: "3.141592", + }; + const op = Operation.manageBuyOffer(opts); + const operation = xdr.Operation.fromXDR(op.toXDR("hex"), "hex"); + const obj = Operation.fromXDRObject(operation); + + expect(obj.type).toBe("manageBuyOffer"); + if (obj.type !== "manageBuyOffer") throw new Error("unexpected type"); + + expect(obj.selling.equals(selling)).toBe(true); + expect(obj.buying.equals(buying)).toBe(true); + expect( + (operation.body().value() as xdr.ManageBuyOfferOp).buyAmount().toString(), + ).toBe("10000000000"); + expect(obj.buyAmount).toBe(opts.buyAmount); + expect(obj.price).toBe(opts.price); + expect(obj.offerId).toBe("0"); + }); + + it("cancels an offer by setting buyAmount to zero", () => { + const opts = { + selling, + buying, + buyAmount: "0.0000000", + price: "3.141592", + offerId: "1", + }; + const op = Operation.manageBuyOffer(opts); + const operation = xdr.Operation.fromXDR(op.toXDR("hex"), "hex"); + const obj = Operation.fromXDRObject(operation); + + expect(obj.type).toBe("manageBuyOffer"); + if (obj.type !== "manageBuyOffer") throw new Error("unexpected type"); + + expect(obj.selling.equals(selling)).toBe(true); + expect(obj.buying.equals(buying)).toBe(true); + expect( + (operation.body().value() as xdr.ManageBuyOfferOp).buyAmount().toString(), + ).toBe("0"); + expect(obj.buyAmount).toBe(opts.buyAmount); + expect(obj.price).toBe(opts.price); + expect(obj.offerId).toBe("1"); + }); + + it("fails with an invalid buyAmount", () => { + expect(() => + Operation.manageBuyOffer({ + selling, + buying, + // @ts-expect-error: intentionally passing non-string amount to test runtime validation + buyAmount: 20, + price: "10", + }), + ).toThrow(/buyAmount argument must be of type String/); + }); + + it("fails with a missing price", () => { + expect(() => + Operation.manageBuyOffer({ + selling, + buying, + buyAmount: "20", + // @ts-expect-error: intentionally omitting required field to test runtime validation + price: undefined, + }), + ).toThrow(/price argument is required/); + }); + + it("fails with a negative price", () => { + expect(() => + Operation.manageBuyOffer({ + selling, + buying, + buyAmount: "20", + price: "-1", + }), + ).toThrow(/price must be positive/); + }); + + it("fails with a non-numeric price string", () => { + expect(() => + Operation.manageBuyOffer({ + selling, + buying, + buyAmount: "20", + price: "test", + }), + ).toThrow(/not a number/i); + }); + + it("preserves an optional source account", () => { + const source = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ"; + const op = Operation.manageBuyOffer({ + selling, + buying, + buyAmount: "3.1234560", + price: "8.141592", + offerId: "1", + source, + }); + const obj = Operation.fromXDRObject( + xdr.Operation.fromXDR(op.toXDR("hex"), "hex"), + ); + + if (obj.type !== "manageBuyOffer") throw new Error("unexpected type"); + expect(obj.source).toBe(source); + }); +}); diff --git a/test/unit/operations/manage_sell_offer.test.ts b/test/unit/operations/manage_sell_offer.test.ts new file mode 100644 index 00000000..9ce63ac1 --- /dev/null +++ b/test/unit/operations/manage_sell_offer.test.ts @@ -0,0 +1,221 @@ +import { describe, it, expect } from "vitest"; +import BigNumber from "bignumber.js"; +import { Operation } from "../../../src/operation.js"; +import { Asset } from "../../../src/asset.js"; +import xdr from "../../../src/xdr.js"; + +const selling = new Asset( + "USD", + "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7", +); +const buying = new Asset( + "USD", + "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7", +); + +describe("Operation.manageSellOffer()", () => { + it("creates a manageSellOfferOp with string price", () => { + const opts = { + selling, + buying, + amount: "3.1234560", + price: "8.141592", + offerId: "1", + }; + const op = Operation.manageSellOffer(opts); + const xdrHex = op.toXDR("hex"); + const operation = xdr.Operation.fromXDR(xdrHex, "hex"); + const obj = Operation.fromXDRObject(operation); + + expect(obj.type).toBe("manageSellOffer"); + if (obj.type !== "manageSellOffer") throw new Error("unexpected type"); + + expect(obj.selling.equals(selling)).toBe(true); + expect(obj.buying.equals(buying)).toBe(true); + expect( + (operation.body().value() as xdr.ManageSellOfferOp).amount().toString(), + ).toBe("31234560"); + expect(obj.amount).toBe(opts.amount); + expect(obj.price).toBe(opts.price); + expect(obj.offerId).toBe(opts.offerId); + }); + + it("creates a manageSellOfferOp with fraction price", () => { + const opts = { + selling, + buying, + amount: "3.123456", + price: { n: 11, d: 10 }, + offerId: "1", + }; + const op = Operation.manageSellOffer(opts); + const obj = Operation.fromXDRObject( + xdr.Operation.fromXDR(op.toXDR("hex"), "hex"), + ); + + expect(obj.type).toBe("manageSellOffer"); + if (obj.type !== "manageSellOffer") throw new Error("unexpected type"); + expect(obj.price).toBe(new BigNumber(11).div(10).toString()); + }); + + it("fails with a negative fraction price", () => { + expect(() => + Operation.manageSellOffer({ + selling, + buying, + amount: "3.123456", + price: { n: 11, d: -1 }, + offerId: "1", + }), + ).toThrow(/price must be positive/); + }); + + it("creates a manageSellOfferOp with number price", () => { + const opts = { + selling, + buying, + amount: "3.123456", + price: 3.07, + offerId: "1", + }; + const op = Operation.manageSellOffer(opts); + const obj = Operation.fromXDRObject( + xdr.Operation.fromXDR(op.toXDR("hex"), "hex"), + ); + + expect(obj.type).toBe("manageSellOffer"); + if (obj.type !== "manageSellOffer") throw new Error("unexpected type"); + expect(obj.price).toBe((3.07).toString()); + }); + + it("creates a manageSellOfferOp with BigNumber price", () => { + const opts = { + selling, + buying, + amount: "3.123456", + price: new BigNumber(5).dividedBy(4), + offerId: "1", + }; + const op = Operation.manageSellOffer(opts); + const obj = Operation.fromXDRObject( + xdr.Operation.fromXDR(op.toXDR("hex"), "hex"), + ); + + expect(obj.type).toBe("manageSellOffer"); + if (obj.type !== "manageSellOffer") throw new Error("unexpected type"); + expect(obj.price).toBe("1.25"); + }); + + it("defaults offerId to '0' when not provided", () => { + const opts = { + selling, + buying, + amount: "1000.0000000", + price: "3.141592", + }; + const op = Operation.manageSellOffer(opts); + const operation = xdr.Operation.fromXDR(op.toXDR("hex"), "hex"); + const obj = Operation.fromXDRObject(operation); + + expect(obj.type).toBe("manageSellOffer"); + if (obj.type !== "manageSellOffer") throw new Error("unexpected type"); + + expect(obj.selling.equals(selling)).toBe(true); + expect(obj.buying.equals(buying)).toBe(true); + expect( + (operation.body().value() as xdr.ManageSellOfferOp).amount().toString(), + ).toBe("10000000000"); + expect(obj.amount).toBe(opts.amount); + expect(obj.price).toBe(opts.price); + expect(obj.offerId).toBe("0"); + }); + + it("cancels an offer by setting amount to zero", () => { + const opts = { + selling, + buying, + amount: "0.0000000", + price: "3.141592", + offerId: "1", + }; + const op = Operation.manageSellOffer(opts); + const operation = xdr.Operation.fromXDR(op.toXDR("hex"), "hex"); + const obj = Operation.fromXDRObject(operation); + + expect(obj.type).toBe("manageSellOffer"); + if (obj.type !== "manageSellOffer") throw new Error("unexpected type"); + + expect(obj.selling.equals(selling)).toBe(true); + expect(obj.buying.equals(buying)).toBe(true); + expect( + (operation.body().value() as xdr.ManageSellOfferOp).amount().toString(), + ).toBe("0"); + expect(obj.amount).toBe(opts.amount); + expect(obj.price).toBe(opts.price); + expect(obj.offerId).toBe("1"); + }); + + it("fails with an invalid amount", () => { + expect(() => + Operation.manageSellOffer({ + selling, + buying, + // @ts-expect-error: intentionally passing non-string amount to test runtime validation + amount: 20, + price: "10", + }), + ).toThrow(/amount argument must be of type String/); + }); + + it("fails with a missing price", () => { + expect(() => + Operation.manageSellOffer({ + selling, + buying, + amount: "20", + // @ts-expect-error: intentionally omitting required field to test runtime validation + price: undefined, + }), + ).toThrow(/price argument is required/); + }); + + it("fails with a negative price", () => { + expect(() => + Operation.manageSellOffer({ + selling, + buying, + amount: "20", + price: "-1", + }), + ).toThrow(/price must be positive/); + }); + + it("fails with a non-numeric price string", () => { + expect(() => + Operation.manageSellOffer({ + selling, + buying, + amount: "20", + price: "test", + }), + ).toThrow(/not a number/i); + }); + + it("preserves an optional source account", () => { + const source = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ"; + const op = Operation.manageSellOffer({ + selling, + buying, + amount: "3.1234560", + price: "8.141592", + offerId: "1", + source, + }); + const obj = Operation.fromXDRObject( + xdr.Operation.fromXDR(op.toXDR("hex"), "hex"), + ); + + if (obj.type !== "manageSellOffer") throw new Error("unexpected type"); + expect(obj.source).toBe(source); + }); +}); diff --git a/test/unit/operations/path_payment_strict_send.test.ts b/test/unit/operations/path_payment_strict_send.test.ts new file mode 100644 index 00000000..4d86b18d --- /dev/null +++ b/test/unit/operations/path_payment_strict_send.test.ts @@ -0,0 +1,180 @@ +import { describe, it, expect } from "vitest"; +import { Operation } from "../../../src/operation.js"; +import { Asset } from "../../../src/asset.js"; +import { + encodeMuxedAccountToAddress, + encodeMuxedAccount, +} from "../../../src/util/decode_encode_muxed_account.js"; +import xdr from "../../../src/xdr.js"; + +const sendAsset = new Asset( + "USD", + "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7", +); +const sendAmount = "3.0070000"; +const destination = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ"; +const destAsset = new Asset( + "USD", + "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7", +); +const destMin = "3.1415000"; +const path = [ + new Asset("USD", "GBBM6BKZPEHWYO3E3YKREDPQXMS4VK35YLNU7NFBRI26RAN7GI5POFBB"), + new Asset("EUR", "GDTNXRLOJD2YEBPKK7KCMR7J33AAG5VZXHAJTHIG736D6LVEFLLLKPDL"), +]; + +describe("Operation.pathPaymentStrictSend()", () => { + it("creates a pathPaymentStrictSendOp", () => { + const op = Operation.pathPaymentStrictSend({ + sendAsset, + sendAmount, + destination, + destAsset, + destMin, + path, + }); + const xdrHex = op.toXDR("hex"); + const operation = xdr.Operation.fromXDR(xdrHex, "hex"); + const obj = Operation.fromXDRObject(operation); + const body = operation.body().value() as xdr.PathPaymentStrictSendOp; + + expect(obj.type).toBe("pathPaymentStrictSend"); + if (obj.type !== "pathPaymentStrictSend") + throw new Error("unexpected type"); + + expect(obj.sendAsset.equals(sendAsset)).toBe(true); + expect(body.sendAmount().toString()).toBe("30070000"); + expect(obj.sendAmount).toBe(sendAmount); + expect(obj.destination).toBe(destination); + expect(obj.destAsset.equals(destAsset)).toBe(true); + expect(body.destMin().toString()).toBe("31415000"); + expect(obj.destMin).toBe(destMin); + + const path0 = obj.path[0]; + const path1 = obj.path[1]; + if (path0 === undefined || path1 === undefined) + throw new Error("missing path element"); + + expect(path0.getCode()).toBe("USD"); + expect(path0.getIssuer()).toBe( + "GBBM6BKZPEHWYO3E3YKREDPQXMS4VK35YLNU7NFBRI26RAN7GI5POFBB", + ); + expect(path1.getCode()).toBe("EUR"); + expect(path1.getIssuer()).toBe( + "GDTNXRLOJD2YEBPKK7KCMR7J33AAG5VZXHAJTHIG736D6LVEFLLLKPDL", + ); + }); + + it("supports muxed accounts", () => { + const base = "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ"; + const muxedSource = encodeMuxedAccountToAddress( + encodeMuxedAccount(base, "1"), + ); + const muxedDestination = encodeMuxedAccountToAddress( + encodeMuxedAccount(base, "2"), + ); + const packed = Operation.pathPaymentStrictSend({ + source: muxedSource, + destination: muxedDestination, + sendAsset, + sendAmount, + destAsset, + destMin, + path: [ + new Asset( + "USD", + "GBBM6BKZPEHWYO3E3YKREDPQXMS4VK35YLNU7NFBRI26RAN7GI5POFBB", + ), + ], + }); + + expect(() => { + xdr.Operation.fromXDR(packed.toXDR("raw"), "raw"); + xdr.Operation.fromXDR(packed.toXDR("hex"), "hex"); + }).not.toThrow(); + + const unpacked = Operation.fromXDRObject(packed); + expect(unpacked.type).toBe("pathPaymentStrictSend"); + + if (unpacked.type !== "pathPaymentStrictSend") + throw new Error("unexpected type"); + expect(unpacked.source).toBe(muxedSource); + expect(unpacked.destination).toBe(muxedDestination); + }); + + it("fails with an invalid destination address", () => { + expect(() => + Operation.pathPaymentStrictSend({ + destination: "GCEZW", + sendAmount: "20", + destMin: "50", + sendAsset: Asset.native(), + destAsset: new Asset( + "USD", + "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7", + ), + }), + ).toThrow(/destination is invalid/); + }); + + it("fails with a non-string sendAmount", () => { + expect(() => + Operation.pathPaymentStrictSend({ + destination, + // @ts-expect-error: intentionally passing non-string amount to test runtime validation + sendAmount: 20, + destMin: "50", + sendAsset: Asset.native(), + destAsset: new Asset( + "USD", + "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7", + ), + }), + ).toThrow(/sendAmount argument must be of type String/); + }); + + it("fails with a non-string destMin", () => { + expect(() => + Operation.pathPaymentStrictSend({ + destination, + sendAmount: "20", + // @ts-expect-error: intentionally passing non-string amount to test runtime validation + destMin: 50, + sendAsset: Asset.native(), + destAsset: new Asset( + "USD", + "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7", + ), + }), + ).toThrow(/destMin argument must be of type String/); + }); + + it("fails without a sendAsset", () => { + expect(() => + Operation.pathPaymentStrictSend({ + destination, + sendAmount: "20", + destMin: "50", + // @ts-expect-error: intentionally omitting required field to test runtime validation + sendAsset: undefined, + destAsset: new Asset( + "USD", + "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7", + ), + }), + ).toThrow(/Must specify a send asset/); + }); + + it("fails without a destAsset", () => { + expect(() => + Operation.pathPaymentStrictSend({ + destination, + sendAmount: "20", + destMin: "50", + sendAsset: Asset.native(), + // @ts-expect-error: intentionally omitting required field to test runtime validation + destAsset: undefined, + }), + ).toThrow(/Must provide a destAsset for a payment operation/); + }); +}); diff --git a/test/unit/operations/revoke_sponsorship.test.ts b/test/unit/operations/revoke_sponsorship.test.ts new file mode 100644 index 00000000..53009f06 --- /dev/null +++ b/test/unit/operations/revoke_sponsorship.test.ts @@ -0,0 +1,281 @@ +import { describe, it, expect } from "vitest"; +import { Operation } from "../../../src/operation.js"; +import { Asset } from "../../../src/asset.js"; +import { LiquidityPoolId } from "../../../src/liquidity_pool_id.js"; +import { hash } from "../../../src/hashing.js"; +import xdr from "../../../src/xdr.js"; + +const account = "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7"; +const source = "GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ"; + +describe("Operation.revokeAccountSponsorship()", () => { + it("creates a revokeAccountSponsorshipOp", () => { + const op = Operation.revokeAccountSponsorship({ account }); + const operation = xdr.Operation.fromXDR(op.toXDR("hex"), "hex"); + const obj = Operation.fromXDRObject(operation); + + expect(operation.body().switch().name).toBe("revokeSponsorship"); + expect(obj.type).toBe("revokeAccountSponsorship"); + + if (obj.type !== "revokeAccountSponsorship") + throw new Error("unexpected type"); + expect(obj.account).toBe(account); + }); + + it("fails with an invalid account", () => { + expect(() => + // @ts-expect-error: intentionally passing empty opts to test runtime validation + Operation.revokeAccountSponsorship({}), + ).toThrow(/account is invalid/); + + expect(() => + Operation.revokeAccountSponsorship({ account: "GBAD" }), + ).toThrow(/account is invalid/); + }); +}); + +describe("Operation.revokeTrustlineSponsorship()", () => { + it("creates a revokeTrustlineSponsorshipOp with an Asset", () => { + const asset = new Asset( + "USDUSD", + "GDGU5OAPHNPU5UCLE5RDJHG7PXZFQYWKCFOEXSXNMR6KRQRI5T6XXCD7", + ); + const op = Operation.revokeTrustlineSponsorship({ account, asset }); + const operation = xdr.Operation.fromXDR(op.toXDR("hex"), "hex"); + const obj = Operation.fromXDRObject(operation); + + expect(operation.body().switch().name).toBe("revokeSponsorship"); + expect(obj.type).toBe("revokeTrustlineSponsorship"); + }); + + it("creates a revokeTrustlineSponsorshipOp with a LiquidityPoolId", () => { + const asset = new LiquidityPoolId( + "dd7b1ab831c273310ddbec6f97870aa83c2fbd78ce22aded37ecbf4f3380fac7", + ); + const op = Operation.revokeTrustlineSponsorship({ account, asset }); + const operation = xdr.Operation.fromXDR(op.toXDR("hex"), "hex"); + const obj = Operation.fromXDRObject(operation); + + expect(operation.body().switch().name).toBe("revokeSponsorship"); + expect(obj.type).toBe("revokeTrustlineSponsorship"); + }); + + it("fails with an invalid account", () => { + expect(() => + // @ts-expect-error: intentionally passing empty opts to test runtime validation + Operation.revokeTrustlineSponsorship({}), + ).toThrow(/account is invalid/); + + expect(() => + // @ts-expect-error: intentionally omitting required asset field to test that account validation runs first + Operation.revokeTrustlineSponsorship({ account: "GBAD" }), + ).toThrow(/account is invalid/); + }); + + it("fails with an invalid asset", () => { + expect(() => + // @ts-expect-error: intentionally omitting required field to test runtime validation + Operation.revokeTrustlineSponsorship({ account }), + ).toThrow(/asset must be an Asset or LiquidityPoolId/); + }); +}); + +describe("Operation.revokeOfferSponsorship()", () => { + it("creates a revokeOfferSponsorshipOp", () => { + const seller = account; + const offerId = "1234"; + const op = Operation.revokeOfferSponsorship({ seller, offerId }); + const operation = xdr.Operation.fromXDR(op.toXDR("hex"), "hex"); + const obj = Operation.fromXDRObject(operation); + + expect(operation.body().switch().name).toBe("revokeSponsorship"); + expect(obj.type).toBe("revokeOfferSponsorship"); + + if (obj.type !== "revokeOfferSponsorship") + throw new Error("unexpected type"); + expect(obj.seller).toBe(seller); + expect(obj.offerId).toBe(offerId); + }); + + it("fails with an invalid seller", () => { + expect(() => + // @ts-expect-error: intentionally passing empty opts to test runtime validation + Operation.revokeOfferSponsorship({}), + ).toThrow(/seller is invalid/); + + expect(() => + Operation.revokeOfferSponsorship({ seller: "GBAD", offerId: "1" }), + ).toThrow(/seller is invalid/); + }); + + it("fails with a missing offerId", () => { + expect(() => + // @ts-expect-error: intentionally omitting required field to test runtime validation + Operation.revokeOfferSponsorship({ seller: account }), + ).toThrow(/offerId is invalid/); + }); +}); + +describe("Operation.revokeDataSponsorship()", () => { + it("creates a revokeDataSponsorshipOp", () => { + const name = "foo"; + const op = Operation.revokeDataSponsorship({ account, name }); + const operation = xdr.Operation.fromXDR(op.toXDR("hex"), "hex"); + const obj = Operation.fromXDRObject(operation); + + expect(operation.body().switch().name).toBe("revokeSponsorship"); + expect(obj.type).toBe("revokeDataSponsorship"); + + if (obj.type !== "revokeDataSponsorship") + throw new Error("unexpected type"); + expect(obj.account).toBe(account); + expect(obj.name).toBe(name); + }); + + it("fails with an invalid account", () => { + expect(() => + // @ts-expect-error: intentionally passing empty opts to test runtime validation + Operation.revokeDataSponsorship({}), + ).toThrow(/account is invalid/); + + expect(() => + Operation.revokeDataSponsorship({ account: "GBAD", name: "foo" }), + ).toThrow(/account is invalid/); + }); + + it("fails with a missing name", () => { + expect(() => + // @ts-expect-error: intentionally omitting required field to test runtime validation + Operation.revokeDataSponsorship({ account }), + ).toThrow(/name must be a string, up to 64 characters/); + }); + + it("fails with a name longer than 64 characters", () => { + expect(() => + Operation.revokeDataSponsorship({ account, name: "a".repeat(65) }), + ).toThrow(/name must be a string, up to 64 characters/); + }); +}); + +describe("Operation.revokeClaimableBalanceSponsorship()", () => { + it("creates a revokeClaimableBalanceSponsorshipOp", () => { + const balanceId = + "00000000da0d57da7d4850e7fc10d2a9d0ebc731f7afb40574c03395b17d49149b91f5be"; + const op = Operation.revokeClaimableBalanceSponsorship({ balanceId }); + const operation = xdr.Operation.fromXDR(op.toXDR("hex"), "hex"); + const obj = Operation.fromXDRObject(operation); + + expect(operation.body().switch().name).toBe("revokeSponsorship"); + expect(obj.type).toBe("revokeClaimableBalanceSponsorship"); + + if (obj.type !== "revokeClaimableBalanceSponsorship") + throw new Error("unexpected type"); + expect(obj.balanceId).toBe(balanceId); + }); + + it("fails with an invalid balanceId", () => { + expect(() => + // @ts-expect-error: intentionally passing empty opts to test runtime validation + Operation.revokeClaimableBalanceSponsorship({}), + ).toThrow(/balanceId is invalid/); + }); +}); + +describe("Operation.revokeLiquidityPoolSponsorship()", () => { + it("creates a revokeLiquidityPoolSponsorshipOp", () => { + const liquidityPoolId = + "dd7b1ab831c273310ddbec6f97870aa83c2fbd78ce22aded37ecbf4f3380fac7"; + const op = Operation.revokeLiquidityPoolSponsorship({ liquidityPoolId }); + const operation = xdr.Operation.fromXDR(op.toXDR("hex"), "hex"); + const obj = Operation.fromXDRObject(operation); + + expect(operation.body().switch().name).toBe("revokeSponsorship"); + expect(obj.type).toBe("revokeLiquidityPoolSponsorship"); + + if (obj.type !== "revokeLiquidityPoolSponsorship") + throw new Error("unexpected type"); + expect(obj.liquidityPoolId).toBe(liquidityPoolId); + }); + + it("fails with an invalid liquidityPoolId", () => { + expect(() => + // @ts-expect-error: intentionally passing empty opts to test runtime validation + Operation.revokeLiquidityPoolSponsorship({}), + ).toThrow(/liquidityPoolId is invalid/); + }); +}); + +describe("Operation.revokeSignerSponsorship()", () => { + it("creates a revokeSignerSponsorshipOp with an ed25519PublicKey signer", () => { + const signer = { ed25519PublicKey: account }; + const op = Operation.revokeSignerSponsorship({ account, signer }); + const operation = xdr.Operation.fromXDR(op.toXDR("hex"), "hex"); + const obj = Operation.fromXDRObject(operation); + + expect(operation.body().switch().name).toBe("revokeSponsorship"); + expect(obj.type).toBe("revokeSignerSponsorship"); + + if (obj.type !== "revokeSignerSponsorship") + throw new Error("unexpected type"); + expect(obj.account).toBe(account); + expect(obj.signer.ed25519PublicKey).toBe(signer.ed25519PublicKey); + }); + + it("creates a revokeSignerSponsorshipOp with a preAuthTx signer", () => { + const signer = { preAuthTx: hash(Buffer.from("Tx hash")).toString("hex") }; + const op = Operation.revokeSignerSponsorship({ account, signer }); + const obj = Operation.fromXDRObject( + xdr.Operation.fromXDR(op.toXDR("hex"), "hex"), + ); + + expect(obj.type).toBe("revokeSignerSponsorship"); + + if (obj.type !== "revokeSignerSponsorship") + throw new Error("unexpected type"); + expect(obj.account).toBe(account); + expect(obj.signer.preAuthTx).toBe(signer.preAuthTx); + }); + + it("creates a revokeSignerSponsorshipOp with a sha256Hash signer", () => { + const signer = { + sha256Hash: hash(Buffer.from("Hash Preimage")).toString("hex"), + }; + const op = Operation.revokeSignerSponsorship({ account, signer }); + const obj = Operation.fromXDRObject( + xdr.Operation.fromXDR(op.toXDR("hex"), "hex"), + ); + + expect(obj.type).toBe("revokeSignerSponsorship"); + + if (obj.type !== "revokeSignerSponsorship") + throw new Error("unexpected type"); + expect(obj.account).toBe(account); + expect(obj.signer.sha256Hash).toBe(signer.sha256Hash); + }); + + it("fails with an invalid account", () => { + const signer = { ed25519PublicKey: source }; + expect(() => + // @ts-expect-error: intentionally omitting required field to test runtime validation + Operation.revokeSignerSponsorship({ signer }), + ).toThrow(/account is invalid/); + }); + + it("fails with an invalid ed25519PublicKey signer", () => { + expect(() => + Operation.revokeSignerSponsorship({ + account, + signer: { ed25519PublicKey: "GBAD" }, + }), + ).toThrow(/signer\.ed25519PublicKey is invalid/); + }); + + it("fails with an unrecognized signer type", () => { + expect(() => + Operation.revokeSignerSponsorship({ + account, + signer: {}, + }), + ).toThrow(/signer is invalid/); + }); +});