commit df491c63df84cd43458397aa06996188373e6fe7 Author: crappyrules Date: Mon Oct 6 13:31:01 2025 -0400 Initial commit: Solana lottery program diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..5e23850 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,46 @@ +# Development files +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Anchor build artifacts +target/ +.anchor/ +Cargo.lock + +# Program files (not needed for frontend) +programs/ +migrations/ +tests/ +client/ + +# Development configs +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# IDE files +.vscode/ +.idea/ +*.swp +*.swo + +# OS files +.DS_Store +Thumbs.db + +# Git +.git/ +.gitignore + +# Build files +*.log +temp/ +tmp/ + +# Test files +test-*.js +*test.js \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2e0446b --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.anchor +.DS_Store +target +**/*.rs.bk +node_modules +test-ledger +.yarn diff --git a/Anchor.toml b/Anchor.toml new file mode 100644 index 0000000..30961e4 --- /dev/null +++ b/Anchor.toml @@ -0,0 +1,25 @@ +[toolchain] +anchor_version = "0.31.0" + +[features] +seeds = false +skip-lint = false + +[programs.localnet] +lottery_simple = "CQKiz5PKgoQjxNDkGowPWWXu8MJCm2HgonfYAtcFZX87" + +[programs.devnet] +lottery_simple = "8hcuEUBcuVBYyD53QPFQrRSWJjQy3UVURiqJpcuvgrTf" + +[programs.mainnet] +lottery_simple = "CQKiz5PKgoQjxNDkGowPWWXu8MJCm2HgonfYAtcFZX87" + +[registry] +url = "https://api.apr.dev" + +[provider] +cluster = "Devnet" +wallet = "~/.config/solana/id.json" + +[scripts] +test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..3e20cab --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,2898 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm-siv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae0784134ba9375416d469ec31e7c5f9fa94405049cf08c5ce5b4698be673e0d" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "polyval", + "subtle", + "zeroize", +] + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anchor-attribute-access-control" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f70fd141a4d18adf11253026b32504f885447048c7494faf5fa83b01af9c0cf" +dependencies = [ + "anchor-syn", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-account" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "715a261c57c7679581e06f07a74fa2af874ac30f86bd8ea07cca4a7e5388a064" +dependencies = [ + "anchor-syn", + "bs58", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-constant" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "730d6df8ae120321c5c25e0779e61789e4b70dc8297102248902022f286102e4" +dependencies = [ + "anchor-syn", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-error" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27e6e449cc3a37b2880b74dcafb8e5a17b954c0e58e376432d7adc646fb333ef" +dependencies = [ + "anchor-syn", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-event" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7710e4c54adf485affcd9be9adec5ef8846d9c71d7f31e16ba86ff9fc1dd49f" +dependencies = [ + "anchor-syn", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-program" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ecfd49b2aeadeb32f35262230db402abed76ce87e27562b34f61318b2ec83c" +dependencies = [ + "anchor-lang-idl", + "anchor-syn", + "anyhow", + "bs58", + "heck", + "proc-macro2", + "quote", + "serde_json", + "syn 1.0.109", +] + +[[package]] +name = "anchor-derive-accounts" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be89d160793a88495af462a7010b3978e48e30a630c91de47ce2c1d3cb7a6149" +dependencies = [ + "anchor-syn", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-derive-serde" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abc6ee78acb7bfe0c2dd2abc677aaa4789c0281a0c0ef01dbf6fe85e0fd9e6e4" +dependencies = [ + "anchor-syn", + "borsh-derive-internal", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-derive-space" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134a01c0703f6fd355a0e472c033f6f3e41fac1ef6e370b20c50f4c8d022cea7" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-lang" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6bab117055905e930f762c196e08f861f8dfe7241b92cee46677a3b15561a0a" +dependencies = [ + "anchor-attribute-access-control", + "anchor-attribute-account", + "anchor-attribute-constant", + "anchor-attribute-error", + "anchor-attribute-event", + "anchor-attribute-program", + "anchor-derive-accounts", + "anchor-derive-serde", + "anchor-derive-space", + "anchor-lang-idl", + "base64 0.21.7", + "bincode", + "borsh 0.10.4", + "bytemuck", + "solana-program", + "thiserror 1.0.69", +] + +[[package]] +name = "anchor-lang-idl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e8599d21995f68e296265aa5ab0c3cef582fd58afec014d01bd0bce18a4418" +dependencies = [ + "anchor-lang-idl-spec", + "anyhow", + "heck", + "regex", + "serde", + "serde_json", + "sha2 0.10.9", +] + +[[package]] +name = "anchor-lang-idl-spec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bdf143115440fe621bdac3a29a1f7472e09f6cd82b2aa569429a0c13f103838" +dependencies = [ + "anyhow", + "serde", +] + +[[package]] +name = "anchor-spl" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c08cb5d762c0694f74bd02c9a5b04ea53cefc496e2c27b3234acffca5cd076b" +dependencies = [ + "anchor-lang", + "spl-associated-token-account", + "spl-pod", + "spl-token", + "spl-token-2022", + "spl-token-group-interface", + "spl-token-metadata-interface", +] + +[[package]] +name = "anchor-syn" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dc7a6d90cc643df0ed2744862cdf180587d1e5d28936538c18fc8908489ed67" +dependencies = [ + "anyhow", + "bs58", + "cargo_toml", + "heck", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2 0.10.9", + "syn 1.0.109", + "thiserror 1.0.69", +] + +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "2.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" + +[[package]] +name = "blake3" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "digest 0.10.7", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "borsh" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115e54d64eb62cdebad391c19efc9dce4981c690c85a33a12199d99bb9546fee" +dependencies = [ + "borsh-derive 0.10.4", + "hashbrown 0.13.2", +] + +[[package]] +name = "borsh" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" +dependencies = [ + "borsh-derive 1.5.7", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831213f80d9423998dd696e2c5345aba6be7a0bd8cd19e31c5243e13df1cef89" +dependencies = [ + "borsh-derive-internal", + "borsh-schema-derive-internal", + "proc-macro-crate 0.1.5", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3" +dependencies = [ + "once_cell", + "proc-macro-crate 3.4.0", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65d6ba50644c98714aa2a70d13d7df3cd75cd2b523a2b452bf010443800976b3" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276691d96f063427be83e6692b86148e488ebba9f48f77788724ca027ba3b6d4" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + +[[package]] +name = "bv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8834bb1d8ee5dc048ee3124f2c7c1afcc6bc9aed03f11e9dfd8c69470a5db340" +dependencies = [ + "feature-probe", + "serde", +] + +[[package]] +name = "bytemuck" +version = "1.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cargo_toml" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a98356df42a2eb1bd8f1793ae4ee4de48e384dd974ce5eac8eee802edb7492be" +dependencies = [ + "serde", + "toml 0.8.23", +] + +[[package]] +name = "cc" +version = "1.2.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d05d92f4b1fd76aad469d46cdd858ca761576082cd37df81416691e50199fb" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "console_log" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89f72f65e8501878b8a004d5a1afb780987e2ce2b4532c562e367a72c57499f" +dependencies = [ + "log", + "web-sys", +] + +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "typenum", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "rand_core 0.6.4", + "rustc_version", + "serde", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "derivation-path" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5c37193a1db1d8ed868c03ec7b152175f26160a5b740e5e484143877e0adf0" + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", + "subtle", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "feature-probe" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "find-msvc-tools" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0399f9d26e5191ce32c498bebd31e7a3ceabc2745f0ac54af3f335126c3f24b3" + +[[package]] +name = "five8" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75b8549488b4715defcb0d8a8a1c1c76a80661b5fa106b4ca0e7fce59d7d875" +dependencies = [ + "five8_core", +] + +[[package]] +name = "five8_const" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26dec3da8bc3ef08f2c04f61eab298c3ab334523e55f076354d6d6f613799a7b" +dependencies = [ + "five8_core", +] + +[[package]] +name = "five8_core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2551bf44bc5f776c15044b9b94153a00198be06743e262afaaa61f11ac7523a5" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "indexmap" +version = "2.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +dependencies = [ + "equivalent", + "hashbrown 0.16.0", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "js-sys" +version = "0.3.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.176" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" + +[[package]] +name = "libsecp256k1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9d220bc1feda2ac231cb78c3d26f27676b8cf82c96971f7aeef3d0cf2797c73" +dependencies = [ + "arrayref", + "base64 0.12.3", + "digest 0.9.0", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand 0.7.3", + "serde", + "sha2 0.9.9", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0f6ab710cec28cef759c5f18671a27dae2a5f952cdaaee1d8e2908cb2478a80" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.6.4", + "zeroize", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" +dependencies = [ + "proc-macro-crate 3.4.0", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "lottery-simple" +version = "0.1.0" +dependencies = [ + "anchor-lang", + "anchor-spl", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml 0.5.11", +] + +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit 0.23.6", +] + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "qstring" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "quote" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "solana-account" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f949fe4edaeaea78c844023bfc1c898e0b1f5a100f8a8d2d0f85d0a7b090258" +dependencies = [ + "solana-account-info", + "solana-clock", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", +] + +[[package]] +name = "solana-account-info" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8f5152a288ef1912300fc6efa6c2d1f9bb55d9398eb6c72326360b8063987da" +dependencies = [ + "bincode", + "serde", + "solana-program-error", + "solana-program-memory", + "solana-pubkey", +] + +[[package]] +name = "solana-address-lookup-table-interface" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1673f67efe870b64a65cb39e6194be5b26527691ce5922909939961a6e6b395" +dependencies = [ + "bincode", + "bytemuck", + "serde", + "serde_derive", + "solana-clock", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", + "solana-slot-hashes", +] + +[[package]] +name = "solana-atomic-u64" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52e52720efe60465b052b9e7445a01c17550666beec855cce66f44766697bc2" +dependencies = [ + "parking_lot", +] + +[[package]] +name = "solana-big-mod-exp" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75db7f2bbac3e62cfd139065d15bcda9e2428883ba61fc8d27ccb251081e7567" +dependencies = [ + "num-bigint", + "num-traits", + "solana-define-syscall", +] + +[[package]] +name = "solana-bincode" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19a3787b8cf9c9fe3dd360800e8b70982b9e5a8af9e11c354b6665dd4a003adc" +dependencies = [ + "bincode", + "serde", + "solana-instruction", +] + +[[package]] +name = "solana-blake3-hasher" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a0801e25a1b31a14494fc80882a036be0ffd290efc4c2d640bfcca120a4672" +dependencies = [ + "blake3", + "solana-define-syscall", + "solana-hash", + "solana-sanitize", +] + +[[package]] +name = "solana-borsh" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "718333bcd0a1a7aed6655aa66bef8d7fb047944922b2d3a18f49cbc13e73d004" +dependencies = [ + "borsh 0.10.4", + "borsh 1.5.7", +] + +[[package]] +name = "solana-clock" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bb482ab70fced82ad3d7d3d87be33d466a3498eb8aa856434ff3c0dfc2e2e31" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-cpi" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dc71126edddc2ba014622fc32d0f5e2e78ec6c5a1e0eb511b85618c09e9ea11" +dependencies = [ + "solana-account-info", + "solana-define-syscall", + "solana-instruction", + "solana-program-error", + "solana-pubkey", + "solana-stable-layout", +] + +[[package]] +name = "solana-curve25519" +version = "2.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa77936de1910002e7ad5817e38c3990402c2d8e92517cdd736df51485c76d88" +dependencies = [ + "bytemuck", + "bytemuck_derive", + "curve25519-dalek", + "solana-define-syscall", + "subtle", + "thiserror 2.0.17", +] + +[[package]] +name = "solana-decode-error" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c781686a18db2f942e70913f7ca15dc120ec38dcab42ff7557db2c70c625a35" +dependencies = [ + "num-traits", +] + +[[package]] +name = "solana-define-syscall" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ae3e2abcf541c8122eafe9a625d4d194b4023c20adde1e251f94e056bb1aee2" + +[[package]] +name = "solana-derivation-path" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "939756d798b25c5ec3cca10e06212bdca3b1443cb9bb740a38124f58b258737b" +dependencies = [ + "derivation-path", + "qstring", + "uriparse", +] + +[[package]] +name = "solana-epoch-rewards" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b575d3dd323b9ea10bb6fe89bf6bf93e249b215ba8ed7f68f1a3633f384db7" +dependencies = [ + "serde", + "serde_derive", + "solana-hash", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-epoch-schedule" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fce071fbddecc55d727b1d7ed16a629afe4f6e4c217bc8d00af3b785f6f67ed" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-example-mocks" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84461d56cbb8bb8d539347151e0525b53910102e4bced875d49d5139708e39d3" +dependencies = [ + "serde", + "serde_derive", + "solana-address-lookup-table-interface", + "solana-clock", + "solana-hash", + "solana-instruction", + "solana-keccak-hasher", + "solana-message", + "solana-nonce", + "solana-pubkey", + "solana-sdk-ids", + "solana-system-interface", + "thiserror 2.0.17", +] + +[[package]] +name = "solana-feature-gate-interface" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f5c5382b449e8e4e3016fb05e418c53d57782d8b5c30aa372fc265654b956d" +dependencies = [ + "bincode", + "serde", + "serde_derive", + "solana-account", + "solana-account-info", + "solana-instruction", + "solana-program-error", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", + "solana-system-interface", +] + +[[package]] +name = "solana-fee-calculator" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89bc408da0fb3812bc3008189d148b4d3e08252c79ad810b245482a3f70cd8d" +dependencies = [ + "log", + "serde", + "serde_derive", +] + +[[package]] +name = "solana-hash" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b96e9f0300fa287b545613f007dfe20043d7812bee255f418c1eb649c93b63" +dependencies = [ + "borsh 1.5.7", + "bytemuck", + "bytemuck_derive", + "five8", + "js-sys", + "serde", + "serde_derive", + "solana-atomic-u64", + "solana-sanitize", + "wasm-bindgen", +] + +[[package]] +name = "solana-instruction" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47298e2ce82876b64f71e9d13a46bc4b9056194e7f9937ad3084385befa50885" +dependencies = [ + "bincode", + "borsh 1.5.7", + "getrandom 0.2.16", + "js-sys", + "num-traits", + "serde", + "serde_derive", + "solana-define-syscall", + "solana-pubkey", + "wasm-bindgen", +] + +[[package]] +name = "solana-instructions-sysvar" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0e85a6fad5c2d0c4f5b91d34b8ca47118fc593af706e523cdbedf846a954f57" +dependencies = [ + "bitflags", + "solana-account-info", + "solana-instruction", + "solana-program-error", + "solana-pubkey", + "solana-sanitize", + "solana-sdk-ids", + "solana-serialize-utils", + "solana-sysvar-id", +] + +[[package]] +name = "solana-keccak-hasher" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7aeb957fbd42a451b99235df4942d96db7ef678e8d5061ef34c9b34cae12f79" +dependencies = [ + "sha3", + "solana-define-syscall", + "solana-hash", + "solana-sanitize", +] + +[[package]] +name = "solana-last-restart-slot" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a6360ac2fdc72e7463565cd256eedcf10d7ef0c28a1249d261ec168c1b55cdd" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-loader-v2-interface" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8ab08006dad78ae7cd30df8eea0539e207d08d91eaefb3e1d49a446e1c49654" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", +] + +[[package]] +name = "solana-loader-v3-interface" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f7162a05b8b0773156b443bccd674ea78bb9aa406325b467ea78c06c99a63a2" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", + "solana-system-interface", +] + +[[package]] +name = "solana-loader-v4-interface" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "706a777242f1f39a83e2a96a2a6cb034cb41169c6ecbee2cf09cb873d9659e7e" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", + "solana-system-interface", +] + +[[package]] +name = "solana-message" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1796aabce376ff74bf89b78d268fa5e683d7d7a96a0a4e4813ec34de49d5314b" +dependencies = [ + "bincode", + "blake3", + "lazy_static", + "serde", + "serde_derive", + "solana-bincode", + "solana-hash", + "solana-instruction", + "solana-pubkey", + "solana-sanitize", + "solana-sdk-ids", + "solana-short-vec", + "solana-system-interface", + "solana-transaction-error", + "wasm-bindgen", +] + +[[package]] +name = "solana-msg" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36a1a14399afaabc2781a1db09cb14ee4cc4ee5c7a5a3cfcc601811379a8092" +dependencies = [ + "solana-define-syscall", +] + +[[package]] +name = "solana-native-token" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61515b880c36974053dd499c0510066783f0cc6ac17def0c7ef2a244874cf4a9" + +[[package]] +name = "solana-nonce" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703e22eb185537e06204a5bd9d509b948f0066f2d1d814a6f475dafb3ddf1325" +dependencies = [ + "serde", + "serde_derive", + "solana-fee-calculator", + "solana-hash", + "solana-pubkey", + "solana-sha256-hasher", +] + +[[package]] +name = "solana-program" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98eca145bd3545e2fbb07166e895370576e47a00a7d824e325390d33bf467210" +dependencies = [ + "bincode", + "blake3", + "borsh 0.10.4", + "borsh 1.5.7", + "bs58", + "bytemuck", + "console_error_panic_hook", + "console_log", + "getrandom 0.2.16", + "lazy_static", + "log", + "memoffset", + "num-bigint", + "num-derive", + "num-traits", + "rand 0.8.5", + "serde", + "serde_bytes", + "serde_derive", + "solana-account-info", + "solana-address-lookup-table-interface", + "solana-atomic-u64", + "solana-big-mod-exp", + "solana-bincode", + "solana-blake3-hasher", + "solana-borsh", + "solana-clock", + "solana-cpi", + "solana-decode-error", + "solana-define-syscall", + "solana-epoch-rewards", + "solana-epoch-schedule", + "solana-example-mocks", + "solana-feature-gate-interface", + "solana-fee-calculator", + "solana-hash", + "solana-instruction", + "solana-instructions-sysvar", + "solana-keccak-hasher", + "solana-last-restart-slot", + "solana-loader-v2-interface", + "solana-loader-v3-interface", + "solana-loader-v4-interface", + "solana-message", + "solana-msg", + "solana-native-token", + "solana-nonce", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-program-option", + "solana-program-pack", + "solana-pubkey", + "solana-rent", + "solana-sanitize", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-secp256k1-recover", + "solana-serde-varint", + "solana-serialize-utils", + "solana-sha256-hasher", + "solana-short-vec", + "solana-slot-hashes", + "solana-slot-history", + "solana-stable-layout", + "solana-stake-interface", + "solana-system-interface", + "solana-sysvar", + "solana-sysvar-id", + "solana-vote-interface", + "thiserror 2.0.17", + "wasm-bindgen", +] + +[[package]] +name = "solana-program-entrypoint" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32ce041b1a0ed275290a5008ee1a4a6c48f5054c8a3d78d313c08958a06aedbd" +dependencies = [ + "solana-account-info", + "solana-msg", + "solana-program-error", + "solana-pubkey", +] + +[[package]] +name = "solana-program-error" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ee2e0217d642e2ea4bee237f37bd61bb02aec60da3647c48ff88f6556ade775" +dependencies = [ + "borsh 1.5.7", + "num-traits", + "serde", + "serde_derive", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-pubkey", +] + +[[package]] +name = "solana-program-memory" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a5426090c6f3fd6cfdc10685322fede9ca8e5af43cd6a59e98bfe4e91671712" +dependencies = [ + "solana-define-syscall", +] + +[[package]] +name = "solana-program-option" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc677a2e9bc616eda6dbdab834d463372b92848b2bfe4a1ed4e4b4adba3397d0" + +[[package]] +name = "solana-program-pack" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "319f0ef15e6e12dc37c597faccb7d62525a509fec5f6975ecb9419efddeb277b" +dependencies = [ + "solana-program-error", +] + +[[package]] +name = "solana-pubkey" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b62adb9c3261a052ca1f999398c388f1daf558a1b492f60a6d9e64857db4ff1" +dependencies = [ + "borsh 0.10.4", + "borsh 1.5.7", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek", + "five8", + "five8_const", + "getrandom 0.2.16", + "js-sys", + "num-traits", + "serde", + "serde_derive", + "solana-atomic-u64", + "solana-decode-error", + "solana-define-syscall", + "solana-sanitize", + "solana-sha256-hasher", + "wasm-bindgen", +] + +[[package]] +name = "solana-rent" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1aea8fdea9de98ca6e8c2da5827707fb3842833521b528a713810ca685d2480" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-sanitize" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61f1bc1357b8188d9c4a3af3fc55276e56987265eb7ad073ae6f8180ee54cecf" + +[[package]] +name = "solana-sdk-ids" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5d8b9cc68d5c88b062a33e23a6466722467dde0035152d8fb1afbcdf350a5f" +dependencies = [ + "solana-pubkey", +] + +[[package]] +name = "solana-sdk-macro" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86280da8b99d03560f6ab5aca9de2e38805681df34e0bb8f238e69b29433b9df" +dependencies = [ + "bs58", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "solana-secp256k1-recover" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baa3120b6cdaa270f39444f5093a90a7b03d296d362878f7a6991d6de3bbe496" +dependencies = [ + "libsecp256k1", + "solana-define-syscall", + "thiserror 2.0.17", +] + +[[package]] +name = "solana-security-txt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" + +[[package]] +name = "solana-seed-derivable" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beb82b5adb266c6ea90e5cf3967235644848eac476c5a1f2f9283a143b7c97f" +dependencies = [ + "solana-derivation-path", +] + +[[package]] +name = "solana-seed-phrase" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36187af2324f079f65a675ec22b31c24919cb4ac22c79472e85d819db9bbbc15" +dependencies = [ + "hmac", + "pbkdf2", + "sha2 0.10.9", +] + +[[package]] +name = "solana-serde-varint" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a7e155eba458ecfb0107b98236088c3764a09ddf0201ec29e52a0be40857113" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-serialize-utils" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "817a284b63197d2b27afdba829c5ab34231da4a9b4e763466a003c40ca4f535e" +dependencies = [ + "solana-instruction", + "solana-pubkey", + "solana-sanitize", +] + +[[package]] +name = "solana-sha256-hasher" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa3feb32c28765f6aa1ce8f3feac30936f16c5c3f7eb73d63a5b8f6f8ecdc44" +dependencies = [ + "sha2 0.10.9", + "solana-define-syscall", + "solana-hash", +] + +[[package]] +name = "solana-short-vec" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c54c66f19b9766a56fa0057d060de8378676cb64987533fa088861858fc5a69" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-signature" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64c8ec8e657aecfc187522fc67495142c12f35e55ddeca8698edbb738b8dbd8c" +dependencies = [ + "five8", + "solana-sanitize", +] + +[[package]] +name = "solana-signer" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c41991508a4b02f021c1342ba00bcfa098630b213726ceadc7cb032e051975b" +dependencies = [ + "solana-pubkey", + "solana-signature", + "solana-transaction-error", +] + +[[package]] +name = "solana-slot-hashes" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c8691982114513763e88d04094c9caa0376b867a29577939011331134c301ce" +dependencies = [ + "serde", + "serde_derive", + "solana-hash", + "solana-sdk-ids", + "solana-sysvar-id", +] + +[[package]] +name = "solana-slot-history" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97ccc1b2067ca22754d5283afb2b0126d61eae734fc616d23871b0943b0d935e" +dependencies = [ + "bv", + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sysvar-id", +] + +[[package]] +name = "solana-stable-layout" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f14f7d02af8f2bc1b5efeeae71bc1c2b7f0f65cd75bcc7d8180f2c762a57f54" +dependencies = [ + "solana-instruction", + "solana-pubkey", +] + +[[package]] +name = "solana-stake-interface" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5269e89fde216b4d7e1d1739cf5303f8398a1ff372a81232abbee80e554a838c" +dependencies = [ + "borsh 0.10.4", + "borsh 1.5.7", + "num-traits", + "serde", + "serde_derive", + "solana-clock", + "solana-cpi", + "solana-decode-error", + "solana-instruction", + "solana-program-error", + "solana-pubkey", + "solana-system-interface", + "solana-sysvar-id", +] + +[[package]] +name = "solana-system-interface" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94d7c18cb1a91c6be5f5a8ac9276a1d7c737e39a21beba9ea710ab4b9c63bc90" +dependencies = [ + "js-sys", + "num-traits", + "serde", + "serde_derive", + "solana-decode-error", + "solana-instruction", + "solana-pubkey", + "wasm-bindgen", +] + +[[package]] +name = "solana-sysvar" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8c3595f95069f3d90f275bb9bd235a1973c4d059028b0a7f81baca2703815db" +dependencies = [ + "base64 0.22.1", + "bincode", + "bytemuck", + "bytemuck_derive", + "lazy_static", + "serde", + "serde_derive", + "solana-account-info", + "solana-clock", + "solana-define-syscall", + "solana-epoch-rewards", + "solana-epoch-schedule", + "solana-fee-calculator", + "solana-hash", + "solana-instruction", + "solana-instructions-sysvar", + "solana-last-restart-slot", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-pubkey", + "solana-rent", + "solana-sanitize", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-slot-hashes", + "solana-slot-history", + "solana-stake-interface", + "solana-sysvar-id", +] + +[[package]] +name = "solana-sysvar-id" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5762b273d3325b047cfda250787f8d796d781746860d5d0a746ee29f3e8812c1" +dependencies = [ + "solana-pubkey", + "solana-sdk-ids", +] + +[[package]] +name = "solana-transaction-error" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222a9dc8fdb61c6088baab34fc3a8b8473a03a7a5fd404ed8dd502fa79b67cb1" +dependencies = [ + "solana-instruction", + "solana-sanitize", +] + +[[package]] +name = "solana-vote-interface" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b80d57478d6599d30acc31cc5ae7f93ec2361a06aefe8ea79bc81739a08af4c3" +dependencies = [ + "bincode", + "num-derive", + "num-traits", + "serde", + "serde_derive", + "solana-clock", + "solana-decode-error", + "solana-hash", + "solana-instruction", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", + "solana-serde-varint", + "solana-serialize-utils", + "solana-short-vec", + "solana-system-interface", +] + +[[package]] +name = "solana-zk-sdk" +version = "2.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffc4ca8e3e26a8f80eb0026adf8af1732863f42739cd2201c40c568ccae360c" +dependencies = [ + "aes-gcm-siv", + "base64 0.22.1", + "bincode", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek", + "itertools", + "js-sys", + "merlin", + "num-derive", + "num-traits", + "rand 0.8.5", + "serde", + "serde_derive", + "serde_json", + "sha3", + "solana-derivation-path", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", + "solana-seed-derivable", + "solana-seed-phrase", + "solana-signature", + "solana-signer", + "subtle", + "thiserror 2.0.17", + "wasm-bindgen", + "zeroize", +] + +[[package]] +name = "spl-associated-token-account" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76fee7d65013667032d499adc3c895e286197a35a0d3a4643c80e7fd3e9969e3" +dependencies = [ + "borsh 1.5.7", + "num-derive", + "num-traits", + "solana-program", + "spl-associated-token-account-client", + "spl-token", + "spl-token-2022", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-associated-token-account-client" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f8349dbcbe575f354f9a533a21f272f3eb3808a49e2fdc1c34393b88ba76cb" +dependencies = [ + "solana-instruction", + "solana-pubkey", +] + +[[package]] +name = "spl-discriminator" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7398da23554a31660f17718164e31d31900956054f54f52d5ec1be51cb4f4b3" +dependencies = [ + "bytemuck", + "solana-program-error", + "solana-sha256-hasher", + "spl-discriminator-derive", +] + +[[package]] +name = "spl-discriminator-derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9e8418ea6269dcfb01c712f0444d2c75542c04448b480e87de59d2865edc750" +dependencies = [ + "quote", + "spl-discriminator-syn", + "syn 2.0.106", +] + +[[package]] +name = "spl-discriminator-syn" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d1dbc82ab91422345b6df40a79e2b78c7bce1ebb366da323572dd60b7076b67" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.9", + "syn 2.0.106", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-elgamal-registry" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce0f668975d2b0536e8a8fd60e56a05c467f06021dae037f1d0cfed0de2e231d" +dependencies = [ + "bytemuck", + "solana-program", + "solana-zk-sdk", + "spl-pod", + "spl-token-confidential-transfer-proof-extraction", +] + +[[package]] +name = "spl-memo" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f09647c0974e33366efeb83b8e2daebb329f0420149e74d3a4bd2c08cf9f7cb" +dependencies = [ + "solana-account-info", + "solana-instruction", + "solana-msg", + "solana-program-entrypoint", + "solana-program-error", + "solana-pubkey", +] + +[[package]] +name = "spl-pod" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d994afaf86b779104b4a95ba9ca75b8ced3fdb17ee934e38cb69e72afbe17799" +dependencies = [ + "borsh 1.5.7", + "bytemuck", + "bytemuck_derive", + "num-derive", + "num-traits", + "solana-decode-error", + "solana-msg", + "solana-program-error", + "solana-program-option", + "solana-pubkey", + "solana-zk-sdk", + "thiserror 2.0.17", +] + +[[package]] +name = "spl-program-error" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d39b5186f42b2b50168029d81e58e800b690877ef0b30580d107659250da1d1" +dependencies = [ + "num-derive", + "num-traits", + "solana-program", + "spl-program-error-derive", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-program-error-derive" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d375dd76c517836353e093c2dbb490938ff72821ab568b545fd30ab3256b3e" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.9", + "syn 2.0.106", +] + +[[package]] +name = "spl-tlv-account-resolution" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd99ff1e9ed2ab86e3fd582850d47a739fec1be9f4661cba1782d3a0f26805f3" +dependencies = [ + "bytemuck", + "num-derive", + "num-traits", + "solana-account-info", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator", + "spl-pod", + "spl-program-error", + "spl-type-length-value", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-token" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed320a6c934128d4f7e54fe00e16b8aeaecf215799d060ae14f93378da6dc834" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "num_enum", + "solana-program", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-token-2022" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b27f7405010ef816587c944536b0eafbcc35206ab6ba0f2ca79f1d28e488f4f" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "num_enum", + "solana-program", + "solana-security-txt", + "solana-zk-sdk", + "spl-elgamal-registry", + "spl-memo", + "spl-pod", + "spl-token", + "spl-token-confidential-transfer-ciphertext-arithmetic", + "spl-token-confidential-transfer-proof-extraction", + "spl-token-confidential-transfer-proof-generation", + "spl-token-group-interface", + "spl-token-metadata-interface", + "spl-transfer-hook-interface", + "spl-type-length-value", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-token-confidential-transfer-ciphertext-arithmetic" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "170378693c5516090f6d37ae9bad2b9b6125069be68d9acd4865bbe9fc8499fd" +dependencies = [ + "base64 0.22.1", + "bytemuck", + "solana-curve25519", + "solana-zk-sdk", +] + +[[package]] +name = "spl-token-confidential-transfer-proof-extraction" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff2d6a445a147c9d6dd77b8301b1e116c8299601794b558eafa409b342faf96" +dependencies = [ + "bytemuck", + "solana-curve25519", + "solana-program", + "solana-zk-sdk", + "spl-pod", + "thiserror 2.0.17", +] + +[[package]] +name = "spl-token-confidential-transfer-proof-generation" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8627184782eec1894de8ea26129c61303f1f0adeed65c20e0b10bc584f09356d" +dependencies = [ + "curve25519-dalek", + "solana-zk-sdk", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-token-group-interface" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d595667ed72dbfed8c251708f406d7c2814a3fa6879893b323d56a10bedfc799" +dependencies = [ + "bytemuck", + "num-derive", + "num-traits", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator", + "spl-pod", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-token-metadata-interface" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfb9c89dbc877abd735f05547dcf9e6e12c00c11d6d74d8817506cab4c99fdbb" +dependencies = [ + "borsh 1.5.7", + "num-derive", + "num-traits", + "solana-borsh", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator", + "spl-pod", + "spl-type-length-value", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-transfer-hook-interface" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aa7503d52107c33c88e845e1351565050362c2314036ddf19a36cd25137c043" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "solana-account-info", + "solana-cpi", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator", + "spl-pod", + "spl-program-error", + "spl-tlv-account-resolution", + "spl-type-length-value", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-type-length-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba70ef09b13af616a4c987797870122863cba03acc4284f226a4473b043923f9" +dependencies = [ + "bytemuck", + "num-derive", + "num-traits", + "solana-account-info", + "solana-decode-error", + "solana-msg", + "solana-program-error", + "spl-discriminator", + "spl-pod", + "thiserror 1.0.69", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl 2.0.17", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "tinyvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime 0.6.11", + "toml_write", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.23.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3effe7c0e86fdff4f69cdd2ccc1b96f933e24811c5441d44904e8683e27184b" +dependencies = [ + "indexmap", + "toml_datetime 0.7.2", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "uriparse" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0200d0fc04d809396c2ad43f3c95da3582a2556eba8d453c1087f4120ee352ff" +dependencies = [ + "fnv", + "lazy_static", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn 2.0.106", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + +[[package]] +name = "winnow" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +dependencies = [ + "memchr", +] + +[[package]] +name = "zerocopy" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..0da7e2c --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,15 @@ +[workspace] +members = [ + "programs/*" +] +resolver = "2" + +[profile.release] +overflow-checks = true +lto = "fat" +codegen-units = 1 + +[profile.release.build-override] +opt-level = 3 +incremental = false +codegen-units = 1 \ No newline at end of file diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md new file mode 100644 index 0000000..1c8618d --- /dev/null +++ b/DEPLOYMENT.md @@ -0,0 +1,85 @@ +# Lottery Simple DApp - Deployment Guide + +## Quick Deployment + +### Local Testing +```bash +# Build and run with Docker +./deploy.sh + +# Or manually: +docker-compose up --build -d + +# Access at: http://localhost:14888 +``` + +### Remote Server Deployment + +1. **Sync files to server:** + ```bash + # Only sync the necessary frontend files + rsync -av --exclude='.git' --exclude='node_modules' --exclude='target' \ + --exclude='programs' --exclude='client' --exclude='tests' \ + /home/crappy/lottery/lottery-simple/ user@your-server:/opt/lottery-simple/ + ``` + +2. **On the remote server:** + ```bash + cd /opt/lottery-simple + ./deploy.sh + ``` + +3. **Nginx reverse proxy (optional):** + ```nginx + location /lottery/ { + proxy_pass http://localhost:14888/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } + ``` + +## Configuration + +### Environment Variables +- Edit `config.json` for different environments +- Update `programId`, `mint`, and `devWallet` as needed + +### Port Configuration +- Default: `14888` (configured in docker-compose.yml) +- Health check: `/health` + +## File Structure (Clean) +``` +lottery-simple/ +โ”œโ”€โ”€ index.html # Frontend HTML +โ”œโ”€โ”€ styles.css # CSS styles +โ”œโ”€โ”€ app.js # Frontend JavaScript +โ”œโ”€โ”€ config.json # Configuration +โ”œโ”€โ”€ Dockerfile # Docker build +โ”œโ”€โ”€ docker-compose.yml # Docker orchestration +โ”œโ”€โ”€ nginx.conf # Web server config +โ”œโ”€โ”€ deploy.sh # Deployment script +โ””โ”€โ”€ .dockerignore # Build exclusions +``` + +## Troubleshooting + +### Check container status: +```bash +docker-compose ps +docker-compose logs +``` + +### Manual container management: +```bash +docker-compose stop +docker-compose start +docker-compose restart +``` + +### Clean rebuild: +```bash +docker-compose down +docker-compose build --no-cache +docker-compose up -d +``` \ No newline at end of file diff --git a/DEVNET-STATUS.md b/DEVNET-STATUS.md new file mode 100644 index 0000000..db4d325 --- /dev/null +++ b/DEVNET-STATUS.md @@ -0,0 +1,101 @@ +# ๐Ÿงช Devnet Deployment Status + +## โœ… Successfully Completed + +### 1. Program Deployment +- **Program ID**: `8hcuEUBcuVBYyD53QPFQrRSWJjQy3UVURiqJpcuvgrTf` +- **Status**: โœ… Successfully deployed to Devnet +- **IDL**: โœ… Successfully created and uploaded +- **Cluster**: Devnet (safe testing environment) + +### 2. Token Mint +- **Mint Address**: `GrCHRSRHdZtiz2fiv1iUgigXCfB5Ta3j8gXepZUUTPP2` +- **Status**: โœ… Created and ready for use +- **Decimals**: 9 (standard SPL token format) + +### 3. Program Features +- โœ… Working Anchor v0.31.0 program +- โœ… All previous fixes implemented: + - Direct lamport manipulation for vault transfers + - Realistic bonding curve math (price increases with supply) + - Dividend distribution system + - Dev fee collection (3%) + - Proper rent exemption handling + - Buy/sell functionality with safety checks + +### 4. Configuration +- โœ… `devnet-config.json` contains all deployment details +- โœ… Program ID matches deployed program +- โœ… Ready for frontend integration + +## ๐Ÿš€ Next Steps + +### Option 1: Test with Browser Interface +1. Open `test-program.html` in your browser +2. Connect Phantom wallet (set to Devnet) +3. Initialize the program +4. Test buy/sell functionality + +### Option 2: Update Your Frontend +1. Update your frontend's config to use `devnet-config.json` +2. Test all functionality with devnet SOL (free!) +3. Verify buy/sell transactions work correctly +4. Test dividend withdrawal + +### Option 3: CLI Testing (if needed) +```bash +# Check program account +solana account 8hcuEUBcuVBYyD53QPFQrRSWJjQy3UVURiqJpcuvgrTf --url devnet + +# Check state PDA (after initialization) +solana account [STATE_PDA] --url devnet + +# Check vault PDA balance +solana account [VAULT_PDA] --url devnet +``` + +## ๐Ÿ“‹ Configuration Details + +```json +{ + "programId": "8hcuEUBcuVBYyD53QPFQrRSWJjQy3UVURiqJpcuvgrTf", + "mintAddress": "GrCHRSRHdZtiz2fiv1iUgigXCfB5Ta3j8gXepZUUTPP2", + "devWallet": "GPFYcM3svcM4Srko6ExLYeSW4Gjwf6XoV4k1eSXoGHoK", + "cluster": "devnet", + "rpcUrl": "https://api.devnet.solana.com" +} +``` + +## โš ๏ธ Important Notes + +1. **This is DEVNET** - No real money is involved +2. **Test thoroughly** before considering mainnet deployment +3. **Devnet SOL is free** - get more from faucets if needed +4. **Program must be initialized** before trading can begin + +## ๐ŸŽฏ Testing Checklist + +Before moving to mainnet, verify: + +- [ ] Program initializes successfully +- [ ] Buy transactions work correctly +- [ ] Sell transactions work correctly +- [ ] Dev fees are collected properly +- [ ] Dividend distribution works +- [ ] Vault PDA maintains proper balance +- [ ] Frontend UI functions correctly +- [ ] Error handling works as expected + +## ๐Ÿšจ Mainnet Deployment + +**Only proceed to mainnet AFTER:** +1. All devnet testing is complete +2. All functionality verified working +3. UI/UX is polished and tested +4. You're confident in the system + +The same program code will work on mainnet - just need to change the cluster configuration and deploy with real SOL. + +--- + +**Current Status**: โœ… DEVNET DEPLOYMENT COMPLETE - READY FOR TESTING \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d008203 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,38 @@ +FROM php:8.1-fpm-alpine + +# Install nginx +RUN apk add --no-cache nginx supervisor + +# Copy site files +COPY index.html /var/www/html/ +COPY styles.css /var/www/html/ +COPY app.js /var/www/html/ +COPY config.json /var/www/html/ +COPY ticker-api.php /var/www/html/ +COPY ticker-data.json /var/www/html/ + +# Copy favicon files +COPY favicon.ico /var/www/html/ +COPY favicon.svg /var/www/html/ +COPY favicon-16.png /var/www/html/ +COPY favicon-32.png /var/www/html/ +COPY apple-touch-icon.png /var/www/html/ + +# Copy nginx config +COPY nginx.conf /etc/nginx/http.d/default.conf + +# Create basic robots.txt and sitemap.xml +RUN echo -e "User-agent: *\nAllow: /\n\nSitemap: /sitemap.xml" > /var/www/html/robots.txt && \ + echo -e '\n\n \n https://your-domain.com/\n 2025-10-06\n weekly\n 0.8\n \n' > /var/www/html/sitemap.xml + +# Set permissions +RUN chown -R www-data:www-data /var/www/html && \ + chmod -R 644 /var/www/html/* && \ + chmod 755 /var/www/html/ && \ + chmod 666 /var/www/html/ticker-data.json + +# Create supervisor config +RUN echo -e '[supervisord]\nnodaemon=true\n\n[program:php-fpm]\ncommand=php-fpm\nautostart=true\nautorestart=true\n\n[program:nginx]\ncommand=nginx -g "daemon off;"\nautostart=true\nautorestart=true' > /etc/supervisord.conf + +EXPOSE 80 +CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"] diff --git a/app.js b/app.js new file mode 100644 index 0000000..66f891e --- /dev/null +++ b/app.js @@ -0,0 +1,838 @@ +/* global solanaWeb3 */ +(() => { + const { Connection, PublicKey, SystemProgram, Transaction, TransactionInstruction } = solanaWeb3; + + // DOM helpers + const $ = (id) => document.getElementById(id); + const DEBUG = new URLSearchParams(location.search).has('debug'); +const log = (m, cls='') => { + if (cls === 'err') console.error(m); + else if (cls === 'warn') console.warn(m); + if (DEBUG) console.debug(m); +}; + + // SNS (Solana Name Service) resolution + const snsCache = new Map(); + const NAME_PROGRAM_ID = new PublicKey('namesLPneVptA9Z5rqUDD9tMTWEJwofgaYwp8cawRkX'); + + async function findOwnedNameAccountsForUser(connection, userAccount) { + try { + const filters = [ + { + memcmp: { + offset: 32, + bytes: userAccount.toBase58(), + }, + }, + ]; + const accounts = await connection.getProgramAccounts(NAME_PROGRAM_ID, { + filters, + }); + return accounts.map((a) => a.publicKey); + } catch (e) { + return []; + } + } + + async function resolveSNSAddress(address) { + try { + if (snsCache.has(address)) { + return snsCache.get(address); + } + + const { cluster } = getCfg(); + const conn = new Connection(cluster, 'confirmed'); + const publicKey = new PublicKey(address); + + // Find owned name accounts + const nameAccounts = await findOwnedNameAccountsForUser(conn, publicKey); + + if (nameAccounts.length > 0) { + // Get the first domain name account data + const accountInfo = await conn.getAccountInfo(nameAccounts[0]); + if (accountInfo && accountInfo.data) { + // Parse the domain name from account data + // SNS account structure: [96 bytes header] + [4 bytes name length] + [name data] + const data = accountInfo.data; + if (data.length > 100) { + const nameLength = data.readUInt32LE(96); + if (nameLength > 0 && nameLength < 64) { + const domainBytes = data.slice(100, 100 + nameLength); + const domain = new TextDecoder().decode(domainBytes); + if (domain && domain.includes('.')) { + snsCache.set(address, domain); + return domain; + } + } + } + } + } + + // If no SNS name found, cache the negative result + snsCache.set(address, null); + return null; + + } catch (e) { + // Silently fail and return null + snsCache.set(address, null); + return null; + } + } + + async function formatAddressWithSNS(address) { + const snsName = await resolveSNSAddress(address); + if (snsName) { + return snsName; + } + return `${address.slice(0,4)}โ€ฆ${address.slice(-4)}`; + } + + // Providers + function standardToLegacyProvider(stdWallet) { + const features = stdWallet?.features || {}; + const connectFeature = features['standard:connect']; + const eventsFeature = features['standard:events']; + const disconnectFeature = features['standard:disconnect']; + const signTxFeature = features['solana:signTransactions']; + const signAndSendFeature = features['solana:signAndSendTransaction']; + const signMsgFeature = features['solana:signMessage']; + + let currentAccount = null; + const listeners = { connect: [], disconnect: [] }; + const emit = (evt, ...args) => (listeners[evt] || []).forEach((fn) => { + try { fn(...args); } catch {} + }); + + // Forward standard events into legacy-style events + if (eventsFeature?.on) { + try { + eventsFeature.on('change', ({ accounts }) => { + if (accounts && accounts[0]) { + currentAccount = accounts[0]; + provider.publicKey = { + toString: () => accounts[0].address, + toBase58: () => accounts[0].address + }; + emit('connect'); + } else { + currentAccount = null; + provider.publicKey = null; + emit('disconnect'); + } + }); + } catch {} + } + + const provider = { + isStandard: true, + publicKey: null, + on: (evt, fn) => { + if (!listeners[evt]) listeners[evt] = []; + listeners[evt].push(fn); + }, + off: (evt, fn) => { + listeners[evt] = (listeners[evt] || []).filter((f) => f !== fn); + }, + connect: async () => { + if (!connectFeature?.connect) throw new Error('Wallet Standard connect not available'); + const { accounts } = await connectFeature.connect(); + if (!accounts?.length) throw new Error('No account returned'); + currentAccount = accounts[0]; + provider.publicKey = { + toString: () => accounts[0].address, + toBase58: () => accounts[0].address + }; + emit('connect'); + return { publicKey: provider.publicKey }; + }, + disconnect: async () => { + try { + if (disconnectFeature?.disconnect) await disconnectFeature.disconnect(); + } finally { + currentAccount = null; + provider.publicKey = null; + emit('disconnect'); + } + }, + signTransaction: async (tx) => { + if (signTxFeature?.signTransactions) { + const signed = await signTxFeature.signTransactions({ transactions: [tx] }); + // Some implementations return { signedTransactions }, others return array directly + const arr = Array.isArray(signed) ? signed : (signed?.signedTransactions || []); + if (!arr[0]) throw new Error('signTransactions returned no result'); + return arr[0]; + } + throw new Error('Wallet Standard wallet does not support signTransactions'); + }, + _standard: { + signTransactions: signTxFeature?.signTransactions, + signAndSendTransaction: signAndSendFeature?.signAndSendTransaction, + signMessage: signMsgFeature?.signMessage + } + }; + + return provider; + } + + function detectProviders() { + const map = new Map(); + const add = (id, name, provider) => { if (provider && !map.has(id)) map.set(id, { id, name, provider }); }; + // Injected + add('phantom','Phantom', window.solana?.isPhantom ? window.solana : null); + add('solflare','Solflare', window.solflare?.isSolflare ? window.solflare : null); + add('backpack','Backpack', window.backpack?.isBackpack ? window.backpack : null); + add('glow','Glow', window.glow?.solana || null); + add('exodus','Exodus', window.exodus?.solana || null); + // Wallet Standard (if present) + try { + const std = window.navigator?.wallets?.get?.(); + if (Array.isArray(std)) { + for (const w of std) { + const id = w.name?.toLowerCase?.().replace(/\s+/g,'-') || 'standard'; + add(id, w.name || id, standardToLegacyProvider(w)); + } + } + } catch {} + return Array.from(map.values()); + } + + function populateWalletSelect(){ + const select = $('walletSelect'); if(!select) return; + const detected = detectProviders(); + // Keep first option as Auto-detect, remove the rest, then append detected + select.innerHTML = '' + detected.map(d=>``).join(''); + // If none detected, keep auto only + } + + // Centralized ticker functions + async function loadTickerFromServer() { + try { + const response = await fetch('ticker-api.php', { + method: 'GET', + cache: 'no-cache' + }); + if (!response.ok) return; + const tickerData = await response.json(); + + const track = document.getElementById('ticker'); + if (!track) return; + + // Clear existing ticker items + track.innerHTML = ''; + + // Add items from server (reverse order since server stores newest first) + for (const item of tickerData.reverse()) { + const span = document.createElement('span'); + span.className = 'ticker-item ' + (item.type || ''); + + // Try to resolve SNS names in existing ticker text + let displayText = item.text; + if (item.snsName) { + // If SNS name is already stored, use it + displayText = displayText.replace(/[A-Za-z0-9]{4}โ€ฆ[A-Za-z0-9]{4}/, item.snsName); + } else { + // Try to extract address and resolve SNS + const addressMatch = displayText.match(/([A-Za-z0-9]{4})โ€ฆ([A-Za-z0-9]{4})/); + if (addressMatch && item.fullAddress) { + const snsName = await resolveSNSAddress(item.fullAddress); + if (snsName) { + displayText = displayText.replace(addressMatch[0], snsName); + } + } + } + + span.textContent = displayText; + track.appendChild(span); + } + } catch (e) { + log('Failed to load ticker data from server', 'warn'); + } + } + + async function saveTickerToServer(text, type, fullAddress = null, snsName = null) { + try { + const payload = { text, type }; + if (fullAddress) payload.fullAddress = fullAddress; + if (snsName) payload.snsName = snsName; + + await fetch('ticker-api.php', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(payload) + }); + } catch (e) { + log('Failed to save ticker item to server', 'warn'); + } + } + + async function pushTickerItem(text, cls, address = null) { + const track = document.getElementById('ticker'); + if (!track) return; + + let displayText = text; + let snsName = null; + + // Try to resolve SNS name if address is provided + if (address) { + snsName = await resolveSNSAddress(address); + if (snsName) { + displayText = text.replace(/[A-Za-z0-9]{4}โ€ฆ[A-Za-z0-9]{4}/, snsName); + } + } + + // Add to local DOM immediately for responsiveness + const span = document.createElement('span'); + span.className = 'ticker-item ' + (cls || ''); + span.textContent = displayText; + track.appendChild(span); + + // Limit items to prevent DOM bloat (keep more than server since DOM updates faster) + while (track.childNodes.length > 50) { + track.removeChild(track.firstChild); + } + + // Save to server for other users + saveTickerToServer(displayText, cls || '', address, snsName); + } + + // Updated discriminator functions for our new program + async function getDiscriminators(){ + const buyTokens = await anchorDisc('buy_tokens'); + const sellTokens = await anchorDisc('sell_tokens'); + return { buy: buyTokens, sell: sellTokens }; + } + + function b64ToBytes(b64){ const bin = atob(b64); const arr = new Uint8Array(bin.length); for(let i=0;ibuf.length) return false; for(let i=0;ik.toString()); + const feePayer = keys[0] || ''; + const ixList = msg.instructions || msg.compiledInstructions || []; + for(const ix of ixList){ + const progIdx = ix.programIdIndex ?? undefined; + const prog = progIdx !== undefined ? keys[progIdx] : ix.programId?.toString(); + if(prog !== programId.toString()) continue; + const dataB64 = ix.data || ''; + const data = typeof dataB64 === 'string' ? b64ToBytes(dataB64) : new Uint8Array(); + if(startsWith(data, discs.buy)){ + const lamports = Number(readLeU64(data, 8)); + const sol = lamports / 1_000_000_000; + await pushTickerItem(`BUY ${sol.toFixed(3)} SOL โ€ข ${feePayer.slice(0,4)}โ€ฆ${feePayer.slice(-4)}`, 'buy', feePayer); + } else if(startsWith(data, discs.sell)){ + const tokensRaw = Number(readLeU64(data, 8)); + const t = tokensRaw / 1_000_000_000; + await pushTickerItem(`SELL ${t.toFixed(3)} tk โ€ข ${feePayer.slice(0,4)}โ€ฆ${feePayer.slice(-4)}`, 'sell', feePayer); + } + } + } + }catch(e){ /*silent*/ } + } + + function pickProvider() { + const sel = $('walletSelect').value; + const detected = detectProviders(); + if (sel !== 'auto') return detected.find(p => p.id === sel)?.provider; + return detected[0]?.provider; + } + + // Buffer helpers + function le64(n) { const b=new ArrayBuffer(8); new DataView(b).setBigUint64(0, BigInt(n), true); return new Uint8Array(b); } + async function anchorDisc(name){ const data=new TextEncoder().encode(`global:${name}`); const h=await crypto.subtle.digest('SHA-256', data); return new Uint8Array(h).slice(0,8); } + async function buildIx(name, args){ const disc=await anchorDisc(name); const out=new Uint8Array(disc.length+args.length); out.set(disc,0); out.set(args,disc.length); return out; } + + // ATAs + const TOKEN_PROGRAM_ID = new PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'); + const ATA_PROGRAM_ID = new PublicKey('ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL'); + async function findAta(mint, owner){ + const [addr] = await PublicKey.findProgramAddress([ + owner.toBuffer(), TOKEN_PROGRAM_ID.toBuffer(), mint.toBuffer() + ], ATA_PROGRAM_ID); + return addr; + } + function createAtaIx(payer, ata, owner, mint){ + const keys=[ + { pubkey:payer, isSigner:true, isWritable:true }, + { pubkey:ata, isSigner:false, isWritable:true }, + { pubkey:owner, isSigner:false, isWritable:false }, + { pubkey:mint, isSigner:false, isWritable:false }, + { pubkey:SystemProgram.programId, isSigner:false, isWritable:false }, + { pubkey:TOKEN_PROGRAM_ID, isSigner:false, isWritable:false }, + { pubkey:solanaWeb3.SYSVAR_RENT_PUBKEY, isSigner:false, isWritable:false }, + ]; + return new TransactionInstruction({ keys, programId: ATA_PROGRAM_ID, data: new Uint8Array([]) }); + } + + // Config via hidden meta tag + function getCfg(){ + const meta = document.getElementById('app-config'); + const cluster = meta?.dataset.cluster || 'https://api.devnet.solana.com'; + const programIdStr = meta?.dataset.programId || ''; + const mintStr = meta?.dataset.mint || ''; + const devWalletStr = meta?.dataset.devWallet || ''; + const programId = programIdStr ? new PublicKey(programIdStr) : null; + const mint = mintStr ? new PublicKey(mintStr) : null; + const devWallet = devWalletStr ? new PublicKey(devWalletStr) : null; + return { programId, mint, cluster, devWallet }; + } + + async function applyConfig(){ + try{ + const res = await fetch('config.json', { cache:'no-store' }); + if(!res.ok) return; + const cfg = await res.json(); + const meta = document.getElementById('app-config'); if(!meta) return; + if(cfg.cluster) meta.dataset.cluster = cfg.cluster; + if(cfg.programId) meta.dataset.programId = cfg.programId; + if(cfg.mint) meta.dataset.mint = cfg.mint; + if(cfg.devWallet) meta.dataset.devWallet = cfg.devWallet; + }catch(e){ /*silent*/ } + } + + let pendingReferrer = ''; + async function readRefFromUrl(){ + const params = new URLSearchParams(location.search); + const ref = params.get('ref'); + if(ref){ + const el = $('referrer'); + if (el) el.value = ref; else pendingReferrer = ref; + } + } + + let walletProvider = null; let walletPubkey = null; + function shortAddr(pk){ const s=pk.toBase58(); return s.slice(0,4)+'โ€ฆ'+s.slice(-4); } + + function updateUIDisconnected(){ + walletPubkey = null; + const chip = $('walletChip'); if(chip){ chip.textContent = 'Not connected'; chip.style.display='none'; } + const wa = $('walletAddr'); if(wa) wa.value = ''; + const ref = $('reflinkRow'); if(ref) ref.style.display = 'none'; + const ap = $('actionsPanel'); if(ap) ap.style.display = 'none'; + const d = $('disconnectBtn'); if(d) d.style.display = 'none'; + const c = $('connectBtn'); if(c) c.style.display = ''; + const st = $('statusValue'); if(st) st.value = 'Connect wallet to participate'; + } + + function updateUIConnected(){ + if(!walletPubkey) return; + const chip = $('walletChip'); if(chip){ chip.textContent = shortAddr(walletPubkey); chip.style.display=''; } + const ref = $('reflinkRow'); if(ref) ref.style.display = ''; + const ap = $('actionsPanel'); if(ap) ap.style.display = ''; + const d = $('disconnectBtn'); if(d) d.style.display = ''; + const c = $('connectBtn'); if(c) c.style.display = 'none'; + const st = $('statusValue'); if(st) st.value = 'Ready'; + } + + async function disconnectWallet(){ + try{ + if(walletProvider && typeof walletProvider.disconnect === 'function'){ + try { await walletProvider.disconnect(); } catch { /* some wallets throw if not connected */ } + } + } finally { + walletProvider = null; + updateUIDisconnected(); + } + } + + async function connectWallet(){ + try{ + walletProvider = pickProvider(); + if(!walletProvider){ log('No compatible wallet detected. Install Phantom/Solflare/Backpack/Glow/Exodus.', 'err'); return; } + // Attach events if provided by wallet + try{ + if (walletProvider.on) { + walletProvider.on('connect', () => { if(walletProvider?.publicKey){ walletPubkey = new PublicKey(walletProvider.publicKey.toString()); $('walletAddr').value = walletPubkey.toBase58(); updateUIConnected(); updateUserBalance(); updateReflink(); } }); + walletProvider.on('disconnect', () => { updateUIDisconnected(); }); + } + }catch{} + + const res = await walletProvider.connect(); + const pubkey = new PublicKey((res?.publicKey ?? walletProvider.publicKey).toString()); + walletPubkey = pubkey; $('walletAddr').value = pubkey.toBase58(); + await readRefFromUrl(); + log(`Connected ${pubkey.toBase58()}`, 'ok'); + updateUIConnected(); + updateUserBalance(); + updateReflink(); + + // Check if user account exists and toggle Prepare button visibility + const { programId } = getCfg(); + await withConn(async (conn)=>{ + const exists = await userExists(conn, programId, walletPubkey); + const prep = document.getElementById('registerBtn'); + if (prep) prep.style.display = exists ? 'none' : ''; + const st = $('statusValue'); if(st) st.value = exists ? 'Ready' : 'Ready โ€” account will be prepared on your first purchase'; + }); + }catch(e){ log(`Connect failed: ${e.message}`,'err'); console.error(e); } + } + + async function withConn(fn){ const {cluster}=getCfg(); const conn=new Connection(cluster,'confirmed'); return fn(conn); } + + async function userExists(conn, programId, owner){ + try { + const [userPda] = await PublicKey.findProgramAddress([new TextEncoder().encode('user'), owner.toBuffer()], programId); + const info = await conn.getAccountInfo(userPda); + return !!info; + } catch { return false; } + } + + function logSendError(e){ + try{ + if (e && typeof e.getLogs === 'function') { + e.getLogs().then((logs)=>console.error('Tx logs:', logs)).catch(()=>{}); + } else if (e?.logs) { + console.error('Tx logs:', e.logs); + } + }catch{} + } + + async function ensureAta(conn, owner, mint){ + const ata = await findAta(mint, owner); + const acc = await conn.getAccountInfo(ata); + if(!acc) return { ata, createIx: createAtaIx(owner, ata, owner, mint) }; + return { ata }; + } + + // Actions - Updated for our new program +let __lastPot = null; +async function updatePot(){ + try{ + const { programId, cluster } = getCfg(); + if(!programId){ const s=$('statusValue'); if(s) s.value='Not configured'; return; } + const conn = new Connection(cluster,'confirmed'); + // Use our new vault PDA + const [vaultPda] = await PublicKey.findProgramAddress([new TextEncoder().encode('vault')], programId); + const lamports = await conn.getBalance(vaultPda, 'confirmed'); + const solNum = lamports/1_000_000_000; + const sol = solNum.toFixed(3); + const potEl = $('potValue'); if(potEl) potEl.value = `${sol} SOL`; + const potEl2 = $('potValue2'); if(potEl2) potEl2.value = `${sol} SOL`; + const potBig = document.getElementById('potBig'); if(potBig) potBig.textContent = sol; + // delta animation + const deltaEl = document.getElementById('potDelta'); + if(deltaEl !== null){ + if(__lastPot !== null){ + const d = solNum - __lastPot; + if(Math.abs(d) >= 0.001){ + deltaEl.textContent = (d>0?'+':'')+d.toFixed(3); + deltaEl.classList.remove('pos','neg','show'); + deltaEl.classList.add(d>0?'pos':'neg'); + // force reflow for animation restart + void deltaEl.offsetWidth; + deltaEl.classList.add('show'); + setTimeout(()=>deltaEl.classList.remove('show'), 1200); + } + } + __lastPot = solNum; + } + }catch(e){ /*silent*/ } + } + + async function updateUserBalance(){ + try{ + if(!walletPubkey) return; + const { mint, cluster } = getCfg(); + const conn = new Connection(cluster,'confirmed'); + const ata = await findAta(mint, walletPubkey); + const bal = await conn.getTokenAccountBalance(ata).catch(()=>null); + const v = bal?.value?.uiAmountString ?? '0'; + const el = $('userBalance'); if(el) el.value = v; + + // Auto-populate sell field with user's raw token balance (9 decimals) + const rawAmount = bal?.value?.amount ?? '0'; + const sellEl = $('sellAmount'); if(sellEl) sellEl.value = rawAmount; + + // Update vault fields + const keysEl = $('userKeys'); if(keysEl) keysEl.value = v; + const keys2El = $('userKeys2'); if(keys2El) keys2El.value = v; // if there's a second field + const earningsEl = $('userEarnings'); if(earningsEl) earningsEl.value = '0.000 SOL'; // placeholder + }catch(e){ /*silent*/ } + } + + function updateReflink(){ + if(!walletPubkey) return; + const url = new URL(location.href); url.searchParams.set('ref', walletPubkey.toBase58()); + const el = $('reflink'); if(el) el.value = url.toString(); + const el2 = $('reflink2'); if(el2) el2.value = url.toString(); + } + + async function register(){ + try{ + if(!walletPubkey) return log('Connect wallet first','warn'); + const { programId, mint } = getCfg(); if(!programId||!mint){ const s=$('statusValue'); if(s) s.value='Not configured'; return; } const owner=walletPubkey; + await withConn(async (conn)=>{ + // Use our new PDA seeds + const [statePda] = await PublicKey.findProgramAddress([new TextEncoder().encode('state')], programId); + const [userPda] = await PublicKey.findProgramAddress([new TextEncoder().encode('user'), owner.toBuffer()], programId); + const ata = await findAta(mint, owner); + + // Our new program uses register_user without referrer args + const data = await buildIx('register_user', new Uint8Array([])); + const keys=[ + { pubkey:statePda, isSigner:false, isWritable:false }, + { pubkey:userPda, isSigner:false, isWritable:true }, + { pubkey:ata, isSigner:false, isWritable:true }, + { pubkey:mint, isSigner:false, isWritable:false }, + { pubkey:owner, isSigner:true, isWritable:true }, + { pubkey:SystemProgram.programId, isSigner:false, isWritable:false }, + { pubkey:TOKEN_PROGRAM_ID, isSigner:false, isWritable:false }, + { pubkey:ATA_PROGRAM_ID, isSigner:false, isWritable:false }, + ]; + const ix = new TransactionInstruction({ keys, programId, data }); + const tx = new Transaction().add(ix); // No manual ATA creation needed + const {blockhash,lastValidBlockHeight}=await conn.getLatestBlockhash('confirmed'); + tx.recentBlockhash=blockhash; tx.feePayer=owner; + const signed = await walletProvider.signTransaction(tx); + const sig = await conn.sendRawTransaction(signed.serialize()); + await conn.confirmTransaction({signature:sig,blockhash,lastValidBlockHeight},'confirmed'); + log(`โœ… Registered: ${sig}`,'ok'); + }); + }catch(e){ log(`Register failed: ${e.message}`,'err'); logSendError(e); } + } + + async function buy(){ + try{ + if(!walletPubkey) return log('Connect wallet first','warn'); + const { programId, mint, devWallet } = getCfg(); if(!programId||!mint){ const s=$('statusValue'); if(s) s.value='Not configured'; return; } const owner=walletPubkey; + const solAmount = parseFloat($('buyAmount').value||'0'); const lamports = Math.floor(solAmount*1_000_000_000); + if(lamports<=0) return log('Invalid amount','warn'); + await withConn(async (conn)=>{ + // Ensure user exists; auto-register if needed + const exists = await userExists(conn, programId, owner); + if(!exists){ + log('User not found; registering...','warn'); + await register(); + } + + // Use our new PDA seeds and account structure + const [statePda] = await PublicKey.findProgramAddress([new TextEncoder().encode('state')], programId); + const [vaultPda] = await PublicKey.findProgramAddress([new TextEncoder().encode('vault')], programId); + const ata = await findAta(mint, owner); + + // Check if ATA exists, create if needed + const ataAccount = await conn.getAccountInfo(ata); + if (!ataAccount) { + log('Creating token account first...', 'warn'); + const createAtaTx = new Transaction().add(createAtaIx(owner, ata, owner, mint)); + const {blockhash: ataBlockhash, lastValidBlockHeight: ataLastValid} = await conn.getLatestBlockhash('confirmed'); + createAtaTx.recentBlockhash = ataBlockhash; + createAtaTx.feePayer = owner; + const signedAtaTx = await walletProvider.signTransaction(createAtaTx); + const ataSig = await conn.sendRawTransaction(signedAtaTx.serialize()); + await conn.confirmTransaction({signature: ataSig, blockhash: ataBlockhash, lastValidBlockHeight: ataLastValid}, 'confirmed'); + log(`ATA created: ${ataSig}`, 'ok'); + } + + const data = await buildIx('buy_tokens', le64(lamports)); + const devWalletPk = devWallet ?? owner; + + // Build keys for our new buy_tokens instruction + const keys = [ + { pubkey: statePda, isSigner:false, isWritable:true }, // state + { pubkey: vaultPda, isSigner:false, isWritable:true }, // vault + { pubkey: mint, isSigner:false, isWritable:true }, // mint + { pubkey: ata, isSigner:false, isWritable:true }, // buyer_token_account + { pubkey: devWalletPk, isSigner:false, isWritable:true }, // dev_wallet + { pubkey: owner, isSigner:true, isWritable:true }, // buyer + { pubkey: SystemProgram.programId, isSigner:false, isWritable:false }, // system_program + { pubkey: TOKEN_PROGRAM_ID, isSigner:false, isWritable:false } // token_program + ]; + const ix = new TransactionInstruction({ keys, programId, data }); + const tx = new Transaction().add(ix); + const {blockhash,lastValidBlockHeight}=await conn.getLatestBlockhash('confirmed'); + tx.recentBlockhash=blockhash; tx.feePayer=owner; + const signed = await walletProvider.signTransaction(tx); + const sig = await conn.sendRawTransaction(signed.serialize()); + await conn.confirmTransaction({signature:sig,blockhash,lastValidBlockHeight},'confirmed'); + await pushTickerItem(`BUY ${solAmount.toFixed(3)} SOL โ€ข ${shortAddr(owner)}`,'buy', owner.toBase58()); + log(`โœ… Buy: ${sig}`,'ok'); + // Refresh balances after successful buy + setTimeout(() => { updateUserBalance(); updatePot(); }, 2000); + }); + }catch(e){ log(`Buy failed: ${e.message}`,'err'); logSendError(e); } + } + + async function sell(){ + try{ + if(!walletPubkey) return log('Connect wallet first','warn'); + const { programId, mint } = getCfg(); const owner=walletPubkey; + const tokensRaw = BigInt($('sellAmount').value||'0'); if(tokensRaw<=0n) return log('Invalid amount','warn'); + await withConn(async (conn)=>{ + // Use our new PDA seeds + const [statePda] = await PublicKey.findProgramAddress([new TextEncoder().encode('state')], programId); + const [vaultPda] = await PublicKey.findProgramAddress([new TextEncoder().encode('vault')], programId); + const ata = await findAta(mint, owner); + const data = await buildIx('sell_tokens', le64(tokensRaw)); + const keys=[ + { pubkey: statePda, isSigner:false, isWritable:true }, + { pubkey: vaultPda, isSigner:false, isWritable:true }, + { pubkey: mint, isSigner:false, isWritable:true }, + { pubkey: ata, isSigner:false, isWritable:true }, + { pubkey: owner, isSigner:true, isWritable:true }, + { pubkey: SystemProgram.programId, isSigner:false, isWritable:false }, + { pubkey: TOKEN_PROGRAM_ID, isSigner:false, isWritable:false }, + ]; + const ix = new TransactionInstruction({ keys, programId, data }); + const tx = new Transaction().add(ix); + const {blockhash,lastValidBlockHeight}=await conn.getLatestBlockhash('confirmed'); + tx.recentBlockhash=blockhash; tx.feePayer=owner; + const signed = await walletProvider.signTransaction(tx); + const sig = await conn.sendRawTransaction(signed.serialize()); + await conn.confirmTransaction({signature:sig,blockhash,lastValidBlockHeight},'confirmed'); + const tk = Number(tokensRaw)/1_000_000_000; await pushTickerItem(`SELL ${tk.toFixed(3)} tk โ€ข ${shortAddr(owner)}`,'sell', owner.toBase58()); + log(`โœ… Sell: ${sig}`,'ok'); + // Refresh balances after successful sell + setTimeout(() => { updateUserBalance(); updatePot(); }, 2000); + }); + }catch(e){ log(`Sell failed: ${e.message}`,'err'); logSendError(e); } + } + + async function withdraw(){ + try{ + if(!walletPubkey) return log('Connect wallet first','warn'); + const { programId, mint } = getCfg(); const owner=walletPubkey; + await withConn(async (conn)=>{ + // Use our new PDA seeds and withdraw_dividends instruction + const [statePda] = await PublicKey.findProgramAddress([new TextEncoder().encode('state')], programId); + const [vaultPda] = await PublicKey.findProgramAddress([new TextEncoder().encode('vault')], programId); + const [userPda] = await PublicKey.findProgramAddress([new TextEncoder().encode('user'), owner.toBuffer()], programId); + const ata = await findAta(mint, owner); + const data = await buildIx('withdraw_dividends', new Uint8Array([])); + const keys=[ + { pubkey: statePda, isSigner:false, isWritable:false }, + { pubkey: vaultPda, isSigner:false, isWritable:true }, + { pubkey: userPda, isSigner:false, isWritable:true }, + { pubkey: ata, isSigner:false, isWritable:false }, + { pubkey: mint, isSigner:false, isWritable:false }, + { pubkey: owner, isSigner:true, isWritable:true }, + { pubkey: SystemProgram.programId, isSigner:false, isWritable:false }, + ]; + const ix = new TransactionInstruction({ keys, programId, data }); + const tx = new Transaction().add(ix); + const {blockhash,lastValidBlockHeight}=await conn.getLatestBlockhash('confirmed'); + tx.recentBlockhash=blockhash; tx.feePayer=owner; + const signed = await walletProvider.signTransaction(tx); + const sig = await conn.sendRawTransaction(signed.serialize()); + await conn.confirmTransaction({signature:sig,blockhash,lastValidBlockHeight},'confirmed'); + log(`โœ… Withdraw: ${sig}`,'ok'); + // Refresh balances after successful withdraw + setTimeout(() => { updateUserBalance(); updatePot(); }, 2000); + }); + }catch(e){ log(`Withdraw failed: ${e.message}`,'err'); logSendError(e); } + } + + // Reflink copy + function copyRef(){ + const el = $('reflink'); if(!el || !el.value) return log('Nothing to copy','warn'); + navigator.clipboard.writeText(el.value); + log('Reflink copied to clipboard','ok'); + } + + // Tabs & countdown + function initTabs(){ + const tabs = document.querySelectorAll('.tab'); + const contents = { + purchase: document.getElementById('tab-purchase'), + vault: document.getElementById('tab-vault'), + referrals: document.getElementById('tab-referrals') + }; + tabs.forEach((tab) => { + tab.addEventListener('click', () => { + const target = tab.dataset.tab; + tabs.forEach((t) => t.classList.remove('active')); + Object.values(contents).forEach((c) => c && c.classList.remove('active')); + tab.classList.add('active'); + if (contents[target]) { + contents[target].classList.add('active'); + contents[target].style.display = ''; + } + }); + }); + } + + function addEventListeners(){ + const connectBtn = $('connectBtn'); if(connectBtn) connectBtn.addEventListener('click', connectWallet); + const disconnectBtn = $('disconnectBtn'); if(disconnectBtn) disconnectBtn.addEventListener('click', disconnectWallet); + const registerBtn = $('registerBtn'); if(registerBtn) registerBtn.addEventListener('click', register); + const buyBtn = $('buyBtn'); if(buyBtn) buyBtn.addEventListener('click', buy); + const sellBtn = $('sellBtn'); if(sellBtn) sellBtn.addEventListener('click', sell); + const withdrawBtn = $('withdrawBtn'); if(withdrawBtn) withdrawBtn.addEventListener('click', withdraw); + const withdrawBtn2 = $('withdrawBtn2'); if(withdrawBtn2) withdrawBtn2.addEventListener('click', withdraw); + const copyRefBtn = $('copyRef'); if(copyRefBtn) copyRefBtn.addEventListener('click', copyRef); + const copyRefBtn2 = $('copyRef2'); if(copyRefBtn2) copyRefBtn2.addEventListener('click', copyRef); + } + + // Money rain animation (working version from website-solana) + function initMoneyRain(count=72){ + const wrap = document.getElementById('moneyRain'); if(!wrap) return; + wrap.innerHTML = ''; + const vw = Math.max(window.innerWidth, document.documentElement.clientWidth); + for(let i=0;i{ clearTimeout(to); to=setTimeout(()=>initMoneyRain(count), 200); }, { passive:true }); + } + + // Initialize + async function init(){ + log('๐Ÿš€ PoWH3d Lottery initializing...'); + populateWalletSelect(); + await applyConfig(); + initTabs(); + addEventListeners(); + updateUIDisconnected(); + + // Load existing ticker data from server + await loadTickerFromServer(); + + // Set up periodic updates + setInterval(updatePot, 5000); + setInterval(pollRecentActivity, 10000); + + // Periodically refresh ticker from server to get updates from other users + setInterval(loadTickerFromServer, 15000); // Every 15 seconds + + initMoneyRain(); // Start the money rain! + updatePot(); // initial load + log('โœ… Ready!'); + } + + // Start when DOM is ready + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', init); + } else { + init(); + } +})(); \ No newline at end of file diff --git a/apple-touch-icon.png b/apple-touch-icon.png new file mode 100644 index 0000000..3632402 Binary files /dev/null and b/apple-touch-icon.png differ diff --git a/burn-all-tokens.sh b/burn-all-tokens.sh new file mode 100755 index 0000000..171333e --- /dev/null +++ b/burn-all-tokens.sh @@ -0,0 +1,87 @@ +#!/bin/bash + +echo "๐Ÿ”ฅ Burning All Tokens in Wallet" +echo "================================" +echo "โš ๏ธ This will permanently destroy ALL tokens in your wallet!" +echo "๐Ÿ“ Cluster: devnet (safe for testing)" +echo "" + +# Confirm before proceeding +read -p "Are you sure you want to burn ALL tokens? (type 'yes' to confirm): " confirm +if [ "$confirm" != "yes" ]; then + echo "โŒ Aborted - no tokens burned" + exit 1 +fi + +echo "๐Ÿ”ฅ Starting token burning process..." +echo "" + +# List of token mints to burn (from spl-token accounts output) +TOKENS=( + "4auc435LJ9AfprLeMziHTJbP8wQmbSi7o4ZpeXdR66jQ" + "5xEQF57sR2L3tJBfdiiqaVtepTMa7nQR9uMybMojEY8n" + "8cJ8APx5TwwmpeRk4Zhz1Qbyi1T3HHdHUEw4GUJqxAGN" + "AK9fXWyDNWurYjZSDhbqBo6fczqLmCLbCZ3vq9Vftsqb" +) + +# Set to devnet +solana config set --url devnet > /dev/null + +echo "๐Ÿ’ฐ Current wallet: $(solana address)" +echo "๐ŸŒ Cluster: devnet" +echo "" + +# Function to burn tokens for a specific mint +burn_token() { + local mint=$1 + echo "๐Ÿ”ฅ Processing mint: $mint" + + # Get the token account balance + local balance=$(spl-token balance $mint --url devnet 2>/dev/null || echo "0") + + if [ "$balance" == "0" ] || [ -z "$balance" ]; then + echo " โ„น๏ธ No balance or account doesn't exist - skipping" + return + fi + + echo " ๐Ÿ’ฐ Current balance: $balance" + + # Try to burn all tokens + echo " ๐Ÿ”ฅ Burning $balance tokens..." + local result=$(spl-token burn $mint $balance --url devnet 2>&1) + + if [ $? -eq 0 ]; then + echo " โœ… Successfully burned $balance tokens" + + # Try to close the token account to reclaim SOL + echo " ๐Ÿ—‘๏ธ Attempting to close token account..." + spl-token close $mint --url devnet 2>/dev/null + if [ $? -eq 0 ]; then + echo " โœ… Token account closed and SOL reclaimed" + else + echo " โš ๏ธ Token account could not be closed (may still have remaining dust)" + fi + else + echo " โŒ Failed to burn tokens: $result" + fi + + echo "" +} + +# Burn tokens for each mint +for mint in "${TOKENS[@]}"; do + burn_token $mint +done + +echo "๐ŸŽฏ Token burning process complete!" +echo "" +echo "๐Ÿ“Š Final token account status:" +spl-token accounts --url devnet + +echo "" +echo "๐Ÿ’ฐ Final SOL balance:" +solana balance --url devnet + +echo "" +echo "โœ… Ready for clean testing!" +echo "๐Ÿงช You can now test the PoWH program from a clean state" \ No newline at end of file diff --git a/close-all-token-accounts.sh b/close-all-token-accounts.sh new file mode 100755 index 0000000..e0d585d --- /dev/null +++ b/close-all-token-accounts.sh @@ -0,0 +1,111 @@ +#!/bin/bash + +echo "๐Ÿ—‘๏ธ Closing All Token Accounts" +echo "==============================" +echo "โš ๏ธ This will close ALL token accounts and burn any remaining tokens!" +echo "๐Ÿ’ฐ You will reclaim the SOL used for rent" +echo "๐Ÿ“ Cluster: devnet (safe for testing)" +echo "" + +# Confirm before proceeding +read -p "Are you sure you want to close ALL token accounts? (type 'yes' to confirm): " confirm +if [ "$confirm" != "yes" ]; then + echo "โŒ Aborted - no accounts closed" + exit 1 +fi + +echo "๐Ÿ—‘๏ธ Starting token account closure process..." +echo "" + +# Set to devnet +solana config set --url devnet > /dev/null + +echo "๐Ÿ’ฐ Current wallet: $(solana address)" +echo "๐ŸŒ Cluster: devnet" +echo "" +echo "๐Ÿ’ฐ SOL balance before: $(solana balance --url devnet)" +echo "" + +# Get all token accounts and close them +echo "๐Ÿ“Š Current token accounts:" +spl-token accounts --url devnet +echo "" + +# List of specific token account addresses to close (from verbose output) +TOKEN_ACCOUNTS=( + "8zr6uF84gTzY5V1MP9EeEfy6m2LNULkH4VEFgxY1fKwh" + "679vTxSpUw55buSgPpUsEp66eiUCQs3Y7acpoeTt6W97" + "4t7iZeFsLXA2Ro1EyxoR88Aqnq62Da4txb74eiC2WovQ" + "AmNmTDXjESr1PZTjEC6QiWqLbeZxdxdQkM2TasSUL88QK" +) + +# Function to close a token account +close_account() { + local account=$1 + echo "๐Ÿ—‘๏ธ Processing token account: $account" + + # Try to close the account directly + local result=$(spl-token close-account $account --url devnet 2>&1) + + if [ $? -eq 0 ]; then + echo " โœ… Successfully closed account and reclaimed SOL" + else + echo " โŒ Failed to close account: $result" + + # If direct closure failed, try to get the mint and burn first + echo " ๐Ÿ”„ Trying alternative approach..." + + # Get account info to find the mint + local account_info=$(solana account $account --url devnet --output json 2>/dev/null) + if [ $? -eq 0 ]; then + echo " โ„น๏ธ Account exists, attempting force closure..." + spl-token close-account $account --force --url devnet 2>/dev/null + if [ $? -eq 0 ]; then + echo " โœ… Force closure successful" + else + echo " โš ๏ธ Account could not be closed (may have non-zero balance)" + fi + else + echo " โ„น๏ธ Account may already be closed or doesn't exist" + fi + fi + echo "" +} + +# Close all token accounts +for account in "${TOKEN_ACCOUNTS[@]}"; do + close_account $account +done + +# Also try to close by mint address (alternative approach) +echo "๐Ÿ”„ Attempting closure by mint address as backup..." +MINTS=( + "4auc435LJ9AfprLeMziHTJbP8wQmbSi7o4ZpeXdR66jQ" + "5xEQF57sR2L3tJBfdiiqaVtepTMa7nQR9uMybMojEY8n" + "8cJ8APx5TwwmpeRk4Zhz1Qbyi1T3HHdHUEw4GUJqxAGN" + "AK9fXWyDNWurYjZSDhbqBo6fczqLmCLbCZ3vq9Vftsqb" +) + +for mint in "${MINTS[@]}"; do + echo "๐Ÿ—‘๏ธ Attempting to close account for mint: $mint" + spl-token close $mint --url devnet 2>/dev/null + if [ $? -eq 0 ]; then + echo " โœ… Closed successfully" + else + echo " โš ๏ธ Could not close (may not exist or have balance)" + fi +done + +echo "" +echo "๐ŸŽฏ Token account closure process complete!" +echo "" +echo "๐Ÿ“Š Final token account status:" +spl-token accounts --url devnet + +echo "" +echo "๐Ÿ’ฐ Final SOL balance:" +solana balance --url devnet + +echo "" +echo "โœ… Token accounts processed!" +echo "๐Ÿงช Ready for clean testing with your PoWH program" \ No newline at end of file diff --git a/config.json b/config.json new file mode 100644 index 0000000..93284d5 --- /dev/null +++ b/config.json @@ -0,0 +1,6 @@ +{ + "cluster": "https://api.devnet.solana.com", + "programId": "CQKiz5PKgoQjxNDkGowPWWXu8MJCm2HgonfYAtcFZX87", + "mint": "8cJ8APx5TwwmpeRk4Zhz1Qbyi1T3HHdHUEw4GUJqxAGN", + "devWallet": "GPFYcM3svcM4Srko6ExLYeSW4Gjwf6XoV4k1eSXoGHoK" +} diff --git a/deploy.sh b/deploy.sh new file mode 100755 index 0000000..5c74f80 --- /dev/null +++ b/deploy.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +# Deployment script for Lottery Simple DApp +set -e + +echo "๐Ÿš€ Building and deploying Lottery Simple DApp..." + +# Build the Docker image +echo "๐Ÿ“ฆ Building Docker image..." +docker-compose build + +# Stop existing container if running +echo "๐Ÿ›‘ Stopping existing container..." +docker-compose down + +# Start the new container +echo "โ–ถ๏ธ Starting new container..." +docker-compose up -d + +# Wait a moment for startup +sleep 3 + +# Check if it's running +if curl -s http://localhost:14888/health > /dev/null; then + echo "โœ… Deployment successful!" + echo "๐ŸŒ Frontend available at: http://localhost:14888" + echo "๐Ÿฅ Health check: http://localhost:14888/health" +else + echo "โŒ Deployment failed - health check failed" + echo "๐Ÿ“‹ Container logs:" + docker-compose logs + exit 1 +fi + +echo "๐ŸŽ‰ Deployment complete!" \ No newline at end of file diff --git a/devnet-config.json b/devnet-config.json new file mode 100644 index 0000000..f1d9686 --- /dev/null +++ b/devnet-config.json @@ -0,0 +1,7 @@ +{ + "programId": "8hcuEUBcuVBYyD53QPFQrRSWJjQy3UVURiqJpcuvgrTf", + "mintAddress": "GrCHRSRHdZtiz2fiv1iUgigXCfB5Ta3j8gXepZUUTPP2", + "devWallet": "GPFYcM3svcM4Srko6ExLYeSW4Gjwf6XoV4k1eSXoGHoK", + "cluster": "devnet", + "rpcUrl": "https://api.devnet.solana.com" +} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..0bd4929 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,15 @@ +version: '3.8' + +services: + lottery-simple-dapp: + build: . + container_name: lottery-simple-dapp + ports: + - "14888:80" + restart: unless-stopped + networks: + - lottery-dapp-net + +networks: + lottery-dapp-net: + driver: bridge \ No newline at end of file diff --git a/favicon-16.png b/favicon-16.png new file mode 100644 index 0000000..8f9d2de Binary files /dev/null and b/favicon-16.png differ diff --git a/favicon-32.png b/favicon-32.png new file mode 100644 index 0000000..3a06d41 Binary files /dev/null and b/favicon-32.png differ diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000..9d398da Binary files /dev/null and b/favicon.ico differ diff --git a/favicon.svg b/favicon.svg new file mode 100644 index 0000000..a5a279d --- /dev/null +++ b/favicon.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..ef6ea7c --- /dev/null +++ b/index.html @@ -0,0 +1,198 @@ + + + + + + PoWH3d Lottery + + + + + + + + + + + + + + + + +
+ + + + + +
+
+
+
+
+

