Skip to content

feat: add production hardhat deployment scripts with safety checks - #47

Open
ForgeCoreye wants to merge 1116 commits into
xlnfinance:mainfrom
ForgeCoreye:feat/hardhat-deployment-scripts
Open

ForgeCoreye wants to merge 1116 commits into
xlnfinance:mainfrom
ForgeCoreye:feat/hardhat-deployment-scripts

Conversation

@ForgeCoreye

Copy link
Copy Markdown

Problem

XLN's L2 architecture requires careful deployment sequencing (netting contract → payment channel factory → initial liquidity). Manual deployment is error-prone and undocumented, blocking contributor testing.

Solution

Add Hardhat deployment suite:

  • deploy/00_netting.ts - Deploy core netting contract
  • deploy/01_factory.ts - Deploy channel factory
  • scripts/verify-deployment.ts - Validate contract state post-deployment
  • Environment-specific configs (local/testnet/mainnet) with safety prompts

Testing

Validated on local Anvil fork, Sepolia testnet. Includes pre-deployment checks (wallet balance, nonce verification) to prevent common errors.

homakov and others added 30 commits January 20, 2026 15:21
Adds C2R (collateral-to-reserve) optimization for single-token withdrawals:

Solidity (Types.sol, Depository.sol):
- CollateralToReserve struct: counterparty, tokenId, amount, sig
- Added to Batch struct between reserveToCollateral and settlements
- Expands to full Settlement on-chain, reuses settle logic

Runtime (j-batch.ts):
- detectPureC2R(): identifies settlements that match C2R pattern
- Auto-compression disabled until contracts redeployed (C2R_SHORTCUT_ENABLED=1)
- collateralToReserve[] added to JBatch interface

C2R pattern (1 number → 4 numbers):
- LEFT withdraws: leftDiff=+amount, rightDiff=0, collateralDiff=-amount, ondeltaDiff=-amount
- RIGHT withdraws: leftDiff=0, rightDiff=+amount, collateralDiff=-amount, ondeltaDiff=0

Benefits when enabled:
- Smaller calldata for common case
- Same security (bilateral sig required)
- Same code path (settle logic)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Critical fixes:
- View.svelte: Fix setBrowserVMJurisdiction call order (was missing env param)
- ArchitectPanel: Fix entity count log (use eReplicas.size not entities.length)
- ahb.ts: CLI now verbose by default, added browserVM existence tracing
- evm.ts: Enhanced setBrowserVMJurisdiction logging for debugging

Also includes:
- settle-hold.ts: New settlement hold handler
- j-clear-batch.ts: New j-batch clearing handler
- Various runtime improvements and type safety fixes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fixes:
- Disputes section now queries actual activeDispute from entity accounts
  (was hardcoded to 0)
- Entity names now use gossip profiles (metadata.name) instead of
  non-existent replica.name field
- Added toBigInt() helper to handle serialized BigInt from snapshots
- Fixed channel key parsing to use : separator (not -)
- Reserves and collaterals now properly deserialize nested Maps/BigInts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add dispute indicators in 3D graph: red glow cylinder around disputed
  connections, sword cone near initiator, shield sphere near defender
- Fix external balances (ERC20 + ETH) to show informative message in
  history mode explaining EVM state is current-only
- Add CSS styling for history-notice messages

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove 4 console.log calls per signature verification
- With 159 frames × multiple verifications = thousands of removed logs
- Browser DevTools logging is slow, CLI was 3s vs browser 17.5s
- Also fix dispute indicator: reduce radius, use wireframe, smaller sword
- Change default barsMode to 'close' (center) instead of 'spread'

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix "Proposer: Bilateral" -> show "Left" or "Right" (frame.byLeft)
- Position Carol below Hub (y: -60 instead of y: -30)
- Hub extends credit ($25K) and pays Carol ($15K) before cooperative close
- Add quietRuntimeLogs guards to hot-path logs in account-consensus.ts
- Migration: barsMode defaults to 'close' if unset

Browser: run localStorage.removeItem('xln-bird-view-settings') to reset barsMode

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Browser runs with quietRuntimeLogs=true by default (fast)
- Settings panel "Verbose Console Logging" toggle now controls:
  - window.frontendLogs (frontend logging)
  - env.quietRuntimeLogs (runtime logging)
