├── data └── wallet.txt ├── config ├── gas.json └── chains.js ├── src ├── tokenApp.js ├── utils │ ├── displayHeader.js │ └── WalletManager.js ├── services │ ├── TokenDeployService.js │ └── TokenTransferService.js └── TokenCLI.js ├── hardhat.config.cjs ├── .gitignore ├── contracts └── Token.sol ├── package.json ├── LICENSE └── README.md /data/wallet.txt: -------------------------------------------------------------------------------- 1 | 0xxxxxxxxxxxxx 2 | 0xxxxxxxxxxxxx 3 | 0xxxxxxxxxxxxx -------------------------------------------------------------------------------- /config/gas.json: -------------------------------------------------------------------------------- 1 | { 2 | "deployment": { 3 | "gasLimit": "3000000", 4 | "gasPrice": "5" 5 | }, 6 | "transfer": { 7 | "gasLimit": "100000", 8 | "gasPrice": "5" 9 | } 10 | } -------------------------------------------------------------------------------- /src/tokenApp.js: -------------------------------------------------------------------------------- 1 | import TokenCLI from './TokenCLI.js'; 2 | 3 | const cli = new TokenCLI(); 4 | cli.run().catch(error => { 5 | console.error('Application error:', error.message); 6 | process.exit(1); 7 | }); -------------------------------------------------------------------------------- /hardhat.config.cjs: -------------------------------------------------------------------------------- 1 | require("@nomicfoundation/hardhat-toolbox"); 2 | 3 | /** @type import('hardhat/config').HardhatUserConfig */ 4 | module.exports = { 5 | solidity: { 6 | version: "0.8.20", 7 | settings: { 8 | optimizer: { 9 | enabled: true, 10 | runs: 200 11 | } 12 | } 13 | } 14 | }; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | node_modules/ 3 | 4 | # Environment variables 5 | .env 6 | .env.local 7 | .env.*.local 8 | 9 | # Sensitive data 10 | data/wallet.txt 11 | 12 | # Hardhat files 13 | cache/ 14 | artifacts/ 15 | 16 | # Logs 17 | npm-debug.log* 18 | yarn-debug.log* 19 | yarn-error.log* 20 | 21 | # IDE 22 | .vscode/ 23 | .idea/ 24 | 25 | # OS 26 | .DS_Store 27 | Thumbs.db 28 | 29 | # Build files 30 | dist/ 31 | build/ 32 | 33 | # Coverage directory 34 | coverage/ -------------------------------------------------------------------------------- /contracts/Token.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.20; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 5 | import "@openzeppelin/contracts/access/Ownable.sol"; 6 | 7 | contract Token is ERC20, Ownable { 8 | constructor( 9 | string memory name, 10 | string memory symbol, 11 | uint256 initialSupply, 12 | address initialOwner 13 | ) ERC20(name, symbol) Ownable(initialOwner) { 14 | _mint(initialOwner, initialSupply * 10 ** decimals()); 15 | } 16 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "winsnip-auto-deploy", 3 | "version": "1.0.0", 4 | "description": "Auto Deploy and Transfer Token System for EVM chains", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node src/tokenApp.js", 8 | "deploy": "hardhat run src/tokenApp.js", 9 | "compile": "hardhat compile", 10 | "test": "hardhat test", 11 | "dev": "nodemon src/tokenApp.js" 12 | }, 13 | "dependencies": { 14 | "@openzeppelin/contracts": "^5.2.0", 15 | "colors": "^1.4.0", 16 | "dotenv": "^16.3.1", 17 | "ethers": "^6.13.5", 18 | "figlet": "^1.8.0", 19 | "gradient-string": "^3.0.0", 20 | "commander": "^11.1.0" 21 | }, 22 | "type": "module", 23 | "license": "MIT", 24 | "author": "Winsnip", 25 | "devDependencies": { 26 | "@nomicfoundation/hardhat-toolbox": "^5.0.0", 27 | "hardhat": "^2.22.19", 28 | "nodemon": "^3.0.3" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/utils/displayHeader.js: -------------------------------------------------------------------------------- 1 | import colors from 'colors/safe.js'; 2 | 3 | function displayHeader() { 4 | process.stdout.write('\x1Bc'); 5 | 6 | console.log(` 7 | ${colors.rainbow('██╗ ██╗ ██╗ ███╗ ██╗ ███████╗ ███╗ ██╗ ██╗ ██████╗')} 8 | ${colors.cyan('██║ ██║ ██║ ████╗ ██║ ██╔════╝ ████╗ ██║ ██║ ██╔══██╗')} 9 | ${colors.green('██║ █╗ ██║ ██║ ██╔██╗ ██║ ███████╗ ██╔██╗ ██║ ██║ ██████╔╝')} 10 | ${colors.yellow('██║███╗██║ ██║ ██║╚██╗██║ ╚════██║ ██║╚██╗██║ ██║ ██╔═══╝')} 11 | ${colors.blue('╚███╔███╔╝ ██║ ██║ ╚████║ ███████║ ██║ ╚████║ ██║ ██║')} 12 | ${colors.red(' ╚══╝╚══╝ ╚═╝ ╚═╝ ╚═══╝ ╚══════╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝')} 13 | 14 | ${colors.bold('🔥 Join grup TG:')} ${colors.cyan.underline('@winsnip')} 15 | ${colors.bold('🔥 Auto Deploy and transfer Token')} 16 | `.split('\n').map(line => line.padStart(50)).join('\n')); 17 | } 18 | 19 | export default displayHeader; -------------------------------------------------------------------------------- /config/chains.js: -------------------------------------------------------------------------------- 1 | export const chains = [ 2 | { 3 | name: "BSC Testnet", 4 | rpcUrl: process.env.RPC_URL || "https://data-seed-prebsc-1-s1.binance.org:8545", 5 | chainId: "97", 6 | symbol: "tBNB", 7 | explorer: "https://testnet.bscscan.com", 8 | isMainnet: false 9 | }, 10 | { 11 | name: "Ethereum Mainnet", 12 | rpcUrl: "https://eth-mainnet.g.alchemy.com/v2/your-api-key", 13 | chainId: "1", 14 | symbol: "ETH", 15 | explorer: "https://etherscan.io", 16 | isMainnet: true 17 | }, 18 | { 19 | name: "0g Testnet", 20 | rpcUrl: "https://evmrpc-testnet.0g.ai", 21 | chainId: "16600", 22 | symbol: "0G", 23 | explorer: "https://chainscan-newton.0g.ai", 24 | isMainnet: false 25 | }, 26 | { 27 | name: "Tea Sepolia", 28 | rpcUrl: "https://tea-sepolia.g.alchemy.com/v2/vot1HrCuj9CmekoM2FKNnv6h4Mnzjyb_", 29 | chainId: "10218", 30 | symbol: "TEA", 31 | explorer: "https://sepolia.tea.xyz", 32 | isMainnet: false 33 | } 34 | ]; 35 | -------------------------------------------------------------------------------- /src/utils/WalletManager.js: -------------------------------------------------------------------------------- 1 | import { ethers } from 'ethers'; 2 | import { chains } from '../../config/chains.js'; 3 | 4 | class WalletManager { 5 | constructor(chain) { 6 | this.chain = chain; 7 | this.provider = null; 8 | this.wallet = null; 9 | } 10 | 11 | async initializeWallet(privateKey) { 12 | try { 13 | this.provider = new ethers.JsonRpcProvider(this.chain.rpcUrl); 14 | this.wallet = new ethers.Wallet(privateKey, this.provider); 15 | const balance = await this.provider.getBalance(this.wallet.address); 16 | console.log(`\n🔗 Connected to ${this.chain.name}`); 17 | console.log(`📍 Wallet Address: ${this.wallet.address}`); 18 | console.log(`💰 Balance: ${ethers.formatEther(balance)} ${this.chain.symbol}\n`); 19 | 20 | return this.wallet; 21 | } catch (error) { 22 | console.error('Failed to initialize wallet:', error.message); 23 | throw error; 24 | } 25 | } 26 | 27 | getProvider() { 28 | return this.provider; 29 | } 30 | 31 | getWallet() { 32 | return this.wallet; 33 | } 34 | } 35 | 36 | export default WalletManager; 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Winsnip 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Auto Deploy dan Transfer EVM 2 | 3 | Aplikasi untuk otomatisasi deploy dan transfer token di jaringan EVM (Ethereum Virtual Machine). 4 | 5 | ## Fitur 6 | 7 | - Deploy smart contract token 8 | - Transfer token ke multiple wallet 9 | - Manajemen wallet dan private key 10 | - Dukungan untuk berbagai chain EVM 11 | - Command line interface yang mudah digunakan 12 | 13 | ## Struktur Proyek 14 | 15 | ``` 16 | ├── config/ 17 | │ ├── chains.js 18 | │ ├── index.js 19 | │ └── gas.json 20 | ├── contracts/ 21 | │ └── Token.sol 22 | ├── data/ 23 | │ ├── deployments/ 24 | │ └── wallet.txt 25 | └── src/ 26 | ├── services/ 27 | │ ├── TokenDeployService.js 28 | │ └── TokenTransferService.js 29 | ├── utils/ 30 | │ ├── displayHeader.js 31 | │ └── walletmanager.js 32 | ├── tokenApp.js 33 | └── tokencli.js 34 | ``` 35 | 36 | ## Instalasi 37 | 38 | 1. Clone repository ini 39 | 2. Install dependencies: 40 | ```bash 41 | npm install && npx hardhat compile 42 | ``` 43 | 44 | ## Penggunaan 45 | 46 | 47 | ### RUN 48 | ```bash 49 | npm start 50 | ``` 51 | 52 | 53 | ## Konfigurasi 54 | 55 | 1. Nanti akan di minta Input PK saat sudah Run 56 | 2. Sesuaikan konfigurasi chain di `config/chains.js` 57 | 3. Atur parameter gas di `config/gas.json` 58 | 59 | ## Kontribusi 60 | 61 | Kontribusi selalu diterima. Silakan buat pull request untuk perbaikan atau penambahan fitur. 62 | 63 | ## License 64 | 65 | Proyek ini dilisensikan di bawah Lisensi MIT - lihat file [LICENSE](LICENSE) untuk detail. 66 | 67 | Copyright © 2025 Winsnip 68 | -------------------------------------------------------------------------------- /src/services/TokenDeployService.js: -------------------------------------------------------------------------------- 1 | import { ethers } from 'ethers'; 2 | import gasConfig from '../../config/gas.json' assert { type: 'json' }; 3 | 4 | class TokenDeployService { 5 | constructor(walletManager) { 6 | this.walletManager = walletManager; 7 | } 8 | 9 | async deployToken(name, symbol, initialSupply) { 10 | try { 11 | const fs = await import('fs'); 12 | const artifactPath = './artifacts/contracts/Token.sol/Token.json'; 13 | const artifact = JSON.parse(fs.readFileSync(artifactPath, 'utf8')); 14 | 15 | const factory = new ethers.ContractFactory( 16 | artifact.abi, 17 | artifact.bytecode, 18 | this.walletManager.wallet 19 | ); 20 | const deployGasLimit = process.env.TOKEN_DEPLOY_GAS_LIMIT || gasConfig.deployment.gasLimit; 21 | const gasPrice = process.env.TOKEN_GAS_PRICE || gasConfig.deployment.gasPrice; 22 | 23 | console.log('\n🚀 Deploying token with the following configuration:'); 24 | console.log(`Name: ${name}`); 25 | console.log(`Symbol: ${symbol}`); 26 | console.log(`Initial Supply: ${initialSupply}`); 27 | console.log(`Gas Limit: ${deployGasLimit}`); 28 | console.log(`Gas Price: ${gasPrice} gwei\n`); 29 | 30 | const deployTx = await factory.deploy( 31 | name, 32 | symbol, 33 | initialSupply, 34 | this.walletManager.wallet.address, 35 | { 36 | gasLimit: ethers.parseUnits(deployGasLimit, 'wei'), 37 | gasPrice: ethers.parseUnits(gasPrice, 'gwei') 38 | } 39 | ); 40 | 41 | console.log(`📝 Token deployment transaction sent: ${deployTx.deploymentTransaction().hash}`); 42 | console.log(`🔍 Explorer: ${this.walletManager.chain.explorer}/tx/${deployTx.deploymentTransaction().hash}`); 43 | 44 | const contract = await deployTx.waitForDeployment(); 45 | console.log(`✅ Token deployed at: ${await contract.getAddress()}`); 46 | const deploymentInfo = { 47 | name, 48 | symbol, 49 | initialSupply, 50 | contractAddress: await contract.getAddress(), 51 | deployerAddress: this.walletManager.wallet.address, 52 | deploymentTxHash: deployTx.deploymentTransaction().hash, 53 | chainId: this.walletManager.chain.chainId 54 | }; 55 | 56 | const deploymentPath = './data/deployments'; 57 | if (!fs.existsSync(deploymentPath)) { 58 | fs.mkdirSync(deploymentPath, { recursive: true }); 59 | } 60 | 61 | const filename = `${deploymentPath}/${symbol}_${Date.now()}.json`; 62 | fs.writeFileSync(filename, JSON.stringify(deploymentInfo, null, 2)); 63 | console.log(`\n💾 Deployment info saved to: ${filename}`); 64 | 65 | return contract; 66 | } catch (error) { 67 | console.error(`Token deployment error: ${error.message}`); 68 | throw error; 69 | } 70 | } 71 | } 72 | 73 | export default TokenDeployService; -------------------------------------------------------------------------------- /src/services/TokenTransferService.js: -------------------------------------------------------------------------------- 1 | import { ethers } from 'ethers'; 2 | import fs from 'fs'; 3 | import path from 'path'; 4 | 5 | class TokenTransferService { 6 | constructor(walletManager) { 7 | this.walletManager = walletManager; 8 | } 9 | 10 | async transferToken(contractAddress, toAddress, amount) { 11 | try { 12 | const artifactPath = './artifacts/contracts/Token.sol/Token.json'; 13 | const artifact = JSON.parse(fs.readFileSync(artifactPath, 'utf8')); 14 | 15 | const contract = new ethers.Contract( 16 | contractAddress, 17 | artifact.abi, 18 | this.walletManager.wallet 19 | ); 20 | 21 | const decimals = await contract.decimals(); 22 | const amountWithDecimals = ethers.parseUnits(amount.toString(), decimals); 23 | 24 | const balance = await contract.balanceOf(this.walletManager.wallet.address); 25 | if (balance < amountWithDecimals) { 26 | throw new Error(`Saldo token tidak mencukupi. Saldo saat ini: ${ethers.formatUnits(balance, decimals)}`); 27 | } 28 | 29 | const tx = await contract.transfer(toAddress, amountWithDecimals); 30 | console.log(`📤 Transaksi transfer token terkirim: ${tx.hash}`); 31 | console.log(`🔍 Explorer: ${this.walletManager.chain.explorer}/tx/${tx.hash}`); 32 | 33 | const receipt = await tx.wait(); 34 | console.log(`✅ Transfer token berhasil dikonfirmasi di block ${receipt.blockNumber}`); 35 | return receipt; 36 | } catch (error) { 37 | console.error(`Error transfer token: ${error.message}`); 38 | throw error; 39 | } 40 | } 41 | 42 | async transferFromWalletTxt(contractAddress, amount) { 43 | try { 44 | const walletPath = './data/wallet.txt'; 45 | if (!fs.existsSync(walletPath)) { 46 | throw new Error('File wallet.txt tidak ditemukan'); 47 | } 48 | 49 | const addresses = fs.readFileSync(walletPath, 'utf8') 50 | .split('\n') 51 | .map(line => line.trim()) 52 | .filter(line => line && line.length > 0); 53 | 54 | if (addresses.length === 0) { 55 | throw new Error('Tidak ada alamat wallet yang valid di wallet.txt'); 56 | } 57 | 58 | console.log(`\n🚀 Memulai transfer token ke ${addresses.length} alamat dari wallet.txt...\n`); 59 | 60 | for (const address of addresses) { 61 | if (!ethers.isAddress(address)) { 62 | console.log(`⚠️ Melewati alamat tidak valid: ${address}`); 63 | continue; 64 | } 65 | 66 | console.log(`💸 Mentransfer token ke ${address}...`); 67 | await this.transferToken(contractAddress, address, amount); 68 | console.log(`✅ Transfer selesai!\n`); 69 | } 70 | 71 | console.log('🎉 Semua transfer selesai!'); 72 | } catch (error) { 73 | console.error(`Error batch transfer: ${error.message}`); 74 | throw error; 75 | } 76 | } 77 | 78 | async transferToNewWallets(contractAddress, numberOfWallets, amount) { 79 | try { 80 | const wallets = []; 81 | console.log(`\n🚀 Membuat ${numberOfWallets} wallet baru dan mentransfer token...\n`); 82 | 83 | for (let i = 0; i < numberOfWallets; i++) { 84 | const newWallet = ethers.Wallet.createRandom(); 85 | wallets.push(newWallet); 86 | 87 | console.log(`💸 Mentransfer token ke wallet #${i + 1}: ${newWallet.address}`); 88 | await this.transferToken(contractAddress, newWallet.address, amount); 89 | console.log(`🔑 Private Key: ${newWallet.privateKey}\n`); 90 | } 91 | 92 | const walletInfo = wallets.map(wallet => ({ 93 | address: wallet.address, 94 | privateKey: wallet.privateKey 95 | })); 96 | 97 | const filename = `./data/generated_wallets_${Date.now()}.json`; 98 | fs.writeFileSync(filename, JSON.stringify(walletInfo, null, 2)); 99 | console.log(`💾 Informasi wallet baru disimpan di: ${filename}`); 100 | 101 | console.log('🎉 Semua transfer ke wallet baru selesai!'); 102 | return wallets; 103 | } catch (error) { 104 | console.error(`Error transfer ke wallet baru: ${error.message}`); 105 | throw error; 106 | } 107 | } 108 | } 109 | 110 | export default TokenTransferService; -------------------------------------------------------------------------------- /src/TokenCLI.js: -------------------------------------------------------------------------------- 1 | import readline from 'readline'; 2 | import displayHeader from './utils/displayHeader.js'; 3 | import { chains } from '../config/chains.js'; 4 | import WalletManager from './utils/WalletManager.js'; 5 | import TokenDeployService from './services/TokenDeployService.js'; 6 | import TokenTransferService from './services/TokenTransferService.js'; 7 | 8 | class TokenCLI { 9 | constructor() { 10 | this.rl = readline.createInterface({ 11 | input: process.stdin, 12 | output: process.stdout 13 | }); 14 | } 15 | 16 | async initialize() { 17 | await displayHeader(); 18 | } 19 | 20 | async question(query) { 21 | return new Promise((resolve) => { 22 | this.rl.question(query, (answer) => { 23 | resolve(answer); 24 | }); 25 | }); 26 | } 27 | 28 | async selectChain() { 29 | try { 30 | if (chains.length === 1) { 31 | console.log(`\n🌐 Menggunakan chain: ${chains[0].name}`); 32 | return chains[0]; 33 | } 34 | 35 | console.log('\n🌐 Chain yang tersedia:'); 36 | chains.forEach((chain, index) => { 37 | console.log(`${index + 1}. ${chain.name}`); 38 | }); 39 | 40 | const answer = await this.question('\nPilih chain (masukkan nomor): '); 41 | const selection = parseInt(answer) - 1; 42 | 43 | if (selection >= 0 && selection < chains.length) { 44 | console.log(`\n✅ Chain terpilih: ${chains[selection].name}`); 45 | return chains[selection]; 46 | } else { 47 | throw new Error('Pilihan chain tidak valid'); 48 | } 49 | } catch (error) { 50 | console.error('Error pemilihan chain:', error.message); 51 | process.exit(1); 52 | } 53 | } 54 | 55 | async getTokenDetails() { 56 | const name = await this.question('\nMasukkan nama token: '); 57 | const symbol = await this.question('Masukkan simbol token: '); 58 | const supply = await this.question('Masukkan jumlah supply awal: '); 59 | 60 | if (!name || !symbol || !supply || isNaN(supply) || parseFloat(supply) <= 0) { 61 | throw new Error('Detail token tidak valid'); 62 | } 63 | 64 | return { name, symbol, supply: parseFloat(supply) }; 65 | } 66 | 67 | async selectOperation() { 68 | console.log('\n📝 Pilih operasi yang akan dilakukan:'); 69 | console.log('1. Deploy token baru'); 70 | console.log('2. Transfer token ke alamat dari wallet.txt'); 71 | console.log('3. Transfer token ke wallet baru'); 72 | 73 | const answer = await this.question('\nPilih operasi (1-3): '); 74 | const selection = parseInt(answer); 75 | 76 | if (selection >= 1 && selection <= 3) { 77 | return selection; 78 | } else { 79 | throw new Error('Pilihan operasi tidak valid'); 80 | } 81 | } 82 | 83 | async getTransferDetails() { 84 | const contractAddress = await this.question('\nMasukkan alamat kontrak token: '); 85 | const amount = await this.question('Masukkan jumlah token yang akan ditransfer: '); 86 | 87 | if (!contractAddress || !amount || isNaN(amount) || parseFloat(amount) <= 0) { 88 | throw new Error('Detail transfer tidak valid'); 89 | } 90 | 91 | return { contractAddress, amount: parseFloat(amount) }; 92 | } 93 | 94 | async getNumberOfWallets() { 95 | const answer = await this.question('\nMasukkan jumlah wallet yang akan dibuat: '); 96 | const number = parseInt(answer); 97 | 98 | if (isNaN(number) || number <= 0) { 99 | throw new Error('Jumlah wallet tidak valid'); 100 | } 101 | 102 | return number; 103 | } 104 | 105 | async run() { 106 | try { 107 | await this.initialize(); 108 | const chain = await this.selectChain(); 109 | const walletManager = new WalletManager(chain); 110 | 111 | const privateKey = await this.question('\nMasukkan private key wallet: '); 112 | await walletManager.initializeWallet(privateKey); 113 | 114 | const operation = await this.selectOperation(); 115 | 116 | if (operation === 1) { 117 | 118 | const tokenDetails = await this.getTokenDetails(); 119 | const tokenDeployService = new TokenDeployService(walletManager); 120 | await tokenDeployService.deployToken( 121 | tokenDetails.name, 122 | tokenDetails.symbol, 123 | tokenDetails.supply 124 | ); 125 | } else { 126 | const transferDetails = await this.getTransferDetails(); 127 | const tokenTransferService = new TokenTransferService(walletManager); 128 | 129 | if (operation === 2) { 130 | await tokenTransferService.transferFromWalletTxt( 131 | transferDetails.contractAddress, 132 | transferDetails.amount 133 | ); 134 | } else { 135 | const numberOfWallets = await this.getNumberOfWallets(); 136 | await tokenTransferService.transferToNewWallets( 137 | transferDetails.contractAddress, 138 | numberOfWallets, 139 | transferDetails.amount 140 | ); 141 | } 142 | } 143 | 144 | this.rl.close(); 145 | } catch (error) { 146 | console.error('Error:', error.message); 147 | this.rl.close(); 148 | process.exit(1); 149 | } 150 | } 151 | } 152 | 153 | export default TokenCLI; 154 | --------------------------------------------------------------------------------