@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.
- package/memory/algorand-plugin.md +1 -0
- package/openclaw.plugin.json +4 -2
- package/package.json +1 -1
- package/skills/algorand-interaction/SKILL.md +6 -2
- package/skills/algorand-interaction/references/algorand-mcp.md +49 -2
- package/skills/algorand-interaction/references/examples-algorand-mcp.md +60 -0
- package/skills/haystack-router-development/SKILL.md +85 -0
- package/skills/haystack-router-development/references/api-reference.md +381 -0
- package/skills/haystack-router-development/references/configuration.md +184 -0
- package/skills/haystack-router-development/references/fees-and-referrals.md +91 -0
- package/skills/haystack-router-development/references/getting-started.md +93 -0
- package/skills/haystack-router-development/references/migration.md +53 -0
- package/skills/haystack-router-development/references/node-automation.md +113 -0
- package/skills/haystack-router-development/references/quotes.md +155 -0
- package/skills/haystack-router-development/references/react-integration.md +260 -0
- package/skills/haystack-router-development/references/swaps.md +161 -0
- package/skills/haystack-router-interaction/SKILL.md +146 -0
- package/skills/haystack-router-interaction/references/configuration.md +53 -0
- package/skills/haystack-router-interaction/references/getting-started.md +48 -0
- package/skills/haystack-router-interaction/references/node-automation.md +51 -0
- package/skills/haystack-router-interaction/references/quotes.md +80 -0
- package/skills/haystack-router-interaction/references/swaps.md +84 -0
|
@@ -53,6 +53,7 @@ mcporter call algorand-mcp.search_assets name=USDC network=mainnet
|
|
|
53
53
|
- Default to testnet during development
|
|
54
54
|
- Every transaction costs 0.001 ALGO minimum
|
|
55
55
|
- Account needs 0.1 ALGO base + 0.1 per asset/app opt-in (MBR)
|
|
56
|
+
- **CRITICAL — x402 Base64 blob handling**: When constructing the `paymentHeader` JSON for `x402_fetch`, NEVER manually re-type or partially copy base64 blob strings. Use the EXACT `bytes` value from `encode_unsigned_transaction` and the EXACT `blob` value from `wallet_sign_transaction` — copy each value in full. Even a single character corruption (e.g., `5` → `4`) causes "signature does not match sender" errors and the payment will be rejected.
|
|
56
57
|
|
|
57
58
|
## Common Mainnet Assets
|
|
58
59
|
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
"id": "openclaw-algorand-plugin",
|
|
3
3
|
"name": "Algorand Integration",
|
|
4
4
|
"description": "Algorand blockchain integration with MCP and skills — by GoPlausible",
|
|
5
|
-
"version": "1.0
|
|
5
|
+
"version": "1.2.0",
|
|
6
6
|
"skills": [
|
|
7
7
|
"skills/algorand-development",
|
|
8
8
|
"skills/algorand-typescript",
|
|
9
9
|
"skills/algorand-python",
|
|
10
10
|
"skills/algorand-interaction",
|
|
11
11
|
"skills/algorand-x402-typescript",
|
|
12
|
-
"skills/algorand-x402-python"
|
|
12
|
+
"skills/algorand-x402-python",
|
|
13
|
+
"skills/haystack-router-development",
|
|
14
|
+
"skills/haystack-router-interaction"
|
|
13
15
|
],
|
|
14
16
|
"configSchema": {
|
|
15
17
|
"type": "object",
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: algorand-interaction
|
|
3
|
-
description: Interact with Algorand blockchain via the Algorand MCP server — wallet operations, ALGO/ASA transactions, smart contracts, account info, NFD lookups, atomic groups, Tinyman swaps, TEAL compilation, knowledge base. Use when user asks about Algorand wallet, balances, sending ALGO or tokens, asset opt-in, transactions, NFD names, DEX swaps, smart contracts, or account details.
|
|
3
|
+
description: Interact with Algorand blockchain via the Algorand MCP server — wallet operations, ALGO/ASA transactions, smart contracts, account info, NFD lookups, atomic groups, Tinyman swaps, Haystack Router DEX-aggregated swaps, TEAL compilation, knowledge base. Use when user asks about Algorand wallet, balances, sending ALGO or tokens, asset opt-in, transactions, NFD names, DEX swaps, smart contracts, or account details.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Algorand MCP Interaction
|
|
7
7
|
|
|
8
|
-
Interact with Algorand blockchain through the Algorand MCP server (
|
|
8
|
+
Interact with Algorand blockchain through the Algorand MCP server (101+ tools across 12 categories).
|
|
9
9
|
|
|
10
10
|
## Key Characteristics
|
|
11
11
|
|
|
@@ -160,6 +160,8 @@ For atomic (all-or-nothing) multi-transaction groups:
|
|
|
160
160
|
|
|
161
161
|
**Tinyman DEX** (9): `api_tinyman_get_pool`, `api_tinyman_get_pool_analytics`, `api_tinyman_get_pool_creation_quote`, `api_tinyman_get_liquidity_quote`, `api_tinyman_get_remove_liquidity_quote`, `api_tinyman_get_swap_quote`, `api_tinyman_get_asset_optin_quote`, `api_tinyman_get_validator_optin_quote`, `api_tinyman_get_validator_optout_quote`
|
|
162
162
|
|
|
163
|
+
**Haystack Router** (3): `api_haystack_get_swap_quote`, `api_haystack_execute_swap`, `api_haystack_needs_optin` — DEX-aggregated swaps across Tinyman V2, Pact, Folks with optimal routing. See the **haystack-router-interaction** skill for detailed workflows and reference docs.
|
|
164
|
+
|
|
163
165
|
**ARC-26 URI** (1): `generate_algorand_uri`
|
|
164
166
|
|
|
165
167
|
**Knowledge Base** (1): `get_knowledge_doc`
|
|
@@ -181,6 +183,8 @@ When `x402_fetch` returns HTTP 402 with `PaymentRequirements`, use the atomic gr
|
|
|
181
183
|
|
|
182
184
|
**Critical**: The `accepted` field is REQUIRED. It must be an exact copy of the `accepts[]` entry you chose to pay with (including all fields: scheme, network, price, payTo, asset, maxAmountRequired, extra, etc.). Without it, the server cannot match your payment and will reject with 402.
|
|
183
185
|
|
|
186
|
+
**Critical — Base64 blob handling**: When constructing the `paymentHeader` JSON string for `x402_fetch`, NEVER manually re-type or partially copy base64 blob strings. Use the EXACT `bytes` value from `encode_unsigned_transaction` and the EXACT `blob` value from `wallet_sign_transaction` — copy each complete value verbatim into the `paymentGroup` array. Even a single character corruption (e.g., `5` → `4`) causes "signature does not match sender" errors and the payment will be rejected.
|
|
187
|
+
|
|
184
188
|
Map CAIP-2 network identifiers from `accepts[].network` to `testnet` or `mainnet`.
|
|
185
189
|
|
|
186
190
|
See [references/examples-algorand-mcp.md](references/examples-algorand-mcp.md) for the full step-by-step workflow.
|
|
@@ -14,8 +14,9 @@
|
|
|
14
14
|
7. [Indexer API Tools](#indexer-api-tools)
|
|
15
15
|
8. [NFDomains API Tools](#nfdomains-api-tools)
|
|
16
16
|
9. [Tinyman DEX API Tools](#tinyman-dex-api-tools)
|
|
17
|
-
10. [
|
|
18
|
-
11. [
|
|
17
|
+
10. [Haystack Router Tools](#haystack-router-tools)
|
|
18
|
+
11. [ARC-26 URI Tools](#arc-26-uri-tools)
|
|
19
|
+
12. [Knowledge Base Tools](#knowledge-base-tools)
|
|
19
20
|
|
|
20
21
|
---
|
|
21
22
|
|
|
@@ -691,6 +692,52 @@ Decentralized exchange operations on Tinyman AMM.
|
|
|
691
692
|
|
|
692
693
|
---
|
|
693
694
|
|
|
695
|
+
## Haystack Router Tools
|
|
696
|
+
|
|
697
|
+
DEX-aggregated swaps across Tinyman V2, Pact, and Folks with smart order routing. For detailed workflows and the full SDK guide, see the **haystack-router-interaction** and **haystack-router-development** skills.
|
|
698
|
+
|
|
699
|
+
### api_haystack_get_swap_quote
|
|
700
|
+
- **Purpose**: Get an optimized swap quote across multiple DEXes without executing
|
|
701
|
+
- **Parameters**:
|
|
702
|
+
```json
|
|
703
|
+
{
|
|
704
|
+
"fromASAID": 0,
|
|
705
|
+
"toASAID": 31566704,
|
|
706
|
+
"amount": 1000000,
|
|
707
|
+
"type": "fixed-input",
|
|
708
|
+
"address": "optional — enables opt-in detection",
|
|
709
|
+
"maxGroupSize": 16,
|
|
710
|
+
"maxDepth": 4,
|
|
711
|
+
"network": "mainnet"
|
|
712
|
+
}
|
|
713
|
+
```
|
|
714
|
+
- **Returns**: `expectedOutput`, `inputAmount`, `usdIn`, `usdOut`, `userPriceImpact`, `route`, `flattenedRoute`, `requiredAppOptIns`, `protocolFees`
|
|
715
|
+
|
|
716
|
+
### api_haystack_execute_swap
|
|
717
|
+
- **Purpose**: All-in-one swap: quote → sign (via wallet) → submit → confirm. Enforces wallet spending limits.
|
|
718
|
+
- **Parameters**:
|
|
719
|
+
```json
|
|
720
|
+
{
|
|
721
|
+
"fromASAID": 0,
|
|
722
|
+
"toASAID": 31566704,
|
|
723
|
+
"amount": 1000000,
|
|
724
|
+
"slippage": 1,
|
|
725
|
+
"type": "fixed-input",
|
|
726
|
+
"note": "optional text note",
|
|
727
|
+
"maxGroupSize": 16,
|
|
728
|
+
"maxDepth": 4,
|
|
729
|
+
"network": "mainnet"
|
|
730
|
+
}
|
|
731
|
+
```
|
|
732
|
+
- **Returns**: `status`, `confirmedRound`, `txIds`, `signer`, `nickname`, quote details, `summary` (inputAmount, outputAmount, totalFees, transactionCount)
|
|
733
|
+
|
|
734
|
+
### api_haystack_needs_optin
|
|
735
|
+
- **Purpose**: Check if an address needs to opt into an asset before swapping
|
|
736
|
+
- **Parameters**: `{ "address": "ALGO_ADDRESS", "assetId": 31566704, "network": "mainnet" }`
|
|
737
|
+
- **Returns**: `{ address, assetId, needsOptIn: true/false, network }`
|
|
738
|
+
|
|
739
|
+
---
|
|
740
|
+
|
|
694
741
|
## ARC-26 URI Tools
|
|
695
742
|
|
|
696
743
|
### generate_algorand_uri
|
|
@@ -398,6 +398,55 @@ api_tinyman_get_pool {
|
|
|
398
398
|
|
|
399
399
|
---
|
|
400
400
|
|
|
401
|
+
## Haystack Router Swap (DEX-Aggregated)
|
|
402
|
+
|
|
403
|
+
Best-price swap across multiple DEXes (Tinyman V2, Pact, Folks). For detailed reference, see the **haystack-router-interaction** skill.
|
|
404
|
+
|
|
405
|
+
### Step 1: Check wallet
|
|
406
|
+
```
|
|
407
|
+
wallet_get_info { "network": "mainnet" }
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### Step 2: Check opt-in (if swapping to an ASA)
|
|
411
|
+
```
|
|
412
|
+
api_haystack_needs_optin {
|
|
413
|
+
"address": "[wallet_address]",
|
|
414
|
+
"assetId": 31566704,
|
|
415
|
+
"network": "mainnet"
|
|
416
|
+
}
|
|
417
|
+
```
|
|
418
|
+
If `needsOptIn: true`:
|
|
419
|
+
```
|
|
420
|
+
wallet_optin_asset { "assetId": 31566704, "network": "mainnet" }
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### Step 3: Get a quote (show user before executing)
|
|
424
|
+
```
|
|
425
|
+
api_haystack_get_swap_quote {
|
|
426
|
+
"fromASAID": 0,
|
|
427
|
+
"toASAID": 31566704,
|
|
428
|
+
"amount": 1000000,
|
|
429
|
+
"type": "fixed-input",
|
|
430
|
+
"address": "[wallet_address]",
|
|
431
|
+
"network": "mainnet"
|
|
432
|
+
}
|
|
433
|
+
```
|
|
434
|
+
> Present to user: expected output, USD values, route, price impact.
|
|
435
|
+
|
|
436
|
+
### Step 4: Execute swap (after user confirms)
|
|
437
|
+
```
|
|
438
|
+
api_haystack_execute_swap {
|
|
439
|
+
"fromASAID": 0,
|
|
440
|
+
"toASAID": 31566704,
|
|
441
|
+
"amount": 1000000,
|
|
442
|
+
"slippage": 1,
|
|
443
|
+
"network": "mainnet"
|
|
444
|
+
}
|
|
445
|
+
```
|
|
446
|
+
> Signs via wallet, submits, and confirms atomically. Returns confirmed round and tx IDs.
|
|
447
|
+
|
|
448
|
+
---
|
|
449
|
+
|
|
401
450
|
## Using the Knowledge Base
|
|
402
451
|
|
|
403
452
|
### Get a specific document
|
|
@@ -638,6 +687,8 @@ Build this JSON string:
|
|
|
638
687
|
|
|
639
688
|
> **Critical**: The `accepted` field is REQUIRED. It must be an exact copy of the `accepts[]` entry you chose (including all fields: scheme, network, price, payTo, asset, maxAmountRequired, extra, etc.). Without it, the server cannot match your payment to a requirement and will reject with 402.
|
|
640
689
|
|
|
690
|
+
> **CRITICAL — Base64 blob handling**: When building the `paymentGroup` array, you MUST use the EXACT `bytes` value from `encode_unsigned_transaction` and the EXACT `blob` value from `wallet_sign_transaction`. NEVER manually re-type, truncate, or partially copy these base64 strings. Even a single character corruption (e.g., `5` → `4`) causes "signature does not match sender" errors. Copy each complete blob verbatim — do not attempt to reconstruct or abbreviate them.
|
|
691
|
+
|
|
641
692
|
### Step 8: Retry with payment
|
|
642
693
|
|
|
643
694
|
Call `x402_fetch` again with `paymentHeader` set to the JSON string from Step 7.
|
|
@@ -645,3 +696,12 @@ The `x402_fetch` tool will base64-encode it and send it as the `PAYMENT-SIGNATUR
|
|
|
645
696
|
The server verifies the payment, submits the transaction group, and returns the resource.
|
|
646
697
|
|
|
647
698
|
> **Important**: The `paymentGroup` array order must match: index 0 = unsigned fee payer txn, index 1 = signed payment txn. The `paymentIndex` indicates which transaction carries the actual payment.
|
|
699
|
+
|
|
700
|
+
### Common x402 Errors
|
|
701
|
+
|
|
702
|
+
| Error | Cause | Solution |
|
|
703
|
+
|-------|-------|---------|
|
|
704
|
+
| `Payment transaction signature does not match sender` | Base64 blob was corrupted when constructing `paymentHeader` JSON | Use EXACT `bytes`/`blob` values from tool responses — never re-type or partially copy base64 strings |
|
|
705
|
+
| `402` returned despite payment header | Missing `accepted` field in payload, or `accepted` doesn't match an `accepts[]` entry exactly | Copy the chosen `accepts[]` entry verbatim into the `accepted` field |
|
|
706
|
+
| `402` with expired transactions | Too much time between building transactions and sending payment | Rebuild transactions immediately before sending — `firstValid`/`lastValid` window is ~1000 rounds |
|
|
707
|
+
| `Simulation failed` | Insufficient balance, asset not opted in, or group structure wrong | Check USDC/ALGO balance, verify opt-in, ensure group order is [feePayer, payment] |
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: haystack-router-development
|
|
3
|
+
description: Comprehensive guide for building applications with Haystack Router SDK (@txnlab/haystack-router) — a DEX aggregator and smart order routing protocol on Algorand. Use when developing swap UIs with React and use-wallet, writing Node.js automation scripts, integrating RouterClient for quotes and swaps, or working with the SDK API surface, middleware, fees, and referral program. Strong triggers include haystack router, @txnlab/haystack-router, RouterClient, DEX aggregator, swap UI, swap React, newQuote, newSwap, deflex migration, haystack SDK, swap routing, best price swap.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Haystack Router (Development)
|
|
7
|
+
|
|
8
|
+
This is the parent skill for building applications that integrate the `@txnlab/haystack-router` SDK — React swap UIs, Node.js automation scripts, custom signing flows, middleware, and direct RouterClient usage. No Algorand MCP tools are involved.
|
|
9
|
+
|
|
10
|
+
> **Want to execute swaps** through the Algorand MCP server instead of building an app? Use the **haystack-router-interaction** skill — it provides Algorand MCP tools for quoting, swapping, and opt-in checking with wallet-based signing.
|
|
11
|
+
> **Need Algorand blockchain interaction guidance?** See the **algorand-interaction** skill for wallet setup, transaction workflows, and MCP tool reference.
|
|
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
|
+
## Package
|
|
16
|
+
|
|
17
|
+
`@txnlab/haystack-router` — TypeScript SDK for DEX-aggregated swaps. Requires `algosdk` (v3+) as a peer dependency.
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @txnlab/haystack-router algosdk
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**API key required.** A free tier key is available for immediate use — see [configuration.md](references/configuration.md) for details.
|
|
24
|
+
|
|
25
|
+
## SDK Core Flow
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
import { RouterClient } from '@txnlab/haystack-router'
|
|
29
|
+
|
|
30
|
+
// 1. Initialize
|
|
31
|
+
const router = new RouterClient({
|
|
32
|
+
apiKey: '1b72df7e-1131-4449-8ce1-29b79dd3f51e', // Free tier (60 requests/min)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
// 2. Get a quote
|
|
36
|
+
const quote = await router.newQuote({
|
|
37
|
+
fromASAID: 0, // ALGO
|
|
38
|
+
toASAID: 31566704, // USDC
|
|
39
|
+
amount: 1_000_000, // 1 ALGO (base units)
|
|
40
|
+
address: activeAddress,
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
// 3. Execute the swap (use-wallet signer for browser, custom signer for Node.js)
|
|
44
|
+
const swap = await router.newSwap({
|
|
45
|
+
quote,
|
|
46
|
+
address: activeAddress,
|
|
47
|
+
signer: transactionSigner,
|
|
48
|
+
slippage: 1, // 1%
|
|
49
|
+
})
|
|
50
|
+
const result = await swap.execute()
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The SDK is the **only** supported integration path. Do not call the API directly.
|
|
54
|
+
|
|
55
|
+
## Key Concepts
|
|
56
|
+
|
|
57
|
+
- **Amounts** are always in base units (microAlgos for ALGO, smallest unit for ASAs)
|
|
58
|
+
- **ASA IDs**: 0 = ALGO, 31566704 = USDC, etc.
|
|
59
|
+
- **Quote types**: `fixed-input` (default) — specify input amount; `fixed-output` — specify desired output
|
|
60
|
+
- **Slippage**: Percentage tolerance on output (e.g., 1 = 1%). Applied to the final output, not individual hops
|
|
61
|
+
- **Routing**: Supports multi-hop and parallel (combo) swaps for optimal pricing
|
|
62
|
+
- **Middleware**: Plugin system for custom pre/post-swap transactions (e.g., auto opt-out)
|
|
63
|
+
|
|
64
|
+
## Reference Files
|
|
65
|
+
|
|
66
|
+
Read the appropriate file based on the task:
|
|
67
|
+
|
|
68
|
+
| Task | Reference |
|
|
69
|
+
| --------------------------------------- | ------------------------------------------------------- |
|
|
70
|
+
| Install SDK, initialize RouterClient | [getting-started.md](references/getting-started.md) |
|
|
71
|
+
| Get swap quotes, display pricing | [quotes.md](references/quotes.md) |
|
|
72
|
+
| Execute swaps with SDK signing | [swaps.md](references/swaps.md) |
|
|
73
|
+
| Build React swap UI with use-wallet | [react-integration.md](references/react-integration.md) |
|
|
74
|
+
| Automate swaps via Node.js scripts | [node-automation.md](references/node-automation.md) |
|
|
75
|
+
| RouterClient config, middleware, debug | [configuration.md](references/configuration.md) |
|
|
76
|
+
| Fee structure, referral program | [fees-and-referrals.md](references/fees-and-referrals.md) |
|
|
77
|
+
| Full API surface and types | [api-reference.md](references/api-reference.md) |
|
|
78
|
+
| Migrate from @txnlab/deflex | [migration.md](references/migration.md) |
|
|
79
|
+
|
|
80
|
+
## How to Use This Skill
|
|
81
|
+
|
|
82
|
+
1. **Start here** to understand which reference you need
|
|
83
|
+
2. **Read the topic `.md`** file for step-by-step guidance
|
|
84
|
+
3. **For MCP-based swaps** (no SDK), see the `haystack-router-interaction` skill
|
|
85
|
+
4. **For general Algorand development**, see `algorand-development`, `algorand-typescript`, or `algorand-python` skills
|
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
# API Reference
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
|
|
5
|
+
- [RouterClient](#routerclient)
|
|
6
|
+
- [SwapComposer](#swapcomposer)
|
|
7
|
+
- [SwapMiddleware](#swapmiddleware)
|
|
8
|
+
- [Types](#types)
|
|
9
|
+
|
|
10
|
+
## RouterClient
|
|
11
|
+
|
|
12
|
+
### Constructor
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
new RouterClient(config: ConfigParams & { middleware?: SwapMiddleware[] })
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**ConfigParams:**
|
|
19
|
+
|
|
20
|
+
| Property | Type | Default | Description |
|
|
21
|
+
| ----------------- | ------------------ | -------------- | ---------------------------------------- |
|
|
22
|
+
| `apiKey` | `string` | — | **Required.** API key |
|
|
23
|
+
| `apiBaseUrl` | `string` | SDK default | API endpoint override |
|
|
24
|
+
| `algodUri` | `string` | MainNet Nodely | Algod node URI |
|
|
25
|
+
| `algodToken` | `string` | `''` | Algod node token |
|
|
26
|
+
| `algodPort` | `string \| number` | `443` | Algod node port |
|
|
27
|
+
| `referrerAddress` | `string` | — | Earn 25% of swap fees |
|
|
28
|
+
| `feeBps` | `number` | `10` | Fee in basis points (10–300) |
|
|
29
|
+
| `autoOptIn` | `boolean` | `false` | Auto-detect asset opt-in |
|
|
30
|
+
| `debugLevel` | `string` | `'none'` | `'none' \| 'info' \| 'debug' \| 'trace'` |
|
|
31
|
+
|
|
32
|
+
### newQuote()
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
async newQuote(params: FetchQuoteParams): Promise<SwapQuote>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Get an optimized swap quote with enhanced types (bigint coercion, timestamps).
|
|
39
|
+
|
|
40
|
+
### fetchQuote()
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
async fetchQuote(params: FetchQuoteParams): Promise<FetchQuoteResponse>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Get a raw swap quote without SwapQuote enhancements.
|
|
47
|
+
|
|
48
|
+
### newSwap()
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
async newSwap(config: {
|
|
52
|
+
quote: SwapQuote | FetchQuoteResponse
|
|
53
|
+
address: string
|
|
54
|
+
signer: TransactionSigner | SignerFunction
|
|
55
|
+
slippage: number
|
|
56
|
+
note?: Uint8Array
|
|
57
|
+
}): Promise<SwapComposer>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Create a swap composer for building and executing the swap transaction group.
|
|
61
|
+
|
|
62
|
+
### needsAssetOptIn()
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
async needsAssetOptIn(address: string, assetId: number | bigint): Promise<boolean>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Check if an address needs to opt into an asset. Always returns `false` for ALGO (ASA 0).
|
|
69
|
+
|
|
70
|
+
### fetchSwapTransactions()
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
async fetchSwapTransactions(params: FetchSwapTxnsParams): Promise<FetchSwapTxnsResponse>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Low-level: fetch executable swap transactions. Typically called internally by `newSwap()`.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## SwapComposer
|
|
81
|
+
|
|
82
|
+
Returned by `router.newSwap()`. Builder pattern for transaction groups.
|
|
83
|
+
|
|
84
|
+
### execute()
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
async execute(waitRounds?: number): Promise<{
|
|
88
|
+
confirmedRound: bigint
|
|
89
|
+
txIds: string[]
|
|
90
|
+
methodResults: ABIResult[]
|
|
91
|
+
}>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Sign, submit, and wait for confirmation. `waitRounds` defaults to 10.
|
|
95
|
+
|
|
96
|
+
### buildGroup()
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
buildGroup(): TransactionWithSigner[]
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Finalize the transaction group and assign group IDs.
|
|
103
|
+
|
|
104
|
+
### sign()
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
async sign(): Promise<Uint8Array[]>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Sign all transactions. Auto-adds swap transactions if not already added.
|
|
111
|
+
|
|
112
|
+
### submit()
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
async submit(): Promise<string[]>
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Sign and submit without waiting for confirmation. Returns transaction IDs.
|
|
119
|
+
|
|
120
|
+
### addTransaction()
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
addTransaction(transaction: Transaction, signer?: TransactionSigner): this
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Add a custom transaction to the group. Chainable. Must be called before `buildGroup()`.
|
|
127
|
+
|
|
128
|
+
### addMethodCall()
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
addMethodCall(methodCall: MethodCall, signer?: TransactionSigner): this
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Add an ABI method call to the group. Chainable.
|
|
135
|
+
|
|
136
|
+
### addSwapTransactions()
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
async addSwapTransactions(): Promise<this>
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Manually add swap transactions (including middleware hooks and app opt-ins). Called automatically by `execute()` if not called explicitly.
|
|
143
|
+
|
|
144
|
+
### getSummary()
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
getSummary(): SwapSummary | undefined
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Get exact swap amounts after execution. Only available after `execute()`.
|
|
151
|
+
|
|
152
|
+
### getInputTransactionId()
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
getInputTransactionId(): string | undefined
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Get the user-signed input transaction ID. Available after `buildGroup()`.
|
|
159
|
+
|
|
160
|
+
### getStatus()
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
getStatus(): SwapComposerStatus
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Returns: `BUILDING` (0) → `BUILT` (1) → `SIGNED` (2) → `SUBMITTED` (3) → `COMMITTED` (4)
|
|
167
|
+
|
|
168
|
+
### count()
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
count(): number
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Number of transactions in the group.
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## SwapMiddleware
|
|
179
|
+
|
|
180
|
+
Interface for plugins that hook into the quote and swap lifecycle.
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
interface SwapMiddleware {
|
|
184
|
+
readonly name: string
|
|
185
|
+
readonly version: string
|
|
186
|
+
|
|
187
|
+
shouldApply(context: QuoteContext): Promise<boolean>
|
|
188
|
+
adjustQuoteParams?(params: FetchQuoteParams): Promise<FetchQuoteParams>
|
|
189
|
+
beforeSwap?(context: SwapContext): Promise<TransactionWithSigner[]>
|
|
190
|
+
afterSwap?(context: SwapContext): Promise<TransactionWithSigner[]>
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Built-in: AutoOptOutMiddleware
|
|
195
|
+
|
|
196
|
+
Automatically opts out of assets when swapping full balance.
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
import { AutoOptOutMiddleware } from '@txnlab/haystack-router'
|
|
200
|
+
|
|
201
|
+
const middleware = new AutoOptOutMiddleware({
|
|
202
|
+
excludedAssets?: readonly (number | bigint)[] // Assets to never auto-opt-out
|
|
203
|
+
})
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### QuoteContext
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
interface QuoteContext {
|
|
210
|
+
fromASAID: bigint
|
|
211
|
+
toASAID: bigint
|
|
212
|
+
amount: bigint
|
|
213
|
+
type: QuoteType
|
|
214
|
+
address?: string
|
|
215
|
+
algodClient: Algodv2
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### SwapContext
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
interface SwapContext {
|
|
223
|
+
quote: SwapQuote
|
|
224
|
+
address: string
|
|
225
|
+
algodClient: Algodv2
|
|
226
|
+
suggestedParams: SuggestedParams
|
|
227
|
+
fromASAID: bigint
|
|
228
|
+
toASAID: bigint
|
|
229
|
+
signer: TransactionSigner
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## Types
|
|
236
|
+
|
|
237
|
+
### FetchQuoteParams
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
interface FetchQuoteParams {
|
|
241
|
+
fromASAID: bigint | number
|
|
242
|
+
toASAID: bigint | number
|
|
243
|
+
amount: bigint | number
|
|
244
|
+
type?: 'fixed-input' | 'fixed-output' // Default: 'fixed-input'
|
|
245
|
+
address?: string | null
|
|
246
|
+
disabledProtocols?: readonly Protocol[]
|
|
247
|
+
maxGroupSize?: number // Default: 16
|
|
248
|
+
maxDepth?: number // Default: 4
|
|
249
|
+
optIn?: boolean
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### FetchQuoteResponse
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
interface FetchQuoteResponse {
|
|
257
|
+
quote: string | number
|
|
258
|
+
profit: Profit // { amount: number, asa: Asset }
|
|
259
|
+
priceBaseline: number
|
|
260
|
+
userPriceImpact?: number
|
|
261
|
+
marketPriceImpact?: number
|
|
262
|
+
usdIn: number
|
|
263
|
+
usdOut: number
|
|
264
|
+
route: Route[]
|
|
265
|
+
flattenedRoute: Record<string, number>
|
|
266
|
+
quotes: DexQuote[]
|
|
267
|
+
requiredAppOptIns: number[]
|
|
268
|
+
txnPayload: TxnPayload | null
|
|
269
|
+
protocolFees: Record<string, number>
|
|
270
|
+
fromASAID: number
|
|
271
|
+
toASAID: number
|
|
272
|
+
type: string
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### SwapQuote
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
type SwapQuote = FetchQuoteResponse & {
|
|
280
|
+
quote: bigint // Coerced to bigint
|
|
281
|
+
amount: bigint // Original request amount
|
|
282
|
+
address?: string
|
|
283
|
+
createdAt: number // Timestamp (ms)
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### SwapSummary
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
interface SwapSummary {
|
|
291
|
+
inputAssetId: bigint
|
|
292
|
+
outputAssetId: bigint
|
|
293
|
+
inputAmount: bigint
|
|
294
|
+
outputAmount: bigint
|
|
295
|
+
type: QuoteType
|
|
296
|
+
totalFees: bigint // microAlgos
|
|
297
|
+
transactionCount: number
|
|
298
|
+
inputTxnId: string
|
|
299
|
+
outputTxnId: string
|
|
300
|
+
inputSender: string
|
|
301
|
+
outputSender: string
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### SwapTransaction
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
interface SwapTransaction {
|
|
309
|
+
data: string // Base64-encoded transaction
|
|
310
|
+
group: string // Group ID
|
|
311
|
+
logicSigBlob: unknown | false
|
|
312
|
+
signature: Signature | false
|
|
313
|
+
}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
### SignerFunction
|
|
317
|
+
|
|
318
|
+
```typescript
|
|
319
|
+
type SignerFunction = (
|
|
320
|
+
txnGroup: Transaction[],
|
|
321
|
+
indexesToSign: number[],
|
|
322
|
+
) => Promise<(Uint8Array | null)[]>
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Supports two return patterns:
|
|
326
|
+
|
|
327
|
+
- `Uint8Array[]` matching `indexesToSign` length (Pera/Defly)
|
|
328
|
+
- `(Uint8Array | null)[]` matching full group length (Lute/ARC-1)
|
|
329
|
+
|
|
330
|
+
### Route and PathElement
|
|
331
|
+
|
|
332
|
+
```typescript
|
|
333
|
+
interface Route {
|
|
334
|
+
percentage: number
|
|
335
|
+
path: PathElement[]
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
interface PathElement {
|
|
339
|
+
name: string // Protocol name + fee tier
|
|
340
|
+
class: string[][]
|
|
341
|
+
in: Asset
|
|
342
|
+
out: Asset
|
|
343
|
+
}
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### Asset
|
|
347
|
+
|
|
348
|
+
```typescript
|
|
349
|
+
interface Asset {
|
|
350
|
+
id: number
|
|
351
|
+
decimals: number
|
|
352
|
+
unit_name: string
|
|
353
|
+
name: string
|
|
354
|
+
price_algo: number
|
|
355
|
+
price_usd: number
|
|
356
|
+
}
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
### Protocol
|
|
360
|
+
|
|
361
|
+
```typescript
|
|
362
|
+
enum Protocol {
|
|
363
|
+
TinymanV2 = 'TinymanV2'
|
|
364
|
+
Algofi = 'Algofi'
|
|
365
|
+
Algomint = 'Algomint'
|
|
366
|
+
Pact = 'Pact'
|
|
367
|
+
Folks = 'Folks'
|
|
368
|
+
TAlgo = 'TAlgo'
|
|
369
|
+
}
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### Constants
|
|
373
|
+
|
|
374
|
+
```typescript
|
|
375
|
+
const DEFAULT_FEE_BPS = 10 // 0.10%
|
|
376
|
+
const MAX_FEE_BPS = 300 // 3.00%
|
|
377
|
+
const DEFAULT_MAX_GROUP_SIZE = 16
|
|
378
|
+
const DEFAULT_MAX_DEPTH = 4
|
|
379
|
+
const DEFAULT_AUTO_OPT_IN = false
|
|
380
|
+
const DEFAULT_CONFIRMATION_ROUNDS = 10
|
|
381
|
+
```
|