solana-mint-recovery-engine 1.0.0 → 1.1.0

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 (53) hide show
  1. package/README.md +278 -0
  2. package/dist/bin/smre.js +13 -1
  3. package/dist/bin/smre.js.map +1 -0
  4. package/dist/src/commands/build.js +86 -20
  5. package/dist/src/commands/build.js.map +1 -0
  6. package/dist/src/commands/config.js +6 -2
  7. package/dist/src/commands/config.js.map +1 -0
  8. package/dist/src/commands/doctor.js +64 -15
  9. package/dist/src/commands/doctor.js.map +1 -0
  10. package/dist/src/commands/inspect.js +48 -20
  11. package/dist/src/commands/inspect.js.map +1 -0
  12. package/dist/src/commands/recover.js +93 -30
  13. package/dist/src/commands/recover.js.map +1 -0
  14. package/dist/src/commands/scan.js +77 -25
  15. package/dist/src/commands/scan.js.map +1 -0
  16. package/dist/src/commands/sign.js +24 -8
  17. package/dist/src/commands/sign.js.map +1 -0
  18. package/dist/src/commands/simulate.d.ts +5 -0
  19. package/dist/src/commands/simulate.js +13 -6
  20. package/dist/src/commands/simulate.js.map +1 -0
  21. package/dist/src/commands/submit.js +44 -10
  22. package/dist/src/commands/submit.js.map +1 -0
  23. package/dist/src/core/constants.d.ts +65 -0
  24. package/dist/src/core/constants.js +93 -0
  25. package/dist/src/core/constants.js.map +1 -0
  26. package/dist/src/core/format.d.ts +35 -0
  27. package/dist/src/core/format.js +62 -0
  28. package/dist/src/core/format.js.map +1 -0
  29. package/dist/src/core/rent.d.ts +17 -1
  30. package/dist/src/core/rent.js +25 -4
  31. package/dist/src/core/rent.js.map +1 -0
  32. package/dist/src/core/transaction.d.ts +32 -5
  33. package/dist/src/core/transaction.js +74 -22
  34. package/dist/src/core/transaction.js.map +1 -0
  35. package/dist/src/core/validation.d.ts +66 -23
  36. package/dist/src/core/validation.js +31 -4
  37. package/dist/src/core/validation.js.map +1 -0
  38. package/dist/src/index.d.ts +14 -0
  39. package/dist/src/index.js +51 -0
  40. package/dist/src/index.js.map +1 -0
  41. package/dist/src/io/file.d.ts +5 -2
  42. package/dist/src/io/file.js +64 -11
  43. package/dist/src/io/file.js.map +1 -0
  44. package/dist/src/io/logger.d.ts +31 -0
  45. package/dist/src/io/logger.js +95 -0
  46. package/dist/src/io/logger.js.map +1 -0
  47. package/dist/src/io/rpc.d.ts +75 -5
  48. package/dist/src/io/rpc.js +213 -109
  49. package/dist/src/io/rpc.js.map +1 -0
  50. package/dist/src/signers/signer.d.ts +6 -3
  51. package/dist/src/signers/signer.js +38 -14
  52. package/dist/src/signers/signer.js.map +1 -0
  53. package/package.json +14 -5