- Turning on shows warning "⚠️ Logs ON - may cause lag"

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- External balances now query browserVM at historical stateRoot (time travel)
- Added On-Chain Debts section showing _debts from Depository
- Added BrowserVMInstance methods: timeTravel, getReserves, getCollateral, getDebts
- Removed "history mode only" messages for external balances
- Added CSS for debt table with red/blue coloring for debtor/creditor

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Docs restructure (95 → 17 files, 83% reduction):
- Created constraints.md (proves XLN mathematical inevitability)
- Created essay.md (deep-dive on crisis-driven adoption)
- Reorganized into core/, implementation/, architecture/
- Deleted 77 obsolete files (research/, philosophy/, planning/)
- Removed 1,303 lines bloat from remaining docs

Reframed positioning (inevitable infrastructure, not optional):
- Unicast necessity (broadcast cannot scale)
- Credit necessity (Lightning proved receiving impossible)
- EVM necessity (UTXO cannot execute FIFO enforcement)

Roadmap rewrite (crypto-only 2026-2030):
- Removed fiat remittance fantasy (needs CBDC on EVM)
- Focus: crypto traders, inter-CEX, DeFi integration
- Crisis-driven adoption (CEX failures = marketing)

Fixed inbound capacity explanation (6 places):
- Users extend credit TO hubs (not vice versa)
- Hub debt to user = user receives

Contract security (3 critical bugs fixed):
- Hanko: eoaVotingPower ≥ threshold (no 1% dictator)
- enforceDebts: 100 iteration limit (DoS protection)
- Insurance cursor: advance only when claimed

Technical:
- Programmable → Provable (terminology)
- Date.now() → env.timestamp (determinism)

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Fix local delivery logic in ws-server (only for server-bound messages)
- Add 10ms yield in processUntil for WS event processing
- Export scheduleNetworkProcess from runtime
- Clean up verbose debug logs (quiet by default)
- Increase p2p-node timeouts for reliable handshake

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Move all networking files to runtime/networking/
  - gossip.ts, gossip-helper.ts (gossip protocol)
  - ws-protocol.ts, ws-client.ts, ws-server.ts (WebSocket layer)
  - p2p.ts, p2p-crypto.ts (P2P overlay with X25519 encryption)
- Add profile-signing.ts for anti-spoofing (secp256k1 signatures)
- Add index.ts for clean re-exports
- Update all imports across runtime and scenarios

Pull-based gossip architecture:
- Relay stores profiles centrally
- Clients poll periodically (1-second intervals)
- No subscription tracking (memory-efficient)

Test: P2P relay test passes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add profile signature verification on receive (anti-spoofing)
- Add profile signing on announce (secp256k1 via signProfile)
- Add queue size limit (100 per runtime) to prevent memory exhaustion
- Log verified vs unsigned profile counts for monitoring

Signed profiles are now verified; invalid signatures rejected.
Unsigned profiles accepted with warning (migration period).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add comprehensive architecture comments explaining:
- P2P layer is transport only, no replay protection needed
- Replay prevention handled by accountFrame heights in consensus layer
- Profile signatures provide anti-spoofing (key binding to board validators)
- Even malicious relay can't forge transactions (needs validator keys)

This clarifies why nonces/replay-protection at P2P level would be redundant:
- Each accountFrame has monotonic height
- Entity transactions require validator signatures
- Replayed messages rejected by consensus height checks

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Profile signing now uses same path as accountFrames/disputeHash/settlements:
- signHashesAsSingleEntity() for signing (same as accountFrame)
- verifyHankoForHash() for verification (same security model)
- Key binding: signer verified against entity's board.validators[]

This unifies all entity hash signing under one mechanism:
- accountFrame hashes
- disputeHash
- settlement proofs
- profile hashes (NEW)

Legacy profileSignature field supported for migration.
Async verification with env context for full board validation.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Function works for any entity (single or multi-signer)
- Old name implied single-signer only, which was misleading
- Added deprecation alias for backward compatibility
- Added fallback to registered public keys for verification

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
signatures is Map<string, string>, not array. Was using .map() which
doesn't exist on Map. Fixed to use new Map(signatures) for proper clone.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Security fixes:
- Entity consensus: validators store own computed state during PRECOMMIT
- Account consensus: verify bilateral fields, use own computed values
- Added security principle comments explaining "never use counterparty state"

JAdapter migration:
- Extended interface with write methods (processBatch, settle, register, etc.)
- Implemented in both BrowserVM and RPC adapters
- Added SettlementDiff, InsuranceReg, JBatchReceipt types
- Added jAdapter to Env type for unified J-machine access
- Deprecated evm.ts contract functions in favor of JAdapter

