Retrieves social infos + post on Telegram
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
Alexandre RAY-BERNAT 2025-04-24 14:04:56 +02:00
parent b4a6da9a81
commit 88310ed023
8 changed files with 824 additions and 285 deletions

56
.drone.yml Normal file
View File

@ -0,0 +1,56 @@
kind: pipeline
type: kubernetes
name: build
platform:
os: linux
arch: amd64
dns_config:
options:
- name: ndots
value: "1"
steps:
- name: prepare docker config
image: alpine
volumes:
- name: docker-config
path: /root/.docker
commands:
- cp /run/secrets/docker_config /root/.docker/config.json
- name: check & build
image: code.raybernat.com/tooling/drone-rust-plugin:latest
pull: always
commands:
- cargo build
- name: docker build & push
image: plugins/docker
volumes:
- name: docker-config
path: /root/.docker
environment:
PLUGIN_MTU: 1300
privileged: true
settings:
dockerfile: Dockerfile
repo: code.raybernat.com/alex/solana_scanner
registry: code.raybernat.com
tags:
- latest
- ${DRONE_COMMIT_SHA}
depends_on:
- "check & build"
when:
event:
- push
trigger:
event:
- pull_request
- push
branch:
- main
volumes:
- name: docker-config
temp: {}

491
Cargo.lock generated
View File

