diff --git a/Cargo.lock b/Cargo.lock index 4d3a600..d36dc4c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -115,6 +115,167 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "anchor-attribute-access-control" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf7d535e1381be3de2c0716c0a1c1e32ad9df1042cddcf7bc18d743569e53319" +dependencies = [ + "anchor-syn", + "anyhow", + "proc-macro2 1.0.60", + "quote 1.0.28", + "regex", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-account" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3bcd731f21048a032be27c7791701120e44f3f6371358fc4261a7f716283d29" +dependencies = [ + "anchor-syn", + "anyhow", + "bs58 0.4.0", + "proc-macro2 1.0.60", + "quote 1.0.28", + "rustversion", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-constant" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1be64a48e395fe00b8217287f226078be2cf32dae42fdf8a885b997945c3d28" +dependencies = [ + "anchor-syn", + "proc-macro2 1.0.60", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-error" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38ea6713d1938c0da03656ff8a693b17dc0396da66d1ba320557f07e86eca0d4" +dependencies = [ + "anchor-syn", + "proc-macro2 1.0.60", + "quote 1.0.28", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-event" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d401f11efb3644285685f8339829a9786d43ed7490bb1699f33c478d04d5a582" +dependencies = [ + "anchor-syn", + "anyhow", + "proc-macro2 1.0.60", + "quote 1.0.28", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-interface" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6700a6f5c888a9c33fe8afc0c64fd8575fa28d05446037306d0f96102ae4480" +dependencies = [ + "anchor-syn", + "anyhow", + "heck 0.3.3", + "proc-macro2 1.0.60", + "quote 1.0.28", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-program" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ad769993b5266714e8939e47fbdede90e5c030333c7522d99a4d4748cf26712" +dependencies = [ + "anchor-syn", + "anyhow", + "proc-macro2 1.0.60", + "quote 1.0.28", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-state" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e677fae4a016a554acdd0e3b7f178d3acafaa7e7ffac6b8690cf4e171f1c116" +dependencies = [ + "anchor-syn", + "anyhow", + "proc-macro2 1.0.60", + "quote 1.0.28", + "syn 1.0.109", +] + +[[package]] +name = "anchor-derive-accounts" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "340beef6809d1c3fcc7ae219153d981e95a8a277ff31985bd7050e32645dc9a8" +dependencies = [ + "anchor-syn", + "anyhow", + "proc-macro2 1.0.60", + "quote 1.0.28", + "syn 1.0.109", +] + +[[package]] +name = "anchor-lang" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "662ceafe667448ee4199a4be2ee83b6bb76da28566eee5cea05f96ab38255af8" +dependencies = [ + "anchor-attribute-access-control", + "anchor-attribute-account", + "anchor-attribute-constant", + "anchor-attribute-error", + "anchor-attribute-event", + "anchor-attribute-interface", + "anchor-attribute-program", + "anchor-attribute-state", + "anchor-derive-accounts", + "arrayref", + "base64 0.13.1", + "bincode", + "borsh 0.9.3", + "bytemuck", + "solana-program", + "thiserror", +] + +[[package]] +name = "anchor-syn" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0418bcb5daac3b8cb1b60d8fdb1d468ca36f5509f31fb51179326fae1028fdcc" +dependencies = [ + "anyhow", + "bs58 0.3.1", + "heck 0.3.3", + "proc-macro2 1.0.60", + "proc-macro2-diagnostics", + "quote 1.0.28", + "serde", + "serde_json", + "sha2 0.9.9", + "syn 1.0.109", + "thiserror", +] + [[package]] name = "android-tzdata" version = "0.1.1" @@ -708,6 +869,12 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "bs58" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "476e9cd489f9e121e02ffa6014a8ef220ecb15c05ed23fc34cca13925dc283fb" + [[package]] name = "bs58" version = "0.4.0" @@ -1956,11 +2123,13 @@ dependencies = [ name = "holaplex-hub-nfts-solana" version = "0.1.0" dependencies = [ + "anchor-lang", "bincode", "holaplex-hub-core", "holaplex-hub-core-build", "holaplex-hub-nfts-solana-core", "holaplex-hub-nfts-solana-entity", + "mpl-bubblegum", "mpl-token-metadata", "prost", "serde", @@ -1968,7 +2137,9 @@ dependencies = [ "solana-client", "solana-program", "solana-sdk", + "spl-account-compression", "spl-associated-token-account", + "spl-noop", "spl-token", ] @@ -2522,6 +2693,21 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "mpl-bubblegum" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a589ceb05c6277253960665ee3658da89f055629c428beb64c55ad24a41b13" +dependencies = [ + "anchor-lang", + "bytemuck", + "mpl-token-metadata", + "solana-program", + "spl-account-compression", + "spl-associated-token-account", + "spl-token", +] + [[package]] name = "mpl-token-auth-rules" version = "1.3.0" @@ -3139,6 +3325,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proc-macro2-diagnostics" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bf29726d67464d49fa6224a1d07936a8c08bb3fba727c7493f6cf1616fdaada" +dependencies = [ + "proc-macro2 1.0.60", + "quote 1.0.28", + "syn 1.0.109", + "version_check", + "yansi", +] + [[package]] name = "prost" version = "0.11.9" @@ -4291,14 +4490,14 @@ dependencies = [ [[package]] name = "solana-account-decoder" -version = "1.14.18" +version = "1.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05a799348a70a5885cf428f1921e851cec204b58de1aeb0ca4409b5973d6d59d" +checksum = "b04c1316932017ae5f947e83d77cc0356c4a395130a480cdc17ffb0570a0c115" dependencies = [ "Inflector", "base64 0.13.1", "bincode", - "bs58", + "bs58 0.4.0", "bv", "lazy_static", "serde", @@ -4316,9 +4515,9 @@ dependencies = [ [[package]] name = "solana-address-lookup-table-program" -version = "1.14.18" +version = "1.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef5f98a080611a417da791853ca245ea7f58efefd4b5d9c5239e82693a65697" +checksum = "5be490ed850c99286a4e4ba169ce20695336fe666c56bd823bfd8db689d23a58" dependencies = [ "bincode", "bytemuck", @@ -4337,9 +4536,9 @@ dependencies = [ [[package]] name = "solana-clap-utils" -version = "1.14.18" +version = "1.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43985f76c072db0412de3dcd8976bf6bc040ee10da8480fb5ba6b9455d733e6f" +checksum = "36228e03e14bc7d7707189b66f625981993f1a000b0b192d5b42367349901d91" dependencies = [ "chrono", "clap 2.34.0", @@ -4355,9 +4554,9 @@ dependencies = [ [[package]] name = "solana-cli-config" -version = "1.14.18" +version = "1.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c6b277a2927981b7f4e437741a37fc457eed5da7de6317c2a89a6996fd573e1" +checksum = "6c43b08f24fd605eaeaafe0e834dc9b209137ac253bc874d32a5bdd791cbd318" dependencies = [ "dirs-next", "lazy_static", @@ -4371,15 +4570,15 @@ dependencies = [ [[package]] name = "solana-client" -version = "1.14.18" +version = "1.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839f0ebb1c14a25da0e2118a96ed630a49e3aa524a459b7ab98b410f44abcc7" +checksum = "a3e270b1afd0b360c2aec42ae302ae7980ebb226017275b32a6156ab2ccbdad9" dependencies = [ "async-mutex", "async-trait", "base64 0.13.1", "bincode", - "bs58", + "bs58 0.4.0", "bytes", "clap 2.34.0", "crossbeam-channel", @@ -4425,9 +4624,9 @@ dependencies = [ [[package]] name = "solana-config-program" -version = "1.14.18" +version = "1.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94cd8f45fddff299b73121fbf751164b7e029b3324b274b50160d787c82673d2" +checksum = "fb275d80a482134f0f0c5439b0c40ba3f04bef70dbc46c0e47f6107f6ae482a8" dependencies = [ "bincode", "chrono", @@ -4439,9 +4638,9 @@ dependencies = [ [[package]] name = "solana-faucet" -version = "1.14.18" +version = "1.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a4b7f4d15cb628a7f89e570a18914551211a5f1da81352dffd93881b191986a" +checksum = "b3ef95ad1f87b8c011d0e4d85a46f4a703e9dd7e722459659b395ed70d6ba924" dependencies = [ "bincode", "byteorder", @@ -4463,14 +4662,14 @@ dependencies = [ [[package]] name = "solana-frozen-abi" -version = "1.14.18" +version = "1.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc7245b88e5bcedc9096d7c7ffd8cf6769987b151e381e8a3561939898d9e495" +checksum = "f44a019070a6cec4d3ad8605c5caa65bdaa13f00b5f1849340f44ffea63b625b" dependencies = [ "ahash 0.7.6", "blake3", "block-buffer 0.9.0", - "bs58", + "bs58 0.4.0", "bv", "byteorder", "cc", @@ -4497,9 +4696,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi-macro" -version = "1.14.18" +version = "1.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "546f204604da1d6958e412f4d3bc8cad34de6a81dc379fac07e53a29e224bcf0" +checksum = "be23cc7a382f54dfe1348edb94610e5cc146b8eb21563cdd04062a403c75ba62" dependencies = [ "proc-macro2 1.0.60", "quote 1.0.28", @@ -4509,9 +4708,9 @@ dependencies = [ [[package]] name = "solana-logger" -version = "1.14.18" +version = "1.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12090fa9b638f374492c86c62b79e0e82479e3632ced02a33ff560ffdce72e04" +checksum = "447d16a70a1b5383736ef44801050c0e1affd022303b22ed899352f958c2de4b" dependencies = [ "env_logger", "lazy_static", @@ -4520,9 +4719,9 @@ dependencies = [ [[package]] name = "solana-measure" -version = "1.14.18" +version = "1.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c98a872ae83f2e7c00846108f98a18f7f40265b2cd86b2d44369c33d9b7fb8f1" +checksum = "2400d2534a19f7605c5059060edea0499600a223f1a1f6a4b172666c04946a77" dependencies = [ "log", "solana-sdk", @@ -4530,9 +4729,9 @@ dependencies = [ [[package]] name = "solana-metrics" -version = "1.14.18" +version = "1.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7557878951c7defed6e4daf34e9334d8ea85b82c9a1b2d5cc50d069fd9191db9" +checksum = "68aaa3d683945dc3b6ca38923ef952ca1f96a27b61f898a1ddf9f4cd79f2df92" dependencies = [ "crossbeam-channel", "gethostname", @@ -4544,9 +4743,9 @@ dependencies = [ [[package]] name = "solana-net-utils" -version = "1.14.18" +version = "1.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7684c80c774275783bb754aa07e2e18f2064551a78cda5e54e12f44c85f3803d" +checksum = "d6d7093739e143d5e2edf3e81e523d47228adb802b847d66f4ab819be7ad6dc8" dependencies = [ "bincode", "clap 3.2.25", @@ -4566,9 +4765,9 @@ dependencies = [ [[package]] name = "solana-perf" -version = "1.14.18" +version = "1.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2db417718e96fd2473025d4f2afb975dd295e9f7bd479cd3a0bcea20da38088" +checksum = "cbc742f8d53f0a6e6f3a27ed11c1d0764b5486813c721d625c56094fcd14e984" dependencies = [ "ahash 0.7.6", "bincode", @@ -4593,9 +4792,9 @@ dependencies = [ [[package]] name = "solana-program" -version = "1.14.18" +version = "1.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e7df881407995597cf32299df06cc8ac3d7fc4cd53e69e95964832beca48c3" +checksum = "d0937481f080f5dd495fae456c94718a7bacf30fb5fdabb02dcb8a9622e446d5" dependencies = [ "base64 0.13.1", "bincode", @@ -4603,7 +4802,7 @@ dependencies = [ "blake3", "borsh 0.9.3", "borsh-derive 0.9.3", - "bs58", + "bs58 0.4.0", "bv", "bytemuck", "cc", @@ -4642,9 +4841,9 @@ dependencies = [ [[package]] name = "solana-program-runtime" -version = "1.14.18" +version = "1.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba1ad7f8f71d46673e2b68edb902856516795dd6b9d2322fa4e9edcd6cf0caac" +checksum = "b4d12047608bac77fca000e18f7a2df3c7fa90656d7c7d387b1cd7faf18b238c" dependencies = [ "base64 0.13.1", "bincode", @@ -4669,9 +4868,9 @@ dependencies = [ [[package]] name = "solana-rayon-threadlimit" -version = "1.14.18" +version = "1.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccad09c8fbcb13ba7a1aca9d6337bf439593e1ea104d7ba9519d6d09c89da63c" +checksum = "b6eca67181e0381532db4bc69a625b1f96a047be461ff9050c451add0165424f" dependencies = [ "lazy_static", "num_cpus", @@ -4679,9 +4878,9 @@ dependencies = [ [[package]] name = "solana-remote-wallet" -version = "1.14.18" +version = "1.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a34ea5c66161b5f6a2085804bd0364bcdfdd584cfdb7237f88b6c3255199601" +checksum = "9b83d035ee90035ebcb07ec73672fdc0272e5b98899846dd29fcb31f856ac78c" dependencies = [ "console", "dialoguer", @@ -4698,16 +4897,16 @@ dependencies = [ [[package]] name = "solana-sdk" -version = "1.14.18" +version = "1.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bdc5c047bf29730ad00e2c9ef92d396877c836633177089a00b7311e6eb3ead" +checksum = "390e7481c56dda2ceab2652beeda30a533e9667b34861a2eb4eec92fa1d826d7" dependencies = [ "assert_matches", "base64 0.13.1", "bincode", "bitflags", "borsh 0.9.3", - "bs58", + "bs58 0.4.0", "bytemuck", "byteorder", "chrono", @@ -4749,11 +4948,11 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "1.14.18" +version = "1.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43cff60ba1f94594f1de7baf649bf781383e806e834e26607ff8857a9452cd3c" +checksum = "33d0acbad862093ea123f3a27364336dcb0c8373522cd6810496a34e932c56c1" dependencies = [ - "bs58", + "bs58 0.4.0", "proc-macro2 1.0.60", "quote 1.0.28", "rustversion", @@ -4762,9 +4961,9 @@ dependencies = [ [[package]] name = "solana-streamer" -version = "1.14.18" +version = "1.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "753f510e0e145e70238fc597571e2bb5f2871dc022b04e869024b5dcf1fd82c3" +checksum = "853b0187fdf233c13e8b7ba76e61d0c7cb49ca92c5fdb3b7568ad5ca30e2cf88" dependencies = [ "crossbeam-channel", "futures-util", @@ -4791,15 +4990,15 @@ dependencies = [ [[package]] name = "solana-transaction-status" -version = "1.14.18" +version = "1.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe6a451415da98f850d5777df18d588d7504393106aea295b642cd243115ed77" +checksum = "3c5bbdaed99403e4a17763bee60c1e0e3418524503c72b514ebff62efbcc9d33" dependencies = [ "Inflector", "base64 0.13.1", "bincode", "borsh 0.9.3", - "bs58", + "bs58 0.4.0", "lazy_static", "log", "serde", @@ -4820,9 +5019,9 @@ dependencies = [ [[package]] name = "solana-version" -version = "1.14.18" +version = "1.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a3d9aa0a819a22f5befc7e8df5413259621b5d20be0a5a210d1fb41a083a09b" +checksum = "5a46c9ecb15ccd5388511cec0c5bfb989589425f8286ce432ff64b55dc7bf61e" dependencies = [ "log", "rustc_version", @@ -4836,9 +5035,9 @@ dependencies = [ [[package]] name = "solana-vote-program" -version = "1.14.18" +version = "1.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb0bb49cc1490ce16133368f4a04e0671f856d481f95416f03f08fede7d993ba" +checksum = "81ab9ff8928282cb42871a370435dd4713f700854801afb476cf63066f1337db" dependencies = [ "bincode", "log", @@ -4857,9 +5056,9 @@ dependencies = [ [[package]] name = "solana-zk-token-sdk" -version = "1.14.18" +version = "1.14.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7a679b4dabee8d23a7bfa657440c892a88420191da11352313ab83f986826a7" +checksum = "cebca4083e982ae01583d1a590c4d679e6f648a4761364ddfb43026d2c433142" dependencies = [ "aes-gcm-siv", "arrayref", @@ -4902,11 +5101,23 @@ dependencies = [ "der", ] +[[package]] +name = "spl-account-compression" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7a5417eae3c924553b872de5f1bca5945334a235f8d94841bd44c6dd7c6358c" +dependencies = [ + "anchor-lang", + "bytemuck", + "spl-concurrent-merkle-tree", + "spl-noop", +] + [[package]] name = "spl-associated-token-account" -version = "1.1.3" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978dba3bcbe88d0c2c58366c254d9ea41c5f73357e72fc0bdee4d6b5fc99c8f4" +checksum = "fbc000f0fdf1f12f99d77d398137c1751345b18c88258ce0f99b7872cf6c9bd6" dependencies = [ "assert_matches", "borsh 0.9.3", @@ -4918,6 +5129,17 @@ dependencies = [ "thiserror", ] +[[package]] +name = "spl-concurrent-merkle-tree" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26dd605d33bdc8d2522a9f55207c3eac06737b2e8310f602e252b510e3db1210" +dependencies = [ + "bytemuck", + "solana-program", + "thiserror", +] + [[package]] name = "spl-memo" version = "3.0.1" @@ -4927,6 +5149,15 @@ dependencies = [ "solana-program", ] +[[package]] +name = "spl-noop" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "558536c75b5aed018113bfca39cddb414cd7ca77da7658d668e751d977830cda" +dependencies = [ + "solana-program", +] + [[package]] name = "spl-token" version = "3.5.0" @@ -4944,9 +5175,9 @@ dependencies = [ [[package]] name = "spl-token-2022" -version = "0.6.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0043b590232c400bad5ee9eb983ced003d15163c4c5d56b090ac6d9a57457b47" +checksum = "0edb869dbe159b018f17fb9bfa67118c30f232d7f54a73742bc96794dff77ed8" dependencies = [ "arrayref", "bytemuck", @@ -6097,6 +6328,12 @@ dependencies = [ "linked-hash-map", ] +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + [[package]] name = "yasna" version = "0.5.2" diff --git a/consumer/Cargo.toml b/consumer/Cargo.toml index 6a4e594..1b1a065 100644 --- a/consumer/Cargo.toml +++ b/consumer/Cargo.toml @@ -10,15 +10,19 @@ build = "build.rs" [lib] [dependencies] +anchor-lang = "0.26.0" bincode = "1.3.3" prost = "0.11.6" serde = { version = "1.0.152", features = ["derive"] } serde_json = "1.0.93" solana-program = "1.14.8" solana-client = "1.14.8" +spl-account-compression = "0.1.10" +spl-noop = "0.1.3" spl-token = "3.5.0" solana-sdk = "1.14.8" spl-associated-token-account = "1.1.2" +mpl-bubblegum = "0.8.0" mpl-token-metadata = "1.8.3" holaplex-hub-nfts-solana-core = { path = "../core" } holaplex-hub-nfts-solana-entity = { path = "../entity" } diff --git a/consumer/proto.lock b/consumer/proto.lock index 13c853d..ea17798 100644 --- a/consumer/proto.lock +++ b/consumer/proto.lock @@ -6,7 +6,7 @@ sha512 = "67fadd3a6185229df033804be2e598b13ac6cbb0464e4e2c4e91caa85d116527170aaf [[schemas]] subject = "solana_nfts" version = 2 -sha512 = "a42cfd38aee98c6fbe445f889430be9fe5a2d84319858063f8f4f9e3d83015f869784246c1b6d5143247c93448560ebad1e225a2769d4743ad6e99bba53ae191" +sha512 = "af3d6037731fafd7aca187e6a858152cfaa225b1f4223ee695fc93f82094d6dc4b75fd432aa10222f7dd943ea7d0e4edccf83c713a4553e5672dc6b908ce2812" [[schemas]] subject = "treasury" diff --git a/consumer/src/backend.rs b/consumer/src/backend.rs new file mode 100644 index 0000000..39cf1f0 --- /dev/null +++ b/consumer/src/backend.rs @@ -0,0 +1,79 @@ +use holaplex_hub_nfts_solana_entity::{collection_mints, collections}; + +use crate::proto::{ + MetaplexMasterEditionTransaction, MintMetaplexEditionTransaction, + TransferMetaplexAssetTransaction, +}; +use hub_core::prelude::*; +use solana_program::pubkey::Pubkey; + +#[derive(Clone)] +pub struct MasterEditionAddresses { + pub metadata: Pubkey, + pub associated_token_account: Pubkey, + pub owner: Pubkey, + pub master_edition: Pubkey, + pub mint: Pubkey, + pub update_authority: Pubkey, +} + +#[derive(Clone)] +pub struct MintEditionAddresses { + pub edition: Pubkey, + pub mint: Pubkey, + pub metadata: Pubkey, + pub owner: Pubkey, + pub associated_token_account: Pubkey, +} + +#[derive(Clone)] +pub struct UpdateMasterEditionAddresses { + pub metadata: Pubkey, + pub update_authority: Pubkey, +} + +#[derive(Clone)] +pub struct TransferAssetAddresses { + pub owner: Pubkey, + pub recipient: Pubkey, + pub recipient_associated_token_account: Pubkey, + pub owner_associated_token_account: Pubkey, +} + +/// Represents a response from a transaction on the blockchain. This struct +/// provides the serialized message and the signatures of the signed message. +pub struct TransactionResponse { + /// The serialized version of the message from the transaction. + pub serialized_message: Vec, + + /// The signatures of the signed message or the public keys of wallets that should sign the transaction. Order matters. + pub signatures_or_signers_public_keys: Vec, + + /// Addresses that are related to the transaction. + pub addresses: A, +} + +pub trait Backend { + fn create( + &self, + txn: MetaplexMasterEditionTransaction, + ) -> Result>; + + fn mint( + &self, + collection: collections::Model, + txn: MintMetaplexEditionTransaction, + ) -> Result>; + + fn update( + &self, + collection: collections::Model, + txn: MetaplexMasterEditionTransaction, + ) -> Result>; + + fn transfer( + &self, + mint: collection_mints::Model, + txn: TransferMetaplexAssetTransaction, + ) -> Result>; +} diff --git a/consumer/src/events.rs b/consumer/src/events.rs index 2014376..a8b05b7 100644 --- a/consumer/src/events.rs +++ b/consumer/src/events.rs @@ -3,6 +3,7 @@ use holaplex_hub_nfts_solana_entity::{collection_mints, collections}; use hub_core::{prelude::*, producer::Producer, thiserror::Error, uuid::Uuid}; use crate::{ + backend::{self, MasterEditionAddresses, TransactionResponse}, proto::{ solana_events::Event::{ CreateDrop, MintDrop, RetryDrop, RetryMintDrop, TransferAsset, UpdateDrop, @@ -15,10 +16,12 @@ use crate::{ }, treasury_events::Event as TreasuryEvent, MetaplexMasterEditionTransaction, MintMetaplexEditionTransaction, NftEventKey, - SolanaCompletedTransaction, SolanaNftEventKey, SolanaNftEvents, SolanaPendingTransaction, - TransferMetaplexAssetTransaction, TreasuryEventKey, + SolanaCompletedMintTransaction, SolanaCompletedTransferTransaction, + SolanaCompletedUpdateTransaction, SolanaNftEventKey, SolanaNftEvents, + SolanaPendingTransaction, TransferMetaplexAssetTransaction, TreasuryEventKey, }, - solana::{MasterEditionAddresses, Solana, TransactionResponse}, + solana::Solana, + solana_compressed::SolanaCompressed, Services, }; @@ -33,15 +36,22 @@ pub enum ProcessorError { #[derive(Clone)] pub struct Processor { solana: Solana, + compressed: SolanaCompressed, db: Connection, producer: Producer, } impl Processor { #[must_use] - pub fn new(solana: Solana, db: Connection, producer: Producer) -> Self { + pub fn new( + solana: Solana, + compressed: SolanaCompressed, + db: Connection, + producer: Producer, + ) -> Self { Self { solana, + compressed, db, producer, } @@ -57,14 +67,49 @@ impl Processor { Services::Nfts(key, e) => { let key = SolanaNftEventKey::from(key); - match e.event { - Some(CreateDrop(payload)) => self.create_drop(key, payload).await, - Some(MintDrop(payload)) => self.mint_drop(key, payload).await, - Some(UpdateDrop(payload)) => self.update_drop(key, payload).await, - Some(TransferAsset(payload)) => self.transfer_asset(key, payload).await, - Some(RetryDrop(payload)) => self.retry_drop(key, payload).await, - Some(RetryMintDrop(payload)) => self.retry_mint_drop(key, payload).await, - None => Ok(()), + if true { + // TODO + match e.event { + Some(CreateDrop(payload)) => { + self.create_drop(&self.compressed, key, payload).await + }, + Some(MintDrop(payload)) => { + self.mint_drop(&self.compressed, key, payload).await + }, + Some(UpdateDrop(payload)) => { + self.update_drop(&self.compressed, key, payload).await + }, + Some(TransferAsset(payload)) => { + self.transfer_asset(&self.compressed, key, payload).await + }, + Some(RetryDrop(payload)) => { + self.retry_drop(&self.compressed, key, payload).await + }, + Some(RetryMintDrop(payload)) => { + self.retry_mint_drop(&self.compressed, key, payload).await + }, + None => Ok(()), + } + } else { + match e.event { + Some(CreateDrop(payload)) => { + self.create_drop(&self.solana, key, payload).await + }, + Some(MintDrop(payload)) => self.mint_drop(&self.solana, key, payload).await, + Some(UpdateDrop(payload)) => { + self.update_drop(&self.solana, key, payload).await + }, + Some(TransferAsset(payload)) => { + self.transfer_asset(&self.solana, key, payload).await + }, + Some(RetryDrop(payload)) => { + self.retry_drop(&self.solana, key, payload).await + }, + Some(RetryMintDrop(payload)) => { + self.retry_mint_drop(&self.solana, key, payload).await + }, + None => Ok(()), + } } }, Services::Treasury(key, e) => { @@ -119,12 +164,13 @@ impl Processor { } } - async fn create_drop( + async fn create_drop( &self, + backend: &B, key: SolanaNftEventKey, payload: MetaplexMasterEditionTransaction, ) -> Result<()> { - let tx = self.solana.create(payload.clone())?; + let tx = backend.create(payload.clone())?; let MasterEditionAddresses { metadata, @@ -161,12 +207,13 @@ impl Processor { Ok(()) } - async fn retry_drop( + async fn retry_drop( &self, + backend: &B, key: SolanaNftEventKey, payload: MetaplexMasterEditionTransaction, ) -> Result<()> { - let tx = self.solana.create(payload.clone())?; + let tx = backend.create(payload.clone())?; let MasterEditionAddresses { metadata, @@ -205,8 +252,9 @@ impl Processor { Ok(()) } - async fn mint_drop( + async fn mint_drop( &self, + backend: &B, key: SolanaNftEventKey, payload: MintMetaplexEditionTransaction, ) -> Result<()> { @@ -218,7 +266,7 @@ impl Processor { .await? .ok_or(ProcessorError::RecordNotFound)?; - let tx = self.solana.mint(collection, payload)?; + let tx = backend.mint(collection, payload)?; let collection_mint = collection_mints::Model { id, @@ -243,8 +291,9 @@ impl Processor { Ok(()) } - async fn retry_mint_drop( + async fn retry_mint_drop( &self, + backend: &B, key: SolanaNftEventKey, payload: MintMetaplexEditionTransaction, ) -> Result<()> { @@ -259,7 +308,7 @@ impl Processor { .await? .ok_or(ProcessorError::RecordNotFound)?; - let tx = self.solana.mint(collection, payload)?; + let tx = backend.mint(collection, payload)?; let mut collection_mint: collection_mints::ActiveModel = collection_mint.into(); @@ -282,8 +331,9 @@ impl Processor { Ok(()) } - async fn update_drop( + async fn update_drop( &self, + backend: &B, key: SolanaNftEventKey, payload: MetaplexMasterEditionTransaction, ) -> Result<()> { @@ -293,7 +343,7 @@ impl Processor { .await? .ok_or(ProcessorError::RecordNotFound)?; - let tx = self.solana.update(collection, payload)?; + let tx = backend.update(collection, payload)?; self.producer .send( @@ -307,8 +357,9 @@ impl Processor { Ok(()) } - async fn transfer_asset( + async fn transfer_asset( &self, + backend: &B, key: SolanaNftEventKey, payload: TransferMetaplexAssetTransaction, ) -> Result<()> { @@ -317,7 +368,7 @@ impl Processor { .await? .ok_or(ProcessorError::RecordNotFound)?; - let tx = self.solana.transfer(collection_mint, payload)?; + let tx = backend.transfer(collection_mint, payload)?; self.producer .send( @@ -332,10 +383,14 @@ impl Processor { } async fn create_drop_submitted(&self, key: SolanaNftEventKey, signature: String) -> Result<()> { + // TODO: who broke the build? the schema changed checksums randomly + let address = todo!("build reproducibility failure!!"); + self.producer .send( Some(&SolanaNftEvents { - event: Some(CreateDropSubmitted(SolanaCompletedTransaction { + event: Some(CreateDropSubmitted(SolanaCompletedMintTransaction { + address, signature, })), }), @@ -350,7 +405,8 @@ impl Processor { self.producer .send( Some(&SolanaNftEvents { - event: Some(UpdateDropSubmitted(SolanaCompletedTransaction { + // TODO + event: Some(UpdateDropSubmitted(SolanaCompletedUpdateTransaction { signature, })), }), @@ -362,10 +418,15 @@ impl Processor { } async fn mint_drop_submitted(&self, key: SolanaNftEventKey, signature: String) -> Result<()> { + let address = todo!("build reproducibility failure!!"); + self.producer .send( Some(&SolanaNftEvents { - event: Some(MintDropSubmitted(SolanaCompletedTransaction { signature })), + event: Some(MintDropSubmitted(SolanaCompletedMintTransaction { + address, + signature, + })), }), Some(&key), ) @@ -382,7 +443,7 @@ impl Processor { self.producer .send( Some(&SolanaNftEvents { - event: Some(TransferAssetSubmitted(SolanaCompletedTransaction { + event: Some(TransferAssetSubmitted(SolanaCompletedTransferTransaction { signature, })), }), @@ -398,10 +459,13 @@ impl Processor { key: SolanaNftEventKey, signature: String, ) -> Result<()> { + let address = todo!("build reproducibility failure!!"); + self.producer .send( Some(&SolanaNftEvents { - event: Some(RetryCreateDropSubmitted(SolanaCompletedTransaction { + event: Some(RetryCreateDropSubmitted(SolanaCompletedMintTransaction { + address, signature, })), }), @@ -417,10 +481,13 @@ impl Processor { key: SolanaNftEventKey, signature: String, ) -> Result<()> { + let address = todo!("build reproducibility failure!!"); + self.producer .send( Some(&SolanaNftEvents { - event: Some(RetryMintDropSubmitted(SolanaCompletedTransaction { + event: Some(RetryMintDropSubmitted(SolanaCompletedMintTransaction { + address, signature, })), }), diff --git a/consumer/src/lib.rs b/consumer/src/lib.rs index 62876be..1dbfc48 100644 --- a/consumer/src/lib.rs +++ b/consumer/src/lib.rs @@ -2,8 +2,10 @@ #![warn(clippy::pedantic, clippy::cargo)] #![allow(clippy::module_name_repetitions)] +mod backend; pub mod events; pub mod solana; +pub mod solana_compressed; use holaplex_hub_nfts_solana_core::db::DbArgs; use hub_core::{clap, consumer::RecvError, prelude::*}; @@ -62,4 +64,7 @@ pub struct Args { #[command(flatten)] pub solana: SolanaArgs, + + #[command(flatten)] + pub solana_compressed: solana_compressed::SolanaCompressedArgs, } diff --git a/consumer/src/main.rs b/consumer/src/main.rs index 78b4195..f73e990 100644 --- a/consumer/src/main.rs +++ b/consumer/src/main.rs @@ -1,6 +1,12 @@ use std::sync::Arc; -use holaplex_hub_nfts_solana::{events::Processor, proto, solana::Solana, Args, Services}; +use holaplex_hub_nfts_solana::{ + events::Processor, + proto, + solana::{Solana, SolanaArgs}, + solana_compressed::SolanaCompressed, + Args, Services, +}; use holaplex_hub_nfts_solana_core::db::Connection; use hub_core::{prelude::*, tokio}; use solana_client::rpc_client::RpcClient; @@ -11,7 +17,15 @@ pub fn main() { }; hub_core::run(opts, |common, args| { - let Args { db, solana } = args; + let Args { + db, + solana: + SolanaArgs { + solana_endpoint, + solana_treasury_wallet_address, + }, + solana_compressed, + } = args; common.rt.block_on(async move { let connection = Connection::new(db) @@ -23,11 +37,18 @@ pub fn main() { .build::() .await?; - let solana_rpc = Arc::new(RpcClient::new(solana.solana_endpoint)); - let solana = Solana::new(solana_rpc, solana.solana_treasury_wallet_address); + let solana_rpc = Arc::new(RpcClient::new(solana_endpoint)); + let solana = Solana::new(solana_rpc.clone(), solana_treasury_wallet_address.clone()); + let compressed = SolanaCompressed::new( + solana_rpc, + solana_treasury_wallet_address + .parse() + .context("Error parsing treasury wallet address")?, + solana_compressed, + ); let cons = common.consumer_cfg.build::().await?; - let event_processor = Processor::new(solana, connection, producer); + let event_processor = Processor::new(solana, compressed, connection, producer); let mut stream = cons.stream(); loop { diff --git a/consumer/src/solana.rs b/consumer/src/solana.rs index 1862c04..20a8c32 100644 --- a/consumer/src/solana.rs +++ b/consumer/src/solana.rs @@ -1,5 +1,3 @@ -use std::vec; - use holaplex_hub_nfts_solana_entity::{collection_mints, collections}; use hub_core::{anyhow::Result, clap, prelude::*, thiserror::Error, uuid::Uuid}; use mpl_token_metadata::{ @@ -21,10 +19,16 @@ use spl_token::{ state, }; -use crate::proto::{ - treasury_events::SolanaSignedTransaction, Creator as ProtoCreator, MasterEdition, - MetaplexMasterEditionTransaction, MintMetaplexEditionTransaction, - TransferMetaplexAssetTransaction, +use crate::{ + backend::{ + Backend, MasterEditionAddresses, MintEditionAddresses, TransactionResponse, + TransferAssetAddresses, UpdateMasterEditionAddresses, + }, + proto::{ + treasury_events::SolanaSignedTransaction, Creator as ProtoCreator, MasterEdition, + MetaplexMasterEditionTransaction, MintMetaplexEditionTransaction, + TransferMetaplexAssetTransaction, + }, }; const TOKEN_PROGRAM_PUBKEY: &str = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"; @@ -64,52 +68,6 @@ pub struct TransferAssetRequest { pub mint_address: String, } -#[derive(Clone)] -pub struct MasterEditionAddresses { - pub metadata: Pubkey, - pub associated_token_account: Pubkey, - pub owner: Pubkey, - pub master_edition: Pubkey, - pub mint: Pubkey, - pub update_authority: Pubkey, -} - -#[derive(Clone)] -pub struct MintEditionAddresses { - pub edition: Pubkey, - pub mint: Pubkey, - pub metadata: Pubkey, - pub owner: Pubkey, - pub associated_token_account: Pubkey, -} - -#[derive(Clone)] -pub struct UpdateMasterEditionAddresses { - pub metadata: Pubkey, - pub update_authority: Pubkey, -} - -#[derive(Clone)] -pub struct TransferAssetAddresses { - pub owner: Pubkey, - pub recipient: Pubkey, - pub recipient_associated_token_account: Pubkey, - pub owner_associated_token_account: Pubkey, -} - -/// Represents a response from a transaction on the blockchain. This struct -/// provides the serialized message and the signatures of the signed message. -pub struct TransactionResponse { - /// The serialized version of the message from the transaction. - pub serialized_message: Vec, - - /// The signatures of the signed message or the public keys of wallets that should sign the transaction. Order matters. - pub signatures_or_signers_public_keys: Vec, - - /// Addresses that are related to the transaction. - pub addresses: A, -} - #[derive(Debug, Error)] enum SolanaError { #[error("master edition message not found")] @@ -161,11 +119,148 @@ impl Solana { Ok(signature.to_string()) } - /// Res - /// - /// # Errors - /// This function fails if unable to assemble or save solana drop - pub fn create( + #[allow(clippy::too_many_lines)] + fn master_edition_transaction( + &self, + payload: MasterEdition, + ) -> Result> { + let payer: Pubkey = self.treasury_wallet_address.parse()?; + let rpc = &self.rpc_client; + let mint = Keypair::new(); + let MasterEdition { + name, + symbol, + seller_fee_basis_points, + metadata_uri, + creators, + supply, + owner_address, + } = payload; + let owner: Pubkey = owner_address.parse()?; + + let (metadata, _) = Pubkey::find_program_address( + &[ + b"metadata", + mpl_token_metadata::ID.as_ref(), + mint.pubkey().as_ref(), + ], + &mpl_token_metadata::ID, + ); + let associated_token_account = get_associated_token_address(&owner, &mint.pubkey()); + let (master_edition, _) = Pubkey::find_program_address( + &[ + b"metadata", + mpl_token_metadata::ID.as_ref(), + mint.pubkey().as_ref(), + b"edition", + ], + &mpl_token_metadata::ID, + ); + let len = spl_token::state::Mint::LEN; + let rent = rpc.get_minimum_balance_for_rent_exemption(len)?; + let blockhash = rpc.get_latest_blockhash()?; + + let create_account_ins = solana_program::system_instruction::create_account( + &payer, + &mint.pubkey(), + rent, + len.try_into()?, + &spl_token::ID, + ); + let initialize_mint_ins = spl_token::instruction::initialize_mint( + &spl_token::ID, + &mint.pubkey(), + &owner, + Some(&owner), + 0, + )?; + let ata_ins = spl_associated_token_account::instruction::create_associated_token_account( + &payer, + &owner, + &mint.pubkey(), + &spl_token::ID, + ); + let min_to_ins = spl_token::instruction::mint_to( + &spl_token::ID, + &mint.pubkey(), + &associated_token_account, + &owner, + &[], + 1, + )?; + let create_metadata_account_ins = + mpl_token_metadata::instruction::create_metadata_accounts_v3( + mpl_token_metadata::ID, + metadata, + mint.pubkey(), + owner, + payer, + owner, + name, + symbol, + metadata_uri, + Some( + creators + .into_iter() + .map(TryInto::try_into) + .collect::, _>>()?, + ), + seller_fee_basis_points.try_into()?, + true, + true, + None, + None, + None, + ); + let create_master_edition_ins = mpl_token_metadata::instruction::create_master_edition_v3( + mpl_token_metadata::ID, + master_edition, + mint.pubkey(), + owner, + owner, + metadata, + payer, + supply.map(TryInto::try_into).transpose()?, + ); + let instructions = vec![ + create_account_ins, + initialize_mint_ins, + ata_ins, + min_to_ins, + create_metadata_account_ins, + create_master_edition_ins, + ]; + + let message = solana_program::message::Message::new_with_blockhash( + &instructions, + Some(&payer), + &blockhash, + ); + + let serialized_message = message.serialize(); + let mint_signature = mint.try_sign_message(&message.serialize())?; + + Ok(TransactionResponse { + serialized_message, + signatures_or_signers_public_keys: vec![ + payer.to_string(), + mint_signature.to_string(), + owner.to_string(), + ], + addresses: MasterEditionAddresses { + master_edition, + update_authority: owner, + associated_token_account, + mint: mint.pubkey(), + owner, + metadata, + }, + }) + } +} + +impl Backend for Solana { + fn create( &self, payload: MetaplexMasterEditionTransaction, ) -> Result> { @@ -177,11 +272,7 @@ impl Solana { Ok(tx) } - /// Res - /// - /// # Errors - /// This function fails if unable to assemble solana mint transaction - pub fn mint( + fn mint( &self, collection: collections::Model, payload: MintMetaplexEditionTransaction, @@ -290,11 +381,7 @@ impl Solana { }) } - /// Res - /// - /// # Errors - /// This function fails if unable to assemble or save solana update of a drop - pub fn update( + fn update( &self, collection: collections::Model, payload: MetaplexMasterEditionTransaction, @@ -363,7 +450,7 @@ impl Solana { }) } - pub fn transfer( + fn transfer( &self, collection_mint: collection_mints::Model, payload: TransferMetaplexAssetTransaction, @@ -423,145 +510,6 @@ impl Solana { }, }) } - - #[allow(clippy::too_many_lines)] - fn master_edition_transaction( - &self, - payload: MasterEdition, - ) -> Result> { - let payer: Pubkey = self.treasury_wallet_address.parse()?; - let rpc = &self.rpc_client; - let mint = Keypair::new(); - let MasterEdition { - name, - symbol, - seller_fee_basis_points, - metadata_uri, - creators, - supply, - owner_address, - } = payload; - let owner: Pubkey = owner_address.parse()?; - - let (metadata, _) = Pubkey::find_program_address( - &[ - b"metadata", - mpl_token_metadata::ID.as_ref(), - mint.pubkey().as_ref(), - ], - &mpl_token_metadata::ID, - ); - let associated_token_account = get_associated_token_address(&owner, &mint.pubkey()); - let (master_edition, _) = Pubkey::find_program_address( - &[ - b"metadata", - mpl_token_metadata::ID.as_ref(), - mint.pubkey().as_ref(), - b"edition", - ], - &mpl_token_metadata::ID, - ); - let len = spl_token::state::Mint::LEN; - let rent = rpc.get_minimum_balance_for_rent_exemption(len)?; - let blockhash = rpc.get_latest_blockhash()?; - - let create_account_ins = solana_program::system_instruction::create_account( - &payer, - &mint.pubkey(), - rent, - len.try_into()?, - &spl_token::ID, - ); - let initialize_mint_ins = spl_token::instruction::initialize_mint( - &spl_token::ID, - &mint.pubkey(), - &owner, - Some(&owner), - 0, - )?; - let ata_ins = spl_associated_token_account::instruction::create_associated_token_account( - &payer, - &owner, - &mint.pubkey(), - &spl_token::ID, - ); - let min_to_ins = spl_token::instruction::mint_to( - &spl_token::ID, - &mint.pubkey(), - &associated_token_account, - &owner, - &[], - 1, - )?; - let create_metadata_account_ins = - mpl_token_metadata::instruction::create_metadata_accounts_v3( - mpl_token_metadata::ID, - metadata, - mint.pubkey(), - owner, - payer, - owner, - name, - symbol, - metadata_uri, - Some( - creators - .into_iter() - .map(TryInto::try_into) - .collect::, _>>()?, - ), - seller_fee_basis_points.try_into()?, - true, - true, - None, - None, - None, - ); - let create_master_edition_ins = mpl_token_metadata::instruction::create_master_edition_v3( - mpl_token_metadata::ID, - master_edition, - mint.pubkey(), - owner, - owner, - metadata, - payer, - supply.map(TryInto::try_into).transpose()?, - ); - let instructions = vec![ - create_account_ins, - initialize_mint_ins, - ata_ins, - min_to_ins, - create_metadata_account_ins, - create_master_edition_ins, - ]; - - let message = solana_program::message::Message::new_with_blockhash( - &instructions, - Some(&payer), - &blockhash, - ); - - let serialized_message = message.serialize(); - let mint_signature = mint.try_sign_message(&message.serialize())?; - - Ok(TransactionResponse { - serialized_message, - signatures_or_signers_public_keys: vec![ - payer.to_string(), - mint_signature.to_string(), - owner.to_string(), - ], - addresses: MasterEditionAddresses { - master_edition, - update_authority: owner, - associated_token_account, - mint: mint.pubkey(), - owner, - metadata, - }, - }) - } } impl TryFrom for Creator { diff --git a/consumer/src/solana_compressed.rs b/consumer/src/solana_compressed.rs new file mode 100644 index 0000000..b6e115e --- /dev/null +++ b/consumer/src/solana_compressed.rs @@ -0,0 +1,304 @@ +use anchor_lang::InstructionData; +use holaplex_hub_nfts_solana_entity::{collection_mints, collections}; +use hub_core::{anyhow::Result, clap, prelude::*}; +use mpl_token_metadata::state::Creator; +use solana_client::rpc_client::RpcClient; +use solana_program::{ + instruction::{AccountMeta, Instruction}, + program_pack::Pack, + pubkey::Pubkey, + system_program, +}; +use solana_sdk::{signature::Keypair, signer::Signer}; +use spl_associated_token_account::get_associated_token_address; + +use crate::{ + backend::{ + Backend, MasterEditionAddresses, MintEditionAddresses, TransactionResponse, + TransferAssetAddresses, UpdateMasterEditionAddresses, + }, + proto::{ + MasterEdition, MetaplexMasterEditionTransaction, MintMetaplexEditionTransaction, + TransferMetaplexAssetTransaction, + }, +}; + +#[derive(Debug, clap::Args)] +pub struct SolanaCompressedArgs { + #[arg(long, env)] + pub tree_authority: Pubkey, + #[arg(long, env)] + pub merkle_tree: Pubkey, +} + +#[derive(Clone)] +pub struct SolanaCompressed { + rpc: Arc, + treasury: Pubkey, + tree_authority: Pubkey, + merkle_tree: Pubkey, +} + +impl Backend for SolanaCompressed { + fn create( + &self, + evt: MetaplexMasterEditionTransaction, + ) -> Result> { + let MetaplexMasterEditionTransaction { master_edition, .. } = evt; + let MasterEdition { + name, + symbol, + metadata_uri, + creators, + seller_fee_basis_points, + supply, // TODO: ? + owner_address, + } = master_edition.context("Missing master edition message")?; + let payer = self.treasury; + let owner = owner_address.parse()?; + let mint = Keypair::new(); + + let (metadata, _) = Pubkey::find_program_address( + &[ + b"metadata", + mpl_token_metadata::ID.as_ref(), + mint.pubkey().as_ref(), + ], + &mpl_token_metadata::ID, + ); + let associated_token_account = get_associated_token_address(&owner, &mint.pubkey()); + + let mint_len = spl_token::state::Mint::LEN; + + // TODO: this is the collection NFT, right? + let instructions = [ + solana_program::system_instruction::create_account( + &payer, + &mint.pubkey(), + self.rpc.get_minimum_balance_for_rent_exemption(mint_len)?, + mint_len.try_into()?, + &spl_token::ID, + ), + spl_token::instruction::initialize_mint( + &spl_token::ID, + &mint.pubkey(), + &owner, + Some(&owner), + 0, + )?, + spl_associated_token_account::instruction::create_associated_token_account( + &payer, + &owner, + &mint.pubkey(), + &spl_token::ID, + ), + spl_token::instruction::mint_to( + &spl_token::ID, + &mint.pubkey(), + &associated_token_account, + &owner, + &[], + 1, + )?, + mpl_token_metadata::instruction::create_metadata_accounts_v3( + mpl_token_metadata::ID, + metadata, + mint.pubkey(), + owner, + payer, + owner, + name, + symbol, + metadata_uri, + Some( + creators + .into_iter() + .map(TryInto::try_into) + .collect::, _>>()?, + ), + seller_fee_basis_points.try_into()?, + true, + true, + None, + None, + None, + ), + ]; + + let serialized_message = solana_program::message::Message::new_with_blockhash( + &instructions, + Some(&payer), + &self.rpc.get_latest_blockhash()?, + ) + .serialize(); + let mint_signature = mint.try_sign_message(&serialized_message)?; + + Ok(TransactionResponse { + serialized_message, + signatures_or_signers_public_keys: vec![ + payer.to_string(), + mint_signature.to_string(), + owner.to_string(), + ], + addresses: MasterEditionAddresses { + metadata, + associated_token_account, + owner, + master_edition: todo!("what"), + mint: mint.pubkey(), + update_authority: owner, + }, + }) + } + + fn mint( + &self, + collection: collections::Model, + evt: MintMetaplexEditionTransaction, + ) -> Result> { + let MintMetaplexEditionTransaction { + recipient_address, + owner_address, + edition, + .. + } = evt; + let payer = self.treasury; + let recipient = recipient_address.parse()?; + let owner = owner_address.parse()?; + + let instructions = [Instruction { + program_id: mpl_bubblegum::ID, + accounts: [ + AccountMeta::new(self.tree_authority, false), + AccountMeta::new_readonly(recipient, false), + AccountMeta::new_readonly(recipient, false), + AccountMeta::new(self.merkle_tree, false), + AccountMeta::new_readonly(payer, true), + AccountMeta::new_readonly(owner, true), // TODO: who will own the trees?? + AccountMeta::new_readonly(spl_noop::ID, false), + AccountMeta::new_readonly(spl_account_compression::ID, false), + AccountMeta::new_readonly(system_program::ID, false), + ] + .into_iter() + .collect(), + data: mpl_bubblegum::instruction::MintV1 { + message: mpl_bubblegum::state::metaplex_adapter::MetadataArgs { + name: todo!(), + symbol: todo!(), + uri: todo!(), + seller_fee_basis_points: todo!(), + primary_sale_happened: todo!(), + is_mutable: todo!(), + edition_nonce: todo!(), + token_standard: todo!(), + collection: todo!(), + uses: todo!(), + token_program_version: todo!(), + creators: todo!(), + }, + } + .data(), + }]; + + let serialized_message = solana_program::message::Message::new_with_blockhash( + &instructions, + Some(&payer), + &self.rpc.get_latest_blockhash()?, + ) + .serialize(); + + Ok(TransactionResponse { + serialized_message, + signatures_or_signers_public_keys: vec![payer.to_string(), owner.to_string()], + addresses: MintEditionAddresses { + edition: todo!("what"), + mint: todo!("what"), + metadata: todo!("what"), + owner, + associated_token_account: todo!("what"), + }, + }) + } + + fn update( + &self, + collection: collections::Model, + evt: MetaplexMasterEditionTransaction, + ) -> Result> { + bail!("Cannot update a compressed NFT") + } + + fn transfer( + &self, + mint: collection_mints::Model, + evt: TransferMetaplexAssetTransaction, + ) -> Result> { + let TransferMetaplexAssetTransaction { + recipient_address, + owner_address, + collection_mint_id, + .. + } = evt; + let payer = self.treasury; + let recipient = recipient_address.parse()?; + let owner = owner_address.parse()?; + + let instructions = [Instruction { + program_id: mpl_bubblegum::ID, + accounts: [ + AccountMeta::new(self.tree_authority, false), + AccountMeta::new_readonly(owner, true), + AccountMeta::new_readonly(owner, false), + AccountMeta::new_readonly(recipient, false), + AccountMeta::new(self.merkle_tree, false), + AccountMeta::new_readonly(spl_noop::ID, false), + AccountMeta::new_readonly(spl_account_compression::ID, false), + AccountMeta::new_readonly(system_program::ID, false), + ] + .into_iter() + .collect(), + data: mpl_bubblegum::instruction::Transfer { + root: todo!("set up DAA"), + data_hash: todo!("set up DAA"), + creator_hash: todo!("set up DAA"), + nonce: todo!("set up DAA"), + index: todo!("set up DAA"), + } + .data(), + }]; + + let serialized_message = solana_program::message::Message::new_with_blockhash( + &instructions, + Some(&payer), + &self.rpc.get_latest_blockhash()?, + ) + .serialize(); + + Ok(TransactionResponse { + serialized_message, + signatures_or_signers_public_keys: vec![payer.to_string(), owner.to_string()], + addresses: TransferAssetAddresses { + owner, + recipient, + recipient_associated_token_account: todo!("what"), + owner_associated_token_account: todo!("what"), + }, + }) + } +} + +impl SolanaCompressed { + #[must_use] + pub fn new(rpc: Arc, treasury: Pubkey, args: SolanaCompressedArgs) -> Self { + let SolanaCompressedArgs { + tree_authority, + merkle_tree, + } = args; + Self { + rpc, + treasury, + tree_authority, + merkle_tree, + } + } +}