PoWH3d Lottery

+
+
0.000 SOL
+
+

8โ€‘bit bondingโ€‘curve lottery on Solana โ€ข ultraโ€‘low fees โ€ข instant settlements

+
+
+ +
+
+
+ + + +
+
+
+
+

Connect

+
+ + + + +
+ +
+ + + + +
+ + + +
+
+

Pot

+
+ + + + +
+
+
+
+ + + +
+ + + + + +
+

How it Works

+

Buy with SOL to mint lottery tokens on a bonding curve. A small protocol fee and referral bonus are taken on each trade; the rest boosts the community pot and holder rewards. Sell anytime; proceeds are net of fees. As activity grows, holders earn more.

+
+ + +
+ +
+ ยฉ PoWH3d Lottery ยท Built for Solana + Privacy +
+ + diff --git a/init-program.js b/init-program.js new file mode 100644 index 0000000..47b92dc --- /dev/null +++ b/init-program.js @@ -0,0 +1,95 @@ +const { Connection, PublicKey, Keypair } = require('@solana/web3.js'); +const { Program, AnchorProvider, web3, utils } = require('@coral-xyz/anchor'); +const fs = require('fs'); + +// Load configuration +const config = JSON.parse(fs.readFileSync('./devnet-config.json', 'utf8')); +const idl = JSON.parse(fs.readFileSync('./target/idl/lottery_simple.json', 'utf8')); + +async function initializeProgram() { + console.log('๐Ÿš€ Initializing PoWH Program...'); + console.log('==============================='); + + // Set up connection and provider + const connection = new Connection(config.rpcUrl, 'confirmed'); + + // Load wallet + const walletKeypair = Keypair.fromSecretKey( + Uint8Array.from(JSON.parse(fs.readFileSync(process.env.HOME + '/.config/solana/id.json', 'utf8'))) + ); + + const wallet = { + publicKey: walletKeypair.publicKey, + signTransaction: async (tx) => { + tx.sign(walletKeypair); + return tx; + }, + signAllTransactions: async (txs) => { + return txs.map(tx => { + tx.sign(walletKeypair); + return tx; + }); + } + }; + + const provider = new AnchorProvider(connection, wallet, { commitment: 'confirmed' }); + const program = new Program(idl, new PublicKey(config.programId), provider); + + console.log('๐Ÿ“‹ Program ID:', config.programId); + console.log('๐Ÿ’ฐ Authority:', walletKeypair.publicKey.toString()); + console.log('๐Ÿช™ Mint:', config.mintAddress); + console.log('๐ŸŒ Cluster:', config.cluster); + + try { + // Derive PDAs + const [statePda] = PublicKey.findProgramAddressSync( + [Buffer.from("state")], + program.programId + ); + + const [vaultPda] = PublicKey.findProgramAddressSync( + [Buffer.from("vault")], + program.programId + ); + + console.log('๐Ÿ›๏ธ State PDA:', statePda.toString()); + console.log('๐Ÿฆ Vault PDA:', vaultPda.toString()); + + // Initialize the program + console.log('โณ Sending initialize transaction...'); + + const tx = await program.methods + .initialize() + .accounts({ + state: statePda, + vault: vaultPda, + mint: new PublicKey(config.mintAddress), + authority: walletKeypair.publicKey, + systemProgram: web3.SystemProgram.programId, + tokenProgram: utils.token.TOKEN_PROGRAM_ID, + }) + .rpc(); + + console.log('โœ… Program initialized successfully!'); + console.log('๐Ÿ“ Transaction:', tx); + + // Update config with PDAs + const updatedConfig = { + ...config, + statePda: statePda.toString(), + vaultPda: vaultPda.toString(), + initialized: true, + initTx: tx + }; + + fs.writeFileSync('./devnet-config.json', JSON.stringify(updatedConfig, null, 2)); + console.log('๐Ÿ’พ Configuration updated with PDA addresses'); + + } catch (error) { + console.error('โŒ Initialization failed:', error); + process.exit(1); + } +} + +// Run the initialization +initializeProgram().catch(console.error); \ No newline at end of file diff --git a/lottery_program/.gitignore b/lottery_program/.gitignore new file mode 100644 index 0000000..2e0446b --- /dev/null +++ b/lottery_program/.gitignore @@ -0,0 +1,7 @@ +.anchor +.DS_Store +target +**/*.rs.bk +node_modules +test-ledger +.yarn diff --git a/lottery_program/.prettierignore b/lottery_program/.prettierignore new file mode 100644 index 0000000..4142583 --- /dev/null +++ b/lottery_program/.prettierignore @@ -0,0 +1,7 @@ +.anchor +.DS_Store +target +node_modules +dist +build +test-ledger diff --git a/lottery_program/Anchor.toml b/lottery_program/Anchor.toml new file mode 100644 index 0000000..2861f1f --- /dev/null +++ b/lottery_program/Anchor.toml @@ -0,0 +1,19 @@ +[toolchain] +package_manager = "yarn" + +[features] +resolution = true +skip-lint = false + +[programs.localnet] +lottery_program = "9Un1evsbgmJa9XH7baEeTSwpQjAPz8pmDFVccVp8HBY4" + +[registry] +url = "https://api.apr.dev" + +[provider] +cluster = "localnet" +wallet = "~/.config/solana/id.json" + +[scripts] +test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" diff --git a/mint-keypair.json b/mint-keypair.json new file mode 100644 index 0000000..ac987e5 --- /dev/null +++ b/mint-keypair.json @@ -0,0 +1 @@ +[228,210,161,242,26,178,81,232,150,232,162,61,163,178,12,246,125,252,229,194,95,188,161,46,214,173,205,225,0,193,115,79,235,121,133,123,65,221,159,48,80,179,37,118,124,100,188,234,93,73,20,79,101,38,82,36,1,80,66,19,145,90,81,53] \ No newline at end of file diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..24bd7bb --- /dev/null +++ b/nginx.conf @@ -0,0 +1,38 @@ +server { + listen 80; + server_name _; + root /var/www/html; + index index.html index.php; + + # Security headers + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + + # Enable gzip compression + gzip on; + gzip_types text/plain text/css application/javascript application/json image/svg+xml; + + # PHP location + location ~ \.php$ { + try_files $uri =404; + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass 127.0.0.1:9000; + fastcgi_index index.php; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param PATH_INFO $fastcgi_path_info; + } + + # Main location + location / { + try_files $uri $uri/ /index.html; + } + + # Health check endpoint + location /health { + access_log off; + return 200 "healthy\n"; + add_header Content-Type text/plain; + } +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..07e7cba --- /dev/null +++ b/package-lock.json @@ -0,0 +1,755 @@ +{ + "name": "lottery-simple", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "lottery-simple", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@coral-xyz/anchor": "^0.31.1", + "@solana/web3.js": "^1.98.4" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@coral-xyz/anchor": { + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/@coral-xyz/anchor/-/anchor-0.31.1.tgz", + "integrity": "sha512-QUqpoEK+gi2S6nlYc2atgT2r41TT3caWr/cPUEL8n8Md9437trZ68STknq897b82p5mW0XrTBNOzRbmIRJtfsA==", + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "@coral-xyz/anchor-errors": "^0.31.1", + "@coral-xyz/borsh": "^0.31.1", + "@noble/hashes": "^1.3.1", + "@solana/web3.js": "^1.69.0", + "bn.js": "^5.1.2", + "bs58": "^4.0.1", + "buffer-layout": "^1.2.2", + "camelcase": "^6.3.0", + "cross-fetch": "^3.1.5", + "eventemitter3": "^4.0.7", + "pako": "^2.0.3", + "superstruct": "^0.15.4", + "toml": "^3.0.0" + }, + "engines": { + "node": ">=17" + } + }, + "node_modules/@coral-xyz/anchor-errors": { + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/@coral-xyz/anchor-errors/-/anchor-errors-0.31.1.tgz", + "integrity": "sha512-NhNEku4F3zzUSBtrYz84FzYWm48+9OvmT1Hhnwr6GnPQry2dsEqH/ti/7ASjjpoFTWRnPXrjAIT1qM6Isop+LQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=10" + } + }, + "node_modules/@coral-xyz/borsh": { + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/@coral-xyz/borsh/-/borsh-0.31.1.tgz", + "integrity": "sha512-9N8AU9F0ubriKfNE3g1WF0/4dtlGXoBN/hd1PvbNBamBNwRgHxH4P+o3Zt7rSEloW1HUs6LfZEchlx9fW7POYw==", + "license": "Apache-2.0", + "dependencies": { + "bn.js": "^5.1.2", + "buffer-layout": "^1.2.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@solana/web3.js": "^1.69.0" + } + }, + "node_modules/@noble/curves": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@solana/buffer-layout": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz", + "integrity": "sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==", + "license": "MIT", + "dependencies": { + "buffer": "~6.0.3" + }, + "engines": { + "node": ">=5.10" + } + }, + "node_modules/@solana/codecs-core": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.3.0.tgz", + "integrity": "sha512-oG+VZzN6YhBHIoSKgS5ESM9VIGzhWjEHEGNPSibiDTxFhsFWxNaz8LbMDPjBUE69r9wmdGLkrQ+wVPbnJcZPvw==", + "license": "MIT", + "dependencies": { + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/codecs-numbers": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.3.0.tgz", + "integrity": "sha512-jFvvwKJKffvG7Iz9dmN51OGB7JBcy2CJ6Xf3NqD/VP90xak66m/Lg48T01u5IQ/hc15mChVHiBm+HHuOFDUrQg==", + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "2.3.0", + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/errors": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-2.3.0.tgz", + "integrity": "sha512-66RI9MAbwYV0UtP7kGcTBVLxJgUxoZGm8Fbc0ah+lGiAw17Gugco6+9GrJCV83VyF2mDWyYnYM9qdI3yjgpnaQ==", + "license": "MIT", + "dependencies": { + "chalk": "^5.4.1", + "commander": "^14.0.0" + }, + "bin": { + "errors": "bin/cli.mjs" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/web3.js": { + "version": "1.98.4", + "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.98.4.tgz", + "integrity": "sha512-vv9lfnvjUsRiq//+j5pBdXig0IQdtzA0BRZ3bXEP4KaIyF1CcaydWqgyzQgfZMNIsWNWmG+AUHwPy4AHOD6gpw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.0", + "@noble/curves": "^1.4.2", + "@noble/hashes": "^1.4.0", + "@solana/buffer-layout": "^4.0.1", + "@solana/codecs-numbers": "^2.1.0", + "agentkeepalive": "^4.5.0", + "bn.js": "^5.2.1", + "borsh": "^0.7.0", + "bs58": "^4.0.1", + "buffer": "6.0.3", + "fast-stable-stringify": "^1.0.0", + "jayson": "^4.1.1", + "node-fetch": "^2.7.0", + "rpc-websockets": "^9.0.2", + "superstruct": "^2.0.2" + } + }, + "node_modules/@solana/web3.js/node_modules/superstruct": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-2.0.2.tgz", + "integrity": "sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@swc/helpers": { + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", + "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "license": "MIT" + }, + "node_modules/@types/uuid": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", + "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/base-x": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", + "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bn.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", + "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==", + "license": "MIT" + }, + "node_modules/borsh": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz", + "integrity": "sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==", + "license": "Apache-2.0", + "dependencies": { + "bn.js": "^5.2.0", + "bs58": "^4.0.0", + "text-encoding-utf-8": "^1.0.2" + } + }, + "node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "license": "MIT", + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-layout": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/buffer-layout/-/buffer-layout-1.2.2.tgz", + "integrity": "sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==", + "license": "MIT", + "engines": { + "node": ">=4.5" + } + }, + "node_modules/bufferutil": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.9.tgz", + "integrity": "sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/commander": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.1.tgz", + "integrity": "sha512-2JkV3gUZUVrbNA+1sjBOYLsMZ5cEEl8GTFP2a4AVz5hvasAMCQ1D2l2le/cX+pV4N6ZU17zjUahLpIXRrnWL8A==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/cross-fetch": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz", + "integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.7.0" + } + }, + "node_modules/delay": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", + "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "license": "MIT" + }, + "node_modules/es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", + "license": "MIT", + "dependencies": { + "es6-promise": "^4.0.3" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==", + "engines": { + "node": "> 0.1.90" + } + }, + "node_modules/fast-stable-stringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz", + "integrity": "sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==", + "license": "MIT" + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "license": "MIT", + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/jayson": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/jayson/-/jayson-4.2.0.tgz", + "integrity": "sha512-VfJ9t1YLwacIubLhONk0KFeosUBwstRWQ0IRT1KDjEjnVnSOVHC3uwugyV7L0c7R9lpVyrUGT2XWiBA1UTtpyg==", + "license": "MIT", + "dependencies": { + "@types/connect": "^3.4.33", + "@types/node": "^12.12.54", + "@types/ws": "^7.4.4", + "commander": "^2.20.3", + "delay": "^5.0.0", + "es6-promisify": "^5.0.0", + "eyes": "^0.1.8", + "isomorphic-ws": "^4.0.1", + "json-stringify-safe": "^5.0.1", + "stream-json": "^1.9.1", + "uuid": "^8.3.2", + "ws": "^7.5.10" + }, + "bin": { + "jayson": "bin/jayson.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jayson/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "license": "ISC" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", + "optional": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/pako": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==", + "license": "(MIT AND Zlib)" + }, + "node_modules/rpc-websockets": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-9.2.0.tgz", + "integrity": "sha512-DS/XHdPxplQTtNRKiBCRWGBJfjOk56W7fyFUpiYi9fSTWTzoEMbUkn3J4gB0IMniIEVeAGR1/rzFQogzD5MxvQ==", + "license": "LGPL-3.0-only", + "dependencies": { + "@swc/helpers": "^0.5.11", + "@types/uuid": "^8.3.4", + "@types/ws": "^8.2.2", + "buffer": "^6.0.3", + "eventemitter3": "^5.0.1", + "uuid": "^8.3.2", + "ws": "^8.5.0" + }, + "funding": { + "type": "paypal", + "url": "https://paypal.me/kozjak" + }, + "optionalDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + } + }, + "node_modules/rpc-websockets/node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/rpc-websockets/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, + "node_modules/rpc-websockets/node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/stream-chain": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/stream-chain/-/stream-chain-2.2.5.tgz", + "integrity": "sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==", + "license": "BSD-3-Clause" + }, + "node_modules/stream-json": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/stream-json/-/stream-json-1.9.1.tgz", + "integrity": "sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==", + "license": "BSD-3-Clause", + "dependencies": { + "stream-chain": "^2.2.5" + } + }, + "node_modules/superstruct": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.15.5.tgz", + "integrity": "sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ==", + "license": "MIT" + }, + "node_modules/text-encoding-utf-8": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz", + "integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==" + }, + "node_modules/toml": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==", + "license": "MIT" + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..f960edb --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "name": "lottery-simple", + "version": "1.0.0", + "description": "", + "main": "app.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "@coral-xyz/anchor": "^0.31.1", + "@solana/web3.js": "^1.98.4" + } +} diff --git a/programs/lottery-simple/Cargo.toml b/programs/lottery-simple/Cargo.toml new file mode 100644 index 0000000..cec5aea --- /dev/null +++ b/programs/lottery-simple/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "lottery-simple" +version = "0.1.0" +description = "A PoWH (Proof of Weak Hands) token with bonding curve" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] +name = "lottery_simple" + +[features] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +cpi = ["no-entrypoint"] +idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"] +default = [] + +[dependencies] +anchor-lang = { version = "0.31.0", features = ["init-if-needed"] } +anchor-spl = "0.31.0" diff --git a/programs/lottery-simple/src/lib.rs b/programs/lottery-simple/src/lib.rs new file mode 100644 index 0000000..0184e58 --- /dev/null +++ b/programs/lottery-simple/src/lib.rs @@ -0,0 +1,457 @@ +use anchor_lang::prelude::*; +use anchor_spl::token::{self, Burn, Mint, MintTo, Token, TokenAccount}; +use anchor_spl::associated_token::AssociatedToken; + +declare_id!("8hcuEUBcuVBYyD53QPFQrRSWJjQy3UVURiqJpcuvgrTf"); + +#[program] +pub mod lottery_simple { + use super::*; + + pub fn initialize(ctx: Context) -> Result<()> { + let state = &mut ctx.accounts.state; + state.bump = ctx.bumps.state; + state.vault_bump = ctx.bumps.vault; + state.authority = ctx.accounts.authority.key(); + state.mint = ctx.accounts.mint.key(); + state.vault = ctx.accounts.vault.key(); + state.total_supply = 0; + state.dev_fee_bps = 300; // 3% + state.dividend_fee_bps = 200; // 2% + state.token_price_initial = 100_000; // 0.0001 SOL + state.token_price_increment = 10_000; // 0.00001 SOL per token + state.profit_per_share = 0; + msg!("PoWH initialized with mint: {}", ctx.accounts.mint.key()); + Ok(()) + } + + pub fn register_user(ctx: Context) -> Result<()> { + let user = &mut ctx.accounts.user; + user.owner = ctx.accounts.owner.key(); + user.token_account = ctx.accounts.token_account.key(); + user.dividends_withdrawn = 0; + msg!("User registered: {}", ctx.accounts.owner.key()); + Ok(()) + } + + pub fn buy_tokens(ctx: Context, sol_amount: u64) -> Result<()> { + // Capture needed values before mutable borrow + let state_bump = ctx.accounts.state.bump; + let buyer_key = ctx.accounts.buyer.key(); + let state_account_info = ctx.accounts.state.to_account_info(); + + let state = &mut ctx.accounts.state; + + // Calculate fees + let dev_fee = (sol_amount as u128 * state.dev_fee_bps as u128) / 10_000; + let dividend_fee = (sol_amount as u128 * state.dividend_fee_bps as u128) / 10_000; + let net_purchase = sol_amount as u128 - dev_fee - dividend_fee; + + // Transfer dev fee from buyer to dev wallet + if dev_fee > 0 { + let transfer_ix = anchor_lang::solana_program::system_instruction::transfer( + &ctx.accounts.buyer.key(), + &ctx.accounts.dev_wallet.key(), + dev_fee as u64, + ); + + anchor_lang::solana_program::program::invoke( + &transfer_ix, + &[ + ctx.accounts.buyer.to_account_info(), + ctx.accounts.dev_wallet.to_account_info(), + ctx.accounts.system_program.to_account_info(), + ], + )?; + } + + // Transfer net purchase + dividend fee to vault (vault holds everything except dev fee) + let vault_amount = net_purchase + dividend_fee; + if vault_amount > 0 { + let transfer_ix = anchor_lang::solana_program::system_instruction::transfer( + &ctx.accounts.buyer.key(), + &ctx.accounts.vault.key(), + vault_amount as u64, + ); + + anchor_lang::solana_program::program::invoke( + &transfer_ix, + &[ + ctx.accounts.buyer.to_account_info(), + ctx.accounts.vault.to_account_info(), + ctx.accounts.system_program.to_account_info(), + ], + )?; + } + + // Distribute dividends to existing holders + if state.total_supply > 0 && dividend_fee > 0 { + let dividend_per_token = (dividend_fee * PRECISION) / state.total_supply as u128; + state.profit_per_share += dividend_per_token; + } + + // Calculate tokens to mint using bonding curve + let tokens_to_mint = calculate_tokens_for_sol(net_purchase as u64, state.total_supply, state)?; + + // Mint tokens to buyer + let seeds = &[b"state".as_ref(), &[state_bump]]; + let signer_seeds = &[&seeds[..]]; + + let cpi_ctx = CpiContext::new_with_signer( + ctx.accounts.token_program.to_account_info(), + MintTo { + mint: ctx.accounts.mint.to_account_info(), + to: ctx.accounts.buyer_token_account.to_account_info(), + authority: state_account_info, + }, + signer_seeds, + ); + token::mint_to(cpi_ctx, tokens_to_mint)?; + + state.total_supply += tokens_to_mint; + + emit!(TradeEvent { + user: buyer_key, + tokens: tokens_to_mint, + sol_amount, + is_buy: true, + }); + + msg!("Bought {} tokens for {} SOL", tokens_to_mint, sol_amount); + Ok(()) + } + + pub fn sell_tokens(ctx: Context, tokens_to_sell: u64) -> Result<()> { + let state = &mut ctx.accounts.state; + require!(tokens_to_sell > 0, ErrorCode::InvalidAmount); + require!(ctx.accounts.seller_token_account.amount >= tokens_to_sell, ErrorCode::InsufficientFunds); + + // Calculate SOL to return using bonding curve + let calculated_sol = calculate_sol_for_tokens(tokens_to_sell, state.total_supply, state)?; + + // Safety check: limit to vault balance to prevent errors + let vault_balance = ctx.accounts.vault.to_account_info().lamports(); + let sol_to_return = if calculated_sol > vault_balance { + msg!("Calculated return {} exceeds vault balance {}, limiting to vault balance", calculated_sol, vault_balance); + // Leave enough for rent exemption - be more conservative + vault_balance.saturating_sub(5000) // Leave 5000 lamports for rent exemption + } else { + calculated_sol + }; + + // Burn tokens from seller + let cpi_ctx = CpiContext::new( + ctx.accounts.token_program.to_account_info(), + Burn { + mint: ctx.accounts.mint.to_account_info(), + from: ctx.accounts.seller_token_account.to_account_info(), + authority: ctx.accounts.seller.to_account_info(), + }, + ); + token::burn(cpi_ctx, tokens_to_sell)?; + + state.total_supply -= tokens_to_sell; + + // Transfer SOL from vault to seller (direct lamport manipulation) + // This is the correct approach for program-owned PDAs as per Solana documentation + if sol_to_return > 0 { + // Direct lamport manipulation - standard practice for program-owned accounts + **ctx.accounts.vault.to_account_info().try_borrow_mut_lamports()? -= sol_to_return; + **ctx.accounts.seller.to_account_info().try_borrow_mut_lamports()? += sol_to_return; + + msg!("Transferred {} lamports from vault to seller", sol_to_return); + } + + emit!(TradeEvent { + user: ctx.accounts.seller.key(), + tokens: tokens_to_sell, + sol_amount: sol_to_return, + is_buy: false, + }); + + msg!("Sold {} tokens for {} SOL", tokens_to_sell, sol_to_return); + Ok(()) + } + + pub fn withdraw_dividends(ctx: Context) -> Result<()> { + let state = &ctx.accounts.state; + let user = &mut ctx.accounts.user; + let token_balance = ctx.accounts.token_account.amount as u128; + + // Calculate available dividends + let total_dividends = (state.profit_per_share * token_balance) / PRECISION; + let available_dividends = total_dividends - user.dividends_withdrawn; + + require!(available_dividends > 0, ErrorCode::NoDividends); + + user.dividends_withdrawn = total_dividends; + + // Transfer dividends from vault to user (direct lamport manipulation) + // This is the correct approach for program-owned PDAs + **ctx.accounts.vault.to_account_info().try_borrow_mut_lamports()? -= available_dividends as u64; + **ctx.accounts.user_authority.to_account_info().try_borrow_mut_lamports()? += available_dividends as u64; + + emit!(WithdrawalEvent { + user: ctx.accounts.user_authority.key(), + amount: available_dividends as u64, + }); + + msg!("Withdrew {} lamports in dividends", available_dividends); + Ok(()) + } +} + +// Realistic bonding curve based on actual SOL in vault +fn calculate_tokens_for_sol(sol: u64, supply: u64, _state: &PowhState) -> Result { + // Linear bonding curve: price increases with supply + // Base price: 0.0001 SOL per token (100,000 lamports per token) + // Price increases by 0.00001 SOL per billion tokens in supply + let base_price_lamports = 100_000u128; // 0.0001 SOL in lamports + let price_increment = 10_000u128; // 0.00001 SOL in lamports + let supply_factor = (supply as u128) / 1_000_000_000; // Per billion tokens + + let current_price = base_price_lamports + (price_increment * supply_factor); + let tokens = (sol as u128 * 1_000_000_000) / current_price; // Convert lamports to tokens + + msg!("Buy: {} lamports -> {} tokens at price {} lamports per token", sol, tokens, current_price); + Ok(tokens as u64) +} + +fn calculate_sol_for_tokens(tokens: u64, supply: u64, _state: &PowhState) -> Result { + // Sell at 90% of current buy price to create spread + let base_price_lamports = 100_000u128; + let price_increment = 10_000u128; + let supply_factor = (supply as u128) / 1_000_000_000; + + let current_price = base_price_lamports + (price_increment * supply_factor); + let sell_price = (current_price * 90) / 100; // 90% of buy price + let sol_lamports = (tokens as u128 * sell_price) / 1_000_000_000; + + msg!("Sell: {} tokens -> {} lamports at price {} lamports per token", tokens, sol_lamports, sell_price); + Ok(sol_lamports as u64) +} + +const PRECISION: u128 = 1_000_000_000_000_000_000; // 18 decimal places for dividend calculations + +#[derive(Accounts)] +pub struct Initialize<'info> { + #[account( + init, + payer = authority, + space = 8 + PowhState::INIT_SPACE, + seeds = [b"state"], + bump + )] + pub state: Account<'info, PowhState>, + + /// CHECK: This is the vault PDA for holding SOL + #[account( + init, + payer = authority, + space = 0, + seeds = [b"vault"], + bump + )] + pub vault: UncheckedAccount<'info>, + + #[account(mut)] + pub mint: Account<'info, Mint>, + + #[account(mut)] + pub authority: Signer<'info>, + + pub system_program: Program<'info, System>, + pub token_program: Program<'info, Token>, +} + +#[derive(Accounts)] +pub struct RegisterUser<'info> { + #[account( + seeds = [b"state"], + bump = state.bump + )] + pub state: Account<'info, PowhState>, + + #[account( + init, + payer = owner, + space = 8 + User::INIT_SPACE, + seeds = [b"user", owner.key().as_ref()], + bump + )] + pub user: Account<'info, User>, + + #[account( + init_if_needed, + payer = owner, + associated_token::mint = mint, + associated_token::authority = owner, + )] + pub token_account: Account<'info, TokenAccount>, + + pub mint: Account<'info, Mint>, + + #[account(mut)] + pub owner: Signer<'info>, + + pub system_program: Program<'info, System>, + pub token_program: Program<'info, Token>, + pub associated_token_program: Program<'info, AssociatedToken>, +} + +#[derive(Accounts)] +pub struct BuyTokens<'info> { + #[account( + mut, + seeds = [b"state"], + bump = state.bump + )] + pub state: Account<'info, PowhState>, + + /// CHECK: This is the vault PDA + #[account( + mut, + seeds = [b"vault"], + bump = state.vault_bump + )] + pub vault: UncheckedAccount<'info>, + + #[account(mut)] + pub mint: Account<'info, Mint>, + + #[account( + mut, + token::mint = mint, + token::authority = buyer, + )] + pub buyer_token_account: Account<'info, TokenAccount>, + + /// CHECK: Dev wallet for fees + #[account(mut)] + pub dev_wallet: UncheckedAccount<'info>, + + #[account(mut)] + pub buyer: Signer<'info>, + + pub system_program: Program<'info, System>, + pub token_program: Program<'info, Token>, +} + +#[derive(Accounts)] +pub struct SellTokens<'info> { + #[account( + mut, + seeds = [b"state"], + bump = state.bump + )] + pub state: Account<'info, PowhState>, + + /// CHECK: This is the vault PDA + #[account( + mut, + seeds = [b"vault"], + bump = state.vault_bump + )] + pub vault: UncheckedAccount<'info>, + + #[account(mut)] + pub mint: Account<'info, Mint>, + + #[account( + mut, + token::mint = mint, + token::authority = seller, + )] + pub seller_token_account: Account<'info, TokenAccount>, + + #[account(mut)] + pub seller: Signer<'info>, + + pub system_program: Program<'info, System>, + pub token_program: Program<'info, Token>, +} + +#[derive(Accounts)] +pub struct WithdrawDividends<'info> { + #[account( + seeds = [b"state"], + bump = state.bump + )] + pub state: Account<'info, PowhState>, + + /// CHECK: This is the vault PDA + #[account( + mut, + seeds = [b"vault"], + bump = state.vault_bump + )] + pub vault: UncheckedAccount<'info>, + + #[account( + mut, + seeds = [b"user", user_authority.key().as_ref()], + bump + )] + pub user: Account<'info, User>, + + #[account( + token::mint = mint, + token::authority = user_authority, + )] + pub token_account: Account<'info, TokenAccount>, + + pub mint: Account<'info, Mint>, + + #[account(mut)] + pub user_authority: Signer<'info>, + + pub system_program: Program<'info, System>, +} + +#[account] +#[derive(InitSpace)] +pub struct PowhState { + pub bump: u8, + pub vault_bump: u8, + pub authority: Pubkey, + pub mint: Pubkey, + pub vault: Pubkey, + pub total_supply: u64, + pub dev_fee_bps: u16, + pub dividend_fee_bps: u16, + pub token_price_initial: u64, + pub token_price_increment: u64, + pub profit_per_share: u128, +} + +#[account] +#[derive(InitSpace)] +pub struct User { + pub owner: Pubkey, + pub token_account: Pubkey, + pub dividends_withdrawn: u128, +} + +#[event] +pub struct TradeEvent { + pub user: Pubkey, + pub tokens: u64, + pub sol_amount: u64, + pub is_buy: bool, +} + +#[event] +pub struct WithdrawalEvent { + pub user: Pubkey, + pub amount: u64, +} + +#[error_code] +pub enum ErrorCode { + #[msg("Insufficient funds")] + InsufficientFunds, + #[msg("Invalid amount")] + InvalidAmount, + #[msg("No dividends available")] + NoDividends, +} \ No newline at end of file diff --git a/send-to-burn.sh b/send-to-burn.sh new file mode 100755 index 0000000..16edd50 --- /dev/null +++ b/send-to-burn.sh @@ -0,0 +1,98 @@ +#!/bin/bash + +echo "๐Ÿ”ฅ Sending All Tokens to Burn Address" +echo "=====================================" +echo "๐ŸŽฏ Burn Address: 1nc1nerator11111111111111111111111111111111" +echo "๐Ÿ“ Cluster: devnet (safe for testing)" +echo "" + +# Confirm before proceeding +read -p "Send ALL tokens to burn address? (type 'yes' to confirm): " confirm +if [ "$confirm" != "yes" ]; then + echo "โŒ Aborted" + exit 1 +fi + +echo "๐Ÿ”ฅ Starting burn process..." +echo "" + +# Set to devnet +solana config set --url devnet > /dev/null + +BURN_ADDRESS="1nc1nerator11111111111111111111111111111111" + +echo "๐Ÿ’ฐ Wallet: $(solana address)" +echo "๐Ÿ”ฅ Burn Address: $BURN_ADDRESS" +echo "" + +# Get all token accounts +echo "๐Ÿ“Š Current token accounts:" +spl-token accounts --url devnet +echo "" + +# List of token mints to burn +MINTS=( + "4auc435LJ9AfprLeMziHTJbP8wQmbSi7o4ZpeXdR66jQ" + "5xEQF57sR2L3tJBfdiiqaVtepTMa7nQR9uMybMojEY8n" + "8cJ8APx5TwwmpeRk4Zhz1Qbyi1T3HHdHUEw4GUJqxAGN" + "AK9fXWyDNWurYjZSDhbqBo6fczqLmCLbCZ3vq9Vftsqb" +) + +# Function to send tokens to burn address +burn_tokens() { + local mint=$1 + echo "๐Ÿ”ฅ Processing mint: $mint" + + # Get balance + local balance=$(spl-token balance $mint --url devnet 2>/dev/null || echo "0") + + if [ "$balance" == "0" ] || [ -z "$balance" ]; then + echo " โ„น๏ธ No balance - skipping" + return + fi + + echo " ๐Ÿ’ฐ Current balance: $balance" + + # Create associated token account for burn address if needed + echo " ๐Ÿญ Creating burn address token account..." + spl-token create-account $mint --owner $BURN_ADDRESS --url devnet 2>/dev/null || true + + # Transfer all tokens to burn address + echo " ๐Ÿ”ฅ Sending $balance tokens to burn address..." + local result=$(spl-token transfer $mint $balance $BURN_ADDRESS --url devnet --allow-unfunded-recipient 2>&1) + + if [ $? -eq 0 ]; then + echo " โœ… Successfully sent $balance tokens to burn address" + + # Close the now-empty account to reclaim rent + echo " ๐Ÿ—‘๏ธ Closing empty token account..." + spl-token close $mint --url devnet 2>/dev/null + if [ $? -eq 0 ]; then + echo " โœ… Token account closed, rent reclaimed" + else + echo " โš ๏ธ Could not close account" + fi + else + echo " โŒ Transfer failed: $result" + fi + + echo "" +} + +# Process each mint +for mint in "${MINTS[@]}"; do + burn_tokens $mint +done + +echo "๐ŸŽฏ Burn process complete!" +echo "" +echo "๐Ÿ“Š Final token account status:" +spl-token accounts --url devnet + +echo "" +echo "๐Ÿ’ฐ Final SOL balance:" +solana balance --url devnet + +echo "" +echo "๐Ÿ”ฅ All tokens have been sent to the incinerator!" +echo "โœ… Ready for clean testing!" \ No newline at end of file diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..41331e0 --- /dev/null +++ b/styles.css @@ -0,0 +1,119 @@ +/* Ticker */ +.ticker-wrap{ position:fixed; top:0; left:0; width:100%; height:36px; background: rgba(11,16,32,0.92); z-index:9999; overflow:hidden; box-shadow:0 2px 10px rgba(0,0,0,0.4); } +.ticker{ display:inline-block; white-space:nowrap; will-change:transform; animation: ticker 28s linear infinite; padding-left:100%; } +.ticker:hover{ animation-play-state: paused; } +.ticker-item{ display:inline-block; padding:8px 18px; font-family:'Press Start 2P',cursive; font-size:11px; color:#cbd5ff; opacity:0.95; } +.ticker-item.buy{ color:#22c55e; } +.ticker-item.sell{ color:#ef4444; } +@keyframes ticker{ 0%{ transform:translateX(0);} 100%{ transform:translateX(-100%);} } + +/* offset hero a bit since ticker is fixed */ +.hero{ padding-top: 64px; } + +/* Chip and delta styles */ +.chip{ background:#0e1430; color:#cbd5ff; border:1px solid rgba(34,211,238,0.35); padding:6px 10px; border-radius:999px; font-size:11px; font-family:'Press Start 2P',cursive; } +.delta{ margin-left:8px; font-size:10px; color:#22d3ee; opacity:0; transition:opacity .3s, transform .3s; font-family: 'Press Start 2P', cursive; text-shadow: 1px 1px 0px rgba(0,0,0,0.8); } +.delta.show{ opacity:1; transform:translateY(-2px) } +.delta.pos{ color:#22d3ee; text-shadow: 0 0 6px #22d3ee; } +.delta.neg{ color:#ef4444; text-shadow: 0 0 6px #ef4444; } + +/* Money rain (from nancymoneysite) */ +.money-rain{ position:fixed; top:0; left:0; width:100%; height:100%; pointer-events:none; z-index:-1; } +.money{ position:absolute; width:30px; height:15px; background:url('data:image/svg+xml;utf8,$') no-repeat center/contain; opacity:.4; animation:rain linear infinite; } +@keyframes rain{ 0%{ transform: translateY(-100vh) rotate(0deg);} 100%{ transform: translateY(100vh) rotate(360deg);} } + +/* Background animation from nancymoneysite */ +.animated-background { position: fixed; top:0; left:0; width:100%; height:100%; z-index:-2; background: var(--bg); overflow:hidden; } +.animated-wave { width:100%; height:100%; } +.wave { fill:none; stroke:#22d3ee; stroke-width:1; stroke-opacity:0.18; animation: chartMove 6s ease-in-out infinite; filter: drop-shadow(0 0 5px rgba(34,211,238,0.25)); } +.wave2 { stroke-opacity:0.12; animation-delay:-2s; } +.wave3 { stroke-opacity:0.08; animation-delay:-1s; } +@keyframes chartMove { + 0% { d: path("M0,90 L20,85 L40,80 L60,85 L80,70 L100,75"); } + 50% { d: path("M0,85 L20,70 L40,50 L60,30 L80,20 L100,10"); } + 100% { d: path("M0,90 L20,85 L40,80 L60,85 L80,70 L100,75"); } +} + + +/* Hero pot */ +.hero-pot { display:flex; align-items:center; justify-content:center; gap:16px; margin: 12px 0 8px; } +.hero-pot .amount { font-family:'Press Start 2P',cursive; font-size:34px; color:#fff; text-shadow:0 0 12px rgba(124,58,237,0.8); } +.hero-pot .timer { color: var(--muted); font-size:10px; font-family: 'Press Start 2P', cursive; } + +/* Tabs */ +.tabs .tabs-nav { display:flex; gap:8px; margin-bottom:8px; } +.tabs .tab { background:#0e1430; color:#cbd5ff; border:1px solid rgba(124,58,237,0.25); padding:8px 12px; border-radius:8px; cursor:pointer; font-family:'Press Start 2P',cursive; font-size:11px; } +.tabs .tab.active { background: linear-gradient(135deg, rgba(124,58,237,0.5), rgba(34,211,238,0.35)); color:#0b1020; } +.tab-content { margin-top:8px; } +.tab-content.active { display:block; } + +/* Numbers */ +.big { font-size: 26px; font-family:'Press Start 2P',cursive; } + +/* 8-bit headings */ +h2, h3, h4 { font-family: 'Press Start 2P', cursive; color: var(--accent); text-shadow: 2px 2px 0px rgba(0,0,0,0.5); } +h2 { font-size: 14px; margin: 0 0 12px 0; } +h3 { font-size: 12px; margin: 0 0 8px 0; } +p { font-family: 'Press Start 2P', cursive; font-size: 10px; line-height: 1.6; } + +/* Select styling */ +select { + background: #0e1430; + color: var(--text); + border: 1px solid rgba(124,58,237,0.25); + border-radius: 8px; + padding: 10px; + font-family: 'Press Start 2P', cursive; + font-size: 10px; +} + +/* Link styling */ +a { + color: var(--accent); + text-decoration: none; + font-family: 'Press Start 2P', cursive; + font-size: 10px; +} +a:hover { + color: #fff; + text-shadow: 0 0 8px var(--accent); +} + +/* 8-bit Dark Theme */ +:root { + --bg: #0b1020; + --panel: #151b2e; + --text: #dbe4ff; + --muted: #8ea0c7; + --primary: #7c3aed; + --accent: #22d3ee; +} +*{box-sizing:border-box} +body { margin:0; background:var(--bg); color:var(--text); font-family: 'Press Start 2P', cursive; font-size: 11px; line-height: 1.6; } +.hero { padding: 48px 0 28px; background: radial-gradient(1200px 600px at 50% -10%, rgba(124,58,237,0.35), transparent 60%), #0b1020; text-align:center; } +.hero h1 { font-family:'Press Start 2P', cursive; margin:0 0 8px; font-size: 28px; letter-spacing: 1px; } +.hero .sub { color: var(--muted); margin:0; font-family: 'Press Start 2P', cursive; font-size: 10px; } +.wrap { max-width: 1100px; margin: 0 auto; padding: 0 16px; } +.panel { background: var(--panel); border:1px solid rgba(124,58,237,0.15); border-radius: 12px; padding: 16px; margin: 16px 0; box-shadow: 0 8px 30px rgba(124,58,237,0.10); } +.row { display:flex; gap:16px; flex-wrap:wrap; } +.col { flex:1 1 420px; } +.grid2 { display:grid; grid-template-columns: 180px 1fr; gap:8px 12px; align-items:center; } +.label { color: var(--muted); font-size: 10px; font-family: 'Press Start 2P', cursive; text-transform: uppercase; } +.input { background:#0e1430; color:var(--text); border:1px solid rgba(124,58,237,0.25); border-radius:8px; padding:10px; width:100%; font-family: 'Press Start 2P', cursive; font-size: 10px; } +.wallet-row { display:flex; gap:8px; margin: 8px 0 12px; } +.btn { background: var(--primary); color:#fff; border:0; border-radius:8px; padding:10px 14px; font-family:'Press Start 2P', cursive; box-shadow:0 0 0 3px #000, 0 8px 0 0 #000; cursor:pointer; } +.btn:active { position:relative; top:2px; box-shadow:0 0 0 3px #000, 0 6px 0 0 #000; } +.btn.alt { background: var(--accent); color:#0b1020; } +.btn.danger { background:#ef4444; } +.muted { color: var(--muted); font-family: 'Press Start 2P', cursive; font-size: 10px; } +.log { background:#060912; border:1px solid rgba(124,58,237,0.15); border-radius:8px; padding:12px; min-height:160px; font-family: ui-monospace, Menlo, Monaco, Consolas, 'Courier New', monospace; overflow:auto; } +.foot { display:flex; justify-content:space-between; align-items:center; padding: 16px 0 48px; color: var(--muted); font-family: 'Press Start 2P', cursive; font-size: 10px; } +@media (max-width: 720px){ + .grid2{grid-template-columns:1fr; gap:12px;} + .label{font-size:9px; margin-bottom:4px;} + h2{font-size:12px;} + .hero h1{font-size:20px;} + .hero-pot .amount{font-size:24px;} + .btn{font-size:9px; padding:8px 10px;} + .input{font-size:9px;} +} diff --git a/switch-to-mainnet.sh b/switch-to-mainnet.sh new file mode 100755 index 0000000..d81c345 --- /dev/null +++ b/switch-to-mainnet.sh @@ -0,0 +1,57 @@ +#!/bin/bash + +# Simple script to switch from devnet to mainnet +set -e + +echo "๐Ÿ”„ Switching to Mainnet Configuration..." +echo "โš ๏ธ WARNING: You'll need to deploy the program to mainnet first!" +echo + +# Get current config +if [[ ! -f "config.json" ]]; then + echo "โŒ config.json not found" + exit 1 +fi + +# Show current config +echo "๐Ÿ“‹ Current config:" +cat config.json +echo + +# Get user inputs +read -p "๐Ÿ”‘ Enter MAINNET program ID: " PROGRAM_ID +read -p "๐Ÿช™ Enter MAINNET mint address: " MINT_ADDRESS +read -p "๐Ÿ’ฐ Enter MAINNET dev wallet (or press enter for current): " DEV_WALLET + +# Use current dev wallet if none provided +if [[ -z "$DEV_WALLET" ]]; then + DEV_WALLET=$(cat config.json | grep devWallet | cut -d'"' -f4) +fi + +# Create mainnet config +cat > config-mainnet.json << EOF +{ + "cluster": "https://api.mainnet-beta.solana.com", + "programId": "$PROGRAM_ID", + "mint": "$MINT_ADDRESS", + "devWallet": "$DEV_WALLET" +} +EOF + +# Backup current config +cp config.json config-devnet-backup.json + +# Switch to mainnet +cp config-mainnet.json config.json + +echo "โœ… Switched to mainnet!" +echo "๐Ÿ“ Devnet config backed up to: config-devnet-backup.json" +echo "๐Ÿ“ Mainnet config saved to: config-mainnet.json" +echo + +echo "๐Ÿ“ To deploy frontend with mainnet config:" +echo " ./deploy.sh" +echo + +echo "๐Ÿ“ To switch back to devnet:" +echo " cp config-devnet-backup.json config.json" \ No newline at end of file diff --git a/test-devnet.sh b/test-devnet.sh new file mode 100755 index 0000000..05033fe --- /dev/null +++ b/test-devnet.sh @@ -0,0 +1,86 @@ +#!/bin/bash + +echo "๐Ÿงช Lottery Devnet Testing Script" +echo "==============================" + +# Set to devnet +solana config set --url devnet +echo "โœ… Set Solana config to devnet" + +# Check wallet balance +echo "๐Ÿ’ฐ Checking wallet balance..." +BALANCE=$(solana balance) +echo "Current balance: $BALANCE" + +# Ensure we have enough SOL (at least 5 SOL for testing) +MIN_BALANCE="5.0" +BALANCE_NUM=$(echo $BALANCE | cut -d' ' -f1) + +if (( $(echo "$BALANCE_NUM < $MIN_BALANCE" | bc -l) )); then + echo "โŒ Insufficient balance for testing. Need at least 5 SOL." + echo "๐Ÿ’ธ Requesting airdrop..." + solana airdrop 5 + echo "โณ Waiting 10 seconds for airdrop confirmation..." + sleep 10 +fi + +# Build the program +echo "๐Ÿ”จ Building Anchor program..." +anchor build +if [ $? -ne 0 ]; then + echo "โŒ Build failed!" + exit 1 +fi + +# Deploy the program +echo "๐Ÿš€ Deploying to devnet..." +anchor deploy --provider.cluster devnet +if [ $? -ne 0 ]; then + echo "โŒ Deploy failed!" + exit 1 +fi + +# Generate the IDL +echo "๐Ÿ“ Generating IDL..." +anchor idl init -f target/idl/lottery_simple.json $(solana-keygen pubkey target/deploy/lottery_simple-keypair.json) + +echo "โœ… Program deployed successfully!" + +# Show deployment info +PROGRAM_ID=$(solana-keygen pubkey target/deploy/lottery_simple-keypair.json) +echo "๐Ÿ“ Program ID: $PROGRAM_ID" + +# Create a simple test to verify the deployment +echo "๐Ÿงช Creating simple test..." + +# Generate a new keypair for the mint +echo "๐Ÿ”‘ Creating mint keypair..." +solana-keygen new --outfile mint-keypair.json --no-bip39-passphrase + +# Create the mint +echo "๐Ÿช™ Creating token mint..." +MINT_ADDRESS=$(solana-keygen pubkey mint-keypair.json) +spl-token create-token mint-keypair.json +echo "โœ… Token mint created: $MINT_ADDRESS" + +# Generate devnet config +echo "๐Ÿ“„ Generating devnet configuration..." +cat > devnet-config.json << EOF +{ + "programId": "$PROGRAM_ID", + "mintAddress": "$MINT_ADDRESS", + "devWallet": "$(solana address)", + "cluster": "devnet", + "rpcUrl": "https://api.devnet.solana.com" +} +EOF + +echo "โœ… Devnet configuration saved to devnet-config.json" +echo "" +echo "๐ŸŽ‰ Deployment complete!" +echo "๐Ÿ“‹ Next steps:" +echo " 1. Update your frontend to use devnet-config.json" +echo " 2. Initialize the program state using the frontend or CLI" +echo " 3. Test buy/sell functionality" +echo "" +echo "โš ๏ธ Remember: This is devnet SOL - not real money!" \ No newline at end of file diff --git a/test-program.html b/test-program.html new file mode 100644 index 0000000..a9a2ed5 --- /dev/null +++ b/test-program.html @@ -0,0 +1,289 @@ + + + + + + PoWH Program Test - Devnet + + + + + +

