{
  "base_url": "https://talk.nervos.org",
  "generated_at": "2026-05-01T17:58:05.347488+00:00",
  "since": "2026-04-30T17:58:01.053220+00:00",
  "until": "2026-05-01T17:58:01.053220+00:00",
  "window_hours": 24,
  "topics": [
    {
      "topic_id": 10199,
      "title": "Cellora — designing a production indexing and query service for CKB (feedback welcome)",
      "slug": "cellora-designing-a-production-indexing-and-query-service-for-ckb-feedback-welcome",
      "url": "https://talk.nervos.org/t/cellora-designing-a-production-indexing-and-query-service-for-ckb-feedback-welcome/10199",
      "created_at": "2026-04-22T15:33:26.290000+00:00",
      "last_posted_at": "2026-05-01T16:57:21.842000+00:00",
      "category_id": 32,
      "tags": [
        "CKB",
        "Nervos-项目动态",
        "dapp",
        "testnet"
      ],
      "posters": [
        "Original Poster",
        "Frequent Poster",
        "Most Recent Poster"
      ],
      "recent_posts": [
        {
          "post_id": 24101,
          "post_number": 6,
          "topic_id": 10199,
          "topic_title": "Cellora — designing a production indexing and query service for CKB (feedback welcome)",
          "topic_slug": "cellora-designing-a-production-indexing-and-query-service-for-ckb-feedback-welcome",
          "author": "matt_ckb",
          "created_at": "2026-05-01T16:37:52.751000+00:00",
          "updated_at": "2026-05-01T16:37:52.751000+00:00",
          "reply_to_post_number": 4,
          "url": "https://talk.nervos.org/t/cellora-designing-a-production-indexing-and-query-service-for-ckb-feedback-welcome/10199/6",
          "content_text": "ArthurZhang:\nFor tx inclusion proofs, the practical first step is likely not Flyclient, but exposing CKB’s existing get_transaction_proof / verify_transaction_proof path through Cellora. That lets clients verify that a transaction is committed under a particular block header, rather than merely trusting Cellora’s indexed result.\nWithout the Flyclient proof, I have trouble seeing how the client can verify that the block header returned from Cellora has been included in the chain. Am I missing something?",
          "content_html": "<aside class=\"quote no-group\" data-username=\"ArthurZhang\" data-post=\"4\" data-topic=\"10199\">\n<div class=\"title\">\n<div class=\"quote-controls\"></div>\n<img alt=\"\" width=\"24\" height=\"24\" src=\"https://talk.nervos.org/user_avatar/talk.nervos.org/arthurzhang/48/11070_2.png\" class=\"avatar\"> ArthurZhang:</div>\n<blockquote>\n<p><strong>For tx inclusion proofs</strong>, the practical first step is likely <strong>not Flyclient</strong>, but exposing CKB’s existing <code>get_transaction_proof</code> / <code>verify_transaction_proof</code> path through Cellora. That lets clients verify that a transaction is committed under a particular block header, rather than merely trusting Cellora’s indexed result.</p>\n</blockquote>\n</aside>\n<p>Without the Flyclient proof, I have trouble seeing how the client can verify that the block header returned from Cellora has been included in the chain. Am I missing something?</p>",
          "like_count": 0,
          "quote_count": 1
        },
        {
          "post_id": 24102,
          "post_number": 7,
          "topic_id": 10199,
          "topic_title": "Cellora — designing a production indexing and query service for CKB (feedback welcome)",
          "topic_slug": "cellora-designing-a-production-indexing-and-query-service-for-ckb-feedback-welcome",
          "author": "ArthurZhang",
          "created_at": "2026-05-01T16:57:21.842000+00:00",
          "updated_at": "2026-05-01T16:57:42.986000+00:00",
          "reply_to_post_number": 6,
          "url": "https://talk.nervos.org/t/cellora-designing-a-production-indexing-and-query-service-for-ckb-feedback-welcome/10199/7",
          "content_text": "Yes, agreed. I was following Antismart’s staged framing here.\nI meant that get_transaction_proof / verify_transaction_proof is useful for the step-2 property: tx-to-header verification. It does not by itself prove that the returned header is canonical.\nThe full trust minimisation later on still needs Flyclient, a local node, or another trusted header source.",
          "content_html": "<p>Yes, agreed. I was following Antismart’s staged framing here.</p>\n<p>I meant that <code>get_transaction_proof / verify_transaction_proof</code> is useful for the step-2 property: tx-to-header verification. It does not by itself prove that the returned header is canonical.</p>\n<p>The full trust minimisation later on still needs Flyclient, a local node, or another trusted header source.</p>",
          "like_count": 0,
          "quote_count": 0
        }
      ]
    },
    {
      "topic_id": 10220,
      "title": "Pckt: A Friendly Way to Send CKB | pckt：一种友好的发送 CKB 的方式",
      "slug": "pckt-a-friendly-way-to-send-ckb-pckt-ckb",
      "url": "https://talk.nervos.org/t/pckt-a-friendly-way-to-send-ckb-pckt-ckb/10220",
      "created_at": "2026-04-30T18:38:17.768000+00:00",
      "last_posted_at": "2026-05-01T15:55:22.939000+00:00",
      "category_id": 32,
      "tags": [
        "CKB",
        "Nervos-项目动态",
        "appchain",
        "dapp"
      ],
      "posters": [
        "Original Poster",
        "Frequent Poster",
        "Most Recent Poster"
      ],
      "recent_posts": [
        {
          "post_id": 24083,
          "post_number": 1,
          "topic_id": 10220,
          "topic_title": "Pckt: A Friendly Way to Send CKB | pckt：一种友好的发送 CKB 的方式",
          "topic_slug": "pckt-a-friendly-way-to-send-ckb-pckt-ckb",
          "author": "RobaireTH",
          "created_at": "2026-04-30T18:38:17.876000+00:00",
          "updated_at": "2026-04-30T18:48:46.936000+00:00",
          "reply_to_post_number": null,
          "url": "https://talk.nervos.org/t/pckt-a-friendly-way-to-send-ckb-pckt-ckb/10220/1",
          "content_text": "pckt is a red-packet style CKB app. A sender seals CKB into a single on-chain packet cell, shares a link, and recipients claim from that packet until it is exhausted or expires. If the packet expires before all claims are taken, the sender can reclaim the remainder\nimage1405×892 127 KB\nFor now, this is a solo-built project. I have tried to keep the architecture small, inspectable, and easy to maintain without requiring a large ops or protocol team.\nProblem and Solution\nThe problem\nSending tokens on-chain is usually transactional, but not ceremonial. Red packets are social. They are meant to be shared into a group, opened by multiple recipients, and claimed with a sense of timing, surprise, and urgency.\nMost wallet transfer flows do not capture that behavior well. They support “send X to Y,” but not:\none sender, many recipients\npartial sequential claiming\ntime-gated opening\n“claim by link” behavior\nreclaiming unclaimed balance after expiry\nThe solution\npckt models the packet as a single live CKB cell governed by a custom lock script. Instead of keeping packet state off-chain, every claim consumes the packet cell and produces its next version. That lets the chain remain the source of truth while the frontend and backend make the experience feel native.\nHosted solution: https://sendpckt.robaireth.dev\nRepo: GitHub - RobaireTH/pckt: The friendliest way to send CKB · GitHub\nThe core user flow is:\nSender seals a packet on-chain.\nSender shares a claim link.\nRecipients claim against the packet cell.\nThe packet shrinks as claims happen.\nIf claims are exhausted, the packet terminates.\nIf time expires first, the sender can reclaim the remainder.\nTechnical Approaches and Design Decisions\n1. One contract, one packet cell\nThe main design decision is that a packet is not an account, and it is not a backend object. It is a single live cell with explicit, serialized state.\nThat gives a few advantages:\neasier audit surface than a larger state machine\nno server custody\nclaims are naturally serialized by cell consumption\neach state transition is verifiable from chain history\n2. Frontend signs the social flow, backend indexes the chain\nimage805×1018 97.9 KB\nimage1425×798 103 KB\nThe system is split into three parts:\nContract: Rust CKB lock script for claim and reclaim paths\nFrontend: React + TypeScript app using CCC to build and sign transactions\nBackend: Rust + Axum + SQLite indexer and UX helper\nThe backend is intentionally non-authoritative. It does not hold keys, does not create truth, and can be replaced. Its role is to index packet state, provide sender/claimer views, short links, and live UX data.\n3. Claim links put the secret in the fragment\nThe claim secret lives in the URL fragment, not in backend storage. That means the browser can hold the secret client-side while the backend only sees the public short-link target. This is an important design boundary: the server helps with UX, but it should not become a custody or secret-management layer.\n4. Testnet-first, with deliberate constraints\nI explicitly kept this testnet-first and avoided pretending every mode is ready for production. In particular:\nreclaim exists on-chain and is now wired into the UI\nsender naming is currently backend-stored and convenience-oriented, not yet decentralized identity\nthe “lucky split” mode is constrained by payout math and safety concerns\nCKB Ecosystem Relevance\npckt is relevant to CKB because it leans into what cells are good at:\nexplicit state\ncomposable lock logic\nsequential consumption and recreation\ncustom social/financial flows without custodial middleware\nI believe it’s of benefit to the wider ecosystem as it is a good initiative to introduce people to the Nervos CKB by bringing in centuries old traditions onchain. A simple sharing of love!\nimage1282×1211 207 KB\nDeployment Architecture\nCurrent deployment shape:\nFrontend: Vite app deployed separately\nBackend: Fly.io app\nDatabase: SQLite on Fly volume\nChain target: CKB testnet (Pudge)\nThe backend runs as:\npacket indexer\npacket/query API\nshort-link service\nprice helper\nrelay endpoint for signed transactions\nThe frontend is configured by environment variables with:\ntestnet RPC URL\nactive contract code hash\ncontract outpoint\nbackend URL\nSecurity Considerations\n1. Self-custody\nFunds are locked on-chain. The backend never has authority to move them.\n2. Non-authoritative backend\nThe backend is replaceable and should be treated as UX infrastructure, not a trust anchor. It’s even the contract that rejects multiple claims, not the backend.\n3. Claim secret handling\nThe claim secret sits in the URL fragment so it is not automatically sent to servers. This avoids a major class of accidental backend custody.\n4. Reorg and index correctness\nThe backend includes reorg handling and block-hash rollback logic because packet state derived from chain history must survive reorgs cleanly.\n5. Explicitly bounded feature set\nI do not want unsafe “it sort of works” behavior around payout math or reclaim timing. Where a mode looks questionable, I prefer to restrict it until it is clean.\nWhy I Don’t Like the Maths Behind Lucky Splits For Now\nI do not dislike the idea of lucky splits. I dislike the current math and operational risk profile of lucky splits in this implementation.\nThe problem is: once you move from fixed shares to random shares, you need to guarantee that:\neach claim remains above minimum live-cell capacity\nenough capacity is reserved for future claims\nthe final claim and reclaim paths still behave safely\nthe user-facing preview matches what on-chain logic will actually allow\nThat is easy to get subtly wrong.\nIn practice, lucky mode becomes a product-security problem, not just a product-design problem. If the random lower bound is too low, you can create unclaimable outputs. If the reservation math is too optimistic, you can strand capacity. If frontend prediction diverges from contract math, users get misleading expectations.\nFor now, I prefer the stricter stance:\nfixed and timed-fixed remain usable\nlucky mode is something I would only re-enable once I am satisfied that the lower-bound math, reservation rules, and UI expectations are all aligned\nI would rather disappoint users with a disabled mode than lock them into a half-correct one.\nMaintenance Plan\nI plan to use this Talk Nervos thread itself as part of the maintenance loop.\nSpecifically:\nI will post updates there as features or fixes land\nI will note contract redeploys and testnet config changes here\nI will use the thread to surface known limitations honestly\nI will treat user reports in the thread as a lightweight public changelog and maintenance channel\nThe near-term maintenance priorities are:\nstabilize sender/claimer UX\nkeep reclaim flow reliable and understandable\ntighten profile/name semantics\nrevisit lucky split math only when it is safe\ncontinue testnet usage before thinking seriously about mainnet\nClosing\npckt is an attempt to build something small, social, and unmistakably native to CKB’s cell model. It is not trying to be a generic wallet feature (Though it can be). It is trying to make a familiar ritual feel right on-chain.\nIf that resonates, I’d love feedback moat importantly on whether the identity layer should remain simple or move toward a more formal DID-based model later.\nZH\npckt 是一个类似红包的 CKB 应用。发送者将 CKB 封装成一个链上数据包，分享一个链接，接收者可以从该数据包中认领代币，直到数据包耗尽或过期。如果数据包在所有代币被认领之前过期，发送者可以重新认领剩余的代币。\nimage1405×892 127 KB\n目前，这是一个由我独立开发的项目。我努力保持架构的简洁、易于检查和维护，无需庞大的运维或协议团队。\n问题与解决方案\n问题\n链上发送代币通常是交易性的，但缺乏仪式感。红包则具有社交性。它们应该被分享给一群人，由多个接收者打开，并以一种带有时机感、惊喜感和紧迫感的方式认领。\n大多数钱包的转账流程都无法很好地体现这种行为。他们支持“向 Y 发送 X”，但不支持：\n一个发送方，多个接收方\n部分顺序声明\n时间门控开启\n“通过链接声明”行为\n过期后回收未声明余额\n解决方案\npckt 将数据包建模为由自定义锁定脚本控制的“单个活跃 CKB 单元”。数据包状态并非保存在链下，而是每次声明都会消耗数据包单元并生成其下一个版本。这使得链始终保持真实性，同时前端和后端提供原生体验。\n托管解决方案：https://sendpckt.robaireth.dev\n代码库：GitHub - RobaireTH/pckt: The friendliest way to send CKB · GitHub\n核心用户流程如下：\n发送方在链上密封数据包。\n发送方共享声明链接。\n接收方针对数据包单元进行声明。\n随着声明的进行，数据包会逐渐缩小。\n如果所有请求权都已用尽，则数据包终止。\n如果时间先到期，发送方可以重新获取剩余的请求权。\n技术方案和设计决策\n1. 一个合约，一个数据包单元\n主要的设计决策是：数据包不是账户，也不是后端对象。它是一个具有明确序列化状态的“单个活动单元”。\n这带来了一些优势：\n比大型状态机更容易审计\n无需服务器托管\n声明自然地按单元消耗进行序列化\n每个状态转换都可以从链历史记录中验证\n2. 前端对社交流进行签名，后端对链进行索引\nimage805×1018 97.9 KB\nimage1425×798 103 KB\n该系统分为三个部分：\nContract：用于声明和回收路径的 Rust CKB 锁定脚本\nFrontend：使用 CCC 构建和签名交易的 React + TypeScript 应用\nBackend：Rust + Axum + SQLite 索引器和 UX 辅助工具\n后端有意设计为非权威。它不持有密钥，不创造真理，并且可以被替换。它的作用是索引数据包状态，提供发送方/声明方视图、短链接和实时用户体验数据。\n3. 声明链接将密钥放在片段中\n声明密钥存储在 URL 片段中，而不是后端存储中。这意味着浏览器可以在客户端持有密钥，而后端只能看到公开的短链接目标。这是一个重要的设计边界：服务器有助于用户体验，但不应成为密钥保管层或密钥管理层。\n4. 测试网优先，并设定了明确的限制\n我特意坚持测试网优先的原则，避免假装所有模式都已准备好用于生产环境。具体而言：\n资金回收功能已上线，并集成到用户界面中\n发送者名称目前存储在后端，仅供方便使用，尚未实现去中心化身份\n“幸运平分”模式受限于支付算法和安全问题。\nCKB 生态系统相关性\npckt 与 CKB 的相关性在于它充分利用了 Cell 的优势：\n显式状态\n可组合的锁逻辑\n顺序消费和再利用\n无需托管中间件的自定义社交/金融流程\n我相信这对整个生态系统都有益处，因为它是一个很好的举措，通过将几个世纪以来的传统引入链上，向人们介绍 Nervos CKB。这是一种简单的分享！\nimage1282×1211 207 KB\n部署架构\n当前部署结构：\n前端：独立部署的 Vite 应用\n后端：Fly.io 应用\n数据库：Fly 卷上的 SQLite 数据库\n目标链：CKB 测试网 (Pudge)\n后端运行方式如下：\n数据包索引器\n数据包/查询 API\n短链接服务\n价格辅助工具\n已签名交易的中继端点\n前端通过环境变量配置，包括：\n测试网 RPC URL\n活动合约代码哈希值\n合约输出点\n后端 URL\n安全注意事项\n1. 自保\n资金锁定在链上。后端无权移动资金。\n2. 非权威后端\n后端是可替换的，应该被视为用户体验基础设施，而不是信任锚点。甚至拒绝多个声明的也是合约，而不是后端。\n3. 声明密钥处理\n声明密钥位于 URL 片段中，因此不会自动发送到服务器。这避免了一类主要的意外后端保管风险。\n4. 重组和索引正确性\n后端包含重组处理和区块哈希回滚逻辑，因为从链历史中派生的包状态必须在重组后保持完好。\n5. 明确限定的功能集\n我不希望在支付计算或回收时间方面出现不安全的“勉强能用”的行为。如果某个模式看起来有问题，我倾向于限制它，直到它变得安全为止。\n为什么我目前不喜欢幸运分割背后的数学原理\n我并不反对幸运分割的想法。我不喜欢当前实现中“幸运拆分”的数学原理和操作风险。\n问题在于：一旦从固定份额改为随机份额，就需要保证：\n每次认领都保持在最低活跃单元容量之上\n为未来的认领预留足够的容量\n最终认领和赎回路径仍然安全\n用户预览与链上逻辑实际允许的情况相符\n这一点很容易出现细微的错误。\n实际上，“幸运模式”会演变成产品安全问题，而不仅仅是产品设计问题。如果随机下限设置得太低，可能会导致无法认领的输出结果。如果预留计算过于乐观，则可能导致资源闲置。如果前端预测与合同计算存在偏差，则会产生误导性的预期。\n目前，我倾向于采取更严格的立场：\n固定模式和限时固定模式仍然可用\n只有在我确信下限计算、预留规则和用户界面预期都一致后，我才会重新启用“幸运模式”。\n我宁愿禁用该模式让用户失望，也不愿让他们使用一个半真半假的模式。\n维护计划\n我计划将此 Talk Nervos 讨论帖本身作为维护流程的一部分。\n具体来说：\n我会在此发布新功能或修复的更新\n我会在此记录合约重新部署和测试网配置变更\n我会在此帖中如实说明已知的限制\n我会将帖子中的用户报告视为一个轻量级的公开变更日志和维护渠道\n近期维护重点如下：\n稳定发送方/领取方的用户体验\n保持回收流程的可靠性和易懂性\n完善个人资料/名称语义\n仅在安全的情况下重新审视幸运拆分算法\n在认真考虑主网之前，继续使用测试网\n结束语\npckt 旨在构建一个小型、社交化且与 CKB 的 cell 模型完美契合的原生应用。它并非旨在成为一个通用的钱包功能（尽管它也可以做到）。它的目标是让熟悉的仪式感在链上自然流畅地呈现。\n如果这引起了您的共鸣，我非常希望收到反馈，尤其希望了解身份层是否应该保持简单，还是应该在未来转向更正式的基于 DID 的模型。",
          "content_html": "<blockquote>\n<p><code>pckt</code> is a red-packet style CKB app. A sender seals CKB into a single on-chain packet cell, shares a link, and recipients claim from that packet until it is exhausted or expires. If the packet expires before all claims are taken, the sender can reclaim the remainder</p>\n</blockquote>\n<p><div class=\"lightbox-wrapper\"><a class=\"lightbox\" href=\"https://talk.nervos.org/uploads/default/original/2X/8/8988c442ef910669b612990ca301ce4b6b9dc598.jpeg\" data-download-href=\"https://talk.nervos.org/uploads/default/8988c442ef910669b612990ca301ce4b6b9dc598\" title=\"image\"><img src=\"https://talk.nervos.org/uploads/default/optimized/2X/8/8988c442ef910669b612990ca301ce4b6b9dc598_2_690x438.jpeg\" alt=\"image\" data-base62-sha1=\"jCGqWKRSzEnp7b1wp7pd2VMbFig\" width=\"690\" height=\"438\" srcset=\"https://talk.nervos.org/uploads/default/optimized/2X/8/8988c442ef910669b612990ca301ce4b6b9dc598_2_690x438.jpeg, https://talk.nervos.org/uploads/default/optimized/2X/8/8988c442ef910669b612990ca301ce4b6b9dc598_2_1035x657.jpeg 1.5x, https://talk.nervos.org/uploads/default/optimized/2X/8/8988c442ef910669b612990ca301ce4b6b9dc598_2_1380x876.jpeg 2x\" data-dominant-color=\"D9CAC4\"><div class=\"meta\"><svg class=\"fa d-icon d-icon-far-image svg-icon\" aria-hidden=\"true\"><use href=\"#far-image\"></use></svg><span class=\"filename\">image</span><span class=\"informations\">1405×892 127 KB</span><svg class=\"fa d-icon d-icon-discourse-expand svg-icon\" aria-hidden=\"true\"><use href=\"#discourse-expand\"></use></svg></div></a></div></p>\n<p>For now, this is a solo-built project. I have tried to keep the architecture small, inspectable, and easy to maintain without requiring a large ops or protocol team.</p>\n<h2><a name=\"p-24083-problem-and-solution-1\" class=\"anchor\" href=\"#p-24083-problem-and-solution-1\" aria-label=\"Heading link\"></a>Problem and Solution</h2>\n<h3><a name=\"p-24083-the-problem-2\" class=\"anchor\" href=\"#p-24083-the-problem-2\" aria-label=\"Heading link\"></a>The problem</h3>\n<p>Sending tokens on-chain is usually transactional, but not ceremonial. Red packets are social. They are meant to be shared into a group, opened by multiple recipients, and claimed with a sense of timing, surprise, and urgency.</p>\n<p>Most wallet transfer flows do not capture that behavior well. They support “send X to Y,” but not:</p>\n<ul>\n<li>one sender, many recipients</li>\n<li>partial sequential claiming</li>\n<li>time-gated opening</li>\n<li>“claim by link” behavior</li>\n<li>reclaiming unclaimed balance after expiry</li>\n</ul>\n<h3><a name=\"p-24083-the-solution-3\" class=\"anchor\" href=\"#p-24083-the-solution-3\" aria-label=\"Heading link\"></a>The solution</h3>\n<p>pckt models the packet as a <code>single live CKB cell</code> governed by a custom lock script. Instead of keeping packet state off-chain, every claim consumes the packet cell and produces its next version. That lets the chain remain the source of truth while the frontend and backend make the experience feel native.</p>\n<p>Hosted solution: <a href=\"https://sendpckt.robaireth.dev\" rel=\"noopener nofollow ugc\">https://sendpckt.robaireth.dev</a><br>\nRepo: <a href=\"https://github.com/robaireth/pckt\" class=\"inline-onebox\" rel=\"noopener nofollow ugc\">GitHub - RobaireTH/pckt: The friendliest way to send CKB · GitHub</a></p>\n<p>The core user flow is:</p>\n<ol>\n<li>\n<p>Sender seals a packet on-chain.</p>\n</li>\n<li>\n<p>Sender shares a claim link.</p>\n</li>\n<li>\n<p>Recipients claim against the packet cell.</p>\n</li>\n<li>\n<p>The packet shrinks as claims happen.</p>\n</li>\n<li>\n<p>If claims are exhausted, the packet terminates.</p>\n</li>\n<li>\n<p>If time expires first, the sender can reclaim the remainder.</p>\n</li>\n</ol>\n<h2><a name=\"p-24083-technical-approaches-and-design-decisions-4\" class=\"anchor\" href=\"#p-24083-technical-approaches-and-design-decisions-4\" aria-label=\"Heading link\"></a>Technical Approaches and Design Decisions</h2>\n<h3><a name=\"p-24083-h-1-one-contract-one-packet-cell-5\" class=\"anchor\" href=\"#p-24083-h-1-one-contract-one-packet-cell-5\" aria-label=\"Heading link\"></a>1. One contract, one packet cell</h3>\n<p>The main design decision is that a packet is not an account, and it is not a backend object. It is a <code>single live cell</code> with explicit, serialized state.</p>\n<p>That gives a few advantages:</p>\n<ul>\n<li>\n<p>easier audit surface than a larger state machine</p>\n</li>\n<li>\n<p>no server custody</p>\n</li>\n<li>\n<p>claims are naturally serialized by cell consumption</p>\n</li>\n<li>\n<p>each state transition is verifiable from chain history</p>\n</li>\n</ul>\n<h3><a name=\"p-24083-h-2-frontend-signs-the-social-flow-backend-indexes-the-chain-6\" class=\"anchor\" href=\"#p-24083-h-2-frontend-signs-the-social-flow-backend-indexes-the-chain-6\" aria-label=\"Heading link\"></a>2. Frontend signs the social flow, backend indexes the chain</h3>\n<p><div class=\"lightbox-wrapper\"><a class=\"lightbox\" href=\"https://talk.nervos.org/uploads/default/original/2X/2/201a7313ea3c9b7f268eb50567719f04f52cb0eb.jpeg\" data-download-href=\"https://talk.nervos.org/uploads/default/201a7313ea3c9b7f268eb50567719f04f52cb0eb\" title=\"image\"><img src=\"https://talk.nervos.org/uploads/default/optimized/2X/2/201a7313ea3c9b7f268eb50567719f04f52cb0eb_2_395x500.jpeg\" alt=\"image\" data-base62-sha1=\"4zZWHREoYyY2icniFXbxaiWMSdd\" width=\"395\" height=\"500\" srcset=\"https://talk.nervos.org/uploads/default/optimized/2X/2/201a7313ea3c9b7f268eb50567719f04f52cb0eb_2_395x500.jpeg, https://talk.nervos.org/uploads/default/optimized/2X/2/201a7313ea3c9b7f268eb50567719f04f52cb0eb_2_592x750.jpeg 1.5x, https://talk.nervos.org/uploads/default/optimized/2X/2/201a7313ea3c9b7f268eb50567719f04f52cb0eb_2_790x1000.jpeg 2x\" data-dominant-color=\"D3B5B4\"><div class=\"meta\"><svg class=\"fa d-icon d-icon-far-image svg-icon\" aria-hidden=\"true\"><use href=\"#far-image\"></use></svg><span class=\"filename\">image</span><span class=\"informations\">805×1018 97.9 KB</span><svg class=\"fa d-icon d-icon-discourse-expand svg-icon\" aria-hidden=\"true\"><use href=\"#discourse-expand\"></use></svg></div></a></div><br>\n<div class=\"lightbox-wrapper\"><a class=\"lightbox\" href=\"https://talk.nervos.org/uploads/default/original/2X/e/e0ded2d333fa7c6789455e0cfcd853795a20b7b8.png\" data-download-href=\"https://talk.nervos.org/uploads/default/e0ded2d333fa7c6789455e0cfcd853795a20b7b8\" title=\"image\"><img src=\"https://talk.nervos.org/uploads/default/optimized/2X/e/e0ded2d333fa7c6789455e0cfcd853795a20b7b8_2_690x386.png\" alt=\"image\" data-base62-sha1=\"w5ilJIw8aXvjSZD03C2LVNmX2as\" width=\"690\" height=\"386\" srcset=\"https://talk.nervos.org/uploads/default/optimized/2X/e/e0ded2d333fa7c6789455e0cfcd853795a20b7b8_2_690x386.png, https://talk.nervos.org/uploads/default/optimized/2X/e/e0ded2d333fa7c6789455e0cfcd853795a20b7b8_2_1035x579.png 1.5x, https://talk.nervos.org/uploads/default/optimized/2X/e/e0ded2d333fa7c6789455e0cfcd853795a20b7b8_2_1380x772.png 2x\" data-dominant-color=\"F7F3EE\"><div class=\"meta\"><svg class=\"fa d-icon d-icon-far-image svg-icon\" aria-hidden=\"true\"><use href=\"#far-image\"></use></svg><span class=\"filename\">image</span><span class=\"informations\">1425×798 103 KB</span><svg class=\"fa d-icon d-icon-discourse-expand svg-icon\" aria-hidden=\"true\"><use href=\"#discourse-expand\"></use></svg></div></a></div></p>\n<p>The system is split into three parts:</p>\n<ul>\n<li>\n<p><code>Contract</code>: Rust CKB lock script for claim and reclaim paths</p>\n</li>\n<li>\n<p><code>Frontend</code>: React + TypeScript app using CCC to build and sign transactions</p>\n</li>\n<li>\n<p><code>Backend</code>: Rust + Axum + SQLite indexer and UX helper</p>\n</li>\n</ul>\n<p>The backend is intentionally <strong>non-authoritative</strong>. It does not hold keys, does not create truth, and can be replaced. Its role is to index packet state, provide sender/claimer views, short links, and live UX data.</p>\n<h3><a name=\"p-24083-h-3-claim-links-put-the-secret-in-the-fragment-7\" class=\"anchor\" href=\"#p-24083-h-3-claim-links-put-the-secret-in-the-fragment-7\" aria-label=\"Heading link\"></a>3. Claim links put the secret in the fragment</h3>\n<p>The claim secret lives in the URL fragment, not in backend storage. That means the browser can hold the secret client-side while the backend only sees the public short-link target. This is an important design boundary: the server helps with UX, but it should not become a custody or secret-management layer.</p>\n<h3><a name=\"p-24083-h-4-testnet-first-with-deliberate-constraints-8\" class=\"anchor\" href=\"#p-24083-h-4-testnet-first-with-deliberate-constraints-8\" aria-label=\"Heading link\"></a>4. Testnet-first, with deliberate constraints</h3>\n<p>I explicitly kept this testnet-first and avoided pretending every mode is ready for production. In particular:</p>\n<ul>\n<li>reclaim exists on-chain and is now wired into the UI</li>\n<li>sender naming is currently backend-stored and convenience-oriented, not yet decentralized identity</li>\n<li>the “lucky split” mode is constrained by payout math and safety concerns</li>\n</ul>\n<h2><a name=\"p-24083-ckb-ecosystem-relevance-9\" class=\"anchor\" href=\"#p-24083-ckb-ecosystem-relevance-9\" aria-label=\"Heading link\"></a>CKB Ecosystem Relevance</h2>\n<p>pckt is relevant to CKB because it leans into what cells are good at:</p>\n<ul>\n<li>\n<p>explicit state</p>\n</li>\n<li>\n<p>composable lock logic</p>\n</li>\n<li>\n<p>sequential consumption and recreation</p>\n</li>\n<li>\n<p>custom social/financial flows without custodial middleware</p>\n</li>\n</ul>\n<p>I believe it’s of benefit to the wider ecosystem as it is a good initiative to introduce people to the Nervos CKB by bringing in centuries old traditions onchain. A simple sharing of love!<br>\n<div class=\"lightbox-wrapper\"><a class=\"lightbox\" href=\"https://talk.nervos.org/uploads/default/original/2X/7/740c8cf8a4fd1017278600c90906119265454215.png\" data-download-href=\"https://talk.nervos.org/uploads/default/740c8cf8a4fd1017278600c90906119265454215\" title=\"image\"><img src=\"https://talk.nervos.org/uploads/default/optimized/2X/7/740c8cf8a4fd1017278600c90906119265454215_2_529x499.png\" alt=\"image\" data-base62-sha1=\"gyCh7VDX7Fz4TzXLFGM3bzkAnMp\" width=\"529\" height=\"499\" srcset=\"https://talk.nervos.org/uploads/default/optimized/2X/7/740c8cf8a4fd1017278600c90906119265454215_2_529x499.png, https://talk.nervos.org/uploads/default/optimized/2X/7/740c8cf8a4fd1017278600c90906119265454215_2_793x748.png 1.5x, https://talk.nervos.org/uploads/default/optimized/2X/7/740c8cf8a4fd1017278600c90906119265454215_2_1058x998.png 2x\" data-dominant-color=\"E7D5D0\"><div class=\"meta\"><svg class=\"fa d-icon d-icon-far-image svg-icon\" aria-hidden=\"true\"><use href=\"#far-image\"></use></svg><span class=\"filename\">image</span><span class=\"informations\">1282×1211 207 KB</span><svg class=\"fa d-icon d-icon-discourse-expand svg-icon\" aria-hidden=\"true\"><use href=\"#discourse-expand\"></use></svg></div></a></div></p>\n<h2><a name=\"p-24083-deployment-architecture-10\" class=\"anchor\" href=\"#p-24083-deployment-architecture-10\" aria-label=\"Heading link\"></a>Deployment Architecture</h2>\n<p>Current deployment shape:</p>\n<ul>\n<li>Frontend: Vite app deployed separately</li>\n<li>Backend: <a href=\"http://Fly.io\" rel=\"noopener nofollow ugc\">Fly.io</a> app</li>\n<li>Database: SQLite on Fly volume</li>\n<li>Chain target: CKB testnet (Pudge)</li>\n</ul>\n<p>The backend runs as:</p>\n<ul>\n<li>\n<p>packet indexer</p>\n</li>\n<li>\n<p>packet/query API</p>\n</li>\n<li>\n<p>short-link service</p>\n</li>\n<li>\n<p>price helper</p>\n</li>\n<li>\n<p>relay endpoint for signed transactions</p>\n</li>\n</ul>\n<p>The frontend is configured by environment variables with:</p>\n<ul>\n<li>testnet RPC URL</li>\n<li>active contract code hash</li>\n<li>contract outpoint</li>\n<li>backend URL</li>\n</ul>\n<h2><a name=\"p-24083-security-considerations-11\" class=\"anchor\" href=\"#p-24083-security-considerations-11\" aria-label=\"Heading link\"></a>Security Considerations</h2>\n<h3><a name=\"p-24083-h-1-self-custody-12\" class=\"anchor\" href=\"#p-24083-h-1-self-custody-12\" aria-label=\"Heading link\"></a>1. Self-custody</h3>\n<p>Funds are locked on-chain. The backend never has authority to move them.</p>\n<h3><a name=\"p-24083-h-2-non-authoritative-backend-13\" class=\"anchor\" href=\"#p-24083-h-2-non-authoritative-backend-13\" aria-label=\"Heading link\"></a>2. Non-authoritative backend</h3>\n<p>The backend is replaceable and should be treated as UX infrastructure, not a trust anchor. It’s even the contract that rejects multiple claims, not the backend.</p>\n<h3><a name=\"p-24083-h-3-claim-secret-handling-14\" class=\"anchor\" href=\"#p-24083-h-3-claim-secret-handling-14\" aria-label=\"Heading link\"></a>3. Claim secret handling</h3>\n<p>The claim secret sits in the URL fragment so it is not automatically sent to servers. This avoids a major class of accidental backend custody.</p>\n<h3><a name=\"p-24083-h-4-reorg-and-index-correctness-15\" class=\"anchor\" href=\"#p-24083-h-4-reorg-and-index-correctness-15\" aria-label=\"Heading link\"></a>4. Reorg and index correctness</h3>\n<p>The backend includes reorg handling and block-hash rollback logic because packet state derived from chain history must survive reorgs cleanly.</p>\n<h3><a name=\"p-24083-h-5-explicitly-bounded-feature-set-16\" class=\"anchor\" href=\"#p-24083-h-5-explicitly-bounded-feature-set-16\" aria-label=\"Heading link\"></a>5. Explicitly bounded feature set</h3>\n<p>I do not want unsafe “it sort of works” behavior around payout math or reclaim timing. Where a mode looks questionable, I prefer to restrict it until it is clean.</p>\n<h2><a name=\"p-24083-why-i-dont-like-the-maths-behind-lucky-splits-for-now-17\" class=\"anchor\" href=\"#p-24083-why-i-dont-like-the-maths-behind-lucky-splits-for-now-17\" aria-label=\"Heading link\"></a>Why I Don’t Like the Maths Behind Lucky Splits For Now</h2>\n<p>I do not dislike the <strong>idea</strong> of lucky splits. I dislike the current <strong>math and operational risk profile</strong> of lucky splits in this implementation.</p>\n<p>The problem is: once you move from fixed shares to random shares, you need to guarantee that:</p>\n<ul>\n<li>\n<p>each claim remains above minimum live-cell capacity</p>\n</li>\n<li>\n<p>enough capacity is reserved for future claims</p>\n</li>\n<li>\n<p>the final claim and reclaim paths still behave safely</p>\n</li>\n<li>\n<p>the user-facing preview matches what on-chain logic will actually allow</p>\n</li>\n</ul>\n<p>That is easy to get subtly wrong.</p>\n<p>In practice, lucky mode becomes a product-security problem, not just a product-design problem. If the random lower bound is too low, you can create unclaimable outputs. If the reservation math is too optimistic, you can strand capacity. If frontend prediction diverges from contract math, users get misleading expectations.</p>\n<p>For now, I prefer the stricter stance:</p>\n<ul>\n<li>fixed and timed-fixed remain usable</li>\n<li>lucky mode is something I would only re-enable once I am satisfied that the lower-bound math, reservation rules, and UI expectations are all aligned</li>\n</ul>\n<p>I would rather disappoint users with a disabled mode than lock them into a half-correct one.</p>\n<h2><a name=\"p-24083-maintenance-plan-18\" class=\"anchor\" href=\"#p-24083-maintenance-plan-18\" aria-label=\"Heading link\"></a>Maintenance Plan</h2>\n<p>I plan to use this Talk Nervos thread itself as part of the maintenance loop.</p>\n<p>Specifically:</p>\n<ul>\n<li>I will post updates there as features or fixes land</li>\n<li>I will note contract redeploys and testnet config changes here</li>\n<li>I will use the thread to surface known limitations honestly</li>\n<li>I will treat user reports in the thread as a lightweight public changelog and maintenance channel</li>\n</ul>\n<p>The near-term maintenance priorities are:</p>\n<ol>\n<li>\n<p>stabilize sender/claimer UX</p>\n</li>\n<li>\n<p>keep reclaim flow reliable and understandable</p>\n</li>\n<li>\n<p>tighten profile/name semantics</p>\n</li>\n<li>\n<p>revisit lucky split math only when it is safe</p>\n</li>\n<li>\n<p>continue testnet usage before thinking seriously about mainnet</p>\n</li>\n</ol>\n<h2><a name=\"p-24083-closing-19\" class=\"anchor\" href=\"#p-24083-closing-19\" aria-label=\"Heading link\"></a>Closing</h2>\n<p>pckt is an attempt to build something small, social, and unmistakably native to CKB’s cell model. It is not trying to be a generic wallet feature (Though it can be). It is trying to make a familiar ritual feel right on-chain.</p>\n<p>If that resonates, I’d love feedback moat importantly on whether the identity layer should remain simple or move toward a more formal DID-based model later.</p>\n<hr>\n<h2><a name=\"p-24083-zh-20\" class=\"anchor\" href=\"#p-24083-zh-20\" aria-label=\"Heading link\"></a>ZH</h2>\n<hr>\n<p><code>pckt</code> 是一个类似红包的 CKB 应用。发送者将 CKB 封装成一个链上数据包，分享一个链接，接收者可以从该数据包中认领代币，直到数据包耗尽或过期。如果数据包在所有代币被认领之前过期，发送者可以重新认领剩余的代币。</p>\n<p><div class=\"lightbox-wrapper\"><a class=\"lightbox\" href=\"https://talk.nervos.org/uploads/default/original/2X/8/8988c442ef910669b612990ca301ce4b6b9dc598.jpeg\" data-download-href=\"https://talk.nervos.org/uploads/default/8988c442ef910669b612990ca301ce4b6b9dc598\" title=\"image\"><img src=\"https://talk.nervos.org/uploads/default/optimized/2X/8/8988c442ef910669b612990ca301ce4b6b9dc598_2_690x438.jpeg\" alt=\"image\" data-base62-sha1=\"jCGqWKRSzEnp7b1wp7pd2VMbFig\" width=\"690\" height=\"438\" srcset=\"https://talk.nervos.org/uploads/default/optimized/2X/8/8988c442ef910669b612990ca301ce4b6b9dc598_2_690x438.jpeg, https://talk.nervos.org/uploads/default/optimized/2X/8/8988c442ef910669b612990ca301ce4b6b9dc598_2_1035x657.jpeg 1.5x, https://talk.nervos.org/uploads/default/optimized/2X/8/8988c442ef910669b612990ca301ce4b6b9dc598_2_1380x876.jpeg 2x\" data-dominant-color=\"D9CAC4\"><div class=\"meta\"><svg class=\"fa d-icon d-icon-far-image svg-icon\" aria-hidden=\"true\"><use href=\"#far-image\"></use></svg><span class=\"filename\">image</span><span class=\"informations\">1405×892 127 KB</span><svg class=\"fa d-icon d-icon-discourse-expand svg-icon\" aria-hidden=\"true\"><use href=\"#discourse-expand\"></use></svg></div></a></div></p>\n<p>目前，这是一个由我独立开发的项目。我努力保持架构的简洁、易于检查和维护，无需庞大的运维或协议团队。</p>\n<h2><a name=\"p-24083-h-21\" class=\"anchor\" href=\"#p-24083-h-21\" aria-label=\"Heading link\"></a>问题与解决方案</h2>\n<h3><a name=\"p-24083-h-22\" class=\"anchor\" href=\"#p-24083-h-22\" aria-label=\"Heading link\"></a>问题</h3>\n<p>链上发送代币通常是交易性的，但缺乏仪式感。红包则具有社交性。它们应该被分享给一群人，由多个接收者打开，并以一种带有时机感、惊喜感和紧迫感的方式认领。</p>\n<p>大多数钱包的转账流程都无法很好地体现这种行为。他们支持“向 Y 发送 X”，但不支持：</p>\n<ul>\n<li>\n<p>一个发送方，多个接收方</p>\n</li>\n<li>\n<p>部分顺序声明</p>\n</li>\n<li>\n<p>时间门控开启</p>\n</li>\n<li>\n<p>“通过链接声明”行为</p>\n</li>\n<li>\n<p>过期后回收未声明余额</p>\n</li>\n</ul>\n<h3><a name=\"p-24083-h-23\" class=\"anchor\" href=\"#p-24083-h-23\" aria-label=\"Heading link\"></a>解决方案</h3>\n<p>pckt 将数据包建模为由自定义锁定脚本控制的“单个活跃 CKB 单元”。数据包状态并非保存在链下，而是每次声明都会消耗数据包单元并生成其下一个版本。这使得链始终保持真实性，同时前端和后端提供原生体验。</p>\n<p>托管解决方案：<a href=\"https://sendpckt.robaireth.dev\" rel=\"noopener nofollow ugc\">https://sendpckt.robaireth.dev</a></p>\n<p>代码库：<a href=\"https://github.com/robaireth/pckt\" class=\"inline-onebox\" rel=\"noopener nofollow ugc\">GitHub - RobaireTH/pckt: The friendliest way to send CKB · GitHub</a></p>\n<p>核心用户流程如下：</p>\n<ol>\n<li>\n<p>发送方在链上密封数据包。</p>\n</li>\n<li>\n<p>发送方共享声明链接。</p>\n</li>\n<li>\n<p>接收方针对数据包单元进行声明。</p>\n</li>\n<li>\n<p>随着声明的进行，数据包会逐渐缩小。</p>\n</li>\n<li>\n<p>如果所有请求权都已用尽，则数据包终止。</p>\n</li>\n<li>\n<p>如果时间先到期，发送方可以重新获取剩余的请求权。</p>\n</li>\n</ol>\n<h2><a name=\"p-24083-h-24\" class=\"anchor\" href=\"#p-24083-h-24\" aria-label=\"Heading link\"></a>技术方案和设计决策</h2>\n<h3><a name=\"p-24083-h-1-25\" class=\"anchor\" href=\"#p-24083-h-1-25\" aria-label=\"Heading link\"></a>1. 一个合约，一个数据包单元</h3>\n<p>主要的设计决策是：数据包不是账户，也不是后端对象。它是一个具有明确序列化状态的“单个活动单元”。</p>\n<p>这带来了一些优势：</p>\n<ul>\n<li>\n<p>比大型状态机更容易审计</p>\n</li>\n<li>\n<p>无需服务器托管</p>\n</li>\n<li>\n<p>声明自然地按单元消耗进行序列化</p>\n</li>\n<li>\n<p>每个状态转换都可以从链历史记录中验证</p>\n</li>\n</ul>\n<h3><a name=\"p-24083-h-2-26\" class=\"anchor\" href=\"#p-24083-h-2-26\" aria-label=\"Heading link\"></a>2. 前端对社交流进行签名，后端对链进行索引</h3>\n<p><div class=\"lightbox-wrapper\"><a class=\"lightbox\" href=\"https://talk.nervos.org/uploads/default/original/2X/2/201a7313ea3c9b7f268eb50567719f04f52cb0eb.jpeg\" data-download-href=\"https://talk.nervos.org/uploads/default/201a7313ea3c9b7f268eb50567719f04f52cb0eb\" title=\"image\"><img src=\"https://talk.nervos.org/uploads/default/optimized/2X/2/201a7313ea3c9b7f268eb50567719f04f52cb0eb_2_395x500.jpeg\" alt=\"image\" data-base62-sha1=\"4zZWHREoYyY2icniFXbxaiWMSdd\" width=\"395\" height=\"500\" srcset=\"https://talk.nervos.org/uploads/default/optimized/2X/2/201a7313ea3c9b7f268eb50567719f04f52cb0eb_2_395x500.jpeg, https://talk.nervos.org/uploads/default/optimized/2X/2/201a7313ea3c9b7f268eb50567719f04f52cb0eb_2_592x750.jpeg 1.5x, https://talk.nervos.org/uploads/default/optimized/2X/2/201a7313ea3c9b7f268eb50567719f04f52cb0eb_2_790x1000.jpeg 2x\" data-dominant-color=\"D3B5B4\"><div class=\"meta\"><svg class=\"fa d-icon d-icon-far-image svg-icon\" aria-hidden=\"true\"><use href=\"#far-image\"></use></svg><span class=\"filename\">image</span><span class=\"informations\">805×1018 97.9 KB</span><svg class=\"fa d-icon d-icon-discourse-expand svg-icon\" aria-hidden=\"true\"><use href=\"#discourse-expand\"></use></svg></div></a></div></p>\n<p><div class=\"lightbox-wrapper\"><a class=\"lightbox\" href=\"https://talk.nervos.org/uploads/default/original/2X/e/e0ded2d333fa7c6789455e0cfcd853795a20b7b8.png\" data-download-href=\"https://talk.nervos.org/uploads/default/e0ded2d333fa7c6789455e0cfcd853795a20b7b8\" title=\"image\"><img src=\"https://talk.nervos.org/uploads/default/optimized/2X/e/e0ded2d333fa7c6789455e0cfcd853795a20b7b8_2_690x386.png\" alt=\"image\" data-base62-sha1=\"w5ilJIw8aXvjSZD03C2LVNmX2as\" width=\"690\" height=\"386\" srcset=\"https://talk.nervos.org/uploads/default/optimized/2X/e/e0ded2d333fa7c6789455e0cfcd853795a20b7b8_2_690x386.png, https://talk.nervos.org/uploads/default/optimized/2X/e/e0ded2d333fa7c6789455e0cfcd853795a20b7b8_2_1035x579.png 1.5x, https://talk.nervos.org/uploads/default/optimized/2X/e/e0ded2d333fa7c6789455e0cfcd853795a20b7b8_2_1380x772.png 2x\" data-dominant-color=\"F7F3EE\"><div class=\"meta\"><svg class=\"fa d-icon d-icon-far-image svg-icon\" aria-hidden=\"true\"><use href=\"#far-image\"></use></svg><span class=\"filename\">image</span><span class=\"informations\">1425×798 103 KB</span><svg class=\"fa d-icon d-icon-discourse-expand svg-icon\" aria-hidden=\"true\"><use href=\"#discourse-expand\"></use></svg></div></a></div></p>\n<p>该系统分为三个部分：</p>\n<ul>\n<li>\n<p><code>Contract</code>：用于声明和回收路径的 Rust CKB 锁定脚本</p>\n</li>\n<li>\n<p><code>Frontend</code>：使用 CCC 构建和签名交易的 React + TypeScript 应用</p>\n</li>\n<li>\n<p><code>Backend</code>：Rust + Axum + SQLite 索引器和 UX 辅助工具</p>\n</li>\n</ul>\n<p>后端有意设计为<strong>非权威</strong>。它不持有密钥，不创造真理，并且可以被替换。它的作用是索引数据包状态，提供发送方/声明方视图、短链接和实时用户体验数据。</p>\n<h3><a name=\"p-24083-h-3-27\" class=\"anchor\" href=\"#p-24083-h-3-27\" aria-label=\"Heading link\"></a>3. 声明链接将密钥放在片段中</h3>\n<p>声明密钥存储在 URL 片段中，而不是后端存储中。这意味着浏览器可以在客户端持有密钥，而后端只能看到公开的短链接目标。这是一个重要的设计边界：服务器有助于用户体验，但不应成为密钥保管层或密钥管理层。</p>\n<h3><a name=\"p-24083-h-4-28\" class=\"anchor\" href=\"#p-24083-h-4-28\" aria-label=\"Heading link\"></a>4. 测试网优先，并设定了明确的限制</h3>\n<p>我特意坚持测试网优先的原则，避免假装所有模式都已准备好用于生产环境。具体而言：</p>\n<ul>\n<li>\n<p>资金回收功能已上线，并集成到用户界面中</p>\n</li>\n<li>\n<p>发送者名称目前存储在后端，仅供方便使用，尚未实现去中心化身份</p>\n</li>\n<li>\n<p>“幸运平分”模式受限于支付算法和安全问题。</p>\n</li>\n</ul>\n<h2><a name=\"p-24083-ckb-29\" class=\"anchor\" href=\"#p-24083-ckb-29\" aria-label=\"Heading link\"></a>CKB 生态系统相关性</h2>\n<p>pckt 与 CKB 的相关性在于它充分利用了 Cell 的优势：</p>\n<ul>\n<li>\n<p>显式状态</p>\n</li>\n<li>\n<p>可组合的锁逻辑</p>\n</li>\n<li>\n<p>顺序消费和再利用</p>\n</li>\n<li>\n<p>无需托管中间件的自定义社交/金融流程</p>\n</li>\n</ul>\n<p>我相信这对整个生态系统都有益处，因为它是一个很好的举措，通过将几个世纪以来的传统引入链上，向人们介绍 Nervos CKB。这是一种简单的分享！</p>\n<p><div class=\"lightbox-wrapper\"><a class=\"lightbox\" href=\"https://talk.nervos.org/uploads/default/original/2X/7/740c8cf8a4fd1017278600c90906119265454215.png\" data-download-href=\"https://talk.nervos.org/uploads/default/740c8cf8a4fd1017278600c90906119265454215\" title=\"image\"><img src=\"https://talk.nervos.org/uploads/default/optimized/2X/7/740c8cf8a4fd1017278600c90906119265454215_2_529x499.png\" alt=\"image\" data-base62-sha1=\"gyCh7VDX7Fz4TzXLFGM3bzkAnMp\" width=\"529\" height=\"499\" srcset=\"https://talk.nervos.org/uploads/default/optimized/2X/7/740c8cf8a4fd1017278600c90906119265454215_2_529x499.png, https://talk.nervos.org/uploads/default/optimized/2X/7/740c8cf8a4fd1017278600c90906119265454215_2_793x748.png 1.5x, https://talk.nervos.org/uploads/default/optimized/2X/7/740c8cf8a4fd1017278600c90906119265454215_2_1058x998.png 2x\" data-dominant-color=\"E7D5D0\"><div class=\"meta\"><svg class=\"fa d-icon d-icon-far-image svg-icon\" aria-hidden=\"true\"><use href=\"#far-image\"></use></svg><span class=\"filename\">image</span><span class=\"informations\">1282×1211 207 KB</span><svg class=\"fa d-icon d-icon-discourse-expand svg-icon\" aria-hidden=\"true\"><use href=\"#discourse-expand\"></use></svg></div></a></div></p>\n<h2><a name=\"p-24083-h-30\" class=\"anchor\" href=\"#p-24083-h-30\" aria-label=\"Heading link\"></a>部署架构</h2>\n<p>当前部署结构：</p>\n<ul>\n<li>\n<p>前端：独立部署的 Vite 应用</p>\n</li>\n<li>\n<p>后端：<a href=\"http://Fly.io\" rel=\"noopener nofollow ugc\">Fly.io</a> 应用</p>\n</li>\n<li>\n<p>数据库：Fly 卷上的 SQLite 数据库</p>\n</li>\n<li>\n<p>目标链：CKB 测试网 (Pudge)</p>\n</li>\n</ul>\n<p>后端运行方式如下：</p>\n<ul>\n<li>\n<p>数据包索引器</p>\n</li>\n<li>\n<p>数据包/查询 API</p>\n</li>\n<li>\n<p>短链接服务</p>\n</li>\n<li>\n<p>价格辅助工具</p>\n</li>\n<li>\n<p>已签名交易的中继端点</p>\n</li>\n</ul>\n<p>前端通过环境变量配置，包括：</p>\n<ul>\n<li>\n<p>测试网 RPC URL</p>\n</li>\n<li>\n<p>活动合约代码哈希值</p>\n</li>\n<li>\n<p>合约输出点</p>\n</li>\n<li>\n<p>后端 URL</p>\n</li>\n</ul>\n<h2><a name=\"p-24083-h-31\" class=\"anchor\" href=\"#p-24083-h-31\" aria-label=\"Heading link\"></a>安全注意事项</h2>\n<h3><a name=\"p-24083-h-1-32\" class=\"anchor\" href=\"#p-24083-h-1-32\" aria-label=\"Heading link\"></a>1. 自保</h3>\n<p>资金锁定在链上。后端无权移动资金。</p>\n<h3><a name=\"p-24083-h-2-33\" class=\"anchor\" href=\"#p-24083-h-2-33\" aria-label=\"Heading link\"></a>2. 非权威后端</h3>\n<p>后端是可替换的，应该被视为用户体验基础设施，而不是信任锚点。甚至拒绝多个声明的也是合约，而不是后端。</p>\n<h3><a name=\"p-24083-h-3-34\" class=\"anchor\" href=\"#p-24083-h-3-34\" aria-label=\"Heading link\"></a>3. 声明密钥处理</h3>\n<p>声明密钥位于 URL 片段中，因此不会自动发送到服务器。这避免了一类主要的意外后端保管风险。</p>\n<h3><a name=\"p-24083-h-4-35\" class=\"anchor\" href=\"#p-24083-h-4-35\" aria-label=\"Heading link\"></a>4. 重组和索引正确性</h3>\n<p>后端包含重组处理和区块哈希回滚逻辑，因为从链历史中派生的包状态必须在重组后保持完好。</p>\n<h3><a name=\"p-24083-h-5-36\" class=\"anchor\" href=\"#p-24083-h-5-36\" aria-label=\"Heading link\"></a>5. 明确限定的功能集</h3>\n<p>我不希望在支付计算或回收时间方面出现不安全的“勉强能用”的行为。如果某个模式看起来有问题，我倾向于限制它，直到它变得安全为止。</p>\n<h2><a name=\"p-24083-h-37\" class=\"anchor\" href=\"#p-24083-h-37\" aria-label=\"Heading link\"></a>为什么我目前不喜欢幸运分割背后的数学原理</h2>\n<p>我并不反对幸运分割的<strong>想法</strong>。我不喜欢当前实现中“幸运拆分”的<strong>数学原理和操作风险</strong>。</p>\n<p>问题在于：一旦从固定份额改为随机份额，就需要保证：</p>\n<ul>\n<li>\n<p>每次认领都保持在最低活跃单元容量之上</p>\n</li>\n<li>\n<p>为未来的认领预留足够的容量</p>\n</li>\n<li>\n<p>最终认领和赎回路径仍然安全</p>\n</li>\n<li>\n<p>用户预览与链上逻辑实际允许的情况相符</p>\n</li>\n</ul>\n<p>这一点很容易出现细微的错误。</p>\n<p>实际上，“幸运模式”会演变成产品安全问题，而不仅仅是产品设计问题。如果随机下限设置得太低，可能会导致无法认领的输出结果。如果预留计算过于乐观，则可能导致资源闲置。如果前端预测与合同计算存在偏差，则会产生误导性的预期。</p>\n<p>目前，我倾向于采取更严格的立场：</p>\n<ul>\n<li>\n<p>固定模式和限时固定模式仍然可用</p>\n</li>\n<li>\n<p>只有在我确信下限计算、预留规则和用户界面预期都一致后，我才会重新启用“幸运模式”。</p>\n</li>\n</ul>\n<p>我宁愿禁用该模式让用户失望，也不愿让他们使用一个半真半假的模式。</p>\n<h2><a name=\"p-24083-h-38\" class=\"anchor\" href=\"#p-24083-h-38\" aria-label=\"Heading link\"></a>维护计划</h2>\n<p>我计划将此 Talk Nervos 讨论帖本身作为维护流程的一部分。</p>\n<p>具体来说：</p>\n<ul>\n<li>\n<p>我会在此发布新功能或修复的更新</p>\n</li>\n<li>\n<p>我会在此记录合约重新部署和测试网配置变更</p>\n</li>\n<li>\n<p>我会在此帖中如实说明已知的限制</p>\n</li>\n<li>\n<p>我会将帖子中的用户报告视为一个轻量级的公开变更日志和维护渠道</p>\n</li>\n</ul>\n<p>近期维护重点如下：</p>\n<ol>\n<li>\n<p>稳定发送方/领取方的用户体验</p>\n</li>\n<li>\n<p>保持回收流程的可靠性和易懂性</p>\n</li>\n<li>\n<p>完善个人资料/名称语义</p>\n</li>\n<li>\n<p>仅在安全的情况下重新审视幸运拆分算法</p>\n</li>\n<li>\n<p>在认真考虑主网之前，继续使用测试网</p>\n</li>\n</ol>\n<h2><a name=\"p-24083-h-39\" class=\"anchor\" href=\"#p-24083-h-39\" aria-label=\"Heading link\"></a>结束语</h2>\n<p>pckt 旨在构建一个小型、社交化且与 CKB 的 cell 模型完美契合的原生应用。它并非旨在成为一个通用的钱包功能（尽管它也可以做到）。它的目标是让熟悉的仪式感在链上自然流畅地呈现。</p>\n<p>如果这引起了您的共鸣，我非常希望收到反馈，尤其希望了解身份层是否应该保持简单，还是应该在未来转向更正式的基于 DID 的模型。</p>",
          "like_count": 0,
          "quote_count": 0
        },
        {
          "post_id": 24088,
          "post_number": 2,
          "topic_id": 10220,
          "topic_title": "Pckt: A Friendly Way to Send CKB | pckt：一种友好的发送 CKB 的方式",
          "topic_slug": "pckt-a-friendly-way-to-send-ckb-pckt-ckb",
          "author": "Yeti",
          "created_at": "2026-04-30T21:26:58.163000+00:00",
          "updated_at": "2026-04-30T21:26:58.163000+00:00",
          "reply_to_post_number": null,
          "url": "https://talk.nervos.org/t/pckt-a-friendly-way-to-send-ckb-pckt-ckb/10220/2",
          "content_text": "Hi @RobaireTH, I’m not trying to put your project down here, but just wanted to bring up that something very similar (in concept at least) has already been developed a couple of years ago by a member here @yixiu.ckbfans.bit.\nhttps://joygift.cc/",
          "content_html": "<p>Hi <a class=\"mention\" href=\"/u/robaireth\">@RobaireTH</a>, I’m not trying to put your project down here, but just wanted to bring up that something very similar (in concept at least) has already been developed a couple of years ago by a member here <a class=\"mention\" href=\"/u/yixiu.ckbfans.bit\">@yixiu.ckbfans.bit</a>.</p>\n<p><a href=\"https://joygift.cc/\">https://joygift.cc/</a></p>",
          "like_count": 0,
          "quote_count": 0
        },
        {
          "post_id": 24089,
          "post_number": 3,
          "topic_id": 10220,
          "topic_title": "Pckt: A Friendly Way to Send CKB | pckt：一种友好的发送 CKB 的方式",
          "topic_slug": "pckt-a-friendly-way-to-send-ckb-pckt-ckb",
          "author": "RobaireTH",
          "created_at": "2026-05-01T02:18:46.170000+00:00",
          "updated_at": "2026-05-01T02:18:46.170000+00:00",
          "reply_to_post_number": 2,
          "url": "https://talk.nervos.org/t/pckt-a-friendly-way-to-send-ckb-pckt-ckb/10220/3",
          "content_text": "Thanks @Yeti for brinnging this up., and, yeah, I don’t taje ut as putting the project down.\nI checked out JoyGift and could see there’s overlap across concepts (wrapping of gift, splits and reclaim policies). JoyGift is JoyID Oriented/native while what I’m exploring with pckt is a more contract-centric and self-custodial model where the packet itself is treated as an on-chain state object, claims/reclaims are explicit chain transitions, and the backend is intentionally non-authoritative.\nWhile I acknowledge this, I will like to not see it as ‘the same project already exists’ but as a real use case builders in the ecosystem found worth exploring on CKB.\nOnce again, I appreciate the pointer. I will look more closely at JoyGift and learn from their implementation. Seems they got the lucky splits right while I’m still sitting at math. @yixiu.ckbfans.bit ,kudos",
          "content_html": "<p>Thanks <a class=\"mention\" href=\"/u/yeti\">@Yeti</a>  for brinnging this up., and, yeah, I don’t taje ut as putting the project down.</p>\n<p>I checked out JoyGift and could see there’s overlap across concepts (wrapping of gift, splits and reclaim policies). JoyGift is JoyID Oriented/native while what I’m exploring with pckt is a more contract-centric and self-custodial model where the packet itself is treated as an on-chain state object, claims/reclaims are explicit chain transitions, and the backend is intentionally non-authoritative.</p>\n<p>While I acknowledge this, I will like to not see it as ‘the same project already exists’ but as a real use case builders in the ecosystem found worth exploring on CKB.</p>\n<p>Once again, I appreciate the pointer. I will look more closely at JoyGift and learn from their implementation. Seems they got the lucky splits right while I’m still sitting at math. <a class=\"mention\" href=\"/u/yixiu.ckbfans.bit\">@yixiu.ckbfans.bit</a>  ,kudos <img src=\"https://talk.nervos.org/images/emoji/apple/flexed_biceps.png?v=15\" title=\":flexed_biceps:\" class=\"emoji\" alt=\":flexed_biceps:\" loading=\"lazy\" width=\"20\" height=\"20\"></p>",
          "like_count": 0,
          "quote_count": 0
        },
        {
          "post_id": 24092,
          "post_number": 4,
          "topic_id": 10220,
          "topic_title": "Pckt: A Friendly Way to Send CKB | pckt：一种友好的发送 CKB 的方式",
          "topic_slug": "pckt-a-friendly-way-to-send-ckb-pckt-ckb",
          "author": "Yeti",
          "created_at": "2026-05-01T06:46:59.328000+00:00",
          "updated_at": "2026-05-01T06:46:59.328000+00:00",
          "reply_to_post_number": 3,
          "url": "https://talk.nervos.org/t/pckt-a-friendly-way-to-send-ckb-pckt-ckb/10220/4",
          "content_text": "Hi mate, yeah, I’m happy someone is going to carry this concept forward, I like it.\nI used Joygift a lot when the Joyid Telegram was really active, mostly with people outside the CKB ecosystem so it was a great way to introduce new users to CKB by gifting them tokens and the gamified ‘race’ to claim the gifts made it fun!\nAlso, because of CKB’s storage requirements, I think this sort of thing could be used in some interesting marketing ways to entice users outside of CKB to take part in things like token airdrops and DOB mints where they also need small amounts of CKB to store these assets.",
          "content_html": "<p>Hi mate, yeah, I’m happy someone is going to carry this concept forward, I like it.</p>\n<p>I used Joygift a lot when the Joyid Telegram was really active, mostly with people outside the CKB ecosystem so it was a great way to introduce new users to CKB by gifting them tokens and the gamified ‘race’ to claim the gifts made it fun!</p>\n<p>Also, because of CKB’s storage requirements, I think this sort of thing could be used in some interesting marketing ways to entice users outside of CKB to take part in things like token airdrops and DOB mints where they also need small amounts of CKB to store these assets.</p>",
          "like_count": 0,
          "quote_count": 0
        },
        {
          "post_id": 24099,
          "post_number": 5,
          "topic_id": 10220,
          "topic_title": "Pckt: A Friendly Way to Send CKB | pckt：一种友好的发送 CKB 的方式",
          "topic_slug": "pckt-a-friendly-way-to-send-ckb-pckt-ckb",
          "author": "joshyates1980",
          "created_at": "2026-05-01T15:55:22.939000+00:00",
          "updated_at": "2026-05-01T15:55:22.939000+00:00",
          "reply_to_post_number": 4,
          "url": "https://talk.nervos.org/t/pckt-a-friendly-way-to-send-ckb-pckt-ckb/10220/5",
          "content_text": "Yes, introducing CKB with pckt would be a great addition to the Nervos ecosystem whereas most of my CKB gifts through Joy had their limitations (for personal reasons), but pckt appears to have a more solid approach and the clean UI finishes off a nice polish.",
          "content_html": "<p>Yes, introducing CKB with pckt would be a great addition to the Nervos ecosystem whereas most of my CKB gifts through Joy had their limitations (for personal reasons), but pckt appears to have a more solid approach and the clean UI finishes off a nice polish.</p>",
          "like_count": 0,
          "quote_count": 0
        }
      ]
    },
    {
      "topic_id": 10224,
      "title": "Feature Preview: `moves` in CellScript",
      "slug": "feature-preview-moves-in-cellscript",
      "url": "https://talk.nervos.org/t/feature-preview-moves-in-cellscript/10224",
      "created_at": "2026-05-01T15:34:27.229000+00:00",
      "last_posted_at": "2026-05-01T15:34:27.304000+00:00",
      "category_id": 49,
      "tags": [
        "CKB-VM",
        "CellScript"
      ],
      "posters": [
        "Original Poster, Most Recent Poster"
      ],
      "recent_posts": [
        {
          "post_id": 24098,
          "post_number": 1,
          "topic_id": 10224,
          "topic_title": "Feature Preview: `moves` in CellScript",
          "topic_slug": "feature-preview-moves-in-cellscript",
          "author": "ArthurZhang",
          "created_at": "2026-05-01T15:34:27.304000+00:00",
          "updated_at": "2026-05-01T17:25:17.156000+00:00",
          "reply_to_post_number": null,
          "url": "https://talk.nervos.org/t/feature-preview-moves-in-cellscript/10224/1",
          "content_text": "Hi, community,\nThank you again for the feedback after last week’s early CellScript preview: CellScript: A DSL for cell-based contracts.\nThe comments were genuinely useful, especially around one boundary: protocol verification logic vs. business workflow.\nThis post is a current 0.13 direction update focused on state transitions, written to match what the implementation supports today.\nState should be visible. Transitions should be explicit. Compiler magic should not mutate your Molecule evidence layout behind your back.\nWhat CellScript is trying to model\nOn CKB, a contract validates a transaction-level transformation: input cells are consumed, output cells are created, and the script checks whether that transformation is allowed.\nSo in CellScript, an action is a protocol verifier case, not a UI step and not a business workflow task.\nExamples of protocol verbs:\naccept: live offer → filled offer\ncancel: live offer → cancelled offer\nclaim: open receipt → claimed receipt\nrelease: locked asset → released asset\n0.13 syntax: explicit state as data\nState is explicit in the resource data:\nenum OfferState {\nCreated,\nLive,\nFilled,\nCancelled,\nExpired,\n}\nresource Offer {\nstate: OfferState,\nseller: Bytes32,\nbuyer: Bytes32,\nprice: u128,\n}\nImportant: enum order gives encoding identity, not lifecycle destiny.\nLive, Filled, Cancelled are names of variants, not an implied linear flow.\n0.13 transition model: declared graph + action-level moves\nIn current implementation, allowed edges are declared explicitly:\nstate_machine OfferFlow for Offer.state {\nLive -> Filled by accept;\nLive -> Cancelled by cancel;\nLive -> Expired by expire;\n}\nThen each action binds to one edge with moves in the action header:\naction accept(input: Offer)\nmoves input.state Live -> Filled\n{\nconsume input\ncreate Offer {\nstate: OfferState::Filled,\nseller: input.seller,\nbuyer: tx.signer(),\nprice: input.price,\n}\n// explicit guards/invariants\n// require ...\n}\nAnother action can bind another edge:\naction cancel(input: Offer)\nmoves input.state Live -> Cancelled\n{\nconsume input\ncreate Offer {\nstate: OfferState::Cancelled,\nseller: input.seller,\nbuyer: input.buyer,\nprice: input.price,\n}\n// explicit guards/invariants\n// require ...\n}\nThis keeps transition intent close to the verifier case that justifies it.\nWhat require is for (and why it still matters)\nmoves is narrow: it encodes the state edge.\nrequire remains the main tool for proof obligations such as:\nauthorization (signed_by(...), signer checks)\nfield preservation / anti-tamper invariants\nnumeric bounds and timing constraints\ncross-cell relationships and conservation checks\nIn short:\nmoves = transition edge\nrequire = guards and invariants\nBoth are needed.\nWhat this design intentionally avoids\nCurrent direction is explicitly not:\nhidden lifecycle field injection\nautomatic Molecule layout mutation\nschema-hidden workflow machinery\n“business process engine” semantics in the verifier DSL\nCKB cell data is verifier evidence. Keeping the data surface explicit is a core auditability goal.\nPerformance posture\nmoves is intended to be low-overhead and predictable.\nIt should compile to straightforward transition validation, without hidden runtime workflow machinery.\nTo stay precise: we should avoid claiming cycle-equivalence to any specific handwritten pattern in all cases, because generated checks may include transition/range validation around consumed/created state.\nDirection: explicit, transparent, cost-conscious.\n0.13 direction summary\nFor 0.13, the working direction is:\nexplicit enum-based state fields in cell data\nexplicit transition graph declaration (state_machine Type.field { ... })\naction-level moves binding one verifier action to one declared edge\nexplicit require guards/invariants\nno hidden state injection\nno Molecule layout mutation\nno general business workflow DSL\nState is data. Transition is policy. Guard is proof.\nThis is still a preview direction, not final doctrine.\nIf you have a real CKB protocol where this model causes major boilerplate or audit friction, I would really like to see that example.",
          "content_html": "<p>Hi, community,</p>\n<p>Thank you again for the feedback after last week’s early CellScript preview: <a href=\"https://talk.nervos.org/t/cellscript-a-dsl-for-cell-based-contracts/\">CellScript: A DSL for cell-based contracts</a>.<br>\nThe comments were genuinely useful, especially around one boundary: protocol verification logic vs. business workflow.</p>\n<p>This post is a <strong>current 0.13 direction update</strong> focused on state transitions, written to match what the implementation supports today.</p>\n<blockquote>\n<p><strong>State should be visible. Transitions should be explicit. Compiler magic should not mutate your Molecule evidence layout behind your back.</strong></p>\n</blockquote>\n<hr>\n<h2><a name=\"p-24098-what-cellscript-is-trying-to-model-1\" class=\"anchor\" href=\"#p-24098-what-cellscript-is-trying-to-model-1\" aria-label=\"Heading link\"></a>What CellScript is trying to model</h2>\n<p>On CKB, a contract validates a transaction-level transformation: input cells are consumed, output cells are created, and the script checks whether that transformation is allowed.</p>\n<p>So in CellScript, an <code>action</code> is a protocol verifier case, not a UI step and not a business workflow task.</p>\n<p>Examples of protocol verbs:</p>\n<ul>\n<li><code>accept</code>: live offer → filled offer</li>\n<li><code>cancel</code>: live offer → cancelled offer</li>\n<li><code>claim</code>: open receipt → claimed receipt</li>\n<li><code>release</code>: locked asset → released asset</li>\n</ul>\n<hr>\n<h2><a name=\"p-24098-h-013-syntax-explicit-state-as-data-2\" class=\"anchor\" href=\"#p-24098-h-013-syntax-explicit-state-as-data-2\" aria-label=\"Heading link\"></a>0.13 syntax: explicit state as data</h2>\n<p>State is explicit in the resource data:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">enum OfferState {\n    Created,\n    Live,\n    Filled,\n    Cancelled,\n    Expired,\n}\n\nresource Offer {\n    state: OfferState,\n    seller: Bytes32,\n    buyer: Bytes32,\n    price: u128,\n}\n</code></pre>\n<p>Important: enum order gives encoding identity, not lifecycle destiny.<br>\n<code>Live</code>, <code>Filled</code>, <code>Cancelled</code> are names of variants, not an implied linear flow.</p>\n<hr>\n<h2><a name=\"p-24098-h-013-transition-model-declared-graph-action-level-moves-3\" class=\"anchor\" href=\"#p-24098-h-013-transition-model-declared-graph-action-level-moves-3\" aria-label=\"Heading link\"></a>0.13 transition model: declared graph + action-level <code>moves</code></h2>\n<p>In current implementation, allowed edges are declared explicitly:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">state_machine OfferFlow for Offer.state {\n    Live -&gt; Filled by accept;\n    Live -&gt; Cancelled by cancel;\n    Live -&gt; Expired by expire;\n}\n</code></pre>\n<p>Then each action binds to one edge with <code>moves</code> in the action header:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">action accept(input: Offer)\n    moves input.state Live -&gt; Filled\n{\n    consume input\n    create Offer {\n        state: OfferState::Filled,\n        seller: input.seller,\n        buyer: tx.signer(),\n        price: input.price,\n    }\n\n    // explicit guards/invariants\n    // require ...\n}\n</code></pre>\n<p>Another action can bind another edge:</p>\n<pre data-code-wrap=\"cellscript\"><code class=\"lang-cellscript\">action cancel(input: Offer)\n    moves input.state Live -&gt; Cancelled\n{\n    consume input\n    create Offer {\n        state: OfferState::Cancelled,\n        seller: input.seller,\n        buyer: input.buyer,\n        price: input.price,\n    }\n\n    // explicit guards/invariants\n    // require ...\n}\n</code></pre>\n<p>This keeps transition intent close to the verifier case that justifies it.</p>\n<hr>\n<h2><a name=\"p-24098-what-require-is-for-and-why-it-still-matters-4\" class=\"anchor\" href=\"#p-24098-what-require-is-for-and-why-it-still-matters-4\" aria-label=\"Heading link\"></a>What <code>require</code> is for (and why it still matters)</h2>\n<p><code>moves</code> is narrow: it encodes the state edge.<br>\n<code>require</code> remains the main tool for proof obligations such as:</p>\n<ul>\n<li>authorization (<code>signed_by(...)</code>, signer checks)</li>\n<li>field preservation / anti-tamper invariants</li>\n<li>numeric bounds and timing constraints</li>\n<li>cross-cell relationships and conservation checks</li>\n</ul>\n<p>In short:</p>\n<ul>\n<li><code>moves</code> = transition edge</li>\n<li><code>require</code> = guards and invariants</li>\n</ul>\n<p>Both are needed.</p>\n<hr>\n<h2><a name=\"p-24098-what-this-design-intentionally-avoids-5\" class=\"anchor\" href=\"#p-24098-what-this-design-intentionally-avoids-5\" aria-label=\"Heading link\"></a>What this design intentionally avoids</h2>\n<p>Current direction is explicitly <strong>not</strong>:</p>\n<ul>\n<li>hidden lifecycle field injection</li>\n<li>automatic Molecule layout mutation</li>\n<li>schema-hidden workflow machinery</li>\n<li>“business process engine” semantics in the verifier DSL</li>\n</ul>\n<p>CKB cell data is verifier evidence. Keeping the data surface explicit is a core auditability goal.</p>\n<hr>\n<h2><a name=\"p-24098-performance-posture-6\" class=\"anchor\" href=\"#p-24098-performance-posture-6\" aria-label=\"Heading link\"></a>Performance posture</h2>\n<p><code>moves</code> is intended to be low-overhead and predictable.<br>\nIt should compile to straightforward transition validation, without hidden runtime workflow machinery.</p>\n<p>To stay precise: we should avoid claiming cycle-equivalence to any specific handwritten pattern in all cases, because generated checks may include transition/range validation around consumed/created state.</p>\n<p>Direction: explicit, transparent, cost-conscious.</p>\n<hr>\n<h2><a name=\"p-24098-h-013-direction-summary-7\" class=\"anchor\" href=\"#p-24098-h-013-direction-summary-7\" aria-label=\"Heading link\"></a>0.13 direction summary</h2>\n<p>For 0.13, the working direction is:</p>\n<ul>\n<li>explicit enum-based state fields in cell data</li>\n<li>explicit transition graph declaration (<code>state_machine Type.field { ... }</code>)</li>\n<li>action-level <code>moves</code> binding one verifier action to one declared edge</li>\n<li>explicit <code>require</code> guards/invariants</li>\n<li>no hidden state injection</li>\n<li>no Molecule layout mutation</li>\n<li>no general business workflow DSL</li>\n</ul>\n<blockquote>\n<p><strong>State is data. Transition is policy. Guard is proof.</strong></p>\n</blockquote>\n<p>This is still a preview direction, not final doctrine.<br>\nIf you have a real CKB protocol where this model causes major boilerplate or audit friction, I would really like to see that example.</p>",
          "like_count": 0,
          "quote_count": 0
        }
      ]
    },
    {
      "topic_id": 10216,
      "title": "Streamlining the forum categories needs your testing and feedback",
      "slug": "streamlining-the-forum-categories-needs-your-testing-and-feedback",
      "url": "https://talk.nervos.org/t/streamlining-the-forum-categories-needs-your-testing-and-feedback/10216",
      "created_at": "2026-04-29T19:34:39.105000+00:00",
      "last_posted_at": "2026-05-01T13:00:28.841000+00:00",
      "category_id": 40,
      "tags": [],
      "posters": [
        "Original Poster",
        "Frequent Poster",
        "Frequent Poster",
        "Frequent Poster",
        "Most Recent Poster"
      ],
      "recent_posts": [
        {
          "post_id": 24085,
          "post_number": 6,
          "topic_id": 10216,
          "topic_title": "Streamlining the forum categories needs your testing and feedback",
          "topic_slug": "streamlining-the-forum-categories-needs-your-testing-and-feedback",
          "author": "terrytai",
          "created_at": "2026-04-30T19:50:46.431000+00:00",
          "updated_at": "2026-04-30T20:36:43.584000+00:00",
          "reply_to_post_number": 2,
          "url": "https://talk.nervos.org/t/streamlining-the-forum-categories-needs-your-testing-and-feedback/10216/6",
          "content_text": "@RetricSu 和 @janx （ @ArthurZhang 的问题也是相关的）都提到了 Development vs Applications & Ecosystem 的问题, 看来这组名字的确比较让人疑惑。我解释一下背后的初衷，然后我们再做选择。\nDevelopment 和 Applications & Ecosystem 在设计时的考虑是，Development 分类是承接所有开发相关的话题的，无论它是什么层次。所以可以大致理解为是按照受众来分的，比如典型的应该放在 Development 分类里的贴子：\nA Small Work to Make CKB Development Resources More Accessible\nIntroducing a Stealth Address Lock Script + Wallet Demo for CKB\nCellScript 0.1 - A DSL for Cell-Based Contracts\nxUDT Information Convention RFC\n而 Applications & Ecosystem 是针对使用者的分类， 这类事典型的应该放在此分类的话题：\nWallet not Syncing （用户求助，钱包同步不上）\nCan’t connect Ledger Nano X with Neuron wallet （用户报告：硬件钱包连不上）\nWhat wallet can I use in the United States for CKB? （用户咨询：在美国能用什么钱包）\nPassword error Neuron Wallet （用户求助：登录密码错误 ）\nNeuron wallet - seed phrase （用户求助：助记词找回）\n所以在这个分类方式的前提下，我们可以 brain storm 一对新名字？这里我给一些我觉得的可能：\nBuilding on CKB vs Using CKB\nBuilders vs Ecosystem\nBuild & Develop vs Use & Discuss\n又或者大家听了我的解释，会觉得原先的设计（Development vs Applications & Ecosystem）更好？只是需要更好的分类描述和指导。",
          "content_html": "<p><a class=\"mention\" href=\"/u/retricsu\">@RetricSu</a> 和 <a class=\"mention\" href=\"/u/janx\">@janx</a>  （ <a class=\"mention\" href=\"/u/arthurzhang\">@ArthurZhang</a> 的问题也是相关的）都提到了  Development  vs Applications &amp; Ecosystem 的问题, 看来这组名字的确比较让人疑惑。我解释一下背后的初衷，然后我们再做选择。</p>\n<p><strong>Development</strong> 和 <strong>Applications &amp; Ecosystem</strong> 在设计时的考虑是，Development 分类是承接所有开发相关的话题的，无论它是什么层次。所以可以大致理解为是按照受众来分的，<strong>比如典型的应该放在 Development 分类里的贴子：</strong></p>\n<ul>\n<li>A Small Work to Make CKB Development Resources More Accessible</li>\n<li>Introducing a Stealth Address Lock Script + Wallet Demo for CKB</li>\n<li>CellScript 0.1 - A DSL for Cell-Based Contracts</li>\n<li>xUDT Information Convention RFC</li>\n</ul>\n<p><strong>而 Applications &amp; Ecosystem 是针对使用者的分类， 这类事典型的应该放在此分类的话题：</strong></p>\n<ul>\n<li>Wallet not Syncing （用户求助，钱包同步不上）</li>\n<li>Can’t connect Ledger Nano X with Neuron wallet （用户报告：硬件钱包连不上）</li>\n<li>What wallet can I use in the United States for CKB? （用户咨询：在美国能用什么钱包）</li>\n<li>Password error Neuron Wallet （用户求助：登录密码错误 ）</li>\n<li>Neuron wallet - seed phrase （用户求助：助记词找回）</li>\n</ul>\n<p>所以在这个分类方式的前提下，我们可以 brain storm 一对新名字？这里我给一些我觉得的可能：</p>\n<ol>\n<li><strong>Building on CKB  vs Using CKB</strong></li>\n<li><strong>Builders vs Ecosystem</strong></li>\n<li><strong>Build &amp; Develop vs Use &amp; Discuss</strong></li>\n</ol>\n<p>又或者大家听了我的解释，会觉得原先的设计（<strong>Development  vs Applications &amp; Ecosystem</strong>）更好？只是需要更好的分类描述和指导。</p>",
          "like_count": 0,
          "quote_count": 0
        },
        {
          "post_id": 24086,
          "post_number": 7,
          "topic_id": 10216,
          "topic_title": "Streamlining the forum categories needs your testing and feedback",
          "topic_slug": "streamlining-the-forum-categories-needs-your-testing-and-feedback",
          "author": "terrytai",
          "created_at": "2026-04-30T19:57:13.437000+00:00",
          "updated_at": "2026-04-30T20:04:04.745000+00:00",
          "reply_to_post_number": 3,
          "url": "https://talk.nervos.org/t/streamlining-the-forum-categories-needs-your-testing-and-feedback/10216/7",
          "content_text": "关于 Community Space 的反馈, 我比较认同，确实有这个问题。\n但你说的 DAOs 感觉有点窄和不准确，因为不一定都是 DAO, 可以是其他的 program, 比如更中心化的 grants 甚至是浮华都可以在这里开设子分类。\n目前认为 DAOs & Programs 可能更好。",
          "content_html": "<p>关于 Community Space 的反馈,  我比较认同，确实有这个问题。</p>\n<p>但你说的 DAOs 感觉有点窄和不准确，因为不一定都是 DAO, 可以是其他的 program, 比如更中心化的 grants 甚至是浮华都可以在这里开设子分类。</p>\n<p>目前认为 <strong>DAOs &amp; Programs</strong>  可能更好。</p>",
          "like_count": 0,
          "quote_count": 0
        },
        {
          "post_id": 24087,
          "post_number": 8,
          "topic_id": 10216,
          "topic_title": "Streamlining the forum categories needs your testing and feedback",
          "topic_slug": "streamlining-the-forum-categories-needs-your-testing-and-feedback",
          "author": "terrytai",
          "created_at": "2026-04-30T20:22:51.851000+00:00",
          "updated_at": "2026-04-30T20:32:47.317000+00:00",
          "reply_to_post_number": 2,
          "url": "https://talk.nervos.org/t/streamlining-the-forum-categories-needs-your-testing-and-feedback/10216/8",
          "content_text": "Theory & Design — 加密经济学与机制设计\n这一条反馈也很好，我也是先想到中文，然后反推英文的，的确有点抽象了。\n关于英文名，我这里也脑爆一下替代方案：\nCryptoeconomics & Mechanism Design\nCryptoeconomics & Protocol Design\nProtocol Research\nTokenomics & Protocol Design",
          "content_html": "<blockquote>\n<p>Theory &amp; Design — 加密经济学与机制设计</p>\n</blockquote>\n<p>这一条反馈也很好，我也是先想到中文，然后反推英文的，的确有点抽象了。</p>\n<p>关于英文名，我这里也脑爆一下替代方案：</p>\n<ol>\n<li><strong>Cryptoeconomics &amp; Mechanism Design</strong></li>\n<li><strong>Cryptoeconomics &amp; Protocol Design</strong></li>\n<li><strong>Protocol Research</strong></li>\n<li><strong>Tokenomics &amp; Protocol Design</strong></li>\n</ol>",
          "like_count": 0,
          "quote_count": 0
        },
        {
          "post_id": 24093,
          "post_number": 9,
          "topic_id": 10216,
          "topic_title": "Streamlining the forum categories needs your testing and feedback",
          "topic_slug": "streamlining-the-forum-categories-needs-your-testing-and-feedback",
          "author": "yifenzi",
          "created_at": "2026-05-01T06:49:10.462000+00:00",
          "updated_at": "2026-05-01T07:02:32.153000+00:00",
          "reply_to_post_number": null,
          "url": "https://talk.nervos.org/t/streamlining-the-forum-categories-needs-your-testing-and-feedback/10216/9",
          "content_text": "关于设立“个人专贴”的建议\n借此论坛即将改版的契机，我建议设立“个人专贴”，对达到一定要求的会员开放，初期可以仅对公认的核心社区成员开放，然后慢慢放开\n“个人专贴”的定义:即某个贴子只属于某个人，只有他有发贴回贴权限，其他人为只读权限\n“个人专贴”的内容:开发者可以整理自己开发的相关项目或案例，一些新的思考或方向以及其他相关信息；非开发人员也可以发布自己的思考，以及提供一些点子供人参考，这也是一种参与和建设；项目方特别是新的项目方可以发布最新的公告信息或者对论坛成员特别的早期信息以吸引第一批用户和关注\n“个人专贴”的意义:提高部分高阶成员的归属感和荣誉感，更多的把价值沉淀在论坛，提高论坛在整个生态的软性竞争力\n“个人专贴”的方式:在某个分区下开辟一个特区，把所有个人专贴放入即可，个人专贴只是某个人能发贴和回复非版主权限(如果程序不支持这种设置，就只能启用子板块和对应的版主权限，这也一定程度可控)\n此计划投入少未知因素可控带来的利好可观，论坛管理团队可尝试看看效果",
          "content_html": "<p>关于设立“个人专贴”的建议</p>\n<p>借此论坛即将改版的契机，我建议设立“个人专贴”，对达到一定要求的会员开放，初期可以仅对公认的核心社区成员开放，然后慢慢放开</p>\n<p>“个人专贴”的定义:即某个贴子只属于某个人，只有他有发贴回贴权限，其他人为只读权限</p>\n<p>“个人专贴”的内容:开发者可以整理自己开发的相关项目或案例，一些新的思考或方向以及其他相关信息；非开发人员也可以发布自己的思考，以及提供一些点子供人参考，这也是一种参与和建设；项目方特别是新的项目方可以发布最新的公告信息或者对论坛成员特别的早期信息以吸引第一批用户和关注</p>\n<p>“个人专贴”的意义:提高部分高阶成员的归属感和荣誉感，更多的把价值沉淀在论坛，提高论坛在整个生态的软性竞争力</p>\n<p>“个人专贴”的方式:在某个分区下开辟一个特区，把所有个人专贴放入即可，个人专贴只是某个人能发贴和回复非版主权限(如果程序不支持这种设置，就只能启用子板块和对应的版主权限，这也一定程度可控)</p>\n<p>此计划投入少未知因素可控带来的利好可观，论坛管理团队可尝试看看效果</p>",
          "like_count": 0,
          "quote_count": 0
        },
        {
          "post_id": 24094,
          "post_number": 10,
          "topic_id": 10216,
          "topic_title": "Streamlining the forum categories needs your testing and feedback",
          "topic_slug": "streamlining-the-forum-categories-needs-your-testing-and-feedback",
          "author": "ArthurZhang",
          "created_at": "2026-05-01T10:32:02.796000+00:00",
          "updated_at": "2026-05-01T10:32:02.796000+00:00",
          "reply_to_post_number": 9,
          "url": "https://talk.nervos.org/t/streamlining-the-forum-categories-needs-your-testing-and-feedback/10216/10",
          "content_text": "I quite like this direction, provided we keep its ambitions modest.\nOne small concern is that Nervos Talk is not yet suffering from the terrible curse of excessive traffic. So before we build too many elegant little rooms, we should probably make sure there are enough people in the house.\nTo me, a project log / builder log would work best as a lightweight continuity layer, not as a separate discussion silo. It could be used for milestones, design notes, progress updates, RFC links, test results, and retrospectives. But broader debate, support questions, grant discussion, governance discussion, and ecosystem feedback should still live in the normal public categories.\nIn other words, the log probably should not become a private chapel for one’s own project. It should be more like a well-kept index, changelog, and map, of a place that preserves context, then points people back to the actual rooms where conversation happens.\nThat would give long-running work a bit more memory, without further thinning out the already rather precious forum traffic.",
          "content_html": "<p>I quite like this direction, provided we keep its ambitions modest.</p>\n<p>One small concern is that Nervos Talk is not yet suffering from the terrible curse of excessive traffic. So before we build too many elegant little rooms, we should probably make sure there are enough people in the house.</p>\n<p>To me, a project log / builder log would work best as a lightweight continuity layer, not as a separate discussion silo. It could be used for milestones, design notes, progress updates, RFC links, test results, and retrospectives. But broader debate, support questions, grant discussion, governance discussion, and ecosystem feedback should still live in the normal public categories.</p>\n<p>In other words, the log probably should not become a private chapel for one’s own project. It should be more like a well-kept index, changelog, and map, of a place that preserves context, then points people back to the actual rooms where conversation happens.</p>\n<p>That would give long-running work a bit more memory, without further thinning out the already rather precious forum traffic.</p>",
          "like_count": 0,
          "quote_count": 0
        },
        {
          "post_id": 24096,
          "post_number": 11,
          "topic_id": 10216,
          "topic_title": "Streamlining the forum categories needs your testing and feedback",
          "topic_slug": "streamlining-the-forum-categories-needs-your-testing-and-feedback",
          "author": "yifenzi",
          "created_at": "2026-05-01T11:24:48.599000+00:00",
          "updated_at": "2026-05-01T11:24:48.599000+00:00",
          "reply_to_post_number": null,
          "url": "https://talk.nervos.org/t/streamlining-the-forum-categories-needs-your-testing-and-feedback/10216/11",
          "content_text": "一点关于“个人专贴”定位的补充\n已有的常规讨论是正常进行是主要承载形式，个人专贴是补充性的提炼性的总结性的\n如果把每个人在论坛的活动看作一本书，那么个人专贴就是书的封面和目录，更具体的说专贴一楼是封面，后面的是目录，可以随时修改让一楼甚至可以担当起“个人公告”的用途\n在论坛搜索个人账户也能找到相关信息，但一个是被动的零散的冰冷的，一个是主动的概括的带有情感的\n数量肯定需要控制，人手一个就失去了意义，“度”的把握需要在实践中来体现\n这个新角色的引入也可以看作在论坛管理版主和普通会员之外的关于社团治理的尝试",
          "content_html": "<p>一点关于“个人专贴”定位的补充</p>\n<p>已有的常规讨论是正常进行是主要承载形式，个人专贴是补充性的提炼性的总结性的</p>\n<p>如果把每个人在论坛的活动看作一本书，那么个人专贴就是书的封面和目录，更具体的说专贴一楼是封面，后面的是目录，可以随时修改让一楼甚至可以担当起“个人公告”的用途</p>\n<p>在论坛搜索个人账户也能找到相关信息，但一个是被动的零散的冰冷的，一个是主动的概括的带有情感的</p>\n<p>数量肯定需要控制，人手一个就失去了意义，“度”的把握需要在实践中来体现</p>\n<p>这个新角色的引入也可以看作在论坛管理版主和普通会员之外的关于社团治理的尝试</p>",
          "like_count": 0,
          "quote_count": 0
        },
        {
          "post_id": 24097,
          "post_number": 12,
          "topic_id": 10216,
          "topic_title": "Streamlining the forum categories needs your testing and feedback",
          "topic_slug": "streamlining-the-forum-categories-needs-your-testing-and-feedback",
          "author": "woodbury.bit",
          "created_at": "2026-05-01T13:00:28.841000+00:00",
          "updated_at": "2026-05-01T13:07:51.926000+00:00",
          "reply_to_post_number": null,
          "url": "https://talk.nervos.org/t/streamlining-the-forum-categories-needs-your-testing-and-feedback/10216/12",
          "content_text": "(post deleted by author)",
          "content_html": "<p>(post deleted by author)</p>",
          "like_count": 0,
          "quote_count": 0
        }
      ]
    },
    {
      "topic_id": 10221,
      "title": "Revamping and Refactoring the CKB Wallet Connection Experience: A Modular Compound Component for React Developers",
      "slug": "revamping-and-refactoring-the-ckb-wallet-connection-experience-a-modular-compound-component-for-react-developers",
      "url": "https://talk.nervos.org/t/revamping-and-refactoring-the-ckb-wallet-connection-experience-a-modular-compound-component-for-react-developers/10221",
      "created_at": "2026-04-30T19:28:31.062000+00:00",
      "last_posted_at": "2026-04-30T19:28:31.123000+00:00",
      "category_id": 49,
      "tags": [
        "CKB",
        "wallet"
      ],
      "posters": [
        "Original Poster, Most Recent Poster"
      ],
      "recent_posts": [
        {
          "post_id": 24084,
          "post_number": 1,
          "topic_id": 10221,
          "topic_title": "Revamping and Refactoring the CKB Wallet Connection Experience: A Modular Compound Component for React Developers",
          "topic_slug": "revamping-and-refactoring-the-ckb-wallet-connection-experience-a-modular-compound-component-for-react-developers",
          "author": "Victor_Okenwa",
          "created_at": "2026-04-30T19:28:31.123000+00:00",
          "updated_at": "2026-05-01T15:51:31.639000+00:00",
          "reply_to_post_number": null,
          "url": "https://talk.nervos.org/t/revamping-and-refactoring-the-ckb-wallet-connection-experience-a-modular-compound-component-for-react-developers/10221/1",
          "content_text": "Hi everyone,\nThe developer experience when integrating wallets is often a trade-off between speed and control. Standard “plug-and-play” components are fast to implement but difficult to style and control, while building from scratch is time-consuming and error-prone.\nTo bridge this gap for the Nervos ecosystem, I have refactored the CKB Wallet Connect component. This revamp focuses on a Compound Component pattern, specifically designed for React and CCC (Common Chain Connector) developers who need a seamless balance between sophisticated UX and developer flexibility.\n<ConnectWallet>\n<ConnectWalletButton />\n<ConnectWalletInfoContainer className=\"flex gap-1\">\n<ConnectWalletInfoImage />\n<div className=\"flex flex-col gap-2\">\n<ConnectWalletInfoBalance withCurrency={false} />\n<ConnectWalletInfoAddress frontChars={5} endChars={12} />\n</div>\n</ConnectWalletInfoContainer>\n</ConnectWallet>\nWhat’s New?\nCompound Component Architecture\nInstead of a single, rigid <ConnectButton/>, the component is now broken down into modular sub-components (e.g., ConnectWalltetButton, ConnectWalletInfoImage, ConnectWalletInfoAddress, ConnectWalletInfoBalance). This allows developers to rearrange the UI or wrap specific parts in custom logic without breaking the internal state management.\nCustom styling control\nThe ConnectWallet components comes with it’s own default styling, but styling can be easily changed or customized by the developer. Using the className prop on all the above listed components, developers who want custom styling can easily apply tailwind classes to any component as desired. This was made possible by clsx and tailwind merge.\nHuman-Readable Financial Data\nSmall details significantly impact user trust. The component now natively handles currency formatting, including standard comma separators for balances. This ensures that users see “1,000 CKB” rather than a raw, hard-to-read string of digits.\nUnified State via CCC\nBy leveraging the CCC, the component maintains a robust connection state while abstracting away the boilerplate. Developers can now focus on their application logic rather than the edge cases of wallet handshakes.\nA Loading State\nLeveraged the animate pulse class from tailwindcss to show loading state while user’s data and details is being fetched. Users can now know when details are being fetched.\nBalance Decimal Places Control\nDevelopers can choose what amount of digits to show after the decimal point using the decimalPlaces prop on the <ConnectWalletInfoBalance decimalPlaces={4} />. Only values of 0-20 is allowed as the number of decimal places. 1,080.78090909 becomes 1,080.7809 when decimal places is set to 4.\nAddress Truncation and Characters Control\nDevelopers can control what amount of characters from a user’s address would be shown. The ConnectWalletInfoAddress can take in this optional props - endChars and frontChars. These are used to control the amount of character that would be shown before and after an ellipsis i.e. .... It has a default of 10 characters as front characters and 6 for end characters. For example <ConnectWalletInfoAddressfrontChars={5}endChars={12} /> becomes ckt1q...3enuqqeax4g0\nCurrency Visibility\nDevelopers can choose to show or not to show the CKB text behind the user’s Balance.\nUsing the withCurrency prop on the ConnectWalletBalance component. It defaults to true when not set, which means the CKB text would show behind the balance by default. Implementation example: <ConnectWalletInfoBalance withCurrency={false} />.\nWhy This Matters\nFor Developers: It drastically reduces development time. You no longer have to choose between a “black box” component that ruins your design or a two-week custom build. You get the logic for free and the UI control you deserve.\nFor Users: The experience is smoother and more professional. Polished details like formatted balances and predictable modal behaviors make dApps feel production-ready and reliable.\nFor the Ecosystem: Standardization around high-quality, flexible UI components lowers the barrier to entry for new builders coming to Nervos.\nGetting Started\nCheck out the live Demo and code on: https://ckb-connect-kit.vercel.app/\nAlso Read the documentation on: revamp-ckb-connect-wallet/ARCHITECTURE.md at main · Victor-Okenwa/revamp-ckb-connect-wallet · GitHub\nI’m eager to hear your thoughts on this pattern. Would this modular approach help your current workflow? I’m open to feedback and looking forward to seeing how we can continue to improve the tooling for the CKB community.\nBest, Victor Okenwa.",
          "content_html": "<p><strong>Hi everyone,</strong></p>\n<p>The developer experience when integrating wallets is often a trade-off between speed and control. Standard “plug-and-play” components are fast to implement but difficult to style and control, while building from scratch is time-consuming and error-prone.</p>\n<p>To bridge this gap for the Nervos ecosystem, I have refactored the <strong>CKB Wallet Connect</strong> component. This revamp focuses on a <strong>Compound Component pattern</strong>, specifically designed for React and CCC (Common Chain Connector) developers who need a seamless balance between sophisticated UX and developer flexibility.</p>\n<pre><code class=\"lang-auto\">        &lt;ConnectWallet&gt;\n              &lt;ConnectWalletButton /&gt;\n\n              &lt;ConnectWalletInfoContainer className=\"flex gap-1\"&gt;\n\n                &lt;ConnectWalletInfoImage /&gt;\n\n                &lt;div className=\"flex flex-col gap-2\"&gt;\n                  &lt;ConnectWalletInfoBalance withCurrency={false} /&gt;\n                  &lt;ConnectWalletInfoAddress frontChars={5} endChars={12} /&gt;\n                &lt;/div&gt;\n              &lt;/ConnectWalletInfoContainer&gt;\n           &lt;/ConnectWallet&gt;\n</code></pre>\n<p>What’s New?</p>\n<ol>\n<li>\n<p><strong>Compound Component Architecture</strong></p>\n<p>Instead of a single, rigid <code>&lt;ConnectButton/&gt;</code>, the component is now broken down into modular sub-components (e.g., <code>ConnectWalltetButton</code>, <code>ConnectWalletInfoImage</code>, <code>ConnectWalletInfoAddress</code>, <code>ConnectWalletInfoBalance</code>). This allows developers to rearrange the UI or wrap specific parts in custom logic without breaking the internal state management.</p>\n</li>\n<li>\n<p><strong>Custom styling control</strong><br>\nThe <strong><code>ConnectWallet</code></strong> components comes with it’s own default styling, but styling can be easily changed or customized by the developer. Using the <strong><code>className</code></strong> prop on all the above listed components, developers who want custom styling can easily apply <strong>tailwind</strong> classes to any component as desired. This was made possible by <strong>clsx</strong> and <strong>tailwind merge.</strong></p>\n</li>\n<li>\n<p><strong>Human-Readable Financial Data</strong></p>\n<p>Small details significantly impact user trust. The component now natively handles currency formatting, including standard comma separators for balances. This ensures that users see “1,000 CKB” rather than a raw, hard-to-read string of digits.</p>\n</li>\n<li>\n<p><strong>Unified State via CCC</strong></p>\n<p>By leveraging the CCC, the component maintains a robust connection state while abstracting away the boilerplate. Developers can now focus on their application logic rather than the edge cases of wallet handshakes.</p>\n</li>\n<li>\n<p><strong>A Loading State</strong><br>\nLeveraged the <code>animate pulse</code> class from <code>tailwindcss</code> to show loading state while user’s data and details is being fetched. Users can now know when details are being fetched.</p>\n</li>\n<li>\n<p><strong>Balance Decimal Places Control</strong><br>\nDevelopers can choose what amount of digits to show after the decimal point using the <code>decimalPlaces</code> prop on the <code>&lt;ConnectWalletInfoBalance decimalPlaces={4} /&gt;</code>. Only values of 0-20 is allowed as the number of decimal places.  <code>1,080.78090909</code> becomes <code>1,080.7809</code> when <code>decimal places</code> is set to <strong>4</strong>.</p>\n</li>\n<li>\n<p><strong>Address Truncation and Characters Control</strong><br>\nDevelopers can control what amount of characters from a user’s address would be shown. The <code>ConnectWalletInfoAddress</code> can take in this optional props - <code>endChars</code> and <code>frontChars.</code> These are used to control the amount of character that would be shown before and after an ellipsis i.e. <code>...</code>. It has a default of <strong>10</strong> characters as <em>front characters</em> and <strong>6</strong> for end characters. For example <code>&lt;ConnectWalletInfoAddress</code><em><code>frontChars</code></em><code>={5}</code><em><code>endChars</code></em><code>={12} /&gt;</code> becomes <code>ckt1q...3enuqqeax4g0</code></p>\n</li>\n<li>\n<p><strong>Currency Visibility</strong><br>\nDevelopers can choose to show or not to show the <code>CKB</code> text behind the user’s Balance.<br>\nUsing the <code>withCurrency</code> prop on the  <code>ConnectWalletBalance</code> component. It defaults to true when not set, which means the CKB text would show behind the balance by default. Implementation example: <code>&lt;ConnectWalletInfoBalance withCurrency={false} /&gt;</code>.</p>\n</li>\n</ol>\n<h4><a name=\"p-24084-why-this-matters-1\" class=\"anchor\" href=\"#p-24084-why-this-matters-1\" aria-label=\"Heading link\"></a>Why This Matters</h4>\n<ul>\n<li>\n<p><strong>For Developers:</strong> It drastically reduces development time. You no longer have to choose between a “black box” component that ruins your design or a two-week custom build. You get the logic for free and the UI control you deserve.</p>\n</li>\n<li>\n<p><strong>For Users:</strong> The experience is smoother and more professional. Polished details like formatted balances and predictable modal behaviors make dApps feel production-ready and reliable.</p>\n</li>\n<li>\n<p><strong>For the Ecosystem:</strong> Standardization around high-quality, flexible UI components lowers the barrier to entry for new builders coming to Nervos.</p>\n</li>\n</ul>\n<h4><a name=\"p-24084-getting-started-2\" class=\"anchor\" href=\"#p-24084-getting-started-2\" aria-label=\"Heading link\"></a>Getting Started</h4>\n<p>Check out the live Demo and code on: <a href=\"https://ckb-connect-kit.vercel.app/\" rel=\"noopener nofollow ugc\">https://ckb-connect-kit.vercel.app/</a><br>\nAlso Read the documentation on: <a href=\"https://github.com/Victor-Okenwa/revamp-ckb-connect-wallet/blob/main/ARCHITECTURE.md\" class=\"inline-onebox\" rel=\"noopener nofollow ugc\">revamp-ckb-connect-wallet/ARCHITECTURE.md at main · Victor-Okenwa/revamp-ckb-connect-wallet · GitHub</a></p>\n<p>I’m eager to hear your thoughts on this pattern. Would this modular approach help your current workflow? I’m open to feedback and looking forward to seeing how we can continue to improve the tooling for the CKB community.</p>\n<p>Best, Victor Okenwa.</p>",
          "like_count": 0,
          "quote_count": 0
        }
      ]
    }
  ]
}