@ -392,6 +392,12 @@ dependencies = [
"syn 2.0.100",
]
[[package]]
name = "atomic-waker"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "atty"
version = "0.2.14"
@ -1201,6 +1207,16 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "errno"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
dependencies = [
"libc",
"windows-sys 0.59.0",
]
[[package]]
name = "event-listener"
version = "2.5.3"
@ -1228,6 +1244,12 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "fastrand"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
[[package]]
name = "feature-probe"
version = "0.1.1"
@ -1487,7 +1509,26 @@ dependencies = [
"futures-core",
"futures-sink",
"futures-util",
"http",
"http 0.2.12",
"indexmap",
"slab",
"tokio",
"tokio-util",
"tracing",
]
[[package]]
name = "h2"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75249d144030531f8dee69fe9cea04d3edf809a017ae445e2abdff6629e86633"
dependencies = [
"atomic-waker",
"bytes",
"fnv",
"futures-core",
"futures-sink",
"http 1.3.1",
"indexmap",
"slab",
"tokio",
@ -1593,6 +1634,17 @@ dependencies = [
"itoa",
]
[[package]]
name = "http"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565"
dependencies = [
"bytes",
"fnv",
"itoa",
]
[[package]]
name = "http-body"
version = "0.4.6"
@ -1600,7 +1652,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
dependencies = [
"bytes",
"http",
"http 0.2.12",
"pin-project-lite",
]
[[package]]
name = "http-body"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
dependencies = [
"bytes",
"http 1.3.1",
]
[[package]]
name = "http-body-util"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
dependencies = [
"bytes",
"futures-core",
"http 1.3.1",
"http-body 1.0.1",
"pin-project-lite",
]
@ -1632,9 +1707,9 @@ dependencies = [
"futures-channel",
"futures-core",
"futures-util",
"h2",
"http",
"http-body",
"h2 0.3.26",
"http 0.2.12",
"http-body 0.4.6",
"httparse",
"httpdate",
"itoa",
@ -1646,6 +1721,26 @@ dependencies = [
"want",
]
[[package]]
name = "hyper"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80"
dependencies = [
"bytes",
"futures-channel",
"futures-util",
"h2 0.4.9",
"http 1.3.1",
"http-body 1.0.1",
"httparse",
"itoa",
"pin-project-lite",
"smallvec",
"tokio",
"want",
]
[[package]]
name = "hyper-rustls"
version = "0.24.2"
@ -1653,11 +1748,64 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590"
dependencies = [
"futures-util",
"http",
"hyper",
"http 0.2.12",
"hyper 0.14.32",
"rustls 0.21.12",
"tokio",
"tokio-rustls",
"tokio-rustls 0.24.1",
]
[[package]]
name = "hyper-rustls"
version = "0.27.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2"
dependencies = [
"futures-util",
"http 1.3.1",
"hyper 1.6.0",
"hyper-util",
"rustls 0.23.25",
"rustls-pki-types",
"tokio",
"tokio-rustls 0.26.2",
"tower-service",
]
[[package]]
name = "hyper-tls"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
dependencies = [
"bytes",
"http-body-util",
"hyper 1.6.0",
"hyper-util",
"native-tls",
"tokio",
"tokio-native-tls",
"tower-service",
]
[[package]]
name = "hyper-util"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2"
dependencies = [
"bytes",
"futures-channel",
"futures-util",
"http 1.3.1",
"http-body 1.0.1",
"hyper 1.6.0",
"libc",
"pin-project-lite",
"socket2",
"tokio",
"tower-service",
"tracing",
]
[[package]]
@ -2016,6 +2164,12 @@ dependencies = [
"libsecp256k1-core",
]
[[package]]
name = "linux-raw-sys"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
[[package]]
name = "litemap"
version = "0.7.5"
@ -2129,6 +2283,23 @@ dependencies = [
"thiserror 1.0.69",
]
[[package]]
name = "native-tls"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e"
dependencies = [
"libc",
"log",
"openssl",
"openssl-probe",
"openssl-sys",
"schannel",
"security-framework 2.11.1",
"security-framework-sys",
"tempfile",
]
[[package]]
name = "nix"
version = "0.29.0"
@ -2819,11 +2990,11 @@ dependencies = [
"encoding_rs",
"futures-core",
"futures-util",
"h2",
"http",
"http-body",
"hyper",
"hyper-rustls",
"h2 0.3.26",
"http 0.2.12",
"http-body 0.4.6",
"hyper 0.14.32",
"hyper-rustls 0.24.2",
"ipnet",
"js-sys",
"log",
@ -2833,14 +3004,14 @@ dependencies = [
"percent-encoding",
"pin-project-lite",
"rustls 0.21.12",
"rustls-pemfile",
"rustls-pemfile 1.0.4",
"serde",
"serde_json",
"serde_urlencoded",
"sync_wrapper",
"system-configuration",
"sync_wrapper 0.1.2",
"system-configuration 0.5.1",
"tokio",
"tokio-rustls",
"tokio-rustls 0.24.1",
"tokio-util",
"tower-service",
"url",
@ -2851,6 +3022,50 @@ dependencies = [
"winreg",
]
[[package]]
name = "reqwest"
version = "0.12.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb"
dependencies = [
"base64 0.22.1",
"bytes",
"encoding_rs",
"futures-core",
"futures-util",
"h2 0.4.9",
"http 1.3.1",
"http-body 1.0.1",
"http-body-util",
"hyper 1.6.0",
"hyper-rustls 0.27.5",
"hyper-tls",
"hyper-util",
"ipnet",
"js-sys",
"log",
"mime",
"native-tls",
"once_cell",
"percent-encoding",
"pin-project-lite",
"rustls-pemfile 2.2.0",
"serde",
"serde_json",
"serde_urlencoded",
"sync_wrapper 1.0.2",
"system-configuration 0.6.1",
"tokio",
"tokio-native-tls",
"tower",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"windows-registry",
]
[[package]]
name = "reqwest-middleware"
version = "0.2.5"
@ -2859,8 +3074,8 @@ checksum = "5a735987236a8e238bf0296c7e351b999c188ccc11477f311b82b55c93984216"
dependencies = [
"anyhow",
"async-trait",
"http",
"reqwest",
"http 0.2.12",
"reqwest 0.11.27",
"serde",
"task-local-extensions",
"thiserror 1.0.69",
@ -2910,6 +3125,19 @@ dependencies = [
"nom",
]
[[package]]
name = "rustix"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf"
dependencies = [
"bitflags 2.9.0",
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.59.0",
]
[[package]]
name = "rustls"
version = "0.21.12"
@ -2945,7 +3173,7 @@ dependencies = [
"openssl-probe",
"rustls-pki-types",
"schannel",
"security-framework",
"security-framework 3.2.0",
]
[[package]]
@ -2957,6 +3185,15 @@ dependencies = [
"base64 0.21.7",
]
[[package]]
name = "rustls-pemfile"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
dependencies = [
"rustls-pki-types",
]
[[package]]
name = "rustls-pki-types"
version = "1.11.0"
@ -2981,7 +3218,7 @@ dependencies = [
"rustls-native-certs",
"rustls-platform-verifier-android",
"rustls-webpki 0.103.1",
"security-framework",
"security-framework 3.2.0",
"security-framework-sys",
"webpki-root-certs",
"windows-sys 0.59.0",
@ -3060,6 +3297,19 @@ dependencies = [
"untrusted",
]
[[package]]
name = "security-framework"
version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
dependencies = [
"bitflags 2.9.0",
"core-foundation 0.9.4",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework"
version = "3.2.0"
@ -3273,9 +3523,9 @@ checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
[[package]]
name = "socket2"
version = "0.5.8"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8"
checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef"
dependencies = [
"libc",
"windows-sys 0.52.0",
@ -4091,7 +4341,7 @@ dependencies = [
"gethostname",
"lazy_static",
"log",
"reqwest",
"reqwest 0.11.27",
"solana-clock",
"solana-cluster-type",
"solana-sha256-hasher",
@ -4481,7 +4731,7 @@ dependencies = [
"crossbeam-channel",
"futures-util",
"log",
"reqwest",
"reqwest 0.11.27",
"semver",
"serde",
"serde_derive",
@ -4623,7 +4873,7 @@ dependencies = [
"bs58",
"indicatif",
"log",
"reqwest",
"reqwest 0.11.27",
"reqwest-middleware",
"semver",
"serde",
@ -4659,7 +4909,7 @@ dependencies = [
"base64 0.22.1",
"bs58",
"jsonrpc-core",
"reqwest",
"reqwest 0.11.27",
"reqwest-middleware",
"semver",
"serde",
@ -5502,6 +5752,7 @@ dependencies = [
"libc",
"log",
"mpl-token-metadata",
"reqwest 0.12.15",
"serde",
"serde_json",
"solana-account-decoder",
@ -5512,6 +5763,7 @@ dependencies = [
"solana-transaction-status",
"solana-transaction-status-client-types",
"spl-token 8.0.0",
"tokio",
]
[[package]]
@ -5955,6 +6207,15 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]]
name = "sync_wrapper"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
dependencies = [
"futures-core",
]
[[package]]
name = "synstructure"
version = "0.12.6"
@ -5986,7 +6247,18 @@ checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
dependencies = [
"bitflags 1.3.2",
"core-foundation 0.9.4",
"system-configuration-sys",
"system-configuration-sys 0.5.0",
]
[[package]]
name = "system-configuration"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
dependencies = [
"bitflags 2.9.0",
"core-foundation 0.9.4",
"system-configuration-sys 0.6.0",
]
[[package]]
@ -5999,6 +6271,16 @@ dependencies = [
"libc",
]
[[package]]
name = "system-configuration-sys"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "task-local-extensions"
version = "0.1.4"
@ -6008,6 +6290,19 @@ dependencies = [
"pin-utils",
]
[[package]]
name = "tempfile"
version = "3.19.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf"
dependencies = [
"fastrand",
"getrandom 0.3.2",
"once_cell",
"rustix",
"windows-sys 0.59.0",
]
[[package]]
name = "termcolor"
version = "1.4.1"
@ -6142,6 +6437,16 @@ dependencies = [
"syn 2.0.100",
]
[[package]]
name = "tokio-native-tls"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
dependencies = [
"native-tls",
"tokio",
]
[[package]]
name = "tokio-rustls"
version = "0.24.1"
@ -6152,6 +6457,16 @@ dependencies = [
"tokio",
]
[[package]]
name = "tokio-rustls"
version = "0.26.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b"
dependencies = [
"rustls 0.23.25",
"tokio",
]
[[package]]
name = "tokio-stream"
version = "0.1.17"
@ -6173,7 +6488,7 @@ dependencies = [
"log",
"rustls 0.21.12",
"tokio",
"tokio-rustls",
"tokio-rustls 0.24.1",
"tungstenite",
"webpki-roots 0.25.4",
]
@ -6217,6 +6532,27 @@ dependencies = [
"winnow",
]
[[package]]
name = "tower"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
dependencies = [
"futures-core",
"futures-util",
"pin-project-lite",
"sync_wrapper 1.0.2",
"tokio",
"tower-layer",
"tower-service",
]
[[package]]
name = "tower-layer"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
[[package]]
name = "tower-service"
version = "0.3.3"
@ -6258,7 +6594,7 @@ dependencies = [
"byteorder",
"bytes",
"data-encoding",
"http",
"http 0.2.12",
"httparse",
"log",
"rand 0.8.5",
@ -6583,6 +6919,35 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
[[package]]
name = "windows-registry"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3"
dependencies = [
"windows-result",
"windows-strings",
"windows-targets 0.53.0",
]
[[package]]
name = "windows-result"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-strings"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-sys"
version = "0.45.0"
@ -6658,13 +7023,29 @@ dependencies = [
"windows_aarch64_gnullvm 0.52.6",
"windows_aarch64_msvc 0.52.6",
"windows_i686_gnu 0.52.6",
"windows_i686_gnullvm",
"windows_i686_gnullvm 0.52.6",
"windows_i686_msvc 0.52.6",
"windows_x86_64_gnu 0.52.6",
"windows_x86_64_gnullvm 0.52.6",
"windows_x86_64_msvc 0.52.6",
]
[[package]]
name = "windows-targets"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b"
dependencies = [
"windows_aarch64_gnullvm 0.53.0",
"windows_aarch64_msvc 0.53.0",
"windows_i686_gnu 0.53.0",
"windows_i686_gnullvm 0.53.0",
"windows_i686_msvc 0.53.0",
"windows_x86_64_gnu 0.53.0",
"windows_x86_64_gnullvm 0.53.0",
"windows_x86_64_msvc 0.53.0",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
@ -6683,6 +7064,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
@ -6701,6 +7088,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_aarch64_msvc"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
@ -6719,12 +7112,24 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnu"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_gnullvm"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
@ -6743,6 +7148,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_i686_msvc"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
@ -6761,6 +7172,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnu"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
@ -6779,6 +7196,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
@ -6797,6 +7220,12 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "windows_x86_64_msvc"
version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
[[package]]
name = "winnow"
version = "0.7.4"

View File

@ -25,7 +25,8 @@ mpl-token-metadata = "5.1.0"
solana-program = "2.2.1"
serde_json = "1.0.140"
log = "0.4.27"
reqwest = { version = "0.12.15", features = ["json"] }
tokio = { version = "1", features = ["full"] }
[target.'cfg(target_os = "linux")'.dependencies]
libc = "0.2"

View File

@ -43,20 +43,22 @@ pub struct UiParsedTokenAccount {
space: Option<u64>,
}
#[derive( Debug)]
pub struct Transaction {
pub(crate) signature: String,
pub(crate) slot: Slot,
pub(crate) block_time: Option<i64>,
pub(crate) status: Option<TransactionError>,
pub(crate) account_keys: AccountKeys
pub(crate) account_keys: AccountKeys,
}
#[derive(Debug)]
pub struct AccountKeys {
pub(crate) payer: Pubkey,
pub(crate) mint_account: Pubkey,
pub(crate) rent_account: Pubkey,
pub(crate) mint_authority: Pubkey,
pub(crate) token_program: Pubkey
pub(crate) token_program: Pubkey,
}
#[derive(Debug, Clone)]
@ -68,5 +70,30 @@ pub struct TokenData {
pub(crate) dev_balance: f64,
pub(crate) mint_authority: bool,
pub(crate) freeze_authority: bool,
}
#[derive(Debug, Deserialize)]
pub struct TokenSocials {
pub(crate) createdOn: String,
pub(crate) description: String,
pub(crate) image: String,
pub(crate) name: String,
pub(crate) symbol: String,
pub(crate) twitter: String,
pub(crate) website: String
}
impl Default for TokenSocials {
fn default() -> Self {
Self {
createdOn: "".to_string(),
description: "".to_string(),
image: "".to_string(),
name: "".to_string(),
symbol: "".to_string(),
twitter: "".to_string(),
website: "".to_string(),
}
}
}
}

View File

@ -1,9 +1,12 @@
use std::error::Error;
use bs58;
use chrono;
use solana_sdk::message::Message;
use anyhow::anyhow;
use crate::dto::{AccountKeys, ParsedAccount, TokenData, TokenInfo, Transaction, TokenSocials };
use crate::utils::{base58_to_pubkey, get_token_socials};
use anyhow::Result;
use anyhow::anyhow;
use base64::prelude::*;
use borsh::{BorshDeserialize, BorshSerialize};
use chrono::Utc;
@ -17,6 +20,7 @@ use solana_client::rpc_client::RpcClient;
use solana_client::rpc_config::RpcAccountInfoConfig;
use solana_client::rpc_request::TokenAccountsFilter;
use solana_program::{program_pack::Pack, pubkey::Pubkey};
use solana_sdk::account::Account;
use solana_sdk::message::VersionedMessage;
use solana_sdk::signature::Signature;
use solana_sdk::transaction::{TransactionError, VersionedTransaction};
@ -25,21 +29,22 @@ use solana_transaction_status::{EncodedConfirmedTransactionWithStatusMeta, UiTra
use solana_transaction_status_client_types::option_serializer;
use spl_token::state::Mint;
use std::str::FromStr;
use solana_program::clock::Slot;
use solana_sdk::account::Account;
use utils::sanitize_string;
use crate::dto::{AccountKeys, ParsedAccount, TokenData, TokenInfo, Transaction};
use crate::utils::base58_to_pubkey;
use solana_rpc_calls::*;
use crate::telegram_publish::send_to_telegram;
mod utils;
mod dto;
mod utils;
mod solana_rpc_calls;
mod telegram_publish;
lazy_static! {
static ref RPC_CLIENT: RpcClient =
RpcClient::new("https://api.mainnet-beta.solana.com".to_string());
}
fn main() {
#[tokio::main]
async fn main() {
// Adresse du programme Token (SPL Token Program) --> pumpfun
let token_program_address = "TSLvdd1pWpHVjahSpsvCXUbgwsL3JAcvokwaKt1eokM";
@ -58,12 +63,13 @@ fn main() {
match signatures {
Ok(sigs) => {
debug!(
"{}",
format!("Nombre total de transactions trouvées : {}", sigs.len())
);
debug!("{}", format!(
"Nombre total de transactions trouvées : {}",
sigs.len()
));
for sig in sigs.iter().take(1000) {
let signature = Signature::from_str(&sig.signature).unwrap();
info!("================ Signature ========================");
@ -87,105 +93,154 @@ fn main() {
});
if !is_token_creation {
continue
continue;
}
match tx.transaction.transaction {
Binary(data, encoding) => {
let decoded = BASE64_STANDARD.decode(data).unwrap();
match tx.transaction.transaction {
Binary(data, encoding) => {
let decoded = BASE64_STANDARD.decode(data).unwrap();
if let Ok(versioned_tx) =
bincode::deserialize::<VersionedTransaction>(
&decoded,
)
{
let account_keys = versioned_tx.message.static_account_keys();
if let Ok(versioned_tx) =
bincode::deserialize::<VersionedTransaction>(
&decoded,
)
{
let account_keys =
versioned_tx.message.static_account_keys();
let transaction = Transaction {
signature: sig.clone().signature,
slot: sig.clone().slot,
block_time: sig.clone().block_time,
status: meta.err,
account_keys: AccountKeys {
payer: account_keys[0],
mint_account: account_keys[1],
rent_account: account_keys[2],
mint_authority: account_keys[3],
token_program: account_keys[4],
},
};
let transaction = Transaction {
signature: sig.clone().signature,
slot: sig.clone().slot,
block_time: sig.clone().block_time,
status: meta.err,
account_keys: AccountKeys {
payer: account_keys[0],
mint_account: account_keys[1],
rent_account: account_keys[2],
mint_authority: account_keys[3],
token_program: account_keys[4],
},
};
let mint_pubkey =transaction.account_keys.mint_account;
dbg!(&transaction);
let dev_pubkey = transaction.account_keys.payer;
let mint_pubkey =
transaction.account_keys.mint_account;
match get_token_metadata(
&RPC_CLIENT,
&mint_pubkey,
) {
Ok(token_metadata) => {
let dev_balance =
get_dev_balance_for_token(
&RPC_CLIENT,
&transaction.account_keys.payer,
&mint_pubkey,
);
if let Err(e) = dev_balance {
error!("{}",format!("{}", e) );
continue
}
match get_token_info(
match get_token_metadata(
&RPC_CLIENT,
&mint_pubkey,
) {
Ok(token_metadata) => {
let dev_balance =
get_dev_balance_for_token(
&RPC_CLIENT,
&transaction.account_keys.payer,
&mint_pubkey,
) {
Ok(token_info) => {
);
let token_data = TokenData {
name: sanitize_string(&token_metadata.name),
symbol: sanitize_string(&token_metadata.symbol),
uri: sanitize_string(&token_metadata.uri),
supply: token_info.supply,
dev_balance: dev_balance.unwrap().clone(),
mint_authority: token_info.mint_authority,
freeze_authority: token_info.freeze_authority,
};
if let Err(e) = dev_balance {
error!("{}", format!("{}", e));
continue;
}
dbg!(token_data.clone());
match get_token_info(
&RPC_CLIENT,
&mint_pubkey,
) {
Ok(token_info) => {
let token_data = TokenData {
name: sanitize_string(
&token_metadata.name,
),
symbol: sanitize_string(
&token_metadata.symbol,
),
uri: sanitize_string(
&token_metadata.uri,
),
supply: token_info.supply / 10u64.pow(token_info.decimals as u32),
dev_balance: dev_balance
.unwrap()
.clone(),
mint_authority: token_info
.mint_authority,
freeze_authority:
token_info
.freeze_authority,
};
let is_safe_token = is_safe_token(token_data.clone());
if(is_safe_token)
{
println!("Token OK")
}
else { println!("Token NOK") }
dbg!(token_data.clone());
}
Err(e) => {
error!(
"Erreur lors de la récupération des informations du token : {:?}",
e
let is_safe_token =
is_safe_token(
token_data.clone(),
);
if (is_safe_token) {
println!("Token OK");
let token = "8176178685:AAHMlXsjx4ffH9sQ1v_eg1nkc-W9XUncIhE";
let chat_id = "945119667"; // can be a group chat too
let socials= get_token_socials(&token_data.uri).await.ok();
let socials = socials.unwrap_or_default();
let message = format!("🚨 #New token detected!\
\n**Name**: {} ({}) \
\n**Uri**: {} \
\nSignature: https://solscan.io/tx/{} \
\nMint address: https://solscan.io/token/{} \
\nDev address: https://solscan.io/account/{} \
\nSource: https://pump.fun/coin/{} \
\nDescription: {} \
\nTwitter: {} \
\nWebsite: {} \
\nImage: {} \
", token_data.name,
token_data.symbol,
token_data.uri,
transaction.signature,
transaction.account_keys.mint_account,
transaction.account_keys.payer,
transaction.account_keys.mint_account,
socials.description,
socials.twitter,
socials.website,
socials.image);
if let Err(e) = send_to_telegram(token, chat_id, message.as_str()).await {
eprintln!("Error sending to Telegram: {}", e);
}
} else {
println!("Token NOK")
}
}
Err(e) => {
error!(
"Erreur lors de la récupération des informations du token : {:?}",
e
);
}
}
Err(_) => {}
};
}
println!(
"============================================="
);
}
Err(_) => {}
};
}
_ => {}
println!(
"============================================="
);
}
_ => {}
}
}
}
}
@ -215,7 +270,6 @@ fn is_safe_token(data: TokenData) -> bool {
!(has_control || holds_too_much)
}
fn find_metadata_account(mint: &Pubkey) -> (Pubkey, u8) {
let metadata_program_id =
Pubkey::from_str("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s").unwrap();
@ -225,82 +279,6 @@ fn find_metadata_account(mint: &Pubkey) -> (Pubkey, u8) {
)
}
fn get_token_metadata(client: &RpcClient, mint: &Pubkey) -> Result<Metadata> {
let (metadata_pubkey, _) = find_metadata_account(mint);
let account = client.get_account(&metadata_pubkey)?;
let metadata = Metadata::safe_deserialize(&mut account.data.as_ref())?;
Ok(metadata)
}
pub const TOKEN_METADATA_PROGRAM_ID: Pubkey = Pubkey::new_from_array([
0x6D, 0x65, 0x74, 0x61, 0x70, 0x6C, 0x65, 0x78, 0x2D, 0x6D, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]);
fn get_creator_of_mint(rpc_client: &RpcClient, mint_address: &Pubkey) -> anyhow::Result<Pubkey> {
// 1. Récupère les signatures associées au compte mint
let signatures = rpc_client
.get_signatures_for_address(mint_address)
.into_iter()
.rev() // on inverse pour avoir les plus anciennes d'abord
.collect::<Vec<_>>();
let first_signature = signatures.first();
match first_signature {
None => Err(anyhow!("Pas de transactions trouvées pour ce mint")),
Some(sig) => {
let sig2 = sig.first().expect("Pzs de signature trouvée");
let sig = sig2
.signature
.parse::<Signature>()
.expect("Signature invalide");
// 2. Récupère les détails de la première transaction
let tx = get_transactions(rpc_client, &sig)?.transaction.transaction;
let tx: anyhow::Result<VersionedMessage> = match tx {
Binary(data, encoding) => {
let decoded = BASE64_STANDARD.decode(data)?;
if let Ok(versioned_tx) = bincode::deserialize::<VersionedTransaction>(&decoded)
{
if let Ok(message) = bincode::deserialize::<VersionedMessage>(
&versioned_tx.message.serialize(),
) {
Ok(message)
} else {
Err(anyhow!(""))
}
} else {
Err(anyhow!(""))
}
}
_ => Err(anyhow!("Encoding of transaction is not supported")),
};
let payer: Result<Message> = match tx {
Ok(msg) => {
match msg {
VersionedMessage::Legacy(legacy_msg) => {
println!("{:?}", legacy_msg);
Ok(legacy_msg)
}
//VersionedMessage::V0(v0_msg) => { println!("{:?}", v0_msg); v0_msg}
_ => Err(anyhow!("Encoding of transaction is not supported")),
}
}
Err(_) => Err(anyhow!("Encoding of transaction is not supported")),
};
let payer = payer;
Ok(*payer?.account_keys.first().unwrap())
}
}
}
fn is_token_creation(instruction: &solana_transaction_status::UiCompiledInstruction) -> bool {
match bs58::decode(&instruction.data).into_vec() {
@ -316,89 +294,6 @@ fn is_token_creation(instruction: &solana_transaction_status::UiCompiledInstruct
}
}
fn get_dev_balance_for_token(rpc: &RpcClient, dev_pubkey: &Pubkey, mint: &Pubkey) -> Result<f64> {
let token_accounts =
rpc.get_token_accounts_by_owner(dev_pubkey, TokenAccountsFilter::Mint(*mint))?;
let mut total_balance: f64 = 0.0;
for account_info in token_accounts {
let amount_option = match account_info.account.data.clone() {
UiAccountData::Json(test) => {
let json = serde_json::to_value(&test.parsed)?;
let token: ParsedAccount = serde_json::from_value(json)?;
token.info.tokenAmount.uiAmount
}
_ => {
error!("Cannot parse account_data");
None
}
};
total_balance += amount_option.unwrap_or_else(|| 0.0);
}
Ok(total_balance)
}
fn fetch_account(rpc_client: &RpcClient, mint_pubkey: &Pubkey) -> Result<Account> {
let config = RpcAccountInfoConfig {
encoding: Some(UiAccountEncoding::Base64),
..RpcAccountInfoConfig::default()
};
match rpc_client.get_account_with_config(&mint_pubkey, config) {
Ok(response) => {
match response.value {
Some(account) => {
Ok(account)
}
None => {
Err(anyhow::Error::msg(format!("Account not found")))
}
}
}
Err(e) => {
Err(anyhow::Error::msg(format!("RPC error {}", e)))
}
}
}
fn get_token_info(client: &RpcClient, mint_pubkey: &Pubkey) -> Result<TokenInfo> {
let account = fetch_account(client, mint_pubkey);
let mint = Mint::unpack(&*account?.data);
match mint {
Ok(mint) => {
Ok(TokenInfo {
mint_address: mint_pubkey.to_string(),
decimals: mint.decimals,
mint_authority: mint.mint_authority.is_some(),
freeze_authority: mint.freeze_authority.is_some(),
supply: mint.supply,
})
}
Err(e) => Err(anyhow::Error::msg(format!("ProgramError: {:?}", e))),
}
}
fn get_transactions(
client: &RpcClient,
signature: &Signature,
) -> solana_client::client_error::Result<EncodedConfirmedTransactionWithStatusMeta> {
let config = solana_client::rpc_config::RpcTransactionConfig {
encoding: Some(UiTransactionEncoding::Base64),
commitment: Some(solana_sdk::commitment_config::CommitmentConfig::confirmed()),
max_supported_transaction_version: Some(0),
};
client.get_transaction_with_config(&signature, config)
}
#[cfg(test)]
mod tests {
use super::*;

98
src/solana_rpc_calls.rs Normal file
View File

@ -0,0 +1,98 @@
use anyhow::anyhow;
use base64::Engine;
use base64::prelude::BASE64_STANDARD;
use log::error;
use mpl_token_metadata::accounts::Metadata;
use solana_account_decoder::{UiAccountData, UiAccountEncoding};
use solana_client::rpc_client::RpcClient;
use solana_client::rpc_config::RpcAccountInfoConfig;
use solana_client::rpc_request::TokenAccountsFilter;
use solana_program::message::{Message, VersionedMessage};
use solana_program::program_pack::Pack;
use solana_program::pubkey::Pubkey;
use solana_sdk::account::Account;
use solana_sdk::signature::Signature;
use solana_sdk::transaction::VersionedTransaction;
use solana_transaction_status_client_types::{EncodedConfirmedTransactionWithStatusMeta, UiTransactionEncoding};
use solana_transaction_status_client_types::EncodedTransaction::Binary;
use spl_token::state::Mint;
use crate::dto::{ParsedAccount, TokenInfo};
use crate::{ find_metadata_account};
pub fn get_token_info(client: &RpcClient, mint_pubkey: &Pubkey) -> anyhow::Result<TokenInfo> {
let account = fetch_account(client, mint_pubkey);
let mint = Mint::unpack(&*account?.data);
match mint {
Ok(mint) => Ok(TokenInfo {
mint_address: mint_pubkey.to_string(),
decimals: mint.decimals,
mint_authority: mint.mint_authority.is_some(),
freeze_authority: mint.freeze_authority.is_some(),
supply: mint.supply,
}),
Err(e) => Err(anyhow::Error::msg(format!("ProgramError: {:?}", e))),
}
}
pub fn get_transactions(
client: &RpcClient,
signature: &Signature,
) -> solana_client::client_error::Result<EncodedConfirmedTransactionWithStatusMeta> {
let config = solana_client::rpc_config::RpcTransactionConfig {
encoding: Some(UiTransactionEncoding::Base64),
commitment: Some(solana_sdk::commitment_config::CommitmentConfig::confirmed()),
max_supported_transaction_version: Some(0),
};
client.get_transaction_with_config(&signature, config)
}
pub fn get_token_metadata(client: &RpcClient, mint: &Pubkey) -> anyhow::Result<Metadata> {
let (metadata_pubkey, _) = find_metadata_account(mint);
let account = client.get_account(&metadata_pubkey)?;
let metadata = Metadata::safe_deserialize(&mut account.data.as_ref())?;
Ok(metadata)
}
pub fn get_dev_balance_for_token(rpc: &RpcClient, dev_pubkey: &Pubkey, mint: &Pubkey) -> anyhow::Result<f64> {
let token_accounts =
rpc.get_token_accounts_by_owner(dev_pubkey, TokenAccountsFilter::Mint(*mint))?;
let mut total_balance: f64 = 0.0;
for account_info in token_accounts {
let amount_option = match account_info.account.data.clone() {
UiAccountData::Json(test) => {
let json = serde_json::to_value(&test.parsed)?;
let token: ParsedAccount = serde_json::from_value(json)?;
token.info.tokenAmount.uiAmount
}
_ => {
error!("Cannot parse account_data");
None
}
};
total_balance += amount_option.unwrap_or_else(|| 0.0);
}
Ok(total_balance)
}
fn fetch_account(rpc_client: &RpcClient, mint_pubkey: &Pubkey) -> anyhow::Result<Account> {
let config = RpcAccountInfoConfig {
encoding: Some(UiAccountEncoding::Base64),
..RpcAccountInfoConfig::default()
};
match rpc_client.get_account_with_config(&mint_pubkey, config) {
Ok(response) => match response.value {
Some(account) => Ok(account),
None => Err(anyhow::Error::msg(format!("Account not found"))),
},
Err(e) => Err(anyhow::Error::msg(format!("RPC error {}", e))),
}
}

20
src/telegram_publish.rs Normal file
View File

@ -0,0 +1,20 @@
use reqwest::Client;
pub async fn send_to_telegram(bot_token: &str, chat_id: &str, message: &str) -> Result<(), Box<dyn std::error::Error>> {
let url = format!("https://api.telegram.org/bot{}/sendMessage", bot_token);
let params = [
("chat_id", chat_id),
("text", message),
("parse_mode", "Markdown")
];
let client = Client::new();
client.post(&url)
.form(&params)
.send()
.await?;
Ok(())
}

View File

@ -1,4 +1,6 @@
use reqwest::Client;
use solana_program::pubkey::Pubkey;
use crate::dto::TokenSocials;
pub fn sanitize_string(s: &str) -> String {
s.trim_end_matches('\0').to_string()
@ -12,4 +14,15 @@ pub fn base58_to_pubkey(address: &str) -> anyhow::Result<Pubkey, Box<dyn std::er
let mut bytes = [0u8; 32];
bytes.copy_from_slice(&decoded);
Ok(Pubkey::new_from_array(bytes))
}
pub async fn get_token_socials(uri: &str) -> Result<TokenSocials, Box<dyn std::error::Error>> {
let client = Client::new();
let response = client.get(uri)
.send()
.await?;
let json: TokenSocials = response.json().await?;
Ok(json)
}