๐Ÿงช PoWH Program Test - Devnet

+ +
+

Connection Status

+
Not connected
+ +
+ +
+

Program Information

+
+
Program ID: Loading...
+
Mint Address: Loading...
+
Cluster: devnet
+
State PDA: Not calculated
+
Vault PDA: Not calculated
+
+ +
+ +
+

Program Initialization

+
Ready to initialize
+ +
+ +
+

Test Trading

+
+ + +
+
+ + +
+
Ready to trade
+
+ + + + \ No newline at end of file diff --git a/ticker-api.php b/ticker-api.php new file mode 100644 index 0000000..033f1f2 --- /dev/null +++ b/ticker-api.php @@ -0,0 +1,79 @@ + 'Invalid input. Required: text, type']); + exit; + } + + $tickerData = readTickerData($tickerFile); + + // Add new item with timestamp + $newItem = [ + 'text' => $input['text'], + 'type' => $input['type'], // 'buy' or 'sell' + 'timestamp' => time() + ]; + + // Add optional SNS fields if provided + if (isset($input['fullAddress'])) { + $newItem['fullAddress'] = $input['fullAddress']; + } + if (isset($input['snsName'])) { + $newItem['snsName'] = $input['snsName']; + } + + // Add to beginning of array (most recent first) + array_unshift($tickerData, $newItem); + + // Keep only the last N items + if (count($tickerData) > $maxItems) { + $tickerData = array_slice($tickerData, 0, $maxItems); + } + + // Save to file + if (writeTickerData($tickerFile, $tickerData)) { + echo json_encode(['success' => true, 'itemsCount' => count($tickerData)]); + } else { + http_response_code(500); + echo json_encode(['error' => 'Failed to save ticker data']); + } + +} else { + http_response_code(405); + echo json_encode(['error' => 'Method not allowed']); +} +?> \ No newline at end of file diff --git a/ticker-data.json b/ticker-data.json new file mode 100644 index 0000000..69a46e2 --- /dev/null +++ b/ticker-data.json @@ -0,0 +1,17 @@ +[ + { + "text": "BUY 0.250 SOL โ€ข 4Zp2โ€ฆ8Tv3", + "type": "buy", + "timestamp": 1728219420 + }, + { + "text": "SELL 15.000 tk โ€ข 8Rv1โ€ฆ2Mn4", + "type": "sell", + "timestamp": 1728219380 + }, + { + "text": "BUY 0.100 SOL โ€ข 2Qm9โ€ฆ5Lp6", + "type": "buy", + "timestamp": 1728219340 + } +]