Files
CurrenciCombo/orchestrator/tests/unit/notaryChain.test.ts
Devin 5bd6a200c3
Some checks failed
Code Quality / SonarQube Analysis (pull_request) Failing after 20s
Code Quality / Code Quality Checks (pull_request) Failing after 8s
Security Scan / Dependency Vulnerability Scan (pull_request) Failing after 3s
Security Scan / OWASP ZAP Scan (pull_request) Failing after 4s
PR C: wire real NotaryRegistry contract on Chain 138 (arch step 4)
- services/notaryChain.ts: new ethers-v6 adapter speaking to the
  deployed NotaryRegistry.sol via CHAIN_138_RPC_URL +
  NOTARY_REGISTRY_ADDRESS + ORCHESTRATOR_PRIVATE_KEY. Exposes
  anchorPlan(plan) -> { mode, txHash, planHash, blockNumber } and
  finalizeAnchor(planId, success) -> { mode, txHash, receiptHash }
  with deterministic mock fallback when envs are absent.
- services/notary.ts: refactored to delegate to notaryChain; preserves
  the prior signature and returns extra on-chain fields (mode, txHash,
  blockNumber, contractAddress) when the anchor lands.
- config/env.ts: add CHAIN_138_RPC_URL, CHAIN_138_CHAIN_ID,
  NOTARY_REGISTRY_ADDRESS, ORCHESTRATOR_PRIVATE_KEY (all optional,
  validated via regex where applicable).
- package.json: add ethers@^6.11.0 dependency.
- tests/unit/notaryChain.test.ts: 6 tests covering deterministic
  hashing helpers and the mock fallback path.

tsc clean. 51 tests pass (45 pre-existing + 6 new).
2026-04-22 16:33:06 +00:00

63 lines
2.0 KiB
TypeScript

import { describe, it, expect, beforeEach } from "@jest/globals";
import {
__resetForTests,
anchorPlan,
computePlanHash,
finalizeAnchor,
planIdToBytes32,
} from "../../src/services/notaryChain";
import type { Plan } from "../../src/types/plan";
const FIXTURE_PLAN: Plan = {
plan_id: "11111111-2222-3333-4444-555555555555",
creator: "0xabc",
steps: [{ type: "pay", amount: 100, asset: "USD" }],
};
describe("NotaryChain adapter", () => {
beforeEach(() => __resetForTests());
describe("helpers", () => {
it("planIdToBytes32 is deterministic and 32 bytes", () => {
const a = planIdToBytes32("p-1");
const b = planIdToBytes32("p-1");
expect(a).toBe(b);
expect(a).toMatch(/^0x[0-9a-f]{64}$/);
});
it("planIdToBytes32 collision-resistant across different ids", () => {
expect(planIdToBytes32("a")).not.toBe(planIdToBytes32("b"));
});
it("computePlanHash is deterministic and sha256", () => {
const h1 = computePlanHash(FIXTURE_PLAN);
const h2 = computePlanHash(FIXTURE_PLAN);
expect(h1).toBe(h2);
expect(h1).toMatch(/^0x[0-9a-f]{64}$/);
});
});
describe("mock fallback (envs unset)", () => {
it("anchorPlan returns mode=mock with planHash when unconfigured", async () => {
const result = await anchorPlan(FIXTURE_PLAN, {});
expect(result.mode).toBe("mock");
expect(result.planHash).toMatch(/^0x[0-9a-f]{64}$/);
expect(result.txHash).toBeUndefined();
});
it("finalizeAnchor returns mode=mock when unconfigured", async () => {
const result = await finalizeAnchor(FIXTURE_PLAN.plan_id!, true, {});
expect(result.mode).toBe("mock");
expect(result.txHash).toBeUndefined();
});
it("anchorPlan stays on the mock path when only some envs are set", async () => {
const result = await anchorPlan(FIXTURE_PLAN, {
rpcUrl: "https://rpc.d-bis.org",
// contractAddress + privateKey missing
});
expect(result.mode).toBe("mock");
});
});
});