Skip to content

feat(deploy): optional contract deploy for foundry, hardhat, cdm#38

Merged
charlesHetterich merged 9 commits intomainfrom
contract-deploy
Apr 22, 2026
Merged

feat(deploy): optional contract deploy for foundry, hardhat, cdm#38
charlesHetterich merged 9 commits intomainfrom
contract-deploy

Conversation

@charlesHetterich
Copy link
Copy Markdown
Collaborator

@charlesHetterich charlesHetterich commented Apr 21, 2026

Contracts in dot deploy

Summary

dot deploy can now compile and deploy the project's contracts alongside
the frontend. Supports foundry, hardhat, and cdm projects — detected at the
project root from foundry.toml, hardhat.config.*, or a Cargo.toml with
a pvm_contract dep. Off by default: the TUI asks "deploy contracts?" when
a contract project is detected; headless runs opt in with --contracts.

Contracts and the frontend build+upload run concurrently; the running-stage
TUI gains a contracts section alongside frontend, with per-contract rows
showing deployed addresses as each chunk lands.

Contract extrinsics are signed by a persistent on-disk session key at
~/.polkadot/accounts.json, not the mobile signer — today's mobile flow
can't handle the encoded size of a batched contract deploy, and the failure
is miscategorised as a user-cancel. The session key is funded by the user's
signer on first deploy (one phone tap) or by Alice in pure dev mode;
subsequent runs skip funding when balance is above threshold.

No constructor args, no registry publish, no on-chain metadata in this
first cut — follow-up work.

What's in the PR

  • dot deploy --contracts flag + interactive "deploy contracts?" prompt
  • Parallel contracts/frontend execution in runDeploy
  • Compile dispatch per toolchain: forge build --resolc, npx hardhat compile,
    or @dotdm/contracts buildContracts
  • Deploy via cdm's ContractDeployer.deployBatch (weight-aware Utility.batch_all)
  • Session-key signing (src/utils/deploy/session-account.ts) with first-run
    Revive.map_account bootstrap and session-key top-up flow
  • Running-stage TUI reshape: contracts + frontend sections with pure
    reducer in src/commands/deploy/runningState.ts
  • dot init gains a foundry (polkadot) check that installs
    foundryup-polkadot

Peripheral

  • runStreamed / runShell consolidated in src/utils/process.ts
    (previously duplicated across build, contracts, and toolchain paths)
  • checkBalance / ensureFunded take optional min-balance and
    fund-amount overrides
  • StepRunner log output now throttled to ≤10 Hz (same
    reconciler-backpressure mitigation as the deploy TUI)
  • Bytecode-parsing helpers (extractFoundryBytecode,
    extractHardhatBytecode, hexToBytes) exported for unit tests
  • Added tests: runningState, contracts helpers, session-account,
    signerMode matrix, process, run (contracts-phase orchestration),
    detect.detectContractsType, summary (contracts row),
    deploy/index helpers

Test plan

  • dot deploy on a foundry project with --contracts → forge compiles,
    contracts deploy, addresses shown in TUI, app still publishes
  • Same for hardhat (@parity/hardhat-polkadot loaded)
  • Same for cdm (Rust/PVM)
  • Interactive flow: contract project detected → prompt appears;
    no contracts → prompt skipped
  • First deploy in phone mode: session key minted, one funding tap,
    Revive.map_account submitted
  • Second deploy: session key reused, funding skipped (balance ≥ threshold)
  • --contracts on a non-contract project errors fast
  • dot init offers + installs foundry (polkadot)
Screenshot 2026-04-22 at 1 04 15 AM Screenshot 2026-04-21 at 11 26 17 PM Screenshot 2026-04-22 at 1 38 49 AM

… and cdm projects

Detects a contract project at the deploy root via three signals:
  - `foundry.toml`               → foundry path
  - `hardhat.config.{ts,js,...}` → hardhat path
  - `Cargo.toml` w/ pvm_contract → cdm path

When detected, the TUI prompts "deploy contracts?" (default no) between
the playground prompt and confirm; non-interactive callers pass `--contracts`.
A new `contracts` phase runs after `build` and before `storage-and-dotns`.
When the user picks "no", or no project is detected, the phase emits
`phase-skipped` so the TUI collapses the row instead of leaving it pending.

All three paths converge on the same Substrate-extrinsic deploy: each one
compiles locally to PolkaVM bytecode, writes the bytes to a tmp `.polkavm`
file, then hands every file to `@dotdm/contracts` `ContractDeployer.deployBatch`,
which weight-aware-chunks them into one or more `Utility.batch_all` calls
on Asset Hub. This means the existing signer plumbing (`//Alice` in
`--signer dev`, the user's session signer in `--signer phone`) signs the
contract instantiations directly — no ECDSA private key, no hardhat-ethers
wallet, no foundry keystore.

Per-language compile:
  - foundry → `forge build --resolc` (the polkadot fork's PolkaVM codegen;
              `--resolc` is forced rather than relying on `foundry.toml`
              config so a plain forge-init project Just Works). Reads
              `out/<C>.sol/<C>.json:bytecode.object`. Skips `.t.sol` and
              `.s.sol` directories.
  - hardhat → `npx hardhat compile`. Reads
              `artifacts/contracts/<C>.sol/<C>.json:bytecode`.
  - cdm     → `@dotdm/contracts` `buildContracts({ rootDir })`, which uses
              cargo metadata for layered detection and pvmContractBuildAsync
              for per-crate compilation.

Solidity output is validated against the `0x50564d00` ("PVM\0") magic
header before deploy, so a foundry user who skipped `--resolc` (or a
hardhat user who forgot to load `@parity/hardhat-polkadot`) gets a
targeted error instead of a cryptic pallet revert later.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 21, 2026

Dev build ready — try this branch:

curl -fsSL https://raw.githubusercontent.com/paritytech/playground-cli/main/install.sh | VERSION=dev/contract-deploy bash

@charlesHetterich charlesHetterich changed the title feat(deploy): add optional contract deploy step for foundry, hardhat,… feat(deploy): optional contract deploy for foundry, hardhat, cdm Apr 21, 2026
- `runDeploy` runs the contracts phase and the frontend build+upload concurrently via `Promise.all`; playground publish stays sequential after both.
- `RunningStage` rewritten: vertical `contracts` / `frontend` sections, per-contract rows showing a spinner → checkmark + full on-chain address (truncate-middle on narrow terminals, 1-char right pad), playground as a single line below. Stays mounted through `done` / `error` so `FinalResult` renders below the sections the way `dot init` keeps its dep list.
- `deploy-chunk` event now carries `{ contracts: [{ name, address }] }` so rows flip to complete + populate the address incrementally as each chunk lands, instead of all at once at `deploy-done`. All rows spin from `compile-detected` onward so cdm's 10–20 s pre-submit silence stops looking like a freeze.
- `runStreamed` consolidated into `src/utils/process.ts`; `build/runner.ts`, `deploy/contracts.ts`, and `toolchain.ts` import from there (−130 duplicated lines).
- `StepRunner` gets coalesced log updates (ref + 100 ms timer, 160-char cap) so firehose sources can't re-trigger the 20 GB reconciler bug.
@charlesHetterich charlesHetterich marked this pull request as ready for review April 22, 2026 05:10
@charlesHetterich charlesHetterich merged commit f4d6ae6 into main Apr 22, 2026
5 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.

1 participant