solforge 0.2.12 → 0.2.14

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 (175) hide show
  1. package/package.json +1 -5
  2. package/start.cjs +19 -23
  3. package/docs/API.md +0 -379
  4. package/docs/CONFIGURATION.md +0 -407
  5. package/docs/bun-single-file-executable.md +0 -585
  6. package/docs/cli-plan.md +0 -154
  7. package/docs/data-indexing-plan.md +0 -214
  8. package/docs/gui-roadmap.md +0 -202
  9. package/scripts/decode-b58.ts +0 -10
  10. package/scripts/install.sh +0 -112
  11. package/server/index.ts +0 -5
  12. package/server/lib/base58.ts +0 -33
  13. package/server/lib/faucet.ts +0 -110
  14. package/server/lib/instruction-parser.ts +0 -328
  15. package/server/lib/parsers/spl-associated-token-account.ts +0 -50
  16. package/server/lib/parsers/spl-token.ts +0 -340
  17. package/server/lib/spl-token.ts +0 -57
  18. package/server/methods/TEMPLATE.md +0 -117
  19. package/server/methods/account/get-account-info.ts +0 -86
  20. package/server/methods/account/get-balance.ts +0 -23
  21. package/server/methods/account/get-multiple-accounts.ts +0 -84
  22. package/server/methods/account/get-parsed-account-info.ts +0 -17
  23. package/server/methods/account/index.ts +0 -12
  24. package/server/methods/account/parsers/index.ts +0 -52
  25. package/server/methods/account/parsers/loader-upgradeable.ts +0 -79
  26. package/server/methods/account/parsers/spl-token.ts +0 -256
  27. package/server/methods/account/parsers/system.ts +0 -4
  28. package/server/methods/account/request-airdrop.ts +0 -271
  29. package/server/methods/admin/adopt-mint-authority.ts +0 -94
  30. package/server/methods/admin/clone-program-accounts.ts +0 -55
  31. package/server/methods/admin/clone-program.ts +0 -152
  32. package/server/methods/admin/clone-token-accounts.ts +0 -117
  33. package/server/methods/admin/clone-token-mint.ts +0 -82
  34. package/server/methods/admin/create-mint.ts +0 -114
  35. package/server/methods/admin/create-token-account.ts +0 -137
  36. package/server/methods/admin/helpers.ts +0 -70
  37. package/server/methods/admin/index.ts +0 -10
  38. package/server/methods/admin/list-mints.ts +0 -21
  39. package/server/methods/admin/load-program.ts +0 -52
  40. package/server/methods/admin/mint-to.ts +0 -266
  41. package/server/methods/block/get-block-height.ts +0 -5
  42. package/server/methods/block/get-block.ts +0 -31
  43. package/server/methods/block/get-blocks-with-limit.ts +0 -19
  44. package/server/methods/block/get-latest-blockhash.ts +0 -12
  45. package/server/methods/block/get-slot.ts +0 -5
  46. package/server/methods/block/index.ts +0 -6
  47. package/server/methods/block/is-blockhash-valid.ts +0 -19
  48. package/server/methods/epoch/get-cluster-nodes.ts +0 -17
  49. package/server/methods/epoch/get-epoch-info.ts +0 -16
  50. package/server/methods/epoch/get-epoch-schedule.ts +0 -15
  51. package/server/methods/epoch/get-highest-snapshot-slot.ts +0 -9
  52. package/server/methods/epoch/get-leader-schedule.ts +0 -8
  53. package/server/methods/epoch/get-max-retransmit-slot.ts +0 -9
  54. package/server/methods/epoch/get-max-shred-insert-slot.ts +0 -9
  55. package/server/methods/epoch/get-slot-leader.ts +0 -6
  56. package/server/methods/epoch/get-slot-leaders.ts +0 -9
  57. package/server/methods/epoch/get-stake-activation.ts +0 -9
  58. package/server/methods/epoch/get-stake-minimum-delegation.ts +0 -9
  59. package/server/methods/epoch/get-vote-accounts.ts +0 -19
  60. package/server/methods/epoch/index.ts +0 -13
  61. package/server/methods/epoch/minimum-ledger-slot.ts +0 -5
  62. package/server/methods/fee/get-fee-calculator-for-blockhash.ts +0 -12
  63. package/server/methods/fee/get-fee-for-message.ts +0 -8
  64. package/server/methods/fee/get-fee-rate-governor.ts +0 -16
  65. package/server/methods/fee/get-fees.ts +0 -14
  66. package/server/methods/fee/get-recent-prioritization-fees.ts +0 -22
  67. package/server/methods/fee/index.ts +0 -5
  68. package/server/methods/get-address-lookup-table.ts +0 -27
  69. package/server/methods/index.ts +0 -265
  70. package/server/methods/performance/get-recent-performance-samples.ts +0 -25
  71. package/server/methods/performance/get-transaction-count.ts +0 -5
  72. package/server/methods/performance/index.ts +0 -2
  73. package/server/methods/program/get-block-commitment.ts +0 -9
  74. package/server/methods/program/get-block-production.ts +0 -14
  75. package/server/methods/program/get-block-time.ts +0 -21
  76. package/server/methods/program/get-blocks.ts +0 -11
  77. package/server/methods/program/get-first-available-block.ts +0 -9
  78. package/server/methods/program/get-genesis-hash.ts +0 -6
  79. package/server/methods/program/get-identity.ts +0 -6
  80. package/server/methods/program/get-inflation-governor.ts +0 -15
  81. package/server/methods/program/get-inflation-rate.ts +0 -10
  82. package/server/methods/program/get-inflation-reward.ts +0 -12
  83. package/server/methods/program/get-largest-accounts.ts +0 -8
  84. package/server/methods/program/get-parsed-program-accounts.ts +0 -12
  85. package/server/methods/program/get-parsed-token-accounts-by-delegate.ts +0 -12
  86. package/server/methods/program/get-parsed-token-accounts-by-owner.ts +0 -12
  87. package/server/methods/program/get-program-accounts.ts +0 -221
  88. package/server/methods/program/get-supply.ts +0 -13
  89. package/server/methods/program/get-token-account-balance.ts +0 -60
  90. package/server/methods/program/get-token-accounts-by-delegate.ts +0 -82
  91. package/server/methods/program/get-token-accounts-by-owner.ts +0 -416
  92. package/server/methods/program/get-token-largest-accounts.ts +0 -81
  93. package/server/methods/program/get-token-supply.ts +0 -39
  94. package/server/methods/program/index.ts +0 -21
  95. package/server/methods/solforge/index.ts +0 -158
  96. package/server/methods/system/get-health.ts +0 -5
  97. package/server/methods/system/get-minimum-balance-for-rent-exemption.ts +0 -13
  98. package/server/methods/system/get-version.ts +0 -9
  99. package/server/methods/system/index.ts +0 -3
  100. package/server/methods/transaction/get-confirmed-transaction.ts +0 -11
  101. package/server/methods/transaction/get-parsed-transaction.ts +0 -17
  102. package/server/methods/transaction/get-signature-statuses.ts +0 -79
  103. package/server/methods/transaction/get-signatures-for-address.ts +0 -41
  104. package/server/methods/transaction/get-transaction.ts +0 -639
  105. package/server/methods/transaction/index.ts +0 -7
  106. package/server/methods/transaction/inner-instructions.test.ts +0 -104
  107. package/server/methods/transaction/send-transaction.ts +0 -469
  108. package/server/methods/transaction/simulate-transaction.ts +0 -57
  109. package/server/rpc-server.ts +0 -521
  110. package/server/types.ts +0 -109
  111. package/server/ws-server.ts +0 -178
  112. package/src/api-server-entry.ts +0 -109
  113. package/src/cli/bootstrap.ts +0 -67
  114. package/src/cli/commands/airdrop.ts +0 -37
  115. package/src/cli/commands/config.ts +0 -39
  116. package/src/cli/commands/mint.ts +0 -187
  117. package/src/cli/commands/program-clone.ts +0 -122
  118. package/src/cli/commands/program-load.ts +0 -64
  119. package/src/cli/commands/rpc-start.ts +0 -49
  120. package/src/cli/commands/token-adopt-authority.ts +0 -37
  121. package/src/cli/commands/token-clone.ts +0 -112
  122. package/src/cli/commands/token-create.ts +0 -81
  123. package/src/cli/main.ts +0 -158
  124. package/src/cli/run-solforge.ts +0 -112
  125. package/src/cli/setup-utils.ts +0 -54
  126. package/src/cli/setup-wizard.ts +0 -258
  127. package/src/cli/utils/args.ts +0 -15
  128. package/src/commands/add-program.ts +0 -333
  129. package/src/commands/init.ts +0 -122
  130. package/src/commands/list.ts +0 -136
  131. package/src/commands/mint.ts +0 -287
  132. package/src/commands/start.ts +0 -881
  133. package/src/commands/status.ts +0 -99
  134. package/src/commands/stop.ts +0 -405
  135. package/src/config/index.ts +0 -146
  136. package/src/config/manager.ts +0 -157
  137. package/src/db/index.ts +0 -83
  138. package/src/db/schema/accounts.ts +0 -23
  139. package/src/db/schema/address-signatures.ts +0 -31
  140. package/src/db/schema/index.ts +0 -6
  141. package/src/db/schema/meta-kv.ts +0 -9
  142. package/src/db/schema/transactions.ts +0 -36
  143. package/src/db/schema/tx-account-states.ts +0 -23
  144. package/src/db/schema/tx-accounts.ts +0 -33
  145. package/src/db/tx-store.ts +0 -264
  146. package/src/gui/public/app.css +0 -1556
  147. package/src/gui/public/build/main.css +0 -1569
  148. package/src/gui/public/build/main.js +0 -303
  149. package/src/gui/public/build/main.js.txt +0 -231
  150. package/src/gui/public/index.html +0 -19
  151. package/src/gui/server.ts +0 -296
  152. package/src/gui/src/api.ts +0 -127
  153. package/src/gui/src/app.tsx +0 -441
  154. package/src/gui/src/components/airdrop-mint-form.tsx +0 -246
  155. package/src/gui/src/components/clone-program-modal.tsx +0 -202
  156. package/src/gui/src/components/clone-token-modal.tsx +0 -230
  157. package/src/gui/src/components/modal.tsx +0 -134
  158. package/src/gui/src/components/programs-panel.tsx +0 -124
  159. package/src/gui/src/components/status-panel.tsx +0 -136
  160. package/src/gui/src/components/tokens-panel.tsx +0 -122
  161. package/src/gui/src/hooks/use-interval.ts +0 -17
  162. package/src/gui/src/index.css +0 -557
  163. package/src/gui/src/main.tsx +0 -17
  164. package/src/index.ts +0 -216
  165. package/src/migrations-bundled.ts +0 -23
  166. package/src/rpc/start.ts +0 -44
  167. package/src/services/api-server.ts +0 -504
  168. package/src/services/port-manager.ts +0 -174
  169. package/src/services/process-registry.ts +0 -153
  170. package/src/services/program-cloner.ts +0 -317
  171. package/src/services/token-cloner.ts +0 -811
  172. package/src/services/validator.ts +0 -293
  173. package/src/types/config.ts +0 -110
  174. package/src/utils/shell.ts +0 -110
  175. package/src/utils/token-loader.ts +0 -115
