x402-engineer 0.1.0

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.
Files changed (38) hide show
  1. package/AGENT.md +102 -0
  2. package/README.md +43 -0
  3. package/dist/cli.cjs +137 -0
  4. package/package.json +51 -0
  5. package/skills/stellar-dev/SKILL.md +146 -0
  6. package/skills/stellar-dev/advanced-patterns.md +188 -0
  7. package/skills/stellar-dev/api-rpc-horizon.md +521 -0
  8. package/skills/stellar-dev/common-pitfalls.md +510 -0
  9. package/skills/stellar-dev/contracts-soroban.md +565 -0
  10. package/skills/stellar-dev/ecosystem.md +430 -0
  11. package/skills/stellar-dev/frontend-stellar-sdk.md +651 -0
  12. package/skills/stellar-dev/resources.md +306 -0
  13. package/skills/stellar-dev/security.md +491 -0
  14. package/skills/stellar-dev/standards-reference.md +94 -0
  15. package/skills/stellar-dev/stellar-assets.md +419 -0
  16. package/skills/stellar-dev/testing.md +786 -0
  17. package/skills/stellar-dev/zk-proofs.md +136 -0
  18. package/skills/x402-add-paywall/SKILL.md +208 -0
  19. package/skills/x402-add-paywall/references/patterns.md +132 -0
  20. package/skills/x402-debug/SKILL.md +92 -0
  21. package/skills/x402-debug/references/checklist.md +146 -0
  22. package/skills/x402-explain/SKILL.md +136 -0
  23. package/skills/x402-init/SKILL.md +129 -0
  24. package/skills/x402-init/templates/env-example.md +17 -0
  25. package/skills/x402-init/templates/express/config.ts.md +29 -0
  26. package/skills/x402-init/templates/express/server.ts.md +30 -0
  27. package/skills/x402-init/templates/fastify/adapter.ts.md +66 -0
  28. package/skills/x402-init/templates/fastify/config.ts.md +29 -0
  29. package/skills/x402-init/templates/fastify/server.ts.md +90 -0
  30. package/skills/x402-init/templates/hono/config.ts.md +29 -0
  31. package/skills/x402-init/templates/hono/server.ts.md +31 -0
  32. package/skills/x402-init/templates/next-app-router/config.ts.md +29 -0
  33. package/skills/x402-init/templates/next-app-router/server.ts.md +31 -0
  34. package/skills/x402-stellar/SKILL.md +139 -0
  35. package/skills/x402-stellar/references/api.md +237 -0
  36. package/skills/x402-stellar/references/patterns.md +276 -0
  37. package/skills/x402-stellar/references/setup.md +138 -0
  38. package/skills/x402-stellar/scripts/check-deps.js +218 -0
