solforge 0.2.12 → 0.2.13

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 (174) hide show
  1. package/package.json +1 -5
  2. package/docs/API.md +0 -379
  3. package/docs/CONFIGURATION.md +0 -407
  4. package/docs/bun-single-file-executable.md +0 -585
  5. package/docs/cli-plan.md +0 -154
  6. package/docs/data-indexing-plan.md +0 -214
  7. package/docs/gui-roadmap.md +0 -202
  8. package/scripts/decode-b58.ts +0 -10
  9. package/scripts/install.sh +0 -112
  10. package/server/index.ts +0 -5
  11. package/server/lib/base58.ts +0 -33
  12. package/server/lib/faucet.ts +0 -110
  13. package/server/lib/instruction-parser.ts +0 -328
  14. package/server/lib/parsers/spl-associated-token-account.ts +0 -50
  15. package/server/lib/parsers/spl-token.ts +0 -340
  16. package/server/lib/spl-token.ts +0 -57
  17. package/server/methods/TEMPLATE.md +0 -117
  18. package/server/methods/account/get-account-info.ts +0 -86
  19. package/server/methods/account/get-balance.ts +0 -23
  20. package/server/methods/account/get-multiple-accounts.ts +0 -84
  21. package/server/methods/account/get-parsed-account-info.ts +0 -17
  22. package/server/methods/account/index.ts +0 -12
  23. package/server/methods/account/parsers/index.ts +0 -52
  24. package/server/methods/account/parsers/loader-upgradeable.ts +0 -79
  25. package/server/methods/account/parsers/spl-token.ts +0 -256
  26. package/server/methods/account/parsers/system.ts +0 -4
  27. package/server/methods/account/request-airdrop.ts +0 -271
  28. package/server/methods/admin/adopt-mint-authority.ts +0 -94
  29. package/server/methods/admin/clone-program-accounts.ts +0 -55
  30. package/server/methods/admin/clone-program.ts +0 -152
  31. package/server/methods/admin/clone-token-accounts.ts +0 -117
  32. package/server/methods/admin/clone-token-mint.ts +0 -82
  33. package/server/methods/admin/create-mint.ts +0 -114
  34. package/server/methods/admin/create-token-account.ts +0 -137
  35. package/server/methods/admin/helpers.ts +0 -70
  36. package/server/methods/admin/index.ts +0 -10
  37. package/server/methods/admin/list-mints.ts +0 -21
  38. package/server/methods/admin/load-program.ts +0 -52
  39. package/server/methods/admin/mint-to.ts +0 -266
  40. package/server/methods/block/get-block-height.ts +0 -5
  41. package/server/methods/block/get-block.ts +0 -31
  42. package/server/methods/block/get-blocks-with-limit.ts +0 -19
  43. package/server/methods/block/get-latest-blockhash.ts +0 -12
  44. package/server/methods/block/get-slot.ts +0 -5
  45. package/server/methods/block/index.ts +0 -6
  46. package/server/methods/block/is-blockhash-valid.ts +0 -19
  47. package/server/methods/epoch/get-cluster-nodes.ts +0 -17
  48. package/server/methods/epoch/get-epoch-info.ts +0 -16
  49. package/server/methods/epoch/get-epoch-schedule.ts +0 -15
  50. package/server/methods/epoch/get-highest-snapshot-slot.ts +0 -9
  51. package/server/methods/epoch/get-leader-schedule.ts +0 -8
  52. package/server/methods/epoch/get-max-retransmit-slot.ts +0 -9
  53. package/server/methods/epoch/get-max-shred-insert-slot.ts +0 -9
  54. package/server/methods/epoch/get-slot-leader.ts +0 -6
  55. package/server/methods/epoch/get-slot-leaders.ts +0 -9
  56. package/server/methods/epoch/get-stake-activation.ts +0 -9
  57. package/server/methods/epoch/get-stake-minimum-delegation.ts +0 -9
  58. package/server/methods/epoch/get-vote-accounts.ts +0 -19
  59. package/server/methods/epoch/index.ts +0 -13
  60. package/server/methods/epoch/minimum-ledger-slot.ts +0 -5
  61. package/server/methods/fee/get-fee-calculator-for-blockhash.ts +0 -12
  62. package/server/methods/fee/get-fee-for-message.ts +0 -8
  63. package/server/methods/fee/get-fee-rate-governor.ts +0 -16
  64. package/server/methods/fee/get-fees.ts +0 -14
  65. package/server/methods/fee/get-recent-prioritization-fees.ts +0 -22
  66. package/server/methods/fee/index.ts +0 -5
  67. package/server/methods/get-address-lookup-table.ts +0 -27
  68. package/server/methods/index.ts +0 -265
  69. package/server/methods/performance/get-recent-performance-samples.ts +0 -25
  70. package/server/methods/performance/get-transaction-count.ts +0 -5
  71. package/server/methods/performance/index.ts +0 -2
  72. package/server/methods/program/get-block-commitment.ts +0 -9
  73. package/server/methods/program/get-block-production.ts +0 -14
  74. package/server/methods/program/get-block-time.ts +0 -21
  75. package/server/methods/program/get-blocks.ts +0 -11
  76. package/server/methods/program/get-first-available-block.ts +0 -9
  77. package/server/methods/program/get-genesis-hash.ts +0 -6
  78. package/server/methods/program/get-identity.ts +0 -6
  79. package/server/methods/program/get-inflation-governor.ts +0 -15
  80. package/server/methods/program/get-inflation-rate.ts +0 -10
  81. package/server/methods/program/get-inflation-reward.ts +0 -12
  82. package/server/methods/program/get-largest-accounts.ts +0 -8
  83. package/server/methods/program/get-parsed-program-accounts.ts +0 -12
  84. package/server/methods/program/get-parsed-token-accounts-by-delegate.ts +0 -12
  85. package/server/methods/program/get-parsed-token-accounts-by-owner.ts +0 -12
  86. package/server/methods/program/get-program-accounts.ts +0 -221
  87. package/server/methods/program/get-supply.ts +0 -13
  88. package/server/methods/program/get-token-account-balance.ts +0 -60
  89. package/server/methods/program/get-token-accounts-by-delegate.ts +0 -82
  90. package/server/methods/program/get-token-accounts-by-owner.ts +0 -416
  91. package/server/methods/program/get-token-largest-accounts.ts +0 -81
  92. package/server/methods/program/get-token-supply.ts +0 -39
  93. package/server/methods/program/index.ts +0 -21
  94. package/server/methods/solforge/index.ts +0 -158
  95. package/server/methods/system/get-health.ts +0 -5
  96. package/server/methods/system/get-minimum-balance-for-rent-exemption.ts +0 -13
  97. package/server/methods/system/get-version.ts +0 -9
  98. package/server/methods/system/index.ts +0 -3
  99. package/server/methods/transaction/get-confirmed-transaction.ts +0 -11
  100. package/server/methods/transaction/get-parsed-transaction.ts +0 -17
  101. package/server/methods/transaction/get-signature-statuses.ts +0 -79
  102. package/server/methods/transaction/get-signatures-for-address.ts +0 -41
  103. package/server/methods/transaction/get-transaction.ts +0 -639
  104. package/server/methods/transaction/index.ts +0 -7
  105. package/server/methods/transaction/inner-instructions.test.ts +0 -104
  106. package/server/methods/transaction/send-transaction.ts +0 -469
  107. package/server/methods/transaction/simulate-transaction.ts +0 -57
  108. package/server/rpc-server.ts +0 -521
  109. package/server/types.ts +0 -109
  110. package/server/ws-server.ts +0 -178
  111. package/src/api-server-entry.ts +0 -109
  112. package/src/cli/bootstrap.ts +0 -67
  113. package/src/cli/commands/airdrop.ts +0 -37
  114. package/src/cli/commands/config.ts +0 -39
  115. package/src/cli/commands/mint.ts +0 -187
  116. package/src/cli/commands/program-clone.ts +0 -122
  117. package/src/cli/commands/program-load.ts +0 -64
  118. package/src/cli/commands/rpc-start.ts +0 -49
  119. package/src/cli/commands/token-adopt-authority.ts +0 -37
  120. package/src/cli/commands/token-clone.ts +0 -112
  121. package/src/cli/commands/token-create.ts +0 -81
  122. package/src/cli/main.ts +0 -158
  123. package/src/cli/run-solforge.ts +0 -112
  124. package/src/cli/setup-utils.ts +0 -54
  125. package/src/cli/setup-wizard.ts +0 -258
  126. package/src/cli/utils/args.ts +0 -15
  127. package/src/commands/add-program.ts +0 -333
  128. package/src/commands/init.ts +0 -122
  129. package/src/commands/list.ts +0 -136
  130. package/src/commands/mint.ts +0 -287
  131. package/src/commands/start.ts +0 -881
  132. package/src/commands/status.ts +0 -99
  133. package/src/commands/stop.ts +0 -405
  134. package/src/config/index.ts +0 -146
  135. package/src/config/manager.ts +0 -157
  136. package/src/db/index.ts +0 -83
  137. package/src/db/schema/accounts.ts +0 -23
  138. package/src/db/schema/address-signatures.ts +0 -31
  139. package/src/db/schema/index.ts +0 -6
  140. package/src/db/schema/meta-kv.ts +0 -9
  141. package/src/db/schema/transactions.ts +0 -36
  142. package/src/db/schema/tx-account-states.ts +0 -23
  143. package/src/db/schema/tx-accounts.ts +0 -33
  144. package/src/db/tx-store.ts +0 -264
  145. package/src/gui/public/app.css +0 -1556
  146. package/src/gui/public/build/main.css +0 -1569
  147. package/src/gui/public/build/main.js +0 -303
  148. package/src/gui/public/build/main.js.txt +0 -231
  149. package/src/gui/public/index.html +0 -19
  150. package/src/gui/server.ts +0 -296
  151. package/src/gui/src/api.ts +0 -127
  152. package/src/gui/src/app.tsx +0 -441
  153. package/src/gui/src/components/airdrop-mint-form.tsx +0 -246
  154. package/src/gui/src/components/clone-program-modal.tsx +0 -202
  155. package/src/gui/src/components/clone-token-modal.tsx +0 -230
  156. package/src/gui/src/components/modal.tsx +0 -134
  157. package/src/gui/src/components/programs-panel.tsx +0 -124
  158. package/src/gui/src/components/status-panel.tsx +0 -136
  159. package/src/gui/src/components/tokens-panel.tsx +0 -122
  160. package/src/gui/src/hooks/use-interval.ts +0 -17
  161. package/src/gui/src/index.css +0 -557
  162. package/src/gui/src/main.tsx +0 -17
  163. package/src/index.ts +0 -216
  164. package/src/migrations-bundled.ts +0 -23
  165. package/src/rpc/start.ts +0 -44
  166. package/src/services/api-server.ts +0 -504
  167. package/src/services/port-manager.ts +0 -174
  168. package/src/services/process-registry.ts +0 -153
  169. package/src/services/program-cloner.ts +0 -317
  170. package/src/services/token-cloner.ts +0 -811
  171. package/src/services/validator.ts +0 -293
  172. package/src/types/config.ts +0 -110
  173. package/src/utils/shell.ts +0 -110
  174. 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
- };