@alpha-arcade/sdk 0.1.2 → 0.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/README.md CHANGED
@@ -26,7 +26,7 @@ const indexerClient = new algosdk.Indexer('', 'https://mainnet-idx.algonode.clou
26
26
  const account = algosdk.mnemonicToSecretKey('your twenty five word mnemonic ...');
27
27
  const signer = algosdk.makeBasicAccountTransactionSigner(account);
28
28
 
29
- // 3. Initialize the client
29
+ // 3. Initialize the client (no API key needed!)
30
30
  const client = new AlphaClient({
31
31
  algodClient,
32
32
  indexerClient,
@@ -34,10 +34,9 @@ const client = new AlphaClient({
34
34
  activeAddress: account.addr,
35
35
  matcherAppId: 3078581851,
36
36
  usdcAssetId: 31566704,
37
- apiKey: 'YOUR_API_KEY',
38
37
  });
39
38
 
40
- // 4. Fetch live markets
39
+ // 4. Fetch live markets (reads directly from chain)
41
40
  const markets = await client.getMarkets();
42
41
  console.log(`Found ${markets.length} live markets`);
43
42
 
@@ -72,8 +71,9 @@ new AlphaClient(config: AlphaClientConfig)
72
71
  | `activeAddress` | `string` | Yes | Your Algorand address |
73
72
  | `matcherAppId` | `number` | Yes | Matcher contract app ID (mainnet: `3078581851`) |
74
73
  | `usdcAssetId` | `number` | Yes | USDC ASA ID (mainnet: `31566704`) |
75
- | `apiKey` | `string` | Yes | Alpha partners API key (x-api-key header) |
74
+ | `apiKey` | `string` | No | Alpha partners API key. If provided, `getMarkets()` uses the API for richer data (images, categories, volume). If omitted, markets are discovered on-chain. |
76
75
  | `apiBaseUrl` | `string` | No | API base URL (default: `https://partners.alphaarcade.com/api`) |
76
+ | `marketCreatorAddress` | `string` | No | Market creator address for on-chain discovery (defaults to Alpha Arcade mainnet) |
77
77
 
78
78
  ---
79
79
 
@@ -226,26 +226,37 @@ for (const order of orders) {
226
226
 
227
227
  ### Markets
228
228
 
229
- #### `getMarkets()`
229
+ Markets can be loaded **on-chain** (default, no API key) or via the **REST API** (richer data, requires API key).
230
230
 
231
- Fetches all live, tradeable markets.
231
+ #### `getMarkets()` / `getMarket(marketId)`
232
+
233
+ Smart defaults — uses the API if `apiKey` is set, otherwise reads from chain.
232
234
 
233
235
  ```typescript
234
236
  const markets = await client.getMarkets();
235
237
  for (const m of markets) {
236
- console.log(`${m.title} — Yes: ${m.yesProb}%, Vol: $${m.volume}`);
238
+ console.log(`${m.title} — App ID: ${m.marketAppId}, source: ${m.source}`);
237
239
  }
240
+
241
+ const market = await client.getMarket('12345'); // app ID string for on-chain, UUID for API
238
242
  ```
239
243
 
240
- #### `getMarket(marketId)`
244
+ #### `getMarketsOnChain()` / `getMarketOnChain(marketAppId)`
241
245
 
242
- Fetches a single market by ID.
246
+ Always reads from the blockchain. No API key needed. Returns core data: title, asset IDs, resolution time, fees.
243
247
 
244
248
  ```typescript
245
- const market = await client.getMarket('abc123');
246
- if (market) {
247
- console.log(market.title, market.marketAppId);
248
- }
249
+ const markets = await client.getMarketsOnChain();
250
+ const market = await client.getMarketOnChain(3012345678);
251
+ ```
252
+
253
+ #### `getMarketsFromApi()` / `getMarketFromApi(marketId)`
254
+
255
+ Always uses the REST API. Requires `apiKey`. Returns richer data: images, categories, volume, probabilities.
256
+
257
+ ```typescript
258
+ const markets = await client.getMarketsFromApi();
259
+ const market = await client.getMarketFromApi('uuid-here');
249
260
  ```
250
261
 
251
262
  ---
@@ -296,13 +307,12 @@ const setup = () => {
296
307
  activeAddress: account.addr,
297
308
  matcherAppId: 3078581851,
298
309
  usdcAssetId: 31566704,
299
- apiKey: 'YOUR_API_KEY',
300
310
  });
301
311
  };
302
312
 
303
313
  const run = async () => {
304
314
  const client = setup();
305
- const markets = await client.getMarkets();
315
+ const markets = await client.getMarkets(); // Loads from chain, no API key needed
306
316
 
307
317
  for (const market of markets) {
308
318
  const book = await client.getOrderbook(market.marketAppId);
package/dist/index.cjs CHANGED
@@ -1955,7 +1955,121 @@ var getPositions = async (config, walletAddress) => {
1955
1955
 
1956
1956
  // src/modules/markets.ts
1957
1957
  var DEFAULT_API_BASE_URL = "https://partners.alphaarcade.com/api";
1958
- var getMarkets = async (config) => {
1958
+ var DEFAULT_MARKET_CREATOR_ADDRESS = "5P5Y6HTWUNG2E3VXBQDZN3ENZD3JPAIR5PKT3LOYJAPAUKOLFD6KANYTRY";
1959
+ var groupMultiChoiceMarkets = (flatMarkets) => {
1960
+ const parentMap = /* @__PURE__ */ new Map();
1961
+ const result = [];
1962
+ for (const m of flatMarkets) {
1963
+ const separatorIdx = m.title.lastIndexOf(" : ");
1964
+ if (separatorIdx === -1) {
1965
+ result.push(m);
1966
+ continue;
1967
+ }
1968
+ const parentTitle = m.title.substring(0, separatorIdx).trim();
1969
+ const optionTitle = m.title.substring(separatorIdx + 3).trim();
1970
+ let parent = parentMap.get(parentTitle);
1971
+ if (!parent) {
1972
+ parent = {
1973
+ id: `group:${parentTitle}`,
1974
+ title: parentTitle,
1975
+ marketAppId: m.marketAppId,
1976
+ // Use first option's app ID as the parent's
1977
+ yesAssetId: 0,
1978
+ noAssetId: 0,
1979
+ endTs: m.endTs,
1980
+ isResolved: m.isResolved,
1981
+ isLive: m.isLive,
1982
+ feeBase: m.feeBase,
1983
+ source: "onchain",
1984
+ options: []
1985
+ };
1986
+ parentMap.set(parentTitle, parent);
1987
+ result.push(parent);
1988
+ }
1989
+ parent.options.push({
1990
+ id: m.id,
1991
+ title: optionTitle,
1992
+ marketAppId: m.marketAppId,
1993
+ yesAssetId: m.yesAssetId,
1994
+ noAssetId: m.noAssetId,
1995
+ yesProb: 0,
1996
+ noProb: 0
1997
+ });
1998
+ }
1999
+ return result;
2000
+ };
2001
+ var getMarketsOnChain = async (config, options) => {
2002
+ const creatorAddress = config.marketCreatorAddress ?? DEFAULT_MARKET_CREATOR_ADDRESS;
2003
+ const activeOnly = options?.activeOnly ?? true;
2004
+ const allApps = [];
2005
+ let nextToken;
2006
+ let hasMore = true;
2007
+ while (hasMore) {
2008
+ let query = config.indexerClient.lookupAccountCreatedApplications(creatorAddress).limit(100);
2009
+ if (nextToken) {
2010
+ query = query.nextToken(nextToken);
2011
+ }
2012
+ const response = await query.do();
2013
+ if (response.applications?.length) {
2014
+ allApps.push(...response.applications);
2015
+ }
2016
+ if (response["next-token"]) {
2017
+ nextToken = response["next-token"];
2018
+ } else {
2019
+ hasMore = false;
2020
+ }
2021
+ }
2022
+ const flatMarkets = [];
2023
+ for (const app of allApps) {
2024
+ if (app.deleted) continue;
2025
+ const rawState = app.params?.["global-state"];
2026
+ if (!rawState) continue;
2027
+ const state = decodeGlobalState(rawState);
2028
+ if (activeOnly && !state.is_activated) continue;
2029
+ if (activeOnly && state.is_resolved) continue;
2030
+ if (activeOnly && state.resolution_time && state.resolution_time < Math.floor(Date.now() / 1e3)) continue;
2031
+ const appId = Number(app.id);
2032
+ flatMarkets.push({
2033
+ id: String(appId),
2034
+ title: state.title || "",
2035
+ marketAppId: appId,
2036
+ yesAssetId: state.yes_asset_id || 0,
2037
+ noAssetId: state.no_asset_id || 0,
2038
+ endTs: state.resolution_time || 0,
2039
+ isResolved: !!state.is_resolved,
2040
+ isLive: !!state.is_activated && !state.is_resolved,
2041
+ feeBase: state.fee_base_percent,
2042
+ source: "onchain"
2043
+ });
2044
+ }
2045
+ return groupMultiChoiceMarkets(flatMarkets);
2046
+ };
2047
+ var getMarketOnChain = async (config, marketAppId) => {
2048
+ try {
2049
+ const appId = typeof marketAppId === "string" ? Number(marketAppId) : marketAppId;
2050
+ const appInfo = await config.algodClient.getApplicationByID(appId).do();
2051
+ const rawState = appInfo.params?.["global-state"] ?? appInfo["params"]?.["global-state"] ?? [];
2052
+ const state = decodeGlobalState(rawState);
2053
+ return {
2054
+ id: String(appId),
2055
+ title: state.title || "",
2056
+ marketAppId: appId,
2057
+ yesAssetId: state.yes_asset_id || 0,
2058
+ noAssetId: state.no_asset_id || 0,
2059
+ endTs: state.resolution_time || 0,
2060
+ isResolved: !!state.is_resolved,
2061
+ isLive: !!state.is_activated && !state.is_resolved,
2062
+ feeBase: state.fee_base_percent,
2063
+ source: "onchain"
2064
+ };
2065
+ } catch {
2066
+ return null;
2067
+ }
2068
+ };
2069
+ var getMarketsFromApi = async (config) => {
2070
+ if (!config.apiKey) {
2071
+ throw new Error("apiKey is required for API-based market fetching. Use getMarketsOnChain() instead, or pass an apiKey.");
2072
+ }
1959
2073
  const baseUrl = config.apiBaseUrl ?? DEFAULT_API_BASE_URL;
1960
2074
  const allMarkets = [];
1961
2075
  let lastEvaluatedKey;
@@ -1972,10 +2086,10 @@ var getMarkets = async (config) => {
1972
2086
  }
1973
2087
  const data = await response.json();
1974
2088
  if (Array.isArray(data)) {
1975
- allMarkets.push(...data);
2089
+ allMarkets.push(...data.map((m) => ({ ...m, source: "api" })));
1976
2090
  hasMore = false;
1977
2091
  } else if (data.markets) {
1978
- allMarkets.push(...data.markets);
2092
+ allMarkets.push(...data.markets.map((m) => ({ ...m, source: "api" })));
1979
2093
  lastEvaluatedKey = data.lastEvaluatedKey;
1980
2094
  hasMore = !!lastEvaluatedKey;
1981
2095
  } else {
@@ -1984,7 +2098,10 @@ var getMarkets = async (config) => {
1984
2098
  }
1985
2099
  return allMarkets;
1986
2100
  };
1987
- var getMarket = async (config, marketId) => {
2101
+ var getMarketFromApi = async (config, marketId) => {
2102
+ if (!config.apiKey) {
2103
+ throw new Error("apiKey is required for API-based market fetching. Use getMarketOnChain() instead, or pass an apiKey.");
2104
+ }
1988
2105
  const baseUrl = config.apiBaseUrl ?? DEFAULT_API_BASE_URL;
1989
2106
  const url = `${baseUrl}/get-market?marketId=${encodeURIComponent(marketId)}`;
1990
2107
  const response = await fetch(url, { headers: { "x-api-key": config.apiKey } });
@@ -1993,7 +2110,21 @@ var getMarket = async (config, marketId) => {
1993
2110
  throw new Error(`Alpha API error: ${response.status} ${response.statusText}`);
1994
2111
  }
1995
2112
  const data = await response.json();
1996
- return data.market ?? data ?? null;
2113
+ const market = data.market ?? data ?? null;
2114
+ if (market) market.source = "api";
2115
+ return market;
2116
+ };
2117
+ var getMarkets = async (config) => {
2118
+ if (config.apiKey) {
2119
+ return getMarketsFromApi(config);
2120
+ }
2121
+ return getMarketsOnChain(config);
2122
+ };
2123
+ var getMarket = async (config, marketId) => {
2124
+ if (config.apiKey) {
2125
+ return getMarketFromApi(config, marketId);
2126
+ }
2127
+ return getMarketOnChain(config, marketId);
1997
2128
  };
1998
2129
 
1999
2130
  // src/client.ts
@@ -2006,7 +2137,6 @@ var AlphaClient = class {
2006
2137
  if (!config.activeAddress) throw new Error("activeAddress is required");
2007
2138
  if (!config.matcherAppId) throw new Error("matcherAppId is required");
2008
2139
  if (!config.usdcAssetId) throw new Error("usdcAssetId is required");
2009
- if (!config.apiKey) throw new Error("apiKey is required");
2010
2140
  this.config = {
2011
2141
  ...config,
2012
2142
  apiBaseUrl: config.apiBaseUrl ?? "https://partners.alphaarcade.com/api"
@@ -2145,9 +2275,10 @@ var AlphaClient = class {
2145
2275
  // Markets
2146
2276
  // ============================================
2147
2277
  /**
2148
- * Fetches all live, tradeable markets from the Alpha API.
2278
+ * Fetches all live, tradeable markets.
2149
2279
  *
2150
- * Automatically paginates to retrieve all markets.
2280
+ * If an API key is configured, uses the Alpha REST API (richer data: images, categories, volume).
2281
+ * Otherwise, discovers markets on-chain from the market creator address (no API key needed).
2151
2282
  *
2152
2283
  * @returns Array of live markets
2153
2284
  */
@@ -2157,21 +2288,69 @@ var AlphaClient = class {
2157
2288
  /**
2158
2289
  * Fetches a single market by its ID.
2159
2290
  *
2160
- * @param marketId - The market ID
2291
+ * If an API key is configured, uses the Alpha REST API.
2292
+ * Otherwise, reads the market's on-chain global state (pass the market app ID as a string).
2293
+ *
2294
+ * @param marketId - The market ID (UUID for API, app ID string for on-chain)
2161
2295
  * @returns The market data, or null if not found
2162
2296
  */
2163
2297
  async getMarket(marketId) {
2164
2298
  return getMarket(this.config, marketId);
2165
2299
  }
2300
+ /**
2301
+ * Fetches all live markets directly from the blockchain (no API key needed).
2302
+ *
2303
+ * Discovers markets by looking up all apps created by the market creator address.
2304
+ * Returns core data: title, asset IDs, resolution time, fees.
2305
+ * Does NOT include images, categories, volume, or probabilities.
2306
+ *
2307
+ * @returns Array of live markets from on-chain data
2308
+ */
2309
+ async getMarketsOnChain() {
2310
+ return getMarketsOnChain(this.config);
2311
+ }
2312
+ /**
2313
+ * Fetches a single market by app ID directly from the blockchain (no API key needed).
2314
+ *
2315
+ * @param marketAppId - The market app ID
2316
+ * @returns The market data, or null if not found
2317
+ */
2318
+ async getMarketOnChain(marketAppId) {
2319
+ return getMarketOnChain(this.config, marketAppId);
2320
+ }
2321
+ /**
2322
+ * Fetches all live markets from the Alpha REST API (requires API key).
2323
+ *
2324
+ * Returns richer data than on-chain: images, categories, volume, probabilities.
2325
+ *
2326
+ * @returns Array of live markets from the API
2327
+ */
2328
+ async getMarketsFromApi() {
2329
+ return getMarketsFromApi(this.config);
2330
+ }
2331
+ /**
2332
+ * Fetches a single market by ID from the Alpha REST API (requires API key).
2333
+ *
2334
+ * @param marketId - The market UUID
2335
+ * @returns The market data, or null if not found
2336
+ */
2337
+ async getMarketFromApi(marketId) {
2338
+ return getMarketFromApi(this.config, marketId);
2339
+ }
2166
2340
  };
2167
2341
 
2168
2342
  exports.AlphaClient = AlphaClient;
2343
+ exports.DEFAULT_MARKET_CREATOR_ADDRESS = DEFAULT_MARKET_CREATOR_ADDRESS;
2169
2344
  exports.calculateFee = calculateFee;
2170
2345
  exports.calculateFeeFromTotal = calculateFeeFromTotal;
2171
2346
  exports.calculateMatchingOrders = calculateMatchingOrders;
2172
2347
  exports.checkAssetOptIn = checkAssetOptIn;
2173
2348
  exports.decodeGlobalState = decodeGlobalState;
2174
2349
  exports.getEscrowGlobalState = getEscrowGlobalState;
2350
+ exports.getMarketFromApi = getMarketFromApi;
2175
2351
  exports.getMarketGlobalState = getMarketGlobalState;
2352
+ exports.getMarketOnChain = getMarketOnChain;
2353
+ exports.getMarketsFromApi = getMarketsFromApi;
2354
+ exports.getMarketsOnChain = getMarketsOnChain;
2176
2355
  //# sourceMappingURL=index.cjs.map
2177
2356
  //# sourceMappingURL=index.cjs.map