@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.
- package/README.md +8 -8
- package/js/chain/metadata.js +76 -0
- package/js/client/idl/loot.js +1 -1
- package/js/client/idl/loot.json +4 -3
- package/js/client/sizes.js +180 -66
- package/js/economy/check.mjs +64 -19
- package/js/economy/cost.mjs +17 -3
- package/js/economy/explain.mjs +14 -0
- package/js/economy/guide.mjs +2 -2
- package/js/economy/plan.mjs +62 -12
- package/js/economy/schema.json +4 -3
- package/js/play/index.js +15 -7
- package/package.json +1 -1
- package/release.json +5 -5
- package/skills/xsolana-economy/SKILL.md +3 -3
- package/skills/xsolana-economy/references/telling-the-person.md +9 -1
- package/types/chain/metadata.d.ts +40 -0
- package/types/client/sizes.d.ts +42 -8
- package/types/economy/check.d.mts +6 -2
- package/types/economy/cost.d.mts +3 -0
- package/types/economy/live.d.mts +2 -0
- package/types/economy/plan.d.mts +23 -15
package/README.md
CHANGED
|
@@ -64,7 +64,7 @@ codex plugin add xsolana@xgamesfun
|
|
|
64
64
|
|
|
65
65
|
**claude.ai, ChatGPT or Claude Desktop:** add `https://xgames.fun/mcp` as a custom connector. Nothing to install.
|
|
66
66
|
|
|
67
|
-
**Cursor, Cline, opencode or any MCP client:** run `npx -y --package=@xgamesfun/solana@0.26.
|
|
67
|
+
**Cursor, Cline, opencode or any MCP client:** run `npx -y --package=@xgamesfun/solana@0.26.2 xsolana mcp`.
|
|
68
68
|
|
|
69
69
|
**Any agent that reads skills** (Copilot, Gemini CLI, Windsurf…): `npx skills add XGamesFun/solana-kit`.
|
|
70
70
|
|
|
@@ -75,19 +75,19 @@ are in [docs/harnesses.md](docs/harnesses.md).
|
|
|
75
75
|
|
|
76
76
|
```bash
|
|
77
77
|
# find a worked example close to your idea
|
|
78
|
-
npx -y @xgamesfun/solana@0.26.
|
|
78
|
+
npx -y @xgamesfun/solana@0.26.2 examples shop with loot boxes
|
|
79
79
|
|
|
80
80
|
# does it work? where does the money go? what does it cost?
|
|
81
|
-
npx -y @xgamesfun/solana@0.26.
|
|
82
|
-
npx -y @xgamesfun/solana@0.26.
|
|
83
|
-
npx -y @xgamesfun/solana@0.26.
|
|
81
|
+
npx -y @xgamesfun/solana@0.26.2 check xsolana.json
|
|
82
|
+
npx -y @xgamesfun/solana@0.26.2 simulate xsolana.json
|
|
83
|
+
npx -y @xgamesfun/solana@0.26.2 cost xsolana.json
|
|
84
84
|
|
|
85
85
|
# the whole economy in plain words, and what a cheater could get
|
|
86
|
-
npx -y @xgamesfun/solana@0.26.
|
|
87
|
-
npx -y @xgamesfun/solana@0.26.
|
|
86
|
+
npx -y @xgamesfun/solana@0.26.2 explain xsolana.json
|
|
87
|
+
npx -y @xgamesfun/solana@0.26.2 review xsolana.json
|
|
88
88
|
|
|
89
89
|
# go live, approved in your own wallet
|
|
90
|
-
npx -y @xgamesfun/solana@0.26.
|
|
90
|
+
npx -y @xgamesfun/solana@0.26.2 approve xsolana.json
|
|
91
91
|
```
|
|
92
92
|
|
|
93
93
|
Each command names an exact version, so you always run the release you meant to. `xsolana help` lists them all.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// A token's name on chain: its Token Metadata record (Metaplex), where wallets and explorers read a classic SPL
|
|
2
|
+
// token's name, ticker and picture link. Only what a setup needs: the record of a fungible token whose mint is made
|
|
3
|
+
// already. Token Metadata takes it only from the mint's authority, so it is made while that authority can still sign:
|
|
4
|
+
// once minting is handed on or turned off, no record can ever be made for the mint.
|
|
5
|
+
import { addressBytes, encodeBase58 } from './base58.js';
|
|
6
|
+
import { concat, uintLE, utf8 } from './bytes.js';
|
|
7
|
+
import { METAPLEX_METADATA_PROGRAM, pdaOf, SYSTEM_PROGRAM, SYSVAR_INSTRUCTIONS, TOKEN_PROGRAM } from './pda.js';
|
|
8
|
+
import { meta } from './programs.js';
|
|
9
|
+
|
|
10
|
+
/** A record's size: Token Metadata pads every one to it, whatever its name, ticker and link. */
|
|
11
|
+
export const METADATA_BYTES = 607;
|
|
12
|
+
/** What Token Metadata keeps in each record it makes, on top of the record's rent: its own fee. */
|
|
13
|
+
export const METADATA_FEE = 10_000_000n;
|
|
14
|
+
/** The longest name, ticker and link a record takes, in UTF-8 bytes. */
|
|
15
|
+
export const METADATA_LIMITS = Object.freeze({ name: 32, symbol: 10, uri: 200 });
|
|
16
|
+
|
|
17
|
+
const CREATE = 42;
|
|
18
|
+
const CREATE_V1 = 0;
|
|
19
|
+
const FUNGIBLE = 2;
|
|
20
|
+
const NONE = Uint8Array.of(0);
|
|
21
|
+
const text = s => concat(uintLE(utf8(s).length, 4), utf8(s));
|
|
22
|
+
|
|
23
|
+
/** The address of a mint's Token Metadata record. */
|
|
24
|
+
export const metadataAddress = mint =>
|
|
25
|
+
pdaOf([utf8('metadata'), addressBytes(METAPLEX_METADATA_PROGRAM), addressBytes(mint)], METAPLEX_METADATA_PROGRAM);
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Token Metadata's CreateV1 for a fungible token whose mint exists: its name, its ticker and a link to a JSON file with
|
|
29
|
+
* its picture ('' for none). `authority` is the mint's authority and signs; it becomes the record's update authority,
|
|
30
|
+
* the only one who can change the record later. `payer` pays its rent and Token Metadata's fee (`METADATA_FEE`).
|
|
31
|
+
* The mint is listed read-only: this path of Token Metadata writes nothing to a mint that exists. That is the
|
|
32
|
+
* program's behaviour, not a lock: in a setup's own transaction the mint is writable all the same (the same
|
|
33
|
+
* transaction makes it), so the tests read its supply and authorities back after the record is made. The record says
|
|
34
|
+
* a fungible token whatever the decimals (CreateMetadataAccountV3 would call one of 0 decimals an asset, which
|
|
35
|
+
* wallets list with collectibles).
|
|
36
|
+
*/
|
|
37
|
+
export function createFungibleMetadataIx({ mint, authority, payer = authority, name, symbol, uri = '' }) {
|
|
38
|
+
for (const [field, value] of Object.entries({ name, symbol, uri })) {
|
|
39
|
+
if (typeof value !== 'string') throw new TypeError(`A token's ${field} is text`);
|
|
40
|
+
if (utf8(value).length > METADATA_LIMITS[field])
|
|
41
|
+
throw new RangeError(`A token's ${field} is at most ${METADATA_LIMITS[field]} bytes`);
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
programId: METAPLEX_METADATA_PROGRAM,
|
|
45
|
+
keys: [
|
|
46
|
+
meta(metadataAddress(mint), false, true),
|
|
47
|
+
meta(METAPLEX_METADATA_PROGRAM, false, false), // no edition: a fungible token has none
|
|
48
|
+
meta(mint, false, false),
|
|
49
|
+
meta(authority, true, false),
|
|
50
|
+
meta(payer, true, true),
|
|
51
|
+
meta(authority, true, false), // the update authority
|
|
52
|
+
meta(SYSTEM_PROGRAM, false, false),
|
|
53
|
+
meta(SYSVAR_INSTRUCTIONS, false, false),
|
|
54
|
+
meta(TOKEN_PROGRAM, false, false),
|
|
55
|
+
],
|
|
56
|
+
data: concat(
|
|
57
|
+
Uint8Array.of(CREATE, CREATE_V1),
|
|
58
|
+
text(name),
|
|
59
|
+
text(symbol),
|
|
60
|
+
text(uri),
|
|
61
|
+
uintLE(0, 2), // no resale royalty
|
|
62
|
+
NONE, // no creators
|
|
63
|
+
Uint8Array.of(0, 1), // no primary sale yet; the record can be changed
|
|
64
|
+
Uint8Array.of(FUNGIBLE),
|
|
65
|
+
NONE, // no collection
|
|
66
|
+
NONE, // no uses
|
|
67
|
+
NONE, // no collection details
|
|
68
|
+
NONE, // no rule set
|
|
69
|
+
NONE, // decimals: the mint's own
|
|
70
|
+
NONE, // no print supply
|
|
71
|
+
),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** The update authority a Token Metadata record names (who can change its name, ticker and link). */
|
|
76
|
+
export const metadataUpdateAuthority = data => (data?.length >= 33 ? encodeBase58(data.subarray(1, 33)) : null);
|