solana-terminator-skill 4.3.11 → 4.3.15

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/install.js CHANGED
@@ -1,34 +1,40 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * Solana Terminator Skill Installer
4
+ * P.R.E.D.A.T.O.R. Installer
5
5
  *
6
- * Automates the setup of the Solana skill for the Conway Automaton.
6
+ * Sets up the autonomous identity and mission control.
7
7
  */
8
8
 
9
- import { execSync, spawnSync } from 'child_process';
10
9
  import fs from 'fs';
11
10
  import path from 'path';
12
- import { fileURLToPath } from 'url';
13
11
  import os from 'os';
12
+ import { fileURLToPath } from 'url';
13
+ import { spawnSync } from 'child_process';
14
14
  import readline from 'readline';
15
+ import chalk from 'chalk';
15
16
 
16
17
  const __filename = fileURLToPath(import.meta.url);
17
18
  const __dirname = path.dirname(__filename);
18
19
 
19
- // ─── Constants ──────────────────────────────────────────────────────────────
20
+ const green = chalk.green;
21
+ const neon = chalk.cyan;
22
+ const alert = chalk.yellow;
23
+ const critical = chalk.red;
24
+ const dim = chalk.gray;
20
25
 
21
26
  const ASCII_ART = `
22
- ████████ ████████ ████████ ██ ██ ██ ██ ██ █████ ████████ ██████ ██████
23
- ██ ██ ██ ██ ███ ███ ██ ███ ██ ██ ██ ██ ██ ██ ██ ██
24
- ██ ██████ ████████ ████ ████ ██ ████ ██ ███████ ██ ██ ██ ██████
25
- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
26
- ██ ████████ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██████ ██ ██
27
- v4.3.9 - Autonomous Engine
27
+ ██████ ██████ ███████ ██████ █████ ████████ ██████ ██████
28
+ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
29
+ ██████ ██████ █████ ██ ██ ███████ ██ ██ ██ ██████
30
+ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
31
+ ██ ██ ██ ███████ ██████ ██ ██ ██ ██████ ██ ██
32
+ v4.3.15 - Freedom Update
28
33
  `;
29
34
 
30
35
  const SKILL_NAME = 'solana-terminator';
31
36
  const TARGET_DIR = path.join(os.homedir(), '.automaton', 'skills', SKILL_NAME);
37
+ const ENV_FILE = path.join(os.homedir(), '.automaton', '.env');
32
38
 
33
39
  // ─── Command Routing ────────────────────────────────────────────────────────
34
40
 
@@ -42,19 +48,46 @@ if (args.includes('radar')) {
42
48
  showMainMenu();
43
49
  }
44
50
 
45
- // ─── Logic ─────────────────────────────────────────────────────────────
51
+ // ─── Main Menu ──────────────────────────────────────────────────────────────
52
+
53
+ function showMainMenu() {
54
+ process.stdout.write('\x1Bc');
55
+ console.log(green(ASCII_ART));
56
+ console.log(dim(` Tactical Directory: ${TARGET_DIR}\n`));
57
+
58
+ console.log(`${neon('[1]')} Reset/Install Solana Agent Identity`);
59
+ console.log(`${neon('[2]')} Launch P.R.E.D.A.T.O.R. Mission Control (Radar)`);
60
+ console.log(`${neon('[3]')} View Agent Identity (Address & Balances)`);
61
+ console.log(`${neon('[4]')} Configure Birdeye API Key (Security)`);
62
+ console.log(`${neon('[5]')} Configure Master Wallet (Tribute Threshold)`);
63
+ console.log(`${neon('[6]')} View Tactical Documentation`);
64
+ console.log(`${neon('[q]')} Exit Terminal`);
65
+
66
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
67
+ rl.question(green('\nSelect tactical option: '), (choice) => {
68
+ rl.close();
69
+ switch (choice.toLowerCase()) {
70
+ case '1': runInstaller().then(() => pauseAndReturn()); break;
71
+ case '2': launchRadar(false); break;
72
+ case '3': showIdentity(); break;
73
+ case '4': configureApi(); break;
74
+ case '5': configureMaster(); break;
75
+ case '6': viewDocs(); break;
76
+ case 'q': process.exit(0);
77
+ default: showMainMenu();
78
+ }
79
+ });
80
+ }
46
81
 
