@wowok/agent-mcp 3.1.2 → 3.1.3
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.
- package/dist/config/runtime.js +1 -1
- package/dist/customer/index.d.ts +3 -9
- package/dist/customer/index.js +1 -1
- package/dist/customer/industry-risks.d.ts +3 -17
- package/dist/customer/industry-risks.js +1 -1
- package/dist/customer/types.d.ts +1 -165
- package/dist/customer/types.js +1 -1
- package/dist/customer/user-preferences.d.ts +0 -49
- package/dist/customer/user-preferences.js +1 -1
- package/dist/evaluation/architecture.spec.d.ts +1 -0
- package/dist/evaluation/architecture.spec.js +1 -0
- package/dist/evaluation/builtins/graph-service.d.ts +16 -0
- package/dist/evaluation/builtins/graph-service.js +1 -0
- package/dist/evaluation/builtins/graph-service.spec.d.ts +1 -0
- package/dist/evaluation/builtins/graph-service.spec.js +1 -0
- package/dist/evaluation/builtins/index.d.ts +1 -1
- package/dist/evaluation/builtins/index.js +1 -1
- package/dist/evaluation/builtins/purity.spec.d.ts +1 -0
- package/dist/evaluation/builtins/purity.spec.js +1 -0
- package/dist/evaluation/engine.js +1 -1
- package/dist/evaluation/facets/catalog.d.ts +19 -0
- package/dist/evaluation/facets/catalog.js +1 -0
- package/dist/evaluation/guard-scan.d.ts +10 -0
- package/dist/evaluation/guard-scan.js +1 -0
- package/dist/evaluation/standards.d.ts +31 -0
- package/dist/evaluation/standards.js +1 -0
- package/dist/evaluation/standards.spec.d.ts +1 -0
- package/dist/evaluation/standards.spec.js +1 -0
- package/dist/evaluation/types.d.ts +9 -0
- package/dist/experience/realtime-feedback.js +1 -1
- package/dist/extensions/index.d.ts +1 -1
- package/dist/extensions/index.js +1 -1
- package/dist/extensions/industry-layers.d.ts +6 -5
- package/dist/extensions/industry-layers.js +1 -1
- package/dist/extensions/industry-pack.js +1 -1
- package/dist/graph/onchain/analyze.d.ts +13 -0
- package/dist/graph/onchain/analyze.js +1 -1
- package/dist/graph/onchain/analyze.spec.js +1 -1
- package/dist/graph/onchain/dataplane.d.ts +1 -1
- package/dist/graph/onchain/dataplane.js +1 -1
- package/dist/graph/onchain/edge-batch.spec.d.ts +1 -0
- package/dist/graph/onchain/edge-batch.spec.js +1 -0
- package/dist/graph/onchain/edge-schema.d.ts +10 -2
- package/dist/graph/onchain/edge-schema.js +1 -1
- package/dist/graph/onchain/entity-profile.spec.d.ts +1 -0
- package/dist/graph/onchain/entity-profile.spec.js +1 -0
- package/dist/graph/onchain/event-history.spec.d.ts +1 -0
- package/dist/graph/onchain/event-history.spec.js +1 -0
- package/dist/graph/onchain/expand.js +1 -1
- package/dist/graph/onchain/extract-deep.spec.d.ts +1 -0
- package/dist/graph/onchain/extract-deep.spec.js +1 -0
- package/dist/graph/onchain/extract.d.ts +11 -3
- package/dist/graph/onchain/extract.js +1 -1
- package/dist/graph/onchain/facet-projection.d.ts +99 -0
- package/dist/graph/onchain/facet-projection.js +1 -0
- package/dist/graph/onchain/facet-projection.spec.d.ts +1 -0
- package/dist/graph/onchain/facet-projection.spec.js +1 -0
- package/dist/graph/onchain/facts.d.ts +103 -0
- package/dist/graph/onchain/facts.js +1 -0
- package/dist/graph/onchain/facts.spec.d.ts +1 -0
- package/dist/graph/onchain/facts.spec.js +1 -0
- package/dist/graph/onchain/field-manifest.d.ts +29 -0
- package/dist/graph/onchain/field-manifest.js +1 -0
- package/dist/graph/onchain/field-manifest.spec.d.ts +1 -0
- package/dist/graph/onchain/field-manifest.spec.js +1 -0
- package/dist/graph/onchain/fixtures.d.ts +80 -0
- package/dist/graph/onchain/fixtures.js +1 -0
- package/dist/graph/onchain/fixtures.spec.d.ts +1 -0
- package/dist/graph/onchain/fixtures.spec.js +1 -0
- package/dist/graph/onchain/index.d.ts +8 -2
- package/dist/graph/onchain/index.js +1 -1
- package/dist/graph/onchain/interest.js +1 -1
- package/dist/graph/onchain/label-lint.spec.d.ts +1 -0
- package/dist/graph/onchain/label-lint.spec.js +1 -0
- package/dist/graph/onchain/names.d.ts +23 -0
- package/dist/graph/onchain/names.js +1 -0
- package/dist/graph/onchain/names.spec.d.ts +1 -0
- package/dist/graph/onchain/names.spec.js +1 -0
- package/dist/graph/onchain/onchain.spec.js +1 -1
- package/dist/graph/onchain/proposal-graph.d.ts +11 -0
- package/dist/graph/onchain/proposal-graph.js +1 -0
- package/dist/graph/onchain/proposal-graph.spec.d.ts +1 -0
- package/dist/graph/onchain/proposal-graph.spec.js +1 -0
- package/dist/graph/onchain/sdk-batch.d.ts +5 -1
- package/dist/graph/onchain/sdk-batch.js +1 -1
- package/dist/graph/onchain/strategy.d.ts +16 -0
- package/dist/graph/onchain/strategy.js +1 -1
- package/dist/graph/onchain/strategy.spec.js +1 -1
- package/dist/graph/onchain/table-ledger.spec.d.ts +1 -0
- package/dist/graph/onchain/table-ledger.spec.js +1 -0
- package/dist/graph/onchain/types.d.ts +46 -6
- package/dist/graph/onchain/viewport.d.ts +1 -0
- package/dist/graph/onchain/viewport.js +1 -1
- package/dist/harness/index.d.ts +1 -5
- package/dist/harness/index.js +1 -1
- package/dist/harness/verify.d.ts +6 -1
- package/dist/harness/verify.js +1 -1
- package/dist/index.js +1 -1
- package/dist/knowledge/allocation-ledger.js +1 -1
- package/dist/knowledge/allocation-risk.d.ts +0 -2
- package/dist/knowledge/allocation-risk.js +1 -1
- package/dist/knowledge/arb-risk.d.ts +0 -1
- package/dist/knowledge/arb-risk.js +1 -1
- package/dist/knowledge/arbitration-risk.d.ts +0 -2
- package/dist/knowledge/arbitration-risk.js +1 -1
- package/dist/knowledge/baselines/evaluation-baselines.json +79 -0
- package/dist/knowledge/baselines/guard-lint-baseline.spec.d.ts +1 -0
- package/dist/knowledge/baselines/guard-lint-baseline.spec.js +1 -0
- package/dist/knowledge/baselines/risk-baselines.spec.d.ts +1 -0
- package/dist/knowledge/baselines/risk-baselines.spec.js +1 -0
- package/dist/knowledge/baselines/risk-cases.d.ts +8 -0
- package/dist/knowledge/baselines/risk-cases.js +1 -0
- package/dist/knowledge/bridge-risk.d.ts +0 -1
- package/dist/knowledge/bridge-risk.js +1 -1
- package/dist/knowledge/contact-risk.d.ts +0 -1
- package/dist/knowledge/contact-risk.js +1 -1
- package/dist/knowledge/contract-invariants.d.ts +1 -0
- package/dist/knowledge/contract-invariants.js +1 -1
- package/dist/knowledge/demand-risk.d.ts +0 -1
- package/dist/knowledge/demand-risk.js +1 -1
- package/dist/knowledge/getting-started.js +1 -1
- package/dist/knowledge/guard-eval.d.ts +15 -0
- package/dist/knowledge/guard-eval.js +1 -0
- package/dist/knowledge/guard-eval.spec.d.ts +1 -0
- package/dist/knowledge/guard-eval.spec.js +1 -0
- package/dist/knowledge/guard-lint.d.ts +1 -1
- package/dist/knowledge/guard-lint.js +1 -1
- package/dist/knowledge/guard-risk.d.ts +4 -19
- package/dist/knowledge/guard-risk.js +1 -1
- package/dist/knowledge/index.d.ts +41 -43
- package/dist/knowledge/index.js +1 -1
- package/dist/knowledge/industry-registry.js +1 -1
- package/dist/knowledge/industry-rule-node.d.ts +7 -0
- package/dist/knowledge/industry-rule-node.js +1 -0
- package/dist/knowledge/jsonrpc-enum.js +1 -1
- package/dist/knowledge/machine-risk.d.ts +0 -6
- package/dist/knowledge/machine-risk.js +1 -1
- package/dist/knowledge/order-risk.d.ts +1 -9
- package/dist/knowledge/order-risk.js +1 -1
- package/dist/knowledge/payment-risk.d.ts +0 -1
- package/dist/knowledge/payment-risk.js +1 -1
- package/dist/knowledge/permission-risk.d.ts +0 -3
- package/dist/knowledge/permission-risk.js +1 -1
- package/dist/knowledge/personal-risk.d.ts +0 -1
- package/dist/knowledge/personal-risk.js +1 -1
- package/dist/knowledge/progress-risk.d.ts +0 -2
- package/dist/knowledge/progress-risk.js +1 -1
- package/dist/knowledge/proof-risk.d.ts +0 -1
- package/dist/knowledge/proof-risk.js +1 -1
- package/dist/knowledge/puzzle-projections.d.ts +11 -0
- package/dist/knowledge/puzzle-projections.js +1 -0
- package/dist/knowledge/registrar-risk.d.ts +0 -1
- package/dist/knowledge/registrar-risk.js +1 -1
- package/dist/knowledge/repository-risk.d.ts +0 -1
- package/dist/knowledge/repository-risk.js +1 -1
- package/dist/knowledge/resource-risk.d.ts +0 -1
- package/dist/knowledge/resource-risk.js +1 -1
- package/dist/knowledge/reward-risk.d.ts +1 -5
- package/dist/knowledge/reward-risk.js +1 -1
- package/dist/knowledge/rule-node-analyzers.d.ts +43 -0
- package/dist/knowledge/rule-node-analyzers.js +1 -0
- package/dist/knowledge/rule-node-analyzers.spec.d.ts +1 -0
- package/dist/knowledge/rule-node-analyzers.spec.js +1 -0
- package/dist/knowledge/rule-outcome.d.ts +5 -0
- package/dist/knowledge/rule-outcome.js +1 -0
- package/dist/knowledge/safety-rules.js +1 -1
- package/dist/knowledge/scenario-topology.js +1 -1
- package/dist/knowledge/service-risk-node.js +1 -1
- package/dist/knowledge/service-risk.d.ts +0 -3
- package/dist/knowledge/service-risk.js +1 -1
- package/dist/knowledge/template-registry.js +1 -1
- package/dist/knowledge/tools-reference.js +1 -1
- package/dist/knowledge/treasury-risk.d.ts +2 -3
- package/dist/knowledge/treasury-risk.js +1 -1
- package/dist/knowledge/util-risk.d.ts +0 -1
- package/dist/knowledge/util-risk.js +1 -1
- package/dist/monitor/MonitorLoop.js +1 -1
- package/dist/persona/bridge.js +1 -1
- package/dist/persona/facet-profile.d.ts +33 -0
- package/dist/persona/facet-profile.js +1 -0
- package/dist/persona/model.d.ts +2 -1
- package/dist/persona/model.js +1 -1
- package/dist/persona/topology-focus.d.ts +2 -2
- package/dist/persona/topology-focus.js +1 -1
- package/dist/persona/types.d.ts +12 -0
- package/dist/playbooks/service-build/business-puzzle.js +1 -1
- package/dist/playbooks/service-build/facet-money.d.ts +22 -0
- package/dist/playbooks/service-build/facet-money.js +1 -0
- package/dist/playbooks/service-build/facet-money.spec.d.ts +1 -0
- package/dist/playbooks/service-build/facet-money.spec.js +1 -0
- package/dist/playbooks/service-build/machine-panorama.d.ts +3 -0
- package/dist/playbooks/service-build/machine-panorama.js +1 -1
- package/dist/playbooks/service-build/object-panorama.d.ts +27 -27
- package/dist/playbooks/service-build/object-panorama.js +1 -1
- package/dist/playbooks/service-build/pipeline-actions.d.ts +2 -2
- package/dist/playbooks/service-build/pipeline-actions.js +1 -1
- package/dist/playbooks/service-build/risk-aggregator.d.ts +2 -1
- package/dist/playbooks/service-build/risk-aggregator.js +1 -1
- package/dist/playbooks/service-build/service-panorama.d.ts +4 -9
- package/dist/playbooks/service-build/service-panorama.js +1 -1
- package/dist/playbooks/service-build/topology-evaluation.spec.d.ts +1 -0
- package/dist/playbooks/service-build/topology-evaluation.spec.js +1 -0
- package/dist/playbooks/service-build/topology-query.d.ts +13 -2
- package/dist/playbooks/service-build/topology-query.js +1 -1
- package/dist/review/arb.d.ts +0 -2
- package/dist/review/arb.js +1 -1
- package/dist/review/order.d.ts +0 -1
- package/dist/review/order.js +1 -1
- package/dist/role/profiles.js +1 -1
- package/dist/rules.d.ts +1 -2
- package/dist/rules.js +1 -1
- package/dist/safety/confirm-gate.js +1 -1
- package/dist/schema/call/base.d.ts +3372 -668
- package/dist/schema/call/base.js +1 -1
- package/dist/schema/call/handler.js +1 -1
- package/dist/schema/call/receipt.d.ts +28 -0
- package/dist/schema/call/receipt.js +1 -0
- package/dist/schema/call/semantic-customer-advice.spec.d.ts +1 -0
- package/dist/schema/call/semantic-customer-advice.spec.js +1 -0
- package/dist/schema/call/semantic.d.ts +5 -2
- package/dist/schema/call/semantic.js +1 -1
- package/dist/schema/call/treasury.js +1 -1
- package/dist/schema/common/index.js +1 -1
- package/dist/schema/evaluation/index.d.ts +289 -211
- package/dist/schema/evaluation/index.js +1 -1
- package/dist/schema/goal/index.d.ts +1 -1
- package/dist/schema/goal/planning.d.ts +2 -2
- package/dist/schema/index.d.ts +0 -1
- package/dist/schema/index.js +1 -1
- package/dist/schema/industry-pack/index.d.ts +1 -1
- package/dist/schema/keeper/index.d.ts +1 -1
- package/dist/schema/local/index.js +1 -1
- package/dist/schema/operations.d.ts +26 -10
- package/dist/schema/operations.js +1 -1
- package/dist/schema/persona/index.d.ts +24 -24
- package/dist/schema/query/bi.d.ts +613 -0
- package/dist/schema/query/bi.js +1 -1
- package/dist/schema/query/index.d.ts +9 -9
- package/dist/schema/schema-version.js +1 -1
- package/dist/schema/workspace/index.d.ts +2 -2
- package/dist/schema-query-impl/index.js +1 -1
- package/dist/schemas/account_operation.output.json +1 -1
- package/dist/schemas/bridge_operation.output.json +1 -1
- package/dist/schemas/evaluation_operation.output.json +691 -163
- package/dist/schemas/evaluation_operation.schema.json +0 -429
- package/dist/schemas/index.json +1 -7
- package/dist/schemas/keeper_operation.output.json +1 -1
- package/dist/schemas/local_history_operation.output.json +1 -1
- package/dist/schemas/local_info_operation.output.json +1 -1
- package/dist/schemas/local_mark_operation.output.json +1 -1
- package/dist/schemas/messenger_operation.output.json +1 -1
- package/dist/schemas/monitor_events.output.json +1 -1
- package/dist/schemas/monitor_subscription.output.json +1 -1
- package/dist/schemas/onchain_events.output.json +1 -1
- package/dist/schemas/onchain_operations.output.json +6357 -3724
- package/dist/schemas/onchain_operations.schema.json +2 -2
- package/dist/schemas/onchain_operations_treasury.schema.json +2 -2
- package/dist/schemas/onchain_table_data.output.json +61 -71
- package/dist/schemas/query_toolkit.output.json +841 -8
- package/dist/schemas/query_toolkit.schema.json +59 -1
- package/dist/strategy/metrics.js +1 -1
- package/dist/tools/handlers/bridge.js +1 -1
- package/dist/tools/handlers/config.js +1 -1
- package/dist/tools/handlers/dispatch-expectations.d.ts +3 -0
- package/dist/tools/handlers/dispatch-expectations.js +1 -0
- package/dist/tools/handlers/evaluation.js +1 -1
- package/dist/tools/handlers/onchain.js +1 -1
- package/dist/tools/handlers/query.js +1 -1
- package/dist/tools/index.js +1 -1
- package/dist/tools/registry/evaluation.d.ts +2 -0
- package/dist/tools/registry/evaluation.js +1 -0
- package/dist/tools/registry/query.js +1 -1
- package/dist/tools/shared.d.ts +0 -1
- package/dist/tools/shared.js +1 -1
- package/dist/tools/wrap.js +1 -1
- package/package.json +4 -3
- package/dist/customer/customer-advice.d.ts +0 -32
- package/dist/customer/customer-advice.js +0 -1
- package/dist/customer/info-puzzle.d.ts +0 -146
- package/dist/customer/info-puzzle.js +0 -1
- package/dist/customer/order-strategy.d.ts +0 -17
- package/dist/customer/order-strategy.js +0 -1
- package/dist/customer/preorder-compare.d.ts +0 -24
- package/dist/customer/preorder-compare.js +0 -1
- package/dist/customer/reminder-system.d.ts +0 -42
- package/dist/customer/reminder-system.js +0 -1
- package/dist/customer/risk-assessment.d.ts +0 -13
- package/dist/customer/risk-assessment.js +0 -1
- package/dist/evaluation/builtins/service-risk.d.ts +0 -7
- package/dist/evaluation/builtins/service-risk.js +0 -1
- package/dist/knowledge/trust-metrics.d.ts +0 -66
- package/dist/knowledge/trust-metrics.js +0 -1
- package/dist/schema/trust/index.d.ts +0 -334
- package/dist/schema/trust/index.js +0 -1
- package/dist/schemas/trust_score.output.json +0 -847
- package/dist/schemas/trust_score.schema.json +0 -364
- package/dist/tools/handlers/trust.d.ts +0 -16
- package/dist/tools/handlers/trust.js +0 -1
- package/dist/tools/registry/trust.d.ts +0 -2
- package/dist/tools/registry/trust.js +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{describe,expect,it}from'vitest';import{readFileSync,writeFileSync}from'node:fs';import{fileURLToPath}from'node:url';import{dirname,join}from'node:path';import{RISK_CASES}from'./risk-cases.js';import{aggregateProjectRisks}from'../../playbooks/service-build/risk-aggregator.js';import{assessTreasuryRisks}from'../treasury-risk.js';import{assessRewardRisks}from'../reward-risk.js';function toArray(a){if(Array['isArray'](a))return a;if(a&&typeof a==='object')for(const b of['risks','detected_risks']){const c=a[b];if(Array['isArray'](c))return c;}return[];}function normalize(a){return toArray(a)['map'](b=>{const c=b??{};return{'id':String(c['id']??c['risk_rule_id']??c['rule_id']??'?'),'level':String(c['level']??c['severity']??'?')['toUpperCase'](),...c['evidence']!=null?{'evidence':String(c['evidence'])}:{}};})['sort']((c,d)=>c['id']===d['id']?(c['evidence']??'')['localeCompare'](d['evidence']??''):c['id']['localeCompare'](d['id']));}function runCase(a,b){try{return{'risks':normalize(a(b)),'threw':![]};}catch(c){return{'risks':[],'threw':!![]};}}function collect(){const a={};for(const b of RISK_CASES){const d=runCase(b['run'],b['empty']),e=runCase(b['run'],b['trigger']);a[b['pack']]={'objectType':b['objectType'],'empty':d['risks'],'emptyThrew':d['threw'],'trigger':e['risks']};}return a;}const here=dirname(fileURLToPath(import.meta.url)),SNAPSHOT=join(here,'risk-baselines.json'),AGG_SNAPSHOT=join(here,'aggregator-baselines.json');function puzzlesFrom(a){const b={};for(const d of RISK_CASES){if(d['pack']==='arb')continue;b[d['objectType']]={'puzzle':a(d)};}return b;}async function runAggregator(a){const b=await aggregateProjectRisks({'project_prefix':'baseline','version':'v1','industry':'general','puzzles':puzzlesFrom(a)});return{'severity_summary':b['severity_summary'],'status':b['status'],'findings':b['findings']['map'](c=>({'risk_rule_id':c['risk_rule_id'],'object_type':c['object_type'],'severity':c['severity']})),'warnings':b['warnings']};}describe('write-side\x20risk\x20packs\x20—\x20pre-migration\x20baseline',()=>{it('every\x20pack\x20trigger\x20context\x20fires\x20at\x20least\x20one\x20pack-specific\x20rule',()=>{for(const a of RISK_CASES){const {risks:b}=runCase(a['run'],a['trigger']);expect(b['length'],'pack\x20'+a['pack']+'\x20trigger\x20fired\x20nothing')['toBeGreaterThan'](0x0);}}),it('matches\x20the\x20committed\x20snapshot\x20(regenerate\x20only\x20with\x20--update)',()=>{const a=collect();if(process['env']['UPDATE_RISK_BASELINE']==='1'){writeFileSync(SNAPSHOT,JSON['stringify'](a,null,0x2)+'\x0a','utf8');return;}const b=JSON['parse'](readFileSync(SNAPSHOT,'utf8'));expect(new Set(Object['keys'](a)))['toEqual'](new Set(Object['keys'](b)));for(const c of Object['keys'](a)['sort']()){expect(a[c],'pack\x20'+c+'\x20drifted')['toEqual'](b[c]);}});}),describe('risk\x20aggregator\x20—\x20Task\x2026\x20parity\x20(id/severity/status)',()=>{const a=[['empty',b=>b['empty']],['trigger',b=>b['trigger']]];it('matches\x20the\x20committed\x20snapshot\x20(regenerate\x20only\x20with\x20--update)',async()=>{const b={};for(const [d,e]of a)b[d]=await runAggregator(e);if(process['env']['UPDATE_RISK_BASELINE']==='1'){writeFileSync(AGG_SNAPSHOT,JSON['stringify'](b,null,0x2)+'\x0a','utf8');return;}const c=JSON['parse'](readFileSync(AGG_SNAPSHOT,'utf8'));expect(b)['toEqual'](c);}),it('trigger\x20row\x20produces\x20CRITICAL\x20blockers\x20(sanity:\x20status\x20machine\x20alive)',async()=>{const b=await runAggregator(d=>d['trigger']);expect(b['findings']['some'](c=>c['severity']==='CRITICAL'))['toBe'](!![]),expect(b['status'])['not']['toBe']('RISK_PASSED');}),it('TR-26.2\x20every\x20finding\x20carries\x20its\x20proposal-graph\x20path\x20(explainability)',async()=>{const b=await aggregateProjectRisks({'project_prefix':'baseline','version':'v1','industry':'general','puzzles':puzzlesFrom(d=>d['trigger'])});expect(b['findings']['length'])['toBeGreaterThan'](0x0);for(const c of b['findings']){expect(c['details']?.['proposal_node'],'finding\x20'+c['risk_rule_id']+'\x20has\x20no\x20proposal\x20node')['toMatch'](/^proposal::/),expect(c['details']?.['rule_source'],'finding\x20'+c['risk_rule_id']+'\x20has\x20no\x20analyzer\x20source')['not']['toBe']('');}});}),describe('R-T-2-04\x20—\x20external_withdraw\x20pays\x20only\x20the\x20transaction\x20sender',()=>{const a={'withdraw':{'amount_by_external_withdraw_guard':'release-guard','recipient':'0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'}};it('flags\x20HIGH\x20(code\x2010\x20abort\x20ahead)\x20when\x20recipient\x20!=\x20known\x20sender',()=>{const {risks:b}=assessTreasuryRisks({...a,'sender_address':'0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'}),c=b['find'](d=>d['id']==='R-T-2-04');expect(c?.['level'])['toBe']('HIGH'),expect(c?.['description']??'')['toContain']('code\x2010');}),it('stays\x20silent\x20when\x20recipient\x20equals\x20the\x20sender',()=>{const {risks:b}=assessTreasuryRisks({...a,'sender_address':'0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'});expect(b['some'](c=>c['id']==='R-T-2-04'))['toBe'](![]);}),it('advises\x20MEDIUM\x20when\x20the\x20sender\x20is\x20not\x20known\x20at\x20analysis\x20time',()=>{const {risks:b}=assessTreasuryRisks(a),c=b['find'](d=>d['id']==='R-T-2-04');expect(c?.['level'])['toBe']('MEDIUM');}),it('does\x20not\x20fire\x20on\x20the\x20fixed\x20(permissioned)\x20withdraw\x20path',()=>{const {risks:b}=assessTreasuryRisks({'withdraw':{'amount_fixed':'1000','recipient':'0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'},'sender_address':'0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'});expect(b['some'](c=>c['id']==='R-T-2-04'))['toBe'](![]);});}),describe('R-T-4-04\x20—\x20mounting\x20external\x20Guards\x20(owner\x20diligence\x20reminder)',()=>{it('flags\x20MEDIUM\x20when\x20mounting\x20external\x20withdraw\x20Guards',()=>{const {risks:a}=assessTreasuryRisks({'external_withdraw_guard':{'op':'add','guards':[{'guard':'0xg1','identifier':0x0}]}}),b=a['find'](c=>c['id']==='R-T-4-04');expect(b?.['level'])['toBe']('MEDIUM'),expect(b?.['description']??'')['toContain']('code\x2010');}),it('flags\x20LOW\x20when\x20mounting\x20external\x20deposit\x20Guards',()=>{const {risks:a}=assessTreasuryRisks({'external_deposit_guard':{'op':'add','guards':[{'guard':'0xg2'}]}}),b=a['find'](c=>c['id']==='R-T-4-04');expect(b?.['level'])['toBe']('LOW');}),it('stays\x20silent\x20on\x20remove/clear',()=>{const {risks:a}=assessTreasuryRisks({'external_withdraw_guard':{'op':'remove','guards':['0xg1']}});expect(a['some'](b=>b['id']==='R-T-4-04'))['toBe'](![]);});}),describe('R-R-2-05\x20—\x20mounting\x20a\x20claim\x20Guard\x20with\x20a\x20GuardIdentifier\x20payout\x20slot',()=>{const a={'guard':'0xg1','amount':{'type':'fixed','value':'100'}};it('flags\x20MEDIUM\x20when\x20the\x20recipient\x20is\x20a\x20GuardIdentifier\x20slot',()=>{const {risks:b}=assessRewardRisks({'guard_add':[{...a,'recipient':{'GuardIdentifier':0x0}}]}),c=b['find'](d=>d['id']==='R-R-2-05');expect(c?.['level'])['toBe']('MEDIUM'),expect(c?.['description']??'')['toContain']('GuardIdentifier');}),it('stays\x20silent\x20for\x20Entity/Signer\x20recipients',()=>{const {risks:b}=assessRewardRisks({'guard_add':[{...a,'recipient':{'Entity':'0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'}}]});expect(b['some'](c=>c['id']==='R-R-2-05'))['toBe'](![]);});});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{assessServiceRisks,assessMachineRisks,assessAllocationRisks,assessTreasuryRisks,assessArbitrationRisks,assessRewardRisks,assessProgressRisks,assessOrderRisks,runGuardRulePack,checkContactRisks,checkResourceRisks,checkPaymentRisks,checkArbRisks,checkPersonalRisks,checkUtilRisks,checkRegistrarRisks,checkBridgeRisks,checkProofRisks,checkRepositoryRisks,checkDemandRisks}from'../index.js';import{assessPermissionRisks}from'../permission-risk.js';const HUGE=0xa**0x9,str=a=>'x'['repeat'](a);export const RISK_CASES=[{'objectType':'service','pack':'service','run':a=>assessServiceRisks(a),'empty':{},'trigger':{'pause':!![]}},{'objectType':'machine','pack':'machine','run':a=>assessMachineRisks(a,{}),'empty':{},'trigger':{'pairs':[],'nodes':[]}},{'objectType':'allocation','pack':'allocation','run':a=>assessAllocationRisks(a),'empty':{},'trigger':{'allocators_config':{'allocators':[{'guard':'0xg1','sharing':[]},{'guard':'0xg2','sharing':[]}]},'has_fallback_allocator':![],'guard_conditions_mutually_exclusive':![]}},{'objectType':'treasury','pack':'treasury','run':a=>assessTreasuryRisks(a),'empty':{},'trigger':{'description':str(0xfa1)}},{'objectType':'arb','pack':'arbitration','run':a=>assessArbitrationRisks(a),'empty':{},'trigger':{'arbitration':'0xarb-svc'}},{'objectType':'reward','pack':'reward','run':a=>assessRewardRisks(a),'empty':{},'trigger':{'guard_add':Array['from']({'length':0xc9},(a,b)=>({'guard':'0xg'+b,'recipient':{'Entity':'0x'+(b+0x1)['toString']()['padStart'](0x40,'0')},'amount':{'type':'fixed','value':'1'}}))}},{'objectType':'progress','pack':'progress','run':a=>assessProgressRisks(a),'empty':{},'trigger':{'machine_published':![],'current_machine':'0xmac'}},{'objectType':'order','pack':'order','run':a=>assessOrderRisks(a),'empty':{},'trigger':{'is_buy_operation':!![],'items':Array['from']({'length':0x33},()=>({}))}},{'objectType':'permission','pack':'permission','run':a=>assessPermissionRisks(a),'empty':{},'trigger':{'table':{'entity':'0xe1','index':Array['from']({'length':0x3e9},(a,b)=>b)}}},{'objectType':'guard','pack':'guard','run':a=>runGuardRulePack(a),'empty':{'table':[],'root':undefined},'trigger':{'table':[],'root':{'type':'identifier','value':0x0},'scene':{'id':'service_order_allocators_guard','host_object':'Service','binding_field':'order_allocators'}}},{'objectType':'contact','pack':'contact','run':a=>checkContactRisks(a),'empty':{},'trigger':{'im_count':0xc8}},{'objectType':'resource','pack':'resource','run':a=>checkResourceRisks(a),'empty':{},'trigger':{'tags_count':HUGE}},{'objectType':'payment','pack':'payment','run':a=>checkPaymentRisks(a),'empty':{},'trigger':{'recipient_count':HUGE}},{'objectType':'arb','pack':'arb','run':a=>checkArbRisks(a),'empty':{},'trigger':{'votor_count':HUGE}},{'objectType':'personal','pack':'personal','run':a=>checkPersonalRisks(a),'empty':{},'trigger':{'information_entries':[{'name':'phone','value':'+8613800000000'}],'information_count':HUGE}},{'objectType':'util','pack':'util','run':a=>checkUtilRisks(a),'empty':{},'trigger':{'uses_typo_function_name':!![],'assumes_stable_address_bytes':!![],'large_util_import':!![],'expects_util_events':!![],'bcs_manually_synced':!![]}},{'objectType':'registrar','pack':'registrar','run':a=>checkRegistrarRisks(a),'empty':{},'trigger':{'address_count':HUGE,'expects_singleton_migration':!![],'uses_reserved_vote_bits':!![],'expects_fresh_resource_on_register':!![],'expects_affiliation_event':!![],'relies_on_typed_value_convention':!![],'is_resource_transfer':!![],'expects_vote_time_only_on_like':!![]}},{'objectType':'bridge','pack':'bridge','run':a=>checkBridgeRisks(a),'empty':{},'trigger':{'idempotency_key_length':HUGE}},{'objectType':'proof','pack':'proof','run':a=>checkProofRisks(a),'empty':{},'trigger':{'proof':str(0x2801)}},{'objectType':'repository','pack':'repository','run':a=>checkRepositoryRisks(a),'empty':{},'trigger':{'data_size':HUGE}},{'objectType':'demand','pack':'demand','run':a=>checkDemandRisks(a),'empty':{},'trigger':{'reward_count':HUGE,'guard_count':HUGE,'feedback_count':HUGE}}];
|
|
@@ -33,4 +33,3 @@ export declare const BRIDGE_RISK_RULES: {
|
|
|
33
33
|
}[];
|
|
34
34
|
export declare const BRIDGE_RISK_VERSION = "1.0.0";
|
|
35
35
|
export declare function checkBridgeRisks(ctx: BridgeRiskCheckContext): BridgeRisk[];
|
|
36
|
-
export declare function getBridgeRiskById(id: string): BridgeRisk | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{BRIDGE_MESSAGE_VERSION,BRIDGE_EVM_ADDRESS_LENGTH,BRIDGE_CURRENT_VERSION}from'@wowok/wowok';const SUPPORTED_TOKENS=['ETH','WETH','WBTC','USDC','USDT'],MAX_IDEMPOTENCY_KEY_LENGTH=0x80,BRIDGE_ERROR_CODE_COUNT=0x14,R_B_01={'rule':{'id':'R-BRIDGE-01','level':'CRITICAL','category':'permission','title':'Cross-chain\x20asset\x20security\x20—\x20committee\x20signature\x20verification\x20is\x20the\x20single\x20trust\x20root','description':'Bridge\x20committee\x20signatures\x20are\x20the\x20only\x20thing\x20preventing\x20forged\x20cross-chain\x20messages\x20'+'from\x20minting\x20tokens\x20out\x20of\x20thin\x20air\x20(bridge.move:60).\x20If\x20a\x20committee\x20key\x20is\x20'+'compromised,\x20or\x20if\x20the\x20verification\x20logic\x20has\x20a\x20bug,\x20an\x20attacker\x20can\x20claim\x20arbitrary\x20'+'amounts\x20of\x20ETH/WETH/WBTC/USDC/USDT.\x20The\x20TransferLimiter\x20caps\x20single-transfer\x20amounts\x20'+'but\x20does\x20not\x20prevent\x20repeated\x20small\x20attacks.','affected_stakeholders':['user','committee','system'],'scenario':'Committee\x20private\x20key\x20leaks;\x20attacker\x20forges\x20an\x20approved\x20transfer\x20and\x20claims\x20funds','mitigation':'Committee\x20members\x20MUST\x20use\x20HSM-backed\x20multi-sig.\x20Rotate\x20keys\x20on\x20a\x20schedule.\x20Audit\x20'+'committee\x20membership\x20and\x20signature\x20verification\x20logic\x20on\x20every\x20release.\x20Monitor\x20'+'limiter\x20utilization\x20for\x20suspicious\x20patterns.\x20Have\x20an\x20EmergencyOp\x20pause\x20plan\x20ready.','auto_fixable':![]},'check':a=>{if(!a['assumes_committee_infallible'])return null;return{...R_B_01['rule'],'evidence':'assumes_committee_infallible=true\x20(trust\x20root\x20is\x20single-point)'};}},R_B_02={'rule':{'id':'R-BRIDGE-02','level':'HIGH','category':'cross_object','title':'Bridge\x20is\x20mainnet-only\x20—\x20testnet\x20operations\x20will\x20fail','description':'The\x20Bridge\x20is\x20only\x20configured\x20on\x20mainnet.\x20testnet\x20nodes\x20do\x20not\x20have\x20the\x20bridge\x20'+'role\x20configured,\x20so\x20any\x20cross-chain\x20operation\x20(cross_chain_wow_to_evm,\x20'+'cross_chain_evm_to_wow,\x20claim_wow_to_evm,\x20etc.)\x20will\x20abort.\x20Developers\x20who\x20test\x20on\x20'+'testnet\x20will\x20see\x20EBridgeUnavailable\x20(8)\x20and\x20may\x20misdiagnose\x20it\x20as\x20a\x20code\x20bug.','affected_stakeholders':['user','operator'],'scenario':'Developer\x20runs\x20cross_chain_wow_to_evm\x20on\x20testnet;\x20aborts\x20with\x20EBridgeUnavailable','mitigation':'MCP\x20layer\x20MUST\x20validate\x20mainnet\x20environment\x20before\x20submitting\x20Bridge\x20ops.\x20Document\x20'+'the\x20mainnet-only\x20restriction\x20prominently.\x20For\x20testing,\x20use\x20mainnet\x20small-amount\x20'+'transactions\x20or\x20fork\x20tests.','related_move_error':'EBridgeUnavailable\x20(8)','auto_fixable':![]},'check':a=>{if(!a['is_non_mainnet'])return null;return{...R_B_02['rule'],'evidence':'is_non_mainnet=true\x20(Bridge\x20unavailable)'};}},R_B_03={'rule':{'id':'R-BRIDGE-03','level':'HIGH','category':'structural','title':'TransferLimiter\x20caps\x20single\x20and\x20cumulative\x20transfer\x20amounts\x20—\x20large\x20transfers\x20reject','description':'The\x20TransferLimiter\x20(bridge.move:64)\x20enforces\x20both\x20per-transfer\x20and\x20cumulative\x20'+'transfer\x20caps\x20per\x20token\x20type.\x20A\x20transfer\x20that\x20exceeds\x20the\x20cap\x20aborts\x20with\x20'+'ETokenAlreadyClaimedOrHitLimit\x20(15)\x20or\x20similar.\x20Users\x20attempting\x20large\x20cross-chain\x20'+'moves\x20will\x20see\x20their\x20transactions\x20rejected\x20and\x20may\x20misdiagnose\x20it\x20as\x20a\x20bug.','affected_stakeholders':['user'],'scenario':'User\x20attempts\x20to\x20bridge\x201000\x20ETH;\x20limiter\x20rejects\x20the\x20transfer','mitigation':'Document\x20the\x20limiter\x20semantics.\x20Before\x20submitting,\x20query\x20the\x20current\x20limiter\x20'+'utilization.\x20For\x20large\x20amounts,\x20split\x20into\x20batches\x20across\x20multiple\x20transactions\x20'+'and/or\x20time\x20windows.\x20Surface\x20the\x20remaining\x20cap\x20in\x20the\x20UI.','related_move_error':'ETokenAlreadyClaimedOrHitLimit\x20(15)','auto_fixable':![]},'check':a=>null},R_B_04={'rule':{'id':'R-BRIDGE-04','level':'MEDIUM','category':'permission','title':'activeEvmAccount\x20is\x20a\x20single\x20global\x20EVM\x20account\x20—\x20key\x20leak\x20affects\x20all\x20assets','description':'Bridge\x20uses\x20a\x20single\x20global\x20activeEvmAccount\x20that\x20is\x20auto-generated\x20and\x20transparent\x20'+'to\x20users.\x20All\x20cross-chain\x20EVM-side\x20operations\x20flow\x20through\x20this\x20one\x20account.\x20If\x20its\x20'+'private\x20key\x20leaks,\x20every\x20supported\x20token\x20(ETH/WETH/WBTC/USDC/USDT)\x20on\x20every\x20'+'supported\x20chain\x20is\x20at\x20risk.\x20There\x20is\x20no\x20per-user\x20EVM\x20account\x20isolation.','affected_stakeholders':['user','system'],'scenario':'activeEvmAccount\x20private\x20key\x20leaks;\x20attacker\x20drains\x20all\x20bridged\x20EVM\x20assets','mitigation':'Store\x20the\x20activeEvmAccount\x20key\x20in\x20an\x20HSM.\x20Rotate\x20the\x20key\x20on\x20a\x20schedule\x20and\x20via\x20'+'Versioned\x20upgrade.\x20Monitor\x20EVM-side\x20balances\x20for\x20anomalous\x20outflows.\x20Have\x20an\x20'+'EmergencyOp\x20pause\x20plan\x20ready.','auto_fixable':![]},'check':a=>{if(!a['assumes_per_user_evm_account'])return null;return{...R_B_04['rule'],'evidence':'assumes_per_user_evm_account=true\x20(it\x20is\x20global)'};}},R_B_05={'rule':{'id':'R-BRIDGE-05','level':'MEDIUM','category':'cross_object','title':'Public\x20EVM\x20RPCs\x20may\x20rate-limit\x20(HTTP\x20429)\x20—\x20cross-chain\x20ops\x20stall','description':'Bridge\x20ops\x20that\x20query\x20EVM\x20state\x20(query_active_evm_account,\x20query_supported_evm_chains,\x20'+'query_transfer_status,\x20etc.)\x20depend\x20on\x20an\x20EVM\x20RPC.\x20Public\x20RPCs\x20(e.g.\x20Infura\x20free\x20tier,\x20'+'Alchemy\x20free\x20tier)\x20frequently\x20return\x20HTTP\x20429\x20under\x20load.\x20A\x20429\x20mid-flow\x20stalls\x20the\x20'+'cross-chain\x20operation\x20and\x20may\x20confuse\x20the\x20user.\x20manage_evm_rpc\x20supports\x20multi-RPC\x20'+'rotation,\x20but\x20it\x20must\x20be\x20configured\x20in\x20advance.','affected_stakeholders':['user','operator'],'scenario':'User\x20queries\x20transfer\x20status;\x20public\x20RPC\x20returns\x20429;\x20UI\x20shows\x20generic\x20error','mitigation':'Configure\x20multiple\x20EVM\x20RPCs\x20via\x20manage_evm_rpc\x20and\x20enable\x20failover.\x20Use\x20a\x20paid\x20RPC\x20'+'tier\x20for\x20production.\x20Surface\x20429\x20as\x20\x27RPC\x20busy,\x20retry\x27\x20rather\x20than\x20\x27operation\x20failed\x27.','auto_fixable':![]},'check':a=>{if(!a['uses_public_evm_rpc'])return null;return{...R_B_05['rule'],'evidence':'uses_public_evm_rpc=true\x20(429\x20risk)'};}},R_B_06={'rule':{'id':'R-BRIDGE-06','level':'MEDIUM','category':'lifecycle','title':'EmergencyOp\x20can\x20pause\x20the\x20Bridge\x20—\x20assets\x20lock\x20during\x20pause','description':'EmergencyOp\x20(bridge.move:89-91)\x20can\x20pause\x20the\x20entire\x20Bridge.\x20While\x20paused,\x20no\x20'+'cross-chain\x20operations\x20proceed\x20—\x20assets\x20in\x20flight\x20cannot\x20be\x20claimed,\x20new\x20transfers\x20'+'cannot\x20be\x20initiated.\x20The\x20pause\x20is\x20intended\x20for\x20incident\x20response,\x20but\x20a\x20prolonged\x20'+'pause\x20locks\x20user\x20funds\x20for\x20the\x20duration.','affected_stakeholders':['user','operator'],'scenario':'Bridge\x20is\x20paused\x20for\x20incident\x20response;\x20users\x20cannot\x20claim\x20in-flight\x20transfers','mitigation':'Document\x20the\x20pause\x20scenario\x20and\x20the\x20emergency\x20plan.\x20Provide\x20a\x20status\x20page\x20showing\x20'+'pause\x20state.\x20Set\x20expectations\x20on\x20pause\x20duration\x20and\x20recovery.\x20Operators\x20should\x20'+'practice\x20un-pause\x20drills.','auto_fixable':![]},'check':a=>{if(!a['is_paused'])return null;return{...R_B_06['rule'],'evidence':'is_paused=true\x20(assets\x20locked)'};}},R_B_07={'rule':{'id':'R-BRIDGE-07','level':'LOW','category':'structural','title':'Only\x20'+SUPPORTED_TOKENS['length']+'\x20tokens\x20supported\x20—\x20unsupported\x20tokens\x20cannot\x20bridge','description':'Bridge\x20supports\x20exactly\x20'+SUPPORTED_TOKENS['length']+'\x20tokens:\x20'+SUPPORTED_TOKENS['join'](',\x20')+'.\x20'+'Any\x20other\x20token\x20(e.g.\x20DAI,\x20LINK,\x20custom\x20tokens)\x20cannot\x20be\x20bridged.\x20Users\x20holding\x20'+'unsupported\x20tokens\x20will\x20see\x20their\x20transfer\x20rejected\x20with\x20EUnexpectedTokenType\x20(3).','affected_stakeholders':['user'],'scenario':'User\x20attempts\x20to\x20bridge\x20DAI;\x20aborts\x20with\x20EUnexpectedTokenType','mitigation':'Document\x20the\x20supported\x20token\x20list\x20prominently.\x20UI\x20should\x20filter\x20the\x20token\x20picker\x20to\x20'+'supported\x20tokens\x20only.\x20For\x20unsupported\x20tokens,\x20recommend\x20an\x20alternative\x20bridge.','related_move_error':'EUnexpectedTokenType\x20(3)','auto_fixable':![]},'check':a=>{if(!a['unsupported_token'])return null;return{...R_B_07['rule'],'evidence':'unsupported_token='+a['unsupported_token']+'\x20(supported:\x20'+SUPPORTED_TOKENS['join'](',')+')'};}},R_B_08={'rule':{'id':'R-BRIDGE-08','level':'MEDIUM','category':'structural','title':'Idempotency\x20key\x20max\x20'+MAX_IDEMPOTENCY_KEY_LENGTH+'\x20chars\x20—\x20long\x20keys\x20truncate\x20or\x20reject','description':'BridgeIdempotencyKeySchema\x20accepts\x20strings\x20of\x20length\x201-'+MAX_IDEMPOTENCY_KEY_LENGTH+'.\x20'+'Callers\x20who\x20generate\x20idempotency\x20keys\x20from\x20long\x20sources\x20(e.g.\x20full\x20JSON\x20payloads,\x20'+'UUIDs\x20with\x20prefixes)\x20may\x20exceed\x20the\x20limit\x20and\x20see\x20the\x20operation\x20rejected.\x20The\x20limit\x20'+'exists\x20to\x20keep\x20on-chain\x20storage\x20bounded.','affected_stakeholders':['user'],'scenario':'Caller\x20uses\x20a\x20200-char\x20idempotency\x20key;\x20operation\x20rejected','mitigation':'Generate\x20idempotency\x20keys\x20from\x20a\x20hash\x20(e.g.\x20keccak256\x20of\x20the\x20payload,\x20hex-encoded\x20=\x20'+'66\x20chars)\x20or\x20a\x20UUID\x20(36\x20chars).\x20Validate\x20length\x20client-side\x20before\x20submission.','auto_fixable':!![]},'check':a=>{if(a['idempotency_key_length']===undefined)return null;if(a['idempotency_key_length']<=MAX_IDEMPOTENCY_KEY_LENGTH)return null;return{...R_B_08['rule'],'evidence':'idempotency_key_length='+a['idempotency_key_length']+',\x20limit='+MAX_IDEMPOTENCY_KEY_LENGTH};}},R_B_09={'rule':{'id':'R-BRIDGE-09','level':'LOW','category':'structural','title':BRIDGE_ERROR_CODE_COUNT+'\x20error\x20codes\x20—\x20debugging\x20requires\x20a\x20lookup\x20table','description':'Bridge\x20defines\x20'+BRIDGE_ERROR_CODE_COUNT+'\x20error\x20codes\x20(EUnexpectedMessageType=0\x20'+'through\x20ETokenValueIsZero=19).\x20Debugging\x20an\x20abort\x20requires\x20mapping\x20the\x20numeric\x20code\x20'+'back\x20to\x20its\x20name\x20and\x20meaning.\x20New\x20contributors\x20often\x20misread\x20codes\x20because\x20they\x20'+'are\x20not\x20enumerated\x20in\x20the\x20abort\x20message.','affected_stakeholders':['user','operator'],'scenario':'Bridge\x20aborts\x20with\x20code\x2015;\x20developer\x20does\x20not\x20know\x20what\x20ETokenAlreadyClaimedOrHitLimit\x20means','mitigation':'Publish\x20an\x20error-code\x20lookup\x20table\x20in\x20the\x20docs.\x20SDK\x20should\x20decode\x20abort\x20codes\x20into\x20'+'human-readable\x20strings.\x20MCP\x20layer\x20should\x20surface\x20the\x20decoded\x20name\x20in\x20error\x20messages.','auto_fixable':![]},'check':a=>{if(!a['expects_simple_error_codes'])return null;return{...R_B_09['rule'],'evidence':'expects_simple_error_codes=true\x20(there\x20are\x20'+BRIDGE_ERROR_CODE_COUNT+')'};}},R_B_10={'rule':{'id':'R-BRIDGE-10','level':'MEDIUM','category':'lifecycle','title':'Versioned\x20upgrade\x20(current='+BRIDGE_CURRENT_VERSION+')\x20can\x20brick\x20the\x20Bridge\x20if\x20botched','description':'Bridge\x20uses\x20Versioned\x20to\x20wrap\x20BridgeInner\x20(bridge.move:49),\x20supporting\x20schema\x20upgrades.\x20'+('The\x20current\x20version\x20is\x20BRIDGE_CURRENT_VERSION='+BRIDGE_CURRENT_VERSION+'.\x20An\x20upgrade\x20')+'that\x20mishandles\x20the\x20inner\x20version\x20migration\x20can\x20permanently\x20brick\x20the\x20Bridge\x20—\x20'+'funds\x20in\x20flight\x20would\x20be\x20locked,\x20and\x20recovery\x20requires\x20a\x20new\x20package\x20version.\x20The\x20'+('message_version\x20(current='+BRIDGE_MESSAGE_VERSION+')\x20and\x20EVM\x20address\x20length\x20')+('('+BRIDGE_EVM_ADDRESS_LENGTH+'\x20bytes)\x20are\x20also\x20versioned.'),'affected_stakeholders':['user','operator','system'],'scenario':'Upgrade\x20mishandles\x20BridgeInner\x20migration;\x20Bridge\x20becomes\x20unusable','mitigation':'Test\x20upgrades\x20on\x20a\x20fork\x20with\x20full\x20state\x20replay.\x20Keep\x20a\x20rollback\x20package\x20version\x20'+'ready.\x20Stage\x20upgrades\x20with\x20a\x20pause\x20window\x20so\x20users\x20can\x20complete\x20in-flight\x20ops.\x20'+'Audit\x20message_version\x20and\x20EVM\x20address\x20length\x20compatibility\x20on\x20every\x20upgrade.','related_move_error':'EWrongInnerVersion\x20(7)','auto_fixable':![]},'check':a=>{if(!a['versioned_upgrade_in_progress'])return null;return{...R_B_10['rule'],'evidence':'versioned_upgrade_in_progress=true\x20(current='+BRIDGE_CURRENT_VERSION+')'};}};export const BRIDGE_RISK_RULES=[R_B_01,R_B_02,R_B_03,R_B_04,R_B_05,R_B_06,R_B_07,R_B_08,R_B_09,R_B_10];export const BRIDGE_RISK_VERSION='1.0.0';export function checkBridgeRisks(a){const b=[];for(const c of BRIDGE_RISK_RULES){const d=c['check'](a);if(d)b['push'](d);}return!b['find'](e=>e['id']==='R-BRIDGE-03')&&b['push'](R_B_03['rule']),b;}export function getBridgeRiskById(a){return BRIDGE_RISK_RULES['find'](b=>b['rule']['id']===a)?.['rule'];}
|
|
1
|
+
import{BRIDGE_MESSAGE_VERSION,BRIDGE_EVM_ADDRESS_LENGTH,BRIDGE_CURRENT_VERSION}from'@wowok/wowok';const SUPPORTED_TOKENS=['ETH','WETH','WBTC','USDC','USDT'],MAX_IDEMPOTENCY_KEY_LENGTH=0x80,BRIDGE_ERROR_CODE_COUNT=0x14,R_B_01={'rule':{'id':'R-BRIDGE-01','level':'CRITICAL','category':'permission','title':'Cross-chain\x20asset\x20security\x20—\x20committee\x20signature\x20verification\x20is\x20the\x20single\x20trust\x20root','description':'Bridge\x20committee\x20signatures\x20are\x20the\x20only\x20thing\x20preventing\x20forged\x20cross-chain\x20messages\x20'+'from\x20minting\x20tokens\x20out\x20of\x20thin\x20air\x20(bridge.move:60).\x20If\x20a\x20committee\x20key\x20is\x20'+'compromised,\x20or\x20if\x20the\x20verification\x20logic\x20has\x20a\x20bug,\x20an\x20attacker\x20can\x20claim\x20arbitrary\x20'+'amounts\x20of\x20ETH/WETH/WBTC/USDC/USDT.\x20The\x20TransferLimiter\x20caps\x20single-transfer\x20amounts\x20'+'but\x20does\x20not\x20prevent\x20repeated\x20small\x20attacks.','affected_stakeholders':['user','committee','system'],'scenario':'Committee\x20private\x20key\x20leaks;\x20attacker\x20forges\x20an\x20approved\x20transfer\x20and\x20claims\x20funds','mitigation':'Committee\x20members\x20MUST\x20use\x20HSM-backed\x20multi-sig.\x20Rotate\x20keys\x20on\x20a\x20schedule.\x20Audit\x20'+'committee\x20membership\x20and\x20signature\x20verification\x20logic\x20on\x20every\x20release.\x20Monitor\x20'+'limiter\x20utilization\x20for\x20suspicious\x20patterns.\x20Have\x20an\x20EmergencyOp\x20pause\x20plan\x20ready.','auto_fixable':![]},'check':a=>{if(!a['assumes_committee_infallible'])return null;return{...R_B_01['rule'],'evidence':'assumes_committee_infallible=true\x20(trust\x20root\x20is\x20single-point)'};}},R_B_02={'rule':{'id':'R-BRIDGE-02','level':'HIGH','category':'cross_object','title':'Bridge\x20is\x20mainnet-only\x20—\x20testnet\x20operations\x20will\x20fail','description':'The\x20Bridge\x20is\x20only\x20configured\x20on\x20mainnet.\x20testnet\x20nodes\x20do\x20not\x20have\x20the\x20bridge\x20'+'role\x20configured,\x20so\x20any\x20cross-chain\x20operation\x20(cross_chain_wow_to_evm,\x20'+'cross_chain_evm_to_wow,\x20claim_wow_to_evm,\x20etc.)\x20will\x20abort.\x20Developers\x20who\x20test\x20on\x20'+'testnet\x20will\x20see\x20EBridgeUnavailable\x20(8)\x20and\x20may\x20misdiagnose\x20it\x20as\x20a\x20code\x20bug.','affected_stakeholders':['user','operator'],'scenario':'Developer\x20runs\x20cross_chain_wow_to_evm\x20on\x20testnet;\x20aborts\x20with\x20EBridgeUnavailable','mitigation':'MCP\x20layer\x20MUST\x20validate\x20mainnet\x20environment\x20before\x20submitting\x20Bridge\x20ops.\x20Document\x20'+'the\x20mainnet-only\x20restriction\x20prominently.\x20For\x20testing,\x20use\x20mainnet\x20small-amount\x20'+'transactions\x20or\x20fork\x20tests.','related_move_error':'EBridgeUnavailable\x20(8)','auto_fixable':![]},'check':a=>{if(!a['is_non_mainnet'])return null;return{...R_B_02['rule'],'evidence':'is_non_mainnet=true\x20(Bridge\x20unavailable)'};}},R_B_03={'rule':{'id':'R-BRIDGE-03','level':'HIGH','category':'structural','title':'TransferLimiter\x20caps\x20single\x20and\x20cumulative\x20transfer\x20amounts\x20—\x20large\x20transfers\x20reject','description':'The\x20TransferLimiter\x20(bridge.move:64)\x20enforces\x20both\x20per-transfer\x20and\x20cumulative\x20'+'transfer\x20caps\x20per\x20token\x20type.\x20A\x20transfer\x20that\x20exceeds\x20the\x20cap\x20aborts\x20with\x20'+'ETokenAlreadyClaimedOrHitLimit\x20(15)\x20or\x20similar.\x20Users\x20attempting\x20large\x20cross-chain\x20'+'moves\x20will\x20see\x20their\x20transactions\x20rejected\x20and\x20may\x20misdiagnose\x20it\x20as\x20a\x20bug.','affected_stakeholders':['user'],'scenario':'User\x20attempts\x20to\x20bridge\x201000\x20ETH;\x20limiter\x20rejects\x20the\x20transfer','mitigation':'Document\x20the\x20limiter\x20semantics.\x20Before\x20submitting,\x20query\x20the\x20current\x20limiter\x20'+'utilization.\x20For\x20large\x20amounts,\x20split\x20into\x20batches\x20across\x20multiple\x20transactions\x20'+'and/or\x20time\x20windows.\x20Surface\x20the\x20remaining\x20cap\x20in\x20the\x20UI.','related_move_error':'ETokenAlreadyClaimedOrHitLimit\x20(15)','auto_fixable':![]},'check':a=>null},R_B_04={'rule':{'id':'R-BRIDGE-04','level':'MEDIUM','category':'permission','title':'activeEvmAccount\x20is\x20a\x20single\x20global\x20EVM\x20account\x20—\x20key\x20leak\x20affects\x20all\x20assets','description':'Bridge\x20uses\x20a\x20single\x20global\x20activeEvmAccount\x20that\x20is\x20auto-generated\x20and\x20transparent\x20'+'to\x20users.\x20All\x20cross-chain\x20EVM-side\x20operations\x20flow\x20through\x20this\x20one\x20account.\x20If\x20its\x20'+'private\x20key\x20leaks,\x20every\x20supported\x20token\x20(ETH/WETH/WBTC/USDC/USDT)\x20on\x20every\x20'+'supported\x20chain\x20is\x20at\x20risk.\x20There\x20is\x20no\x20per-user\x20EVM\x20account\x20isolation.','affected_stakeholders':['user','system'],'scenario':'activeEvmAccount\x20private\x20key\x20leaks;\x20attacker\x20drains\x20all\x20bridged\x20EVM\x20assets','mitigation':'Store\x20the\x20activeEvmAccount\x20key\x20in\x20an\x20HSM.\x20Rotate\x20the\x20key\x20on\x20a\x20schedule\x20and\x20via\x20'+'Versioned\x20upgrade.\x20Monitor\x20EVM-side\x20balances\x20for\x20anomalous\x20outflows.\x20Have\x20an\x20'+'EmergencyOp\x20pause\x20plan\x20ready.','auto_fixable':![]},'check':a=>{if(!a['assumes_per_user_evm_account'])return null;return{...R_B_04['rule'],'evidence':'assumes_per_user_evm_account=true\x20(it\x20is\x20global)'};}},R_B_05={'rule':{'id':'R-BRIDGE-05','level':'MEDIUM','category':'cross_object','title':'Public\x20EVM\x20RPCs\x20may\x20rate-limit\x20(HTTP\x20429)\x20—\x20cross-chain\x20ops\x20stall','description':'Bridge\x20ops\x20that\x20query\x20EVM\x20state\x20(query_active_evm_account,\x20query_supported_evm_chains,\x20'+'query_transfer_status,\x20etc.)\x20depend\x20on\x20an\x20EVM\x20RPC.\x20Public\x20RPCs\x20(e.g.\x20Infura\x20free\x20tier,\x20'+'Alchemy\x20free\x20tier)\x20frequently\x20return\x20HTTP\x20429\x20under\x20load.\x20A\x20429\x20mid-flow\x20stalls\x20the\x20'+'cross-chain\x20operation\x20and\x20may\x20confuse\x20the\x20user.\x20manage_evm_rpc\x20supports\x20multi-RPC\x20'+'rotation,\x20but\x20it\x20must\x20be\x20configured\x20in\x20advance.','affected_stakeholders':['user','operator'],'scenario':'User\x20queries\x20transfer\x20status;\x20public\x20RPC\x20returns\x20429;\x20UI\x20shows\x20generic\x20error','mitigation':'Configure\x20multiple\x20EVM\x20RPCs\x20via\x20manage_evm_rpc\x20and\x20enable\x20failover.\x20Use\x20a\x20paid\x20RPC\x20'+'tier\x20for\x20production.\x20Surface\x20429\x20as\x20\x27RPC\x20busy,\x20retry\x27\x20rather\x20than\x20\x27operation\x20failed\x27.','auto_fixable':![]},'check':a=>{if(!a['uses_public_evm_rpc'])return null;return{...R_B_05['rule'],'evidence':'uses_public_evm_rpc=true\x20(429\x20risk)'};}},R_B_06={'rule':{'id':'R-BRIDGE-06','level':'MEDIUM','category':'lifecycle','title':'EmergencyOp\x20can\x20pause\x20the\x20Bridge\x20—\x20assets\x20lock\x20during\x20pause','description':'EmergencyOp\x20(bridge.move:89-91)\x20can\x20pause\x20the\x20entire\x20Bridge.\x20While\x20paused,\x20no\x20'+'cross-chain\x20operations\x20proceed\x20—\x20assets\x20in\x20flight\x20cannot\x20be\x20claimed,\x20new\x20transfers\x20'+'cannot\x20be\x20initiated.\x20The\x20pause\x20is\x20intended\x20for\x20incident\x20response,\x20but\x20a\x20prolonged\x20'+'pause\x20locks\x20user\x20funds\x20for\x20the\x20duration.','affected_stakeholders':['user','operator'],'scenario':'Bridge\x20is\x20paused\x20for\x20incident\x20response;\x20users\x20cannot\x20claim\x20in-flight\x20transfers','mitigation':'Document\x20the\x20pause\x20scenario\x20and\x20the\x20emergency\x20plan.\x20Provide\x20a\x20status\x20page\x20showing\x20'+'pause\x20state.\x20Set\x20expectations\x20on\x20pause\x20duration\x20and\x20recovery.\x20Operators\x20should\x20'+'practice\x20un-pause\x20drills.','auto_fixable':![]},'check':a=>{if(!a['is_paused'])return null;return{...R_B_06['rule'],'evidence':'is_paused=true\x20(assets\x20locked)'};}},R_B_07={'rule':{'id':'R-BRIDGE-07','level':'LOW','category':'structural','title':'Only\x20'+SUPPORTED_TOKENS['length']+'\x20tokens\x20supported\x20—\x20unsupported\x20tokens\x20cannot\x20bridge','description':'Bridge\x20supports\x20exactly\x20'+SUPPORTED_TOKENS['length']+'\x20tokens:\x20'+SUPPORTED_TOKENS['join'](',\x20')+'.\x20'+'Any\x20other\x20token\x20(e.g.\x20DAI,\x20LINK,\x20custom\x20tokens)\x20cannot\x20be\x20bridged.\x20Users\x20holding\x20'+'unsupported\x20tokens\x20will\x20see\x20their\x20transfer\x20rejected\x20with\x20EUnexpectedTokenType\x20(3).','affected_stakeholders':['user'],'scenario':'User\x20attempts\x20to\x20bridge\x20DAI;\x20aborts\x20with\x20EUnexpectedTokenType','mitigation':'Document\x20the\x20supported\x20token\x20list\x20prominently.\x20UI\x20should\x20filter\x20the\x20token\x20picker\x20to\x20'+'supported\x20tokens\x20only.\x20For\x20unsupported\x20tokens,\x20recommend\x20an\x20alternative\x20bridge.','related_move_error':'EUnexpectedTokenType\x20(3)','auto_fixable':![]},'check':a=>{if(!a['unsupported_token'])return null;return{...R_B_07['rule'],'evidence':'unsupported_token='+a['unsupported_token']+'\x20(supported:\x20'+SUPPORTED_TOKENS['join'](',')+')'};}},R_B_08={'rule':{'id':'R-BRIDGE-08','level':'MEDIUM','category':'structural','title':'Idempotency\x20key\x20max\x20'+MAX_IDEMPOTENCY_KEY_LENGTH+'\x20chars\x20—\x20long\x20keys\x20truncate\x20or\x20reject','description':'BridgeIdempotencyKeySchema\x20accepts\x20strings\x20of\x20length\x201-'+MAX_IDEMPOTENCY_KEY_LENGTH+'.\x20'+'Callers\x20who\x20generate\x20idempotency\x20keys\x20from\x20long\x20sources\x20(e.g.\x20full\x20JSON\x20payloads,\x20'+'UUIDs\x20with\x20prefixes)\x20may\x20exceed\x20the\x20limit\x20and\x20see\x20the\x20operation\x20rejected.\x20The\x20limit\x20'+'exists\x20to\x20keep\x20on-chain\x20storage\x20bounded.','affected_stakeholders':['user'],'scenario':'Caller\x20uses\x20a\x20200-char\x20idempotency\x20key;\x20operation\x20rejected','mitigation':'Generate\x20idempotency\x20keys\x20from\x20a\x20hash\x20(e.g.\x20keccak256\x20of\x20the\x20payload,\x20hex-encoded\x20=\x20'+'66\x20chars)\x20or\x20a\x20UUID\x20(36\x20chars).\x20Validate\x20length\x20client-side\x20before\x20submission.','auto_fixable':!![]},'check':a=>{if(a['idempotency_key_length']===undefined)return null;if(a['idempotency_key_length']<=MAX_IDEMPOTENCY_KEY_LENGTH)return null;return{...R_B_08['rule'],'evidence':'idempotency_key_length='+a['idempotency_key_length']+',\x20limit='+MAX_IDEMPOTENCY_KEY_LENGTH};}},R_B_09={'rule':{'id':'R-BRIDGE-09','level':'LOW','category':'structural','title':BRIDGE_ERROR_CODE_COUNT+'\x20error\x20codes\x20—\x20debugging\x20requires\x20a\x20lookup\x20table','description':'Bridge\x20defines\x20'+BRIDGE_ERROR_CODE_COUNT+'\x20error\x20codes\x20(EUnexpectedMessageType=0\x20'+'through\x20ETokenValueIsZero=19).\x20Debugging\x20an\x20abort\x20requires\x20mapping\x20the\x20numeric\x20code\x20'+'back\x20to\x20its\x20name\x20and\x20meaning.\x20New\x20contributors\x20often\x20misread\x20codes\x20because\x20they\x20'+'are\x20not\x20enumerated\x20in\x20the\x20abort\x20message.','affected_stakeholders':['user','operator'],'scenario':'Bridge\x20aborts\x20with\x20code\x2015;\x20developer\x20does\x20not\x20know\x20what\x20ETokenAlreadyClaimedOrHitLimit\x20means','mitigation':'Publish\x20an\x20error-code\x20lookup\x20table\x20in\x20the\x20docs.\x20SDK\x20should\x20decode\x20abort\x20codes\x20into\x20'+'human-readable\x20strings.\x20MCP\x20layer\x20should\x20surface\x20the\x20decoded\x20name\x20in\x20error\x20messages.','auto_fixable':![]},'check':a=>{if(!a['expects_simple_error_codes'])return null;return{...R_B_09['rule'],'evidence':'expects_simple_error_codes=true\x20(there\x20are\x20'+BRIDGE_ERROR_CODE_COUNT+')'};}},R_B_10={'rule':{'id':'R-BRIDGE-10','level':'MEDIUM','category':'lifecycle','title':'Versioned\x20upgrade\x20(current='+BRIDGE_CURRENT_VERSION+')\x20can\x20brick\x20the\x20Bridge\x20if\x20botched','description':'Bridge\x20uses\x20Versioned\x20to\x20wrap\x20BridgeInner\x20(bridge.move:49),\x20supporting\x20schema\x20upgrades.\x20'+('The\x20current\x20version\x20is\x20BRIDGE_CURRENT_VERSION='+BRIDGE_CURRENT_VERSION+'.\x20An\x20upgrade\x20')+'that\x20mishandles\x20the\x20inner\x20version\x20migration\x20can\x20permanently\x20brick\x20the\x20Bridge\x20—\x20'+'funds\x20in\x20flight\x20would\x20be\x20locked,\x20and\x20recovery\x20requires\x20a\x20new\x20package\x20version.\x20The\x20'+('message_version\x20(current='+BRIDGE_MESSAGE_VERSION+')\x20and\x20EVM\x20address\x20length\x20')+('('+BRIDGE_EVM_ADDRESS_LENGTH+'\x20bytes)\x20are\x20also\x20versioned.'),'affected_stakeholders':['user','operator','system'],'scenario':'Upgrade\x20mishandles\x20BridgeInner\x20migration;\x20Bridge\x20becomes\x20unusable','mitigation':'Test\x20upgrades\x20on\x20a\x20fork\x20with\x20full\x20state\x20replay.\x20Keep\x20a\x20rollback\x20package\x20version\x20'+'ready.\x20Stage\x20upgrades\x20with\x20a\x20pause\x20window\x20so\x20users\x20can\x20complete\x20in-flight\x20ops.\x20'+'Audit\x20message_version\x20and\x20EVM\x20address\x20length\x20compatibility\x20on\x20every\x20upgrade.','related_move_error':'EWrongInnerVersion\x20(7)','auto_fixable':![]},'check':a=>{if(!a['versioned_upgrade_in_progress'])return null;return{...R_B_10['rule'],'evidence':'versioned_upgrade_in_progress=true\x20(current='+BRIDGE_CURRENT_VERSION+')'};}};export const BRIDGE_RISK_RULES=[R_B_01,R_B_02,R_B_03,R_B_04,R_B_05,R_B_06,R_B_07,R_B_08,R_B_09,R_B_10];export const BRIDGE_RISK_VERSION='1.0.0';export function checkBridgeRisks(a){const b=[];for(const c of BRIDGE_RISK_RULES){const d=c['check'](a);if(d)b['push'](d);}return!b['find'](e=>e['id']==='R-BRIDGE-03')&&b['push'](R_B_03['rule']),b;}
|
|
@@ -29,4 +29,3 @@ export declare const CONTACT_RISK_RULES: {
|
|
|
29
29
|
}[];
|
|
30
30
|
export declare const CONTACT_RISK_VERSION = "1.0.0";
|
|
31
31
|
export declare function checkContactRisks(ctx: ContactRiskCheckContext): ContactRisk[];
|
|
32
|
-
export declare function getContactRiskById(id: string): ContactRisk | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{MAX_IM_COUNT}from'@wowok/wowok';const R_C_01={'rule':{'id':'R-CONTACT-01','level':'MEDIUM','category':'permission','title':'change_status\x20has\x20no\x20permission\x20check\x20—\x20IM\x20list\x20pollution\x20risk','description':'change_status\x20lets\x20any\x20IM\x20member\x20self-update\x20their\x20status\x20string\x20without\x20Permission\x20'+'verification\x20(contact.move:32-43).\x20If\x20an\x20attacker\x27s\x20address\x20is\x20added\x20to\x20the\x20ims\x20list\x20'+'(via\x20im_add,\x20which\x20requires\x20permission\x20index\x20453),\x20the\x20attacker\x20can\x20freely\x20pollute\x20'+'their\x20status\x20field\x20(e.g.\x20set\x20status\x20to\x20\x27fraud\x27).\x20The\x20risk\x20is\x20bounded\x20by\x20the\x20im_add\x20'+'permission\x20gate,\x20but\x20a\x20misconfigured\x20Permission\x20could\x20expose\x20the\x20IM\x20list.','affected_stakeholders':['creator','im_member'],'scenario':'Contact\x27s\x20IM\x20list\x20is\x20misconfigured\x20to\x20allow\x20public\x20adds;\x20attacker\x20pollutes\x20status','mitigation':'Restrict\x20permission\x20index\x20453\x20(CONTACT_IM)\x20to\x20trusted\x20guardians.\x20Audit\x20the\x20IM\x20list\x20'+'periodically.\x20Business\x20layer\x20may\x20validate\x20status\x20strings\x20against\x20an\x20allowlist.','auto_fixable':![]},'check':a=>{if(!a['change_status_no_permission'])return null;return{...R_C_01['rule'],'evidence':'change_status_no_permission=true'};}},R_C_02={'rule':{'id':'R-CONTACT-02','level':'LOW','category':'structural','title':'MAX_IM_COUNT='+MAX_IM_COUNT+'\x20is\x20permissive\x20—\x20on-chain\x20storage\x20cost','description':'A\x20single\x20Contact\x20may\x20hold\x20up\x20to\x20MAX_IM_COUNT='+MAX_IM_COUNT+'\x20IM\x20entries\x20(contact.move:14).\x20'+'Aborting\x20with\x20E_IM_COUNT_EXCEEDED\x20(1)\x20only\x20triggers\x20at\x20the\x20boundary.\x20200\x20entries\x20is\x20'+'relatively\x20permissive\x20for\x20a\x20social\x20scenario;\x20loading\x20the\x20full\x20list\x20on\x20every\x20read\x20'+'increases\x20gas\x20and\x20storage\x20cost.','affected_stakeholders':['creator'],'scenario':'Caller\x20adds\x20200\x20IM\x20entries\x20to\x20a\x20single\x20Contact','mitigation':'Business\x20layer\x20should\x20self-limit\x20IM\x20count\x20well\x20below\x20200.\x20For\x20high-volume\x20contact\x20'+'lists,\x20shard\x20across\x20multiple\x20Contact\x20objects\x20and\x20aggregate\x20off-chain.','related_move_error':'E_IM_COUNT_EXCEEDED\x20(1)','auto_fixable':![]},'check':a=>{if(a['im_count']===undefined)return null;if(a['im_count']<MAX_IM_COUNT)return null;return{...R_C_02['rule'],'evidence':'im_count='+a['im_count']+',\x20limit='+MAX_IM_COUNT};}},R_C_03={'rule':{'id':'R-CONTACT-03','level':'MEDIUM','category':'semantic','title':'IM\x20list\x20mutations\x20emit\x20no\x20events\x20—\x20external\x20indexers\x20must\x20poll','description':'im_add\x20/\x20im_remove\x20/\x20im_clear\x20do\x20not\x20emit\x20events\x20(contact.move:70-100).\x20External\x20'+'indexers\x20and\x20notification\x20systems\x20cannot\x20rely\x20on\x20event\x20streams\x20to\x20track\x20IM\x20list\x20'+'changes;\x20they\x20must\x20poll\x20the\x20ims\x20field\x20directly,\x20increasing\x20latency\x20and\x20RPC\x20cost.','affected_stakeholders':['creator','consumer'],'scenario':'Indexer\x20expects\x20an\x20event\x20on\x20im_add\x20but\x20none\x20is\x20emitted;\x20UI\x20fails\x20to\x20refresh','mitigation':'External\x20indexers\x20should\x20poll\x20the\x20Contact.ims\x20field\x20on\x20a\x20cadence.\x20A\x20future\x20version\x20'+'may\x20add\x20IMEvent;\x20until\x20then,\x20do\x20not\x20build\x20critical\x20UX\x20on\x20IM\x20event\x20streams.','auto_fixable':![]},'check':a=>null},R_C_04={'rule':{'id':'R-CONTACT-04','level':'LOW','category':'semantic','title':'location\x20defaults\x20to\x20empty\x20string\x20—\x20may\x20be\x20misread\x20as\x20\x27unset\x27','description':'A\x20freshly\x20created\x20Contact\x20has\x20location=\x22\x22\x20(empty\x20String).\x20The\x20Move\x20type\x20does\x20not\x20'+'distinguish\x20\x27unset\x27\x20from\x20\x27empty\x27,\x20so\x20consumers\x20may\x20misinterpret\x20an\x20empty\x20location\x20'+'as\x20\x27globally\x20applicable\x27\x20or\x20as\x20\x27missing\x20data\x27.','affected_stakeholders':['creator','consumer'],'scenario':'Consumer\x20reads\x20location=\x22\x22\x20and\x20treats\x20the\x20Contact\x20as\x20global\x20when\x20it\x20was\x20never\x20set','mitigation':'Document\x20that\x20empty\x20location\x20means\x20\x27not\x20specified\x27.\x20If\x20a\x20default\x20region\x20is\x20required,\x20'+'set\x20location\x20explicitly\x20at\x20creation\x20time.','auto_fixable':!![]},'check':a=>{if(!a['location_empty'])return null;return{...R_C_04['rule'],'evidence':'location=\x22\x22\x20(empty,\x20default)'};}},R_C_05={'rule':{'id':'R-CONTACT-05','level':'MEDIUM','category':'lifecycle','title':'my_status\x20silently\x20fails\x20for\x20non-IM-members','description':'my_status\x20only\x20updates\x20the\x20caller\x27s\x20status\x20entry\x20if\x20the\x20caller\x20is\x20in\x20the\x20ims\x20list\x20'+'(contact.move:35-42).\x20For\x20a\x20non-IM-member,\x20the\x20call\x20silently\x20succeeds\x20without\x20any\x20'+'state\x20change\x20—\x20there\x20is\x20no\x20abort\x20and\x20no\x20event.\x20Users\x20get\x20no\x20feedback,\x20making\x20it\x20'+'impossible\x20to\x20distinguish\x20\x27status\x20updated\x27\x20from\x20\x27operation\x20ignored\x27.','affected_stakeholders':['im_member'],'scenario':'Non-IM-member\x20calls\x20my_status\x20expecting\x20an\x20error;\x20operation\x20is\x20silently\x20ignored','mitigation':'SDK\x20layer\x20should\x20pre-validate\x20IM\x20membership\x20before\x20submitting\x20my_status\x20and\x20return\x20a\x20'+'clear\x20error.\x20UI\x20should\x20show\x20\x27not\x20an\x20IM\x20member\x27\x20instead\x20of\x20\x27success\x27.','auto_fixable':![]},'check':a=>{if(!a['my_status_from_non_member'])return null;return{...R_C_05['rule'],'evidence':'my_status_from_non_member=true\x20(will\x20be\x20silently\x20ignored)'};}},R_C_06={'rule':{'id':'R-CONTACT-06','level':'LOW','category':'semantic','title':'im_add\x20description\x20uses\x20LONG_NAME\x20(not\x20DESCRIPTION)\x20—\x20different\x20length\x20cap','description':'im_add\x27s\x20description\x20parameter\x20is\x20validated\x20with\x20common::LONG_NAME\x20rather\x20than\x20'+'common::DESCRIPTION\x20(contact.move:70-86).\x20The\x20two\x20validators\x20have\x20different\x20length\x20'+'limits;\x20callers\x20expecting\x20DESCRIPTION\x20semantics\x20may\x20submit\x20overly\x20long\x20strings\x20and\x20'+'hit\x20an\x20unexpected\x20abort.','affected_stakeholders':['creator'],'scenario':'Caller\x20submits\x20an\x20im_add\x20description\x20sized\x20for\x20DESCRIPTION\x20but\x20hits\x20LONG_NAME\x20limit','mitigation':'Document\x20that\x20im_add\x20description\x20uses\x20LONG_NAME\x20validation.\x20SDK\x20should\x20expose\x20the\x20'+'exact\x20limit\x20so\x20callers\x20size\x20their\x20strings\x20correctly.','auto_fixable':![]},'check':a=>{if(!a['im_add_description_uses_long_name'])return null;return{...R_C_06['rule'],'evidence':'im_add\x20description\x20validated\x20with\x20LONG_NAME'};}},R_C_07={'rule':{'id':'R-CONTACT-07','level':'MEDIUM','category':'cross_object','title':'permission_um_set\x20creates\x20Contact\x20↔\x20Permission\x20bidirectional\x20dependency','description':'When\x20Contact\x20is\x20set\x20as\x20a\x20Permission\x27s\x20um\x20via\x20permission_um_set\x20(contact.move:207-209),\x20'+'a\x20bidirectional\x20dependency\x20forms:\x20Permission.um\x20→\x20Contact,\x20and\x20Contact.permission\x20→\x20'+'Permission.\x20Deleting\x20the\x20Contact\x20without\x20first\x20clearing\x20the\x20um\x20reference\x20leaves\x20a\x20'+'dangling\x20pointer\x20in\x20Permission.um.','affected_stakeholders':['creator','consumer'],'scenario':'Contact\x20is\x20deleted\x20while\x20still\x20bound\x20as\x20Permission.um;\x20Permission.um\x20becomes\x20dangling','mitigation':'Document\x20the\x20deletion\x20order:\x20(1)\x20clear\x20Permission.um\x20via\x20permission_um_set(null)\x20'+'first,\x20(2)\x20then\x20delete\x20the\x20Contact.\x20SDK\x20should\x20refuse\x20to\x20delete\x20a\x20Contact\x20that\x20is\x20'+'still\x20bound\x20as\x20a\x20um.','auto_fixable':![]},'check':a=>{if(!a['bound_to_permission_um'])return null;return{...R_C_07['rule'],'evidence':'bound_to_permission_um=true\x20(deletion\x20requires\x20unbinding)'};}},R_C_08={'rule':{'id':'R-CONTACT-08','level':'LOW','category':'knowledge','title':'Knowledge\x20layer\x20&\x20constant\x20sync\x20—\x20RESOLVED','description':'MAX_IM_COUNT\x20is\x20now\x20synced\x20to\x20onchain-constants.ts\x20('+MAX_IM_COUNT+').\x20The\x20MCP\x20'+'Knowledge\x20layer\x20now\x20includes\x20contact-risk.ts.\x20This\x20risk\x20rule\x20is\x20retained\x20for\x20'+'historical\x20audit\x20and\x20to\x20detect\x20future\x20regressions.','affected_stakeholders':['system'],'scenario':'Future\x20regression:\x20someone\x20removes\x20MAX_IM_COUNT\x20from\x20onchain-constants.ts','mitigation':'Run\x20the\x20onchain-constants\x20sync\x20test\x20to\x20detect\x20drift.','auto_fixable':![]},'check':a=>{if(a['constants_synced'])return null;return{...R_C_08['rule'],'evidence':'constants_synced=false'};}};export const CONTACT_RISK_RULES=[R_C_01,R_C_02,R_C_03,R_C_04,R_C_05,R_C_06,R_C_07,R_C_08];export const CONTACT_RISK_VERSION='1.0.0';export function checkContactRisks(a){const b=[];for(const c of CONTACT_RISK_RULES){const d=c['check'](a);if(d)b['push'](d);}return!b['find'](e=>e['id']==='R-CONTACT-03')&&b['push'](R_C_03['rule']),b;}
|
|
1
|
+
import{MAX_IM_COUNT}from'@wowok/wowok';const R_C_01={'rule':{'id':'R-CONTACT-01','level':'MEDIUM','category':'permission','title':'change_status\x20has\x20no\x20permission\x20check\x20—\x20IM\x20list\x20pollution\x20risk','description':'change_status\x20lets\x20any\x20IM\x20member\x20self-update\x20their\x20status\x20string\x20without\x20Permission\x20'+'verification\x20(contact.move:32-43).\x20If\x20an\x20attacker\x27s\x20address\x20is\x20added\x20to\x20the\x20ims\x20list\x20'+'(via\x20im_add,\x20which\x20requires\x20permission\x20index\x20453),\x20the\x20attacker\x20can\x20freely\x20pollute\x20'+'their\x20status\x20field\x20(e.g.\x20set\x20status\x20to\x20\x27fraud\x27).\x20The\x20risk\x20is\x20bounded\x20by\x20the\x20im_add\x20'+'permission\x20gate,\x20but\x20a\x20misconfigured\x20Permission\x20could\x20expose\x20the\x20IM\x20list.','affected_stakeholders':['creator','im_member'],'scenario':'Contact\x27s\x20IM\x20list\x20is\x20misconfigured\x20to\x20allow\x20public\x20adds;\x20attacker\x20pollutes\x20status','mitigation':'Restrict\x20permission\x20index\x20453\x20(CONTACT_IM)\x20to\x20trusted\x20guardians.\x20Audit\x20the\x20IM\x20list\x20'+'periodically.\x20Business\x20layer\x20may\x20validate\x20status\x20strings\x20against\x20an\x20allowlist.','auto_fixable':![]},'check':a=>{if(!a['change_status_no_permission'])return null;return{...R_C_01['rule'],'evidence':'change_status_no_permission=true'};}},R_C_02={'rule':{'id':'R-CONTACT-02','level':'LOW','category':'structural','title':'MAX_IM_COUNT='+MAX_IM_COUNT+'\x20is\x20permissive\x20—\x20on-chain\x20storage\x20cost','description':'A\x20single\x20Contact\x20may\x20hold\x20up\x20to\x20MAX_IM_COUNT='+MAX_IM_COUNT+'\x20IM\x20entries\x20(contact.move:14).\x20'+'Aborting\x20with\x20E_IM_COUNT_EXCEEDED\x20(1)\x20only\x20triggers\x20at\x20the\x20boundary.\x20200\x20entries\x20is\x20'+'relatively\x20permissive\x20for\x20a\x20social\x20scenario;\x20loading\x20the\x20full\x20list\x20on\x20every\x20read\x20'+'increases\x20gas\x20and\x20storage\x20cost.','affected_stakeholders':['creator'],'scenario':'Caller\x20adds\x20200\x20IM\x20entries\x20to\x20a\x20single\x20Contact','mitigation':'Business\x20layer\x20should\x20self-limit\x20IM\x20count\x20well\x20below\x20200.\x20For\x20high-volume\x20contact\x20'+'lists,\x20shard\x20across\x20multiple\x20Contact\x20objects\x20and\x20aggregate\x20off-chain.','related_move_error':'E_IM_COUNT_EXCEEDED\x20(1)','auto_fixable':![]},'check':a=>{if(a['im_count']===undefined)return null;if(a['im_count']<MAX_IM_COUNT)return null;return{...R_C_02['rule'],'evidence':'im_count='+a['im_count']+',\x20limit='+MAX_IM_COUNT};}},R_C_03={'rule':{'id':'R-CONTACT-03','level':'MEDIUM','category':'semantic','title':'IM\x20list\x20mutations\x20emit\x20no\x20events\x20—\x20external\x20indexers\x20must\x20poll','description':'im_add\x20/\x20im_remove\x20/\x20im_clear\x20do\x20not\x20emit\x20events\x20(contact.move:70-100).\x20External\x20'+'indexers\x20and\x20notification\x20systems\x20cannot\x20rely\x20on\x20event\x20streams\x20to\x20track\x20IM\x20list\x20'+'changes;\x20they\x20must\x20poll\x20the\x20ims\x20field\x20directly,\x20increasing\x20latency\x20and\x20RPC\x20cost.','affected_stakeholders':['creator','consumer'],'scenario':'Indexer\x20expects\x20an\x20event\x20on\x20im_add\x20but\x20none\x20is\x20emitted;\x20UI\x20fails\x20to\x20refresh','mitigation':'External\x20indexers\x20should\x20poll\x20the\x20Contact.ims\x20field\x20on\x20a\x20cadence.\x20A\x20future\x20version\x20'+'may\x20add\x20IMEvent;\x20until\x20then,\x20do\x20not\x20build\x20critical\x20UX\x20on\x20IM\x20event\x20streams.','auto_fixable':![]},'check':a=>null},R_C_04={'rule':{'id':'R-CONTACT-04','level':'LOW','category':'semantic','title':'location\x20defaults\x20to\x20empty\x20string\x20—\x20may\x20be\x20misread\x20as\x20\x27unset\x27','description':'A\x20freshly\x20created\x20Contact\x20has\x20location=\x22\x22\x20(empty\x20String).\x20The\x20Move\x20type\x20does\x20not\x20'+'distinguish\x20\x27unset\x27\x20from\x20\x27empty\x27,\x20so\x20consumers\x20may\x20misinterpret\x20an\x20empty\x20location\x20'+'as\x20\x27globally\x20applicable\x27\x20or\x20as\x20\x27missing\x20data\x27.','affected_stakeholders':['creator','consumer'],'scenario':'Consumer\x20reads\x20location=\x22\x22\x20and\x20treats\x20the\x20Contact\x20as\x20global\x20when\x20it\x20was\x20never\x20set','mitigation':'Document\x20that\x20empty\x20location\x20means\x20\x27not\x20specified\x27.\x20If\x20a\x20default\x20region\x20is\x20required,\x20'+'set\x20location\x20explicitly\x20at\x20creation\x20time.','auto_fixable':!![]},'check':a=>{if(!a['location_empty'])return null;return{...R_C_04['rule'],'evidence':'location=\x22\x22\x20(empty,\x20default)'};}},R_C_05={'rule':{'id':'R-CONTACT-05','level':'MEDIUM','category':'lifecycle','title':'my_status\x20silently\x20fails\x20for\x20non-IM-members','description':'my_status\x20only\x20updates\x20the\x20caller\x27s\x20status\x20entry\x20if\x20the\x20caller\x20is\x20in\x20the\x20ims\x20list\x20'+'(contact.move:35-42).\x20For\x20a\x20non-IM-member,\x20the\x20call\x20silently\x20succeeds\x20without\x20any\x20'+'state\x20change\x20—\x20there\x20is\x20no\x20abort\x20and\x20no\x20event.\x20Users\x20get\x20no\x20feedback,\x20making\x20it\x20'+'impossible\x20to\x20distinguish\x20\x27status\x20updated\x27\x20from\x20\x27operation\x20ignored\x27.','affected_stakeholders':['im_member'],'scenario':'Non-IM-member\x20calls\x20my_status\x20expecting\x20an\x20error;\x20operation\x20is\x20silently\x20ignored','mitigation':'SDK\x20layer\x20should\x20pre-validate\x20IM\x20membership\x20before\x20submitting\x20my_status\x20and\x20return\x20a\x20'+'clear\x20error.\x20UI\x20should\x20show\x20\x27not\x20an\x20IM\x20member\x27\x20instead\x20of\x20\x27success\x27.','auto_fixable':![]},'check':a=>{if(!a['my_status_from_non_member'])return null;return{...R_C_05['rule'],'evidence':'my_status_from_non_member=true\x20(will\x20be\x20silently\x20ignored)'};}},R_C_06={'rule':{'id':'R-CONTACT-06','level':'LOW','category':'semantic','title':'im_add\x20description\x20uses\x20LONG_NAME\x20(not\x20DESCRIPTION)\x20—\x20different\x20length\x20cap','description':'im_add\x27s\x20description\x20parameter\x20is\x20validated\x20with\x20common::LONG_NAME\x20rather\x20than\x20'+'common::DESCRIPTION\x20(contact.move:70-86).\x20The\x20two\x20validators\x20have\x20different\x20length\x20'+'limits;\x20callers\x20expecting\x20DESCRIPTION\x20semantics\x20may\x20submit\x20overly\x20long\x20strings\x20and\x20'+'hit\x20an\x20unexpected\x20abort.','affected_stakeholders':['creator'],'scenario':'Caller\x20submits\x20an\x20im_add\x20description\x20sized\x20for\x20DESCRIPTION\x20but\x20hits\x20LONG_NAME\x20limit','mitigation':'Document\x20that\x20im_add\x20description\x20uses\x20LONG_NAME\x20validation.\x20SDK\x20should\x20expose\x20the\x20'+'exact\x20limit\x20so\x20callers\x20size\x20their\x20strings\x20correctly.','auto_fixable':![]},'check':a=>{if(!a['im_add_description_uses_long_name'])return null;return{...R_C_06['rule'],'evidence':'im_add\x20description\x20validated\x20with\x20LONG_NAME'};}},R_C_07={'rule':{'id':'R-CONTACT-07','level':'MEDIUM','category':'cross_object','title':'permission_um_set\x20creates\x20Contact\x20↔\x20Permission\x20bidirectional\x20dependency','description':'When\x20Contact\x20is\x20set\x20as\x20a\x20Permission\x27s\x20um\x20via\x20permission_um_set\x20(contact.move:207-209),\x20'+'a\x20bidirectional\x20dependency\x20forms:\x20Permission.um\x20→\x20Contact,\x20and\x20Contact.permission\x20→\x20'+'Permission.\x20Deleting\x20the\x20Contact\x20without\x20first\x20clearing\x20the\x20um\x20reference\x20leaves\x20a\x20'+'dangling\x20pointer\x20in\x20Permission.um.','affected_stakeholders':['creator','consumer'],'scenario':'Contact\x20is\x20deleted\x20while\x20still\x20bound\x20as\x20Permission.um;\x20Permission.um\x20becomes\x20dangling','mitigation':'Document\x20the\x20deletion\x20order:\x20(1)\x20clear\x20Permission.um\x20via\x20permission_um_set(null)\x20'+'first,\x20(2)\x20then\x20delete\x20the\x20Contact.\x20SDK\x20should\x20refuse\x20to\x20delete\x20a\x20Contact\x20that\x20is\x20'+'still\x20bound\x20as\x20a\x20um.','auto_fixable':![]},'check':a=>{if(!a['bound_to_permission_um'])return null;return{...R_C_07['rule'],'evidence':'bound_to_permission_um=true\x20(deletion\x20requires\x20unbinding)'};}},R_C_08={'rule':{'id':'R-CONTACT-08','level':'LOW','category':'knowledge','title':'Knowledge\x20layer\x20&\x20constant\x20sync\x20—\x20RESOLVED','description':'MAX_IM_COUNT\x20is\x20now\x20synced\x20to\x20onchain-constants.ts\x20('+MAX_IM_COUNT+').\x20The\x20MCP\x20'+'Knowledge\x20layer\x20now\x20includes\x20contact-risk.ts.\x20This\x20risk\x20rule\x20is\x20retained\x20for\x20'+'historical\x20audit\x20and\x20to\x20detect\x20future\x20regressions.','affected_stakeholders':['system'],'scenario':'Future\x20regression:\x20someone\x20removes\x20MAX_IM_COUNT\x20from\x20onchain-constants.ts','mitigation':'Run\x20the\x20onchain-constants\x20sync\x20test\x20to\x20detect\x20drift.','auto_fixable':![]},'check':a=>{if(a['constants_synced'])return null;return{...R_C_08['rule'],'evidence':'constants_synced=false'};}};export const CONTACT_RISK_RULES=[R_C_01,R_C_02,R_C_03,R_C_04,R_C_05,R_C_06,R_C_07,R_C_08];export const CONTACT_RISK_VERSION='1.0.0';export function checkContactRisks(a){const b=[];for(const c of CONTACT_RISK_RULES){const d=c['check'](a);if(d)b['push'](d);}return!b['find'](e=>e['id']==='R-CONTACT-03')&&b['push'](R_C_03['rule']),b;}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{EDGE_SCHEMAS}from'../graph/onchain/index.js';const LOCAL_FIELD_RULES=[{'object_type':'Service','field':'order_allocators','frozen_when':'after\x20publish','forbidden_actions':['set'],'allowed_actions':[],'unfreeze':null,'move_anchor':'service.move\x20order_allocators_set_imp\x20(assert!(!bPublished))'},{'object_type':'Service','field':'sales','frozen_when':null,'forbidden_actions':[],'allowed_actions':['add','remove','clear','update'],'unfreeze':null,'move_anchor':'service.move\x20sales_*_imp\x20/\x20price_*\x20/\x20stock_*\x20(mutable\x20after\x20publish)'},{'object_type':'Service','field':'description','frozen_when':null,'forbidden_actions':[],'allowed_actions':['set'],'unfreeze':null,'move_anchor':'service.move\x20description_set_imp'},{'object_type':'Service','field':'location','frozen_when':null,'forbidden_actions':[],'allowed_actions':['set'],'unfreeze':null,'move_anchor':'service.move\x20location_set_imp'},{'object_type':'Service','field':'bPaused','frozen_when':null,'forbidden_actions':[],'allowed_actions':['set'],'unfreeze':null,'move_anchor':'service.move\x20pause_imp'},{'object_type':'Machine','field':'bPaused','frozen_when':null,'forbidden_actions':[],'allowed_actions':['set'],'unfreeze':null,'move_anchor':'machine.move\x20pause_imp'},{'object_type':'Treasury','field':'external_deposit_guard','frozen_when':null,'forbidden_actions':[],'allowed_actions':['add','remove','clear'],'unfreeze':null,'move_anchor':'treasury.move\x20external_deposit_guard_add/remove/clear_imp\x20(no\x20freeze)'},{'object_type':'Treasury','field':'external_withdraw_guard','frozen_when':null,'forbidden_actions':[],'allowed_actions':['add','remove','clear'],'unfreeze':null,'move_anchor':'treasury.move\x20external_withdraw_guard_add/remove/clear_imp\x20(no\x20freeze)'},{'object_type':'Treasury','field':'history','frozen_when':'at\x20creation\x20(append-only)','forbidden_actions':['remove','clear','set'],'allowed_actions':['add'],'unfreeze':null,'move_anchor':'treasury.move\x20parent_table::add\x20(withdraw/deposit/receive\x20append\x20only;\x20no\x20delete\x20entry)'},{'object_type':'Allocation','field':'payment_info','frozen_when':'after\x20create\x20(share)','forbidden_actions':['set','remove'],'allowed_actions':[],'unfreeze':null,'move_anchor':'allocation.move\x20create\x20(payment_info\x20bound\x20at\x20creation;\x20no\x20mutation\x20entry)'}],EDGE_DERIVED_FIELD_RULES=EDGE_SCHEMAS['flatMap'](a=>{if(!a['contract'])return[];const b=a['contract'];return[{'object_type':a['source'],'field':b['field'],'frozen_when':b['frozenWhen'],'forbidden_actions':[...b['forbiddenActions']],'allowed_actions':[...b['allowedActions']],'unfreeze':b['unfreeze'],'move_anchor':b['moveAnchor']}];});export const FIELD_MUTABILITY_RULES=[...EDGE_DERIVED_FIELD_RULES,...LOCAL_FIELD_RULES];export const LOCK_CONSTRAINTS=[{'object_type':'Service','trigger':'after\x20publish\x20(bPublished=true)','locked':'remove\x20/\x20clear\x20of\x20rewards\x20/\x20arbitrations','release':'paused_time\x20present\x20and\x20paused_time\x20+\x20setting_lock_duration\x20<=\x20current\x20clock','move_anchor':'service.move\x20assert_not_published\x20(E_LOCKED_TIME_NOT_ENOUGH)'},{'object_type':'Reward','trigger':'guard_not_added_expiration_time\x20is\x20set\x20(Some)','locked':'add\x20of\x20guards','release':'clock\x20>\x20guard_not_added_expiration_time','move_anchor':'reward.move\x20guard_add_imp\x20(E_GUARD_LOCKED_TIME)'},{'object_type':'Reward','trigger':'guard.expiration_time\x20is\x20set\x20(Some)','locked':'claim','release':'clock\x20<=\x20guard.expiration_time\x20(cannot\x20claim\x20after\x20expiry)','move_anchor':'reward.move\x20claim\x20(E_GUARD_EXPIRED)'}];export const IRREVERSIBLE_OPERATIONS=[{'object_type':'Machine','operation':'publish','reason':'nodes/pairs/forwards\x20frozen\x20forever;\x20cannot\x20be\x20changed\x20again','move_anchor':'machine.move\x20publish_imp'},{'object_type':'Service','operation':'publish','reason':'machine\x20/\x20order_allocators\x20frozen\x20(rewards/arbitrations\x20need\x20pause+lock\x20before\x20remove)','move_anchor':'service.move\x20publish_imp'},{'object_type':'Permission','operation':'transfer','reason':'owner\x20change\x20is\x20irreversible;\x20the\x20old\x20owner\x20permanently\x20loses\x20control','move_anchor':'permission.move\x20transfer'},{'object_type':'Arb','operation':'arbitration\x20(award)','reason':'enters\x20Arbitrated\x20once\x20indemnity\x20is\x20set;\x20the\x20award\x20is\x20irreversible','move_anchor':'arb.move\x20arbitration'},{'object_type':'Arb','operation':'finish\x20/\x20withdraw','reason':'enters\x20terminal\x20state\x20Finished\x20/\x20Withdrawn;\x20state\x20no\x20longer\x20migrates','move_anchor':'arb.move\x20finish\x20/\x20withdraw'},{'object_type':'Payment','operation':'unwrap\x20/\x20transfer','reason':'fund\x20movement\x20is\x20irreversible','move_anchor':'payment.move\x20unwrap_with_check'},{'object_type':'Progress','operation':'task_set','reason':'task\x20is\x20set\x20once\x20and\x20cannot\x20be\x20reset\x20(permanently\x20bound\x20to\x20an\x20order/reward)','move_anchor':'progress.move\x20task_set_imp\x20(E_TASK_ALREADY_SET)'},{'object_type':'Allocation','operation':'create\x20(share)','reason':'allocators\x20/\x20payment_info\x20are\x20frozen\x20after\x20binding;\x20distribution\x20rules\x20cannot\x20change','move_anchor':'allocation.move\x20create'},{'object_type':'Reward','operation':'guard_expiration_time_add','reason':'guard_not_added_expiration_time\x20can\x20only\x20increase\x20(lock\x20cannot\x20be\x20shortened)','move_anchor':'reward.move\x20guard_expiration_time_add_imp\x20(E_GUARD_LOCKED_TIME_NOT_INCREASING)'}];export const STATE_MACHINE_TERMINALS=[{'object_type':'Arb','terminal_states':['Finished','Withdrawn'],'forbidden':'vote\x20/\x20arbitration\x20/\x20feedback\x20/\x20reset\x20(state\x20machine\x20no\x20longer\x20migrates)','move_anchor':'arb.move\x20status\x20state\x20machine\x20(7\x20states)'}];export const NUMERIC_LIMIT_CONSTRAINTS=[{'object_type':'Arb','field':'indemnity','limit':'<=\x20order.amount\x20*\x203\x20(MAX_INDEMNITY_MULTIPLE=3,\x20enforced\x20at\x20award\x20time,\x20not\x20claim\x20time)','move_anchor':'arb.move\x20arbitration\x20(E_INDEMNITY_EXCEEDS_LIMIT)'}];export const EXTERNAL_ACCESS_MECHANISMS=[{'object_type':'Treasury','field':'external_deposit_guard','actor':'any\x20external\x20party\x20that\x20passes\x20passport::result_for_guard\x20(no\x20Treasury\x20Permission\x20needed)','limit_source':'identifier\x20points\x20to\x20a\x20Guard\x20submission\x20amount\x20field\x20(u64);\x20deposit\x20amount\x20constrained\x20by\x20Guard\x20logic;\x20store_from_id\
|
|
1
|
+
import{EDGE_SCHEMAS}from'../graph/onchain/index.js';const LOCAL_FIELD_RULES=[{'object_type':'Service','field':'order_allocators','frozen_when':'after\x20publish','forbidden_actions':['set'],'allowed_actions':[],'unfreeze':null,'move_anchor':'service.move\x20order_allocators_set_imp\x20(assert!(!bPublished))'},{'object_type':'Service','field':'sales','frozen_when':null,'forbidden_actions':[],'allowed_actions':['add','remove','clear','update'],'unfreeze':null,'move_anchor':'service.move\x20sales_*_imp\x20/\x20price_*\x20/\x20stock_*\x20(mutable\x20after\x20publish)'},{'object_type':'Service','field':'description','frozen_when':null,'forbidden_actions':[],'allowed_actions':['set'],'unfreeze':null,'move_anchor':'service.move\x20description_set_imp'},{'object_type':'Service','field':'location','frozen_when':null,'forbidden_actions':[],'allowed_actions':['set'],'unfreeze':null,'move_anchor':'service.move\x20location_set_imp'},{'object_type':'Service','field':'bPaused','frozen_when':null,'forbidden_actions':[],'allowed_actions':['set'],'unfreeze':null,'move_anchor':'service.move\x20pause_imp'},{'object_type':'Machine','field':'bPaused','frozen_when':null,'forbidden_actions':[],'allowed_actions':['set'],'unfreeze':null,'move_anchor':'machine.move\x20pause_imp'},{'object_type':'Treasury','field':'external_deposit_guard','frozen_when':null,'forbidden_actions':[],'allowed_actions':['add','remove','clear'],'unfreeze':null,'move_anchor':'treasury.move\x20external_deposit_guard_add/remove/clear_imp\x20(no\x20freeze)'},{'object_type':'Treasury','field':'external_withdraw_guard','frozen_when':null,'forbidden_actions':[],'allowed_actions':['add','remove','clear'],'unfreeze':null,'move_anchor':'treasury.move\x20external_withdraw_guard_add/remove/clear_imp\x20(no\x20freeze)'},{'object_type':'Treasury','field':'history','frozen_when':'at\x20creation\x20(append-only)','forbidden_actions':['remove','clear','set'],'allowed_actions':['add'],'unfreeze':null,'move_anchor':'treasury.move\x20parent_table::add\x20(withdraw/deposit/receive\x20append\x20only;\x20no\x20delete\x20entry)'},{'object_type':'Allocation','field':'payment_info','frozen_when':'after\x20create\x20(share)','forbidden_actions':['set','remove'],'allowed_actions':[],'unfreeze':null,'move_anchor':'allocation.move\x20create\x20(payment_info\x20bound\x20at\x20creation;\x20no\x20mutation\x20entry)'}],EDGE_DERIVED_FIELD_RULES=EDGE_SCHEMAS['flatMap'](a=>{if(!a['contract'])return[];const b=a['contract'];return[{'object_type':a['source'],'field':b['field'],'frozen_when':b['frozenWhen'],'forbidden_actions':[...b['forbiddenActions']],'allowed_actions':[...b['allowedActions']],'unfreeze':b['unfreeze'],'move_anchor':b['moveAnchor']}];});export const FIELD_MUTABILITY_RULES=[...EDGE_DERIVED_FIELD_RULES,...LOCAL_FIELD_RULES];export const LOCK_CONSTRAINTS=[{'object_type':'Service','trigger':'after\x20publish\x20(bPublished=true)','locked':'remove\x20/\x20clear\x20of\x20rewards\x20/\x20arbitrations','release':'paused_time\x20present\x20and\x20paused_time\x20+\x20setting_lock_duration\x20<=\x20current\x20clock','move_anchor':'service.move\x20assert_not_published\x20(E_LOCKED_TIME_NOT_ENOUGH)'},{'object_type':'Reward','trigger':'guard_not_added_expiration_time\x20is\x20set\x20(Some)','locked':'add\x20of\x20guards','release':'clock\x20>\x20guard_not_added_expiration_time','move_anchor':'reward.move\x20guard_add_imp\x20(E_GUARD_LOCKED_TIME)'},{'object_type':'Reward','trigger':'guard.expiration_time\x20is\x20set\x20(Some)','locked':'claim','release':'clock\x20<=\x20guard.expiration_time\x20(cannot\x20claim\x20after\x20expiry)','move_anchor':'reward.move\x20claim\x20(E_GUARD_EXPIRED)'}];export const IRREVERSIBLE_OPERATIONS=[{'object_type':'Machine','operation':'publish','reason':'nodes/pairs/forwards\x20frozen\x20forever;\x20cannot\x20be\x20changed\x20again','move_anchor':'machine.move\x20publish_imp'},{'object_type':'Service','operation':'publish','reason':'machine\x20/\x20order_allocators\x20frozen\x20(rewards/arbitrations\x20need\x20pause+lock\x20before\x20remove)','move_anchor':'service.move\x20publish_imp'},{'object_type':'Permission','operation':'transfer','reason':'owner\x20change\x20is\x20irreversible;\x20the\x20old\x20owner\x20permanently\x20loses\x20control','move_anchor':'permission.move\x20transfer'},{'object_type':'Arb','operation':'arbitration\x20(award)','reason':'enters\x20Arbitrated\x20once\x20indemnity\x20is\x20set;\x20the\x20award\x20is\x20irreversible','move_anchor':'arb.move\x20arbitration'},{'object_type':'Arb','operation':'finish\x20/\x20withdraw','reason':'enters\x20terminal\x20state\x20Finished\x20/\x20Withdrawn;\x20state\x20no\x20longer\x20migrates','move_anchor':'arb.move\x20finish\x20/\x20withdraw'},{'object_type':'Payment','operation':'unwrap\x20/\x20transfer','reason':'fund\x20movement\x20is\x20irreversible','move_anchor':'payment.move\x20unwrap_with_check'},{'object_type':'Progress','operation':'task_set','reason':'task\x20is\x20set\x20once\x20and\x20cannot\x20be\x20reset\x20(permanently\x20bound\x20to\x20an\x20order/reward)','move_anchor':'progress.move\x20task_set_imp\x20(E_TASK_ALREADY_SET)'},{'object_type':'Allocation','operation':'create\x20(share)','reason':'allocators\x20/\x20payment_info\x20are\x20frozen\x20after\x20binding;\x20distribution\x20rules\x20cannot\x20change','move_anchor':'allocation.move\x20create'},{'object_type':'Reward','operation':'guard_expiration_time_add','reason':'guard_not_added_expiration_time\x20can\x20only\x20increase\x20(lock\x20cannot\x20be\x20shortened)','move_anchor':'reward.move\x20guard_expiration_time_add_imp\x20(E_GUARD_LOCKED_TIME_NOT_INCREASING)'}];export const STATE_MACHINE_TERMINALS=[{'object_type':'Arb','terminal_states':['Finished','Withdrawn'],'forbidden':'vote\x20/\x20arbitration\x20/\x20feedback\x20/\x20reset\x20(state\x20machine\x20no\x20longer\x20migrates)','move_anchor':'arb.move\x20status\x20state\x20machine\x20(7\x20states)'}];export const NUMERIC_LIMIT_CONSTRAINTS=[{'object_type':'Arb','field':'indemnity','limit':'<=\x20order.amount\x20*\x203\x20(MAX_INDEMNITY_MULTIPLE=3,\x20enforced\x20at\x20award\x20time,\x20not\x20claim\x20time)','move_anchor':'arb.move\x20arbitration\x20(E_INDEMNITY_EXCEEDS_LIMIT)'}];export const EXTERNAL_ACCESS_MECHANISMS=[{'object_type':'Treasury','field':'external_deposit_guard','actor':'any\x20external\x20party\x20that\x20passes\x20passport::result_for_guard\x20(no\x20Treasury\x20Permission\x20needed)','limit_source':'identifier\x20points\x20to\x20a\x20Guard\x20submission\x20amount\x20field\x20(u64);\x20the\x20deposit\x20amount\x20is\x20constrained\x20by\x20Guard\x20logic;\x20optional\x20store_from_id\x20resolves\x20an\x20address\x20from\x20another\x20submission\x20slot\x20for\x20record-keeping','flow_bound':'the\x20deposited\x20Coin\x20is\x20a\x20transaction\x20argument,\x20so\x20value\x20can\x20only\x20come\x20from\x20the\x20transaction\x20sender','move_anchor':'treasury.move\x20external_deposit\x20(no\x20permission::assert)'},{'object_type':'Treasury','field':'external_withdraw_guard','actor':'any\x20external\x20party\x20that\x20passes\x20passport::result_for_guard\x20(no\x20Treasury\x20Permission\x20needed)','limit_source':'identifier\x20points\x20to\x20a\x20Guard\x20submission\x20amount\x20field\x20(u64)\x20=\x20the\x20withdrawal\x20amount;\x20optional\x20store_from_id\x20resolves\x20an\x20address\x20from\x20another\x20submission\x20slot\x20for\x20record-keeping\x20(it\x20is\x20NOT\x20the\x20destination)','flow_bound':'recipient\x20is\x20a\x20bare\x20address\x20parameter\x20no\x20guard\x20predicate\x20can\x20constrain;\x20funds\x20release\x20only\x20to\x20the\x20transaction\x20sender\x20—\x20a\x20mismatch\x20aborts\x20with\x20EEXTERNAL_RECIPIENT_NOT_SIGNER\x20(treasury\x20code\x2010).\x20Pay\x20another\x20address\x20via\x20the\x20permissioned\x20withdraw\x20(index\x20254)','move_anchor':'treasury.move\x20external_withdraw\x20assert!(*recipient\x20==\x20tx_context::sender(ctx))'}];export function externalAccessOf(a,b){return EXTERNAL_ACCESS_MECHANISMS['find'](d=>d['object_type']===a&&d['field']===b);}export function numericLimitOf(a,b){return NUMERIC_LIMIT_CONSTRAINTS['find'](d=>d['object_type']===a&&d['field']===b);}export function fieldMutabilityOf(a,b){return FIELD_MUTABILITY_RULES['find'](c=>c['object_type']===a&&c['field']===b);}export function isActionForbidden(a,b,c,d){const e=fieldMutabilityOf(a,b);if(!e)return![];if(!d)return![];return e['forbidden_actions']['includes'](c);}export function lockConstraintOf(a){return LOCK_CONSTRAINTS['find'](b=>b['object_type']===a);}
|
|
@@ -27,4 +27,3 @@ export declare const DEMAND_RISK_RULES: {
|
|
|
27
27
|
check: (ctx: DemandRiskCheckContext) => DemandRisk | null;
|
|
28
28
|
}[];
|
|
29
29
|
export declare function checkDemandRisks(ctx: DemandRiskCheckContext): DemandRisk[];
|
|
30
|
-
export declare function getDemandRiskById(id: string): DemandRisk | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{MAX_REWARD_COUNT,MAX_GUARD_COUNT_DEMAND}from'@wowok/wowok';const MAX_FEEDBACK_COUNT=0x14,R_DEM_1_01={'rule':{'id':'R-DEM-01','level':'HIGH','category':'structural','title':'rewards\x20count\x20exceeds\x20MAX_REWARD_COUNT\x20('+MAX_REWARD_COUNT+')','description':'The\x20\x27rewards\x27\x20vector\x20is\x20bounded\x20by\x20MAX_REWARD_COUNT='+MAX_REWARD_COUNT+'\x20(Move\x20source:\x20demand.move:21).\x20'+'Exceeding\x20this\x20limit\x20aborts\x20with\x20E_MAX_REWARD_COUNT_EXCEEDED\x20(1).\x20Each\x20reward\x20is\x20bound\x20via\x20object_linker::affiliation_core,\x20'+'so\x20adding\x20a\x20reward\x20also\x20triggers\x20object_linker::affiliation_core.\x20Use\x20reward_remove/reward_clear\x20to\x20free\x20slots\x20before\x20'+'adding\x20new\x20ones\x20if\x20the\x20limit\x20is\x20reached.','affected_stakeholders':['creator'],'scenario':'Caller\x20calls\x20reward_add\x20when\x2020\x20rewards\x20are\x20already\x20affiliated','mitigation':'Track\x20the\x20current\x20reward\x20count.\x20Before\x20adding\x20a\x20new\x20reward,\x20call\x20reward_remove\x20or\x20reward_clear\x20to\x20'+'free\x20a\x20slot.\x20Consider\x20consolidating\x20rewards\x20into\x20a\x20single\x20Reward\x20object\x20with\x20multiple\x20tiers\x20if\x20the\x20'+'\x20Demand\x20needs\x20to\x20offer\x20more\x20than\x2020\x20distinct\x20reward\x20paths.','related_move_error':'E_MAX_REWARD_COUNT_EXCEEDED\x20(1)','auto_fixable':![]},'check':a=>{if(a['reward_count']===undefined)return null;if(a['reward_count']<=MAX_REWARD_COUNT)return null;return{...R_DEM_1_01['rule'],'evidence':'reward_count='+a['reward_count']+',\x20limit='+MAX_REWARD_COUNT};}},R_DEM_1_02={'rule':{'id':'R-DEM-02','level':'HIGH','category':'structural','title':'guards\x20count\x20exceeds\x20MAX_GUARD_COUNT_DEMAND\x20('+MAX_GUARD_COUNT_DEMAND+')','description':'The\x20\x27guards\x27\x20vector\x20is\x20bounded\x20by\x20MAX_GUARD_COUNT_DEMAND='+MAX_GUARD_COUNT_DEMAND+'\x20(Move\x20source:\x20demand.move:22).\x20'+'Exceeding\x20this\x20limit\x20aborts\x20with\x20E_MAX_GUARD_COUNT_EXCEEDED\x20(2).\x20Each\x20guard\x20carries\x20an\x20optional\x20'+'service_identifier\x20(u8)\x20that\x20routes\x20present_with_passport\x20submissions\x20to\x20a\x20specific\x20Service\x20submission\x20'+'extracted\x20from\x20the\x20Passport.\x20Adding\x20a\x20duplicate\x20guard\x20updates\x20the\x20service_identifier\x20instead\x20of\x20pushing.','affected_stakeholders':['creator','presenter'],'scenario':'Caller\x20calls\x20guard_add\x20when\x2020\x20guards\x20are\x20already\x20affiliated\x20and\x20the\x20address\x20is\x20new','mitigation':'Track\x20the\x20current\x20guard\x20count.\x20Before\x20adding\x20a\x20new\x20guard,\x20call\x20guard_remove\x20or\x20guard_clear.\x20'+'If\x20updating\x20an\x20existing\x20guard\x27s\x20service_identifier,\x20call\x20guard_add\x20with\x20the\x20same\x20address\x20(it\x20updates\x20'+'in\x20place\x20rather\x20than\x20pushing).','related_move_error':'E_MAX_GUARD_COUNT_EXCEEDED\x20(2)','auto_fixable':![]},'check':a=>{if(a['guard_count']===undefined)return null;if(a['guard_count']<=MAX_GUARD_COUNT_DEMAND)return null;return{...R_DEM_1_02['rule'],'evidence':'guard_count='+a['guard_count']+',\x20limit='+MAX_GUARD_COUNT_DEMAND};}},R_DEM_1_03={'rule':{'id':'R-DEM-03','level':'MEDIUM','category':'structural','title':'feedback\x20batch\x20exceeds\x20MAX_FEEDBACK_COUNT\x20('+MAX_FEEDBACK_COUNT+')','description':'The\x20\x27feedback\x27\x20Move\x20function\x20(demand.move:352)\x20updates\x20ONE\x20presenter\x20per\x20call\x20(feedback_imp\x20iterates\x20'+('no\x20vector).\x20The\x20SDK\x20batches\x20multiple\x20feedback\x20calls\x20and\x20caps\x20the\x20batch\x20at\x20MAX_FEEDBACK_COUNT='+MAX_FEEDBACK_COUNT+'\x20')+'(SDK-only\x20limit,\x20NOT\x20in\x20onchain-constants.ts\x20—\x20Move\x20has\x20no\x20aggregate\x20feedback-count\x20check).\x20Exceeding\x20the\x20'+'SDK\x20batch\x20limit\x20causes\x20the\x20SDK\x20to\x20refuse\x20the\x20call\x20before\x20transaction\x20building.\x20Each\x20feedback\x20entry\x20writes\x20'+'a\x20String\x20(bounded\x20by\x20common::DESCRIPTION,\x204000\x20chars)\x20and\x20an\x20optional\x20u8\x20acceptance_score\x20to\x20a\x20presenter\x27s\x20'+'ServiceInfo\x20record.','affected_stakeholders':['creator'],'scenario':'Caller\x20attempts\x20to\x20submit\x2021\x20feedback\x20entries\x20in\x20a\x20single\x20SDK\x20call','mitigation':'Split\x20the\x20feedback\x20batch\x20into\x20chunks\x20of\x20≤\x2020\x20entries.\x20If\x20the\x20Demand\x20has\x20more\x20than\x2020\x20presenters\x20to\x20'+'give\x20feedback\x20on,\x20submit\x20multiple\x20transactions.\x20Consider\x20whether\x20bulk\x20feedback\x20is\x20appropriate\x20—\x20'+'individualized\x20feedback\x20per\x20presenter\x20is\x20often\x20more\x20meaningful.','auto_fixable':![]},'check':a=>{if(a['feedback_count']===undefined)return null;if(a['feedback_count']<=MAX_FEEDBACK_COUNT)return null;return{...R_DEM_1_03['rule'],'evidence':'feedback_count='+a['feedback_count']+',\x20limit='+MAX_FEEDBACK_COUNT};}},R_DEM_2_01={'rule':{'id':'R-DEM-04','level':'HIGH','category':'semantic','title':'present\x20called\x20without\x20passport\x20when\x20guards\x20vector\x20is\x20non-empty','description':'The\x20Move\x20present\x20function\x20(demand.move:100)\x20asserts\x20`vector::is_empty(&self.guards)`\x20and\x20aborts\x20with\x20'+'E_NEED_PASSPORT\x20(3)\x20if\x20the\x20guards\x20vector\x20is\x20non-empty.\x20When\x20guards\x20exist,\x20every\x20presenter\x20MUST\x20go\x20through\x20'+'present_with_passport\x20(or\x20present_service_with_passport),\x20which\x20routes\x20through\x20present_with_passport_imp.\x20'+'That\x20function\x20looks\x20up\x20the\x20specified\x20Guard\x20in\x20the\x20guards\x20vector,\x20calls\x20passport::result_for_guard\x20to\x20'+'verify\x20the\x20Passport,\x20and\x20(if\x20service_identifier\x20is\x20set)\x20extracts\x20the\x20submission\x20address\x20from\x20the\x20Passport.\x20'+'Calling\x20plain\x20`present`\x20on\x20a\x20guarded\x20Demand\x20always\x20aborts\x20—\x20there\x20is\x20no\x20fallback\x20path.','affected_stakeholders':['presenter','creator'],'scenario':'Demand\x20has\x202\x20guards;\x20a\x20presenter\x20calls\x20present()\x20instead\x20of\x20present_with_passport()','mitigation':'Before\x20presenting,\x20query\x20the\x20Demand\x27s\x20guards\x20vector.\x20If\x20non-empty,\x20use\x20present_with_passport\x20and\x20'+'supply\x20a\x20Guard\x20+\x20Passport.\x20The\x20Guard\x20address\x20must\x20already\x20be\x20in\x20the\x20guards\x20vector\x20(otherwise\x20'+'E_GUARD_NOT_FOUND\x20(4)\x20aborts).\x20If\x20service_identifier\x20is\x20set\x20on\x20the\x20matching\x20guard,\x20the\x20submission\x20'+'address\x20is\x20extracted\x20from\x20the\x20Passport\x20—\x20do\x20not\x20pass\x20a\x20separate\x20service\x20parameter.','related_move_error':'E_NEED_PASSPORT\x20(3)','auto_fixable':![]},'check':a=>{if(!a['using_present_without_passport'])return null;if(!a['guards_non_empty'])return null;return{...R_DEM_2_01['rule'],'evidence':'guards_non_empty=true,\x20using\x20present\x20(no\x20passport)'};}},R_DEM_3_01={'rule':{'id':'R-DEM-05','level':'INFO','category':'lifecycle','title':'um_set_imp\x20object-linker\x20dependency\x20leak\x20—\x20RESOLVED\x20(P-DEM-P1-1)','description':'PREVIOUS\x20RISK:\x20um_set_imp\x20(demand.move:139-147)\x20previously\x20set\x20self.um\x20to\x20the\x20new\x20Contact\x20address\x20'+'BEFORE\x20disaffiliating\x20the\x20old\x20um,\x20causing\x20the\x20old\x20Contact\x20to\x20retain\x20a\x20stale\x20object-linker\x20binding\x20record\x20in\x20the\x20'+'object_linker.\x20affiliation_change_core\x20was\x20not\x20called\x20for\x20the\x20old\x20um,\x20leading\x20to\x20an\x20object-linker\x20dependency\x20leak.\x0a\x0a'+'FIX\x20(P-DEM-P1-1):\x20um_set_imp\x20now\x20disaffiliates\x20the\x20old\x20um\x20via\x20object_linker::disaffiliation_core\x20BEFORE\x20setting\x20'+'the\x20new\x20one.\x20The\x20new\x20um\x20is\x20then\x20affiliated\x20via\x20object_linker::affiliation_core.\x20This\x20matches\x20the\x20pattern\x20used\x20'+'by\x20permission_set\x20(which\x20uses\x20affiliation_change_core).\x20um_none_imp\x20also\x20disaffiliates\x20before\x20clearing.\x0a\x0a'+'This\x20rule\x20is\x20retained\x20for\x20historical\x20audit\x20and\x20to\x20detect\x20regressions.','affected_stakeholders':['creator','system'],'scenario':'Future\x20regression:\x20someone\x20reorders\x20um_set_imp\x20to\x20set\x20new\x20before\x20disaffiliating\x20old','mitigation':'Keep\x20the\x20disaffiliate-then-set\x20ordering.\x20The\x20Move\x20invariant:\x20any\x20path\x20that\x20mutates\x20self.um\x20MUST\x20call\x20'+'object_linker::disaffiliation_core\x20on\x20the\x20old\x20value\x20before\x20assigning\x20a\x20new\x20one.','auto_fixable':![]},'check':a=>{if(a['constants_synced'])return null;return{...R_DEM_3_01['rule'],'evidence':'constants_synced=false\x20(regression\x20check)'};}},R_DEM_2_02={'rule':{'id':'R-DEM-06','level':'INFO','category':'semantic','title':'guard_add_imp\x20service_identifier\x20type\x20check\x20skipped\x20on\x20early\x20return\x20—\x20RESOLVED\x20(P-DEM-P1-2)','description':'PREVIOUS\x20RISK:\x20guard_add_imp\x20(demand.move:213-242)\x20previously\x20had\x20the\x20service_identifier\x20type\x20check\x20'+'AFTER\x20the\x20early-return\x20path\x20that\x20updates\x20an\x20existing\x20guard\x27s\x20service_identifier.\x20When\x20a\x20guard\x20with\x20'+'the\x20same\x20address\x20already\x20existed,\x20the\x20function\x20returned\x20before\x20validating\x20the\x20new\x20service_identifier\x20'+'against\x20guard::get_submission_object_type.\x20This\x20allowed\x20setting\x20an\x20invalid\x20service_identifier\x20that\x20'+'would\x20later\x20fail\x20at\x20present_with_passport\x20time\x20with\x20E_INVALID_SERVICE_OBJECT_TYPE\x20(common.move:13).\x0a\x0a'+'FIX\x20(P-DEM-P1-2):\x20The\x20service_identifier\x20type\x20check\x20now\x20runs\x20FIRST\x20(demand.move:218-222),\x20BEFORE\x20the\x20'+'duplicate-detection\x20loop.\x20common::assert_service_object_type\x20is\x20called\x20for\x20any\x20non-None\x20service_identifier,\x20'+'ensuring\x20both\x20the\x20insert\x20and\x20update\x20paths\x20validate\x20the\x20type.\x0a\x0a'+'This\x20rule\x20is\x20retained\x20for\x20historical\x20audit\x20and\x20to\x20detect\x20regressions.','affected_stakeholders':['creator','presenter'],'scenario':'Future\x20regression:\x20someone\x20moves\x20the\x20type\x20check\x20back\x20to\x20after\x20the\x20duplicate-detection\x20loop','mitigation':'Keep\x20the\x20type\x20check\x20at\x20the\x20top\x20of\x20guard_add_imp.\x20The\x20Move\x20invariant:\x20any\x20service_identifier\x20provided\x20'+'to\x20guard_add\x20MUST\x20be\x20validated\x20via\x20guard::get_submission_object_type\x20+\x20common::assert_service_object_type\x20'+'BEFORE\x20any\x20mutation\x20of\x20the\x20guards\x20vector.','auto_fixable':![]},'check':a=>{if(a['constants_synced'])return null;return{...R_DEM_2_02['rule'],'evidence':'constants_synced=false\x20(regression\x20check)'};}},R_DEM_4_01={'rule':{'id':'R-DEM-07','level':'INFO','category':'knowledge','title':'Demand\x20matching\x20must\x20not\x20read\x20non-existent\x20Move\x20fields\x20—\x20RESOLVED\x20(P-DEM-P1-3)','description':'PREVIOUS\x20RISK:\x20the\x20retired\x20demand-matching.ts\x20engine\x20(matchDemand/extractDemandInfo)\x20read\x20fields\x20(tags,\x20'+'maxPrice,\x20scenario,\x20minTrustScore,\x20keywords)\x20that\x20do\x20NOT\x20exist\x20on\x20the\x20Move\x20Demand\x20struct.\x20The\x20Move\x20struct\x20'+'only\x20has:\x20description,\x20location,\x20rewards,\x20guards,\x20presenters,\x20um,\x20permission.\x20This\x20caused\x20the\x20matching\x20'+'engine\x20to\x20silently\x20produce\x20undefined\x20values\x20when\x20fed\x20raw\x20on-chain\x20query\x20results.\x0a\x0a'+'FIX\x20(P-DEM-P1-3):\x20the\x20capability-vector\x20engine\x20(evaluation/builtins/demand-match.ts)\x20enriches\x20via\x20'+'evaluation/extract.ts\x20(extractDemandCapability/extractServiceCapability).\x20Only\x20`location`\x20maps\x20directly\x20'+'to\x20the\x20Move\x20Demand\x20struct;\x20all\x20other\x20signals\x20(industry/tags/keywords/region/trust/price\x20budget)\x20are\x20'+'enriched\x20from\x20description\x20NLP,\x20the\x20industry\x20generalizer,\x20or\x20caller-injected\x20overrides/data\x20sources.\x0a\x0a'+'This\x20rule\x20is\x20retained\x20for\x20historical\x20audit\x20and\x20to\x20detect\x20regressions.','affected_stakeholders':['system'],'scenario':'Future\x20regression:\x20someone\x20removes\x20the\x20enrichment\x20contract\x20docs\x20from\x20evaluation/extract.ts','mitigation':'Keep\x20the\x20enrichment\x20contract\x20in\x20evaluation/extract.ts\x20(non-chain-derivable\x20fields\x20are\x20enriched\x20there,\x20'+'not\x20read\x20as\x20on-chain\x20fact).\x20The\x20matching\x20engine\x20must\x20never\x20query\x20on-chain\x20data\x20directly\x20—\x20it\x20scores\x20'+'over\x20already-enriched\x20capability\x20vectors.','auto_fixable':![]},'check':a=>{if(a['constants_synced'])return null;return{...R_DEM_4_01['rule'],'evidence':'constants_synced=false\x20(regression\x20check)'};}},R_DEM_4_02={'rule':{'id':'R-DEM-08','level':'INFO','category':'knowledge','title':'permission_set\x20not\x20exposed\x20in\x20SDK\x20—\x20RESOLVED\x20(DE-D-2=A)','description':'PREVIOUS\x20GAP:\x20The\x20Move\x20permission_set\x20function\x20(demand.move:286)\x20was\x20not\x20exposed\x20as\x20a\x20standalone\x20'+'function\x20in\x20the\x20SDK\x27s\x20call/demand.ts.\x20Callers\x20could\x20not\x20change\x20the\x20Permission\x20object\x20bound\x20to\x20a\x20Demand\x20'+'after\x20creation.\x0a\x0a'+'RESOLUTION\x20(DE-D-2=A):\x20permission_set\x20is\x20now\x20exposed\x20via\x20the\x20CallPermission.apply\x20mechanism.\x20The\x20SDK\x20'+'wraps\x20permission_set\x20by\x20routing\x20it\x20through\x20CallPermission,\x20which\x20performs\x20the\x20assert_owner\x20check\x20on\x20the\x20'+'old\x20Permission\x20and\x20updates\x20the\x20Demand\x27s\x20bound\x20permission.\x20object_linker\x27s\x20affiliation_change_core\x20is\x20called\x20'+'to\x20migrate\x20the\x20binding\x20from\x20the\x20old\x20Permission\x20to\x20the\x20new\x20one.\x0a\x0a'+'Permission\x20indices\x20for\x20Demand\x20(demand.move:20):\x20400=DEMAND_NEW,\x20401=DEMAND_DESCRIPTION,\x20402=DEMAND_LOCATION,\x20'+'404=DEMAND_GUARD,\x20405=DEMAND_REWARD,\x20406=DEMAND_FEEDBACK,\x20407=DEMAND_OWNER_RECEIVE,\x20408=DEMAND_UM.\x0a\x0a'+'This\x20rule\x20is\x20retained\x20for\x20historical\x20audit\x20and\x20to\x20detect\x20regressions.','affected_stakeholders':['creator','system'],'scenario':'Future\x20regression:\x20someone\x20removes\x20the\x20CallPermission.apply\x20path\x20for\x20permission_set','mitigation':'Keep\x20permission_set\x20exposed\x20via\x20CallPermission.apply.\x20The\x20Move\x20invariant:\x20permission_set\x20requires\x20'+'permission::assert_owner(old)\x20and\x20MUST\x20call\x20object_linker::affiliation_change_core\x20to\x20migrate\x20the\x20binding.','auto_fixable':![]},'check':a=>{if(a['constants_synced'])return null;return{...R_DEM_4_02['rule'],'evidence':'constants_synced=false\x20(regression\x20check)'};}};export const DEMAND_RISK_RULES=[R_DEM_1_01,R_DEM_1_02,R_DEM_1_03,R_DEM_2_01,R_DEM_3_01,R_DEM_2_02,R_DEM_4_01,R_DEM_4_02];export function checkDemandRisks(a){const b=[];for(const c of DEMAND_RISK_RULES){const d=c['check'](a);if(d)b['push'](d);}return b;}export function getDemandRiskById(a){return DEMAND_RISK_RULES['find'](b=>b['rule']['id']===a)?.['rule'];}
|
|
1
|
+
import{MAX_REWARD_COUNT,MAX_GUARD_COUNT_DEMAND}from'@wowok/wowok';const MAX_FEEDBACK_COUNT=0x14,R_DEM_1_01={'rule':{'id':'R-DEM-01','level':'HIGH','category':'structural','title':'rewards\x20count\x20exceeds\x20MAX_REWARD_COUNT\x20('+MAX_REWARD_COUNT+')','description':'The\x20\x27rewards\x27\x20vector\x20is\x20bounded\x20by\x20MAX_REWARD_COUNT='+MAX_REWARD_COUNT+'\x20(Move\x20source:\x20demand.move:21).\x20'+'Exceeding\x20this\x20limit\x20aborts\x20with\x20E_MAX_REWARD_COUNT_EXCEEDED\x20(1).\x20Each\x20reward\x20is\x20bound\x20via\x20object_linker::affiliation_core,\x20'+'so\x20adding\x20a\x20reward\x20also\x20triggers\x20object_linker::affiliation_core.\x20Use\x20reward_remove/reward_clear\x20to\x20free\x20slots\x20before\x20'+'adding\x20new\x20ones\x20if\x20the\x20limit\x20is\x20reached.','affected_stakeholders':['creator'],'scenario':'Caller\x20calls\x20reward_add\x20when\x2020\x20rewards\x20are\x20already\x20affiliated','mitigation':'Track\x20the\x20current\x20reward\x20count.\x20Before\x20adding\x20a\x20new\x20reward,\x20call\x20reward_remove\x20or\x20reward_clear\x20to\x20'+'free\x20a\x20slot.\x20Consider\x20consolidating\x20rewards\x20into\x20a\x20single\x20Reward\x20object\x20with\x20multiple\x20tiers\x20if\x20the\x20'+'\x20Demand\x20needs\x20to\x20offer\x20more\x20than\x2020\x20distinct\x20reward\x20paths.','related_move_error':'E_MAX_REWARD_COUNT_EXCEEDED\x20(1)','auto_fixable':![]},'check':a=>{if(a['reward_count']===undefined)return null;if(a['reward_count']<=MAX_REWARD_COUNT)return null;return{...R_DEM_1_01['rule'],'evidence':'reward_count='+a['reward_count']+',\x20limit='+MAX_REWARD_COUNT};}},R_DEM_1_02={'rule':{'id':'R-DEM-02','level':'HIGH','category':'structural','title':'guards\x20count\x20exceeds\x20MAX_GUARD_COUNT_DEMAND\x20('+MAX_GUARD_COUNT_DEMAND+')','description':'The\x20\x27guards\x27\x20vector\x20is\x20bounded\x20by\x20MAX_GUARD_COUNT_DEMAND='+MAX_GUARD_COUNT_DEMAND+'\x20(Move\x20source:\x20demand.move:22).\x20'+'Exceeding\x20this\x20limit\x20aborts\x20with\x20E_MAX_GUARD_COUNT_EXCEEDED\x20(2).\x20Each\x20guard\x20carries\x20an\x20optional\x20'+'service_identifier\x20(u8)\x20that\x20routes\x20present_with_passport\x20submissions\x20to\x20a\x20specific\x20Service\x20submission\x20'+'extracted\x20from\x20the\x20Passport.\x20Adding\x20a\x20duplicate\x20guard\x20updates\x20the\x20service_identifier\x20instead\x20of\x20pushing.','affected_stakeholders':['creator','presenter'],'scenario':'Caller\x20calls\x20guard_add\x20when\x2020\x20guards\x20are\x20already\x20affiliated\x20and\x20the\x20address\x20is\x20new','mitigation':'Track\x20the\x20current\x20guard\x20count.\x20Before\x20adding\x20a\x20new\x20guard,\x20call\x20guard_remove\x20or\x20guard_clear.\x20'+'If\x20updating\x20an\x20existing\x20guard\x27s\x20service_identifier,\x20call\x20guard_add\x20with\x20the\x20same\x20address\x20(it\x20updates\x20'+'in\x20place\x20rather\x20than\x20pushing).','related_move_error':'E_MAX_GUARD_COUNT_EXCEEDED\x20(2)','auto_fixable':![]},'check':a=>{if(a['guard_count']===undefined)return null;if(a['guard_count']<=MAX_GUARD_COUNT_DEMAND)return null;return{...R_DEM_1_02['rule'],'evidence':'guard_count='+a['guard_count']+',\x20limit='+MAX_GUARD_COUNT_DEMAND};}},R_DEM_1_03={'rule':{'id':'R-DEM-03','level':'MEDIUM','category':'structural','title':'feedback\x20batch\x20exceeds\x20MAX_FEEDBACK_COUNT\x20('+MAX_FEEDBACK_COUNT+')','description':'The\x20\x27feedback\x27\x20Move\x20function\x20(demand.move:352)\x20updates\x20ONE\x20presenter\x20per\x20call\x20(feedback_imp\x20iterates\x20'+('no\x20vector).\x20The\x20SDK\x20batches\x20multiple\x20feedback\x20calls\x20and\x20caps\x20the\x20batch\x20at\x20MAX_FEEDBACK_COUNT='+MAX_FEEDBACK_COUNT+'\x20')+'(SDK-only\x20limit,\x20NOT\x20in\x20onchain-constants.ts\x20—\x20Move\x20has\x20no\x20aggregate\x20feedback-count\x20check).\x20Exceeding\x20the\x20'+'SDK\x20batch\x20limit\x20causes\x20the\x20SDK\x20to\x20refuse\x20the\x20call\x20before\x20transaction\x20building.\x20Each\x20feedback\x20entry\x20writes\x20'+'a\x20String\x20(bounded\x20by\x20common::DESCRIPTION,\x204000\x20chars)\x20and\x20an\x20optional\x20u8\x20acceptance_score\x20to\x20a\x20presenter\x27s\x20'+'ServiceInfo\x20record.','affected_stakeholders':['creator'],'scenario':'Caller\x20attempts\x20to\x20submit\x2021\x20feedback\x20entries\x20in\x20a\x20single\x20SDK\x20call','mitigation':'Split\x20the\x20feedback\x20batch\x20into\x20chunks\x20of\x20≤\x2020\x20entries.\x20If\x20the\x20Demand\x20has\x20more\x20than\x2020\x20presenters\x20to\x20'+'give\x20feedback\x20on,\x20submit\x20multiple\x20transactions.\x20Consider\x20whether\x20bulk\x20feedback\x20is\x20appropriate\x20—\x20'+'individualized\x20feedback\x20per\x20presenter\x20is\x20often\x20more\x20meaningful.','auto_fixable':![]},'check':a=>{if(a['feedback_count']===undefined)return null;if(a['feedback_count']<=MAX_FEEDBACK_COUNT)return null;return{...R_DEM_1_03['rule'],'evidence':'feedback_count='+a['feedback_count']+',\x20limit='+MAX_FEEDBACK_COUNT};}},R_DEM_2_01={'rule':{'id':'R-DEM-04','level':'HIGH','category':'semantic','title':'present\x20called\x20without\x20passport\x20when\x20guards\x20vector\x20is\x20non-empty','description':'The\x20Move\x20present\x20function\x20(demand.move:100)\x20asserts\x20`vector::is_empty(&self.guards)`\x20and\x20aborts\x20with\x20'+'E_NEED_PASSPORT\x20(3)\x20if\x20the\x20guards\x20vector\x20is\x20non-empty.\x20When\x20guards\x20exist,\x20every\x20presenter\x20MUST\x20go\x20through\x20'+'present_with_passport\x20(or\x20present_service_with_passport),\x20which\x20routes\x20through\x20present_with_passport_imp.\x20'+'That\x20function\x20looks\x20up\x20the\x20specified\x20Guard\x20in\x20the\x20guards\x20vector,\x20calls\x20passport::result_for_guard\x20to\x20'+'verify\x20the\x20Passport,\x20and\x20(if\x20service_identifier\x20is\x20set)\x20extracts\x20the\x20submission\x20address\x20from\x20the\x20Passport.\x20'+'Calling\x20plain\x20`present`\x20on\x20a\x20guarded\x20Demand\x20always\x20aborts\x20—\x20there\x20is\x20no\x20fallback\x20path.','affected_stakeholders':['presenter','creator'],'scenario':'Demand\x20has\x202\x20guards;\x20a\x20presenter\x20calls\x20present()\x20instead\x20of\x20present_with_passport()','mitigation':'Before\x20presenting,\x20query\x20the\x20Demand\x27s\x20guards\x20vector.\x20If\x20non-empty,\x20use\x20present_with_passport\x20and\x20'+'supply\x20a\x20Guard\x20+\x20Passport.\x20The\x20Guard\x20address\x20must\x20already\x20be\x20in\x20the\x20guards\x20vector\x20(otherwise\x20'+'E_GUARD_NOT_FOUND\x20(4)\x20aborts).\x20If\x20service_identifier\x20is\x20set\x20on\x20the\x20matching\x20guard,\x20the\x20submission\x20'+'address\x20is\x20extracted\x20from\x20the\x20Passport\x20—\x20do\x20not\x20pass\x20a\x20separate\x20service\x20parameter.','related_move_error':'E_NEED_PASSPORT\x20(3)','auto_fixable':![]},'check':a=>{if(!a['using_present_without_passport'])return null;if(!a['guards_non_empty'])return null;return{...R_DEM_2_01['rule'],'evidence':'guards_non_empty=true,\x20using\x20present\x20(no\x20passport)'};}},R_DEM_3_01={'rule':{'id':'R-DEM-05','level':'INFO','category':'lifecycle','title':'um_set_imp\x20object-linker\x20dependency\x20leak\x20—\x20RESOLVED\x20(P-DEM-P1-1)','description':'PREVIOUS\x20RISK:\x20um_set_imp\x20(demand.move:139-147)\x20previously\x20set\x20self.um\x20to\x20the\x20new\x20Contact\x20address\x20'+'BEFORE\x20disaffiliating\x20the\x20old\x20um,\x20causing\x20the\x20old\x20Contact\x20to\x20retain\x20a\x20stale\x20object-linker\x20binding\x20record\x20in\x20the\x20'+'object_linker.\x20affiliation_change_core\x20was\x20not\x20called\x20for\x20the\x20old\x20um,\x20leading\x20to\x20an\x20object-linker\x20dependency\x20leak.\x0a\x0a'+'FIX\x20(P-DEM-P1-1):\x20um_set_imp\x20now\x20disaffiliates\x20the\x20old\x20um\x20via\x20object_linker::disaffiliation_core\x20BEFORE\x20setting\x20'+'the\x20new\x20one.\x20The\x20new\x20um\x20is\x20then\x20affiliated\x20via\x20object_linker::affiliation_core.\x20This\x20matches\x20the\x20pattern\x20used\x20'+'by\x20permission_set\x20(which\x20uses\x20affiliation_change_core).\x20um_none_imp\x20also\x20disaffiliates\x20before\x20clearing.\x0a\x0a'+'This\x20rule\x20is\x20retained\x20for\x20historical\x20audit\x20and\x20to\x20detect\x20regressions.','affected_stakeholders':['creator','system'],'scenario':'Future\x20regression:\x20someone\x20reorders\x20um_set_imp\x20to\x20set\x20new\x20before\x20disaffiliating\x20old','mitigation':'Keep\x20the\x20disaffiliate-then-set\x20ordering.\x20The\x20Move\x20invariant:\x20any\x20path\x20that\x20mutates\x20self.um\x20MUST\x20call\x20'+'object_linker::disaffiliation_core\x20on\x20the\x20old\x20value\x20before\x20assigning\x20a\x20new\x20one.','auto_fixable':![]},'check':a=>{if(a['constants_synced'])return null;return{...R_DEM_3_01['rule'],'evidence':'constants_synced=false\x20(regression\x20check)'};}},R_DEM_2_02={'rule':{'id':'R-DEM-06','level':'INFO','category':'semantic','title':'guard_add_imp\x20service_identifier\x20type\x20check\x20skipped\x20on\x20early\x20return\x20—\x20RESOLVED\x20(P-DEM-P1-2)','description':'PREVIOUS\x20RISK:\x20guard_add_imp\x20(demand.move:213-242)\x20previously\x20had\x20the\x20service_identifier\x20type\x20check\x20'+'AFTER\x20the\x20early-return\x20path\x20that\x20updates\x20an\x20existing\x20guard\x27s\x20service_identifier.\x20When\x20a\x20guard\x20with\x20'+'the\x20same\x20address\x20already\x20existed,\x20the\x20function\x20returned\x20before\x20validating\x20the\x20new\x20service_identifier\x20'+'against\x20guard::get_submission_object_type.\x20This\x20allowed\x20setting\x20an\x20invalid\x20service_identifier\x20that\x20'+'would\x20later\x20fail\x20at\x20present_with_passport\x20time\x20with\x20E_INVALID_SERVICE_OBJECT_TYPE\x20(common.move:13).\x0a\x0a'+'FIX\x20(P-DEM-P1-2):\x20The\x20service_identifier\x20type\x20check\x20now\x20runs\x20FIRST\x20(demand.move:218-222),\x20BEFORE\x20the\x20'+'duplicate-detection\x20loop.\x20common::assert_service_object_type\x20is\x20called\x20for\x20any\x20non-None\x20service_identifier,\x20'+'ensuring\x20both\x20the\x20insert\x20and\x20update\x20paths\x20validate\x20the\x20type.\x0a\x0a'+'This\x20rule\x20is\x20retained\x20for\x20historical\x20audit\x20and\x20to\x20detect\x20regressions.','affected_stakeholders':['creator','presenter'],'scenario':'Future\x20regression:\x20someone\x20moves\x20the\x20type\x20check\x20back\x20to\x20after\x20the\x20duplicate-detection\x20loop','mitigation':'Keep\x20the\x20type\x20check\x20at\x20the\x20top\x20of\x20guard_add_imp.\x20The\x20Move\x20invariant:\x20any\x20service_identifier\x20provided\x20'+'to\x20guard_add\x20MUST\x20be\x20validated\x20via\x20guard::get_submission_object_type\x20+\x20common::assert_service_object_type\x20'+'BEFORE\x20any\x20mutation\x20of\x20the\x20guards\x20vector.','auto_fixable':![]},'check':a=>{if(a['constants_synced'])return null;return{...R_DEM_2_02['rule'],'evidence':'constants_synced=false\x20(regression\x20check)'};}},R_DEM_4_01={'rule':{'id':'R-DEM-07','level':'INFO','category':'knowledge','title':'Demand\x20matching\x20must\x20not\x20read\x20non-existent\x20Move\x20fields\x20—\x20RESOLVED\x20(P-DEM-P1-3)','description':'PREVIOUS\x20RISK:\x20the\x20retired\x20demand-matching.ts\x20engine\x20(matchDemand/extractDemandInfo)\x20read\x20fields\x20(tags,\x20'+'maxPrice,\x20scenario,\x20minTrustScore,\x20keywords)\x20that\x20do\x20NOT\x20exist\x20on\x20the\x20Move\x20Demand\x20struct.\x20The\x20Move\x20struct\x20'+'only\x20has:\x20description,\x20location,\x20rewards,\x20guards,\x20presenters,\x20um,\x20permission.\x20This\x20caused\x20the\x20matching\x20'+'engine\x20to\x20silently\x20produce\x20undefined\x20values\x20when\x20fed\x20raw\x20on-chain\x20query\x20results.\x0a\x0a'+'FIX\x20(P-DEM-P1-3):\x20the\x20capability-vector\x20engine\x20(evaluation/builtins/demand-match.ts)\x20enriches\x20via\x20'+'evaluation/extract.ts\x20(extractDemandCapability/extractServiceCapability).\x20Only\x20`location`\x20maps\x20directly\x20'+'to\x20the\x20Move\x20Demand\x20struct;\x20all\x20other\x20signals\x20(industry/tags/keywords/region/trust/price\x20budget)\x20are\x20'+'enriched\x20from\x20description\x20NLP,\x20the\x20industry\x20generalizer,\x20or\x20caller-injected\x20overrides/data\x20sources.\x0a\x0a'+'This\x20rule\x20is\x20retained\x20for\x20historical\x20audit\x20and\x20to\x20detect\x20regressions.','affected_stakeholders':['system'],'scenario':'Future\x20regression:\x20someone\x20removes\x20the\x20enrichment\x20contract\x20docs\x20from\x20evaluation/extract.ts','mitigation':'Keep\x20the\x20enrichment\x20contract\x20in\x20evaluation/extract.ts\x20(non-chain-derivable\x20fields\x20are\x20enriched\x20there,\x20'+'not\x20read\x20as\x20on-chain\x20fact).\x20The\x20matching\x20engine\x20must\x20never\x20query\x20on-chain\x20data\x20directly\x20—\x20it\x20scores\x20'+'over\x20already-enriched\x20capability\x20vectors.','auto_fixable':![]},'check':a=>{if(a['constants_synced'])return null;return{...R_DEM_4_01['rule'],'evidence':'constants_synced=false\x20(regression\x20check)'};}},R_DEM_4_02={'rule':{'id':'R-DEM-08','level':'INFO','category':'knowledge','title':'permission_set\x20not\x20exposed\x20in\x20SDK\x20—\x20RESOLVED\x20(DE-D-2=A)','description':'PREVIOUS\x20GAP:\x20The\x20Move\x20permission_set\x20function\x20(demand.move:286)\x20was\x20not\x20exposed\x20as\x20a\x20standalone\x20'+'function\x20in\x20the\x20SDK\x27s\x20call/demand.ts.\x20Callers\x20could\x20not\x20change\x20the\x20Permission\x20object\x20bound\x20to\x20a\x20Demand\x20'+'after\x20creation.\x0a\x0a'+'RESOLUTION\x20(DE-D-2=A):\x20permission_set\x20is\x20now\x20exposed\x20via\x20the\x20CallPermission.apply\x20mechanism.\x20The\x20SDK\x20'+'wraps\x20permission_set\x20by\x20routing\x20it\x20through\x20CallPermission,\x20which\x20performs\x20the\x20assert_owner\x20check\x20on\x20the\x20'+'old\x20Permission\x20and\x20updates\x20the\x20Demand\x27s\x20bound\x20permission.\x20object_linker\x27s\x20affiliation_change_core\x20is\x20called\x20'+'to\x20migrate\x20the\x20binding\x20from\x20the\x20old\x20Permission\x20to\x20the\x20new\x20one.\x0a\x0a'+'Permission\x20indices\x20for\x20Demand\x20(demand.move:20):\x20400=DEMAND_NEW,\x20401=DEMAND_DESCRIPTION,\x20402=DEMAND_LOCATION,\x20'+'404=DEMAND_GUARD,\x20405=DEMAND_REWARD,\x20406=DEMAND_FEEDBACK,\x20407=DEMAND_OWNER_RECEIVE,\x20408=DEMAND_UM.\x0a\x0a'+'This\x20rule\x20is\x20retained\x20for\x20historical\x20audit\x20and\x20to\x20detect\x20regressions.','affected_stakeholders':['creator','system'],'scenario':'Future\x20regression:\x20someone\x20removes\x20the\x20CallPermission.apply\x20path\x20for\x20permission_set','mitigation':'Keep\x20permission_set\x20exposed\x20via\x20CallPermission.apply.\x20The\x20Move\x20invariant:\x20permission_set\x20requires\x20'+'permission::assert_owner(old)\x20and\x20MUST\x20call\x20object_linker::affiliation_change_core\x20to\x20migrate\x20the\x20binding.','auto_fixable':![]},'check':a=>{if(a['constants_synced'])return null;return{...R_DEM_4_02['rule'],'evidence':'constants_synced=false\x20(regression\x20check)'};}};export const DEMAND_RISK_RULES=[R_DEM_1_01,R_DEM_1_02,R_DEM_1_03,R_DEM_2_01,R_DEM_3_01,R_DEM_2_02,R_DEM_4_01,R_DEM_4_02];export function checkDemandRisks(a){const b=[];for(const c of DEMAND_RISK_RULES){const d=c['check'](a);if(d)b['push'](d);}return b;}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import*as
|
|
1
|
+
import*as a147a from'fs';import*as a147b from'os';import*as a147c from'path';export const SKILLS_PACKAGE='@wowok/skills';export const SKILLS_INSTALL_COMMAND='npm\x20install\x20-g\x20@wowok/skills';export const SKILLS_DOCTOR_COMMAND='wowok-skills\x20doctor';export const SKILLS_REPAIR_COMMAND='wowok-skills\x20init\x20--force';export const COLD_START_SECONDS=0x14;export const SKILL_ROLES=['wowok-onboard','wowok-provider','wowok-order','wowok-supplier','wowok-collaborator','wowok-machine','wowok-arbitrator','wowok-messenger','wowok-market','wowok-governance','wowok-planner','wowok-auditor','wowok-output'];export const COMMON_GOALS=[{'goal':'Onboard\x20a\x20new\x20merchant\x20and\x20publish\x20a\x20commercial\x20service\x20end-to-end','skills':['wowok-onboard','wowok-provider'],'tools':['goal_operation','onchain_operations','query_toolkit']},{'goal':'Design\x20or\x20modify\x20a\x20Machine\x20workflow\x20(nodes,\x20forwards,\x20guards)','skills':['wowok-machine','wowok-auditor'],'tools':['onchain_operations','machineNode2file','guard2file']},{'goal':'Evaluate\x20or\x20buy\x20a\x20service\x20/\x20handle\x20an\x20in-order\x20customer\x20lifecycle','skills':['wowok-order'],'tools':['query_toolkit','onchain_operations','messenger_operation']},{'goal':'Fulfill\x20a\x20sub-order\x20as\x20a\x20supplier\x20and\x20collect\x20settlement','skills':['wowok-supplier','wowok-collaborator'],'tools':['watch_operation','workflow_operation','keeper_operation']},{'goal':'Operate\x20order\x20workflows\x20/\x20advance\x20progress\x20on\x20behalf\x20of\x20a\x20merchant','skills':['wowok-collaborator'],'tools':['workflow_operation','watch_operation','keeper_operation']},{'goal':'Handle\x20a\x20dispute\x20or\x20run\x20an\x20arbitration\x20service','skills':['wowok-arbitrator','wowok-messenger'],'tools':['evaluation_operation','onchain_operations','messenger_operation']},{'goal':'Govern\x20permissions,\x20treasury\x20funds\x20and\x20the\x20on-chain\x20profile\x20after\x20setup','skills':['wowok-governance'],'tools':['permission_operation','onchain_operations','query_toolkit']},{'goal':'Obtain\x20WOW\x20gas\x20/\x20payment\x20tokens\x20before\x20the\x20first\x20transaction','skills':['wowok-onboard'],'tools':['wowok_buildin_info','bridge_operation','account_operation']}];function candidateSkillRoots(a){const b=a147b['homedir'](),c=[a147c['join'](b,'.claude','skills'),a147c['join'](b,'.agents','skills'),a147c['join'](b,'.codex','skills'),a147c['join'](b,'.cursor','skills'),a147c['join'](b,'.codebuddy','skills'),a147c['join'](b,'.kilo','skills'),a147c['join'](b,'.roo','skills'),a147c['join'](b,'.cline','skills'),a147c['join'](b,'.copilot','skills'),a147c['join'](b,'.codeium','windsurf','skills'),a147a['existsSync'](a147c['join'](b,'.trae-cn','skills'))?a147c['join'](b,'.trae-cn','skills'):a147c['join'](b,'.trae','skills')],d=['.agents/skills','.claude/skills','.cursor/skills','.trae/skills','.codebuddy/skills','.roo/skills','.cline/skills','.kilo/skills','.github/skills']['map'](e=>a147c['resolve'](a,e));return[...new Set([...c,...d])];}function rootHasWowokSkill(a){let b;try{b=a147a['readdirSync'](a,{'withFileTypes':!![]});}catch{return![];}if(b['some'](c=>c['isFile']()&&c['name']==='.wowok-skills.json'))return!![];return b['some'](c=>c['isDirectory']()&&c['name']['startsWith']('wowok-'));}export function detectInstalledSkills(a=process['cwd']()){const b=[];for(const c of candidateSkillRoots(a)){try{if(rootHasWowokSkill(c))b['push'](c);}catch{}}return{'status':b['length']>0x0?'detected':'not_detected','detected_roots':b};}export function getGettingStarted(a=process['cwd']()){return{'skills':{'what':'WoWok\x20Skills\x20are\x20role-based\x20playbooks\x20(SKILL.md\x20files\x20installed\x20into\x20AI\x20clients)\x20that\x20sit\x20on\x20top\x20of\x20this\x20MCP\x20server.\x20The\x20MCP\x20exposes\x20the\x20tools;\x20the\x20skills\x20tell\x20an\x20agent\x20WHEN\x20and\x20in\x20what\x20ORDER\x20to\x20use\x20them\x20for\x20complex\x20goals\x20(onboarding,\x20buying,\x20fulfillment,\x20arbitration,\x20governance),\x20and\x20materially\x20reduce\x20failed\x20calls.\x20This\x20server\x20works\x20without\x20them;\x20with\x20them\x20loaded,\x20agents\x20start\x20from\x20structured\x20guidance\x20instead\x20of\x20discovering\x20sub-tools\x20by\x20trial\x20and\x20error.','package':SKILLS_PACKAGE,'recommended':!![],'install_command':SKILLS_INSTALL_COMMAND,'doctor_command':SKILLS_DOCTOR_COMMAND,'repair_command':SKILLS_REPAIR_COMMAND,'detection':detectInstalledSkills(a),'detection_note':'Best-effort\x20scan\x20of\x20standard\x20client\x20skill\x20roots\x20on\x20this\x20machine.\x20`wowok-skills\x20doctor`\x20is\x20authoritative\x20and\x20also\x20reports\x20MCP\x20registration\x20state\x20per\x20client.\x20If\x20detection\x20says\x20not_detected\x20but\x20skills\x20were\x20installed\x20for\x20a\x20client\x20with\x20a\x20non-standard\x20root,\x20trust\x20doctor.','roles':[...SKILL_ROLES]},'cold_start':{'ready_seconds':COLD_START_SECONDS,'note':'The\x20first\x20call\x20after\x20the\x20server\x20boots\x20can\x20take\x20around\x2020\x20seconds\x20while\x20@wowok/agent-mcp\x20is\x20bootstrapped\x20(especially\x20via\x20npx\x20on\x20Windows).\x20A\x20transport\x20timeout\x20on\x20the\x20FIRST\x20call\x20is\x20startup\x20latency,\x20not\x20a\x20broken\x20server\x20—\x20wait\x20and\x20retry;\x20subsequent\x20calls\x20are\x20fast.\x20Never\x20interpret\x20a\x20delayed\x20first\x20response\x20as\x20a\x20failed\x20on-chain\x20transaction.'},'common_goals':COMMON_GOALS['map'](b=>({...b,'skills':[...b['skills']],'tools':[...b['tools']]})),'first_calls':['wowok_buildin_info\x20info=\x27getting\x20started\x27\x20—\x20this\x20orientation','wowok_buildin_info\x20info=\x27current\x20network\x27\x20—\x20which\x20chain\x20(mainnet/testnet)\x20the\x20SDK\x20defaults\x20to','wowok_buildin_info\x20info=\x27funding\x20guidance\x27\x20—\x20testnet\x20faucet\x20/\x20mainnet\x20bridge\x20/\x20airdrop','wowok_buildin_info\x20info=\x27upgrade_check\x27\x20—\x20whether\x20the\x20MCP\x20server\x20and\x20SDK\x20are\x20current','schema_query\x20action=\x27list\x27\x20—\x20enumerate\x20every\x20sub-tool\x20and\x20fetch\x20its\x20input\x20schema']};}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type Finding } from "../graph/onchain/index.js";
|
|
2
|
+
import { type GuardRiskAssessment, type RiskCheckContext } from "./guard-risk.js";
|
|
3
|
+
import type { GuardScene } from "./guard-ledger.js";
|
|
4
|
+
export interface GuardDraftContext {
|
|
5
|
+
table: RiskCheckContext["table"];
|
|
6
|
+
root: any;
|
|
7
|
+
rely?: RiskCheckContext["rely"];
|
|
8
|
+
scene?: GuardScene;
|
|
9
|
+
sharing_recipients?: RiskCheckContext["sharing_recipients"];
|
|
10
|
+
}
|
|
11
|
+
export interface GuardDraftEvaluation {
|
|
12
|
+
findings: Finding[];
|
|
13
|
+
assessment: GuardRiskAssessment;
|
|
14
|
+
}
|
|
15
|
+
export declare function evaluateGuardDraft(ctx: GuardDraftContext): GuardDraftEvaluation;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ENTRYPOINT}from'@wowok/wowok';import{buildViewport,runNodeAnalyzers}from'../graph/onchain/index.js';import{makeProposalNode}from'../graph/onchain/proposal-graph.js';import{RULE_NODE_ANALYZERS}from'./rule-node-analyzers.js';import{assembleGuardAssessment}from'./guard-risk.js';function guardDraftGraph(a){const b=makeProposalNode('guard',a);return{'network':ENTRYPOINT['Testnet'],'seed':b['id'],'builtAt':Date['now'](),'nodes':new Map([[b['id'],b]]),'edges':[],'out':new Map(),'inc':new Map(),'gaps':[],'truncations':[],'rpcReport':{'batches':0x0,'byChannel':{'objects':0x0,'keyedFields':0x0,'tables':0x0,'events':0x0},'dedupHits':0x0},'budgetExhausted':{}};}export function evaluateGuardDraft(a){const b=guardDraftGraph(a),c=buildViewport(b,b['seed'],'neutral'),d=runNodeAnalyzers(c,RULE_NODE_ANALYZERS),e=d['map'](g=>g['nativeRisk'])['filter'](f=>f!=null);return{'findings':d,'assessment':assembleGuardAssessment(a,e)};}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{describe,expect,it}from'vitest';import{evaluateGuardDraft}from'./guard-eval.js';import{findScene}from'./guard-ledger.js';const TRIGGER={'table':[{'identifier':0x0,'b_submission':![],'value_type':'Address','value':'0xabc','name':'selector'}],'root':{'type':'identifier','identifier':0x0},'scene':findScene('Service','order_allocators')};describe('guard\x20draft\x20evaluation\x20—\x20unified\x20registry\x20bridge\x20(T27)',()=>{it('runs\x20rules\x20through\x20the\x20registry\x20with\x20GD1\x20native\x20risks\x20carried\x20on\x20findings',()=>{const {findings:a}=evaluateGuardDraft(TRIGGER);expect(a['length'],'trigger\x20draft\x20fired\x20nothing')['toBeGreaterThan'](0x0);for(const b of a){expect(b['path'][0x0])['toBe']('proposal::guard'),expect(b['source'])['toBe']('proposal'),expect(b['ruleId'],'rule\x20id\x20carried')['toBeTruthy'](),expect(b['nativeRisk'],'native\x20risk\x20carried\x20(carryNative)')['toBeDefined']();const c=b['nativeRisk'];expect(c['id'])['toBe'](b['ruleId']),expect(c['level'])['toBe'](b['severity']);}}),it('rebuilds\x20the\x20GuardRiskAssessment\x20contract\x201:1\x20from\x20the\x20findings',()=>{const {findings:a,assessment:b}=evaluateGuardDraft(TRIGGER);expect(b['risks']['length'])['toBe'](a['length']);for(let c=0x0;c<a['length'];c++){expect(b['risks'][c]['id'])['toBe'](a[c]['ruleId']),expect(b['risks'][c])['toBe'](a[c]['nativeRisk']);}expect(typeof b['overall_risk'])['toBe']('string'),expect(b['overall_risk']['length'])['toBeGreaterThan'](0x0),expect(typeof b['needs_human_review'])['toBe']('boolean'),expect(b['scene']?.['id'])['toBe']('service_order_allocators_guard'),expect(b['guard_summary']['length'])['toBeGreaterThan'](0x0),expect(b['stakeholder_advice'])['toBeDefined']();}),it('informs\x20a\x20scene-free\x20sparse\x20draft\x20honestly\x20(stubs\x20stay\x20silent)',()=>{const {findings:a,assessment:b}=evaluateGuardDraft({'table':[],'root':undefined});expect(b['risks']['length'])['toBe'](a['length']);for(let c=0x0;c<a['length'];c++){expect(b['risks'][c]['id'])['toBe'](a[c]['ruleId']);}});});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { GuardRiskAssessment } from "./guard-risk.js";
|
|
2
2
|
export type DiagnosticSource = "sdk" | "lint" | "risk";
|
|
3
3
|
export type DiagnosticSeverity = "error" | "warning" | "info" | "hint";
|
|
4
4
|
export interface GuardDiagnostic {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{validateGuardData,MAX_DESCRIPTION_LENGTH,MAX_GUARD_TABLE_ITEM_LENGTH}from'@wowok/wowok';import{assessGuardRisks}from'./guard-risk.js';import{findScene,inferSceneFromAction}from'./guard-ledger.js';import{suggestTemplateForScene}from'./guard-templates.js';function deepClone(a){return JSON['parse'](JSON['stringify'](a));}function rootToString(a){return JSON['stringify'](a);}function hasSignerContext(a){const b=rootToString(a);return b['includes']('\x22Signer\x22')||b['includes']('\x22context\x22:\x22Signer\x22')||b['includes']('\x22context\x22:\x20\x22Signer\x22');}function getSubmissionEntries(a){return a['filter'](b=>b['b_submission']===!![]);}function inferValueType(a){if(typeof a==='string'){if(a['startsWith']('0x')&&a['length']>=0x3)return'Address';return'String';}if(typeof a==='number'){if(Number['isInteger'](a)){if(a>=0x0&&a<=0xff)return'U8';if(a>=0x0&&a<=0xffff)return'U16';return'U64';}return'U256';}if(typeof a==='boolean')return'Bool';if(Array['isArray'](a)){if(a['length']>0x0){const b=inferValueType(a[0x0]);if(b==='Address')return'Vec<Address>';if(b==='String')return'Vec<String>';if(b==='Bool')return'Vec<Bool>';}return'Vec<Address>';}return undefined;}function sdkIssueToDiagnostic(a){return{'code':a['code'],'message':a['message'],'severity':a['severity'],'source':'sdk','location':{'path':a['path']},'fix':{'description':'SDK\x20validation\x20failed\x20('+(a['sdk_error']??'InvalidParam')+');\x20manual\x20fix\x20required','auto_fixable':![]}};}async function checkSdkSyntax(a){const b=a['table']['map'](d=>({'identifier':d['identifier'],'b_submission':d['b_submission']??![],'value_type':d['value_type']??'Address','value':d['value'],'name':d['name']??''})),c=await validateGuardData({'description':a['description'],'table':b,'root':a['root'],'rely':a['rely']});return c['map'](sdkIssueToDiagnostic);}function checkSemanticErrors(a){const b=[],{table:c,root:d,binding_hint:e}=a,f=e?findScene(e['host_object']??'',e['binding_field']??''):undefined,g=getSubmissionEntries(c);if(g['length']>0x0&&d&&!hasSignerContext(d)){const h=g['some'](j=>j['value_type']==='Address'),i=f?.['id']==='service_order_allocators_guard'&&e?.['sharing_recipients']!==undefined&&e['sharing_recipients']['length']>0x0&&!e['sharing_recipients']['includes']('Signer');if(h&&!i){const j=g['filter'](k=>k['value_type']==='Address')['map'](k=>c['indexOf'](k));b['push']({'code':'LE-04','message':'Submitted\x20data\x20has\x20no\x20Signer\x20binding\x20(submission\x20forgery\x20risk)','severity':'error','source':'lint','location':{'path':j['map'](k=>'/table/'+k)['join']('\x20→\x20')},'fix':{'description':'Add\x20logic_equal(context(Signer),\x20identifier[N])\x20in\x20root\x20to\x20bind\x20the\x20submitter\x20identity','auto_fixable':![]}});}}if(f?.['id']==='arbitration_voting_guard'){const k=g['some'](l=>['U8','U16','U32','U64','U128','U256']['includes'](l['value_type']??''));if(k){const l=g['filter'](m=>['U8','U16','U32','U64','U128','U256']['includes'](m['value_type']??''))['map'](m=>c['indexOf'](m));b['push']({'code':'LE-05','message':'voting_guard\x20voting\x20weight\x20comes\x20from\x20submitted\x20data\x20(weight\x20forgery\x20risk)','severity':'error','source':'lint','location':{'path':l['map'](m=>'/table/'+m)['join']('\x20→\x20')},'fix':{'description':'Derive\x20arbitrator\x20weights\x20from\x20the\x20Arb\x20object\x20via\x20witness\x20(e.g.\x20105\x20TypeArbArbitration)\x20rather\x20than\x20submitting\x20them\x20directly','auto_fixable':![]}});}}if(f?.['id']==='gen_passport_guard'||e?.['action']==='gen_passport'){const m=rootToString(d);if(m['includes']('1167')||m['includes']('repository.data')){const n=m['includes']('quote_guard');n&&b['push']({'code':'LE-06','message':'repository.data\x20query\x20with\x20quote_guard:\x20rigid\x20verification\x20requirement\x20—\x20ensure\x20Passport\x20includes\x20quote_guard\x20verification\x20with\x20necessary\x20submissions\x20(e.g.,\x20Payment\x20proof)','severity':'info','source':'lint','location':{'path':'/root'},'fix':{'description':'Ensure\x20the\x20quote_guard\x20is\x20verified:\x20user\x20submits\x20Payment\x20via\x20Passport,\x20quote_guard\x20verifies\x20Payment\x20fields,\x20repository\x20data\x20query\x20passes','auto_fixable':![]}});}}if(e?.['host_object']&&f){const o=e['host_object'],p=c['filter'](q=>!q['b_submission']&&q['value_type']==='Address'&&typeof q['value']==='string'&&q['value']['startsWith']('0x')&&q['object_type']===o);if(p['length']>0x0){const q=p['map'](r=>c['indexOf'](r));b['push']({'code':'LE-07','message':'Circular\x20reference\x20uses\x20an\x20address\x20rather\x20than\x20a\x20name\x20(Host\x20Object\x20may\x20not\x20be\x20published\x20yet\x20when\x20the\x20Guard\x20is\x20created)','severity':'error','source':'lint','location':{'path':q['map'](r=>'/table/'+r+'/value')['join']('\x20→\x20')},'fix':{'description':'Change\x20value\x20from\x20an\x20address\x20to\x20an\x20object\x20name\x20(e.g.\x20\x22service1\x22);\x20the\x20SDK\x20will\x20resolve\x20it\x20to\x20an\x20address\x20after\x20the\x20Host\x20Object\x20is\x20published','auto_fixable':![]}});}}return b;}function checkSyntaxHints(a){const b=[],{table:c}=a;(!a['description']||a['description']['trim']()==='')&&b['push']({'code':'SH-01','message':'description\x20is\x20missing\x20or\x20empty','severity':'info','source':'lint','location':{'path':'/description'},'fix':{'description':'Add\x20a\x20description,\x20e.g.\x20\x27Service\x20buy_guard:\x20whitelist\x20validation\x27','auto_fixable':!![]}});for(let d=0x0;d<c['length'];d++){const e=c[d];(!e['name']||e['name']['trim']()==='')&&b['push']({'code':'SH-03','message':'table['+d+']\x20is\x20missing\x20name','severity':'warning','source':'lint','location':{'path':'/table/'+d+'/name'},'fix':{'description':'Add\x20a\x20name,\x20e.g.\x20\x22data\x20entry\x20'+e['identifier']+'\x22','auto_fixable':!![]}});}for(let f=0x0;f<c['length'];f++){const g=c[f];!g['value_type']&&b['push']({'code':'SH-05','message':'table['+f+']\x20is\x20missing\x20value_type','severity':'warning','source':'lint','location':{'path':'/table/'+f+'/value_type'},'fix':{'description':'Infer\x20value_type\x20from\x20value\x20(e.g.\x20Address/String/U64,\x20etc.)','auto_fixable':!![]}});}c['length']>MAX_GUARD_TABLE_ITEM_LENGTH&&b['push']({'code':'SH-07','message':'table\x20entry\x20count\x20'+c['length']+'\x20exceeds\x20the\x20maximum\x20limit\x20'+MAX_GUARD_TABLE_ITEM_LENGTH,'severity':'error','source':'lint','location':{'path':'/table'},'fix':{'description':'Slim\x20down\x20the\x20table\x20by\x20merging\x20similar\x20entries,\x20or\x20split\x20into\x20multiple\x20Guards\x20+\x20rely','auto_fixable':![]}});for(let h=0x0;h<c['length'];h++){c[h]['b_submission']===undefined&&b['push']({'code':'SH-10','message':'table['+h+']\x20b_submission\x20is\x20missing','severity':'info','source':'lint','location':{'path':'/table/'+h+'/b_submission'},'fix':{'description':'Set\x20to\x20false\x20(constant)\x20or\x20true\x20(submitted\x20data)','auto_fixable':!![]}});}for(let j=0x0;j<c['length'];j++){const k=c[j];k['b_submission']===!![]&&k['value']!==undefined&&k['value']!==null&&b['push']({'code':'SH-11','message':'table['+j+']\x20has\x20a\x20redundant\x20value\x20field\x20on\x20b_submission=true\x20entry\x20(the\x20verifier\x20supplies\x20the\x20value\x20at\x20runtime;\x20this\x20value\x20is\x20ignored\x20by\x20BCS\x20encoding\x20and\x20wastes\x20gas)','severity':'warning','source':'lint','location':{'path':'/table/'+j+'/value'},'fix':{'description':'Remove\x20the\x20value\x20field\x20—\x20it\x20is\x20ignored\x20for\x20b_submission=true\x20entries','auto_fixable':!![]}});}return b;}function checkSuggestions(a){const b=[],{root:c,binding_hint:d,table:e}=a;if(c){const g=rootToString(c);if(g['includes']('vec_contains_address')&&g['includes']('Signer'))b['push']({'code':'SG-01','message':'Matches\x20Pattern\x20P04\x20(whitelist\x20validation)','severity':'hint','source':'lint','location':{'path':'/root'},'fix':{'description':'Refer\x20to\x20the\x20P04\x20Pattern\x20to\x20ensure\x20best\x20practices','auto_fixable':![]}});else{if(g['includes']('logic_equal')&&g['includes']('Signer')){const h=e['some'](i=>!i['b_submission']&&i['value_type']==='Address'&&typeof i['value']==='string'&&i['value']['length']>0x0);h&&b['push']({'code':'SG-01','message':'Matches\x20Pattern\x20P04\x20(whitelist\x20validation\x20—\x20single-address\x20variant)','severity':'hint','source':'lint','location':{'path':'/root'},'fix':{'description':'P04\x20single-address\x20form;\x20for\x20multi-address\x20scenarios,\x20consider\x20vec_contains_address','auto_fixable':![]}});}}(g['includes']('logic_as_u256_greater')||g['includes']('logic_as_u256_lesser'))&&b['push']({'code':'SG-01','message':'Matches\x20Pattern\x20P02\x20(numeric\x20threshold\x20validation)','severity':'hint','source':'lint','location':{'path':'/root'},'fix':{'description':'Suitable\x20for\x20amount/quantity\x20threshold\x20validation\x20scenarios','auto_fixable':![]}}),g['includes']('convert_witness')&&b['push']({'code':'SG-01','message':'Matches\x20Pattern\x20P09\x20(witness-derived\x20validation)','severity':'hint','source':'lint','location':{'path':'/root'},'fix':{'description':'Suitable\x20for\x20cross-object\x20relationship\x20validation\x20(e.g.\x20Order→Progress)','auto_fixable':![]}});}if(d?.['action']){const i=['buy','forward','allocate','claim_reward','vote','dispute','write_repository','submit_progress','gen_passport'];if(i['includes'](d['action'])){const j=inferSceneFromAction(d['action']);if(j){const k=suggestTemplateForScene(j['id']);k&&b['push']({'code':'SG-02','message':'Recommended\x20scene\x20template:\x20'+k['name'],'severity':'hint','source':'lint','location':{'path':'/'},'fix':{'description':'Refer\x20to\x20template\x20'+k['id']+'\x20('+k['example_use_case']+')','auto_fixable':![]}});}}}const f=getSubmissionEntries(e);for(const l of f){const m=l['name']??'';if(m['length']<0xa||/^[a-z_]+$/i['test'](m)){const n=e['indexOf'](l);b['push']({'code':'SG-03','message':'table['+n+']\x20submitted\x20data\x20has\x20a\x20vague\x20name\x20description','severity':'info','source':'lint','location':{'path':'/table/'+n+'/name'},'fix':{'description':'Use\x20a\x20full\x20natural-language\x20description\x20(≥10\x20characters),\x20e.g.\x20\x27user-submitted\x20operation\x20type\x20(return/damage)\x27','auto_fixable':![]}});}}if(c){const o=rootToString(c),p=o['includes']('proof.signer'),q=o['includes']('proof.time'),r=o['includes']('calc_string_length'),s=f['some'](t=>t['value_type']==='String');if(p&&q)b['push']({'code':'SG-04','message':'Strict-mode\x20privacy-delivery\x20guard\x20detected\x20(proof.signer\x20+\x20proof.time).\x20'+'Recommended\x20three\x20conditions:\x20Signer==proof.signer\x20(submitter\x20accountability),\x20'+'proof.time>order.time\x20(freshness),\x20order.service==service\x20(project\x20binding).\x20'+'No\x20content\x20verification\x20—\x20only\x20submission\x20responsibility\x20(\x27whoever\x20benefits\x20bears\x20the\x20burden\x20of\x20proof\x27).','severity':'info','source':'lint','location':{'path':'/root'},'fix':{'description':'Ensure\x20all\x20three\x20conditions\x20are\x20present\x20(logic_and).\x20Refer\x20to\x20template\x20tpl_forward_privacy_delivery_proof.\x20'+'Query\x20IDs:\x20proof.signer=1958,\x20proof.time=1960,\x20order.time=1574,\x20order.service=1563.','auto_fixable':![]}});else r&&s&&b['push']({'code':'SG-04','message':'Broad-mode\x20privacy-delivery\x20guard\x20detected\x20(String\x20submission\x20+\x20length\x20check,\x20e.g.\x20Merkle\x20Root\x20length\x20==\x2066).\x20'+'This\x20trusts\x20the\x20submitter\x27s\x20honesty;\x20the\x20counterparty\x20can\x20dispute\x20by\x20checking\x20their\x20own\x20Messenger\x20conversation.\x20'+'Suitable\x20as\x20an\x20arbitration\x20basis,\x20not\x20a\x20fund-flow\x20gate.','severity':'info','source':'lint','location':{'path':'/root'},'fix':{'description':'For\x20stronger\x20assurance,\x20consider\x20strict\x20mode:\x20submit\x20a\x20Proof\x20object\x20address\x20(from\x20messenger.submitChainProof)\x20+\x20'+'Order\x20address,\x20then\x20verify\x20proof.signer/proof.time/order.service.\x20See\x20template\x20tpl_forward_privacy_delivery_proof.','auto_fixable':![]}});}return b;}export function autoFixGuard(a){const b=deepClone(a),c=[];(!b['description']||b['description']['trim']()==='')&&(b['description']='Guard\x20(table:\x20'+b['table']['length']+'\x20items,\x20root:\x20'+(b['root']?.['type']??'unknown')+')',c['push']({'diagnostic_code':'SH-01','description':'Fill\x20in\x20default\x20description','after':b['description'],'path':'/description'}));if(b['description']&&b['description']['length']>MAX_DESCRIPTION_LENGTH){const f=b['description'];b['description']=b['description']['substring'](0x0,MAX_DESCRIPTION_LENGTH),c['push']({'diagnostic_code':'G-001','description':'Truncate\x20description\x20to\x20'+MAX_DESCRIPTION_LENGTH+'\x20characters','before':f['length']+'\x20characters','after':b['description']['length']+'\x20characters','path':'/description'});}for(let g=0x0;g<b['table']['length'];g++){const h=b['table'][g];(!h['name']||h['name']['trim']()==='')&&(h['name']='data\x20entry\x20'+h['identifier'],c['push']({'diagnostic_code':'SH-03','description':'table['+g+']\x20fill\x20in\x20name','after':h['name'],'path':'/table/'+g+'/name'}));}for(let j=0x0;j<b['table']['length'];j++){const k=b['table'][j];if(!k['value_type']&&k['value']!==undefined&&k['value']!==null){const l=inferValueType(k['value']);l&&(k['value_type']=l,c['push']({'diagnostic_code':'SH-05','description':'table['+j+']\x20infer\x20value_type','after':l,'path':'/table/'+j+'/value_type'}));}}const d=new Map();let e=0x0;for(let m=0x0;m<b['table']['length'];m++){const n=b['table'][m];if(!d['has'](n['identifier']))d['set'](n['identifier'],e),n['identifier']!==e&&c['push']({'diagnostic_code':'G-007','description':'table['+m+']\x20identifier\x20'+n['identifier']+'\x20→\x20'+e,'before':String(n['identifier']),'after':String(e),'path':'/table/'+m+'/identifier'}),n['identifier']=e,e++;else{const o=n['identifier'];n['identifier']=e,d['set'](o,e),c['push']({'diagnostic_code':'G-007','description':'table['+m+']\x20identifier\x20'+o+'\x20duplicate\x20→\x20reallocated\x20to\x20'+e,'before':String(o),'after':String(e),'path':'/table/'+m+'/identifier'}),e++;}}for(let p=0x0;p<b['table']['length'];p++){const q=b['table'][p];q['b_submission']===undefined&&(q['b_submission']=![],c['push']({'diagnostic_code':'SH-10','description':'table['+p+']\x20b_submission\x20default\x20set\x20to\x20false','after':'false','path':'/table/'+p+'/b_submission'}));}if(b['rely']?.['guards']&&b['rely']['guards']['length']>0x0){const r=[...new Set(b['rely']['guards'])];r['length']!==b['rely']['guards']['length']&&(c['push']({'diagnostic_code':'G-009','description':'rely\x20deduplicate:\x20'+b['rely']['guards']['length']+'\x20→\x20'+r['length'],'before':JSON['stringify'](b['rely']['guards']),'after':JSON['stringify'](r),'path':'/rely/guards'}),b['rely']['guards']=r);}for(let s=0x0;s<b['table']['length'];s++){const t=b['table'][s];if(t['b_submission']===!![]&&t['value']!==undefined&&t['value']!==null){const u=JSON['stringify'](t['value']);delete t['value'],c['push']({'diagnostic_code':'SH-11','description':'table['+s+']\x20remove\x20redundant\x20value\x20on\x20b_submission=true\x20entry','before':u,'after':'(removed)','path':'/table/'+s+'/value'});}}return{'fixed':b,'actions':c};}export async function lintGuard(a,b){const c=b?.['auto_fix']??!![],{table:d,root:e,rely:f,binding_hint:g}=a,h=[];let i;const j=await checkSdkSyntax(a);h['push'](...j);const k=checkSemanticErrors(a);h['push'](...k);const l=checkSyntaxHints(a);h['push'](...l);let m,n=[];if(c){const {fixed:v,actions:w}=autoFixGuard(a);w['length']>0x0&&(m=v,n=w);}if(d['length']>0x0&&e){const x=g?findScene(g['host_object']??'',g['binding_field']??''):undefined,y=d['map'](z=>({'identifier':z['identifier'],'b_submission':z['b_submission']??![],'value_type':z['value_type']??'Address','value':z['value'],'name':z['name'],'object_type':z['object_type']}));i=assessGuardRisks({'table':y,'root':e,'rely':f,'scene':x,'sharing_recipients':g?.['sharing_recipients']});for(const z of i['risks']){const A=z['level']==='critical'||z['level']==='high'?'error':z['level']==='medium'?'warning':z['level']==='low'?'info':'hint',B=z['evidence']??'',C=B['startsWith']('/')?B:'/';h['push']({'code':z['id'],'message':'['+z['level']+']\x20'+z['title'],'severity':A,'source':'risk','location':{'path':C},'fix':{'description':z['mitigation'],'auto_fixable':![]}});}}const o=checkSuggestions(a);h['push'](...o);const p=h['filter'](D=>D['severity']==='error')['length'],q=h['filter'](D=>D['severity']==='warning')['length'],s=h['filter'](D=>D['severity']==='info'||D['severity']==='hint')['length'],t=p===0x0;let u;if(p>0x0)u='Fix\x20'+p+'\x20error(s)\x20and\x20re-run\x20lint';else q>0x0?u='Consider\x20addressing\x20'+q+'\x20warning(s),\x20then\x20submit\x20to\x20SDK\x20newGuard()\x20for\x20final\x20syntax\x20validation':u='lint\x20passed\x20(no\x20errors);\x20submit\x20to\x20SDK\x20newGuard()\x20for\x20final\x20syntax\x20validation\x20before\x20going\x20on-chain';return{'json_summary':{'table_count':d['length'],'root_type':e?.['type']??'unknown','has_rely':!!f?.['guards']?.['length'],'rely_count':f?.['guards']?.['length']??0x0,'has_description':!!a['description']},'diagnostics':h,'fixed_json':m,'fix_actions':n,'risk_assessment':i,'summary':{'errors':p,'warnings':q,'infos':s,'auto_fixes_applied':n['length'],'ready':t,'next_step':u}};}export async function isGuardReady(a){const b=await lintGuard(a,{'auto_fix':![]});return b['summary']['ready'];}export async function getGuardErrors(a){const b=await lintGuard(a,{'auto_fix':![]});return b['diagnostics']['filter'](c=>c['severity']==='error');}export function formatLintResult(a){const b=[];b['push']('===\x20Guard\x20JSON\x20Lint\x20Report\x20==='),b['push'](''),b['push']('Summary:'),b['push']('\x20\x20Errors:\x20\x20\x20\x20\x20'+a['summary']['errors']),b['push']('\x20\x20Warnings:\x20\x20\x20'+a['summary']['warnings']),b['push']('\x20\x20Infos:\x20\x20\x20\x20\x20\x20'+a['summary']['infos']),b['push']('\x20\x20Auto-fixes:\x20'+a['summary']['auto_fixes_applied']),b['push']('\x20\x20Ready:\x20\x20\x20\x20\x20\x20'+(a['summary']['ready']?'YES':'NO')),b['push']('\x20\x20Next\x20step:\x20\x20'+a['summary']['next_step']),b['push']('');if(a['fix_actions']['length']>0x0){b['push']('---\x20Auto-fix\x20Actions\x20---');for(const g of a['fix_actions']){b['push']('\x20\x20['+g['diagnostic_code']+']\x20'+g['description']),b['push']('\x20\x20\x20\x20Path:\x20'+g['path']),g['before']&&g['after']&&b['push']('\x20\x20\x20\x20'+g['before']+'\x20->\x20'+g['after']);}b['push']('');}const c=a['diagnostics']['filter'](h=>h['severity']==='error'),e=a['diagnostics']['filter'](h=>h['severity']==='warning'),f=a['diagnostics']['filter'](h=>h['severity']==='info'||h['severity']==='hint');if(c['length']>0x0){b['push']('---\x20Errors\x20(must\x20fix)\x20---');for(const h of c){b['push']('\x20\x20['+h['code']+']\x20('+h['source']+')\x20'+h['message']),b['push']('\x20\x20\x20\x20Path:\x20'+h['location']['path']);if(h['fix'])b['push']('\x20\x20\x20\x20Fix:\x20\x20'+h['fix']['description']);}b['push']('');}if(e['length']>0x0){b['push']('---\x20Warnings\x20(consider\x20fixing)\x20---');for(const i of e){b['push']('\x20\x20['+i['code']+']\x20('+i['source']+')\x20'+i['message']),b['push']('\x20\x20\x20\x20Path:\x20'+i['location']['path']);if(i['fix'])b['push']('\x20\x20\x20\x20Fix:\x20\x20'+i['fix']['description']);}b['push']('');}if(f['length']>0x0){b['push']('---\x20Info\x20&\x20Hints\x20---');for(const j of f){b['push']('\x20\x20['+j['code']+']\x20('+j['source']+')\x20'+j['message']),b['push']('\x20\x20\x20\x20Path:\x20'+j['location']['path']);}}return b['join']('\x0a');}
|
|
1
|
+
import{validateGuardData,MAX_DESCRIPTION_LENGTH,MAX_GUARD_TABLE_ITEM_LENGTH}from'@wowok/wowok';import{evaluateGuardDraft}from'./guard-eval.js';import{findScene,inferSceneFromAction}from'./guard-ledger.js';import{suggestTemplateForScene}from'./guard-templates.js';function deepClone(a){return JSON['parse'](JSON['stringify'](a));}function rootToString(a){return JSON['stringify'](a);}function hasSignerContext(a){const b=rootToString(a);return b['includes']('\x22Signer\x22')||b['includes']('\x22context\x22:\x22Signer\x22')||b['includes']('\x22context\x22:\x20\x22Signer\x22');}function getSubmissionEntries(a){return a['filter'](b=>b['b_submission']===!![]);}function inferValueType(a){if(typeof a==='string'){if(a['startsWith']('0x')&&a['length']>=0x3)return'Address';return'String';}if(typeof a==='number'){if(Number['isInteger'](a)){if(a>=0x0&&a<=0xff)return'U8';if(a>=0x0&&a<=0xffff)return'U16';return'U64';}return'U256';}if(typeof a==='boolean')return'Bool';if(Array['isArray'](a)){if(a['length']>0x0){const b=inferValueType(a[0x0]);if(b==='Address')return'Vec<Address>';if(b==='String')return'Vec<String>';if(b==='Bool')return'Vec<Bool>';}return'Vec<Address>';}return undefined;}function sdkIssueToDiagnostic(a){return{'code':a['code'],'message':a['message'],'severity':a['severity'],'source':'sdk','location':{'path':a['path']},'fix':{'description':'SDK\x20validation\x20failed\x20('+(a['sdk_error']??'InvalidParam')+');\x20manual\x20fix\x20required','auto_fixable':![]}};}async function checkSdkSyntax(a){const b=a['table']['map'](d=>({'identifier':d['identifier'],'b_submission':d['b_submission']??![],'value_type':d['value_type']??'Address','value':d['value'],'name':d['name']??''})),c=await validateGuardData({'description':a['description'],'table':b,'root':a['root'],'rely':a['rely']});return c['map'](sdkIssueToDiagnostic);}function checkSemanticErrors(a){const b=[],{table:c,root:d,binding_hint:e}=a,f=e?findScene(e['host_object']??'',e['binding_field']??''):undefined,g=getSubmissionEntries(c);if(g['length']>0x0&&d&&!hasSignerContext(d)){const h=g['some'](j=>j['value_type']==='Address'),i=f?.['id']==='service_order_allocators_guard'&&e?.['sharing_recipients']!==undefined&&e['sharing_recipients']['length']>0x0&&!e['sharing_recipients']['includes']('Signer');if(h&&!i){const j=g['filter'](k=>k['value_type']==='Address')['map'](k=>c['indexOf'](k));b['push']({'code':'LE-04','message':'Submitted\x20data\x20has\x20no\x20Signer\x20binding\x20(submission\x20forgery\x20risk)','severity':'error','source':'lint','location':{'path':j['map'](k=>'/table/'+k)['join']('\x20→\x20')},'fix':{'description':'Add\x20logic_equal(context(Signer),\x20identifier[N])\x20in\x20root\x20to\x20bind\x20the\x20submitter\x20identity','auto_fixable':![]}});}}if(f?.['id']==='arbitration_voting_guard'){const k=g['some'](l=>['U8','U16','U32','U64','U128','U256']['includes'](l['value_type']??''));if(k){const l=g['filter'](m=>['U8','U16','U32','U64','U128','U256']['includes'](m['value_type']??''))['map'](m=>c['indexOf'](m));b['push']({'code':'LE-05','message':'voting_guard\x20voting\x20weight\x20comes\x20from\x20submitted\x20data\x20(weight\x20forgery\x20risk)','severity':'error','source':'lint','location':{'path':l['map'](m=>'/table/'+m)['join']('\x20→\x20')},'fix':{'description':'Derive\x20arbitrator\x20weights\x20from\x20the\x20Arb\x20object\x20via\x20witness\x20(e.g.\x20105\x20TypeArbArbitration)\x20rather\x20than\x20submitting\x20them\x20directly','auto_fixable':![]}});}}if(f?.['id']==='gen_passport_guard'||e?.['action']==='gen_passport'){const m=rootToString(d);if(m['includes']('1167')||m['includes']('repository.data')){const n=m['includes']('quote_guard');n&&b['push']({'code':'LE-06','message':'repository.data\x20query\x20with\x20quote_guard:\x20rigid\x20verification\x20requirement\x20—\x20ensure\x20Passport\x20includes\x20quote_guard\x20verification\x20with\x20necessary\x20submissions\x20(e.g.,\x20Payment\x20proof)','severity':'info','source':'lint','location':{'path':'/root'},'fix':{'description':'Ensure\x20the\x20quote_guard\x20is\x20verified:\x20user\x20submits\x20Payment\x20via\x20Passport,\x20quote_guard\x20verifies\x20Payment\x20fields,\x20repository\x20data\x20query\x20passes','auto_fixable':![]}});}}if(e?.['host_object']&&f){const o=e['host_object'],p=c['filter'](q=>!q['b_submission']&&q['value_type']==='Address'&&typeof q['value']==='string'&&q['value']['startsWith']('0x')&&q['object_type']===o);if(p['length']>0x0){const q=p['map'](r=>c['indexOf'](r));b['push']({'code':'LE-07','message':'Circular\x20reference\x20uses\x20an\x20address\x20rather\x20than\x20a\x20name\x20(Host\x20Object\x20may\x20not\x20be\x20published\x20yet\x20when\x20the\x20Guard\x20is\x20created)','severity':'error','source':'lint','location':{'path':q['map'](r=>'/table/'+r+'/value')['join']('\x20→\x20')},'fix':{'description':'Change\x20value\x20from\x20an\x20address\x20to\x20an\x20object\x20name\x20(e.g.\x20\x22service1\x22);\x20the\x20SDK\x20will\x20resolve\x20it\x20to\x20an\x20address\x20after\x20the\x20Host\x20Object\x20is\x20published','auto_fixable':![]}});}}return b;}function checkSyntaxHints(a){const b=[],{table:c}=a;(!a['description']||a['description']['trim']()==='')&&b['push']({'code':'SH-01','message':'description\x20is\x20missing\x20or\x20empty','severity':'info','source':'lint','location':{'path':'/description'},'fix':{'description':'Add\x20a\x20description,\x20e.g.\x20\x27Service\x20buy_guard:\x20whitelist\x20validation\x27','auto_fixable':!![]}});for(let d=0x0;d<c['length'];d++){const e=c[d];(!e['name']||e['name']['trim']()==='')&&b['push']({'code':'SH-03','message':'table['+d+']\x20is\x20missing\x20name','severity':'warning','source':'lint','location':{'path':'/table/'+d+'/name'},'fix':{'description':'Add\x20a\x20name,\x20e.g.\x20\x22data\x20entry\x20'+e['identifier']+'\x22','auto_fixable':!![]}});}for(let f=0x0;f<c['length'];f++){const g=c[f];!g['value_type']&&b['push']({'code':'SH-05','message':'table['+f+']\x20is\x20missing\x20value_type','severity':'warning','source':'lint','location':{'path':'/table/'+f+'/value_type'},'fix':{'description':'Infer\x20value_type\x20from\x20value\x20(e.g.\x20Address/String/U64,\x20etc.)','auto_fixable':!![]}});}c['length']>MAX_GUARD_TABLE_ITEM_LENGTH&&b['push']({'code':'SH-07','message':'table\x20entry\x20count\x20'+c['length']+'\x20exceeds\x20the\x20maximum\x20limit\x20'+MAX_GUARD_TABLE_ITEM_LENGTH,'severity':'error','source':'lint','location':{'path':'/table'},'fix':{'description':'Slim\x20down\x20the\x20table\x20by\x20merging\x20similar\x20entries,\x20or\x20split\x20into\x20multiple\x20Guards\x20+\x20rely','auto_fixable':![]}});for(let h=0x0;h<c['length'];h++){c[h]['b_submission']===undefined&&b['push']({'code':'SH-10','message':'table['+h+']\x20b_submission\x20is\x20missing','severity':'info','source':'lint','location':{'path':'/table/'+h+'/b_submission'},'fix':{'description':'Set\x20to\x20false\x20(constant)\x20or\x20true\x20(submitted\x20data)','auto_fixable':!![]}});}for(let j=0x0;j<c['length'];j++){const k=c[j];k['b_submission']===!![]&&k['value']!==undefined&&k['value']!==null&&b['push']({'code':'SH-11','message':'table['+j+']\x20has\x20a\x20redundant\x20value\x20field\x20on\x20b_submission=true\x20entry\x20(the\x20verifier\x20supplies\x20the\x20value\x20at\x20runtime;\x20this\x20value\x20is\x20ignored\x20by\x20BCS\x20encoding\x20and\x20wastes\x20gas)','severity':'warning','source':'lint','location':{'path':'/table/'+j+'/value'},'fix':{'description':'Remove\x20the\x20value\x20field\x20—\x20it\x20is\x20ignored\x20for\x20b_submission=true\x20entries','auto_fixable':!![]}});}return b;}function checkSuggestions(a){const b=[],{root:c,binding_hint:d,table:e}=a;if(c){const g=rootToString(c);if(g['includes']('vec_contains_address')&&g['includes']('Signer'))b['push']({'code':'SG-01','message':'Matches\x20Pattern\x20P04\x20(whitelist\x20validation)','severity':'hint','source':'lint','location':{'path':'/root'},'fix':{'description':'Refer\x20to\x20the\x20P04\x20Pattern\x20to\x20ensure\x20best\x20practices','auto_fixable':![]}});else{if(g['includes']('logic_equal')&&g['includes']('Signer')){const h=e['some'](i=>!i['b_submission']&&i['value_type']==='Address'&&typeof i['value']==='string'&&i['value']['length']>0x0);h&&b['push']({'code':'SG-01','message':'Matches\x20Pattern\x20P04\x20(whitelist\x20validation\x20—\x20single-address\x20variant)','severity':'hint','source':'lint','location':{'path':'/root'},'fix':{'description':'P04\x20single-address\x20form;\x20for\x20multi-address\x20scenarios,\x20consider\x20vec_contains_address','auto_fixable':![]}});}}(g['includes']('logic_as_u256_greater')||g['includes']('logic_as_u256_lesser'))&&b['push']({'code':'SG-01','message':'Matches\x20Pattern\x20P02\x20(numeric\x20threshold\x20validation)','severity':'hint','source':'lint','location':{'path':'/root'},'fix':{'description':'Suitable\x20for\x20amount/quantity\x20threshold\x20validation\x20scenarios','auto_fixable':![]}}),g['includes']('convert_witness')&&b['push']({'code':'SG-01','message':'Matches\x20Pattern\x20P09\x20(witness-derived\x20validation)','severity':'hint','source':'lint','location':{'path':'/root'},'fix':{'description':'Suitable\x20for\x20cross-object\x20relationship\x20validation\x20(e.g.\x20Order→Progress)','auto_fixable':![]}});}if(d?.['action']){const i=['buy','forward','allocate','claim_reward','vote','dispute','write_repository','submit_progress','gen_passport'];if(i['includes'](d['action'])){const j=inferSceneFromAction(d['action']);if(j){const k=suggestTemplateForScene(j['id']);k&&b['push']({'code':'SG-02','message':'Recommended\x20scene\x20template:\x20'+k['name'],'severity':'hint','source':'lint','location':{'path':'/'},'fix':{'description':'Refer\x20to\x20template\x20'+k['id']+'\x20('+k['example_use_case']+')','auto_fixable':![]}});}}}const f=getSubmissionEntries(e);for(const l of f){const m=l['name']??'';if(m['length']<0xa||/^[a-z_]+$/i['test'](m)){const n=e['indexOf'](l);b['push']({'code':'SG-03','message':'table['+n+']\x20submitted\x20data\x20has\x20a\x20vague\x20name\x20description','severity':'info','source':'lint','location':{'path':'/table/'+n+'/name'},'fix':{'description':'Use\x20a\x20full\x20natural-language\x20description\x20(≥10\x20characters),\x20e.g.\x20\x27user-submitted\x20operation\x20type\x20(return/damage)\x27','auto_fixable':![]}});}}if(c){const o=rootToString(c),p=o['includes']('proof.signer'),q=o['includes']('proof.time'),r=o['includes']('calc_string_length'),s=f['some'](t=>t['value_type']==='String');if(p&&q)b['push']({'code':'SG-04','message':'Strict-mode\x20privacy-delivery\x20guard\x20detected\x20(proof.signer\x20+\x20proof.time).\x20'+'Recommended\x20three\x20conditions:\x20Signer==proof.signer\x20(submitter\x20accountability),\x20'+'proof.time>order.time\x20(freshness),\x20order.service==service\x20(project\x20binding).\x20'+'No\x20content\x20verification\x20—\x20only\x20submission\x20responsibility\x20(\x27whoever\x20benefits\x20bears\x20the\x20burden\x20of\x20proof\x27).','severity':'info','source':'lint','location':{'path':'/root'},'fix':{'description':'Ensure\x20all\x20three\x20conditions\x20are\x20present\x20(logic_and).\x20Refer\x20to\x20template\x20tpl_forward_privacy_delivery_proof.\x20'+'Query\x20IDs:\x20proof.signer=1958,\x20proof.time=1960,\x20order.time=1574,\x20order.service=1563.','auto_fixable':![]}});else r&&s&&b['push']({'code':'SG-04','message':'Broad-mode\x20privacy-delivery\x20guard\x20detected\x20(String\x20submission\x20+\x20length\x20check,\x20e.g.\x20Merkle\x20Root\x20length\x20==\x2066).\x20'+'This\x20trusts\x20the\x20submitter\x27s\x20honesty;\x20the\x20counterparty\x20can\x20dispute\x20by\x20checking\x20their\x20own\x20Messenger\x20conversation.\x20'+'Suitable\x20as\x20an\x20arbitration\x20basis,\x20not\x20a\x20fund-flow\x20gate.','severity':'info','source':'lint','location':{'path':'/root'},'fix':{'description':'For\x20stronger\x20assurance,\x20consider\x20strict\x20mode:\x20submit\x20a\x20Proof\x20object\x20address\x20(from\x20messenger.submitChainProof)\x20+\x20'+'Order\x20address,\x20then\x20verify\x20proof.signer/proof.time/order.service.\x20See\x20template\x20tpl_forward_privacy_delivery_proof.','auto_fixable':![]}});}return b;}export function autoFixGuard(a){const b=deepClone(a),c=[];(!b['description']||b['description']['trim']()==='')&&(b['description']='Guard\x20(table:\x20'+b['table']['length']+'\x20items,\x20root:\x20'+(b['root']?.['type']??'unknown')+')',c['push']({'diagnostic_code':'SH-01','description':'Fill\x20in\x20default\x20description','after':b['description'],'path':'/description'}));if(b['description']&&b['description']['length']>MAX_DESCRIPTION_LENGTH){const f=b['description'];b['description']=b['description']['substring'](0x0,MAX_DESCRIPTION_LENGTH),c['push']({'diagnostic_code':'G-001','description':'Truncate\x20description\x20to\x20'+MAX_DESCRIPTION_LENGTH+'\x20characters','before':f['length']+'\x20characters','after':b['description']['length']+'\x20characters','path':'/description'});}for(let g=0x0;g<b['table']['length'];g++){const h=b['table'][g];(!h['name']||h['name']['trim']()==='')&&(h['name']='data\x20entry\x20'+h['identifier'],c['push']({'diagnostic_code':'SH-03','description':'table['+g+']\x20fill\x20in\x20name','after':h['name'],'path':'/table/'+g+'/name'}));}for(let j=0x0;j<b['table']['length'];j++){const k=b['table'][j];if(!k['value_type']&&k['value']!==undefined&&k['value']!==null){const l=inferValueType(k['value']);l&&(k['value_type']=l,c['push']({'diagnostic_code':'SH-05','description':'table['+j+']\x20infer\x20value_type','after':l,'path':'/table/'+j+'/value_type'}));}}const d=new Map();let e=0x0;for(let m=0x0;m<b['table']['length'];m++){const n=b['table'][m];if(!d['has'](n['identifier']))d['set'](n['identifier'],e),n['identifier']!==e&&c['push']({'diagnostic_code':'G-007','description':'table['+m+']\x20identifier\x20'+n['identifier']+'\x20→\x20'+e,'before':String(n['identifier']),'after':String(e),'path':'/table/'+m+'/identifier'}),n['identifier']=e,e++;else{const o=n['identifier'];n['identifier']=e,d['set'](o,e),c['push']({'diagnostic_code':'G-007','description':'table['+m+']\x20identifier\x20'+o+'\x20duplicate\x20→\x20reallocated\x20to\x20'+e,'before':String(o),'after':String(e),'path':'/table/'+m+'/identifier'}),e++;}}for(let p=0x0;p<b['table']['length'];p++){const q=b['table'][p];q['b_submission']===undefined&&(q['b_submission']=![],c['push']({'diagnostic_code':'SH-10','description':'table['+p+']\x20b_submission\x20default\x20set\x20to\x20false','after':'false','path':'/table/'+p+'/b_submission'}));}if(b['rely']?.['guards']&&b['rely']['guards']['length']>0x0){const r=[...new Set(b['rely']['guards'])];r['length']!==b['rely']['guards']['length']&&(c['push']({'diagnostic_code':'G-009','description':'rely\x20deduplicate:\x20'+b['rely']['guards']['length']+'\x20→\x20'+r['length'],'before':JSON['stringify'](b['rely']['guards']),'after':JSON['stringify'](r),'path':'/rely/guards'}),b['rely']['guards']=r);}for(let s=0x0;s<b['table']['length'];s++){const t=b['table'][s];if(t['b_submission']===!![]&&t['value']!==undefined&&t['value']!==null){const u=JSON['stringify'](t['value']);delete t['value'],c['push']({'diagnostic_code':'SH-11','description':'table['+s+']\x20remove\x20redundant\x20value\x20on\x20b_submission=true\x20entry','before':u,'after':'(removed)','path':'/table/'+s+'/value'});}}return{'fixed':b,'actions':c};}export async function lintGuard(a,b){const c=b?.['auto_fix']??!![],{table:d,root:e,rely:f,binding_hint:g}=a,h=[];let i;const j=await checkSdkSyntax(a);h['push'](...j);const k=checkSemanticErrors(a);h['push'](...k);const l=checkSyntaxHints(a);h['push'](...l);let m,n=[];if(c){const {fixed:v,actions:w}=autoFixGuard(a);w['length']>0x0&&(m=v,n=w);}if(d['length']>0x0&&e){const x=g?findScene(g['host_object']??'',g['binding_field']??''):undefined,y=d['map'](A=>({'identifier':A['identifier'],'b_submission':A['b_submission']??![],'value_type':A['value_type']??'Address','value':A['value'],'name':A['name'],'object_type':A['object_type']})),z=evaluateGuardDraft({'table':y,'root':e,'rely':f,'scene':x,'sharing_recipients':g?.['sharing_recipients']});i=z['assessment'];for(const A of i['risks']){const B=A['level']==='critical'||A['level']==='high'?'error':A['level']==='medium'?'warning':A['level']==='low'?'info':'hint',C=A['evidence']??'',D=C['startsWith']('/')?C:'/';h['push']({'code':A['id'],'message':'['+A['level']+']\x20'+A['title'],'severity':B,'source':'risk','location':{'path':D},'fix':{'description':A['mitigation'],'auto_fixable':![]}});}}const o=checkSuggestions(a);h['push'](...o);const p=h['filter'](E=>E['severity']==='error')['length'],q=h['filter'](E=>E['severity']==='warning')['length'],s=h['filter'](E=>E['severity']==='info'||E['severity']==='hint')['length'],t=p===0x0;let u;if(p>0x0)u='Fix\x20'+p+'\x20error(s)\x20and\x20re-run\x20lint';else q>0x0?u='Consider\x20addressing\x20'+q+'\x20warning(s),\x20then\x20submit\x20to\x20SDK\x20newGuard()\x20for\x20final\x20syntax\x20validation':u='lint\x20passed\x20(no\x20errors);\x20submit\x20to\x20SDK\x20newGuard()\x20for\x20final\x20syntax\x20validation\x20before\x20going\x20on-chain';return{'json_summary':{'table_count':d['length'],'root_type':e?.['type']??'unknown','has_rely':!!f?.['guards']?.['length'],'rely_count':f?.['guards']?.['length']??0x0,'has_description':!!a['description']},'diagnostics':h,'fixed_json':m,'fix_actions':n,'risk_assessment':i,'summary':{'errors':p,'warnings':q,'infos':s,'auto_fixes_applied':n['length'],'ready':t,'next_step':u}};}export async function isGuardReady(a){const b=await lintGuard(a,{'auto_fix':![]});return b['summary']['ready'];}export async function getGuardErrors(a){const b=await lintGuard(a,{'auto_fix':![]});return b['diagnostics']['filter'](c=>c['severity']==='error');}export function formatLintResult(a){const b=[];b['push']('===\x20Guard\x20JSON\x20Lint\x20Report\x20==='),b['push'](''),b['push']('Summary:'),b['push']('\x20\x20Errors:\x20\x20\x20\x20\x20'+a['summary']['errors']),b['push']('\x20\x20Warnings:\x20\x20\x20'+a['summary']['warnings']),b['push']('\x20\x20Infos:\x20\x20\x20\x20\x20\x20'+a['summary']['infos']),b['push']('\x20\x20Auto-fixes:\x20'+a['summary']['auto_fixes_applied']),b['push']('\x20\x20Ready:\x20\x20\x20\x20\x20\x20'+(a['summary']['ready']?'YES':'NO')),b['push']('\x20\x20Next\x20step:\x20\x20'+a['summary']['next_step']),b['push']('');if(a['fix_actions']['length']>0x0){b['push']('---\x20Auto-fix\x20Actions\x20---');for(const g of a['fix_actions']){b['push']('\x20\x20['+g['diagnostic_code']+']\x20'+g['description']),b['push']('\x20\x20\x20\x20Path:\x20'+g['path']),g['before']&&g['after']&&b['push']('\x20\x20\x20\x20'+g['before']+'\x20->\x20'+g['after']);}b['push']('');}const c=a['diagnostics']['filter'](h=>h['severity']==='error'),e=a['diagnostics']['filter'](h=>h['severity']==='warning'),f=a['diagnostics']['filter'](h=>h['severity']==='info'||h['severity']==='hint');if(c['length']>0x0){b['push']('---\x20Errors\x20(must\x20fix)\x20---');for(const h of c){b['push']('\x20\x20['+h['code']+']\x20('+h['source']+')\x20'+h['message']),b['push']('\x20\x20\x20\x20Path:\x20'+h['location']['path']);if(h['fix'])b['push']('\x20\x20\x20\x20Fix:\x20\x20'+h['fix']['description']);}b['push']('');}if(e['length']>0x0){b['push']('---\x20Warnings\x20(consider\x20fixing)\x20---');for(const i of e){b['push']('\x20\x20['+i['code']+']\x20('+i['source']+')\x20'+i['message']),b['push']('\x20\x20\x20\x20Path:\x20'+i['location']['path']);if(i['fix'])b['push']('\x20\x20\x20\x20Fix:\x20\x20'+i['fix']['description']);}b['push']('');}if(f['length']>0x0){b['push']('---\x20Info\x20&\x20Hints\x20---');for(const j of f){b['push']('\x20\x20['+j['code']+']\x20('+j['source']+')\x20'+j['message']),b['push']('\x20\x20\x20\x20Path:\x20'+j['location']['path']);}}return b['join']('\x0a');}
|