@@ -0,0 +1,565 @@
1
+ # Soroban Smart Contract Development
2
+
3
+ ## When to use Soroban
4
+ Use Soroban when you need:
5
+ - Custom on-chain logic beyond Stellar's built-in operations
6
+ - Programmable escrow, lending, or DeFi primitives
7
+ - Complex authorization rules
8
+ - State management beyond account balances
9
+ - Interoperability with Stellar Assets via SAC
10
+
11
+ ## Quick Navigation
12
+ - Initialization and constructors: [Project Setup](#project-setup), [Contract Constructors (Protocol 22+)](#contract-constructors-protocol-22)
13
+ - Core implementation patterns: [Core Contract Structure](#core-contract-structure), [Storage Types](#storage-types), [Authorization](#authorization)
14
+ - Advanced interactions: [Cross-Contract Calls](#cross-contract-calls), [Events](#events), [Error Handling](#error-handling)
15
+ - Delivery workflow: [Building and Deploying](#building-and-deploying), [Unit Testing](#unit-testing), [Best Practices](#best-practices)
16
+ - ZK status guidance: [Zero-Knowledge Cryptography (Status-Sensitive)](#zero-knowledge-cryptography-status-sensitive)
17
+
18
+ ## Alternative Languages
19
+
20
+ Rust is the primary and recommended language for Soroban contracts. Community-maintained alternatives exist but are not recommended for production:
21
+ - **AssemblyScript**: [`as-soroban-sdk`](https://github.com/Soneso/as-soroban-sdk) by Soneso — allows TypeScript-like syntax, officially listed on Stellar docs, but may lag behind the latest protocol version
22
+ - **Solidity**: [Hyperledger Solang](https://github.com/hyperledger-solang/solang) — SDF-funded, compiles Solidity to Soroban WASM, currently **pre-alpha** ([docs](https://developers.stellar.org/docs/learn/migrate/evm/solidity-support-via-solang))
23
+
24
+ ## Architecture Overview
25
+
26
+ ### Host-Guest Model
27
+ Soroban uses a WebAssembly sandbox with strict separation:
28
+ - **Host Environment**: Provides storage, crypto, cross-contract calls
29
+ - **Guest Contract**: Your Rust code compiled to WASM
30
+ - Contracts reference host objects via handles (not direct memory)
31
+
32
+ ### Key Constraints
33
+ - `#![no_std]` required - no Rust standard library
34
+ - 64KB contract size limit (use release optimizations)
35
+ - Limited heap allocation
36
+ - No string type (use `String` from soroban-sdk or `Symbol` for short strings)
37
+ - `Symbol` limited to 32 characters (was 10 in earlier versions)
38
+
39
+ ## Project Setup
40
+
41
+ ### Initialize a new contract
42
+ ```bash
43
+ stellar contract init my-contract
44
+ cd my-contract
45
+ ```
46
+
47
+ This creates:
48
+ ```
49
+ my-contract/
50
+ ├── Cargo.toml
51
+ ├── src/
52
+ │ └── lib.rs
53
+ └── contracts/
54
+ └── hello_world/
55
+ ├── Cargo.toml
56
+ └── src/
57
+ └── lib.rs
58
+ ```
59
+
60
+ ### Cargo.toml configuration
61
+ ```toml
62
+ [package]
63
+ name = "my-contract"
64
+ version = "0.1.0"
65
+ edition = "2021"
66
+
67
+ [lib]
68
+ crate-type = ["cdylib"]
69
+
70
+ [dependencies]
71
+ soroban-sdk = "25.0.1" # check https://crates.io/crates/soroban-sdk for latest
72
+
73
+ [dev-dependencies]
74
+ soroban-sdk = { version = "25.0.1", features = ["testutils"] } # match above
75
+
76
+ [profile.release]
77
+ opt-level = "z"
78
+ overflow-checks = true
79
+ debug = 0
80
+ strip = "symbols"
81
+ debug-assertions = false
82
+ panic = "abort"
83
+ codegen-units = 1
84
+ lto = true
85
+
86
+ [profile.release-with-logs]
87
+ inherits = "release"
88
+ debug-assertions = true
89
+ ```
90
+
91
+ ## Contract Constructors (Protocol 22+)
92
+
93
+ Use constructors for atomic initialization when protocol support is available. This avoids a separate `initialize` transaction and reduces front-running risk.
94
+
95
+ ### Constructor pattern
96
+ ```rust
97
+ #![no_std]
98
+ use soroban_sdk::{contract, contractimpl, contracttype, Address, Env};
99
+
100
+ #[contracttype]
101
+ #[derive(Clone)]
102
+ pub enum DataKey {
103
+ Admin,
104
+ Value,
105
+ }
106
+
107
+ #[contract]
108
+ pub struct MyContract;
109
+
110
+ #[contractimpl]
111
+ impl MyContract {
112
+ // Runs once at deployment time.
113
+ pub fn __constructor(env: Env, admin: Address, initial_value: u32) {
114
+ env.storage().instance().set(&DataKey::Admin, &admin);
115
+ env.storage().instance().set(&DataKey::Value, &initial_value);
116
+ }
117
+ }
118
+ ```
119
+
120
+ ### Deploy with constructor args (CLI)
121
+ ```bash
122
+ stellar contract deploy \
123
+ --wasm target/wasm32-unknown-unknown/release/my_contract.wasm \
124
+ --source alice \
125
+ --network testnet \
126
+ -- \
127
+ --admin alice \
128
+ --initial_value 100
129
+ ```
130
+
131
+ ### Rules
132
+ 1. Name must be `__constructor` exactly.
133
+ 2. Constructor returns `()` (no return value).
134
+ 3. Runs only at creation time and does not run on upgrade.
135
+ 4. If constructor fails, deployment fails atomically.
136
+
137
+ ### Backwards compatibility
138
+ If targeting older protocol environments, use guarded `initialize` patterns and prevent re-initialization explicitly.
139
+
140
+ ## Core Contract Structure
141
+
142
+ ### Basic Contract
143
+ ```rust
144
+ #![no_std]
145
+ use soroban_sdk::{contract, contractimpl, symbol_short, vec, Env, Symbol, Vec};
146
+
147
+ #[contract]
148
+ pub struct HelloContract;
149
+
150
+ #[contractimpl]
151
+ impl HelloContract {
152
+ pub fn hello(env: Env, to: Symbol) -> Vec<Symbol> {
153
+ vec![&env, symbol_short!("Hello"), to]
154
+ }
155
+ }
156
+ ```
157
+
158
+ ### Contract with State
159
+ ```rust
160
+ #![no_std]
161
+ use soroban_sdk::{contract, contractimpl, contracttype, Address, Env};
162
+
163
+ #[contracttype]
164
+ #[derive(Clone)]
165
+ pub enum DataKey {
166
+ Counter,
167
+ Admin,
168
+ UserBalance(Address),
169
+ }
170
+
171
+ #[contract]
172
+ pub struct CounterContract;
173
+
174
+ #[contractimpl]
175
+ impl CounterContract {
176
+ pub fn initialize(env: Env, admin: Address) {
177
+ if env.storage().instance().has(&DataKey::Admin) {
178
+ panic!("already initialized");
179
+ }
180
+ env.storage().instance().set(&DataKey::Admin, &admin);
181
+ env.storage().instance().set(&DataKey::Counter, &0u32);
182
+ }
183
+
184
+ pub fn increment(env: Env) -> u32 {
185
+ let mut count: u32 = env.storage().instance().get(&DataKey::Counter).unwrap_or(0);
186
+ count += 1;
187
+ env.storage().instance().set(&DataKey::Counter, &count);
188
+
189
+ // Extend TTL to prevent archival
190
+ env.storage().instance().extend_ttl(100, 518400); // threshold, ~30 days
191
+
192
+ count
193
+ }
194
+
195
+ pub fn get_count(env: Env) -> u32 {
196
+ env.storage().instance().get(&DataKey::Counter).unwrap_or(0)
197
+ }
198
+ }
199
+ ```
200
+
201
+ ## Storage Types
202
+
203
+ Soroban has three storage types with different costs and lifetimes:
204
+
205
+ ### Instance Storage
206
+ - Tied to contract instance lifetime
207
+ - Shared across all users
208
+ - Best for: admin addresses, global config, counters
209
+ ```rust
210
+ env.storage().instance().set(&key, &value);
211
+ env.storage().instance().get(&key);
212
+ env.storage().instance().extend_ttl(min_ttl, extend_to);
213
+ ```
214
+
215
+ ### Persistent Storage
216
+ - Survives archival (can be restored)
217
+ - Per-key TTL management
218
+ - Best for: user balances, important state
219
+ ```rust
220
+ env.storage().persistent().set(&key, &value);
221
+ env.storage().persistent().get(&key);
222
+ env.storage().persistent().extend_ttl(&key, min_ttl, extend_to);
223
+ ```
224
+
225
+ ### Temporary Storage
226
+ - Cheapest, automatically deleted when TTL expires
227
+ - Cannot be restored after archival
228
+ - Best for: caches, temporary flags, session data
229
+ ```rust
230
+ env.storage().temporary().set(&key, &value);
231
+ env.storage().temporary().get(&key);
232
+ env.storage().temporary().extend_ttl(&key, min_ttl, extend_to);
233
+ ```
234
+
235
+ ### TTL Management
236
+ ```rust
237
+ // Check remaining TTL
238
+ let ttl = env.storage().persistent().get_ttl(&key);
239
+
240
+ // Extend if below threshold
241
+ const MIN_TTL: u32 = 17280; // ~1 day at 5s ledgers
242
+ const EXTEND_TO: u32 = 518400; // ~30 days
243
+
244
+ if ttl < MIN_TTL {
245
+ env.storage().persistent().extend_ttl(&key, MIN_TTL, EXTEND_TO);
246
+ }
247
+ ```
248
+
249
+ ## Data Types
250
+
251
+ ### Primitive Types
252
+ ```rust
253
+ use soroban_sdk::{Address, Bytes, BytesN, Map, String, Symbol, Vec, I128, U256};
254
+
255
+ // Address - account or contract identifier
256
+ let addr: Address = env.current_contract_address();
257
+
258
+ // Symbol - short strings (max 32 chars)
259
+ let sym: Symbol = symbol_short!("transfer");
260
+
261
+ // String - longer strings
262
+ let s: String = String::from_str(&env, "Hello, Stellar!");
263
+
264
+ // Fixed-size bytes
265
+ let hash: BytesN<32> = env.crypto().sha256(&bytes);
266
+
267
+ // Collections
268
+ let v: Vec<u32> = vec![&env, 1, 2, 3];
269
+ let m: Map<Symbol, u32> = Map::new(&env);
270
+ ```
271
+
272
+ ### Custom Types
273
+ ```rust
274
+ #[contracttype]
275
+ #[derive(Clone, Debug, Eq, PartialEq)]
276
+ pub struct TokenMetadata {
277
+ pub name: String,
278
+ pub symbol: Symbol,
279
+ pub decimals: u32,
280
+ }
281
+
282
+ #[contracttype]
283
+ #[derive(Clone)]
284
+ pub enum DataKey {
285
+ Admin,
286
+ Balance(Address),
287
+ Allowance(Address, Address), // (owner, spender)
288
+ }
289
+ ```
290
+
291
+ ## Authorization
292
+
293
+ ### Requiring Authorization
294
+ ```rust
295
+ #[contractimpl]
296
+ impl TokenContract {
297
+ pub fn transfer(env: Env, from: Address, to: Address, amount: i128) {
298
+ // Require 'from' to authorize this call
299
+ from.require_auth();
300
+
301
+ // Or require auth for specific arguments
302
+ from.require_auth_for_args((&to, amount).into_val(&env));
303
+
304
+ // Transfer logic...
305
+ }
306
+ }
307
+ ```
308
+
309
+ ### Admin Patterns
310
+ ```rust
311
+ fn require_admin(env: &Env) {
312
+ let admin: Address = env.storage().instance().get(&DataKey::Admin).unwrap();
313
+ admin.require_auth();
314
+ }
315
+
316
+ pub fn set_admin(env: Env, new_admin: Address) {
317
+ require_admin(&env);
318
+ env.storage().instance().set(&DataKey::Admin, &new_admin);
319
+ }
320
+ ```
321
+
322
+ ## Cross-Contract Calls
323
+
324
+ ### Calling Another Contract
325
+ ```rust
326
+ use soroban_sdk::{contract, contractimpl, Address, Env};
327
+
328
+ mod token_contract {
329
+ soroban_sdk::contractimport!(
330
+ file = "../token/target/wasm32-unknown-unknown/release/token.wasm"
331
+ );
332
+ }
333
+
334
+ #[contract]
335
+ pub struct VaultContract;
336
+
337
+ #[contractimpl]
338
+ impl VaultContract {
339
+ pub fn deposit(env: Env, user: Address, token: Address, amount: i128) {
340
+ user.require_auth();
341
+
342
+ // Create client for token contract
343
+ let token_client = token_contract::Client::new(&env, &token);
344
+
345
+ // Call transfer on token contract
346
+ token_client.transfer(&user, &env.current_contract_address(), &amount);
347
+
348
+ // Update vault state...
349
+ }
350
+ }
351
+ ```
352
+
353
+ ### Using Stellar Asset Contract (SAC)
354
+ ```rust
355
+ use soroban_sdk::token::Client as TokenClient;
356
+
357
+ pub fn transfer_asset(env: Env, from: Address, to: Address, asset: Address, amount: i128) {
358
+ from.require_auth();
359
+
360
+ let token = TokenClient::new(&env, &asset);
361
+ token.transfer(&from, &to, &amount);
362
+ }
363
+ ```
364
+
365
+ ## Events
366
+
367
+ ### Emitting Events
368
+ ```rust
369
+ use soroban_sdk::{contract, contractevent, contractimpl, Address, Env};
370
+
371
+ #[contractevent(topics = ["transfer"])]
372
+ pub struct TransferEvent {
373
+ pub from: Address,
374
+ pub to: Address,
375
+ pub amount: i128,
376
+ }
377
+
378
+ #[contract]
379
+ pub struct TokenContract;
380
+
381
+ #[contractimpl]
382
+ impl TokenContract {
383
+ pub fn transfer(env: Env, from: Address, to: Address, amount: i128) {
384
+ // ... transfer logic ...
385
+
386
+ // Emit event
387
+ TransferEvent { from, to, amount }.publish(&env);
388
+ }
389
+ }
390
+ ```
391
+
392
+ ## Error Handling
393
+
394
+ ### Custom Errors
395
+ ```rust
396
+ use soroban_sdk::contracterror;
397
+
398
+ #[contracterror]
399
+ #[derive(Copy, Clone, Debug, Eq, PartialEq)]
400
+ #[repr(u32)]
401
+ pub enum ContractError {
402
+ AlreadyInitialized = 1,
403
+ NotInitialized = 2,
404
+ InsufficientBalance = 3,
405
+ Unauthorized = 4,
406
+ InvalidAmount = 5,
407
+ }
408
+
409
+ // Usage
410
+ pub fn transfer(env: Env, from: Address, to: Address, amount: i128) -> Result<(), ContractError> {
411
+ if amount <= 0 {
412
+ return Err(ContractError::InvalidAmount);
413
+ }
414
+
415
+ let balance: i128 = get_balance(&env, &from);
416
+ if balance < amount {
417
+ return Err(ContractError::InsufficientBalance);
418
+ }
419
+
420
+ // ... transfer logic ...
421
+ Ok(())
422
+ }
423
+ ```
424
+
425
+ ## Building and Deploying
426
+
427
+ ### Build Contract
428
+ ```bash
429
+ # Build optimized WASM
430
+ stellar contract build
431
+
432
+ # Output: target/wasm32-unknown-unknown/release/my_contract.wasm
433
+ ```
434
+
435
+ ### Deploy to Testnet
436
+ ```bash
437
+ # Generate and fund a new identity
438
+ stellar keys generate --global alice --network testnet --fund
439
+
440
+ # Deploy contract
441
+ stellar contract deploy \
442
+ --wasm target/wasm32-unknown-unknown/release/my_contract.wasm \
443
+ --source alice \
444
+ --network testnet
445
+
446
+ # Returns: CONTRACT_ID (starts with 'C')
447
+ ```
448
+
449
+ ### Initialize Contract
450
+ ```bash
451
+ stellar contract invoke \
452
+ --id CONTRACT_ID \
453
+ --source alice \
454
+ --network testnet \
455
+ -- \
456
+ initialize \
457
+ --admin alice
458
+ ```
459
+
460
+ ### Invoke Functions
461
+ ```bash
462
+ stellar contract invoke \
463
+ --id CONTRACT_ID \
464
+ --source alice \
465
+ --network testnet \
466
+ -- \
467
+ increment
468
+ ```
469
+
470
+ ## Unit Testing
471
+
472
+ ```rust
473
+ #![cfg(test)]
474
+
475
+ use super::*;
476
+ use soroban_sdk::testutils::Address as _;
477
+ use soroban_sdk::Env;
478
+
479
+ #[test]
480
+ fn test_increment() {
481
+ let env = Env::default();
482
+ let contract_id = env.register_contract(None, CounterContract);
483
+ let client = CounterContractClient::new(&env, &contract_id);
484
+
485
+ let admin = Address::generate(&env);
486
+ client.initialize(&admin);
487
+
488
+ assert_eq!(client.get_count(), 0);
489
+ assert_eq!(client.increment(), 1);
490
+ assert_eq!(client.increment(), 2);
491
+ assert_eq!(client.get_count(), 2);
492
+ }
493
+
494
+ #[test]
495
+ fn test_transfer_with_auth() {
496
+ let env = Env::default();
497
+ env.mock_all_auths(); // Auto-approve all auth requests
498
+
499
+ let contract_id = env.register_contract(None, TokenContract);
500
+ let client = TokenContractClient::new(&env, &contract_id);
501
+
502
+ let alice = Address::generate(&env);
503
+ let bob = Address::generate(&env);
504
+
505
+ // Mint tokens to alice
506
+ client.mint(&alice, &1000);
507
+
508
+ // Transfer from alice to bob
509
+ client.transfer(&alice, &bob, &100);
510
+
511
+ assert_eq!(client.balance(&alice), 900);
512
+ assert_eq!(client.balance(&bob), 100);
513
+ }
514
+ ```
515
+
516
+ ## Best Practices
517
+
518
+ ### Contract Size Optimization
519
+ - Use `symbol_short!()` for symbols under 9 chars (more efficient)
520
+ - Avoid unnecessary string operations
521
+ - Use appropriate storage type for data lifetime
522
+ - Consider splitting large contracts
523
+
524
+ ### Storage Efficiency
525
+ - Use compact data structures
526
+ - Clean up temporary storage
527
+ - Batch storage operations when possible
528
+ - Manage TTLs proactively to avoid archival
529
+
530
+ ### Security
531
+ - Always validate inputs
532
+ - Use `require_auth()` for sensitive operations
533
+ - Check contract ownership in initialization
534
+ - Prevent reinitialization attacks
535
+ - Validate cross-contract call targets
536
+
537
+ ### Gas/Resource Optimization
538
+ - Minimize storage reads/writes
539
+ - Use events for data that doesn't need on-chain queries
540
+ - Batch operations where possible
541
+ - Profile resource usage with `stellar contract invoke --sim`
542
+
543
+ ## Zero-Knowledge Cryptography (Status-Sensitive)
544
+
545
+ Stellar's ZK cryptography capabilities are evolving. Treat availability as protocol- and network-dependent.
546
+
547
+ - [CAP-0059](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0059.md): BLS12-381 primitives
548
+ - [CAP-0074](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0074.md): BN254 host functions (proposed)
549
+ - [CAP-0075](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0075.md): Poseidon/Poseidon2 host functions (proposed)
550
+
551
+ Before implementation, always verify:
552
+ 1. CAP status in the CAP preamble (`Accepted`/`Implemented` vs draft/awaiting decision)
553
+ 2. Target network software version and protocol support
554
+ 3. `soroban-sdk` release support for the target host functions
555
+
556
+ ### Practical guidance
557
+ - Use BLS12-381 features where supported and documented in your target SDK/network.
558
+ - For BN254/Poseidon plans, design feature flags and graceful fallbacks until support is active.
559
+ - Keep cryptographic assumptions explicit in audits and deployment notes.
560
+
561
+ ### Example references
562
+ - [Groth16 Verifier](https://github.com/stellar/soroban-examples/tree/main/groth16_verifier)
563
+ - [Soroban examples repository](https://github.com/stellar/soroban-examples)
564
+
565
+ > See [zk-proofs.md](zk-proofs.md) for Groth16 verification patterns, Poseidon usage, Noir/RISC Zero integration, and implementation guidance.