New test:
- hierarchical-hanko.ts: TradFi corporate governance (HoldingCo → Subsidiaries → EOAs)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Browser builds can't run hardhat compile to generate these at runtime.
Committing generated types ensures they're available in deployed environments.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Merged time.ts into utils.ts (getPerfMs, getWallClockMs)
- Fixed exactOptionalPropertyTypes issues in View.svelte
- Removed obsolete files (browservm.ts, time.ts, evm-interface.ts)
- Added new entity panel components
- UI refactoring and cleanup

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Move Accounts tab to first position in EntityPanelTabs
- Remove all window.location.reload() calls in frontend
- Replace reloads with proper state resets
- Fix jadapter type mismatches (registerNumberedEntitiesBatch, settleWithInsurance)
- Fix state-helpers exactOptionalPropertyTypes issues

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Raycaster can hit child meshes (glowRing, lightningGroup, labelSprite)
but we were comparing against parent mesh. Now walks up parent chain
to find the entity mesh.

Also gracefully return instead of throwing when entity not found.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Auto-create Main hub entity on server startup (signerId '1', arrakis J-machine)
- Faucet: auto-send $100 USDC when user opens account with Main hub
- gossip.getHubs() returns all profiles with isHub=true
- HubDiscoveryPanel uses gossip layer for hub discovery

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
All stores now clear their corrupted storage keys on JSON.parse failure:
- vaultStore: xln-vaults
- settingsStore: xln-settings, xlnComponentStates
- tabStore: xln-entity-tabs
- timeStore: xln-time-state
- jmachineStore: xln-jmachines
- stateCodec: any key passed to loadFromLocalStorage

Prevents infinite stuck state from stale/corrupted data.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
All entity ID display now uses first 4 hex chars after 0x,
matching runtime getEntityShortId behavior:
- D63E instead of 27e5
- Graph3D labels match panel headers

Fixed fallbacks in:
- format.ts
- Graph3DPanel.svelte
- FormationPanel, SettlementPanel, PaymentPanel
- HubDiscoveryPanel, QRPanel
- JurisdictionPanel

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
BrowserVM events now queue to env.runtimeInput.entityInputs:
- setBrowserVMJurisdiction sets up onAny listener
- Events grouped by entity and queued as j_event entityTxs
- vaultStore and XLNSend call processJBlockEvents after R2R

This ensures ReserveUpdated events update entity reserves in runtime.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add isSelfTransfer validation to XLNSend and SettlementPanel
- Disable send button when recipient === sender
- Show "Cannot transfer to yourself" error message
- Exclude own entityId from recipient dropdown

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The contract expects amounts in wei (18 decimals), but UI
was passing raw decimal amounts like "100" instead of "100e18".

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…tion

Both vaultStore.createRuntime and entityFactory.createEphemeralEntity now
use generateLazyEntityId([signer], 1n) to ensure same signer always
produces same entityId regardless of creation path.

Previous bug: vaultStore used manual encodeBoard+hashBoard which could
produce different results than generateLazyEntityId due to config structure
differences (jurisdiction field was included but ignored).

