stellar-agent 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 (59) hide show
  1. package/README.md +162 -0
  2. package/package.json +37 -0
  3. package/src/core-skills/module-help.csv +5 -0
  4. package/src/core-skills/module.yaml +33 -0
  5. package/src/core-skills/stellar-brainstorming/SKILL.md +6 -0
  6. package/src/core-skills/stellar-brainstorming/steps/step-01-session-setup.md +67 -0
  7. package/src/core-skills/stellar-brainstorming/steps/step-02a-user-selected.md +20 -0
  8. package/src/core-skills/stellar-brainstorming/steps/step-02b-ai-recommended.md +29 -0
  9. package/src/core-skills/stellar-brainstorming/steps/step-03-technique-execution.md +69 -0
  10. package/src/core-skills/stellar-brainstorming/steps/step-04-idea-organization.md +64 -0
  11. package/src/core-skills/stellar-brainstorming/workflow.md +50 -0
  12. package/src/core-skills/stellar-help/SKILL.md +71 -0
  13. package/src/core-skills/stellar-party-mode/SKILL.md +109 -0
  14. package/src/scripts/resolve_config.py +170 -0
  15. package/src/scripts/resolve_customization.py +209 -0
  16. package/src/stellar-skills/1-analysis/stellar-agent-analyst/SKILL.md +71 -0
  17. package/src/stellar-skills/1-analysis/stellar-agent-analyst/customize.toml +41 -0
  18. package/src/stellar-skills/1-analysis/stellar-analytics/SKILL.md +239 -0
  19. package/src/stellar-skills/1-analysis/stellar-domain-research/SKILL.md +82 -0
  20. package/src/stellar-skills/1-analysis/stellar-market-research/SKILL.md +90 -0
  21. package/src/stellar-skills/2-planning/stellar-agent-pm/SKILL.md +57 -0
  22. package/src/stellar-skills/2-planning/stellar-agent-pm/customize.toml +36 -0
  23. package/src/stellar-skills/2-planning/stellar-epics-stories/SKILL.md +106 -0
  24. package/src/stellar-skills/2-planning/stellar-prd/SKILL.md +115 -0
  25. package/src/stellar-skills/2-planning/stellar-project-brief/SKILL.md +83 -0
  26. package/src/stellar-skills/3-architecture/stellar-agent-architect/SKILL.md +53 -0
  27. package/src/stellar-skills/3-architecture/stellar-agent-architect/customize.toml +31 -0
  28. package/src/stellar-skills/3-architecture/stellar-architecture-doc/SKILL.md +162 -0
  29. package/src/stellar-skills/4-implementation/stellar-agent-developer/SKILL.md +54 -0
  30. package/src/stellar-skills/4-implementation/stellar-agent-developer/customize.toml +56 -0
  31. package/src/stellar-skills/4-implementation/stellar-agent-devops/SKILL.md +54 -0
  32. package/src/stellar-skills/4-implementation/stellar-agent-devops/customize.toml +36 -0
  33. package/src/stellar-skills/4-implementation/stellar-agent-frontend/SKILL.md +54 -0
  34. package/src/stellar-skills/4-implementation/stellar-agent-frontend/customize.toml +52 -0
  35. package/src/stellar-skills/4-implementation/stellar-agent-qa/SKILL.md +54 -0
  36. package/src/stellar-skills/4-implementation/stellar-agent-qa/customize.toml +31 -0
  37. package/src/stellar-skills/4-implementation/stellar-create-asset/SKILL.md +145 -0
  38. package/src/stellar-skills/4-implementation/stellar-create-transaction/SKILL.md +134 -0
  39. package/src/stellar-skills/4-implementation/stellar-deploy-contract/SKILL.md +124 -0
  40. package/src/stellar-skills/4-implementation/stellar-freighter-integration/SKILL.md +193 -0
  41. package/src/stellar-skills/4-implementation/stellar-horizon-integration/SKILL.md +198 -0
  42. package/src/stellar-skills/4-implementation/stellar-init-contract/SKILL.md +102 -0
  43. package/src/stellar-skills/4-implementation/stellar-liquidity-pool/SKILL.md +156 -0
  44. package/src/stellar-skills/4-implementation/stellar-nextjs-setup/SKILL.md +198 -0
  45. package/src/stellar-skills/4-implementation/stellar-nextjs-soroban/SKILL.md +228 -0
  46. package/src/stellar-skills/4-implementation/stellar-nextjs-wallet/SKILL.md +276 -0
  47. package/src/stellar-skills/4-implementation/stellar-sep10-auth/SKILL.md +252 -0
  48. package/src/stellar-skills/4-implementation/stellar-setup-environment/SKILL.md +163 -0
  49. package/src/stellar-skills/4-implementation/stellar-setup-trustline/SKILL.md +107 -0
  50. package/src/stellar-skills/4-implementation/stellar-test-contract/SKILL.md +146 -0
  51. package/src/stellar-skills/4-implementation/stellar-write-contract/SKILL.md +140 -0
  52. package/src/stellar-skills/module-help.csv +24 -0
  53. package/src/stellar-skills/module.yaml +103 -0
  54. package/tools/installer/cli-utils.js +39 -0
  55. package/tools/installer/commands/init.js +335 -0
  56. package/tools/installer/fs-native.js +116 -0
  57. package/tools/installer/prompts.js +852 -0
  58. package/tools/installer/stellar-cli.js +80 -0
  59. package/tools/installer/yaml-format.js +245 -0
