-
Notifications
You must be signed in to change notification settings - Fork 27
feat(docs): improve CBOR decoder tool UI and add data decoder option #65
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,12 +1,15 @@ | ||||||
| 'use client' | ||||||
|
|
||||||
| import { useState } from 'react' | ||||||
| import { Core } from "@evolution-sdk/evolution" | ||||||
| import { Core, Schema } from "@evolution-sdk/evolution" | ||||||
|
|
||||||
| type DecodeType = 'transaction' | 'witnessSet' | 'data' | ||||||
|
|
||||||
| export function TransactionDecoder() { | ||||||
| const [txHex, setTxHex] = useState("") | ||||||
| const [decodedJson, setDecodedJson] = useState<string>("") | ||||||
| const [error, setError] = useState<string | null>(null) | ||||||
| const [decodeType, setDecodeType] = useState<DecodeType>('transaction') | ||||||
|
|
||||||
| const decodeTx = async () => { | ||||||
| setError(null) | ||||||
|
|
@@ -16,60 +19,114 @@ export function TransactionDecoder() { | |||||
| const cleanHex = txHex.trim().replace(/\s+/g, '') | ||||||
|
|
||||||
| if (!cleanHex) { | ||||||
| setError("Please enter a transaction CBOR hex string") | ||||||
| setError(`Please enter a ${decodeType === 'transaction' ? 'transaction' : decodeType === 'witnessSet' ? 'transaction witness set' : 'plutus data'} CBOR hex string`) | ||||||
| return | ||||||
| } | ||||||
|
|
||||||
| const tx = Core.Transaction.fromCBORHex(cleanHex) | ||||||
| const json = JSON.stringify(tx.toJSON(), (key, value) => | ||||||
| typeof value === 'bigint' ? value.toString() : value | ||||||
| , 2) | ||||||
| setDecodedJson(json) | ||||||
| if (decodeType === 'transaction') { | ||||||
| const tx = Core.Transaction.fromCBORHex(cleanHex) | ||||||
| const json = Schema.encodeSync(Schema.parseJson(Core.Transaction.Transaction, {space: 2}))(tx) | ||||||
| setDecodedJson(json) | ||||||
| } else if (decodeType === 'witnessSet') { | ||||||
| const witnessSet = Core.TransactionWitnessSet.fromCBORHex(cleanHex) | ||||||
| const json = Schema.encodeSync(Schema.parseJson(Core.TransactionWitnessSet.TransactionWitnessSet, {space: 2}))(witnessSet) | ||||||
| setDecodedJson(json) | ||||||
| } else { | ||||||
| const data = Core.Data.fromCBORHex(cleanHex) | ||||||
| const json = Schema.encodeSync(Schema.parseJson(Core.Data.DataSchema, {space: 2}))(data) | ||||||
| setDecodedJson(json) | ||||||
| } | ||||||
| } catch (err) { | ||||||
| console.error('Decode error:', err) | ||||||
| setError(err instanceof Error ? err.message : "Failed to decode transaction") | ||||||
| setError(err instanceof Error ? err.message : `Failed to decode ${decodeType === 'transaction' ? 'transaction' : decodeType === 'witnessSet' ? 'witness set' : 'data'}`) | ||||||
|
Comment on lines
+22
to
+41
|
||||||
| } | ||||||
| } | ||||||
|
|
||||||
| return ( | ||||||
| <div className="space-y-6"> | ||||||
| <div className="space-y-4"> | ||||||
| <button | ||||||
| onClick={decodeTx} | ||||||
| className="px-4 py-2 bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors" | ||||||
| > | ||||||
| Decode Transaction | ||||||
| </button> | ||||||
|
|
||||||
| <div className="space-y-2"> | ||||||
| <label htmlFor="tx-hex" className="block text-sm font-medium"> | ||||||
| Transaction CBOR Hex | ||||||
| </label> | ||||||
| <textarea | ||||||
| id="tx-hex" | ||||||
| value={txHex} | ||||||
| onChange={(e) => setTxHex(e.target.value)} | ||||||
| placeholder="Paste transaction CBOR hex here..." | ||||||
| className="w-full h-32 px-3 py-2 bg-background border border-border rounded-md font-mono text-sm resize-y focus:outline-none focus:ring-2 focus:ring-ring" | ||||||
| /> | ||||||
| <div className="max-w-6xl mx-auto space-y-6"> | ||||||
| <div className="rounded-lg border bg-card text-card-foreground shadow-sm"> | ||||||
| <div className="p-6 space-y-6"> | ||||||
| <div className="flex items-center justify-between"> | ||||||
| <div className="space-y-1"> | ||||||
| <h3 className="text-2xl font-semibold tracking-tight">CBOR Decoder</h3> | ||||||
| <p className="text-sm text-muted-foreground">Decode Cardano CBOR hex strings</p> | ||||||
| </div> | ||||||
| </div> | ||||||
|
|
||||||
| <div className="space-y-4"> | ||||||
| <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4"> | ||||||
| <div className="space-y-2"> | ||||||
| <label htmlFor="decode-type" className="text-sm font-medium leading-none"> | ||||||
| Type | ||||||
| </label> | ||||||
| <select | ||||||
| id="decode-type" | ||||||
| value={decodeType} | ||||||
| onChange={(e) => setDecodeType(e.target.value as DecodeType)} | ||||||
| className="flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring" | ||||||
| > | ||||||
| <option value="transaction">Transaction</option> | ||||||
| <option value="witnessSet">Transaction Witness Set</option> | ||||||
| <option value="data">Plutus Data</option> | ||||||
| </select> | ||||||
|
Comment on lines
+62
to
+71
|
||||||
| </div> | ||||||
| </div> | ||||||
|
|
||||||
| <div className="space-y-2"> | ||||||
| <label htmlFor="tx-hex" className="text-sm font-medium leading-none"> | ||||||
| CBOR Hex Input | ||||||
| </label> | ||||||
| <textarea | ||||||
| id="tx-hex" | ||||||
| value={txHex} | ||||||
| onChange={(e) => setTxHex(e.target.value)} | ||||||
| placeholder={`Paste ${decodeType === 'transaction' ? 'transaction' : decodeType === 'witnessSet' ? 'transaction witness set' : 'plutus data'} CBOR hex here...`} | ||||||
| className="flex min-h-[120px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm font-mono resize-y focus:outline-none focus:ring-2 focus:ring-ring" | ||||||
| /> | ||||||
| </div> | ||||||
|
|
||||||
| <button | ||||||
| onClick={decodeTx} | ||||||
| className="sm:w-auto w-full inline-flex items-center justify-center rounded-md text-sm font-medium h-9 px-6 py-2 bg-zinc-700 text-white hover:bg-zinc-600 active:bg-zinc-500 transition-all cursor-pointer shadow-sm hover:shadow" | ||||||
| > | ||||||
| Decode {decodeType === 'transaction' ? 'Transaction' : decodeType === 'witnessSet' ? 'Witness Set' : 'Data'} | ||||||
| </button> | ||||||
| </div> | ||||||
| </div> | ||||||
| </div> | ||||||
|
|
||||||
| {error && ( | ||||||
| <div className="p-4 bg-destructive/10 border border-destructive/20 rounded-md"> | ||||||
| <p className="text-destructive font-medium">Error decoding transaction:</p> | ||||||
| <p className="text-destructive/80 text-sm mt-1">{error}</p> | ||||||
| <div className="rounded-lg border bg-card text-card-foreground shadow-sm"> | ||||||
| <div className="p-6"> | ||||||
| <div className="flex gap-3"> | ||||||
| <svg className="h-5 w-5 text-destructive shrink-0 mt-0.5" viewBox="0 0 20 20" fill="currentColor"> | ||||||
| <path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clipRule="evenodd" /> | ||||||
| </svg> | ||||||
| <div className="flex-1 min-w-0 space-y-2"> | ||||||
| <p className="text-sm font-medium text-destructive">Error decoding {decodeType === 'transaction' ? 'transaction' : decodeType === 'witnessSet' ? 'witness set' : 'data'}</p> | ||||||
| <pre className="text-xs text-muted-foreground whitespace-pre-wrap break-words overflow-wrap-anywhere font-mono">{error}</pre> | ||||||
|
||||||
| <pre className="text-xs text-muted-foreground whitespace-pre-wrap break-words overflow-wrap-anywhere font-mono">{error}</pre> | |
| <pre className="text-xs text-muted-foreground whitespace-pre-wrap break-words font-mono">{error}</pre> |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -20,8 +20,6 @@ parent: Modules | |||||
| - [int](#int) | ||||||
| - [list](#list) | ||||||
| - [map](#map) | ||||||
| - [either](#either) | ||||||
| - [Either (namespace)](#either-namespace) | ||||||
| - [equality](#equality) | ||||||
| - [equals](#equals) | ||||||
| - [hash](#hash) | ||||||
|
|
@@ -71,6 +69,7 @@ parent: Modules | |||||
| - [utils](#utils) | ||||||
| - [ByteArray (type alias)](#bytearray-type-alias) | ||||||
| - [CDDLSchema](#cddlschema) | ||||||
| - [DataSchema (interface)](#dataschema-interface) | ||||||
| - [Int (type alias)](#int-type-alias) | ||||||
|
|
||||||
| --- | ||||||
|
|
@@ -88,12 +87,12 @@ export declare const withSchema: <A, I extends Data>( | |||||
| schema: Schema.Schema<A, I>, | ||||||
| options?: CBOR.CodecOptions | ||||||
| ) => { | ||||||
| toData: (input: A) => I | ||||||
| fromData: (input: I) => A | ||||||
| toCBORHex: (input: A, options?: CBOR.CodecOptions) => string | ||||||
| toCBORBytes: (input: A, options?: CBOR.CodecOptions) => Uint8Array | ||||||
| fromCBORHex: (hex: string, options?: CBOR.CodecOptions) => A | ||||||
| fromCBORBytes: (bytes: Uint8Array, options?: CBOR.CodecOptions) => A | ||||||
| toData: (a: A, overrideOptions?: ParseOptions) => I | ||||||
| fromData: (i: I, overrideOptions?: ParseOptions) => A | ||||||
| toCBORHex: (a: A, overrideOptions?: ParseOptions) => string | ||||||
| toCBORBytes: (a: A, overrideOptions?: ParseOptions) => any | ||||||
|
||||||
| toCBORBytes: (a: A, overrideOptions?: ParseOptions) => any | |
| toCBORBytes: (a: A, overrideOptions?: ParseOptions) => Uint8Array |
Copilot
AI
Nov 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The parameter type for fromCBORBytes has been changed from Uint8Array to any, which removes input type safety. This allows any type to be passed without compile-time validation, potentially leading to runtime errors. The parameter should be typed as Uint8Array to maintain API safety and catch errors at compile time.
| fromCBORBytes: (i: any, overrideOptions?: ParseOptions) => A | |
| fromCBORBytes: (i: Uint8Array, overrideOptions?: ParseOptions) => A |
Copilot
AI
Nov 21, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The return type of toCBORBytes has been changed from Uint8Array to any, which removes type safety. This is inconsistent with the function's purpose of encoding data to CBOR bytes. The return type should be Uint8Array to provide proper type guarantees to API consumers.
| export declare const toCBORBytes: (data: Data, options?: CBOR.CodecOptions) => any | |
| export declare const toCBORBytes: (data: Data, options?: CBOR.CodecOptions) => Uint8Array |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
decodeTxfunction is declared asasyncbut doesn't useawaitanywhere in its body. The function performs only synchronous operations (decoding CBOR, encoding to JSON, and setting state). Remove theasynckeyword to accurately reflect the function's behavior.