solana-mint-recovery-engine 1.1.0 → 1.2.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.
- package/README.md +32 -7
- package/dist/bin/smre.js +22 -2
- package/dist/bin/smre.js.map +1 -1
- package/dist/src/commands/build.d.ts +3 -0
- package/dist/src/commands/build.js +84 -17
- package/dist/src/commands/build.js.map +1 -1
- package/dist/src/commands/inspect.js +34 -11
- package/dist/src/commands/inspect.js.map +1 -1
- package/dist/src/commands/recover.d.ts +3 -0
- package/dist/src/commands/recover.js +76 -15
- package/dist/src/commands/recover.js.map +1 -1
- package/dist/src/commands/scan.js +87 -18
- package/dist/src/commands/scan.js.map +1 -1
- package/dist/src/core/constants.d.ts +2 -2
- package/dist/src/core/constants.js +2 -2
- package/dist/src/core/constants.js.map +1 -1
- package/dist/src/core/transaction.d.ts +13 -14
- package/dist/src/core/transaction.js +41 -26
- package/dist/src/core/transaction.js.map +1 -1
- package/dist/src/core/validation.d.ts +18 -6
- package/dist/src/core/validation.js +7 -3
- package/dist/src/core/validation.js.map +1 -1
- package/dist/src/io/rpc.d.ts +11 -6
- package/dist/src/io/rpc.js +34 -12
- package/dist/src/io/rpc.js.map +1 -1
- package/package.json +7 -4
package/README.md
CHANGED
|
@@ -51,22 +51,41 @@ Since the **Authority** is already a required signer on the `WithdrawExcessLampo
|
|
|
51
51
|
|
|
52
52
|
### Requirements
|
|
53
53
|
- **Node.js:** >= 18.0.0
|
|
54
|
-
- **
|
|
54
|
+
- **NPM:** (Included with Node.js)
|
|
55
55
|
|
|
56
|
-
###
|
|
56
|
+
### 1. Global Installation (Recommended)
|
|
57
|
+
To install the CLI globally on your system and run it from any directory:
|
|
58
|
+
```bash
|
|
59
|
+
npm install -g solana-mint-recovery-engine
|
|
60
|
+
```
|
|
61
|
+
Once installed, verify the installation by checking the version or running the diagnostics:
|
|
62
|
+
```bash
|
|
63
|
+
smre --version
|
|
64
|
+
smre doctor
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 2. Run Instantly with NPX (No Installation Required)
|
|
68
|
+
If you prefer not to install the package permanently, you can execute commands on-demand directly from the npm registry using `npx`:
|
|
69
|
+
```bash
|
|
70
|
+
npx solana-mint-recovery-engine doctor
|
|
71
|
+
npx solana-mint-recovery-engine scan addresses.txt
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 3. Local Development & Contribution
|
|
75
|
+
If you want to build and run the project locally from source:
|
|
57
76
|
1. Clone the repository and install dependencies:
|
|
58
77
|
```bash
|
|
59
78
|
npm install
|
|
60
79
|
```
|
|
61
|
-
2. Build the
|
|
80
|
+
2. Build the TypeScript files:
|
|
62
81
|
```bash
|
|
63
82
|
npm run build
|
|
64
83
|
```
|
|
65
|
-
3. Link the
|
|
84
|
+
3. Link the package to your global bin path for local testing:
|
|
66
85
|
```bash
|
|
67
86
|
npm link
|
|
68
87
|
```
|
|
69
|
-
You can now run
|
|
88
|
+
You can now run `smre` globally, and it will execute your local build.
|
|
70
89
|
|
|
71
90
|
---
|
|
72
91
|
|
|
@@ -105,7 +124,10 @@ smre build <source-address> \
|
|
|
105
124
|
-o <output-envelope.json> \
|
|
106
125
|
[--fee-wallet <address>] \
|
|
107
126
|
[--fee-percent <number>] \
|
|
108
|
-
[--fee-payer <address>]
|
|
127
|
+
[--fee-payer <address>] \
|
|
128
|
+
[--nonce <nonce-account-address>] \
|
|
129
|
+
[--nonce-authority <address>] \
|
|
130
|
+
[--close]
|
|
109
131
|
```
|
|
110
132
|
|
|
111
133
|
### 6. Simulation: `simulate`
|
|
@@ -135,7 +157,10 @@ smre recover <source-address> \
|
|
|
135
157
|
-k <keypair-secret-or-path> \
|
|
136
158
|
-d <destination-address> \
|
|
137
159
|
[--fee-wallet <address>] \
|
|
138
|
-
[--fee-percent <number>]
|
|
160
|
+
[--fee-percent <number>] \
|
|
161
|
+
[--nonce <nonce-account-address>] \
|
|
162
|
+
[--nonce-authority <address>] \
|
|
163
|
+
[--close]
|
|
139
164
|
```
|
|
140
165
|
|
|
141
166
|
---
|
package/dist/bin/smre.js
CHANGED
|
@@ -11,8 +11,16 @@ 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
|
-
//
|
|
15
|
-
|
|
14
|
+
// Determine package.json path dynamically based on runtime location
|
|
15
|
+
let packageJson;
|
|
16
|
+
try {
|
|
17
|
+
// Production path (dist/bin/smre.js -> ../../package.json)
|
|
18
|
+
packageJson = require('../../package.json');
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
// Development path (bin/smre.ts -> ../package.json)
|
|
22
|
+
packageJson = require('../package.json');
|
|
23
|
+
}
|
|
16
24
|
// MED-12: Global error handler for unhandled exceptions/rejections
|
|
17
25
|
process.on('unhandledRejection', (reason) => {
|
|
18
26
|
console.error(`\n✘ Unhandled error: ${reason}`);
|
|
@@ -50,6 +58,9 @@ program
|
|
|
50
58
|
.option('--fee-wallet <address>', 'Wallet to receive the platform fee')
|
|
51
59
|
.option('--fee-percent <number>', 'Platform fee percentage (0-100)')
|
|
52
60
|
.option('--fee-payer <address>', 'Fee payer for the transaction')
|
|
61
|
+
.option('--nonce <address>', 'Durable nonce account address (Q3)')
|
|
62
|
+
.option('--nonce-authority <address>', 'Durable nonce authority (if different from authority)')
|
|
63
|
+
.option('--close', 'Close the account completely to recover rent floor (required for legacy) (Q4)')
|
|
53
64
|
.action((address, options) => {
|
|
54
65
|
(0, build_1.runBuild)(address, {
|
|
55
66
|
destination: options.destination,
|
|
@@ -58,6 +69,9 @@ program
|
|
|
58
69
|
feeWallet: options.feeWallet,
|
|
59
70
|
feePercent: options.feePercent,
|
|
60
71
|
feePayer: options.feePayer,
|
|
72
|
+
nonce: options.nonce,
|
|
73
|
+
nonceAuthority: options.nonceAuthority,
|
|
74
|
+
close: options.close,
|
|
61
75
|
});
|
|
62
76
|
});
|
|
63
77
|
program
|
|
@@ -90,6 +104,9 @@ program
|
|
|
90
104
|
.option('-d, --destination <address>', 'Recipient address for the recovered SOL')
|
|
91
105
|
.option('--fee-wallet <address>', 'Wallet to receive the platform fee')
|
|
92
106
|
.option('--fee-percent <number>', 'Platform fee percentage (0-100)')
|
|
107
|
+
.option('--nonce <address>', 'Durable nonce account address (Q3)')
|
|
108
|
+
.option('--nonce-authority <address>', 'Durable nonce authority')
|
|
109
|
+
.option('--close', 'Close the account completely to recover rent floor (required for legacy) (Q4)')
|
|
93
110
|
.action((address, options) => {
|
|
94
111
|
(0, recover_1.runRecover)(address, {
|
|
95
112
|
keypair: options.keypair,
|
|
@@ -97,6 +114,9 @@ program
|
|
|
97
114
|
config: program.opts().config,
|
|
98
115
|
feeWallet: options.feeWallet,
|
|
99
116
|
feePercent: options.feePercent,
|
|
117
|
+
nonce: options.nonce,
|
|
118
|
+
nonceAuthority: options.nonceAuthority,
|
|
119
|
+
close: options.close,
|
|
100
120
|
});
|
|
101
121
|
});
|
|
102
122
|
// Nested config commands
|
package/dist/bin/smre.js.map
CHANGED
|
@@ -1 +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,
|
|
1
|
+
{"version":3,"file":"smre.js","sourceRoot":"","sources":["../../bin/smre.ts"],"names":[],"mappings":"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"}
|
|
@@ -28,11 +28,23 @@ async function runBuild(addressStr, options) {
|
|
|
28
28
|
// 1. Inspect account state
|
|
29
29
|
logger_1.logger.step(1, 8, 'Inspecting target account...');
|
|
30
30
|
const account = await rpc.inspectAccount(source);
|
|
31
|
-
//
|
|
31
|
+
// Handle legacy vs Token-2022 close recovery pathways (Q4)
|
|
32
|
+
let closeAccount = !!options.close;
|
|
32
33
|
if (!account.isToken2022) {
|
|
33
|
-
|
|
34
|
-
`
|
|
35
|
-
|
|
34
|
+
if (account.type !== 'token-account') {
|
|
35
|
+
throw new Error(`Account ${source.toBase58()} is a legacy SPL ${account.type.toUpperCase()}.\n` +
|
|
36
|
+
`Legacy mints/multisigs cannot be recovered because the legacy program has no close or withdraw instructions for them.`);
|
|
37
|
+
}
|
|
38
|
+
// For legacy token accounts, closeAccount is mandatory
|
|
39
|
+
closeAccount = true;
|
|
40
|
+
// Check token balance to prevent close failure on-chain
|
|
41
|
+
if (account.tokenAmount !== undefined && account.tokenAmount > 0n) {
|
|
42
|
+
throw new Error(`Legacy Token Account ${source.toBase58()} has a non-zero token balance of ${account.tokenAmount.toLocaleString()}.\n` +
|
|
43
|
+
`Solana does not allow closing accounts with a non-zero token balance.\n` +
|
|
44
|
+
`Please transfer the tokens out to another wallet first, then rerun this recovery.`);
|
|
45
|
+
}
|
|
46
|
+
logger_1.logger.warn(`Legacy SPL Token account detected. Routing recovery through the CLOSE-ACCOUNT flow.\n` +
|
|
47
|
+
`This transaction will close the account and recover 100% of the rent floor + excess SOL.`);
|
|
36
48
|
}
|
|
37
49
|
// HIGH-04: Use RPC-based rent floor
|
|
38
50
|
let rentFloor;
|
|
@@ -46,7 +58,10 @@ async function runBuild(addressStr, options) {
|
|
|
46
58
|
rentFloor = offlineResult.rentFloor;
|
|
47
59
|
excess = offlineResult.excess;
|
|
48
60
|
}
|
|
49
|
-
|
|
61
|
+
// If close account is requested, we recover the ENTIRE balance.
|
|
62
|
+
// If not, we only recover excess above the floor.
|
|
63
|
+
const recoveryAmount = closeAccount ? account.balance : excess;
|
|
64
|
+
if (recoveryAmount <= 0n) {
|
|
50
65
|
throw new Error(`Account has no excess lamports above the rent floor (${rentFloor.toLocaleString()} lamports).`);
|
|
51
66
|
}
|
|
52
67
|
// 2. Resolve destination
|
|
@@ -107,21 +122,54 @@ async function runBuild(addressStr, options) {
|
|
|
107
122
|
if (feeWallet && feePercentage > 0) {
|
|
108
123
|
logger_1.logger.info(`Platform fee: ${feePercentage}% to ${feeWallet.toBase58()}`);
|
|
109
124
|
}
|
|
110
|
-
// 6. Fetch
|
|
111
|
-
|
|
112
|
-
|
|
125
|
+
// 6. Fetch blockhash or query durable nonce (Q3)
|
|
126
|
+
let blockhash;
|
|
127
|
+
let lastValidBlockHeight;
|
|
128
|
+
let nonceAccountPubkey;
|
|
129
|
+
let nonceAuthorityPubkey;
|
|
130
|
+
if (options.nonce) {
|
|
131
|
+
logger_1.logger.step(6, 8, 'Resolving durable nonce account...');
|
|
132
|
+
try {
|
|
133
|
+
nonceAccountPubkey = new web3_js_1.PublicKey(options.nonce);
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
throw new Error(`Invalid nonce account address: "${options.nonce}".`);
|
|
137
|
+
}
|
|
138
|
+
const nonceAccount = await rpc.getNonceAccount(nonceAccountPubkey);
|
|
139
|
+
blockhash = nonceAccount.nonce;
|
|
140
|
+
nonceAuthorityPubkey = nonceAccount.authorizedPubkey;
|
|
141
|
+
if (options.nonceAuthority) {
|
|
142
|
+
try {
|
|
143
|
+
nonceAuthorityPubkey = new web3_js_1.PublicKey(options.nonceAuthority);
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
throw new Error(`Invalid nonce authority address: "${options.nonceAuthority}".`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
logger_1.logger.success(`Fetched durable nonce: ${blockhash}`);
|
|
150
|
+
logger_1.logger.info(`Nonce Authority: ${nonceAuthorityPubkey.toBase58()}`);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
logger_1.logger.step(6, 8, 'Fetching latest blockhash...');
|
|
154
|
+
const bhResult = await rpc.getLatestBlockhash();
|
|
155
|
+
blockhash = bhResult.blockhash;
|
|
156
|
+
lastValidBlockHeight = bhResult.lastValidBlockHeight;
|
|
157
|
+
}
|
|
113
158
|
// 7. Build instructions
|
|
114
159
|
logger_1.logger.step(7, 8, 'Building transaction instructions...');
|
|
115
160
|
const instructions = (0, transaction_1.buildRecoveryInstructions)({
|
|
116
161
|
source,
|
|
117
162
|
destination,
|
|
118
163
|
authority,
|
|
119
|
-
excessAmount:
|
|
164
|
+
excessAmount: recoveryAmount,
|
|
120
165
|
developerFeeWallet: feeWallet,
|
|
121
166
|
feePercentage,
|
|
122
167
|
multiSigners: account.multisigSigners,
|
|
123
168
|
programId: account.ownerProgram,
|
|
124
169
|
priorityFee: config.priorityFee,
|
|
170
|
+
nonceAccount: nonceAccountPubkey,
|
|
171
|
+
nonceAuthority: nonceAuthorityPubkey,
|
|
172
|
+
closeAccount,
|
|
125
173
|
});
|
|
126
174
|
// 8. Compile transaction
|
|
127
175
|
logger_1.logger.step(8, 8, 'Compiling transaction...');
|
|
@@ -138,20 +186,22 @@ async function runBuild(addressStr, options) {
|
|
|
138
186
|
// Create envelope JSON
|
|
139
187
|
const envelope = {
|
|
140
188
|
version: constants_1.ENVELOPE_VERSION,
|
|
141
|
-
type: 'withdraw-excess-lamports',
|
|
189
|
+
type: closeAccount ? 'close-account' : 'withdraw-excess-lamports',
|
|
142
190
|
metadata: {
|
|
143
191
|
sourceAddress: source.toBase58(),
|
|
144
192
|
sourceType: account.type,
|
|
145
193
|
destinationAddress: destination.toBase58(),
|
|
146
194
|
authorityAddress: authority.toBase58(),
|
|
147
|
-
excessLamports:
|
|
148
|
-
rentFloor: rentFloor.toString(),
|
|
195
|
+
excessLamports: recoveryAmount.toString(),
|
|
196
|
+
rentFloor: closeAccount ? '0' : rentFloor.toString(),
|
|
149
197
|
createdAt: new Date().toISOString(),
|
|
150
198
|
blockhash,
|
|
151
199
|
lastValidBlockHeight,
|
|
152
200
|
isToken2022: account.isToken2022,
|
|
153
201
|
feePercentage: feeWallet ? feePercentage : undefined,
|
|
154
202
|
feeWallet: feeWallet?.toBase58(),
|
|
203
|
+
nonceAccount: nonceAccountPubkey?.toBase58(),
|
|
204
|
+
nonceAuthority: nonceAuthorityPubkey?.toBase58(),
|
|
155
205
|
},
|
|
156
206
|
rawTransactionB64,
|
|
157
207
|
signatures: [],
|
|
@@ -179,6 +229,16 @@ async function runBuild(addressStr, options) {
|
|
|
179
229
|
signature: null,
|
|
180
230
|
});
|
|
181
231
|
}
|
|
232
|
+
// Ensure nonceAuthority is present in signatures (Q3)
|
|
233
|
+
if (nonceAuthorityPubkey) {
|
|
234
|
+
const nonceAuthStr = nonceAuthorityPubkey.toBase58();
|
|
235
|
+
if (!envelope.signatures.some(s => s.pubkey === nonceAuthStr)) {
|
|
236
|
+
envelope.signatures.push({
|
|
237
|
+
pubkey: nonceAuthStr,
|
|
238
|
+
signature: null,
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
182
242
|
// Write envelope file
|
|
183
243
|
(0, file_1.writeEnvelope)(options.output, envelope);
|
|
184
244
|
logger_1.logger.success(`Built transaction envelope → ${options.output}`);
|
|
@@ -187,15 +247,22 @@ async function runBuild(addressStr, options) {
|
|
|
187
247
|
console.log(` Destination: ${envelope.metadata.destinationAddress}`);
|
|
188
248
|
console.log(` Authority: ${envelope.metadata.authorityAddress}`);
|
|
189
249
|
console.log(` Fee Payer: ${feePayer.toBase58()}`);
|
|
190
|
-
console.log(` Recoverable: ${(0, format_1.formatSol)(
|
|
250
|
+
console.log(` Recoverable: ${(0, format_1.formatSol)(recoveryAmount)} ${closeAccount ? chalk_1.default.red('(CLOSE FLOW)') : ''}`);
|
|
191
251
|
if (feeWallet && feePercentage > 0) {
|
|
192
|
-
const feeAmount = (
|
|
193
|
-
const netAmount =
|
|
252
|
+
const feeAmount = (recoveryAmount * BigInt(Math.round(feePercentage * 100))) / 10000n;
|
|
253
|
+
const netAmount = recoveryAmount - feeAmount;
|
|
194
254
|
console.log(` Fee Split: ${feePercentage}% → ${feeWallet.toBase58()} (${(0, format_1.formatSol)(feeAmount)})`);
|
|
195
255
|
console.log(` Net Amount: ${(0, format_1.formatSol)(netAmount)}`);
|
|
196
256
|
}
|
|
197
|
-
|
|
198
|
-
|
|
257
|
+
if (nonceAccountPubkey) {
|
|
258
|
+
console.log(` Nonce Acct: ${nonceAccountPubkey.toBase58()}`);
|
|
259
|
+
console.log(` Nonce Value: ${envelope.metadata.blockhash}`);
|
|
260
|
+
console.log(chalk_1.default.green(` ✔ Transaction is durable. Signatures will not expire.`));
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
console.log(` Blockhash: ${envelope.metadata.blockhash}`);
|
|
264
|
+
console.log(chalk_1.default.yellow(` ⚠ Blockhash expires in ~60-90 seconds. Sign and submit promptly.`));
|
|
265
|
+
}
|
|
199
266
|
}
|
|
200
267
|
catch (err) {
|
|
201
268
|
logger_1.logger.fail(`Failed to build transaction: ${err.message}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../../src/commands/build.ts"],"names":[],"mappings":";;;;;AAWA,
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../../src/commands/build.ts"],"names":[],"mappings":"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"}
|
|
@@ -24,7 +24,7 @@ async function runInspect(addressStr, options) {
|
|
|
24
24
|
throw new Error(`Invalid Solana address: "${addressStr}". Expected a valid base58-encoded public key.`);
|
|
25
25
|
}
|
|
26
26
|
const account = await rpc.inspectAccount(address);
|
|
27
|
-
// HIGH-04: Use RPC-based rent floor
|
|
27
|
+
// HIGH-04: Use RPC-based rent floor
|
|
28
28
|
let rentFloor;
|
|
29
29
|
let excess;
|
|
30
30
|
try {
|
|
@@ -36,6 +36,11 @@ async function runInspect(addressStr, options) {
|
|
|
36
36
|
rentFloor = offlineResult.rentFloor;
|
|
37
37
|
excess = offlineResult.excess;
|
|
38
38
|
}
|
|
39
|
+
// Determine legacy close recovery feasibility (Q4)
|
|
40
|
+
const isLegacyTokenAccount = !account.isToken2022 && account.type === 'token-account';
|
|
41
|
+
const isLegacyRecoverable = isLegacyTokenAccount && account.tokenAmount === 0n && account.balance > 0n;
|
|
42
|
+
const isRecoverable = (account.isToken2022 && excess > 0n) || isLegacyRecoverable;
|
|
43
|
+
const recoveryAmount = isLegacyTokenAccount ? account.balance : excess;
|
|
39
44
|
if (options.json) {
|
|
40
45
|
console.log(JSON.stringify({
|
|
41
46
|
address: account.address.toBase58(),
|
|
@@ -49,26 +54,38 @@ async function runInspect(addressStr, options) {
|
|
|
49
54
|
solExcess: (0, format_1.lamportsToSolString)(excess),
|
|
50
55
|
authority: account.authority ? account.authority.toBase58() : null,
|
|
51
56
|
isToken2022: account.isToken2022,
|
|
52
|
-
|
|
57
|
+
tokenAmount: account.tokenAmount?.toString(),
|
|
58
|
+
isRecoverable,
|
|
59
|
+
recoveryAmount: recoveryAmount.toString(),
|
|
60
|
+
recoveryMethod: isLegacyTokenAccount ? 'close-account' : 'withdraw-excess',
|
|
53
61
|
isLegacy: !account.isToken2022,
|
|
54
62
|
multisigSigners: account.multisigSigners?.map(s => s.toBase58()),
|
|
55
63
|
multisigThreshold: account.multisigThreshold,
|
|
56
64
|
}, null, 2));
|
|
57
|
-
process.exit(
|
|
65
|
+
process.exit(isRecoverable ? 0 : 3);
|
|
58
66
|
}
|
|
59
67
|
console.log(chalk_1.default.bold(`\nAccount Inspection: ${address.toBase58()}`));
|
|
60
68
|
console.log('──────────────────────────────────────────────────────');
|
|
61
69
|
console.log(`Program Owner: ${account.isToken2022 ? chalk_1.default.green('Token-2022') : chalk_1.default.yellow('Legacy Token (SPL Token v1)')} (${account.ownerProgram.toBase58()})`);
|
|
62
70
|
console.log(`Account Type: ${chalk_1.default.blue(account.type.toUpperCase())}`);
|
|
63
71
|
console.log(`Total Balance: ${chalk_1.default.cyan((0, format_1.formatSolWithLamports)(account.balance))}`);
|
|
72
|
+
if (account.type === 'token-account') {
|
|
73
|
+
console.log(`Token Balance: ${account.tokenAmount !== undefined ? account.tokenAmount.toLocaleString() : 'N/A'}`);
|
|
74
|
+
}
|
|
64
75
|
console.log(`Rent Floor: ${(0, format_1.formatSolWithLamports)(rentFloor)}`);
|
|
65
|
-
|
|
76
|
+
if (isLegacyTokenAccount) {
|
|
77
|
+
console.log(`Recoverable: ${recoveryAmount > 0n ? chalk_1.default.green((0, format_1.formatSolWithLamports)(recoveryAmount)) : chalk_1.default.grey('0 SOL')}`);
|
|
78
|
+
console.log(`Recovery Mode: ${chalk_1.default.yellow('CLOSE-ACCOUNT FLOW')} (Legacy token accounts must be closed to recover rent floor)`);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
console.log(`Recoverable: ${excess > 0n ? chalk_1.default.green((0, format_1.formatSolWithLamports)(excess)) : chalk_1.default.grey('0.000000000 SOL (0 lamports)')}`);
|
|
82
|
+
console.log(`Recovery Mode: ${chalk_1.default.green('WITHDRAW-EXCESS FLOW')}`);
|
|
83
|
+
}
|
|
66
84
|
if (account.authority) {
|
|
67
85
|
console.log(`Authority: ${account.authority.toBase58()}`);
|
|
68
86
|
}
|
|
69
87
|
else {
|
|
70
88
|
console.log(`Authority: ${chalk_1.default.red('NONE (Mint authority revoked)')}`);
|
|
71
|
-
// CRIT-05: Clear messaging about revoked mint authority
|
|
72
89
|
if (account.type === 'mint') {
|
|
73
90
|
console.log(chalk_1.default.yellow(`\n ⚠ Mint authority has been revoked. Recovery requires the ORIGINAL MINT KEYPAIR\n` +
|
|
74
91
|
` (the private key used to create mint address ${address.toBase58()}).\n` +
|
|
@@ -82,14 +99,20 @@ async function runInspect(addressStr, options) {
|
|
|
82
99
|
console.log(` - [${index + 1}] ${signer.toBase58()}`);
|
|
83
100
|
});
|
|
84
101
|
}
|
|
85
|
-
//
|
|
86
|
-
if (
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
102
|
+
// Warnings & Recovery Verification
|
|
103
|
+
if (isLegacyTokenAccount) {
|
|
104
|
+
if (account.tokenAmount !== undefined && account.tokenAmount > 0n) {
|
|
105
|
+
console.log(chalk_1.default.red(`\n✘ Account has a non-zero token balance of ${account.tokenAmount.toLocaleString()}.\n` +
|
|
106
|
+
` You must transfer the tokens out before recovery. Closing will fail on-chain.`));
|
|
107
|
+
process.exit(3);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
else if (!account.isToken2022) {
|
|
111
|
+
console.log(chalk_1.default.red(`\n✘ Legacy SPL ${account.type.toUpperCase()} accounts cannot be recovered.\n` +
|
|
112
|
+
` Solana has no close or withdraw instructions for legacy mints/multisigs.`));
|
|
90
113
|
process.exit(3);
|
|
91
114
|
}
|
|
92
|
-
if (
|
|
115
|
+
if (recoveryAmount === 0n) {
|
|
93
116
|
console.log(chalk_1.default.yellow('\nℹ Account has no excess lamports above the rent floor.'));
|
|
94
117
|
process.exit(3);
|
|
95
118
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inspect.js","sourceRoot":"","sources":["../../../src/commands/inspect.ts"],"names":[],"mappings":";;;;;AAQA,
|
|
1
|
+
{"version":3,"file":"inspect.js","sourceRoot":"","sources":["../../../src/commands/inspect.ts"],"names":[],"mappings":"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"}
|