Skip to content

Add deployment history log to the editor #16

Description

@Pvsaint

Summary

After deploying a contract, users have no record of what was deployed, to which network, when, or how the on-chain transaction resolved. This issue builds a full deployment history system with persistent storage, Stellar Explorer deep-links, transaction status polling, and the ability to re-inspect a past deployment in the contract inspector.

Why This Is Hard

  • Transaction status is async: at the moment of a successful deployContract() call the transaction may still be PENDING on-chain. The history system must store the initial record immediately, then poll GET /transaction/:hash in the background and update the record when the status resolves to SUCCESS or FAILED.
  • Storage schema versioning: localStorage is long-lived. The schema for deployment records will evolve. The system must include a schema version field and a migration function so records written today still load correctly after future updates.
  • Re-inspection link: each history entry must link back to /inspect/[contractId] (see issue Build a read-only contract inspector / viewer #18) — but the inspector needs the network context, so the history record must persist the network alongside the contract ID.
  • WASM hash tracking: the record should store the sourceHash from the compile response so users can verify which graph version produced a given deployment. This requires passing sourceHash from compileContract() all the way through to deployContract() and up to the history writer.
  • Data integrity: history records contain sensitive-ish data (wallet address, contract IDs). The size of localStorage is bounded (~5 MB). The system must cap records at a configurable max (default: 50) and evict oldest-first when the cap is reached.

Proposed Design

Storage layer (src/lib/editor/deploymentHistory.ts)

export type DeploymentStatus = "pending" | "success" | "failed"

export interface DeploymentRecord {
  id: string                   // uuid
  version: 1                   // schema version
  timestamp: number            // Date.now() at submission
  network: StellarNetwork
  contractId: string
  txHash: string | null
  status: DeploymentStatus
  sourceHash: string           // from CompileResponse.sourceHash
  walletAddress: string
  graphNodeCount: number
}

export function appendDeploymentRecord(record: Omit<DeploymentRecord, "id" | "version">): DeploymentRecord
export function loadDeploymentHistory(): DeploymentRecord[]
export function updateDeploymentStatus(id: string, status: DeploymentStatus): void
export function deleteDeploymentRecord(id: string): void
export function clearDeploymentHistory(): void

Records are stored as a JSON array under lumens-block:deployments. Cap at 50 entries; evict oldest on overflow.

Status poller (src/lib/stellar/txPoller.ts)

export function pollTransactionStatus(
  txHash: string,
  network: StellarNetwork,
  onResult: (status: "success" | "failed") => void,
  options?: { intervalMs?: number; maxAttempts?: number }
): () => void   // returns a cancel function
  • Polls SorobanRpc.Server.getTransaction(txHash) every 2 seconds.
  • Stops after 60 attempts (2 minutes) and marks the record as "failed" on timeout.
  • Returns a cancel function that clears the interval — must be called on component unmount.

DeploymentHistory component (src/components/editor/DeploymentHistory.tsx)

  • Slide-out drawer (right-side, 380 px), opened by a History button in the Toolbar.
  • Each record shows:
    • Status icon: spinner (pending), green tick (success), red X (failed)
    • Relative timestamp ("2 minutes ago") via Intl.RelativeTimeFormat
    • Network badge (Testnet / Mainnet)
    • Truncated contract ID + copy button
    • Tx hash truncated + Stellar Expert link (correct network URL)
    • Graph size ("7 nodes")
    • Inspect button → navigates to /inspect/[contractId]?network=[network]
    • Delete button (trash icon, confirm on click)
  • Empty state: "No deployments yet. Deploy a contract to see it here."
  • Clear All button at the bottom, gated by a confirmation dialog.

Integration (DeployButton.tsx)

After deployContract() resolves:

  1. Call appendDeploymentRecord(...) with the result.
  2. Call pollTransactionStatus(txHash, network, (status) => updateDeploymentStatus(id, status)).
  3. Store the cancel function and call it on component unmount.

Acceptance Criteria

  • DeploymentRecord schema includes all required fields plus version: 1.
  • Records are persisted to localStorage and survive page refresh.
  • The record cap (50 entries) is enforced; oldest entry is evicted when exceeded.
  • pollTransactionStatus updates a pending record to success or failed after the transaction resolves.
  • The poller is cancelled on component unmount (no memory leak).
  • The history drawer shows the correct status icon (spinner / tick / X) per record.
  • Contract ID and tx hash are copyable with a single click (copy-to-clipboard + "Copied!" tooltip).
  • Stellar Expert links open https://stellar.expert/explorer/[network]/tx/[hash] on the correct network.
  • Inspect button navigates to /inspect/[contractId]?network=[network].
  • Individual records and all records can be deleted with a confirmation step.
  • Unit tests cover: appendDeploymentRecord cap enforcement, updateDeploymentStatus correctness, pollTransactionStatus resolve and timeout paths.
  • A Playwright E2E test: mocks a deploy response, asserts the history drawer shows a new pending record, then asserts it updates to success after the mock poller fires.
  • All existing tests pass.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions