mirror of
https://github.com/mortdeus/legacy-cc.git
synced 2026-10-10 12:52:27 +00:00
init
This commit is contained in:
1
#_sniper (Rust) using jito Shred stream/.dockerignore
Normal file
1
#_sniper (Rust) using jito Shred stream/.dockerignore
Normal file
@@ -0,0 +1 @@
|
||||
**/target
|
||||
80
#_sniper (Rust) using jito Shred stream/Cargo.toml
Normal file
80
#_sniper (Rust) using jito Shred stream/Cargo.toml
Normal file
@@ -0,0 +1,80 @@
|
||||
[package]
|
||||
name = "grpc-raydium-pool-monitoring-rust"
|
||||
version = "3.0.0"
|
||||
authors = ["Mephisto"]
|
||||
edition = "2021"
|
||||
license = "Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.62"
|
||||
backoff = { version = "0.4.0", features = ["tokio"] }
|
||||
bincode = "1.3.3"
|
||||
borsh = { version = "1.5.3" }
|
||||
bs58 = "0.5.1"
|
||||
chrono = "0.4.39"
|
||||
clap = { version = "4.3.0", features = ["derive"] }
|
||||
env_logger = "0.11.3"
|
||||
futures = "0.3.24"
|
||||
hex = "0.4.3"
|
||||
log = "0.4.17"
|
||||
maplit = "1.0.2"
|
||||
serde_json = "1.0.135"
|
||||
solana-sdk = "2.1.7"
|
||||
solana-entry = "=2.1.7"
|
||||
|
||||
solana-transaction-status = "2.1.7"
|
||||
solana-program = "2.1.7"
|
||||
solana-account-decoder-client-types = "2.1.7"
|
||||
tokio = { version = "1.21.2", features = ["full", "rt-multi-thread", "fs"] }
|
||||
openssl = { version = "0.10", features = ["vendored"] }
|
||||
reqwest = { version = "0.11.27", features = ["json", "socks", "native-tls", "blocking"] }
|
||||
tonic = "0.12.1"
|
||||
yellowstone-grpc-client = "4.0.0"
|
||||
yellowstone-grpc-proto = { version = "4.0.0", default-features = false ,features = ["plugin"] }
|
||||
yellowstone-vixen-core = { git = "https://github.com/rpcpool/yellowstone-vixen" }
|
||||
yellowstone-vixen-parser = { git = "https://github.com/rpcpool/yellowstone-vixen", features = ["raydium"] }
|
||||
indicatif = "0.17.9"
|
||||
pump_interface = { path = "./parsers/pump_interface", features = ["serde"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_with = "3.0"
|
||||
postgres = "0.19"
|
||||
solana-client = "2.1.7"
|
||||
spl-associated-token-account = { version = "4.0.0", features = ["no-entrypoint"] }
|
||||
|
||||
dotenv = "0.15"
|
||||
lazy_static = "1.5.0"
|
||||
shared_state = { path = "./shared_state" }
|
||||
sdk = "0.1.0"
|
||||
once_cell = "1.21.3"
|
||||
uuid = { version = "1", features = ["v4"] }
|
||||
|
||||
solana-account-decoder = "=2.1.7"
|
||||
spl-token = { version = "7.0.0", features = ["no-entrypoint"] }
|
||||
spl-token-2022 = { version = "7.0.0", features = ["no-entrypoint"] }
|
||||
spl-token-client = "=0.14.0"
|
||||
|
||||
jito-json-rpc-client = { path = "./json-rpc-client", package = "jito-block-engine-json-rpc-client" }
|
||||
anchor-lang = "=0.31.0"
|
||||
bytemuck = "1.21.0"
|
||||
rand = "0.8.5"
|
||||
tracing = "0.1.40"
|
||||
futures-util = "0.3.30"
|
||||
tokio-tungstenite = { version = "0.26.1", features = ["native-tls"] }
|
||||
tokio-stream = "0.1.17"
|
||||
borsh-derive = "1.5.3"
|
||||
solana-transaction-status-client-types = "=2.1.7"
|
||||
url = "2.3.1"
|
||||
base64 = "0.22.1"
|
||||
jito-protos = { path = "/home/ubuntu/shreds_sniper/shredstream-proxy/jito_protos" }
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"json-rpc-client",
|
||||
"shared_state",
|
||||
]
|
||||
|
||||
|
||||
|
||||
[build-dependencies]
|
||||
tonic-build = "0.10"
|
||||
protobuf-src = "1.0"
|
||||
29
#_sniper (Rust) using jito Shred stream/docker-compose.yml
Normal file
29
#_sniper (Rust) using jito Shred stream/docker-compose.yml
Normal file
@@ -0,0 +1,29 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
rustapp:
|
||||
container_name: rustapp
|
||||
image: francescoxx/rustapp:1.0.0
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
DATABASE_URL: postgres://postgres:postgres@db:5432/postgres
|
||||
ports:
|
||||
- '8080:8080'
|
||||
depends_on:
|
||||
- db
|
||||
db:
|
||||
container_name: db
|
||||
image: postgres:12
|
||||
environment:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_DB: postgres
|
||||
ports:
|
||||
- '5432:5432'
|
||||
volumes:
|
||||
- pgdata:/var/lib/postgresql/data
|
||||
|
||||
volumes:
|
||||
pgdata: {}
|
||||
1934
#_sniper (Rust) using jito Shred stream/idls/pump_0.1.0.json
Normal file
1934
#_sniper (Rust) using jito Shred stream/idls/pump_0.1.0.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,845 @@
|
||||
{
|
||||
"version": "3.3.0",
|
||||
"name": "spl_token",
|
||||
"instructions": [
|
||||
{
|
||||
"name": "initializeMint",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "mint",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "rent",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "decimals",
|
||||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "mintAuthority",
|
||||
"type": "publicKey"
|
||||
},
|
||||
{
|
||||
"name": "freezeAuthority",
|
||||
"type": {
|
||||
"option": "publicKey"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "initializeAccount",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "account",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "mint",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "rent",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
}
|
||||
],
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"name": "initializeMultisig",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "multisig",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "rent",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "m",
|
||||
"type": "u8"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "transfer",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "source",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "destination",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "authority",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "amount",
|
||||
"type": "u64"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "approve",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "source",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "delegate",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "amount",
|
||||
"type": "u64"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "revoke",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "source",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
}
|
||||
],
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"name": "setAuthority",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "owned",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
},
|
||||
{
|
||||
"name": "signer",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "authorityType",
|
||||
"type": {
|
||||
"defined": "AuthorityType"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "newAuthority",
|
||||
"type": {
|
||||
"option": "publicKey"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "mintTo",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "mint",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "account",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "amount",
|
||||
"type": "u64"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "burn",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "account",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "mint",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "authority",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "amount",
|
||||
"type": "u64"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "closeAccount",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "account",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "destination",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
}
|
||||
],
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"name": "freezeAccount",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "account",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "mint",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
}
|
||||
],
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"name": "thawAccount",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "account",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "mint",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
}
|
||||
],
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"name": "transferChecked",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "source",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "mint",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "destination",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "authority",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "amount",
|
||||
"type": "u64"
|
||||
},
|
||||
{
|
||||
"name": "decimals",
|
||||
"type": "u8"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "approveChecked",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "source",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "mint",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "delegate",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "amount",
|
||||
"type": "u64"
|
||||
},
|
||||
{
|
||||
"name": "decimals",
|
||||
"type": "u8"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "mintToChecked",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "mint",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "account",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "amount",
|
||||
"type": "u64"
|
||||
},
|
||||
{
|
||||
"name": "decimals",
|
||||
"type": "u8"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "burnChecked",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "account",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "mint",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "authority",
|
||||
"isMut": false,
|
||||
"isSigner": true
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "amount",
|
||||
"type": "u64"
|
||||
},
|
||||
{
|
||||
"name": "decimals",
|
||||
"type": "u8"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "initializeAccount2",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "account",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "mint",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "rent",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "owner",
|
||||
"type": "publicKey"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "syncNative",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "account",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
}
|
||||
],
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"name": "initializeAccount3",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "account",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "mint",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "owner",
|
||||
"type": "publicKey"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "initializeMultisig2",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "multisig",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
},
|
||||
{
|
||||
"name": "signer",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "m",
|
||||
"type": "u8"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "initializeMint2",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "mint",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "decimals",
|
||||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "mintAuthority",
|
||||
"type": "publicKey"
|
||||
},
|
||||
{
|
||||
"name": "freezeAuthority",
|
||||
"type": {
|
||||
"option": "publicKey"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "getAccountDataSize",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "mint",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
}
|
||||
],
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"name": "initializeImmutableOwner",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "account",
|
||||
"isMut": true,
|
||||
"isSigner": false
|
||||
}
|
||||
],
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"name": "amountToUiAmount",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "mint",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "amount",
|
||||
"type": "u64"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "uiAmountToAmount",
|
||||
"accounts": [
|
||||
{
|
||||
"name": "mint",
|
||||
"isMut": false,
|
||||
"isSigner": false
|
||||
}
|
||||
],
|
||||
"args": [
|
||||
{
|
||||
"name": "uiAmount",
|
||||
"type": "u64"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"accounts": [
|
||||
{
|
||||
"name": "Mint",
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{
|
||||
"name": "mintAuthority",
|
||||
"type": {
|
||||
"option": "publicKey"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "supply",
|
||||
"type": "u64"
|
||||
},
|
||||
{
|
||||
"name": "decimals",
|
||||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "isInitialized",
|
||||
"type": "bool"
|
||||
},
|
||||
{
|
||||
"name": "freezeAuthority",
|
||||
"type": {
|
||||
"option": "publicKey"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Account",
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{
|
||||
"name": "mint",
|
||||
"type": "publicKey"
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"type": "publicKey"
|
||||
},
|
||||
{
|
||||
"name": "amount",
|
||||
"type": "u64"
|
||||
},
|
||||
{
|
||||
"name": "delegate",
|
||||
"type": {
|
||||
"option": "publicKey"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "state",
|
||||
"type": {
|
||||
"defined": "AccountState"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "isNative",
|
||||
"type": {
|
||||
"option": "u64"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "delegatedAmount",
|
||||
"type": "u64"
|
||||
},
|
||||
{
|
||||
"name": "closeAuthority",
|
||||
"type": {
|
||||
"option": "publicKey"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Multisig",
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
"fields": [
|
||||
{
|
||||
"name": "m",
|
||||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "n",
|
||||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "isInitialized",
|
||||
"type": "bool"
|
||||
},
|
||||
{
|
||||
"name": "signers",
|
||||
"type": {
|
||||
"array": [
|
||||
"publicKey",
|
||||
11
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"types": [
|
||||
{
|
||||
"name": "AccountState",
|
||||
"type": {
|
||||
"kind": "enum",
|
||||
"variants": [
|
||||
{
|
||||
"name": "Uninitialized"
|
||||
},
|
||||
{
|
||||
"name": "Initialized"
|
||||
},
|
||||
{
|
||||
"name": "Frozen"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "AuthorityType",
|
||||
"type": {
|
||||
"kind": "enum",
|
||||
"variants": [
|
||||
{
|
||||
"name": "MintTokens"
|
||||
},
|
||||
{
|
||||
"name": "FreezeAccount"
|
||||
},
|
||||
{
|
||||
"name": "AccountOwner"
|
||||
},
|
||||
{
|
||||
"name": "CloseAccount"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"errors": [
|
||||
{
|
||||
"code": 0,
|
||||
"name": "NotRentExempt",
|
||||
"msg": "Lamport balance below rent-exempt threshold"
|
||||
},
|
||||
{
|
||||
"code": 1,
|
||||
"name": "InsufficientFunds",
|
||||
"msg": "Insufficient funds"
|
||||
},
|
||||
{
|
||||
"code": 2,
|
||||
"name": "InvalidMint",
|
||||
"msg": "Invalid Mint"
|
||||
},
|
||||
{
|
||||
"code": 3,
|
||||
"name": "MintMismatch",
|
||||
"msg": "Account not associated with this Mint"
|
||||
},
|
||||
{
|
||||
"code": 4,
|
||||
"name": "OwnerMismatch",
|
||||
"msg": "Owner does not match"
|
||||
},
|
||||
{
|
||||
"code": 5,
|
||||
"name": "FixedSupply",
|
||||
"msg": "Fixed supply"
|
||||
},
|
||||
{
|
||||
"code": 6,
|
||||
"name": "AlreadyInUse",
|
||||
"msg": "Already in use"
|
||||
},
|
||||
{
|
||||
"code": 7,
|
||||
"name": "InvalidNumberOfProvidedSigners",
|
||||
"msg": "Invalid number of provided signers"
|
||||
},
|
||||
{
|
||||
"code": 8,
|
||||
"name": "InvalidNumberOfRequiredSigners",
|
||||
"msg": "Invalid number of required signers"
|
||||
},
|
||||
{
|
||||
"code": 9,
|
||||
"name": "UninitializedState",
|
||||
"msg": "State is unititialized"
|
||||
},
|
||||
{
|
||||
"code": 10,
|
||||
"name": "NativeNotSupported",
|
||||
"msg": "Instruction does not support native tokens"
|
||||
},
|
||||
{
|
||||
"code": 11,
|
||||
"name": "NonNativeHasBalance",
|
||||
"msg": "Non-native account can only be closed if its balance is zero"
|
||||
},
|
||||
{
|
||||
"code": 12,
|
||||
"name": "InvalidInstruction",
|
||||
"msg": "Invalid instruction"
|
||||
},
|
||||
{
|
||||
"code": 13,
|
||||
"name": "InvalidState",
|
||||
"msg": "State is invalid for requested operation"
|
||||
},
|
||||
{
|
||||
"code": 14,
|
||||
"name": "Overflow",
|
||||
"msg": "Operation overflowed"
|
||||
},
|
||||
{
|
||||
"code": 15,
|
||||
"name": "AuthorityTypeNotSupported",
|
||||
"msg": "Account does not support specified authority type"
|
||||
},
|
||||
{
|
||||
"code": 16,
|
||||
"name": "MintCannotFreeze",
|
||||
"msg": "This token mint cannot freeze accounts"
|
||||
},
|
||||
{
|
||||
"code": 17,
|
||||
"name": "AccountFrozen",
|
||||
"msg": "Account is frozen"
|
||||
},
|
||||
{
|
||||
"code": 18,
|
||||
"name": "MintDecimalsMismatch",
|
||||
"msg": "The provided decimals value different from the Mint decimals"
|
||||
},
|
||||
{
|
||||
"code": 19,
|
||||
"name": "NonNativeNotSupported",
|
||||
"msg": "Instruction does not support non-native tokens"
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
|
||||
}
|
||||
}
|
||||
3286
#_sniper (Rust) using jito Shred stream/idls/whirlpool_idl.json
Normal file
3286
#_sniper (Rust) using jito Shred stream/idls/whirlpool_idl.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,25 @@
|
||||
[package]
|
||||
name = "jito-block-engine-json-rpc-client"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
description = "A sample rpc client to generate and send requests to jito block engine server"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1.68"
|
||||
bincode = "1.3.3"
|
||||
log = "0.4.17"
|
||||
reqwest = { version = "0.11", features = ["json"] }
|
||||
serde = { version = "1.0.189", features = ["derive"] }
|
||||
serde_json = "1.0.107"
|
||||
solana-rpc-client = "=2.1.7"
|
||||
solana-rpc-client-api = "=2.1.7"
|
||||
solana-sdk = "=2.1.7"
|
||||
solana-transaction-status = "=2.1.7"
|
||||
thiserror = "1.0.40"
|
||||
tokio = { version = "1", features = ["rt-multi-thread"] }
|
||||
|
||||
[dev-dependencies]
|
||||
solana-program = "=2.1.7"
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# json-rpc-client
|
||||
|
||||
This repository contains code to communicate with Jito's Block-Engine.
|
||||
@@ -0,0 +1,5 @@
|
||||
edition = "2021" # required by rust-analyzer
|
||||
imports_granularity="Crate"
|
||||
format_code_in_doc_comments = true
|
||||
error_on_unformatted = true
|
||||
group_imports = "StdExternalCrate"
|
||||
@@ -0,0 +1,125 @@
|
||||
pub use reqwest;
|
||||
use solana_rpc_client_api::{client_error::ErrorKind, request};
|
||||
use solana_sdk::{
|
||||
signature::SignerError, transaction::TransactionError, transport::TransportError,
|
||||
};
|
||||
use thiserror::Error as ThisError;
|
||||
|
||||
use crate::jsonrpc_client::request::RpcRequest;
|
||||
|
||||
#[derive(ThisError, Debug)]
|
||||
#[error("{kind}")]
|
||||
pub struct Error {
|
||||
pub request: Option<RpcRequest>,
|
||||
|
||||
#[source]
|
||||
pub kind: ErrorKind,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub fn new_with_request(kind: ErrorKind, request: RpcRequest) -> Self {
|
||||
Self {
|
||||
request: Some(request),
|
||||
kind,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_with_request(self, request: RpcRequest) -> Self {
|
||||
Self {
|
||||
request: Some(request),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub fn request(&self) -> Option<&RpcRequest> {
|
||||
self.request.as_ref()
|
||||
}
|
||||
|
||||
pub fn kind(&self) -> &ErrorKind {
|
||||
&self.kind
|
||||
}
|
||||
|
||||
pub fn get_transaction_error(&self) -> Option<TransactionError> {
|
||||
self.kind.get_transaction_error()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ErrorKind> for Error {
|
||||
fn from(kind: ErrorKind) -> Self {
|
||||
Self {
|
||||
request: None,
|
||||
kind,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TransportError> for Error {
|
||||
fn from(err: TransportError) -> Self {
|
||||
Self {
|
||||
request: None,
|
||||
kind: err.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Error> for TransportError {
|
||||
fn from(client_error: Error) -> Self {
|
||||
client_error.kind.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for Error {
|
||||
fn from(err: std::io::Error) -> Self {
|
||||
Self {
|
||||
request: None,
|
||||
kind: err.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<reqwest::Error> for Error {
|
||||
fn from(err: reqwest::Error) -> Self {
|
||||
Self {
|
||||
request: None,
|
||||
kind: err.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<request::RpcError> for Error {
|
||||
fn from(err: request::RpcError) -> Self {
|
||||
Self {
|
||||
request: None,
|
||||
kind: err.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<serde_json::error::Error> for Error {
|
||||
fn from(err: serde_json::error::Error) -> Self {
|
||||
Self {
|
||||
request: None,
|
||||
kind: err.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SignerError> for Error {
|
||||
fn from(err: SignerError) -> Self {
|
||||
Self {
|
||||
request: None,
|
||||
kind: err.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TransactionError> for Error {
|
||||
fn from(err: TransactionError) -> Self {
|
||||
Self {
|
||||
request: None,
|
||||
kind: err.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
@@ -0,0 +1,218 @@
|
||||
use std::{
|
||||
sync::{
|
||||
atomic::{AtomicU64, Ordering},
|
||||
Arc, RwLock,
|
||||
},
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use log::debug;
|
||||
use reqwest::{
|
||||
self,
|
||||
header::{CONTENT_TYPE, RETRY_AFTER},
|
||||
StatusCode,
|
||||
};
|
||||
use solana_rpc_client_api::{
|
||||
custom_error,
|
||||
error_object::RpcErrorObject,
|
||||
request::{RpcError, RpcResponseErrorData},
|
||||
response::RpcSimulateTransactionResult,
|
||||
};
|
||||
use tokio::time::sleep;
|
||||
|
||||
use crate::jsonrpc_client::{client_error::Result, request::RpcRequest, rpc_sender::RpcSender};
|
||||
|
||||
pub struct HttpSender {
|
||||
client: Arc<reqwest::Client>,
|
||||
url: String,
|
||||
request_id: AtomicU64,
|
||||
stats: RwLock<solana_rpc_client::rpc_sender::RpcTransportStats>,
|
||||
}
|
||||
|
||||
/// Nonblocking [`RpcSender`] over HTTP.
|
||||
impl HttpSender {
|
||||
/// Create an HTTP RPC sender.
|
||||
///
|
||||
/// The URL is an HTTP URL, usually for port 8899, as in
|
||||
/// "http://localhost:8899". The sender has a default timeout of 30 seconds.
|
||||
pub fn new<U: ToString>(url: U) -> Self {
|
||||
Self::new_with_timeout(url, Duration::from_secs(30))
|
||||
}
|
||||
|
||||
/// Create an HTTP RPC sender.
|
||||
///
|
||||
/// The URL is an HTTP URL, usually for port 8899.
|
||||
pub fn new_with_timeout<U: ToString>(url: U, timeout: Duration) -> Self {
|
||||
let client = Arc::new(
|
||||
reqwest::Client::builder()
|
||||
.timeout(timeout)
|
||||
.pool_idle_timeout(timeout)
|
||||
.build()
|
||||
.expect("build rpc client"),
|
||||
);
|
||||
|
||||
Self {
|
||||
client,
|
||||
url: url.to_string(),
|
||||
request_id: AtomicU64::new(0),
|
||||
stats: RwLock::new(solana_rpc_client::rpc_sender::RpcTransportStats::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct StatsUpdater<'a> {
|
||||
stats: &'a RwLock<solana_rpc_client::rpc_sender::RpcTransportStats>,
|
||||
request_start_time: Instant,
|
||||
rate_limited_time: Duration,
|
||||
}
|
||||
|
||||
impl<'a> StatsUpdater<'a> {
|
||||
fn new(stats: &'a RwLock<solana_rpc_client::rpc_sender::RpcTransportStats>) -> Self {
|
||||
Self {
|
||||
stats,
|
||||
request_start_time: Instant::now(),
|
||||
rate_limited_time: Duration::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_rate_limited_time(&mut self, duration: Duration) {
|
||||
self.rate_limited_time += duration;
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for StatsUpdater<'_> {
|
||||
fn drop(&mut self) {
|
||||
let mut stats = self.stats.write().unwrap();
|
||||
stats.request_count += 1;
|
||||
stats.elapsed_time += Instant::now().duration_since(self.request_start_time);
|
||||
stats.rate_limited_time += self.rate_limited_time;
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl RpcSender for HttpSender {
|
||||
fn get_transport_stats(&self) -> solana_rpc_client::rpc_sender::RpcTransportStats {
|
||||
self.stats.read().unwrap().clone()
|
||||
}
|
||||
|
||||
async fn send(
|
||||
&self,
|
||||
request: RpcRequest,
|
||||
params: serde_json::Value,
|
||||
) -> Result<serde_json::Value> {
|
||||
let mut stats_updater = StatsUpdater::new(&self.stats);
|
||||
|
||||
let request_id = self.request_id.fetch_add(1, Ordering::Relaxed);
|
||||
let request_json = request.build_request_json(request_id, params).to_string();
|
||||
|
||||
let mut too_many_requests_retries = 5;
|
||||
loop {
|
||||
let response = {
|
||||
let client = self.client.clone();
|
||||
let request_json = request_json.clone();
|
||||
client
|
||||
.post(&self.url)
|
||||
.header(CONTENT_TYPE, "application/json")
|
||||
.body(request_json)
|
||||
.send()
|
||||
.await
|
||||
}?;
|
||||
|
||||
if !response.status().is_success() {
|
||||
if response.status() == StatusCode::TOO_MANY_REQUESTS
|
||||
&& too_many_requests_retries > 0
|
||||
{
|
||||
let mut duration = Duration::from_millis(500);
|
||||
if let Some(retry_after) = response.headers().get(RETRY_AFTER) {
|
||||
if let Ok(retry_after) = retry_after.to_str() {
|
||||
if let Ok(retry_after) = retry_after.parse::<u64>() {
|
||||
if retry_after < 120 {
|
||||
duration = Duration::from_secs(retry_after);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
too_many_requests_retries -= 1;
|
||||
debug!(
|
||||
"Too many requests: server responded with {:?}, {} retries left, pausing for {:?}",
|
||||
response, too_many_requests_retries, duration
|
||||
);
|
||||
|
||||
sleep(duration).await;
|
||||
stats_updater.add_rate_limited_time(duration);
|
||||
continue;
|
||||
}
|
||||
return Err(response.error_for_status().unwrap_err().into());
|
||||
}
|
||||
|
||||
let mut json = response.json::<serde_json::Value>().await?;
|
||||
if json["error"].is_object() {
|
||||
return match serde_json::from_value::<RpcErrorObject>(json["error"].clone()) {
|
||||
Ok(rpc_error_object) => {
|
||||
let data = match rpc_error_object.code {
|
||||
solana_rpc_client_api::custom_error::JSON_RPC_SERVER_ERROR_SEND_TRANSACTION_PREFLIGHT_FAILURE => {
|
||||
match serde_json::from_value::<RpcSimulateTransactionResult>(json["error"]["data"].clone()) {
|
||||
Ok(data) => RpcResponseErrorData::SendTransactionPreflightFailure(data),
|
||||
Err(err) => {
|
||||
debug!("Failed to deserialize RpcSimulateTransactionResult: {:?}", err);
|
||||
RpcResponseErrorData::Empty
|
||||
}
|
||||
}
|
||||
},
|
||||
custom_error::JSON_RPC_SERVER_ERROR_NODE_UNHEALTHY => {
|
||||
match serde_json::from_value::<custom_error::NodeUnhealthyErrorData>(json["error"]["data"].clone()) {
|
||||
Ok(custom_error::NodeUnhealthyErrorData {num_slots_behind}) => RpcResponseErrorData::NodeUnhealthy {num_slots_behind},
|
||||
Err(_err) => {
|
||||
RpcResponseErrorData::Empty
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => RpcResponseErrorData::Empty
|
||||
};
|
||||
|
||||
Err(RpcError::RpcResponseError {
|
||||
code: rpc_error_object.code,
|
||||
message: rpc_error_object.message,
|
||||
data,
|
||||
}
|
||||
.into())
|
||||
}
|
||||
Err(err) => Err(RpcError::RpcRequestError(format!(
|
||||
"Failed to deserialize RPC error response: {} [{}]",
|
||||
serde_json::to_string(&json["error"]).unwrap(),
|
||||
err
|
||||
))
|
||||
.into()),
|
||||
};
|
||||
}
|
||||
return Ok(json["result"].take());
|
||||
}
|
||||
}
|
||||
|
||||
fn url(&self) -> String {
|
||||
self.url.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn http_sender_on_tokio_multi_thread() {
|
||||
let http_sender = HttpSender::new("http://localhost:1234".to_string());
|
||||
let _ = http_sender
|
||||
.send(RpcRequest::GetTipAccounts, serde_json::Value::Null)
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn http_sender_on_tokio_current_thread() {
|
||||
let http_sender = HttpSender::new("http://localhost:1234".to_string());
|
||||
let _ = http_sender
|
||||
.send(RpcRequest::GetTipAccounts, serde_json::Value::Null)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
pub mod client_error;
|
||||
pub mod http_sender;
|
||||
pub mod request;
|
||||
pub mod rpc_client;
|
||||
pub mod rpc_sender;
|
||||
@@ -0,0 +1,55 @@
|
||||
use std::fmt;
|
||||
|
||||
use serde_json::{json, Value};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||
pub enum RpcRequest {
|
||||
Custom { method: &'static str },
|
||||
GetBundlesStatuses,
|
||||
GetTipAccounts,
|
||||
SendBundle,
|
||||
}
|
||||
|
||||
impl fmt::Display for RpcRequest {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let method = match self {
|
||||
RpcRequest::Custom { method } => method,
|
||||
RpcRequest::GetBundlesStatuses => "getBundleStatuses",
|
||||
RpcRequest::GetTipAccounts => "getTipAccounts",
|
||||
RpcRequest::SendBundle => "sendBundle",
|
||||
};
|
||||
|
||||
write!(f, "{method}")
|
||||
}
|
||||
}
|
||||
|
||||
impl RpcRequest {
|
||||
pub fn build_request_json(self, id: u64, params: Value) -> Value {
|
||||
let jsonrpc = "2.0";
|
||||
json!({
|
||||
"jsonrpc": jsonrpc,
|
||||
"id": id,
|
||||
"method": format!("{self}"),
|
||||
"params": params,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_build_request_json() {
|
||||
let test_request = RpcRequest::GetTipAccounts;
|
||||
let request = test_request.build_request_json(1, json!([]));
|
||||
assert_eq!(request["method"], "getTipAccounts");
|
||||
assert_eq!(request["params"], json!([]));
|
||||
|
||||
let test_request = RpcRequest::GetBundlesStatuses;
|
||||
let addr = json!("deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx");
|
||||
let request = test_request.build_request_json(1, json!([addr]));
|
||||
assert_eq!(request["method"], "getBundleStatuses");
|
||||
assert_eq!(request["params"], json!([addr]));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,406 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use bincode::serialize;
|
||||
use log::*;
|
||||
use serde_json::{json, Value};
|
||||
use solana_rpc_client::{
|
||||
rpc_client::{RpcClientConfig, SerializableTransaction},
|
||||
rpc_sender::RpcTransportStats,
|
||||
};
|
||||
use solana_rpc_client_api::{
|
||||
client_error::ErrorKind as ClientErrorKind, request::RpcError, response::Response,
|
||||
};
|
||||
use solana_sdk::{bs58, commitment_config::CommitmentConfig};
|
||||
use solana_transaction_status::UiTransactionEncoding;
|
||||
|
||||
use crate::jsonrpc_client::{
|
||||
client_error,
|
||||
client_error::{Error as ClientError, Result as ClientResult},
|
||||
http_sender::HttpSender,
|
||||
request::RpcRequest,
|
||||
rpc_sender::*,
|
||||
};
|
||||
|
||||
pub type RpcResult<T> = client_error::Result<Response<T>>;
|
||||
/// A client of a remote Jito block engine node.
|
||||
///
|
||||
/// `RpcClient` communicates with a block engine node over [JSON-RPC]
|
||||
/// It is the primary Rust interface for querying and transacting with the network
|
||||
/// from external programs.
|
||||
///
|
||||
/// This is modeled very closely with the solan RpcClient with similar error types.
|
||||
/// You can treat the client similar to the Solana RpcClient with the difference being
|
||||
/// the RpcClient supports the block engine apis.
|
||||
///
|
||||
/// The client can be used with jito block engine proxy server for authentication
|
||||
/// The client can be used as is to send requests unauthenticated to the jito block engine as well
|
||||
///
|
||||
/// Please note that the commitment level is not used at the moment. Support will be added
|
||||
/// later on to specify and use the commitment levels.
|
||||
pub struct RpcClient {
|
||||
sender: Box<dyn RpcSender + Send + Sync + 'static>,
|
||||
config: RpcClientConfig,
|
||||
}
|
||||
|
||||
impl RpcClient {
|
||||
/// Create an `RpcClient` from an [`RpcSender`] and an [`RpcClientConfig`].
|
||||
///
|
||||
/// This is the basic constructor, allowing construction with any type of
|
||||
/// `RpcSender`. Most applications should use one of the other constructors,
|
||||
/// such as [`RpcClient::new`], [`RpcClient::new_with_commitment`] or
|
||||
/// [`RpcClient::new_with_timeout`].
|
||||
pub fn new_sender<T: RpcSender + Send + Sync + 'static>(
|
||||
sender: T,
|
||||
config: RpcClientConfig,
|
||||
) -> Self {
|
||||
Self {
|
||||
sender: Box::new(sender),
|
||||
config,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create an HTTP `RpcClient`.
|
||||
///
|
||||
/// The URL is an HTTP URL, usually for port 8899, as in
|
||||
/// "http://localhost:8899".
|
||||
///
|
||||
/// The client has a default timeout of 30 seconds, and a default [commitment
|
||||
/// level][cl] of [`Finalized`](CommitmentLevel::Finalized).
|
||||
///
|
||||
/// [cl]: https://docs.solana.com/developing/clients/jsonrpc-api#configuring-state-commitment
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use jito_block_engine_json_rpc_client::jsonrpc_client::rpc_client::RpcClient;
|
||||
/// let url = "http://localhost:8899".to_string();
|
||||
/// let client = RpcClient::new(url);
|
||||
/// ```
|
||||
pub fn new(url: String) -> Self {
|
||||
Self::new_with_commitment(url, CommitmentConfig::default())
|
||||
}
|
||||
|
||||
/// Create an HTTP `RpcClient` with specified [commitment level][cl].
|
||||
///
|
||||
/// Please note the client is not currently implemented to support commitment level configs
|
||||
///
|
||||
/// [cl]: https://docs.solana.com/developing/clients/jsonrpc-api#configuring-state-commitment
|
||||
///
|
||||
/// The URL is an HTTP URL, usually for port 8899, as in
|
||||
/// "http://localhost:8899".
|
||||
///
|
||||
/// The client has a default timeout of 30 seconds, and a user-specified
|
||||
/// [`CommitmentLevel`] via [`CommitmentConfig`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// # use solana_sdk::commitment_config::CommitmentConfig;
|
||||
/// # use jito_block_engine_json_rpc_client::jsonrpc_client::rpc_client::RpcClient;
|
||||
/// let url = "http://localhost:8899".to_string();
|
||||
/// let commitment_config = CommitmentConfig::processed();
|
||||
/// let client = RpcClient::new_with_commitment(url, commitment_config);
|
||||
fn new_with_commitment(url: String, commitment_config: CommitmentConfig) -> Self {
|
||||
Self::new_sender(
|
||||
HttpSender::new(url),
|
||||
RpcClientConfig::with_commitment(commitment_config),
|
||||
)
|
||||
}
|
||||
|
||||
/// Create an HTTP `RpcClient` with specified timeout.
|
||||
///
|
||||
/// The URL is an HTTP URL, usually for port 8899, as in
|
||||
/// "http://localhost:8899".
|
||||
///
|
||||
/// The client has and a default [commitment level][cl] of
|
||||
/// [`Finalized`](CommitmentLevel::Finalized).
|
||||
///
|
||||
/// [cl]: https://docs.solana.com/developing/clients/jsonrpc-api#configuring-state-commitment
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use std::time::Duration;
|
||||
/// # use jito_block_engine_json_rpc_client::jsonrpc_client::rpc_client::RpcClient;
|
||||
/// let url = "http://localhost::8899".to_string();
|
||||
/// let timeout = Duration::from_secs(1);
|
||||
/// let client = RpcClient::new_with_timeout(url, timeout);
|
||||
/// ```
|
||||
pub fn new_with_timeout(url: String, timeout: Duration) -> Self {
|
||||
Self::new_sender(
|
||||
HttpSender::new_with_timeout(url, timeout),
|
||||
RpcClientConfig::with_commitment(CommitmentConfig::default()),
|
||||
)
|
||||
}
|
||||
|
||||
/// Get the configured url of the client's sender
|
||||
pub fn url(&self) -> String {
|
||||
self.sender.url()
|
||||
}
|
||||
|
||||
/// Get the configured default [commitment level][cl].
|
||||
///
|
||||
/// [cl]: https://docs.solana.com/developing/clients/jsonrpc-api#configuring-state-commitment
|
||||
///
|
||||
/// The commitment config may be specified during construction, and
|
||||
/// determines how thoroughly committed a transaction must be when waiting
|
||||
/// for its confirmation or otherwise checking for confirmation. If not
|
||||
/// specified, the default commitment level is
|
||||
/// [`Finalized`](CommitmentLevel::Finalized).
|
||||
///
|
||||
/// The default commitment level is overridden when calling methods that
|
||||
/// explicitly provide a [`CommitmentConfig`], like
|
||||
/// [`RpcClient::confirm_transaction_with_commitment`].
|
||||
pub fn commitment(&self) -> CommitmentConfig {
|
||||
self.config.commitment_config
|
||||
}
|
||||
|
||||
/// Submits a bundle of signed transactions to the network.
|
||||
///
|
||||
/// This returns a bundle_id on success and will return an error
|
||||
/// code on failure. The error code will only be on the basic
|
||||
/// validation of the bundle and publishing the bundle to the mempool
|
||||
/// For the bundle status regarding whether it landed or not, get_bundle_statuses
|
||||
/// should be used with the bundle id.
|
||||
///
|
||||
/// Example excerpt can be as below
|
||||
///
|
||||
/// use jito_block_engine_json_rpc_client::jsonrpc_client::rpc_client::RpcClient;
|
||||
/// use solana_program::hash::Hash;
|
||||
/// use solana_sdk::{pubkey::Pubkey, signer::keypair::Keypair};
|
||||
///
|
||||
/// let base = 0;
|
||||
/// let MAX_BUNDLE_LEN = 5;
|
||||
/// let searcher_keypair = Keypair::new();
|
||||
/// let recent_blockhash = Hash::new_unique();
|
||||
///
|
||||
/// let mut bundle: Vec<_> = (0..(MAX_BUNDLE_LEN) as u64)
|
||||
/// .map(|amount| {
|
||||
/// VersionedTransaction::from(system_transaction::transfer(
|
||||
/// &searcher_keypair,
|
||||
/// &searcher_keypair.pubkey(),
|
||||
/// base + amount,
|
||||
/// recent_blockhash,
|
||||
/// ))
|
||||
/// })
|
||||
/// .collect();
|
||||
///
|
||||
/// let rpc_client = RpcClient::new(SERVER_URL.to_owned());
|
||||
/// let response = rpc_client.send_bundle(&bundle).await;
|
||||
pub async fn send_bundle(
|
||||
&self,
|
||||
transactions: &[impl SerializableTransaction],
|
||||
) -> ClientResult<String> {
|
||||
let mut serialized_encoded: Vec<String> = Vec::with_capacity(transactions.len());
|
||||
for transaction in transactions {
|
||||
let encoding = self.default_cluster_transaction_encoding().await?;
|
||||
serialized_encoded.push(serialize_and_encode(transaction, encoding)?);
|
||||
}
|
||||
//The bundle may or may
|
||||
// not have been submitted to the cluster, so callers should verify the success of
|
||||
// the correct transaction signature independently.
|
||||
match self
|
||||
.send(RpcRequest::SendBundle, json!([serialized_encoded]))
|
||||
.await
|
||||
{
|
||||
Ok(signature_base58_str) => ClientResult::Ok(signature_base58_str),
|
||||
Err(err) => {
|
||||
if let ClientErrorKind::RpcError(RpcError::RpcResponseError {
|
||||
code, message, ..
|
||||
}) = &err.kind
|
||||
{
|
||||
debug!("{} {}", code, message);
|
||||
}
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn default_cluster_transaction_encoding(
|
||||
&self,
|
||||
) -> Result<UiTransactionEncoding, RpcError> {
|
||||
Ok(UiTransactionEncoding::Base58)
|
||||
}
|
||||
|
||||
/// Gets the statuses of a list of bundle ids.
|
||||
///
|
||||
/// Returns the statuses of a list of signatures. Each signature must be a bundle_id.
|
||||
/// bundle ids are sha256 hashes of their tx signatures (we get it after a sendBundle)
|
||||
/// This method currently will provide information regarding whether the bundle
|
||||
/// landed or not.
|
||||
/// The behavior is similar to the solana rpc method getSignatureStatuses
|
||||
/// https://docs.solana.com/api/http#getsignaturestatuses
|
||||
///
|
||||
/// If the bundle_id is not found or the all of the transactions in the bundle has not landed,
|
||||
/// we return null. If found and landed, we return the context information including the slot
|
||||
/// at which the request was made and result with the bundle_id(s) and the transactions with the
|
||||
/// slot and confirmation status. At this point, its assumed that all transactions within a bundle
|
||||
/// will have the same slot number and confirmation status.
|
||||
///
|
||||
/// The confirmation status of a bundle is the confirmation status of the transactions.
|
||||
/// This api does not provide a commitment level to configure, but will return the commitment level
|
||||
/// as returned by the rpc. The rpc used to fetch bulk transaction status does not provide a commitment
|
||||
/// level configuration option either.
|
||||
///
|
||||
/// Example excerpt can be as below
|
||||
///
|
||||
/// use jito_block_engine_json_rpc_client::jsonrpc_client::rpc_client::RpcClient;
|
||||
///
|
||||
/// let SERVER_URL = "http://localhost:8899";
|
||||
/// let bundle_id = "bundle_id".to_owned();
|
||||
///
|
||||
/// let rpc_client = RpcClient::new(SERVER_URL.to_owned());
|
||||
/// let response = rpc_client.get_bundle_statuses(&[bundle_id.clone()]).await;
|
||||
pub async fn get_bundle_statuses(
|
||||
&self,
|
||||
signatures: &[String],
|
||||
) -> RpcResult<Vec<serde_json::Value>> {
|
||||
self.send(RpcRequest::GetBundlesStatuses, json!([signatures]))
|
||||
.await
|
||||
}
|
||||
|
||||
/// Returns the tip accounts to be used for tip payments.
|
||||
pub async fn get_tip_accounts(&self) -> ClientResult<Vec<String>> {
|
||||
self.send(RpcRequest::GetTipAccounts, Value::Null).await
|
||||
}
|
||||
|
||||
pub async fn send<T>(&self, request: RpcRequest, params: Value) -> ClientResult<T>
|
||||
where
|
||||
T: serde::de::DeserializeOwned,
|
||||
{
|
||||
assert!(params.is_array() || params.is_null());
|
||||
|
||||
let response = self
|
||||
.sender
|
||||
.send(request, params)
|
||||
.await
|
||||
.map_err(|err| err.into_with_request(request))?;
|
||||
serde_json::from_value(response)
|
||||
.map_err(|err| ClientError::new_with_request(err.into(), request))
|
||||
}
|
||||
|
||||
pub fn get_transport_stats(&self) -> RpcTransportStats {
|
||||
self.sender.get_transport_stats()
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_and_encode<T>(input: &T, encoding: UiTransactionEncoding) -> ClientResult<String>
|
||||
where
|
||||
T: serde::ser::Serialize,
|
||||
{
|
||||
let serialized = serialize(input)
|
||||
.map_err(|e| ClientErrorKind::Custom(format!("Serialization failed: {e}")))?;
|
||||
let encoded = match encoding {
|
||||
UiTransactionEncoding::Base58 => bs58::encode(serialized).into_string(),
|
||||
_ => {
|
||||
return Err(ClientErrorKind::Custom(format!(
|
||||
"unsupported encoding: {encoding}. Supported encodings: base58"
|
||||
))
|
||||
.into())
|
||||
}
|
||||
};
|
||||
Ok(encoded)
|
||||
}
|
||||
|
||||
// Sample tests. Can use these as a reference point on how to use the api and what to expect
|
||||
#[cfg(test)]
|
||||
mod rpc_client_tests {
|
||||
use solana_program::hash::Hash;
|
||||
use solana_sdk::{
|
||||
pubkey::Pubkey, signature::Signer, signer::keypair::Keypair, system_transaction,
|
||||
transaction::VersionedTransaction,
|
||||
};
|
||||
|
||||
use crate::jsonrpc_client::rpc_client::RpcClient;
|
||||
|
||||
// Use the proxy server url here.
|
||||
const SERVER_URL: &str = "http://0.0.0.0:8080/api/v1/bundles";
|
||||
|
||||
#[tokio::test]
|
||||
pub async fn get_tip_accounts() {
|
||||
// Let's try the same with the rpc client
|
||||
let rpc_client = RpcClient::new(SERVER_URL.to_owned());
|
||||
|
||||
let tip_accounts = rpc_client.get_tip_accounts().await;
|
||||
|
||||
// Sample output. Pick only randomly to not have contention
|
||||
// ["9ttgPBBhRYFuQccdR1DSnb7hydsWANoDsV3P9kaGMCEh",
|
||||
// "EoW3SUQap7ZeynXQ2QJ847aerhxbPVr843uMeTfc9dxM",
|
||||
// "4xgEmT58RwTNsF5xm2RMYCnR1EVukdK8a1i2qFjnJFu3",
|
||||
// "B1mrQSpdeMU9gCvkJ6VsXVVoYjRGkNA7TtjMyqxrhecH",
|
||||
// "aTtUk2DHgLhKZRDjePq6eiHRKC1XXFMBiSUfQ2JNDbN",
|
||||
// "9n3d1K5YD2vECAbRFhFFGYNNjiXtHXJWn9F31t89vsAV",
|
||||
// "ARTtviJkLLt6cHGQDydfo1Wyk6M4VGZdKZ2ZhdnJL336",
|
||||
// "E2eSqe33tuhAHKTrwky5uEjaVqnb2T9ns6nHHUrN8588"]
|
||||
println!("{:?}", tip_accounts);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
pub async fn send_bundle() {
|
||||
let rpc_client = RpcClient::new(SERVER_URL.to_owned());
|
||||
|
||||
// Use your own keypair to sign
|
||||
let signer_keypair = Keypair::new();
|
||||
|
||||
// Get the latest blockhash from solana cluster. Can use https://docs.solana.com/api/http#getlatestblockhash
|
||||
let recent_blockhash = Hash::new_unique();
|
||||
|
||||
// Use the get_tip_accounts to randomly select a tip account to send tips to
|
||||
let tip_account = Pubkey::try_from("DCN82qDxJAQuSqHhv2BJuAgi41SPeKZB5ioBCTMNDrCC").unwrap();
|
||||
|
||||
let mut bundle: Vec<_> = vec![VersionedTransaction::from(system_transaction::transfer(
|
||||
&signer_keypair,
|
||||
&signer_keypair.pubkey(),
|
||||
10000,
|
||||
recent_blockhash,
|
||||
))];
|
||||
|
||||
// Add the tip
|
||||
bundle.push(VersionedTransaction::from(system_transaction::transfer(
|
||||
&signer_keypair,
|
||||
&tip_account,
|
||||
10000,
|
||||
recent_blockhash,
|
||||
)));
|
||||
let response = rpc_client.send_bundle(&bundle).await;
|
||||
|
||||
// If successful, the bundle_id can be retrieved. Else, an error code will be provided
|
||||
println!("{:?}", response);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
pub async fn get_bundle_statuses() {
|
||||
let rpc_client = RpcClient::new(SERVER_URL.to_owned());
|
||||
|
||||
// Use the bundle id you got from send_bundle
|
||||
let bundle_id =
|
||||
"6e4b90284778a40633b56e4289202ea79e62d2296bb3d45398bb93f6c9ec083d".to_owned();
|
||||
|
||||
let response = rpc_client.get_bundle_statuses(&[bundle_id]).await;
|
||||
|
||||
// Sample success output:
|
||||
// Response {
|
||||
// context: RpcResponseContext {
|
||||
// slot: 0, api_version: None },
|
||||
// value: [Object {
|
||||
// "bundle_id": String("6e4b90284778a40633b56e4289202ea79e62d2296bb3d45398bb93f6c9ec083d"),
|
||||
// "transactions": Array [String("4DGCuaKc2oue4Z8YC6mBwyg3oPAFG64BfxDtMbqDU3Du9zr26oVSuZcjSnJqTnHnKYFJ4AdPuq5kUrWKwTFLKtW6"),
|
||||
// String("srrgfKABYeaKazZjBmpuPKySJ8qgqezYaCdDnB9nhED5CFhviZ1wgcs5vEKnAK9L2ytRauWG9czGoKRxajpZ1YR")],
|
||||
// "slot": Number(240632575),
|
||||
// "confirmation_status": String("finalized"),
|
||||
// "err": Object {"Ok": Null}}] }
|
||||
//
|
||||
// Sample retryable error output:
|
||||
// Response {
|
||||
// context: RpcResponseContext {
|
||||
// slot: 0, api_version: None },
|
||||
// value: [Object {
|
||||
// "bundle_id": String("6e4b90284778a40633b56e4289202ea79e62d2296bb3d45398bb93f6c9ec083d"),
|
||||
// "transactions": Array [String("4DGCuaKc2oue4Z8YC6mBwyg3oPAFG64BfxDtMbqDU3Du9zr26oVSuZcjSnJqTnHnKYFJ4AdPuq5kUrWKwTFLKtW6"),
|
||||
// String("srrgfKABYeaKazZjBmpuPKySJ8qgqezYaCdDnB9nhED5CFhviZ1wgcs5vEKnAK9L2ytRauWG9czGoKRxajpZ1YR")],
|
||||
// "slot": Number(612529),
|
||||
// "confirmation_status": Null,
|
||||
// "err": Object {"Err": Object {"Retryable": String("Failed to retrieve information from solana cluster")}}}] }
|
||||
// If unknown bundle, the response would be null
|
||||
println!("{:?}", response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
use async_trait::async_trait;
|
||||
use solana_rpc_client::rpc_sender::RpcTransportStats;
|
||||
|
||||
use crate::jsonrpc_client::{client_error::Result, request::RpcRequest};
|
||||
|
||||
/// A transport for RPC calls.
|
||||
///
|
||||
/// `RpcSender` implements the underlying transport of requests to, and
|
||||
/// responses from, a Solana node, and is used primarily by [`RpcClient`].
|
||||
///
|
||||
/// [`RpcClient`]: crate::rpc_client::RpcClient
|
||||
#[async_trait]
|
||||
pub trait RpcSender {
|
||||
async fn send(
|
||||
&self,
|
||||
request: RpcRequest,
|
||||
params: serde_json::Value,
|
||||
) -> Result<serde_json::Value>;
|
||||
fn get_transport_stats(&self) -> RpcTransportStats;
|
||||
fn url(&self) -> String;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod jsonrpc_client;
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc_fingerprint":16894786775884202872,"outputs":{"17747080675513052775":{"success":true,"status":"","code":0,"stdout":"rustc 1.85.1 (4eb161250 2025-03-15)\nbinary: rustc\ncommit-hash: 4eb161250e340c8f48f66e2b929ef4a5bed7c181\ncommit-date: 2025-03-15\nhost: x86_64-unknown-linux-gnu\nrelease: 1.85.1\nLLVM version: 19.1.7\n","stderr":""},"13331785392996375709":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/root/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""}},"successes":{}}
|
||||
@@ -0,0 +1,3 @@
|
||||
Signature: 8a477f597d28d172789f06886806bc55
|
||||
# This file is a cache directory tag created by cargo.
|
||||
# For information about cache directory tags see https://bford.info/cachedir/
|
||||
@@ -0,0 +1 @@
|
||||
/pumpfun_indexer/json-rpc-client/target/release/libjito_block_engine_json_rpc_client.rlib: /pumpfun_indexer/json-rpc-client/src/jsonrpc_client/client_error.rs /pumpfun_indexer/json-rpc-client/src/jsonrpc_client/http_sender.rs /pumpfun_indexer/json-rpc-client/src/jsonrpc_client/mod.rs /pumpfun_indexer/json-rpc-client/src/jsonrpc_client/request.rs /pumpfun_indexer/json-rpc-client/src/jsonrpc_client/rpc_client.rs /pumpfun_indexer/json-rpc-client/src/jsonrpc_client/rpc_sender.rs /pumpfun_indexer/json-rpc-client/src/lib.rs
|
||||
Binary file not shown.
1132
#_sniper (Rust) using jito Shred stream/logs.json
Normal file
1132
#_sniper (Rust) using jito Shred stream/logs.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,32 @@
|
||||
[package]
|
||||
name = "pump_interface"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies.borsh]
|
||||
version = "^0.10"
|
||||
|
||||
[dependencies.num-derive]
|
||||
version = "^0.3"
|
||||
|
||||
[dependencies.num-traits]
|
||||
version = "^0.2"
|
||||
|
||||
[dependencies.serde]
|
||||
optional = true
|
||||
version = "^1.0"
|
||||
|
||||
[dependencies.solana-program]
|
||||
version = "^2.1.7"
|
||||
|
||||
[dependencies.thiserror]
|
||||
version = "^1.0"
|
||||
|
||||
[dependencies.strum]
|
||||
version = "0.26.3"
|
||||
|
||||
[dependencies.strum_macros]
|
||||
version = "0.26.4"
|
||||
|
||||
[dependencies.Inflector]
|
||||
version = "=0.11.4"
|
||||
@@ -0,0 +1,84 @@
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use solana_program::pubkey::Pubkey;
|
||||
pub const GLOBAL_ACCOUNT_DISCM: [u8; 8] = [167, 232, 232, 177, 200, 108, 114, 127];
|
||||
#[derive(Clone, Debug, BorshDeserialize, BorshSerialize, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct Global {
|
||||
pub initialized: bool,
|
||||
pub authority: Pubkey,
|
||||
pub fee_recipient: Pubkey,
|
||||
pub initial_virtual_token_reserves: u64,
|
||||
pub initial_virtual_sol_reserves: u64,
|
||||
pub initial_real_token_reserves: u64,
|
||||
pub token_total_supply: u64,
|
||||
pub fee_basis_points: u64,
|
||||
}
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct GlobalAccount(pub Global);
|
||||
impl GlobalAccount {
|
||||
pub fn deserialize(buf: &[u8]) -> std::io::Result<Self> {
|
||||
use std::io::Read;
|
||||
let mut reader = buf;
|
||||
let mut maybe_discm = [0u8; 8];
|
||||
reader.read_exact(&mut maybe_discm)?;
|
||||
if maybe_discm != GLOBAL_ACCOUNT_DISCM {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!(
|
||||
"discm does not match. Expected: {:?}. Received: {:?}",
|
||||
GLOBAL_ACCOUNT_DISCM, maybe_discm
|
||||
),
|
||||
));
|
||||
}
|
||||
Ok(Self(Global::deserialize(&mut reader)?))
|
||||
}
|
||||
pub fn serialize<W: std::io::Write>(&self, mut writer: W) -> std::io::Result<()> {
|
||||
writer.write_all(&GLOBAL_ACCOUNT_DISCM)?;
|
||||
self.0.serialize(&mut writer)
|
||||
}
|
||||
pub fn try_to_vec(&self) -> std::io::Result<Vec<u8>> {
|
||||
let mut data = Vec::new();
|
||||
self.serialize(&mut data)?;
|
||||
Ok(data)
|
||||
}
|
||||
}
|
||||
pub const BONDING_CURVE_ACCOUNT_DISCM: [u8; 8] = [23, 183, 248, 55, 96, 216, 172, 96];
|
||||
#[derive(Clone, Debug, BorshDeserialize, BorshSerialize, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct BondingCurve {
|
||||
pub virtual_token_reserves: u64,
|
||||
pub virtual_sol_reserves: u64,
|
||||
pub real_token_reserves: u64,
|
||||
pub real_sol_reserves: u64,
|
||||
pub token_total_supply: u64,
|
||||
pub complete: bool,
|
||||
}
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct BondingCurveAccount(pub BondingCurve);
|
||||
impl BondingCurveAccount {
|
||||
pub fn deserialize(buf: &[u8]) -> std::io::Result<Self> {
|
||||
use std::io::Read;
|
||||
let mut reader = buf;
|
||||
let mut maybe_discm = [0u8; 8];
|
||||
reader.read_exact(&mut maybe_discm)?;
|
||||
if maybe_discm != BONDING_CURVE_ACCOUNT_DISCM {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!(
|
||||
"discm does not match. Expected: {:?}. Received: {:?}",
|
||||
BONDING_CURVE_ACCOUNT_DISCM, maybe_discm
|
||||
),
|
||||
));
|
||||
}
|
||||
Ok(Self(BondingCurve::deserialize(&mut reader)?))
|
||||
}
|
||||
pub fn serialize<W: std::io::Write>(&self, mut writer: W) -> std::io::Result<()> {
|
||||
writer.write_all(&BONDING_CURVE_ACCOUNT_DISCM)?;
|
||||
self.0.serialize(&mut writer)
|
||||
}
|
||||
pub fn try_to_vec(&self) -> std::io::Result<Vec<u8>> {
|
||||
let mut data = Vec::new();
|
||||
self.serialize(&mut data)?;
|
||||
Ok(data)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#![allow(non_local_definitions)]
|
||||
use solana_program::{
|
||||
decode_error::DecodeError,
|
||||
msg,
|
||||
program_error::{PrintProgramError, ProgramError},
|
||||
};
|
||||
use thiserror::Error;
|
||||
#[derive(Clone, Copy, Debug, Eq, Error, num_derive::FromPrimitive, PartialEq)]
|
||||
pub enum PumpError {
|
||||
#[error("The given account is not authorized to execute this instruction.")]
|
||||
NotAuthorized = 6000,
|
||||
#[error("The program is already initialized.")]
|
||||
AlreadyInitialized = 6001,
|
||||
#[error("slippage: Too much SOL required to buy the given amount of tokens.")]
|
||||
TooMuchSolRequired = 6002,
|
||||
#[error("slippage: Too little SOL received to sell the given amount of tokens.")]
|
||||
TooLittleSolReceived = 6003,
|
||||
#[error("The mint does not match the bonding curve.")]
|
||||
MintDoesNotMatchBondingCurve = 6004,
|
||||
#[error("The bonding curve has completed and liquidity migrated to raydium.")]
|
||||
BondingCurveComplete = 6005,
|
||||
#[error("The bonding curve has not completed.")]
|
||||
BondingCurveNotComplete = 6006,
|
||||
#[error("The program is not initialized.")]
|
||||
NotInitialized = 6007,
|
||||
}
|
||||
impl From<PumpError> for ProgramError {
|
||||
fn from(e: PumpError) -> Self {
|
||||
ProgramError::Custom(e as u32)
|
||||
}
|
||||
}
|
||||
impl<T> DecodeError<T> for PumpError {
|
||||
fn type_of() -> &'static str {
|
||||
"PumpError"
|
||||
}
|
||||
}
|
||||
impl PrintProgramError for PumpError {
|
||||
fn print<E>(&self)
|
||||
where
|
||||
E: 'static
|
||||
+ std::error::Error
|
||||
+ DecodeError<E>
|
||||
+ PrintProgramError
|
||||
+ num_traits::FromPrimitive,
|
||||
{
|
||||
msg!(&self.to_string());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use solana_program::pubkey::Pubkey;
|
||||
pub const CREATE_EVENT_EVENT_DISCM: [u8; 8] = [27, 114, 169, 77, 222, 235, 99, 118];
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize)]
|
||||
pub struct CreateEvent {
|
||||
name: String,
|
||||
symbol: String,
|
||||
uri: String,
|
||||
mint: Pubkey,
|
||||
bonding_curve: Pubkey,
|
||||
user: Pubkey,
|
||||
}
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct CreateEventEvent(pub CreateEvent);
|
||||
impl BorshSerialize for CreateEventEvent {
|
||||
fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
|
||||
CREATE_EVENT_EVENT_DISCM.serialize(writer)?;
|
||||
self.0.serialize(writer)
|
||||
}
|
||||
}
|
||||
impl CreateEventEvent {
|
||||
pub fn deserialize(buf: &mut &[u8]) -> std::io::Result<Self> {
|
||||
let maybe_discm = <[u8; 8]>::deserialize(buf)?;
|
||||
if maybe_discm != CREATE_EVENT_EVENT_DISCM {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!(
|
||||
"discm does not match. Expected: {:?}. Received: {:?}",
|
||||
CREATE_EVENT_EVENT_DISCM, maybe_discm
|
||||
),
|
||||
));
|
||||
}
|
||||
Ok(Self(CreateEvent::deserialize(buf)?))
|
||||
}
|
||||
}
|
||||
pub const TRADE_EVENT_EVENT_DISCM: [u8; 8] = [189, 219, 127, 211, 78, 230, 97, 238];
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize)]
|
||||
pub struct TradeEvent {
|
||||
mint: Pubkey,
|
||||
sol_amount: u64,
|
||||
token_amount: u64,
|
||||
is_buy: bool,
|
||||
user: Pubkey,
|
||||
timestamp: i64,
|
||||
virtual_sol_reserves: u64,
|
||||
virtual_token_reserves: u64,
|
||||
}
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct TradeEventEvent(pub TradeEvent);
|
||||
impl BorshSerialize for TradeEventEvent {
|
||||
fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
|
||||
TRADE_EVENT_EVENT_DISCM.serialize(writer)?;
|
||||
self.0.serialize(writer)
|
||||
}
|
||||
}
|
||||
impl TradeEventEvent {
|
||||
pub fn deserialize(buf: &mut &[u8]) -> std::io::Result<Self> {
|
||||
let maybe_discm = <[u8; 8]>::deserialize(buf)?;
|
||||
if maybe_discm != TRADE_EVENT_EVENT_DISCM {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!(
|
||||
"discm does not match. Expected: {:?}. Received: {:?}",
|
||||
TRADE_EVENT_EVENT_DISCM, maybe_discm
|
||||
),
|
||||
));
|
||||
}
|
||||
Ok(Self(TradeEvent::deserialize(buf)?))
|
||||
}
|
||||
}
|
||||
pub const COMPLETE_EVENT_EVENT_DISCM: [u8; 8] = [95, 114, 97, 156, 212, 46, 152, 8];
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize)]
|
||||
pub struct CompleteEvent {
|
||||
user: Pubkey,
|
||||
mint: Pubkey,
|
||||
bonding_curve: Pubkey,
|
||||
timestamp: i64,
|
||||
}
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct CompleteEventEvent(pub CompleteEvent);
|
||||
impl BorshSerialize for CompleteEventEvent {
|
||||
fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
|
||||
COMPLETE_EVENT_EVENT_DISCM.serialize(writer)?;
|
||||
self.0.serialize(writer)
|
||||
}
|
||||
}
|
||||
impl CompleteEventEvent {
|
||||
pub fn deserialize(buf: &mut &[u8]) -> std::io::Result<Self> {
|
||||
let maybe_discm = <[u8; 8]>::deserialize(buf)?;
|
||||
if maybe_discm != COMPLETE_EVENT_EVENT_DISCM {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!(
|
||||
"discm does not match. Expected: {:?}. Received: {:?}",
|
||||
COMPLETE_EVENT_EVENT_DISCM, maybe_discm
|
||||
),
|
||||
));
|
||||
}
|
||||
Ok(Self(CompleteEvent::deserialize(buf)?))
|
||||
}
|
||||
}
|
||||
pub const SET_PARAMS_EVENT_EVENT_DISCM: [u8; 8] = [223, 195, 159, 246, 62, 48, 143, 131];
|
||||
#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize)]
|
||||
pub struct SetParamsEvent {
|
||||
fee_recipient: Pubkey,
|
||||
initial_virtual_token_reserves: u64,
|
||||
initial_virtual_sol_reserves: u64,
|
||||
initial_real_token_reserves: u64,
|
||||
token_total_supply: u64,
|
||||
fee_basis_points: u64,
|
||||
}
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct SetParamsEventEvent(pub SetParamsEvent);
|
||||
impl BorshSerialize for SetParamsEventEvent {
|
||||
fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
|
||||
SET_PARAMS_EVENT_EVENT_DISCM.serialize(writer)?;
|
||||
self.0.serialize(writer)
|
||||
}
|
||||
}
|
||||
impl SetParamsEventEvent {
|
||||
pub fn deserialize(buf: &mut &[u8]) -> std::io::Result<Self> {
|
||||
let maybe_discm = <[u8; 8]>::deserialize(buf)?;
|
||||
if maybe_discm != SET_PARAMS_EVENT_EVENT_DISCM {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!(
|
||||
"discm does not match. Expected: {:?}. Received: {:?}",
|
||||
SET_PARAMS_EVENT_EVENT_DISCM, maybe_discm
|
||||
),
|
||||
));
|
||||
}
|
||||
Ok(Self(SetParamsEvent::deserialize(buf)?))
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,9 @@
|
||||
solana_program::declare_id!("6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P");
|
||||
pub mod accounts;
|
||||
pub use accounts::*;
|
||||
pub mod instructions;
|
||||
pub use instructions::*;
|
||||
pub mod errors;
|
||||
pub use errors::*;
|
||||
pub mod events;
|
||||
pub use events::*;
|
||||
@@ -0,0 +1,37 @@
|
||||
// src/serializer.rs
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::Deserialize;
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
pub fn serialize_u128_as_string<S>(value: &u128, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
serializer.serialize_str(&value.to_string())
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
pub fn deserialize_u128_as_string<'de, D>(deserializer: D) -> Result<u128, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let s = String::deserialize(deserializer)?;
|
||||
s.parse::<u128>().map_err(serde::de::Error::custom)
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
pub fn serialize_i128_as_string<S>(value: &i128, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
serializer.serialize_str(&value.to_string())
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
pub fn deserialize_i128_as_string<'de, D>(deserializer: D) -> Result<i128, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let s = String::deserialize(deserializer)?;
|
||||
s.parse::<i128>().map_err(serde::de::Error::custom)
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
#[cfg(feature = "serde")]
|
||||
use crate::serializer::{
|
||||
deserialize_i128_as_string, deserialize_u128_as_string, serialize_i128_as_string,
|
||||
serialize_u128_as_string,
|
||||
};
|
||||
use borsh::{BorshDeserialize, BorshSerialize};
|
||||
use solana_program::pubkey::Pubkey;
|
||||
#[derive(Default, Clone, Debug, BorshDeserialize, BorshSerialize, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct OpenPositionBumps {
|
||||
pub position_bump: u8,
|
||||
}
|
||||
#[derive(Default, Clone, Debug, BorshDeserialize, BorshSerialize, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct OpenPositionWithMetadataBumps {
|
||||
pub position_bump: u8,
|
||||
pub metadata_bump: u8,
|
||||
}
|
||||
#[derive(Clone, Debug, BorshDeserialize, BorshSerialize, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct PositionRewardInfo {
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
serde(
|
||||
serialize_with = "serialize_u128_as_string",
|
||||
deserialize_with = "deserialize_u128_as_string"
|
||||
)
|
||||
)]
|
||||
pub growth_inside_checkpoint: u128,
|
||||
pub amount_owed: u64,
|
||||
}
|
||||
#[derive(Clone, Debug, BorshDeserialize, BorshSerialize, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct Tick {
|
||||
pub initialized: bool,
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
serde(
|
||||
serialize_with = "serialize_i128_as_string",
|
||||
deserialize_with = "deserialize_i128_as_string"
|
||||
)
|
||||
)]
|
||||
pub liquidity_net: i128,
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
serde(
|
||||
serialize_with = "serialize_u128_as_string",
|
||||
deserialize_with = "deserialize_u128_as_string"
|
||||
)
|
||||
)]
|
||||
pub liquidity_gross: u128,
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
serde(
|
||||
serialize_with = "serialize_u128_as_string",
|
||||
deserialize_with = "deserialize_u128_as_string"
|
||||
)
|
||||
)]
|
||||
pub fee_growth_outside_a: u128,
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
serde(
|
||||
serialize_with = "serialize_u128_as_string",
|
||||
deserialize_with = "deserialize_u128_as_string"
|
||||
)
|
||||
)]
|
||||
pub fee_growth_outside_b: u128,
|
||||
pub reward_growths_outside: [u128; 3],
|
||||
}
|
||||
#[derive(Clone, Debug, BorshDeserialize, BorshSerialize, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct WhirlpoolRewardInfo {
|
||||
pub mint: Pubkey,
|
||||
pub vault: Pubkey,
|
||||
pub authority: Pubkey,
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
serde(
|
||||
serialize_with = "serialize_u128_as_string",
|
||||
deserialize_with = "deserialize_u128_as_string"
|
||||
)
|
||||
)]
|
||||
pub emissions_per_second_x64: u128,
|
||||
#[cfg_attr(
|
||||
feature = "serde",
|
||||
serde(
|
||||
serialize_with = "serialize_u128_as_string",
|
||||
deserialize_with = "deserialize_u128_as_string"
|
||||
)
|
||||
)]
|
||||
pub growth_global_x64: u128,
|
||||
}
|
||||
#[derive(Default, Clone, Debug, BorshDeserialize, BorshSerialize, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct WhirlpoolBumps {
|
||||
pub whirlpool_bump: u8,
|
||||
}
|
||||
#[derive(Clone, Debug, BorshDeserialize, BorshSerialize, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct RemainingAccountsSlice {
|
||||
pub accounts_type: AccountsType,
|
||||
pub length: u8,
|
||||
}
|
||||
#[derive(Clone, Debug, BorshDeserialize, BorshSerialize, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct RemainingAccountsInfo {
|
||||
pub slices: Vec<RemainingAccountsSlice>,
|
||||
}
|
||||
#[derive(Clone, Debug, BorshDeserialize, BorshSerialize, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum CurrIndex {
|
||||
Below,
|
||||
Inside,
|
||||
Above,
|
||||
}
|
||||
#[derive(Clone, Debug, BorshDeserialize, BorshSerialize, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum TickLabel {
|
||||
Upper,
|
||||
Lower,
|
||||
}
|
||||
#[derive(Clone, Debug, BorshDeserialize, BorshSerialize, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum Direction {
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
#[derive(Clone, Debug, BorshDeserialize, BorshSerialize, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum AccountsType {
|
||||
TransferHookA,
|
||||
TransferHookB,
|
||||
TransferHookReward,
|
||||
TransferHookInput,
|
||||
TransferHookIntermediate,
|
||||
TransferHookOutput,
|
||||
SupplementalTickArrays,
|
||||
SupplementalTickArraysOne,
|
||||
SupplementalTickArraysTwo,
|
||||
}
|
||||
20
#_sniper (Rust) using jito Shred stream/run.sh
Normal file
20
#_sniper (Rust) using jito Shred stream/run.sh
Normal file
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# ─── 1) jump to script’s own dir ───
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# ─── 2) build in release (skips if up-to-date) ───
|
||||
cargo build --release
|
||||
|
||||
# ─── 3) where our binary really lives ───
|
||||
BIN="$(pwd)/target/release/grpc-raydium-pool-monitoring-rust"
|
||||
|
||||
# ─── 4) if PIN_CORES is set, pin there; otherwise run normally ───
|
||||
if [[ -n "${PIN_CORES:-}" ]]; then
|
||||
echo "📌 pinning to cores: $PIN_CORES"
|
||||
exec taskset -c "$PIN_CORES" "$BIN" "$@"
|
||||
else
|
||||
echo "▶️ running on all available cores"
|
||||
exec "$BIN" "$@"
|
||||
fi
|
||||
@@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "shared_state"
|
||||
version = "0.1.0"
|
||||
authors = ["Mephisto"]
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1", features = ["sync"] }
|
||||
lazy_static = "1.4"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
once_cell = "1.21.3"
|
||||
solana-sdk = "2.1.7"
|
||||
|
||||
[lib]
|
||||
path = "src/lib.rs"
|
||||
@@ -0,0 +1 @@
|
||||
pub mod state;
|
||||
269
#_sniper (Rust) using jito Shred stream/shared_state/src/lib.rs
Normal file
269
#_sniper (Rust) using jito Shred stream/shared_state/src/lib.rs
Normal file
@@ -0,0 +1,269 @@
|
||||
// shared_state/src/lib.rs
|
||||
use lazy_static::lazy_static;
|
||||
use once_cell::sync::Lazy;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::atomic::AtomicU64;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use std::time::Instant;
|
||||
use tokio::sync::Mutex;
|
||||
/// A request to sell a mint for a given amount, marking if it's urgent.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SellOrder {
|
||||
pub mint: String,
|
||||
pub amount: u64,
|
||||
pub use_jito: bool, // Indicates if Jito should be used for this sell
|
||||
pub urgent: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BuyOrder {
|
||||
pub mint: String,
|
||||
pub creator: Pubkey,
|
||||
pub use_jito: bool,
|
||||
pub urgent: bool,
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BoughtTokenInfo {
|
||||
mint: String,
|
||||
ata: Option<String>,
|
||||
amount: u64,
|
||||
fallback_amount: u64,
|
||||
timestamp: Instant,
|
||||
last_activity: Instant,
|
||||
signature: Option<String>,
|
||||
follow_up_buys: u32,
|
||||
sell_triggered: bool,
|
||||
first_sell_detected: bool,
|
||||
sol_inflow: f64,
|
||||
sol_outflow: f64,
|
||||
creator_vault: Option<Pubkey>,
|
||||
unique_buyers: std::collections::HashSet<String>,
|
||||
|
||||
suspected_creator: Option<String>,
|
||||
mint_detected_at: Instant,
|
||||
buy_executed_at: Option<Instant>,
|
||||
sell_triggered_at: Option<Instant>,
|
||||
ata_balance_zeroed: bool,
|
||||
pub sell_issued_slot: u64,
|
||||
sell_confirmed: bool,
|
||||
pub buy_slot: u64,
|
||||
pub sell_slot: Option<u64>,
|
||||
pub sell_signature: Option<String>,
|
||||
sell_executed_at: Option<std::time::Instant>,
|
||||
sell_retry_count: u8,
|
||||
}
|
||||
|
||||
impl BoughtTokenInfo {
|
||||
pub fn new(
|
||||
mint: String,
|
||||
ata: Option<String>,
|
||||
fallback_amount: u64,
|
||||
timestamp: Instant,
|
||||
signature: Option<String>,
|
||||
buy_slot: u64,
|
||||
creator_vault: Option<Pubkey>, // new param
|
||||
) -> Self {
|
||||
Self {
|
||||
mint,
|
||||
ata,
|
||||
amount: fallback_amount,
|
||||
fallback_amount,
|
||||
timestamp,
|
||||
last_activity: timestamp,
|
||||
signature,
|
||||
follow_up_buys: 0,
|
||||
sell_triggered: false,
|
||||
first_sell_detected: false,
|
||||
sol_inflow: 0.0,
|
||||
sol_outflow: 0.0,
|
||||
unique_buyers: std::collections::HashSet::new(),
|
||||
suspected_creator: None,
|
||||
mint_detected_at: timestamp,
|
||||
buy_executed_at: None,
|
||||
sell_triggered_at: None,
|
||||
ata_balance_zeroed: false,
|
||||
buy_slot,
|
||||
sell_slot: None,
|
||||
sell_signature: None,
|
||||
sell_issued_slot: 0,
|
||||
sell_confirmed: false,
|
||||
creator_vault, // initialize the creator vault
|
||||
sell_executed_at: None,
|
||||
sell_retry_count: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn creator_vault(&self) -> Option<&Pubkey> {
|
||||
self.creator_vault.as_ref()
|
||||
}
|
||||
|
||||
pub fn mint(&self) -> &String {
|
||||
&self.mint
|
||||
}
|
||||
|
||||
pub fn buy_slot(&self) -> u64 {
|
||||
self.buy_slot
|
||||
}
|
||||
pub fn set_buy_slot(&mut self, slot: u64) {
|
||||
self.buy_slot = slot;
|
||||
}
|
||||
|
||||
pub fn sell_slot(&self) -> Option<u64> {
|
||||
self.sell_slot
|
||||
}
|
||||
|
||||
pub fn set_sell_slot(&mut self, slot: u64) {
|
||||
self.sell_slot = Some(slot);
|
||||
}
|
||||
|
||||
pub fn set_buy_executed_at(&mut self, when: Instant) {
|
||||
self.buy_executed_at = Some(when);
|
||||
}
|
||||
pub fn buy_executed_at(&self) -> Option<Instant> {
|
||||
self.buy_executed_at
|
||||
}
|
||||
|
||||
pub fn record_sell(&mut self, sig: String, slot: u64) {
|
||||
self.sell_signature = Some(sig);
|
||||
self.sell_issued_slot = slot;
|
||||
self.sell_slot = Some(slot);
|
||||
self.sell_confirmed = false;
|
||||
}
|
||||
|
||||
pub fn confirm_sell(&mut self) {
|
||||
self.sell_confirmed = true;
|
||||
}
|
||||
|
||||
pub fn sell_confirmed(&self) -> bool {
|
||||
self.sell_confirmed
|
||||
}
|
||||
|
||||
pub fn sell_issued_slot(&self) -> u64 {
|
||||
self.sell_issued_slot
|
||||
}
|
||||
|
||||
pub fn set_sell_triggered_at(&mut self, when: Instant) {
|
||||
self.sell_triggered_at = Some(when);
|
||||
}
|
||||
pub fn sell_triggered_at(&self) -> Option<Instant> {
|
||||
self.sell_triggered_at
|
||||
}
|
||||
|
||||
pub fn set_suspected_creator(&mut self, creator: String) {
|
||||
self.suspected_creator = Some(creator);
|
||||
}
|
||||
pub fn suspected_creator(&self) -> Option<&String> {
|
||||
self.suspected_creator.as_ref()
|
||||
}
|
||||
|
||||
pub fn ata_balance_zeroed(&self) -> bool {
|
||||
self.ata_balance_zeroed
|
||||
}
|
||||
pub fn set_ata_balance_zeroed(&mut self, value: bool) {
|
||||
self.ata_balance_zeroed = value;
|
||||
}
|
||||
|
||||
pub fn sol_inflow(&self) -> f64 {
|
||||
self.sol_inflow
|
||||
}
|
||||
pub fn add_sol_inflow(&mut self, amount: f64) {
|
||||
self.sol_inflow += amount;
|
||||
self.update_last_activity();
|
||||
}
|
||||
pub fn sol_outflow(&self) -> f64 {
|
||||
self.sol_outflow
|
||||
}
|
||||
pub fn add_sol_outflow(&mut self, amount: f64) {
|
||||
self.sol_outflow += amount;
|
||||
self.update_last_activity();
|
||||
}
|
||||
pub fn ata(&self) -> Option<&String> {
|
||||
self.ata.as_ref()
|
||||
}
|
||||
pub fn amount(&self) -> u64 {
|
||||
self.amount
|
||||
}
|
||||
pub fn set_amount(&mut self, amt: u64) {
|
||||
self.amount = amt;
|
||||
}
|
||||
pub fn fallback_amount(&self) -> u64 {
|
||||
self.fallback_amount
|
||||
}
|
||||
pub fn timestamp(&self) -> Instant {
|
||||
self.timestamp
|
||||
}
|
||||
pub fn last_activity(&self) -> Instant {
|
||||
self.last_activity
|
||||
}
|
||||
pub fn update_last_activity(&mut self) {
|
||||
self.last_activity = Instant::now();
|
||||
}
|
||||
pub fn signature(&self) -> Option<&String> {
|
||||
self.signature.as_ref()
|
||||
}
|
||||
pub fn set_sell_signature(&mut self, sig: String) {
|
||||
self.sell_signature = Some(sig);
|
||||
}
|
||||
pub fn sell_signature(&self) -> Option<&String> {
|
||||
self.sell_signature.as_ref()
|
||||
}
|
||||
pub fn follow_up_buys(&self) -> u32 {
|
||||
self.follow_up_buys
|
||||
}
|
||||
pub fn increment_follow_up_buys(&mut self) {
|
||||
self.follow_up_buys += 1;
|
||||
self.update_last_activity();
|
||||
}
|
||||
pub fn sell_triggered(&self) -> bool {
|
||||
self.sell_triggered
|
||||
}
|
||||
pub fn set_sell_triggered(&mut self, v: bool) {
|
||||
self.sell_triggered = v;
|
||||
}
|
||||
pub fn first_sell_detected(&self) -> bool {
|
||||
self.first_sell_detected
|
||||
}
|
||||
pub fn mark_first_sell_detected(&mut self) {
|
||||
self.first_sell_detected = true;
|
||||
self.update_last_activity();
|
||||
}
|
||||
pub fn zero_amount(&mut self) {
|
||||
self.amount = 0;
|
||||
}
|
||||
pub fn unique_buyers(&self) -> &std::collections::HashSet<String> {
|
||||
&self.unique_buyers
|
||||
}
|
||||
pub fn add_unique_buyer(&mut self, addr: String) -> bool {
|
||||
let ins = self.unique_buyers.insert(addr);
|
||||
if ins {
|
||||
self.update_last_activity();
|
||||
}
|
||||
ins
|
||||
}
|
||||
pub fn sell_executed_at(&self) -> Option<Instant> {
|
||||
self.sell_executed_at
|
||||
}
|
||||
pub fn set_sell_executed_at(&mut self, t: Instant) {
|
||||
self.sell_executed_at = Some(t);
|
||||
}
|
||||
pub fn retry_count(&self) -> u8 {
|
||||
self.sell_retry_count
|
||||
}
|
||||
pub fn increment_retry_count(&mut self) {
|
||||
self.sell_retry_count = self.sell_retry_count.saturating_add(1);
|
||||
}
|
||||
pub fn reset_retry_count(&mut self) {
|
||||
self.sell_retry_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref BOUGHT_TOKENS: Mutex<HashMap<String, BoughtTokenInfo>> =
|
||||
Mutex::new(HashMap::new());
|
||||
}
|
||||
|
||||
pub static CURRENT_SLOT: Lazy<AtomicU64> = Lazy::new(|| AtomicU64::new(0));
|
||||
|
||||
pub static PENDING_MINTS: Lazy<AtomicUsize> = Lazy::new(|| AtomicUsize::new(0));
|
||||
@@ -0,0 +1,21 @@
|
||||
// shared_state/src/lib.rs
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TokenTrackingState {
|
||||
pub mint: String,
|
||||
pub first_buyer: Option<String>,
|
||||
pub first_buy_amount: f64,
|
||||
pub suspected_creators: HashSet<String>,
|
||||
pub sell_detected: bool,
|
||||
pub sell_split_ratio: usize,
|
||||
}
|
||||
|
||||
|
||||
lazy_static! {
|
||||
pub static ref TRACKED_TOKENS: Arc<Mutex<HashMap<String, TokenTrackingState>>> =
|
||||
Arc::new(Mutex::new(HashMap::new()));
|
||||
}
|
||||
24
#_sniper (Rust) using jito Shred stream/shredstreamproxy.sh
Normal file
24
#_sniper (Rust) using jito Shred stream/shredstreamproxy.sh
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 2) Set any necessary environment variables
|
||||
export RUST_LOG=info
|
||||
export BLOCK_ENGINE_URL="https://mainnet.block-engine.jito.wtf"
|
||||
|
||||
# Path to your approved Jito auth keypair
|
||||
export AUTH_KEYPAIR="/home/ubuntu/shreds_sniper/shredstream-proxy/validator-keypair.json"
|
||||
|
||||
# Comma-separated Jito regions
|
||||
export DESIRED_REGIONS="tokyo, frankfurt, amsterdam, ny, london, singapore, slc"
|
||||
|
||||
# Comma-separated list of destination IP:UDP_PORT entries
|
||||
# (example: forward to localhost:8001 and a remote at 10.0.1.5:8002)
|
||||
export DEST_IP_PORTS="127.0.0.1:8001"
|
||||
|
||||
# 3) Run the proxy binary
|
||||
# If you built with `cargo build --release`, the binary lives under `target/release/`
|
||||
exec /home/ubuntu/shreds_sniper/shredstream-proxy/target/release/jito-shredstream-proxy shredstream \
|
||||
--block-engine-url "${BLOCK_ENGINE_URL}" \
|
||||
--auth-keypair "${AUTH_KEYPAIR}" \
|
||||
--desired-regions "${DESIRED_REGIONS}" \
|
||||
--dest-ip-ports "${DEST_IP_PORTS}" \
|
||||
--grpc-service-port 50051 \
|
||||
@@ -0,0 +1,86 @@
|
||||
struct TradeDispatcher {
|
||||
db: Database,
|
||||
bot: AutoSend<Bot>,
|
||||
user_ids: Vec<i64>, // all whitelisted telegram IDs
|
||||
next_idx: AtomicUsize, // for round-robin
|
||||
}
|
||||
|
||||
impl TradeDispatcher {
|
||||
pub async fn new(db: Database, bot: AutoSend<Bot>) -> Self {
|
||||
let ids = db
|
||||
.users
|
||||
.find(doc! { "is_whitelisted": true }, None)
|
||||
.await
|
||||
.unwrap()
|
||||
.try_collect::<Vec<UserRecord>>()
|
||||
.await
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|u| u.telegram_id)
|
||||
.collect();
|
||||
TradeDispatcher { db, bot, user_ids: ids, next_idx: AtomicUsize::new(0) }
|
||||
}
|
||||
|
||||
/// Round-robin pick your next telegram user
|
||||
fn pop_next_user(&self) -> i64 {
|
||||
let len = self.user_ids.len();
|
||||
let i = self.next_idx.fetch_add(1, Ordering::Relaxed) % len;
|
||||
self.user_ids[i]
|
||||
}
|
||||
|
||||
pub async fn dispatch_buy(&self, buy: BuyOrder) {
|
||||
// 1) pick user
|
||||
let telegram_id = self.pop_next_user();
|
||||
let user = self.db.get_user(telegram_id).await.unwrap()
|
||||
.expect("should exist and be whitelisted");
|
||||
|
||||
// 2) decrypt & load their Keypair
|
||||
let keypair = decrypt_keypair(&user
|
||||
.wallets
|
||||
.iter()
|
||||
.find(|w| w.id == user.trading_wallet_id.unwrap())
|
||||
.unwrap()
|
||||
.private_key_enc
|
||||
);
|
||||
|
||||
// 3) build per-user SwapConfig
|
||||
let mut cfg = SwapConfig::default();
|
||||
if let Some(sl) = user.slippage_pct { cfg.slippage_bps = (sl * 100.0) as u16 }
|
||||
if let Some(tip) = user.tip_amount { cfg.use_priority_tip = tip > 0 }
|
||||
if let Some(min_tok) = user.min_tokens_to_buy { cfg.min_tokens = Some(min_tok as u64) }
|
||||
|
||||
// 4) hand off to pump_swap
|
||||
let input = /* build your SwapInput exactly as before */;
|
||||
let result = pump_swap(
|
||||
AppState {
|
||||
rpc_client: /* shared */,
|
||||
rpc_nonblocking_client: /* shared */,
|
||||
wallet: Arc::new(keypair),
|
||||
},
|
||||
input,
|
||||
"buy",
|
||||
buy.use_jito,
|
||||
buy.urgent,
|
||||
)
|
||||
.await;
|
||||
|
||||
// 5) notify on Telegram
|
||||
let msg = match result {
|
||||
Ok(sigs) => format!("✅ [{}] buy for `{}` succeeded: {}", telegram_id, buy.mint, sigs[0]),
|
||||
Err(e) => format!("❌ [{}] buy for `{}` failed: {}", telegram_id, buy.mint, e),
|
||||
};
|
||||
let _ = self.bot.send_message(telegram_id, msg).await;
|
||||
}
|
||||
|
||||
pub async fn dispatch_sell(&self, sell: SellOrder) {
|
||||
// Look up who originally bought this mint
|
||||
let user_id = {
|
||||
let tokens = shared_state::BOUGHT_TOKENS.lock().await;
|
||||
let info = tokens.get(&sell.mint).unwrap();
|
||||
info.telegram_id().unwrap()
|
||||
};
|
||||
|
||||
// same as buy: fetch user, decrypt, build cfg, call pump_swap("sell", ...) and notify
|
||||
/* … */
|
||||
}
|
||||
}
|
||||
239
#_sniper (Rust) using jito Shred stream/src/commands.rs
Normal file
239
#_sniper (Rust) using jito Shred stream/src/commands.rs
Normal file
@@ -0,0 +1,239 @@
|
||||
// src/commands.rs
|
||||
use teloxide::prelude::*;
|
||||
use teloxide::utils::command::BotCommand;
|
||||
use mongodb::bson::oid::ObjectId;
|
||||
use crate::db::Database;
|
||||
use anyhow::Result;
|
||||
|
||||
#[derive(BotCommand, Clone)]
|
||||
#[command(rename = "lowercase", description = "These commands are supported:")]
|
||||
pub enum Command {
|
||||
#[command(description = "display this text.")]
|
||||
Help,
|
||||
#[command(description = "start the bot.")]
|
||||
Start,
|
||||
#[command(description = "create a new wallet: /create_wallet <name> <private_key_or_mnemonic>")]
|
||||
CreateWallet { name: String, key: String },
|
||||
#[command(description = "list your wallets.")]
|
||||
ListWallets,
|
||||
#[command(description = "remove a wallet: /remove_wallet <wallet_id>")]
|
||||
RemoveWallet { wallet_id: String },
|
||||
#[command(description = "set trading wallet: /set_trading_wallet <wallet_id>")]
|
||||
SetTradingWallet { wallet_id: String },
|
||||
#[command(description = "set min tokens to buy: /set_min_tokens <amount>")]
|
||||
SetMinTokens { amount: f64 },
|
||||
#[command(description = "set slippage percent: /set_slippage <percent>")]
|
||||
SetSlippage { percent: f64 },
|
||||
#[command(description = "set tip amount: /set_tip <amount>")]
|
||||
SetTip { amount: u64 },
|
||||
#[command(description = "withdraw: /withdraw <wallet_id> <dest_address> <amount>")]
|
||||
Withdraw { wallet_id: String, dest: String, amount: f64 },
|
||||
#[command(description = "transfer: /transfer <wallet_id> <dest_address> <amount>")]
|
||||
Transfer { wallet_id: String, dest: String, amount: f64 },
|
||||
// Admin only:
|
||||
#[command(description = "whitelist a user: /whitelist <telegram_id>")]
|
||||
Whitelist { telegram_id: i64 },
|
||||
#[command(description = "remove from whitelist: /unwhitelist <telegram_id>")]
|
||||
Unwhitelist { telegram_id: i64 },
|
||||
}
|
||||
|
||||
pub async fn handle_command(
|
||||
bot: Bot,
|
||||
msg: Message,
|
||||
cmd: Command,
|
||||
db: Database,
|
||||
admin_ids: Vec<i64>,
|
||||
) -> Result<()> {
|
||||
let chat_id = msg.chat.id;
|
||||
let user_id = msg.from().map(|u| u.id.0 as i64).unwrap_or(0);
|
||||
|
||||
match cmd {
|
||||
Command::Help => {
|
||||
bot.send_message(chat_id, Command::descriptions()).await?;
|
||||
}
|
||||
Command::Start => {
|
||||
// Check whitelist
|
||||
let is_whitelisted = db.is_whitelisted(user_id).await?;
|
||||
if !is_whitelisted {
|
||||
bot.send_message(chat_id, "You are not whitelisted. Please contact admin.").await?;
|
||||
} else {
|
||||
bot.send_message(chat_id, "Welcome! Use /help to see commands.").await?;
|
||||
}
|
||||
}
|
||||
Command::CreateWallet { name, key } => {
|
||||
if !db.is_whitelisted(user_id).await? {
|
||||
bot.send_message(chat_id, "Not whitelisted.").await?;
|
||||
return Ok(());
|
||||
}
|
||||
// TODO: encrypt `key` before storing, e.g. AES with ENCRYPTION_KEY
|
||||
let private_enc = encrypt_key(&key)?;
|
||||
match db.add_wallet(user_id, name.clone(), derive_address(&key)?, private_enc).await {
|
||||
Ok(entry) => {
|
||||
bot.send_message(chat_id, format!("Wallet created with ID: {}", entry.id)).await?;
|
||||
}
|
||||
Err(e) => {
|
||||
bot.send_message(chat_id, format!("Error creating wallet: {}", e)).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Command::ListWallets => {
|
||||
if !db.is_whitelisted(user_id).await? {
|
||||
bot.send_message(chat_id, "Not whitelisted.").await?;
|
||||
return Ok(());
|
||||
}
|
||||
let wallets = db.list_wallets(user_id).await?;
|
||||
if wallets.is_empty() {
|
||||
bot.send_message(chat_id, "No wallets. Use /create_wallet.").await?;
|
||||
} else {
|
||||
let mut text = String::from("Your wallets:\n");
|
||||
for w in wallets {
|
||||
text.push_str(&format!("- ID: {}, name: {}, address: {}\n", w.id, w.name, w.address));
|
||||
}
|
||||
bot.send_message(chat_id, text).await?;
|
||||
}
|
||||
}
|
||||
Command::RemoveWallet { wallet_id } => {
|
||||
if !db.is_whitelisted(user_id).await? {
|
||||
bot.send_message(chat_id, "Not whitelisted.").await?;
|
||||
return Ok(());
|
||||
}
|
||||
match ObjectId::parse_str(&wallet_id) {
|
||||
Ok(oid) => {
|
||||
if let Err(e) = db.remove_wallet(user_id, oid).await {
|
||||
bot.send_message(chat_id, format!("Error removing wallet: {}", e)).await?;
|
||||
} else {
|
||||
bot.send_message(chat_id, "Wallet removed.").await?;
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
bot.send_message(chat_id, "Invalid wallet ID format.").await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Command::SetTradingWallet { wallet_id } => {
|
||||
if !db.is_whitelisted(user_id).await? {
|
||||
bot.send_message(chat_id, "Not whitelisted.").await?;
|
||||
return Ok(());
|
||||
}
|
||||
match ObjectId::parse_str(&wallet_id) {
|
||||
Ok(oid) => {
|
||||
if let Err(e) = db.set_trading_wallet(user_id, oid).await {
|
||||
bot.send_message(chat_id, format!("Error: {}", e)).await?;
|
||||
} else {
|
||||
bot.send_message(chat_id, "Trading wallet set.").await?;
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
bot.send_message(chat_id, "Invalid wallet ID.").await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Command::SetMinTokens { amount } => {
|
||||
if !db.is_whitelisted(user_id).await? {
|
||||
bot.send_message(chat_id, "Not whitelisted.").await?;
|
||||
return Ok(());
|
||||
}
|
||||
if let Err(e) = db.update_setting_min_tokens(user_id, amount).await {
|
||||
bot.send_message(chat_id, format!("Error: {}", e)).await?;
|
||||
} else {
|
||||
bot.send_message(chat_id, format!("min_tokens_to_buy set to {}", amount)).await?;
|
||||
}
|
||||
}
|
||||
Command::SetSlippage { percent } => {
|
||||
if !db.is_whitelisted(user_id).await? {
|
||||
bot.send_message(chat_id, "Not whitelisted.").await?;
|
||||
return Ok(());
|
||||
}
|
||||
if let Err(e) = db.update_setting_slippage(user_id, percent).await {
|
||||
bot.send_message(chat_id, format!("Error: {}", e)).await?;
|
||||
} else {
|
||||
bot.send_message(chat_id, format!("slippage_pct set to {}%", percent)).await?;
|
||||
}
|
||||
}
|
||||
Command::SetTip { amount } => {
|
||||
if !db.is_whitelisted(user_id).await? {
|
||||
bot.send_message(chat_id, "Not whitelisted.").await?;
|
||||
return Ok(());
|
||||
}
|
||||
if let Err(e) = db.update_setting_tip(user_id, amount).await {
|
||||
bot.send_message(chat_id, format!("Error: {}", e)).await?;
|
||||
} else {
|
||||
bot.send_message(chat_id, format!("tip_amount set to {}", amount)).await?;
|
||||
}
|
||||
}
|
||||
Command::Withdraw { wallet_id, dest, amount } |
|
||||
Command::Transfer { wallet_id, dest, amount } => {
|
||||
if !db.is_whitelisted(user_id).await? {
|
||||
bot.send_message(chat_id, "Not whitelisted.").await?;
|
||||
return Ok(());
|
||||
}
|
||||
// Parse wallet ID
|
||||
let oid = match ObjectId::parse_str(&wallet_id) {
|
||||
Ok(o) => o,
|
||||
Err(_) => {
|
||||
bot.send_message(chat_id, "Invalid wallet ID.").await?;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
// Fetch user & wallet
|
||||
if let Some(user) = db.get_user(user_id).await? {
|
||||
if let Some(wallet) = user.wallets.iter().find(|w| w.id == oid) {
|
||||
// Decrypt private key:
|
||||
let private_key = decrypt_key(&wallet.private_key_enc)?;
|
||||
// Then implement withdraw/transfer logic, e.g., call chain RPC:
|
||||
// withdraw: send transaction moving `amount` tokens from wallet.address to dest.
|
||||
// Here just stub:
|
||||
bot.send_message(chat_id, format!(
|
||||
"{} from wallet {} to {} of amount {}: not implemented yet",
|
||||
if matches!(cmd, Command::Withdraw {..}) { "Withdraw" } else { "Transfer" },
|
||||
wallet.name, dest, amount
|
||||
)).await?;
|
||||
} else {
|
||||
bot.send_message(chat_id, "Wallet not found.").await?;
|
||||
}
|
||||
} else {
|
||||
bot.send_message(chat_id, "User not found.").await?;
|
||||
}
|
||||
}
|
||||
Command::Whitelist { telegram_id: target } => {
|
||||
if !admin_ids.contains(&user_id) {
|
||||
bot.send_message(chat_id, "You are not admin.").await?;
|
||||
return Ok(());
|
||||
}
|
||||
if let Err(e) = db.set_whitelist(target, true).await {
|
||||
bot.send_message(chat_id, format!("Error whitelisting: {}", e)).await?;
|
||||
} else {
|
||||
bot.send_message(chat_id, format!("User {} whitelisted.", target)).await?;
|
||||
}
|
||||
}
|
||||
Command::Unwhitelist { telegram_id: target } => {
|
||||
if !admin_ids.contains(&user_id) {
|
||||
bot.send_message(chat_id, "You are not admin.").await?;
|
||||
return Ok(());
|
||||
}
|
||||
if let Err(e) = db.set_whitelist(target, false).await {
|
||||
bot.send_message(chat_id, format!("Error removing whitelist: {}", e)).await?;
|
||||
} else {
|
||||
bot.send_message(chat_id, format!("User {} unwhitelisted.", target)).await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Placeholder encryption/decryption. In real use, implement AES or other.
|
||||
fn encrypt_key(raw: &str) -> Result<String> {
|
||||
// e.g. base64 or AES-encrypt with env key
|
||||
Ok(base64::encode(raw))
|
||||
}
|
||||
fn decrypt_key(enc: &str) -> Result<String> {
|
||||
let bytes = base64::decode(enc)?;
|
||||
Ok(String::from_utf8(bytes)?)
|
||||
}
|
||||
|
||||
// Placeholder derive address from private key/mnemonic: implement per-chain.
|
||||
fn derive_address(key: &str) -> Result<String> {
|
||||
// stub: in Solana, parse keypair and extract pubkey:
|
||||
// ...
|
||||
Ok("public_address_stub".to_string())
|
||||
}
|
||||
90
#_sniper (Rust) using jito Shred stream/src/common/logger.rs
Normal file
90
#_sniper (Rust) using jito Shred stream/src/common/logger.rs
Normal file
@@ -0,0 +1,90 @@
|
||||
use chrono::Local;
|
||||
use serde_json::json;
|
||||
use std::{
|
||||
fs::OpenOptions,
|
||||
io::Write,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
const LOG_LEVEL: &str = "LOG";
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Logger {
|
||||
prefix: String,
|
||||
date_format: String,
|
||||
file: Arc<Mutex<std::fs::File>>,
|
||||
}
|
||||
|
||||
impl Logger {
|
||||
// Constructor to create a new logger that writes to "logs.json"
|
||||
pub fn new(prefix: String) -> Self {
|
||||
let file = OpenOptions::new()
|
||||
.create(true)
|
||||
.append(true)
|
||||
.open("logs.json")
|
||||
.expect("Failed to open logs.json for writing");
|
||||
|
||||
Logger {
|
||||
prefix,
|
||||
date_format: String::from("%Y-%m-%d %H:%M:%S"),
|
||||
file: Arc::new(Mutex::new(file)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn log(&self, message: String) -> String {
|
||||
let full_log = format!("{} {}", self.prefix_with_date(), message);
|
||||
println!("{}", full_log);
|
||||
self.write_json("INFO", &message);
|
||||
full_log
|
||||
}
|
||||
|
||||
pub fn debug(&self, message: String) -> String {
|
||||
let full_log = format!("{} [{}] {}", self.prefix_with_date(), "DEBUG", message);
|
||||
if LogLevel::new().is_debug() {
|
||||
println!("{}", full_log);
|
||||
self.write_json("DEBUG", &message);
|
||||
}
|
||||
full_log
|
||||
}
|
||||
|
||||
pub fn error(&self, message: String) -> String {
|
||||
let full_log = format!("{} [{}] {}", self.prefix_with_date(), "ERROR", message);
|
||||
println!("{}", full_log);
|
||||
self.write_json("ERROR", &message);
|
||||
full_log
|
||||
}
|
||||
|
||||
fn prefix_with_date(&self) -> String {
|
||||
let date = Local::now();
|
||||
format!("[{}] {}", date.format(&self.date_format), self.prefix)
|
||||
}
|
||||
|
||||
fn write_json(&self, level: &str, message: &str) {
|
||||
let now = Local::now();
|
||||
let entry = json!({
|
||||
"timestamp": now.to_rfc3339(),
|
||||
"level": level,
|
||||
"prefix": self.prefix,
|
||||
"message": message,
|
||||
});
|
||||
|
||||
if let Ok(mut file) = self.file.lock() {
|
||||
if let Err(e) = writeln!(file, "{}", entry) {
|
||||
eprintln!("Failed to write to log file: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct LogLevel<'a> {
|
||||
level: &'a str,
|
||||
}
|
||||
impl LogLevel<'_> {
|
||||
fn new() -> Self {
|
||||
LogLevel { level: LOG_LEVEL }
|
||||
}
|
||||
|
||||
fn is_debug(&self) -> bool {
|
||||
self.level.to_lowercase() == "debug"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
pub mod logger;
|
||||
pub mod rpc;
|
||||
pub mod utils;
|
||||
131
#_sniper (Rust) using jito Shred stream/src/common/rpc.rs
Normal file
131
#_sniper (Rust) using jito Shred stream/src/common/rpc.rs
Normal file
@@ -0,0 +1,131 @@
|
||||
use anchor_lang::AccountDeserialize;
|
||||
use anyhow::Result;
|
||||
use base64::{prelude::BASE64_STANDARD, Engine};
|
||||
use solana_account_decoder::UiAccountEncoding;
|
||||
use solana_client::{
|
||||
rpc_client::RpcClient,
|
||||
rpc_config::{RpcAccountInfoConfig, RpcProgramAccountsConfig, RpcSendTransactionConfig},
|
||||
rpc_filter::RpcFilterType,
|
||||
rpc_request::RpcRequest,
|
||||
rpc_response::{RpcResult, RpcSimulateTransactionResult},
|
||||
};
|
||||
use solana_sdk::{
|
||||
account::Account, commitment_config::CommitmentConfig, instruction::Instruction,
|
||||
message::Message, pubkey::Pubkey, signature::Signature, signer::signers::Signers,
|
||||
transaction::Transaction,
|
||||
};
|
||||
use solana_transaction_status::UiTransactionEncoding;
|
||||
|
||||
pub fn build_txn(
|
||||
client: &RpcClient,
|
||||
instructions: &[Instruction],
|
||||
fee_payer: &Pubkey,
|
||||
signing_keypairs: &dyn Signers,
|
||||
) -> Result<Transaction> {
|
||||
let blockhash = client.get_latest_blockhash().unwrap();
|
||||
let message = Message::new_with_blockhash(instructions, Some(fee_payer), &blockhash);
|
||||
let mut transaction = Transaction::new_unsigned(message);
|
||||
|
||||
transaction
|
||||
.try_partial_sign(signing_keypairs, blockhash)
|
||||
.unwrap();
|
||||
Ok(transaction)
|
||||
}
|
||||
|
||||
pub fn send_txn(client: &RpcClient, txn: &Transaction, skip_preflight: bool) -> Result<Signature> {
|
||||
Ok(client.send_and_confirm_transaction_with_spinner_and_config(
|
||||
txn,
|
||||
CommitmentConfig::confirmed(),
|
||||
RpcSendTransactionConfig {
|
||||
skip_preflight,
|
||||
..RpcSendTransactionConfig::default()
|
||||
},
|
||||
)?)
|
||||
}
|
||||
|
||||
pub fn simulate_transaction(
|
||||
client: &RpcClient,
|
||||
transaction: &Transaction,
|
||||
sig_verify: bool,
|
||||
cfg: CommitmentConfig,
|
||||
) -> RpcResult<RpcSimulateTransactionResult> {
|
||||
let serialized = bincode::serialize(transaction)
|
||||
.map_err(|e| (format!("Serialization failed: {e}")))
|
||||
.unwrap();
|
||||
let serialized_encoded = BASE64_STANDARD.encode(serialized);
|
||||
println!("{}", serialized_encoded);
|
||||
|
||||
client.send(
|
||||
RpcRequest::SimulateTransaction,
|
||||
serde_json::json!([serialized_encoded, {
|
||||
"sigVerify": sig_verify, "commitment": cfg.commitment, "encoding": Some(UiTransactionEncoding::Base64)
|
||||
}]),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn send_without_confirm_txn(client: &RpcClient, txn: &Transaction) -> Result<Signature> {
|
||||
Ok(client.send_transaction_with_config(
|
||||
txn,
|
||||
RpcSendTransactionConfig {
|
||||
skip_preflight: true,
|
||||
..RpcSendTransactionConfig::default()
|
||||
},
|
||||
)?)
|
||||
}
|
||||
|
||||
pub fn get_account(client: &RpcClient, addr: &Pubkey) -> Result<Option<Vec<u8>>> {
|
||||
if let Some(account) = client
|
||||
.get_account_with_commitment(addr, CommitmentConfig::processed())?
|
||||
.value
|
||||
{
|
||||
let account_data = account.data;
|
||||
Ok(Some(account_data))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_anchor_account<T: AccountDeserialize>(
|
||||
client: &RpcClient,
|
||||
addr: &Pubkey,
|
||||
) -> Result<Option<T>> {
|
||||
if let Some(account) = client
|
||||
.get_account_with_commitment(addr, CommitmentConfig::processed())?
|
||||
.value
|
||||
{
|
||||
let mut data: &[u8] = &account.data;
|
||||
let ret = T::try_deserialize(&mut data).unwrap();
|
||||
Ok(Some(ret))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_multiple_accounts(
|
||||
client: &RpcClient,
|
||||
pubkeys: &[Pubkey],
|
||||
) -> Result<Vec<Option<Account>>> {
|
||||
Ok(client.get_multiple_accounts(pubkeys)?)
|
||||
}
|
||||
|
||||
pub fn get_program_accounts_with_filters(
|
||||
client: &RpcClient,
|
||||
program: Pubkey,
|
||||
filters: Option<Vec<RpcFilterType>>,
|
||||
) -> Result<Vec<(Pubkey, Account)>> {
|
||||
let accounts = client
|
||||
.get_program_accounts_with_config(
|
||||
&program,
|
||||
RpcProgramAccountsConfig {
|
||||
filters,
|
||||
account_config: RpcAccountInfoConfig {
|
||||
encoding: Some(UiAccountEncoding::Base64Zstd),
|
||||
..RpcAccountInfoConfig::default()
|
||||
},
|
||||
with_context: Some(false),
|
||||
sort_results: None, // <-- add this line
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
Ok(accounts)
|
||||
}
|
||||
107
#_sniper (Rust) using jito Shred stream/src/common/utils.rs
Normal file
107
#_sniper (Rust) using jito Shred stream/src/common/utils.rs
Normal file
@@ -0,0 +1,107 @@
|
||||
// utils.rs
|
||||
use crate::engine::swap::SwapDirection;
|
||||
use anyhow::Result;
|
||||
use solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey, signature::Keypair};
|
||||
use std::{env, sync::Arc};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AppState {
|
||||
pub rpc_client: Arc<solana_client::rpc_client::RpcClient>,
|
||||
pub rpc_nonblocking_client: Arc<solana_client::nonblocking::rpc_client::RpcClient>,
|
||||
pub wallet: Arc<Keypair>,
|
||||
}
|
||||
|
||||
pub struct ParseTx {
|
||||
pub type_tx: String,
|
||||
pub direction: Option<String>,
|
||||
pub amount_in: f64,
|
||||
pub amount_out: f64,
|
||||
pub mint: String,
|
||||
}
|
||||
|
||||
pub fn import_env_var(key: &str) -> String {
|
||||
env::var(key).unwrap_or_else(|_| panic!("Environment variable {} is not set", key))
|
||||
}
|
||||
|
||||
pub fn create_rpc_client() -> Result<Arc<solana_client::rpc_client::RpcClient>> {
|
||||
let rpc_https = import_env_var("RPC_ENDPOINT");
|
||||
let rpc_client = solana_client::rpc_client::RpcClient::new_with_commitment(
|
||||
rpc_https,
|
||||
CommitmentConfig::processed(),
|
||||
);
|
||||
Ok(Arc::new(rpc_client))
|
||||
}
|
||||
|
||||
pub async fn create_nonblocking_rpc_client(
|
||||
) -> Result<Arc<solana_client::nonblocking::rpc_client::RpcClient>> {
|
||||
let rpc_https = import_env_var("RPC_ENDPOINT");
|
||||
let rpc_client = solana_client::nonblocking::rpc_client::RpcClient::new_with_commitment(
|
||||
rpc_https,
|
||||
CommitmentConfig::processed(),
|
||||
);
|
||||
Ok(Arc::new(rpc_client))
|
||||
}
|
||||
|
||||
pub fn import_wallet() -> Result<Arc<Keypair>> {
|
||||
let priv_key = import_env_var("PRIVATE_KEY");
|
||||
let wallet: Keypair = Keypair::from_base58_string(priv_key.as_str());
|
||||
|
||||
Ok(Arc::new(wallet))
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
pub enum ComputeUnitLimits {
|
||||
#[default]
|
||||
Dynamic,
|
||||
Fixed(u64),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum PriorityFeeConfig {
|
||||
DynamicMultiplier(u64),
|
||||
FixedCuPrice(u64),
|
||||
JitoTip(u64),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SwapConfig {
|
||||
pub priority_fee: Option<PriorityFeeConfig>,
|
||||
pub cu_limits: Option<ComputeUnitLimits>,
|
||||
pub wrap_and_unwrap_sol: Option<bool>,
|
||||
pub as_legacy_transaction: Option<bool>,
|
||||
pub slippage: u64,
|
||||
pub swap_direction: SwapDirection,
|
||||
pub use_jito: bool,
|
||||
pub use_priority_tip: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct SwapConfigOverrides {
|
||||
pub priority_fee: Option<PriorityFeeConfig>,
|
||||
pub cu_limits: Option<ComputeUnitLimits>,
|
||||
pub wrap_and_unwrap_sol: Option<bool>,
|
||||
pub destination_token_account: Option<Pubkey>,
|
||||
pub as_legacy_transaction: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct SwapInput {
|
||||
pub input_token_mint: Pubkey,
|
||||
pub output_token_mint: Pubkey,
|
||||
pub slippage_bps: u16,
|
||||
pub amount: u64,
|
||||
pub mode: SwapExecutionMode,
|
||||
pub market: Option<Pubkey>,
|
||||
pub creator_vault: Option<Pubkey>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum SwapExecutionMode {
|
||||
ExactIn,
|
||||
ExactOut,
|
||||
}
|
||||
impl SwapExecutionMode {
|
||||
pub fn amount_specified_is_input(&self) -> bool {
|
||||
matches!(self, SwapExecutionMode::ExactIn)
|
||||
}
|
||||
}
|
||||
2
#_sniper (Rust) using jito Shred stream/src/core/mod.rs
Normal file
2
#_sniper (Rust) using jito Shred stream/src/core/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod token;
|
||||
pub mod tx;
|
||||
117
#_sniper (Rust) using jito Shred stream/src/core/token.rs
Normal file
117
#_sniper (Rust) using jito Shred stream/src/core/token.rs
Normal file
@@ -0,0 +1,117 @@
|
||||
use solana_sdk::{pubkey::Pubkey, signature::Keypair};
|
||||
use spl_token_2022::{
|
||||
extension::StateWithExtensionsOwned,
|
||||
state::{Account, Mint},
|
||||
};
|
||||
use spl_token_client::{
|
||||
client::{ProgramClient, ProgramRpcClient, ProgramRpcClientSendTransaction},
|
||||
token::{Token, TokenError, TokenResult},
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
use tracing::info;
|
||||
|
||||
pub async fn get_token_balance(
|
||||
client: Arc<solana_client::nonblocking::rpc_client::RpcClient>,
|
||||
keypair: Arc<Keypair>,
|
||||
mint: &Pubkey,
|
||||
owner: &Pubkey,
|
||||
) -> Result<u64, TokenError> {
|
||||
let ata = get_associated_token_address(client.clone(), keypair.clone(), mint, owner);
|
||||
info!(
|
||||
"🔎 Fetching token balance for ATA: {} | Mint: {} | Owner: {}",
|
||||
ata, mint, owner
|
||||
);
|
||||
|
||||
match get_account_info(client.clone(), keypair, mint, &ata).await {
|
||||
Ok(account_info) => {
|
||||
info!(
|
||||
"✅ Token balance found: {} tokens (raw amount)",
|
||||
account_info.base.amount
|
||||
);
|
||||
Ok(account_info.base.amount)
|
||||
}
|
||||
Err(e) => {
|
||||
info!("❌ Failed to fetch token balance for ATA {}: {:?}", ata, e);
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_associated_token_address(
|
||||
client: Arc<solana_client::nonblocking::rpc_client::RpcClient>,
|
||||
keypair: Arc<Keypair>,
|
||||
address: &Pubkey,
|
||||
owner: &Pubkey,
|
||||
) -> Pubkey {
|
||||
let token_client = Token::new(
|
||||
Arc::new(ProgramRpcClient::new(
|
||||
client.clone(),
|
||||
ProgramRpcClientSendTransaction,
|
||||
)),
|
||||
&spl_token::ID,
|
||||
address,
|
||||
None,
|
||||
Arc::new(Keypair::from_bytes(&keypair.to_bytes()).expect("failed to copy keypair")),
|
||||
);
|
||||
token_client.get_associated_token_address(owner)
|
||||
}
|
||||
|
||||
pub async fn get_account_info(
|
||||
client: Arc<solana_client::nonblocking::rpc_client::RpcClient>,
|
||||
_keypair: Arc<Keypair>,
|
||||
address: &Pubkey,
|
||||
account: &Pubkey,
|
||||
) -> TokenResult<StateWithExtensionsOwned<Account>> {
|
||||
let program_client = Arc::new(ProgramRpcClient::new(
|
||||
client.clone(),
|
||||
ProgramRpcClientSendTransaction,
|
||||
));
|
||||
let account = program_client
|
||||
.get_account(*account)
|
||||
.await
|
||||
.map_err(TokenError::Client)?
|
||||
.ok_or(TokenError::AccountNotFound)
|
||||
.inspect_err(|err| println!("get_account_info: {} {}: mint {}", account, err, address))?;
|
||||
|
||||
if account.owner != spl_token::ID {
|
||||
return Err(TokenError::AccountInvalidOwner);
|
||||
}
|
||||
let account = StateWithExtensionsOwned::<Account>::unpack(account.data)?;
|
||||
if account.base.mint != *address {
|
||||
return Err(TokenError::AccountInvalidMint);
|
||||
}
|
||||
|
||||
Ok(account)
|
||||
}
|
||||
|
||||
pub async fn get_mint_info(
|
||||
client: Arc<solana_client::nonblocking::rpc_client::RpcClient>,
|
||||
_keypair: Arc<Keypair>,
|
||||
address: &Pubkey,
|
||||
) -> TokenResult<StateWithExtensionsOwned<Mint>> {
|
||||
let program_client = Arc::new(ProgramRpcClient::new(
|
||||
client.clone(),
|
||||
ProgramRpcClientSendTransaction,
|
||||
));
|
||||
let account = program_client
|
||||
.get_account(*address)
|
||||
.await
|
||||
.map_err(TokenError::Client)?
|
||||
.ok_or(TokenError::AccountNotFound)
|
||||
.inspect_err(|err| println!("{} {}: mint {}", address, err, address))?;
|
||||
|
||||
if account.owner != spl_token::ID {
|
||||
return Err(TokenError::AccountInvalidOwner);
|
||||
}
|
||||
|
||||
let mint_result = StateWithExtensionsOwned::<Mint>::unpack(account.data).map_err(Into::into);
|
||||
let decimals: Option<u8> = None;
|
||||
if let (Ok(mint), Some(decimals)) = (&mint_result, decimals) {
|
||||
if decimals != mint.base.decimals {
|
||||
return Err(TokenError::InvalidDecimals);
|
||||
}
|
||||
}
|
||||
|
||||
mint_result
|
||||
}
|
||||
224
#_sniper (Rust) using jito Shred stream/src/core/tx.rs
Normal file
224
#_sniper (Rust) using jito Shred stream/src/core/tx.rs
Normal file
@@ -0,0 +1,224 @@
|
||||
// tx.rs
|
||||
|
||||
use crate::{
|
||||
common::{logger::Logger, rpc},
|
||||
services::{jito, nextblock},
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
use base64;
|
||||
use once_cell::sync::Lazy;
|
||||
use reqwest::Client as HttpClient;
|
||||
use serde_json::json;
|
||||
use solana_client::rpc_client::RpcClient;
|
||||
use solana_sdk::{
|
||||
compute_budget::ComputeBudgetInstruction, hash::Hash, instruction::Instruction,
|
||||
signature::Keypair, signer::Signer, system_instruction, transaction::Transaction,
|
||||
};
|
||||
use spl_token::ui_amount_to_amount;
|
||||
use std::{env, sync::Arc, time::Duration};
|
||||
use tokio::{spawn, sync::Mutex, time::Instant};
|
||||
|
||||
//——————————————————————————————————————————————————
|
||||
// 1) One global HTTP client for all block‐engine calls
|
||||
//——————————————————————————————————————————————————
|
||||
static HTTP_CLIENT: Lazy<HttpClient> = Lazy::new(|| {
|
||||
HttpClient::builder()
|
||||
.pool_max_idle_per_host(0)
|
||||
.build()
|
||||
.expect("failed to build HTTP client")
|
||||
});
|
||||
|
||||
//——————————————————————————————————————————————————
|
||||
// 2) Cached blockhash, refreshed every 500 ms in the background
|
||||
//——————————————————————————————————————————————————
|
||||
pub static LATEST_BLOCKHASH: Lazy<Mutex<Hash>> = Lazy::new(|| Mutex::new(Hash::default()));
|
||||
|
||||
/// Spawn this once at startup to keep our blockhash fresh.
|
||||
pub fn spawn_blockhash_refresher(rpc: Arc<RpcClient>) {
|
||||
spawn(async move {
|
||||
loop {
|
||||
if let Ok(hash) = rpc.get_latest_blockhash() {
|
||||
*LATEST_BLOCKHASH.lock().await = hash;
|
||||
}
|
||||
tokio::time::sleep(Duration::from_millis(50)).await;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//——————————————————————————————————————————————————
|
||||
// 3) One-time init of tip account & tip value (Jito vs NextBlock)
|
||||
//——————————————————————————————————————————————————
|
||||
static TIP_ACCOUNT: Lazy<Mutex<solana_sdk::pubkey::Pubkey>> =
|
||||
Lazy::new(|| Mutex::new(solana_sdk::pubkey::Pubkey::default()));
|
||||
static TIP_VALUE: Lazy<Mutex<f64>> = Lazy::new(|| Mutex::new(0.0));
|
||||
|
||||
/// Call this **once** at startup (before any swaps).
|
||||
/// `use_nextblock` comes from e.g. `env("BLOCK_ENGINE_PROVIDER") == "nextblock"`,
|
||||
/// `use_priority_tip` from your config.
|
||||
pub async fn init_tip_state(use_nextblock: bool, use_priority_tip: bool) -> Result<()> {
|
||||
if use_nextblock {
|
||||
nextblock::init_tip_accounts().await?;
|
||||
let base = nextblock::get_tip_value().await?;
|
||||
let mut acct = TIP_ACCOUNT.lock().await;
|
||||
let mut val = TIP_VALUE.lock().await;
|
||||
*acct = nextblock::get_tip_account().await?;
|
||||
*val = if use_priority_tip { base * 2.0 } else { base };
|
||||
} else {
|
||||
jito::init_tip_accounts().await?;
|
||||
let base = jito::get_tip_value().await?;
|
||||
let mut acct = TIP_ACCOUNT.lock().await;
|
||||
let mut val = TIP_VALUE.lock().await;
|
||||
*acct = jito::get_tip_account().await?;
|
||||
*val = if use_priority_tip { base * 5.0 } else { base };
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
//——————————————————————————————————————————————————
|
||||
// 4) Pre-built compute-budget instructions
|
||||
//——————————————————————————————————————————————————
|
||||
fn unit_price() -> u64 {
|
||||
env::var("UNIT_PRICE")
|
||||
.ok()
|
||||
.and_then(|v| v.parse().ok())
|
||||
.unwrap_or(1)
|
||||
}
|
||||
|
||||
fn unit_limit() -> u32 {
|
||||
env::var("UNIT_LIMIT")
|
||||
.ok()
|
||||
.and_then(|v| v.parse().ok())
|
||||
.unwrap_or(300_000)
|
||||
}
|
||||
|
||||
static BUDGET_INSTRUCTIONS: Lazy<Vec<Instruction>> = Lazy::new(|| {
|
||||
vec![
|
||||
ComputeBudgetInstruction::set_compute_unit_price(unit_price()),
|
||||
ComputeBudgetInstruction::set_compute_unit_limit(unit_limit()),
|
||||
]
|
||||
});
|
||||
|
||||
//——————————————————————————————————————————————————
|
||||
// 5) The refactored send‐tx function (handles RPC, Jito & NextBlock)
|
||||
//——————————————————————————————————————————————————
|
||||
#[allow(deprecated, unused_variables)]
|
||||
pub async fn new_signed_and_send(
|
||||
client: &RpcClient,
|
||||
keypair: &Keypair,
|
||||
mut instructions: Vec<Instruction>,
|
||||
use_priority_engine: bool, // e.g. swap_config.use_jito
|
||||
use_priority_tip: bool, // e.g. swap_config.use_priority_tip
|
||||
logger: &Logger,
|
||||
) -> Result<Vec<String>> {
|
||||
// a) If *not* using a block‐engine, prepend compute‐budget ixs
|
||||
if !use_priority_engine {
|
||||
instructions.splice(0..0, BUDGET_INSTRUCTIONS.iter().cloned());
|
||||
}
|
||||
|
||||
// b) Grab our cached blockhash
|
||||
let blockhash = *LATEST_BLOCKHASH.lock().await;
|
||||
|
||||
// c) Dispatch
|
||||
let start = Instant::now();
|
||||
let mut sigs = Vec::new();
|
||||
|
||||
if use_priority_engine {
|
||||
// i) build tip‐transfer ix
|
||||
let tip_account = *TIP_ACCOUNT.lock().await;
|
||||
let tip_value = *TIP_VALUE.lock().await;
|
||||
let lamports = ui_amount_to_amount(tip_value.min(0.1), spl_token::native_mint::DECIMALS);
|
||||
let tip_ix = system_instruction::transfer(&keypair.pubkey(), &tip_account, lamports);
|
||||
|
||||
// ii) weave it into a fresh txn
|
||||
let mut pe_ixs = Vec::with_capacity(instructions.len() + 1);
|
||||
pe_ixs.push(tip_ix);
|
||||
pe_ixs.extend(instructions);
|
||||
let pe_tx = Transaction::new_signed_with_payer(
|
||||
&pe_ixs,
|
||||
Some(&keypair.pubkey()),
|
||||
&[keypair],
|
||||
blockhash,
|
||||
);
|
||||
|
||||
// iii) encode + HTTP‐POST to NextBlock or Jito
|
||||
let encoded = base64::encode(bincode::serialize(&pe_tx)?);
|
||||
let payload = json!({
|
||||
"transaction": { "content": encoded },
|
||||
"frontRunningProtection": true,
|
||||
});
|
||||
|
||||
let engine_is_nextblock = env::var("BLOCK_ENGINE_PROVIDER")
|
||||
.unwrap_or_default()
|
||||
.to_lowercase()
|
||||
== "nextblock";
|
||||
|
||||
if engine_is_nextblock {
|
||||
// — NextBlock —
|
||||
let auth = env::var("NEXTBLOCK_AUTH").unwrap_or_default();
|
||||
let resp = HTTP_CLIENT
|
||||
.post("https://ny.nextblock.io/api/v2/submit")
|
||||
.header("Content-Type", "application/json")
|
||||
.header("Authorization", auth)
|
||||
.json(&payload)
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
if !resp.status().is_success() {
|
||||
return Err(anyhow!(
|
||||
"NextBlock error {}: {}",
|
||||
resp.status(),
|
||||
resp.text().await?
|
||||
));
|
||||
}
|
||||
let body = resp.json::<serde_json::Value>().await?;
|
||||
if let Some(sig) = body.get("signature").and_then(|v| v.as_str()) {
|
||||
sigs.push(sig.to_string());
|
||||
} else {
|
||||
return Err(anyhow!("Missing signature in NextBlock response"));
|
||||
}
|
||||
} else {
|
||||
// — Jito —
|
||||
let url = format!("{}/api/v1/transactions", *jito::BLOCK_ENGINE_URL);
|
||||
let rpc_resp = HTTP_CLIENT
|
||||
.post(&url)
|
||||
.header("Content-Type", "application/json")
|
||||
.json(&json!({
|
||||
"id": 1,
|
||||
"jsonrpc": "2.0",
|
||||
"method": "sendTransaction",
|
||||
"params": [encoded, { "encoding": "base64" }]
|
||||
}))
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
if !rpc_resp.status().is_success() {
|
||||
return Err(anyhow!(
|
||||
"Jito error {}: {}",
|
||||
rpc_resp.status(),
|
||||
rpc_resp.text().await?
|
||||
));
|
||||
}
|
||||
let body = rpc_resp.json::<serde_json::Value>().await?;
|
||||
if let Some(sig) = body.get("result").and_then(|v| v.as_str()) {
|
||||
sigs.push(sig.to_string());
|
||||
} else {
|
||||
return Err(anyhow!("Missing signature in Jito response"));
|
||||
}
|
||||
}
|
||||
|
||||
logger.log(format!("✅ Sent via block‐engine in {:?}", start.elapsed()));
|
||||
} else {
|
||||
// — standard RPC path —
|
||||
let std_tx = Transaction::new_signed_with_payer(
|
||||
&instructions,
|
||||
Some(&keypair.pubkey()),
|
||||
&[keypair],
|
||||
blockhash,
|
||||
);
|
||||
let sig = rpc::send_txn(client, &std_tx, true)?;
|
||||
sigs.push(sig.to_string());
|
||||
logger.log("✅ Sent via standard RPC".into());
|
||||
}
|
||||
|
||||
Ok(sigs)
|
||||
}
|
||||
170
#_sniper (Rust) using jito Shred stream/src/db.rs
Normal file
170
#_sniper (Rust) using jito Shred stream/src/db.rs
Normal file
@@ -0,0 +1,170 @@
|
||||
// src/db.rs
|
||||
use mongodb::{Client, Collection, options::ClientOptions};
|
||||
use mongodb::bson::{doc, oid::ObjectId};
|
||||
use crate::models::{UserRecord, WalletEntry};
|
||||
use anyhow::{Result, Context};
|
||||
use futures::TryStreamExt;
|
||||
|
||||
pub struct Database {
|
||||
users: Collection<UserRecord>,
|
||||
}
|
||||
|
||||
impl Database {
|
||||
/// Initialize MongoDB client and get `users` collection.
|
||||
pub async fn new(mongo_uri: &str, db_name: &str) -> Result<Self> {
|
||||
let mut client_options = ClientOptions::parse(mongo_uri).await?;
|
||||
client_options.app_name = Some("TelegramWalletBot".to_string());
|
||||
let client = Client::with_options(client_options)?;
|
||||
let db = client.database(db_name);
|
||||
let users = db.collection::<UserRecord>("users");
|
||||
// Ensure index on telegram_id
|
||||
users.create_index(
|
||||
mongodb::IndexModel::builder()
|
||||
.keys(doc! { "telegram_id": 1 })
|
||||
.options(Some(mongodb::options::IndexOptions::builder().unique(true).build()))
|
||||
.build(),
|
||||
None
|
||||
).await?;
|
||||
Ok(Self { users })
|
||||
}
|
||||
|
||||
/// Fetch or create a user record. If not exist, create with is_whitelisted=false.
|
||||
pub async fn get_or_create_user(&self, telegram_id: i64) -> Result<UserRecord> {
|
||||
if let Some(user) = self.users
|
||||
.find_one(doc! { "telegram_id": telegram_id }, None)
|
||||
.await?
|
||||
{
|
||||
Ok(user)
|
||||
} else {
|
||||
let new = UserRecord {
|
||||
id: ObjectId::new(),
|
||||
telegram_id,
|
||||
is_whitelisted: false,
|
||||
wallets: Vec::new(),
|
||||
trading_wallet_id: None,
|
||||
min_tokens_to_buy: None,
|
||||
slippage_pct: None,
|
||||
tip_amount: None,
|
||||
};
|
||||
self.users.insert_one(&new, None).await?;
|
||||
Ok(new)
|
||||
}
|
||||
}
|
||||
|
||||
/// Check whitelist
|
||||
pub async fn is_whitelisted(&self, telegram_id: i64) -> Result<bool> {
|
||||
if let Some(user) = self.users.find_one(doc! { "telegram_id": telegram_id }, None).await? {
|
||||
Ok(user.is_whitelisted)
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
||||
/// Set whitelist status (admin only).
|
||||
pub async fn set_whitelist(&self, telegram_id: i64, status: bool) -> Result<()> {
|
||||
let filter = doc! { "telegram_id": telegram_id };
|
||||
let update = doc! { "$set": { "is_whitelisted": status } };
|
||||
self.users.update_one(filter, update, None).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Add a wallet (limit 5). Returns error if >5.
|
||||
pub async fn add_wallet(&self, telegram_id: i64, name: String, address: String, private_enc: String) -> Result<WalletEntry> {
|
||||
// Load user
|
||||
let mut user = self.get_or_create_user(telegram_id).await?;
|
||||
if user.wallets.len() >= 5 {
|
||||
anyhow::bail!("wallet limit reached (5)");
|
||||
}
|
||||
// Create entry
|
||||
let entry = WalletEntry {
|
||||
id: ObjectId::new(),
|
||||
name,
|
||||
address,
|
||||
private_key_enc: private_enc,
|
||||
};
|
||||
user.wallets.push(entry.clone());
|
||||
// Update in DB
|
||||
self.users.update_one(
|
||||
doc! { "telegram_id": telegram_id },
|
||||
doc! { "$set": { "wallets": bson::to_bson(&user.wallets)? } },
|
||||
None
|
||||
).await?;
|
||||
Ok(entry)
|
||||
}
|
||||
|
||||
/// List wallets
|
||||
pub async fn list_wallets(&self, telegram_id: i64) -> Result<Vec<WalletEntry>> {
|
||||
if let Some(user) = self.users.find_one(doc! { "telegram_id": telegram_id }, None).await? {
|
||||
Ok(user.wallets)
|
||||
} else {
|
||||
Ok(Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
/// Set trading wallet by wallet id
|
||||
pub async fn set_trading_wallet(&self, telegram_id: i64, wallet_id: ObjectId) -> Result<()> {
|
||||
// Verify wallet belongs to user
|
||||
if let Some(user) = self.users.find_one(doc! { "telegram_id": telegram_id }, None).await? {
|
||||
if user.wallets.iter().any(|w| w.id == wallet_id) {
|
||||
self.users.update_one(
|
||||
doc! { "telegram_id": telegram_id },
|
||||
doc! { "$set": { "trading_wallet_id": wallet_id } },
|
||||
None
|
||||
).await?;
|
||||
Ok(())
|
||||
} else {
|
||||
anyhow::bail!("wallet not found");
|
||||
}
|
||||
} else {
|
||||
anyhow::bail!("user not found");
|
||||
}
|
||||
}
|
||||
|
||||
/// Update a setting (min_tokens_to_buy, slippage_pct, tip_amount)
|
||||
pub async fn update_setting_min_tokens(&self, telegram_id: i64, min_tokens: f64) -> Result<()> {
|
||||
self.users.update_one(
|
||||
doc! { "telegram_id": telegram_id },
|
||||
doc! { "$set": { "min_tokens_to_buy": min_tokens } },
|
||||
None
|
||||
).await?;
|
||||
Ok(())
|
||||
}
|
||||
pub async fn update_setting_slippage(&self, telegram_id: i64, slippage_pct: f64) -> Result<()> {
|
||||
self.users.update_one(
|
||||
doc! { "telegram_id": telegram_id },
|
||||
doc! { "$set": { "slippage_pct": slippage_pct } },
|
||||
None
|
||||
).await?;
|
||||
Ok(())
|
||||
}
|
||||
pub async fn update_setting_tip(&self, telegram_id: i64, tip: u64) -> Result<()> {
|
||||
self.users.update_one(
|
||||
doc! { "telegram_id": telegram_id },
|
||||
doc! { "$set": { "tip_amount": tip } },
|
||||
None
|
||||
).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Remove wallet by id
|
||||
pub async fn remove_wallet(&self, telegram_id: i64, wallet_id: ObjectId) -> Result<()> {
|
||||
// Pull from array
|
||||
self.users.update_one(
|
||||
doc! { "telegram_id": telegram_id },
|
||||
doc! { "$pull": { "wallets": { "id": wallet_id } } },
|
||||
None
|
||||
).await?;
|
||||
// If trading_wallet_id was this, clear it
|
||||
self.users.update_one(
|
||||
doc! { "telegram_id": telegram_id, "trading_wallet_id": wallet_id },
|
||||
doc! { "$set": { "trading_wallet_id": bson::Bson::Null } },
|
||||
None
|
||||
).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Fetch user record
|
||||
pub async fn get_user(&self, telegram_id: i64) -> Result<Option<UserRecord>> {
|
||||
Ok(self.users.find_one(doc! { "telegram_id": telegram_id }, None).await?)
|
||||
}
|
||||
}
|
||||
146
#_sniper (Rust) using jito Shred stream/src/dex/middleware.rs
Normal file
146
#_sniper (Rust) using jito Shred stream/src/dex/middleware.rs
Normal file
@@ -0,0 +1,146 @@
|
||||
pub const TEN_THOUSAND: u64 = 10000;
|
||||
pub const TOKEN_PROGRAM: &str = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
|
||||
pub const RENT_PROGRAM: &str = "SysvarRent111111111111111111111111111111111";
|
||||
pub const ASSOCIATED_TOKEN_PROGRAM: &str = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL";
|
||||
pub const PUMP_GLOBAL: &str = "4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf";
|
||||
pub const PUMP_FEE_RECIPIENT: &str = "CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM";
|
||||
pub const PUMP_PROGRAM: &str = "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P";
|
||||
// pub const PUMP_FUN_MINT_AUTHORITY: &str = "TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM";
|
||||
pub const PUMP_ACCOUNT: &str = "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1";
|
||||
pub const PUMP_BUY_METHOD: u64 = 16927863322537952870;
|
||||
pub const PUMP_SELL_METHOD: u64 = 12502976635542562355;
|
||||
|
||||
pub struct Pump {
|
||||
pub rpc_nonblocking_client: Arc<solana_client::nonblocking::rpc_client::RpcClient>,
|
||||
pub keypair: Arc<Keypair>,
|
||||
pub rpc_client: Option<Arc<solana_client::rpc_client::RpcClient>>,
|
||||
}
|
||||
|
||||
impl Pump {
|
||||
pub fn new(
|
||||
rpc_nonblocking_client: Arc<solana_client::nonblocking::rpc_client::RpcClient>,
|
||||
rpc_client: Arc<solana_client::rpc_client::RpcClient>,
|
||||
keypair: Arc<Keypair>,
|
||||
) -> Self {
|
||||
Self {
|
||||
rpc_nonblocking_client,
|
||||
keypair,
|
||||
rpc_client: Some(rpc_client),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn swap(&self, mint: &str, swap_config: SwapConfig) -> Result<Vec<String>> {
|
||||
let logger = Logger::new("[SWAP IN PUMP.FUN] => ".to_string());
|
||||
let slippage_bps = swap_config.slippage * 100;
|
||||
let owner = self.keypair.pubkey();
|
||||
let mint =
|
||||
Pubkey::from_str(mint).map_err(|e| anyhow!("failed to parse mint pubkey: {}", e))?;
|
||||
let program_id = spl_token::ID;
|
||||
let native_mint = spl_token::native_mint::ID;
|
||||
|
||||
let (token_in, token_out, pump_method) = match swap_config.swap_direction {
|
||||
SwapDirection::Buy => (native_mint, mint, PUMP_BUY_METHOD),
|
||||
SwapDirection::Sell => (mint, native_mint, PUMP_SELL_METHOD),
|
||||
};
|
||||
let pump_program = Pubkey::from_str(PUMP_PROGRAM)?;
|
||||
let (bonding_curve, associated_bonding_curve, bonding_curve_account) =
|
||||
get_bonding_curve_account(self.rpc_client.clone().unwrap(), &mint, &pump_program)
|
||||
.await?;
|
||||
|
||||
let in_ata = token::get_associated_token_address(
|
||||
self.rpc_nonblocking_client.clone(),
|
||||
self.keypair.clone(),
|
||||
&token_in,
|
||||
&owner,
|
||||
);
|
||||
let out_ata = token::get_associated_token_address(
|
||||
self.rpc_nonblocking_client.clone(),
|
||||
self.keypair.clone(),
|
||||
&token_out,
|
||||
&owner,
|
||||
);
|
||||
|
||||
let mut create_instruction = None;
|
||||
let mut close_instruction = None;
|
||||
|
||||
tx::new_signed_and_send(
|
||||
&client,
|
||||
&self.keypair,
|
||||
instructions,
|
||||
swap_config.use_jito,
|
||||
&logger,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
impl Raydium {
|
||||
pub fn new(
|
||||
rpc_nonblocking_client: Arc<solana_client::nonblocking::rpc_client::RpcClient>,
|
||||
rpc_client: Arc<solana_client::rpc_client::RpcClient>,
|
||||
keypair: Arc<Keypair>,
|
||||
) -> Self {
|
||||
Self {
|
||||
rpc_nonblocking_client,
|
||||
keypair,
|
||||
rpc_client: Some(rpc_client),
|
||||
pool_id: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn swap(
|
||||
&self,
|
||||
swap_config: SwapConfig,
|
||||
amm_pool_id: Pubkey,
|
||||
pool_state: AmmInfo,
|
||||
) -> Result<Vec<String>> {
|
||||
let logger = Logger::new(format!(
|
||||
"[SWAP IN RAYDIUM]({}) => ",
|
||||
chrono::Utc::now().timestamp()
|
||||
));
|
||||
let slippage_bps = swap_config.slippage * 100;
|
||||
let owner = self.keypair.pubkey();
|
||||
let program_id = spl_token::ID;
|
||||
let native_mint = spl_token::native_mint::ID;
|
||||
let mint = pool_state.coin_vault_mint;
|
||||
|
||||
let (token_in, token_out, user_input_token, swap_base_in) = match (
|
||||
swap_config.swap_direction.clone(),
|
||||
pool_state.coin_vault_mint == native_mint,
|
||||
) {
|
||||
(SwapDirection::Buy, true) => (native_mint, mint, pool_state.coin_vault, true),
|
||||
(SwapDirection::Buy, false) => (native_mint, mint, pool_state.pc_vault, true),
|
||||
(SwapDirection::Sell, true) => (mint, native_mint, pool_state.pc_vault, true),
|
||||
(SwapDirection::Sell, false) => (mint, native_mint, pool_state.coin_vault, true),
|
||||
};
|
||||
|
||||
logger.log(format!(
|
||||
"token_in:{}, token_out:{}, user_input_token:{}, swap_base_in:{}",
|
||||
token_in, token_out, user_input_token, swap_base_in
|
||||
));
|
||||
|
||||
let in_ata = get_associated_token_address(
|
||||
self.rpc_nonblocking_client.clone(),
|
||||
self.keypair.clone(),
|
||||
&token_in,
|
||||
&owner,
|
||||
);
|
||||
let out_ata = get_associated_token_address(
|
||||
self.rpc_nonblocking_client.clone(),
|
||||
self.keypair.clone(),
|
||||
&token_out,
|
||||
&owner,
|
||||
);
|
||||
|
||||
let mut create_instruction = None;
|
||||
let mut close_instruction = None;
|
||||
|
||||
tx::new_signed_and_send(
|
||||
&client,
|
||||
&self.keypair,
|
||||
instructions,
|
||||
swap_config.use_jito,
|
||||
&logger,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
1
#_sniper (Rust) using jito Shred stream/src/dex/mod.rs
Normal file
1
#_sniper (Rust) using jito Shred stream/src/dex/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod pump_fun;
|
||||
470
#_sniper (Rust) using jito Shred stream/src/dex/pump_fun.rs
Normal file
470
#_sniper (Rust) using jito Shred stream/src/dex/pump_fun.rs
Normal file
@@ -0,0 +1,470 @@
|
||||
// pump_fun.rs
|
||||
use crate::common::utils::SwapInput;
|
||||
use crate::{
|
||||
common::{logger::Logger, utils::SwapConfig},
|
||||
core::tx,
|
||||
engine::swap::SwapDirection,
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
use borsh::{from_slice, to_vec, BorshDeserialize, BorshSerialize};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use shared_state::BoughtTokenInfo;
|
||||
use shared_state::BOUGHT_TOKENS;
|
||||
use shared_state::CURRENT_SLOT;
|
||||
use solana_sdk::{
|
||||
instruction::{AccountMeta, Instruction},
|
||||
pubkey::Pubkey,
|
||||
signature::Keypair,
|
||||
signer::Signer,
|
||||
system_program,
|
||||
};
|
||||
use spl_associated_token_account::get_associated_token_address;
|
||||
use spl_associated_token_account::instruction::create_associated_token_account as create_ata;
|
||||
use std::collections::HashSet;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::time::Instant;
|
||||
use std::{str::FromStr, sync::Arc, time::Duration};
|
||||
use tokio::sync::Mutex;
|
||||
use tracing::info;
|
||||
// Define the 8-byte discriminator for the pump swap instruction.
|
||||
// (These bytes must match what the on‑chain program expects.)
|
||||
const PUMP_SWAP_DISCRIMINATOR: [u8; 8] = [102, 6, 61, 18, 1, 218, 235, 234];
|
||||
|
||||
pub const TEN_THOUSAND: u64 = 10000;
|
||||
pub const TOKEN_PROGRAM: &str = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
|
||||
pub const RENT_PROGRAM: &str = "SysvarRent111111111111111111111111111111111";
|
||||
pub const ASSOCIATED_TOKEN_PROGRAM: &str = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL";
|
||||
pub const PUMP_GLOBAL: &str = "4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf";
|
||||
pub const PUMP_FEE_RECIPIENT: &str = "CebN5WGQ4jvEPvsVU4EoHEpgzq1VV7AbicfhtW4xC9iM";
|
||||
pub const PUMP_PROGRAM: &str = "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P";
|
||||
// pub const PUMP_FUN_MINT_AUTHORITY: &str = "TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM";
|
||||
pub const PUMP_ACCOUNT: &str = "Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1";
|
||||
pub const PUMP_BUY_METHOD: u64 = 16927863322537952870;
|
||||
pub const PUMP_SELL_METHOD: u64 = 12502976635542562355;
|
||||
|
||||
/// This struct will be serialized (after the discriminator) as the instruction data.
|
||||
#[derive(BorshSerialize, BorshDeserialize, Debug)]
|
||||
pub struct PumpBuyInstruction {
|
||||
/// The minimum number of tokens the buyer expects to receive.
|
||||
pub amount: u64,
|
||||
/// The maximum SOL (in lamports) the buyer is willing to spend.
|
||||
pub max_sol_cost: u64,
|
||||
}
|
||||
|
||||
#[derive(BorshSerialize, BorshDeserialize, Debug)]
|
||||
pub struct PumpSellInstruction {
|
||||
/// Amount of tokens to sell
|
||||
pub amount: u64,
|
||||
/// Minimum SOL to receive
|
||||
pub min_sol_output: u64,
|
||||
}
|
||||
|
||||
pub struct Pump {
|
||||
pub rpc_nonblocking_client: Arc<solana_client::nonblocking::rpc_client::RpcClient>,
|
||||
pub keypair: Arc<Keypair>,
|
||||
pub rpc_client: Option<Arc<solana_client::rpc_client::RpcClient>>,
|
||||
created_atas: Arc<Mutex<HashSet<Pubkey>>>,
|
||||
}
|
||||
|
||||
impl Pump {
|
||||
pub fn new(
|
||||
rpc_nonblocking_client: Arc<solana_client::nonblocking::rpc_client::RpcClient>,
|
||||
rpc_client: Arc<solana_client::rpc_client::RpcClient>,
|
||||
keypair: Arc<Keypair>,
|
||||
) -> Self {
|
||||
Self {
|
||||
rpc_nonblocking_client,
|
||||
keypair,
|
||||
rpc_client: Some(rpc_client),
|
||||
created_atas: Arc::new(Mutex::new(HashSet::new())),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn swap(
|
||||
&self,
|
||||
mint: &str,
|
||||
swap_config: SwapConfig,
|
||||
swap_input: SwapInput,
|
||||
amount_in_lamports: u64,
|
||||
) -> Result<Vec<String>> {
|
||||
match swap_config.swap_direction {
|
||||
SwapDirection::Buy => {
|
||||
self.swap_buy(mint, swap_config, &swap_input, amount_in_lamports)
|
||||
.await
|
||||
}
|
||||
SwapDirection::Sell => self.swap_sell(mint, swap_config).await,
|
||||
}
|
||||
}
|
||||
|
||||
async fn swap_buy(
|
||||
&self,
|
||||
_mint: &str,
|
||||
swap_config: SwapConfig,
|
||||
swap_input: &SwapInput,
|
||||
amount_in_lamports: u64,
|
||||
) -> Result<Vec<String>> {
|
||||
let creator_vault = swap_input
|
||||
.creator_vault
|
||||
.ok_or_else(|| anyhow!("creator_vault not provided in SwapInput"))?;
|
||||
|
||||
// still need a Logger for the lower‐level TX helper
|
||||
let logger = Logger::new("[BUY SWAP] => ".to_string());
|
||||
let owner = self.keypair.pubkey();
|
||||
let mint_pubkey = swap_input.output_token_mint;
|
||||
let pump_program = Pubkey::from_str(PUMP_PROGRAM)?;
|
||||
|
||||
// derive PDAs
|
||||
let bonding_curve = get_pda(&mint_pubkey, &pump_program)?;
|
||||
let associated_bonding_curve = get_associated_token_address(&bonding_curve, &mint_pubkey);
|
||||
|
||||
// derive ATA locally
|
||||
let out_ata =
|
||||
spl_associated_token_account::get_associated_token_address(&owner, &mint_pubkey);
|
||||
|
||||
// 1) ensure user ATA exists via cache
|
||||
let mut instructions = Vec::new();
|
||||
{
|
||||
let cache = self.created_atas.lock().await;
|
||||
if !cache.contains(&out_ata) {
|
||||
instructions.push(create_ata(&owner, &owner, &mint_pubkey, &spl_token::ID));
|
||||
}
|
||||
}
|
||||
|
||||
// 2) build the buy instruction data
|
||||
let min_tokens: u64 = std::env::var("MIN_TOKENS_EXPECTED")
|
||||
.ok()
|
||||
.and_then(|v| v.parse().ok())
|
||||
.unwrap_or(8_000_000_000_000);
|
||||
let mut data = PUMP_SWAP_DISCRIMINATOR.to_vec();
|
||||
data.extend_from_slice(&to_vec(&PumpBuyInstruction {
|
||||
amount: min_tokens,
|
||||
max_sol_cost: amount_in_lamports,
|
||||
})?);
|
||||
|
||||
// 3) assemble accounts in *exact* IDL order
|
||||
let global = Pubkey::find_program_address(&[b"global"], &pump_program).0;
|
||||
let fee_recipient = Pubkey::from_str(PUMP_FEE_RECIPIENT)?;
|
||||
let event_authority = Pubkey::from_str(PUMP_ACCOUNT)?;
|
||||
let accounts = vec![
|
||||
AccountMeta::new_readonly(global, false), // 1
|
||||
AccountMeta::new(fee_recipient, false), // 2
|
||||
AccountMeta::new_readonly(mint_pubkey, false), // 3
|
||||
AccountMeta::new(bonding_curve, false), // 4
|
||||
AccountMeta::new(associated_bonding_curve, false), // 5
|
||||
AccountMeta::new(out_ata, false), // 6
|
||||
AccountMeta::new(owner, true), // 7
|
||||
AccountMeta::new_readonly(system_program::ID, false), // 8
|
||||
AccountMeta::new_readonly(spl_token::ID, false), // 9
|
||||
AccountMeta::new(creator_vault, false), // 10
|
||||
AccountMeta::new_readonly(event_authority, false), // 11
|
||||
AccountMeta::new_readonly(pump_program, false), // 12
|
||||
];
|
||||
|
||||
info!(
|
||||
"⛓ Preparing BUY for {}: min_tokens={}, max_sol={}; accounts={:?}",
|
||||
mint_pubkey,
|
||||
min_tokens,
|
||||
amount_in_lamports,
|
||||
accounts
|
||||
.iter()
|
||||
.map(|m| m.pubkey.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
|
||||
// 4) push your swap instruction
|
||||
instructions.push(Instruction {
|
||||
program_id: pump_program,
|
||||
accounts,
|
||||
data,
|
||||
});
|
||||
|
||||
// 5) dispatch
|
||||
let tx_result = tx::new_signed_and_send(
|
||||
self.rpc_client.as_ref().unwrap(),
|
||||
&self.keypair,
|
||||
instructions,
|
||||
swap_config.use_jito,
|
||||
swap_config.use_priority_tip,
|
||||
&logger,
|
||||
)
|
||||
.await;
|
||||
|
||||
// 6) record on success
|
||||
if let Ok(sigs) = &tx_result {
|
||||
let buy_slot = CURRENT_SLOT.load(std::sync::atomic::Ordering::Relaxed);
|
||||
let mut tokens = BOUGHT_TOKENS.lock().await;
|
||||
let mut info = BoughtTokenInfo::new(
|
||||
mint_pubkey.to_string(),
|
||||
Some(out_ata.to_string()),
|
||||
min_tokens,
|
||||
Instant::now(),
|
||||
sigs.first().cloned(),
|
||||
buy_slot,
|
||||
Some(creator_vault),
|
||||
);
|
||||
info.set_buy_executed_at(Instant::now());
|
||||
tokens.insert(mint_pubkey.to_string(), info);
|
||||
|
||||
info!(
|
||||
"✅ BUY sent for {}: sigs={:?} @ slot={}",
|
||||
mint_pubkey, sigs, buy_slot
|
||||
);
|
||||
}
|
||||
|
||||
tx_result
|
||||
}
|
||||
|
||||
async fn swap_sell(&self, mint: &str, swap_config: SwapConfig) -> Result<Vec<String>> {
|
||||
// logger still used for the helper
|
||||
let logger = Logger::new("[SELL SWAP] => ".to_string());
|
||||
let owner = self.keypair.pubkey();
|
||||
let mint_pubkey = Pubkey::from_str(mint)?;
|
||||
let pump_program = Pubkey::from_str(PUMP_PROGRAM)?;
|
||||
|
||||
// derive PDAs
|
||||
let global_pda = Pubkey::find_program_address(&[b"global"], &pump_program).0;
|
||||
let fee_recipient = Pubkey::from_str(PUMP_FEE_RECIPIENT)?;
|
||||
let bonding_curve = get_pda(&mint_pubkey, &pump_program)?;
|
||||
let associated_bonding_curve = get_associated_token_address(&bonding_curve, &mint_pubkey);
|
||||
let event_authority = Pubkey::from_str(PUMP_ACCOUNT)?;
|
||||
|
||||
// fetch stored info including creator_vault
|
||||
let (in_ata, sell_amount, creator_vault) = {
|
||||
let tokens = BOUGHT_TOKENS.lock().await;
|
||||
let info = tokens
|
||||
.get(mint)
|
||||
.ok_or_else(|| anyhow!("Missing buy record for {}", mint))?;
|
||||
let ata_str = info
|
||||
.ata()
|
||||
.ok_or_else(|| anyhow!("Missing ATA for {}", mint))?;
|
||||
let tracked = info.amount();
|
||||
let fallback = info.fallback_amount();
|
||||
let sell_amount = tracked.max(fallback);
|
||||
let vault = *info
|
||||
.creator_vault()
|
||||
.ok_or_else(|| anyhow!("Missing stored creator_vault for {}", mint))?;
|
||||
(Pubkey::from_str(ata_str)?, sell_amount, vault)
|
||||
};
|
||||
|
||||
// build instruction data
|
||||
const PUMP_SELL_DISCRIMINATOR: [u8; 8] = [51, 230, 133, 164, 1, 127, 131, 173];
|
||||
let mut data = PUMP_SELL_DISCRIMINATOR.to_vec();
|
||||
data.extend_from_slice(&to_vec(&PumpSellInstruction {
|
||||
amount: sell_amount,
|
||||
min_sol_output: 1_000,
|
||||
})?);
|
||||
|
||||
// assemble accounts in IDL order
|
||||
let accounts = vec![
|
||||
AccountMeta::new_readonly(global_pda, false),
|
||||
AccountMeta::new(fee_recipient, false),
|
||||
AccountMeta::new_readonly(mint_pubkey, false),
|
||||
AccountMeta::new(bonding_curve, false),
|
||||
AccountMeta::new(associated_bonding_curve, false),
|
||||
AccountMeta::new(in_ata, false),
|
||||
AccountMeta::new(owner, true),
|
||||
AccountMeta::new_readonly(system_program::ID, false),
|
||||
AccountMeta::new(creator_vault, false),
|
||||
AccountMeta::new_readonly(Pubkey::from_str(TOKEN_PROGRAM)?, false),
|
||||
AccountMeta::new_readonly(event_authority, false),
|
||||
AccountMeta::new_readonly(pump_program, false),
|
||||
];
|
||||
|
||||
info!(
|
||||
"⛓ Preparing SELL for {}: amount={}, creator_vault={}; accounts={:?}",
|
||||
mint_pubkey,
|
||||
sell_amount,
|
||||
creator_vault,
|
||||
accounts
|
||||
.iter()
|
||||
.map(|m| m.pubkey.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
|
||||
let ix = Instruction {
|
||||
program_id: pump_program,
|
||||
accounts,
|
||||
data,
|
||||
};
|
||||
let mut last: Result<Vec<String>> = Err(anyhow!("no attempts"));
|
||||
for attempt in 1..=3 {
|
||||
let res = tx::new_signed_and_send(
|
||||
self.rpc_client.as_ref().unwrap(),
|
||||
&self.keypair,
|
||||
vec![ix.clone()],
|
||||
swap_config.use_jito,
|
||||
swap_config.use_priority_tip,
|
||||
&logger,
|
||||
)
|
||||
.await;
|
||||
|
||||
match res {
|
||||
Ok(sigs) => {
|
||||
let sell_slot = CURRENT_SLOT.load(Ordering::Relaxed);
|
||||
info!(
|
||||
"💰 SELL succeeded for {}: sigs={:?} @ slot={}",
|
||||
mint_pubkey, sigs, sell_slot
|
||||
);
|
||||
|
||||
// ** record the signature so your gRPC‐stream confirmation can see it **
|
||||
let mut tokens = BOUGHT_TOKENS.lock().await;
|
||||
if let Some(entry) = tokens.get_mut(&mint_pubkey.to_string()) {
|
||||
entry.set_sell_signature(sigs[0].clone());
|
||||
}
|
||||
|
||||
last = Ok(sigs);
|
||||
break;
|
||||
}
|
||||
|
||||
Err(err) => {
|
||||
info!(
|
||||
"❌ SELL attempt {} failed for {}: {}",
|
||||
attempt, mint_pubkey, err
|
||||
);
|
||||
if attempt < 3 {
|
||||
tokio::time::sleep(Duration::from_millis(600 * attempt)).await;
|
||||
}
|
||||
last = Err(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
last
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn wait_for_bonding_curve_account(
|
||||
rpc_client: Arc<solana_client::rpc_client::RpcClient>,
|
||||
mint: &Pubkey,
|
||||
program_id: &Pubkey,
|
||||
max_retries: usize,
|
||||
delay_ms: u64,
|
||||
) -> Result<(Pubkey, Pubkey, BondingCurveAccount)> {
|
||||
let bonding_curve = get_pda(mint, program_id)?;
|
||||
let associated_bonding_curve = get_associated_token_address(&bonding_curve, mint);
|
||||
|
||||
for attempt in 0..max_retries {
|
||||
match rpc_client.get_account_data(&bonding_curve) {
|
||||
Ok(data) => {
|
||||
let bonding_curve_account: BondingCurveAccount =
|
||||
from_slice::<BondingCurveAccount>(&data).map_err(|e| {
|
||||
anyhow!("Failed to deserialize bonding curve account: {}", e)
|
||||
})?;
|
||||
return Ok((
|
||||
bonding_curve,
|
||||
associated_bonding_curve,
|
||||
bonding_curve_account,
|
||||
));
|
||||
}
|
||||
Err(err) => {
|
||||
if attempt == max_retries - 1 {
|
||||
return Err(anyhow!(
|
||||
"Bonding curve account not found after retries: {}",
|
||||
err
|
||||
));
|
||||
}
|
||||
tokio::time::sleep(Duration::from_millis(delay_ms)).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(anyhow!(
|
||||
"Bonding curve account retry logic failed unexpectedly"
|
||||
))
|
||||
}
|
||||
|
||||
/// Derives the bonding curve PDA and its associated token account for a given mint.
|
||||
pub async fn get_bonding_curve_account(
|
||||
rpc_client: Arc<solana_client::rpc_client::RpcClient>,
|
||||
mint: &Pubkey,
|
||||
program_id: &Pubkey,
|
||||
) -> Result<(Pubkey, Pubkey, BondingCurveAccount)> {
|
||||
let bonding_curve = get_pda(mint, program_id)?;
|
||||
let associated_bonding_curve =
|
||||
spl_associated_token_account::get_associated_token_address(&bonding_curve, mint);
|
||||
let bonding_curve_data = rpc_client
|
||||
.get_account_data(&bonding_curve)
|
||||
.inspect_err(|err| {
|
||||
println!(
|
||||
"Failed to get bonding curve account data: {}, err: {}",
|
||||
bonding_curve, err
|
||||
);
|
||||
})?;
|
||||
|
||||
let bonding_curve_account =
|
||||
from_slice::<BondingCurveAccount>(&bonding_curve_data).map_err(|e| {
|
||||
anyhow!(
|
||||
"Failed to deserialize bonding curve account: {}",
|
||||
e.to_string()
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok((
|
||||
bonding_curve,
|
||||
associated_bonding_curve,
|
||||
bonding_curve_account,
|
||||
))
|
||||
}
|
||||
|
||||
/// Derives the PDA for the bonding curve from the mint and program id.
|
||||
pub fn get_pda(mint: &Pubkey, program_id: &Pubkey) -> Result<Pubkey> {
|
||||
let seeds = [b"bonding-curve".as_ref(), mint.as_ref()];
|
||||
let (bonding_curve, _bump) = Pubkey::find_program_address(&seeds, program_id);
|
||||
Ok(bonding_curve)
|
||||
}
|
||||
|
||||
#[derive(Debug, BorshSerialize, BorshDeserialize)]
|
||||
pub struct BondingCurveAccount {
|
||||
pub discriminator: u64,
|
||||
pub virtual_token_reserves: u64,
|
||||
pub virtual_sol_reserves: u64,
|
||||
pub real_token_reserves: u64,
|
||||
pub real_sol_reserves: u64,
|
||||
pub token_total_supply: u64,
|
||||
pub complete: bool,
|
||||
pub creator: Pubkey,
|
||||
}
|
||||
|
||||
/// Retrieves pump info for a given token mint.
|
||||
pub async fn get_pump_info(
|
||||
rpc_client: Arc<solana_client::rpc_client::RpcClient>,
|
||||
mint: &str,
|
||||
) -> Result<PumpInfo> {
|
||||
let mint = Pubkey::from_str(mint)?;
|
||||
let program_id = Pubkey::from_str(PUMP_PROGRAM)?;
|
||||
let (bonding_curve, associated_bonding_curve, bonding_curve_account) =
|
||||
get_bonding_curve_account(rpc_client, &mint, &program_id).await?;
|
||||
|
||||
let pump_info = PumpInfo {
|
||||
mint: mint.to_string(),
|
||||
bonding_curve: bonding_curve.to_string(),
|
||||
associated_bonding_curve: associated_bonding_curve.to_string(),
|
||||
raydium_pool: None,
|
||||
raydium_info: None,
|
||||
complete: bonding_curve_account.complete,
|
||||
virtual_sol_reserves: bonding_curve_account.virtual_sol_reserves,
|
||||
virtual_token_reserves: bonding_curve_account.virtual_token_reserves,
|
||||
total_supply: bonding_curve_account.token_total_supply,
|
||||
};
|
||||
Ok(pump_info)
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct RaydiumInfo {
|
||||
pub base: f64,
|
||||
pub quote: f64,
|
||||
pub price: f64,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct PumpInfo {
|
||||
pub mint: String,
|
||||
pub bonding_curve: String,
|
||||
pub associated_bonding_curve: String,
|
||||
pub raydium_pool: Option<String>,
|
||||
pub raydium_info: Option<RaydiumInfo>,
|
||||
pub complete: bool,
|
||||
pub virtual_sol_reserves: u64,
|
||||
pub virtual_token_reserves: u64,
|
||||
pub total_supply: u64,
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod swap;
|
||||
85
#_sniper (Rust) using jito Shred stream/src/engine/swap.rs
Normal file
85
#_sniper (Rust) using jito Shred stream/src/engine/swap.rs
Normal file
@@ -0,0 +1,85 @@
|
||||
// swap.rs
|
||||
use crate::common::utils::{AppState, SwapConfig, SwapInput};
|
||||
use crate::dex::pump_fun::Pump;
|
||||
use anyhow::Result;
|
||||
use clap::ValueEnum;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(ValueEnum, Copy, Debug, Clone, Deserialize, PartialEq)]
|
||||
pub enum SwapDirection {
|
||||
#[serde(rename = "buy")]
|
||||
Buy,
|
||||
#[serde(rename = "sell")]
|
||||
Sell,
|
||||
}
|
||||
impl From<SwapDirection> for u8 {
|
||||
fn from(value: SwapDirection) -> Self {
|
||||
match value {
|
||||
SwapDirection::Buy => 0,
|
||||
SwapDirection::Sell => 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(ValueEnum, Debug, Clone, Deserialize)]
|
||||
pub enum SwapInType {
|
||||
#[serde(rename = "qty")]
|
||||
Qty,
|
||||
#[serde(rename = "pct")]
|
||||
Pct,
|
||||
}
|
||||
|
||||
pub async fn pump_swap(
|
||||
state: AppState,
|
||||
swap_input: SwapInput,
|
||||
swap_direction: &str,
|
||||
use_jito: bool,
|
||||
urgent: bool,
|
||||
) -> Result<Vec<String>> {
|
||||
if swap_input.amount == 0 {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Skipping swap: provided amount is 0 lamports"
|
||||
));
|
||||
}
|
||||
|
||||
// Convert the provided swap_direction string to our enum.
|
||||
let swap_direction_enum = match swap_direction {
|
||||
"buy" => SwapDirection::Buy,
|
||||
"sell" => SwapDirection::Sell,
|
||||
_ => anyhow::bail!("Invalid swap direction"),
|
||||
};
|
||||
|
||||
// Default to the provided slippage...
|
||||
let mut slippage = swap_input.slippage_bps as u64;
|
||||
|
||||
// 🔧 Add more slippage for sells to prevent 6003 errors
|
||||
if swap_direction_enum == SwapDirection::Sell {
|
||||
slippage += 50; // Add 10bps extra
|
||||
}
|
||||
|
||||
let swap_config = SwapConfig {
|
||||
slippage,
|
||||
swap_direction: swap_direction_enum,
|
||||
use_jito,
|
||||
use_priority_tip: urgent,
|
||||
cu_limits: None,
|
||||
priority_fee: None,
|
||||
wrap_and_unwrap_sol: Some(true),
|
||||
as_legacy_transaction: Some(false),
|
||||
};
|
||||
|
||||
let swapx = Pump::new(state.rpc_nonblocking_client, state.rpc_client, state.wallet);
|
||||
|
||||
let mint = if swap_direction_enum == SwapDirection::Buy {
|
||||
swap_input.output_token_mint.to_string()
|
||||
} else {
|
||||
swap_input.input_token_mint.to_string()
|
||||
};
|
||||
|
||||
let amount_in = swap_input.amount;
|
||||
|
||||
let res = swapx
|
||||
.swap(&mint, swap_config, swap_input, amount_in)
|
||||
.await?;
|
||||
Ok(res)
|
||||
}
|
||||
151
#_sniper (Rust) using jito Shred stream/src/hardcap.rs
Normal file
151
#_sniper (Rust) using jito Shred stream/src/hardcap.rs
Normal file
@@ -0,0 +1,151 @@
|
||||
pub async fn handle_buy_and_sell_logic(
|
||||
txn: &ConfirmedTransactionWithStatusMeta,
|
||||
sell_sender: &Sender<(String, u64)>,
|
||||
) {
|
||||
let logger = Logger::new("[BUY/SELL LOGIC] => ".to_string());
|
||||
let our_pubkey = env::var("WALLET_PUBKEY").unwrap_or_default();
|
||||
let min_inflow: f64 = env::var("MIN_SOL_INFLOW_TRIGGER").unwrap_or("0.5".to_string()).parse().unwrap_or(0.5);
|
||||
let min_outflow: f64 = env::var("MIN_SOL_OUTFLOW_TRIGGER").unwrap_or("0.5".to_string()).parse().unwrap_or(0.5);
|
||||
|
||||
// Extract our on-chain slot for comparisons
|
||||
let current_slot = CURRENT_SLOT.load(std::sync::atomic::Ordering::Relaxed);
|
||||
|
||||
let TransactionWithStatusMeta::Complete(vtx) = &txn.tx_with_meta else { return };
|
||||
let Some(post_balances) = &vtx.meta.post_token_balances else { return };
|
||||
let Some(pre_balances) = &vtx.meta.pre_token_balances else { return };
|
||||
|
||||
let mut tokens = BOUGHT_TOKENS.lock().await;
|
||||
|
||||
for (i, post_tb) in post_balances.iter().enumerate() {
|
||||
if i >= pre_balances.len() { continue; }
|
||||
|
||||
let pre_tb = &pre_balances[i];
|
||||
let mint = &post_tb.mint;
|
||||
let owner = post_tb.owner.clone();
|
||||
let ata = post_tb.account_index.to_string();
|
||||
|
||||
let pre_amount = pre_tb.ui_token_amount.ui_amount.unwrap_or(0.0);
|
||||
let post_amount = post_tb.ui_token_amount.ui_amount.unwrap_or(0.0);
|
||||
let delta = post_amount - pre_amount;
|
||||
|
||||
if let Some(entry) = tokens.get_mut(mint) {
|
||||
if entry.buy_slot() == 0 {
|
||||
continue;
|
||||
}
|
||||
if entry.sell_triggered_at().is_some() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let is_from_our_ata = Some(ata.clone()) == entry.ata().cloned();
|
||||
let is_owner_ours = owner == our_pubkey;
|
||||
|
||||
|
||||
// Time to slot delta instead of wall-clock
|
||||
let slot_delta = current_slot.saturating_sub(entry.buy_slot());
|
||||
|
||||
if delta > 0.0 && !is_owner_ours && !is_from_our_ata {
|
||||
if entry.add_unique_buyer(owner.clone()) {
|
||||
logger.log(format!(
|
||||
"🧍 Unique buyer for {}: {} | Total: {}",
|
||||
mint,
|
||||
owner,
|
||||
entry.unique_buyers().len()
|
||||
));
|
||||
|
||||
if entry.unique_buyers().len() == 1 && entry.suspected_creator().is_none() {
|
||||
entry.set_suspected_creator(owner.clone());
|
||||
info!("{}", format!("🧠 Suspected creator flagged: {} on {}", owner, mint));
|
||||
}
|
||||
}
|
||||
|
||||
// Early rug detection: <2 buyers after X slots
|
||||
if entry.unique_buyers().len() < 10 && slot_delta > 12 {
|
||||
entry.set_sell_triggered(true);
|
||||
entry.set_sell_triggered_at(Instant::now());
|
||||
info!("{}", format!("🛑 Rug suspected — Forcing sell on {} after {} slots", mint, slot_delta));
|
||||
if sell_sender.send((mint.clone(), entry.amount())).await.is_ok() {
|
||||
info!("{}", format!("📤 Sell sent for {}", mint));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Exhausted follow-ups
|
||||
if entry.unique_buyers().len() >= 5 {
|
||||
entry.set_sell_triggered(true);
|
||||
entry.set_sell_triggered_at(Instant::now());
|
||||
info!("{}", format!("📉 Follow-up exhaustion — Selling {} after 3 buyers", mint));
|
||||
if sell_sender.send((mint.clone(), entry.amount())).await.is_ok() {
|
||||
info!("{}", format!("📤 Sell sent for {}", mint));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// SOL inflow/outflow logic (unchanged)
|
||||
if let Ok(pid) = Pubkey::from_str(PUMP_PROGRAM) {
|
||||
if let Ok(bonding_curve) = get_pda(&Pubkey::from_str(mint).unwrap(), &pid) {
|
||||
let message = &vtx.transaction.message;
|
||||
let mut keys = match message {
|
||||
VersionedMessage::Legacy(m) => m.account_keys.clone(),
|
||||
VersionedMessage::V0(v0) => {
|
||||
let mut k = v0.account_keys.clone();
|
||||
k.extend(vtx.meta.loaded_addresses.writable.clone());
|
||||
k.extend(vtx.meta.loaded_addresses.readonly.clone());
|
||||
k
|
||||
}
|
||||
};
|
||||
if let Some(idx) = keys.iter().position(|k| k == &bonding_curve) {
|
||||
let pre_sol = vtx.meta.pre_balances[idx];
|
||||
let post_sol = vtx.meta.post_balances[idx];
|
||||
let delta_sol = (post_sol as i64 - pre_sol as i64) as f64 / 1e9;
|
||||
logger.log(format!(
|
||||
"🔍 Mint: {} | ΔSOL: {:.6} | Slot: {}", mint, delta_sol, txn.slot
|
||||
));
|
||||
|
||||
if delta_sol > 0.0 {
|
||||
entry.add_sol_inflow(delta_sol);
|
||||
} else if delta_sol < 0.0 {
|
||||
entry.add_sol_outflow(-delta_sol);
|
||||
if slot_delta <= 1 {
|
||||
entry.set_sell_triggered(true);
|
||||
entry.set_sell_triggered_at(Instant::now());
|
||||
info!("{}", format!("💣 Early SOL drain! Fast sell on {}", mint));
|
||||
if sell_sender.send((mint.clone(), entry.amount())).await.is_ok() {
|
||||
info!("{}", format!("📤 Sell sent for {}", mint));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if delta_sol < -min_outflow {
|
||||
entry.set_sell_triggered(true);
|
||||
entry.set_sell_triggered_at(Instant::now());
|
||||
info!("{}", format!("💣 Outflow sell on {} | ΔSOL: {:.6}", mint, delta_sol));
|
||||
if sell_sender.send((mint.clone(), entry.amount())).await.is_ok() {
|
||||
info!("{}", format!("📤 Sell sent for {}", mint));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if entry.sol_inflow() >= min_inflow {
|
||||
entry.set_sell_triggered(true);
|
||||
entry.set_sell_triggered_at(Instant::now());
|
||||
info!("{}", format!("🚀 Inflow sell on {} | Total {:.6} SOL", mint, entry.sol_inflow()));
|
||||
let mint_c = mint.clone(); let amt = entry.amount(); let tx_s = sell_sender.clone();
|
||||
let target_slot = current_slot + 1;
|
||||
tokio::spawn(async move {
|
||||
while CURRENT_SLOT.load(Ordering::Relaxed) < target_slot {
|
||||
tokio::time::sleep(Duration::from_millis(10)).await;
|
||||
}
|
||||
if tx_s.send((mint_c.clone(), amt)).await.is_ok() {
|
||||
info!("📤 Delayed sell sent for {}", mint_c);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
use crate::serialization::serialize_pubkey;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use solana_program::{program_error::ProgramError, pubkey::Pubkey};
|
||||
use solana_sdk::instruction::AccountMeta;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct IdlInstruction {
|
||||
name: String,
|
||||
accounts: Vec<IdlAccount>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct IdlAccount {
|
||||
name: String,
|
||||
#[serde(rename = "isMut")]
|
||||
is_mut: bool,
|
||||
#[serde(rename = "isSigner")]
|
||||
is_signer: bool,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Idl {
|
||||
instructions: Vec<IdlInstruction>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct AccountMetadata {
|
||||
#[serde(serialize_with = "serialize_pubkey")]
|
||||
pub pubkey: Pubkey,
|
||||
pub is_writable: bool,
|
||||
pub is_signer: bool,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
pub trait InstructionAccountMapper<'info> {
|
||||
fn map_accounts<'me>(
|
||||
&self,
|
||||
accounts: &[AccountMeta],
|
||||
instruction_name: &str,
|
||||
) -> Result<Vec<AccountMetadata>, ProgramError>;
|
||||
}
|
||||
|
||||
impl<'info> InstructionAccountMapper<'info> for Idl {
|
||||
fn map_accounts<'me>(
|
||||
&self,
|
||||
accounts: &[AccountMeta],
|
||||
instruction_name: &str,
|
||||
) -> Result<Vec<AccountMetadata>, ProgramError> {
|
||||
let instruction = self
|
||||
.instructions
|
||||
.iter()
|
||||
.find(|ix| ix.name == instruction_name)
|
||||
.ok_or(ProgramError::InvalidArgument)?;
|
||||
|
||||
let mut account_metadata: Vec<AccountMetadata> = accounts
|
||||
.iter()
|
||||
.take(instruction.accounts.len())
|
||||
.enumerate()
|
||||
.map(|(i, account)| {
|
||||
let account_info = &instruction.accounts[i];
|
||||
AccountMetadata {
|
||||
pubkey: account.pubkey,
|
||||
is_writable: account_info.is_mut,
|
||||
is_signer: account_info.is_signer,
|
||||
name: account_info.name.clone(),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
for (i, account) in accounts.iter().enumerate().skip(instruction.accounts.len()) {
|
||||
account_metadata.push(AccountMetadata {
|
||||
pubkey: account.pubkey,
|
||||
is_writable: account.is_writable,
|
||||
is_signer: account.is_signer,
|
||||
name: format!("Remaining accounts {}", i - instruction.accounts.len() + 1),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(account_metadata)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
pub fn run_latency(block_time_a : i64, block_time_b: i64) -> i64 {
|
||||
block_time_a - block_time_b
|
||||
}
|
||||
14
#_sniper (Rust) using jito Shred stream/src/latest_block.rs
Normal file
14
#_sniper (Rust) using jito Shred stream/src/latest_block.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
use solana_client::rpc_client::RpcClient;
|
||||
use solana_client::client_error::ClientError;
|
||||
use anyhow::Context;
|
||||
|
||||
|
||||
const API_KEY: &str = "api_key";
|
||||
|
||||
pub fn get_latest_slot() -> anyhow::Result<u64> {
|
||||
let rpc_url = format!("https://rpc.va.shyft.to?api_key={}", API_KEY);
|
||||
|
||||
let client = RpcClient::new(rpc_url);
|
||||
|
||||
client.get_slot().context("Failed to fetch latest slot")
|
||||
}
|
||||
9
#_sniper (Rust) using jito Shred stream/src/lib.rs
Normal file
9
#_sniper (Rust) using jito Shred stream/src/lib.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
pub mod common;
|
||||
pub mod core;
|
||||
pub mod dex;
|
||||
pub mod engine;
|
||||
pub mod services;
|
||||
pub mod trading_loop;
|
||||
|
||||
pub use trading_loop::get_notify_handle;
|
||||
pub use trading_loop::start_trading_loop;
|
||||
90
#_sniper (Rust) using jito Shred stream/src/logger.rs
Normal file
90
#_sniper (Rust) using jito Shred stream/src/logger.rs
Normal file
@@ -0,0 +1,90 @@
|
||||
use chrono::Local;
|
||||
use serde_json::json;
|
||||
use std::{
|
||||
fs::OpenOptions,
|
||||
io::Write,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
const LOG_LEVEL: &str = "LOG";
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Logger {
|
||||
prefix: String,
|
||||
date_format: String,
|
||||
file: Arc<Mutex<std::fs::File>>,
|
||||
}
|
||||
|
||||
impl Logger {
|
||||
// Constructor to create a new logger that writes to "logs.json"
|
||||
pub fn new(prefix: String) -> Self {
|
||||
let file = OpenOptions::new()
|
||||
.create(true)
|
||||
.append(true)
|
||||
.open("detectionlogs.json")
|
||||
.expect("Failed to open logs.json for writing");
|
||||
|
||||
Logger {
|
||||
prefix,
|
||||
date_format: String::from("%Y-%m-%d %H:%M:%S"),
|
||||
file: Arc::new(Mutex::new(file)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn log(&self, message: String) -> String {
|
||||
let full_log = format!("{} {}", self.prefix_with_date(), message);
|
||||
println!("{}", full_log);
|
||||
self.write_json("INFO", &message);
|
||||
full_log
|
||||
}
|
||||
|
||||
pub fn debug(&self, message: String) -> String {
|
||||
let full_log = format!("{} [{}] {}", self.prefix_with_date(), "DEBUG", message);
|
||||
if LogLevel::new().is_debug() {
|
||||
println!("{}", full_log);
|
||||
self.write_json("DEBUG", &message);
|
||||
}
|
||||
full_log
|
||||
}
|
||||
|
||||
pub fn error(&self, message: String) -> String {
|
||||
let full_log = format!("{} [{}] {}", self.prefix_with_date(), "ERROR", message);
|
||||
println!("{}", full_log);
|
||||
self.write_json("ERROR", &message);
|
||||
full_log
|
||||
}
|
||||
|
||||
fn prefix_with_date(&self) -> String {
|
||||
let date = Local::now();
|
||||
format!("[{}] {}", date.format(&self.date_format), self.prefix)
|
||||
}
|
||||
|
||||
fn write_json(&self, level: &str, message: &str) {
|
||||
let now = Local::now();
|
||||
let entry = json!({
|
||||
"timestamp": now.to_rfc3339(),
|
||||
"level": level,
|
||||
"prefix": self.prefix,
|
||||
"message": message,
|
||||
});
|
||||
|
||||
if let Ok(mut file) = self.file.lock() {
|
||||
if let Err(e) = writeln!(file, "{}", entry) {
|
||||
eprintln!("Failed to write to log file: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct LogLevel<'a> {
|
||||
level: &'a str,
|
||||
}
|
||||
impl LogLevel<'_> {
|
||||
fn new() -> Self {
|
||||
LogLevel { level: LOG_LEVEL }
|
||||
}
|
||||
|
||||
fn is_debug(&self) -> bool {
|
||||
self.level.to_lowercase() == "debug"
|
||||
}
|
||||
}
|
||||
157
#_sniper (Rust) using jito Shred stream/src/secondbuy.rs
Normal file
157
#_sniper (Rust) using jito Shred stream/src/secondbuy.rs
Normal file
@@ -0,0 +1,157 @@
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum DetectionStrategy {
|
||||
TokenCreation,
|
||||
FirstBuy,
|
||||
SuspectedCreatorSell,
|
||||
}
|
||||
|
||||
|
||||
pub async fn handle_detection_event(
|
||||
txn: &ConfirmedTransactionWithStatusMeta,
|
||||
slot: u64,
|
||||
strategy: DetectionStrategy,
|
||||
mint_override: Option<String>, // Only used for creation strategy
|
||||
) {
|
||||
match strategy {
|
||||
DetectionStrategy::TokenCreation => {
|
||||
if let Some(mint) = mint_override {
|
||||
let creation_time = current_unix_timestamp();
|
||||
let mut creations = TOKEN_CREATIONS.lock().await;
|
||||
creations.insert(mint.clone(), TokenCreationInfo {
|
||||
mint,
|
||||
creation_time,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
DetectionStrategy::FirstBuy => {
|
||||
if TOKEN_CREATIONS.lock().await.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
if let TransactionWithStatusMeta::Complete(versioned_tx_with_meta) = &txn.tx_with_meta {
|
||||
if let (Some(pre_token_balances), Some(post_token_balances)) =
|
||||
(&versioned_tx_with_meta.meta.pre_token_balances, &versioned_tx_with_meta.meta.post_token_balances)
|
||||
{
|
||||
for (i, post_tb) in post_token_balances.iter().enumerate() {
|
||||
if let Some(post_ui) = post_tb.ui_token_amount.ui_amount {
|
||||
if i >= pre_token_balances.len() { continue; }
|
||||
|
||||
let pre_tb = &pre_token_balances[i];
|
||||
if let Some(pre_ui) = pre_tb.ui_token_amount.ui_amount {
|
||||
let delta = post_ui - pre_ui;
|
||||
if delta >= 0.0 { continue; }
|
||||
|
||||
let buy_amount = -delta;
|
||||
let mint = pre_tb.mint.clone();
|
||||
let buyer = pre_tb.owner.clone();
|
||||
|
||||
const DEFAULT_TOTAL_SUPPLY: f64 = SUPPLY_THRESHOLD_UI;
|
||||
const MIN_BUY_FRACTION: f64 = 0.000001;
|
||||
const MAX_BUY_FRACTION: f64 = 0.10;
|
||||
|
||||
if pre_ui < DEFAULT_TOTAL_SUPPLY * 0.98 { continue; }
|
||||
if buy_amount < DEFAULT_TOTAL_SUPPLY * MIN_BUY_FRACTION
|
||||
|| buy_amount > DEFAULT_TOTAL_SUPPLY * MAX_BUY_FRACTION
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut creations = TOKEN_CREATIONS.lock().await;
|
||||
if !creations.contains_key(&mint) {
|
||||
println!("[EVENT] No creation event for {}; skipping first buy.", mint);
|
||||
continue;
|
||||
}
|
||||
|
||||
creations.remove(&mint);
|
||||
drop(creations);
|
||||
|
||||
let mut map = TRACKED_TOKENS.lock().await;
|
||||
if let Some(entry) = map.get_mut(&mint) {
|
||||
if entry.suspected_creators.insert(buyer.clone()) {
|
||||
entry.sell_split_ratio = entry.suspected_creators.len();
|
||||
println!(
|
||||
"[FOLLOW-UP CREATOR] Mint: {} | New suspected creator: {} | Total creators: {}",
|
||||
mint, buyer, entry.sell_split_ratio
|
||||
);
|
||||
}
|
||||
} else {
|
||||
let mut suspected = HashSet::new();
|
||||
suspected.insert(buyer.clone());
|
||||
|
||||
map.insert(mint.clone(), TokenTrackingState {
|
||||
mint: mint.clone(),
|
||||
first_buyer: Some(buyer.clone()),
|
||||
first_buy_amount: buy_amount,
|
||||
suspected_creators: suspected,
|
||||
sell_detected: false,
|
||||
sell_split_ratio: 0,
|
||||
has_bought: false,
|
||||
bought_amount: None,
|
||||
has_sold: false,
|
||||
open_trade_permit: None,
|
||||
detected_buy_slot: Some(slot),
|
||||
});
|
||||
|
||||
println!("[NEW TOKEN TRACKED] Mint: {} | First Buyer: {} | Buy Amount: {} | Slot: {}",
|
||||
mint, buyer, buy_amount, slot);
|
||||
log::info!("New token tracked: {} bought by {}", mint, buyer);
|
||||
|
||||
let notify = get_notify_handle().await;
|
||||
notify.notify_one();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DetectionStrategy::SuspectedCreatorSell => {
|
||||
if let TransactionWithStatusMeta::Complete(versioned_tx_with_meta) = &txn.tx_with_meta {
|
||||
if let (Some(pre_token_balances), Some(post_token_balances)) =
|
||||
(&versioned_tx_with_meta.meta.pre_token_balances, &versioned_tx_with_meta.meta.post_token_balances)
|
||||
{
|
||||
for (i, post_tb) in post_token_balances.iter().enumerate() {
|
||||
if let Some(post_ui) = post_tb.ui_token_amount.ui_amount {
|
||||
if i < pre_token_balances.len() {
|
||||
let pre_tb = &pre_token_balances[i];
|
||||
if let Some(pre_ui) = pre_tb.ui_token_amount.ui_amount {
|
||||
let delta = post_ui - pre_ui;
|
||||
if delta >= 0.0 { continue; }
|
||||
|
||||
let mint = pre_tb.mint.clone();
|
||||
let seller = pre_tb.owner.clone();
|
||||
|
||||
let mut map = TRACKED_TOKENS.lock().await;
|
||||
if let Some(entry) = map.get_mut(&mint) {
|
||||
if !entry.has_bought || entry.bought_amount.unwrap_or(0) == 0 {
|
||||
log::info!(
|
||||
"[SELL IGNORED] Mint {}: Suspected creator {} sold but we haven't bought yet",
|
||||
mint, seller
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if entry.suspected_creators.contains(&seller) && !entry.sell_detected {
|
||||
entry.sell_detected = true;
|
||||
entry.sell_split_ratio = entry.suspected_creators.len();
|
||||
|
||||
log::info!(
|
||||
"[SELL DETECTED] Mint {}: Seller {} triggered sell | Total suspected creators: {}",
|
||||
mint, seller, entry.sell_split_ratio
|
||||
);
|
||||
|
||||
let notify = get_notify_handle().await;
|
||||
notify.notify_one();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
18
#_sniper (Rust) using jito Shred stream/src/serialization.rs
Normal file
18
#_sniper (Rust) using jito Shred stream/src/serialization.rs
Normal file
@@ -0,0 +1,18 @@
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
|
||||
pub fn serialize_pubkey<S>(value: &Pubkey, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
serializer.serialize_str(&value.to_string())
|
||||
}
|
||||
|
||||
pub fn serialize_option_pubkey<S>(value: &Option<Pubkey>, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
match value {
|
||||
Some(pubkey) => serializer.serialize_str(&pubkey.to_string()),
|
||||
None => serializer.serialize_none(),
|
||||
}
|
||||
}
|
||||
180
#_sniper (Rust) using jito Shred stream/src/services/jito.rs
Normal file
180
#_sniper (Rust) using jito Shred stream/src/services/jito.rs
Normal file
@@ -0,0 +1,180 @@
|
||||
use std::{future::Future, str::FromStr, sync::LazyLock, time::Duration};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use indicatif::{ProgressBar, ProgressStyle};
|
||||
use rand::{seq::IteratorRandom, thread_rng};
|
||||
use serde::Deserialize;
|
||||
use serde_json::Value;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use tokio::{
|
||||
sync::RwLock,
|
||||
time::{sleep, Instant},
|
||||
};
|
||||
|
||||
use crate::common::utils::import_env_var;
|
||||
|
||||
pub static BLOCK_ENGINE_URL: LazyLock<String> =
|
||||
LazyLock::new(|| import_env_var("JITO_BLOCK_ENGINE_URL"));
|
||||
pub static TIP_STREAM_URL: LazyLock<String> =
|
||||
LazyLock::new(|| import_env_var("JITO_TIP_STREAM_URL"));
|
||||
pub static TIP_PERCENTILE: LazyLock<String> =
|
||||
LazyLock::new(|| import_env_var("JITO_TIP_PERCENTILE"));
|
||||
|
||||
pub static TIP_ACCOUNTS: LazyLock<RwLock<Vec<String>>> = LazyLock::new(|| RwLock::new(vec![]));
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TipAccountResult {
|
||||
pub accounts: Vec<String>,
|
||||
}
|
||||
|
||||
pub async fn init_tip_accounts() -> Result<()> {
|
||||
let accounts = TipAccountResult {
|
||||
accounts: vec![
|
||||
"96gYZGLnJYVFmbjzopPSU6QiEV5fGqZNyN9nmNhvrZU5".to_string(),
|
||||
"HFqU5x63VTqvQss8hp11i4wVV8bD44PvwucfZ2bU7gRe".to_string(),
|
||||
"Cw8CFyM9FkoMi7K7Crf6HNQqf4uEMzpKw6QNghXLvLkY".to_string(),
|
||||
"ADaUMid9yfUytqMBgopwjb2DTLSokTSzL1zt6iGPaS49".to_string(),
|
||||
"DfXygSm4jCyNCybVYYK6DwvWqjKee8pbDmJGcLWNDXjh".to_string(),
|
||||
"ADuUkR4vqLUMWXxW9gh6D6L8pMSawimctcNZ5pGwDcEt".to_string(),
|
||||
"DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL".to_string(),
|
||||
"3AVi9Tg9Uo68tJfuvoKvqKNWKkC5wPdSSdeBnizKZ6jT".to_string(),
|
||||
],
|
||||
};
|
||||
let mut tip_accounts = TIP_ACCOUNTS.write().await;
|
||||
|
||||
accounts
|
||||
.accounts
|
||||
.iter()
|
||||
.for_each(|account| tip_accounts.push(account.to_string()));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_tip_account() -> Result<Pubkey> {
|
||||
let accounts = TIP_ACCOUNTS.read().await;
|
||||
let mut rng = thread_rng();
|
||||
match accounts.iter().choose(&mut rng) {
|
||||
Some(acc) => Ok(Pubkey::from_str(acc).inspect_err(|err| {
|
||||
println!("jito: failed to parse Pubkey: {:?}", err);
|
||||
})?),
|
||||
None => Err(anyhow!("jito: no tip accounts available")),
|
||||
}
|
||||
}
|
||||
// unit sol
|
||||
pub async fn get_tip_value() -> Result<f64> {
|
||||
// If TIP_VALUE is set, use it
|
||||
if let Ok(tip_value) = std::env::var("JITO_TIP_VALUE") {
|
||||
match f64::from_str(&tip_value) {
|
||||
Ok(value) => Ok(value),
|
||||
Err(_) => {
|
||||
println!(
|
||||
"Invalid JITO_TIP_VALUE in environment variable: '{}'. Falling back to percentile calculation.",
|
||||
tip_value
|
||||
);
|
||||
Err(anyhow!("Invalid TIP_VALUE in environment variable"))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Err(anyhow!("JITO_TIP_VALUE environment variable not set"))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn fetch_bundle_status(bundle_id: String) -> Result<Vec<serde_json::Value>> {
|
||||
// Example implementation using reqwest:
|
||||
use reqwest::Client;
|
||||
let url = format!(
|
||||
"{}/bundle/{}",
|
||||
crate::common::utils::import_env_var("JITO_BLOCK_ENGINE_URL"),
|
||||
bundle_id
|
||||
);
|
||||
let client = Client::new();
|
||||
let resp = client.get(&url).send().await?;
|
||||
let json: Vec<serde_json::Value> = resp.json().await?;
|
||||
Ok(json)
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct BundleStatus {
|
||||
pub bundle_id: String,
|
||||
pub transactions: Vec<String>,
|
||||
pub slot: u64,
|
||||
pub confirmation_status: String,
|
||||
pub err: ErrorStatus,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct ErrorStatus {
|
||||
#[serde(rename = "Ok")]
|
||||
pub ok: Option<()>,
|
||||
}
|
||||
|
||||
pub async fn wait_for_bundle_confirmation<F, Fut>(
|
||||
fetch_statuses: F,
|
||||
bundle_id: String,
|
||||
interval: Duration,
|
||||
timeout: Duration,
|
||||
) -> Result<Vec<String>>
|
||||
where
|
||||
F: Fn(String) -> Fut,
|
||||
Fut: Future<Output = Result<Vec<Value>>>,
|
||||
{
|
||||
let progress_bar = new_progress_bar();
|
||||
let start_time = Instant::now();
|
||||
|
||||
loop {
|
||||
let statuses = fetch_statuses(bundle_id.clone()).await?;
|
||||
|
||||
if let Some(status) = statuses.first() {
|
||||
let bundle_status: BundleStatus =
|
||||
serde_json::from_value(status.clone()).inspect_err(|err| {
|
||||
println!(
|
||||
"Failed to parse JSON when get_bundle_statuses, err: {}",
|
||||
err,
|
||||
);
|
||||
})?;
|
||||
|
||||
println!("{:?}", bundle_status);
|
||||
match bundle_status.confirmation_status.as_str() {
|
||||
"finalized" | "confirmed" => {
|
||||
progress_bar.finish_and_clear();
|
||||
println!(
|
||||
"Finalized bundle {}: {}",
|
||||
bundle_id, bundle_status.confirmation_status
|
||||
);
|
||||
// print tx
|
||||
bundle_status
|
||||
.transactions
|
||||
.iter()
|
||||
.for_each(|tx| println!("https://solscan.io/tx/{}", tx));
|
||||
return Ok(bundle_status.transactions);
|
||||
}
|
||||
_ => {
|
||||
progress_bar.set_message(format!(
|
||||
"Finalizing bundle {}: {}",
|
||||
bundle_id, bundle_status.confirmation_status
|
||||
));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
progress_bar.set_message(format!("Finalizing bundle {}: {}", bundle_id, "None"));
|
||||
}
|
||||
|
||||
// check loop exceeded 1 minute,
|
||||
if start_time.elapsed() > timeout {
|
||||
println!("Loop exceeded {:?}, breaking out.", timeout);
|
||||
return Err(anyhow!("Bundle status get timeout"));
|
||||
}
|
||||
|
||||
// Wait for a certain duration before retrying
|
||||
sleep(interval).await;
|
||||
}
|
||||
}
|
||||
pub fn new_progress_bar() -> ProgressBar {
|
||||
let progress_bar = ProgressBar::new(42);
|
||||
progress_bar.set_style(
|
||||
ProgressStyle::default_spinner()
|
||||
.template("{spinner:.green} {wide_msg}")
|
||||
.expect("ProgressStyle::template direct input to be correct"),
|
||||
);
|
||||
progress_bar.enable_steady_tick(Duration::from_millis(100));
|
||||
progress_bar
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
pub mod jito;
|
||||
pub mod nextblock;
|
||||
pub mod zeroslot;
|
||||
@@ -0,0 +1,75 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use rand::{seq::IteratorRandom, thread_rng};
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use std::{str::FromStr, sync::LazyLock};
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use crate::common::utils::import_env_var;
|
||||
|
||||
// Endpoint and auth token from env
|
||||
pub static NEXTBLOCK_API_URL: LazyLock<String> =
|
||||
LazyLock::new(|| import_env_var("NEXTBLOCK_API_URL"));
|
||||
pub static NEXTBLOCK_AUTH_HEADER: LazyLock<String> =
|
||||
LazyLock::new(|| import_env_var("NEXTBLOCK_AUTH_HEADER"));
|
||||
pub static NEXTBLOCK_TIP_VALUE: LazyLock<String> =
|
||||
LazyLock::new(|| import_env_var("NEXTBLOCK_TIP_VALUE"));
|
||||
|
||||
// List of hardcoded tip accounts
|
||||
pub static TIP_ACCOUNTS: LazyLock<RwLock<Vec<String>>> = LazyLock::new(|| RwLock::new(vec![]));
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TipAccountResult {
|
||||
pub accounts: Vec<String>,
|
||||
}
|
||||
|
||||
pub async fn init_tip_accounts() -> Result<()> {
|
||||
let accounts = TipAccountResult {
|
||||
accounts: vec![
|
||||
"NextbLoCkVtMGcV47JzewQdvBpLqT9TxQFozQkN98pE".to_string(),
|
||||
"NexTbLoCkWykbLuB1NkjXgFWkX9oAtcoagQegygXXA2".to_string(),
|
||||
"NeXTBLoCKs9F1y5PJS9CKrFNNLU1keHW71rfh7KgA1X".to_string(),
|
||||
"NexTBLockJYZ7QD7p2byrUa6df8ndV2WSd8GkbWqfbb".to_string(),
|
||||
"neXtBLock1LeC67jYd1QdAa32kbVeubsfPNTJC1V5At".to_string(),
|
||||
"nEXTBLockYgngeRmRrjDV31mGSekVPqZoMGhQEZtPVG".to_string(),
|
||||
"NEXTbLoCkB51HpLBLojQfpyVAMorm3zzKg7w9NFdqid".to_string(),
|
||||
"nextBLoCkPMgmG8ZgJtABeScP35qLa2AMCNKntAP7Xc".to_string(),
|
||||
],
|
||||
};
|
||||
let mut tip_accounts = TIP_ACCOUNTS.write().await;
|
||||
|
||||
accounts
|
||||
.accounts
|
||||
.iter()
|
||||
.for_each(|account| tip_accounts.push(account.to_string()));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_tip_account() -> Result<Pubkey> {
|
||||
let accounts = TIP_ACCOUNTS.read().await;
|
||||
let mut rng = thread_rng();
|
||||
match accounts.iter().choose(&mut rng) {
|
||||
Some(acc) => Ok(Pubkey::from_str(acc).inspect_err(|err| {
|
||||
println!("nextblock: failed to parse Pubkey: {:?}", err);
|
||||
})?),
|
||||
None => Err(anyhow!("nextblock: no tip accounts available")),
|
||||
}
|
||||
}
|
||||
|
||||
// unit sol
|
||||
pub async fn get_tip_value() -> Result<f64> {
|
||||
// If TIP_VALUE is set, use it
|
||||
if let Ok(tip_value) = std::env::var("NEXTBLOCK_TIP_VALUE") {
|
||||
match f64::from_str(&tip_value) {
|
||||
Ok(value) => Ok(value),
|
||||
Err(_) => {
|
||||
println!(
|
||||
"Invalid NEXTBLOCK_TIP_VALUE in environment variable: '{}'. Falling back to percentile calculation.",
|
||||
tip_value
|
||||
);
|
||||
Err(anyhow!("Invalid TIP_VALUE in environment variable"))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Err(anyhow!("NEXTBLOCK_TIP_VALUE environment variable not set"))
|
||||
}
|
||||
}
|
||||
179
#_sniper (Rust) using jito Shred stream/src/services/zeroslot.rs
Normal file
179
#_sniper (Rust) using jito Shred stream/src/services/zeroslot.rs
Normal file
@@ -0,0 +1,179 @@
|
||||
use std::{future::Future, str::FromStr, sync::LazyLock, time::Duration};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use indicatif::{ProgressBar, ProgressStyle};
|
||||
use rand::{seq::IteratorRandom, thread_rng};
|
||||
use serde::Deserialize;
|
||||
use serde_json::Value;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use tokio::{
|
||||
sync::RwLock,
|
||||
time::{sleep, Instant},
|
||||
};
|
||||
|
||||
use crate::common::utils::import_env_var;
|
||||
|
||||
pub static BLOCK_ENGINE_URL: LazyLock<String> =
|
||||
LazyLock::new(|| import_env_var("ZEROSLOT_BLOCK_ENGINE_URL"));
|
||||
pub static TIP_STREAM_URL: LazyLock<String> =
|
||||
LazyLock::new(|| import_env_var("ZEROSLOT_TIP_STREAM_URL"));
|
||||
pub static TIP_PERCENTILE: LazyLock<String> =
|
||||
LazyLock::new(|| import_env_var("ZEROSLOT_TIP_PERCENTILE"));
|
||||
|
||||
pub static TIP_ACCOUNTS: LazyLock<RwLock<Vec<String>>> = LazyLock::new(|| RwLock::new(vec![]));
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TipAccountResult {
|
||||
pub accounts: Vec<String>,
|
||||
}
|
||||
|
||||
pub async fn init_tip_accounts() -> Result<()> {
|
||||
let accounts = TipAccountResult {
|
||||
accounts: vec![
|
||||
"Eb2KpSC8uMt9GmzyAEm5Eb1AAAgTjRaXWFjKyFXHZxF3".to_string(),
|
||||
"FCjUJZ1qozm1e8romw216qyfQMaaWKxWsuySnumVCCNe".to_string(),
|
||||
"ENxTEjSQ1YabmUpXAdCgevnHQ9MHdLv8tzFiuiYJqa13".to_string(),
|
||||
"6rYLG55Q9RpsPGvqdPNJs4z5WTxJVatMB8zV3WJhs5EK".to_string(),
|
||||
"Cix2bHfqPcKcM233mzxbLk14kSggUUiz2A87fJtGivXr".to_string(),
|
||||
],
|
||||
};
|
||||
let mut tip_accounts = TIP_ACCOUNTS.write().await;
|
||||
|
||||
accounts
|
||||
.accounts
|
||||
.iter()
|
||||
.for_each(|account| tip_accounts.push(account.to_string()));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_tip_account() -> Result<Pubkey> {
|
||||
let accounts = TIP_ACCOUNTS.read().await;
|
||||
let mut rng = thread_rng();
|
||||
match accounts.iter().choose(&mut rng) {
|
||||
Some(acc) => Ok(Pubkey::from_str(acc).inspect_err(|err| {
|
||||
println!("jito: failed to parse Pubkey: {:?}", err);
|
||||
})?),
|
||||
None => Err(anyhow!("jito: no tip accounts available")),
|
||||
}
|
||||
}
|
||||
// unit sol
|
||||
pub async fn get_tip_value() -> Result<f64> {
|
||||
// If TIP_VALUE is set, use it
|
||||
if let Ok(tip_value) = std::env::var("ZEROSLOT_TIP_VALUE") {
|
||||
match f64::from_str(&tip_value) {
|
||||
Ok(value) => Ok(value),
|
||||
Err(_) => {
|
||||
println!(
|
||||
"Invalid ZEROSLOT_TIP_VALUE in environment variable: '{}'. Falling back to percentile calculation.",
|
||||
tip_value
|
||||
);
|
||||
Err(anyhow!(
|
||||
"Invalid ZEROSLOT_TIP_VALUE in environment variable"
|
||||
))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Err(anyhow!("ZEROSLOT_TIP_VALUE environment variable not set"))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn fetch_bundle_status(bundle_id: String) -> Result<Vec<serde_json::Value>> {
|
||||
// Example implementation using reqwest:
|
||||
use reqwest::Client;
|
||||
let url = format!(
|
||||
"{}/bundle/{}",
|
||||
crate::common::utils::import_env_var("JITO_BLOCK_ENGINE_URL"),
|
||||
bundle_id
|
||||
);
|
||||
let client = Client::new();
|
||||
let resp = client.get(&url).send().await?;
|
||||
let json: Vec<serde_json::Value> = resp.json().await?;
|
||||
Ok(json)
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct BundleStatus {
|
||||
pub bundle_id: String,
|
||||
pub transactions: Vec<String>,
|
||||
pub slot: u64,
|
||||
pub confirmation_status: String,
|
||||
pub err: ErrorStatus,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct ErrorStatus {
|
||||
#[serde(rename = "Ok")]
|
||||
pub ok: Option<()>,
|
||||
}
|
||||
|
||||
pub async fn wait_for_bundle_confirmation<F, Fut>(
|
||||
fetch_statuses: F,
|
||||
bundle_id: String,
|
||||
interval: Duration,
|
||||
timeout: Duration,
|
||||
) -> Result<Vec<String>>
|
||||
where
|
||||
F: Fn(String) -> Fut,
|
||||
Fut: Future<Output = Result<Vec<Value>>>,
|
||||
{
|
||||
let progress_bar = new_progress_bar();
|
||||
let start_time = Instant::now();
|
||||
|
||||
loop {
|
||||
let statuses = fetch_statuses(bundle_id.clone()).await?;
|
||||
|
||||
if let Some(status) = statuses.first() {
|
||||
let bundle_status: BundleStatus =
|
||||
serde_json::from_value(status.clone()).inspect_err(|err| {
|
||||
println!(
|
||||
"Failed to parse JSON when get_bundle_statuses, err: {}",
|
||||
err,
|
||||
);
|
||||
})?;
|
||||
|
||||
println!("{:?}", bundle_status);
|
||||
match bundle_status.confirmation_status.as_str() {
|
||||
"finalized" | "confirmed" => {
|
||||
progress_bar.finish_and_clear();
|
||||
println!(
|
||||
"Finalized bundle {}: {}",
|
||||
bundle_id, bundle_status.confirmation_status
|
||||
);
|
||||
// print tx
|
||||
bundle_status
|
||||
.transactions
|
||||
.iter()
|
||||
.for_each(|tx| println!("https://solscan.io/tx/{}", tx));
|
||||
return Ok(bundle_status.transactions);
|
||||
}
|
||||
_ => {
|
||||
progress_bar.set_message(format!(
|
||||
"Finalizing bundle {}: {}",
|
||||
bundle_id, bundle_status.confirmation_status
|
||||
));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
progress_bar.set_message(format!("Finalizing bundle {}: {}", bundle_id, "None"));
|
||||
}
|
||||
|
||||
// check loop exceeded 1 minute,
|
||||
if start_time.elapsed() > timeout {
|
||||
println!("Loop exceeded {:?}, breaking out.", timeout);
|
||||
return Err(anyhow!("Bundle status get timeout"));
|
||||
}
|
||||
|
||||
// Wait for a certain duration before retrying
|
||||
sleep(interval).await;
|
||||
}
|
||||
}
|
||||
pub fn new_progress_bar() -> ProgressBar {
|
||||
let progress_bar = ProgressBar::new(42);
|
||||
progress_bar.set_style(
|
||||
ProgressStyle::default_spinner()
|
||||
.template("{spinner:.green} {wide_msg}")
|
||||
.expect("ProgressStyle::template direct input to be correct"),
|
||||
);
|
||||
progress_bar.enable_steady_tick(Duration::from_millis(100));
|
||||
progress_bar
|
||||
}
|
||||
505
#_sniper (Rust) using jito Shred stream/src/shred_stream.rs
Normal file
505
#_sniper (Rust) using jito Shred stream/src/shred_stream.rs
Normal file
@@ -0,0 +1,505 @@
|
||||
// src/shred_stream.rs
|
||||
// Module to replace Geyser-based streams with Jito Shred-stream
|
||||
use crate::apply_sol_flow_rules;
|
||||
use crate::MIN_SOL_INFLOW_TRIGGER;
|
||||
use crate::MIN_SOL_OUTFLOW_TRIGGER;
|
||||
use crate::PENDING_MINTS;
|
||||
use crate::PUMP_PROGRAM_PUBKEY;
|
||||
use crate::{flatten_transaction_response, try_send_buy_if_allowed};
|
||||
use anyhow::Context;
|
||||
use backoff::future::retry;
|
||||
use backoff::ExponentialBackoff;
|
||||
use jito_protos::shredstream::{
|
||||
shredstream_proxy_client::ShredstreamProxyClient, SubscribeEntriesRequest,
|
||||
};
|
||||
use log::{debug, info, warn};
|
||||
use once_cell::sync::Lazy;
|
||||
use pump_interface::PumpProgramIx;
|
||||
use shared_state::CURRENT_SLOT;
|
||||
use shared_state::{BuyOrder, SellOrder, BOUGHT_TOKENS};
|
||||
use solana_client::nonblocking::rpc_client::RpcClient;
|
||||
use solana_entry::entry::Entry as SolanaEntry;
|
||||
use solana_sdk::message::VersionedMessage;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use solana_sdk::transaction::VersionedTransaction;
|
||||
use solana_transaction_status::{
|
||||
ConfirmedTransactionWithStatusMeta, TransactionStatusMeta, TransactionWithStatusMeta,
|
||||
VersionedTransactionWithStatusMeta,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::atomic::Ordering::Relaxed;
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
use tokio::sync::mpsc::Sender;
|
||||
use tokio::sync::Mutex;
|
||||
use tokio_stream::StreamExt;
|
||||
const FALLBACK_SELL_AFTER_SLOTS: u64 = 50;
|
||||
|
||||
struct MintTracker {
|
||||
creator: Pubkey,
|
||||
last_activity: Instant,
|
||||
sol_inflow: f64,
|
||||
sol_outflow: f64,
|
||||
waiting_sw: bool,
|
||||
silence_until: Instant,
|
||||
}
|
||||
|
||||
static MINT_TRACKERS: Lazy<Mutex<HashMap<String, MintTracker>>> =
|
||||
Lazy::new(|| Mutex::new(HashMap::new()));
|
||||
|
||||
// Silence window duration before we begin listening for the "second wave"
|
||||
static SILENCE_DURATION: Lazy<Duration> = Lazy::new(|| {
|
||||
let secs = std::env::var("SW_SILENCE_SECS").unwrap_or_else(|_| "60".into());
|
||||
Duration::from_secs(secs.parse().unwrap_or(60))
|
||||
});
|
||||
|
||||
|
||||
// at top of file, make sure you have:
|
||||
static SECOND_WAVE_MODE: Lazy<bool> = Lazy::new(|| {
|
||||
std::env::var("SECOND_WAVE_MODE").map(|v| v == "true").unwrap_or(false)
|
||||
});
|
||||
|
||||
|
||||
/// Begin tracking a newly detected mint, recording its creator
|
||||
/// and setting up the silence window before second‐wave sniping.
|
||||
async fn start_tracking_mint(mint: String, creator: Pubkey) {
|
||||
let now = Instant::now();
|
||||
let silence = *SILENCE_DURATION; // from your SW_SILENCE_SECS env
|
||||
|
||||
let tracker = MintTracker {
|
||||
creator,
|
||||
last_activity: now,
|
||||
sol_inflow: 0.0,
|
||||
sol_outflow: 0.0,
|
||||
waiting_sw: false,
|
||||
silence_until: now + silence,
|
||||
};
|
||||
|
||||
MINT_TRACKERS.lock().await.insert(mint, tracker);
|
||||
}
|
||||
|
||||
/// Subscribe to Jito shredstream and manage new‐mint sniping vs. second‐wave mode
|
||||
pub async fn shred_subscribe_transactions(
|
||||
url: String,
|
||||
sell_sender: Sender<SellOrder>,
|
||||
mint_sender: Sender<BuyOrder>,
|
||||
) -> anyhow::Result<()> {
|
||||
let backoff = ExponentialBackoff::default();
|
||||
let mut client = retry(backoff, || async {
|
||||
ShredstreamProxyClient::connect(url.clone())
|
||||
.await
|
||||
.map_err(backoff::Error::transient)
|
||||
})
|
||||
.await?;
|
||||
|
||||
let mut stream = client
|
||||
.subscribe_entries(SubscribeEntriesRequest::default())
|
||||
.await?
|
||||
.into_inner();
|
||||
|
||||
while let Some(Ok(batch)) = stream.next().await {
|
||||
let slot = batch.slot;
|
||||
CURRENT_SLOT.store(slot, Ordering::Relaxed);
|
||||
|
||||
let entries: Vec<SolanaEntry> = bincode::deserialize(&batch.entries)?;
|
||||
for sol_entry in entries {
|
||||
for tx in sol_entry.transactions {
|
||||
if let Some((mint, creator)) = detect_raw_create(&tx) {
|
||||
info!("New mint {} @ slot {}", mint, slot);
|
||||
|
||||
// Always start the silence‐window tracker
|
||||
let mint_clone = mint.clone();
|
||||
tokio::spawn(async move {
|
||||
start_tracking_mint(mint_clone, creator).await;
|
||||
});
|
||||
|
||||
// Only fire the *immediate* new‐mint buy if NOT in second‐wave mode
|
||||
if !*SECOND_WAVE_MODE {
|
||||
try_send_buy_if_allowed(
|
||||
&mint,
|
||||
creator,
|
||||
true, // first_buy
|
||||
true, // urgent=false
|
||||
&mint_sender,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
// offload your reconcilers (flows, confirms, sells)
|
||||
let sell_tx = sell_sender.clone();
|
||||
let mint_tx = mint_sender.clone();
|
||||
tokio::spawn(async move {
|
||||
let confirmed = confirm_from_versioned(tx, slot);
|
||||
reconcile_flows(&confirmed, &sell_tx, &mint_tx).await;
|
||||
reconcile_buys(&confirmed, slot).await;
|
||||
reconcile_sells(&confirmed, slot, &sell_tx).await;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
/// Update flows and trigger second-wave sniping, but only after our own buy has confirmed.
|
||||
async fn reconcile_flows(
|
||||
confirmed: &ConfirmedTransactionWithStatusMeta,
|
||||
sell_sender: &Sender<SellOrder>,
|
||||
mint_sender: &Sender<BuyOrder>,
|
||||
) {
|
||||
// only complete transactions
|
||||
let vtx = match &confirmed.tx_with_meta {
|
||||
TransactionWithStatusMeta::Complete(v) => v,
|
||||
_ => return,
|
||||
};
|
||||
let now = Instant::now();
|
||||
|
||||
for tx_ix in flatten_transaction_response(vtx) {
|
||||
// skip non-Pump instructions
|
||||
if tx_ix.instruction.program_id != *PUMP_PROGRAM_PUBKEY {
|
||||
continue;
|
||||
}
|
||||
let mint = tx_ix.instruction.accounts[2].pubkey.to_string();
|
||||
|
||||
// don’t start counting flows until our buy has landed
|
||||
{
|
||||
let tokens = BOUGHT_TOKENS.lock().await;
|
||||
if tokens.get(&mint).map(|e| e.buy_slot()).unwrap_or(0) == 0 {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(tracker) = MINT_TRACKERS.lock().await.get_mut(&mint) {
|
||||
tracker.last_activity = now;
|
||||
|
||||
if let Ok(ix) = PumpProgramIx::deserialize(&tx_ix.instruction.data) {
|
||||
match ix {
|
||||
PumpProgramIx::Buy(buy_args) => {
|
||||
let sol_in = buy_args.max_sol_cost as f64 / 1e9;
|
||||
tracker.sol_inflow += sol_in;
|
||||
debug!("SOL inflow +{:.6} on {}", sol_in, mint);
|
||||
|
||||
if tracker.waiting_sw {
|
||||
info!("🚀 Second wave hit on {} → sniping", mint);
|
||||
try_send_buy_if_allowed(
|
||||
&mint,
|
||||
tracker.creator,
|
||||
true,
|
||||
true,
|
||||
mint_sender,
|
||||
).await;
|
||||
tracker.waiting_sw = false;
|
||||
}
|
||||
}
|
||||
PumpProgramIx::Sell(sell_args) => {
|
||||
let sol_out = sell_args.min_sol_output as f64 / 1e9;
|
||||
tracker.sol_outflow += sol_out;
|
||||
debug!("SOL outflow +{:.6} on {}", sol_out, mint);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
if !tracker.waiting_sw && now >= tracker.silence_until {
|
||||
tracker.waiting_sw = true;
|
||||
info!("⏱ {} entered second-wave watch mode", mint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Confirm our buy, then reset that mint’s tracker so we only count SOL flows from now on.
|
||||
async fn reconcile_buys(
|
||||
confirmed: &ConfirmedTransactionWithStatusMeta,
|
||||
slot: u64,
|
||||
) {
|
||||
// pull out on-chain signature (if any)
|
||||
let sig_opt = match &confirmed.tx_with_meta {
|
||||
TransactionWithStatusMeta::Complete(v) => v.transaction.signatures.get(0).cloned(),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
if let Some(sig) = sig_opt {
|
||||
let sig_str = sig.to_string();
|
||||
let mut tokens = BOUGHT_TOKENS.lock().await;
|
||||
|
||||
// find our minted entry by matching its stored signature
|
||||
if let Some((mint, entry)) = tokens
|
||||
.iter_mut()
|
||||
.find(|(_, e)| e.signature() == Some(&sig_str))
|
||||
{
|
||||
// confirm the buy
|
||||
entry.set_buy_slot(slot);
|
||||
entry.set_buy_executed_at(Instant::now());
|
||||
PENDING_MINTS.fetch_sub(1, Ordering::Relaxed);
|
||||
info!("✅ Confirmed BUY for {} @ slot {}", mint, slot);
|
||||
|
||||
// re-arm second-wave tracker
|
||||
if let Some(tracker) = MINT_TRACKERS.lock().await.get_mut(mint) {
|
||||
let now = Instant::now();
|
||||
tracker.last_activity = now;
|
||||
tracker.sol_inflow = 0.0;
|
||||
tracker.sol_outflow = 0.0;
|
||||
tracker.waiting_sw = false;
|
||||
tracker.silence_until = now + *SILENCE_DURATION;
|
||||
info!("🔄 Re-armed second-wave tracker for {}", mint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn detect_raw_create(vtx: &VersionedTransaction) -> Option<(String, Pubkey)> {
|
||||
let msg = &vtx.message;
|
||||
let keys = msg.static_account_keys();
|
||||
debug!(
|
||||
"🔑 static keys (len={}): {:?}",
|
||||
keys.len(),
|
||||
keys.iter().take(4).collect::<Vec<_>>()
|
||||
);
|
||||
|
||||
for instr in msg.instructions() {
|
||||
let program_key = keys[instr.program_id_index as usize];
|
||||
if program_key == *PUMP_PROGRAM_PUBKEY {
|
||||
debug!(
|
||||
"🧩 Found PumpProgramIx at idx={} data_prefix={:02x?}",
|
||||
instr.program_id_index,
|
||||
&instr.data[..4.min(instr.data.len())]
|
||||
);
|
||||
|
||||
match PumpProgramIx::deserialize(&instr.data) {
|
||||
Ok(PumpProgramIx::Create(args)) => {
|
||||
let mint_key = keys[instr.accounts[0] as usize];
|
||||
debug!("✅ Deserialized Create; mint = {}", mint_key);
|
||||
return Some((mint_key.to_string(), args.creator));
|
||||
}
|
||||
Ok(other) => {
|
||||
debug!("ℹ️ Other PumpProgramIx::{:?}, skipping", other);
|
||||
}
|
||||
Err(e) => {
|
||||
debug!("❌ deserialize error: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Quickly wrap a VersionedTransaction in a ConfirmedTransactionWithStatusMeta
|
||||
fn confirm_from_versioned(
|
||||
tx: solana_sdk::transaction::VersionedTransaction,
|
||||
slot: u64,
|
||||
) -> ConfirmedTransactionWithStatusMeta {
|
||||
// minimal meta with defaults:
|
||||
let meta = TransactionStatusMeta {
|
||||
status: Ok(()),
|
||||
fee: 0,
|
||||
pre_balances: vec![],
|
||||
post_balances: vec![],
|
||||
inner_instructions: None,
|
||||
log_messages: None,
|
||||
pre_token_balances: None,
|
||||
post_token_balances: None,
|
||||
rewards: None,
|
||||
loaded_addresses: Default::default(),
|
||||
return_data: None,
|
||||
compute_units_consumed: None,
|
||||
};
|
||||
|
||||
let vtx = VersionedTransactionWithStatusMeta {
|
||||
transaction: tx,
|
||||
meta,
|
||||
};
|
||||
ConfirmedTransactionWithStatusMeta {
|
||||
slot,
|
||||
tx_with_meta: TransactionWithStatusMeta::Complete(vtx),
|
||||
block_time: None,
|
||||
}
|
||||
}
|
||||
/// Decode raw bytes and slot into ConfirmedTransactionWithStatusMeta
|
||||
pub fn decode_txn_from_bytes(
|
||||
raw: &[u8],
|
||||
slot: u64,
|
||||
) -> anyhow::Result<ConfirmedTransactionWithStatusMeta> {
|
||||
use bincode;
|
||||
use solana_sdk::transaction::VersionedTransaction;
|
||||
use solana_transaction_status::TransactionStatusMeta;
|
||||
|
||||
// 1. Deserialize the wire-format VersionedTransaction
|
||||
let tx: VersionedTransaction = bincode::deserialize(raw)
|
||||
.context("failed to deserialize VersionedTransaction from shred entry")?;
|
||||
|
||||
// 2. Build a minimal TransactionStatusMeta with defaults
|
||||
let meta = TransactionStatusMeta {
|
||||
status: Ok(()),
|
||||
fee: 0,
|
||||
pre_balances: vec![],
|
||||
post_balances: vec![],
|
||||
inner_instructions: None,
|
||||
log_messages: None,
|
||||
pre_token_balances: None,
|
||||
post_token_balances: None,
|
||||
rewards: None,
|
||||
loaded_addresses: Default::default(),
|
||||
return_data: None,
|
||||
compute_units_consumed: None,
|
||||
};
|
||||
|
||||
// 3. Wrap into VersionedTransactionWithStatusMeta and then into ConfirmedTransactionWithStatusMeta
|
||||
let vtx = VersionedTransactionWithStatusMeta {
|
||||
transaction: tx,
|
||||
meta,
|
||||
};
|
||||
Ok(ConfirmedTransactionWithStatusMeta {
|
||||
slot,
|
||||
tx_with_meta: TransactionWithStatusMeta::Complete(vtx),
|
||||
block_time: None,
|
||||
})
|
||||
}
|
||||
|
||||
const LOW_BUY_FREQ_WINDOW_SLOTS: u64 = 10;
|
||||
const MIN_BUYS_IN_WINDOW: usize = 6;
|
||||
|
||||
const BUY_CONFIRM_TIMEOUT_SECS: u64 = 60;
|
||||
|
||||
const SELL_CONFIRM_TIMEOUT_SECS: u64 = 60;
|
||||
|
||||
async fn reconcile_sells(
|
||||
confirmed: &ConfirmedTransactionWithStatusMeta,
|
||||
slot: u64,
|
||||
sell_sender: &Sender<SellOrder>,
|
||||
) {
|
||||
// --- 0) remove any entries that are already confirmed sells, just in case ---
|
||||
{
|
||||
let mut tokens = BOUGHT_TOKENS.lock().await;
|
||||
let to_remove: Vec<String> = tokens
|
||||
.iter()
|
||||
.filter_map(|(mint, entry)| {
|
||||
if entry.sell_confirmed() {
|
||||
Some(mint.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
for mint in to_remove {
|
||||
tokens.remove(&mint);
|
||||
}
|
||||
}
|
||||
|
||||
// 1) On-chain confirmations
|
||||
if let Some(sig) = match &confirmed.tx_with_meta {
|
||||
TransactionWithStatusMeta::Complete(v) => {
|
||||
v.transaction.signatures.get(0).map(|s| s.to_string())
|
||||
}
|
||||
_ => None,
|
||||
} {
|
||||
// find mint without holding a mutable borrow across removal
|
||||
let mint_opt = {
|
||||
let tokens = BOUGHT_TOKENS.lock().await;
|
||||
tokens
|
||||
.iter()
|
||||
.find(|(_, e)| e.sell_signature().as_deref() == Some(&sig))
|
||||
.map(|(m, _)| m.clone())
|
||||
};
|
||||
|
||||
if let Some(mint) = mint_opt {
|
||||
// confirm + slot in one lock
|
||||
{
|
||||
let mut tokens = BOUGHT_TOKENS.lock().await;
|
||||
if let Some(entry) = tokens.get_mut(&mint) {
|
||||
entry.confirm_sell();
|
||||
entry.set_sell_slot(slot);
|
||||
}
|
||||
// guard against underflow
|
||||
if PENDING_MINTS.load(Relaxed) > 0 {
|
||||
PENDING_MINTS.fetch_sub(1, Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
// remove in a separate lock
|
||||
{
|
||||
let mut tokens = BOUGHT_TOKENS.lock().await;
|
||||
tokens.remove(&mint);
|
||||
}
|
||||
|
||||
log::info!("✅ Confirmed SELL for {} @ slot {}", mint, slot);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 2) retry logic
|
||||
// build stale list under lock
|
||||
let now = Instant::now();
|
||||
let timeout = Duration::from_secs(SELL_CONFIRM_TIMEOUT_SECS);
|
||||
let stale: Vec<String> = {
|
||||
let tokens = BOUGHT_TOKENS.lock().await;
|
||||
tokens
|
||||
.iter()
|
||||
.filter_map(|(mint, entry)| {
|
||||
if entry.sell_signature().is_some()
|
||||
&& !entry.sell_confirmed()
|
||||
&& entry.retry_count() < 3
|
||||
&& entry
|
||||
.sell_executed_at()
|
||||
.map(|t| now.duration_since(t) > timeout)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
Some(mint.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
|
||||
// drop lock, then re-send each stale sell
|
||||
for mint in stale {
|
||||
let mut tokens = BOUGHT_TOKENS.lock().await;
|
||||
if let Some(entry) = tokens.get_mut(&mint) {
|
||||
entry.increment_retry_count();
|
||||
log::info!(
|
||||
"⌛ Sell for {} timed out; retry #{}, re-sending…",
|
||||
mint,
|
||||
entry.retry_count()
|
||||
);
|
||||
let amount = entry.amount();
|
||||
let _ = sell_sender
|
||||
.send(SellOrder {
|
||||
mint: mint.clone(),
|
||||
amount,
|
||||
use_jito: true,
|
||||
urgent: true,
|
||||
})
|
||||
.await;
|
||||
// record when we issued this retry
|
||||
entry.set_sell_executed_at(Instant::now());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Find mint & creator from Create ix
|
||||
fn extract_mint_and_creator(
|
||||
confirmed: &ConfirmedTransactionWithStatusMeta,
|
||||
) -> Option<(String, Pubkey)> {
|
||||
if let TransactionWithStatusMeta::Complete(v) = &confirmed.tx_with_meta {
|
||||
for tx_ix in flatten_transaction_response(v) {
|
||||
if tx_ix.instruction.program_id == *crate::PUMP_PROGRAM_PUBKEY {
|
||||
if let Ok(PumpProgramIx::Create(args)) =
|
||||
PumpProgramIx::deserialize(&tx_ix.instruction.data)
|
||||
{
|
||||
// the very first account is the mint
|
||||
if let Some(meta) = tx_ix.instruction.accounts.get(0) {
|
||||
// return (mint_pubkey_string, creator_pubkey)
|
||||
return Some((meta.pubkey.to_string(), args.creator));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
179
#_sniper (Rust) using jito Shred stream/src/solana_helper.rs
Normal file
179
#_sniper (Rust) using jito Shred stream/src/solana_helper.rs
Normal file
@@ -0,0 +1,179 @@
|
||||
// src/solana_helpers.rs
|
||||
|
||||
use aes_gcm::{Aes256Gcm, Key, Nonce}; // Or `aes_gcm::Aes256Gcm`
|
||||
use aes_gcm::aead::{Aead, NewAead};
|
||||
use base64::{encode as b64_encode, decode as b64_decode};
|
||||
use hex::decode as hex_decode;
|
||||
use rand::RngCore;
|
||||
use rand::rngs::OsRng;
|
||||
use solana_sdk::signature::{Keypair, Signer};
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use bip39::{Mnemonic, Language, Seed};
|
||||
use anyhow::{Result, Context};
|
||||
use serde_json::Value;
|
||||
|
||||
/// Load the AES-256 key from the environment variable `ENCRYPTION_KEY`.
|
||||
/// The env var should be a hex-encoded 32-byte key (i.e., 64 hex chars).
|
||||
fn load_encryption_key() -> Result<[u8; 32]> {
|
||||
let hex = std::env::var("ENCRYPTION_KEY")
|
||||
.context("ENCRYPTION_KEY env var not set")?;
|
||||
let bytes = hex_decode(&hex)
|
||||
.context("Failed to hex-decode ENCRYPTION_KEY")?;
|
||||
if bytes.len() != 32 {
|
||||
anyhow::bail!("ENCRYPTION_KEY must be 32 bytes (hex-encoded 64 chars)");
|
||||
}
|
||||
let mut key = [0u8; 32];
|
||||
key.copy_from_slice(&bytes);
|
||||
Ok(key)
|
||||
}
|
||||
|
||||
/// Encrypt `plaintext` using AES-256-GCM. Returns a base64 string containing nonce||ciphertext.
|
||||
/// Format: base64( [12-byte nonce] || ciphertext ).
|
||||
pub fn encrypt_data(plaintext: &str) -> Result<String> {
|
||||
let key_bytes = load_encryption_key()?;
|
||||
let key = Key::from_slice(&key_bytes);
|
||||
let cipher = Aes256Gcm::new(key);
|
||||
|
||||
// Generate a random 12-byte nonce
|
||||
let mut nonce_bytes = [0u8; 12];
|
||||
OsRng.fill_bytes(&mut nonce_bytes);
|
||||
let nonce = Nonce::from_slice(&nonce_bytes);
|
||||
|
||||
let ciphertext = cipher
|
||||
.encrypt(nonce, plaintext.as_bytes())
|
||||
.context("Encryption failure")?;
|
||||
|
||||
// Prepend nonce
|
||||
let mut combined = Vec::with_capacity(12 + ciphertext.len());
|
||||
combined.extend_from_slice(&nonce_bytes);
|
||||
combined.extend_from_slice(&ciphertext);
|
||||
|
||||
Ok(b64_encode(&combined))
|
||||
}
|
||||
|
||||
/// Decrypt a base64 string produced by `encrypt_data`, returning the plaintext.
|
||||
pub fn decrypt_data(encoded: &str) -> Result<String> {
|
||||
let combined = b64_decode(encoded).context("Base64 decode failed")?;
|
||||
if combined.len() < 12 {
|
||||
anyhow::bail!("Ciphertext too short");
|
||||
}
|
||||
let (nonce_bytes, ciphertext) = combined.split_at(12);
|
||||
let key_bytes = load_encryption_key()?;
|
||||
let key = Key::from_slice(&key_bytes);
|
||||
let cipher = Aes256Gcm::new(key);
|
||||
let nonce = Nonce::from_slice(nonce_bytes);
|
||||
let plaintext = cipher
|
||||
.decrypt(nonce, ciphertext)
|
||||
.context("Decryption failure")?;
|
||||
let s = String::from_utf8(plaintext).context("Decrypted data not valid UTF-8")?;
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
/// Derive Solana public address (Pubkey) from a JSON-array keypair string.
|
||||
///
|
||||
/// # Arguments
|
||||
/// - `json`: a JSON string representing an array of 64 or 32 or 64 u8 values, e.g. `[12,34, ...]`.
|
||||
/// - If length is 64: interpreted as full keypair bytes.
|
||||
/// - If length is 32: interpreted as secret seed, but Solana Keypair::from_bytes expects 64; you may need to expand.
|
||||
///
|
||||
/// Returns the `Pubkey` as a base58 string.
|
||||
pub fn derive_address_from_json_keypair(json: &str) -> Result<String> {
|
||||
// Parse JSON array
|
||||
let v: Value = serde_json::from_str(json).context("Invalid JSON")?;
|
||||
let arr = v.as_array().context("Expected JSON array")?;
|
||||
// Convert to Vec<u8>
|
||||
let bytes: Vec<u8> = arr.iter()
|
||||
.map(|val| {
|
||||
val.as_u64()
|
||||
.and_then(|n| Some(n as u8))
|
||||
.ok_or_else(|| anyhow::anyhow!("Invalid byte in array"))
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
// Depending on length:
|
||||
let kp = if bytes.len() == 64 {
|
||||
Keypair::from_bytes(&bytes).context("Failed to parse keypair from bytes")?
|
||||
} else if bytes.len() == 32 {
|
||||
// interpret as secret seed: expand to keypair via `from_seed`
|
||||
// Note: solana_sdk::signature::Keypair::from_seed requires `Signer` trait; but no direct from_seed in stable.
|
||||
// We can use ed25519_dalek to expand, then wrap in Keypair.
|
||||
// Solana Keypair::from_seed is nightly; instead:
|
||||
// Use solana_sdk::signature::Keypair::from_seed (requires "ed25519-dalek" feature)
|
||||
Keypair::from_seed(&bytes).context("Failed to derive keypair from 32-byte seed")?
|
||||
} else {
|
||||
anyhow::bail!("Keypair JSON must be 32 or 64 bytes");
|
||||
};
|
||||
|
||||
let pubkey = kp.pubkey();
|
||||
Ok(pubkey.to_string())
|
||||
}
|
||||
|
||||
/// Derive Solana public address from a base58-encoded secret key (64-byte) string.
|
||||
/// E.g., if user has a base58 of secret key bytes.
|
||||
///
|
||||
/// # Arguments
|
||||
/// - `b58`: base58 string of 64 bytes.
|
||||
/// Returns base58 pubkey string.
|
||||
pub fn derive_address_from_base58_secret(b58: &str) -> Result<String> {
|
||||
let data = bs58::decode(b58).into_vec().context("Invalid base58")?;
|
||||
if data.len() == 64 {
|
||||
let kp = Keypair::from_bytes(&data).context("Failed to parse keypair bytes")?;
|
||||
Ok(kp.pubkey().to_string())
|
||||
} else if data.len() == 32 {
|
||||
let kp = Keypair::from_seed(&data).context("Failed to derive keypair from seed")?;
|
||||
Ok(kp.pubkey().to_string())
|
||||
} else {
|
||||
anyhow::bail!("Base58 secret must be 32 or 64 bytes");
|
||||
}
|
||||
}
|
||||
|
||||
/// Derive Solana public address from a BIP39 mnemonic phrase.
|
||||
/// Uses the standard Solana derivation: m/44'/501'/0'/0' by default, but this can be adjusted.
|
||||
///
|
||||
/// # Arguments
|
||||
/// - `mnemonic`: the phrase, e.g. "abandon abandon ...".
|
||||
/// - `passphrase`: optional passphrase for mnemonic (usually empty string).
|
||||
/// - `account`: u32, default 0.
|
||||
/// - `change`: u32, default 0.
|
||||
///
|
||||
/// Returns base58 pubkey string.
|
||||
pub fn derive_address_from_mnemonic(
|
||||
mnemonic: &str,
|
||||
passphrase: &str,
|
||||
account: u32,
|
||||
change: u32,
|
||||
) -> Result<String> {
|
||||
// Parse mnemonic
|
||||
let mn = Mnemonic::from_phrase(mnemonic, Language::English)
|
||||
.context("Invalid mnemonic phrase")?;
|
||||
let seed = Seed::new(&mn, passphrase);
|
||||
let seed_bytes = seed.as_bytes(); // 64 bytes
|
||||
|
||||
// Derivation path for Solana: m/44'/501'/<account>'/<change>'
|
||||
// We can use `solana_sdk::derivation_path::DerivationPath` if available, or derive via ed25519-dalek + slip10.
|
||||
// For simplicity, we use `solana_sdk::derivation_path::DerivationPath` if in scope:
|
||||
// If not, use `ed25519-dalek-bip32` or similar. Here we assume solana-sdk has `derive_keypair_from_seed_and_path`.
|
||||
// As of solana-sdk v1.14+, there's `keypair_from_seed_and_derivation_path`.
|
||||
#[cfg(feature = "solana-derive-keypair")]
|
||||
{
|
||||
// Pseudo-code; adjust per your solana-sdk version:
|
||||
/*
|
||||
use solana_sdk::derivation_path::DerivationPath;
|
||||
let path = DerivationPath::new_bip44(Some(501), Some(account), Some(change));
|
||||
let kp = Keypair::from_seed_with_derivation(&seed_bytes, &path)
|
||||
.context("Failed deriving keypair from mnemonic")?;
|
||||
Ok(kp.pubkey().to_string())
|
||||
*/
|
||||
unimplemented!("Adjust to your solana-sdk version's derivation API");
|
||||
}
|
||||
#[cfg(not(feature = "solana-derive-keypair"))]
|
||||
{
|
||||
// As fallback: derive the ED25519 key by directly using the seed (not recommended for multiple accounts).
|
||||
// Here we just derive from seed_bytes[0..32]:
|
||||
let seed32 = &seed_bytes[0..32];
|
||||
let kp = Keypair::from_seed(seed32).context("Failed to derive keypair from mnemonic seed")?;
|
||||
Ok(kp.pubkey().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
44
#_sniper (Rust) using jito Shred stream/src/tginterface.rs
Normal file
44
#_sniper (Rust) using jito Shred stream/src/tginterface.rs
Normal file
@@ -0,0 +1,44 @@
|
||||
// src/tginterface.rs
|
||||
use teloxide::prelude::*;
|
||||
use std::env;
|
||||
use dotenv::dotenv;
|
||||
use crate::db::Database;
|
||||
use crate::commands::{handle_command, Command};
|
||||
|
||||
mod db;
|
||||
mod models;
|
||||
mod commands;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
dotenv().ok();
|
||||
env_logger::init();
|
||||
|
||||
let bot_token = env::var("TELEGRAM_BOT_TOKEN").expect("TELEGRAM_BOT_TOKEN not set");
|
||||
let mongo_uri = env::var("MONGODB_URI").expect("MONGODB_URI not set");
|
||||
let mongo_db = env::var("MONGODB_DB").unwrap_or_else(|_| "telegram_wallet_bot".to_string());
|
||||
let admin_ids: Vec<i64> = env::var("ADMIN_IDS")
|
||||
.unwrap_or_default()
|
||||
.split(',')
|
||||
.filter_map(|s| s.trim().parse().ok())
|
||||
.collect();
|
||||
|
||||
let db = Database::new(&mongo_uri, &mongo_db)
|
||||
.await
|
||||
.expect("failed to initialize database");
|
||||
|
||||
let bot = Bot::new(bot_token).auto_send();
|
||||
|
||||
log::info!("Starting bot...");
|
||||
|
||||
// Use a cloned Database in handler
|
||||
teloxide::commands_repl(bot.clone(), move |bot: AutoSend<Bot>, msg: Message, cmd: Command| {
|
||||
let db = db.clone(); // Database should be Cloneable or use Arc
|
||||
let admin_ids = admin_ids.clone();
|
||||
async move {
|
||||
if let Err(e) = handle_command(bot.clone().into_inner(), msg, cmd, db.clone(), admin_ids.clone()).await {
|
||||
log::error!("Error handling command: {:?}", e);
|
||||
}
|
||||
}
|
||||
}, Command::ty()).await;
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::{serde_as, DisplayFromStr};
|
||||
use solana_program::{program_option::COption, pubkey::Pubkey};
|
||||
use spl_token::instruction::{AuthorityType, TokenInstruction};
|
||||
|
||||
// Helper function to convert COption<Pubkey> to Option<Pubkey>
|
||||
fn convert_coption<T>(coption: COption<T>) -> Option<T> {
|
||||
match coption {
|
||||
COption::Some(value) => Some(value),
|
||||
COption::None => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_set_authority(
|
||||
authority_type: AuthorityType,
|
||||
new_authority: COption<Pubkey>,
|
||||
) -> SerializableSetAuthority {
|
||||
SerializableSetAuthority {
|
||||
authority_type: match authority_type {
|
||||
AuthorityType::MintTokens => "MintTokens".to_string(),
|
||||
AuthorityType::FreezeAccount => "FreezeAccount".to_string(),
|
||||
AuthorityType::AccountOwner => "AccountOwner".to_string(),
|
||||
AuthorityType::CloseAccount => "CloseAccount".to_string(),
|
||||
},
|
||||
new_authority: new_authority.into(), // Convert COption<Pubkey> to Option<Pubkey>
|
||||
}
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct SerializableInitializeMint {
|
||||
decimals: u8,
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
mint_authority: Pubkey,
|
||||
#[serde_as(as = "Option<DisplayFromStr>")]
|
||||
freeze_authority: Option<Pubkey>,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct SerializableInitializeAccount3 {
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
owner: Pubkey,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct SerializableSetAuthority {
|
||||
authority_type: String,
|
||||
#[serde_as(as = "Option<DisplayFromStr>")]
|
||||
new_authority: Option<Pubkey>,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct SerializableTransfer {
|
||||
amount: u64,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub enum SerializableTokenInstruction {
|
||||
InitializeMint(SerializableInitializeMint),
|
||||
InitializeAccount,
|
||||
InitializeMultisig {
|
||||
m: u8,
|
||||
},
|
||||
Transfer(SerializableTransfer),
|
||||
Approve {
|
||||
amount: u64,
|
||||
},
|
||||
Revoke,
|
||||
SetAuthority(SerializableSetAuthority),
|
||||
MintTo {
|
||||
amount: u64,
|
||||
},
|
||||
Burn {
|
||||
amount: u64,
|
||||
},
|
||||
CloseAccount,
|
||||
FreezeAccount,
|
||||
ThawAccount,
|
||||
TransferChecked {
|
||||
amount: u64,
|
||||
decimals: u8,
|
||||
},
|
||||
ApproveChecked {
|
||||
amount: u64,
|
||||
decimals: u8,
|
||||
},
|
||||
MintToChecked {
|
||||
amount: u64,
|
||||
decimals: u8,
|
||||
},
|
||||
BurnChecked {
|
||||
amount: u64,
|
||||
decimals: u8,
|
||||
},
|
||||
InitializeAccount2 {
|
||||
#[serde_as(as = "DisplayFromStr")]
|
||||
owner: Pubkey,
|
||||
},
|
||||
SyncNative,
|
||||
InitializeAccount3(SerializableInitializeAccount3),
|
||||
InitializeMultisig2 {
|
||||
m: u8,
|
||||
},
|
||||
InitializeMint2(SerializableInitializeMint),
|
||||
GetAccountDataSize,
|
||||
InitializeImmutableOwner,
|
||||
AmountToUiAmount {
|
||||
amount: u64,
|
||||
},
|
||||
UiAmountToAmount {
|
||||
ui_amount: String,
|
||||
},
|
||||
}
|
||||
|
||||
// Convert TokenInstruction to SerializableTokenInstruction
|
||||
pub fn convert_to_serializable(ix: TokenInstruction) -> SerializableTokenInstruction {
|
||||
match ix {
|
||||
TokenInstruction::InitializeMint {
|
||||
decimals,
|
||||
mint_authority,
|
||||
freeze_authority,
|
||||
} => {
|
||||
SerializableTokenInstruction::InitializeMint(SerializableInitializeMint {
|
||||
decimals,
|
||||
mint_authority,
|
||||
freeze_authority: freeze_authority.into(), // Convert COption to Option
|
||||
})
|
||||
}
|
||||
TokenInstruction::InitializeAccount => SerializableTokenInstruction::InitializeAccount,
|
||||
TokenInstruction::InitializeMultisig { m } => {
|
||||
SerializableTokenInstruction::InitializeMultisig { m }
|
||||
}
|
||||
TokenInstruction::Transfer { amount } => {
|
||||
SerializableTokenInstruction::Transfer(SerializableTransfer { amount })
|
||||
}
|
||||
TokenInstruction::Approve { amount } => SerializableTokenInstruction::Approve { amount },
|
||||
TokenInstruction::Revoke => SerializableTokenInstruction::Revoke,
|
||||
TokenInstruction::SetAuthority {
|
||||
authority_type,
|
||||
new_authority,
|
||||
} => SerializableTokenInstruction::SetAuthority(convert_set_authority(
|
||||
authority_type,
|
||||
new_authority,
|
||||
)),
|
||||
TokenInstruction::MintTo { amount } => SerializableTokenInstruction::MintTo { amount },
|
||||
TokenInstruction::Burn { amount } => SerializableTokenInstruction::Burn { amount },
|
||||
TokenInstruction::CloseAccount => SerializableTokenInstruction::CloseAccount,
|
||||
TokenInstruction::FreezeAccount => SerializableTokenInstruction::FreezeAccount,
|
||||
TokenInstruction::ThawAccount => SerializableTokenInstruction::ThawAccount,
|
||||
TokenInstruction::TransferChecked { amount, decimals } => {
|
||||
SerializableTokenInstruction::TransferChecked { amount, decimals }
|
||||
}
|
||||
TokenInstruction::ApproveChecked { amount, decimals } => {
|
||||
SerializableTokenInstruction::ApproveChecked { amount, decimals }
|
||||
}
|
||||
TokenInstruction::MintToChecked { amount, decimals } => {
|
||||
SerializableTokenInstruction::MintToChecked { amount, decimals }
|
||||
}
|
||||
TokenInstruction::BurnChecked { amount, decimals } => {
|
||||
SerializableTokenInstruction::BurnChecked { amount, decimals }
|
||||
}
|
||||
TokenInstruction::InitializeAccount2 { owner } => {
|
||||
SerializableTokenInstruction::InitializeAccount2 { owner }
|
||||
}
|
||||
TokenInstruction::SyncNative => SerializableTokenInstruction::SyncNative,
|
||||
TokenInstruction::InitializeAccount3 { owner } => {
|
||||
SerializableTokenInstruction::InitializeAccount3(SerializableInitializeAccount3 {
|
||||
owner,
|
||||
})
|
||||
}
|
||||
TokenInstruction::InitializeMultisig2 { m } => {
|
||||
SerializableTokenInstruction::InitializeMultisig2 { m }
|
||||
}
|
||||
TokenInstruction::InitializeMint2 {
|
||||
decimals,
|
||||
mint_authority,
|
||||
freeze_authority,
|
||||
} => SerializableTokenInstruction::InitializeMint2(SerializableInitializeMint {
|
||||
decimals,
|
||||
mint_authority,
|
||||
freeze_authority: freeze_authority.into(),
|
||||
}),
|
||||
TokenInstruction::GetAccountDataSize => SerializableTokenInstruction::GetAccountDataSize,
|
||||
TokenInstruction::InitializeImmutableOwner => {
|
||||
SerializableTokenInstruction::InitializeImmutableOwner
|
||||
}
|
||||
TokenInstruction::AmountToUiAmount { amount } => {
|
||||
SerializableTokenInstruction::AmountToUiAmount { amount }
|
||||
}
|
||||
TokenInstruction::UiAmountToAmount { ui_amount } => {
|
||||
SerializableTokenInstruction::UiAmountToAmount {
|
||||
ui_amount: ui_amount.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
143
#_sniper (Rust) using jito Shred stream/src/trade_logger.rs
Normal file
143
#_sniper (Rust) using jito Shred stream/src/trade_logger.rs
Normal file
@@ -0,0 +1,143 @@
|
||||
// trade_logger.rs
|
||||
use once_cell::sync::Lazy;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use tokio::sync::Mutex;
|
||||
// Remove std::io::BufReader / std::fs::File imports for async loading:
|
||||
use std::collections::HashSet;
|
||||
use std::sync::RwLock;
|
||||
use tokio::fs::File;
|
||||
use tokio::io::{AsyncBufReadExt, BufReader};
|
||||
|
||||
static SKIP_CREATORS: Lazy<RwLock<HashSet<Pubkey>>> = Lazy::new(|| RwLock::new(HashSet::new()));
|
||||
|
||||
/// Full record to serialize:
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct TradeRecord {
|
||||
pub mint: String,
|
||||
pub creator: String,
|
||||
pub buy_lamports: u64,
|
||||
pub tokens_received: u64,
|
||||
pub buy_slot: u64,
|
||||
pub sell_lamports: u64,
|
||||
pub tokens_sold: u64,
|
||||
pub sell_slot: u64,
|
||||
pub pnl_lamports: i128,
|
||||
pub timestamp: i64, // unix secs
|
||||
}
|
||||
|
||||
// At startup, load trade_records.jsonl and populate SKIP_CREATORS.
|
||||
// Assumes each line is a JSON object matching TradeRecord.
|
||||
pub async fn load_skip_creators_from_file(path: &str) -> anyhow::Result<()> {
|
||||
// Use tokio::fs::File so we can await.
|
||||
let file = match File::open(path).await {
|
||||
Ok(f) => f,
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
|
||||
// No file yet: nothing to skip
|
||||
return Ok(());
|
||||
}
|
||||
Err(e) => return Err(e.into()),
|
||||
};
|
||||
let reader = BufReader::new(file);
|
||||
let mut lines = reader.lines();
|
||||
|
||||
// Acquire write lock synchronously (no `.await`).
|
||||
let mut skip_set = SKIP_CREATORS.write().unwrap();
|
||||
while let Some(line) = lines.next_line().await? {
|
||||
let line = line.trim();
|
||||
if line.is_empty() {
|
||||
continue;
|
||||
}
|
||||
match serde_json::from_str::<TradeRecord>(line) {
|
||||
Ok(rec) => {
|
||||
if rec.pnl_lamports < 0 {
|
||||
if let Ok(pubkey) = Pubkey::from_str(&rec.creator) {
|
||||
skip_set.insert(pubkey);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
log::warn!("Invalid trade record line: {}", line);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// When a new trade record is written and is negative, also update SKIP_CREATORS in-memory:
|
||||
pub async fn record_trade_and_maybe_skip(path: &str, rec: &TradeRecord) -> anyhow::Result<()> {
|
||||
// append to file asynchronously
|
||||
let mut file = tokio::fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.append(true)
|
||||
.open(path)
|
||||
.await?;
|
||||
let json = serde_json::to_string(rec)?;
|
||||
file.write_all(json.as_bytes()).await?;
|
||||
file.write_all(b"\n").await?;
|
||||
if rec.pnl_lamports < 0 {
|
||||
if let Ok(pubkey) = Pubkey::from_str(&rec.creator) {
|
||||
// Acquire write lock synchronously:
|
||||
SKIP_CREATORS.write().unwrap().insert(pubkey);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// In-memory partials keyed by mint:
|
||||
static PARTIALS: Lazy<Mutex<HashMap<String, PartialTrade>>> =
|
||||
Lazy::new(|| Mutex::new(HashMap::new()));
|
||||
|
||||
struct PartialTrade {
|
||||
creator: String,
|
||||
buy_lamports: u64,
|
||||
tokens_received: u64,
|
||||
buy_slot: u64,
|
||||
}
|
||||
|
||||
/// Call when a buy is confirmed:
|
||||
pub async fn record_buy(
|
||||
mint: &str,
|
||||
creator: &Pubkey,
|
||||
buy_lamports: u64,
|
||||
tokens_received: u64,
|
||||
buy_slot: u64,
|
||||
) {
|
||||
let mut map = PARTIALS.lock().await;
|
||||
map.insert(
|
||||
mint.to_string(),
|
||||
PartialTrade {
|
||||
creator: creator.to_string(),
|
||||
buy_lamports,
|
||||
tokens_received,
|
||||
buy_slot,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Call when a sell is confirmed:
|
||||
pub async fn record_sell(mint: &str, sell_lamports: u64, tokens_sold: u64, sell_slot: u64) {
|
||||
let mut map = PARTIALS.lock().await;
|
||||
if let Some(partial) = map.remove(mint) {
|
||||
let pnl = sell_lamports as i128 - partial.buy_lamports as i128;
|
||||
let record = TradeRecord {
|
||||
mint: mint.to_string(),
|
||||
creator: partial.creator.clone(),
|
||||
buy_lamports: partial.buy_lamports,
|
||||
tokens_received: partial.tokens_received,
|
||||
buy_slot: partial.buy_slot,
|
||||
sell_lamports,
|
||||
tokens_sold,
|
||||
sell_slot,
|
||||
pnl_lamports: pnl,
|
||||
timestamp: chrono::Utc::now().timestamp(),
|
||||
};
|
||||
// Append to file and update skip-set if needed
|
||||
if let Err(e) = record_trade_and_maybe_skip("trade_records.jsonl", &record).await {
|
||||
log::error!("Failed to append trade record: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
120
#_sniper (Rust) using jito Shred stream/src/trading_loop.rs
Normal file
120
#_sniper (Rust) using jito Shred stream/src/trading_loop.rs
Normal file
@@ -0,0 +1,120 @@
|
||||
// trading_loop.rs
|
||||
|
||||
use crate::common::utils::{
|
||||
create_nonblocking_rpc_client, create_rpc_client, import_env_var, import_wallet, AppState,
|
||||
SwapExecutionMode, SwapInput,
|
||||
};
|
||||
use crate::core::tx;
|
||||
use crate::dex::pump_fun::PUMP_PROGRAM;
|
||||
use crate::engine::swap::pump_swap;
|
||||
use dotenv::dotenv;
|
||||
use shared_state::{BuyOrder, SellOrder};
|
||||
use solana_sdk::{native_token, pubkey::Pubkey};
|
||||
use std::{
|
||||
env,
|
||||
str::FromStr,
|
||||
sync::{Arc, OnceLock},
|
||||
};
|
||||
use tokio::sync::{mpsc::Receiver, Notify, OnceCell};
|
||||
|
||||
static TRIGGER_NOTIFY: OnceCell<Arc<Notify>> = OnceCell::const_new();
|
||||
|
||||
/// Exposed so `pub use trading_loop::get_notify_handle;` still works.
|
||||
pub async fn get_notify_handle() -> Arc<Notify> {
|
||||
TRIGGER_NOTIFY
|
||||
.get_or_init(|| async { Arc::new(Notify::new()) })
|
||||
.await
|
||||
.clone()
|
||||
}
|
||||
|
||||
// Pre-parse these exactly once at program load:
|
||||
static PUMP_PROGRAM_KEY: OnceLock<Pubkey> = OnceLock::new();
|
||||
static LAMPORTS_PER_SOL_U64: OnceLock<u64> = OnceLock::new();
|
||||
|
||||
pub async fn start_trading_loop(mut mint_rx: Receiver<BuyOrder>, mut sell_rx: Receiver<SellOrder>) {
|
||||
// load .env if present
|
||||
dotenv().ok();
|
||||
|
||||
// one-time RPC & wallet setup
|
||||
let rpc = create_rpc_client().unwrap();
|
||||
let rpc_nonblocking = create_nonblocking_rpc_client().await.unwrap();
|
||||
let wallet = import_wallet().unwrap();
|
||||
|
||||
let app = AppState {
|
||||
rpc_client: rpc.clone(),
|
||||
rpc_nonblocking_client: rpc_nonblocking.clone(),
|
||||
wallet: wallet.clone(),
|
||||
};
|
||||
|
||||
// ─── SPAWN BLOCKHASH REFRESHER ───
|
||||
// This will keep a fresh recent‐blockhash in the background so sends never stall
|
||||
// ─── ONE-TIME TIP‐ENGINE INITIALIZATION ───
|
||||
// Read your env vars just once
|
||||
let block_engine = env::var("BLOCK_ENGINE_PROVIDER").unwrap_or_default();
|
||||
let use_nextblock = block_engine.eq_ignore_ascii_case("nextblock");
|
||||
let use_priority_tip = env::var("USE_PRIORITY_TIP")
|
||||
.unwrap_or_default()
|
||||
.eq_ignore_ascii_case("true");
|
||||
// This will create/fetch your tip‐accounts and pull the first tip value
|
||||
tx::init_tip_state(use_nextblock, use_priority_tip)
|
||||
.await
|
||||
.expect("failed to init tip engine");
|
||||
// stash env vars once
|
||||
let slippage_bps = import_env_var("SLIPPAGE").parse::<u16>().unwrap_or(15);
|
||||
let buy_amount_sol = import_env_var("BUY_AMOUNT_SOL")
|
||||
.parse::<f64>()
|
||||
.unwrap_or(0.01);
|
||||
|
||||
// initialize our OnceLocks
|
||||
let lamports_per_sol = *LAMPORTS_PER_SOL_U64.get_or_init(|| native_token::LAMPORTS_PER_SOL);
|
||||
let buy_amount_lamports = (buy_amount_sol * lamports_per_sol as f64) as u64;
|
||||
let pump_program_key =
|
||||
*PUMP_PROGRAM_KEY.get_or_init(|| Pubkey::from_str(PUMP_PROGRAM).unwrap());
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
// ───────── BUY ORDERS ─────────
|
||||
Some(BuyOrder { mint, creator, use_jito, urgent }) = mint_rx.recv() => {
|
||||
let mint_pk = Pubkey::from_str(&mint).unwrap();
|
||||
// derive creator vault address
|
||||
let (creator_vault, _) =
|
||||
Pubkey::find_program_address(&[b"creator-vault", creator.as_ref()], &pump_program_key);
|
||||
|
||||
let input = SwapInput {
|
||||
input_token_mint: spl_token::native_mint::ID,
|
||||
output_token_mint: mint_pk,
|
||||
slippage_bps,
|
||||
amount: buy_amount_lamports,
|
||||
mode: SwapExecutionMode::ExactIn,
|
||||
market: None,
|
||||
creator_vault: Some(creator_vault),
|
||||
};
|
||||
|
||||
let app_clone = app.clone();
|
||||
tokio::spawn(async move {
|
||||
let _ = pump_swap(app_clone, input, "buy", use_jito, urgent).await;
|
||||
});
|
||||
}
|
||||
|
||||
// ───────── SELL ORDERS ────────
|
||||
Some(SellOrder { mint, amount, use_jito, urgent }) = sell_rx.recv() => {
|
||||
let mint_pk = Pubkey::from_str(&mint).unwrap();
|
||||
|
||||
let input = SwapInput {
|
||||
input_token_mint: mint_pk,
|
||||
output_token_mint: spl_token::native_mint::ID,
|
||||
slippage_bps,
|
||||
amount,
|
||||
mode: SwapExecutionMode::ExactOut,
|
||||
market: None,
|
||||
creator_vault: None,
|
||||
};
|
||||
|
||||
let app_clone = app.clone();
|
||||
tokio::spawn(async move {
|
||||
let _ = pump_swap(app_clone, input, "sell", use_jito, urgent).await;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
390
#_sniper (Rust) using jito Shred stream/trade_records.jsonl
Normal file
390
#_sniper (Rust) using jito Shred stream/trade_records.jsonl
Normal file
@@ -0,0 +1,390 @@
|
||||
{"mint":"4DxH2nRs2SA4uqqddkSkpAM3mPLbhTK86q3ZahBypump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":153937741,"tokens_received":0,"buy_slot":347311946,"sell_lamports":137943497,"tokens_sold":5000000000000,"sell_slot":347311982,"pnl_lamports":-15994244,"timestamp":1750133620}
|
||||
{"mint":"F6LCD6eLzLcCivZiGiQddyrvm8xJgAGS31bkTZoLpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":174649889,"tokens_received":0,"buy_slot":347316858,"sell_lamports":137297743,"tokens_sold":0,"sell_slot":347316894,"pnl_lamports":-37352146,"timestamp":1750135583}
|
||||
{"mint":"3P1UMsoUntc5GDJRvnoS38py3K8wNNJyJFAyEo7apump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":144623036,"tokens_received":0,"buy_slot":347316984,"sell_lamports":136639943,"tokens_sold":5000000000000,"sell_slot":347317010,"pnl_lamports":-7983093,"timestamp":1750135633}
|
||||
{"mint":"5AYswZcdHVdu5BCKJPzbNyBCSzaLfTG8bXzcrQZ5pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":168758193,"tokens_received":0,"buy_slot":347317104,"sell_lamports":159867553,"tokens_sold":0,"sell_slot":347317120,"pnl_lamports":-8890640,"timestamp":1750135678}
|
||||
{"mint":"6jusvqh1dUm7KUCcK56hxeBQYkggAMKpmSEaaY8Ef3ZC","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":151494208,"tokens_received":0,"buy_slot":347471412,"sell_lamports":136785977,"tokens_sold":0,"sell_slot":347471446,"pnl_lamports":-14708231,"timestamp":1750197584}
|
||||
{"mint":"DsSFNuRPxGX9AHhuRSTdKVf232x2Dk3TTRZNEkLUpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":145098776,"tokens_received":0,"buy_slot":347477111,"sell_lamports":137559240,"tokens_sold":0,"sell_slot":347477261,"pnl_lamports":-7539536,"timestamp":1750199923}
|
||||
{"mint":"E9AdXtfabeBWR7UdJZw29DiNWutRfFb9Jro2cfq2pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":144420990,"tokens_received":0,"buy_slot":347477343,"sell_lamports":136818639,"tokens_sold":0,"sell_slot":347477427,"pnl_lamports":-7602351,"timestamp":1750199993}
|
||||
{"mint":"EieqGdcJMwRuqVnSbfULwTJzmYhQRq8JT9idQkCzpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":177810409,"tokens_received":0,"buy_slot":347477727,"sell_lamports":138039943,"tokens_sold":0,"sell_slot":347477745,"pnl_lamports":-39770466,"timestamp":1750200119}
|
||||
{"mint":"9rNGPghfS2THjDaJQQKmiJM3o26ykyatVZn39fL4pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":170546532,"tokens_received":0,"buy_slot":347479142,"sell_lamports":158050354,"tokens_sold":0,"sell_slot":347479146,"pnl_lamports":-12496178,"timestamp":1750200681}
|
||||
{"mint":"9ceRs9ZwsB3mTAwFGdQ5qSGZeQmgLA8WLMniHJEApump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":171638164,"tokens_received":0,"buy_slot":347479151,"sell_lamports":139039943,"tokens_sold":5000000000000,"sell_slot":347479171,"pnl_lamports":-32598221,"timestamp":1750200691}
|
||||
{"mint":"CDTDTqqJmL1ft8a3gcPuYBvMXEA9zXNWhoFVEDaipump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":146002227,"tokens_received":0,"buy_slot":347487368,"sell_lamports":141102292,"tokens_sold":5000000000000,"sell_slot":347487523,"pnl_lamports":-4899935,"timestamp":1750204042}
|
||||
{"mint":"Dqp6ats2iFAwXHZrBpV2NsXuo5hW41FLLD8NNRdWpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":163592683,"tokens_received":0,"buy_slot":347488212,"sell_lamports":136639951,"tokens_sold":0,"sell_slot":347488244,"pnl_lamports":-26952732,"timestamp":1750204329}
|
||||
{"mint":"8Hc3xZydnjDWnmicCiDn57kbLSJFM45EdxZPhSZipump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":185930736,"tokens_received":0,"buy_slot":347488323,"sell_lamports":177546077,"tokens_sold":0,"sell_slot":347488380,"pnl_lamports":-8384659,"timestamp":1750204384}
|
||||
{"mint":"DLWq4iKhQintex7j8kghjrFE4H6SPp95aeBRHW9ppump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":148677265,"tokens_received":0,"buy_slot":347488678,"sell_lamports":141744160,"tokens_sold":0,"sell_slot":347488831,"pnl_lamports":-6933105,"timestamp":1750204567}
|
||||
{"mint":"34wqHmwFKdC671bBmE5weWNeXCWQeHHXBaumgnuBpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347491416,"sell_lamports":0,"tokens_sold":0,"sell_slot":347491421,"pnl_lamports":-5000,"timestamp":1750205606}
|
||||
{"mint":"5Q4QYSeRtVeqoKKv2i7jABuhiMiYJNSrSzHqKmmrpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":148754165,"tokens_received":0,"buy_slot":347491652,"sell_lamports":141819538,"tokens_sold":5000000000000,"sell_slot":347491808,"pnl_lamports":-6934627,"timestamp":1750205760}
|
||||
{"mint":"CALrEKfSxko4gTgtpxxhjuHJbA35k6MzudADcUteo6xM","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":180453395,"tokens_received":0,"buy_slot":347491892,"sell_lamports":157616043,"tokens_sold":0,"sell_slot":347491903,"pnl_lamports":-22837352,"timestamp":1750205797}
|
||||
{"mint":"GoLqWvc1DqQGDNpbjx5XFXRqdapcdStXR9CUnvAXKRak","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":147230609,"tokens_received":0,"buy_slot":347491991,"sell_lamports":140785927,"tokens_sold":5000000000000,"sell_slot":347492016,"pnl_lamports":-6444682,"timestamp":1750205843}
|
||||
{"mint":"DnC6p9dHZnFwGtPy8FwkSaifswVCDVTBQS5zKoqcpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347492108,"sell_lamports":0,"tokens_sold":0,"sell_slot":347492127,"pnl_lamports":-5000,"timestamp":1750205887}
|
||||
{"mint":"ERy1mi86Yj5bvwkj6ZcPTENqKtMaMz9JiQMHLwbEPpDU","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":185361594,"tokens_received":0,"buy_slot":347492217,"sell_lamports":138039950,"tokens_sold":5000000000000,"sell_slot":347492349,"pnl_lamports":-47321644,"timestamp":1750205976}
|
||||
{"mint":"4z8vxGoPS2HMnNz61WpqqCT2Grpb5exVqRDbsZwCpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":156439422,"tokens_received":0,"buy_slot":347493397,"sell_lamports":136039952,"tokens_sold":0,"sell_slot":347493422,"pnl_lamports":-20399470,"timestamp":1750206407}
|
||||
{"mint":"5d1sEe8zsjkssyQtYau6ALpCgtiAEiptvAMFPdZppump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":148842226,"tokens_received":0,"buy_slot":347493500,"sell_lamports":137945459,"tokens_sold":0,"sell_slot":347493653,"pnl_lamports":-10896767,"timestamp":1750206501}
|
||||
{"mint":"2xQeszcoYrKsMmnobE8hQYR1AD5EDKBfUcXZFUtCpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":153189012,"tokens_received":0,"buy_slot":347496103,"sell_lamports":134460553,"tokens_sold":5000000000000,"sell_slot":347496508,"pnl_lamports":-18728459,"timestamp":1750207644}
|
||||
{"mint":"AsFHiuqHUU4mLDE6xUii4UBekk7eXacgR15TXienpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":198747842,"tokens_received":0,"buy_slot":347496774,"sell_lamports":181218546,"tokens_sold":0,"sell_slot":347496777,"pnl_lamports":-17529296,"timestamp":1750207752}
|
||||
{"mint":"BpaSVkodWrV1ZbxRpGDu5E4VMvXiZjpcykmvYf6ypump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":157954942,"tokens_received":0,"buy_slot":347496856,"sell_lamports":142917329,"tokens_sold":5000000000000,"sell_slot":347496862,"pnl_lamports":-15037613,"timestamp":1750207788}
|
||||
{"mint":"Fu6PgDj4RkjhyvhG5zVpjQNHPx3A4bUo52CCB8UndmAk","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":186653950,"tokens_received":0,"buy_slot":347496943,"sell_lamports":171048041,"tokens_sold":5000000000000,"sell_slot":347496944,"pnl_lamports":-15605909,"timestamp":1750207821}
|
||||
{"mint":"5oUFJFHK84hZfMZqPF2BRfWgEh1PfaToM1PzADmepump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":148978986,"tokens_received":0,"buy_slot":347497258,"sell_lamports":134166999,"tokens_sold":0,"sell_slot":347497662,"pnl_lamports":-14811987,"timestamp":1750208108}
|
||||
{"mint":"H7jqp3g6uTcLydmWQBCnrRnRpzf1H9CkPu4sVURqpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":154580474,"tokens_received":0,"buy_slot":347501008,"sell_lamports":135885940,"tokens_sold":0,"sell_slot":347501020,"pnl_lamports":-18694534,"timestamp":1750209465}
|
||||
{"mint":"EyNzeVDoFPPXfGhDh9LcCrgt2oPjjh9qGcALGzcopump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347502059,"sell_lamports":0,"tokens_sold":0,"sell_slot":347502062,"pnl_lamports":-5000,"timestamp":1750209879}
|
||||
{"mint":"BuEKpmaJiXgnjZzH8PckLMzNGkFBkZDv1DekgJofpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":165885512,"tokens_received":0,"buy_slot":347502067,"sell_lamports":136684668,"tokens_sold":5000000000000,"sell_slot":347502071,"pnl_lamports":-29200844,"timestamp":1750209883}
|
||||
{"mint":"AYR3GRRJ5VRwPo591GdmHdFkSyaAfwYHvMZU6cmYpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":161639469,"tokens_received":0,"buy_slot":347502077,"sell_lamports":138479030,"tokens_sold":5000000000000,"sell_slot":347502085,"pnl_lamports":-23160439,"timestamp":1750209888}
|
||||
{"mint":"DRVqp9uBWfScfjxC2wj3ADbK8K8Ar1WuC6HKA5Aipump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":161000817,"tokens_received":0,"buy_slot":347502087,"sell_lamports":134039952,"tokens_sold":0,"sell_slot":347502159,"pnl_lamports":-26960865,"timestamp":1750209919}
|
||||
{"mint":"H9oC98SM2MnFhHxujKZbayjecf7YM8qiPkd111KJpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":164582588,"tokens_received":0,"buy_slot":347502521,"sell_lamports":136819798,"tokens_sold":0,"sell_slot":347502533,"pnl_lamports":-27762790,"timestamp":1750210066}
|
||||
{"mint":"5sq6xDoiqnTEXToLpA4ZavJW3UmwuUXeR9GgzeHdpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":185047505,"tokens_received":0,"buy_slot":347502738,"sell_lamports":152106430,"tokens_sold":0,"sell_slot":347502784,"pnl_lamports":-32941075,"timestamp":1750210166}
|
||||
{"mint":"4ZPs2t1TfaXX5QN6Y6KhoKwbs2hZsUFTTYFJWmTQpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":162337130,"tokens_received":0,"buy_slot":347503132,"sell_lamports":152857570,"tokens_sold":0,"sell_slot":347503148,"pnl_lamports":-9479560,"timestamp":1750210310}
|
||||
{"mint":"aG8kT6wwLZMrrJ55iQ9HanphmrMnstd597QRyCrpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":177645442,"tokens_received":0,"buy_slot":347503403,"sell_lamports":162997634,"tokens_sold":5000000000000,"sell_slot":347503404,"pnl_lamports":-14647808,"timestamp":1750210414}
|
||||
{"mint":"E5rzqJzBvFDx4zq6mTTEyV5ou8YQg92dj1CeTW9ipump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":154851919,"tokens_received":0,"buy_slot":347503408,"sell_lamports":140151244,"tokens_sold":5000000000000,"sell_slot":347503585,"pnl_lamports":-14700675,"timestamp":1750210487}
|
||||
{"mint":"8Jbe8VgaLEVpmE8DRYAsi8c8Rm7WxSfaqYRwykt1pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":180767390,"tokens_received":0,"buy_slot":347503589,"sell_lamports":241765820,"tokens_sold":5000000000000,"sell_slot":347503597,"pnl_lamports":60998430,"timestamp":1750210492}
|
||||
{"mint":"3BoomWazAARD3yLrtUfvqmkja23GEonVzs6NoJecpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":164766466,"tokens_received":0,"buy_slot":347504654,"sell_lamports":169873045,"tokens_sold":5000000000000,"sell_slot":347504658,"pnl_lamports":5106579,"timestamp":1750210914}
|
||||
{"mint":"CHeFZPQZ6X4rL6sTvQZVxk7atywWXgv9uq51Uyivpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":169334341,"tokens_received":0,"buy_slot":347504662,"sell_lamports":162480810,"tokens_sold":0,"sell_slot":347504703,"pnl_lamports":-6853531,"timestamp":1750210932}
|
||||
{"mint":"HhELATZZia8u2KRRrZYLuQjCweCHGf7LS4pMcNmEpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347504706,"sell_lamports":0,"tokens_sold":0,"sell_slot":347504709,"pnl_lamports":-5000,"timestamp":1750210936}
|
||||
{"mint":"FvaqGvRv4mCm8yRrLe3mwXceUzcubVsc4qbMWXtTpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":177139433,"tokens_received":0,"buy_slot":347504722,"sell_lamports":301752412,"tokens_sold":5000000000000,"sell_slot":347504728,"pnl_lamports":124612979,"timestamp":1750210943}
|
||||
{"mint":"GPpZtiJ7LEhTjERnuKLaNC2G5i2hXdBJCsjvGGQ4pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":164021069,"tokens_received":0,"buy_slot":347504737,"sell_lamports":139266269,"tokens_sold":5000000000000,"sell_slot":347504743,"pnl_lamports":-24754800,"timestamp":1750210949}
|
||||
{"mint":"G8zfcGneV7bX3zfme9AfZeYvYHLe3ayMGgyn8y1Tpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":165029947,"tokens_received":0,"buy_slot":347504760,"sell_lamports":162676058,"tokens_sold":5000000000000,"sell_slot":347504776,"pnl_lamports":-2353889,"timestamp":1750210963}
|
||||
{"mint":"HAVgh5JDKdfW5S6QKUsraLTbr9YduR5YaU8TLCVcpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":179279906,"tokens_received":0,"buy_slot":347504795,"sell_lamports":170518209,"tokens_sold":5000000000000,"sell_slot":347504796,"pnl_lamports":-8761697,"timestamp":1750210970}
|
||||
{"mint":"AZjq4U89GDYfoD1cSdMccoQE54476KM298M2aPQoyc4H","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347504808,"sell_lamports":0,"tokens_sold":0,"sell_slot":347504814,"pnl_lamports":-5000,"timestamp":1750210978}
|
||||
{"mint":"9rmEegGhmcipQ91mSdUHLs9JgNHYqhieHXcjW4Gqpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":175512577,"tokens_received":0,"buy_slot":347504817,"sell_lamports":138039951,"tokens_sold":5000000000000,"sell_slot":347504859,"pnl_lamports":-37472626,"timestamp":1750210996}
|
||||
{"mint":"79WYGn7ANggpawF9QZtFY9XXkfyJwkkZ5jzSNhPMpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":169977975,"tokens_received":0,"buy_slot":347504873,"sell_lamports":146010644,"tokens_sold":0,"sell_slot":347504892,"pnl_lamports":-23967331,"timestamp":1750211010}
|
||||
{"mint":"GiXb7UQjBjS412uWhbPwBi7MrGmgdqxxcidvNW8dpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":175206230,"tokens_received":0,"buy_slot":347504896,"sell_lamports":169400726,"tokens_sold":0,"sell_slot":347504903,"pnl_lamports":-5805504,"timestamp":1750211014}
|
||||
{"mint":"CVkEbMhDHe6JawXvmx8eanHHYcZkekHtd13QBpQKpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":160712566,"tokens_received":0,"buy_slot":347504908,"sell_lamports":138662517,"tokens_sold":0,"sell_slot":347505164,"pnl_lamports":-22050049,"timestamp":1750211119}
|
||||
{"mint":"Aq1wu7GJ4yKGe3SSNvQQnSrU2v1aCs3NSpsRHvocpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":162002474,"tokens_received":0,"buy_slot":347505175,"sell_lamports":147392215,"tokens_sold":5000000000000,"sell_slot":347505196,"pnl_lamports":-14610259,"timestamp":1750211132}
|
||||
{"mint":"92TWc7kEjprezUTZ2VViz6Aw37fRxJsfLhjRDGVZpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":170819668,"tokens_received":0,"buy_slot":347505209,"sell_lamports":159948483,"tokens_sold":0,"sell_slot":347505295,"pnl_lamports":-10871185,"timestamp":1750211172}
|
||||
{"mint":"8jHMSkXEQiSchfURmxRBBuk6bjXhgSCkfk5nTjRjpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":163799593,"tokens_received":0,"buy_slot":347505300,"sell_lamports":177434405,"tokens_sold":0,"sell_slot":347505321,"pnl_lamports":13634812,"timestamp":1750211181}
|
||||
{"mint":"1Tp3k5DRKBdQ3B5RYm7CvKLGwZNSFUVUEFBGiC1YFKc","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":175654766,"tokens_received":0,"buy_slot":347506777,"sell_lamports":177981016,"tokens_sold":5000000000000,"sell_slot":347506789,"pnl_lamports":2326250,"timestamp":1750211770}
|
||||
{"mint":"CDUcTUQMNiYhX3E9vjLc94uau6XdojLQPkE9sYtwC3v9","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":147277924,"tokens_received":0,"buy_slot":347506795,"sell_lamports":138039952,"tokens_sold":5000000000000,"sell_slot":347506857,"pnl_lamports":-9237972,"timestamp":1750211796}
|
||||
{"mint":"2QmaWwjheohrLUusSB1Zz1fmMcgwSPrfcdjn6sDspump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":167349441,"tokens_received":0,"buy_slot":347507551,"sell_lamports":157050364,"tokens_sold":5000000000000,"sell_slot":347507573,"pnl_lamports":-10299077,"timestamp":1750212084}
|
||||
{"mint":"9VpmheJu714qmwbWabkWaB3nDCzSjKsvXNduYsaTpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347507578,"sell_lamports":0,"tokens_sold":0,"sell_slot":347507583,"pnl_lamports":-5000,"timestamp":1750212087}
|
||||
{"mint":"3xP6Ju9pWJ8sRLSc8PxNR1L328vUjC6zYLEjtCkppump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":180576243,"tokens_received":0,"buy_slot":347507587,"sell_lamports":142543755,"tokens_sold":5000000000000,"sell_slot":347507591,"pnl_lamports":-38032488,"timestamp":1750212090}
|
||||
{"mint":"9q5bCnBW6TKNZZeMEW58cLKNVQses6Z7nGMaABCLPXBn","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":178158085,"tokens_received":0,"buy_slot":347507593,"sell_lamports":191063682,"tokens_sold":5000000000000,"sell_slot":347507604,"pnl_lamports":12905597,"timestamp":1750212096}
|
||||
{"mint":"FWQUcSoU2eGshPGc2hs2MG4sqs2FoT1qXzcoFV2rpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":168587994,"tokens_received":0,"buy_slot":347507614,"sell_lamports":183743684,"tokens_sold":0,"sell_slot":347507617,"pnl_lamports":15155690,"timestamp":1750212102}
|
||||
{"mint":"9ft48QMXug18oo7KghoYcixXFVVVae1Bjhfzgdc8pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":162562531,"tokens_received":0,"buy_slot":347507626,"sell_lamports":149700840,"tokens_sold":5000000000000,"sell_slot":347507641,"pnl_lamports":-12861691,"timestamp":1750212111}
|
||||
{"mint":"AykmqoiLDHioQxJcgREdThzt6uL2t4kgMjwAhqsvak1N","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347509026,"sell_lamports":0,"tokens_sold":0,"sell_slot":347509036,"pnl_lamports":-5000,"timestamp":1750212674}
|
||||
{"mint":"FeHNSjVCDiJuDV8ZZdnKTvciz53CWwepUW84XSwjpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":326240564,"tokens_received":0,"buy_slot":347509039,"sell_lamports":453783733,"tokens_sold":10000000000000,"sell_slot":347509043,"pnl_lamports":127543169,"timestamp":1750212676}
|
||||
{"mint":"9kXVDAQdyiD1shTMgPLXEkQ3fJPVSb2D3ZtnEz4Fsrtz","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":302587330,"tokens_received":0,"buy_slot":347509044,"sell_lamports":278694782,"tokens_sold":10000000000000,"sell_slot":347509061,"pnl_lamports":-23892548,"timestamp":1750212683}
|
||||
{"mint":"1dpF1Zirs9asqxuXQCFW9Pk7SgbQS1ZkgCdGnWQxFLg","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":288086615,"tokens_received":0,"buy_slot":347509081,"sell_lamports":278411315,"tokens_sold":10000000000000,"sell_slot":347509483,"pnl_lamports":-9675300,"timestamp":1750212852}
|
||||
{"mint":"2fRJApP8puJzynzYihgp2G1CLeHVZrGN4TczDxQ1pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":327159115,"tokens_received":0,"buy_slot":347509487,"sell_lamports":278392945,"tokens_sold":10000000000000,"sell_slot":347509535,"pnl_lamports":-48766170,"timestamp":1750212873}
|
||||
{"mint":"vkTRLDaFZ8o5NAoE3pD49sCLP8gAjQw6bipp7V9pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":358376754,"tokens_received":0,"buy_slot":347509540,"sell_lamports":351989860,"tokens_sold":10000000000000,"sell_slot":347509541,"pnl_lamports":-6386894,"timestamp":1750212876}
|
||||
{"mint":"9P9zJWnEVzjfHeiLZVKA7sm4i3xDM7V31RGtgkgpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":311611639,"tokens_received":0,"buy_slot":347509544,"sell_lamports":301452110,"tokens_sold":10000000000000,"sell_slot":347509551,"pnl_lamports":-10159529,"timestamp":1750212880}
|
||||
{"mint":"7x4KXgQ3h9tULjdQe9jz6dWN2tDZ9uuMzHogASe9pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":337528122,"tokens_received":0,"buy_slot":347509560,"sell_lamports":278392928,"tokens_sold":0,"sell_slot":347509610,"pnl_lamports":-59135194,"timestamp":1750212905}
|
||||
{"mint":"CU7px7F94bgQP1M4N2pZ1NTf3Wy39eLGGz1bpDaq1aEg","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":391627824,"tokens_received":0,"buy_slot":347509627,"sell_lamports":278392942,"tokens_sold":0,"sell_slot":347509704,"pnl_lamports":-113234882,"timestamp":1750212942}
|
||||
{"mint":"AputqVucipkN6SKtKSJH1Gt3gd5Xcr5GYCcxgJEVpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":178512891,"tokens_received":0,"buy_slot":347511703,"sell_lamports":138039943,"tokens_sold":5000000000000,"sell_slot":347511745,"pnl_lamports":-40472948,"timestamp":1750213761}
|
||||
{"mint":"FuSuvNP31ugJ7a3M6j2dxDA686ANEWdLrNtYgCDMpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":191562495,"tokens_received":0,"buy_slot":347511757,"sell_lamports":209372956,"tokens_sold":0,"sell_slot":347511761,"pnl_lamports":17810461,"timestamp":1750213768}
|
||||
{"mint":"Bx6GthauvET9wPzEX9dhYZFQZREQaZuG2yQNB9jepump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":169450415,"tokens_received":0,"buy_slot":347511780,"sell_lamports":144967615,"tokens_sold":5000000000000,"sell_slot":347511966,"pnl_lamports":-24482800,"timestamp":1750213850}
|
||||
{"mint":"FYiszCW3gFAG8D1hwU4jKyhdWRwkJaynVnv7KXgVpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":168313880,"tokens_received":0,"buy_slot":347512476,"sell_lamports":138039951,"tokens_sold":0,"sell_slot":347512547,"pnl_lamports":-30273929,"timestamp":1750214084}
|
||||
{"mint":"5Qw1dS2AMFPUcmvgC7xbpaa9LAewHJSNePdSP1Wf2jqJ","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":174767935,"tokens_received":0,"buy_slot":347512555,"sell_lamports":160765646,"tokens_sold":5000000000000,"sell_slot":347512584,"pnl_lamports":-14002289,"timestamp":1750214098}
|
||||
{"mint":"DeW5KqFmH4mBe4nSgpiQm47c139GfJSsUVX4RumApump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":175458276,"tokens_received":0,"buy_slot":347512593,"sell_lamports":138039951,"tokens_sold":5000000000000,"sell_slot":347512657,"pnl_lamports":-37418325,"timestamp":1750214126}
|
||||
{"mint":"FoFq5ffiipdCoFEejKGkJHDSHKPUPd2N1wrTjFUDoHLt","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":185361583,"tokens_received":0,"buy_slot":347512941,"sell_lamports":174028315,"tokens_sold":0,"sell_slot":347512964,"pnl_lamports":-11333268,"timestamp":1750214249}
|
||||
{"mint":"NNT2Q5cpnKSBbhFSyTyQtZekKyE8sk6bCNfApiipump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":166320932,"tokens_received":0,"buy_slot":347512976,"sell_lamports":167804891,"tokens_sold":0,"sell_slot":347512986,"pnl_lamports":1483959,"timestamp":1750214258}
|
||||
{"mint":"8veaQPsWZ2mDwphJQEs2RbZMh8eUiN7FJGriUkFUpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":180360057,"tokens_received":0,"buy_slot":347512998,"sell_lamports":185120939,"tokens_sold":0,"sell_slot":347513010,"pnl_lamports":4760882,"timestamp":1750214267}
|
||||
{"mint":"GZk7aLb6fwysRZwHFvNRuDzpTbSaazfStEMmarC8pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":154829405,"tokens_received":0,"buy_slot":347513857,"sell_lamports":138711380,"tokens_sold":0,"sell_slot":347513894,"pnl_lamports":-16118025,"timestamp":1750214623}
|
||||
{"mint":"61SBrndyLQweFvYz1RUC6C9rSwLUcdhDrXspQqz5pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":168080857,"tokens_received":0,"buy_slot":347513906,"sell_lamports":157050364,"tokens_sold":5000000000000,"sell_slot":347513924,"pnl_lamports":-11030493,"timestamp":1750214636}
|
||||
{"mint":"Fp833QMb3YRWHrDoyGnndSq8GoPjz1ZMQeNgwJQY4ynL","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":196274018,"tokens_received":0,"buy_slot":347513929,"sell_lamports":138080471,"tokens_sold":0,"sell_slot":347514014,"pnl_lamports":-58193547,"timestamp":1750214671}
|
||||
{"mint":"134tbGFATvhQwDUYfp7Dpju79KxmTCYZq2cpGypWpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":175425825,"tokens_received":0,"buy_slot":347514019,"sell_lamports":138085938,"tokens_sold":5000000000000,"sell_slot":347514332,"pnl_lamports":-37339887,"timestamp":1750214800}
|
||||
{"mint":"6ygocSg36t7su8b52NZqgwbbLHcVG5vii8saSJJvpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":190116418,"tokens_received":0,"buy_slot":347515425,"sell_lamports":194304301,"tokens_sold":5000000000000,"sell_slot":347515426,"pnl_lamports":4187883,"timestamp":1750215240}
|
||||
{"mint":"FjTSrGt8N1PTWC8ywWjKjuChFGKtaJ3euuNo6qRxpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":167309527,"tokens_received":0,"buy_slot":347515428,"sell_lamports":138039951,"tokens_sold":0,"sell_slot":347515479,"pnl_lamports":-29269576,"timestamp":1750215260}
|
||||
{"mint":"EAayig1Cqk1eNH9RYJZAsEfEdAcMb3K4ZiXDLuD6pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":174767935,"tokens_received":0,"buy_slot":347515485,"sell_lamports":167318194,"tokens_sold":0,"sell_slot":347515513,"pnl_lamports":-7449741,"timestamp":1750215274}
|
||||
{"mint":"Gi4HkMfywxGwHVJWCDTJsKb1FcKJKPwEQdjozBknpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347515518,"sell_lamports":0,"tokens_sold":0,"sell_slot":347515532,"pnl_lamports":-5000,"timestamp":1750215281}
|
||||
{"mint":"GYP4aTcDaVkKm7YeDDLmcA2Qni247trgsWt9RiQ8pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":193516428,"tokens_received":0,"buy_slot":347515544,"sell_lamports":224002490,"tokens_sold":0,"sell_slot":347515550,"pnl_lamports":30486062,"timestamp":1750215288}
|
||||
{"mint":"3gABeNGS5Fj6FEsNwEZtawXCvrrsYHRfABwJEwHqwbDW","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":159118273,"tokens_received":0,"buy_slot":347515563,"sell_lamports":145974801,"tokens_sold":5000000000000,"sell_slot":347515579,"pnl_lamports":-13143472,"timestamp":1750215299}
|
||||
{"mint":"DCGuj3YVS3dY9BmxMQBn9ahPVn9pp33wDZp53XHcpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":168321400,"tokens_received":0,"buy_slot":347515584,"sell_lamports":138039951,"tokens_sold":5000000000000,"sell_slot":347515618,"pnl_lamports":-30281449,"timestamp":1750215315}
|
||||
{"mint":"GXUHcwp9HDrwoqDHiBPtQeaEpKuL5TUeBiRYGUp8M4Ve","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":154536409,"tokens_received":0,"buy_slot":347515624,"sell_lamports":147487282,"tokens_sold":5000000000000,"sell_slot":347515702,"pnl_lamports":-7049127,"timestamp":1750215349}
|
||||
{"mint":"H3uqskXom9Yo7A5qBLyK55aLxc3nzgsC2tZ4cXC2pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":145838296,"tokens_received":0,"buy_slot":347516120,"sell_lamports":139017358,"tokens_sold":5000000000000,"sell_slot":347516151,"pnl_lamports":-6820938,"timestamp":1750215527}
|
||||
{"mint":"4z7EMkVbcgwjBjrCmB2W7e1xbdhpTU4EW4M5fwiTf8rn","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347516155,"sell_lamports":0,"tokens_sold":0,"sell_slot":347516166,"pnl_lamports":-5000,"timestamp":1750215533}
|
||||
{"mint":"43DatYePiw5wAx6S5yXHEwcyqtLKMDhQL9ZpNMmJdiqJ","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":196274018,"tokens_received":0,"buy_slot":347516172,"sell_lamports":138039950,"tokens_sold":0,"sell_slot":347516245,"pnl_lamports":-58234068,"timestamp":1750215566}
|
||||
{"mint":"2BNFmyfcnSjnYgwiRMMwNvrMEHG4EMFRkPJSP8fwpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":164292683,"tokens_received":0,"buy_slot":347516251,"sell_lamports":157050364,"tokens_sold":0,"sell_slot":347516328,"pnl_lamports":-7242319,"timestamp":1750215599}
|
||||
{"mint":"Epwg2GGZ4ccNeFCUudqUjtxzzWFcQn3W6vz1pgEiLCAg","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":185361583,"tokens_received":0,"buy_slot":347516337,"sell_lamports":138039950,"tokens_sold":0,"sell_slot":347516388,"pnl_lamports":-47321633,"timestamp":1750215623}
|
||||
{"mint":"4resdanSkUpY7Eru1jXbUDpn9XqsEkJRCoLUANzGpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":190977591,"tokens_received":0,"buy_slot":347516390,"sell_lamports":191111142,"tokens_sold":0,"sell_slot":347516392,"pnl_lamports":133551,"timestamp":1750215625}
|
||||
{"mint":"Buwa3feVdgVZG1sSYYeY4yZhPtEdw72YLS7WqtrFpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":192382339,"tokens_received":0,"buy_slot":347516404,"sell_lamports":167931074,"tokens_sold":5000000000000,"sell_slot":347516409,"pnl_lamports":-24451265,"timestamp":1750215632}
|
||||
{"mint":"DCR7ZZoFM5KDWjePbVSGXHEK2X7G9JL5y3EkJqVrpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":159901727,"tokens_received":0,"buy_slot":347516437,"sell_lamports":138189808,"tokens_sold":0,"sell_slot":347516440,"pnl_lamports":-21711919,"timestamp":1750215644}
|
||||
{"mint":"E5Y7atNeq6s4FX2R9Nw2XktMoVPtiFss5HNycQMKpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":160596506,"tokens_received":0,"buy_slot":347516458,"sell_lamports":147392214,"tokens_sold":5000000000000,"sell_slot":347516466,"pnl_lamports":-13204292,"timestamp":1750215655}
|
||||
{"mint":"CKvzjdVm5jfBymN3LHUZsNQi9fhExaFznwZYTAd9pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":144992082,"tokens_received":0,"buy_slot":347516767,"sell_lamports":138251038,"tokens_sold":5000000000000,"sell_slot":347516793,"pnl_lamports":-6741044,"timestamp":1750215786}
|
||||
{"mint":"4uyLURYRqZHSgWz8xesi7u258QsK2QeojU6mwcgppump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":180560153,"tokens_received":0,"buy_slot":347516795,"sell_lamports":225265367,"tokens_sold":5000000000000,"sell_slot":347516801,"pnl_lamports":44705214,"timestamp":1750215790}
|
||||
{"mint":"3rpp1AkGnSiL2Sn8LMhtm128V9JnDZNj7ktb3aqupump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":165817451,"tokens_received":0,"buy_slot":347516802,"sell_lamports":167423757,"tokens_sold":5000000000000,"sell_slot":347516851,"pnl_lamports":1606306,"timestamp":1750215811}
|
||||
{"mint":"H1BCkUB7UtjESVcHXDwUAnR4mR3aXp7q4V7JmXAipump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":176992067,"tokens_received":0,"buy_slot":347517155,"sell_lamports":176243609,"tokens_sold":0,"sell_slot":347517157,"pnl_lamports":-748458,"timestamp":1750215931}
|
||||
{"mint":"769QBKCMDFEhyA4kxacJ9VPYiZpVk1y76LGVgN9bpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":168128579,"tokens_received":0,"buy_slot":347517173,"sell_lamports":148493513,"tokens_sold":0,"sell_slot":347517178,"pnl_lamports":-19635066,"timestamp":1750215940}
|
||||
{"mint":"BgBiSYYZ3YC7xzkVaCrx4cWpr2iqrsXFt2N66VYMpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":154439412,"tokens_received":0,"buy_slot":347517185,"sell_lamports":139228417,"tokens_sold":5000000000000,"sell_slot":347517190,"pnl_lamports":-15210995,"timestamp":1750215944}
|
||||
{"mint":"24rpR3wxbd6PHNiXVzYk82Z1KVkyybctmRA98DXjpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":154829492,"tokens_received":0,"buy_slot":347517203,"sell_lamports":138217201,"tokens_sold":0,"sell_slot":347517210,"pnl_lamports":-16612291,"timestamp":1750215953}
|
||||
{"mint":"8qJ2z1Hi4maiTHyP9a6dzsTNPwvnJ8pvvoshpUk1Sgny","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":174552930,"tokens_received":0,"buy_slot":347517218,"sell_lamports":187522131,"tokens_sold":5000000000000,"sell_slot":347517220,"pnl_lamports":12969201,"timestamp":1750215957}
|
||||
{"mint":"DcDnAQqjLR8g5sj3tDTFtjxFXzsaYVYyNmfpZueFpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":176861169,"tokens_received":0,"buy_slot":347517222,"sell_lamports":155874037,"tokens_sold":5000000000000,"sell_slot":347517225,"pnl_lamports":-20987132,"timestamp":1750215960}
|
||||
{"mint":"CN6b4XxEaHCyUb2Ey2gpV1DY7AHzWrUCtuopMZkm3mGK","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":174024140,"tokens_received":0,"buy_slot":347517227,"sell_lamports":160251850,"tokens_sold":5000000000000,"sell_slot":347517237,"pnl_lamports":-13772290,"timestamp":1750215965}
|
||||
{"mint":"DFQfq3YxQAfFg5BUcLKKJ2TnjHMNGuYCdgsYKtC2pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":151914813,"tokens_received":0,"buy_slot":347517240,"sell_lamports":142488375,"tokens_sold":0,"sell_slot":347517318,"pnl_lamports":-9426438,"timestamp":1750215997}
|
||||
{"mint":"GaAAvMGR8TNECm9LN7BhHJGHsMSZE9H2bFR5eeFvpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":166320932,"tokens_received":0,"buy_slot":347517333,"sell_lamports":159232051,"tokens_sold":0,"sell_slot":347517344,"pnl_lamports":-7088881,"timestamp":1750216007}
|
||||
{"mint":"Dh3uEWobcyERQJZGFdavTdNPxgKjCWrBj91YWUv6d7xM","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":170619703,"tokens_received":0,"buy_slot":347517889,"sell_lamports":163252094,"tokens_sold":0,"sell_slot":347517891,"pnl_lamports":-7367609,"timestamp":1750216229}
|
||||
{"mint":"69uHdZNRzPYFJvRifAhfUqnd7UePPfEhfgqzEbehpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":166320932,"tokens_received":0,"buy_slot":347517893,"sell_lamports":437980310,"tokens_sold":5000000000000,"sell_slot":347517899,"pnl_lamports":271659378,"timestamp":1750216232}
|
||||
{"mint":"6bFKPWTUD6Xep3M3BWdVxGrRM7kLoe5uSmJgBHK9pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":151717366,"tokens_received":0,"buy_slot":347517908,"sell_lamports":142497725,"tokens_sold":0,"sell_slot":347517986,"pnl_lamports":-9219641,"timestamp":1750216267}
|
||||
{"mint":"8dpmBfMGcsFdNRT3B3k112X8QnpgPGeTjVcEwuF9pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":150175534,"tokens_received":0,"buy_slot":347518199,"sell_lamports":141266384,"tokens_sold":5000000000000,"sell_slot":347518257,"pnl_lamports":-8909150,"timestamp":1750216376}
|
||||
{"mint":"9aDtA41UDhBUnts6V1pGR4uM2zAnewWG4FxuXGPBpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":177686389,"tokens_received":0,"buy_slot":347518267,"sell_lamports":179128076,"tokens_sold":0,"sell_slot":347518277,"pnl_lamports":1441687,"timestamp":1750216385}
|
||||
{"mint":"DoBuLF4oGf4c7pYYupuXxWTfu8ZhrKexUUPSF1o2pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":153471252,"tokens_received":0,"buy_slot":347518284,"sell_lamports":138039943,"tokens_sold":5000000000000,"sell_slot":347518329,"pnl_lamports":-15431309,"timestamp":1750216406}
|
||||
{"mint":"5vHnVZRetzwVoGq7rkXtgxWpH6YANDeAaaRa7bx4pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":184101706,"tokens_received":0,"buy_slot":347518339,"sell_lamports":269163656,"tokens_sold":5000000000000,"sell_slot":347518344,"pnl_lamports":85061950,"timestamp":1750216412}
|
||||
{"mint":"85ArwijitJ8pUqpQNiP6zrrWgxUYebyRzVDyWoX5pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":189889436,"tokens_received":0,"buy_slot":347518349,"sell_lamports":152248365,"tokens_sold":0,"sell_slot":347518354,"pnl_lamports":-37641071,"timestamp":1750216416}
|
||||
{"mint":"C1NdJvJmxnunUPUWqPG9AcjRsH68XmkYDPBTfpJjpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":170507468,"tokens_received":0,"buy_slot":347518366,"sell_lamports":148344253,"tokens_sold":0,"sell_slot":347518370,"pnl_lamports":-22163215,"timestamp":1750216422}
|
||||
{"mint":"7RMQre4vQMtQdjWJt5SkRGYHBby4EKxpgEhQrWW3pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":202376021,"tokens_received":0,"buy_slot":347518379,"sell_lamports":193518242,"tokens_sold":5000000000000,"sell_slot":347518384,"pnl_lamports":-8857779,"timestamp":1750216428}
|
||||
{"mint":"A9Tabone9NJ3sK193DjSJvT7ShGKTxpmXktFW5aYpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":158382562,"tokens_received":0,"buy_slot":347518401,"sell_lamports":147392215,"tokens_sold":0,"sell_slot":347518409,"pnl_lamports":-10990347,"timestamp":1750216438}
|
||||
{"mint":"5mrnPovjnpypbebb7mvUoVmCEmyzpHG5kufvnaSZpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":170609809,"tokens_received":0,"buy_slot":347518442,"sell_lamports":153843546,"tokens_sold":0,"sell_slot":347518452,"pnl_lamports":-16766263,"timestamp":1750216455}
|
||||
{"mint":"DtrrKkCah7iXtwPUYokDymTCRgyycANwipAFvXEjFpLE","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":154536400,"tokens_received":0,"buy_slot":347518932,"sell_lamports":147487282,"tokens_sold":0,"sell_slot":347519010,"pnl_lamports":-7049118,"timestamp":1750216678}
|
||||
{"mint":"5rjvHdcF2B1ArjmFB9RJiVxP2tCVPN4bSdrZGWrkpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":181826373,"tokens_received":0,"buy_slot":347519017,"sell_lamports":144277064,"tokens_sold":0,"sell_slot":347519022,"pnl_lamports":-37549309,"timestamp":1750216682}
|
||||
{"mint":"4YobXovMLVeEqVGzs3oPAe3JQYEywKsgG2CQu1XEpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":154738234,"tokens_received":0,"buy_slot":347519031,"sell_lamports":138045462,"tokens_sold":5000000000000,"sell_slot":347519040,"pnl_lamports":-16692772,"timestamp":1750216690}
|
||||
{"mint":"7Q4FJRc8vgAMSJAdgUtA5os4MYEjEBA8mydvTCQbpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347519050,"sell_lamports":0,"tokens_sold":0,"sell_slot":347519063,"pnl_lamports":-5000,"timestamp":1750216699}
|
||||
{"mint":"7zT8ZNqJtMmSXgAhmCPRXuiTyQEToHYWcicecbiypump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":180873334,"tokens_received":0,"buy_slot":347519352,"sell_lamports":175450475,"tokens_sold":0,"sell_slot":347519353,"pnl_lamports":-5422859,"timestamp":1750216817}
|
||||
{"mint":"6DrHbBvBPQTyLcwwWZFYiHnAbcqfwR7bx9iUK8eXpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":174767935,"tokens_received":0,"buy_slot":347519355,"sell_lamports":142699951,"tokens_sold":0,"sell_slot":347519360,"pnl_lamports":-32067984,"timestamp":1750216820}
|
||||
{"mint":"HGMCJkXHyJDEd1MzJxCf6i7hSr6kKo6YCy1tWVsgpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":169365309,"tokens_received":0,"buy_slot":347519373,"sell_lamports":162022550,"tokens_sold":0,"sell_slot":347519375,"pnl_lamports":-7342759,"timestamp":1750216826}
|
||||
{"mint":"7CyK5ZK3GAg8zedHGr5wCy5ptpVTshYQsm5Cz4rTpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":154407936,"tokens_received":0,"buy_slot":347519380,"sell_lamports":149430944,"tokens_sold":0,"sell_slot":347519389,"pnl_lamports":-4976992,"timestamp":1750216831}
|
||||
{"mint":"Gt8XznFv5hN2K6YZyyiwF5d5UJowRKqDdzBvpt9upump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":160154094,"tokens_received":0,"buy_slot":347519392,"sell_lamports":164607744,"tokens_sold":0,"sell_slot":347519393,"pnl_lamports":4453650,"timestamp":1750216832}
|
||||
{"mint":"3jGDUnFJj2tFUts4t9RLK9bLhrYE4ZZ1rRUEnLECpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":152664321,"tokens_received":0,"buy_slot":347519401,"sell_lamports":142299640,"tokens_sold":0,"sell_slot":347519480,"pnl_lamports":-10364681,"timestamp":1750216867}
|
||||
{"mint":"8r6VZKDbJjTTBf6mcmfY2qAAWFRm8KsQmSr9gcyzpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":185466956,"tokens_received":0,"buy_slot":347519770,"sell_lamports":179967098,"tokens_sold":0,"sell_slot":347519776,"pnl_lamports":-5499858,"timestamp":1750216987}
|
||||
{"mint":"37KSUe76NCu4pUWUDX6nNpLhmmanx6Rst7MhuivPpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347519792,"sell_lamports":0,"tokens_sold":0,"sell_slot":347519797,"pnl_lamports":-5000,"timestamp":1750216995}
|
||||
{"mint":"AgpMKK3Q8FBYD4CfCbFZZoUfv9kgwRprATUYcwqepump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":168464311,"tokens_received":0,"buy_slot":347519836,"sell_lamports":138039951,"tokens_sold":0,"sell_slot":347519848,"pnl_lamports":-30424360,"timestamp":1750217016}
|
||||
{"mint":"BHfyTvcM89GvgoqbJ8EVs2WvLtvRtYR6y2fF7Chypump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347519856,"sell_lamports":0,"tokens_sold":0,"sell_slot":347519863,"pnl_lamports":-5000,"timestamp":1750217021}
|
||||
{"mint":"Ds7Mcxg9x8mPAkFXvGyP2LKHZ2LFR3CQdFnRPxR154Jc","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":182110735,"tokens_received":0,"buy_slot":347519876,"sell_lamports":174516121,"tokens_sold":5000000000000,"sell_slot":347519878,"pnl_lamports":-7594614,"timestamp":1750217027}
|
||||
{"mint":"8YyvwW6eB2gZSNH7pFX1sQ8TthFukDSeYE3JNXJspump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":168716762,"tokens_received":0,"buy_slot":347519885,"sell_lamports":161059462,"tokens_sold":0,"sell_slot":347519886,"pnl_lamports":-7657300,"timestamp":1750217031}
|
||||
{"mint":"7e8EjeHCbSzvPXuxQwsF8fpWrXYZnJDG7mdSD7mRpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":156404624,"tokens_received":0,"buy_slot":347519891,"sell_lamports":147392215,"tokens_sold":0,"sell_slot":347519909,"pnl_lamports":-9012409,"timestamp":1750217040}
|
||||
{"mint":"GSbFoKiHuWSuNRRMXW6c8ExGN8XpXwzqVujbgHh5pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":194272644,"tokens_received":0,"buy_slot":347519917,"sell_lamports":186436673,"tokens_sold":5000000000000,"sell_slot":347519918,"pnl_lamports":-7835971,"timestamp":1750217044}
|
||||
{"mint":"91HjAWvPBhDZADUySKK4JKaeBVJsoCDChT3QhHncpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":150442710,"tokens_received":0,"buy_slot":347519942,"sell_lamports":143667871,"tokens_sold":5000000000000,"sell_slot":347519943,"pnl_lamports":-6774839,"timestamp":1750217054}
|
||||
{"mint":"4jsQHqshVcfJ5wy3xBREKy5VbkXK4eCyWPT8zXicpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":149598851,"tokens_received":0,"buy_slot":347519956,"sell_lamports":141744160,"tokens_sold":0,"sell_slot":347519958,"pnl_lamports":-7854691,"timestamp":1750217060}
|
||||
{"mint":"B2MMargytCabncwmDfz7JzrcGXcUhYnNPx1BWdvcpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":165817461,"tokens_received":0,"buy_slot":347519975,"sell_lamports":157050364,"tokens_sold":0,"sell_slot":347519982,"pnl_lamports":-8767097,"timestamp":1750217070}
|
||||
{"mint":"8VQd57yZoTNESX2MhyAuoK5YYV2Jdfij8QTJW9Vwpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":185466953,"tokens_received":0,"buy_slot":347519987,"sell_lamports":179967095,"tokens_sold":5000000000000,"sell_slot":347519988,"pnl_lamports":-5499858,"timestamp":1750217072}
|
||||
{"mint":"G9ETocYppB3Ek6ew4Xy32RuhMq63UxtqRyMLsSTmpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":150167351,"tokens_received":0,"buy_slot":347520013,"sell_lamports":143204750,"tokens_sold":0,"sell_slot":347520018,"pnl_lamports":-6962601,"timestamp":1750217084}
|
||||
{"mint":"4xrTSPjXxYoVE4UU1Bfpds9SvFB2ub9rdxgytmrjpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":157523807,"tokens_received":0,"buy_slot":347520019,"sell_lamports":151468252,"tokens_sold":5000000000000,"sell_slot":347520020,"pnl_lamports":-6055555,"timestamp":1750217085}
|
||||
{"mint":"ErfaH7fMh1QgDbY3JpqgHt2seygUkATcwDsoX38yr2Mz","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347520036,"sell_lamports":0,"tokens_sold":0,"sell_slot":347520040,"pnl_lamports":-5000,"timestamp":1750217092}
|
||||
{"mint":"BoA5ib3xAUxyMrdHkZBscY2id4q6P5ifjbW8CsZSpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":165416759,"tokens_received":0,"buy_slot":347520057,"sell_lamports":164583479,"tokens_sold":0,"sell_slot":347520067,"pnl_lamports":-833280,"timestamp":1750217103}
|
||||
{"mint":"F9nXCqW5u1ZH3jS35U9UcuC3HNumEqEWfx7mrdAgpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":173429492,"tokens_received":0,"buy_slot":347520089,"sell_lamports":166006254,"tokens_sold":5000000000000,"sell_slot":347520090,"pnl_lamports":-7423238,"timestamp":1750217112}
|
||||
{"mint":"D4umoMz2nTrm9L2XqdbpjrJsctaZyYpvaNpQSMvbpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":172910222,"tokens_received":0,"buy_slot":347520104,"sell_lamports":166001070,"tokens_sold":0,"sell_slot":347520110,"pnl_lamports":-6909152,"timestamp":1750217121}
|
||||
{"mint":"DLDZ88ZFDVm25RuqqbsSCa2NxVde2yCdC4YfmVY5pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":163410441,"tokens_received":0,"buy_slot":347520130,"sell_lamports":153130600,"tokens_sold":0,"sell_slot":347520153,"pnl_lamports":-10279841,"timestamp":1750217139}
|
||||
{"mint":"79u2TnaXemucTGGtxrWmte8isX19u6Uebx96tz9npump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":163909844,"tokens_received":0,"buy_slot":347520168,"sell_lamports":156675114,"tokens_sold":0,"sell_slot":347520171,"pnl_lamports":-7234730,"timestamp":1750217147}
|
||||
{"mint":"2zMCWe2Y79hJutHmbYwy47UUPF7LN8cmQ6LQayXPpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":165773028,"tokens_received":0,"buy_slot":347520186,"sell_lamports":158501404,"tokens_sold":0,"sell_slot":347520187,"pnl_lamports":-7271624,"timestamp":1750217153}
|
||||
{"mint":"EzvRjRBQoLSfiLJXuAfK2Lwj8ve6QdCg7xx2LQdupump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":163589942,"tokens_received":0,"buy_slot":347520208,"sell_lamports":158655803,"tokens_sold":5000000000000,"sell_slot":347520209,"pnl_lamports":-4934139,"timestamp":1750217163}
|
||||
{"mint":"E4PzfTZo5NY4Ug9oDTJJ2YZVT8yP7Y8eZx22moqUpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":158382552,"tokens_received":0,"buy_slot":347520226,"sell_lamports":151257273,"tokens_sold":0,"sell_slot":347520227,"pnl_lamports":-7125279,"timestamp":1750217169}
|
||||
{"mint":"3EaWwNWkWHJFxGH5c82uxE8aAxzmtAapozi7Ch8Xpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":181872778,"tokens_received":0,"buy_slot":347520229,"sell_lamports":175205215,"tokens_sold":0,"sell_slot":347520232,"pnl_lamports":-6667563,"timestamp":1750217171}
|
||||
{"mint":"5kxqRb3g6s7DYzpMN72LK8D4rW4pByZPE2z8ZW2DKH7n","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":179139900,"tokens_received":0,"buy_slot":347520241,"sell_lamports":171603585,"tokens_sold":0,"sell_slot":347520242,"pnl_lamports":-7536315,"timestamp":1750217176}
|
||||
{"mint":"BJ5qNX9rt3cYa71u1w6vsebYhgrJMSA69qCmMFLPpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":160281832,"tokens_received":0,"buy_slot":347520722,"sell_lamports":153118943,"tokens_sold":5000000000000,"sell_slot":347520727,"pnl_lamports":-7162889,"timestamp":1750217368}
|
||||
{"mint":"EpY1rVa2FPAD1rFQvGcdVysdETBNurFy5tBQRD9ipump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":164798544,"tokens_received":0,"buy_slot":347520739,"sell_lamports":147088682,"tokens_sold":0,"sell_slot":347520752,"pnl_lamports":-17709862,"timestamp":1750217378}
|
||||
{"mint":"66cJUuYv69g6i9PyViWHojX7vPXraFuFcKdVyc94pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":170144542,"tokens_received":0,"buy_slot":347520762,"sell_lamports":142764913,"tokens_sold":5000000000000,"sell_slot":347520763,"pnl_lamports":-27379629,"timestamp":1750217382}
|
||||
{"mint":"DoREj57VkS1jrAyMYCdzY5qDSEk6jhSU5Hxm8nkapump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":168341659,"tokens_received":0,"buy_slot":347520768,"sell_lamports":159018702,"tokens_sold":5000000000000,"sell_slot":347520789,"pnl_lamports":-9322957,"timestamp":1750217392}
|
||||
{"mint":"2RaQQ7k8tHCV7GApk1ZorLA9KrwBc4EmQArXbkHjDHGM","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":196274029,"tokens_received":0,"buy_slot":347520822,"sell_lamports":138039950,"tokens_sold":5000000000000,"sell_slot":347520898,"pnl_lamports":-58234079,"timestamp":1750217436}
|
||||
{"mint":"7ZZJbeCPkQm6nZ56DtNLGs1c2GFUjPuxcTZc5vJapump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":147697046,"tokens_received":0,"buy_slot":347520909,"sell_lamports":172967400,"tokens_sold":0,"sell_slot":347520962,"pnl_lamports":25270354,"timestamp":1750217461}
|
||||
{"mint":"C1NKN93pkT3zTtM7JecwnuYrtVEorUptXzTS4Csapump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":178904976,"tokens_received":0,"buy_slot":347521102,"sell_lamports":173808497,"tokens_sold":5000000000000,"sell_slot":347521104,"pnl_lamports":-5096479,"timestamp":1750217517}
|
||||
{"mint":"2Sk19LDFmd9bnQyg2KDyk6N7tvNU2cBVfjQ2zNnnpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":182813629,"tokens_received":0,"buy_slot":347521106,"sell_lamports":177549144,"tokens_sold":5000000000000,"sell_slot":347521107,"pnl_lamports":-5264485,"timestamp":1750217518}
|
||||
{"mint":"9k8BFvvtMzRqtovmodjSbi7wMcnGEDdRCsCi9Wt6pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":176452042,"tokens_received":0,"buy_slot":347521109,"sell_lamports":168968941,"tokens_sold":0,"sell_slot":347521110,"pnl_lamports":-7483101,"timestamp":1750217519}
|
||||
{"mint":"F85S3X1wEhbrAzPCTagcNUngCVNuY7dFtGuuQs7kpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":170144542,"tokens_received":0,"buy_slot":347521131,"sell_lamports":162786354,"tokens_sold":5000000000000,"sell_slot":347521133,"pnl_lamports":-7358188,"timestamp":1750217529}
|
||||
{"mint":"99dYt5XHu7gJ7Q4KsuJ2xn1EqyodbCzhMBVECMBVMTMK","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347521147,"sell_lamports":0,"tokens_sold":0,"sell_slot":347521153,"pnl_lamports":-5000,"timestamp":1750217537}
|
||||
{"mint":"HaaHpJJXw3vWorMP5yABnJNBXUDHTQoPmiRg8wr2Jw5C","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":188535477,"tokens_received":0,"buy_slot":347521157,"sell_lamports":180813111,"tokens_sold":0,"sell_slot":347521159,"pnl_lamports":-7722366,"timestamp":1750217539}
|
||||
{"mint":"2TkEpjRjDT9GmxnyEA6GVuXHEd351XvVtMTuB3Rmpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":153171339,"tokens_received":0,"buy_slot":347521163,"sell_lamports":146142931,"tokens_sold":0,"sell_slot":347521184,"pnl_lamports":-7028408,"timestamp":1750217549}
|
||||
{"mint":"AppAUHfC2USYs8eoDjbg91AbGdMGbJhtaSRj3UvLpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":163410441,"tokens_received":0,"buy_slot":347521187,"sell_lamports":162039233,"tokens_sold":0,"sell_slot":347521200,"pnl_lamports":-1371208,"timestamp":1750217556}
|
||||
{"mint":"CRLwGR99o9HJyNbjn34gd5oc7RSMjGUYyZ4pzoXMg99E","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347521249,"sell_lamports":0,"tokens_sold":0,"sell_slot":347521262,"pnl_lamports":-5000,"timestamp":1750217582}
|
||||
{"mint":"3pCkxnvU9vX5vp2o8LYtpwDYJxaq8sKSDxrCDTqKpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":174612538,"tokens_received":0,"buy_slot":347521269,"sell_lamports":167165865,"tokens_sold":5000000000000,"sell_slot":347521270,"pnl_lamports":-7446673,"timestamp":1750217585}
|
||||
{"mint":"6tqLq2FK5cXbxDTqHBcqeqvAdrQhczGshNkqqgeTpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":173978664,"tokens_received":0,"buy_slot":347521275,"sell_lamports":161945257,"tokens_sold":5000000000000,"sell_slot":347521281,"pnl_lamports":-12033407,"timestamp":1750217589}
|
||||
{"mint":"85Xm7XbRaP4nWZwhg3gFzKdJRZHgeC66WsNcHuuapump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":144916986,"tokens_received":0,"buy_slot":347521297,"sell_lamports":138131808,"tokens_sold":0,"sell_slot":347521302,"pnl_lamports":-6785178,"timestamp":1750217598}
|
||||
{"mint":"DuvPcmGHwkXcrF5MxwxatU2AjtY8HhM2sKxPVzmGpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347522916,"sell_lamports":0,"tokens_sold":0,"sell_slot":347522921,"pnl_lamports":-5000,"timestamp":1750218248}
|
||||
{"mint":"5xpTAv5mEYJKk5KgMPi1xuXwnr8qPAjH4DdQtSBupump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":152418032,"tokens_received":0,"buy_slot":347522992,"sell_lamports":142488375,"tokens_sold":0,"sell_slot":347523070,"pnl_lamports":-9929657,"timestamp":1750218308}
|
||||
{"mint":"CgofhQEowd5bU5j5vjcKTmTrRLSLPtqzjVNKCJrdpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347523088,"sell_lamports":0,"tokens_sold":0,"sell_slot":347523093,"pnl_lamports":-5000,"timestamp":1750218317}
|
||||
{"mint":"DQvmGbuchtC9PevTzpu4Pt6bYxEkhAoXEL2AogtWpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":145085980,"tokens_received":0,"buy_slot":347523095,"sell_lamports":138251351,"tokens_sold":5000000000000,"sell_slot":347523106,"pnl_lamports":-6834629,"timestamp":1750218322}
|
||||
{"mint":"72fxuwMXixzJgkpGqA8vW3Dp381QRdPER2tfwuwBpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347523118,"sell_lamports":0,"tokens_sold":0,"sell_slot":347523136,"pnl_lamports":-5000,"timestamp":1750218335}
|
||||
{"mint":"R5daazaATfx5vaA2axFHdvpZJ3uKspSteSaRJRRpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347523161,"sell_lamports":0,"tokens_sold":0,"sell_slot":347523167,"pnl_lamports":-5000,"timestamp":1750218347}
|
||||
{"mint":"FnEbgV2fy9WwcTxN85DUujxHYjzQnRpq8V2Kc4STpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":145838304,"tokens_received":0,"buy_slot":347523181,"sell_lamports":139146182,"tokens_sold":5000000000000,"sell_slot":347523241,"pnl_lamports":-6692122,"timestamp":1750218377}
|
||||
{"mint":"4ryoNE6jq92dpLrDSAoVUea3NC7fYznKsRit7Rtkpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347523268,"sell_lamports":0,"tokens_sold":0,"sell_slot":347523273,"pnl_lamports":-5000,"timestamp":1750218390}
|
||||
{"mint":"5YNJDStETkwmjq4uhmgQ5Qw3ZCrd3XyDYYQPnCq9pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347523281,"sell_lamports":0,"tokens_sold":0,"sell_slot":347523288,"pnl_lamports":-5000,"timestamp":1750218396}
|
||||
{"mint":"8H1UiWLhPEqXBN4bCyVfu8Dbd1gptYo2ULzb32VSpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347523302,"sell_lamports":0,"tokens_sold":0,"sell_slot":347523307,"pnl_lamports":-5000,"timestamp":1750218403}
|
||||
{"mint":"6jrnjH8MgohX9NdtLMFEpW7ERnZjRn6W6CchrWE2pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347523310,"sell_lamports":0,"tokens_sold":0,"sell_slot":347523318,"pnl_lamports":-5000,"timestamp":1750218408}
|
||||
{"mint":"R5jY9aieD42yJr5ebagtF9eUmZSabqWHgF3Pq3ppump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347523352,"sell_lamports":0,"tokens_sold":0,"sell_slot":347523364,"pnl_lamports":-5000,"timestamp":1750218426}
|
||||
{"mint":"2JzgWCs4sBCNfhrBLKg2i6TGLJMak2FzhgLfwA7Mpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347523367,"sell_lamports":0,"tokens_sold":0,"sell_slot":347523379,"pnl_lamports":-5000,"timestamp":1750218432}
|
||||
{"mint":"7wyNUAerada8d2biycudofwPTaz3zQmibn7Y4h4NFLV9","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":147532319,"tokens_received":0,"buy_slot":347523401,"sell_lamports":140628344,"tokens_sold":5000000000000,"sell_slot":347523408,"pnl_lamports":-6903975,"timestamp":1750218444}
|
||||
{"mint":"7UVFcESedP2bqHH3vogpTSMjvbXoc76vPpu2tTqY4Tok","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":144898214,"tokens_received":0,"buy_slot":347523412,"sell_lamports":166418629,"tokens_sold":5000000000000,"sell_slot":347523422,"pnl_lamports":21520415,"timestamp":1750218449}
|
||||
{"mint":"R6Uzwg7ekTd2gUW1MZ8p8r1GNMEhvsDUG4H3aFDpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347523428,"sell_lamports":0,"tokens_sold":0,"sell_slot":347523435,"pnl_lamports":-5000,"timestamp":1750218454}
|
||||
{"mint":"GdEh9vmcGNXzfqBtuuLqtZTDvCN6bw4SgZJQ4CjZekDh","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347523451,"sell_lamports":0,"tokens_sold":0,"sell_slot":347523453,"pnl_lamports":-5000,"timestamp":1750218462}
|
||||
{"mint":"8NDjtwUV9Hcdi36xjn7PggJfxGhoKESJdeY5hti8pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":155218132,"tokens_received":0,"buy_slot":347523472,"sell_lamports":148361381,"tokens_sold":5000000000000,"sell_slot":347523477,"pnl_lamports":-6856751,"timestamp":1750218472}
|
||||
{"mint":"H4qiPNnbpBn7DrtrMWdTZFDNZ1crakZioE9LQSSJpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347523486,"sell_lamports":0,"tokens_sold":0,"sell_slot":347523507,"pnl_lamports":-5000,"timestamp":1750218484}
|
||||
{"mint":"5WuTwnqNa1GcocTpXmdwbgW5hrMrUt1ANqysr2pMpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":149963610,"tokens_received":0,"buy_slot":347523522,"sell_lamports":141390129,"tokens_sold":5000000000000,"sell_slot":347523526,"pnl_lamports":-8573481,"timestamp":1750218492}
|
||||
{"mint":"R6mbY1YUufeS1cpGEA1zrgXmNaURF2EB269vyFWpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347523535,"sell_lamports":0,"tokens_sold":0,"sell_slot":347523546,"pnl_lamports":-5000,"timestamp":1750218500}
|
||||
{"mint":"ewJSLCqhrcZq3V3EZ8JE1SbPFtEpqLxa4o5jSzfpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347523556,"sell_lamports":0,"tokens_sold":0,"sell_slot":347523567,"pnl_lamports":-5000,"timestamp":1750218508}
|
||||
{"mint":"HTdPEk7uqWJayi4k9Uasy5vK6QiQQA7ZMMmS4sLipump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347523581,"sell_lamports":0,"tokens_sold":0,"sell_slot":347523588,"pnl_lamports":-5000,"timestamp":1750218517}
|
||||
{"mint":"v87i1Tmpm9eppeKqW1LJccvyU9tCAHi8Y7px1oEpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347523611,"sell_lamports":0,"tokens_sold":0,"sell_slot":347523616,"pnl_lamports":-5000,"timestamp":1750218529}
|
||||
{"mint":"Da1v3xajSxzAszjWGkAPg9G9WA6rCLkr6UA1Y9p1pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":147318183,"tokens_received":0,"buy_slot":347523627,"sell_lamports":141364787,"tokens_sold":5000000000000,"sell_slot":347523629,"pnl_lamports":-5953396,"timestamp":1750218534}
|
||||
{"mint":"3jeSGwURoNdTaQFqgXuY2Ab2bjhqiDo1dsFND6cTpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347523654,"sell_lamports":0,"tokens_sold":0,"sell_slot":347523678,"pnl_lamports":-5000,"timestamp":1750218554}
|
||||
{"mint":"5iSjy2hiBXQiQWnerf2j841pvUDNte4oNhhCDnZypump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":144992082,"tokens_received":0,"buy_slot":347523680,"sell_lamports":138159846,"tokens_sold":5000000000000,"sell_slot":347523683,"pnl_lamports":-6832236,"timestamp":1750218556}
|
||||
{"mint":"6dnA1DmnGEgBHsN4AhNmhkxzVx2KWxeztGnBefwnpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347523686,"sell_lamports":0,"tokens_sold":0,"sell_slot":347523690,"pnl_lamports":-5000,"timestamp":1750218559}
|
||||
{"mint":"R6nWKdqBatoS6BnzeCBkcoGgwQSfpsXzDTVqrHwpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347523696,"sell_lamports":0,"tokens_sold":0,"sell_slot":347523703,"pnl_lamports":-5000,"timestamp":1750218564}
|
||||
{"mint":"CPxLWQWxojneW2yiu5ypFtdgMZD2638aRmFNSNVqpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347523717,"sell_lamports":0,"tokens_sold":0,"sell_slot":347523720,"pnl_lamports":-5000,"timestamp":1750218571}
|
||||
{"mint":"GMG83dGQapxy8gZjCSZQRRnEnXuQAAvQNfPGWpVwstfZ","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347523729,"sell_lamports":0,"tokens_sold":0,"sell_slot":347523775,"pnl_lamports":-5000,"timestamp":1750218592}
|
||||
{"mint":"9Ybv8kCJnVCDgkiYvTDyRuToMm2xL9DstaoMrq6XNckT","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347523779,"sell_lamports":0,"tokens_sold":0,"sell_slot":347523782,"pnl_lamports":-5000,"timestamp":1750218595}
|
||||
{"mint":"5sAAvfFmp1VPZrkZe4a8JjhAHLgYJMXygweFyyFekXaJ","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347523791,"sell_lamports":0,"tokens_sold":0,"sell_slot":347523799,"pnl_lamports":-5000,"timestamp":1750218602}
|
||||
{"mint":"bnUshhvY3LAthpDgvdNJpTfPRoTkoTxuBqpn1kXHNGk","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347523815,"sell_lamports":0,"tokens_sold":0,"sell_slot":347523823,"pnl_lamports":-5000,"timestamp":1750218611}
|
||||
{"mint":"GTguetbZkuH5dBHQ2bE7YxZRG8jbWukbcweQKMhtpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":33686594,"tokens_received":0,"buy_slot":347651814,"sell_lamports":22383525,"tokens_sold":0,"sell_slot":347651819,"pnl_lamports":-11303069,"timestamp":1750269868}
|
||||
{"mint":"DjeTfNx91DzBHXQYJSX1Kmddy9VC2HivFS92QeUDpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":31314865,"tokens_received":0,"buy_slot":347651828,"sell_lamports":26724424,"tokens_sold":0,"sell_slot":347651907,"pnl_lamports":-4590441,"timestamp":1750269904}
|
||||
{"mint":"Cxr6B2E1KuEDzcs9JaexX1FwFpWu59Cs5H1mijupump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":103977367,"tokens_received":0,"buy_slot":347651912,"sell_lamports":91412904,"tokens_sold":0,"sell_slot":347651925,"pnl_lamports":-12564463,"timestamp":1750269911}
|
||||
{"mint":"E4fniLy4uk2c6qpWHhcamCAK5TbMbLHcecrbY7MhH5Am","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":41010893,"tokens_received":0,"buy_slot":347651927,"sell_lamports":26871354,"tokens_sold":0,"sell_slot":347651942,"pnl_lamports":-14139539,"timestamp":1750269917}
|
||||
{"mint":"DTCZd58vQ6UBsQjGCtyZSjwErWCt7oMSvJbS6RQfpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":41394187,"tokens_received":0,"buy_slot":347651954,"sell_lamports":32864512,"tokens_sold":1000000000000,"sell_slot":347651962,"pnl_lamports":-8529675,"timestamp":1750269925}
|
||||
{"mint":"HVqKyb8qzKjdMT5cm196ZKugJe4QoTJ8qe3yPP9Rpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":35568697,"tokens_received":0,"buy_slot":347651970,"sell_lamports":23875372,"tokens_sold":1000000000000,"sell_slot":347651972,"pnl_lamports":-11693325,"timestamp":1750269929}
|
||||
{"mint":"CMKt348vhbRbSRoeRnUqGexKMTmQkVLdmjygqs3Vpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":36813604,"tokens_received":0,"buy_slot":347651977,"sell_lamports":25504182,"tokens_sold":0,"sell_slot":347651988,"pnl_lamports":-11309422,"timestamp":1750269936}
|
||||
{"mint":"8eY3nivHeQpofx4zCnxrLdBZG6M9xGxvV2BK56WKpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":33636182,"tokens_received":0,"buy_slot":347651992,"sell_lamports":19718522,"tokens_sold":0,"sell_slot":347652000,"pnl_lamports":-13917660,"timestamp":1750269941}
|
||||
{"mint":"CPkAyHABqZYxnj83tuL6AB3C6xkiuSrqDzopaXwppump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":31309207,"tokens_received":0,"buy_slot":347652002,"sell_lamports":19705766,"tokens_sold":1000000000000,"sell_slot":347652009,"pnl_lamports":-11603441,"timestamp":1750269944}
|
||||
{"mint":"EFfQuW5n8PxTCDSQg7znVFr6nWs4M43j9zHyPU1zpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":31309209,"tokens_received":0,"buy_slot":347652032,"sell_lamports":19714901,"tokens_sold":1000000000000,"sell_slot":347652064,"pnl_lamports":-11594308,"timestamp":1750269965}
|
||||
{"mint":"2ZNttFyToZn4xzGAWPiecgJMCmGw3YiqwbX7LcDkpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":144973597,"tokens_received":0,"buy_slot":347657917,"sell_lamports":135113842,"tokens_sold":0,"sell_slot":347657931,"pnl_lamports":-9859755,"timestamp":1750272320}
|
||||
{"mint":"FTaje9uPJ3goHcSHmx6qGfrYyzfHcJRKtNpYhqktpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":159277773,"tokens_received":0,"buy_slot":347657947,"sell_lamports":144392215,"tokens_sold":0,"sell_slot":347657976,"pnl_lamports":-14885558,"timestamp":1750272339}
|
||||
{"mint":"7fc1XyeSgX4bqbFprQsj83kVvSjiJsnrnNFkfUoHpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":170315856,"tokens_received":0,"buy_slot":347657995,"sell_lamports":159954265,"tokens_sold":5000000000000,"sell_slot":347658004,"pnl_lamports":-10361591,"timestamp":1750272350}
|
||||
{"mint":"FCfPzzrX2RcYKBjEGQpXUxrhseLibo1nDzTfKZp3pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":186326929,"tokens_received":0,"buy_slot":347658016,"sell_lamports":222443290,"tokens_sold":0,"sell_slot":347658019,"pnl_lamports":36116361,"timestamp":1750272356}
|
||||
{"mint":"4PGQ1HQH5LtGD927w4sizLWBkD8GMu8iLx4pHecppump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347658027,"sell_lamports":0,"tokens_sold":0,"sell_slot":347658036,"pnl_lamports":-5000,"timestamp":1750272363}
|
||||
{"mint":"B6YJ7vKJBsWts9Ecd8mPEf9q5fPvCyEpMyJAdFzFpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":144898232,"tokens_received":0,"buy_slot":347658047,"sell_lamports":135067837,"tokens_sold":5000000000000,"sell_slot":347658049,"pnl_lamports":-9830395,"timestamp":1750272368}
|
||||
{"mint":"9P8ct4q8ZARFtaA2JRYXS2BEDEXkoQUpWtwbz3Hvpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":156502233,"tokens_received":0,"buy_slot":347658091,"sell_lamports":135175315,"tokens_sold":5000000000000,"sell_slot":347658104,"pnl_lamports":-21326918,"timestamp":1750272389}
|
||||
{"mint":"7Cj2BiXpNKVneyQcYDo1a2M1tpXyGkcuiwU3wc11n2z5","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":378638037,"tokens_received":0,"buy_slot":347660845,"sell_lamports":366151276,"tokens_sold":10000000000000,"sell_slot":347660847,"pnl_lamports":-12486761,"timestamp":1750273487}
|
||||
{"mint":"39Dyg4x5Qns6SWVEuVYBnfpMwTbE74osrV9ekuUQpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":291249420,"tokens_received":0,"buy_slot":347660879,"sell_lamports":280493105,"tokens_sold":10000000000000,"sell_slot":347660909,"pnl_lamports":-10756315,"timestamp":1750273512}
|
||||
{"mint":"AaSFnZ9c1HJb6sUncmoWYyvTu2GGHMcsVKVApAR3pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":307306228,"tokens_received":0,"buy_slot":347660911,"sell_lamports":277392946,"tokens_sold":0,"sell_slot":347660941,"pnl_lamports":-29913282,"timestamp":1750273524}
|
||||
{"mint":"GjFD4BD2ZXfDj2uRiWKL2bk5Vwjw6FbQKLdRQHiCpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":319624088,"tokens_received":0,"buy_slot":347660945,"sell_lamports":319423640,"tokens_sold":0,"sell_slot":347660958,"pnl_lamports":-200448,"timestamp":1750273531}
|
||||
{"mint":"29LDXaLQyMfxVMaYFN49Pkq2DN3128W5Xs1cod5gpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":321597674,"tokens_received":0,"buy_slot":347660966,"sell_lamports":310240424,"tokens_sold":0,"sell_slot":347660967,"pnl_lamports":-11357250,"timestamp":1750273534}
|
||||
{"mint":"9mYZUZ6q2YYSZyb89mnqqktLBpBhNDpaNcBquSaXpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":407502529,"tokens_received":0,"buy_slot":347660969,"sell_lamports":277393061,"tokens_sold":10000000000000,"sell_slot":347660974,"pnl_lamports":-130109468,"timestamp":1750273537}
|
||||
{"mint":"H7p6mqKyVjYeEQTgAsHRExy3pz3pC6eqKwaJS6xxpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":355242021,"tokens_received":0,"buy_slot":347660993,"sell_lamports":315691735,"tokens_sold":0,"sell_slot":347660997,"pnl_lamports":-39550286,"timestamp":1750273547}
|
||||
{"mint":"6SP2Ft7RDu1xKtH3fpHsm94Z84SL1NN57BX4Bb4Npump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":351861219,"tokens_received":0,"buy_slot":347664296,"sell_lamports":332772812,"tokens_sold":10000000000000,"sell_slot":347664313,"pnl_lamports":-19088407,"timestamp":1750274867}
|
||||
{"mint":"DLkQ8GVG7EmSjNhNDygW9sVzrcDwUXdXrabWzpU2pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":350764564,"tokens_received":0,"buy_slot":347664324,"sell_lamports":457910398,"tokens_sold":0,"sell_slot":347664327,"pnl_lamports":107145834,"timestamp":1750274873}
|
||||
{"mint":"ZpoARLgzJmVTjnU1N62Nfiunyd2omcumccXjhbisL4Y","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347664339,"sell_lamports":0,"tokens_sold":0,"sell_slot":347664350,"pnl_lamports":-5000,"timestamp":1750274883}
|
||||
{"mint":"7D38JZZ6C3azhFggWtxeNnGL8eoyw7tYPnePcBe1pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":351446695,"tokens_received":0,"buy_slot":347664355,"sell_lamports":276614126,"tokens_sold":0,"sell_slot":347664361,"pnl_lamports":-74832569,"timestamp":1750274888}
|
||||
{"mint":"G4cccQhUouzAWCGpPWmkqXvJUbq8BBkC9HxM6xHspump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":369435393,"tokens_received":0,"buy_slot":347664377,"sell_lamports":354130840,"tokens_sold":10000000000000,"sell_slot":347664378,"pnl_lamports":-15304553,"timestamp":1750274894}
|
||||
{"mint":"8QpZwfj98wi6v6sWD9c4TRjxTdH8MWCXeauhxSf6PF5w","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":472864273,"tokens_received":0,"buy_slot":347682852,"sell_lamports":506578913,"tokens_sold":0,"sell_slot":347682856,"pnl_lamports":33714640,"timestamp":1750282288}
|
||||
{"mint":"BRNWNzumrc9x6rZBdwXoTgDgh8s1hehpcRGSMsUrpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":332048230,"tokens_received":0,"buy_slot":347682893,"sell_lamports":287515097,"tokens_sold":0,"sell_slot":347682900,"pnl_lamports":-44533133,"timestamp":1750282306}
|
||||
{"mint":"3WsRWtCvYjf4hkQPesLSmPWU31u36MmF1TfWChUNvYAY","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347683876,"sell_lamports":0,"tokens_sold":0,"sell_slot":347683882,"pnl_lamports":-5000,"timestamp":1750282706}
|
||||
{"mint":"GnTE6mHszVGDkz9QXcqKQvPNW66W7gv8fEwRbF3zBP6D","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347683903,"sell_lamports":0,"tokens_sold":0,"sell_slot":347683984,"pnl_lamports":-5000,"timestamp":1750282747}
|
||||
{"mint":"jydouknW2GaN2rXZidBYfV1ozQkwUnEAXNSChctdsnN","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":479870273,"tokens_received":0,"buy_slot":347683996,"sell_lamports":481255002,"tokens_sold":0,"sell_slot":347684002,"pnl_lamports":1384729,"timestamp":1750282756}
|
||||
{"mint":"H4F2vsKRzHJ8qiUT5Lp38ggE9PgB3dbx4oFMEAAh8W7j","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":5000,"tokens_received":0,"buy_slot":347684120,"sell_lamports":0,"tokens_sold":0,"sell_slot":347684123,"pnl_lamports":-5000,"timestamp":1750282803}
|
||||
{"mint":"Aqof3jsSFkk19FeRtCR7HzHB9CUSn83sg7TRjCuSS3BM","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":403098867,"tokens_received":0,"buy_slot":347684174,"sell_lamports":388850105,"tokens_sold":0,"sell_slot":347684184,"pnl_lamports":-14248762,"timestamp":1750282828}
|
||||
{"mint":"JALaa12J3tBoXSTSr3iwQAyugnpAzaLJGpHniZwVpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":295924374,"tokens_received":0,"buy_slot":347684224,"sell_lamports":285373372,"tokens_sold":10000000000000,"sell_slot":347684227,"pnl_lamports":-10551002,"timestamp":1750282846}
|
||||
{"mint":"4tKgCaKthWAaHZoru2hazfgvtronp8RjKBTBmrK5pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":327811783,"tokens_received":0,"buy_slot":347684231,"sell_lamports":412300142,"tokens_sold":0,"sell_slot":347684236,"pnl_lamports":84488359,"timestamp":1750282849}
|
||||
{"mint":"Cd64Z7G4mDs79JqMvHGq1AvUWNNqopA1CFkwnHeYpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":313154743,"tokens_received":0,"buy_slot":347684247,"sell_lamports":302994274,"tokens_sold":0,"sell_slot":347684249,"pnl_lamports":-10160469,"timestamp":1750282855}
|
||||
{"mint":"5kW1YP7emJebpeFkZCJSWkM7DqkmJubecEhfBPKqpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":317753321,"tokens_received":0,"buy_slot":347684276,"sell_lamports":284052007,"tokens_sold":0,"sell_slot":347684285,"pnl_lamports":-33701314,"timestamp":1750282869}
|
||||
{"mint":"8PiREhyPeRErKPqsnfQkiHHborRJpb8iiWknDxSCpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":288464426,"tokens_received":0,"buy_slot":347685760,"sell_lamports":278763277,"tokens_sold":0,"sell_slot":347685838,"pnl_lamports":-9701149,"timestamp":1750283491}
|
||||
{"mint":"HnjY5HJk9C66vx4j7VEi31yMBraVTg4m5iW2fQGWpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":305700847,"tokens_received":0,"buy_slot":347685924,"sell_lamports":274745221,"tokens_sold":0,"sell_slot":347685937,"pnl_lamports":-30955626,"timestamp":1750283529}
|
||||
{"mint":"2XQ6wdbry1t6mhNsb6JY8XT4cy4NwYfyPmBmyeKypump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":311001924,"tokens_received":0,"buy_slot":347685951,"sell_lamports":274392928,"tokens_sold":0,"sell_slot":347686011,"pnl_lamports":-36608996,"timestamp":1750283557}
|
||||
{"mint":"FdJsMFv4P71ty3CrRGEWZFCnDAhY8ELxC65gNDJvpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":344984494,"tokens_received":0,"buy_slot":347686029,"sell_lamports":435820988,"tokens_sold":10000000000000,"sell_slot":347686031,"pnl_lamports":90836494,"timestamp":1750283565}
|
||||
{"mint":"7KHsbXfhQhQGfbAX5CCpV8La5BvzTyGiLhtVmxeJpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":288653993,"tokens_received":0,"buy_slot":347686046,"sell_lamports":278392928,"tokens_sold":0,"sell_slot":347686128,"pnl_lamports":-10261065,"timestamp":1750283604}
|
||||
{"mint":"CRFwRUrcxwAy4Up4r63NM2MCnT7tyNPVK3yAJj9vpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":305324623,"tokens_received":0,"buy_slot":347686259,"sell_lamports":275320147,"tokens_sold":0,"sell_slot":347686264,"pnl_lamports":-30004476,"timestamp":1750283657}
|
||||
{"mint":"12y2Q8evxufgCmnBsAXP5L9dwEB3xvNv32DXbhuuuFnS","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":289042032,"tokens_received":0,"buy_slot":347686324,"sell_lamports":278392928,"tokens_sold":10000000000000,"sell_slot":347686405,"pnl_lamports":-10649104,"timestamp":1750283714}
|
||||
{"mint":"8th48ghUL8tdmNwizWVtgvzhCy9mGEPJPZV21YZVv3ND","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":435128951,"tokens_received":0,"buy_slot":347686412,"sell_lamports":387127712,"tokens_sold":10000000000000,"sell_slot":347686418,"pnl_lamports":-48001239,"timestamp":1750283720}
|
||||
{"mint":"6yRiSqPnaDPCQSB2SkSXdZELaEvEgYb41xUPkkVZpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":329175211,"tokens_received":0,"buy_slot":347686456,"sell_lamports":312419643,"tokens_sold":0,"sell_slot":347686505,"pnl_lamports":-16755568,"timestamp":1750283756}
|
||||
{"mint":"4FqiHcXQJCWTE92anDMNq1KyJ5uYjN4dD4tEm1ex6H5Z","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":341956180,"tokens_received":0,"buy_slot":347686531,"sell_lamports":327195789,"tokens_sold":10000000000000,"sell_slot":347686536,"pnl_lamports":-14760391,"timestamp":1750283767}
|
||||
{"mint":"9qm3muJEU1UUzv2SJKZ9qKorvFtg9jSni3FRVfxrpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":311720649,"tokens_received":0,"buy_slot":347686616,"sell_lamports":297364174,"tokens_sold":0,"sell_slot":347686622,"pnl_lamports":-14356475,"timestamp":1750283802}
|
||||
{"mint":"9XZupxgDtySniAuTSxHNNW25nF3tvWsQJATg37MMpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":291310898,"tokens_received":0,"buy_slot":347686655,"sell_lamports":275674460,"tokens_sold":0,"sell_slot":347686657,"pnl_lamports":-15636438,"timestamp":1750283816}
|
||||
{"mint":"VfnRfXhgaLxxgxpeEonko84ZhqT9cxVvd6PcqvZxWqM","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":435128951,"tokens_received":0,"buy_slot":347686659,"sell_lamports":387127712,"tokens_sold":0,"sell_slot":347686663,"pnl_lamports":-48001239,"timestamp":1750283819}
|
||||
{"mint":"66xb6Q6AE6dFTsqRZBdXXD2FHcdXRwodWgS9bwk1pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":322282591,"tokens_received":0,"buy_slot":347686701,"sell_lamports":307911758,"tokens_sold":0,"sell_slot":347686703,"pnl_lamports":-14370833,"timestamp":1750283834}
|
||||
{"mint":"8QAEP3JX1j1a11JCoDLcs2q4prDRvNxPhU4SGeicpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":288088506,"tokens_received":0,"buy_slot":347686708,"sell_lamports":278394781,"tokens_sold":10000000000000,"sell_slot":347686789,"pnl_lamports":-9693725,"timestamp":1750283868}
|
||||
{"mint":"Hn8TxYAYywRSMSKSfFCaSztCQG7za7qTpv4heSarpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":292534049,"tokens_received":0,"buy_slot":347686817,"sell_lamports":282752296,"tokens_sold":10000000000000,"sell_slot":347686898,"pnl_lamports":-9781753,"timestamp":1750283913}
|
||||
{"mint":"7M12yzD1ASQjmBanzhSuR6DuM3ZCFDBuDFFjAA8vpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":321048816,"tokens_received":0,"buy_slot":347686905,"sell_lamports":276620856,"tokens_sold":0,"sell_slot":347686912,"pnl_lamports":-44427960,"timestamp":1750283919}
|
||||
{"mint":"8f9wP7iHBA5pyGDaRUu5fbZGu4UCZmJEkZtQmegCoBHz","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":435128951,"tokens_received":0,"buy_slot":347686915,"sell_lamports":323648283,"tokens_sold":10000000000000,"sell_slot":347686920,"pnl_lamports":-111480668,"timestamp":1750283922}
|
||||
{"mint":"ARqTuFKGb62WmE7vJBg7gbCX5U2yk95hpmrfowmUpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":314140763,"tokens_received":0,"buy_slot":347686922,"sell_lamports":299931173,"tokens_sold":0,"sell_slot":347686923,"pnl_lamports":-14209590,"timestamp":1750283923}
|
||||
{"mint":"D8ckMoJ4ZqKaS62sPxdWrbN4wYp7snyWRX8nuEzkpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":290169595,"tokens_received":0,"buy_slot":347686955,"sell_lamports":276248915,"tokens_sold":10000000000000,"sell_slot":347686973,"pnl_lamports":-13920680,"timestamp":1750283942}
|
||||
{"mint":"AbdSJ2xPafdUahWRdGdPuz4bKCvax2DVx1W5s4Q2pump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":392170980,"tokens_received":0,"buy_slot":347687017,"sell_lamports":379647746,"tokens_sold":0,"sell_slot":347687018,"pnl_lamports":-12523234,"timestamp":1750283960}
|
||||
{"mint":"3VhMRcxzUmWpqgoRv71pnAUWzCoWUWTxcGgbqvXRpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":288464615,"tokens_received":0,"buy_slot":347687070,"sell_lamports":274763463,"tokens_sold":10000000000000,"sell_slot":347687072,"pnl_lamports":-13701152,"timestamp":1750283982}
|
||||
{"mint":"9aY4rmAvtFUAGgZ2iHKz3CuxewgYz2NH4UcoY8Tipump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":306733320,"tokens_received":0,"buy_slot":347687087,"sell_lamports":292476124,"tokens_sold":10000000000000,"sell_slot":347687098,"pnl_lamports":-14257196,"timestamp":1750283991}
|
||||
{"mint":"Cb3Gpk6nqRzLZm2PvKACin8qgZqUXGaksVnNCqEupump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":291120836,"tokens_received":0,"buy_slot":347687106,"sell_lamports":275488788,"tokens_sold":10000000000000,"sell_slot":347687109,"pnl_lamports":-15632048,"timestamp":1750283997}
|
||||
{"mint":"3KiYcBcBBnMzyhFgBMVAD3xytRP1tjt6ezWNSaWrpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":313967694,"tokens_received":0,"buy_slot":347687150,"sell_lamports":303369747,"tokens_sold":10000000000000,"sell_slot":347687153,"pnl_lamports":-10597947,"timestamp":1750284013}
|
||||
{"mint":"8juTw5JwFTQCu48MLGWAqvw99VuxjiXqaHLJVoVepump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":288407738,"tokens_received":0,"buy_slot":347687176,"sell_lamports":274522535,"tokens_sold":0,"sell_slot":347687191,"pnl_lamports":-13885203,"timestamp":1750284028}
|
||||
{"mint":"9QDvRhURSoHeXiRBRegc9viGPsrUA5YbUGwBHCMXpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":329122976,"tokens_received":0,"buy_slot":347687204,"sell_lamports":284051989,"tokens_sold":10000000000000,"sell_slot":347687212,"pnl_lamports":-45070987,"timestamp":1750284036}
|
||||
{"mint":"A2ehpGjMkeCryNN6ygV459bB7DyDgUuv9tGxn8UGpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":365496699,"tokens_received":0,"buy_slot":347687223,"sell_lamports":321844504,"tokens_sold":10000000000000,"sell_slot":347687227,"pnl_lamports":-43652195,"timestamp":1750284042}
|
||||
{"mint":"HhsynLsfhq322wmRJ7jhEdKK8CLB8g3fEuTaWWT2yR7k","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":435128951,"tokens_received":0,"buy_slot":347687270,"sell_lamports":387127710,"tokens_sold":10000000000000,"sell_slot":347687272,"pnl_lamports":-48001241,"timestamp":1750284061}
|
||||
{"mint":"ENx4DytUYunhxVDXMoQazMDzuHviKLNpQNjY7pMJpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":305324640,"tokens_received":0,"buy_slot":348530992,"sell_lamports":275320162,"tokens_sold":0,"sell_slot":348530999,"pnl_lamports":-30004478,"timestamp":1750623238}
|
||||
{"mint":"3ZvCMKFVmunNzMt71M9PfrPjsbLjfTBB8ZH2mRvUpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":288086634,"tokens_received":0,"buy_slot":348535865,"sell_lamports":274392966,"tokens_sold":10000000000000,"sell_slot":348535871,"pnl_lamports":-13693668,"timestamp":1750625194}
|
||||
{"mint":"pVJz467uLWsEjpM8S7dhMCLZztwpFWBZtnAgo88eAVW","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":294237211,"tokens_received":0,"buy_slot":348538810,"sell_lamports":283649685,"tokens_sold":0,"sell_slot":348538819,"pnl_lamports":-10587526,"timestamp":1750626384}
|
||||
{"mint":"7RV1MNLsPNnS2pw9Lxz1dJ8FtSndQtJmHAFDPxBspump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":312446438,"tokens_received":0,"buy_slot":348539436,"sell_lamports":275320162,"tokens_sold":0,"sell_slot":348539448,"pnl_lamports":-37126276,"timestamp":1750626637}
|
||||
{"mint":"3o7Hty7d2Wj99FkXYYpYFjJURj9x1sRzgMg4bUNMpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":288266294,"tokens_received":0,"buy_slot":348539473,"sell_lamports":276116188,"tokens_sold":0,"sell_slot":348539545,"pnl_lamports":-12150106,"timestamp":1750626677}
|
||||
{"mint":"EqDG46R2eRrhu53ywcE3St5qRFxnUPoE8UTY4xrFpump","creator":"6s86v9Scfo6FwhgMJ6gAQtecKYKi4u5y5tHnbSVqGYBM","buy_lamports":317753341,"tokens_received":0,"buy_slot":348740038,"sell_lamports":283734905,"tokens_sold":0,"sell_slot":348740047,"pnl_lamports":-34018436,"timestamp":1750707421}
|
||||
{"mint":"88qNZrT2W13ytxjnCayT7j1yrM5wo8h4QQjZxC2Dpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":34822021,"tokens_received":0,"buy_slot":348749679,"sell_lamports":24711721,"tokens_sold":1000000000000,"sell_slot":348749684,"pnl_lamports":-10110300,"timestamp":1750711298}
|
||||
{"mint":"B3t3RnV8Q2XGuT5vKMPso6AZgEaxu91bVAatkyxipump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":33499429,"tokens_received":0,"buy_slot":348749733,"sell_lamports":24847074,"tokens_sold":1000000000000,"sell_slot":348749740,"pnl_lamports":-8652355,"timestamp":1750711320}
|
||||
{"mint":"EtqDQssJeHtzHRRPuKBkDrhJyLTWknXzdTLQMNXDpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":32630843,"tokens_received":0,"buy_slot":348749764,"sell_lamports":23436892,"tokens_sold":1000000000000,"sell_slot":348749771,"pnl_lamports":-9193951,"timestamp":1750711331}
|
||||
{"mint":"9bAF3JQJayKw1H4km9ZMmACpr61KapdoJYsTLTQeivqy","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":36366188,"tokens_received":0,"buy_slot":348755001,"sell_lamports":29260596,"tokens_sold":0,"sell_slot":348755004,"pnl_lamports":-7105592,"timestamp":1750713435}
|
||||
{"mint":"FSbSa9Uypd2rvquFCLAo9fpYTKQurAXiPP9VF9b7pump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":33474832,"tokens_received":0,"buy_slot":348755009,"sell_lamports":26883483,"tokens_sold":0,"sell_slot":348755018,"pnl_lamports":-6591349,"timestamp":1750713440}
|
||||
{"mint":"88rPZtRTfXtq7J1DkT697zzQg2pda3wYV1cK8aKwpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":33204059,"tokens_received":0,"buy_slot":348812776,"sell_lamports":28557558,"tokens_sold":0,"sell_slot":348812779,"pnl_lamports":-4646501,"timestamp":1750736664}
|
||||
{"mint":"AkCPPeaTa4CXzMDuSPWyZq13oEdUaSWWnN6nLRswpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":56033618,"tokens_received":0,"buy_slot":348813757,"sell_lamports":50817696,"tokens_sold":0,"sell_slot":348813765,"pnl_lamports":-5215922,"timestamp":1750737058}
|
||||
{"mint":"7qxFW16XW1UWWY1wyGvFpPHAyE8FGk1o1TRJ2jzXpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":32250132,"tokens_received":0,"buy_slot":348814248,"sell_lamports":27078277,"tokens_sold":1000000000000,"sell_slot":348814326,"pnl_lamports":-5171855,"timestamp":1750737285}
|
||||
{"mint":"i4ksN5rHgktSehPjkhbCcRCthGzbRFBKVbsX6Wxpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":31361989,"tokens_received":0,"buy_slot":348815496,"sell_lamports":26751960,"tokens_sold":1000000000000,"sell_slot":348815503,"pnl_lamports":-4610029,"timestamp":1750737756}
|
||||
{"mint":"9AeRMCq3K6qkZRARQM9WxVbdamEXSgtdDaKgi16Apump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":34346346,"tokens_received":0,"buy_slot":348815629,"sell_lamports":26718522,"tokens_sold":1000000000000,"sell_slot":348815638,"pnl_lamports":-7627824,"timestamp":1750737810}
|
||||
{"mint":"GHXRJqNM2cyUQc8VrvLi1Ztz6prwQeGiVYfqGMDxpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":33337197,"tokens_received":0,"buy_slot":348815680,"sell_lamports":27996655,"tokens_sold":0,"sell_slot":348815686,"pnl_lamports":-5340542,"timestamp":1750737830}
|
||||
{"mint":"AuGFGJwd296eMAQYuQfKQq65wWPVCBY4eeTBPQGrpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":35303726,"tokens_received":0,"buy_slot":348815713,"sell_lamports":29991635,"tokens_sold":0,"sell_slot":348815720,"pnl_lamports":-5312091,"timestamp":1750737843}
|
||||
{"mint":"3J1xNU6kSPqZ1ZMs78RYNtpbGmyenfMmvRyj6339pump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":33011009,"tokens_received":0,"buy_slot":348816097,"sell_lamports":26851735,"tokens_sold":0,"sell_slot":348816500,"pnl_lamports":-6159274,"timestamp":1750738155}
|
||||
{"mint":"ESEF31DFwc4ZWABSDB6g3KbssZduRYe6rTgbJvGrV6oA","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":31309207,"tokens_received":0,"buy_slot":348816781,"sell_lamports":26719259,"tokens_sold":1000000000000,"sell_slot":348817184,"pnl_lamports":-4589948,"timestamp":1750738431}
|
||||
{"mint":"B7GTauiL3TovWhkGJ3VESZEBzdAKJdau1X8Qm5yzpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":33300595,"tokens_received":0,"buy_slot":348818123,"sell_lamports":26709449,"tokens_sold":1000000000000,"sell_slot":348818213,"pnl_lamports":-6591146,"timestamp":1750738842}
|
||||
{"mint":"4giCz8P46ADLqmxTyivtGnCguYqGH4EBd2CbFLGHpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":35150107,"tokens_received":0,"buy_slot":348819072,"sell_lamports":30950293,"tokens_sold":1000000000000,"sell_slot":348819077,"pnl_lamports":-4199814,"timestamp":1750739190}
|
||||
{"mint":"CoMMuhRaH9iLZxHC9E6RRd3yyE7dx2yniGyixrKMXh1P","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":31309207,"tokens_received":0,"buy_slot":348831244,"sell_lamports":26818359,"tokens_sold":1000000000000,"sell_slot":348832247,"pnl_lamports":-4490848,"timestamp":1750744486}
|
||||
{"mint":"64MQsQ8HWxLJkrDEHESCv12jnDyjygnvPsJ93RUgCWdq","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":31309207,"tokens_received":0,"buy_slot":348832312,"sell_lamports":26793653,"tokens_sold":1000000000000,"sell_slot":348833362,"pnl_lamports":-4515554,"timestamp":1750744938}
|
||||
{"mint":"5kMazLt27ieg9STMtYJ34f1fabxNmuEYcJhrXrVh26M7","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":31309207,"tokens_received":0,"buy_slot":348833394,"sell_lamports":26700224,"tokens_sold":1000000000000,"sell_slot":348834397,"pnl_lamports":-4608983,"timestamp":1750745353}
|
||||
{"mint":"DjMhGUMwo4MPbzw2DGuVvymPTKKfgTCeR6yhSfRypump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":33397128,"tokens_received":0,"buy_slot":348834398,"sell_lamports":27067350,"tokens_sold":1000000000000,"sell_slot":348834408,"pnl_lamports":-6329778,"timestamp":1750745358}
|
||||
{"mint":"7ssjU8pYAr2cEqwvkagzRzM2CH28RiNb5MEq78QZHP5i","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":59626914,"tokens_received":0,"buy_slot":348835300,"sell_lamports":55182365,"tokens_sold":0,"sell_slot":348835322,"pnl_lamports":-4444549,"timestamp":1750745726}
|
||||
{"mint":"BYU4vT8qWQbb2wWDemv1S33Kb3Mg8oPDvtYfasuupump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":65716073,"tokens_received":0,"buy_slot":348835329,"sell_lamports":57647290,"tokens_sold":0,"sell_slot":348835336,"pnl_lamports":-8068783,"timestamp":1750745732}
|
||||
{"mint":"95GgR39yenDuxWJAJmyAnSzamW7bfVxNDkMuVEdBQDc5","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":59626914,"tokens_received":0,"buy_slot":348835382,"sell_lamports":54546531,"tokens_sold":0,"sell_slot":348835435,"pnl_lamports":-5080383,"timestamp":1750745772}
|
||||
{"mint":"38UdutHoZXsrt8CgYFGte2MKjWGfwnNqkfJUMt5RnYfG","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":59627292,"tokens_received":0,"buy_slot":348840114,"sell_lamports":50457557,"tokens_sold":0,"sell_slot":348840128,"pnl_lamports":-9169735,"timestamp":1750747663}
|
||||
{"mint":"2s7PnQyG2bLjt68jncLx6oZMyxDqb3z2NVx1hygmpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":63930981,"tokens_received":0,"buy_slot":348840171,"sell_lamports":50824219,"tokens_sold":0,"sell_slot":348840180,"pnl_lamports":-13106762,"timestamp":1750747685}
|
||||
{"mint":"3EM51q1mX12WLFpF96YcZkpRMutDsTysCg8Av3Vfpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":63643571,"tokens_received":0,"buy_slot":348840696,"sell_lamports":50551763,"tokens_sold":2000000000000,"sell_slot":348840703,"pnl_lamports":-13091808,"timestamp":1750747894}
|
||||
{"mint":"2wnUBZeKbAP1FgkDKbg38zvJaJi1vfADH95Nhtyypump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":61892059,"tokens_received":0,"buy_slot":348840710,"sell_lamports":52677486,"tokens_sold":0,"sell_slot":348840711,"pnl_lamports":-9214573,"timestamp":1750747897}
|
||||
{"mint":"XnvGxuhRJ5qKykyCsSCLdQ8mNtCQfDpXPgGr7VEpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":70515426,"tokens_received":0,"buy_slot":348840723,"sell_lamports":61207149,"tokens_sold":0,"sell_slot":348840724,"pnl_lamports":-9308277,"timestamp":1750747903}
|
||||
{"mint":"8tx9X4zhqLtpT8qLfxY65kCfQgJLYfNGUdUFZuGjpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":62293709,"tokens_received":0,"buy_slot":348840733,"sell_lamports":53071178,"tokens_sold":2000000000000,"sell_slot":348840734,"pnl_lamports":-9222531,"timestamp":1750747907}
|
||||
{"mint":"4tXD7WHgn2ccxmkbCZ3s81CKKXGEDMiEp6qTvvqXpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":154426662,"tokens_received":0,"buy_slot":348841422,"sell_lamports":139611451,"tokens_sold":5000000000000,"sell_slot":348841431,"pnl_lamports":-14815211,"timestamp":1750748189}
|
||||
{"mint":"Hv66WMPFagcSbW5kNRQ37Vvudf4uTjAv7oVZQKtZpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":144899153,"tokens_received":0,"buy_slot":348841457,"sell_lamports":138040862,"tokens_sold":5000000000000,"sell_slot":348841759,"pnl_lamports":-6858291,"timestamp":1750748324}
|
||||
{"mint":"DDiUg3cmaEAt2uZTAnw4hciyrC5re5ZPuofwADA5pump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":156083841,"tokens_received":0,"buy_slot":348841764,"sell_lamports":139250703,"tokens_sold":5000000000000,"sell_slot":348841773,"pnl_lamports":-16833138,"timestamp":1750748329}
|
||||
{"mint":"EtHhzzKgeqMJVEqj8kcMctEy9v7hMeD6VMNPGWo9pump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":144992007,"tokens_received":0,"buy_slot":348841778,"sell_lamports":139088741,"tokens_sold":5000000000000,"sell_slot":348842081,"pnl_lamports":-5903266,"timestamp":1750748453}
|
||||
{"mint":"5KPEoMgmhQjs5LxAN2aAt5bubQQcYoHkJrPKQPBnpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":154426682,"tokens_received":0,"buy_slot":348843341,"sell_lamports":146879709,"tokens_sold":0,"sell_slot":348843349,"pnl_lamports":-7546973,"timestamp":1750748959}
|
||||
{"mint":"4JE5RU41HiWy6A1C4zPW1hCnCdANhsSgWJZGvAbsdDMS","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":144898214,"tokens_received":0,"buy_slot":348843440,"sell_lamports":138039952,"tokens_sold":0,"sell_slot":348843643,"pnl_lamports":-6858262,"timestamp":1750749078}
|
||||
{"mint":"Dx6JEfVaqey9ZAAAnvrKv42AWVCWpwiJt3NJYydypump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":163277721,"tokens_received":0,"buy_slot":348843644,"sell_lamports":158473874,"tokens_sold":0,"sell_slot":348843652,"pnl_lamports":-4803847,"timestamp":1750749082}
|
||||
{"mint":"ByvKVN91Jcw3rpeM8bSGX7aVG8ALkCFeqCoKZ8S7pump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":5000,"tokens_received":0,"buy_slot":348843670,"sell_lamports":0,"tokens_sold":0,"sell_slot":348843677,"pnl_lamports":-5000,"timestamp":1750749091}
|
||||
{"mint":"4wW6FvqqhCwpp54xXPyQnqwnCeHLYGUygfpjDCz2pump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":144992082,"tokens_received":0,"buy_slot":348843696,"sell_lamports":139705382,"tokens_sold":0,"sell_slot":348843899,"pnl_lamports":-5286700,"timestamp":1750749182}
|
||||
{"mint":"BywScsj9XgcxUCmizhD2ZsCTWnvm2AYPf3rLh7ggpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":313193009,"tokens_received":0,"buy_slot":348845062,"sell_lamports":296730083,"tokens_sold":0,"sell_slot":348845068,"pnl_lamports":-16462926,"timestamp":1750749649}
|
||||
{"mint":"FWYeJNcKckKD5gEkofe81BqQsxXyzGqf4o86ACG3pump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":313195045,"tokens_received":0,"buy_slot":348845137,"sell_lamports":296731976,"tokens_sold":10000000000000,"sell_slot":348845143,"pnl_lamports":-16463069,"timestamp":1750749680}
|
||||
{"mint":"Ghf16Uo4S6FmVzqUWejiT23ydWxiK3pQoPfPKvNLcFZN","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":288086634,"tokens_received":0,"buy_slot":348845505,"sell_lamports":278392947,"tokens_sold":10000000000000,"sell_slot":348845658,"pnl_lamports":-9693687,"timestamp":1750749887}
|
||||
{"mint":"CEiBAsaG1jSYkvYtv65vrgxqLVyPgbtAodxNCRYspump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":314419813,"tokens_received":0,"buy_slot":348845670,"sell_lamports":277892928,"tokens_sold":10000000000000,"sell_slot":348845677,"pnl_lamports":-36526885,"timestamp":1750749895}
|
||||
{"mint":"2SdcFK2nXiVJWTyG1qxUsQuPZA4BmUex77mxXGRnpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":337630594,"tokens_received":0,"buy_slot":348845684,"sell_lamports":298424223,"tokens_sold":10000000000000,"sell_slot":348845693,"pnl_lamports":-39206371,"timestamp":1750749901}
|
||||
{"mint":"Hb9a7eSFQdauPaC9uT9SmtTugRGVAutLFGwbJF9upump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":158164387,"tokens_received":0,"buy_slot":348846820,"sell_lamports":147665459,"tokens_sold":0,"sell_slot":348846824,"pnl_lamports":-10498928,"timestamp":1750750359}
|
||||
{"mint":"G6wD1MiBDwhChjTwNMxQFke71CYK3wSG8ouRMUwZp5SV","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":144898214,"tokens_received":0,"buy_slot":348847162,"sell_lamports":138039952,"tokens_sold":5000000000000,"sell_slot":348847248,"pnl_lamports":-6858262,"timestamp":1750750531}
|
||||
{"mint":"5PAAjsJta7j5fobWM9YMBs6w1quq1faYxLpRmbKZpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":163277710,"tokens_received":0,"buy_slot":348847272,"sell_lamports":145386402,"tokens_sold":5000000000000,"sell_slot":348847310,"pnl_lamports":-17891308,"timestamp":1750750556}
|
||||
{"mint":"3U2MfYZxdFRQT9nGb8ZfMbiTp115ddH3FNKbHqbspump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":240557728,"tokens_received":0,"buy_slot":348848043,"sell_lamports":225797371,"tokens_sold":8000000000000,"sell_slot":348848049,"pnl_lamports":-14760357,"timestamp":1750750854}
|
||||
{"mint":"B87cFXzCEFG8xko4y1vTroFfd2Bx3z6w9o5fzgXvpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":262531414,"tokens_received":0,"buy_slot":348848071,"sell_lamports":243690170,"tokens_sold":8000000000000,"sell_slot":348848073,"pnl_lamports":-18841244,"timestamp":1750750864}
|
||||
{"mint":"59M9CEptdEKVRHiJhifJEppJAP1tHK7cigQJ1Rp2pump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":230649918,"tokens_received":0,"buy_slot":348848113,"sell_lamports":222093654,"tokens_sold":0,"sell_slot":348848165,"pnl_lamports":-8556264,"timestamp":1750750903}
|
||||
{"mint":"W1m7WqD8gaMU24fPamTCa21vMuVyq1RkxYAi48qpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":32893681,"tokens_received":0,"buy_slot":348850445,"sell_lamports":29311907,"tokens_sold":1000000000000,"sell_slot":348850455,"pnl_lamports":-3581774,"timestamp":1750751827}
|
||||
{"mint":"7q1NLLamka5W2HMiYuY9WiZEX53gYtcGxDUA6eutpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":35298671,"tokens_received":0,"buy_slot":348850469,"sell_lamports":29310040,"tokens_sold":0,"sell_slot":348850475,"pnl_lamports":-5988631,"timestamp":1750751835}
|
||||
{"mint":"7afH9uykpURnQ4iZwzvG56UVe12U3xaqgA59WKA9pump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":38113536,"tokens_received":0,"buy_slot":348850489,"sell_lamports":37218322,"tokens_sold":0,"sell_slot":348850491,"pnl_lamports":-895214,"timestamp":1750751841}
|
||||
{"mint":"DYvBqTkRBb4a1Rq6qQynGHvJx8mUXJ57HbnqZPFGpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":32887781,"tokens_received":0,"buy_slot":348850517,"sell_lamports":29677597,"tokens_sold":0,"sell_slot":348850524,"pnl_lamports":-3210184,"timestamp":1750751854}
|
||||
{"mint":"2SuZKRgnv79boZfAmWaWGNB1eh1u4TeCS6t2A8aypump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":30336949,"tokens_received":0,"buy_slot":348851141,"sell_lamports":27707612,"tokens_sold":0,"sell_slot":348851173,"pnl_lamports":-2629337,"timestamp":1750752115}
|
||||
{"mint":"6SSroMAYNH2ALPXDjcUabeLhCJ9Pf3GYBBtzSJeDpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":31077283,"tokens_received":0,"buy_slot":348851184,"sell_lamports":27766686,"tokens_sold":0,"sell_slot":348851189,"pnl_lamports":-3310597,"timestamp":1750752123}
|
||||
{"mint":"G3wAS3VSCbup1WFgZFRqDBdXJhPJgLeEDwLpg2k3pump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":36911512,"tokens_received":0,"buy_slot":348851741,"sell_lamports":38879167,"tokens_sold":0,"sell_slot":348851744,"pnl_lamports":1967655,"timestamp":1750752347}
|
||||
{"mint":"8E1Nga4Ks6vaaZseotTh3gsJKaTGChqXihRLy9M5pump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":32998500,"tokens_received":0,"buy_slot":348851790,"sell_lamports":29510227,"tokens_sold":1000000000000,"sell_slot":348851793,"pnl_lamports":-3488273,"timestamp":1750752368}
|
||||
{"mint":"9hTNAimEz3D9Xv2gwqGEanhE3QzriKVt6NHqhFaEpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":35090224,"tokens_received":0,"buy_slot":348851816,"sell_lamports":31536764,"tokens_sold":1000000000000,"sell_slot":348851818,"pnl_lamports":-3553460,"timestamp":1750752378}
|
||||
{"mint":"CMRaF9TmsJvk6aRX95vzgZFQtoyRi6EvyXMKmjw9pump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":34544665,"tokens_received":0,"buy_slot":348851831,"sell_lamports":30413481,"tokens_sold":0,"sell_slot":348851832,"pnl_lamports":-4131184,"timestamp":1750752383}
|
||||
{"mint":"nX8Det3HEpa1m2VAXrkeF75CFzkG18vvuEvdPtMpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":33083505,"tokens_received":0,"buy_slot":348851842,"sell_lamports":31023264,"tokens_sold":0,"sell_slot":348851848,"pnl_lamports":-2060241,"timestamp":1750752389}
|
||||
{"mint":"CGfSih9Ls2f6ngnxMHcPeVerLxfyQDE4F8iowupBpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":58672448,"tokens_received":0,"buy_slot":348852512,"sell_lamports":55844128,"tokens_sold":2000000000000,"sell_slot":348852595,"pnl_lamports":-2828320,"timestamp":1750752687}
|
||||
{"mint":"EBDgRzqq26677T7xbA4jhyDcRHmzboEg1Y6FYZtzpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":58674304,"tokens_received":0,"buy_slot":348852605,"sell_lamports":56542102,"tokens_sold":2000000000000,"sell_slot":348852688,"pnl_lamports":-2132202,"timestamp":1750752724}
|
||||
{"mint":"C37mTvcaiL3jgVHDE86KrG1mNBZ8rABQBnrAaTn3pump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":334214149,"tokens_received":0,"buy_slot":348852699,"sell_lamports":327276460,"tokens_sold":2000000000000,"sell_slot":348852714,"pnl_lamports":-6937689,"timestamp":1750752734}
|
||||
{"mint":"56PoMj2gagSkA3dXzomZAH23X5GrkGnexThgzBWWpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":59707519,"tokens_received":0,"buy_slot":348853382,"sell_lamports":56496588,"tokens_sold":0,"sell_slot":348853465,"pnl_lamports":-3210931,"timestamp":1750753038}
|
||||
{"mint":"3fxc1hJ7JQ4LQjoS1NrCHtMViRe4eU7MhyJh16sZpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":68240263,"tokens_received":0,"buy_slot":348853486,"sell_lamports":64895234,"tokens_sold":0,"sell_slot":348853489,"pnl_lamports":-3345029,"timestamp":1750753047}
|
||||
{"mint":"55w2WX4VVC6bPYUspCs6ZCDBW2YZ6dTCAfXTQvRsvuPB","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":58640691,"tokens_received":0,"buy_slot":348853530,"sell_lamports":55537060,"tokens_sold":2000000000000,"sell_slot":348853613,"pnl_lamports":-3103631,"timestamp":1750753096}
|
||||
{"mint":"GytSoBW3hPr1uEYobsyYmdJLowHDnEjgsVfqAGZ8pump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":83452730,"tokens_received":0,"buy_slot":348853650,"sell_lamports":79257200,"tokens_sold":2000000000000,"sell_slot":348853655,"pnl_lamports":-4195530,"timestamp":1750753113}
|
||||
{"mint":"7qwYv16DNYCD5yHuvQtU5ZxbY9vodBfBrf73r8Kepump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":63401503,"tokens_received":0,"buy_slot":348853683,"sell_lamports":62121470,"tokens_sold":2000000000000,"sell_slot":348853687,"pnl_lamports":-1280033,"timestamp":1750753126}
|
||||
{"mint":"7BRQYQosZBLGzPeNCqRVMbMovEPyyVgv4P8SNpvHpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":60653849,"tokens_received":0,"buy_slot":348853694,"sell_lamports":57138474,"tokens_sold":2000000000000,"sell_slot":348853776,"pnl_lamports":-3515375,"timestamp":1750753164}
|
||||
{"mint":"Go6g4aZXZ3RsgXFRNANvYp1pPztyLrS2rDTk4LaHpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":64411884,"tokens_received":0,"buy_slot":348853820,"sell_lamports":59904272,"tokens_sold":2000000000000,"sell_slot":348853825,"pnl_lamports":-4507612,"timestamp":1750753184}
|
||||
{"mint":"EJZJ22gQqf9XgtjZ9N31pJCRtakjyd4YCmcdmFwLpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":87052436,"tokens_received":0,"buy_slot":348855812,"sell_lamports":83361598,"tokens_sold":0,"sell_slot":348855865,"pnl_lamports":-3690838,"timestamp":1750754013}
|
||||
{"mint":"GBBrsJEjVomNxGYt2Dkrhfi4wJbzwUsP8RTyW9Rzpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":90031336,"tokens_received":0,"buy_slot":348859474,"sell_lamports":84832357,"tokens_sold":3000000000000,"sell_slot":348859556,"pnl_lamports":-5198979,"timestamp":1750755507}
|
||||
{"mint":"3hmxuDesxQD7ZrVXn28QnhWwF6C91fbPvxBudCZipump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":94947622,"tokens_received":0,"buy_slot":348859569,"sell_lamports":95767332,"tokens_sold":0,"sell_slot":348859604,"pnl_lamports":819710,"timestamp":1750755526}
|
||||
{"mint":"FaGKu4x2gx7xMLnZSd8M6Aq6eNZKRNcdBUgUrtuLpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":87007606,"tokens_received":0,"buy_slot":348859744,"sell_lamports":83317598,"tokens_sold":0,"sell_slot":348859789,"pnl_lamports":-3690008,"timestamp":1750755600}
|
||||
{"mint":"HqAhSCmcCVLtGdXoPeomAmQs3Jebk94TgeybRGSUpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":98105407,"tokens_received":0,"buy_slot":348859840,"sell_lamports":88903282,"tokens_sold":0,"sell_slot":348859849,"pnl_lamports":-9202125,"timestamp":1750755625}
|
||||
{"mint":"WFdd1g4EY54QKixKLgnpU7WhP1Re7PE3soka8EKpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":5000,"tokens_received":0,"buy_slot":348859860,"sell_lamports":0,"tokens_sold":0,"sell_slot":348859868,"pnl_lamports":-5000,"timestamp":1750755632}
|
||||
{"mint":"BzbwMagMLkU5y7SaywZneiUuznwcwgEmFLGWDRGr78Lv","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":79093510,"tokens_received":0,"buy_slot":348921450,"sell_lamports":79088938,"tokens_sold":2000000000000,"sell_slot":348921453,"pnl_lamports":-4572,"timestamp":1750780447}
|
||||
{"mint":"25y7YcNghk9TMHYynYZwKYgBUK9x4tuhhaJbnHJ2pump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":63601160,"tokens_received":0,"buy_slot":348921487,"sell_lamports":59132111,"tokens_sold":0,"sell_slot":348921494,"pnl_lamports":-4469049,"timestamp":1750780463}
|
||||
{"mint":"5n4iU2VP4k4rNaqPsWxgVcHz28a8j1CMGnHWbWqLpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":65198490,"tokens_received":0,"buy_slot":348921528,"sell_lamports":59132115,"tokens_sold":2000000000000,"sell_slot":348921535,"pnl_lamports":-6066375,"timestamp":1750780479}
|
||||
{"mint":"YVrBU2ZxMSi8gdMDTRxcofKnSYmWs9Vm9sbnvHWpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":77811086,"tokens_received":0,"buy_slot":348921549,"sell_lamports":75745702,"tokens_sold":0,"sell_slot":348921552,"pnl_lamports":-2065384,"timestamp":1750780486}
|
||||
{"mint":"FBDFQdN1ztSVy4thoPibtECeZg3kZ35Nw3FdMCNEe19e","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":65566214,"tokens_received":0,"buy_slot":348921597,"sell_lamports":56409159,"tokens_sold":0,"sell_slot":348921601,"pnl_lamports":-9157055,"timestamp":1750780506}
|
||||
{"mint":"7KGg12TnBD497VvTUyBEx9WndmTrtokWSTe33FGtpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":66800206,"tokens_received":0,"buy_slot":348921609,"sell_lamports":60570130,"tokens_sold":0,"sell_slot":348921615,"pnl_lamports":-6230076,"timestamp":1750780511}
|
||||
{"mint":"7to5A8SaV8jM4L86CV2FRd7X7mcoF3fmk2ZmigbQPsZa","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":85237997,"tokens_received":0,"buy_slot":348921634,"sell_lamports":75458701,"tokens_sold":0,"sell_slot":348921639,"pnl_lamports":-9779296,"timestamp":1750780521}
|
||||
{"mint":"4BrkzdZaNzs4rN5VoeqQjN9496c1U7sKPgQmzizTpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":69490872,"tokens_received":0,"buy_slot":348921648,"sell_lamports":83127494,"tokens_sold":2000000000000,"sell_slot":348921649,"pnl_lamports":13636622,"timestamp":1750780525}
|
||||
{"mint":"HBFKY3oeXsTBj2hzXZgPiQze2Q8PgtKzEesfzPFhAe7E","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":58674678,"tokens_received":0,"buy_slot":348921685,"sell_lamports":55444203,"tokens_sold":2000000000000,"sell_slot":348921705,"pnl_lamports":-3230475,"timestamp":1750780549}
|
||||
{"mint":"GzRmd7nD8dbggpCxFiMwEmE4fwJE5KwgzXa98mXLpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":63647684,"tokens_received":0,"buy_slot":348921772,"sell_lamports":55833614,"tokens_sold":2000000000000,"sell_slot":348921780,"pnl_lamports":-7814070,"timestamp":1750780579}
|
||||
{"mint":"81enfW3nvwMuUZPP3fB3m7X4FrTB3jF3bXSMKnEKpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":61397067,"tokens_received":0,"buy_slot":348921810,"sell_lamports":61590721,"tokens_sold":2000000000000,"sell_slot":348921812,"pnl_lamports":193654,"timestamp":1750780592}
|
||||
{"mint":"YWHvhAWSMddbnWMtZ1yV1nhDNVAtA4SPJwJnc7Cpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":76060939,"tokens_received":0,"buy_slot":348921836,"sell_lamports":84497393,"tokens_sold":2000000000000,"sell_slot":348921839,"pnl_lamports":8436454,"timestamp":1750780603}
|
||||
{"mint":"7YcGpgdcGe12mPgQSGqvbBUjTBQrnQ7ncZwhJD6spump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":65789598,"tokens_received":0,"buy_slot":348921884,"sell_lamports":78228983,"tokens_sold":2000000000000,"sell_slot":348921886,"pnl_lamports":12439385,"timestamp":1750780621}
|
||||
{"mint":"F9p4NK7kQyik7PTyESZP7Qq9LB2Mi7e4YSvvApAqpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":62940981,"tokens_received":0,"buy_slot":348921923,"sell_lamports":55774219,"tokens_sold":2000000000000,"sell_slot":348921930,"pnl_lamports":-7166762,"timestamp":1750780638}
|
||||
{"mint":"H9YKYRF3QSaN6gLiSHXLgN9jkLL8YNy3N6LfiQ7Zpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":66451413,"tokens_received":0,"buy_slot":348921948,"sell_lamports":58970843,"tokens_sold":2000000000000,"sell_slot":348921956,"pnl_lamports":-7480570,"timestamp":1750780649}
|
||||
{"mint":"DHAkZieMnbcNBBoRaPriKRhyJL96r4SSnazbaQJpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":62835541,"tokens_received":0,"buy_slot":348921988,"sell_lamports":58377427,"tokens_sold":0,"sell_slot":348921996,"pnl_lamports":-4458114,"timestamp":1750780666}
|
||||
{"mint":"2iMHfPLU1mVKQ1LA1wxX141ppXRebbFJaPRiq4QGpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":77534598,"tokens_received":0,"buy_slot":348922008,"sell_lamports":74746215,"tokens_sold":0,"sell_slot":348922061,"pnl_lamports":-2788383,"timestamp":1750780690}
|
||||
{"mint":"5sKaSuEjnKCk78dhCnMHrBw8hibkuvAu4wXBvr18pump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":63612975,"tokens_received":0,"buy_slot":348922082,"sell_lamports":59132115,"tokens_sold":2000000000000,"sell_slot":348922094,"pnl_lamports":-4480860,"timestamp":1750780704}
|
||||
{"mint":"GqBGxcrFURRRzmSDVBAWbvdCaAr7ZiS46u9xF5BTpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":58640654,"tokens_received":0,"buy_slot":348922095,"sell_lamports":55446996,"tokens_sold":0,"sell_slot":348922131,"pnl_lamports":-3193658,"timestamp":1750780719}
|
||||
{"mint":"Gz9fgqH1zdjrQcGSAKM3p1LhbjwSYZYFbUEgaxdkpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":64099711,"tokens_received":0,"buy_slot":348922139,"sell_lamports":60112225,"tokens_sold":0,"sell_slot":348922141,"pnl_lamports":-3987486,"timestamp":1750780723}
|
||||
{"mint":"JAULmkXKAYPb7LtzLwKRvv9RuhKfa2BHqLRnFzCUpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":62354825,"tokens_received":0,"buy_slot":348922192,"sell_lamports":57422024,"tokens_sold":2000000000000,"sell_slot":348922201,"pnl_lamports":-4932801,"timestamp":1750780747}
|
||||
{"mint":"5qWm348XTs6n5fygzumMHmjr8K7CggSgPQfMo3Sepump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":66035518,"tokens_received":0,"buy_slot":348922228,"sell_lamports":68444613,"tokens_sold":2000000000000,"sell_slot":348922230,"pnl_lamports":2409095,"timestamp":1750780759}
|
||||
{"mint":"9yzz3jASKveAsFy28eCE67DMTtFukMBsqY23RAYzpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":58636918,"tokens_received":0,"buy_slot":348922259,"sell_lamports":57536067,"tokens_sold":2000000000000,"sell_slot":348922260,"pnl_lamports":-1100851,"timestamp":1750780771}
|
||||
{"mint":"DC8hVnwsNKAdFDfDrhULLTHQewyBYxd7DhQvw3LfkMSx","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":66559643,"tokens_received":0,"buy_slot":348922283,"sell_lamports":58968010,"tokens_sold":0,"sell_slot":348922288,"pnl_lamports":-7591633,"timestamp":1750780782}
|
||||
{"mint":"HWAy2jF9YxwkkYCakuB4oXUMwiAWoHWNz7L9CKWzpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":69276780,"tokens_received":0,"buy_slot":348922298,"sell_lamports":61562354,"tokens_sold":2000000000000,"sell_slot":348922308,"pnl_lamports":-7714426,"timestamp":1750780791}
|
||||
{"mint":"5gSAhjhryMaLurtSPTmmXcq83J2A7xkc9EqYCWT2pump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":5000,"tokens_received":0,"buy_slot":348924397,"sell_lamports":0,"tokens_sold":0,"sell_slot":348924482,"pnl_lamports":-5000,"timestamp":1750781674}
|
||||
{"mint":"Dzc9wxBKcGjaeKJQQnyqnxfYDXa5AZdqSK4wVAaUpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":63641160,"tokens_received":0,"buy_slot":348924497,"sell_lamports":58932115,"tokens_sold":2000000000000,"sell_slot":348924504,"pnl_lamports":-4709045,"timestamp":1750781682}
|
||||
{"mint":"3hdnm9VmE8XeaFmLJj9LwfTjWXzbgC1QS13t7BFHpump","creator":"ETiN5Tdx2zGfJGuB5XN29sGybPk7i1rZrYzLeSY1BviH","buy_lamports":62820272,"tokens_received":0,"buy_slot":348924517,"sell_lamports":56834800,"tokens_sold":2000000000000,"sell_slot":348924525,"pnl_lamports":-5985472,"timestamp":1750781691}
|
||||
Reference in New Issue
Block a user