diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..ec43a72 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,47 @@ +kind: pipeline +type: kubernetes +name: build + +platform: + os: linux + arch: amd64 + +dns_config: + options: + - name: ndots + value: "1" +steps: + - name: check & build + image: code.raybernat.com/tooling/drone-rust-plugin:latest + pull: always + commands: + - cargo build + - name: docker build & push + image: plugins/docker + environment: + PLUGIN_MTU: 1300 + DRONE_REGISTRY_PLUGIN_ENDPOINT: code.raybernat.com + DRONE_REGISTRY_PLUGIN_TOKEN: fd8fe4ad4ef1b2eb88fdfebffeeb847ebfbe3bf6 + privileged: true + settings: + dockerfile: Dockerfile + repo: code.raybernat.com/alex/solana_scanner + registry: code.raybernat.com + username: drone + password: + from_secret: kaniko_registry_password + tags: + - latest + - ${DRONE_COMMIT_SHA} + depends_on: + - "check & build" + when: + event: + - push + +trigger: + event: + - pull_request + - push + branch: + - main \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 059d8cc..5f2c897 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index cadb998..c995848 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/src/dto.rs b/src/dto.rs index 8658e3f..69b0368 100644 --- a/src/dto.rs +++ b/src/dto.rs @@ -43,20 +43,22 @@ pub struct UiParsedTokenAccount { space: Option, } +#[derive( Debug)] pub struct Transaction { pub(crate) signature: String, pub(crate) slot: Slot, pub(crate) block_time: Option, pub(crate) status: Option, - 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(), + } + } +} -} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 9bd3d30..d751a05 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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::( - &decoded, - ) - { - let account_keys = versioned_tx.message.static_account_keys(); + if let Ok(versioned_tx) = + bincode::deserialize::( + &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 { - 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 { - // 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::>(); - - 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::() - .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 = match tx { - Binary(data, encoding) => { - let decoded = BASE64_STANDARD.decode(data)?; - - if let Ok(versioned_tx) = bincode::deserialize::(&decoded) - { - if let Ok(message) = bincode::deserialize::( - &versioned_tx.message.serialize(), - ) { - Ok(message) - } else { - Err(anyhow!("")) - } - } else { - Err(anyhow!("")) - } - } - _ => Err(anyhow!("Encoding of transaction is not supported")), - }; - - let payer: Result = 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 { - 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 { - 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 { - - 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 { - 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::*; diff --git a/src/solana_rpc_calls.rs b/src/solana_rpc_calls.rs new file mode 100644 index 0000000..40557f9 --- /dev/null +++ b/src/solana_rpc_calls.rs @@ -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 { + 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 { + 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 { + 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 { + 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 { + 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))), + } +} \ No newline at end of file diff --git a/src/telegram_publish.rs b/src/telegram_publish.rs new file mode 100644 index 0000000..0e5d31e --- /dev/null +++ b/src/telegram_publish.rs @@ -0,0 +1,20 @@ +use reqwest::Client; + +pub async fn send_to_telegram(bot_token: &str, chat_id: &str, message: &str) -> Result<(), Box> { + 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(¶ms) + .send() + .await?; + + Ok(()) +} \ No newline at end of file diff --git a/src/utils.rs b/src/utils.rs index 1ab60c1..27b9707 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -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 Result> { + let client = Client::new(); + let response = client.get(uri) + .send() + .await?; + + let json: TokenSocials = response.json().await?; + + Ok(json) } \ No newline at end of file