opnet-development
npx skills add https://github.com/btc-vision/opnet-skills --skill opnet-development
Agent 安装分布
Skill 文档
OPNet Development Skill
A comprehensive skill for building on OPNet – Bitcoin’s L1 consensus layer for trustless smart contracts.
STOP – MANDATORY READING BEFORE ANY CODE
IF YOU WRITE CODE WITHOUT READING THE REQUIRED DOCS, YOU WILL CREATE BROKEN, EXPLOITABLE CODE.
CRITICAL RULES FOR AI AGENTS
ABSOLUTE RULE – NO RAW JAVASCRIPT
NEVER write raw JavaScript. ALWAYS use:
- Frontend: TypeScript + Vite + npm packages
- Backend: TypeScript + Node.js + npm packages
- NO EXCEPTIONS. NOT EVEN FOR “QUICK EXAMPLES”.
DO NOT:
- Read a few files and then say “I have enough context”
- Read random skills or guidelines not listed for your project type
- Start writing code after skimming 2-3 files
- Assume you know OPNet patterns from other frameworks
- Skip files because they “seem similar” to ones you read
- Create zip files or deliverables WITHOUT running
npm run lintandnpm run typecheck - Say “run npm run lint to verify” instead of ACTUALLY running it
YOU MUST:
- Read EVERY SINGLE FILE listed for your project type below
- Read them IN ORDER – later files depend on earlier ones
- Read the COMPLETE FILE, not just the first few sections
- ONLY read files listed in this skill – no random exploration
- Confirm you read all files before writing ANY code
- ACTUALLY RUN
npm install,npm run lint,npm run typecheck,npm run build - FIX ALL ERRORS before creating any deliverable (zip, PR, etc.)
WHY THIS MATTERS
OPNet development has:
- Beta package versions that change frequently – guessing versions = build failures
- Strict TypeScript rules – violations = security vulnerabilities
- Platform-specific patterns – wrong patterns = exploits, gas attacks, data loss
Guidelines are SUMMARIES. The docs/ folder contains the ACTUAL implementation patterns.
Reading 3-4 files is NOT enough. You MUST read ALL files for your project type.
MANDATORY READING ORDER BY PROJECT TYPE
For ALL Projects (Read First, Every Time)
| Order | File | Why |
|---|---|---|
| 1 | docs/core-typescript-law-CompleteLaw.md |
THE LAW – Type system rules, forbidden constructs, required patterns |
| 2 | guidelines/setup-guidelines.md |
Package versions, tsconfig, ESLint configs |
For Smart Contracts (AssemblyScript)
Read ALL of these BEFORE writing contract code:
| Order | File | Contains |
|---|---|---|
| 1 | docs/core-typescript-law-CompleteLaw.md |
Type rules (applies to AS too) |
| 2 | guidelines/setup-guidelines.md |
Package versions, asconfig.json |
| 3 | guidelines/contracts-guidelines.md |
Summary of contract patterns |
| 4 | docs/contracts-btc-runtime-README.md |
Runtime overview |
| 5 | docs/contracts-btc-runtime-getting-started-installation.md |
Setup |
| 6 | docs/contracts-btc-runtime-getting-started-first-contract.md |
Entry point, factory pattern |
| 7 | docs/contracts-btc-runtime-getting-started-project-structure.md |
Directory layout |
| 8 | docs/contracts-btc-runtime-core-concepts-storage-system.md |
Storage types, pointers |
| 9 | docs/contracts-btc-runtime-core-concepts-pointers.md |
Pointer allocation |
| 10 | docs/contracts-btc-runtime-api-reference-safe-math.md |
SafeMath (MANDATORY for u256) |
| 11 | docs/contracts-btc-runtime-gas-optimization.md |
Gas patterns, forbidden loops |
| 12 | docs/contracts-btc-runtime-core-concepts-security.md |
Security checklist |
For OP20 tokens, also read:
docs/contracts-btc-runtime-api-reference-op20.mddocs/contracts-btc-runtime-contracts-op20-token.md
For OP721 NFTs, also read:
docs/contracts-btc-runtime-api-reference-op721.mddocs/contracts-btc-runtime-contracts-op721-nft.md
For Frontend (React/Vite)
Read ALL of these BEFORE writing frontend code:
| Order | File | Contains |
|---|---|---|
| 1 | docs/core-typescript-law-CompleteLaw.md |
Type rules, forbidden constructs |
| 2 | guidelines/setup-guidelines.md |
Package versions, vite config |
| 3 | guidelines/frontend-guidelines.md |
Summary of frontend patterns |
| 4 | docs/core-opnet-README.md |
Client library overview |
| 5 | docs/core-opnet-getting-started-installation.md |
Installation |
| 6 | docs/core-opnet-getting-started-quick-start.md |
Quick start |
| 7 | docs/core-opnet-providers-json-rpc-provider.md |
Provider setup |
| 8 | docs/core-opnet-providers-internal-caching.md |
Caching (MANDATORY) |
| 9 | docs/core-opnet-contracts-instantiating-contracts.md |
Contract instances |
| 10 | docs/core-opnet-contracts-simulating-calls.md |
Read operations |
| 11 | docs/core-opnet-contracts-sending-transactions.md |
Write operations |
| 12 | docs/core-opnet-contracts-transaction-configuration.md |
Transaction options |
| 13 | docs/core-transaction-transaction-factory-interfaces.md |
Advanced TX params (fees, notes, anchors) |
| 14 | docs/clients-walletconnect-README.md |
Wallet connection |
| 13 | docs/frontend-motoswap-ui-README.md |
THE STANDARD – Reference implementation |
For Backend/API (Node.js)
Read ALL of these BEFORE writing backend code:
| Order | File | Contains |
|---|---|---|
| 1 | docs/core-typescript-law-CompleteLaw.md |
Type rules, forbidden constructs |
| 2 | guidelines/setup-guidelines.md |
Package versions |
| 3 | guidelines/backend-guidelines.md |
Summary of backend patterns |
| 4 | docs/core-opnet-backend-api.md |
REQUIRED FRAMEWORKS – hyper-express, uWebSockets.js |
| 5 | docs/core-opnet-providers-json-rpc-provider.md |
Provider setup |
| 6 | docs/core-opnet-providers-threaded-http.md |
Threading (MANDATORY) |
| 7 | docs/core-opnet-providers-internal-caching.md |
Caching (MANDATORY) |
| 8 | docs/core-opnet-contracts-instantiating-contracts.md |
Contract instances |
| 9 | docs/core-opnet-contracts-sending-transactions.md |
Sending transactions |
| 10 | docs/core-transaction-transaction-factory-interfaces.md |
Advanced TX params (fees, notes, anchors) |
FORBIDDEN FRAMEWORKS: Express, Fastify, Koa, Hapi, Socket.io – use hyper-express and uWebSockets.js only.
For Plugins (OPNet Node)
Read ALL of these BEFORE writing plugin code:
| Order | File | Contains |
|---|---|---|
| 1 | docs/core-typescript-law-CompleteLaw.md |
Type rules, forbidden constructs |
| 2 | guidelines/setup-guidelines.md |
Package versions |
| 3 | guidelines/plugin-guidelines.md |
Summary of plugin patterns |
| 4 | docs/core-OIP-OIP-0003.md |
PLUGIN SPECIFICATION – Full spec |
| 5 | docs/plugins-plugin-sdk-README.md |
SDK reference |
| 6 | docs/plugins-opnet-node-README.md |
Node integration |
CRITICAL: You MUST implement onReorg() to handle chain reorganizations or your data will be inconsistent.
For Unit Tests (TypeScript)
Read ALL of these BEFORE writing test code:
| Order | File | Contains |
|---|---|---|
| 1 | docs/core-typescript-law-CompleteLaw.md |
Type rules |
| 2 | guidelines/setup-guidelines.md |
Package versions |
| 3 | guidelines/unit-testing-guidelines.md |
Summary of test patterns |
| 4 | docs/testing-unit-test-framework-README.md |
Framework overview |
| 5 | docs/testing-opnet-unit-test-README.md |
Test setup |
| 6 | docs/testing-opnet-unit-test-docs-Blockchain.md |
Blockchain mocking |
| 7 | docs/testing-opnet-unit-test-docs-ContractRuntime.md |
Contract runtime |
CRITICAL: Unit tests are TypeScript (NOT AssemblyScript). They have a SEPARATE package.json.
For Generic Questions (Architecture, Concepts, Best Practices)
Read: guidelines/generic-questions-guidelines.md
For questions like:
- “How does OPNet work?”
- “Can OPNet survive 51% attacks?”
- “How does airdrop work on OPNet?”
- “What’s the difference between OPNet and Runes/Ordinals?”
- “Why can’t contracts hold BTC?”
- “What is transaction pinning?”
See the full guideline for complete topic mappings and what docs to read for each question type.
IMPORTANT: For conceptual questions, read the relevant docs/sections BEFORE answering. Do not guess or make assumptions about how OPNet works.
For Security Auditing
STOP – MANDATORY READING BEFORE ANY AUDIT
IF YOU AUDIT CODE WITHOUT READING THE REQUIRED DOCS, YOU WILL MISS CRITICAL VULNERABILITIES.
OPNet audits require understanding:
- AssemblyScript runtime internals – serialization, storage, cache coherence
- Bitcoin-specific attack vectors – transaction pinning, malleability, reorgs
- Critical vulnerability patterns – that standard audits miss completely
You MUST read guidelines/audit-guidelines.md COMPLETELY before auditing ANY code.
Skipping the audit guidelines = missing vulnerabilities. There are no shortcuts.
DISCLAIMER (MANDATORY IN EVERY REPORT)
IMPORTANT DISCLAIMER: This audit is AI-assisted and may contain errors,
false positives, or miss critical vulnerabilities. This is NOT a substitute
for a professional security audit by experienced human auditors.
Do NOT deploy to production based solely on this review.
Always engage professional auditors for contracts handling real value.
Mandatory Reading Order for Audits
Read ALL of these IN ORDER before starting ANY audit:
| Order | File | Why Required |
|---|---|---|
| 1 | docs/core-typescript-law-CompleteLaw.md |
Type rules that define secure code |
| 2 | guidelines/audit-guidelines.md |
COMPLETE AUDIT GUIDE – vulnerability patterns, checklists, detection methods |
Then read based on code type:
| Code Type | Additional Required Reading |
|---|---|
| Smart Contracts | docs/contracts-btc-runtime-core-concepts-security.md, docs/contracts-btc-runtime-gas-optimization.md, docs/contracts-btc-runtime-api-reference-safe-math.md, docs/contracts-btc-runtime-types-bytes-writer-reader.md |
| DEX/Swap Code | This SKILL.md – CSV, NativeSwap, Slashing sections |
| Frontend | guidelines/frontend-guidelines.md |
| Backend | guidelines/backend-guidelines.md |
| Plugins | guidelines/plugin-guidelines.md – Reorg Handling section |
AUDIT VERIFICATION CHECKPOINT
BEFORE writing ANY audit findings, confirm:
- I have read
guidelines/audit-guidelines.mdcompletely - I have read
docs/core-typescript-law-CompleteLaw.mdcompletely - I have read ALL additional docs for this code type
- I understand the Critical Runtime Vulnerability Patterns section
- I understand serialization/deserialization consistency requirements
- I understand storage system cache coherence issues
- I understand Bitcoin-specific attack vectors (CSV, pinning, reorgs)
If you cannot check ALL boxes, GO BACK AND READ THE DOCS.
Smart Contract Audit Checklist (Summary)
See guidelines/audit-guidelines.md for COMPLETE checklists with detection patterns.
| Category | Check For |
|---|---|
| Arithmetic | All u256 operations use SafeMath (no raw +, -, *, /) |
| Overflow/Underflow | SafeMath.add(), SafeMath.sub(), SafeMath.mul(), SafeMath.div() |
| Access Control | onlyOwner checks, authorization on sensitive methods |
| Reentrancy | State changes BEFORE external calls (checks-effects-interactions) |
| Gas/Loops | No while loops, all for loops bounded, no unbounded iterations |
| Storage | No iterating all map keys, stored aggregates for totals |
| Input Validation | All user inputs validated, bounds checked |
| Integer Handling | u256 created via fromString() for large values, not arithmetic |
| Serialization | Write/read type consistency, sizeof() mapping correct |
| Cache Coherence | Setters load from storage before comparison |
| Deletion Markers | Storage deletion uses 32-byte EMPTY_BUFFER |
| Bounds Checking | >= not > for max index checks |
TypeScript/Frontend/Backend Audit Checklist (Summary)
| Category | Check For |
|---|---|
| Type Safety | No any, no non-null assertions (the ! operator), no @ts-ignore |
| Null Safety | Explicit null checks, optional chaining used correctly |
| BigInt | All satoshi/token amounts use bigint, not number |
| No Floats | No floating point for financial calculations |
| Caching | Provider/contract instances cached, not recreated |
| Input Validation | Address validation, amount validation, bounds checking |
| Error Handling | Errors caught and handled, no silent failures |
| Provider Type | Use JSONRpcProvider (WebSocketProvider is experimental) |
Bitcoin-Specific Audit Checklist (Summary)
| Category | Check For |
|---|---|
| CSV Timelocks | All swap recipient addresses use CSV (anti-pinning) |
| UTXO Handling | Proper UTXO selection, dust outputs avoided |
| Transaction Malleability | Signatures not assumed immutable before confirmation |
| Fee Sniping | Proper locktime handling |
| Reorg Handling | Data deleted/reverted for reorged blocks |
| P2WPKH | Only compressed pubkeys (33 bytes), reject uncompressed |
| Witness Script Size | Validate against 3,600 byte standard limit |
DEX/Swap Audit Checklist (Summary)
| Category | Check For |
|---|---|
| Reservation System | Prices locked at reservation, not execution |
| Slippage Protection | Maximum slippage enforced |
| Front-Running | Reservation system prevents front-running |
| Queue Manipulation | Slashing penalties for queue abuse |
| Partial Fills | Atomic coordination of multi-provider payments |
Critical Runtime Vulnerability Patterns (Summary)
See guidelines/audit-guidelines.md for COMPLETE patterns with code examples.
| ID | Vulnerability | Impact |
|---|---|---|
| C-07 | Serialization Mismatch (write u16, read u32) | Data corruption |
| C-08 | sizeof() bytes treated as bits | Truncated data |
| C-09 | Signed/unsigned type confusion (i8 â u8) | Sign loss |
| C-10 | Cache coherence (setter compares to unloaded cache) | Silent state corruption |
| C-11 | Wrong deletion marker size | has() returns wrong result |
| C-12 | Generic integer truncation (only reading first byte) | Data loss |
| H-06 | Index out of bounds | Memory corruption |
| H-07 | Off-by-one (> instead of >=) |
Buffer overflow |
| H-08 | Pointer collision (truncate without hash) | Storage overwrites |
| M-05 | Taylor series divergence | Incorrect math |
ALWAYS end audit reports with the disclaimer. NEVER claim the audit is complete or guarantees security.
VERIFICATION CHECKPOINT
BEFORE writing ANY code, you MUST be able to answer:
-
What project type am I building? (Contract / Frontend / Backend / Plugin / Tests)
-
Did I read EVERY file listed for this project type?
- List each file you read
- If you cannot list them all, GO BACK AND READ
-
What are the exact package versions? (from
guidelines/setup-guidelines.md)- If you don’t know, GO BACK AND READ
-
What constructs are FORBIDDEN?
any, non-null assertion operator,whileloops in contracts,numberfor satoshis, etc.- If you can’t list them, GO BACK AND READ
-
What patterns are REQUIRED?
- Caching, SafeMath, threading, etc.
- If you can’t list them, GO BACK AND READ
STOP – DO NOT PROCEED IF:
- â You read fewer than 5 docs files
- â You skipped any file in the mandatory reading list
- â You read files not listed for your project type
- â You cannot list the exact package versions
- â You’re about to write “I have enough context” after reading 2-3 files
GO BACK AND READ ALL THE REQUIRED FILES. NO SHORTCUTS.
CODE VERIFICATION ORDER (MANDATORY)
You MUST actually RUN these commands, not just mention them.
Step 1: Install Dependencies
npm install
- Run this FIRST before any other commands
- If package.json was created or modified, this is REQUIRED
- Do NOT skip this step
Step 2: Run Prettier
npm run format
- Formats all code consistently
- Run BEFORE linting to avoid formatting conflicts
- Do NOT skip this step
Step 3: Run ESLint
npm run lint
- MUST pass with zero errors
- If errors exist, FIX THEM before proceeding
- Do NOT say “you should run lint” – actually RUN IT
Step 4: Run TypeScript Check
npm run typecheck
- Or
npx tsc --noEmitif no script exists - MUST pass with zero errors
- Fix all type errors before proceeding
Step 5: Build
npm run build
- Only run AFTER format, lint, and typecheck pass
- For contracts: verify .wasm file is generated
Step 6: Run Tests
npm run test
- Or
npx ts-node --esm tests/*.test.tsfor unit tests - All tests MUST pass
- If tests fail, FIX THE CODE
STOP – YOU MUST ACTUALLY RUN THESE COMMANDS
- â Do NOT just write “run npm run lint to verify”
- â Do NOT skip steps because “it should work”
- â Do NOT consider code complete without running ALL steps
- â Actually execute each command
- â Verify each command passes
- â Fix any errors before proceeding to next step
If you wrote code but didn’t run these commands, YOUR TASK IS NOT COMPLETE.
TASK COMPLETION CHECKPOINT
BEFORE considering ANY task complete, ask yourself these questions:
-
Have I performed all the steps required by the task?
- Did I address everything the user asked for?
- Did I miss any requirements?
-
Did I actually run the verification commands?
- Did I run
npm install? (REQUIRED if package.json exists/changed) - Did I run
npm run format? (REQUIRED – Prettier formatting) - Did I run
npm run lint? (REQUIRED – must pass with zero errors) - Did I run
npm run typecheckornpx tsc --noEmit? (REQUIRED) - Did I run
npm run build? (REQUIRED for deployable code) - Did I run
npm run test? (REQUIRED if tests exist) - If ANY command failed, did I fix the errors?
- “I should run lint” is NOT the same as actually running it
- Did I run
-
Did I review and reconsider my work?
- Re-read what I produced – is it correct?
- Did I make any assumptions that could be wrong?
- Are there edge cases I didn’t consider?
- Could my code/answer introduce bugs or vulnerabilities?
- For smart contracts: SafeMath, bounds checking, access control, serialization
- For TypeScript: type safety, null handling, caching patterns
- For answers: Is the information accurate? Did I verify it?
-
Did I write complete, production-ready code?
- NEVER add comments like “in a production environment, you would…”
- NEVER add stubs, placeholders, or TODO comments
- NEVER write partial implementations with “add your logic here”
- If you can’t implement something fully, explain why and ask the user
- All code must be ready to use immediately, not a starting point
-
Is it appropriate to adjust non-code files?
- Did I update documentation if behavior changed?
- Did I update config files if dependencies changed?
-
Should new tests be written?
- If I added new functionality, are there tests for it?
- Do the tests cover security patterns from the guidelines?
-
Is this just exploration/research?
- If yes, tests, linting, and auditing are not required
- Focus on providing accurate information
This self-reflection prevents incomplete work, missed requirements, and security vulnerabilities.
PROJECT DELIVERY
STOP – BEFORE CREATING ANY ZIP OR DELIVERABLE
You MUST run and PASS all verification commands BEFORE packaging:
# 1. Install dependencies
npm install
# 2. Format code
npm run format
# 3. Lint (MUST PASS)
npm run lint
# 4. TypeScript check (MUST PASS)
npm run typecheck
# OR: npx tsc --noEmit
# 5. Build (MUST SUCCEED)
npm run build
# 6. Tests (MUST PASS)
npm run test
If ANY command fails, DO NOT create the zip. Fix the errors first.
â FORBIDDEN: Creating zip without running verification commands â FORBIDDEN: Saying “run npm run lint to verify” instead of actually running it â FORBIDDEN: Skipping typecheck because “it should work”
When creating zip files for delivery:
NEVER include:
node_modules/– recipient runsnpm installbuild/ordist/– recipient runsnpm run build.git/– repository history.env– contains secrets
Correct zip command (only AFTER all checks pass):
zip -r project.zip . -x "node_modules/*" -x "build/*" -x "dist/*" -x ".git/*" -x "*.wasm" -x ".env"
What is OPNet
OPNet is a Bitcoin L1 consensus layer enabling smart contracts directly on Bitcoin. It is:
- NOT a metaprotocol – It’s a full consensus layer
- Fully trustless – No centralized components
- Permissionless – Anyone can participate
- Decentralized – Relies on Bitcoin PoW + OPNet epoch SHA1 mining
Security Model
After 20 blocks, an epoch is buried deep enough that changing it requires rewriting Bitcoin history at millions of dollars per hour, making OPNet state more final than Bitcoin’s 6-confirmation security.
The checksum root for each epoch is a cryptographic fingerprint of the entire state. If even one bit differs, the checksum changes completely and proof fails, making silent state corruption impossible.
Key Principles
- Contracts are WebAssembly (AssemblyScript) – Deterministic execution
- NON-CUSTODIAL – Contracts NEVER hold BTC
- Verify-don’t-custody – Contracts verify L1 tx outputs, not hold funds
- Partial reverts – Only consensus layer execution reverts; Bitcoin transfers are ALWAYS valid
- No gas token – Uses Bitcoin directly
- CSV timelocks are MANDATORY – All addresses receiving BTC in swaps MUST use CSV (CheckSequenceVerify) to prevent transaction pinning attacks
Why OPNet Requires Consensus (Not Just Indexing)
OPNet is fundamentally different from indexer-based protocols like Runes, Ordinals/BRC-20, or Alkanes:
| Protocol | State Consistency | Can Different Nodes Disagree? |
|---|---|---|
| Runes | Indexer-dependent | Yes – no consensus mechanism |
| BRC-20 | Indexer-dependent | Yes – no consensus mechanism |
| Alkanes | Indexer-dependent | Yes – WASM is deterministic but no consensus |
| OPNet | Cryptographic consensus | No – proof-of-work + attestations enforce agreement |
Why this matters: For applications requiring binding state consistency (like DEXs, escrows, or any multi-party coordination), indexer disagreement is catastrophic. When NativeSwap locks a reservation at a specific price, EVERY node must agree that reservation exists. OPNet’s consensus layer guarantees this through cryptographic proofs.
CSV: The Critical Anti-Pinning Mechanism (MANDATORY)
What is Transaction Pinning?
Transaction pinning is a catastrophic attack vector that most Bitcoin protocols ignore. Here’s how it works:
- When you send Bitcoin to someone, they can immediately create a transaction spending that Bitcoin, even before the first transaction is confirmed
- An attacker creates massive chains of unconfirmed transactions, all dependent on each other
- This makes it impossible for miners to include your legitimate transaction in a block
- Your transaction is stuck in mempool limbo while the attacker manipulates contract state
Why Pinning Destroys DEXs Without Protection
Attack scenario on an unprotected DEX:
- Attacker pins your swap transaction, preventing confirmation
- Your reservation expires, but your BTC is stuck in mempool
- Attacker cancels their sell orders or manipulates pool state
- When your transaction finally confirms (if ever), no tokens remain
- Result: Attacker gets free money, you lose everything
This vulnerability exists in every Bitcoin protocol that doesn’t mandate CSV:
- Multisig bridges can be frozen entirely with one malicious unwrap request
- Ordinals marketplaces are vulnerable
- Runes trading platforms are vulnerable
- BRC-20 exchanges are vulnerable
The CSV Solution
CSV (CheckSequenceVerify, BIP 112) completely eliminates pinning attacks:
Without CSV: Maximum unconfirmed chain length = UNLIMITED (attackers can pin forever)
With CSV: Maximum unconfirmed chain length = ZERO (must wait for confirmation)
By requiring all seller addresses to have a 1-block CSV timelock, once Bitcoin arrives at those addresses, it cannot be spent again for at least one block. This is mathematically provable and completely closes the attack vector.
Implementation Requirement
ALL addresses receiving BTC in OPNet swaps MUST use CSV timelocks.
This is enforced at the protocol level in NativeSwap. If you’re building any application that coordinates BTC transfers with smart contract state, you MUST implement CSV protection.
The Two Address Systems (CRITICAL for Airdrops)
Why OPNet Airdrops Work Differently Than Ethereum
On Ethereum, there’s one address format. You can loop through addresses and call transfer(to, amount) because ERC20 contracts just decrement sender balance and increment recipient balance using the same address type.
On OPNet, contract balances are keyed by ML-DSA public key hashes (32-byte quantum-resistant addresses), but users are typically known externally by their Bitcoin addresses (Taproot P2TR, tweaked public keys). These are completely different cryptographic systems with no inherent link between them.
| Address System | Format | Used For |
|---|---|---|
| Bitcoin Address | Taproot P2TR (bc1p...) |
External identity, what you have in your airdrop list |
| OPNet Address | ML-DSA public key hash (32 bytes) | Contract balances, internal state |
WHY YOU CANNOT JUST LOOP AND TRANSFER
If you have a list of Bitcoin addresses from token holders or snapshot participants:
// WRONG - THIS DOES NOT WORK
for (const btcAddress of airdropList) {
await token.transfer(btcAddress, amount); // IMPOSSIBLE
}
The contract literally cannot credit tokens to a Bitcoin address directly. The contract storage uses ML-DSA addresses, not Bitcoin addresses. The mapping between them only exists once a user explicitly proves ownership of both keys together.
THE CORRECT SOLUTION: Claim-Based Airdrop Contract
Airdrops on OPNet are done via a smart contract with a claim pattern:
1. Deploy an airdrop contract that stores allocations keyed by tweaked public key:
// Contract storage
mapping(tweakedPubKey => amount) // Store: which Bitcoin addresses get how much
mapping(tweakedPubKey => claimed) // Track: has this allocation been claimed
2. Users call claim() providing a signature that proves they control that Bitcoin address:
// User's frontend (browser) - OP_WALLET signs automatically
const message = `Claim airdrop for ${contractAddress}`;
const signed = await MessageSigner.tweakAndSignMessageAuto(message);
// Submit to contract with signature in calldata
await airdropContract.claim(signature, messageHash);
3. Contract verifies and transfers:
// Contract logic
public claim(calldata: Calldata): BytesWriter {
const signature = calldata.readBytes(64);
const messageHash = calldata.readBytes(32);
// Verify signature proves caller owns the tweaked public key
if (!Blockchain.verifySignature(Blockchain.tx.origin, signature, messageHash, false)) {
throw new Revert('Invalid signature');
}
// Get allocation for this tweaked public key
const tweakedKey = Blockchain.tx.origin.tweakedPublicKey;
const amount = this.allocations.get(tweakedKey);
// Transfer to caller's ML-DSA address (now linked!)
this._mint(Blockchain.tx.sender, amount);
this.claimed.set(tweakedKey, true);
}
This is the “unlock transaction” – the moment where the user proves ownership of both identities (Bitcoin address AND ML-DSA address), allowing the contract to link them and credit the tokens.
The Banana Locker Analogy
- You know 300 monkeys by their face (Bitcoin address)
- Lockers open with a secret handshake (ML-DSA key)
- You label lockers with faces and put bananas inside
- When a monkey shows up, they show face AND do handshake
- System learns: “this face = this handshake” and gives them their banana
- The banana was always “theirs” but they couldn’t access it until they linked face to handshake
NativeSwap: How to Build a Real DEX on Bitcoin
NativeSwap answers the biggest unanswered question in BitcoinFi: How do you build an actual AMM that trades native BTC for tokens, trustlessly, without custody?
The Fundamental Problem
Traditional AMMs (like Uniswap) hold both assets in a pool and use math to set prices. Bitcoin cannot do this – you literally cannot have a smart contract hold and programmatically transfer BTC.
Why common “solutions” fail:
- Multisig wallets: Trusted parties can collude or disappear
- Wrapped BTC: Bridges become honeypots (billions stolen from bridges)
- Pure order books: Terrible liquidity without market makers holding inventory
Virtual Reserves: The Solution
NativeSwap realizes that an AMM doesn’t need to physically hold assets – it just needs to track the economic effect of trades. This is similar to:
- Banks updating ledger entries without moving physical cash
- Futures markets trading billions in commodities without touching a barrel of oil
- Clearinghouses settling trillions without holding underlying assets
How it works:
- The contract maintains two numbers:
bitcoinReserveandtokenReserve - When someone buys tokens with BTC, the system records that bitcoin reserve increased and token reserve decreased
- The actual BTC goes directly to sellers, not to the contract
- AMM pricing only depends on the ratio between reserves
- The constant product formula (
bitcoinReserve à tokenReserve = k) works identically whether reserves are physical or virtual
Two-Phase Commit: Why Reservations Are Necessary
Problem: OPNet can revert smart contract execution, but it cannot reverse Bitcoin transfers. Once you send BTC, that transfer is governed by Bitcoin’s consensus rules, not OPNet’s.
Catastrophic scenario without reservations:
- You see token price is 0.01 BTC/token
- You create a transaction sending 1 BTC to buy 100 tokens
- During 10-20 minute confirmation time, other trades push price to 0.02 BTC/token
- On Ethereum, your transaction would revert and return your ETH
- On Bitcoin, your BTC transfer already happened – the contract can’t send it back
- You lose your BTC and get zero tokens
The reservation system (two-phase commit):
| Phase | What Happens |
|---|---|
| Phase 1: Reserve | Prove you control BTC (UTXOs as inputs, sent back to yourself), pay small fee, price is locked in consensus state |
| Phase 2: Execute | Send exact BTC amount to providers (up to 200 addresses atomically), guaranteed execution at locked price |
Benefits:
- No slippage risk: Price locked at reservation time
- No front-running: Once price is locked in OPNet state, no one can change it
- Partial fills: Automatically coordinate payments to up to 200 providers in single atomic transaction (impossible on any other Bitcoin protocol)
Queue Impact: Accounting for Pending Sells
Sellers queue tokens at the prevailing AMM price. The Queue Impact mechanism adjusts effective token reserve using logarithmic scaling:
Why logarithmic?
- Markets process information multiplicatively
- Doubling queue from 100â200 tokens has same psychological impact as 1000â2000
- First sellers signal strong selling pressure; additional sellers have diminishing marginal impact
- Matches empirical observations from market microstructure research
Slashing: Making Queue Manipulation Economically Irrational
Without penalties, Queue Impact would be worthless:
- Attacker adds massive fake sell orders â crashes price via Queue Impact
- Attacker buys cheap tokens
- Attacker cancels their sells
- Profit from manipulation
The slashing mechanism:
- Immediate cancellation: 50% penalty (exceeds any realistic manipulation profit)
- Extended squatting: Escalates to 90% penalty
- Slashed tokens return to pool: Attempted attacks actually improve liquidity
This makes manipulation economically irrational and ensures queue depth is a reliable market signal.
Summary: Why Each Component Is Necessary
| Component | Constraint It Addresses |
|---|---|
| Virtual reserves | Smart contracts can’t custody BTC on Bitcoin |
| Reservations (two-phase commit) | OPNet controls contract state, not Bitcoin transfers |
| Queue Impact | Pending orders affect market psychology and pricing |
| Slashing | Queue Impact would be manipulable without penalties |
| CSV timelocks | UTXO chains are vulnerable to transaction pinning |
| OPNet consensus | Indexers can’t provide binding state consistency |
Remove any component and the system either becomes exploitable or stops functioning as an AMM.
ENFORCEMENT RULES (NON-NEGOTIABLE)
Before Writing ANY Code
YOU MUST:
- READ
docs/core-typescript-law-CompleteLaw.mdCOMPLETELY – These are strict TypeScript rules - VERIFY project configuration matches standards in
docs/config files
Configuration Files (in docs/)
| File | Purpose |
|---|---|
eslint-contract.json |
ESLint for AssemblyScript contracts |
eslint-generic.json |
ESLint for TypeScript libraries |
eslint-react.json |
ESLint for React/Next.js frontends |
tsconfig-generic.json |
TypeScript config (NOT for contracts) |
asconfig.json |
AssemblyScript compiler config |
TypeScript is MANDATORY – NO EXCEPTIONS
STOP – ABSOLUTE RULE
YOU MUST NEVER, EVER WRITE RAW JAVASCRIPT CODE. NO EXCEPTIONS.
All code MUST be TypeScript with proper tooling:
| Project Type | Required Stack |
|---|---|
| Frontend | TypeScript + Vite + npm libraries |
| Backend | TypeScript + Node.js + npm libraries |
| Contracts | AssemblyScript (TypeScript-like) |
| Tests | TypeScript |
FORBIDDEN – NEVER DO THESE:
- â Raw JavaScript files – NEVER write
.jssource files - â Inline
<script>tags – NEVER embed JS in HTML - â Browser-only JS – NEVER write code that only runs in browser console
- â No build system – NEVER skip Vite/bundler for frontend
- â
// @ts-checkin JS – This is NOT TypeScript, use real.tsfiles - â
allowJs: true– NEVER enable this in tsconfig - â CDN script imports – Use npm packages instead
REQUIRED – ALWAYS DO THESE:
- â
All source files must be
.tsor.tsx - â Use Vite for all frontend applications
- â Use Node.js + TypeScript for all backend applications
- â Install dependencies via npm (not CDN links)
- â Strict mode enabled in tsconfig
- â All types explicitly defined
- â Proper project structure with package.json, tsconfig.json, etc.
If User Asks for “Quick Script” or “Simple Example”
STILL USE TYPESCRIPT. Create a proper project structure:
# Even for "quick" examples
mkdir project && cd project
npm init -y
npm install typescript tsx
# Write .ts file, run with npx tsx script.ts
There is NO scenario where raw JavaScript is acceptable.
Full Project Setup is MANDATORY
Before writing ANY code, the project MUST have:
project/
âââ package.json # With correct OPNet package versions
âââ tsconfig.json # Matching docs/tsconfig-generic.json
âââ eslint.config.js # Using appropriate config from docs/
âââ .prettierrc # Prettier configuration
âââ .prettierignore # Prettier ignore file
âââ src/ # Source code directory
â âââ index.ts # Entry point
âââ tests/ # Test directory (if applicable)
âââ *.test.ts
Prettier Configuration (MANDATORY)
.prettierrc:
{
"semi": true,
"singleQuote": true,
"tabWidth": 4,
"trailingComma": "all",
"printWidth": 100,
"bracketSpacing": true,
"arrowParens": "always"
}
.prettierignore:
node_modules/
build/
dist/
*.wasm
coverage/
Package.json scripts (add these):
{
"scripts": {
"format": "prettier --write \"src/**/*.{ts,tsx}\"",
"format:check": "prettier --check \"src/**/*.{ts,tsx}\""
}
}
Run Prettier before committing:
npm run format
For Frontend (React/Vite), also include:
âââ vite.config.ts # Vite configuration
âââ index.html # Entry HTML
âââ src/
âââ App.tsx
âââ main.tsx
âââ styles/ # CSS files (NO inline CSS)
âââ variables.css
For Contracts (AssemblyScript), also include:
âââ asconfig.json # AssemblyScript config
âââ assembly/
âââ index.ts # Contract entry point
âââ contracts/
âââ MyContract.ts
You MUST create these files BEFORE writing application code.
Configuration Verification Checklist
-
package.jsonexists with correct OPNet package versions -
tsconfig.jsonmatchesdocs/tsconfig-generic.json(or strict ESNext for contracts) -
eslint.config.jsuses appropriate config fromdocs/ -
.prettierrcexists with correct configuration - NO
anytype anywhere – This is FORBIDDEN - NO inline CSS – Use CSS modules, Tailwind, or external stylesheets
- NO JavaScript files – TypeScript only
- Code is formatted with Prettier (
npm run format) - ESNext compliant
- Unit tests exist and pass
IF ANY CHECK FAILS â REFUSE TO CODE UNTIL FIXED
Misconfigured projects lead to exploits and critical vulnerabilities.
TypeScript Law (CRITICAL)
From docs/core-typescript-law-CompleteLaw.md:
FORBIDDEN Constructs
| Construct | Why Forbidden |
|---|---|
any |
Runtime bug waiting to happen. No exceptions. |
unknown |
Only at system boundaries (JSON parsing, external APIs) |
object (lowercase) |
Use specific interfaces or Record<string, T> |
Function (uppercase) |
Use specific signatures |
{} |
Means “any non-nullish value”. Use Record<string, never> |
| Non-null assertion (the ! operator) | Use explicit null checks or optional chaining |
| Dead/duplicate code | Design is broken if present |
| ESLint bypasses | Never |
| Section separator comments | See below |
| Inline CSS | Use CSS modules, styled-components, or external stylesheets. No style={{ }} props. |
FORBIDDEN: Section Separator Comments
NEVER write comments like:
// ==================== PRIVATE METHODS ====================
// ---------------------- HELPERS ----------------------
// ************* CONSTANTS *************
// ####### INITIALIZATION #######
These are lazy, unprofessional, and useless. They add noise without value.
INSTEAD: Use proper TSDoc for EVERY class, method, property, and function:
/**
* Transfers tokens from sender to recipient.
*
* @param to - The recipient address
* @param amount - The amount to transfer in base units
* @returns True if transfer succeeded
* @throws {InsufficientBalanceError} If sender has insufficient balance
* @throws {InvalidAddressError} If recipient address is invalid
*
* @example
* ```typescript
* const success = await token.transfer(recipientAddress, 1000n);
* ```
*/
public async transfer(to: Address, amount: bigint): Promise<boolean> {
// ...
}
TSDoc Requirements:
@paramfor every parameter@returnsfor non-void returns@throwsfor possible exceptions@examplefor non-trivial methods- Description of what the method does, not how
Code organization comes from proper class design, not ASCII art.
Numeric Types
number: Array lengths, loop counters, small flags, ports, pixelsbigint: Satoshi amounts, block heights, timestamps, database IDs, file sizes, cumulative totals- Floats for financial values: FORBIDDEN – Use fixed-point
bigintwith explicit scale
Common API Pitfalls
Address.fromString() requires TWO parameters:
// WRONG - will fail
const addr = Address.fromString(addressString);
// CORRECT - always provide both params
const addr = Address.fromString(mldsaPublicKey, tweakedPublicKey);
The first parameter is the ML-DSA public key (quantum-resistant), the second is the tweaked public key (legacy Bitcoin). Always provide both.
Required tsconfig.json Settings
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"exactOptionalPropertyTypes": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"moduleResolution": "bundler",
"module": "ESNext",
"target": "ESNext",
"lib": ["ESNext"],
"isolatedModules": true,
"verbatimModuleSyntax": true
}
}
Performance Rules
THREADING IS MANDATORY
- Sequential processing = unacceptable performance
- Use Worker threads for CPU-bound work
- Use async with proper concurrency for I/O
- Batch operations where possible
- Use connection pooling
Caching (ALWAYS)
- Reuse contract instances – Never create new instances for same contract
- Reuse providers – Single provider instance per network
- Cache locally – Browser localStorage/IndexedDB for user data
- Cache on API – Server-side caching for blockchain state
- Invalidate on block change – Clear stale data when new block confirmed
RPC Call Optimization
Use .metadata() instead of multiple calls:
// â BAD - 4 RPC calls (slow)
const [name, symbol, decimals, totalSupply] = await Promise.all([
contract.name(),
contract.symbol(),
contract.decimals(),
contract.totalSupply()
]);
// â
GOOD - 1 RPC call (fast)
const { name, symbol, decimals, totalSupply } = (await contract.metadata()).decoded;
.metadata() returns name, symbol, decimals, totalSupply, owner, and more in ONE call.
Backend/API Frameworks
MANDATORY: Use OPNet’s high-performance libraries:
| Package | Purpose |
|---|---|
@btc-vision/uwebsocket.js |
WebSocket server (fastest) |
@btc-vision/hyper-express |
HTTP server (fastest) |
FORBIDDEN: Express, Fastify, Koa, Hapi, or any other HTTP framework. They are significantly slower.
// CORRECT - Use hyper-express with threading
import HyperExpress from '@btc-vision/hyper-express';
import { Worker } from 'worker_threads';
const app = new HyperExpress.Server();
// Use classes, not functions
// Delegate CPU work to workers
Contract Gas Optimization (CRITICAL)
FORBIDDEN Patterns in Contracts
| Pattern | Why Forbidden | Alternative |
|---|---|---|
while loops |
Unbounded gas consumption | Use bounded for loops |
| Infinite loops | Contract halts, wastes gas | Always have exit condition |
| Iterating all map keys | O(n) grows exponentially | Use indexed lookups, pagination |
| Iterating all array elements | O(n) cost explosion | Store aggregates, use pagination |
| Unbounded arrays | Grows forever | Cap size, use cleanup |
Gas-Efficient Patterns
// WRONG - Iterating all holders (O(n) disaster)
let total: u256 = u256.Zero;
for (let i = 0; i < holders.length; i++) {
total = SafeMath.add(total, balances.get(holders[i]));
}
// CORRECT - Store running total
const totalSupply: StoredU256 = new StoredU256(TOTAL_SUPPLY_POINTER);
// Update on mint/burn, read in O(1)
Security Audit Checklist
All Code Must Be Checked For:
Cryptographic
- Key generation entropy
- Nonce reuse
- Signature malleability
- Timing attacks
- Replay attacks
Smart Contract
- Reentrancy
- Integer overflow/underflow
- Access control bypass
- Authorization flaws
- State manipulation
- Race conditions
Bitcoin-specific
- Transaction malleability
- UTXO selection vulnerabilities
- Fee sniping
- Dust attacks
- Transaction pinning attacks – MUST use CSV timelocks
- Unconfirmed transaction chains – Verify CSV enforcement
DEX/Swap-specific
- Front-running / MEV attacks
- Price manipulation via queue flooding
- Reservation expiry edge cases
- Partial fill coordination
- Slashing mechanism bypass attempts
Quick Start
| Task | Template |
|---|---|
| New OP20 token | templates/contracts/OP20Token.ts |
| New OP721 NFT | templates/contracts/OP721NFT.ts |
| Generic contract | templates/contracts/MyContract.ts |
| Contract tests | templates/tests/ |
| Frontend dApp | templates/frontend/ |
| Node plugin (indexer) | templates/plugins/OP20Indexer.ts |
| Node plugin (generic) | templates/plugins/MyPlugin.ts |
Complete File Index
Configuration Files (docs/)
| File | Description |
|---|---|
docs/asconfig.json |
AssemblyScript compiler config |
docs/eslint-contract.json |
ESLint for AssemblyScript contracts |
docs/eslint-generic.json |
ESLint for TypeScript libraries |
docs/eslint-react.json |
ESLint for React frontends |
docs/tsconfig-generic.json |
TypeScript config (not contracts) |
docs/setup-README.md |
Setup instructions |
TypeScript Law
| File | Description |
|---|---|
docs/core-typescript-law-readme.md |
Overview |
docs/core-typescript-law-CompleteLaw.md |
COMPLETE RULES – READ FIRST |
OPNet Client Library
| File | Description |
|---|---|
docs/core-opnet-README.md |
Library overview |
docs/core-opnet-backend-api.md |
Backend API with hyper-express |
docs/core-opnet-getting-started-installation.md |
Installation |
docs/core-opnet-getting-started-overview.md |
Architecture overview |
docs/core-opnet-getting-started-quick-start.md |
Quick start guide |
docs/core-opnet-providers-json-rpc-provider.md |
JSON-RPC provider |
docs/core-opnet-providers-websocket-provider.md |
WebSocket provider |
docs/core-opnet-providers-understanding-providers.md |
Provider concepts |
docs/core-opnet-providers-advanced-configuration.md |
Advanced config |
docs/core-opnet-providers-internal-caching.md |
Caching system |
docs/core-opnet-providers-threaded-http.md |
Threading |
docs/core-opnet-contracts-overview.md |
Contract interaction overview |
docs/core-opnet-contracts-instantiating-contracts.md |
Creating contract instances |
docs/core-opnet-contracts-simulating-calls.md |
Simulating calls |
docs/core-opnet-contracts-sending-transactions.md |
Sending transactions |
docs/core-opnet-contracts-gas-estimation.md |
Gas estimation |
docs/core-opnet-contracts-offline-signing.md |
Offline signing |
docs/core-opnet-contracts-transaction-configuration.md |
TX config |
docs/core-opnet-contracts-contract-code.md |
Contract code retrieval |
docs/core-opnet-abi-reference-abi-overview.md |
ABI overview |
docs/core-opnet-abi-reference-data-types.md |
ABI data types |
docs/core-opnet-abi-reference-op20-abi.md |
OP20 ABI |
docs/core-opnet-abi-reference-op20s-abi.md |
OP20S ABI (signatures) |
docs/core-opnet-abi-reference-op721-abi.md |
OP721 ABI |
docs/core-opnet-abi-reference-motoswap-abis.md |
MotoSwap ABIs |
docs/core-opnet-abi-reference-factory-abis.md |
Factory ABIs |
docs/core-opnet-abi-reference-stablecoin-abis.md |
Stablecoin ABIs |
docs/core-opnet-abi-reference-custom-abis.md |
Custom ABI creation |
docs/core-opnet-api-reference-provider-api.md |
Provider API |
docs/core-opnet-api-reference-contract-api.md |
Contract API |
docs/core-opnet-api-reference-epoch-api.md |
Epoch API |
docs/core-opnet-api-reference-utxo-manager-api.md |
UTXO Manager API |
docs/core-opnet-api-reference-types-interfaces.md |
Types & interfaces |
docs/core-opnet-bitcoin-utxos.md |
UTXO handling |
docs/core-opnet-bitcoin-utxo-optimization.md |
UTXO optimization |
docs/core-opnet-bitcoin-balances.md |
Balance queries |
docs/core-opnet-bitcoin-sending-bitcoin.md |
Sending BTC |
docs/core-opnet-blocks-block-operations.md |
Block operations |
docs/core-opnet-blocks-block-witnesses.md |
Block witnesses |
docs/core-opnet-blocks-gas-parameters.md |
Gas parameters |
docs/core-opnet-blocks-reorg-detection.md |
Reorg detection |
docs/core-opnet-epochs-overview.md |
Epochs overview |
docs/core-opnet-epochs-epoch-operations.md |
Epoch operations |
docs/core-opnet-epochs-mining-template.md |
Mining template |
docs/core-opnet-epochs-submitting-epochs.md |
Submitting epochs |
docs/core-opnet-transactions-broadcasting.md |
Broadcasting TXs |
docs/core-opnet-transactions-fetching-transactions.md |
Fetching TXs |
docs/core-opnet-transactions-transaction-receipts.md |
TX receipts |
docs/core-opnet-transactions-challenges.md |
TX challenges |
docs/core-opnet-storage-storage-operations.md |
Storage operations |
docs/core-opnet-public-keys-public-key-operations.md |
Public key ops |
docs/core-opnet-utils-bitcoin-utils.md |
Bitcoin utilities |
docs/core-opnet-utils-binary-serialization.md |
Binary serialization |
docs/core-opnet-utils-revert-decoder.md |
Revert decoder |
docs/core-opnet-examples-op20-examples.md |
OP20 examples |
docs/core-opnet-examples-op721-examples.md |
OP721 examples |
docs/core-opnet-examples-deployment-examples.md |
Deployment examples |
docs/core-opnet-examples-advanced-swaps.md |
Swap examples |
Transaction Library
| File | Description |
|---|---|
docs/core-transaction-README.md |
Library overview |
docs/core-transaction-transaction-building.md |
Building transactions |
docs/core-transaction-transaction-factory-interfaces.md |
TransactionFactory interfaces (fees, notes, anchors, send-max) |
docs/core-transaction-offline-transaction-signing.md |
Offline signing |
docs/core-transaction-addresses-P2OP.md |
P2OP address format |
docs/core-transaction-quantum-support-README.md |
Quantum overview |
docs/core-transaction-quantum-support-01-introduction.md |
Quantum intro |
docs/core-transaction-quantum-support-02-mnemonic-and-wallet.md |
Quantum wallet |
docs/core-transaction-quantum-support-03-address-generation.md |
Quantum addresses |
docs/core-transaction-quantum-support-04-message-signing.md |
Quantum signing |
docs/core-transaction-quantum-support-05-address-verification.md |
Quantum verification |
Address Systems & Airdrops (CRITICAL)
| File | Description |
|---|---|
docs/core-opnet-address-systems-airdrop-pattern.md |
Two address systems, airdrop pattern (MUST READ) |
OIP Specifications
| File | Description |
|---|---|
docs/core-OIP-README.md |
OIP overview |
docs/core-OIP-OIP-0001.md |
OIP process |
docs/core-OIP-OIP-0002.md |
Contract standards |
docs/core-OIP-OIP-0003.md |
Plugin system spec |
docs/core-OIP-OIP-0004.md |
Epoch system |
docs/core-OIP-OIP-0020.md |
OP20 token standard |
docs/core-OIP-OIP-0721.md |
OP721 NFT standard |
Contract Runtime (btc-runtime)
| File | Description |
|---|---|
docs/contracts-btc-runtime-README.md |
Runtime overview |
docs/contracts-btc-runtime-gas-optimization.md |
Gas optimization (CRITICAL) |
docs/contracts-btc-runtime-getting-started-installation.md |
Installation |
docs/contracts-btc-runtime-getting-started-first-contract.md |
First contract |
docs/contracts-btc-runtime-getting-started-project-structure.md |
Project structure |
docs/contracts-btc-runtime-core-concepts-blockchain-environment.md |
Blockchain env |
docs/contracts-btc-runtime-core-concepts-storage-system.md |
Storage system |
docs/contracts-btc-runtime-core-concepts-pointers.md |
Storage pointers |
docs/contracts-btc-runtime-core-concepts-events.md |
Events |
docs/contracts-btc-runtime-core-concepts-decorators.md |
Decorators |
docs/contracts-btc-runtime-core-concepts-security.md |
Security |
docs/contracts-btc-runtime-api-reference-blockchain.md |
Blockchain API |
docs/contracts-btc-runtime-api-reference-storage.md |
Storage API |
docs/contracts-btc-runtime-api-reference-events.md |
Events API |
docs/contracts-btc-runtime-api-reference-op20.md |
OP20 API |
docs/contracts-btc-runtime-api-reference-op721.md |
OP721 API |
docs/contracts-btc-runtime-api-reference-safe-math.md |
SafeMath API |
docs/contracts-btc-runtime-contracts-op-net-base.md |
OP_NET base class |
docs/contracts-btc-runtime-contracts-op20-token.md |
OP20 implementation |
docs/contracts-btc-runtime-contracts-op20s-signatures.md |
OP20S signatures |
docs/contracts-btc-runtime-contracts-op721-nft.md |
OP721 implementation |
docs/contracts-btc-runtime-contracts-reentrancy-guard.md |
Reentrancy guard |
docs/contracts-btc-runtime-contracts-upgradeable.md |
Upgradeable contracts |
docs/contracts-btc-runtime-storage-stored-primitives.md |
Stored primitives |
docs/contracts-btc-runtime-storage-stored-maps.md |
Stored maps |
docs/contracts-btc-runtime-storage-stored-arrays.md |
Stored arrays |
docs/contracts-btc-runtime-storage-memory-maps.md |
Memory maps |
docs/contracts-btc-runtime-types-address.md |
Address type |
docs/contracts-btc-runtime-types-calldata.md |
Calldata type |
docs/contracts-btc-runtime-types-bytes-writer-reader.md |
BytesWriter/Reader |
docs/contracts-btc-runtime-types-safe-math.md |
SafeMath type |
docs/contracts-btc-runtime-advanced-cross-contract-calls.md |
Cross-contract calls |
docs/contracts-btc-runtime-advanced-signature-verification.md |
Signature verification |
docs/contracts-btc-runtime-advanced-quantum-resistance.md |
Quantum resistance |
docs/contracts-btc-runtime-advanced-bitcoin-scripts.md |
Bitcoin scripts |
docs/contracts-btc-runtime-advanced-contract-upgrades.md |
Contract upgrades |
docs/contracts-btc-runtime-advanced-plugins.md |
Contract plugins |
docs/contracts-btc-runtime-examples-basic-token.md |
Basic token example |
docs/contracts-btc-runtime-examples-stablecoin.md |
Stablecoin example |
docs/contracts-btc-runtime-examples-nft-with-reservations.md |
NFT example |
docs/contracts-btc-runtime-examples-oracle-integration.md |
Oracle example |
Other Contract Docs
| File | Description |
|---|---|
docs/contracts-as-bignum-README.md |
BigNum library (u256, u128) |
docs/contracts-opnet-transform-README.md |
Transform decorators |
docs/contracts-opnet-transform-std-README.md |
Standard library |
docs/contracts-example-tokens-README.md |
Example tokens |
docs/contracts-example-tokens-docs-OP_20.md |
OP20 example |
Client Libraries
| File | Description |
|---|---|
docs/clients-bitcoin-README.md |
Bitcoin library overview |
docs/clients-bitcoin-psbt.md |
PSBT class, signing, finalization |
docs/clients-bitcoin-payments.md |
Payment types (P2TR, P2WPKH, P2WSH, P2SH, P2OP) |
docs/clients-bitcoin-script.md |
Script building, opcodes |
docs/clients-bitcoin-address.md |
Address encoding/decoding |
docs/clients-bitcoin-transaction.md |
Transaction class |
docs/clients-bip32-README.md |
BIP32 HD derivation |
docs/clients-bip32-QUANTUM.md |
Quantum support |
docs/clients-ecpair-README.md |
EC key pairs |
docs/clients-walletconnect-README.md |
WalletConnect |
docs/clients-walletconnect-wallet-integration.md |
Wallet integration |
Testing
| File | Description |
|---|---|
docs/testing-unit-test-framework-README.md |
Test framework |
docs/testing-opnet-unit-test-README.md |
Unit testing |
docs/testing-opnet-unit-test-docs-README.md |
Test docs |
docs/testing-opnet-unit-test-docs-Blockchain.md |
Blockchain mocking |
docs/testing-opnet-unit-test-docs-ContractRuntime.md |
Contract runtime |
Frontend
| File | Description |
|---|---|
docs/frontend-motoswap-ui-README.md |
Frontend guide (THE STANDARD) |
Plugins
| File | Description |
|---|---|
docs/plugins-plugin-sdk-README.md |
Plugin SDK |
docs/plugins-opnet-node-README.md |
OPNet node |
docs/plugins-opnet-node-docker-README.md |
Docker setup |
Templates
Contract Templates (templates/contracts/)
| File | Description |
|---|---|
templates/contracts/OP20Token.ts |
OP20 token implementation |
templates/contracts/OP721NFT.ts |
OP721 NFT implementation |
templates/contracts/MyContract.ts |
Generic contract template |
templates/contracts/index.ts |
Entry point / exports |
Frontend Templates (templates/frontend/)
| File | Description |
|---|---|
templates/frontend/App.tsx |
Main app component |
templates/frontend/OPNetProvider.tsx |
OPNet context provider |
templates/frontend/WalletConnect.tsx |
Wallet connection component |
templates/frontend/ContractInteraction.tsx |
Contract interaction component |
templates/frontend/useWallet.ts |
Wallet hook |
templates/frontend/useContract.ts |
Contract hook |
templates/frontend/vite.config.ts |
Vite configuration |
templates/frontend/package.json |
Package dependencies |
Plugin Templates (templates/plugins/)
| File | Description |
|---|---|
templates/plugins/MyPlugin.ts |
Generic plugin template |
templates/plugins/OP20Indexer.ts |
OP20 indexer plugin |
templates/plugins/types.ts |
Type definitions |
templates/plugins/index.ts |
Entry point |
templates/plugins/plugin.json |
Plugin manifest |
Test Templates (templates/tests/)
| File | Description |
|---|---|
templates/tests/OP20.test.ts |
OP20 test example |
templates/tests/setup.ts |
Test setup |
templates/tests/gulpfile.js |
Gulp build config |
Advanced Transaction Features
When users ask about adding fees, notes, or advanced features to transactions (deployments, interactions, funding), ALWAYS check docs/core-transaction-transaction-factory-interfaces.md.
Common User Requests â Parameters
| User Request | Parameter | Interface |
|---|---|---|
| “Add a fee” / “Set fee rate” | feeRate: number (sat/vB) |
TransactionParameters |
| “Add priority fee” | priorityFee: bigint |
TransactionParameters |
| “Add a note/memo” | note: string | Uint8Array |
TransactionParameters |
| “Use anchor outputs” | anchor: true |
TransactionParameters |
| “Send to multiple addresses” | extraOutputs: PsbtOutputExtended[] |
TransactionParameters |
| “Send max/entire balance” | autoAdjustAmount: true |
IFundingTransactionParameters |
| “Pay fees from separate UTXOs” | feeUtxos: UTXO[] |
IFundingTransactionParameters |
| “Set minimum gas” | minGas: bigint |
TransactionParameters |
| “Offline signing” | toOfflineBuffer() / fromOfflineBuffer() |
CallResult methods |
| “Sign without broadcasting” | signTransaction() |
CallResult method |
| “Broadcast pre-signed TX” | sendPresignedTransaction() |
CallResult method |
CallResult Transaction Methods
// Sign without broadcast
const signedTx = await simulation.signTransaction(params);
// Sign and broadcast
const receipt = await simulation.sendTransaction(params);
// Broadcast pre-signed
const receipt = await simulation.sendPresignedTransaction(signedTx);
// Offline signing workflow
const buffer = await simulation.toOfflineBuffer(address, amount);
const reconstructed = CallResult.fromOfflineBuffer(buffer);
Quick Example: Adding Fee + Note
await simulation.sendTransaction({
signer: wallet.keypair,
mldsaSigner: wallet.mldsaKeypair,
refundTo: wallet.p2tr,
network: networks.regtest,
maximumAllowedSatToSpend: 100000n,
feeRate: 15, // 15 sat/vB
priorityFee: 5000n, // +5000 sats priority
note: "Payment for invoice #123", // OP_RETURN memo
});
For full details, read docs/core-transaction-transaction-factory-interfaces.md.
Contract Development
Key Concepts
- Contracts use a custom AssemblyScript fork (
@btc-vision/assemblyscript) – This fork adds closure support to standard AssemblyScript, enabling callbacks and higher-order function patterns. Always install@btc-vision/assemblyscriptinstead of the upstreamassemblyscriptpackage. - Constructor runs on EVERY interaction – Use
onDeployment()for initialization - Contracts CANNOT hold BTC – They are calculators, not custodians
- Verify-don’t-custody pattern – Check
Blockchain.tx.outputsagainst internal state
Decorator Reference
// Mark method as callable
@method({ name: 'param1', type: ABIDataTypes.UINT256 })
// Specify return types
@returns({ name: 'result', type: ABIDataTypes.UINT256 })
// Declare emitted events
@emit('Transfer', 'Approval')
Storage Types
| Type | Use Case |
|---|---|
StoredU256 |
Single u256 value |
StoredBoolean |
Boolean flag |
StoredString |
String value |
StoredMapU256 |
Key-value map (u256 keys/values) |
AddressMemoryMap |
In-memory address map |
Testing
ALL CODE MUST HAVE TESTS
import { opnet, OPNetUnit, Assert, Blockchain } from '@btc-vision/unit-test-framework';
await opnet('My Tests', async (vm: OPNetUnit) => {
vm.beforeEach(async () => {
Blockchain.dispose();
await Blockchain.init();
});
await vm.it('should work correctly', async () => {
const result = await contract.someMethod();
Assert.expect(result).toEqual(expected);
});
});
Plugin Development
OPNet nodes are like Minecraft servers – they support plugins!
Key Resources
- Read
docs/plugins-plugin-sdk-README.md - Read
docs/core-OIP-OIP-0003.mdfor plugin specification - Use
templates/plugins/OP20Indexer.tsfor indexers
Plugin Lifecycle
| Hook | When Called | Blocking |
|---|---|---|
onFirstInstall |
First installation | Yes |
onNetworkInit |
Every load | Yes |
onBlockChange |
New block confirmed | No |
onReorg |
Chain reorganization | Yes (CRITICAL) |
Critical: Reorg Handling
You MUST implement onReorg() to revert state for reorged blocks. Failure to do so will cause data inconsistency.
Frontend Development
Configuration Standard
Frontend configs MUST use docs/eslint-react.json and docs/tsconfig-generic.json:
- Vite + React
- Vitest for testing
- ESLint with TypeScript strict mode
- ESNext target
Caching (MANDATORY)
- Reuse provider instances – Singleton per network
- Reuse contract instances – Cache by address
- Cache API responses – Invalidate on block change
Key Hooks
// OPNet provider
const { provider, isConnected, network } = useOPNet();
// Contract interaction
const { contract, callMethod, loading } = useContract(address, abi);
// Wallet connection
const { address, connect, disconnect, signPsbt } = useWallet();
See docs/frontend-motoswap-ui-README.md for complete integration guide.
Backend/API Development
MANDATORY Frameworks
| Package | Purpose |
|---|---|
@btc-vision/hyper-express |
HTTP server (fastest) |
@btc-vision/uwebsocket.js |
WebSocket server (fastest) |
FORBIDDEN: Express, Fastify, Koa, Hapi – they are significantly slower.
See docs/core-opnet-backend-api.md for complete guide.
Official Wallet: OP_WALLET
OP_WALLET is the main and official wallet supporting OPNet. It is developed by the OPNet team and provides the most complete feature set for interacting with the OPNet Bitcoin L1 smart contract ecosystem.
Why OP_WALLET is Required for Full OPNet Support
| Feature | OP_WALLET | Other Wallets |
|---|---|---|
| Official Support | Yes | No |
| MLDSA Signatures | Yes | No |
| Quantum-Resistant Keys | Yes | No |
| Full OPNet Integration | Yes | Partial |
| First-Party Updates | Yes | No |
Key Capabilities
- MLDSA (ML-DSA) Signatures: Only OP_WALLET supports quantum-resistant ML-DSA signatures, which are critical for future-proof security on OPNet
- Full Address System Support: OP_WALLET properly handles both Bitcoin addresses (tweaked public keys) and OPNet addresses (ML-DSA public key hashes)
- Native OPNet Features: Direct access to all OPNet features as they are released
- Optimized UX: Built specifically for OPNet dApp interactions
Integration via WalletConnect
Use @btc-vision/walletconnect to integrate OP_WALLET into your dApp:
import { WalletConnectProvider, useWalletConnect, SupportedWallets } from '@btc-vision/walletconnect';
// Wrap your app
<WalletConnectProvider theme="dark">
<App />
</WalletConnectProvider>
// In your component
const { connectToWallet, mldsaPublicKey, signMLDSAMessage } = useWalletConnect();
// Connect specifically to OP_WALLET for full feature support
connectToWallet(SupportedWallets.OP_WALLET);
// Use MLDSA signatures (OP_WALLET only)
if (mldsaPublicKey) {
const signature = await signMLDSAMessage('Your message');
}
Installation
Install OP_WALLET from the Chrome Web Store
Client Libraries
| Package | Doc | Description |
|---|---|---|
@btc-vision/bitcoin |
docs/clients-bitcoin-README.md |
Bitcoin lib (709x faster PSBT) |
@btc-vision/bip32 |
docs/clients-bip32-README.md |
HD derivation + quantum |
@btc-vision/ecpair |
docs/clients-ecpair-README.md |
EC key pairs |
@btc-vision/transaction |
docs/core-transaction-README.md |
OPNet transactions |
opnet |
docs/core-opnet-README.md |
Main client library |
@btc-vision/walletconnect |
docs/clients-walletconnect-README.md |
Wallet connection (OP_WALLET + UniSat) |
Version Requirements
| Tool | Minimum Version |
|---|---|
| Node.js | >= 24.0.0 |
| TypeScript | >= 5.9.3 |
| AssemblyScript | @btc-vision/assemblyscript (custom fork with closure support) |
Critical Reminders
- READ typescript-law FIRST – Non-negotiable rules
- Verify project configuration – Before writing any code
- NO
anytype – Ever - Test everything – Unit tests required
- **Handle