@@ -1,137 +0,0 @@
1
- import {
2
- ACCOUNT_SIZE,
3
- AccountLayout,
4
- getAssociatedTokenAddressSync,
5
- TOKEN_PROGRAM_ID,
6
- } from "@solana/spl-token";
7
- import { PublicKey } from "@solana/web3.js";
8
- import type { RpcMethodHandler } from "../../types";
9
-
10
- // Create or overwrite a token account (ATA) with a specified amount
11
- export const solforgeCreateTokenAccount: RpcMethodHandler = async (
12
- id,
13
- params,
14
- context,
15
- ) => {
16
- try {
17
- const [mintStr, ownerStr, rawAmount, decimals] = params as [
18
- string,
19
- string | null | undefined,
20
- number | string | bigint,
21
- number?,
22
- ];
23
- if (!mintStr || rawAmount == null)
24
- return context.createErrorResponse(
25
- id,
26
- -32602,
27
- "Invalid params: mint and amount required",
28
- );
29
- const mint = new PublicKey(mintStr);
30
- const owner = ownerStr
31
- ? new PublicKey(ownerStr)
32
- : context.getFaucet().publicKey;
33
- // Amount is in base units (not UI). The layout stores a u64 bigint
34
- const amount =
35
- typeof rawAmount === "bigint" ? rawAmount : BigInt(rawAmount);
36
-
37
- const buf = Buffer.alloc(ACCOUNT_SIZE);
38
- type TokenAccountStruct = Parameters<typeof AccountLayout.encode>[0];
39
- const tokenAccount = {
40
- mint,
41
- owner,
42
- amount,
43
- delegateOption: 0,
44
- delegate: PublicKey.default,
45
- delegatedAmount: 0n,
46
- state: 1,
47
- isNativeOption: 0,
48
- isNative: 0n,
49
- closeAuthorityOption: 0,
50
- closeAuthority: PublicKey.default,
51
- } satisfies Partial<TokenAccountStruct> as TokenAccountStruct;
52
- AccountLayout.encode(tokenAccount, buf);
53
-
54
- const rentLamports = Number(
55
- context.svm.minimumBalanceForRentExemption(BigInt(ACCOUNT_SIZE)),
56
- );
57
-
58
- // Compute the canonical associated token account address for mint+owner
59
- const address = getAssociatedTokenAddressSync(mint, owner, true);
60
-
61
- context.svm.setAccount(address, {
62
- lamports: rentLamports,
63
- data: new Uint8Array(buf),
64
- owner: TOKEN_PROGRAM_ID,
65
- executable: false,
66
- rentEpoch: 0,
67
- });
68
- try {
69
- await context.store?.upsertAccounts([
70
- {
71
- address: address.toBase58(),
72
- lamports: rentLamports,
73
- ownerProgram: TOKEN_PROGRAM_ID.toBase58(),
74
- executable: false,
75
- rentEpoch: 0,
76
- dataLen: ACCOUNT_SIZE,
77
- dataBase64: undefined,
78
- lastSlot: Number(context.slot),
79
- },
80
- ]);
81
- } catch {}
82
- // Record a synthetic transaction so explorers can show activity
83
- try {
84
- const sig = `admin:mint:${address.toBase58()}:${Date.now()}`;
85
- await context.store?.insertTransactionBundle({
86
- signature: sig,
87
- slot: Number(context.slot),
88
- blockTime: Math.floor(Date.now() / 1000),
89
- version: "legacy",
90
- fee: 0,
91
- err: null,
92
- rawBase64: "",
93
- preBalances: [],
94
- postBalances: [],
95
- logs: ["admin mint"],
96
- accounts: [
97
- {
98
- address: address.toBase58(),
99
- index: 0,
100
- signer: false,
101
- writable: true,
102
- },
103
- {
104
- address: mint.toBase58(),
105
- index: 1,
106
- signer: false,
107
- writable: false,
108
- },
109
- {
110
- address: owner.toBase58(),
111
- index: 2,
112
- signer: false,
113
- writable: false,
114
- },
115
- ],
116
- });
117
- } catch {}
118
-
119
- return context.createSuccessResponse(id, {
120
- ok: true,
121
- address: address.toBase58(),
122
- mint: mintStr,
123
- owner: owner.toBase58(),
124
- amount: amount.toString(),
125
- decimals: decimals ?? null,
126
- });
127
- } catch (e) {
128
- return context.createErrorResponse(
129
- id,
130
- -32603,
131
- "Create token account failed",
132
- (e as Error)?.message || String(e),
133
- );
134
- }
135
- };
136
-
137
- export type { RpcMethodHandler } from "../../types";
@@ -1,70 +0,0 @@
1
- import {
2
- getMetadataPointerState,
3
- MINT_SIZE,
4
- TOKEN_2022_PROGRAM_ID,
5
- TOKEN_PROGRAM_ID,
6
- unpackMint,
7
- } from "@solana/spl-token";
8
- import type { AccountInfo, Connection, PublicKey } from "@solana/web3.js";
9
-
10
- import type { RpcMethodContext } from "../../types";
11
-
12
- export async function cloneMintExtensionAccounts(
13
- conn: Connection,
14
- context: RpcMethodContext,
15
- mint: PublicKey,
16
- info: AccountInfo<Buffer>,
17
- ): Promise<void> {
18
- if (!info.data || info.data.length <= MINT_SIZE) return;
19
- try {
20
- const programId = info.owner.equals(TOKEN_2022_PROGRAM_ID)
21
- ? TOKEN_2022_PROGRAM_ID
22
- : TOKEN_PROGRAM_ID;
23
- const mintState = unpackMint(mint, info, programId);
24
- if (!mintState.tlvData || mintState.tlvData.length === 0) return;
25
-
26
- const metadataPtr = getMetadataPointerState(mintState);
27
- if (metadataPtr?.metadataAddress) {
28
- await cloneSingleAccount(
29
- conn,
30
- context,
31
- metadataPtr.metadataAddress,
32
- "metadata",
33
- );
34
- }
35
- } catch (error) {
36
- console.warn("[admin] mint extension clone skipped", {
37
- mint: mint.toBase58(),
38
- error: String(error),
39
- });
40
- }
41
- }
42
-
43
- export async function cloneSingleAccount(
44
- conn: Connection,
45
- context: RpcMethodContext,
46
- address: PublicKey,
47
- label: string,
48
- ): Promise<void> {
49
- try {
50
- const info = await conn.getAccountInfo(address, "confirmed");
51
- if (!info) {
52
- console.warn(`[admin] ${label} account not found on endpoint`, {
53
- address: address.toBase58(),
54
- });
55
- return;
56
- }
57
- context.svm.setAccount(address, {
58
- data: new Uint8Array(info.data as Buffer),
59
- executable: info.executable,
60
- lamports: Number(info.lamports),
61
- owner: info.owner,
62
- rentEpoch: 0,
63
- });
64
- } catch (error) {
65
- console.warn(`[admin] clone ${label} account failed`, {
66
- address: address.toBase58(),
67
- error: String(error),
68
- });
69
- }
70
- }
@@ -1,10 +0,0 @@
1
- export { solforgeAdoptMintAuthority } from "./adopt-mint-authority";
2
- export { solforgeAdminCloneProgram } from "./clone-program";
3
- export { solforgeAdminCloneProgramAccounts } from "./clone-program-accounts";
4
- export { solforgeAdminCloneTokenAccounts } from "./clone-token-accounts";
5
- export { solforgeAdminCloneTokenMint } from "./clone-token-mint";
6
- export { solforgeCreateMint } from "./create-mint";
7
- export { solforgeCreateTokenAccount } from "./create-token-account";
8
- export { solforgeListMints } from "./list-mints";
9
- export { solforgeLoadProgram } from "./load-program";
10
- export { solforgeMintTo } from "./mint-to";
@@ -1,21 +0,0 @@
1
- import type { RpcMethodHandler } from "../../types";
2
-
3
- export const solforgeListMints: RpcMethodHandler = async (
4
- id,
5
- _params,
6
- context,
7
- ) => {
8
- try {
9
- const list = context.listMints ? context.listMints() : [];
10
- return context.createSuccessResponse(id, list);
11
- } catch (e) {
12
- return context.createErrorResponse(
13
- id,
14
- -32603,
15
- "List mints failed",
16
- (e as Error)?.message || String(e),
17
- );
18
- }
19
- };
20
-
21
- export type { RpcMethodHandler } from "../../types";
@@ -1,52 +0,0 @@
1
- import { PublicKey } from "@solana/web3.js";
2
- import type { RpcMethodHandler } from "../../types";
3
-
4
- // Load a program ELF into LiteSVM for a given programId
5
- export const solforgeLoadProgram: RpcMethodHandler = async (
6
- id,
7
- params,
8
- context,
9
- ) => {
10
- try {
11
- const [programIdStr, elfBase64] = params as [string, string];
12
- if (!programIdStr || !elfBase64)
13
- return context.createErrorResponse(
14
- id,
15
- -32602,
16
- "Invalid params: programId, base64 required",
17
- );
18
- const pid = new PublicKey(programIdStr);
19
- const bytes = Uint8Array.from(Buffer.from(elfBase64, "base64"));
20
- try {
21
- context.svm.addProgram(pid, bytes);
22
- } catch {}
23
- // Mirror program account metadata as executable; owner = upgradeable loader for realism
24
- const LOADER_UPGRADEABLE = new PublicKey(
25
- "BPFLoaderUpgradeab1e11111111111111111111111",
26
- );
27
- context.svm.setAccount(pid, {
28
- lamports: 1_000_000_000,
29
- data: new Uint8Array(bytes.length), // minimal stub data for the program account itself
30
- owner: LOADER_UPGRADEABLE,
31
- executable: true,
32
- rentEpoch: 0,
33
- });
34
- try {
35
- context.registerProgram?.(pid);
36
- } catch {}
37
- return context.createSuccessResponse(id, {
38
- ok: true,
39
- programId: programIdStr,
40
- size: bytes.length,
41
- });
42
- } catch (e) {
43
- return context.createErrorResponse(
44
- id,
45
- -32603,
46
- "Load program failed",
47
- (e as Error)?.message || String(e),
48
- );
49
- }
50
- };
51
-
52
- export type { RpcMethodHandler } from "../../types";
@@ -1,266 +0,0 @@
1
- import {
2
- ACCOUNT_SIZE,
3
- AccountLayout,
4
- createAssociatedTokenAccountInstruction,
5
- createMintToCheckedInstruction,
6
- getAssociatedTokenAddressSync,
7
- MINT_SIZE,
8
- MintLayout,
9
- TOKEN_2022_PROGRAM_ID,
10
- TOKEN_PROGRAM_ID,
11
- } from "@solana/spl-token";
12
- import type { TransactionInstruction } from "@solana/web3.js";
13
- import {
14
- PublicKey,
15
- TransactionMessage,
16
- VersionedTransaction,
17
- } from "@solana/web3.js";
18
- import type { RpcMethodHandler } from "../../types";
19
- import { sendTransaction as sendTxRpc } from "../transaction/send-transaction";
20
-
21
- // Mint via a real SPL Token transaction signed by faucet (must be mint authority)
22
- export const solforgeMintTo: RpcMethodHandler = async (id, params, context) => {
23
- try {
24
- const [mintStr, ownerStr, rawAmount] = params as [
25
- string,
26
- string,
27
- number | string | bigint,
28
- ];
29
- if (!mintStr || !ownerStr || rawAmount == null)
30
- return context.createErrorResponse(
31
- id,
32
- -32602,
33
- "Invalid params: mint, owner, amount required",
34
- );
35
- const mint = new PublicKey(mintStr);
36
- const owner = new PublicKey(ownerStr);
37
- const faucet = context.getFaucet();
38
-
39
- // Read mint to get decimals and authority
40
- const mintAcc = context.svm.getAccount(mint);
41
- if (!mintAcc)
42
- return context.createErrorResponse(
43
- id,
44
- -32004,
45
- "Mint not found in LiteSVM",
46
- );
47
- const mintInfo = MintLayout.decode(
48
- Buffer.from(mintAcc.data).slice(0, MINT_SIZE),
49
- );
50
- const decimals = mintInfo.decimals;
51
- const hasAuth = mintInfo.mintAuthorityOption === 1;
52
- const authPk = hasAuth ? new PublicKey(mintInfo.mintAuthority) : null;
53
- if (!hasAuth || !authPk || !authPk.equals(faucet.publicKey)) {
54
- return context.createErrorResponse(
55
- id,
56
- -32000,
57
- "Mint has no faucet authority; cannot mint real tokens",
58
- );
59
- }
60
-
61
- const ixs: TransactionInstruction[] = [];
62
- // Detect which token program the mint belongs to (SPL v1 vs Token-2022)
63
- const mintOwnerStr = (() => {
64
- try {
65
- return (mintAcc.owner as PublicKey).toBase58();
66
- } catch {
67
- return String(mintAcc.owner);
68
- }
69
- })();
70
- const tokenProgramId =
71
- mintOwnerStr === TOKEN_2022_PROGRAM_ID.toBase58()
72
- ? TOKEN_2022_PROGRAM_ID
73
- : TOKEN_PROGRAM_ID;
74
-
75
- // Derive ATA using the correct token program
76
- const ata = getAssociatedTokenAddressSync(
77
- mint,
78
- owner,
79
- true,
80
- tokenProgramId,
81
- );
82
- const ataAcc = context.svm.getAccount(ata);
83
-
84
- // Ensure ATA exists under the correct token program
85
- if (!ataAcc || (ataAcc.data?.length ?? 0) < ACCOUNT_SIZE) {
86
- ixs.push(
87
- createAssociatedTokenAccountInstruction(
88
- faucet.publicKey,
89
- ata,
90
- owner,
91
- mint,
92
- tokenProgramId,
93
- ),
94
- );
95
- }
96
-
97
- const amount =
98
- typeof rawAmount === "bigint" ? rawAmount : BigInt(rawAmount);
99
- ixs.push(
100
- createMintToCheckedInstruction(
101
- mint,
102
- ata,
103
- faucet.publicKey,
104
- amount,
105
- decimals,
106
- [],
107
- tokenProgramId,
108
- ),
109
- );
110
-
111
- // Build a VersionedTransaction (legacy message) to ensure consistent encoding/decoding downstream
112
- let rb = context.svm.latestBlockhash();
113
- if (!rb || rb.length === 0) {
114
- const bh = new Uint8Array(32);
115
- crypto.getRandomValues(bh);
116
- rb = context.encodeBase58(bh);
117
- }
118
- const msg = new TransactionMessage({
119
- payerKey: faucet.publicKey,
120
- recentBlockhash: rb,
121
- instructions: ixs,
122
- });
123
- const legacy = msg.compileToLegacyMessage();
124
- const vtx = new VersionedTransaction(legacy);
125
- vtx.sign([faucet]);
126
-
127
- // Capture preBalances for primary accounts referenced and token pre amount
128
- const trackedKeys = [faucet.publicKey, ata, mint, owner];
129
- const _preBalances = trackedKeys.map((pk) => {
130
- try {
131
- return Number(context.svm.getBalance(pk) || 0n);
132
- } catch {
133
- return 0;
134
- }
135
- });
136
- // Token mint decimals and pre amount
137
- let decsForMint = 0;
138
- let preTokenAmt: bigint = 0n;
139
- try {
140
- const mintAcc0 = context.svm.getAccount(mint);
141
- const mintInfo0 = mintAcc0
142
- ? MintLayout.decode(Buffer.from(mintAcc0.data).slice(0, MINT_SIZE))
143
- : undefined;
144
- decsForMint = Number(mintInfo0?.decimals ?? decimals ?? 0);
145
- const ataAcc0 = context.svm.getAccount(ata);
146
- if (ataAcc0 && (ataAcc0.data?.length ?? 0) >= ACCOUNT_SIZE) {
147
- const dec0 = AccountLayout.decode(Buffer.from(ataAcc0.data));
148
- preTokenAmt = BigInt(dec0.amount.toString());
149
- }
150
- } catch {}
151
-
152
- // Send via the standard RPC sendTransaction path to unify capture/parsing
153
- const rawBase64ForRpc = Buffer.from(vtx.serialize()).toString("base64");
154
- const rpcResp = await (sendTxRpc as RpcMethodHandler)(
155
- id,
156
- [rawBase64ForRpc],
157
- context,
158
- );
159
- if (
160
- rpcResp &&
161
- typeof rpcResp === "object" &&
162
- "error" in (rpcResp as Record<string, unknown>) &&
163
- (rpcResp as Record<string, unknown>).error != null
164
- ) {
165
- return rpcResp;
166
- }
167
- const signatureStr = (() => {
168
- try {
169
- const r = rpcResp as Record<string, unknown>;
170
- const v = r?.result;
171
- return v == null ? "" : String(v);
172
- } catch {
173
- return "";
174
- }
175
- })();
176
-
177
- // Token balance deltas (pre/post) for ATA
178
- type UiTokenAmount = {
179
- amount: string;
180
- decimals: number;
181
- uiAmount: number;
182
- uiAmountString: string;
183
- };
184
- type TokenBalance = {
185
- accountIndex: number;
186
- mint: string;
187
- owner: string;
188
- uiTokenAmount: UiTokenAmount;
189
- };
190
- const _preTokenBalances: TokenBalance[] = [];
191
- let _postTokenBalances: TokenBalance[] = [];
192
- try {
193
- const decs = decsForMint;
194
- const ui = (n: bigint) => ({
195
- amount: n.toString(),
196
- decimals: decs,
197
- uiAmount: Number(n) / 10 ** decs,
198
- uiAmountString: (Number(n) / 10 ** decs).toString(),
199
- });
200
- const preAmt = preTokenAmt;
201
- const ataPostAcc = context.svm.getAccount(ata); // after send
202
- const postAmt =
203
- ataPostAcc && (ataPostAcc.data?.length ?? 0) >= ACCOUNT_SIZE
204
- ? BigInt(
205
- AccountLayout.decode(
206
- Buffer.from(ataPostAcc.data),
207
- ).amount.toString(),
208
- )
209
- : preAmt;
210
- const msgAny = vtx.message as unknown as {
211
- staticAccountKeys?: Array<string | PublicKey>;
212
- accountKeys?: Array<string | PublicKey>;
213
- };
214
- const rawKeys: Array<string | PublicKey> = Array.isArray(
215
- msgAny.staticAccountKeys,
216
- )
217
- ? msgAny.staticAccountKeys
218
- : Array.isArray(msgAny.accountKeys)
219
- ? msgAny.accountKeys
220
- : [];
221
- const keys = rawKeys.map((k: string | PublicKey) => {
222
- try {
223
- return typeof k === "string" ? k : new PublicKey(k).toBase58();
224
- } catch {
225
- return String(k);
226
- }
227
- });
228
- const ataIndex = keys.indexOf(ata.toBase58());
229
- preTokenBalances = [
230
- {
231
- accountIndex: ataIndex >= 0 ? ataIndex : 0,
232
- mint: mint.toBase58(),
233
- owner: owner.toBase58(),
234
- uiTokenAmount: ui(preAmt),
235
- },
236
- ];
237
- _postTokenBalances = [
238
- {
239
- accountIndex: ataIndex >= 0 ? ataIndex : 0,
240
- mint: mint.toBase58(),
241
- owner: owner.toBase58(),
242
- uiTokenAmount: ui(postAmt),
243
- },
244
- ];
245
- } catch {}
246
-
247
- // send-transaction already records/announces signature and persists to DB
248
-
249
- return context.createSuccessResponse(id, {
250
- ok: true,
251
- signature: signatureStr,
252
- mint: mintStr,
253
- owner: ownerStr,
254
- amount: amount.toString(),
255
- });
256
- } catch (e) {
257
- return context.createErrorResponse(
258
- id,
259
- -32603,
260
- "MintTo failed",
261
- (e as Error)?.message || String(e),
262
- );
263
- }
264
- };
265
-
266
- export type { RpcMethodHandler } from "../../types";
@@ -1,5 +0,0 @@
1
- import type { RpcMethodHandler } from "../../types";
2
-
3
- export const getBlockHeight: RpcMethodHandler = (id, _params, context) => {
4
- return context.createSuccessResponse(id, Number(context.blockHeight));
5
- };
@@ -1,31 +0,0 @@
1
- import type { RpcMethodHandler } from "../../types";
2
-
3
- export const getBlock: RpcMethodHandler = (id, params, context) => {
4
- try {
5
- const [slotRaw] = params || [];
6
- const slot = Number(slotRaw);
7
- if (!Number.isFinite(slot) || slot < 0) throw new Error("Invalid slot");
8
- const parentSlot = Math.max(0, slot - 1);
9
- const blockhash = context.svm.latestBlockhash();
10
- const previousBlockhash = context.svm.latestBlockhash();
11
- const SLOT_TIME_MS = 400;
12
- const currentTime = Math.floor(Date.now() / 1000);
13
- const slotDiff = Number(context.slot) - slot;
14
- const blockTime =
15
- slot > Number(context.slot)
16
- ? null
17
- : currentTime -
18
- Math.floor((Math.max(0, slotDiff) * SLOT_TIME_MS) / 1000);
19
- return context.createSuccessResponse(id, {
20
- blockhash,
21
- previousBlockhash,
22
- parentSlot,
23
- transactions: [],
24
- rewards: [],
25
- blockTime,
26
- });
27
- } catch (error: unknown) {
28
- const message = error instanceof Error ? error.message : String(error);
29
- return context.createErrorResponse(id, -32602, "Invalid params", message);
30
- }
31
- };
@@ -1,19 +0,0 @@
1
- import type { RpcMethodHandler } from "../../types";
2
-
3
- export const getBlocksWithLimit: RpcMethodHandler = (id, params, context) => {
4
- try {
5
- const [startSlotRaw, limitRaw] = params || [];
6
- const start = Number(startSlotRaw);
7
- const limit = Number(limitRaw);
8
- if (!Number.isFinite(start) || start < 0)
9
- throw new Error("Invalid start slot");
10
- if (!Number.isFinite(limit) || limit <= 0) throw new Error("Invalid limit");
11
- const end = Math.min(Number(context.slot), start + limit - 1);
12
- const blocks: number[] = [];
13
- for (let s = start; s <= end; s++) blocks.push(s);
14
- return context.createSuccessResponse(id, blocks);
15
- } catch (error: unknown) {
16
- const message = error instanceof Error ? error.message : String(error);
17
- return context.createErrorResponse(id, -32602, "Invalid params", message);
18
- }
19
- };
@@ -1,12 +0,0 @@
1
- import type { RpcMethodHandler } from "../../types";
2
-
3
- export const getLatestBlockhash: RpcMethodHandler = (id, _params, context) => {
4
- const blockhash = context.svm.latestBlockhash();
5
- return context.createSuccessResponse(id, {
6
- context: { slot: Number(context.slot) },
7
- value: {
8
- blockhash,
9
- lastValidBlockHeight: Number(context.blockHeight + 150n),
10
- },
11
- });
12
- };
@@ -1,5 +0,0 @@
1
- import type { RpcMethodHandler } from "../../types";
2
-
3
- export const getSlot: RpcMethodHandler = (id, _params, context) => {
4
- return context.createSuccessResponse(id, Number(context.slot));
5
- };
@@ -1,6 +0,0 @@
1
- export { getBlock } from "./get-block";
2
- export { getBlockHeight } from "./get-block-height";
3
- export { getBlocksWithLimit } from "./get-blocks-with-limit";
4
- export { getLatestBlockhash } from "./get-latest-blockhash";
5
- export { getSlot } from "./get-slot";
6
- export { isBlockhashValid } from "./is-blockhash-valid";
@@ -1,19 +0,0 @@
1
- import type { RpcMethodHandler } from "../../types";
2
-
3
- export const isBlockhashValid: RpcMethodHandler = (id, params, context) => {
4
- try {
5
- const [blockhash] = params || [];
6
- const current = context.svm.latestBlockhash();
7
- const isValid =
8
- typeof blockhash === "string" &&
9
- blockhash.length > 0 &&
10
- blockhash === current;
11
- return context.createSuccessResponse(id, {
12
- context: { slot: Number(context.slot) },
13
- value: isValid,
14
- });
15
- } catch (error: unknown) {
16
- const message = error instanceof Error ? error.message : String(error);
17
- return context.createErrorResponse(id, -32602, "Invalid params", message);
18
- }
19
- };
@@ -1,17 +0,0 @@
1
- import type { RpcMethodHandler } from "../../types";
2
-
3
- export const getClusterNodes: RpcMethodHandler = (id, _params, _context) => {
4
- return {
5
- jsonrpc: "2.0",
6
- id,
7
- result: [
8
- {
9
- pubkey: "11111111111111111111111111111111",
10
- gossip: "127.0.0.1:8001",
11
- tpu: "127.0.0.1:8003",
12
- rpc: "127.0.0.1:8899",
13
- version: "1.17.0",
14
- },
15
- ],
16
- };
17
- };