[CN/EN] LeapFi 早期预览:一个非托管 RGB++ 资产管理 DApp 的开发笔记 | LeapFi Early Preview: Notes from Building a Non-Custodial RGB++ Asset Management DApp

中文版


LeapFi Early Preview: Notes from Building a Non-Custodial RGB++ Asset Management DApp

Hey devs,

I’ve been building an RGB++ asset management tool called LeapFi.

Preview: https://leapfi-preview.netlify.app/

LeapFi is meant to be a simple non-custodial app for managing RGB++ assets across BTC and CKB. The current preview focuses on:

  • Leap to BTC

  • Transfer on BTC

  • Leap to CKB

  • UDT and Spore asset views

  • Transaction progress tracking and recovery

This is not a final release yet. It is more of an early preview, plus a few notes from actually building with @ckb-ccc/rgbpp and btc-assets-api.

One clarification on the word “DApp”: LeapFi is not fully decentralized. It still relies on centralized infrastructure such as btc-assets-api for asset queries, BTC data, SPV-related work, and transaction status coordination. But user keys stay in local wallets, btc-assets-api cannot sign for users, and final asset state is determined by BTC / CKB on-chain transactions. So I would describe LeapFi as a non-custodial RGB++ DApp, not a fully decentralized app.

Why LeapFi?

RGB++ is exciting because it binds Bitcoin UTXOs with CKB Cells. Users keep Bitcoin-style ownership while getting CKB programmability.

At the application layer, though, the RGB++ ecosystem still lacks a simple asset management entry point. Developers can build transactions and query assets through SDKs and APIs, but regular users do not yet have an obvious place to see where their RGB++ UDTs and Spores live, or to complete Leap, Transfer, and transaction tracking flows in one interface.

LeapFi started as an attempt to fill that gap: first by building a simple RGB++ asset management interface, and then by using a real DApp to understand where the RGB++ workflow still feels complex.

But once this becomes a real DApp, the hard part is not just building a transaction. The hard part is helping users survive a long cross-chain workflow.

A Transfer on BTC flow may involve:

  1. building a CKB partial transaction

  2. building a BTC PSBT

  3. signing and broadcasting the BTC transaction

  4. waiting for BTC confirmation

  5. fetching SPV proof

  6. signing and broadcasting the CKB transaction

  7. waiting for CKB transaction confirmation

For the protocol, this is reasonable. For users, they clicked one button.

So LeapFi uses a transaction pipeline UI. It shows which stage the transaction is in, what has completed, and where it failed if something goes wrong.

Development Notes: Long Workflows, Recovery, and Infrastructure Boundaries

While building LeapFi, the biggest takeaway is that RGB++ DApp complexity does not only come from transaction construction. It also comes from long-running workflow state, recovery, and the boundary between the frontend and btc-assets-api.

Checkpoints in Long Transaction Flows

One important lesson: after the BTC transaction is broadcast, some intermediate data must be preserved.

In particular, the exact CKB partial transaction committed into the BTC transaction should be saved. If the page refreshes and the app rebuilds it from scratch, UTXO selection or transaction structure may change, and the commitment may no longer match.

LeapFi currently saves checkpoints after critical steps and tries to resume from them after refresh.

This makes me think the SDK could eventually provide a standard transaction session / resume API.

For example:

await rgbpp.workflow.transferOnBtc(params, {
  onStep,
  persistence,
  waitStrategy,
});

The idea is not to hide the protocol. The idea is to provide a recoverable workflow state machine.

onStep would emit structured progress events for the UI.

persistence would define how to save required recovery data, such as operation, network, BTC txid, CKB partial transaction, commitment, and last completed step.

waitStrategy would define how the app waits: frontend polling, backend jobs, SSE, webhook, or other mechanisms.

With this shape, every DApp would not need to rediscover the same checkpoint and resume rules.

Should btc-assets-api Handle More BTC Transaction Orchestration?

btc-assets-api already handles a lot of the workflow after BTC broadcast, including confirmation, SPV-related work, and job status. A further question is whether BTC transaction construction and broadcasting can also move into btc-assets-api.

I think this is worth discussing, and it may lead to better UX. But the security boundary must stay clear.

A reasonable flow could be:

  1. frontend submits user intent to btc-assets-api

  2. btc-assets-api returns an unsigned PSBT, committed CKB transaction data, and a job/session id

  3. frontend or SDK verifies that the PSBT matches the user intent

  4. user signs the PSBT with their wallet

  5. frontend submits the signed PSBT or raw BTC tx back to btc-assets-api

  6. btc-assets-api broadcasts the BTC tx and continues the SPV / CKB workflow

In other words: btc-assets-api can build unsigned PSBTs and broadcast already signed BTC transactions. It should not sign for the user, and users should not be asked to blindly sign unverifiable PSBTs.

The main risk is that regular BTC wallets usually do not understand RGB++ semantics. They may show BTC inputs, outputs, and OP_RETURN data, but they do not know which RGB++ asset is being transferred.

So if btc-assets-api builds the PSBT, the SDK or frontend must verify:

  • receiver BTC address

  • selected RGB++ asset input

  • CKB partial transaction commitment

  • change address

  • fee limit

  • unexpected inputs or outputs

  • network

  • sighash mode

Ideally, btc-assets-api returns a structured prepare response:


{
  jobId,
  psbt,
  operation,
  assetSummary,
  receivers,
  fee,
  commitment,
  ckbPartialTxHash,
  expectedBtcOutputs,
}

Then @ckb-ccc/rgbpp could provide something like:

rgbpp.verifyPreparedTransfer(response, userIntent);

Only after verification should the DApp pass the PSBT to the wallet.

My current view: moving BTC construction and broadcasting into btc-assets-api is reasonable, and may be better UX, as long as signing stays local and the client verifies the PSBT semantics. btc-assets-api can become a workflow coordinator, but it should not become a trusted custodian.

Mainnet JWT and the Frontend DApp Access Model

btc-assets-api is important infrastructure. Auth and rate limiting make sense because SPV and transaction queue services are not free to run.

But mainnet JWT is awkward for frontend-first DApps.

A token cannot safely live in frontend code. Regular users also cannot easily obtain one. In practice, apps need a backend proxy that stores the token server-side.

LeapFi currently uses this proxy approach.

It works, but it adds friction:

  • frontend demos need a backend

  • app developers must operate proxy infrastructure

  • app-level tokens do not map cleanly to individual users

  • endpoints with different resource costs share the same auth model

Maybe the API could support tiers:

  • low-rate anonymous access for simple read-only queries

  • authenticated access for heavier endpoints

  • wallet-signed challenge to obtain short-lived scoped tokens

  • verified app tokens for production integrations

The question is not whether auth is needed. It is what auth model best fits open Web DApps.

Open questions

I’d love to hear what others think:

  1. Should @ckb-ccc/rgbpp provide a higher-level workflow / session API that standardizes checkpointing, resume logic, and step tracking?

  2. Where should the btc-assets-api boundary be? Should it move beyond post-BTC-broadcast jobs into unsigned PSBT construction and signed tx broadcasting?

  3. If PSBTs are built by the API, what semantic checks should the client and SDK perform to avoid blind signing?

  4. How can mainnet API auth and rate limiting become friendlier to frontend-first DApps while still controlling resource usage?

  5. As an early RGB++ asset management DApp, what should LeapFi prioritize next?

LeapFi is still early. Please try the preview, break things, and tell me what feels confusing.

6 Likes