@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.
Files changed (22) hide show
  1. package/lib/x402-fetch.ts +3 -10
  2. package/openclaw.plugin.json +4 -2
  3. package/package.json +1 -1
  4. package/skills/algorand-interaction/SKILL.md +12 -6
  5. package/skills/algorand-interaction/references/algorand-mcp.md +81 -7
  6. package/skills/algorand-interaction/references/examples-algorand-mcp.md +77 -2
  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,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)