@@ -0,0 +1,252 @@
1
+ ---
2
+ name: stellar-sep10-auth
3
+ description: 'Implement SEP-10 Web Authentication for Stellar dApps — challenge/response flow, JWT issuance, and backend verification. Use when the user needs to authenticate users by their Stellar account without sharing private keys.'
4
+ ---
5
+
6
+ # SEP-10 Web Authentication
7
+
8
+ ## Purpose
9
+
10
+ Implement the Stellar SEP-10 standard to authenticate users by proving ownership of a Stellar account. Issues a JWT for subsequent API calls.
11
+
12
+ ## On Activation
13
+
14
+ Load `{network_preference}` from `{project-root}/_stellar/stellar/config.yaml`.
15
+
16
+ ## How SEP-10 Works
17
+
18
+ 1. **Client** requests a challenge from the server, providing their public key
19
+ 2. **Server** builds a Stellar transaction encoding a random nonce — signed by the server's keypair — and returns it as XDR
20
+ 3. **Client** signs the challenge transaction with their wallet (Freighter)
21
+ 4. **Server** verifies both signatures, checks nonce/expiry, issues a JWT
22
+ 5. **Client** sends the JWT in `Authorization: Bearer {token}` on subsequent API requests
23
+
24
+ ## Backend Setup (Node.js / Next.js API Routes)
25
+
26
+ ### Step 1: Install Dependencies
27
+
28
+ ```bash
29
+ yarn add express jsonwebtoken stellar-sdk
30
+ # or for Next.js only:
31
+ npm install jsonwebtoken stellar-sdk
32
+ npm install --save-dev @types/jsonwebtoken
33
+ ```
34
+
35
+ ### Step 2: Environment Variables
36
+
37
+ ```env
38
+ # Server-side only (no NEXT_PUBLIC_ prefix)
39
+ SEP10_SERVER_SECRET=S... # Stellar keypair secret key for signing challenges
40
+ SEP10_HOME_DOMAIN=yourdomain.com # must match stellar.toml WEB_AUTH_ENDPOINT host
41
+ JWT_SECRET=your-jwt-secret-here # random 32+ char string
42
+ JWT_EXPIRES_IN=24h
43
+ ```
44
+
45
+ ### Step 3: Challenge Endpoint
46
+
47
+ `src/app/api/auth/challenge/route.ts`:
48
+
49
+ ```typescript
50
+ import { NextRequest, NextResponse } from 'next/server';
51
+ import {
52
+ Keypair, TransactionBuilder, Networks, Operation,
53
+ Account, StrKey, BASE_FEE,
54
+ } from 'stellar-sdk';
55
+
56
+ const SERVER_KEYPAIR = Keypair.fromSecret(process.env.SEP10_SERVER_SECRET!);
57
+ const HOME_DOMAIN = process.env.SEP10_HOME_DOMAIN!;
58
+ const NETWORK_PASSPHRASE = process.env.NEXT_PUBLIC_NETWORK_PASSPHRASE!;
59
+
60
+ export async function GET(request: NextRequest) {
61
+ const { searchParams } = new URL(request.url);
62
+ const clientPublicKey = searchParams.get('account');
63
+
64
+ if (!clientPublicKey || !StrKey.isValidEd25519PublicKey(clientPublicKey)) {
65
+ return NextResponse.json({ error: 'Invalid account' }, { status: 400 });
66
+ }
67
+
68
+ // SEP-10 requires a fake account with sequence 0
69
+ const serverAccount = new Account(SERVER_KEYPAIR.publicKey(), '-1');
70
+
71
+ const now = Math.floor(Date.now() / 1000);
72
+ const tx = new TransactionBuilder(serverAccount, {
73
+ fee: BASE_FEE,
74
+ networkPassphrase: NETWORK_PASSPHRASE,
75
+ timebounds: {
76
+ minTime: now,
77
+ maxTime: now + 300, // 5 minute window
78
+ },
79
+ })
80
+ .addOperation(
81
+ Operation.manageData({
82
+ name: `${HOME_DOMAIN} auth`,
83
+ value: Buffer.from(crypto.getRandomValues(new Uint8Array(48))).toString('base64'),
84
+ source: clientPublicKey, // operation source = client account
85
+ })
86
+ )
87
+ .addOperation(
88
+ Operation.manageData({
89
+ name: 'web_auth_domain',
90
+ value: HOME_DOMAIN,
91
+ source: SERVER_KEYPAIR.publicKey(),
92
+ })
93
+ )
94
+ .build();
95
+
96
+ tx.sign(SERVER_KEYPAIR);
97
+
98
+ return NextResponse.json({
99
+ transaction: tx.toXDR(),
100
+ network_passphrase: NETWORK_PASSPHRASE,
101
+ });
102
+ }
103
+ ```
104
+
105
+ ### Step 4: Token Endpoint
106
+
107
+ `src/app/api/auth/token/route.ts`:
108
+
109
+ ```typescript
110
+ import { NextRequest, NextResponse } from 'next/server';
111
+ import { TransactionBuilder, Keypair, StrKey } from 'stellar-sdk';
112
+ import jwt from 'jsonwebtoken';
113
+
114
+ const SERVER_KEYPAIR = Keypair.fromSecret(process.env.SEP10_SERVER_SECRET!);
115
+ const HOME_DOMAIN = process.env.SEP10_HOME_DOMAIN!;
116
+ const NETWORK_PASSPHRASE = process.env.NEXT_PUBLIC_NETWORK_PASSPHRASE!;
117
+ const JWT_SECRET = process.env.JWT_SECRET!;
118
+
119
+ export async function POST(request: NextRequest) {
120
+ const { transaction } = await request.json();
121
+
122
+ try {
123
+ const tx = TransactionBuilder.fromXDR(transaction, NETWORK_PASSPHRASE);
124
+
125
+ // 1. Verify server signature
126
+ const serverSigned = tx.signatures.some(sig =>
127
+ SERVER_KEYPAIR.verify(tx.hash(), sig.signature())
128
+ );
129
+ if (!serverSigned) {
130
+ return NextResponse.json({ error: 'Invalid server signature' }, { status: 400 });
131
+ }
132
+
133
+ // 2. Extract client public key from first operation's source
134
+ const clientKey = (tx.operations[0] as any).source;
135
+ if (!clientKey || !StrKey.isValidEd25519PublicKey(clientKey)) {
136
+ return NextResponse.json({ error: 'Missing client source account' }, { status: 400 });
137
+ }
138
+
139
+ // 3. Verify client signature
140
+ const clientKeypair = Keypair.fromPublicKey(clientKey);
141
+ const clientSigned = tx.signatures.some(sig => {
142
+ try {
143
+ return clientKeypair.verify(tx.hash(), sig.signature());
144
+ } catch {
145
+ return false;
146
+ }
147
+ });
148
+ if (!clientSigned) {
149
+ return NextResponse.json({ error: 'Client signature missing or invalid' }, { status: 400 });
150
+ }
151
+
152
+ // 4. Verify timebounds not expired
153
+ const now = Math.floor(Date.now() / 1000);
154
+ const { minTime, maxTime } = tx.timeBounds!;
155
+ if (now < Number(minTime) || now > Number(maxTime)) {
156
+ return NextResponse.json({ error: 'Challenge expired' }, { status: 400 });
157
+ }
158
+
159
+ // 5. Issue JWT
160
+ const token = jwt.sign(
161
+ { sub: clientKey, iss: HOME_DOMAIN },
162
+ JWT_SECRET,
163
+ { expiresIn: process.env.JWT_EXPIRES_IN || '24h' }
164
+ );
165
+
166
+ return NextResponse.json({ token });
167
+ } catch (err) {
168
+ return NextResponse.json({ error: String(err) }, { status: 400 });
169
+ }
170
+ }
171
+ ```
172
+
173
+ ### Step 5: Client-Side SEP-10 Flow
174
+
175
+ `src/lib/stellar/sep10.ts`:
176
+
177
+ ```typescript
178
+ import { TransactionBuilder } from 'stellar-sdk';
179
+ import { NETWORK_PASSPHRASE } from './config';
180
+
181
+ export async function authenticate(
182
+ publicKey: string,
183
+ signFn: (xdr: string) => Promise<string>
184
+ ): Promise<string> {
185
+ // 1. Get challenge
186
+ const chalRes = await fetch(`/api/auth/challenge?account=${publicKey}`);
187
+ if (!chalRes.ok) throw new Error('Failed to get challenge');
188
+ const { transaction } = await chalRes.json();
189
+
190
+ // 2. Sign with wallet (Freighter)
191
+ const signedXdr = await signFn(transaction);
192
+
193
+ // 3. Submit signed challenge
194
+ const tokenRes = await fetch('/api/auth/token', {
195
+ method: 'POST',
196
+ headers: { 'Content-Type': 'application/json' },
197
+ body: JSON.stringify({ transaction: signedXdr }),
198
+ });
199
+ if (!tokenRes.ok) throw new Error('Authentication failed');
200
+ const { token } = await tokenRes.json();
201
+ return token;
202
+ }
203
+ ```
204
+
205
+ ### Step 6: Protect API Routes
206
+
207
+ Middleware helper for authenticated routes:
208
+
209
+ ```typescript
210
+ import jwt from 'jsonwebtoken';
211
+ import { NextRequest } from 'next/server';
212
+
213
+ export function verifyJwt(request: NextRequest): string | null {
214
+ const auth = request.headers.get('Authorization');
215
+ if (!auth?.startsWith('Bearer ')) return null;
216
+ try {
217
+ const payload = jwt.verify(auth.slice(7), process.env.JWT_SECRET!) as jwt.JwtPayload;
218
+ return payload.sub ?? null; // returns the Stellar public key
219
+ } catch {
220
+ return null;
221
+ }
222
+ }
223
+ ```
224
+
225
+ Usage in protected routes:
226
+ ```typescript
227
+ export async function GET(request: NextRequest) {
228
+ const publicKey = verifyJwt(request);
229
+ if (!publicKey) {
230
+ return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
231
+ }
232
+ // publicKey is the authenticated Stellar account
233
+ }
234
+ ```
235
+
236
+ ### Step 7: stellar.toml Entry
237
+
238
+ Add to your `/.well-known/stellar.toml`:
239
+ ```toml
240
+ WEB_AUTH_ENDPOINT="https://yourdomain.com/api/auth/challenge"
241
+ SIGNING_KEY="G..." # SERVER_KEYPAIR public key
242
+ ```
243
+
244
+ ### Reference
245
+
246
+ - Full spec: [SEP-10](https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0010.md)
247
+ - Related: SEP-24 (hosted deposit/withdraw), SEP-31 (cross-border payments)
248
+
249
+ ### Next Steps
250
+
251
+ - Use the JWT from `authenticate()` in fetch headers for all protected API calls
252
+ - `stellar-nextjs-wallet` — hook the auth flow into the wallet connect button
@@ -0,0 +1,163 @@
1
+ ---
2
+ name: stellar-setup-environment
3
+ description: 'Set up a complete local Stellar development environment including the Docker quickstart bundle, Stellar CLI, Rust toolchain, and SDK installation. Use when the user wants to set up their local Stellar development environment.'
4
+ ---
5
+
6
+ # Set Up Stellar Development Environment
7
+
8
+ ## Purpose
9
+
10
+ Configure a fully working local Stellar development environment for Soroban and Classic Stellar development.
11
+
12
+ ## On Activation
13
+
14
+ Load `{network_preference}` and `{primary_language}` from `{project-root}/_stellar/stellar/config.yaml`.
15
+
16
+ ## Workflow
17
+
18
+ ### Step 1: Detect Current State
19
+
20
+ Run `stellar doctor` if already installed:
21
+
22
+ ```bash
23
+ stellar doctor
24
+ ```
25
+
26
+ Report what's installed and what's missing. If everything is green, skip to the verification step.
27
+
28
+ ### Step 2: Install Rust (for Soroban)
29
+
30
+ ```bash
31
+ # Install Rust via rustup
32
+ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
33
+
34
+ # Add the WASM compile target
35
+ rustup target add wasm32-unknown-unknown
36
+
37
+ # Verify
38
+ rustc --version
39
+ cargo --version
40
+ ```
41
+
42
+ ### Step 3: Install Stellar CLI
43
+
44
+ ```bash
45
+ # Install via cargo (recommended — always gets latest stable)
46
+ cargo install --locked stellar-cli --features opt
47
+
48
+ # Verify installation
49
+ stellar --version
50
+
51
+ # Diagnose environment
52
+ stellar doctor
53
+ ```
54
+
55
+ ### Step 4: Install Docker (for Local Network)
56
+
57
+ **macOS:** Install [Docker Desktop](https://www.docker.com/products/docker-desktop/)
58
+
59
+ **Linux (Ubuntu/Debian):**
60
+ ```bash
61
+ sudo apt-get update
62
+ sudo apt-get install docker-ce docker-ce-cli containerd.io
63
+ sudo usermod -aG docker $USER # run without sudo
64
+ ```
65
+
66
+ Verify: `docker --version`
67
+
68
+ ### Step 5: Start Local Stellar Network
69
+
70
+ **Option A: Stellar CLI (recommended)**
71
+ ```bash
72
+ stellar network container start local
73
+ ```
74
+
75
+ **Option B: Docker directly**
76
+ ```bash
77
+ docker run --rm -it \
78
+ -p 8000:8000 \
79
+ --name stellar \
80
+ stellar/quickstart:testing \
81
+ --local \
82
+ --enable-stellar-rpc
83
+ ```
84
+
85
+ The quickstart bundle includes:
86
+ - **Stellar Core** — validates and applies transactions
87
+ - **Horizon** — REST API at `http://localhost:8000`
88
+ - **Stellar RPC** — contract invocation at `http://localhost:8000/soroban/rpc`
89
+ - **Friendbot** — testnet faucet at `http://localhost:8000/friendbot`
90
+
91
+ Verify: `curl http://localhost:8000/`
92
+
93
+ ### Step 6: Configure Stellar CLI Networks
94
+
95
+ ```bash
96
+ # Add local network
97
+ stellar network add local \
98
+ --rpc-url http://localhost:8000/soroban/rpc \
99
+ --network-passphrase "Standalone Network ; February 2017"
100
+
101
+ # Testnet is pre-configured, but you can add it explicitly:
102
+ stellar network add testnet \
103
+ --rpc-url https://soroban-testnet.stellar.org \
104
+ --network-passphrase "Test SDF Network ; September 2015"
105
+ ```
106
+
107
+ ### Step 7: Create Development Keypairs
108
+
109
+ ```bash
110
+ # Generate a new keypair and fund it
111
+ stellar keys generate dev-account --network local
112
+ stellar keys fund dev-account --network local
113
+
114
+ # View the address
115
+ stellar keys address dev-account
116
+ ```
117
+
118
+ ### Step 8: Install JS/TS SDK (if applicable)
119
+
120
+ ```bash
121
+ npm install @stellar/stellar-sdk
122
+ # or
123
+ yarn add @stellar/stellar-sdk
124
+ # or
125
+ bun add @stellar/stellar-sdk
126
+ ```
127
+
128
+ ### Step 9: Install Python SDK (if applicable)
129
+
130
+ ```bash
131
+ pip install stellar-sdk
132
+ ```
133
+
134
+ ### Step 8b: Install TypeScript Wallet SDK (optional)
135
+
136
+ ```bash
137
+ yarn add @stellar/typescript-wallet-sdk
138
+ ```
139
+
140
+ ### Step 10: End-to-End Verification
141
+
142
+ Deploy the hello-world contract to local network:
143
+
144
+ ```bash
145
+ stellar contract init hello-world
146
+ cd hello-world
147
+ stellar contract build
148
+ stellar contract deploy \
149
+ --wasm target/wasm32-unknown-unknown/release/hello_world.wasm \
150
+ --source dev-account \
151
+ --network local
152
+ stellar contract invoke \
153
+ --id {contract_id} \
154
+ --source dev-account \
155
+ --network local \
156
+ -- hello --to World
157
+ ```
158
+
159
+ Expected output: `["Hello, World!"]`
160
+
161
+ ### Step 11: Document Setup
162
+
163
+ Save environment details to `{project-root}/_stellar-output/project-knowledge/environment-guide.md`.
@@ -0,0 +1,107 @@
1
+ ---
2
+ name: stellar-setup-trustline
3
+ description: 'Set up trustlines for custom Stellar assets, handle authorization for regulated assets, and manage trustline limits. Use when the user needs to configure an account to hold a custom Stellar asset.'
4
+ ---
5
+
6
+ # Set Up Trustline
7
+
8
+ ## Purpose
9
+
10
+ Configure trustlines so accounts can hold and receive custom Stellar assets.
11
+
12
+ ## On Activation
13
+
14
+ Load `{network_preference}` from `{project-root}/_stellar/stellar/config.yaml`.
15
+
16
+ ## Concepts
17
+
18
+ - A **trustline** is an explicit opt-in by an account to hold a specific custom asset.
19
+ - The account must maintain enough XLM to cover the **base reserve** (0.5 XLM per trustline).
20
+ - If the issuing account has `AUTH_REQUIRED` set, the issuer must separately authorize each trustline.
21
+
22
+ ## Workflow
23
+
24
+ ### Step 1: Gather Information
25
+
26
+ Collect from user:
27
+ - Asset code and issuer public key (e.g., `USDC:GABCDE...`)
28
+ - Account that needs the trustline
29
+ - Trust limit (or leave blank for maximum: `922337203685.4775807`)
30
+ - Does the asset have `AUTH_REQUIRED`? (check via Horizon: `GET /accounts/{issuer}`)
31
+
32
+ ### Step 2: Check Account Balance
33
+
34
+ ```typescript
35
+ const account = await server.loadAccount(accountPublicKey);
36
+ const xlmBalance = account.balances.find(b => b.asset_type === 'native');
37
+ console.log('XLM balance:', xlmBalance?.balance);
38
+ // Ensure at least 0.5 XLM above minimum reserve
39
+ ```
40
+
41
+ ### Step 3: Create Trustline
42
+
43
+ ```typescript
44
+ const asset = new StellarSDK.Asset(assetCode, issuerPublicKey);
45
+
46
+ const tx = new StellarSDK.TransactionBuilder(account, {
47
+ fee: StellarSDK.BASE_FEE,
48
+ networkPassphrase: StellarSDK.Networks.TESTNET,
49
+ })
50
+ .addOperation(
51
+ StellarSDK.Operation.changeTrust({
52
+ asset,
53
+ limit: '1000000', // omit for maximum limit
54
+ })
55
+ )
56
+ .setTimeout(30)
57
+ .build();
58
+
59
+ tx.sign(accountKeypair);
60
+ await server.submitTransaction(tx);
61
+ ```
62
+
63
+ ### Step 4: Authorize Trustline (AUTH_REQUIRED Assets)
64
+
65
+ If the asset has `AUTH_REQUIRED`, the issuer must authorize each new trustline:
66
+
67
+ ```typescript
68
+ const issuerAccount = await server.loadAccount(issuerPublicKey);
69
+
70
+ const authTx = new StellarSDK.TransactionBuilder(issuerAccount, {
71
+ fee: StellarSDK.BASE_FEE,
72
+ networkPassphrase: StellarSDK.Networks.TESTNET,
73
+ })
74
+ .addOperation(
75
+ StellarSDK.Operation.setTrustLineFlags({
76
+ trustor: accountPublicKey,
77
+ asset,
78
+ flags: {
79
+ authorized: true,
80
+ authorizedToMaintainLiabilities: false,
81
+ },
82
+ })
83
+ )
84
+ .setTimeout(30)
85
+ .build();
86
+
87
+ authTx.sign(issuerKeypair);
88
+ await server.submitTransaction(authTx);
89
+ ```
90
+
91
+ ### Step 5: Verify
92
+
93
+ ```typescript
94
+ const updatedAccount = await server.loadAccount(accountPublicKey);
95
+ const trustline = updatedAccount.balances.find(
96
+ b => b.asset_code === assetCode && b.asset_issuer === issuerPublicKey
97
+ );
98
+ console.log('Trustline:', trustline);
99
+ // { balance: '0.0000000', limit: '1000000.0000000', is_authorized: true }
100
+ ```
101
+
102
+ ### Step 6: Remove Trustline (if needed)
103
+
104
+ ```typescript
105
+ // Set limit to '0' to remove — only works if balance is zero
106
+ StellarSDK.Operation.changeTrust({ asset, limit: '0' })
107
+ ```
@@ -0,0 +1,146 @@
1
+ ---
2
+ name: stellar-test-contract
3
+ description: 'Write and run comprehensive Soroban contract tests using the Rust test harness and soroban_sdk testutils. Use when the user wants to test a Soroban smart contract.'
4
+ ---
5
+
6
+ # Test Soroban Contract
7
+
8
+ ## Purpose
9
+
10
+ Achieve comprehensive contract coverage using the Soroban Rust test framework.
11
+
12
+ ## On Activation
13
+
14
+ Load config from `{project-root}/_stellar/stellar/config.yaml`.
15
+
16
+ ## Core Testing Patterns
17
+
18
+ ### Test Environment Setup
19
+
20
+ ```rust
21
+ #[cfg(test)]
22
+ mod tests {
23
+ use super::*;
24
+ use soroban_sdk::{testutils::Address as _, Address, Env};
25
+
26
+ fn setup() -> (Env, Address, MyContractClient<'static>) {
27
+ let env = Env::default();
28
+ env.mock_all_auths();
29
+ let contract_id = env.register(MyContract, ());
30
+ let client = MyContractClient::new(&env, &contract_id);
31
+ let admin = Address::generate(&env);
32
+ (env, admin, client)
33
+ }
34
+
35
+ #[test]
36
+ fn test_initialize_sets_admin() {
37
+ let (env, admin, client) = setup();
38
+ client.initialize(&admin);
39
+ assert_eq!(client.get_admin(), admin);
40
+ }
41
+ }
42
+ ```
43
+
44
+ ### Authorization Testing
45
+
46
+ ```rust
47
+ #[test]
48
+ fn test_transfer_requires_from_auth() {
49
+ let env = Env::default();
50
+ env.mock_all_auths();
51
+ let contract_id = env.register(MyContract, ());
52
+ let client = MyContractClient::new(&env, &contract_id);
53
+ let from = Address::generate(&env);
54
+ let to = Address::generate(&env);
55
+
56
+ client.transfer(&from, &to, &100i128);
57
+
58
+ // Verify the authorization was required
59
+ assert_auth!(env, from, contract_id, "transfer");
60
+ }
61
+ ```
62
+
63
+ ### Error Path Testing
64
+
65
+ ```rust
66
+ #[test]
67
+ fn test_withdraw_fails_when_insufficient_balance() {
68
+ let (env, admin, client) = setup();
69
+ client.initialize(&admin);
70
+ let user = Address::generate(&env);
71
+
72
+ let result = client.try_withdraw(&user, &1000i128);
73
+ assert_eq!(result, Err(Ok(ContractError::InsufficientBalance)));
74
+ }
75
+ ```
76
+
77
+ ### Event Testing
78
+
79
+ ```rust
80
+ #[test]
81
+ fn test_deposit_emits_event() {
82
+ let (env, admin, client) = setup();
83
+ client.initialize(&admin);
84
+ let user = Address::generate(&env);
85
+
86
+ client.deposit(&user, &500i128);
87
+
88
+ let events = env.events().all();
89
+ assert_eq!(events.len(), 1);
90
+ // Assert event data matches expected values
91
+ }
92
+ ```
93
+
94
+ ### Storage Expiration Testing
95
+
96
+ ```rust
97
+ #[test]
98
+ fn test_persistent_storage_survives_archival() {
99
+ let env = Env::default();
100
+ env.mock_all_auths();
101
+ let contract_id = env.register(MyContract, ());
102
+ let client = MyContractClient::new(&env, &contract_id);
103
+
104
+ // Simulate ledger advancement
105
+ env.ledger().with_mut(|l| {
106
+ l.sequence_number += 100_000;
107
+ l.timestamp += 100_000;
108
+ });
109
+
110
+ // Persistent data should still be accessible
111
+ let balance = client.get_balance(&Address::generate(&env));
112
+ assert_eq!(balance, 0i128);
113
+ }
114
+ ```
115
+
116
+ ## Workflow
117
+
118
+ ### Step 1: Identify Test Cases
119
+
120
+ For each contract function, enumerate:
121
+ - Happy path (valid inputs, expected output)
122
+ - Authorization failures (wrong signer, missing auth)
123
+ - Input validation failures (negative amount, zero, overflow)
124
+ - State-dependent failures (already initialized, not initialized, paused)
125
+ - Edge cases (max values, empty collections)
126
+
127
+ ### Step 2: Implement Tests
128
+
129
+ Write one test per scenario. Test names must describe expected behavior:
130
+ `test_deposit_fails_when_paused` — not `test_deposit_2`.
131
+
132
+ ### Step 3: Run Tests
133
+
134
+ ```bash
135
+ cargo test
136
+ cargo test -- --nocapture # for event/log debugging
137
+ cargo test test_deposit # run specific test
138
+ ```
139
+
140
+ ### Step 4: Coverage Review
141
+
142
+ Walk through each storage key and each event emission — confirm a test exercises each path.
143
+
144
+ ### Step 5: Next Steps
145
+
146
+ After tests pass, proceed to `stellar-deploy-contract` for testnet deployment.