Skip to content

feat(sdk-coin-canton): added message signing builders for canton#8962

Merged
ravibitgo merged 1 commit into
masterfrom
CHALO-545
Jun 8, 2026
Merged

feat(sdk-coin-canton): added message signing builders for canton#8962
ravibitgo merged 1 commit into
masterfrom
CHALO-545

Conversation

@ravibitgo

Copy link
Copy Markdown
Contributor

Ticket: CHALO-545

@linear-code

linear-code Bot commented Jun 8, 2026

Copy link
Copy Markdown

CHALO-545

@bhavidhingra bhavidhingra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issues

Medium — Missing error boundary on decodePreparedTransaction

clearSigning.ts — no guard against calling this with topology bytes. utils.extractCantonCommandInfo will throw if proto parsing fails, and the caller gets an unhandled exception. The JSDoc says "Only meaningful when detectCantonSigningPayloadType() returns CANTON_SIGN_TRANSACTION" but that is documentation, not enforcement. Should either:

  • Throw a descriptive error: throw new Error("Not a PreparedTransaction — call detectCantonSigningPayloadType first")
  • Or add a test for the invalid-input path so the failure mode is documented

Medium — Duplicate getSignablePayload implementation

cantonSignTransactionMessage.ts and cantonSignTopologyMessage.ts have byte-for-byte identical getSignablePayload() bodies:

this.signablePayload = Buffer.from(this.payload, "base64");
return this.signablePayload;

The only difference between the two classes is the type passed to super(). Consider extracting to a shared CantonBaseMessage extends BaseMessage to avoid future drift.

Low — @ts-ignore → prefer @ts-expect-error

clearSigning.ts:3:

// @ts-ignore – JS resource with hand-written .d.ts

@ts-expect-error will error if the suppression becomes unnecessary (e.g. when the .d.ts is replaced with proper types), making the tech debt visible.

Low — Redundant test

In canton.ts, the test "tcanton should also return true" fetches tcanton again, but before() already sets basecoin = bitgo.coin("tcanton"). Two tests asserting the same inherited method on the same coin instance.


Positives

  • Clean factory pattern — getMessageBuilder switch + clear error on unsupported type
  • Payload-type detection via try/catch on proto parse is the right approach (nodes-length check is correct discriminator since proto is permissive)
  • JSDoc on clearSigning.ts is genuinely useful — explains the HSM format split clearly
  • Good edge case test coverage (empty bytes, random bytes, proto parse failure)

@ravibitgo ravibitgo marked this pull request as ready for review June 8, 2026 10:26
@ravibitgo ravibitgo requested review from a team as code owners June 8, 2026 10:26

@bhavidhingra bhavidhingra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remaining Nits

Nit — Double proto parse in decodePreparedTransaction happy path

clearSigning.ts — the guard calls detectCantonSigningPayloadType() (which parses the proto via PreparedTransaction.fromBinary), then utils.extractCantonCommandInfo() parses the same bytes a second time. For invalid input the guard throws early so no waste, but valid input pays two full proto decodes. Not a correctness issue, but worth noting if Canton transactions are large. Could be addressed by combining into a single parse-and-decode function if perf ever matters.

Nit — Unnecessary constructor in CantonBaseMessage

cantonBaseMessage.ts:15-17 — the constructor only calls super(options) with no other logic. TypeScript synthesizes this automatically; the explicit constructor is dead weight and can be removed.


Summary

Both are nits, not blockers. The core logic is solid — error guard, base class extraction, and test coverage for invalid input are all well done. LGTM otherwise.

@bhavidhingra bhavidhingra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Two minor observations (not blocking):

  • MessageBuilderFactory pass-through constructor — same pattern that was cleaned up in CantonBaseMessage; constructor(coinConfig) { super(coinConfig); } can be removed since TypeScript synthesizes it.

  • Misleading test namecantonSignTopologyMessage.ts: "should produce same byte structure as CANTON_SIGN_TRANSACTION for equivalent hash" only instantiates CantonSignTopologyMessage; never creates a CantonSignTransactionMessage to compare against. The assertion is correct but the name implies a cross-type comparison that does not happen.

Approving.

@ravibitgo ravibitgo merged commit 6ddc3e5 into master Jun 8, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants