@goplausible/openclaw-algorand-plugin 1.0.2 → 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.
Files changed (22) hide show
  1. package/memory/algorand-plugin.md +1 -0
  2. package/openclaw.plugin.json +4 -2
  3. package/package.json +1 -1
  4. package/skills/algorand-interaction/SKILL.md +6 -2
  5. package/skills/algorand-interaction/references/algorand-mcp.md +49 -2
  6. package/skills/algorand-interaction/references/examples-algorand-mcp.md +60 -0
  7. package/skills/haystack-router-development/SKILL.md +85 -0
  8. package/skills/haystack-router-development/references/api-reference.md +381 -0
  9. package/skills/haystack-router-development/references/configuration.md +184 -0
  10. package/skills/haystack-router-development/references/fees-and-referrals.md +91 -0
  11. package/skills/haystack-router-development/references/getting-started.md +93 -0
  12. package/skills/haystack-router-development/references/migration.md +53 -0
  13. package/skills/haystack-router-development/references/node-automation.md +113 -0
  14. package/skills/haystack-router-development/references/quotes.md +155 -0
  15. package/skills/haystack-router-development/references/react-integration.md +260 -0
  16. package/skills/haystack-router-development/references/swaps.md +161 -0
  17. package/skills/haystack-router-interaction/SKILL.md +146 -0
  18. package/skills/haystack-router-interaction/references/configuration.md +53 -0
  19. package/skills/haystack-router-interaction/references/getting-started.md +48 -0
  20. package/skills/haystack-router-interaction/references/node-automation.md +51 -0
  21. package/skills/haystack-router-interaction/references/quotes.md +80 -0
  22. package/skills/haystack-router-interaction/references/swaps.md +84 -0
@@ -0,0 +1,184 @@
1
+ # Configuration (SDK)
2
+
3
+ ## API Key Tiers
4
+
5
+ | Tier | Key | Rate Limit | Use Case |
6
+ | -------------- | -------------------------------------- | --------------- | --------------------------------------------- |
7
+ | **Free** | `1b72df7e-1131-4449-8ce1-29b79dd3f51e` | 60 requests/min | Development, testing, low-volume integrations |
8
+ | **Production** | Request from support@txnlab.dev | Higher limits | Production applications |
9
+
10
+ The free tier key requires no registration and works immediately. The rate limit applies to all API calls (both `fetchQuote` and `fetchExecuteSwapTxns`), not just quotes.
11
+
12
+ For production integrations with higher rate limits, contact support@txnlab.dev for a dedicated key.
13
+
14
+ ## RouterClient Options
15
+
16
+ ```typescript
17
+ import { RouterClient } from '@txnlab/haystack-router'
18
+
19
+ const router = new RouterClient({
20
+ // Required
21
+ apiKey: '1b72df7e-1131-4449-8ce1-29b79dd3f51e', // Free tier (60 requests/min)
22
+
23
+ // Optional
24
+ apiBaseUrl: undefined, // Override API endpoint (SDK manages defaults)
25
+ algodUri: undefined, // Algod node URI (default: MainNet via Nodely)
26
+ algodToken: undefined, // Algod node token
27
+ algodPort: undefined, // Algod node port (default: 443)
28
+ referrerAddress: undefined, // Earn 25% of swap fees
29
+ feeBps: undefined, // Fee in basis points (default: 10, max: 300)
30
+ autoOptIn: false, // Auto-detect asset opt-in needs
31
+ debugLevel: 'none', // Logging: 'none' | 'info' | 'debug' | 'trace'
32
+ middleware: [], // SwapMiddleware plugins
33
+ })
34
+ ```
35
+
36
+ ## Network Configuration
37
+
38
+ ### MainNet (Default)
39
+
40
+ ```typescript
41
+ const router = new RouterClient({
42
+ apiKey: '1b72df7e-1131-4449-8ce1-29b79dd3f51e',
43
+ })
44
+ ```
45
+
46
+ Uses default Nodely MainNet algod endpoint.
47
+
48
+ ### TestNet
49
+
50
+ ```typescript
51
+ const router = new RouterClient({
52
+ apiKey: '1b72df7e-1131-4449-8ce1-29b79dd3f51e', // Free tier (60 requests/min)
53
+ algodUri: 'https://testnet-api.4160.nodely.dev/',
54
+ })
55
+ ```
56
+
57
+ ### Custom Algod Node
58
+
59
+ ```typescript
60
+ const router = new RouterClient({
61
+ apiKey: '1b72df7e-1131-4449-8ce1-29b79dd3f51e', // Free tier (60 requests/min)
62
+ algodUri: 'http://localhost:4001',
63
+ algodToken:
64
+ 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
65
+ algodPort: 4001,
66
+ })
67
+ ```
68
+
69
+ ## Slippage
70
+
71
+ Slippage is a percentage tolerance on the output amount. Set per-swap, not on the client.
72
+
73
+ ```typescript
74
+ const swap = await router.newSwap({
75
+ quote,
76
+ address,
77
+ signer,
78
+ slippage: 1, // 1% — receive at least 99% of quoted output
79
+ })
80
+ ```
81
+
82
+ **Recommendations:**
83
+
84
+ - **Stable pairs** (ALGO/USDC): 0.5–1%
85
+ - **Volatile pairs**: 1–3%
86
+ - **Low liquidity**: 3–5%
87
+
88
+ Slippage is verified on the **final output** of the swap, not on individual hops. This means intermediate steps can have higher variance as long as the final result is within tolerance.
89
+
90
+ ## Fee Configuration
91
+
92
+ ```typescript
93
+ const router = new RouterClient({
94
+ apiKey: '1b72df7e-1131-4449-8ce1-29b79dd3f51e', // Free tier (60 requests/min)
95
+ feeBps: 15, // 0.15% output fee
96
+ })
97
+ ```
98
+
99
+ - **Default**: 10 bps (0.10%)
100
+ - **Range**: 10–300 bps (0.10%–3.00%)
101
+ - Fee is applied to the **output amount**
102
+ - Additional network transaction fees apply (paid by swapper)
103
+
104
+ ## Referrer Address
105
+
106
+ Earn 25% of swap fees by setting a referrer address:
107
+
108
+ ```typescript
109
+ const router = new RouterClient({
110
+ apiKey: '1b72df7e-1131-4449-8ce1-29b79dd3f51e', // Free tier (60 requests/min)
111
+ referrerAddress: 'YOUR_ALGORAND_ADDRESS',
112
+ })
113
+ ```
114
+
115
+ See [fees-and-referrals.md](fees-and-referrals.md) for details on the referral program.
116
+
117
+ ## Auto Opt-In
118
+
119
+ When `autoOptIn: true`, the SDK automatically checks if the user needs to opt into the output asset and includes the opt-in transaction in the swap group.
120
+
121
+ ```typescript
122
+ const router = new RouterClient({
123
+ apiKey: '1b72df7e-1131-4449-8ce1-29b79dd3f51e', // Free tier (60 requests/min)
124
+ autoOptIn: true,
125
+ })
126
+
127
+ // Address is required for auto opt-in detection
128
+ const quote = await router.newQuote({
129
+ fromASAID: 0,
130
+ toASAID: 31566704,
131
+ amount: 1_000_000,
132
+ address: activeAddress,
133
+ })
134
+ ```
135
+
136
+ ## Middleware
137
+
138
+ Plugins that hook into the quote and swap lifecycle:
139
+
140
+ ```typescript
141
+ import { RouterClient, AutoOptOutMiddleware } from '@txnlab/haystack-router'
142
+
143
+ // Built-in: auto opt-out when swapping full balance
144
+ const autoOptOut = new AutoOptOutMiddleware({
145
+ excludedAssets: [31566704], // Never auto-opt-out of USDC
146
+ })
147
+
148
+ const router = new RouterClient({
149
+ apiKey: '1b72df7e-1131-4449-8ce1-29b79dd3f51e', // Free tier (60 requests/min)
150
+ middleware: [autoOptOut],
151
+ })
152
+ ```
153
+
154
+ See [api-reference.md](api-reference.md) for the `SwapMiddleware` interface.
155
+
156
+ ## Debug Logging
157
+
158
+ ```typescript
159
+ const router = new RouterClient({
160
+ apiKey: '1b72df7e-1131-4449-8ce1-29b79dd3f51e', // Free tier (60 requests/min)
161
+ debugLevel: 'info',
162
+ })
163
+ ```
164
+
165
+ | Level | Output |
166
+ | ------- | ------------------------------------------------------------------ |
167
+ | `none` | No logging (default) |
168
+ | `info` | High-level operations (quote fetched, swap submitted) |
169
+ | `debug` | Detailed flow (middleware applied, validation, status transitions) |
170
+ | `trace` | Everything including request/response payloads |
171
+
172
+ ## Finding ASA IDs
173
+
174
+ Common Algorand Standard Asset IDs:
175
+
176
+ | Asset | ASA ID |
177
+ | ----- | --------- |
178
+ | ALGO | 0 |
179
+ | USDC | 31566704 |
180
+ | USDt | 312769 |
181
+ | goBTC | 386192725 |
182
+ | goETH | 386195940 |
183
+
184
+ Look up ASA IDs on [Allo.info](https://allo.info) or [Pera Explorer](https://explorer.perawallet.app/).
@@ -0,0 +1,91 @@
1
+ # Fees and Referrals
2
+
3
+ ## Fee Structure
4
+
5
+ ### Swap Fees
6
+
7
+ - **Default fee**: 10 basis points (0.10%) on the **output** amount
8
+ - **Configurable**: 10–300 bps via the `feeBps` parameter
9
+ - **Positive slippage**: When a swap executes better than quoted, the excess is captured as additional revenue
10
+
11
+ ```typescript
12
+ const router = new RouterClient({
13
+ apiKey: '1b72df7e-1131-4449-8ce1-29b79dd3f51e', // Free tier (60 requests/min)
14
+ feeBps: 15, // 0.15%
15
+ })
16
+ ```
17
+
18
+ ### Network Fees
19
+
20
+ Swappers pay all Algorand network transaction fees (min fee per transaction in the group). These are separate from the protocol output fee.
21
+
22
+ ### Fee Distribution
23
+
24
+ | Recipient | Share |
25
+ | --------- | ----- |
26
+ | Protocol | 75% |
27
+ | Referrer | 25% |
28
+
29
+ ## Referral Program
30
+
31
+ Integrators earn **25% of swap fees** generated by their users.
32
+
33
+ ### Setup
34
+
35
+ Pass your Algorand address as the `referrerAddress` when creating the RouterClient:
36
+
37
+ ```typescript
38
+ const router = new RouterClient({
39
+ apiKey: '1b72df7e-1131-4449-8ce1-29b79dd3f51e', // Free tier (60 requests/min)
40
+ referrerAddress: 'YOUR_ALGORAND_ADDRESS',
41
+ })
42
+ ```
43
+
44
+ Every swap executed through this client generates referral commissions.
45
+
46
+ ### How It Works
47
+
48
+ 1. Fees from each swap are deposited into an **escrow account** linked to your referrer address
49
+ 2. The escrow is an on-chain account **rekeyed to the protocol app** — only your address can claim from it
50
+ 3. When new assets are swapped, the escrow automatically opts into them
51
+ 4. Commissions accumulate across all assets traded
52
+
53
+ ### Claiming Commissions
54
+
55
+ Claim accumulated commissions through the referrer dashboard:
56
+
57
+ - **Dashboard**: Register and claim at the referrer portal
58
+ - **Bulk claim**: Withdraw multiple asset commissions simultaneously
59
+ - **Single claim**: Withdraw a specific asset, optionally closing out the position
60
+
61
+ ### Auto-Conversion (Optional)
62
+
63
+ Optionally convert accumulated commissions to a target asset (ALGO, USDC, etc.):
64
+
65
+ - **Disabled by default** — requires explicit opt-in
66
+ - **1% convenience fee** on auto-conversion swaps
67
+ - Runs daily when enabled
68
+ - Select any target asset for conversion
69
+ - Can be enabled/disabled at any time
70
+
71
+ ### Referral Escrow Details
72
+
73
+ - Each referrer gets a unique escrow account
74
+ - Escrow is **permanently linked** once created (cannot be unlinked)
75
+ - The escrow is controlled by the protocol smart contract
76
+ - Only the linked referrer address can claim funds
77
+ - Minimum 0.257 ALGO required for escrow Minimum Balance Requirement (MBR)
78
+
79
+ ## Protocol Contracts
80
+
81
+ ### MainNet (Latest: V2.2)
82
+
83
+ - **Application ID**: 3172554435
84
+ - **Contract Address**: `ESPO2SMA5BPAAAFAN66EFNHGR3HJ63U2OYM6RJXSEP6YOBU4HJTWZG7D5A`
85
+
86
+ ### Security
87
+
88
+ The protocol has been audited by:
89
+
90
+ - **Ulam Labs** (April 2023)
91
+ - **Vantage Point** (November 2022)
@@ -0,0 +1,93 @@
1
+ # Getting Started
2
+
3
+ ## Prerequisites
4
+
5
+ - **Node.js** >= 20
6
+ - **algosdk** 3.x (peer dependency)
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ npm install @txnlab/haystack-router algosdk
12
+ ```
13
+
14
+ ## RouterClient Initialization
15
+
16
+ ```typescript
17
+ import { RouterClient } from '@txnlab/haystack-router'
18
+
19
+ const router = new RouterClient({
20
+ apiKey: '1b72df7e-1131-4449-8ce1-29b79dd3f51e', // Free tier (60 requests/min)
21
+ })
22
+ ```
23
+
24
+ ### With Options
25
+
26
+ ```typescript
27
+ const router = new RouterClient({
28
+ apiKey: '1b72df7e-1131-4449-8ce1-29b79dd3f51e', // Free tier (60 requests/min)
29
+ autoOptIn: true, // Auto-detect asset opt-in needs
30
+ referrerAddress: 'ABC...', // Earn 25% of swap fees
31
+ feeBps: 15, // Fee in basis points (default: 10)
32
+ debugLevel: 'info', // 'none' | 'info' | 'debug' | 'trace'
33
+ })
34
+ ```
35
+
36
+ ### TestNet
37
+
38
+ Override the algod connection and API base URL for TestNet:
39
+
40
+ ```typescript
41
+ const router = new RouterClient({
42
+ apiKey: '1b72df7e-1131-4449-8ce1-29b79dd3f51e', // Free tier (60 requests/min)
43
+ algodUri: 'https://testnet-api.4160.nodely.dev/',
44
+ // Set apiBaseUrl if using a TestNet-specific API endpoint
45
+ })
46
+ ```
47
+
48
+ ## Quick Example
49
+
50
+ ```typescript
51
+ import { RouterClient } from '@txnlab/haystack-router'
52
+
53
+ const router = new RouterClient({
54
+ apiKey: '1b72df7e-1131-4449-8ce1-29b79dd3f51e', // Free tier (60 requests/min)
55
+ })
56
+
57
+ // Get a quote: swap 1 ALGO → USDC
58
+ const quote = await router.newQuote({
59
+ fromASAID: 0, // ALGO
60
+ toASAID: 31566704, // USDC
61
+ amount: 1_000_000, // 1 ALGO in microAlgos
62
+ address: activeAddress,
63
+ })
64
+
65
+ console.log(`Expected output: ${quote.quote} microUSDC`)
66
+ console.log(`USD value: $${quote.usdOut}`)
67
+
68
+ // Execute the swap (use-wallet signer for browser, custom signer for Node.js)
69
+ const swap = await router.newSwap({
70
+ quote,
71
+ address: activeAddress,
72
+ signer: transactionSigner,
73
+ slippage: 1, // 1% slippage tolerance
74
+ })
75
+
76
+ const result = await swap.execute()
77
+ console.log(`Confirmed in round ${result.confirmedRound}`)
78
+ ```
79
+
80
+ ## Amounts and Units
81
+
82
+ All amounts are in **base units** (smallest denomination):
83
+
84
+ | Asset | Decimals | 1 unit in base | Example |
85
+ | ------------------- | -------- | -------------- | -------------------- |
86
+ | ALGO (ASA 0) | 6 | 1,000,000 | `1_000_000` = 1 ALGO |
87
+ | USDC (ASA 31566704) | 6 | 1,000,000 | `5_000_000` = 5 USDC |
88
+
89
+ Convert human-readable amounts:
90
+
91
+ ```typescript
92
+ const amount = BigInt(Math.floor(parseFloat(userInput) * 10 ** decimals))
93
+ ```
@@ -0,0 +1,53 @@
1
+ # Migration from @txnlab/deflex
2
+
3
+ ## Package Rename
4
+
5
+ ```bash
6
+ npm uninstall @txnlab/deflex
7
+ npm install @txnlab/haystack-router
8
+ ```
9
+
10
+ ## Import Changes
11
+
12
+ ```typescript
13
+ // Before
14
+ import { DeflexClient } from '@txnlab/deflex'
15
+
16
+ // After
17
+ import { RouterClient } from '@txnlab/haystack-router'
18
+ ```
19
+
20
+ ## Class and Type Renames
21
+
22
+ | Before (@txnlab/deflex) | After (@txnlab/haystack-router) |
23
+ | ----------------------- | ------------------------------- |
24
+ | `DeflexClient` | `RouterClient` |
25
+ | `DeflexQuote` | `SwapQuote` |
26
+ | `DeflexTransaction` | `SwapTransaction` |
27
+ | `DeflexConfig` | `Config` |
28
+ | `DeflexConfigParams` | `ConfigParams` |
29
+ | `DeflexSignature` | `Signature` |
30
+
31
+ ## API Endpoint
32
+
33
+ The SDK automatically uses the updated API endpoint. No manual URL changes needed.
34
+
35
+ ## Functionality
36
+
37
+ All functionality is identical — only naming changed. A find-and-replace of the class and type names is sufficient.
38
+
39
+ ### Quick Migration
40
+
41
+ ```bash
42
+ # Find all files that import from @txnlab/deflex
43
+ grep -r "@txnlab/deflex" --include="*.ts" --include="*.tsx" -l
44
+
45
+ # Replace imports
46
+ # @txnlab/deflex → @txnlab/haystack-router
47
+ # DeflexClient → RouterClient
48
+ # DeflexQuote → SwapQuote
49
+ # DeflexTransaction → SwapTransaction
50
+ # DeflexConfig → Config
51
+ # DeflexConfigParams → ConfigParams
52
+ # DeflexSignature → Signature
53
+ ```
@@ -0,0 +1,113 @@
1
+ # Node.js Automation (SDK)
2
+
3
+ When building Node.js automation scripts that integrate Haystack Router directly in application code:
4
+
5
+ ## Setup
6
+
7
+ ```bash
8
+ npm install @txnlab/haystack-router algosdk
9
+ ```
10
+
11
+ ## Environment Variables
12
+
13
+ ```bash
14
+ # .env
15
+ HAYSTACK_API_KEY=1b72df7e-1131-4449-8ce1-29b79dd3f51e # Free tier (60 requests/min)
16
+ ```
17
+
18
+ ## Complete Example
19
+
20
+ ```typescript
21
+ import algosdk from 'algosdk'
22
+ import { RouterClient } from '@txnlab/haystack-router'
23
+
24
+ async function main() {
25
+ const apiKey = process.env.HAYSTACK_API_KEY!
26
+
27
+ // For application code, use use-wallet or AlgorandClient for signing
28
+ // For Node.js scripts, create a custom signer:
29
+ const account = algosdk.mnemonicToSecretKey(process.env.MNEMONIC!)
30
+ const address = account.addr.toString()
31
+
32
+ const signer = async (
33
+ txnGroup: algosdk.Transaction[],
34
+ indexesToSign: number[],
35
+ ): Promise<Uint8Array[]> => {
36
+ return indexesToSign.map(
37
+ (index) => algosdk.signTransaction(txnGroup[index], account.sk).blob,
38
+ )
39
+ }
40
+
41
+ // Initialize router
42
+ const router = new RouterClient({
43
+ apiKey,
44
+ autoOptIn: true,
45
+ })
46
+
47
+ // Get quote: 1 ALGO → USDC
48
+ const quote = await router.newQuote({
49
+ fromASAID: 0,
50
+ toASAID: 31566704,
51
+ amount: 1_000_000,
52
+ address,
53
+ })
54
+
55
+ console.log(`Expected output: ${Number(quote.quote) / 1e6} USDC`)
56
+ console.log(`USD value: $${quote.usdOut.toFixed(2)}`)
57
+
58
+ // Execute swap
59
+ const swap = await router.newSwap({
60
+ quote,
61
+ address,
62
+ signer,
63
+ slippage: 1,
64
+ })
65
+
66
+ const result = await swap.execute()
67
+ console.log(`Confirmed in round ${result.confirmedRound}`)
68
+ console.log(`Transaction IDs: ${result.txIds.join(', ')}`)
69
+
70
+ const summary = swap.getSummary()
71
+ if (summary) {
72
+ console.log(`Input: ${summary.inputAmount} microunits`)
73
+ console.log(`Output: ${summary.outputAmount} microunits`)
74
+ console.log(`Fees: ${summary.totalFees} microAlgos`)
75
+ }
76
+ }
77
+
78
+ main().catch(console.error)
79
+ ```
80
+
81
+ ## Tracking with Notes
82
+
83
+ Attach identifiers to transactions for backend tracking:
84
+
85
+ ```typescript
86
+ const swap = await router.newSwap({
87
+ quote,
88
+ address,
89
+ signer,
90
+ slippage: 1,
91
+ note: new TextEncoder().encode(
92
+ JSON.stringify({
93
+ orderId: 'order-123',
94
+ timestamp: Date.now(),
95
+ }),
96
+ ),
97
+ })
98
+
99
+ await swap.execute()
100
+ const txId = swap.getInputTransactionId()
101
+ console.log(`Tracked: order-123 → ${txId}`)
102
+ ```
103
+
104
+ ## Debug Logging
105
+
106
+ Enable verbose logging for troubleshooting:
107
+
108
+ ```typescript
109
+ const router = new RouterClient({
110
+ apiKey,
111
+ debugLevel: 'debug', // 'none' | 'info' | 'debug' | 'trace'
112
+ })
113
+ ```
@@ -0,0 +1,155 @@
1
+ # Quotes
2
+
3
+ ## Getting a Quote
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
+ const quote = await router.newQuote({
13
+ fromASAID: 0, // ALGO
14
+ toASAID: 31566704, // USDC
15
+ amount: 1_000_000, // 1 ALGO in base units
16
+ address: activeAddress,
17
+ })
18
+ ```
19
+
20
+ ## Parameters
21
+
22
+ | Parameter | Type | Required | Description |
23
+ | ------------------- | ------------------ | -------- | ----------------------------------------------- |
24
+ | `fromASAID` | `number \| bigint` | Yes | Input asset ID (0 = ALGO) |
25
+ | `toASAID` | `number \| bigint` | Yes | Output asset ID |
26
+ | `amount` | `number \| bigint` | Yes | Amount in base units |
27
+ | `type` | `string` | No | `'fixed-input'` (default) or `'fixed-output'` |
28
+ | `address` | `string` | No | User address (needed for auto opt-in detection) |
29
+ | `maxGroupSize` | `number` | No | Max transactions in group (default: 16) |
30
+ | `maxDepth` | `number` | No | Max routing hops (default: 4) |
31
+ | `optIn` | `boolean` | No | Include opt-in transaction for output asset |
32
+ | `disabledProtocols` | `Protocol[]` | No | Protocols to exclude from routing |
33
+
34
+ ## Quote Response (SwapQuote)
35
+
36
+ `newQuote()` returns a `SwapQuote` (extends `FetchQuoteResponse`):
37
+
38
+ ```typescript
39
+ quote.quote // bigint — expected output amount in base units
40
+ quote.amount // bigint — original input amount
41
+ quote.usdIn // number — USD value of input
42
+ quote.usdOut // number — USD value of output
43
+ quote.userPriceImpact // number | undefined — price impact %
44
+ quote.marketPriceImpact // number | undefined — market price impact %
45
+ quote.route // Route[] — routing path details
46
+ quote.flattenedRoute // Record<string, number> — protocol split percentages
47
+ quote.quotes // DexQuote[] — individual DEX quotes
48
+ quote.requiredAppOptIns // number[] — app IDs needing opt-in
49
+ quote.createdAt // number — timestamp (ms)
50
+ quote.address // string | undefined — user address if provided
51
+ ```
52
+
53
+ ## Quote Types
54
+
55
+ **Fixed-input** (default): Specify exact input amount, receive variable output.
56
+
57
+ ```typescript
58
+ const quote = await router.newQuote({
59
+ fromASAID: 0,
60
+ toASAID: 31566704,
61
+ amount: 1_000_000, // Exact: send 1 ALGO
62
+ type: 'fixed-input',
63
+ })
64
+ // quote.quote = expected USDC received
65
+ ```
66
+
67
+ **Fixed-output**: Specify desired output, send variable input.
68
+
69
+ ```typescript
70
+ const quote = await router.newQuote({
71
+ fromASAID: 0,
72
+ toASAID: 31566704,
73
+ amount: 1_000_000, // Exact: receive 1 USDC
74
+ type: 'fixed-output',
75
+ })
76
+ // quote.quote = ALGO required to send
77
+ ```
78
+
79
+ ## Displaying Quote Data
80
+
81
+ ```typescript
82
+ const fromDecimals = 6 // ALGO
83
+ const toDecimals = 6 // USDC
84
+
85
+ const outputHuman = Number(quote.quote) / 10 ** toDecimals
86
+ const inputHuman = Number(quote.amount) / 10 ** fromDecimals
87
+ const rate = outputHuman / inputHuman
88
+
89
+ console.log(`${inputHuman} ALGO → ${outputHuman} USDC`)
90
+ console.log(`Rate: 1 ALGO = ${rate.toFixed(4)} USDC`)
91
+ console.log(`USD in: $${quote.usdIn.toFixed(2)}`)
92
+ console.log(`USD out: $${quote.usdOut.toFixed(2)}`)
93
+
94
+ if (quote.userPriceImpact !== undefined) {
95
+ console.log(`Price impact: ${quote.userPriceImpact.toFixed(2)}%`)
96
+ }
97
+ ```
98
+
99
+ ## Route Details
100
+
101
+ Each quote includes routing information showing how the swap is split:
102
+
103
+ ```typescript
104
+ // Flattened view: protocol → percentage
105
+ for (const [protocol, pct] of Object.entries(quote.flattenedRoute)) {
106
+ console.log(`${protocol}: ${pct}%`)
107
+ }
108
+ // e.g., "TinymanV2: 60%", "Pact: 40%"
109
+
110
+ // Detailed route with hops
111
+ for (const route of quote.route) {
112
+ console.log(`${route.percentage}% of swap:`)
113
+ for (const hop of route.path) {
114
+ console.log(` ${hop.in.unit_name} → ${hop.out.unit_name} via ${hop.name}`)
115
+ }
116
+ }
117
+ ```
118
+
119
+ ## Asset Opt-In Detection
120
+
121
+ ```typescript
122
+ // Option 1: Set autoOptIn on the client
123
+ const router = new RouterClient({
124
+ apiKey: '1b72df7e-1131-4449-8ce1-29b79dd3f51e', // Free tier (60 requests/min)
125
+ autoOptIn: true,
126
+ })
127
+ const quote = await router.newQuote({
128
+ fromASAID: 0,
129
+ toASAID: 31566704,
130
+ amount: 1_000_000,
131
+ address: activeAddress, // Required for auto opt-in
132
+ })
133
+
134
+ // Option 2: Check manually and pass optIn flag
135
+ const needsOptIn = await router.needsAssetOptIn(activeAddress, 31566704)
136
+ const quote = await router.newQuote({
137
+ fromASAID: 0,
138
+ toASAID: 31566704,
139
+ amount: 1_000_000,
140
+ optIn: needsOptIn,
141
+ })
142
+ ```
143
+
144
+ ## Lower-Level: fetchQuote()
145
+
146
+ `fetchQuote()` returns the raw `FetchQuoteResponse` without `SwapQuote` enhancements (no bigint coercion, no `createdAt`). Use `newQuote()` unless you need the raw response.
147
+
148
+ ```typescript
149
+ const raw = await router.fetchQuote({
150
+ fromASAID: 0,
151
+ toASAID: 31566704,
152
+ amount: 1_000_000,
153
+ })
154
+ // raw.quote is string | number (not bigint)
155
+ ```