@alpha-arcade/sdk 0.1.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/LICENSE +21 -0
- package/README.md +367 -0
- package/dist/index.cjs +2178 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +535 -0
- package/dist/index.d.ts +535 -0
- package/dist/index.js +2146 -0
- package/dist/index.js.map +1 -0
- package/package.json +65 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Alpha Market
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
# @alpha-market/sdk
|
|
2
|
+
|
|
3
|
+
TypeScript SDK for trading on **Alpha Market** — Algorand prediction markets.
|
|
4
|
+
|
|
5
|
+
Place orders, manage positions, read orderbooks, and build automated trading bots — all directly on-chain.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @alpha-market/sdk algosdk @algorandfoundation/algokit-utils
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
`algosdk` and `@algorandfoundation/algokit-utils` are peer dependencies.
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { AlphaClient } from '@alpha-market/sdk';
|
|
19
|
+
import algosdk from 'algosdk';
|
|
20
|
+
|
|
21
|
+
// 1. Setup clients
|
|
22
|
+
const algodClient = new algosdk.Algodv2('', 'https://mainnet-api.algonode.cloud', 443);
|
|
23
|
+
const indexerClient = new algosdk.Indexer('', 'https://mainnet-idx.algonode.cloud', 443);
|
|
24
|
+
|
|
25
|
+
// 2. Setup signer from mnemonic (or use any TransactionSigner)
|
|
26
|
+
const account = algosdk.mnemonicToSecretKey('your twenty five word mnemonic ...');
|
|
27
|
+
const signer = algosdk.makeBasicAccountTransactionSigner(account);
|
|
28
|
+
|
|
29
|
+
// 3. Initialize the client
|
|
30
|
+
const client = new AlphaClient({
|
|
31
|
+
algodClient,
|
|
32
|
+
indexerClient,
|
|
33
|
+
signer,
|
|
34
|
+
activeAddress: account.addr,
|
|
35
|
+
matcherAppId: 741347297,
|
|
36
|
+
usdcAssetId: 31566704,
|
|
37
|
+
feeAddress: 'YOUR_FEE_ADDRESS',
|
|
38
|
+
apiKey: 'YOUR_API_KEY',
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// 4. Fetch live markets
|
|
42
|
+
const markets = await client.getMarkets();
|
|
43
|
+
console.log(`Found ${markets.length} live markets`);
|
|
44
|
+
|
|
45
|
+
// 5. Place a limit buy order on the first market
|
|
46
|
+
const market = markets[0];
|
|
47
|
+
const result = await client.createLimitOrder({
|
|
48
|
+
marketAppId: market.marketAppId,
|
|
49
|
+
position: 1, // 1 = Yes
|
|
50
|
+
price: 500_000, // $0.50
|
|
51
|
+
quantity: 1_000_000, // 1 share
|
|
52
|
+
isBuying: true,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
console.log(`Order created! Escrow app ID: ${result.escrowAppId}`);
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## API Reference
|
|
59
|
+
|
|
60
|
+
### AlphaClient
|
|
61
|
+
|
|
62
|
+
#### Constructor
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
new AlphaClient(config: AlphaClientConfig)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
| Parameter | Type | Required | Description |
|
|
69
|
+
|-----------|------|----------|-------------|
|
|
70
|
+
| `algodClient` | `algosdk.Algodv2` | Yes | Algorand algod client |
|
|
71
|
+
| `indexerClient` | `algosdk.Indexer` | Yes | Algorand indexer client |
|
|
72
|
+
| `signer` | `TransactionSigner` | Yes | Transaction signer |
|
|
73
|
+
| `activeAddress` | `string` | Yes | Your Algorand address |
|
|
74
|
+
| `matcherAppId` | `number` | Yes | Matcher contract app ID (mainnet: `741347297`) |
|
|
75
|
+
| `usdcAssetId` | `number` | Yes | USDC ASA ID (mainnet: `31566704`) |
|
|
76
|
+
| `feeAddress` | `string` | Yes | Platform fee address |
|
|
77
|
+
| `apiKey` | `string` | Yes | Alpha partners API key (x-api-key header) |
|
|
78
|
+
| `apiBaseUrl` | `string` | No | API base URL (default: `https://partners.alphaarcade.com/api`) |
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
### Trading
|
|
83
|
+
|
|
84
|
+
#### `createLimitOrder(params)`
|
|
85
|
+
|
|
86
|
+
Creates a limit order that sits on the orderbook at your price.
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
const result = await client.createLimitOrder({
|
|
90
|
+
marketAppId: 123456789,
|
|
91
|
+
position: 1, // 1 = Yes, 0 = No
|
|
92
|
+
price: 500_000, // $0.50 in microunits
|
|
93
|
+
quantity: 2_000_000, // 2 shares in microunits
|
|
94
|
+
isBuying: true,
|
|
95
|
+
});
|
|
96
|
+
// result: { escrowAppId, txIds, confirmedRound }
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
#### `createMarketOrder(params)`
|
|
100
|
+
|
|
101
|
+
Creates a market order that auto-matches against the orderbook.
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
const result = await client.createMarketOrder({
|
|
105
|
+
marketAppId: 123456789,
|
|
106
|
+
position: 1,
|
|
107
|
+
price: 550_000, // willing to pay up to $0.55
|
|
108
|
+
quantity: 1_000_000,
|
|
109
|
+
isBuying: true,
|
|
110
|
+
slippage: 50_000, // $0.05 slippage tolerance
|
|
111
|
+
});
|
|
112
|
+
// result: { escrowAppId, matchedQuantity, txIds, confirmedRound }
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
#### `cancelOrder(params)`
|
|
116
|
+
|
|
117
|
+
Cancels an open order and returns funds to the owner.
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
const result = await client.cancelOrder({
|
|
121
|
+
marketAppId: 123456789,
|
|
122
|
+
escrowAppId: 987654321,
|
|
123
|
+
orderOwner: 'ALGO_ADDRESS...',
|
|
124
|
+
});
|
|
125
|
+
// result: { success, txIds }
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
#### `proposeMatch(params)`
|
|
129
|
+
|
|
130
|
+
Manually matches an existing maker order against a taker.
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
const result = await client.proposeMatch({
|
|
134
|
+
marketAppId: 123456789,
|
|
135
|
+
makerEscrowAppId: 987654321,
|
|
136
|
+
makerAddress: 'MAKER_ALGO_ADDRESS...',
|
|
137
|
+
quantityMatched: 500_000,
|
|
138
|
+
});
|
|
139
|
+
// result: { success, txIds }
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
### Positions
|
|
145
|
+
|
|
146
|
+
#### `splitShares(params)`
|
|
147
|
+
|
|
148
|
+
Splits USDC into equal YES + NO tokens. 1 USDC = 1 YES + 1 NO.
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
const result = await client.splitShares({
|
|
152
|
+
marketAppId: 123456789,
|
|
153
|
+
amount: 5_000_000, // $5.00 USDC
|
|
154
|
+
});
|
|
155
|
+
// You now hold 5 YES + 5 NO tokens for this market
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
#### `mergeShares(params)`
|
|
159
|
+
|
|
160
|
+
Merges equal YES + NO tokens back into USDC.
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
const result = await client.mergeShares({
|
|
164
|
+
marketAppId: 123456789,
|
|
165
|
+
amount: 3_000_000, // Merge 3 YES + 3 NO = $3.00 USDC
|
|
166
|
+
});
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
#### `claim(params)`
|
|
170
|
+
|
|
171
|
+
Claims USDC from a resolved market.
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
const result = await client.claim({
|
|
175
|
+
marketAppId: 123456789,
|
|
176
|
+
assetId: 111222333, // The YES or NO token ASA ID
|
|
177
|
+
});
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
#### `getPositions(walletAddress?)`
|
|
181
|
+
|
|
182
|
+
Gets all token positions across all markets.
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
const positions = await client.getPositions();
|
|
186
|
+
for (const pos of positions) {
|
|
187
|
+
console.log(`Market ${pos.marketAppId}: ${pos.yesBalance / 1e6} YES, ${pos.noBalance / 1e6} NO`);
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
### Orderbook
|
|
194
|
+
|
|
195
|
+
#### `getOrderbook(marketAppId)`
|
|
196
|
+
|
|
197
|
+
Fetches the full on-chain orderbook.
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
const book = await client.getOrderbook(123456789);
|
|
201
|
+
|
|
202
|
+
console.log('Yes bids:', book.yes.bids.length);
|
|
203
|
+
console.log('Yes asks:', book.yes.asks.length);
|
|
204
|
+
console.log('No bids:', book.no.bids.length);
|
|
205
|
+
console.log('No asks:', book.no.asks.length);
|
|
206
|
+
|
|
207
|
+
// Best yes bid
|
|
208
|
+
if (book.yes.bids.length > 0) {
|
|
209
|
+
const best = book.yes.bids.sort((a, b) => b.price - a.price)[0];
|
|
210
|
+
console.log(`Best Yes bid: $${best.price / 1e6} for ${best.quantity / 1e6} shares`);
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
#### `getOpenOrders(marketAppId, walletAddress?)`
|
|
215
|
+
|
|
216
|
+
Gets open orders for a wallet on a specific market.
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
const orders = await client.getOpenOrders(123456789);
|
|
220
|
+
for (const order of orders) {
|
|
221
|
+
const side = order.side === 1 ? 'BUY' : 'SELL';
|
|
222
|
+
const pos = order.position === 1 ? 'YES' : 'NO';
|
|
223
|
+
console.log(`${side} ${pos} @ $${order.price / 1e6} - ${order.quantity / 1e6} shares`);
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
### Markets
|
|
230
|
+
|
|
231
|
+
#### `getMarkets()`
|
|
232
|
+
|
|
233
|
+
Fetches all live, tradeable markets.
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
const markets = await client.getMarkets();
|
|
237
|
+
for (const m of markets) {
|
|
238
|
+
console.log(`${m.title} — Yes: ${m.yesProb}%, Vol: $${m.volume}`);
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
#### `getMarket(marketId)`
|
|
243
|
+
|
|
244
|
+
Fetches a single market by ID.
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
const market = await client.getMarket('abc123');
|
|
248
|
+
if (market) {
|
|
249
|
+
console.log(market.title, market.marketAppId);
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
### Utility Functions
|
|
256
|
+
|
|
257
|
+
These are exported for advanced users:
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
import { calculateFee, calculateMatchingOrders, getMarketGlobalState } from '@alpha-market/sdk';
|
|
261
|
+
|
|
262
|
+
// Fee calculation
|
|
263
|
+
const fee = calculateFee(1_000_000, 500_000, 70_000); // quantity, price, feeBase
|
|
264
|
+
|
|
265
|
+
// Read market state directly
|
|
266
|
+
const state = await getMarketGlobalState(algodClient, marketAppId);
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## Units & Conventions
|
|
272
|
+
|
|
273
|
+
| Concept | Unit | Example |
|
|
274
|
+
|---------|------|---------|
|
|
275
|
+
| Prices | Microunits (1M = $1.00) | `500_000` = $0.50 |
|
|
276
|
+
| Quantities | Microunits (1M = 1 share) | `2_000_000` = 2 shares |
|
|
277
|
+
| Position | `1` = Yes, `0` = No | `position: 1` |
|
|
278
|
+
| Side | `1` = Buy, `0` = Sell | Order side |
|
|
279
|
+
| Fee base | Microunits | `70_000` = 7% |
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## Building a Trading Bot
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
import { AlphaClient } from '@alpha-market/sdk';
|
|
287
|
+
import algosdk from 'algosdk';
|
|
288
|
+
|
|
289
|
+
const setup = () => {
|
|
290
|
+
const algodClient = new algosdk.Algodv2('', 'https://mainnet-api.algonode.cloud', 443);
|
|
291
|
+
const indexerClient = new algosdk.Indexer('', 'https://mainnet-idx.algonode.cloud', 443);
|
|
292
|
+
const account = algosdk.mnemonicToSecretKey(process.env.MNEMONIC!);
|
|
293
|
+
|
|
294
|
+
return new AlphaClient({
|
|
295
|
+
algodClient,
|
|
296
|
+
indexerClient,
|
|
297
|
+
signer: algosdk.makeBasicAccountTransactionSigner(account),
|
|
298
|
+
activeAddress: account.addr,
|
|
299
|
+
matcherAppId: 741347297,
|
|
300
|
+
usdcAssetId: 31566704,
|
|
301
|
+
feeAddress: 'YOUR_FEE_ADDRESS',
|
|
302
|
+
apiKey: 'YOUR_API_KEY',
|
|
303
|
+
});
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
const run = async () => {
|
|
307
|
+
const client = setup();
|
|
308
|
+
const markets = await client.getMarkets();
|
|
309
|
+
|
|
310
|
+
for (const market of markets) {
|
|
311
|
+
const book = await client.getOrderbook(market.marketAppId);
|
|
312
|
+
|
|
313
|
+
// Simple strategy: buy Yes if best ask < $0.30
|
|
314
|
+
const bestAsk = book.yes.asks.sort((a, b) => a.price - b.price)[0];
|
|
315
|
+
if (bestAsk && bestAsk.price < 300_000) {
|
|
316
|
+
console.log(`Buying Yes on "${market.title}" at $${bestAsk.price / 1e6}`);
|
|
317
|
+
|
|
318
|
+
await client.createMarketOrder({
|
|
319
|
+
marketAppId: market.marketAppId,
|
|
320
|
+
position: 1,
|
|
321
|
+
price: bestAsk.price,
|
|
322
|
+
quantity: 1_000_000,
|
|
323
|
+
isBuying: true,
|
|
324
|
+
slippage: 20_000, // $0.02 slippage
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
run().catch(console.error);
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
## Network Configuration
|
|
334
|
+
|
|
335
|
+
### Mainnet (default)
|
|
336
|
+
|
|
337
|
+
```typescript
|
|
338
|
+
const algodClient = new algosdk.Algodv2('', 'https://mainnet-api.algonode.cloud', 443);
|
|
339
|
+
const indexerClient = new algosdk.Indexer('', 'https://mainnet-idx.algonode.cloud', 443);
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Testnet
|
|
343
|
+
|
|
344
|
+
```typescript
|
|
345
|
+
const algodClient = new algosdk.Algodv2('', 'https://testnet-api.algonode.cloud', 443);
|
|
346
|
+
const indexerClient = new algosdk.Indexer('', 'https://testnet-idx.algonode.cloud', 443);
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
## Error Handling
|
|
350
|
+
|
|
351
|
+
All methods throw on failure. Wrap calls in try/catch:
|
|
352
|
+
|
|
353
|
+
```typescript
|
|
354
|
+
try {
|
|
355
|
+
const result = await client.createLimitOrder({ ... });
|
|
356
|
+
} catch (error) {
|
|
357
|
+
if (error.message.includes('balance')) {
|
|
358
|
+
console.error('Insufficient funds');
|
|
359
|
+
} else {
|
|
360
|
+
console.error('Order failed:', error.message);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
## License
|
|
366
|
+
|
|
367
|
+
MIT
|