@goplausible/openclaw-algorand-plugin 1.1.0 → 1.3.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/lib/x402-fetch.ts +3 -10
- package/openclaw.plugin.json +4 -2
- package/package.json +1 -1
- package/skills/algorand-interaction/SKILL.md +12 -6
- package/skills/algorand-interaction/references/algorand-mcp.md +81 -7
- package/skills/algorand-interaction/references/examples-algorand-mcp.md +77 -2
- 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
|
@@ -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
|
+
```
|
|
@@ -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)
|