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.
- package/README.md +162 -0
- package/package.json +37 -0
- package/src/core-skills/module-help.csv +5 -0
- package/src/core-skills/module.yaml +33 -0
- package/src/core-skills/stellar-brainstorming/SKILL.md +6 -0
- package/src/core-skills/stellar-brainstorming/steps/step-01-session-setup.md +67 -0
- package/src/core-skills/stellar-brainstorming/steps/step-02a-user-selected.md +20 -0
- package/src/core-skills/stellar-brainstorming/steps/step-02b-ai-recommended.md +29 -0
- package/src/core-skills/stellar-brainstorming/steps/step-03-technique-execution.md +69 -0
- package/src/core-skills/stellar-brainstorming/steps/step-04-idea-organization.md +64 -0
- package/src/core-skills/stellar-brainstorming/workflow.md +50 -0
- package/src/core-skills/stellar-help/SKILL.md +71 -0
- package/src/core-skills/stellar-party-mode/SKILL.md +109 -0
- package/src/scripts/resolve_config.py +170 -0
- package/src/scripts/resolve_customization.py +209 -0
- package/src/stellar-skills/1-analysis/stellar-agent-analyst/SKILL.md +71 -0
- package/src/stellar-skills/1-analysis/stellar-agent-analyst/customize.toml +41 -0
- package/src/stellar-skills/1-analysis/stellar-analytics/SKILL.md +239 -0
- package/src/stellar-skills/1-analysis/stellar-domain-research/SKILL.md +82 -0
- package/src/stellar-skills/1-analysis/stellar-market-research/SKILL.md +90 -0
- package/src/stellar-skills/2-planning/stellar-agent-pm/SKILL.md +57 -0
- package/src/stellar-skills/2-planning/stellar-agent-pm/customize.toml +36 -0
- package/src/stellar-skills/2-planning/stellar-epics-stories/SKILL.md +106 -0
- package/src/stellar-skills/2-planning/stellar-prd/SKILL.md +115 -0
- package/src/stellar-skills/2-planning/stellar-project-brief/SKILL.md +83 -0
- package/src/stellar-skills/3-architecture/stellar-agent-architect/SKILL.md +53 -0
- package/src/stellar-skills/3-architecture/stellar-agent-architect/customize.toml +31 -0
- package/src/stellar-skills/3-architecture/stellar-architecture-doc/SKILL.md +162 -0
- package/src/stellar-skills/4-implementation/stellar-agent-developer/SKILL.md +54 -0
- package/src/stellar-skills/4-implementation/stellar-agent-developer/customize.toml +56 -0
- package/src/stellar-skills/4-implementation/stellar-agent-devops/SKILL.md +54 -0
- package/src/stellar-skills/4-implementation/stellar-agent-devops/customize.toml +36 -0
- package/src/stellar-skills/4-implementation/stellar-agent-frontend/SKILL.md +54 -0
- package/src/stellar-skills/4-implementation/stellar-agent-frontend/customize.toml +52 -0
- package/src/stellar-skills/4-implementation/stellar-agent-qa/SKILL.md +54 -0
- package/src/stellar-skills/4-implementation/stellar-agent-qa/customize.toml +31 -0
- package/src/stellar-skills/4-implementation/stellar-create-asset/SKILL.md +145 -0
- package/src/stellar-skills/4-implementation/stellar-create-transaction/SKILL.md +134 -0
- package/src/stellar-skills/4-implementation/stellar-deploy-contract/SKILL.md +124 -0
- package/src/stellar-skills/4-implementation/stellar-freighter-integration/SKILL.md +193 -0
- package/src/stellar-skills/4-implementation/stellar-horizon-integration/SKILL.md +198 -0
- package/src/stellar-skills/4-implementation/stellar-init-contract/SKILL.md +102 -0
- package/src/stellar-skills/4-implementation/stellar-liquidity-pool/SKILL.md +156 -0
- package/src/stellar-skills/4-implementation/stellar-nextjs-setup/SKILL.md +198 -0
- package/src/stellar-skills/4-implementation/stellar-nextjs-soroban/SKILL.md +228 -0
- package/src/stellar-skills/4-implementation/stellar-nextjs-wallet/SKILL.md +276 -0
- package/src/stellar-skills/4-implementation/stellar-sep10-auth/SKILL.md +252 -0
- package/src/stellar-skills/4-implementation/stellar-setup-environment/SKILL.md +163 -0
- package/src/stellar-skills/4-implementation/stellar-setup-trustline/SKILL.md +107 -0
- package/src/stellar-skills/4-implementation/stellar-test-contract/SKILL.md +146 -0
- package/src/stellar-skills/4-implementation/stellar-write-contract/SKILL.md +140 -0
- package/src/stellar-skills/module-help.csv +24 -0
- package/src/stellar-skills/module.yaml +103 -0
- package/tools/installer/cli-utils.js +39 -0
- package/tools/installer/commands/init.js +335 -0
- package/tools/installer/fs-native.js +116 -0
- package/tools/installer/prompts.js +852 -0
- package/tools/installer/stellar-cli.js +80 -0
- package/tools/installer/yaml-format.js +245 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: stellar-freighter-integration
|
|
3
|
+
description: 'Deep Freighter wallet integration covering installation, connection lifecycle, network verification, transaction signing, and blob signing. Use when the user needs to integrate the Freighter browser wallet into their Stellar dApp.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Freighter Wallet Integration
|
|
7
|
+
|
|
8
|
+
## Purpose
|
|
9
|
+
|
|
10
|
+
Wire up the Freighter browser extension wallet for full dApp authentication, transaction signing, and network management.
|
|
11
|
+
|
|
12
|
+
## On Activation
|
|
13
|
+
|
|
14
|
+
Load `{network_preference}` and `{primary_language}` from `{project-root}/_stellar/stellar/config.yaml`.
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @stellar/freighter-api bignumber.js stellar-sdk
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Core API Reference
|
|
23
|
+
|
|
24
|
+
| Function | Purpose |
|
|
25
|
+
|---|---|
|
|
26
|
+
| `isConnected()` | Check if Freighter extension is installed |
|
|
27
|
+
| `isAllowed()` | Check if dApp has permission to access Freighter |
|
|
28
|
+
| `setAllowed()` | Request dApp permission (shows Freighter popup) |
|
|
29
|
+
| `getPublicKey()` | Get the active account's public key |
|
|
30
|
+
| `getNetworkDetails()` | Get current network info (passphrase, URL) |
|
|
31
|
+
| `signTransaction(xdr, opts)` | Sign a transaction XDR |
|
|
32
|
+
| `signBlob(blob, opts)` | Sign arbitrary data (for SEP-10) |
|
|
33
|
+
| `addToken(opts)` | Add a Soroban token to Freighter's asset list |
|
|
34
|
+
|
|
35
|
+
## Workflow
|
|
36
|
+
|
|
37
|
+
### Step 1: Detect Freighter Installation
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
import { isConnected } from '@stellar/freighter-api';
|
|
41
|
+
|
|
42
|
+
async function detectFreighter(): Promise<boolean> {
|
|
43
|
+
try {
|
|
44
|
+
return await isConnected();
|
|
45
|
+
} catch {
|
|
46
|
+
return false; // extension not installed
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
If not installed, direct the user to `https://www.freighter.app/`.
|
|
52
|
+
|
|
53
|
+
### Step 2: Connection Lifecycle
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { isConnected, isAllowed, setAllowed, getPublicKey, getNetworkDetails } from '@stellar/freighter-api';
|
|
57
|
+
|
|
58
|
+
interface WalletConnection {
|
|
59
|
+
publicKey: string;
|
|
60
|
+
network: string;
|
|
61
|
+
networkPassphrase: string;
|
|
62
|
+
networkUrl: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function connectWallet(expectedPassphrase: string): Promise<WalletConnection> {
|
|
66
|
+
const installed = await isConnected();
|
|
67
|
+
if (!installed) throw new Error('Freighter not installed');
|
|
68
|
+
|
|
69
|
+
// Request permission if not already granted
|
|
70
|
+
const allowed = await isAllowed();
|
|
71
|
+
if (!allowed) {
|
|
72
|
+
await setAllowed(); // shows Freighter popup
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const publicKey = await getPublicKey();
|
|
76
|
+
const networkDetails = await getNetworkDetails();
|
|
77
|
+
|
|
78
|
+
// Verify user is on the correct network
|
|
79
|
+
if (networkDetails.networkPassphrase !== expectedPassphrase) {
|
|
80
|
+
throw new Error(
|
|
81
|
+
`Wrong network. Expected ${expectedPassphrase}, ` +
|
|
82
|
+
`got ${networkDetails.networkPassphrase}. ` +
|
|
83
|
+
`Please switch networks in Freighter.`
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
publicKey,
|
|
89
|
+
network: networkDetails.network,
|
|
90
|
+
networkPassphrase: networkDetails.networkPassphrase,
|
|
91
|
+
networkUrl: networkDetails.networkUrl,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Step 3: Sign a Transaction
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
import { signTransaction } from '@stellar/freighter-api';
|
|
100
|
+
import { TransactionBuilder } from 'stellar-sdk';
|
|
101
|
+
|
|
102
|
+
async function signWithFreighter(
|
|
103
|
+
txXdr: string,
|
|
104
|
+
publicKey: string,
|
|
105
|
+
networkPassphrase: string
|
|
106
|
+
): Promise<string> {
|
|
107
|
+
// Returns signed XDR string
|
|
108
|
+
const signedXdr = await signTransaction(txXdr, {
|
|
109
|
+
accountToSign: publicKey, // ensure correct account signs
|
|
110
|
+
networkPassphrase,
|
|
111
|
+
});
|
|
112
|
+
return signedXdr;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Reconstruct the signed Transaction object
|
|
116
|
+
const signedTx = TransactionBuilder.fromXDR(signedXdr, networkPassphrase);
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Step 4: Sign a Blob (for SEP-10 / arbitrary data)
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
import { signBlob } from '@stellar/freighter-api';
|
|
123
|
+
|
|
124
|
+
async function signChallenge(
|
|
125
|
+
blob: string, // base64-encoded bytes
|
|
126
|
+
publicKey: string
|
|
127
|
+
): Promise<string> {
|
|
128
|
+
const result = await signBlob(blob, { accountToSign: publicKey });
|
|
129
|
+
return result; // base64-encoded signature
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Step 5: Add a Soroban Token to Freighter
|
|
134
|
+
|
|
135
|
+
After deploying a Soroban token contract, register it in the user's Freighter asset list:
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
import { addToken } from '@stellar/freighter-api';
|
|
139
|
+
|
|
140
|
+
await addToken({
|
|
141
|
+
contractId: 'C...', // contract ID on the network
|
|
142
|
+
network: 'TESTNET', // 'TESTNET' | 'PUBLIC'
|
|
143
|
+
});
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Step 6: Handle Common Errors
|
|
147
|
+
|
|
148
|
+
| Error message | Cause | Fix |
|
|
149
|
+
|---|---|---|
|
|
150
|
+
| `"Freighter is not connected"` | Extension not installed | Show install link |
|
|
151
|
+
| `"User declined"` | User rejected the popup | Show retry button |
|
|
152
|
+
| `"Wrong network"` | Mismatch between dApp and Freighter | Prompt user to switch network in extension |
|
|
153
|
+
| `"Could not retrieve account"` | Freighter is locked | Prompt user to unlock Freighter |
|
|
154
|
+
| `signTransaction` throws | User rejected signing | Catch and show error toast |
|
|
155
|
+
|
|
156
|
+
### Step 7: Network Passphrases Reference
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
const PASSPHRASES = {
|
|
160
|
+
mainnet: 'Public Global Stellar Network ; September 2015',
|
|
161
|
+
testnet: 'Test SDF Network ; September 2015',
|
|
162
|
+
futurenet: 'Test SDF Future Network ; October 2022',
|
|
163
|
+
// local standalone:
|
|
164
|
+
local: 'Standalone Network ; February 2017',
|
|
165
|
+
};
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Step 8: Vanilla JS Integration (non-framework)
|
|
169
|
+
|
|
170
|
+
```html
|
|
171
|
+
<script type="module">
|
|
172
|
+
import {
|
|
173
|
+
isConnected, setAllowed, getPublicKey, signTransaction
|
|
174
|
+
} from 'https://unpkg.com/@stellar/freighter-api@latest/src/index.js';
|
|
175
|
+
|
|
176
|
+
document.getElementById('connect-btn').addEventListener('click', async () => {
|
|
177
|
+
const installed = await isConnected();
|
|
178
|
+
if (!installed) {
|
|
179
|
+
alert('Please install Freighter from freighter.app');
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
await setAllowed();
|
|
183
|
+
const key = await getPublicKey();
|
|
184
|
+
document.getElementById('wallet-display').textContent = key.slice(0, 8) + '...';
|
|
185
|
+
});
|
|
186
|
+
</script>
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Next Steps
|
|
190
|
+
|
|
191
|
+
- `stellar-nextjs-wallet` — wrap this in a Next.js hook and context
|
|
192
|
+
- `stellar-sep10-auth` — use `signBlob` for SEP-10 web authentication
|
|
193
|
+
- `stellar-create-transaction` — build the transactions to sign
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: stellar-horizon-integration
|
|
3
|
+
description: 'Integrate with the Stellar Horizon REST API for account queries, transaction streaming, order book data, and fee estimation. Use when the user needs to interact with Stellar Horizon or stream network data.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Stellar Horizon Integration
|
|
7
|
+
|
|
8
|
+
## Purpose
|
|
9
|
+
|
|
10
|
+
Guide Horizon API integration for data-intensive Stellar dApp features.
|
|
11
|
+
|
|
12
|
+
## On Activation
|
|
13
|
+
|
|
14
|
+
Load `{network_preference}` from `{project-root}/_stellar/stellar/config.yaml`.
|
|
15
|
+
|
|
16
|
+
Set Horizon URL based on network:
|
|
17
|
+
- `testnet` → `https://horizon-testnet.stellar.org`
|
|
18
|
+
- `mainnet` → `https://horizon.stellar.org`
|
|
19
|
+
- `local` → `http://localhost:8000`
|
|
20
|
+
|
|
21
|
+
## Core Patterns
|
|
22
|
+
|
|
23
|
+
### SDK Setup
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import * as StellarSDK from '@stellar/stellar-sdk';
|
|
27
|
+
|
|
28
|
+
const server = new StellarSDK.Horizon.Server(
|
|
29
|
+
'https://horizon-testnet.stellar.org'
|
|
30
|
+
);
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Account Data
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
const account = await server.loadAccount(publicKey);
|
|
37
|
+
// Returns: balances, sequence, flags, signers, data, home_domain
|
|
38
|
+
|
|
39
|
+
// Find a specific balance
|
|
40
|
+
const usdcBalance = account.balances.find(
|
|
41
|
+
b => b.asset_code === 'USDC' && b.asset_issuer === issuerPublicKey
|
|
42
|
+
);
|
|
43
|
+
console.log('USDC balance:', usdcBalance?.balance);
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Transaction History
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
const transactions = await server
|
|
50
|
+
.transactions()
|
|
51
|
+
.forAccount(publicKey)
|
|
52
|
+
.limit(20)
|
|
53
|
+
.order('desc')
|
|
54
|
+
.call();
|
|
55
|
+
|
|
56
|
+
for (const tx of transactions.records) {
|
|
57
|
+
console.log(tx.hash, tx.created_at, tx.successful);
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Real-Time Transaction Streaming (Server-Sent Events)
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
let eventSource: EventSource | null = null;
|
|
65
|
+
|
|
66
|
+
function startStream(publicKey: string) {
|
|
67
|
+
eventSource = server
|
|
68
|
+
.transactions()
|
|
69
|
+
.forAccount(publicKey)
|
|
70
|
+
.cursor('now')
|
|
71
|
+
.stream({
|
|
72
|
+
onmessage: (tx) => {
|
|
73
|
+
console.log('New transaction:', tx.hash);
|
|
74
|
+
// Update UI state here
|
|
75
|
+
},
|
|
76
|
+
onerror: (err) => {
|
|
77
|
+
console.error('Stream error:', err);
|
|
78
|
+
// Reconnect after delay
|
|
79
|
+
setTimeout(() => startStream(publicKey), 5000);
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function stopStream() {
|
|
85
|
+
eventSource?.(); // close function returned by stream()
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Payment History
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
const payments = await server
|
|
93
|
+
.payments()
|
|
94
|
+
.forAccount(publicKey)
|
|
95
|
+
.limit(10)
|
|
96
|
+
.order('desc')
|
|
97
|
+
.call();
|
|
98
|
+
|
|
99
|
+
for (const payment of payments.records) {
|
|
100
|
+
if (payment.type === 'payment') {
|
|
101
|
+
console.log(`${payment.from} → ${payment.to}: ${payment.amount} ${payment.asset_code || 'XLM'}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Order Book
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
const orderBook = await server
|
|
110
|
+
.orderbook(
|
|
111
|
+
new StellarSDK.Asset('USD', issuerPublicKey),
|
|
112
|
+
StellarSDK.Asset.native()
|
|
113
|
+
)
|
|
114
|
+
.call();
|
|
115
|
+
|
|
116
|
+
console.log('Bids:', orderBook.bids.slice(0, 5));
|
|
117
|
+
console.log('Asks:', orderBook.asks.slice(0, 5));
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Fee Statistics
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
const feeStats = await server.feeStats();
|
|
124
|
+
|
|
125
|
+
// Use p75 for reliable inclusion without overpaying
|
|
126
|
+
const recommendedFee = feeStats.fee_charged.p75;
|
|
127
|
+
console.log('Recommended fee (stroops):', recommendedFee);
|
|
128
|
+
// Convert to XLM: parseInt(recommendedFee) / 10_000_000
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Liquidity Pool Query
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
const pool = await server
|
|
135
|
+
.liquidityPools()
|
|
136
|
+
.liquidityPoolId(poolId)
|
|
137
|
+
.call();
|
|
138
|
+
|
|
139
|
+
console.log('Reserves:', pool.reserves);
|
|
140
|
+
console.log('Total shares:', pool.total_shares);
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Workflow
|
|
144
|
+
|
|
145
|
+
### Step 1: Identify Integration Needs
|
|
146
|
+
|
|
147
|
+
Ask what data the dApp needs:
|
|
148
|
+
- Account balances and flags
|
|
149
|
+
- Transaction submission only
|
|
150
|
+
- Real-time transaction streaming
|
|
151
|
+
- Order book and trade data
|
|
152
|
+
- Historical payment data
|
|
153
|
+
|
|
154
|
+
### Step 2: Configure the Client
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
// With retry logic for mainnet
|
|
158
|
+
const server = new StellarSDK.Horizon.Server(
|
|
159
|
+
'https://horizon.stellar.org',
|
|
160
|
+
{ allowHttp: false }
|
|
161
|
+
);
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Step 3: Implement Data Layer
|
|
165
|
+
|
|
166
|
+
Build typed wrapper functions around Horizon calls with proper error handling:
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
async function getAccountBalance(publicKey: string, assetCode: string, issuer: string): Promise<string> {
|
|
170
|
+
try {
|
|
171
|
+
const account = await server.loadAccount(publicKey);
|
|
172
|
+
const balance = account.balances.find(
|
|
173
|
+
b => 'asset_code' in b && b.asset_code === assetCode && b.asset_issuer === issuer
|
|
174
|
+
);
|
|
175
|
+
return balance?.balance ?? '0';
|
|
176
|
+
} catch (error) {
|
|
177
|
+
if (error instanceof StellarSDK.NotFoundError) return '0';
|
|
178
|
+
throw error;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Step 4: Handle Pagination
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
// Fetch all records across pages
|
|
187
|
+
async function fetchAll<T>(
|
|
188
|
+
builder: StellarSDK.Horizon.CallBuilder<StellarSDK.Horizon.ServerApi.CollectionPage<T>>
|
|
189
|
+
): Promise<T[]> {
|
|
190
|
+
const records: T[] = [];
|
|
191
|
+
let page = await builder.call();
|
|
192
|
+
while (page.records.length > 0) {
|
|
193
|
+
records.push(...page.records);
|
|
194
|
+
page = await page.next();
|
|
195
|
+
}
|
|
196
|
+
return records;
|
|
197
|
+
}
|
|
198
|
+
```
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: stellar-init-contract
|
|
3
|
+
description: 'Initialize a new Soroban smart contract project with correct Rust workspace structure, Cargo.toml configuration, and hello-world contract scaffold. Use when the user wants to start a new Soroban contract.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Initialize Soroban Contract
|
|
7
|
+
|
|
8
|
+
## Purpose
|
|
9
|
+
|
|
10
|
+
Scaffold a complete Soroban smart contract project ready for development.
|
|
11
|
+
|
|
12
|
+
## On Activation
|
|
13
|
+
|
|
14
|
+
Load config from `{project-root}/_stellar/stellar/config.yaml` and resolve `{network_preference}` and `{primary_language}`.
|
|
15
|
+
|
|
16
|
+
## Workflow
|
|
17
|
+
|
|
18
|
+
### Step 1: Gather Context
|
|
19
|
+
|
|
20
|
+
Ask the user:
|
|
21
|
+
- Contract name (kebab-case, becomes the Rust crate name)
|
|
22
|
+
- Contract purpose in one sentence
|
|
23
|
+
- Network target: confirm `{network_preference}` or override
|
|
24
|
+
- Standalone contract or part of a multi-contract workspace?
|
|
25
|
+
|
|
26
|
+
### Step 2: Prerequisites Check
|
|
27
|
+
|
|
28
|
+
Verify the user has the Stellar CLI and Rust toolchain installed:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
stellar --version
|
|
32
|
+
cargo --version
|
|
33
|
+
rustup target list --installed | grep wasm32-unknown-unknown
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
If missing, direct them to `stellar-setup-environment` first.
|
|
37
|
+
|
|
38
|
+
### Step 3: Initialize the Contract
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
stellar contract init {contract_name}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
This creates:
|
|
45
|
+
```
|
|
46
|
+
{contract_name}/
|
|
47
|
+
Cargo.toml # crate manifest with soroban-sdk dependency
|
|
48
|
+
src/
|
|
49
|
+
lib.rs # contract entrypoint
|
|
50
|
+
Makefile # build/test shortcuts
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Explain each file's role and each macro in `lib.rs`:
|
|
54
|
+
- `#[contract]` — marks the struct as a Soroban contract
|
|
55
|
+
- `#[contractimpl]` — marks the implementation block with contract functions
|
|
56
|
+
- `#[contracttype]` — derives Soroban storage encoding for custom types
|
|
57
|
+
|
|
58
|
+
### Step 4: Multi-Contract Workspace (if applicable)
|
|
59
|
+
|
|
60
|
+
Show how to set up a Cargo workspace with a root `Cargo.toml`:
|
|
61
|
+
|
|
62
|
+
```toml
|
|
63
|
+
[workspace]
|
|
64
|
+
members = [
|
|
65
|
+
"contracts/contract-a",
|
|
66
|
+
"contracts/contract-b",
|
|
67
|
+
]
|
|
68
|
+
resolver = "2"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
And per-contract `Cargo.toml`:
|
|
72
|
+
|
|
73
|
+
```toml
|
|
74
|
+
[package]
|
|
75
|
+
name = "{contract_name}"
|
|
76
|
+
version = "0.1.0"
|
|
77
|
+
edition = "2021"
|
|
78
|
+
|
|
79
|
+
[lib]
|
|
80
|
+
crate-type = ["cdylib"]
|
|
81
|
+
|
|
82
|
+
[dependencies]
|
|
83
|
+
soroban-sdk = { version = "22", features = ["testutils"] }
|
|
84
|
+
|
|
85
|
+
[dev-dependencies]
|
|
86
|
+
soroban-sdk = { version = "22", features = ["testutils"] }
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Step 5: Verify Setup
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
cd {contract_name}
|
|
93
|
+
cargo build --target wasm32-unknown-unknown --release
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
A successful build produces `target/wasm32-unknown-unknown/release/{contract_name}.wasm`.
|
|
97
|
+
|
|
98
|
+
### Step 6: Next Steps
|
|
99
|
+
|
|
100
|
+
Suggest:
|
|
101
|
+
- `stellar-write-contract` — implement the contract logic
|
|
102
|
+
- `stellar-test-contract` — write tests before implementing
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: stellar-liquidity-pool
|
|
3
|
+
description: 'Create and interact with Stellar AMM liquidity pools including deposit, withdrawal, and swap operations through the DEX. Use when the user wants to work with Stellar liquidity pools or the Stellar DEX.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Stellar Liquidity Pool
|
|
7
|
+
|
|
8
|
+
## Purpose
|
|
9
|
+
|
|
10
|
+
Guide creation and interaction with Stellar's built-in AMM liquidity pools.
|
|
11
|
+
|
|
12
|
+
## On Activation
|
|
13
|
+
|
|
14
|
+
Load `{network_preference}` from `{project-root}/_stellar/stellar/config.yaml`.
|
|
15
|
+
|
|
16
|
+
## Core Concepts
|
|
17
|
+
|
|
18
|
+
- Stellar uses a **constant-product AMM** (`x * y = k`) for liquidity pools.
|
|
19
|
+
- Pool IDs are **deterministic** from the asset pair — compute them, don't guess.
|
|
20
|
+
- The fee is **0.3%** per swap (fee parameter = 30 in basis points / 100).
|
|
21
|
+
- Liquidity positions are represented as **Liquidity Pool Share assets**.
|
|
22
|
+
- Both assets in the pool must be sorted lexicographically (the SDK handles this).
|
|
23
|
+
|
|
24
|
+
## Workflow
|
|
25
|
+
|
|
26
|
+
### Step 1: Determine Operation
|
|
27
|
+
|
|
28
|
+
Ask the user:
|
|
29
|
+
- Create a new pool and provide initial liquidity?
|
|
30
|
+
- Deposit into an existing pool?
|
|
31
|
+
- Withdraw from a pool?
|
|
32
|
+
- Swap via a pool (path payment)?
|
|
33
|
+
|
|
34
|
+
### Step 2: Compute Pool ID
|
|
35
|
+
|
|
36
|
+
Assets in a pool must be sorted lexicographically. Use `Asset.compare()` to ensure correct ordering:
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
const rawA = new StellarSDK.Asset('USD', issuerPublicKey);
|
|
40
|
+
const rawB = StellarSDK.Asset.native(); // XLM
|
|
41
|
+
|
|
42
|
+
// Always sort — pool ID depends on asset order
|
|
43
|
+
const [assetA, assetB] = StellarSDK.Asset.compare(rawA, rawB) <= 0
|
|
44
|
+
? [rawA, rawB]
|
|
45
|
+
: [rawB, rawA];
|
|
46
|
+
|
|
47
|
+
const liquidityPoolId = StellarSDK.getLiquidityPoolId(
|
|
48
|
+
'constant_product',
|
|
49
|
+
{
|
|
50
|
+
assetA,
|
|
51
|
+
assetB,
|
|
52
|
+
fee: StellarSDK.LiquidityPoolFeeV18, // 30 (0.3%)
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
console.log('Pool ID:', liquidityPoolId);
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Step 3: Create Pool Share Trustline
|
|
59
|
+
|
|
60
|
+
Before depositing, establish a trustline for the pool share asset:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
const poolShareAsset = new StellarSDK.LiquidityPoolAsset(assetA, assetB, 30);
|
|
64
|
+
|
|
65
|
+
const account = await server.loadAccount(providerPublicKey);
|
|
66
|
+
const tx = new StellarSDK.TransactionBuilder(account, {
|
|
67
|
+
fee: StellarSDK.BASE_FEE,
|
|
68
|
+
networkPassphrase: StellarSDK.Networks.TESTNET,
|
|
69
|
+
})
|
|
70
|
+
.addOperation(
|
|
71
|
+
StellarSDK.Operation.changeTrust({ asset: poolShareAsset })
|
|
72
|
+
)
|
|
73
|
+
.setTimeout(30)
|
|
74
|
+
.build();
|
|
75
|
+
|
|
76
|
+
tx.sign(providerKeypair);
|
|
77
|
+
await server.submitTransaction(tx);
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Step 4: Deposit Liquidity
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
const depositTx = new StellarSDK.TransactionBuilder(account, {
|
|
84
|
+
fee: StellarSDK.BASE_FEE,
|
|
85
|
+
networkPassphrase: StellarSDK.Networks.TESTNET,
|
|
86
|
+
})
|
|
87
|
+
.addOperation(
|
|
88
|
+
StellarSDK.Operation.liquidityPoolDeposit({
|
|
89
|
+
liquidityPoolId,
|
|
90
|
+
maxAmountA: '1000', // max of assetA to deposit
|
|
91
|
+
maxAmountB: '1000', // max of assetB to deposit
|
|
92
|
+
minPrice: { n: 1, d: 2 }, // min price ratio A/B (0.5)
|
|
93
|
+
maxPrice: { n: 2, d: 1 }, // max price ratio A/B (2.0)
|
|
94
|
+
})
|
|
95
|
+
)
|
|
96
|
+
.setTimeout(30)
|
|
97
|
+
.build();
|
|
98
|
+
|
|
99
|
+
depositTx.sign(providerKeypair);
|
|
100
|
+
await server.submitTransaction(depositTx);
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The `minPrice`/`maxPrice` protect against front-running by bounding the accepted deposit ratio.
|
|
104
|
+
|
|
105
|
+
### Step 5: Withdraw Liquidity
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
const withdrawTx = new StellarSDK.TransactionBuilder(account, {
|
|
109
|
+
fee: StellarSDK.BASE_FEE,
|
|
110
|
+
networkPassphrase: StellarSDK.Networks.TESTNET,
|
|
111
|
+
})
|
|
112
|
+
.addOperation(
|
|
113
|
+
StellarSDK.Operation.liquidityPoolWithdraw({
|
|
114
|
+
liquidityPoolId,
|
|
115
|
+
amount: '500', // pool shares to burn
|
|
116
|
+
minAmountA: '400', // minimum assetA to receive
|
|
117
|
+
minAmountB: '400', // minimum assetB to receive
|
|
118
|
+
})
|
|
119
|
+
)
|
|
120
|
+
.setTimeout(30)
|
|
121
|
+
.build();
|
|
122
|
+
|
|
123
|
+
withdrawTx.sign(providerKeypair);
|
|
124
|
+
await server.submitTransaction(withdrawTx);
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Step 6: Swap via Pool (Path Payment)
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
// Buy exactly 100 USD, paying at most 110 XLM
|
|
131
|
+
const swapTx = new StellarSDK.TransactionBuilder(account, {
|
|
132
|
+
fee: StellarSDK.BASE_FEE,
|
|
133
|
+
networkPassphrase: StellarSDK.Networks.TESTNET,
|
|
134
|
+
})
|
|
135
|
+
.addOperation(
|
|
136
|
+
StellarSDK.Operation.pathPaymentStrictReceive({
|
|
137
|
+
sendAsset: StellarSDK.Asset.native(),
|
|
138
|
+
sendMax: '110',
|
|
139
|
+
destination: accountPublicKey,
|
|
140
|
+
destAsset: assetA,
|
|
141
|
+
destAmount: '100',
|
|
142
|
+
path: [], // empty = Stellar automatically routes through pools
|
|
143
|
+
})
|
|
144
|
+
)
|
|
145
|
+
.setTimeout(30)
|
|
146
|
+
.build();
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Step 7: Query Pool State
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
const pool = await server.liquidityPools().liquidityPoolId(liquidityPoolId).call();
|
|
153
|
+
console.log('Reserves:', pool.reserves);
|
|
154
|
+
console.log('Total shares:', pool.total_shares);
|
|
155
|
+
console.log('Fee:', pool.fee_bp, 'basis points');
|
|
156
|
+
```
|