@goplausible/openclaw-algorand-plugin 1.1.0 → 1.2.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.
@@ -0,0 +1,260 @@
1
+ # React Integration
2
+
3
+ ## Setup
4
+
5
+ Install dependencies:
6
+
7
+ ```bash
8
+ npm install @txnlab/haystack-router @txnlab/use-wallet-react algosdk
9
+ ```
10
+
11
+ Wrap your app with `WalletProvider`:
12
+
13
+ ```tsx
14
+ import { WalletProvider, WalletId } from '@txnlab/use-wallet-react'
15
+
16
+ const walletProviders = [
17
+ { id: WalletId.PERA },
18
+ { id: WalletId.DEFLY },
19
+ { id: WalletId.LUTE },
20
+ ]
21
+
22
+ function App() {
23
+ return (
24
+ <WalletProvider wallets={walletProviders}>
25
+ <SwapInterface />
26
+ </WalletProvider>
27
+ )
28
+ }
29
+ ```
30
+
31
+ ## Basic Swap Component
32
+
33
+ ```tsx
34
+ import { useState } from 'react'
35
+ import { useWallet } from '@txnlab/use-wallet-react'
36
+ import { RouterClient, type SwapQuote } from '@txnlab/haystack-router'
37
+
38
+ function SwapInterface() {
39
+ const { activeAddress, transactionSigner } = useWallet()
40
+ const [amount, setAmount] = useState('')
41
+ const [fromAsset, setFromAsset] = useState(0) // ALGO
42
+ const [toAsset, setToAsset] = useState(31566704) // USDC
43
+ const [slippage, setSlippage] = useState('1')
44
+ const [quote, setQuote] = useState<SwapQuote | null>(null)
45
+
46
+ const getQuote = async () => {
47
+ const router = new RouterClient({
48
+ apiKey: import.meta.env.VITE_HAYSTACK_API_KEY,
49
+ autoOptIn: true,
50
+ })
51
+
52
+ const amountInBaseUnits = BigInt(Math.floor(parseFloat(amount) * 1_000_000))
53
+
54
+ const result = await router.newQuote({
55
+ fromASAID: fromAsset,
56
+ toASAID: toAsset,
57
+ amount: amountInBaseUnits,
58
+ address: activeAddress!,
59
+ })
60
+
61
+ setQuote(result)
62
+ }
63
+
64
+ const executeSwap = async () => {
65
+ if (!quote || !activeAddress) return
66
+
67
+ const router = new RouterClient({
68
+ apiKey: import.meta.env.VITE_HAYSTACK_API_KEY,
69
+ autoOptIn: true,
70
+ })
71
+
72
+ const swap = await router.newSwap({
73
+ quote,
74
+ address: activeAddress,
75
+ signer: transactionSigner,
76
+ slippage: parseFloat(slippage),
77
+ })
78
+
79
+ const result = await swap.execute()
80
+ console.log(`Confirmed in round ${result.confirmedRound}`)
81
+
82
+ setQuote(null) // Clear stale quote
83
+ }
84
+
85
+ return (
86
+ <div>
87
+ <input
88
+ type="number"
89
+ value={amount}
90
+ onChange={(e) => setAmount(e.target.value)}
91
+ placeholder="Amount"
92
+ />
93
+ <button onClick={getQuote} disabled={!activeAddress || !amount}>
94
+ Get Quote
95
+ </button>
96
+
97
+ {quote && (
98
+ <div>
99
+ <p>Output: {(Number(quote.quote) / 1e6).toFixed(4)} USDC</p>
100
+ <p>USD value: ${quote.usdOut.toFixed(2)}</p>
101
+ <p>
102
+ Route:{' '}
103
+ {Object.entries(quote.flattenedRoute)
104
+ .map(([protocol, pct]) => `${protocol}: ${pct}%`)
105
+ .join(', ')}
106
+ </p>
107
+ <button onClick={executeSwap}>Execute Swap</button>
108
+ </div>
109
+ )}
110
+ </div>
111
+ )
112
+ }
113
+ ```
114
+
115
+ ## TanStack Query Integration
116
+
117
+ For production UIs, use TanStack Query for auto-refreshing quotes and better state management.
118
+
119
+ ```bash
120
+ npm install @tanstack/react-query
121
+ ```
122
+
123
+ ```tsx
124
+ import { useState, useEffect, useMemo } from 'react'
125
+ import {
126
+ useQuery,
127
+ useMutation,
128
+ QueryClient,
129
+ QueryClientProvider,
130
+ } from '@tanstack/react-query'
131
+ import { useWallet } from '@txnlab/use-wallet-react'
132
+ import { RouterClient, type SwapQuote } from '@txnlab/haystack-router'
133
+
134
+ const queryClient = new QueryClient()
135
+
136
+ function SwapWithAutoRefresh() {
137
+ const { activeAddress, transactionSigner } = useWallet()
138
+ const [amount, setAmount] = useState('')
139
+ const [debouncedAmount, setDebouncedAmount] = useState('')
140
+ const [fromAsset] = useState(0)
141
+ const [toAsset] = useState(31566704)
142
+ const [slippage] = useState(1)
143
+
144
+ // Debounce amount input (500ms)
145
+ useEffect(() => {
146
+ const timer = setTimeout(() => setDebouncedAmount(amount), 500)
147
+ return () => clearTimeout(timer)
148
+ }, [amount])
149
+
150
+ const router = useMemo(
151
+ () =>
152
+ new RouterClient({
153
+ apiKey: import.meta.env.VITE_HAYSTACK_API_KEY,
154
+ autoOptIn: true,
155
+ }),
156
+ [],
157
+ )
158
+
159
+ const isValidRequest =
160
+ activeAddress && debouncedAmount && parseFloat(debouncedAmount) > 0
161
+
162
+ // Auto-fetch and refresh quotes
163
+ const {
164
+ data: quote,
165
+ error,
166
+ isLoading,
167
+ } = useQuery({
168
+ queryKey: ['quote', fromAsset, toAsset, debouncedAmount, activeAddress],
169
+ queryFn: () =>
170
+ router.newQuote({
171
+ fromASAID: fromAsset,
172
+ toASAID: toAsset,
173
+ amount: BigInt(Math.floor(parseFloat(debouncedAmount) * 1_000_000)),
174
+ address: activeAddress!,
175
+ }),
176
+ enabled: !!isValidRequest,
177
+ refetchInterval: 15_000, // Refresh every 15 seconds
178
+ retry: 1,
179
+ })
180
+
181
+ // Swap mutation
182
+ const swapMutation = useMutation({
183
+ mutationFn: async () => {
184
+ if (!quote || !activeAddress) throw new Error('Missing quote or address')
185
+
186
+ const swap = await router.newSwap({
187
+ quote,
188
+ address: activeAddress,
189
+ signer: transactionSigner,
190
+ slippage,
191
+ })
192
+ return swap.execute()
193
+ },
194
+ onSuccess: (result) => {
195
+ console.log(`Confirmed in round ${result.confirmedRound}`)
196
+ queryClient.invalidateQueries({ queryKey: ['quote'] })
197
+ },
198
+ })
199
+
200
+ return (
201
+ <div>
202
+ <input
203
+ type="number"
204
+ value={amount}
205
+ onChange={(e) => setAmount(e.target.value)}
206
+ placeholder="Amount"
207
+ />
208
+
209
+ {isLoading && <p>Fetching quote...</p>}
210
+ {error && <p>Error: {(error as Error).message}</p>}
211
+
212
+ {quote && (
213
+ <div>
214
+ <p>Output: {(Number(quote.quote) / 1e6).toFixed(4)} USDC</p>
215
+ <p>USD: ${quote.usdOut.toFixed(2)}</p>
216
+ <button
217
+ onClick={() => swapMutation.mutate()}
218
+ disabled={swapMutation.isPending}
219
+ >
220
+ {swapMutation.isPending ? 'Swapping...' : 'Swap'}
221
+ </button>
222
+ </div>
223
+ )}
224
+ </div>
225
+ )
226
+ }
227
+ ```
228
+
229
+ Key patterns:
230
+
231
+ - **Debounced input**: Prevent quote requests on every keystroke
232
+ - **Auto-refresh**: `refetchInterval: 15_000` keeps quotes current
233
+ - **Invalidation**: Clear stale quotes after a successful swap
234
+ - **Loading/error states**: TanStack Query manages all async state
235
+
236
+ ## Displaying Route Details
237
+
238
+ ```tsx
239
+ function RouteDisplay({ quote }: { quote: SwapQuote }) {
240
+ return (
241
+ <div>
242
+ <h4>Route</h4>
243
+ {quote.route.map((route, i) => (
244
+ <div key={i}>
245
+ <strong>{route.percentage}%</strong>
246
+ {route.path.map((hop, j) => (
247
+ <span key={j}>
248
+ {j > 0 && ' → '}
249
+ {hop.in.unit_name} → {hop.out.unit_name} ({hop.name})
250
+ </span>
251
+ ))}
252
+ </div>
253
+ ))}
254
+ {quote.userPriceImpact !== undefined && (
255
+ <p>Price impact: {quote.userPriceImpact.toFixed(2)}%</p>
256
+ )}
257
+ </div>
258
+ )
259
+ }
260
+ ```
@@ -0,0 +1,161 @@
1
+ # Swaps
2
+
3
+ ## Executing a Swap
4
+
5
+ ```typescript
6
+ import { RouterClient } from '@txnlab/haystack-router'
7
+
8
+ const router = new RouterClient({
9
+ apiKey: '1b72df7e-1131-4449-8ce1-29b79dd3f51e', // Free tier (60 requests/min)
10
+ })
11
+
12
+ // 1. Get a quote
13
+ const quote = await router.newQuote({
14
+ fromASAID: 0,
15
+ toASAID: 31566704,
16
+ amount: 1_000_000,
17
+ address: activeAddress,
18
+ })
19
+
20
+ // 2. Create and execute swap
21
+ const swap = await router.newSwap({
22
+ quote,
23
+ address: activeAddress,
24
+ signer: transactionSigner,
25
+ slippage: 1, // 1%
26
+ })
27
+
28
+ const result = await swap.execute()
29
+ console.log(`Confirmed in round ${result.confirmedRound}`)
30
+ ```
31
+
32
+ ## newSwap() Parameters
33
+
34
+ | Parameter | Type | Required | Description |
35
+ | ---------- | ------------------------------------- | -------- | ----------------------------------------- |
36
+ | `quote` | `SwapQuote \| FetchQuoteResponse` | Yes | Quote from `newQuote()` or `fetchQuote()` |
37
+ | `address` | `string` | Yes | Signer's Algorand address |
38
+ | `signer` | `TransactionSigner \| SignerFunction` | Yes | Transaction signing function |
39
+ | `slippage` | `number` | Yes | Slippage tolerance (e.g., `1` = 1%) |
40
+ | `note` | `Uint8Array` | No | Note attached to input transaction |
41
+
42
+ ## Signer Patterns
43
+
44
+ ### Browser: use-wallet
45
+
46
+ ```typescript
47
+ import { useWallet } from '@txnlab/use-wallet-react'
48
+
49
+ const { activeAddress, transactionSigner } = useWallet()
50
+
51
+ const swap = await router.newSwap({
52
+ quote,
53
+ address: activeAddress,
54
+ signer: transactionSigner,
55
+ slippage: 1,
56
+ })
57
+ ```
58
+
59
+ The SDK supports two signer return patterns:
60
+
61
+ - **Pera/Defly style**: Returns `Uint8Array[]` matching `indexesToSign` length
62
+ - **Lute/ARC-1 style**: Returns `(Uint8Array | null)[]` matching full group length, `null` for unsigned
63
+
64
+ Both are detected and handled automatically.
65
+
66
+ ## Slippage Guidance
67
+
68
+ | Pair Type | Recommended Slippage |
69
+ | ----------------- | -------------------- |
70
+ | Stable pairs | 0.5–1% |
71
+ | Volatile pairs | 1–3% |
72
+ | Low liquidity | 3–5% |
73
+
74
+ Slippage is verified on the **final output** of the swap, not individual hops. This means intermediate steps can have higher variance as long as the final result is within tolerance.
75
+
76
+ ## Execution Result
77
+
78
+ ```typescript
79
+ const result = await swap.execute()
80
+
81
+ result.confirmedRound // bigint — block where swap confirmed
82
+ result.txIds // string[] — all transaction IDs
83
+ result.methodResults // ABIResult[] — ABI method call results
84
+ ```
85
+
86
+ ## Swap Summary
87
+
88
+ After execution, get exact amounts (may differ from quote due to slippage):
89
+
90
+ ```typescript
91
+ const result = await swap.execute()
92
+ const summary = swap.getSummary()
93
+
94
+ if (summary) {
95
+ summary.inputAssetId // bigint
96
+ summary.outputAssetId // bigint
97
+ summary.inputAmount // bigint — exact input sent
98
+ summary.outputAmount // bigint — exact output received
99
+ summary.totalFees // bigint — total ALGO fees (microAlgos)
100
+ summary.transactionCount // number
101
+ summary.inputTxnId // string — user-signed input txn ID
102
+ summary.outputTxnId // string — app call containing output
103
+ }
104
+ ```
105
+
106
+ ## Advanced: Custom Transaction Composition
107
+
108
+ Add custom transactions before/after the swap in the same atomic group:
109
+
110
+ ```typescript
111
+ const swap = await router.newSwap({
112
+ quote,
113
+ address: activeAddress,
114
+ signer: transactionSigner,
115
+ slippage: 1,
116
+ })
117
+
118
+ const result = await swap
119
+ .addTransaction(customTxn) // Add before swap
120
+ .addSwapTransactions() // Add swap txns + middleware
121
+ .addMethodCall(abiCall) // Add ABI call after swap
122
+ .execute()
123
+ ```
124
+
125
+ Constraints:
126
+
127
+ - Max 16 transactions per group
128
+ - Non-composable swaps (Tinyman v1) cannot add custom transactions
129
+ - Call `addSwapTransactions()` to manually control ordering
130
+
131
+ ## Advanced: Step-by-Step Execution
132
+
133
+ For more control over the signing and submission flow:
134
+
135
+ ```typescript
136
+ const swap = await router.newSwap({ quote, address, signer, slippage: 1 })
137
+
138
+ // Build (assigns group IDs)
139
+ const txnsWithSigners = swap.buildGroup()
140
+
141
+ // Sign
142
+ const signedTxns = await swap.sign()
143
+
144
+ // Submit (doesn't wait)
145
+ const txIds = await swap.submit()
146
+
147
+ // Check status
148
+ swap.getStatus() // BUILDING → BUILT → SIGNED → SUBMITTED → COMMITTED
149
+ ```
150
+
151
+ ## Error Handling
152
+
153
+ Common errors:
154
+
155
+ - **Slippage exceeded** — price moved beyond tolerance, refetch quote
156
+ - **Insufficient balance** — check account balance
157
+ - **Asset not opted in** — include opt-in in quote or opt in manually
158
+ - **Transaction rejected** — user declined or signing failed
159
+ - **Network timeout** — retry after brief delay
160
+
161
+ Quotes are time-sensitive. If a quote is stale (prices moved significantly), refetch before executing.
@@ -0,0 +1,146 @@
1
+ ---
2
+ name: haystack-router-interaction
3
+ description: Route and execute optimal token swaps on Algorand using Haystack Router via Algorand MCP tools. Use when getting best-price quotes across multiple Algorand DEXes and LST protocols, executing atomic swaps, and checking asset opt-in — all through the Algorand MCP server. Strong triggers include haystack swap, best price swap, DEX aggregator swap, swap ALGO to USDC, api_haystack, haystack quote, execute swap, swap routing, optimal swap, multi-DEX swap.
4
+ ---
5
+
6
+ # Haystack Router (Interaction)
7
+
8
+ This is the parent skill for interacting with Haystack Router through Algorand MCP tools — getting quotes, executing swaps, and checking opt-in status. All operations use the Algorand MCP wallet for signing; no SDK installation or API keys needed.
9
+
10
+ > **Building an application** that integrates Haystack Router directly? Use the **haystack-router-development** skill instead — it covers the `@txnlab/haystack-router` SDK, React integration, Node.js automation, middleware, and the full API surface.
11
+ > **Need general wallet/transaction guidance?** See the **algorand-interaction** skill for wallet setup, session start checklist, network selection, and pre-transaction validation.
12
+
13
+ Haystack Router is a DEX aggregator and smart order routing protocol on Algorand. It finds optimal swap routes across multiple DEXes (Tinyman V2, Pact, Folks) and LST protocols (tALGO, xALGO), then executes them atomically through on-chain smart contracts.
14
+
15
+ ## mcporter Syntax (OpenClaw CLI)
16
+
17
+ When calling Haystack Router MCP tools via mcporter in OpenClaw CLI:
18
+
19
+ ```bash
20
+ mcporter call algorand-mcp.api_haystack_get_swap_quote --args '{"fromASAID": 0, "toASAID": 31566704, "amount": 1000000, "network": "mainnet"}'
21
+ ```
22
+
23
+ Key: use `server.tool` (dot notation) with `--args '{"json"}'`. See `algorand-interaction` skill for full mcporter reference.
24
+
25
+ ## Network Selection
26
+
27
+ Every Haystack Router tool accepts a `network` parameter:
28
+
29
+ | Value | Description |
30
+ |-------|-------------|
31
+ | `mainnet` | Algorand mainnet (default) — **real value, exercise caution** |
32
+ | `testnet` | Algorand testnet — safe for development |
33
+
34
+ Default to `testnet` during development. Always confirm with the user before mainnet swaps.
35
+
36
+ ## Algorand MCP Haystack Router Tools
37
+
38
+ Three dedicated Algorand MCP tools provide full Haystack Router functionality. These handle quoting, execution (with wallet signing), and opt-in checking — no raw mnemonics or secret keys needed.
39
+
40
+ ### `api_haystack_get_swap_quote`
41
+
42
+ Get an optimized swap quote without executing. Use to preview pricing, route, and price impact before confirming with user.
43
+
44
+ ```
45
+ → api_haystack_get_swap_quote {
46
+ fromASAID: 0, // Input asset (0 = ALGO)
47
+ toASAID: 31566704, // Output asset (USDC)
48
+ amount: 1000000, // 1 ALGO in base units
49
+ type: "fixed-input", // or "fixed-output"
50
+ address: "<address>", // optional, for opt-in detection
51
+ maxGroupSize: 16, // optional
52
+ maxDepth: 4, // optional
53
+ network: "mainnet"
54
+ }
55
+
56
+ Returns: expectedOutput, inputAmount, usdIn, usdOut, userPriceImpact,
57
+ route, flattenedRoute, requiredAppOptIns, protocolFees
58
+ ```
59
+
60
+ ### `api_haystack_execute_swap`
61
+
62
+ All-in-one swap: quote → sign (via wallet) → submit → confirm. Uses the active wallet account for signing. Enforces wallet spending limits.
63
+
64
+ ```
65
+ → api_haystack_execute_swap {
66
+ fromASAID: 0, // Input asset
67
+ toASAID: 31566704, // Output asset
68
+ amount: 1000000, // Amount in base units
69
+ slippage: 1, // 1% slippage tolerance
70
+ type: "fixed-input", // optional
71
+ note: "my swap", // optional text note
72
+ maxGroupSize: 16, // optional
73
+ maxDepth: 4, // optional
74
+ network: "mainnet"
75
+ }
76
+
77
+ Returns: status, confirmedRound, txIds, signer, nickname, quote details,
78
+ summary (inputAmount, outputAmount, totalFees, transactionCount)
79
+ ```
80
+
81
+ ### `api_haystack_needs_optin`
82
+
83
+ Check if an address needs to opt into an asset before swapping.
84
+
85
+ ```
86
+ → api_haystack_needs_optin {
87
+ address: "<address>",
88
+ assetId: 31566704,
89
+ network: "mainnet"
90
+ }
91
+
92
+ Returns: { address, assetId, needsOptIn: true/false, network }
93
+ ```
94
+
95
+ ## Algorand MCP Agent Swap Workflow
96
+
97
+ ```
98
+ Step 1: Check wallet
99
+ → wallet_get_info { network }
100
+
101
+ Step 2: Check opt-in (if swapping to an ASA)
102
+ → api_haystack_needs_optin { address, assetId, network }
103
+ → If needed: wallet_optin_asset { assetId, network }
104
+
105
+ Step 3: Preview quote (recommended — show user before executing)
106
+ → api_haystack_get_swap_quote { fromASAID, toASAID, amount, address, network }
107
+ → Present to user: expected output, USD values, route, price impact
108
+
109
+ Step 4: User confirms → Execute
110
+ → api_haystack_execute_swap { fromASAID, toASAID, amount, slippage, network }
111
+ → Returns confirmed result with summary
112
+ ```
113
+
114
+ **Key rules:**
115
+ - Always check wallet with `wallet_get_info` before any swap
116
+ - Always confirm with the user before executing (show quote details)
117
+ - The execute tool handles signing via the active wallet — no manual signing needed
118
+ - Default to testnet during development; confirm before mainnet
119
+ - Quotes are time-sensitive — execute promptly after user confirms
120
+
121
+ ## Key Concepts
122
+
123
+ - **Amounts** are always in base units (microAlgos for ALGO, smallest unit for ASAs)
124
+ - **ASA IDs**: 0 = ALGO, 31566704 = USDC, etc.
125
+ - **Quote types**: `fixed-input` (default) — specify input amount; `fixed-output` — specify desired output
126
+ - **Slippage**: Percentage tolerance on output (e.g., 1 = 1%). Applied to the final output, not individual hops
127
+ - **Routing**: Supports multi-hop and parallel (combo) swaps for optimal pricing
128
+
129
+ ## Reference Files
130
+
131
+ Read the appropriate file based on the task:
132
+
133
+ | Task | Reference |
134
+ | ------------------------------------------- | ----------------------------------------------------- |
135
+ | Quick start and Algorand MCP tool reference | [getting-started.md](references/getting-started.md) |
136
+ | Get swap quotes, display pricing | [quotes.md](references/quotes.md) |
137
+ | Execute swaps via Algorand MCP tools | [swaps.md](references/swaps.md) |
138
+ | Automate swaps via Algorand MCP tools | [node-automation.md](references/node-automation.md) |
139
+ | Network, slippage, rate limits, ASA IDs | [configuration.md](references/configuration.md) |
140
+
141
+ ## How to Use This Skill
142
+
143
+ 1. **Start here** to understand the three Haystack Router MCP tools and the swap workflow
144
+ 2. **Read the topic `.md`** file for detailed guidance on quotes, swaps, or automation
145
+ 3. **For SDK-based development** (React UIs, Node.js apps), see the `haystack-router-development` skill
146
+ 4. **For wallet setup and general blockchain interaction**, see the `algorand-interaction` skill
@@ -0,0 +1,53 @@
1
+ # Configuration (Algorand MCP)
2
+
3
+ ## Network
4
+
5
+ All Algorand MCP Haystack Router tools accept a `network` parameter:
6
+
7
+ - `"mainnet"` — MainNet (default)
8
+ - `"testnet"` — TestNet
9
+
10
+ ```
11
+ → api_haystack_get_swap_quote {
12
+ fromASAID: 0, toASAID: 31566704, amount: 1000000,
13
+ network: "testnet"
14
+ }
15
+ ```
16
+
17
+ Default to **testnet** during development; confirm with user before using mainnet.
18
+
19
+ ## Slippage
20
+
21
+ Set slippage (percentage tolerance on output) when executing swaps:
22
+
23
+ ```
24
+ → api_haystack_execute_swap {
25
+ fromASAID: 0, toASAID: 31566704, amount: 1000000,
26
+ slippage: 1, // 1% — receive at least 99% of quoted output
27
+ network: "testnet"
28
+ }
29
+ ```
30
+
31
+ **Recommendations:**
32
+
33
+ - **Stable pairs** (ALGO/USDC): 0.5–1%
34
+ - **Volatile pairs**: 1–3%
35
+ - **Low liquidity**: 3–5%
36
+
37
+ Slippage is verified on the **final output** of the swap, not on individual hops.
38
+
39
+ ## Rate Limits
40
+
41
+ The Algorand MCP server uses a free tier API key (60 requests/min). This applies to all Haystack Router tool calls. Override via `HAYSTACK_API_KEY` environment variable.
42
+
43
+ ## Common ASA IDs
44
+
45
+ | Asset | ASA ID |
46
+ | ----- | --------- |
47
+ | ALGO | 0 |
48
+ | USDC | 31566704 |
49
+ | USDt | 312769 |
50
+ | goBTC | 386192725 |
51
+ | goETH | 386195940 |
52
+
53
+ Look up ASA IDs on [Allo.info](https://allo.info) or [Pera Explorer](https://explorer.perawallet.app/).
@@ -0,0 +1,48 @@
1
+ # Getting Started
2
+
3
+ When operating as an Algorand MCP agent, use Algorand MCP tools directly. No SDK installation or API key management needed — the Algorand MCP server handles this internally.
4
+
5
+ ## Quick Swap (2 steps)
6
+
7
+ ```
8
+ 1. wallet_get_info { network: "testnet" }
9
+ → Get wallet address and balance
10
+
11
+ 2. api_haystack_execute_swap {
12
+ fromASAID: 0, toASAID: 31566704, amount: 1000000,
13
+ slippage: 1, network: "testnet"
14
+ }
15
+ → Quotes, signs via wallet, submits, confirms — all in one call
16
+ ```
17
+
18
+ ## With Preview (recommended for user-facing swaps)
19
+
20
+ ```
21
+ 1. wallet_get_info { network: "testnet" }
22
+ 2. api_haystack_needs_optin { address, assetId: 31566704, network: "testnet" }
23
+ → If needed: wallet_optin_asset { assetId: 31566704, network: "testnet" }
24
+ 3. api_haystack_get_swap_quote { fromASAID: 0, toASAID: 31566704, amount: 1000000, network: "testnet" }
25
+ → Show user the quote → get confirmation
26
+ 4. api_haystack_execute_swap { fromASAID: 0, toASAID: 31566704, amount: 1000000, slippage: 1, network: "testnet" }
27
+ ```
28
+
29
+ ## Algorand MCP Tool Reference
30
+
31
+ | Tool | Purpose |
32
+ | ------------------------------- | ------------------------------------------------ |
33
+ | `api_haystack_get_swap_quote` | Preview swap quote with routing and pricing |
34
+ | `api_haystack_execute_swap` | Execute swap: quote + sign + submit + confirm |
35
+ | `api_haystack_needs_optin` | Check if address needs asset opt-in |
36
+ | `wallet_get_info` | Get wallet address and ALGO balance |
37
+ | `wallet_optin_asset` | Opt into an ASA (one-step build+sign+submit) |
38
+
39
+ See [swaps.md](swaps.md) for detailed workflow and [quotes.md](quotes.md) for quote parameters.
40
+
41
+ ## Amounts and Units
42
+
43
+ All amounts are in **base units** (smallest denomination):
44
+
45
+ | Asset | Decimals | 1 unit in base | Example |
46
+ | ------------------- | -------- | -------------- | -------------------- |
47
+ | ALGO (ASA 0) | 6 | 1,000,000 | `1_000_000` = 1 ALGO |
48
+ | USDC (ASA 31566704) | 6 | 1,000,000 | `5_000_000` = 5 USDC |