diff --git a/.env.injective.example b/.env.injective.example index 6aa02d5..8f6fc88 100644 --- a/.env.injective.example +++ b/.env.injective.example @@ -19,12 +19,12 @@ USE_SKIP="1" SKIP_URL="https://injective-1-api.skip.money" SKIP_BID_WALLET="inj17yqtnk08ly94lgz3fzagfu2twsws33z7sfsv46" SKIP_BID_RATE="0.1" #e.g. 20% of the profit is used as a bid to win the auction -TRY_WO_SKIP="0" # Try without skip if the next Validator is not using skip. Send a standard Tx through the Mempool. More Risk! 0 == false -TIMEOUT_FOR_DUR="100" # Timeout Duration for Addresses that send failed Arbitrage opportunities +TRY_WITHOUT_SKIP="0" # Try without skip if the next Validator is not using skip. Send a standard Tx through the Mempool. More Risk! 0 == false # Addresses to Blacklist. Needed against Spam Txs. # For more Info Discord Channel Developers/Bot-Support IGNORE_ADDRESSES='[""]' +TIMEOUT_DURATION="100" # Timeout Duration for Addresses in Blocks ## INJECTIVE SETTINGS BASE_DENOM="peggy0xdAC17F958D2ee523a2206206994597C13D831ec7" diff --git a/.env.juno.example b/.env.juno.example index be50ade..fd42da3 100644 --- a/.env.juno.example +++ b/.env.juno.example @@ -19,12 +19,13 @@ USE_SKIP= "1" SKIP_URL= "http://juno-1-api.skip.money" SKIP_BID_WALLET= "juno1qan7ffv9kqpp704ywevq26hw53997ppdkwzs74" SKIP_BID_RATE="0.31" #e.g. 31% of the profit is used as a bid to win the auction -TRY_WO_SKIP="0" # Try without skip if the next Validator is not using skip. Send a standard Tx through the Mempool. More Risk! 0 == false -TIMEOUT_FOR_DUR="100" # Timeout Duration for Addresses that send failed Arbitrage opportunities +TRY_WITHOUT_SKIP="0" # Try without skip if the next Validator is not using skip. Send a standard Tx through the Mempool. More Risk! 0 == false + # Addresses to Blacklist. Needed against Spam Txs. # For more Info Discord Channel Developers/Bot-Support IGNORE_ADDRESSES='[""]' +TIMEOUT_DURATION="100" # Timeout Duration for Addresses in Blocks ##JUNO SETTINGS BASE_DENOM="ujuno" # The asset denom to be used as base asset. This should be the denom of a Native Token only. diff --git a/.env.terra.example b/.env.terra.example index 3303d59..73f04f6 100644 --- a/.env.terra.example +++ b/.env.terra.example @@ -17,14 +17,14 @@ SIGN_OF_LIFE="30" #Sign of Life in Minutes. E.g. "30" ##SKIP SPECIFIC ENVIRONMENT VARIABLES FOR CURRENT CHAIN USE_SKIP = "1" SKIP_URL= "http://phoenix-1-api.skip.money" -SKIP_BID_WALLET= "terra1lgex5ks77r7f5u6k8y5l6j5q0uc3te8k7wsymk" +SKIP_BID_WALLET= "terra1kdx075ghexr2l6mx4mgn37deshu9fn59r9zq9v" SKIP_BID_RATE="0.1" #e.g. 10% of the profit is used as a bid to win the auction -TRY_WO_SKIP="0" # Try without skip if the next Validator is not using skip. Send a standard Tx through the Mempool. More Risk! 0 == false -TIMEOUT_FOR_DUR="100" # Timeout Duration for Addresses that send failed Arbitrage opportunities +TRY_WITHOUT_SKIP="0" # Try without skip if the next Validator is not using skip. Send a standard Tx through the Mempool. More Risk! 0 == false # Addresses to Blacklist. Needed against Spam Txs. # For more Info Discord Channel Developers/Bot-Support IGNORE_ADDRESSES='[""]' +TIMEOUT_DURATION="100" # Timeout Duration for Addresses in Blocks ##TERRA SETTINGS BASE_DENOM="uluna" diff --git a/src/core/chainOperator/chainoperator.ts b/src/core/chainOperator/chainoperator.ts index 5055890..3a22972 100644 --- a/src/core/chainOperator/chainoperator.ts +++ b/src/core/chainOperator/chainoperator.ts @@ -46,8 +46,13 @@ export class ChainOperator { async queryContractSmart(address: string, queryMsg: Record): Promise { try { return await this.client.queryContractSmart(address, queryMsg); - } catch (e) { + } catch (e: any) { + //custom error for initPools JunoSwapPoolState + if (e.message.includes("Query failed with (18):")) { + throw new Error(e.message); + } console.log(e); + await this.client.getNewClients(); await this.client.queryContractSmart(address, queryMsg); } } diff --git a/src/core/types/arbitrageloops/mempoolLoop.ts b/src/core/types/arbitrageloops/mempoolLoop.ts index 8f8652c..4e2285f 100644 --- a/src/core/types/arbitrageloops/mempoolLoop.ts +++ b/src/core/types/arbitrageloops/mempoolLoop.ts @@ -8,7 +8,7 @@ import { ChainOperator } from "../../chainOperator/chainoperator"; import { Logger } from "../../logging"; import { BotConfig } from "../base/botConfig"; import { LogType } from "../base/logging"; -import { decodeMempool, flushTxMemory, Mempool, MempoolTx } from "../base/mempool"; +import { decodeMempool, flushTxMemory, IgnoredAddresses, Mempool, MempoolTx } from "../base/mempool"; import { Path } from "../base/path"; import { applyMempoolMessagesOnPools, Pool } from "../base/pool"; /** @@ -20,7 +20,7 @@ export class MempoolLoop { pathlib: Array; //holds all known paths CDpaths: Map; //holds all cooldowned paths' identifiers chainOperator: ChainOperator; - ignoreAddresses: { [index: string]: { source: boolean; timeout_at: number; duration: number } }; + ignoreAddresses: IgnoredAddresses; botConfig: BotConfig; logger: Logger | undefined; // CACHE VALUES @@ -56,7 +56,7 @@ export class MempoolLoop { botConfig: BotConfig, logger: Logger | undefined, pathlib: Array, - ignoreAddresses: { [index: string]: { source: boolean; timeout_at: number; duration: number } }, + ignoreAddresses: IgnoredAddresses, ) { this.pools = pools; this.CDpaths = new Map(); @@ -95,35 +95,14 @@ export class MempoolLoop { this.totalBytes = +this.mempool.total_bytes; } - const mempooltxs: [Array, Array<{ sender: string; reciever: string }>] = decodeMempool( + const mempoolTxs: Array = decodeMempool( this.mempool, this.ignoreAddresses, + this.botConfig.timeoutDuration, + this.iterations, ); + // Checks if there is a SendMsg from a blacklisted Address, if so add the reciever to the timeouted addresses - mempooltxs[1].forEach((Element) => { - if (this.ignoreAddresses[Element.sender]) { - if ( - this.ignoreAddresses[Element.sender].source || - this.ignoreAddresses[Element.sender].timeout_at + - this.ignoreAddresses[Element.sender].duration <= - this.iterations - ) { - this.ignoreAddresses[Element.reciever] = { - source: false, - timeout_at: this.iterations, - duration: 100, - }; - this.ignoreAddresses[Element.sender].timeout_at = this.iterations; - } else if ( - this.ignoreAddresses[Element.sender].timeout_at + - this.ignoreAddresses[Element.sender].duration >= - this.iterations - ) { - delete this.ignoreAddresses[Element.sender]; - } - } - }); - const mempoolTxs: Array = mempooltxs[0]; if (mempoolTxs.length === 0) { continue; } else { @@ -228,12 +207,12 @@ export class MempoolLoop { /** * */ - public clear_ignoreAddresses() { + public clearIgnoreAddresses() { const keys = Object.keys(this.ignoreAddresses); for (let i = 0; i < keys.length; i++) { if ( - !this.ignoreAddresses[keys[i]].source && - this.ignoreAddresses[keys[i]].timeout_at + this.ignoreAddresses[keys[i]].duration <= this.iterations + this.ignoreAddresses[keys[i]].timeoutAt > 0 && + this.ignoreAddresses[keys[i]].timeoutAt + this.ignoreAddresses[keys[i]].duration <= this.iterations ) { delete this.ignoreAddresses[keys[i]]; } diff --git a/src/core/types/arbitrageloops/nomempoolLoop.ts b/src/core/types/arbitrageloops/nomempoolLoop.ts index dbb8fd3..777e3a4 100644 --- a/src/core/types/arbitrageloops/nomempoolLoop.ts +++ b/src/core/types/arbitrageloops/nomempoolLoop.ts @@ -154,7 +154,7 @@ export class NoMempoolLoop { /** * */ - public clear_ignoreAddresses() { + public clearIgnoreAddresses() { return; } } diff --git a/src/core/types/arbitrageloops/skipLoop.ts b/src/core/types/arbitrageloops/skipLoop.ts index 6c3d23d..3d74599 100644 --- a/src/core/types/arbitrageloops/skipLoop.ts +++ b/src/core/types/arbitrageloops/skipLoop.ts @@ -14,7 +14,7 @@ import { SkipResult } from "../../chainOperator/skipclients"; import { Logger } from "../../logging"; import { BotConfig } from "../base/botConfig"; import { LogType } from "../base/logging"; -import { decodeMempool, MempoolTx } from "../base/mempool"; +import { decodeMempool, IgnoredAddresses, MempoolTx } from "../base/mempool"; import { Path } from "../base/path"; import { applyMempoolMessagesOnPools, Pool } from "../base/pool"; import { MempoolLoop } from "./mempoolLoop"; @@ -47,7 +47,7 @@ export class SkipLoop extends MempoolLoop { logger: Logger | undefined, pathlib: Array, - ignoreAddresses: { [index: string]: { source: boolean; timeout_at: number; duration: number } }, + ignoreAddresses: IgnoredAddresses, ) { super( pools, @@ -88,36 +88,14 @@ export class SkipLoop extends MempoolLoop { this.totalBytes = +this.mempool.total_bytes; } - const mempoolTxs: [Array, Array<{ sender: string; reciever: string }>] = processMempool( + const mempoolTxs: Array = decodeMempool( this.mempool, this.ignoreAddresses, + this.botConfig.timeoutDuration, + this.iterations, ); - const mempoolTrades = mempoolTxs[0]; - mempoolTxs[1].forEach((Element) => { - if (this.ignoreAddresses[Element.sender]) { - if ( - this.ignoreAddresses[Element.sender].source || - this.ignoreAddresses[Element.sender].timeout_at + - this.ignoreAddresses[Element.sender].duration <= - this.iterations - ) { - this.ignoreAddresses[Element.reciever] = { - source: false, - timeout_at: this.iterations, - duration: this.botConfig.skipConfig!.timout_dur, - }; - this.ignoreAddresses[Element.sender].timeout_at = this.iterations; - } else if ( - this.ignoreAddresses[Element.sender].timeout_at + - this.ignoreAddresses[Element.sender].duration >= - this.iterations - ) { - delete this.ignoreAddresses[Element.sender]; - } - } - }); - if (mempoolTxs[0].length === 0) { + if (mempoolTxs.length === 0) { continue; } else { for (const mempoolTx of mempoolTxs) { @@ -150,9 +128,10 @@ export class SkipLoop extends MempoolLoop { return; } - const skiprate = Math.max(Math.round(arbTrade.profit * this.botConfig.skipConfig.skipBidRate), 651); + const skipFee = Math.max(Math.round(arbTrade.profit * this.botConfig.skipConfig.skipBidRate), 651); + const bidMsgEncoded = getSendMessage( - String(skiprate), + String(skipFee), this.botConfig.gasDenom, this.chainOperator.client.publicAddress, this.botConfig.skipConfig.skipBidWallet, @@ -184,13 +163,13 @@ export class SkipLoop extends MempoolLoop { let logItem = ""; let logMessage = `**wallet:** ${this.chainOperator.client.publicAddress}\t **block:** ${ res.result.desired_height - }\t **profit:** ${arbTrade.profit - skiprate}`; + }\t **profit:** ${arbTrade.profit - skipFee}`; if (res.result.code !== 0) { logMessage += `\t **error code:** ${res.result.code}\n**error:** ${res.result.error}\n`; } - if (res.result.code === 4) { - console.log("no skip validator up, trying default broadcast"); + if (this.botConfig.skipConfig.tryWithoutSkip && res.result.code === 4) { + await this.logger?.sendMessage("no skip validator up, trying default broadcast", LogType.Console); await this.trade(arbTrade); } @@ -203,9 +182,8 @@ export class SkipLoop extends MempoolLoop { logMessage = logMessage.concat(logMessageCheckTx); if (toArbTrade?.message.sender && idx == 0 && item["code"] == "5") { this.ignoreAddresses[toArbTrade.message.sender] = { - source: false, - timeout_at: this.iterations, - duration: this.botConfig.skipConfig!.timout_dur, + timeoutAt: this.iterations, + duration: this.botConfig.timeoutDuration, }; await this.logger?.sendMessage( "Error on Trade from Address: " + toArbTrade.message.sender, @@ -225,9 +203,8 @@ export class SkipLoop extends MempoolLoop { if (idx == 0 && (item["code"] == 10 || item["code"] == 5)) { if (toArbTrade?.message.sender) { this.ignoreAddresses[toArbTrade.message.sender] = { - source: false, - timeout_at: this.iterations, - duration: this.botConfig.skipConfig!.timout_dur, + timeoutAt: this.iterations, + duration: this.botConfig.timeoutDuration, }; await this.logger?.sendMessage( "Error on Trade from Address: " + toArbTrade.message.sender, @@ -248,11 +225,6 @@ export class SkipLoop extends MempoolLoop { if (res.result.code != 4) { this.cdPaths(arbTrade.path); } - - if (this.botConfig.skipConfig.trywithout && res.result.code === 4) { - await this.trade(arbTrade); - } - if (res.result.code === 0) { this.chainOperator.client.sequence = this.chainOperator.client.sequence + 1; } diff --git a/src/core/types/base/botConfig.ts b/src/core/types/base/botConfig.ts index 06d4817..56b0dbc 100644 --- a/src/core/types/base/botConfig.ts +++ b/src/core/types/base/botConfig.ts @@ -3,14 +3,14 @@ import axios from "axios"; import { assert } from "console"; import { NativeAssetInfo } from "./asset"; +import { IgnoredAddresses } from "./mempool"; interface SkipConfig { useSkip: boolean; skipRpcUrl: string; skipBidWallet: string; skipBidRate: number; - trywithout: boolean; - timout_dur: number; + tryWithoutSkip: boolean; } interface LoggerConfig { @@ -28,7 +28,7 @@ export interface BotConfig { grpcUrl: string; restUrl: string; useRpcUrlScraper: boolean; - ignoreAddresses: { [index: string]: { source: boolean; timeout_at: number; duration: number } }; + ignoreAddresses: IgnoredAddresses; poolEnvs: Array<{ pool: string; inputfee: number; outputfee: number; LPratio: number }>; maxPathPools: number; mappingFactoryRouter: Array<{ factory: string; router: string }>; @@ -37,6 +37,7 @@ export interface BotConfig { offerAssetInfo: NativeAssetInfo; mnemonic: string; useMempool: boolean; + timeoutDuration: number; baseDenom: string; gasDenom: string; signOfLife: number; @@ -89,12 +90,12 @@ export async function setBotConfig(envs: NodeJS.ProcessEnv): Promise const GAS_USAGE_PER_HOP = +envs.GAS_USAGE_PER_HOP; const MAX_PATH_HOPS = +envs.MAX_PATH_HOPS; //required gas units per trade (hop) - - const IGNORE_ADDRS: { [index: string]: { source: boolean; timeout_at: number; duration: number } } = {}; + const timeoutDuration = envs.TIMEOUT_DURATION === undefined ? 100 : Number(envs.TIMEOUT_DURATION); + const IGNORE_ADDRS: IgnoredAddresses = {}; // set ignored Addresses if (envs.IGNORE_ADDRESSES) { const addrs = JSON.parse(envs.IGNORE_ADDRESSES); - addrs.forEach((element: string) => (IGNORE_ADDRS[element] = { source: true, timeout_at: 0, duration: 1000 })); + addrs.forEach((element: string) => (IGNORE_ADDRS[element] = { timeoutAt: 0, duration: timeoutDuration })); } // setup skipconfig if present let skipConfig; @@ -105,8 +106,7 @@ export async function setBotConfig(envs: NodeJS.ProcessEnv): Promise skipRpcUrl: envs.SKIP_URL ?? "", skipBidWallet: envs.SKIP_BID_WALLET ?? "", skipBidRate: envs.SKIP_BID_RATE === undefined ? 0 : +envs.SKIP_BID_RATE, - trywithout: envs.TRY_WO_SKIP === undefined || envs.TRY_WO_SKIP === "0" ? false : true, - timout_dur: envs.TIMEOUT_FOR_DUR === undefined ? 100 : Number(envs.TIMEOUT_FOR_DUR), + tryWithoutSkip: envs.TRY_WITHOUT_SKIP === undefined || envs.TRY_WITHOUT_SKIP === "0" ? false : true, }; } @@ -163,6 +163,7 @@ export async function setBotConfig(envs: NodeJS.ProcessEnv): Promise gasPrice: envs.GAS_UNIT_PRICE, profitThresholds: PROFIT_THRESHOLDS, txFees: TX_FEES, + timeoutDuration: timeoutDuration, skipConfig: skipConfig, loggerConfig: loggerConfig, signOfLife: SIGN_OF_LIFE, diff --git a/src/core/types/base/mempool.ts b/src/core/types/base/mempool.ts index d0e7f9e..c783a9a 100644 --- a/src/core/types/base/mempool.ts +++ b/src/core/types/base/mempool.ts @@ -17,6 +17,10 @@ export interface MempoolTx { txBytes: Uint8Array; } +export interface IgnoredAddresses { + [index: string]: { timeoutAt: number; duration: number }; +} + let txMemory: { [key: string]: boolean } = {}; /** @@ -37,7 +41,12 @@ export function showTxMemory() { *@param mempool The mempool(state) to process. *@return An array of swap, send and swap-operation messages that exist in the `mempool`. */ -export function decodeMempool(mempool: Mempool, ignoreAddresses: Record): Array { +export function decodeMempool( + mempool: Mempool, + ignoreAddresses: IgnoredAddresses, + timeoutDur: number, + iteration: number, +): Array { const decodedMessages: Array = []; for (const tx of mempool.txs) { if (txMemory[tx] == true) { @@ -58,7 +67,7 @@ export function decodeMempool(mempool: Mempool, ignoreAddresses: Record): boolean { +function isAllowedMempoolMsg(msg: MsgExecuteContract, ignoreAddresses: IgnoredAddresses, iteration: number): boolean { //if the sender of the message is in our ignore list: skip this message if (ignoreAddresses[msg.sender]) { - return false; + return discardIgnored(msg.sender, undefined, ignoreAddresses, iteration); // if they use a contract to fund new wallets } else if (ignoreAddresses[msg.contract]) { const containedMsg = JSON.parse(fromUtf8(msg.msg)); - const gets = fromAscii(fromBase64(containedMsg.delegate.msg)); - ignoreAddresses[gets] = true; - return false; - } else { + if (containedMsg.delegate) { + const gets = fromAscii(fromBase64(containedMsg.delegate.msg)); + return discardIgnored(msg.sender, gets, ignoreAddresses, iteration); + } + } + return true; +} +/** + * + */ +function discardIgnored( + address: string, + reciever: string | undefined, + ignoreAddresses: IgnoredAddresses, + iteration: number, +) { + if ( + ignoreAddresses[address].timeoutAt === 0 || + ignoreAddresses[address].timeoutAt + ignoreAddresses[address].duration <= iteration + ) { + if (reciever) { + ignoreAddresses[reciever] = { + timeoutAt: iteration, + duration: ignoreAddresses[address].duration, + }; + } + ignoreAddresses[address].timeoutAt = iteration; + } else if (ignoreAddresses[address].timeoutAt + ignoreAddresses[address].duration >= iteration) { + delete ignoreAddresses[address]; return true; } + return false; } diff --git a/src/core/types/modules.d.ts b/src/core/types/modules.d.ts index 8f39929..a6f77ed 100644 --- a/src/core/types/modules.d.ts +++ b/src/core/types/modules.d.ts @@ -130,5 +130,17 @@ declare namespace NodeJS { * The ratio of the profit to send as a bid. */ SKIP_BID_RATE: string | undefined; + /** + * Try sending a regular TX if the next validator is not using Skip. + */ + TRY_WITHOUT_SKIP: string | undefined; + /** + * Addresses of Transaction-Spammer that should be ignored. + */ + IGNORE_ADDRESSES: string | undefined; + /** + * Timeout added addresses for this amount of blocks. + */ + TIMEOUT_DURATION: string | undefined; } } diff --git a/src/index.ts b/src/index.ts index a6badde..430a329 100644 --- a/src/index.ts +++ b/src/index.ts @@ -146,7 +146,7 @@ Total Paths:** \t${paths.length}\n`; const message = `**chain:** ${chainOperator.client.chainId} **wallet:** **status:** running for ${ loop.iterations } blocks or ${hours === 0 ? "" : hours + " Hour(s) and "}${mins} Minutes`; - loop.clear_ignoreAddresses(); + loop.clearIgnoreAddresses(); //switching RPCS every 6 Hrs if (mins == 0 && hours === 6 && botConfig.rpcUrls.length > 1) { await chainOperator.client.getNewClients();