Skip to content

feat: add Transaction Composer - GUI builder for multi-op Stellar transactions#23

Open
bytebinders wants to merge 9 commits into
Savitura:mainfrom
bytebinders:main
Open

feat: add Transaction Composer - GUI builder for multi-op Stellar transactions#23
bytebinders wants to merge 9 commits into
Savitura:mainfrom
bytebinders:main

Conversation

@bytebinders

Copy link
Copy Markdown

Summary

Implements a full-stack, GUI-based Transaction Composer that lets developers visually assemble, preview, and submit multi-operation Stellar transactions without writing raw SDK code.

Closes #[issue_number]


What Was Built

API — apps/api/src/modules/composer/

Three new endpoints under /v1/composer:

Endpoint Description
GET /operations Returns all 12 supported operation types with per-field schemas (label, type, required, placeholder)
POST /build Accepts an ordered array of operation objects + source account, validates each op, returns unsigned XDR envelope + hash
POST /simulate Dry-runs an unsigned XDR envelope against Horizon testnet/mainnet, returns success/failure, fee consumed, tx result code, and per-operation result codes

Web — /composer route

Full replacement of the placeholder stub with a three-panel composer:

  • Operation palette (left) — 12 color-coded cards, click to append an operation
  • Operation list (center) — drag-to-reorder via @hello-pangea/dnd; each item shows index, type, destination preview, and a hover-reveal delete button
  • Operation form (right) — dynamic fields driven by the API manifest; supports dotted field paths (asset.code), boolean radio pairs, and text/number inputs
  • XDR preview (bottom) — live-updating monospace panel with green status indicator and one-click copy
  • Simulate result (inline) — shows fee in stroops, transaction result code, per-operation result codes, and tx hash
  • Toolbar (top) — testnet/mainnet network toggle (persisted to localStorage), op count badge, Simulate and Submit to Horizon buttons with loading states and a Stellar Expert explorer link on success

Supported Operation Types (12)

payment · create_account · change_trust · manage_sell_offer · manage_buy_offer · create_passive_sell_offer · set_options · account_merge · allow_trust · path_payment_strict_send · path_payment_strict_receive · manage_data


Key Design Decisions

  • Unsigned XDR — the API returns unsigned envelopes; the developer signs locally via Freighter or Stellar Lab before submitting. No private keys are handled server-side.
  • Auto-build — XDR rebuilds automatically 600 ms after any change (debounced) so the preview stays live without button clicks.
  • Network toggle — a new useNetwork() React context (testnet/mainnet) is persisted to localStorage and available app-wide via NetworkProvider added to the root layout.
  • Drag integrity — reorder uses splice(source.index, 1) + splice(destination.index, 0, moved) to guarantee correct re-indexing.

How to Test

# Start the API
cd apps/api && npm run dev

# Verify manifest endpoint
curl http://localhost:3001/api/v1/composer/operations

# Start the web
cd apps/web && npm run dev
# Navigate to http://localhost:3000/composer

Closes #15

Introduces BuildTransactionDto and SimulateTransactionDto with full
class-validator and class-transformer decorators.

Supported op types: payment, create_account, change_trust,
manage_sell_offer, manage_buy_offer, create_passive_sell_offer,
set_options, account_merge, allow_trust, path_payment_strict_send,
path_payment_strict_receive, manage_data.

Each DTO uses @isin for type discrimination, @ValidateNested for
nested asset/price sub-objects, and @ApiProperty for Swagger docs.
…mulation

Adds ComposerService with three methods:

- getOperations(): returns static manifest of all 12 op types with
  per-field schemas (name, label, type, required, placeholder) for
  the UI to render dynamic forms.

- buildTransaction(dto): loads source account from Horizon, constructs
  a TransactionBuilder, appends each op via a type-switch dispatch,
  applies optional memo, and returns the unsigned XDR envelope + hash.

- simulateTransaction(dto): parses the XDR envelope, submits to Horizon,
  and returns { success, fee, resultCodes, operationResults }. Horizon
  error responses are decoded to extract result_codes for the UI.

Uses @stellar/stellar-sdk (already in deps) for all Stellar primitives.
Supports both testnet and mainnet via network passphrase selection.
ComposerController exposes three endpoints under /v1/composer:
  GET  /operations  - returns full op-type manifest with field schemas
  POST /build       - accepts ordered op array, returns unsigned XDR
  POST /simulate    - dry-runs XDR on Horizon, returns fee + result codes

ComposerModule wires controller and service with standard NestJS pattern.
ComposerModule imported into AppModule alongside existing feature modules.
network-context.tsx: React context providing useNetwork() hook with
testnet/mainnet toggle. State is persisted to localStorage under the
key 'savitools:network' and defaults to 'testnet'.

composer-api.ts: Typed fetch wrappers (using existing apiFetch helper)
for all three composer endpoints. Also exports submitToHorizon() which
posts directly to Horizon /transactions as
application/x-www-form-urlencoded for final signed submission.
Imports NetworkProvider from lib/network-context and wraps the
AuthProvider subtree so every page (including /composer) can access
the testnet/mainnet toggle via useNetwork() without prop-drilling.
Adds six focused components under src/components/tools/composer/:

operation-palette.tsx
  Left panel with 12 color-coded op-type cards. Each card shows an
  icon, label, and hover-reveal plus icon. Click appends op to list.

operation-list.tsx
  Center drag-to-reorder list using @hello-pangea/dnd DragDropContext.
  Each item shows index, op type, destination preview, grip handle,
  and hover-reveal trash button. Re-index is guaranteed by splice/insert
  on drag result indices.

operation-form.tsx
  Right dynamic form driven by the op schema manifest fetched from the
  API. Supports dotted field paths (asset.code), boolean radio pairs,
  and text/number inputs. Fires onChange with deep-merged field state.

xdr-preview.tsx
  Bottom monospace panel. Green dot when XDR is present. One-click
  copy with 2s confirmation state.

simulate-result.tsx
  Inline result panel showing success/failure badge, fee in stroops,
  tx result code, per-operation result codes, and tx hash.

composer-toolbar.tsx
  Testnet/mainnet toggle (reads/writes useNetwork context), op count
  badge, Simulate and Submit to Horizon buttons with loading spinners,
  inline submit result with Stellar Expert explorer link.

index.tsx (root ComposerTool)
  Manages all composer state. Fetches op manifest on mount. Auto-builds
  XDR 600ms after any change (debounced, avoids excess Horizon calls).
  Resets simulate/submit results on each rebuild.
other-tools.tsx: replace the ComposerTool placeholder stub with a
re-export from the new ./composer module. WebhooksTool and MonitorTool
stubs are preserved unchanged.

package.json: formally declare @hello-pangea/dnd ^17.0.0 as a
dependency (package was already installed to node_modules during
development setup).
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.

Transaction Composer; Visual Multi-Operation Builder

1 participant