Skip to content

Commit 2a46648

Browse files
authored
Merge pull request #115 from BitGo/BTC-2929-ui-signatures
feat(webui): add signatures display to transaction parser
2 parents 171820c + 85da6ab commit 2a46648

1 file changed

Lines changed: 107 additions & 1 deletion

File tree

  • packages/webui/src/wasm-solana/transaction

packages/webui/src/wasm-solana/transaction/index.ts

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,75 @@ class SolanaTransactionParser extends BaseComponent {
323323
color: var(--bg);
324324
}
325325
326+
.signatures-section {
327+
margin-bottom: 2rem;
328+
}
329+
330+
.signatures-section h2 {
331+
font-size: 1rem;
332+
margin-bottom: 1rem;
333+
color: var(--muted, #8b949e);
334+
}
335+
336+
.signatures-list {
337+
padding: 1rem;
338+
background: var(--surface, #161b22);
339+
border: 1px solid var(--border, #30363d);
340+
border-radius: 6px;
341+
}
342+
343+
.signature-item {
344+
display: flex;
345+
align-items: center;
346+
gap: 0.75rem;
347+
padding: 0.375rem 0;
348+
font-size: 0.8125rem;
349+
}
350+
351+
.signature-item:not(:last-child) {
352+
border-bottom: 1px solid var(--border, #30363d);
353+
}
354+
355+
.signature-index {
356+
font-size: 0.75rem;
357+
padding: 0.125rem 0.5rem;
358+
background: var(--border, #30363d);
359+
border-radius: 4px;
360+
color: var(--muted, #8b949e);
361+
min-width: 2rem;
362+
text-align: center;
363+
}
364+
365+
.signature-value {
366+
font-family: var(--mono);
367+
word-break: break-all;
368+
color: var(--fg, #c9d1d9);
369+
font-size: 0.75rem;
370+
}
371+
372+
.signature-item.unsigned .signature-value {
373+
color: var(--muted, #8b949e);
374+
font-style: italic;
375+
}
376+
377+
.signature-badge {
378+
font-size: 0.625rem;
379+
padding: 0.125rem 0.375rem;
380+
border-radius: 3px;
381+
text-transform: uppercase;
382+
font-weight: 500;
383+
}
384+
385+
.signature-badge.signed {
386+
background: var(--green);
387+
color: var(--bg);
388+
}
389+
390+
.signature-badge.unsigned {
391+
background: var(--muted);
392+
color: var(--bg);
393+
}
394+
326395
@media (max-width: 768px) {
327396
.tx-info-grid,
328397
.instruction-params {
@@ -379,6 +448,7 @@ class SolanaTransactionParser extends BaseComponent {
379448
),
380449
h("div", { id: "error-message" }),
381450
h("div", { id: "tx-info" }),
451+
h("div", { id: "signatures" }),
382452
h("div", { id: "account-keys" }),
383453
h(
384454
"div",
@@ -431,14 +501,16 @@ class SolanaTransactionParser extends BaseComponent {
431501
private parse(txData: string): void {
432502
const errorEl = this.$("#error-message");
433503
const txInfoEl = this.$("#tx-info");
504+
const signaturesEl = this.$("#signatures");
434505
const accountKeysEl = this.$("#account-keys");
435506
const resultsEl = this.$("#results");
436507

437-
if (!errorEl || !txInfoEl || !accountKeysEl || !resultsEl) return;
508+
if (!errorEl || !txInfoEl || !signaturesEl || !accountKeysEl || !resultsEl) return;
438509

439510
// Clear previous state
440511
errorEl.innerHTML = "";
441512
txInfoEl.innerHTML = "";
513+
signaturesEl.innerHTML = "";
442514
accountKeysEl.innerHTML = "";
443515

444516
try {
@@ -449,6 +521,9 @@ class SolanaTransactionParser extends BaseComponent {
449521
// Render transaction info
450522
txInfoEl.replaceChildren(this.renderTxInfo(parsed));
451523

524+
// Render signatures
525+
signaturesEl.replaceChildren(this.renderSignatures(parsed));
526+
452527
// Render account keys
453528
accountKeysEl.replaceChildren(this.renderAccountKeys(parsed));
454529

@@ -499,6 +574,35 @@ class SolanaTransactionParser extends BaseComponent {
499574
return h("div", { class: "tx-info" }, h("div", { class: "tx-info-grid" }, ...children));
500575
}
501576

577+
private renderSignatures(parsed: ParsedTransaction): HTMLElement {
578+
// All-zero signature in base58 (64 zero bytes)
579+
const UNSIGNED_SIGNATURE = "1111111111111111111111111111111111111111111111111111111111111111";
580+
581+
return h(
582+
"section",
583+
{ class: "signatures-section" },
584+
h("h2", {}, `Signatures (${parsed.signatures.length})`),
585+
h(
586+
"div",
587+
{ class: "signatures-list" },
588+
...parsed.signatures.map((sig, idx) => {
589+
const isSigned = sig !== UNSIGNED_SIGNATURE;
590+
return h(
591+
"div",
592+
{ class: `signature-item${isSigned ? "" : " unsigned"}` },
593+
h("span", { class: "signature-index" }, String(idx)),
594+
h("span", { class: "signature-value" }, isSigned ? sig : "(not signed)"),
595+
h(
596+
"span",
597+
{ class: `signature-badge ${isSigned ? "signed" : "unsigned"}` },
598+
isSigned ? "Signed" : "Pending",
599+
),
600+
);
601+
}),
602+
),
603+
);
604+
}
605+
502606
private renderAccountKeys(parsed: ParsedTransaction): HTMLElement {
503607
const feePayer = parsed.feePayer;
504608

@@ -575,11 +679,13 @@ class SolanaTransactionParser extends BaseComponent {
575679
private showEmpty(): void {
576680
const errorEl = this.$("#error-message");
577681
const txInfoEl = this.$("#tx-info");
682+
const signaturesEl = this.$("#signatures");
578683
const accountKeysEl = this.$("#account-keys");
579684
const resultsEl = this.$("#results");
580685

581686
if (errorEl) errorEl.innerHTML = "";
582687
if (txInfoEl) txInfoEl.innerHTML = "";
688+
if (signaturesEl) signaturesEl.innerHTML = "";
583689
if (accountKeysEl) accountKeysEl.innerHTML = "";
584690
if (resultsEl) {
585691
resultsEl.replaceChildren(

0 commit comments

Comments
 (0)