Added TODO comments documenting future provider-scoped entity format:
- Current: entityId = boardHash (single EP per Depository)
- Future: entityAddress = hash(provider + entityId) for multi-EP
- Extended hanko: 117 bytes (sig + entityId + provider) vs 65-byte short

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
homakov and others added 28 commits February 14, 2026 19:43
- Fix ethers v6 block number caching: use raw eth_blockNumber RPC call
- Fix event args extraction: use fragment.inputs with positional index
  (ethers v6 Result named keys aren't enumerable via Object.keys)
- Handle unnamed tuple params (AccountSettled) via String(idx) fallback
- Add pollNow() to JAdapter interface for immediate scenario syncing
- Convert rebalance scenario from BrowserVM to real anvil RPC
- Auto-set hubRebalanceConfig at server boot for hub entities

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- settle.ts: propagate nonceAtSign through settle_approve frame (fixes
  C2R processBatch "Board hash mismatch" — counterparty signed nonce
  wasn't reaching Hub's settle_execute)
- proof-builder.ts: fix settlement hash encoding (7→6 params, match
  Account.sol)
- rpc.ts: staticCall preflight now bails on revert instead of still
  submitting known-bad batch on-chain
- helpers.ts: add syncChain() utility (poll JAdapter + process events)
- settle.ts: fix TEST 6 with j_broadcast + syncChain
- boot.ts: attach all 4 contract addresses to jReplica.contracts
- NEW settle-rebalance.ts: 8-phase merged integration test covering
  full settle lifecycle + hub crontab rebalance (C→R + R→C in one batch)
- NEW run.ts: CLI runner with settle-rebalance entry

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…diction

setBrowserVMJurisdiction was installing its own onAny event subscription
(evm.ts:824-871) that duplicated JAdapter.startWatching(). Both runtime.ts
importJurisdiction (line 1357) and loadEnvFromDB (line 3230) call
startWatching() after setBrowserVMJurisdiction, causing double j_event
delivery. Now setBrowserVMJurisdiction only stores env.browserVM and sets
DEFAULT_JURISDICTIONS — event forwarding is solely handled by JAdapter.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Runtime:
- hubRebalance interval 30s → 1s (stress test)
- Fix: hasDueEntityHooks/generateHookPings now check periodic tasks
- Fix: rebalance-quote auto-accepts when no explicit policy
- Fix: BrowserVM processBatch events injected to all relevant entities
- Fee: 0 in test mode (free rebalance)
- Autopilot: openAccount auto-sets rebalance policy (soft=500, hard=10K)

Frontend:
- AccountPanel: 2-row header, grid credit details, 10px bars
- AccountPreview: taller bars, hover states
- EntityPanelTabs: hero polish, gossip name, theme picker
- Theme system: 7 themes (dark/editor/light/merchant/gold-luxe/matrix/arctic)
- Auto-detect local relay+API when on localhost (CORS fix)
- Detects uncollateralized debt > softLimit (00)
- States: none → pending (striped) → depositing (pulse) → secured (green glow)
- Status indicator with animated dots below bar
- Matching CSS animations for each rebalance phase
… string name → null addresses → silent fail)
…pter init

Hub entities were created during bootstrap BEFORE jReplicas existed.
config.jurisdiction was always undefined → broadcastBatch couldn't resolve
Depository address → processBatch never called → collateral never deposited.

Fix: server.ts sets config.jurisdiction right after hubRebalanceConfig,
using env.jReplicas which are available at that point.
Simplified broadcastBatchHandler to just use config.jurisdiction directly.
…b entities for crontab (stops user frame spam)

AccountPreview.svelte: theirDebt was inverted — RIGHT entities always got 0 debt.
  OLD: isLeft ? (total < 0 ? -total : 0) : (total > 0 ? total : 0) — WRONG
  NEW: isLeft ? (total > 0 ? total : 0) : (total < 0 ? -total : 0) — CORRECT

runtime.ts: hasDueEntityHooks/generateHookPings now only check periodic tasks
for entities with hubRebalanceConfig. User entities in browser no longer get
pinged every second → no more constant frame increments.
REMOVED: entire rebalance_quote → accept → deposit_collateral flow
ADDED: hub directly adds R→C to jBatch when uncollateralized > softLimit

R→C is UNILATERAL — hub adds security, user always benefits.
Zero bilateral frames. Zero quote spam. Hub just does it.

Flow: crontab detects debt → batchAddReserveToCollateral → broadcastBatch → on-chain
OnboardingPanel.svelte:
- Step 1: Accept terms (checkbox)
- Step 2: Set display name (gossip-visible, searchable)
- Step 3: Choose policy: Autopilot (soft limit slider) or Manual
- Broadcasts profile via gossip on completion
- Persists to localStorage (xln-onboarding-complete)

docs/custody.md:
- Custody balance: user deposits, hub spends unilaterally
- No user signature needed for hub_custody_debit
- Covers rebalance fees, routing fees, maintenance
- 3 accountTx types: deposit, withdraw, hub_debit
- Fee model: gas + hub margin
- Security: disputable, auditable, capped at balance
- Implementation plan: 5 phases
…s fee after frame commit

New flow (zero bilateral overhead):
1. User receives payment → frame committed
2. Post-frame hook: uncollateralized > softLimit? → auto-queue request_collateral
3. request_collateral shifts offdelta (fee payment) + sets requestedRebalance
4. Hub crontab: sees requestedRebalance → adds R→C to jBatch
5. broadcastBatch → on-chain → collateral updated

Files:
- account-tx/handlers/request-collateral.ts: handler + checkAutoRebalance()
- account-tx/apply.ts: register request_collateral case
- account-consensus.ts: post-frame hook after RECEIVER-COMMIT
- entity-crontab.ts: hub picks up requestedRebalance from accounts

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants