@xgamesfun/solana 0.26.0 → 0.26.2

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.
@@ -1,7 +1,8 @@
1
1
  // The setup plan: every instruction that puts an economy live on loot, in order, built with the client and
2
2
  // packed into transactions that fit. Nothing here signs or talks to the chain. Pure.
3
3
  //
4
- // A step is { id, part, says, signers, creates: [{ what, bytes }], build(ctx) → instructions }. `ctx` names the
4
+ // A step is { id, part, says, signers, creates: [{ what, bytes, fee? }], build(ctx) → instructions } (`fee`: lamports
5
+ // the program that makes the account keeps in it, on top of its rent: Token Metadata's). `ctx` names the
5
6
  // addresses a step needs: { owner, authority, project, collection, tree, treasury, mints: { tokenKey: mint }, keys: {
6
7
  // name: address } } where `keys` are the fresh keys this setup makes ("new:collection", "new:tree", "new:mint/points"), each of
7
8
  // which signs the step that creates it. `placeholderContext` fills every address with a stand-in, so a plan can be
@@ -20,8 +21,14 @@ import {
20
21
  TOKEN_PROGRAM,
21
22
  } from '../chain/pda.js';
22
23
  import { createTableIx, extendTableIx } from '../chain/lookup.js';
24
+ import { createFungibleMetadataIx, METADATA_BYTES, METADATA_FEE, METADATA_LIMITS } from '../chain/metadata.js';
23
25
  import { MEMO_PROGRAM } from '../chain/token2022.js';
24
- import { createAssociatedTokenAccountIdempotent, syncNative, transferLamports } from '../chain/programs.js';
26
+ import {
27
+ computeUnitLimit,
28
+ createAssociatedTokenAccountIdempotent,
29
+ syncNative,
30
+ transferLamports,
31
+ } from '../chain/programs.js';
25
32
  import {
26
33
  createAccountIx,
27
34
  initializeMint2Ix,
@@ -34,7 +41,7 @@ import { compileMessage, transactionSize } from '../chain/tx.js';
34
41
  import { sha256 } from '../chain/sha256.js';
35
42
  import { utf8 } from '../chain/bytes.js';
36
43
  import * as loot from '../client/index.js';
37
- import { check } from './check.mjs';
44
+ import { check, MAX_COMPUTE_UNITS } from './check.mjs';
38
45
  import {
39
46
  ACCOUNT_OVERHEAD,
40
47
  boxBuys,
@@ -727,18 +734,40 @@ export function setupSteps(economy, { now = 0, only = null, live: given = null }
727
734
  const fresh = !live?.project;
728
735
 
729
736
  // Tokens the project mints: a classic mint with the owner as its authority, handed to the project right after.
737
+ // Each is named on chain in the same step (its Token Metadata record: the name, the ticker and the link wallets
738
+ // show), while the owner is still its mint authority: Token Metadata takes a record from nobody else, so a mint whose
739
+ // minting was handed on or turned off without one can never have one. The owner stays the record's update authority.
730
740
  for (const t of m.tokens.values()) {
731
741
  if (t.source !== 'game' || live?.mints?.[t.key] || (t.mint && !t.mint.startsWith('@'))) continue;
732
742
  const key = `new:mint/${t.key}`;
743
+ const named = `write its name on chain (“${t.name}”, ${t.symbol}, ${t.uri ? `with the link ${t.uri}` : 'no picture link'}: only your wallet can change it later, which these tools don’t do yet, and Token Metadata keeps ${Number(METADATA_FEE) / 1e9} SOL for it)`;
744
+ const record = { what: `the name of ${t.symbol} on chain`, bytes: METADATA_BYTES, fee: Number(METADATA_FEE) };
745
+ // The checker refuses a name, ticker or link too long for a record before any plan is made, except on a token
746
+ // that is live already, whose words are only labels. Such a token is made here only when a live economy is
747
+ // planned as if it were new (explain's cost of the whole setup, which is never sent): its record is left out.
748
+ const fits = ['name', 'symbol', 'uri'].every(f => utf8(String(t[f] ?? '')).length <= METADATA_LIMITS[f]);
749
+ const name = ctx =>
750
+ fits
751
+ ? [
752
+ createFungibleMetadataIx({
753
+ mint: ctx.keys[key],
754
+ authority: ctx.owner,
755
+ name: t.name,
756
+ symbol: t.symbol,
757
+ uri: t.uri ?? '',
758
+ }),
759
+ ]
760
+ : [];
733
761
  if (t.fixedSupply) {
734
762
  const supply = amount(t.supply, t);
735
763
  add({
736
764
  id: `token:${t.key}`,
737
765
  part: `token:${t.key}`,
738
- says: `Make the token ${t.symbol} (${t.decimals} decimals) with a fixed supply of ${t.supply}, all of it to your wallet, then turn its minting off for good`,
766
+ says: `Make the token ${t.symbol} (${t.decimals} decimals) with a fixed supply of ${t.supply}, all of it to your wallet, ${named}, then turn its minting off for good`,
739
767
  signers: [owner, key],
740
768
  creates: [
741
769
  { what: `the mint of ${t.symbol}`, bytes: MINT_BYTES },
770
+ ...(fits ? [record] : []),
742
771
  { what: `your ${t.symbol} account`, bytes: 165 },
743
772
  ],
744
773
  build: ctx => [
@@ -750,6 +779,7 @@ export function setupSteps(economy, { now = 0, only = null, live: given = null }
750
779
  owner: TOKEN_PROGRAM,
751
780
  }),
752
781
  initializeMint2Ix({ mint: ctx.keys[key], decimals: t.decimals, authority: ctx.owner }),
782
+ ...name(ctx),
753
783
  createAssociatedTokenAccountIdempotent(ctx.owner, ctx.owner, ctx.keys[key]),
754
784
  mintToIx({
755
785
  mint: ctx.keys[key],
@@ -765,9 +795,9 @@ export function setupSteps(economy, { now = 0, only = null, live: given = null }
765
795
  add({
766
796
  id: `token:${t.key}`,
767
797
  part: `token:${t.key}`,
768
- says: `Make the token ${t.symbol} (${t.decimals} decimals), then hand its minting to the project`,
798
+ says: `Make the token ${t.symbol} (${t.decimals} decimals), ${named}, then hand its minting to the project`,
769
799
  signers: [owner, key],
770
- creates: [{ what: `the mint of ${t.symbol}`, bytes: MINT_BYTES }],
800
+ creates: [{ what: `the mint of ${t.symbol}`, bytes: MINT_BYTES }, ...(fits ? [record] : [])],
771
801
  build: ctx => [
772
802
  createAccountIx({
773
803
  from: ctx.owner,
@@ -777,6 +807,7 @@ export function setupSteps(economy, { now = 0, only = null, live: given = null }
777
807
  owner: TOKEN_PROGRAM,
778
808
  }),
779
809
  initializeMint2Ix({ mint: ctx.keys[key], decimals: t.decimals, authority: ctx.owner }),
810
+ ...name(ctx),
780
811
  setAuthorityIx({ account: ctx.keys[key], current: ctx.owner, newAuthority: ctx.project }),
781
812
  ],
782
813
  });
@@ -944,6 +975,10 @@ export function setupSteps(economy, { now = 0, only = null, live: given = null }
944
975
  id: `${part}:${kind}`,
945
976
  part,
946
977
  says,
978
+ // A box's write finds each of its pools' and stashes' addresses (1,500 units a try) and compares its entries
979
+ // pair by pair: a box of 16 stashes takes some 170,000 units, more where its addresses take more tries, past
980
+ // the 200,000 an instruction has by default. Its transaction asks for all a transaction can have.
981
+ compute: Boolean(def.Box),
947
982
  creates: [{ what, bytes }, ...pot],
948
983
  build: ctx => [
949
984
  loot.upsertIx({ owner: ctx.owner, project: project(ctx), def: resolve(def, ctx), ...options(ctx) }),
@@ -1785,7 +1820,18 @@ export function setupContext(m, { owner: ownerKey, keys, live: given = {}, rent
1785
1820
  export const stepBytes = (instructions, ctx) =>
1786
1821
  transactionSize(compileMessage({ payer: ctx.owner, blockhash: placeholderKey('blockhash'), instructions }));
1787
1822
 
1788
- /** Packs steps into transactions under the size budget, one signer set at a time; each step whole. */
1823
+ /** `instructions`, led by a compute limit of all a transaction can have when `compute` (a box's write is in them). */
1824
+ const budgeted = (instructions, compute) =>
1825
+ compute ? [computeUnitLimit(MAX_COMPUTE_UNITS), ...instructions] : instructions;
1826
+
1827
+ /** The bytes of a transaction of `step` alone, as `pack` sends it (its compute limit included). */
1828
+ export const stepAloneBytes = (step, ctx) => stepBytes(budgeted(step.build(ctx), Boolean(step.compute)), ctx);
1829
+
1830
+ /**
1831
+ * Packs steps into transactions under the size budget, one signer set at a time; each step whole. A transaction that
1832
+ * carries a step needing more compute than an instruction has by default (`compute`: a box's write) asks for all a
1833
+ * transaction can have, first.
1834
+ */
1789
1835
  export function pack(steps, ctx) {
1790
1836
  const transactions = [];
1791
1837
  let current = null;
@@ -1795,25 +1841,28 @@ export function pack(steps, ctx) {
1795
1841
  // A step with nothing to send (the lookup table of a plan built with no recent slot) is left out.
1796
1842
  if (!instructions.length) continue;
1797
1843
  const signerKind = step.signers.includes('authority') ? 'authority' : 'owner';
1798
- // A write that names boxes to roll takes all the compute a transaction has: alone.
1799
1844
  if (current && current.signer === signerKind && !step.alone && !current.alone) {
1800
- const next = [...current.instructions, ...instructions];
1845
+ const compute = current.compute || Boolean(step.compute);
1846
+ const next = budgeted([...current.built.flat(), ...instructions], compute);
1801
1847
  if (sizeOf(next) <= BUDGET) {
1802
1848
  current.instructions = next;
1849
+ current.compute = compute;
1803
1850
  current.steps.push(step);
1804
1851
  current.built.push(instructions);
1805
1852
  current.signers = [...new Set([...current.signers, ...step.signers])];
1806
1853
  continue;
1807
1854
  }
1808
1855
  }
1809
- const size = sizeOf(instructions);
1856
+ const alone = budgeted(instructions, Boolean(step.compute));
1857
+ const size = sizeOf(alone);
1810
1858
  if (size > BUDGET) throw new Error(`The step “${step.says}” is ${size} bytes: too big for one transaction.`);
1811
1859
  // `built`: each step's own instructions, in the order of `steps`.
1812
1860
  current = {
1813
1861
  signer: signerKind,
1814
1862
  steps: [step],
1815
1863
  built: [instructions],
1816
- instructions,
1864
+ instructions: alone,
1865
+ compute: Boolean(step.compute),
1817
1866
  signers: [...step.signers],
1818
1867
  alone: Boolean(step.alone),
1819
1868
  };
@@ -1828,7 +1877,8 @@ export function pack(steps, ctx) {
1828
1877
  * real instructions; without it they are built on stand-in addresses (for sizing, cost and showing).
1829
1878
  */
1830
1879
  export function plan(economy, { now = Math.floor(Date.now() / 1000), ctx = null, only = null, live = null } = {}) {
1831
- const checked = check(economy, { now });
1880
+ // With a real context the project is known: a box's write is checked with its own address searches counted.
1881
+ const checked = check(economy, { now, ...(ctx?.project ? { project: ctx.project } : {}) });
1832
1882
  if (!checked.ok) return { ok: false, refusals: checked.refusals, warnings: checked.warnings };
1833
1883
  const { steps, model: m } = setupSteps(economy, { now, only, live });
1834
1884
  if (ctx)
@@ -363,7 +363,7 @@
363
363
  "type": "object",
364
364
  "required": ["key", "source"],
365
365
  "additionalProperties": false,
366
- "description": "A currency. `sol`: SOL (players pay in wrapped SOL). `existing`: any mint by address, launched anywhere, classic or Token-2022, pump.fun included (xgames.fun takes no share of its fees). `project` (`game` is its older spelling): a token made when the economy goes live: the project mints it as its rules say (points, tickets, shards), or, with `supply`, a fixed supply minted once to the owner (a community token you keep).",
366
+ "description": "A currency. `sol`: SOL (players pay in wrapped SOL). `existing`: any mint by address, launched anywhere, classic or Token-2022, pump.fun included (xgames.fun takes no share of its fees). `project` (`game` is its older spelling): a token made when the economy goes live: the project mints it as its rules say (points, tickets, shards), or, with `supply`, a fixed supply minted once to the owner (a community token you keep). A token made this way is named on chain as it is made (its `name`, `symbol` and `uri`), which is what wallets show. Only the owner's wallet can change that later, and a change to them in a spec that is already live changes nothing on chain yet.",
367
367
  "properties": {
368
368
  "key": {
369
369
  "$ref": "#/$defs/key"
@@ -401,11 +401,12 @@
401
401
  "description": "Where the token trades, recorded for the app and not read or enforced by the tools: loot doesn't launch or trade tokens. A token launched elsewhere is `existing`, by its mint. `games.fun` is the older spelling of `xgames.fun`."
402
402
  },
403
403
  "uri": {
404
- "$ref": "#/$defs/link"
404
+ "$ref": "#/$defs/link",
405
+ "description": "`project` only: a link to a JSON file that names the token's picture (`{ \"name\", \"symbol\", \"image\": \"https://…\" }`), at most 200 bytes. Going live writes it on chain with the token's name and ticker; without it wallets show the name and ticker and no picture."
405
406
  },
406
407
  "image": {
407
408
  "$ref": "#/$defs/link",
408
- "description": "A picture of it, recorded for the app: the tools don't read it, and the setup doesn't write it to the mint."
409
+ "description": "A picture of it, recorded for the app: the tools don't read it, and the setup doesn't write it on chain (what wallets show is the `image` the JSON file at `uri` names)."
409
410
  },
410
411
  "powers": {
411
412
  "type": "object",
package/js/play/index.js CHANGED
@@ -1489,6 +1489,11 @@ export function solanaApp({
1489
1489
  const g = await projectNow();
1490
1490
  const box = await read('LootBox', loot.pda.box(project, boxId));
1491
1491
  if (!Number.isInteger(count) || count < 1) throw new Error('Buy a whole number, one at least (count).');
1492
+ // One `buy` prices at most so many sales (`PackTooLarge` past it): more is several purchases.
1493
+ if (count > loot.MOST_SALES_A_BUY)
1494
+ throw new Error(
1495
+ `One purchase buys at most ${loot.MOST_SALES_A_BUY.toLocaleString('en-US')} (count): buy the rest in another.`,
1496
+ );
1492
1497
  const bound =
1493
1498
  boundOf({ ...box, currencyKey: part?.currency }, part?.name ?? `box ${boxId}`, { maxPrice, listing }, part?.key) *
1494
1499
  BigInt(count);
@@ -2325,8 +2330,9 @@ export function solanaApp({
2325
2330
  const e = i == null ? null : r.entries[i];
2326
2331
  const out = [];
2327
2332
  const rolls = [];
2328
- // Whether a pull here wants the largest heap (a run of rolls), and whether one stops short of the part (a raffle's
2329
- // NFTs past what one pull takes out, a run of rolls past what one transaction carries): a next pull carries on.
2333
+ // Whether a pull here wants the largest heap (a run of rolls, or several NFTs out of the round's own stash), and
2334
+ // whether one stops short of the part (a raffle's NFTs past what one pull takes out or one transaction carries, a
2335
+ // run of rolls past what one transaction carries): a next pull carries on.
2330
2336
  let heap = false;
2331
2337
  let partial = false;
2332
2338
  const g = await projectNow();
@@ -2382,10 +2388,12 @@ export function solanaApp({
2382
2388
  projectMint: mintOf(),
2383
2389
  };
2384
2390
  more.nonce = pullNonce(key, i);
2385
- // A run of places that each give a roll: two accounts a place, as many as one transaction carries, on the
2386
- // largest heap. The pull is sized from a dry run, largest first; the next pull carries on, and only the last
2387
- // carries the close.
2388
- if (given.Roll) {
2391
+ // A run of places that each give a roll (two accounts a place), or several NFTs out of the round's own stash
2392
+ // (each NFT's accounts, and heap the program does not give back: 8 Core moves in a round of some 125 places or
2393
+ // more run past the default 32 KiB): as many places as one transaction carries, on the largest heap. The pull
2394
+ // is sized from a dry run, largest first; the next pull carries on while the round still owes the entry, and
2395
+ // only the last carries the close.
2396
+ if (given.Roll || (stash && loot.prizePlacesOwed(r, i, run).length > 1)) {
2389
2397
  const owed = loot.prizePlacesOwed(r, i, run).length;
2390
2398
  const sized = async most => {
2391
2399
  const ix = loot.pullIx({
@@ -4928,7 +4936,7 @@ export function solanaApp({
4928
4936
  heap ||= built.heap;
4929
4937
  partial ||= built.partial;
4930
4938
  }
4931
- // A run of rolls asks for the largest heap.
4939
+ // A run of rolls, or several NFTs out of the round's own stash, asks for the largest heap.
4932
4940
  if (heap) instructions.splice(1, 0, requestHeapFrame(loot.LARGE_SETTLE_HEAP));
4933
4941
  // A pull that stopped short of its part (a raffle's NFTs, 64 a pull; a run of rolls): sent, then the next carries
4934
4942
  // on while the round moves (its NFTs out, its places paid) and still owes it.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xgamesfun/solana",
3
- "version": "0.26.0",
3
+ "version": "0.26.2",
4
4
  "mcpName": "io.github.XGamesFun/solana-kit",
5
5
  "description": "Loot boxes, gacha, shops, lotteries, auctions, NFT staking, crafting and rewards on Solana without writing a smart contract: one shared program, its JS client, a CLI, and an MCP server and skill so Claude Code, Codex or any AI agent can design, check, simulate and launch an economy.",
6
6
  "license": "Apache-2.0",
package/release.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
- "version": "0.26.0",
2
+ "version": "0.26.1",
3
3
  "programId": "9cwqM1TXytPnFZsLfmUyv2dg4uW6Ch9C6UJVPns7NFQ",
4
- "sbfBytes": 1779872,
5
- "sbfSha256": "d5d4a2ca2bca79e8d4930b697cc3aecfcf54399aa85585c02e267ffbbdfda429",
6
- "idlSha256": "4e1407b41c5947821d154472bd26c2df0fff9c750475239d444b2f5fd5d3d8dc",
7
- "clientSha256": "e6b1783c6f68e342aa165474f1d3b96a7a24a3a981be4882ebcd7ae071e41e6e"
4
+ "sbfBytes": 1783800,
5
+ "sbfSha256": "af318ccfa4d2901076b85fcd1b4467b03253adf0de16e73a9dfc1ef8077b2c14",
6
+ "idlSha256": "0e88fc826a585cf17917cbc654e33b68232771769fe9aae1d5899a257940ff47",
7
+ "clientSha256": "20e40ee24d808d10091a0bd9973c3c4883e9dd35da4a6beac97557dd85a362c8"
8
8
  }
@@ -9,8 +9,8 @@ An economy is one JSON spec (`xsolana.json` in the project) on **loot**, a Solan
9
9
  writes or deploys a contract: the spec is checked, simulated and priced by the `xsolana_*` tools, and the project's
10
10
  owner puts it live by approving in their own wallet. It runs on **devnet** until the program is audited.
11
11
 
12
- The tools are the `xsolana_*` MCP tools. Without MCP, the same from a terminal: `npx -y @xgamesfun/solana@0.26.0 <guide|examples|check|simulate|cost|explain|review|publish|status> [xsolana.json]`,
13
- or `npx -y @xgamesfun/solana@0.26.0 tool <name> '<json>'` for any tool (always with the exact version).
12
+ The tools are the `xsolana_*` MCP tools. Without MCP, the same from a terminal: `npx -y @xgamesfun/solana@0.26.2 <guide|examples|check|simulate|cost|explain|review|publish|status> [xsolana.json]`,
13
+ or `npx -y @xgamesfun/solana@0.26.2 tool <name> '<json>'` for any tool (always with the exact version).
14
14
 
15
15
  ## Rules (always)
16
16
 
@@ -121,7 +121,7 @@ or `npx -y @xgamesfun/solana@0.26.0 tool <name> '<json>'` for any tool (always w
121
121
  level would cost. Run it again after every change that touches a route that pays.
122
122
  9. **When they say "put it live"**: `xsolana_publish` lists every step and its cost and gives the command. Tell them to
123
123
  run it themselves in the project folder, exactly as `xsolana_publish` gives it (it names the exact version:
124
- `npx -y @xgamesfun/solana@0.26.0 approve xsolana.json`; never drop the version). It opens a page on their computer where
124
+ `npx -y @xgamesfun/solana@0.26.2 approve xsolana.json`; never drop the version). It opens a page on their computer where
125
125
  they connect a devnet wallet and approve; what lands is written back into `xsolana.json`. You publish nothing.
126
126
  10. **After it is live**: `xsolana_status` shows each part on chain; read it before acting on what the person says
127
127
  happened. A later change is the same loop: save, publish, and the approval sends only what changed. What only the
@@ -90,7 +90,8 @@ money; it holds no files and serves nothing.
90
90
  the mints and vaults of its tokens, a fresh item's tables) are bounded by that, however many outcomes it has.
91
91
  `xsolana_check` counts them. One answer also holds only so much of a box (measured: 128 outcomes that give
92
92
  nothing, 29 of token amounts, 18 each of its own item; 41 slots; 72 odds rules; 16 token prizes or 18 collectibles
93
- in one outcome; 340 texts in a gate): a box past that is refused when written. Put a long weighted list in a table
93
+ in one outcome; 340 texts in a gate; fewer where outcomes name pools or stashes, since the write counts finding
94
+ each one's address): a box past that is refused when written. Put a long weighted list in a table
94
95
  or a stash, drawn by one outcome.
95
96
  - **The program takes any time, and the checker says a far one's date in words (W-FAR-TIME).** A time that looks like
96
97
  milliseconds, or lands more than three years out, locks the bids, tickets, NFTs or vault that wait on it until then.
@@ -116,6 +117,13 @@ Don'ts:
116
117
  otherwise, and until it is filled those prizes pay nothing.
117
118
  - **A token the project mints** (`source: "project"`) is how points, tickets, attempts and shards work; an existing coin
118
119
  needs its mint address and decimals from the person (ask; never guess an address).
120
+ - **A token the setup makes is named on chain as it goes live**: its `name`, its `symbol` and its `uri` (a link to a
121
+ JSON file the project hosts, `{ "name", "symbol", "image": "https://…" }`), which is what wallets and explorers show.
122
+ Ask for the name, the ticker and a picture before going live: with no `uri` it shows by name and ticker with no
123
+ picture. Only the owner's wallet can change the three later (Token Metadata's rule, not loot's), and these tools
124
+ don't change a live token's yet, so get them right first. The record costs about 0.014 SOL (`xsolana_cost` says it:
125
+ rent, and 0.01 SOL Token Metadata keeps). A token that went live before the tools wrote one has none and
126
+ can't be given one: only a mint's own authority can name it, and its minting was handed on or turned off.
119
127
  - **NFTs the project has no authority over** (any collection but its own): they count as they are. Say that
120
128
  whatever their collection lets be written on an NFT (even by its holder) is what a gate or a boost reads, and that
121
129
  the project's notes about one (levels, uses) live in its Sheet, which the authority writes and pays for. Every
@@ -0,0 +1,40 @@
1
+ /** A record's size: Token Metadata pads every one to it, whatever its name, ticker and link. */
2
+ export declare const METADATA_BYTES = 607;
3
+ /** What Token Metadata keeps in each record it makes, on top of the record's rent: its own fee. */
4
+ export declare const METADATA_FEE = 10000000n;
5
+ /** The longest name, ticker and link a record takes, in UTF-8 bytes. */
6
+ export declare const METADATA_LIMITS: Readonly<{
7
+ name: 32;
8
+ symbol: 10;
9
+ uri: 200;
10
+ }>;
11
+ /** The address of a mint's Token Metadata record. */
12
+ export declare const metadataAddress: (mint: any) => any;
13
+ /**
14
+ * Token Metadata's CreateV1 for a fungible token whose mint exists: its name, its ticker and a link to a JSON file with
15
+ * its picture ('' for none). `authority` is the mint's authority and signs; it becomes the record's update authority,
16
+ * the only one who can change the record later. `payer` pays its rent and Token Metadata's fee (`METADATA_FEE`).
17
+ * The mint is listed read-only: this path of Token Metadata writes nothing to a mint that exists. That is the
18
+ * program's behaviour, not a lock: in a setup's own transaction the mint is writable all the same (the same
19
+ * transaction makes it), so the tests read its supply and authorities back after the record is made. The record says
20
+ * a fungible token whatever the decimals (CreateMetadataAccountV3 would call one of 0 decimals an asset, which
21
+ * wallets list with collectibles).
22
+ */
23
+ export declare function createFungibleMetadataIx({ mint, authority, payer, name, symbol, uri }: {
24
+ authority: any;
25
+ mint: any;
26
+ name: any;
27
+ payer?: any;
28
+ symbol: any;
29
+ uri?: string | undefined;
30
+ }): {
31
+ programId: string;
32
+ keys: {
33
+ pubkey: any;
34
+ isSigner: any;
35
+ isWritable: any;
36
+ }[];
37
+ data: Uint8Array<any>;
38
+ };
39
+ /** The update authority a Token Metadata record names (who can change its name, ticker and link). */
40
+ export declare const metadataUpdateAuthority: (data: any) => string | null;
@@ -41,6 +41,19 @@ export declare function entryRows(entries: any, items?: {}): any;
41
41
  * gives items. A pack's order grows with its cards.
42
42
  */
43
43
  export declare function orderBytes(lootBox: any, shares: number | undefined, opens: number | undefined, items: any): number;
44
+ /** The most draws one `open_box` takes in all, its count times the box's draws: what one answer could weigh, each draw
45
+ * at its weighing at least (`ROLL_BUDGET / COST_WEIGH`, 300). More is refused before any price is added up
46
+ * (`PackTooLarge`). */
47
+ export declare const MOST_DRAWS_A_PURCHASE: number;
48
+ /** The most sales one `buy` takes (`count`): what one transaction can price (`MAX_TX_CU / COST_SALE`, rounded down:
49
+ * 25,454). More is refused before any price is added up (`PackTooLarge`). */
50
+ export declare const MOST_SALES_A_BUY: number;
51
+ /**
52
+ * The tries counted for finding a pool's or a stash's address when the project is not known yet (a spec checked before
53
+ * any wallet is named): 2, what an address takes on average (half are found at the first try, a quarter at the second,
54
+ * and so on). With the project known, the count is exact: `256 - bump` tries an address.
55
+ */
56
+ export declare const ASSUMED_TRIES = 2;
44
57
  /**
45
58
  * The heap reading a box takes beyond its entries (`order::box_bytes`): its odds, gate, shares, subject, slots and
46
59
  * fates, read whole with it, by their bytes and their number. `box`: the box's args, as `upsertBoxIx` takes them.
@@ -53,20 +66,30 @@ export declare function boxBytes({ odds, gate, shares, subject, slots, fates }:
53
66
  slots?: never[] | undefined;
54
67
  subject?: null | undefined;
55
68
  }): bigint;
69
+ /**
70
+ * The tries finding a pool's (`pool` true) or a stash's address takes (`order::searched`: `256 - bump`), for `project`'s
71
+ * pool or stash `id`. With no project, `ASSUMED_TRIES`.
72
+ */
73
+ export declare function searchTries(project: any, pool: any, id: any): number;
56
74
  /**
57
75
  * Whether all of `opens` opens of `entries` by `slots` fit one oracle answer (`order::draws_fit`), each draw at the
58
- * dearest its slot could make, with what is known from the box alone (no table rows, a stash of one group), its `odds`,
59
- * `shares` and `fates` counted, and `bytes` (`boxBytes`) of heap reading the box takes beyond its entries. `slots` may
60
- * be a number: that many draws among every entry. The answer's heap counts for a box that rolls, or one sold through
61
- * the oracle (`oracle`: a box that doesn't roll but one `buy` can't carry, `buyFits`). The program refuses a box whose
62
- * one open doesn't fit at its upsert, and a purchase that doesn't at `open_box`, where it also reads what the accounts
63
- * hold (`PackTooLarge`).
76
+ * dearest its slot could make, with what is known from the box alone (no table rows, a stash of one group, a named
77
+ * NFT's stash of one row), its `odds`, `shares` and `fates` counted, and `bytes` (`boxBytes`) of heap reading the box
78
+ * takes beyond its entries. `slots` may be a number: that many draws among every entry. The answer's heap counts for a
79
+ * box that rolls, or one sold through the oracle (`oracle`: a box that doesn't roll but one `buy` can't carry,
80
+ * `buyFits`). `project`: the project the box is in, whose pools' and stashes' addresses the write searches for (each
81
+ * search counted at `256 - bump` tries of 1,500 units); without it, at `ASSUMED_TRIES` tries an address. The program
82
+ * refuses a box whose one open doesn't fit at its upsert (`PackTooLarge`). `purchase`: counted as `open_box` counts a
83
+ * purchase of `opens` instead (the answer's heap always; a draw's own stock read again only when there are several; at
84
+ * most `MOST_DRAWS_A_PURCHASE` draws in all), from what the box alone tells: the program reads the accounts too.
64
85
  */
65
- export declare function drawsFit(entries: any, slots: any, opens?: number, { odds, shares, fates, bytes, oracle }?: {
86
+ export declare function drawsFit(entries: any, slots: any, opens?: number, { odds, shares, fates, bytes, oracle, project, purchase }?: {
66
87
  bytes?: bigint | undefined;
67
88
  fates?: number | undefined;
68
89
  odds?: number | undefined;
69
90
  oracle?: boolean | undefined;
91
+ project?: null | undefined;
92
+ purchase?: boolean | undefined;
70
93
  shares?: number | undefined;
71
94
  }): boolean;
72
95
  /**
@@ -76,10 +99,21 @@ export declare function drawsFit(entries: any, slots: any, opens?: number, { odd
76
99
  * (`drawsFit` with `oracle`), and can't give a roll (`PackTooLarge`). `box`: the box's args.
77
100
  */
78
101
  export declare function buyFits(box: any, draws?: any): boolean;
102
+ /**
103
+ * Whether the program writes `box` (its args, as `upsertBoxIx` takes them, or a box read from the chain) as far as what
104
+ * it costs goes (`catalog::loot_box`, `PackTooLarge`): a box that doesn't roll sells by `buy` when one transaction carries
105
+ * the whole purchase (`buyFits`), else through the oracle, whose heap then counts and which can't give a roll; and every
106
+ * draw of one open fits one answer (`drawsFit`). `project`: whose pools and stashes the box names (a box read from the
107
+ * chain says); without it, each search at `ASSUMED_TRIES` tries.
108
+ */
109
+ export declare function boxFits(box: any, { project }?: {
110
+ project?: any;
111
+ }): boolean;
79
112
  /** The most program rent and fee one order takes from its player, in lamports (0.01 SOL): a client cap (`opensAnOrder`). */
80
113
  export declare const ORDER_COST_CAP = 10000000n;
81
114
  /**
82
- * The most opens of `lootBox` a client puts in one order: what one oracle answer draws (`drawsFit`), and what keeps the
115
+ * The most opens of `lootBox` a client puts in one order: what one oracle answer draws (`drawsFit` as a purchase counts
116
+ * it, the box's project's searches counted when the box names it: a box read from the chain does), and what keeps the
83
117
  * order's rent and the player's fee within `ORDER_COST_CAP` (`orderBytes` with `items`, so with the box's shares). At
84
118
  * least one: a box whose one open is over the cap is still bought one open an order. A purchase of more is several
85
119
  * orders, each its own answer.
@@ -87,12 +87,16 @@ export declare const FAR_SECONDS: number;
87
87
  /** A Unix time in words, in English: "14 March 2031". Past what a date can show, the year alone. */
88
88
  export declare function dateWords(seconds: any): string;
89
89
  /**
90
- * Checks an economy spec. `now` (Unix seconds) dates "publish".
90
+ * Checks an economy spec. `now` (Unix seconds) dates "publish". `project`: the project's address, once a wallet is named
91
+ * (the plan for a real setup passes it; a live economy's file names it): a box's write searches for each of its pools'
92
+ * and stashes' addresses, and the checker counts each search exactly with it, else at an assumed 2 tries an address
93
+ * (`ASSUMED_TRIES`).
91
94
  * Returns { ok, refusals: [{ code, where, message, fix }], warnings: [{ code, where, message, fix? }] }.
92
95
  */
93
- export declare function check(economy: any, { network, now }?: {
96
+ export declare function check(economy: any, { network, now, project }?: {
94
97
  network?: string | undefined;
95
98
  now?: number | undefined;
99
+ project?: any;
96
100
  }): {
97
101
  ok: boolean;
98
102
  refusals: any[];
@@ -2,6 +2,7 @@
2
2
  export declare function setupCost(plan: any, economy: any): {
3
3
  accounts: any;
4
4
  rentSol: any;
5
+ metadataFeesSol: any;
5
6
  programFeesSol: any;
6
7
  networkFeesSol: any;
7
8
  seeds: {};
@@ -40,6 +41,7 @@ export declare function cost(economy: any, { now, only, live }?: {
40
41
  steps: any[];
41
42
  built: any[];
42
43
  instructions: any;
44
+ compute: boolean;
43
45
  signers: any[];
44
46
  alone: boolean;
45
47
  }[];
@@ -50,6 +52,7 @@ export declare function cost(economy: any, { now, only, live }?: {
50
52
  setup: {
51
53
  accounts: any;
52
54
  rentSol: any;
55
+ metadataFeesSol: any;
53
56
  programFeesSol: any;
54
57
  networkFeesSol: any;
55
58
  seeds: {};
@@ -33,6 +33,7 @@ export declare function prepare(economy: any, { owner, keys, live, now, rent, on
33
33
  steps: any[];
34
34
  built: any[];
35
35
  instructions: any;
36
+ compute: boolean;
36
37
  signers: any[];
37
38
  alone: boolean;
38
39
  }[];
@@ -68,6 +69,7 @@ export declare function prepare(economy: any, { owner, keys, live, now, rent, on
68
69
  steps: any[];
69
70
  built: any[];
70
71
  instructions: any;
72
+ compute: boolean;
71
73
  signers: any[];
72
74
  alone: boolean;
73
75
  }[];