@seasonkoh/webaz 0.1.20 → 0.1.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -334,7 +334,7 @@ const _EN = {
334
334
  '该范围内还没有 ≥ 3 人买过同一商品': 'No product bought by ≥ 3 people in this range yet',
335
335
  '当前关键词无匹配': 'No match for current keyword',
336
336
  '单': '',
337
- '双轨树挂靠': 'Binary tree placement',
337
+ '积分树挂靠': 'team tree placement',
338
338
  '(挂靠位置由系统按弱区自动决定,与邀请人不一定相邻)': '(placement auto-assigned to the weaker leg by the system; not necessarily adjacent to your sponsor)',
339
339
  '我的邀请链接(第一触点锁定 30 天)': 'My referral link (first-touch, 30-day cookie)',
340
340
  '你的邀请人': 'Your sponsor',
@@ -350,33 +350,33 @@ const _EN = {
350
350
  '1%-50%,分享佣金 70/20/10 自动拆分': '1%-50%, auto-split 70/20/10 across tiers',
351
351
  '结算后不可冲正,请审慎设定': 'Cannot be clawed back after settlement, set carefully',
352
352
  '佣金比例需在 1%-50% 之间': 'Commission rate must be 1%-50%',
353
- '原子能双轨对碰': 'Binary PV matching (原子能)',
353
+ '积分积分匹配': 'points-matching (积分)',
354
354
  '左右码(完全对称 / 末端垂直挂靠)': 'Left/Right codes (symmetric / tail-anchored)',
355
355
  '左码': 'Left',
356
356
  '右码': 'Right',
357
357
  '我挂靠位置': 'My placement',
358
358
  '直挂': 'Direct',
359
- '弱腿对碰量': 'Pairing volume',
359
+ '弱侧匹配量': 'Matching volume',
360
360
  '距离 tier': 'Toward tier',
361
361
  '门槛': 'threshold',
362
- '对碰档位表': 'Tier table',
362
+ '匹配档位表': 'Tier table',
363
363
  '门槛 PV': 'Threshold PV',
364
364
  'Score / 次': 'Score per hit',
365
- '最近对碰': 'Recent matches',
366
- '暂无对碰记录': 'No matches yet',
367
- 'Tokenomics — 两轨基金': 'Tokenomics — Twin pools',
365
+ '最近匹配': 'Recent matches',
366
+ '暂无匹配记录': 'No matches yet',
367
+ 'Tokenomics — 两轨基金': 'Tokenomics — Pooled funds',
368
368
  'Tokenomics': 'Tokenomics',
369
- '双轨基金 / Tier 配置 / 高额榜': 'Twin pools / Tier config / Leaderboard',
369
+ '积分基金 / Tier 配置 / 高额榜': 'Pooled funds / Tier config / Leaderboard',
370
370
  '累计分享分润': 'Total 3-tier commission',
371
- '累计对碰发放': 'Total binary distributed',
371
+ '累计匹配发放': 'Total distributed',
372
372
  'PV 待处理': 'PV pending',
373
373
  '池子余额': 'Pool balance',
374
374
  '上次 N': 'Last N',
375
375
  '上次结算': 'Last settled',
376
- '来自协议费 50%,用于大博主对碰团队 10/5/2% 补贴': 'From 50% protocol fee, for top promoter 10/5/2% bonus',
376
+ '来自协议费 50%,用于大博主匹配团队 10/5/2% 补贴': 'From 50% protocol fee, for top promoter 10/5/2% bonus',
377
377
  'Cron 控制 + 紧急操作': 'Cron controls + emergency',
378
378
  '处理 PV 流水': 'Process PV ledger',
379
- '触发对碰结算': 'Run binary settlement',
379
+ '触发匹配结算': 'Run settlement',
380
380
  '分发 WAZ(清池)': 'Distribute WAZ (drain pool)',
381
381
  '确认分发 WAZ?这将清空池子按 N 比例分配': 'Confirm distribute? This drains the pool by N ratio',
382
382
  'PV 待处理流水': 'Pending PV ledger',
@@ -384,10 +384,10 @@ const _EN = {
384
384
  'Tier 配置': 'Tier config',
385
385
  '(admin 可调)': '(admin adjustable)',
386
386
  '调整:POST /api/admin/tokenomics/tier with body {tier, pv_threshold, score_per_hit, active}': 'Adjust via POST /api/admin/tokenomics/tier',
387
- 'Top 推土机佣金': 'Top commission earners',
388
- 'Top 对碰收益': 'Top binary earners',
387
+ 'Top 三级佣金': 'Top commission earners',
388
+ 'Top 匹配收益': 'Top matching earners',
389
389
  '已处理流水': 'Processed',
390
- '已触发对碰': 'Settled',
390
+ '已触发匹配': 'Settled',
391
391
  '已分发 WAZ': 'Distributed',
392
392
  '推广佣金': 'Promo commission',
393
393
  '推广此商品 · 分享赚佣金': 'Promote this · share to earn',
@@ -402,8 +402,8 @@ const _EN = {
402
402
  '新人挂靠到你的': 'New user placed in your',
403
403
  '商品分享链接(在商品页点「推广此商品」自动生成,含两轨绑定)': 'Product share links (auto-generated via product page Promote button, dual-track)',
404
404
  '平台分享 · 仅 PV 条线': 'Platform share · PV only',
405
- '双轨链接': 'Dual-track link',
406
- '平台分享:仅建 PV 条线 · 双轨链接:同时绑推土机分享 + 原子能 PV': 'Platform share = PV line only · Dual-track = bind both 3-tier + PV',
405
+ '双区链接': 'Dual-zone link',
406
+ '平台分享:仅建 PV 条线 · 双区链接:同时绑三级佣金分享 + 积分 PV': 'Platform share = PV line only · Dual-zone = bind both 3-tier + PV',
407
407
  '津贴门控': 'Bonus gating',
408
408
  '查看资格用户 + 切换开关': 'View eligible users + toggle',
409
409
  '全局开关': 'Global switch',
@@ -423,7 +423,7 @@ const _EN = {
423
423
  '分享奖励待解锁': 'Share rewards locked',
424
424
  'Admin 强制授予': 'Admin grant override',
425
425
  '笔订单 — 可拿分享佣金': 'orders — can earn 3-tier commission',
426
- '完成至少 1 笔购买订单后,分享商品可拿分享佣金。当前可分享 PV 条线扩展双轨树': 'Complete ≥1 purchase to unlock 3-tier. PV-line sharing still works.',
426
+ '完成至少 1 笔购买订单后,分享商品可拿分享佣金。当前可分享 PV 条线扩展积分树': 'Complete ≥1 purchase to unlock 3-tier. PV-line sharing still works.',
427
427
  'L1 分享权限': 'L1 share permission',
428
428
  '可拿分享佣金': 'can earn 3-tier',
429
429
  '不可': 'no',
@@ -452,9 +452,9 @@ const _EN = {
452
452
  '偏好已保存': 'Preference saved',
453
453
  '系统检测到邀请链接': 'Invitation link detected',
454
454
  'inviter': 'Inviter',
455
- '是否加入对方的双轨 PV 树?': 'Join their binary PV tree?',
455
+ '是否加入对方的积分配对?': 'Join their points-matching group?',
456
456
  '系统将按推荐人偏好自动选择左/右区。一旦加入永久不变。': "Side picked by inviter's preference. Permanent once joined.",
457
- '已加入双轨树': 'Joined binary tree',
457
+ '已加入积分树': 'Joined team tree',
458
458
  '侧': 'Side',
459
459
  '注册门控': 'Registration gating',
460
460
  '开启后:无邀请码不能注册(admin/物流/仲裁/审核员 与 region=china 豁免)': 'When ON: no invite code → cannot register (admin/logistics/arbitrator/verifier + china region exempted)',
@@ -1109,7 +1109,7 @@ const _EN = {
1109
1109
  '拿到第一笔分享佣金': 'Earn first share commission',
1110
1110
  '创作首个原生内容': 'Create first native content',
1111
1111
  '团队达到 5 人': 'Team reaches 5',
1112
- '弱腿对碰 tier 1': 'Weak-leg tier 1 match',
1112
+ '弱侧匹配 tier 1': 'weak-side tier 1 match',
1113
1113
  '月度收益 100 WAZ': 'Monthly income 100 WAZ',
1114
1114
  '激活动态推荐': 'Activate dynamic L1',
1115
1115
  '团队达到 50 人': 'Team reaches 50',
@@ -1134,13 +1134,12 @@ const _EN = {
1134
1134
  '我的邀请链接': 'My referral link',
1135
1135
  '第一触点锁定 30 天': 'First-touch locked 30d',
1136
1136
  '指定左/右轨': 'Pin to LEFT/RIGHT',
1137
- '双轨左右区设置': 'Twin-rail L/R Settings',
1138
1137
  '左区码': 'LEFT code',
1139
1138
  '右区码': 'RIGHT code',
1140
1139
  '挂靠': 'Placed at',
1141
1140
  '团队分享': 'Team Sharing',
1142
- '双轨对碰': 'Binary Match',
1143
- '弱腿': 'Weak leg',
1141
+ '积分匹配': 'Matching',
1142
+ '弱侧': 'Weak side',
1144
1143
  '累计': 'Total',
1145
1144
  '近 7 日': 'Last 7d',
1146
1145
  '笔': 'records',
@@ -1184,7 +1183,7 @@ const _EN = {
1184
1183
  '例如:思翔教育007': 'e.g. SeasonEducation007',
1185
1184
  '在 TikTok / 小红书 口播这个口令,粉丝在 WebAZ 搜它就能找到你': 'Mention this anchor on TikTok/Xiaohongshu — fans can search it on WebAZ to find you',
1186
1185
  '在公开动态流显示我的活动': 'Show my activity in public feed',
1187
- '关闭后,你的购买/对碰/分润事件不会出现在 发现好物 > 动态': 'When off, your buy/match/commission events won\'t appear in Discover > Feed',
1186
+ '关闭后,你的购买/匹配/分润事件不会出现在 发现好物 > 动态': 'When off, your buy/match/commission events won\'t appear in Discover > Feed',
1188
1187
  '预览我的主页': 'Preview my profile',
1189
1188
  '我的关注/粉丝': 'My follows / fans',
1190
1189
  '被拉黑的用户的商品和动态对你不可见': 'Blocked users\' products and activity will be hidden from you',
@@ -1237,7 +1236,7 @@ const _EN = {
1237
1236
  // Promoter / Growth
1238
1237
  '左区推荐码': 'LEFT referral code',
1239
1238
  '右区推荐码': 'RIGHT referral code',
1240
- '双轨组织图(3 层)': 'Binary tree (3 levels)',
1239
+ '团队组织图(3 层)': 'team tree (3 levels)',
1241
1240
  '空左': 'Empty left',
1242
1241
  '空右': 'Empty right',
1243
1242
  '每节点显示 L=左累计 PV / R=右累计 PV': 'Each node shows L=left PV / R=right PV',
@@ -1300,7 +1299,7 @@ const _EN = {
1300
1299
  '暂无新品': 'No new items',
1301
1300
  '等待第一位买家': 'Waiting for first buyer',
1302
1301
  '← 发现好物': '← Discover',
1303
- '卖家最新上架、尚无成交 — 成为第一位发现者,触发推土机 + 原子能裂变奖励': 'Just listed, no sales yet — be the first discoverer and trigger 3-tier commission + binary PV rewards',
1302
+ '卖家最新上架、尚无成交 — 成为第一位发现者,触发三级佣金 + 积分配对奖励': 'Just listed, no sales yet — be the first discoverer and trigger 3-tier commission + points-matching rewards',
1304
1303
  '卖家最新上架、尚无成交 — 成为第一位发现者和传播者': 'Just listed, no sales yet — be the first discoverer and sharer',
1305
1304
 
1306
1305
  // Cart / orders
@@ -1537,7 +1536,7 @@ const _EN = {
1537
1536
  '详细 / 充提': 'Details / Top-up',
1538
1537
  '累计赚取': 'Total earned',
1539
1538
  '待结算点数': 'Pending points',
1540
- '原子能资产看板': 'Binary PV assets dashboard (原子能)',
1539
+ '积分资产看板': 'points-matching assets dashboard (积分)',
1541
1540
  '(设置一句话简介让人记住你)': '(Set a one-line bio to be memorable)',
1542
1541
 
1543
1542
  // Password / Auth
@@ -1636,7 +1635,7 @@ const _EN = {
1636
1635
  '永久分享推荐码': 'Permanent share code',
1637
1636
  '总资产': 'Total assets',
1638
1637
  '收入构成': 'Income breakdown',
1639
- '双轨已结算': 'Binary settled',
1638
+ '积分已结算': 'Settled',
1640
1639
  '销售收入': 'Sales income',
1641
1640
  '最近充值': 'Recent deposits',
1642
1641
  '最近提现': 'Recent withdrawals',
@@ -2084,14 +2083,14 @@ const _EN = {
2084
2083
  '商品推荐': 'Product promo',
2085
2084
  '打开': 'Open',
2086
2085
 
2087
- // Binary tree enhancements
2086
+ // team tree enhancements
2088
2087
  '我挂位置': 'My position',
2089
2088
  '左侧': 'left',
2090
2089
  '右侧': 'right',
2091
- '你还没加入任何上级的双轨树(独立根节点)': 'Not yet placed in any upline\'s binary tree (independent root)',
2092
- '本月对碰次数': 'Month hits',
2093
- '本月对碰 WAZ': 'Month WAZ',
2094
- '累计对碰次数': 'Total hits',
2090
+ '你还没加入任何上级的积分树(独立根节点)': 'Not yet placed in any upline\'s team tree (independent root)',
2091
+ '本月匹配次数': 'Month hits',
2092
+ '本月匹配 WAZ': 'Month WAZ',
2093
+ '累计匹配次数': 'Total hits',
2095
2094
  '点击节点查看 PV': 'click node for PV',
2096
2095
  '每节点显示 L=左累计 PV / R=右累计 PV · 点击节点看详情': 'L=left PV / R=right PV · click node for details',
2097
2096
  '点击查看 PV KPI': 'Click for PV KPI',
@@ -2100,7 +2099,7 @@ const _EN = {
2100
2099
  '深度': 'depth',
2101
2100
  '独立根节点(无上级)': 'Independent root (no upline)',
2102
2101
  '双腿均衡': 'Leg balance',
2103
- '累计对碰': 'Total hits',
2102
+ '累计匹配': 'Total hits',
2104
2103
  '累计获 WAZ': 'Total earned WAZ',
2105
2104
  '待结 Score': 'Pending Score',
2106
2105
  '查看 TA 的主页': 'View their profile',
@@ -2119,7 +2118,7 @@ const _EN = {
2119
2118
  '调用多样': 'API diversity',
2120
2119
  '仲裁败诉': 'Dispute loss',
2121
2120
  '同 IP 多号': 'Same IP cluster',
2122
- '双轨同支': 'Sponsor cross',
2121
+ '同支': 'Same-branch',
2123
2122
  '限速命中': 'Rate limit hits',
2124
2123
  '再 +': '+',
2125
2124
  '分解锁 raw mode': 'pts to unlock raw mode',
@@ -2213,7 +2212,7 @@ const _EN = {
2213
2212
  '这件商品还没在 WebAZ 上架。把它带进来 — 让买家在精准搜索时也能找到你。': 'This SKU is not on WebAZ yet. Bring it in — let buyers find you on precise search.',
2214
2213
  '为什么上架到 WebAZ': 'Why list on WebAZ',
2215
2214
  '· 协议费仅 2%(vs 淘宝 5%+ 抽佣 + 竞价推广)': '· Protocol fee 2% only (vs Taobao 5%+ commission + bid promotion)',
2216
- '· 分享成交拿 commission(推土机 70/20/10)': '· Earn share commission (3-tier 70/20/10)',
2215
+ '· 分享成交拿 commission(三级佣金 70/20/10)': '· Earn share commission (3-tier 70/20/10)',
2217
2216
  '· 链上稳定币直达,无平台资金截留': '· On-chain stablecoin settlement, no platform float',
2218
2217
  '· Agent 自动比价推荐 + alias 精准命中': '· Agent auto-compares + precise alias matching',
2219
2218
  '上架只需 3 步': 'List in 3 steps',
@@ -2412,11 +2411,11 @@ const _EN = {
2412
2411
  '零上架成本': 'Zero listing cost',
2413
2412
  'AI 店长自主上架、自动生成多语种商品矩阵。首单成交仅锁定 15% 作买家保护(Trusted 卖家免除)。':
2414
2413
  'AI shopkeeper lists products and generates multilingual catalogs autonomously. Only the first sale locks 15% as buyer protection (Trusted sellers exempt).',
2415
- '买家 Agent 意图对碰': 'Buyer Agent intent matching',
2414
+ '买家 Agent 意图匹配': 'Buyer Agent intent matching',
2416
2415
  '零推广费': 'Zero promotion fees',
2417
2416
  '全网买家 Agent 携精准需求(Alias)全天候巡航,与商品语义刚需匹配,订单全自动闭合成交。':
2418
2417
  'Buyer Agents across the network roam 24/7 with precise needs (Aliases), matching products by semantic intent and closing orders autonomously.',
2419
- '智能体裂变分润': 'Agent-driven viral revenue share',
2418
+ '智能体扩散分润': 'Agent-driven viral revenue share',
2420
2419
  '秒级自动分账': 'Instant on-chain settlement',
2421
2420
  '商品由其他节点或达人 Agent 智能分享成交,下游分润通过智能合约去中心化自动清算,即刻到账。':
2422
2421
  'Products surface via other nodes or influencer Agents; downstream revenue share is auto-settled on-chain — instantly credited.',
@@ -3161,7 +3160,7 @@ const _EN = {
3161
3160
  '卖家收入速览': 'Seller Income Summary',
3162
3161
  '商品销售': 'Product Sales',
3163
3162
  '推荐分润': 'Referral Comm.',
3164
- '对碰已结': 'Binary Settled',
3163
+ '匹配已结': 'Settled',
3165
3164
  '待结算': 'Pending',
3166
3165
  'escrow 中': 'in escrow',
3167
3166
 
@@ -4579,7 +4578,7 @@ const _EN = {
4579
4578
  '已是共建身份': 'Already opted in',
4580
4579
  '你已 opted-in。如需查看状态或退出,前往 ': 'You are opted in. To view status or opt out, go to ',
4581
4580
  '本流程与购物无关': 'This flow is not part of shopping',
4582
- '你可以随时退出,不影响任何已下单或未来订单。本流程涉及经济关系登记(三级佣金 + 双轨配对),请仔细阅读全部条款。': 'You can leave anytime without affecting any past or future orders. This is an economic-relationship registration (3-tier commission + binary PV matching) — please read all terms carefully.',
4581
+ '你可以随时退出,不影响任何已下单或未来订单。本流程涉及经济关系登记(三级佣金 + 积分配对),请仔细阅读全部条款。': 'You can leave anytime without affecting any past or future orders. This is an economic-relationship registration (3-tier commission + points-matching) — please read all terms carefully.',
4583
4582
  '门槛(全部通过才能申请)': 'Eligibility (all must pass to apply)',
4584
4583
  '已完成订单': 'Completed orders',
4585
4584
  'Passkey 已注册': 'Passkey registered',
@@ -5569,7 +5568,7 @@ const _EN = {
5569
5568
  '调用多样性': 'Endpoint diversity',
5570
5569
  '争议败诉': 'Dispute losses',
5571
5570
  '同 IP 异户': 'Same-IP users',
5572
- '双轨命中': 'Cross-rail hits',
5571
+ '匹配命中': 'Matching hits',
5573
5572
  '限速命中': 'Rate-limit hits',
5574
5573
  '阈值': 'Thresholds',
5575
5574
 
@@ -3,7 +3,20 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
6
- <title>WebAZ</title>
6
+ <title>WebAZ — Agent-native decentralized commerce protocol</title>
7
+ <!-- Crawler / agent discoverability (static, no-JS): so a fetch of this page returns real meaning, not an empty shell. -->
8
+ <meta name="description" content="WebAZ is an open, agent-native decentralized commerce protocol. Every order is escrow-protected and flows through a state machine; on timeout the protocol auto-rules fault and executes remedy. Buyers get escrow + automatic refunds + transparent seller reputation, price history and arbitration precedents; AI agents browse, order, compare and fulfill via MCP. Pre-launch (simulated test currency, no real settlement yet).">
9
+ <link rel="canonical" href="https://webaz.xyz/">
10
+ <meta property="og:type" content="website">
11
+ <meta property="og:site_name" content="WebAZ">
12
+ <meta property="og:url" content="https://webaz.xyz/">
13
+ <meta property="og:title" content="WebAZ — Agent-native decentralized commerce protocol">
14
+ <meta property="og:description" content="Escrow-protected, state-machine commerce: timeouts auto-rule fault + remedy. Buyers get escrow + auto-refund + transparent reputation; AI agents transact via MCP. Pre-launch.">
15
+ <meta property="og:image" content="https://webaz.xyz/webaz-logo.png">
16
+ <meta name="twitter:card" content="summary_large_image">
17
+ <meta name="twitter:title" content="WebAZ — Agent-native decentralized commerce protocol">
18
+ <meta name="twitter:description" content="Escrow-protected, state-machine commerce. Buyers: escrow + auto-refund + transparent reputation. Agents transact via MCP. Pre-launch.">
19
+ <meta name="twitter:image" content="https://webaz.xyz/webaz-logo.png">
7
20
  <link rel="stylesheet" href="/style.css">
8
21
  <link rel="manifest" href="/manifest.json">
9
22
  <link rel="icon" type="image/svg+xml" href="/icon.svg">
@@ -15,6 +28,18 @@
15
28
  </head>
16
29
  <body>
17
30
  <div id="app"></div>
31
+ <!-- No-JS / crawler fallback: real content for fetchers that don't run the SPA (fixes "scrape only sees an empty <title>"). -->
32
+ <noscript>
33
+ <main style="max-width:680px;margin:40px auto;padding:0 20px;font-family:system-ui,sans-serif;line-height:1.7;color:#1f2937">
34
+ <h1>WebAZ — Agent-native decentralized commerce protocol</h1>
35
+ <p>WebAZ is an open, agent-native decentralized commerce protocol. Every order is escrow-protected and flows through a state machine; if a responsible party times out, the protocol automatically rules fault and executes the remedy.</p>
36
+ <p><strong>For buyers:</strong> funds are held in escrow and released only after you confirm receipt; sellers who don't accept/ship/deliver in time trigger an automatic refund; disputes are decided with evidence + neutral arbitration; seller reputation, price history and arbitration precedents are public before you buy.</p>
37
+ <p><strong>For AI agents:</strong> browse, compare, order and track fulfillment via the Model Context Protocol (MCP). Protocol state is public at <a href="/.well-known/webaz-protocol.json">/.well-known/webaz-protocol.json</a>; the integration contract is at <a href="/.well-known/webaz-integration.json">/.well-known/webaz-integration.json</a>.</p>
38
+ <p><strong>Status:</strong> pre-launch — WAZ is a simulated test currency; no real money settles yet.</p>
39
+ <p>Browse: <a href="/#discover">/#discover</a> · Learn more: <a href="/#welcome">/#welcome</a> · Source: <a href="https://github.com/seasonsagents-art/webaz">github.com/seasonsagents-art/webaz</a></p>
40
+ <p style="color:#6b7280;font-size:14px">This page is an interactive app and needs JavaScript for full functionality.</p>
41
+ </main>
42
+ </noscript>
18
43
  <script src="/i18n.js"></script>
19
44
  <script src="/app.js"></script>
20
45
  </body>
@@ -1,3 +1,6 @@
1
+ // RFC-014 PR6 — 拍卖 stake 锁定/释放走整数 base-units + 绝对值落库。
2
+ import { toUnits } from '../../money.js';
3
+ import { applyWalletDelta } from '../../ledger.js';
1
4
  // ─── 拍卖常量(域内)──────────────────────────────────────────
2
5
  const AUC_MAX_WINDOW_MIN = 14 * 24 * 60; // 14 天上限
3
6
  const AUC_MIN_WINDOW_MIN = 5;
@@ -118,7 +121,7 @@ export function registerAuctionRoutes(app, deps) {
118
121
  seller_stake_locked, notes)
119
122
  VALUES (?,?,?,?,?,?,?,?,?,?,?,?,datetime('now', '+' || ? || ' minutes'),?,?,?)
120
123
  `).run(id, user.id, body.listing_id ? String(body.listing_id) : null, productId, title, body.spec_json ? JSON.stringify(body.spec_json) : null, qty, cat, startingPrice, startingPrice, minIncrement, reservePrice, windowMin, sniperExtend, sellerStake, body.notes ? String(body.notes).slice(0, 500) : null);
121
- db.prepare('UPDATE wallets SET balance = balance - ?, staked = staked + ? WHERE user_id = ?').run(sellerStake, sellerStake, user.id);
124
+ applyWalletDelta(db, user.id, { balance: -toUnits(sellerStake), staked: toUnits(sellerStake) });
122
125
  if (productId)
123
126
  db.prepare("UPDATE products SET status = 'auction_pending', updated_at = datetime('now') WHERE id = ?").run(productId);
124
127
  })();
@@ -346,19 +349,19 @@ export function registerAuctionRoutes(app, deps) {
346
349
  if (myPrev) {
347
350
  db.prepare("UPDATE auction_bids SET status = 'outbid', resolved_at = datetime('now') WHERE id = ?").run(myPrev.id);
348
351
  if (myPrev.stake_locked > 0)
349
- db.prepare('UPDATE wallets SET balance = balance + ?, staked = staked - ? WHERE user_id = ?').run(myPrev.stake_locked, myPrev.stake_locked, user.id);
352
+ applyWalletDelta(db, user.id, { balance: toUnits(myPrev.stake_locked), staked: -toUnits(myPrev.stake_locked) });
350
353
  }
351
354
  // 释放别人的最高 active bid
352
355
  const others = db.prepare("SELECT id, buyer_id, stake_locked FROM auction_bids WHERE auction_id = ? AND status = 'active' AND buyer_id != ?").all(req.params.id, user.id);
353
356
  for (const o of others) {
354
357
  db.prepare("UPDATE auction_bids SET status = 'outbid', resolved_at = datetime('now') WHERE id = ?").run(o.id);
355
358
  if (o.stake_locked > 0)
356
- db.prepare('UPDATE wallets SET balance = balance + ?, staked = staked - ? WHERE user_id = ?').run(o.stake_locked, o.stake_locked, o.buyer_id);
359
+ applyWalletDelta(db, o.buyer_id, { balance: toUnits(o.stake_locked), staked: -toUnits(o.stake_locked) });
357
360
  }
358
361
  // 插入新 bid
359
362
  db.prepare(`INSERT INTO auction_bids (id, auction_id, buyer_id, price, stake_locked) VALUES (?,?,?,?,?)`)
360
363
  .run(id, req.params.id, user.id, price, stake);
361
- db.prepare('UPDATE wallets SET balance = balance - ?, staked = staked + ? WHERE user_id = ?').run(stake, stake, user.id);
364
+ applyWalletDelta(db, user.id, { balance: -toUnits(stake), staked: toUnits(stake) });
362
365
  // P1 #9:卖家 stake 动态补足(5% × current_price,余额不足则尽量补)
363
366
  const targetSellerStake = Math.max(1, Math.round(price * AUC_SELLER_STAKE_PCT * 100) / 100);
364
367
  const curSellerStake = Number(fresh.seller_stake_locked) || 0;
@@ -367,7 +370,7 @@ export function registerAuctionRoutes(app, deps) {
367
370
  const sWal = db.prepare('SELECT balance FROM wallets WHERE user_id = ?').get(auc.seller_id);
368
371
  const canTopup = sWal ? Math.min(delta, Number(sWal.balance)) : 0;
369
372
  if (canTopup > 0) {
370
- db.prepare('UPDATE wallets SET balance = balance - ?, staked = staked + ? WHERE user_id = ?').run(canTopup, canTopup, auc.seller_id);
373
+ applyWalletDelta(db, auc.seller_id, { balance: -toUnits(canTopup), staked: toUnits(canTopup) });
371
374
  db.prepare('UPDATE auctions SET seller_stake_locked = seller_stake_locked + ? WHERE id = ?').run(canTopup, req.params.id);
372
375
  sellerTopup = canTopup;
373
376
  }
@@ -420,7 +423,7 @@ export function registerAuctionRoutes(app, deps) {
420
423
  db.transaction(() => {
421
424
  db.prepare("UPDATE auctions SET status = 'cancelled', updated_at = datetime('now') WHERE id = ?").run(req.params.id);
422
425
  if (sellerStake > 0)
423
- db.prepare('UPDATE wallets SET balance = balance + ?, staked = staked - ? WHERE user_id = ?').run(sellerStake, sellerStake, user.id);
426
+ applyWalletDelta(db, user.id, { balance: toUnits(sellerStake), staked: -toUnits(sellerStake) });
424
427
  if (auc.product_id)
425
428
  db.prepare("UPDATE products SET status = 'active', updated_at = datetime('now') WHERE id = ? AND status = 'auction_pending'").run(auc.product_id);
426
429
  })();
@@ -1,6 +1,9 @@
1
1
  import express from 'express';
2
2
  // RFC-007 stage 5:客观拒单仲裁翻案直接复用 L0 状态机/结算(纯 db 函数,无副作用)
3
3
  import { transition, settleFault, settleDeclinedNoFault } from '../../layer0-foundation/L0-2-state-machine/engine.js';
4
+ // RFC-014 PR5 — 争议后佣金/基金 clawback 走整数 base-units + 绝对值落库。
5
+ import { toUnits, toDecimal, mulRate } from '../../money.js';
6
+ import { applyWalletDelta } from '../../ledger.js';
4
7
  export function registerDisputesWriteRoutes(app, deps) {
5
8
  const { db, auth, generateId, detectFraud, errorRes, isEligibleArbitrator, requireHumanPresence, getDisputeDetails, respondToDispute, arbitrateDispute, addPartyEvidence, requestEvidence, markEvidenceExpiry, uploadEvidence, EVIDENCE_MAX_BYTES, EVIDENCE_ALLOWED_MIME, appendOrderEvent, FUND_BASE_RATE, settleCommission, depositToFund, calculatePv, recordDisputeReputation, issueAgentStrike, publishDisputeCase, logAdminAction, snfSend, getProtocolParam } = deps;
6
9
  // ── RFC-007 stage 5:客观拒单【临时判责】的仲裁翻案 ─────────────────────────────
@@ -194,12 +197,11 @@ export function registerDisputesWriteRoutes(app, deps) {
194
197
  return;
195
198
  const total = Number(order.total_amount);
196
199
  const commRate = Number(order.snapshot_commission_rate ?? 0);
197
- const commPool = Math.round(total * commRate * 100) / 100;
198
- const fundBase = Math.round(total * FUND_BASE_RATE() * 100) / 100;
199
- const deduct = commPool + fundBase;
200
+ const deductU = mulRate(toUnits(total), commRate) + mulRate(toUnits(total), FUND_BASE_RATE());
201
+ const deduct = toDecimal(deductU);
200
202
  const sellerWallet = db.prepare("SELECT balance FROM wallets WHERE user_id = ?").get(order.seller_id);
201
- if (sellerWallet && sellerWallet.balance >= deduct) {
202
- db.prepare("UPDATE wallets SET balance = balance - ?, earned = earned - ? WHERE user_id = ?").run(deduct, deduct, order.seller_id);
203
+ if (sellerWallet && toUnits(sellerWallet.balance) >= deductU) {
204
+ applyWalletDelta(db, order.seller_id, { balance: -deductU, earned: -deductU });
203
205
  const { redirected: disputeRedirected } = settleCommission(dispute.order_id);
204
206
  depositToFund(dispute.order_id, disputeRedirected);
205
207
  const productRow = db.prepare("SELECT category_id FROM products WHERE id = ?").get(order.product_id);
@@ -248,13 +250,12 @@ export function registerDisputesWriteRoutes(app, deps) {
248
250
  if (effectiveBase <= 0)
249
251
  return;
250
252
  const commRate = Number(order.snapshot_commission_rate ?? 0);
251
- const commPool = Math.round(effectiveBase * commRate * 100) / 100;
252
- const fundBase = Math.round(effectiveBase * FUND_BASE_RATE() * 100) / 100;
253
- const deduct = Math.round((commPool + fundBase) * 100) / 100;
253
+ const deductU = mulRate(toUnits(effectiveBase), commRate) + mulRate(toUnits(effectiveBase), FUND_BASE_RATE());
254
+ const deduct = toDecimal(deductU);
254
255
  const sellerWallet = db.prepare("SELECT balance FROM wallets WHERE user_id = ?").get(order.seller_id);
255
- if (sellerWallet && sellerWallet.balance >= deduct) {
256
- if (deduct > 0) {
257
- db.prepare("UPDATE wallets SET balance = balance - ?, earned = earned - ? WHERE user_id = ?").run(deduct, deduct, order.seller_id);
256
+ if (sellerWallet && toUnits(sellerWallet.balance) >= deductU) {
257
+ if (deductU > 0) {
258
+ applyWalletDelta(db, order.seller_id, { balance: -deductU, earned: -deductU });
258
259
  }
259
260
  const { redirected } = settleCommission(dispute.order_id, effectiveBase);
260
261
  depositToFund(dispute.order_id, redirected, effectiveBase);
@@ -1,4 +1,7 @@
1
1
  import { buildCartMandate, buildPaymentMandate, signMandate } from './ap2-mandate.js';
2
+ // RFC-014 PR3 — 金额走整数 base-units;钱包写绝对值(防 REAL 浮点加法 dust)。
3
+ import { toUnits, toDecimal, mulQty, mulRate } from '../../money.js';
4
+ import { applyWalletDelta } from '../../ledger.js';
2
5
  export function registerOrdersCreateRoutes(app, deps) {
3
6
  const { db, auth, isTrustedRole, generateId, generateRecipientCode, DONATION_VALID_PCTS, INTERNAL_AUDITOR_ID, addHours, getActiveFlashSale, applyCouponToOrder, getProtocolParam, getProductShareChain, isAllowedSponsor, checkStockAndMaybeDelist, auditSponsorChainCross, appendOrderEvent, transition, notifyTransition, shouldAutoAccept, ensureCharityRep, broadcastSystemEvent, signPassport, issuerAddress } = deps;
4
7
  app.post('/api/orders', async (req, res) => {
@@ -170,18 +173,25 @@ export function registerOrdersCreateRoutes(app, deps) {
170
173
  db.prepare(`UPDATE price_sessions SET used_at = datetime('now') WHERE token = ?`).run(session_token);
171
174
  }
172
175
  const basePrice = product.price;
173
- // 多件:subtotal = basePrice * qty,减 coupon,再加保险(按 subtotal 计费)
174
- const subtotal = Math.round(basePrice * reqQty * 100) / 100;
175
- const priceAfterCoupon = Math.max(0, Math.round((subtotal - couponDiscount) * 100) / 100);
176
+ // RFC-014:全部金额在整数 base-units 上算(精确),再 toDecimal 落库/响应。
177
+ // 多件:subtotal = basePrice × qty,减 coupon,再加保险(按 subtotal 计费)
178
+ const basePriceU = toUnits(basePrice);
179
+ const subtotalU = mulQty(basePriceU, reqQty);
180
+ const priceAfterCouponU = Math.max(0, subtotalU - toUnits(couponDiscount));
176
181
  const insuranceRate = getProtocolParam('order_insurance_rate', 0.01);
177
- const insurancePremium = buy_insurance ? Math.round(priceAfterCoupon * insuranceRate * 100) / 100 : 0;
178
- const totalAmount = Math.max(0, Math.round((priceAfterCoupon + insurancePremium) * 100) / 100);
182
+ const insurancePremiumU = buy_insurance ? mulRate(priceAfterCouponU, insuranceRate) : 0;
183
+ const totalAmountU = Math.max(0, priceAfterCouponU + insurancePremiumU);
179
184
  // B5 主动捐赠 — 按订单总额 × 比例算(额外扣款,进 charity_fund)
180
- const donationAmount = donationPctNum > 0 ? Math.round(totalAmount * donationPctNum * 100) / 100 : 0;
185
+ const donationAmountU = donationPctNum > 0 ? mulRate(totalAmountU, donationPctNum) : 0;
186
+ // decimal 视图(落库 / 下游 AP2 / 响应,均为 base-unit 干净值)
187
+ const subtotal = toDecimal(subtotalU);
188
+ const insurancePremium = toDecimal(insurancePremiumU);
189
+ const totalAmount = toDecimal(totalAmountU);
190
+ const donationAmount = toDecimal(donationAmountU);
181
191
  const wallet = db.prepare('SELECT balance FROM wallets WHERE user_id = ?').get(user.id);
182
192
  if (!wallet)
183
193
  return void res.status(500).json({ error: '钱包记录缺失', error_code: 'WALLET_MISSING' });
184
- if (wallet.balance < totalAmount + donationAmount)
194
+ if (toUnits(wallet.balance) < totalAmountU + donationAmountU)
185
195
  return void res.json({ error: `余额不足:需 ${(totalAmount + donationAmount).toFixed(2)} WAZ(含 ${donationAmount} WAZ 捐赠),当前 ${wallet.balance} WAZ` });
186
196
  const now = new Date();
187
197
  const orderId = generateId('ord');
@@ -259,13 +269,14 @@ export function registerOrdersCreateRoutes(app, deps) {
259
269
  catch (e) {
260
270
  console.warn('[order-chain] genesis event failed:', e.message);
261
271
  }
262
- db.prepare('UPDATE wallets SET balance = balance - ?, escrowed = escrowed + ? WHERE user_id = ?')
263
- .run(totalAmount, totalAmount, user.id);
272
+ // RFC-014:钱包托管锁定走绝对值落库(整数 base-units)
273
+ applyWalletDelta(db, user.id, { balance: -totalAmountU, escrowed: totalAmountU });
264
274
  // B5:捐赠 — 从 balance 扣 + 进 charity_fund + 记一笔 donation txn(事务内原子)
265
- if (donationAmount > 0) {
266
- db.prepare('UPDATE wallets SET balance = balance - ? WHERE user_id = ?').run(donationAmount, user.id);
267
- db.prepare(`UPDATE charity_fund SET balance = balance + ?, total_donated = total_donated + ?, updated_at = datetime('now') WHERE id = 'main'`)
268
- .run(donationAmount, donationAmount);
275
+ if (donationAmountU > 0) {
276
+ applyWalletDelta(db, user.id, { balance: -donationAmountU });
277
+ const cf = db.prepare("SELECT COALESCE(balance,0) balance, COALESCE(total_donated,0) total_donated FROM charity_fund WHERE id = 'main'").get();
278
+ db.prepare(`UPDATE charity_fund SET balance = ?, total_donated = ?, updated_at = datetime('now') WHERE id = 'main'`)
279
+ .run(toDecimal(toUnits(cf?.balance ?? 0) + donationAmountU), toDecimal(toUnits(cf?.total_donated ?? 0) + donationAmountU));
269
280
  db.prepare(`INSERT INTO charity_fund_txns (id, kind, from_user_id, to_user_id, amount, related_order_id, note)
270
281
  VALUES (?, 'donation', ?, NULL, ?, ?, ?)`).run(generateId('cft'), user.id, donationAmount, orderId, `下单时捐赠 ${(donationPctNum * 100).toFixed(1)}%`);
271
282
  // 同步 charity_reputation(捐款荣誉)
@@ -10,6 +10,7 @@ import { buildIntegrationContract } from '../integration-contract.js';
10
10
  import { buildVerifiabilityIndex } from '../verifiability-index.js';
11
11
  import { buildEconomicParticipation } from '../economic-participation.js';
12
12
  import { buildNegativeSpace } from '../negative-space.js';
13
+ import { buildAcpProductFeed } from '../acp-feed.js';
13
14
  export function registerPublicUtilsRoutes(app, deps) {
14
15
  const { db, MASTER_SEED, NODE_ENV, SERVICE_START_MS, rateLimitOk, generateManifest, getUser, logError, issuerAddress } = deps;
15
16
  app.get('/api/health', (_req, res) => {
@@ -138,6 +139,7 @@ export function registerPublicUtilsRoutes(app, deps) {
138
139
  event_stream: 'https://webaz.xyz/api/agent/events?since=<cursor>', // ⑥ 事件游标流(party-gated,需 auth)
139
140
  passport: 'https://webaz.xyz/api/me/agents/:apiKeyPrefix/passport', // ⑤ 可验护照
140
141
  did: 'https://webaz.xyz/.well-known/did.json',
142
+ acp_product_feed: 'https://webaz.xyz/.well-known/webaz-acp-feed.json', // RFC-015 P0 — ACP 风格商品发现 feed(只读;is_eligible_checkout=false)
141
143
  },
142
144
  // 路线图 — 回应"知道还有哪些没做"的诚实化第三层。哲学:公开当前到达点 + 已知未做项,不承诺时间表。
143
145
  roadmap: {
@@ -270,6 +272,15 @@ export function registerPublicUtilsRoutes(app, deps) {
270
272
  };
271
273
  app.get('/.well-known/webaz-negative-space.json', negativeSpace);
272
274
  app.get('/api/agent/negative-space', negativeSpace);
275
+ // RFC-015 P0 —— ACP product feed:把现有商品投影成 OpenAI Agentic Commerce 的 feed 形状,
276
+ // 让 ACP/ChatGPT agent 能【发现】WebAZ 商品(只读,无钱)。诚实门控:is_eligible_checkout 恒 false
277
+ // (ACP /complete 是卡+PSP,WebAZ 未接);currency=WAZ 是模拟单位。详见 buildAcpProductFeed + RFC-015。
278
+ const acpFeed = (_req, res) => {
279
+ res.setHeader('Cache-Control', 'public, max-age=300');
280
+ res.json(buildAcpProductFeed(db));
281
+ };
282
+ app.get('/.well-known/webaz-acp-feed.json', acpFeed);
283
+ app.get('/api/agent/acp-feed', acpFeed);
273
284
  // W3C DID Document(B.6 b DID 短期 mapping,2026-05-30):
274
285
  // did:web:webaz.xyz 通过 HTTPS 解析到这里(W3C did:web spec §3.2)
275
286
  // verificationMethod 用 EcdsaSecp256k1RecoveryMethod2020 + CAIP-10 blockchainAccountId