|
| 1 | +import { describe, expect, test } from "bun:test"; |
| 2 | +import { Wallet, decodeAccountID } from "xrpl"; |
| 3 | +import { validateRAddress } from "../xrpl/helpers"; |
| 4 | +import { |
| 5 | + deriveSignerEntries, |
| 6 | + parseManagerSet, |
| 7 | + signerEntriesFromAddresses, |
| 8 | +} from "../xrpl/manager-set"; |
| 9 | + |
| 10 | +describe("validateRAddress", () => { |
| 11 | + test("accepts a valid classic address", () => { |
| 12 | + expect(validateRAddress("r9qAVHiq4gNPFJTHduy7fWEgUPvre2VLpG")).toBe( |
| 13 | + "r9qAVHiq4gNPFJTHduy7fWEgUPvre2VLpG" |
| 14 | + ); |
| 15 | + }); |
| 16 | + |
| 17 | + test("rejects an invalid address", () => { |
| 18 | + expect(() => validateRAddress("not-an-address")).toThrow(/Invalid XRPL/); |
| 19 | + }); |
| 20 | +}); |
| 21 | + |
| 22 | +describe("parseManagerSet", () => { |
| 23 | + function pk(byte: number): Buffer { |
| 24 | + const b = Buffer.alloc(33, byte); |
| 25 | + b[0] = 0x02; // compressed-key prefix-ish (value irrelevant to parsing) |
| 26 | + return b; |
| 27 | + } |
| 28 | + |
| 29 | + test("parses version, threshold, total and 33-byte pubkeys", () => { |
| 30 | + const header = Buffer.from([1, 2, 3]); // version 1, mThreshold 2, nTotal 3 |
| 31 | + const body = Buffer.concat([pk(0xaa), pk(0xbb), pk(0xcc)]); |
| 32 | + const set = parseManagerSet(Buffer.concat([header, body])); |
| 33 | + expect(set.mThreshold).toBe(2); |
| 34 | + expect(set.nTotal).toBe(3); |
| 35 | + expect(set.pubkeys.length).toBe(3); |
| 36 | + expect(set.pubkeys[0].length).toBe(33); |
| 37 | + }); |
| 38 | + |
| 39 | + test("rejects a bad version", () => { |
| 40 | + expect(() => parseManagerSet(Buffer.from([0, 1, 0]))).toThrow(/version/); |
| 41 | + }); |
| 42 | + |
| 43 | + test("rejects truncated pubkey data", () => { |
| 44 | + // nTotal says 2 but only one 33-byte key follows |
| 45 | + const buf = Buffer.concat([Buffer.from([1, 1, 2]), Buffer.alloc(33)]); |
| 46 | + expect(() => parseManagerSet(buf)).toThrow(/expected/); |
| 47 | + }); |
| 48 | +}); |
| 49 | + |
| 50 | +describe("signer entries", () => { |
| 51 | + test("deriveSignerEntries: pubkey -> account, weight 1, sorted", () => { |
| 52 | + const w1 = Wallet.generate(); |
| 53 | + const w2 = Wallet.generate(); |
| 54 | + const entries = deriveSignerEntries([ |
| 55 | + Buffer.from(w1.publicKey, "hex"), |
| 56 | + Buffer.from(w2.publicKey, "hex"), |
| 57 | + ]); |
| 58 | + // derived accounts match the wallets' classic addresses |
| 59 | + const accounts = entries.map((e) => e.SignerEntry.Account); |
| 60 | + expect(accounts).toContain(w1.classicAddress); |
| 61 | + expect(accounts).toContain(w2.classicAddress); |
| 62 | + expect(entries.every((e) => e.SignerEntry.SignerWeight === 1)).toBe(true); |
| 63 | + // sorted ascending by account ID |
| 64 | + const ids = accounts.map((a) => Buffer.from(decodeAccountID(a))); |
| 65 | + expect(Buffer.compare(ids[0], ids[1])).toBeLessThanOrEqual(0); |
| 66 | + }); |
| 67 | + |
| 68 | + test("signerEntriesFromAddresses: trims, weight 1, sorted", () => { |
| 69 | + const a = "r9qAVHiq4gNPFJTHduy7fWEgUPvre2VLpG"; |
| 70 | + const b = "rMxCKbEDwqr76QuheSUMdEGf4B9xJ8m5De"; |
| 71 | + const entries = signerEntriesFromAddresses([` ${a} `, b]); |
| 72 | + expect(entries.length).toBe(2); |
| 73 | + expect(entries.every((e) => e.SignerEntry.SignerWeight === 1)).toBe(true); |
| 74 | + const ids = entries.map((e) => |
| 75 | + Buffer.from(decodeAccountID(e.SignerEntry.Account)) |
| 76 | + ); |
| 77 | + expect(Buffer.compare(ids[0], ids[1])).toBeLessThanOrEqual(0); |
| 78 | + }); |
| 79 | +}); |
0 commit comments