Skip to content

dApp builder

Describe a web3 app in chat, get a working preview, iterate by talking to it, then deploy real contracts on-chain through a managed smart account you own.

Intents: CREATE_DAPP, MODIFY_DAPP, SHOW_DAPP, GO_ONCHAIN, DEPLOY_CONTRACTS · Action: create_dapp

Full design document: defi-set/DAPP_BUILDER_ARCHITECTURE.md. Progress log: DAPP_BUILDER_PROGRESS.md.

What it does

Lovable or Bolt, but web3-native. The difference from a generic code generator is that a Blazpay dApp can go on-chain — the builder generates Solidity, deploys it, and wires the frontend to the deployed address, all from chat.

Core design principles

These are from the architecture document and they explain most of the implementation choices:

  1. Template + AI hybrid. v1 is a fast template render. Every subsequent version is AI-modified actual code, per user.
  2. Per-user codebase. Each dApp is its own versioned codebase in MongoDB. Iterations modify that user's code, not a shared template. This was the fix for the original iteration bug, where changes appeared to apply and then vanished.
  3. Non-custodial on-chain. The user owns their smart account through their own MetaMask. Blazpay holds a restricted session key for automation only. Funds stay under user control.
  4. Paymaster-sponsored gas. The user deposits ~$10 once; the ZeroDev paymaster pays gas invisibly per transaction.
  5. Cost-controlled AI. A complexity classifier routes simple changes to cheap models; only complex changes reach the expensive tier.

Iteration mechanics

aiDeveloper.service does more than call an LLM:

StepPurpose
Complexity checkRejects a request bundling more than ~3 distinct changes, so the model is not asked to do too much at once
Load current versionIterations are against real code, not the template
Classify the changevisual / feature / content / contract — routes to the right model tier and prompt
Call the model with code + requestThe whole current file is context
Validate outputHTML must parse, scripts must be intact, no XSS introduced
Save as a new versioncurrentVersionId advances; previous versions remain

Validation is the load-bearing step. An LLM asked to change a colour can silently drop a <script> block, and without the check the user's app quietly breaks.

Versioning and rollback

EndpointPurpose
GET /v1/dapp/project/:projectId/versionsVersion list
POST /v1/dapp/project/:projectId/rollbackRestore a previous version
GET /v1/dapp/project/:projectId/htmlRaw HTML for the preview iframe
POST /v1/dapp/project/:projectId/iterateApply a change
DELETE /v1/dapp/project/:projectIdDelete

Going on-chain

ERC-4337 via ZeroDev (@zerodev/sdk, @zerodev/ecdsa-validator, @zerodev/permissions, plus permissionless).

The sequence, from the architecture document:

  1. The user asks to make the app real. The bot quotes the cost (~$10, covering contract deployment plus roughly 500 user interactions) and states plainly that the user owns the account via their MetaMask.
  2. The user signs a one-time EIP-712 setup message.
  3. smartAccount.service computes the counterfactual smart-account address, asks the user to send $10 of native to it, and verifies the deposit on-chain.
  4. The smart account is deployed as the first UserOp.
  5. A session key with tight permissions is registered for Blazpay's automation.
  6. The ZeroDev paymaster budget is topped up with the user's deposit.
  7. aiDeveloper.service generates the Solidity.
  8. contractDeployer.service compiles with solc and deploys via the session key plus paymaster.

Endpoints

EndpointPurpose
POST /v1/dapp/project/:projectId/go-onchainStart setup
POST /v1/dapp/account/verify-depositConfirm the $10 landed
POST /v1/dapp/account/:projectId/deploy-accountDeploy the smart account
GET /v1/dapp/account/:projectIdAccount state
POST /v1/dapp/account/:projectId/top-upAdd paymaster budget
POST /v1/dapp/account/:projectId/revoke-sessionRevoke Blazpay's session key
POST /v1/dapp/account/:projectId/verify-contractSubmit for explorer verification
GET /v1/dapp/account/:projectId/verify-contract/:guidPoll verification status

Withdrawal and revocation

Both are user-controlled:

  • Withdraw — the frontend has the user sign { action: 'WITHDRAW', amount, to } with their owner key. The backend verifies the signature and constructs the UserOp.
  • Revoke — the user can revoke the session key at any time, after which the smart account is entirely self-controlled and Blazpay's automation stops working.

This is the only place Blazpay holds a key that can move user funds

The session key is scoped by ZeroDev permissions to the operations the builder needs, and revocable unilaterally by the user. It is a genuinely different trust posture from the rest of the platform, and the UI should say so at the point of setup — not in a footer.

Subscription and quota

EndpointPurpose
GET /v1/dapp/subscriptionCurrent tier
GET /v1/dapp/subscription/statusUsage against the tier
POST /v1/dapp/subscription/upgradeUpgrade

Iteration counts are per-project — iterationsUsed / maxIterations on the project record, in models/dappProjectModel.js. Tier data lives in models/dappSubscriptionModel.js.

Session state

The active project is activeDappProjectId on blazSession, passed to bz-agent with every chat request. That is how the precondition on MODIFY_DAPP, SHOW_DAPP, GO_ONCHAIN, DEPLOY_CONTRACTS and SHOW_DAPP is enforced — without an active project, those intents are not selectable.

Under the hood

ConcernWhere
Project + version storagebz-backend/models/dappProjectModel.js, generatedDappModel.js, dappModel.js
Subscriptionmodels/dappSubscriptionModel.js
Smart account recordmodels/managedAccountModel.js
Generation + iterationv1/services/dappBuilder.service.js, v1/services/aiDeveloper.service.js
Routesv1/routes/dapp.routes.js (~24 endpoints)
Agent nodesbz-agent/src/agent/{createDappNode,modifyDappNode,goOnchainNode}.ts
Templatesbz-agent/src/template/{createDapp,modifyDapp,goOnchain}.ts
Chat carddefi-dex/src/component/defi/swapAI/dapp/DappPreview.tsx

Endpoint detail: dApp API reference.

Intent boundaries

GO_ONCHAIN versus DEPLOY_CONTRACTS is the confusion to watch, and both descriptions carry explicit exclusion lists:

User saysIntent
"go onchain", "set up smart account", "make my dapp live"GO_ONCHAIN
"deploy my contracts", "deploy solidity", "deploy via smart account", "generate contracts"DEPLOY_CONTRACTS
"show my dapp", "open preview", "let me see it"SHOW_DAPP

Known limits

  • HTML single-file output. Generated dApps are self-contained HTML rendered in a blob-URL iframe, not multi-file React projects. That bounds what can be built.
  • Complexity ceiling per iteration. More than ~3 distinct changes in one message is rejected rather than attempted.
  • Generated Solidity is not audited. It is compiled and deployed. Users deploying a generated contract that will hold funds should run it through the contract auditor — which is available in the same chat, and is the obvious integration to make automatic.
  • Chain coverage is narrower than the trading products. See §12 of the architecture document for the target list.
  • The session key is a real trust delegation. Documented above; make sure the UI is honest about it.
  • No export. A user cannot download their generated codebase and self-host it. That is a retention decision, but it is also a lock-in users will eventually object to.

Internal + developer documentation. Usage figures are point-in-time snapshots — re-verify before publishing them.