AgentSkillsCN

rigor

验证web3组件中的数据正确性

SKILL.md
--- frontmatter
name: rigor
description: Validate data correctness in web3 components
user-invocable: true
disable-model-invocation: true
allowed-tools:
  - Read
  - Glob

Rigor

Validate data correctness in web3 components.

Usage

code
/rigor file.tsx          # Validate specific file
/rigor                   # Validate current context

Philosophy

Correctness over feel. A beautiful button that sends the wrong amount is worse than an ugly one that's accurate.

On-chain over indexed. When money is involved, trust the blockchain, not the indexer.

What Rigor Checks

1. BigInt Safety

JavaScript BigInt has a critical footgun: 0n is falsy.

javascript
if (0n) console.log('true')   // Never prints!

Safe Pattern:

tsx
if (amount != null && amount > 0n) { ... }

Anti-Pattern:

tsx
if (shares) { ... }  // BROKEN: 0n is valid but falsy

2. Data Sources

Use CaseSourceWhy
Display (read-only)IndexedFaster UX
Transaction amountsOn-chainMust be accurate
Button enabled stateOn-chainPrevents failed tx

Safe Pattern:

tsx
const { data: txShares } = useReadContract({...})  // On-chain
const canWithdraw = (txShares ?? 0n) > 0n

Anti-Pattern:

tsx
const canWithdraw = envioData?.hasBalance  // Stale!

3. Receipt Guards

Prevent re-execution when receipt updates trigger effects.

Safe Pattern:

tsx
const lastHashRef = useRef<string>()

useEffect(() => {
  if (!receipt) return
  if (receipt.transactionHash === lastHashRef.current) return
  lastHashRef.current = receipt.transactionHash
  onReceipt(receipt)
}, [receipt, onReceipt])

Anti-Pattern:

tsx
useEffect(() => {
  if (receipt) handleSuccess(receipt)  // May trigger multiple times
}, [receipt])

4. Stale Closures

useEffect callbacks capture state at creation time.

Safe Pattern:

tsx
const amountRef = useRef(currentAmount)
amountRef.current = currentAmount

useEffect(() => {
  if (receipt) processReceipt(amountRef.current)
}, [receipt])

Report Format

markdown
## Rigor Validation

### VaultWithdraw.tsx

CRITICAL: Transaction amount from indexed data (line 45)
  → Amount should come from useReadContract, not useEnvioQuery
  → Fix: Replace `envioData.shares` with on-chain read

HIGH: BigInt falsy check (line 67)
  → `if (shares)` fails when shares === 0n
  → Fix: `if (shares != null && shares > 0n)`

### Summary
- 1 file checked
- 2 findings (1 CRITICAL, 1 HIGH)

Severity Levels

SeverityExampleAction
CRITICALTransaction from indexed dataBlock
HIGHBigInt falsy checkRequire fix
MEDIUMStale closure riskWarn
LOWMissing type annotationNote

Rules Loaded

  • .claude/constructs/packs/rune/rules/rigor/*.md
  • .claude/rules/rigor/*.md (local overrides)