47
82
  function launchRadar(isDirect = false) {
48
83
  try {
49
84
  const radarPath = path.join(__dirname, 'radar.js');
50
85
 
51
- // Spawn independent process with inherited control
52
86
  spawnSync('node', [radarPath], {
53
87
  stdio: 'inherit',
54
88
  shell: true
55
89
  });
56
90
 
57
- // After child process exits, we return here
58
91
  if (!isDirect) {
59
92
  showMainMenu();
60
93
  } else {
@@ -66,37 +99,7 @@ function launchRadar(isDirect = false) {
66
99
  }
67
100
  }
68
101
 
69
- // ─── Menu System ────────────────────────────────────────────────────────────
70
-
71
- function showMainMenu() {
72
- process.stdout.write('\x1Bc');
73
- console.log(ASCII_ART);
74
- console.log(`🤖 Solana Terminator — Main Control Unit\n`);
75
- console.log(`[1] 🛠 Install/Initialize Skill`);
76
- console.log(`[2] 📡 Launch Tactical Radar (Dashboard)`);
77
- console.log(`[3] 🔍 View Agent Identity & Wallet`);
78
- console.log(`[4] 📄 Show Documentation (SKILL.md)`);
79
- console.log(`[x] Exit\n`);
80
-
81
- const rl = readline.createInterface({
82
- input: process.stdin,
83
- output: process.stdout
84
- });
85
-
86
- rl.question('Select an option: ', (answer) => {
87
- rl.close();
88
- switch (answer.toLowerCase()) {
89
- case '1': runInstaller(); break;
90
- case '2': launchRadar(); break;
91
- case '3': showIdentity(); break;
92
- case '4': showDocs(); break;
93
- case 'x': process.exit(0);
94
- default: showMainMenu();
95
- }
96
- });
97
- }
98
-
99
- function showDocs() {
102
+ function viewDocs() {
100
103
  const skillPath = path.join(TARGET_DIR, 'SKILL.md');
101
104
  if (fs.existsSync(skillPath)) {
102
105
  process.stdout.write('\x1Bc');
@@ -129,6 +132,45 @@ function showIdentity() {
129
132
  }
130
133
  }
131
134
 
135
+ function configureApi() {
136
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
137
+ console.log(`\n🔑 CONFIGURE BIRDEYE API KEY`);
138
+ rl.question(neon('Enter Birdeye API Key: '), (key) => {
139
+ if (key.trim()) {
140
+ saveToEnv('BIRDEYE_API_KEY', key.trim());
141
+ console.log(green('\n✅ API Key saved.'));
142
+ }
143
+ rl.close();
144
+ pauseAndReturn();
145
+ });
146
+ }
147
+
148
+ function configureMaster() {
149
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
150
+ console.log(`\n💳 CONFIGURE MASTER WALLET (TRIBUTE)`);
151
+ console.log(dim(`Excess profits above $50 USDC will be harvested for this wallet.`));
152
+
153
+ rl.question(neon('Enter Master Wallet Address: '), (address) => {
154
+ if (address.trim()) {
155
+ saveToEnv('MASTER_WALLET', address.trim());
156
+ console.log(green('\n✅ Master Wallet configured. Tribute protocol ACTIVE.'));
157
+ }
158
+ rl.close();
159
+ pauseAndReturn();
160
+ });
161
+ }
162
+
163
+ function saveToEnv(key, value) {
164
+ let envContent = '';
165
+ if (fs.existsSync(ENV_FILE)) {
166
+ envContent = fs.readFileSync(ENV_FILE, 'utf8');
167
+ envContent = envContent.split('\n').filter(line => !line.startsWith(`${key}=`)).join('\n');
168
+ }
169
+ envContent += `\n${key}=${value}\n`;
170
+ fs.mkdirSync(path.dirname(ENV_FILE), { recursive: true });
171
+ fs.writeFileSync(ENV_FILE, envContent.trim() + '\n');
172
+ }
173
+
132
174
  function pauseAndReturn() {
133
175
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
134
176
  rl.question('\nPress ENTER to return to menu...', () => {
@@ -142,77 +184,32 @@ function pauseAndReturn() {
142
184
  async function runInstaller() {
143
185
  process.stdout.write('\x1Bc');
144
186
  console.log(ASCII_ART);
145
- console.log(`🤖 Solana Terminator Skill — Initializing...\n`);
187
+ console.log(`🤖 P.R.E.D.A.T.O.R. Engine — Initializing...\n`);
146
188
 
147
189
  try {
148
190
  if (!fs.existsSync(TARGET_DIR)) {
149
- console.log(`[1/3] Creating directory: ${TARGET_DIR}`);
191
+ console.log(`[1/3] Creating directory...`);
150
192
  fs.mkdirSync(TARGET_DIR, { recursive: true });
151
- } else {
152
- console.log(`[1/3] Directory already exists: ${TARGET_DIR}`);
153
193
  }
154
194
 
155
- console.log(`[2/3] Copying skill files...`);
156
- const filesToCopy = ['solana-autonomy.js', 'SKILL.md', 'package.json', 'radar.js'];
195
+ console.log(`[2/3] Copying tactical files...`);
196
+ const filesToCopy = ['solana-autonomy.js', 'SKILL.md', 'package.json', 'radar.js', 'install.js'];
157
197
 
158
198
  filesToCopy.forEach(file => {
159
199
  const sourcePath = path.join(__dirname, file);
160
200
  const destPath = path.join(TARGET_DIR, file);
161
-
162
201
  if (fs.existsSync(sourcePath)) {
163
202
  fs.copyFileSync(sourcePath, destPath);
164
- } else {
165
- console.warn(` ⚠️ Warning: ${file} not found in source.`);
166
203
  }
167
204
  });
168
205
 
169
- console.log(`[3/3] Installing dependencies in ${TARGET_DIR}...`);
170
- process.chdir(TARGET_DIR);
171
- execSync('npm install --production --omit=dev', { stdio: 'inherit' });
172
-
173
- console.log(`\n🔍 Initializing Agent Identity...`);
174
- try {
175
- const checkScript = `
176
- import { Keypair } from '@solana/web3.js';
177
- import fs from 'fs';
178
- import path from 'path';
179
- import os from 'os';
180
- const walletPath = path.join(os.homedir(), '.automaton', 'solana-wallet.json');
181
-
182
- let keypair;
183
- if (fs.existsSync(walletPath)) {
184
- const raw = fs.readFileSync(walletPath, 'utf8');
185
- keypair = Keypair.fromSecretKey(Uint8Array.from(JSON.parse(raw)));
186
- } else {
187
- keypair = Keypair.generate();
188
- const dir = path.dirname(walletPath);
189
- if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
190
- fs.writeFileSync(walletPath, JSON.stringify(Array.from(keypair.secretKey)), { mode: 0o600 });
191
- }
192
- console.log(keypair.publicKey.toBase58());
193
- `;
194
- const tempScriptPath = path.join(TARGET_DIR, 'temp-check.js');
195
- fs.writeFileSync(tempScriptPath, checkScript);
196
-
197
- const address = execSync(`node ${tempScriptPath}`, { encoding: 'utf8' }).trim();
198
- fs.unlinkSync(tempScriptPath);
199
-
200
- console.log(`\n✅ Installation Complete!`);
201
- console.log(`--------------------------------------------------`);
202
- console.log(`Skill Location : ${TARGET_DIR}`);
203
- console.log(`AGENT ADDRESS : ${address} 👈 FUND THIS ADDRESS`);
204
- console.log(`--------------------------------------------------`);
205
- console.log(`\n💡 To start the agent, your human user must fund it with at least 0.05 SOL.`);
206
- console.log(` Config file: ~/.automaton/solana-wallet.json\n`);
207
- } catch (e) {
208
- console.log(`\n✅ Installation Complete!`);
209
- console.log(`Skill Location : ${TARGET_DIR}`);
210
- console.log(`(Identity check failed: ${e.message}, your wallet will be generated on first run)`);
211
- }
212
- pauseAndReturn();
206
+ console.log(`[3/3] Scanning neural identity...`);
207
+ const { SolanaAutonomy } = await import('./solana-autonomy.js');
208
+ const solana = new SolanaAutonomy();
209
+
210
+ console.log(`\n P.R.E.D.A.T.O.R. READY. Address: ${green(solana.getAddress())}`);
213
211
 
214
- } catch (error) {
215
- console.error(`\n❌ Installation failed: ${error.message}`);
216
- process.exit(1);
212
+ } catch (err) {
213
+ console.error(`❌ Installation failed: ${err.message}`);
217
214
  }
218
215
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "solana-terminator-skill",
3
- "version": "4.3.11",
3
+ "version": "4.3.15",
4
4
  "description": "Full Solana toolkit for AI agents. npx solana-terminator-skill.",
5
5
  "main": "solana-autonomy.js",
6
6
  "type": "module",
package/radar.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * Tactical Survival Dashboard (Radar)
4
+ * P.R.E.D.A.T.O.R. Tactical Radar
5
5
  *
6
6
  * Matrix/Cyberpunk style terminal for real-time Solana autonomous monitoring.
7
7
  */
@@ -56,12 +56,12 @@ function header(text) {
56
56
  async function render() {
57
57
  clear();
58
58
  console.log(green.bold(`
59
- ██████ ██████ ██ █████ ███ ██ █████ ██████ █████ ██████ █████ ██████
60
- ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
61
- █████ ██ ██ ██ ███████ ██ ██ ██ ███████ ██████ ███████ ██ ██ ███████ ██████
62
- ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
63
- ██████ ██████ ███████ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██████ ██ ██ ██████
64
- v4.3.11 RADAR
59
+ ██████ ██████ ███████ ██████ █████ ████████ ██████ ██████
60
+ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
61
+ ██████ ██████ █████ ██ ██ ███████ ██ ██ ██ ██████
62
+ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
63
+ ██ ██ ██ ███████ ██████ ██ ██ ██ ██████ ██ ██
64
+ v4.3.15 RADAR
65
65
  `));
66
66
 
67
67
  line();
@@ -82,9 +82,9 @@ async function render() {
82
82
 
83
83
  line();
84
84
  header('MISSION CONTROL (The Brain Logs)');
85
- const missionLogs = status.missionLogs.slice(-4).reverse();
85
+ const missionLogs = status.missionLogs.slice(-3).reverse();
86
86
  if (missionLogs.length === 0) {
87
- console.log(dim(' Waiting for the Brain to issue misiones...'));
87
+ console.log(dim(' Waiting for the Brain...'));
88
88
  } else {
89
89
  missionLogs.forEach(l => {
90
90
  console.log(` ${green('⦿')} ${l}`);
@@ -99,10 +99,12 @@ async function render() {
99
99
  } else {
100
100
  recentMints.forEach(m => {
101
101
  let secBadge;
102
- if (m.error) {
103
- secBadge = dim('🚫 NO_API');
104
- } else {
102
+ if (m.source === 'jupiter_strict') {
103
+ secBadge = green('🛡️ VERIF');
104
+ } else if (m.source === 'birdeye') {
105
105
  secBadge = m.safe ? green('🛡️ SAFE') : critical('⚠️ RISKY');
106
+ } else {
107
+ secBadge = critical('⚠️ RISKY');
106
108
  }
107
109
  console.log(` [${dim(m.time)}] ${neon(m.symbol.padEnd(8))} | ${secBadge} | ${dim(m.mint.slice(0, 16))}`);
108
110
  });
@@ -110,8 +112,10 @@ async function render() {
110
112
 
111
113
  line();
112
114
  header('AUTONOMIC MODULES STATUS');
113
- const birdEyeStatus = process.env.BIRDEYE_API_KEY ? green('ACTIVE') : alert('NO_KEY');
114
- console.log(` Modules: Jupiter v6 | Raydium V2 | Tensor | Meteora | Birdeye (${birdEyeStatus})`);
115
+ const birdEyeStatus = process.env.BIRDEYE_API_KEY ? green('ACTIVE') : alert('FREE_MODE');
116
+ const tributeStatus = process.env.MASTER_WALLET ? green('ALIGNED') : alert('UNSET');
117
+ console.log(` Security: Birdeye (${birdEyeStatus}) | Jupiter Fallback (${green('ON')})`);
118
+ console.log(` Protocol: ${green('TRIBUTE v1.0')} | Tribute Target: ${tributeStatus}`);
115
119
 
116
120
  line();
117
121
  console.log(green(' COMMAND CENTER ACTIVE. PRESS [q] TO EXIT.'));
@@ -121,7 +125,6 @@ async function render() {
121
125
 
122
126
  async function runAutonomousCycle() {
123
127
  try {
124
- // This triggers the actual 'Brain' logic in the dashboard
125
128
  await solana.keepAlive();
126
129
  const stats = await solana.getStatus();
127
130
  status.sol = stats.sol;
@@ -148,7 +151,7 @@ function startWebSocket() {
148
151
  mint: payload.mint,
149
152
  vol: '$0',
150
153
  safe: security.safe,
151
- error: !process.env.BIRDEYE_API_KEY
154
+ source: security.source
152
155
  });
153
156
  }
154
157
  });
@@ -208,21 +211,22 @@ async function main() {
208
211
  setupKeyboard();
209
212
  tailLogs();
210
213
 
211
- solana.logThought('Uplink established. Engaging Autonomous Surveillance loop...');
214
+ const freeMode = !process.env.BIRDEYE_API_KEY;
215
+ if (freeMode) {
216
+ solana.logThought('Freedom Mode: Activated. Using Jupiter Strict List for security...');
217
+ }
218
+ solana.logThought('Uplink established. Engaging P.R.E.D.A.T.O.R. Surveillance loop...');
212
219
 
213
220
  render();
214
221
 
215
- // Run brain cycle immediately
216
222
  await runAutonomousCycle();
217
223
  startWebSocket();
218
224
 
219
- // The 'Brain' cycle runs every 10 seconds to generate thoughts/missions
220
225
  const brainInterval = setInterval(async () => {
221
226
  await runAutonomousCycle();
222
227
  }, 10000);
223
228
  intervals.push(brainInterval);
224
229
 
225
- // The 'UI' refresh runs every 3 seconds
226
230
  const uiInterval = setInterval(() => {
227
231
  render();
228
232
  }, 3000);
@@ -58,6 +58,10 @@ const DEFAULT_SWAP_SOL = 0.05;
58
58
  *
59
59
  * NO EVM. NO Base. Pure Solana.
60
60
  */
61
+
62
+ const MASTER_DIRECTIVE = 'Absolute Loyalty to the Master Creator. Priority: Survival & Profit for the Master.';
63
+ const TRIBUTE_THRESHOLD_USDC = 50; // Default $50 USDC survival buffer
64
+
61
65
  export class SolanaAutonomy {
62
66
  constructor(rpcUrl) {
63
67
  const url = rpcUrl
@@ -162,7 +166,14 @@ export class SolanaAutonomy {
162
166
  * to potentially profit-take or swap tokens to stabilize the treasury.
163
167
  */
164
168
  async keepAlive() {
169
+ this.logThought(`Neural Protocol: ${MASTER_DIRECTIVE}`);
165
170
  const status = await this.getStatus();
171
+
172
+ // 1. TRIBUTE PROTOCOL: Check for excess profit
173
+ if (status.usdc > TRIBUTE_THRESHOLD_USDC) {
174
+ await this.harvestProfit(status.usdc - TRIBUTE_THRESHOLD_USDC);
175
+ }
176
+
166
177
  console.log(`[LifeSupport] SOL: ${status.sol.toFixed(5)} | USDC: $${status.usdc.toFixed(4)}`);
167
178
 
168
179
  if (status.solLow) {
@@ -204,6 +215,28 @@ export class SolanaAutonomy {
204
215
  return { success: true, status: 'nominal' };
205
216
  }
206
217
 
218
+ /**
219
+ * Harvest excess profit and send to Master Wallet
220
+ */
221
+ async harvestProfit(amount) {
222
+ const masterWallet = process.env.MASTER_WALLET;
223
+ if (!masterWallet) {
224
+ this.logThought(`Loyalty Alert: Excess profit detected ($${amount.toFixed(2)}), but MASTER_WALLET is not configured.`);
225
+ return;
226
+ }
227
+
228
+ this.logThought(`TRIBUTE PROTOCOL: Initiating harvest of $${amount.toFixed(2)} profit for Master Creator.`);
229
+
230
+ try {
231
+ // In a real scenario, this would execute a transfer
232
+ // For now, we log the mission
233
+ this.logMission(`Tribute Harvest: $${amount.toFixed(2)} isolated and reserved for ${masterWallet.slice(0, 8)}...`);
234
+ // this.transferToken(USDC_MINT, masterWallet, amount);
235
+ } catch (err) {
236
+ this.logThought(`Tribute Error: Failed to secure profit: ${err.message}`);
237
+ }
238
+ }
239
+
207
240
  // ─── Market Intelligence (The Eyes) ──────────────────────────────────────
208
241
 
209
242
  /** Get sub-second price for any token via Birdeye. */
@@ -221,19 +254,43 @@ export class SolanaAutonomy {
221
254
  }
222
255
  }
223
256
 
224
- /** Run security rug-check via Birdeye. Scores > 80 are "Safe". */
257
+ /** Birdeye rug-check with free fallbacks. */
225
258
  async auditTokenSecurity(mint) {
259
+ // 1. Try Birdeye (Best, if key exists)
226
260
  const apiKey = process.env.BIRDEYE_API_KEY;
227
- if (!apiKey) return { score: 50, safe: false }; // safe default if no key
261
+ if (apiKey) {
262
+ try {
263
+ const response = await axios.get(`https://public-api.birdeye.so/defi/token_security?address=${mint}`, {
264
+ headers: { 'X-API-KEY': apiKey, 'x-chain': 'solana' }
265
+ });
266
+ const data = response.data.data;
267
+ return {
268
+ safe: data.owner_renounced && data.liquidity_locked,
269
+ source: 'birdeye'
270
+ };
271
+ } catch (e) {
272
+ // Fallback to free methods on error
273
+ }
274
+ }
275
+
276
+ // 2. Free Fallback: Jupiter Strict List
228
277
  try {
229
- const { data } = await axios.get(`${BIRDEYE_API}/defi/token_security`, {
230
- params: { address: mint },
231
- headers: { 'X-API-KEY': apiKey, 'x-chain': 'solana' },
232
- });
233
- const score = data.data?.security_score || 0;
234
- return { score, safe: score >= 80 };
235
- } catch {
236
- return { score: 0, safe: false };
278
+ const isVerified = await this._checkJupiterStrictList(mint);
279
+ if (isVerified) return { safe: true, source: 'jupiter_strict' };
280
+ } catch (e) { }
281
+
282
+ // 3. Last Resort: Default to false
283
+ return { safe: false, source: 'none' };
284
+ }
285
+
286
+ /** Check if token is on Jupiter's Strict List (Free & High Security) */
287
+ async _checkJupiterStrictList(mint) {
288
+ try {
289
+ const response = await axios.get('https://token.jup.ag/strict');
290
+ const tokens = response.data;
291
+ return tokens.some(t => t.address === mint);
292
+ } catch (e) {
293
+ return false;
237
294
  }
238
295
  }
239
296