@xgamesfun/solana 0.28.1 → 0.28.3

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 (50) hide show
  1. package/DISCLAIMER.md +3 -1
  2. package/README.md +18 -16
  3. package/bin/xsolana.mjs +27 -1
  4. package/js/approve/details.mjs +3 -3
  5. package/js/approve/live-check.mjs +2 -2
  6. package/js/approve/page.html +5 -5
  7. package/js/approve/page.js +16 -4
  8. package/js/approve/server.mjs +31 -26
  9. package/js/approve/with-key.mjs +7 -4
  10. package/js/chain/borsh.js +5 -3
  11. package/js/chain/rpc.js +26 -10
  12. package/js/client/accounts.js +6 -6
  13. package/js/client/cluster.js +136 -0
  14. package/js/client/grant.js +2 -2
  15. package/js/client/ix.js +16 -16
  16. package/js/client/pda.js +18 -5
  17. package/js/economy/check.mjs +28 -13
  18. package/js/economy/explain.mjs +2 -1
  19. package/js/economy/guide.mjs +6 -4
  20. package/js/economy/live.mjs +2 -2
  21. package/js/economy/plan.mjs +1 -1
  22. package/js/economy/schema.json +2 -2
  23. package/js/mcp/server.mjs +35 -4
  24. package/js/mcp/tools.mjs +56 -45
  25. package/js/mcp/with-cluster.mjs +25 -0
  26. package/js/play/index.js +48 -38
  27. package/js/play/sponsor.js +4 -4
  28. package/js/results/index.js +36 -14
  29. package/js/results/server.js +4 -3
  30. package/js/results/wire.js +9 -8
  31. package/package.json +6 -1
  32. package/release.json +6 -1
  33. package/skills/xsolana-economy/SKILL.md +13 -9
  34. package/skills/xsolana-economy/references/apps.md +2 -1
  35. package/skills/xsolana-economy/references/telling-the-person.md +1 -1
  36. package/skills/xsolana-economy/references/trust-and-cheating.md +1 -1
  37. package/types/chain/borsh.d.ts +4 -2
  38. package/types/chain/rpc.d.ts +10 -4
  39. package/types/client/cluster.d.ts +61 -0
  40. package/types/client/idl/loot.d.ts +9 -9
  41. package/types/client/pda.d.ts +1 -1
  42. package/types/economy/check.d.mts +1 -2
  43. package/types/economy/plan.d.mts +14 -14
  44. package/types/mcp/server.d.mts +1 -1
  45. package/types/mcp/tools.d.mts +9 -7
  46. package/types/mcp/with-cluster.d.mts +8 -0
  47. package/types/play/index.d.ts +2 -2
  48. package/types/results/index.d.ts +14 -7
  49. package/types/results/server.d.ts +3 -3
  50. package/types/results/wire.d.ts +8 -8
@@ -8,11 +8,12 @@ description: Build a web3, token or NFT economy on Solana without writing a smar
8
8
  An economy is one JSON spec (`xsolana.json` in the project) on **loot**, a Solana program every project shares. Nobody
9
9
  writes or deploys a contract: the spec is checked, simulated and priced by the `xsolana_*` tools, and it goes live
10
10
  signed by a key file on the owner's own machine, once they have read what will be sent and said yes. It runs on
11
- **devnet** until the program is audited.
11
+ **devnet**, where nothing is real money, and on **mainnet**, where everything is: an economy is on devnet unless its
12
+ file says `"network": "mainnet"`.
12
13
 
13
- The tools are the `xsolana_*` MCP tools. Without MCP, the same from a terminal: `npx -y @xgamesfun/solana@0.28.1 <guide|examples|check|simulate|cost|explain|review|publish|status> [xsolana.json]`,
14
- `npx -y @xgamesfun/solana@0.28.1 token <mint>` for a coin made elsewhere,
15
- or `npx -y @xgamesfun/solana@0.28.1 tool <name> '<json>'` for any tool (always with the exact version).
14
+ The tools are the `xsolana_*` MCP tools. Without MCP, the same from a terminal: `npx -y @xgamesfun/solana@0.28.3 <guide|examples|check|simulate|cost|explain|review|publish|status> [xsolana.json]`,
15
+ `npx -y @xgamesfun/solana@0.28.3 token <mint>` for a coin made elsewhere,
16
+ or `npx -y @xgamesfun/solana@0.28.3 tool <name> '<json>'` for any tool (always with the exact version).
16
17
 
17
18
  ## Rules (always)
18
19
 
@@ -33,7 +34,10 @@ or `npx -y @xgamesfun/solana@0.28.1 tool <name> '<json>'` for any tool (always w
33
34
  owner: whoever can read it controls the project. Never open it, copy it or print it, and never put it in a chat, a
34
35
  spec, a repository or a page. Never ask for a seed phrase or the key of a wallet the person already has; if they
35
36
  paste one, tell them to treat it as exposed and move its funds, and write it nowhere.
36
- 3. **Devnet only.** Nothing here is real money yet; say so.
37
+ 3. **Devnet first; mainnet only on the person's own word.** Build, check and try every economy on devnet, and say
38
+ that nothing there is real money. Write `"network": "mainnet"` only when the person asks for mainnet in their own
39
+ words, never to make something feel real. Tell them then, before anything is sent: it is real money, loot has not
40
+ been independently audited, what is sent can be lost, and what the review and the checker's legal warnings say.
37
41
  4. **The checker decides.** Never save or publish a spec with refusals. Fix each refusal the way its `fix` says.
38
42
  5. **Numbers come from the tools.** What a box gives back, how long a pool lasts, what going live costs: quote
39
43
  `xsolana_simulate`, `xsolana_cost` and `xsolana_explain`, never your own arithmetic. What a player pays is the tools'
@@ -137,7 +141,7 @@ or `npx -y @xgamesfun/solana@0.28.1 tool <name> '<json>'` for any tool (always w
137
141
  9. **When they say "put it live"**: `xsolana_publish` lists every step and its cost and gives the commands, which you
138
142
  run in the project folder exactly as given (they name the exact version; never drop it):
139
143
  - **A new economy gets a key file**, unless the project has one:
140
- `npx -y @xgamesfun/solana@0.28.1 keygen ~/.config/xsolana/<name>.json`. Give the person the address it prints. A
144
+ `npx -y @xgamesfun/solana@0.28.3 keygen ~/.config/xsolana/<name>.json`. Give the person the address it prints. A
141
145
  Solana key file they already have and name themselves (`~/.config/solana/id.json`) works the same; never go
142
146
  looking for one.
143
147
  - **Say what the key file is** before anything is sent: the project's owner, and, unless the spec says otherwise,
@@ -148,11 +152,11 @@ or `npx -y @xgamesfun/solana@0.28.1 tool <name> '<json>'` for any tool (always w
148
152
  set `"treasury": "wallet:<address>"` first: it can't be changed through the spec once live. Tell them to back
149
153
  the file up themselves (a USB stick, a password manager): if it is lost, nobody can change the economy, decide
150
154
  a contest or move what its address holds, and nothing restores it. You never open or copy it.
151
- - **Everything the setup takes from the owner must be at the key's address first**: the devnet SOL
152
- (`xsolana_cost`), any seed in a coin that already exists, and every NFT a stash, a raffle or an auction names. A
155
+ - **Everything the setup takes from the owner must be at the key's address first**: the SOL (`xsolana_cost`;
156
+ devnet SOL for an economy on devnet, real SOL for one on mainnet), any seed in a coin that already exists, and every NFT a stash, a raffle or an auction names. A
153
157
  collection they already have needs the key's address as its update authority. If they would rather not move
154
158
  those, offer the browser wallet.
155
- - **Show it**: `npx -y @xgamesfun/solana@0.28.1 approve xsolana.json --keypair <key file>` prints every step with
159
+ - **Show it**: `npx -y @xgamesfun/solana@0.28.3 approve xsolana.json --keypair <key file>` prints every step with
156
160
  what it pays and trusts, the warnings, the notice and a code, and sends nothing. Give the person that printout as
157
161
  it is, not a summary of it, and ask.
158
162
  - **On their yes**, the same command with `--yes <code>`. What lands is written back into `xsolana.json`. If it
@@ -76,7 +76,8 @@ await app.balances(); // what they hold of each of the economy's tokens
76
76
  }
77
77
  </script>
78
78
  ```
79
- Tell the person the one command that starts it, and that it serves on devnet.
79
+ Tell the person the one command that starts it, and which cluster its economy is on (devnet unless its file says
80
+ mainnet).
80
81
  - **What a roll looks like**: a box of several outcomes is rolled by the oracle a few seconds after the open; `openBox`
81
82
  waits for it. Show the player that it is rolling.
82
83
  - **A page that closes before the settle**: the SOL its settle key holds is not lost in the same browser (on another device, with nothing stored, it can't be found yet). Build the wallet with
@@ -29,7 +29,7 @@ and the spec differ (a limit, an amount, a key not set yet), change one of them
29
29
  a score): "Checking that a player really did it is up to you, on your own server: a game runs in the player's
30
30
  browser, and the program trusts the authority's signature."
31
31
  6. **Flags for the law, once.** `W-CHANCE-PRIZE`: "Players pay for a chance at money. That is gambling in many places once
32
- it is real money; this runs on devnet only." `W-CHANCE-ITEMS`: "Players pay for random items they can resell: some
32
+ it is real money; this one is on devnet, which is not." (On mainnet: "this one is on mainnet, so it is.") `W-CHANCE-ITEMS`: "Players pay for random items they can resell: some
33
33
  places treat that as gambling, and many require the odds to be shown." `W-REVENUE-SHARE`: "Stakers are paid from
34
34
  what players spend; regulators look at that when they decide whether a token is a security." `W-TOKEN-SALE`:
35
35
  "People pay for a share of a new token; selling a token to raise money is what securities law looks at first."
@@ -104,7 +104,7 @@ Run `xsolana_review` and go through what it reports; these are the points behind
104
104
  11. **The authority and the treasury.** The owner's wallet alone changes every price, rate, grant, limit and voucher
105
105
  key; the authority mints, moves pool funds, decides contests and releases holds, with no caps. On devnet the
106
106
  owner's key is the key file the setup was signed with: readable by its user alone, outside any repository, never
107
- pasted anywhere. With real money (mainnet is not open) those keys belong in a hardware wallet or a multisig; a
107
+ pasted anywhere. With real money (an economy on mainnet) those keys belong in a hardware wallet or a multisig; a
108
108
  server that signs gets an authority key of its own, never the owner's.
109
109
  12. **The page is untrusted.** A page builds the player's transactions, and a cheater builds their own: the program's
110
110
  checks are what count, never the page's. Anything the page decides (a score, a reward amount, who won) is only as
@@ -15,9 +15,11 @@ export declare function isAccount(idl: any, name: any, data: any): boolean;
15
15
  * [{ name, data }]. Only lines the program itself printed count: the log names which program each line comes from
16
16
  * (`Program <id> invoke [n]` … `success`), and any program can print a line that looks like an event. Logs alone
17
17
  * cannot say whether the transaction succeeded (the runtime can fail it after every instruction logged success), so
18
- * the caller decides that from the transaction's `meta.err` and reads events only when it is null.
18
+ * the caller decides that from the transaction's `meta.err` and reads events only when it is null. `program` is the
19
+ * address the program runs at: the IDL's own unless the caller names another (the program has an address of its own on
20
+ * each cluster, and an IDL holds one).
19
21
  */
20
- export declare function decodeEvents(idl: any, logs: any): {
22
+ export declare function decodeEvents(idl: any, logs: any, program?: any): {
21
23
  name: any;
22
24
  data: any;
23
25
  }[];
@@ -19,13 +19,19 @@ export declare const GENESIS: Readonly<{
19
19
  mainnet: "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d";
20
20
  testnet: "4uhcVJyU9pJkvQyS88uRDiswHXSCkY3zQawwpjk2NsNY";
21
21
  }>;
22
+ /**
23
+ * Refuses an RPC URL that names another cluster than the one the caller works on (`devnet` or `mainnet`). Returns the
24
+ * URL. A URL names nothing for certain: `checkCluster` reads the chain itself.
25
+ */
26
+ export declare function rightCluster(url: any, cluster?: string): any;
22
27
  /** Refuses an RPC URL that names mainnet. Returns the URL. */
23
- export declare function notMainnet(url: any): any;
28
+ export declare const notMainnet: (url: any) => any;
24
29
  /**
25
- * Refuses a chain that is mainnet or testnet, by its genesis block, whatever its URL says (a local validator is
26
- * let through). `rpc` has `call`. Returns the genesis hash.
30
+ * Refuses a chain that is not the cluster the caller works on, by its genesis block, whatever its URL says. On
31
+ * devnet, mainnet and testnet are refused and a local validator is let through; on mainnet, only mainnet itself
32
+ * passes. `rpc` has `call`. Returns the genesis hash.
27
33
  */
28
- export declare function checkCluster(rpc: any): Promise<any>;
34
+ export declare function checkCluster(rpc: any, cluster?: string): Promise<any>;
29
35
  /** The program's own words for a failed run (`AnchorError … Error Message: …`), else the last error log line. A program
30
36
  * built without its errors' text logs the error's name as its message: then the name alone (the client's IDL has
31
37
  * the sentence: `loot.lootError`). */
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Each cluster: loot's program there (devnet's is the IDL's own address), the chain as a wallet names it (Wallet
3
+ * Standard), and the RPC used when none is given. Mainnet has none: its public RPC refuses or limits what loot reads
4
+ * (a program's accounts, a compressed NFT's proof), so a mainnet RPC is always named (XSOLANA_RPC_URL, or `rpcUrl`).
5
+ */
6
+ export declare const CLUSTERS: Readonly<{
7
+ devnet: Readonly<{
8
+ program: string;
9
+ chain: "solana:devnet";
10
+ rpc: "https://api.devnet.solana.com";
11
+ }>;
12
+ mainnet: Readonly<{
13
+ program: "xgames8C758PyweWB9sDw8evvwsTVwyA2fGRUeAXVPy";
14
+ chain: "solana:mainnet";
15
+ rpc: null;
16
+ }>;
17
+ }>;
18
+ /**
19
+ * loot's program on this process's own cluster. A live binding: it follows `useCluster`. It knows nothing of
20
+ * `withCluster`: code that may run for either cluster asks `lootProgram()`, as the client itself does.
21
+ * @type {string}
22
+ */
23
+ export declare let LOOT_PROGRAM: string;
24
+ /**
25
+ * For a server's own set-up (js/mcp/with-cluster.mjs does it): `current()` answers the cluster of the work being done now,
26
+ * or nothing outside any. While it answers one, the client is on that cluster.
27
+ * @param {(() => string | undefined | null) | null} current
28
+ */
29
+ export declare function scopeClusters(current: (() => string | undefined | null) | null): void;
30
+ /**
31
+ * Names the cluster this process works on (`devnet` or `mainnet`) and returns it. Call it first, before any address
32
+ * is derived: it throws when the process already works on another cluster. Inside `withCluster` it names nothing: it
33
+ * throws unless the cluster named is the one that work is on.
34
+ * @param {'devnet' | 'mainnet'} cluster
35
+ * @returns {'devnet' | 'mainnet'}
36
+ */
37
+ export declare function useCluster(cluster: 'devnet' | 'mainnet'): 'devnet' | 'mainnet';
38
+ /**
39
+ * The cluster the client works on now: inside `withCluster` that work's, else the process's own (asking settles it).
40
+ * @returns {'devnet' | 'mainnet'}
41
+ */
42
+ export declare function cluster(): 'devnet' | 'mainnet';
43
+ /**
44
+ * loot's program on the cluster the client works on now (`cluster()`): what derives an address, builds an
45
+ * instruction or reads who owns an account calls this.
46
+ * @returns {string}
47
+ */
48
+ export declare function lootProgram(): string;
49
+ /** Whether the client works on mainnet now: what is paid and won there is real money. */
50
+ export declare const realMoney: () => boolean;
51
+ /** The cluster an economy is on: the `network` its file names, devnet when it names none. */
52
+ export declare const networkOf: (economy: any) => any;
53
+ /**
54
+ * The RPC URL this process reads and sends through: the one given, else XSOLANA_RPC_URL, else the cluster's own
55
+ * (devnet's public RPC; mainnet has none). A URL that names another cluster is refused.
56
+ */
57
+ export declare function clusterRpcUrl(url?: any): any;
58
+ /** Refuses a chain that is not this process's cluster, by its genesis block (`rpc.js`, `checkCluster`). */
59
+ export declare const checkOnCluster: (rpc: any) => Promise<any>;
60
+ /** This process's cluster as a wallet names it (Wallet Standard): `solana:devnet` or `solana:mainnet`. */
61
+ export declare const walletChain: () => "solana:devnet" | "solana:mainnet";
@@ -3613,8 +3613,8 @@ declare const _default: {
3613
3613
  };
3614
3614
  }[];
3615
3615
  } | {
3616
- fields?: undefined;
3617
3616
  name: string;
3617
+ fields?: undefined;
3618
3618
  })[];
3619
3619
  fields?: undefined;
3620
3620
  };
@@ -3862,7 +3862,6 @@ declare const _default: {
3862
3862
  name: string;
3863
3863
  docs: string[];
3864
3864
  type: {
3865
- fields?: undefined;
3866
3865
  kind: string;
3867
3866
  variants: ({
3868
3867
  name: string;
@@ -3888,6 +3887,7 @@ declare const _default: {
3888
3887
  type: string;
3889
3888
  })[];
3890
3889
  })[];
3890
+ fields?: undefined;
3891
3891
  };
3892
3892
  } | {
3893
3893
  name: string;
@@ -4041,11 +4041,11 @@ declare const _default: {
4041
4041
  docs?: undefined;
4042
4042
  name: string;
4043
4043
  type: {
4044
- fields?: undefined;
4045
4044
  kind: string;
4046
4045
  variants: {
4047
4046
  name: string;
4048
4047
  }[];
4048
+ fields?: undefined;
4049
4049
  };
4050
4050
  } | {
4051
4051
  name: string;
@@ -4378,7 +4378,6 @@ declare const _default: {
4378
4378
  name: string;
4379
4379
  docs: string[];
4380
4380
  type: {
4381
- fields?: undefined;
4382
4381
  kind: string;
4383
4382
  variants: ({
4384
4383
  name: string;
@@ -4397,9 +4396,10 @@ declare const _default: {
4397
4396
  name: string;
4398
4397
  fields: string[];
4399
4398
  } | {
4400
- fields?: undefined;
4401
4399
  name: string;
4400
+ fields?: undefined;
4402
4401
  })[];
4402
+ fields?: undefined;
4403
4403
  };
4404
4404
  } | {
4405
4405
  name: string;
@@ -4485,11 +4485,10 @@ declare const _default: {
4485
4485
  name: string;
4486
4486
  docs: string[];
4487
4487
  type: {
4488
- fields?: undefined;
4489
4488
  kind: string;
4490
4489
  variants: ({
4491
- fields?: undefined;
4492
4490
  name: string;
4491
+ fields?: undefined;
4493
4492
  } | {
4494
4493
  name: string;
4495
4494
  fields: string[];
@@ -4502,16 +4501,16 @@ declare const _default: {
4502
4501
  };
4503
4502
  }[];
4504
4503
  })[];
4504
+ fields?: undefined;
4505
4505
  };
4506
4506
  } | {
4507
4507
  name: string;
4508
4508
  docs: string[];
4509
4509
  type: {
4510
- fields?: undefined;
4511
4510
  kind: string;
4512
4511
  variants: ({
4513
- fields?: undefined;
4514
4512
  name: string;
4513
+ fields?: undefined;
4515
4514
  } | {
4516
4515
  name: string;
4517
4516
  fields: string[];
@@ -4524,6 +4523,7 @@ declare const _default: {
4524
4523
  };
4525
4524
  }[];
4526
4525
  })[];
4526
+ fields?: undefined;
4527
4527
  };
4528
4528
  })[];
4529
4529
  constants: ({
@@ -1,5 +1,5 @@
1
1
  import { MPL_CORE_PROGRAM } from '../chain/pda.js';
2
- export declare const LOOT_PROGRAM: string;
2
+ export { checkOnCluster, CLUSTERS, cluster, clusterRpcUrl, LOOT_PROGRAM, lootProgram, networkOf, realMoney, scopeClusters, useCluster, walletChain, } from './cluster.js';
3
3
  /** MagicBlock's VRF program and its default queue, the only queue the program accepts. */
4
4
  export declare const VRF_PROGRAM = "Vrf1RNUjXmQGjmQrQLvJHs9SNkvDJEsRVFPkfSQUwGz";
5
5
  export declare const VRF_QUEUE = "Cuj97ggrhhidhbu39TijNVqE74xvKJ69gDervRUXAxGh";
@@ -93,8 +93,7 @@ export declare function dateWords(seconds: any): string;
93
93
  * (`ASSUMED_TRIES`).
94
94
  * Returns { ok, refusals: [{ code, where, message, fix }], warnings: [{ code, where, message, fix? }] }.
95
95
  */
96
- export declare function check(economy: any, { network, now, project }?: {
97
- network?: string | undefined;
96
+ export declare function check(economy: any, { now, project }?: {
98
97
  now?: number | undefined;
99
98
  project?: any;
100
99
  }): {
@@ -30,11 +30,11 @@ export declare function tableBatches(t: any): never[][];
30
30
  export declare function partPrize(o: any, m: any): "Raffled" | {
31
31
  Stash: any[];
32
32
  } | {
33
+ Item?: undefined;
33
34
  Compressed: {
34
35
  item: any;
35
36
  tree: string;
36
37
  };
37
- Item?: undefined;
38
38
  Held?: undefined;
39
39
  Nft?: undefined;
40
40
  Roll?: undefined;
@@ -137,8 +137,8 @@ export declare function boxArgs(b: any, m: any): {
137
137
  Item: any[];
138
138
  Collection?: undefined;
139
139
  } | {
140
- Collection: any[];
141
140
  Item?: undefined;
141
+ Collection: any[];
142
142
  };
143
143
  key: any;
144
144
  test: any;
@@ -159,8 +159,8 @@ export declare function boxArgs(b: any, m: any): {
159
159
  Item: any[];
160
160
  Collection?: undefined;
161
161
  } | {
162
- Collection: any[];
163
162
  Item?: undefined;
163
+ Collection: any[];
164
164
  };
165
165
  key: any;
166
166
  test: any;
@@ -341,11 +341,11 @@ export declare function scheduleArgs(s: any, m: any): {
341
341
  * of the pool), an item (a compressed NFT of it into the project's tree, "@tree"), one NFT of a stash, or a roll of a box.
342
342
  */
343
343
  export declare function prizeArgs(p: any, m: any): "Raffled" | {
344
+ Item?: undefined;
344
345
  Compressed: {
345
346
  item: any;
346
347
  tree: string;
347
348
  };
348
- Item?: undefined;
349
349
  Held?: undefined;
350
350
  Nft?: undefined;
351
351
  Roll?: undefined;
@@ -464,8 +464,8 @@ export declare function lotteryArgs(l: any, m: any): {
464
464
  Item: any[];
465
465
  Collection?: undefined;
466
466
  } | {
467
- Collection: any[];
468
467
  Item?: undefined;
468
+ Collection: any[];
469
469
  };
470
470
  key: any;
471
471
  test: any;
@@ -514,8 +514,8 @@ export declare function lotteryArgs(l: any, m: any): {
514
514
  Item: any[];
515
515
  Collection?: undefined;
516
516
  } | {
517
- Collection: any[];
518
517
  Item?: undefined;
518
+ Collection: any[];
519
519
  };
520
520
  key: any;
521
521
  test: any;
@@ -608,8 +608,8 @@ export declare function contestArgs(c: any, m: any, at?: any): {
608
608
  Item: any[];
609
609
  Collection?: undefined;
610
610
  } | {
611
- Collection: any[];
612
611
  Item?: undefined;
612
+ Collection: any[];
613
613
  };
614
614
  key: any;
615
615
  test: any;
@@ -619,11 +619,11 @@ export declare function contestArgs(c: any, m: any, at?: any): {
619
619
  min_pot: bigint;
620
620
  stake: bigint;
621
621
  prize: string | {
622
+ Item?: undefined;
622
623
  Compressed: {
623
624
  item: any;
624
625
  tree: string;
625
626
  };
626
- Item?: undefined;
627
627
  Held?: undefined;
628
628
  Nft?: undefined;
629
629
  Roll?: undefined;
@@ -682,8 +682,8 @@ export declare function contestArgs(c: any, m: any, at?: any): {
682
682
  Item: any[];
683
683
  Collection?: undefined;
684
684
  } | {
685
- Collection: any[];
686
685
  Item?: undefined;
686
+ Collection: any[];
687
687
  };
688
688
  key: any;
689
689
  test: any;
@@ -700,8 +700,8 @@ export declare function farmArgs(f: any, m: any): {
700
700
  Item: any[];
701
701
  Collection?: undefined;
702
702
  } | {
703
- Collection: any[];
704
703
  Item?: undefined;
704
+ Collection: any[];
705
705
  };
706
706
  key: any;
707
707
  test: any;
@@ -780,8 +780,8 @@ export declare function auctionArgs(a: any, m: any): {
780
780
  Item: any[];
781
781
  Collection?: undefined;
782
782
  } | {
783
- Collection: any[];
784
783
  Item?: undefined;
784
+ Collection: any[];
785
785
  };
786
786
  key: any;
787
787
  test: any;
@@ -792,8 +792,8 @@ export declare function auctionArgs(a: any, m: any): {
792
792
  Item: any[];
793
793
  Collection?: undefined;
794
794
  } | {
795
- Collection: any[];
796
795
  Item?: undefined;
796
+ Collection: any[];
797
797
  };
798
798
  key: any;
799
799
  test: any;
@@ -801,11 +801,11 @@ export declare function auctionArgs(a: any, m: any): {
801
801
  };
802
802
  export declare function grantArgs(g: any, m: any): {
803
803
  gives: string | {
804
+ Item?: undefined;
804
805
  Compressed: {
805
806
  item: any;
806
807
  tree: string;
807
808
  };
808
- Item?: undefined;
809
809
  Held?: undefined;
810
810
  Nft?: undefined;
811
811
  Roll?: undefined;
@@ -911,8 +911,8 @@ export declare function grantArgs(g: any, m: any): {
911
911
  Item: any[];
912
912
  Collection?: undefined;
913
913
  } | {
914
- Collection: any[];
915
914
  Item?: undefined;
915
+ Collection: any[];
916
916
  };
917
917
  key: any;
918
918
  test: any;
@@ -352,7 +352,7 @@ export declare function runTool(name: any, input?: {}, ctx?: {}): Promise<{
352
352
  text: string;
353
353
  } | {
354
354
  program: string;
355
- cluster: "devnet";
355
+ cluster: "devnet" | "mainnet";
356
356
  version: string;
357
357
  idl: "@xgamesfun/solana/idl.json";
358
358
  package: `@xgamesfun/solana@${any}`;
@@ -22,12 +22,14 @@ export declare function approveCommand(file?: string, paths?: any): string;
22
22
  export declare function keyFileFor(name: any): string;
23
23
  /** The command that makes a project's key file (it prints the key's address, never the key). */
24
24
  export declare const keygenCommand: (keyFile: any) => string;
25
- export declare const CLUSTER = "devnet";
26
25
  export declare const DEVNET_RPC = "https://api.devnet.solana.com";
27
- /** What every answer carries, so an agent never has to remember the program's address. */
26
+ /**
27
+ * What every answer carries, so an agent never has to remember the program's address. The program and the cluster are
28
+ * read when asked for: this process's cluster (`client/cluster.js`).
29
+ */
28
30
  export declare const PROGRAM_INFO: Readonly<{
29
- program: string;
30
- cluster: "devnet";
31
+ readonly program: string;
32
+ readonly cluster: "devnet" | "mainnet";
31
33
  version: string;
32
34
  idl: "@xgamesfun/solana/idl.json";
33
35
  package: `@xgamesfun/solana@${any}`;
@@ -90,7 +92,7 @@ export declare const tools: ({
90
92
  };
91
93
  handler({ part }?: Readonly<Record<string, any>>): Promise<{
92
94
  program: string;
93
- cluster: "devnet";
95
+ cluster: "devnet" | "mainnet";
94
96
  version: string;
95
97
  idl: "@xgamesfun/solana/idl.json";
96
98
  package: `@xgamesfun/solana@${any}`;
@@ -743,10 +745,10 @@ export declare const tools: ({
743
745
  additionalProperties: boolean;
744
746
  };
745
747
  handler(input: any, ctx: any): Promise<{
748
+ token?: undefined;
746
749
  mint?: undefined;
747
750
  ok: boolean;
748
751
  text: string;
749
- token?: undefined;
750
752
  } | {
751
753
  mint?: undefined;
752
754
  ok: boolean;
@@ -823,7 +825,7 @@ export declare const tools: ({
823
825
  };
824
826
  handler(): Promise<{
825
827
  program: string;
826
- cluster: "devnet";
828
+ cluster: "devnet" | "mainnet";
827
829
  version: string;
828
830
  idl: "@xgamesfun/solana/idl.json";
829
831
  package: `@xgamesfun/solana@${any}`;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Runs `fn` on `cluster` (`devnet` or `mainnet`) and returns what it returns. A cluster loot does not know is refused.
3
+ * @template T
4
+ * @param {'devnet' | 'mainnet'} cluster
5
+ * @param {() => T} fn
6
+ * @returns {T}
7
+ */
8
+ export declare function withCluster<T>(cluster: 'devnet' | 'mainnet', fn: () => T): T;
@@ -4,7 +4,7 @@ export { checkSponsored, httpSponsor, sponsoredCost, sponsorGiveBack, sponsorHan
4
4
  * `solana:signMessage`, also `signMessage(bytes)`: the app's settle keys are made from one signature of it a session,
5
5
  * so a page that closes can make them again (`recover`).
6
6
  */
7
- export declare function walletStandardSigner(wallet: any, account: any, chain?: string): {
7
+ export declare function walletStandardSigner(wallet: any, account: any, chain?: "solana:devnet" | "solana:mainnet"): {
8
8
  address: any;
9
9
  signTransaction(wire: any): Promise<any>;
10
10
  signMessage?: ((message: any) => Promise<any>) | undefined;
@@ -34,7 +34,7 @@ export declare function solanaApp({ spec, rpcUrl, rpc, wallet, programs, now, ke
34
34
  now?: (() => number) | undefined;
35
35
  programs?: {} | undefined;
36
36
  rpc?: null | undefined;
37
- rpcUrl?: string | undefined;
37
+ rpcUrl?: null | undefined;
38
38
  spec: any;
39
39
  sponsor?: null | undefined;
40
40
  wallet: any;
@@ -1,5 +1,5 @@
1
1
  export { canonicalJson, CERT_KINDS, CLUSTERS, drawText, entryText, giveawayHostText, hostCertText, lockText, NO_GRANT, RESULT_DOMAIN, resultBytes, revokeGiveawayText, revokeText, rosterHash, } from './wire.js';
2
- /** xgames.fun's results server, on its play host (devnet until the program's audit). */
2
+ /** xgames.fun's results server, on its play host. One host answers for devnet and for mainnet: each request names its cluster. */
3
3
  export declare const RESULTS_SERVER = "https://play.xgames.fun/xsolana";
4
4
  /** A fresh round id: 16 random bytes, in hex. Make it when the round starts. */
5
5
  export declare const newRound: () => string;
@@ -19,7 +19,7 @@ export declare function keyFromSecret(secret: any): Promise<{
19
19
  sign: (message: any) => Promise<Uint8Array<ArrayBuffer>>;
20
20
  }>;
21
21
  /** One signer's signature of a result: { key, signature }. `signer` is a key from newKey, or anything with sign(). */
22
- export declare function signResult(signer: any, result: any, cluster?: string): Promise<{
22
+ export declare function signResult(signer: any, result: any, cluster?: "devnet" | "mainnet"): Promise<{
23
23
  key: any;
24
24
  signature: string;
25
25
  }>;
@@ -30,7 +30,7 @@ export declare function signResult(signer: any, result: any, cluster?: string):
30
30
  */
31
31
  export declare function report({ server, cert, signer, game, round, endedAt, winners, cluster, fetchImpl, }: {
32
32
  cert: any;
33
- cluster?: string | undefined;
33
+ cluster?: "devnet" | "mainnet" | undefined;
34
34
  endedAt: any;
35
35
  fetchImpl?: typeof fetch | undefined;
36
36
  game: any;
@@ -40,7 +40,8 @@ export declare function report({ server, cert, signer, game, round, endedAt, win
40
40
  winners: any;
41
41
  }): Promise<any>;
42
42
  /** A wallet's vouchers for a round it won: [{ grant, publicKey, signature, round, expires, … }]. */
43
- export declare function fetchVouchers({ server, game, round, wallet, fetchImpl }: {
43
+ export declare function fetchVouchers({ server, game, round, wallet, cluster, fetchImpl, }: {
44
+ cluster?: "devnet" | "mainnet" | undefined;
44
45
  fetchImpl?: typeof fetch | undefined;
45
46
  game: any;
46
47
  round: any;
@@ -80,6 +81,12 @@ export declare function signVoucher({ signer, game, grant, incarnation, wallet,
80
81
  personHash: string;
81
82
  amount: string;
82
83
  }>;
84
+ /**
85
+ * A path on a results server, for the cluster the request is on. One server answers for both clusters, and a request
86
+ * that names none is devnet's: so nothing is added on devnet (as every request was before), and `cluster=mainnet` on
87
+ * mainnet.
88
+ */
89
+ export declare function serverUrl(server: any, path: any, cluster?: "devnet" | "mainnet"): string;
83
90
  /**
84
91
  * A draw, from the organizer's side and the players'. `signMessage(text) → signature bytes` is the organizer's wallet
85
92
  * (its signMessage) or a host key's sign; `by` its address; `cert` the owner's host certificate when `by` is a host key.
@@ -96,7 +103,7 @@ export declare const draws: {
96
103
  }) => Promise<any>;
97
104
  /** A player enters with their play-host token, or with their wallet's signature (`wallet`, `signMessage`). */
98
105
  enter: ({ server, game, draw, token, wallet, signMessage, cluster, fetchImpl, }: {
99
- cluster?: string | undefined;
106
+ cluster?: "devnet" | "mainnet" | undefined;
100
107
  draw: any;
101
108
  fetchImpl?: typeof fetch | undefined;
102
109
  game: any;
@@ -110,7 +117,7 @@ export declare const draws: {
110
117
  beacon: any;
111
118
  by: any;
112
119
  cert?: null | undefined;
113
- cluster?: string | undefined;
120
+ cluster?: "devnet" | "mainnet" | undefined;
114
121
  draw: any;
115
122
  fetchImpl?: typeof fetch | undefined;
116
123
  game: any;
@@ -142,7 +149,7 @@ export declare const giveaways: {
142
149
  }) => Promise<any>;
143
150
  /** Reports its result, signed by its session key. `grant`: the host's grant (each winner is paid from it). */
144
151
  report: ({ server, game, giveaway, session, endedAt, winners, grant, cluster, fetchImpl, }: {
145
- cluster?: string | undefined;
152
+ cluster?: "devnet" | "mainnet" | undefined;
146
153
  endedAt: any;
147
154
  fetchImpl?: typeof fetch | undefined;
148
155
  game: any;
@@ -35,7 +35,7 @@ export declare function holds({ rpc, spec, wallet, item, atLeast, attribute, min
35
35
  }): Promise<number>;
36
36
  /** The exact text a wallet signs to prove it is its owner's: fixed lines, so nothing else can be passed off as it. */
37
37
  export declare const proofText: ({ cluster, game, wallet, purpose, nonce, expires }: {
38
- cluster?: string | undefined;
38
+ cluster?: "devnet" | "mainnet" | undefined;
39
39
  expires: any;
40
40
  game: any;
41
41
  nonce: any;
@@ -47,7 +47,7 @@ export declare const proofText: ({ cluster, game, wallet, purpose, nonce, expire
47
47
  * (unix seconds, `seconds` from now) and takes each nonce once, so a signed proof can't be replayed.
48
48
  */
49
49
  export declare function proofRequest({ cluster, game, wallet, purpose, seconds, now, }: {
50
- cluster?: string | undefined;
50
+ cluster?: "devnet" | "mainnet" | undefined;
51
51
  game: any;
52
52
  now?: number | undefined;
53
53
  purpose?: string | undefined;
@@ -69,7 +69,7 @@ export declare function readProof(text: any): {
69
69
  * `fields.nonce` against the ones the server handed out and not yet used.
70
70
  */
71
71
  export declare function verifyProof({ text, signature, wallet, game, purpose, cluster, now, }: {
72
- cluster?: string | undefined;
72
+ cluster?: "devnet" | "mainnet" | undefined;
73
73
  game: any;
74
74
  now?: number | undefined;
75
75
  purpose?: null | undefined;