package/README.md ADDED
@@ -0,0 +1,278 @@
1
+ # Solana Mint & Token Account Recovery Engine (SMRE)
2
+
3
+ SMRE is an enterprise-grade Command Line Interface (CLI) tool and programmatic library designed to safely scan, inspect, build, sign, simulate, and submit transactions to recover excess SOL (lamports) lying above the rent-exempt minimum in Solana **Token-2022 (Token Extensions)** accounts, mints, and multisigs.
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+ 1. [Core Features](#core-features)
9
+ 2. [Architectural Highlights](#architectural-highlights)
10
+ 3. [Installation & Setup](#installation--setup)
11
+ 4. [CLI Command Reference](#cli-command-reference)
12
+ - [1. Diagnostics: `doctor`](#1-diagnostics-doctor)
13
+ - [2. Config Initialization: `config init`](#2-config-initialization-config-init)
14
+ - [3. Batch Scanning: `scan`](#3-batch-scanning-scan)
15
+ - [4. Single Inspection: `inspect`](#4-single-inspection-inspect)
16
+ - [5. Building Transaction Envelopes: `build`](#5-building-transaction-envelopes-build)
17
+ - [6. Simulation: `simulate`](#6-simulation-simulate)
18
+ - [7. Offline Signing: `sign`](#7-offline-signing-sign)
19
+ - [8. Submission: `submit`](#8-submission-submit)
20
+ - [9. Inline Recovery: `recover`](#9-inline-recovery-recover)
21
+ 5. [Configuration Schema](#configuration-schema)
22
+ 6. [Offline Transaction Envelope Schema](#offline-transaction-envelope-schema)
23
+ 7. [Programmatic Library Usage](#programmatic-library-usage)
24
+ 8. [NPM Publishing Guide (Developer Release Flow)](#npm-publishing-guide-developer-release-flow)
25
+
26
+ ---
27
+
28
+ ## Core Features
29
+ - **Zero-Loss Float Arithmetic:** Operates entirely with native TypeScript `BigInt` types to prevent floating-point inaccuracies for multi-million SOL recoveries.
30
+ - **Multisig Support:** Handles Token-2022 multisig accounts, tracking thresholds and collecting multi-signatures offline.
31
+ - **Offline / Air-Gapped Signature Collection:** Supports separation of duties. Build transactions online, sign offline, and broadcast from a secure node.
32
+ - **On-Chain Simulations:** Employs stable, public `@solana/web3.js` simulation APIs to run pre-execution checks and print execution logs.
33
+ - **Network Resilience:** Automatically injects Compute Budget and Priority Fee instructions to land transactions during times of high congestion.
34
+ - **Secure Key Handling:** Automatically scrubs private key arrays from memory immediately after keypair instantiation.
35
+
36
+ ---
37
+
38
+ ## Architectural Highlights
39
+
40
+ ### Precision-Safe Fee Routing (HIGH-08 Fix)
41
+ In standard implementations, splitting fees requires both the destination address and the authority to sign the transaction. SMRE avoids this requirement:
42
+ 1. Withdraws excess lamports from the Token-2022 account to the **Authority** address.
43
+ 2. Transfers the platform fee from the **Authority** to the **Fee Wallet**.
44
+ 3. Forwards the net amount from the **Authority** to the final **Destination**.
45
+
46
+ Since the **Authority** is already a required signer on the `WithdrawExcessLamports` instruction, no additional signature is required from the destination wallet.
47
+
48
+ ---
49
+
50
+ ## Installation & Setup
51
+
52
+ ### Requirements
53
+ - **Node.js:** >= 18.0.0
54
+ - **TypeScript:** >= 5.0.0
55
+
56
+ ### Local Installation
57
+ 1. Clone the repository and install dependencies:
58
+ ```bash
59
+ npm install
60
+ ```
61
+ 2. Build the project:
62
+ ```bash
63
+ npm run build
64
+ ```
65
+ 3. Link the CLI binary to your global system path:
66
+ ```bash
67
+ npm link
68
+ ```
69
+ You can now run the `smre` command from anywhere in your terminal.
70
+
71
+ ---
72
+
73
+ ## CLI Command Reference
74
+
75
+ ### 1. Diagnostics: `doctor`
76
+ Performs comprehensive checks on the system environment, Node.js version, configuration file health, RPC connection latency, and rent exemption estimates.
77
+ ```bash
78
+ smre doctor [--config <path>]
79
+ ```
80
+
81
+ ### 2. Config Initialization: `config init`
82
+ Creates a default `smre.config.json` configuration file in the working directory.
83
+ ```bash
84
+ smre config init [-o <output-path>]
85
+ ```
86
+
87
+ ### 3. Batch Scanning: `scan`
88
+ Scans a text file containing base58-encoded Solana addresses for recoverable excess lamports. Uses high-performance batching (100 accounts per batch) and reports results in a clean table or structured JSON.
89
+ ```bash
90
+ smre scan <address-file> [--json] [--config <path>]
91
+ ```
92
+ *Note: The address file should contain one address per line. Lines starting with `#` or `//` are treated as comments.*
93
+
94
+ ### 4. Single Inspection: `inspect`
95
+ Analyzes a single Token-2022 account, mint, or multisig on-chain, rendering details about owner program, balance, rent floor, authority, and recovery status.
96
+ ```bash
97
+ smre inspect <address> [--json] [--config <path>]
98
+ ```
99
+
100
+ ### 5. Building Transaction Envelopes: `build`
101
+ Constructs an unsigned transaction to recover excess lamports and saves it into an offline Transaction Envelope JSON file.
102
+ ```bash
103
+ smre build <source-address> \
104
+ -d <destination-address> \
105
+ -o <output-envelope.json> \
106
+ [--fee-wallet <address>] \
107
+ [--fee-percent <number>] \
108
+ [--fee-payer <address>]
109
+ ```
110
+
111
+ ### 6. Simulation: `simulate`
112
+ Runs an on-chain simulation of the constructed Transaction Envelope to verify instructions, print execution logs, and measure compute unit consumption without broadcasting.
113
+ ```bash
114
+ smre simulate <envelope-file>
115
+ ```
116
+
117
+ ### 7. Offline Signing: `sign`
118
+ Signs an offline Transaction Envelope. Supports JSON keypair files, raw base58 private key strings, or direct JSON private key arrays. Automatically tracks signature slots.
119
+ ```bash
120
+ smre sign <envelope-file> \
121
+ -k <keypair-secret-or-path> \
122
+ [-o <output-envelope.json>]
123
+ ```
124
+
125
+ ### 8. Submission: `submit`
126
+ Validates that the required signature threshold is met (including multisig threshold), broadcasts the transaction to the network, and polls the node for confirmation.
127
+ ```bash
128
+ smre submit <envelope-file>
129
+ ```
130
+
131
+ ### 9. Inline Recovery: `recover`
132
+ Convenience command that performs inspection, building, signing, simulation, submission, and confirmation in a single online step.
133
+ ```bash
134
+ smre recover <source-address> \
135
+ -k <keypair-secret-or-path> \
136
+ -d <destination-address> \
137
+ [--fee-wallet <address>] \
138
+ [--fee-percent <number>]
139
+ ```
140
+
141
+ ---
142
+
143
+ ## Configuration Schema
144
+ Configuration options can be placed in `smre.config.json` or passed as a custom file using the `-c` flag.
145
+ ```json
146
+ {
147
+ "rpcUrl": "https://api.mainnet-beta.solana.com",
148
+ "commitment": "confirmed",
149
+ "defaultDestination": "9xQdBNbLqP55ePE1R24g5652uhGzTsw34JmUCwm",
150
+ "feeWallet": "EGMQSHdW5vLvTZ4ro8BkGjWerXcWH7oHVW2EDMJqPA4x",
151
+ "feePercentage": 2.5,
152
+ "priorityFee": 5000
153
+ }
154
+ ```
155
+
156
+ ---
157
+
158
+ ## Offline Transaction Envelope Schema
159
+ Transaction envelopes use a strict, schema-validated JSON format:
160
+ ```json
161
+ {
162
+ "version": "1.1.0",
163
+ "type": "withdraw-excess-lamports",
164
+ "metadata": {
165
+ "sourceAddress": "4zMMC9ZdZhLx2u223612q76Cc223612q76Cc223612",
166
+ "sourceType": "mint",
167
+ "destinationAddress": "9xQdBNbLqP55ePE1R24g5652uhGzTsw34JmUCwm",
168
+ "authorityAddress": "F223612q76Cc223612q76Cc223612q76Cc223612q",
169
+ "excessLamports": "2960720",
170
+ "rentFloor": "1461600",
171
+ "createdAt": "2026-07-07T13:25:28Z",
172
+ "blockhash": "D9yVwZ9p8N...WdQsK",
173
+ "lastValidBlockHeight": 268495034,
174
+ "feePercentage": 2.5,
175
+ "feeWallet": "EGMQSHdW5vLvTZ4ro8BkGjWerXcWH7oHVW2EDMJqPA4x",
176
+ "isToken2022": true
177
+ },
178
+ "rawTransactionB64": "AYADg...",
179
+ "signatures": [
180
+ {
181
+ "pubkey": "F223612q76Cc223612q76Cc223612q76Cc223612q",
182
+ "signature": "3uXp9G..."
183
+ }
184
+ ]
185
+ }
186
+ ```
187
+
188
+ ---
189
+
190
+ ## Programmatic Library Usage
191
+ SMRE is fully typed and can be imported directly into node-based scripts:
192
+ ```typescript
193
+ import { RpcAdapter, buildRecoveryInstructions, lamportsToSolString } from 'solana-mint-recovery-engine';
194
+ import { PublicKey, Transaction } from '@solana/web3.js';
195
+
196
+ async function main() {
197
+ const rpc = new RpcAdapter('https://api.mainnet-beta.solana.com', 'confirmed');
198
+
199
+ // Inspect
200
+ const target = new PublicKey('...');
201
+ const account = await rpc.inspectAccount(target);
202
+
203
+ const rentFloor = await rpc.getMinimumBalanceForRentExemption(account.dataSize);
204
+ const excess = account.balance - rentFloor;
205
+
206
+ console.log(`Recoverable amount: ${lamportsToSolString(excess)} SOL`);
207
+
208
+ if (excess > 0n && account.authority) {
209
+ const instructions = buildRecoveryInstructions({
210
+ source: target,
211
+ destination: new PublicKey('...'),
212
+ authority: account.authority,
213
+ excessAmount: excess,
214
+ priorityFee: 1000,
215
+ });
216
+
217
+ const tx = new Transaction().add(...instructions);
218
+ // Continue with sign/submit...
219
+ }
220
+ }
221
+ ```
222
+
223
+ ---
224
+
225
+ ## NPM Publishing Guide (Developer Release Flow)
226
+
227
+ Follow these steps to publish or update the package on the NPM registry:
228
+
229
+ ### 1. Prerequisite Checks
230
+ Before publishing, ensure the codebase is completely clean, builds successfully, and passes all tests.
231
+ ```bash
232
+ # Verify TypeScript compiles without errors
233
+ npm run lint
234
+
235
+ # Run Jest tests and verification tests
236
+ npm run test
237
+ npm run test:run
238
+ ```
239
+
240
+ ### 2. Configure package.json Metadata
241
+ Ensure the following fields are correct in `package.json`:
242
+ - `"name"`: Set to your package name (e.g., `solana-mint-recovery-engine` or a scoped package name like `@my-org/smre`).
243
+ - `"publishConfig"`: If using a scoped package, you may want to set it to public:
244
+ ```json
245
+ "publishConfig": {
246
+ "access": "public"
247
+ }
248
+ ```
249
+
250
+ ### 3. Versioning
251
+ Increment the package version according to Semantic Versioning (SemVer):
252
+ - **Patch release** (bug fixes): `npm version patch` (e.g., `1.1.0` → `1.1.1`)
253
+ - **Minor release** (new backward-compatible features): `npm version minor` (e.g., `1.1.0` → `1.2.0`)
254
+ - **Major release** (breaking changes): `npm version major` (e.g., `1.1.0` → `2.0.0`)
255
+
256
+ This command updates `package.json`, `package-lock.json`, and creates a local Git tag.
257
+
258
+ ### 4. Authenticate with NPM
259
+ If you are not logged in, run:
260
+ ```bash
261
+ npm login
262
+ ```
263
+ Provide your username, password, email, and one-time password (OTP).
264
+
265
+ ### 5. Publish to the Registry
266
+ Publish the package. The `"prepack"` script in `package.json` will automatically trigger `npm run build` to compile the TypeScript code to `./dist` before packaging:
267
+ ```bash
268
+ npm publish
269
+ ```
270
+ If you are publishing a scoped package for the first time:
271
+ ```bash
272
+ npm publish --access public
273
+ ```
274
+
275
+ ---
276
+
277
+ ## License
278
+ MIT
package/dist/bin/smre.js CHANGED
@@ -11,11 +11,22 @@ const submit_1 = require("../src/commands/submit");
11
11
  const recover_1 = require("../src/commands/recover");
12
12
  const config_1 = require("../src/commands/config");
13
13
  const doctor_1 = require("../src/commands/doctor");
14
+ // HIGH-05 FIX: Read version dynamically from package.json
15
+ const packageJson = require('../package.json');
16
+ // MED-12: Global error handler for unhandled exceptions/rejections
17
+ process.on('unhandledRejection', (reason) => {
18
+ console.error(`\n✘ Unhandled error: ${reason}`);
19
+ process.exit(1);
20
+ });
21
+ process.on('uncaughtException', (err) => {
22
+ console.error(`\n✘ Fatal error: ${err.message}`);
23
+ process.exit(1);
24
+ });
14
25
  const program = new commander_1.Command();
15
26
  program
16
27
  .name('smre')
17
28
  .description('Solana Mint & Token Account Recovery Engine (SMRE) CLI')
18
- .version('1.0.0')
29
+ .version(packageJson.version)
19
30
  .option('-c, --config <path>', 'Path to custom configuration JSON file');
20
31
  program
21
32
  .command('scan <address-file>')
@@ -104,3 +115,4 @@ program
104
115
  (0, doctor_1.runDoctor)(program.opts().config);
105
116
  });
106
117
  program.parse(process.argv);
118
+ //# sourceMappingURL=smre.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smre.js","sourceRoot":"","sources":["../../bin/smre.ts"],"names":[],"mappings":";;;AACA,yCAAoC;AACpC,+CAA+C;AAC/C,qDAAqD;AACrD,iDAAiD;AACjD,+CAA+C;AAC/C,uDAAuD;AACvD,mDAAmD;AACnD,qDAAqD;AACrD,mDAAoD;AACpD,mDAAmD;AAEnD,0DAA0D;AAC1D,MAAM,WAAW,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAE/C,mEAAmE;AACnE,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,MAAM,EAAE,EAAE;IAC1C,OAAO,CAAC,KAAK,CAAC,wBAAwB,MAAM,EAAE,CAAC,CAAC;IAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,OAAO,CAAC,EAAE,CAAC,mBAAmB,EAAE,CAAC,GAAG,EAAE,EAAE;IACtC,OAAO,CAAC,KAAK,CAAC,oBAAoB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,MAAM,CAAC;KACZ,WAAW,CAAC,wDAAwD,CAAC;KACrE,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC;KAC5B,MAAM,CAAC,qBAAqB,EAAE,wCAAwC,CAAC,CAAC;AAE3E,OAAO;KACJ,OAAO,CAAC,qBAAqB,CAAC;KAC9B,WAAW,CAAC,6EAA6E,CAAC;KAC1F,MAAM,CAAC,QAAQ,EAAE,wBAAwB,CAAC;KAC1C,MAAM,CAAC,CAAC,WAAW,EAAE,OAAO,EAAE,EAAE;IAC/B,IAAA,cAAO,EAAC,WAAW,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;AAC9E,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,mBAAmB,CAAC;KAC5B,WAAW,CAAC,sEAAsE,CAAC;KACnF,MAAM,CAAC,QAAQ,EAAE,wBAAwB,CAAC;KAC1C,MAAM,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE;IAC3B,IAAA,oBAAU,EAAC,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;AAC7E,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,iBAAiB,CAAC;KAC1B,WAAW,CAAC,2EAA2E,CAAC;KACxF,MAAM,CAAC,6BAA6B,EAAE,yCAAyC,CAAC;KAChF,MAAM,CAAC,qBAAqB,EAAE,4CAA4C,EAAE,kBAAkB,CAAC;KAC/F,MAAM,CAAC,wBAAwB,EAAE,oCAAoC,CAAC;KACtE,MAAM,CAAC,wBAAwB,EAAE,iCAAiC,CAAC;KACnE,MAAM,CAAC,uBAAuB,EAAE,+BAA+B,CAAC;KAChE,MAAM,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE;IAC3B,IAAA,gBAAQ,EAAC,OAAO,EAAE;QAChB,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM;QAC7B,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,QAAQ,EAAE,OAAO,CAAC,QAAQ;KAC3B,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,0BAA0B,CAAC;KACnC,WAAW,CAAC,6DAA6D,CAAC;KAC1E,MAAM,CAAC,CAAC,YAAY,EAAE,EAAE;IACvB,IAAA,sBAAW,EAAC,YAAY,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;AAC/D,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,sBAAsB,CAAC;KAC/B,WAAW,CAAC,gFAAgF,CAAC;KAC7F,cAAc,CAAC,wBAAwB,EAAE,8DAA8D,CAAC;KACxG,MAAM,CAAC,qBAAqB,EAAE,kEAAkE,CAAC;KACjG,MAAM,CAAC,CAAC,YAAY,EAAE,OAAO,EAAE,EAAE;IAChC,IAAA,cAAO,EAAC,YAAY,EAAE;QACpB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,wBAAwB,CAAC;KACjC,WAAW,CAAC,qEAAqE,CAAC;KAClF,MAAM,CAAC,CAAC,YAAY,EAAE,EAAE;IACvB,IAAA,kBAAS,EAAC,YAAY,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;AAC7D,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,mBAAmB,CAAC;KAC5B,WAAW,CAAC,qFAAqF,CAAC;KAClG,cAAc,CAAC,wBAAwB,EAAE,oDAAoD,CAAC;KAC9F,MAAM,CAAC,6BAA6B,EAAE,yCAAyC,CAAC;KAChF,MAAM,CAAC,wBAAwB,EAAE,oCAAoC,CAAC;KACtE,MAAM,CAAC,wBAAwB,EAAE,iCAAiC,CAAC;KACnE,MAAM,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE;IAC3B,IAAA,oBAAU,EAAC,OAAO,EAAE;QAClB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM;QAC7B,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,UAAU,EAAE,OAAO,CAAC,UAAU;KAC/B,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEL,yBAAyB;AACzB,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,yBAAyB,CAAC,CAAC;AAEnF,SAAS;KACN,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,2DAA2D,CAAC;KACxE,MAAM,CAAC,qBAAqB,EAAE,6BAA6B,EAAE,kBAAkB,CAAC;KAChF,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE;IAClB,IAAA,mBAAU,EAAC,OAAO,CAAC,MAAM,CAAC,CAAC;AAC7B,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,4DAA4D,CAAC;KACzE,MAAM,CAAC,GAAG,EAAE;IACX,IAAA,kBAAS,EAAC,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC;AACnC,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
@@ -9,40 +9,82 @@ const rpc_1 = require("../io/rpc");
9
9
  const rent_1 = require("../core/rent");
10
10
  const transaction_1 = require("../core/transaction");
11
11
  const file_1 = require("../io/file");
12
+ const constants_1 = require("../core/constants");
13
+ const format_1 = require("../core/format");
14
+ const logger_1 = require("../io/logger");
12
15
  const chalk_1 = __importDefault(require("chalk"));
13
16
  async function runBuild(addressStr, options) {
14
17
  try {
15
18
  const config = (0, file_1.loadConfig)(options.config);
16
19
  const rpc = new rpc_1.RpcAdapter(config.rpcUrl, config.commitment);
17
- const source = new web3_js_1.PublicKey(addressStr);
20
+ // MED-07: Validate public key input
21
+ let source;
22
+ try {
23
+ source = new web3_js_1.PublicKey(addressStr);
24
+ }
25
+ catch {
26
+ throw new Error(`Invalid source address: "${addressStr}". Expected a valid base58-encoded public key.`);
27
+ }
18
28
  // 1. Inspect account state
29
+ logger_1.logger.step(1, 8, 'Inspecting target account...');
19
30
  const account = await rpc.inspectAccount(source);
31
+ // CRIT-03: Reject legacy token accounts
20
32
  if (!account.isToken2022) {
21
- throw new Error(`Account is not owned by the Token-2022 program. Recoveries are not supported.`);
33
+ throw new Error(`Account ${source.toBase58()} is owned by the legacy SPL Token Program. ` +
34
+ `The WithdrawExcessLamports instruction is a Token-2022-only feature. ` +
35
+ `Recovery from legacy token accounts requires a different mechanism.`);
36
+ }
37
+ // HIGH-04: Use RPC-based rent floor
38
+ let rentFloor;
39
+ let excess;
40
+ try {
41
+ rentFloor = await rpc.getMinimumBalanceForRentExemption(account.dataSize);
42
+ excess = account.balance > rentFloor ? account.balance - rentFloor : 0n;
43
+ }
44
+ catch {
45
+ const offlineResult = (0, rent_1.calculateExcessLamports)(account.dataSize, account.balance);
46
+ rentFloor = offlineResult.rentFloor;
47
+ excess = offlineResult.excess;
22
48
  }
23
- const { excess, rentFloor } = (0, rent_1.calculateExcessLamports)(account.dataSize, account.balance);
24
49
  if (excess <= 0n) {
25
50
  throw new Error(`Account has no excess lamports above the rent floor (${rentFloor.toLocaleString()} lamports).`);
26
51
  }
27
52
  // 2. Resolve destination
53
+ logger_1.logger.step(2, 8, 'Resolving destination...');
28
54
  const destinationStr = options.destination || config.defaultDestination;
29
55
  if (!destinationStr) {
30
56
  throw new Error(`No destination address specified. Use --destination <address> or define defaultDestination in config.`);
31
57
  }
32
- const destination = new web3_js_1.PublicKey(destinationStr);
58
+ let destination;
59
+ try {
60
+ destination = new web3_js_1.PublicKey(destinationStr);
61
+ }
62
+ catch {
63
+ throw new Error(`Invalid destination address: "${destinationStr}". Expected a valid base58-encoded public key.`);
64
+ }
33
65
  // 3. Resolve authority
34
- const authority = account.authority;
66
+ logger_1.logger.step(3, 8, 'Resolving authority...');
67
+ let authority = account.authority;
35
68
  if (!authority) {
36
- throw new Error(`No authority found for account. It is not recoverable.`);
69
+ if (account.type === 'mint') {
70
+ authority = source;
71
+ // CRIT-05: Clear messaging about what this means
72
+ logger_1.logger.warn(`Mint authority is revoked. Recovery will require the ORIGINAL MINT KEYPAIR ` +
73
+ `(the private key that created mint address ${source.toBase58()}). ` +
74
+ `If you do not possess this keypair, the transaction will fail to sign.`);
75
+ }
76
+ else {
77
+ throw new Error(`No authority found for account ${source.toBase58()}. Recovery is not possible.`);
78
+ }
37
79
  }
38
80
  // 4. Resolve fee payer
81
+ logger_1.logger.step(4, 8, 'Resolving fee payer...');
39
82
  let feePayer = authority;
40
83
  if (account.type === 'multisig' && account.multisigSigners && account.multisigSigners.length > 0) {
41
84
  if (options.feePayer) {
42
85
  feePayer = new web3_js_1.PublicKey(options.feePayer);
43
86
  }
44
87
  else {
45
- // Default to the first co-signer for multisig accounts
46
88
  feePayer = account.multisigSigners[0];
47
89
  }
48
90
  }
@@ -50,14 +92,26 @@ async function runBuild(addressStr, options) {
50
92
  feePayer = new web3_js_1.PublicKey(options.feePayer);
51
93
  }
52
94
  // 5. Resolve platform fee wallet & percentage
95
+ logger_1.logger.step(5, 8, 'Resolving fee configuration...');
53
96
  const feeWalletStr = options.feeWallet || config.feeWallet;
54
- const feePercentage = options.feePercent !== undefined
55
- ? parseInt(options.feePercent, 10)
56
- : config.feePercentage;
97
+ // CRIT-06 FIX: Proper fee percentage parsing with validation
98
+ let feePercentage = config.feePercentage;
99
+ if (options.feePercent !== undefined) {
100
+ const parsed = parseFloat(options.feePercent);
101
+ if (isNaN(parsed) || parsed < 0 || parsed > 100) {
102
+ throw new Error(`Invalid fee percentage: "${options.feePercent}". Must be a number between 0 and 100.`);
103
+ }
104
+ feePercentage = parsed;
105
+ }
57
106
  const feeWallet = feeWalletStr ? new web3_js_1.PublicKey(feeWalletStr) : undefined;
58
- // 6. Fetch latest blockhash
59
- const blockhash = await rpc.getLatestBlockhash();
107
+ if (feeWallet && feePercentage > 0) {
108
+ logger_1.logger.info(`Platform fee: ${feePercentage}% to ${feeWallet.toBase58()}`);
109
+ }
110
+ // 6. Fetch latest blockhash (HIGH-02: include lastValidBlockHeight)
111
+ logger_1.logger.step(6, 8, 'Fetching latest blockhash...');
112
+ const { blockhash, lastValidBlockHeight } = await rpc.getLatestBlockhash();
60
113
  // 7. Build instructions
114
+ logger_1.logger.step(7, 8, 'Building transaction instructions...');
61
115
  const instructions = (0, transaction_1.buildRecoveryInstructions)({
62
116
  source,
63
117
  destination,
@@ -66,8 +120,11 @@ async function runBuild(addressStr, options) {
66
120
  developerFeeWallet: feeWallet,
67
121
  feePercentage,
68
122
  multiSigners: account.multisigSigners,
123
+ programId: account.ownerProgram,
124
+ priorityFee: config.priorityFee,
69
125
  });
70
126
  // 8. Compile transaction
127
+ logger_1.logger.step(8, 8, 'Compiling transaction...');
71
128
  const tx = new web3_js_1.Transaction();
72
129
  tx.add(...instructions);
73
130
  tx.recentBlockhash = blockhash;
@@ -78,9 +135,9 @@ async function runBuild(addressStr, options) {
78
135
  verifySignatures: false,
79
136
  });
80
137
  const rawTransactionB64 = serialized.toString('base64');
81
- // 9. Create envelope JSON
138
+ // Create envelope JSON
82
139
  const envelope = {
83
- version: '1.0.0',
140
+ version: constants_1.ENVELOPE_VERSION,
84
141
  type: 'withdraw-excess-lamports',
85
142
  metadata: {
86
143
  sourceAddress: source.toBase58(),
@@ -91,6 +148,10 @@ async function runBuild(addressStr, options) {
91
148
  rentFloor: rentFloor.toString(),
92
149
  createdAt: new Date().toISOString(),
93
150
  blockhash,
151
+ lastValidBlockHeight,
152
+ isToken2022: account.isToken2022,
153
+ feePercentage: feeWallet ? feePercentage : undefined,
154
+ feeWallet: feeWallet?.toBase58(),
94
155
  },
95
156
  rawTransactionB64,
96
157
  signatures: [],
@@ -120,20 +181,25 @@ async function runBuild(addressStr, options) {
120
181
  }
121
182
  // Write envelope file
122
183
  (0, file_1.writeEnvelope)(options.output, envelope);
123
- console.log(chalk_1.default.green(`✔ Built transaction envelope and saved to ${options.output}`));
124
- console.log('\nTransaction Metadata:');
184
+ logger_1.logger.success(`Built transaction envelope ${options.output}`);
185
+ console.log('\nTransaction Details:');
125
186
  console.log(` Source: ${envelope.metadata.sourceAddress} (${envelope.metadata.sourceType})`);
126
187
  console.log(` Destination: ${envelope.metadata.destinationAddress}`);
127
188
  console.log(` Authority: ${envelope.metadata.authorityAddress}`);
128
189
  console.log(` Fee Payer: ${feePayer.toBase58()}`);
129
- console.log(` Recoverable: ${Number(excess) / 1e9} SOL`);
130
- if (feeWallet) {
131
- console.log(` Fee Split: ${feePercentage}% to ${feeWallet.toBase58()}`);
190
+ console.log(` Recoverable: ${(0, format_1.formatSol)(excess)}`);
191
+ if (feeWallet && feePercentage > 0) {
192
+ const feeAmount = (excess * BigInt(Math.round(feePercentage * 100))) / 10000n;
193
+ const netAmount = excess - feeAmount;
194
+ console.log(` Fee Split: ${feePercentage}% → ${feeWallet.toBase58()} (${(0, format_1.formatSol)(feeAmount)})`);
195
+ console.log(` Net Amount: ${(0, format_1.formatSol)(netAmount)}`);
132
196
  }
133
197
  console.log(` Blockhash: ${envelope.metadata.blockhash}`);
198
+ console.log(chalk_1.default.yellow(` ⚠ Blockhash expires in ~60-90 seconds. Sign and submit promptly.`));
134
199
  }
135
200
  catch (err) {
136
- console.error(chalk_1.default.red(`✘ Failed to build transaction: ${err.message}`));
201
+ logger_1.logger.fail(`Failed to build transaction: ${err.message}`);
137
202
  process.exit(1);
138
203
  }
139
204
  }
205
+ //# sourceMappingURL=build.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../../../src/commands/build.ts"],"names":[],"mappings":"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"}
@@ -6,16 +6,20 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.initConfig = initConfig;
7
7
  const file_1 = require("../io/file");
8
8
  const validation_1 = require("../core/validation");
9
+ const logger_1 = require("../io/logger");
9
10
  const chalk_1 = __importDefault(require("chalk"));
10
11
  function initConfig(outputPath = 'smre.config.json') {
11
12
  try {
12
13
  const defaultConfig = validation_1.ConfigSchema.parse({});
13
14
  (0, file_1.writeConfig)(outputPath, defaultConfig);
14
- console.log(chalk_1.default.green(`✔ Initialized default configuration at ${outputPath}`));
15
+ logger_1.logger.success(`Initialized default configuration at ${outputPath}`);
15
16
  console.log(JSON.stringify(defaultConfig, null, 2));
17
+ console.log(chalk_1.default.yellow(`\n ⚠ Review and customize this file before use.\n` +
18
+ ` In particular, set your defaultDestination and review fee settings.`));
16
19
  }
17
20
  catch (err) {
18
- console.error(chalk_1.default.red(`✘ Failed to initialize configuration: ${err.message}`));
21
+ logger_1.logger.fail(`Failed to initialize configuration: ${err.message}`);
19
22
  process.exit(1);
20
23
  }
21
24
  }
25
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/commands/config.ts"],"names":[],"mappings":";;;;;AAKA,gCAcC;AAnBD,qCAAyC;AACzC,mDAAkD;AAClD,yCAAsC;AACtC,kDAA0B;AAE1B,SAAgB,UAAU,CAAC,aAAqB,kBAAkB;IAChE,IAAI,CAAC;QACH,MAAM,aAAa,GAAG,yBAAY,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC7C,IAAA,kBAAW,EAAC,UAAU,EAAE,aAAa,CAAC,CAAC;QACvC,eAAM,CAAC,OAAO,CAAC,wCAAwC,UAAU,EAAE,CAAC,CAAC;QACrE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACpD,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,MAAM,CACtB,oDAAoD;YACpD,uEAAuE,CACxE,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,eAAM,CAAC,IAAI,CAAC,uCAAwC,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QAC7E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -6,39 +6,88 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.runDoctor = runDoctor;
7
7
  const web3_js_1 = require("@solana/web3.js");
8
8
  const file_1 = require("../io/file");
9
+ const constants_1 = require("../core/constants");
10
+ const logger_1 = require("../io/logger");
9
11
  const chalk_1 = __importDefault(require("chalk"));
10
12
  async function runDoctor(configPath) {
11
- console.log(chalk_1.default.bold('Running SMRE Doctor Diagnostics...'));
13
+ console.log(chalk_1.default.bold('┌─────────────────────────────────────────┐'));
14
+ console.log(chalk_1.default.bold('│ SMRE Doctor — System Diagnostics │'));
15
+ console.log(chalk_1.default.bold('└─────────────────────────────────────────┘'));
12
16
  let isHealthy = true;
13
- // 1. Validate Config Load
17
+ let checkCount = 0;
18
+ const totalChecks = 5;
19
+ // 1. Check Node.js version (MED-09)
20
+ checkCount++;
21
+ logger_1.logger.step(checkCount, totalChecks, 'Checking Node.js version...');
22
+ const nodeVersion = process.versions.node;
23
+ const majorVersion = parseInt(nodeVersion.split('.')[0], 10);
24
+ if (majorVersion >= constants_1.MIN_NODE_VERSION) {
25
+ logger_1.logger.success(`Node.js v${nodeVersion} (>= v${constants_1.MIN_NODE_VERSION} required)`);
26
+ }
27
+ else {
28
+ logger_1.logger.fail(`Node.js v${nodeVersion} — version >= v${constants_1.MIN_NODE_VERSION} is required!`);
29
+ isHealthy = false;
30
+ }
31
+ // 2. Check dependency availability
32
+ checkCount++;
33
+ logger_1.logger.step(checkCount, totalChecks, 'Checking critical dependencies...');
34
+ try {
35
+ require('@solana/web3.js');
36
+ require('@solana/spl-token');
37
+ require('bs58');
38
+ logger_1.logger.success('All critical dependencies available.');
39
+ }
40
+ catch (err) {
41
+ logger_1.logger.fail(`Missing dependency: ${err.message}`);
42
+ console.log(chalk_1.default.yellow(' Run: npm install'));
43
+ isHealthy = false;
44
+ }
45
+ // 3. Validate Config Load
46
+ checkCount++;
47
+ logger_1.logger.step(checkCount, totalChecks, 'Validating configuration...');
14
48
  try {
15
49
  const config = (0, file_1.loadConfig)(configPath);
16
- console.log(chalk_1.default.green(`✔ Configuration loaded successfully.`));
17
- console.log(` RPC Endpoint: ${config.rpcUrl}`);
18
- console.log(` Commitment: ${config.commitment}`);
19
- console.log(` Default Destination: ${config.defaultDestination || 'None specified'}`);
20
- console.log(` Platform Fee %: ${config.feePercentage}%`);
21
- // 2. Validate RPC Connectivity
22
- console.log('\nTesting RPC connectivity...');
50
+ logger_1.logger.success('Configuration loaded successfully.');
51
+ console.log(` RPC Endpoint: ${config.rpcUrl}`);
52
+ console.log(` Commitment: ${config.commitment}`);
53
+ console.log(` Default Destination: ${config.defaultDestination || chalk_1.default.yellow('Not configured')}`);
54
+ console.log(` Fee Wallet: ${config.feeWallet || chalk_1.default.gray('None (no fee)')}`);
55
+ console.log(` Fee Percentage: ${config.feePercentage}%`);
56
+ console.log(` Priority Fee: ${config.priorityFee} micro-lamports/CU`);
57
+ // 4. Validate RPC Connectivity
58
+ checkCount++;
59
+ logger_1.logger.step(checkCount, totalChecks, 'Testing RPC connectivity...');
23
60
  const startTime = Date.now();
24
61
  const connection = new web3_js_1.Connection(config.rpcUrl, config.commitment);
25
62
  const version = await connection.getVersion();
26
63
  const latency = Date.now() - startTime;
27
- console.log(chalk_1.default.green(`✔ Connected to Solana node version: ${version['solana-core']}`));
28
- console.log(` Latency: ${latency}ms`);
64
+ logger_1.logger.success(`Connected to Solana node v${version['solana-core']}`);
65
+ console.log(` Latency: ${latency}ms ${latency > 1000 ? chalk_1.default.yellow('(slow — consider a dedicated RPC)') : chalk_1.default.green('(good)')}`);
66
+ // 5. Test blockhash and slot
67
+ checkCount++;
68
+ logger_1.logger.step(checkCount, totalChecks, 'Verifying chain state...');
29
69
  const slot = await connection.getSlot();
30
- console.log(chalk_1.default.green(`✔ Latest confirmed slot: ${slot}`));
70
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
71
+ logger_1.logger.success(`Latest confirmed slot: ${slot}`);
72
+ console.log(` Blockhash: ${blockhash}`);
73
+ console.log(` Last valid block height: ${lastValidBlockHeight}`);
74
+ // Test rent RPC
75
+ const rentExempt = await connection.getMinimumBalanceForRentExemption(165);
76
+ logger_1.logger.success(`Rent exempt (165 bytes): ${rentExempt.toLocaleString()} lamports`);
31
77
  }
32
78
  catch (err) {
33
- console.error(chalk_1.default.red(`✘ Diagnostic failed: ${err.message}`));
79
+ logger_1.logger.fail(`Diagnostic failed: ${err.message}`);
34
80
  isHealthy = false;
35
81
  }
82
+ // Final verdict
83
+ console.log('');
36
84
  if (isHealthy) {
37
- console.log(chalk_1.default.bold.green('\nEnvironment is healthy! You are ready to run SMRE.'));
85
+ console.log(chalk_1.default.bold.green('✔ All checks passed! Environment is healthy.'));
38
86
  process.exit(0);
39
87
  }
40
88
  else {
41
- console.log(chalk_1.default.bold.red('\n✘ Some checks failed. Please review your settings.'));
89
+ console.log(chalk_1.default.bold.red('✘ Some checks failed. Please review the output above.'));
42
90
  process.exit(1);
43
91
  }
44
92
  }
93
+ //# sourceMappingURL=doctor.js.map