├── .github └── workflows │ └── deploy.yml ├── .gitignore ├── .vscode └── settings.json ├── Cargo.lock ├── Cargo.toml ├── Readme.md ├── docs ├── .gitignore ├── book.toml └── src │ ├── README.md │ ├── SUMMARY.md │ ├── installation.md │ ├── mapping-into-anchor │ ├── README.md │ ├── account-constraints.md │ ├── cpi.md │ ├── instruction.md │ ├── pda.md │ ├── program.md │ └── state.md │ ├── reference │ └── other-resources.md │ ├── tutorial.md │ └── usage.md ├── examples ├── escrow │ ├── rust │ │ └── escrow.rs │ └── typescript │ │ └── escrow.ts ├── favorites │ ├── rust │ │ └── favorites.rs │ └── typescript │ │ └── favorites.ts ├── vault │ ├── rust │ │ └── vault.rs │ └── typescript │ │ └── vault.ts └── vote │ ├── rust │ └── vote.rs │ └── typescript │ └── vote.ts ├── images └── solana-explorer.png └── src ├── cli.rs ├── errors.rs ├── helpers ├── extract_type.rs ├── format_account_struct.rs └── mod.rs ├── main.rs ├── parse_ts.rs ├── rs_types ├── instruction_account.rs ├── mod.rs ├── program_account.rs ├── program_instruction.rs └── program_module.rs ├── transpiler.rs └── ts_types.rs /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy 2 | on: 3 | push: 4 | branches: 5 | - master 6 | 7 | jobs: 8 | deploy: 9 | runs-on: ubuntu-latest 10 | permissions: 11 | contents: write # To push a branch 12 | pages: write # To push to a GitHub Pages site 13 | id-token: write # To update the deployment status 14 | steps: 15 | - uses: actions/checkout@v4 16 | with: 17 | fetch-depth: 0 18 | - name: Install latest mdbook 19 | run: | 20 | tag=$(curl 'https://api.github.com/repos/rust-lang/mdbook/releases/latest' | jq -r '.tag_name') 21 | url="https://github.com/rust-lang/mdbook/releases/download/${tag}/mdbook-${tag}-x86_64-unknown-linux-gnu.tar.gz" 22 | mkdir mdbook 23 | curl -sSL $url | tar -xz --directory=./mdbook 24 | echo `pwd`/mdbook >> $GITHUB_PATH 25 | - name: Build Book 26 | run: | 27 | # This assumes your book is in the root of your repository. 28 | # Just add a `cd` here if you need to change to another directory. 29 | cd docs 30 | mdbook build 31 | - name: Setup Pages 32 | uses: actions/configure-pages@v4 33 | - name: Upload artifact 34 | uses: actions/upload-pages-artifact@v3 35 | with: 36 | # Upload entire repository 37 | path: "docs/book" 38 | - name: Deploy to GitHub Pages 39 | id: deployment 40 | uses: actions/deploy-pages@v4 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | target 4 | .ideas -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "CodeGPT.apiKey": "Ollama" 3 | } -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "Inflector" 7 | version = "0.11.4" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" 10 | dependencies = [ 11 | "lazy_static", 12 | "regex", 13 | ] 14 | 15 | [[package]] 16 | name = "ahash" 17 | version = "0.7.8" 18 | source = "registry+https://github.com/rust-lang/crates.io-index" 19 | checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" 20 | dependencies = [ 21 | "getrandom 0.2.10", 22 | "once_cell", 23 | "version_check", 24 | ] 25 | 26 | [[package]] 27 | name = "ahash" 28 | version = "0.8.11" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" 31 | dependencies = [ 32 | "cfg-if", 33 | "getrandom 0.2.10", 34 | "once_cell", 35 | "version_check", 36 | "zerocopy", 37 | ] 38 | 39 | [[package]] 40 | name = "aho-corasick" 41 | version = "1.1.2" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" 44 | dependencies = [ 45 | "memchr", 46 | ] 47 | 48 | [[package]] 49 | name = "anchor-attribute-access-control" 50 | version = "0.30.0" 51 | source = "registry+https://github.com/rust-lang/crates.io-index" 52 | checksum = "dd7368e171b3a317885dc08ec0f74eed9d0ad6c726cc819593aed81440dca926" 53 | dependencies = [ 54 | "anchor-syn", 55 | "proc-macro2", 56 | "quote", 57 | "syn 1.0.109", 58 | ] 59 | 60 | [[package]] 61 | name = "anchor-attribute-account" 62 | version = "0.30.0" 63 | source = "registry+https://github.com/rust-lang/crates.io-index" 64 | checksum = "f527df85a8cba3f2bea04e46ed71b66e525ea378c7fec538aa205f4520b73e31" 65 | dependencies = [ 66 | "anchor-syn", 67 | "bs58 0.5.1", 68 | "proc-macro2", 69 | "quote", 70 | "syn 1.0.109", 71 | ] 72 | 73 | [[package]] 74 | name = "anchor-attribute-constant" 75 | version = "0.30.0" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | checksum = "3eb1dc1845cf8636c2e046a274ca074dabd3884ac8ed11cc4ed64b7e8ef5a318" 78 | dependencies = [ 79 | "anchor-syn", 80 | "quote", 81 | "syn 1.0.109", 82 | ] 83 | 84 | [[package]] 85 | name = "anchor-attribute-error" 86 | version = "0.30.0" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | checksum = "7f382e41514c59a77ffa7bb1a47df9a0359564a749b6934485c742c11962e540" 89 | dependencies = [ 90 | "anchor-syn", 91 | "quote", 92 | "syn 1.0.109", 93 | ] 94 | 95 | [[package]] 96 | name = "anchor-attribute-event" 97 | version = "0.30.0" 98 | source = "registry+https://github.com/rust-lang/crates.io-index" 99 | checksum = "473a122aeed3f6b666438236338d2ef7833ee5fdc5688e1baa80185d61088a53" 100 | dependencies = [ 101 | "anchor-syn", 102 | "proc-macro2", 103 | "quote", 104 | "syn 1.0.109", 105 | ] 106 | 107 | [[package]] 108 | name = "anchor-attribute-program" 109 | version = "0.30.0" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "7f88c7ffe2eb40aeac43ffd0d74a6671581158aedfaa0552330a2ef92fa5c889" 112 | dependencies = [ 113 | "anchor-lang-idl", 114 | "anchor-syn", 115 | "anyhow", 116 | "bs58 0.5.1", 117 | "heck 0.3.3", 118 | "proc-macro2", 119 | "quote", 120 | "serde_json", 121 | "syn 1.0.109", 122 | ] 123 | 124 | [[package]] 125 | name = "anchor-derive-accounts" 126 | version = "0.30.0" 127 | source = "registry+https://github.com/rust-lang/crates.io-index" 128 | checksum = "ed9b97c99dcec135aae0ff908c14bcfcd3e78cfc16a0c6f245135038f0e6d390" 129 | dependencies = [ 130 | "anchor-syn", 131 | "quote", 132 | "syn 1.0.109", 133 | ] 134 | 135 | [[package]] 136 | name = "anchor-derive-serde" 137 | version = "0.30.0" 138 | source = "registry+https://github.com/rust-lang/crates.io-index" 139 | checksum = "bbece98f6ad9c37070edc0841326c9623a249346cd74f433e7cef69b14f7f31d" 140 | dependencies = [ 141 | "anchor-syn", 142 | "borsh-derive-internal 0.10.3", 143 | "proc-macro2", 144 | "quote", 145 | "syn 1.0.109", 146 | ] 147 | 148 | [[package]] 149 | name = "anchor-derive-space" 150 | version = "0.30.0" 151 | source = "registry+https://github.com/rust-lang/crates.io-index" 152 | checksum = "8badbe2648bc99a85ee05a7a5f9512e5e2af8ffac71476a69350cb278057ac53" 153 | dependencies = [ 154 | "proc-macro2", 155 | "quote", 156 | "syn 1.0.109", 157 | ] 158 | 159 | [[package]] 160 | name = "anchor-lang" 161 | version = "0.30.0" 162 | source = "registry+https://github.com/rust-lang/crates.io-index" 163 | checksum = "e41feb9c1cd9f4b0fad1c004fc8f289183f3ce27e9db38fa6e434470c716fb1e" 164 | dependencies = [ 165 | "anchor-attribute-access-control", 166 | "anchor-attribute-account", 167 | "anchor-attribute-constant", 168 | "anchor-attribute-error", 169 | "anchor-attribute-event", 170 | "anchor-attribute-program", 171 | "anchor-derive-accounts", 172 | "anchor-derive-serde", 173 | "anchor-derive-space", 174 | "arrayref", 175 | "base64 0.21.7", 176 | "bincode", 177 | "borsh 0.10.3", 178 | "bytemuck", 179 | "getrandom 0.2.10", 180 | "solana-program", 181 | "thiserror", 182 | ] 183 | 184 | [[package]] 185 | name = "anchor-lang-idl" 186 | version = "0.1.0" 187 | source = "registry+https://github.com/rust-lang/crates.io-index" 188 | checksum = "b29da81eae478b1bb846749b06b8a2cb9c6f9ed26ca793b0c916793fdf36adab" 189 | dependencies = [ 190 | "anyhow", 191 | "serde", 192 | "serde_json", 193 | ] 194 | 195 | [[package]] 196 | name = "anchor-syn" 197 | version = "0.30.0" 198 | source = "registry+https://github.com/rust-lang/crates.io-index" 199 | checksum = "ac53f2378bc08e89e20c2b893c01986ffd34cfbc69a17e35bd6f754753e9fdad" 200 | dependencies = [ 201 | "anyhow", 202 | "bs58 0.5.1", 203 | "heck 0.3.3", 204 | "proc-macro2", 205 | "quote", 206 | "serde", 207 | "serde_json", 208 | "sha2 0.10.8", 209 | "syn 1.0.109", 210 | "thiserror", 211 | ] 212 | 213 | [[package]] 214 | name = "anstream" 215 | version = "0.6.14" 216 | source = "registry+https://github.com/rust-lang/crates.io-index" 217 | checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" 218 | dependencies = [ 219 | "anstyle", 220 | "anstyle-parse", 221 | "anstyle-query", 222 | "anstyle-wincon", 223 | "colorchoice", 224 | "is_terminal_polyfill", 225 | "utf8parse", 226 | ] 227 | 228 | [[package]] 229 | name = "anstyle" 230 | version = "1.0.7" 231 | source = "registry+https://github.com/rust-lang/crates.io-index" 232 | checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" 233 | 234 | [[package]] 235 | name = "anstyle-parse" 236 | version = "0.2.4" 237 | source = "registry+https://github.com/rust-lang/crates.io-index" 238 | checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" 239 | dependencies = [ 240 | "utf8parse", 241 | ] 242 | 243 | [[package]] 244 | name = "anstyle-query" 245 | version = "1.1.0" 246 | source = "registry+https://github.com/rust-lang/crates.io-index" 247 | checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" 248 | dependencies = [ 249 | "windows-sys", 250 | ] 251 | 252 | [[package]] 253 | name = "anstyle-wincon" 254 | version = "3.0.3" 255 | source = "registry+https://github.com/rust-lang/crates.io-index" 256 | checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" 257 | dependencies = [ 258 | "anstyle", 259 | "windows-sys", 260 | ] 261 | 262 | [[package]] 263 | name = "anyhow" 264 | version = "1.0.75" 265 | source = "registry+https://github.com/rust-lang/crates.io-index" 266 | checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" 267 | 268 | [[package]] 269 | name = "ark-bn254" 270 | version = "0.4.0" 271 | source = "registry+https://github.com/rust-lang/crates.io-index" 272 | checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" 273 | dependencies = [ 274 | "ark-ec", 275 | "ark-ff", 276 | "ark-std", 277 | ] 278 | 279 | [[package]] 280 | name = "ark-ec" 281 | version = "0.4.2" 282 | source = "registry+https://github.com/rust-lang/crates.io-index" 283 | checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" 284 | dependencies = [ 285 | "ark-ff", 286 | "ark-poly", 287 | "ark-serialize", 288 | "ark-std", 289 | "derivative", 290 | "hashbrown 0.13.2", 291 | "itertools", 292 | "num-traits", 293 | "zeroize", 294 | ] 295 | 296 | [[package]] 297 | name = "ark-ff" 298 | version = "0.4.2" 299 | source = "registry+https://github.com/rust-lang/crates.io-index" 300 | checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" 301 | dependencies = [ 302 | "ark-ff-asm", 303 | "ark-ff-macros", 304 | "ark-serialize", 305 | "ark-std", 306 | "derivative", 307 | "digest 0.10.7", 308 | "itertools", 309 | "num-bigint", 310 | "num-traits", 311 | "paste", 312 | "rustc_version", 313 | "zeroize", 314 | ] 315 | 316 | [[package]] 317 | name = "ark-ff-asm" 318 | version = "0.4.2" 319 | source = "registry+https://github.com/rust-lang/crates.io-index" 320 | checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" 321 | dependencies = [ 322 | "quote", 323 | "syn 1.0.109", 324 | ] 325 | 326 | [[package]] 327 | name = "ark-ff-macros" 328 | version = "0.4.2" 329 | source = "registry+https://github.com/rust-lang/crates.io-index" 330 | checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" 331 | dependencies = [ 332 | "num-bigint", 333 | "num-traits", 334 | "proc-macro2", 335 | "quote", 336 | "syn 1.0.109", 337 | ] 338 | 339 | [[package]] 340 | name = "ark-poly" 341 | version = "0.4.2" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" 344 | dependencies = [ 345 | "ark-ff", 346 | "ark-serialize", 347 | "ark-std", 348 | "derivative", 349 | "hashbrown 0.13.2", 350 | ] 351 | 352 | [[package]] 353 | name = "ark-serialize" 354 | version = "0.4.2" 355 | source = "registry+https://github.com/rust-lang/crates.io-index" 356 | checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" 357 | dependencies = [ 358 | "ark-serialize-derive", 359 | "ark-std", 360 | "digest 0.10.7", 361 | "num-bigint", 362 | ] 363 | 364 | [[package]] 365 | name = "ark-serialize-derive" 366 | version = "0.4.2" 367 | source = "registry+https://github.com/rust-lang/crates.io-index" 368 | checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" 369 | dependencies = [ 370 | "proc-macro2", 371 | "quote", 372 | "syn 1.0.109", 373 | ] 374 | 375 | [[package]] 376 | name = "ark-std" 377 | version = "0.4.0" 378 | source = "registry+https://github.com/rust-lang/crates.io-index" 379 | checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" 380 | dependencies = [ 381 | "num-traits", 382 | "rand 0.8.5", 383 | ] 384 | 385 | [[package]] 386 | name = "arrayref" 387 | version = "0.3.7" 388 | source = "registry+https://github.com/rust-lang/crates.io-index" 389 | checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" 390 | 391 | [[package]] 392 | name = "arrayvec" 393 | version = "0.7.4" 394 | source = "registry+https://github.com/rust-lang/crates.io-index" 395 | checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" 396 | 397 | [[package]] 398 | name = "ast_node" 399 | version = "0.9.5" 400 | source = "registry+https://github.com/rust-lang/crates.io-index" 401 | checksum = "c09c69dffe06d222d072c878c3afe86eee2179806f20503faec97250268b4c24" 402 | dependencies = [ 403 | "pmutil", 404 | "proc-macro2", 405 | "quote", 406 | "swc_macros_common", 407 | "syn 2.0.38", 408 | ] 409 | 410 | [[package]] 411 | name = "atty" 412 | version = "0.2.14" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 415 | dependencies = [ 416 | "hermit-abi", 417 | "libc", 418 | "winapi", 419 | ] 420 | 421 | [[package]] 422 | name = "autocfg" 423 | version = "1.1.0" 424 | source = "registry+https://github.com/rust-lang/crates.io-index" 425 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 426 | 427 | [[package]] 428 | name = "base64" 429 | version = "0.12.3" 430 | source = "registry+https://github.com/rust-lang/crates.io-index" 431 | checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" 432 | 433 | [[package]] 434 | name = "base64" 435 | version = "0.21.7" 436 | source = "registry+https://github.com/rust-lang/crates.io-index" 437 | checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" 438 | 439 | [[package]] 440 | name = "better_scoped_tls" 441 | version = "0.1.1" 442 | source = "registry+https://github.com/rust-lang/crates.io-index" 443 | checksum = "794edcc9b3fb07bb4aecaa11f093fd45663b4feadb782d68303a2268bc2701de" 444 | dependencies = [ 445 | "scoped-tls", 446 | ] 447 | 448 | [[package]] 449 | name = "bincode" 450 | version = "1.3.3" 451 | source = "registry+https://github.com/rust-lang/crates.io-index" 452 | checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" 453 | dependencies = [ 454 | "serde", 455 | ] 456 | 457 | [[package]] 458 | name = "bitflags" 459 | version = "1.3.2" 460 | source = "registry+https://github.com/rust-lang/crates.io-index" 461 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 462 | 463 | [[package]] 464 | name = "bitflags" 465 | version = "2.4.1" 466 | source = "registry+https://github.com/rust-lang/crates.io-index" 467 | checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" 468 | dependencies = [ 469 | "serde", 470 | ] 471 | 472 | [[package]] 473 | name = "bitmaps" 474 | version = "2.1.0" 475 | source = "registry+https://github.com/rust-lang/crates.io-index" 476 | checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" 477 | dependencies = [ 478 | "typenum", 479 | ] 480 | 481 | [[package]] 482 | name = "blake3" 483 | version = "1.5.1" 484 | source = "registry+https://github.com/rust-lang/crates.io-index" 485 | checksum = "30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52" 486 | dependencies = [ 487 | "arrayref", 488 | "arrayvec", 489 | "cc", 490 | "cfg-if", 491 | "constant_time_eq", 492 | "digest 0.10.7", 493 | ] 494 | 495 | [[package]] 496 | name = "block-buffer" 497 | version = "0.9.0" 498 | source = "registry+https://github.com/rust-lang/crates.io-index" 499 | checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" 500 | dependencies = [ 501 | "generic-array", 502 | ] 503 | 504 | [[package]] 505 | name = "block-buffer" 506 | version = "0.10.4" 507 | source = "registry+https://github.com/rust-lang/crates.io-index" 508 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 509 | dependencies = [ 510 | "generic-array", 511 | ] 512 | 513 | [[package]] 514 | name = "borsh" 515 | version = "0.9.3" 516 | source = "registry+https://github.com/rust-lang/crates.io-index" 517 | checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" 518 | dependencies = [ 519 | "borsh-derive 0.9.3", 520 | "hashbrown 0.11.2", 521 | ] 522 | 523 | [[package]] 524 | name = "borsh" 525 | version = "0.10.3" 526 | source = "registry+https://github.com/rust-lang/crates.io-index" 527 | checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" 528 | dependencies = [ 529 | "borsh-derive 0.10.3", 530 | "hashbrown 0.13.2", 531 | ] 532 | 533 | [[package]] 534 | name = "borsh-derive" 535 | version = "0.9.3" 536 | source = "registry+https://github.com/rust-lang/crates.io-index" 537 | checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" 538 | dependencies = [ 539 | "borsh-derive-internal 0.9.3", 540 | "borsh-schema-derive-internal 0.9.3", 541 | "proc-macro-crate", 542 | "proc-macro2", 543 | "syn 1.0.109", 544 | ] 545 | 546 | [[package]] 547 | name = "borsh-derive" 548 | version = "0.10.3" 549 | source = "registry+https://github.com/rust-lang/crates.io-index" 550 | checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7" 551 | dependencies = [ 552 | "borsh-derive-internal 0.10.3", 553 | "borsh-schema-derive-internal 0.10.3", 554 | "proc-macro-crate", 555 | "proc-macro2", 556 | "syn 1.0.109", 557 | ] 558 | 559 | [[package]] 560 | name = "borsh-derive-internal" 561 | version = "0.9.3" 562 | source = "registry+https://github.com/rust-lang/crates.io-index" 563 | checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" 564 | dependencies = [ 565 | "proc-macro2", 566 | "quote", 567 | "syn 1.0.109", 568 | ] 569 | 570 | [[package]] 571 | name = "borsh-derive-internal" 572 | version = "0.10.3" 573 | source = "registry+https://github.com/rust-lang/crates.io-index" 574 | checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb" 575 | dependencies = [ 576 | "proc-macro2", 577 | "quote", 578 | "syn 1.0.109", 579 | ] 580 | 581 | [[package]] 582 | name = "borsh-schema-derive-internal" 583 | version = "0.9.3" 584 | source = "registry+https://github.com/rust-lang/crates.io-index" 585 | checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" 586 | dependencies = [ 587 | "proc-macro2", 588 | "quote", 589 | "syn 1.0.109", 590 | ] 591 | 592 | [[package]] 593 | name = "borsh-schema-derive-internal" 594 | version = "0.10.3" 595 | source = "registry+https://github.com/rust-lang/crates.io-index" 596 | checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd" 597 | dependencies = [ 598 | "proc-macro2", 599 | "quote", 600 | "syn 1.0.109", 601 | ] 602 | 603 | [[package]] 604 | name = "bs58" 605 | version = "0.4.0" 606 | source = "registry+https://github.com/rust-lang/crates.io-index" 607 | checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" 608 | 609 | [[package]] 610 | name = "bs58" 611 | version = "0.5.1" 612 | source = "registry+https://github.com/rust-lang/crates.io-index" 613 | checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" 614 | dependencies = [ 615 | "tinyvec", 616 | ] 617 | 618 | [[package]] 619 | name = "bumpalo" 620 | version = "3.16.0" 621 | source = "registry+https://github.com/rust-lang/crates.io-index" 622 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 623 | 624 | [[package]] 625 | name = "bv" 626 | version = "0.11.1" 627 | source = "registry+https://github.com/rust-lang/crates.io-index" 628 | checksum = "8834bb1d8ee5dc048ee3124f2c7c1afcc6bc9aed03f11e9dfd8c69470a5db340" 629 | dependencies = [ 630 | "feature-probe", 631 | "serde", 632 | ] 633 | 634 | [[package]] 635 | name = "bytemuck" 636 | version = "1.15.0" 637 | source = "registry+https://github.com/rust-lang/crates.io-index" 638 | checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" 639 | dependencies = [ 640 | "bytemuck_derive", 641 | ] 642 | 643 | [[package]] 644 | name = "bytemuck_derive" 645 | version = "1.6.0" 646 | source = "registry+https://github.com/rust-lang/crates.io-index" 647 | checksum = "4da9a32f3fed317401fa3c862968128267c3106685286e15d5aaa3d7389c2f60" 648 | dependencies = [ 649 | "proc-macro2", 650 | "quote", 651 | "syn 2.0.38", 652 | ] 653 | 654 | [[package]] 655 | name = "byteorder" 656 | version = "1.5.0" 657 | source = "registry+https://github.com/rust-lang/crates.io-index" 658 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 659 | 660 | [[package]] 661 | name = "cc" 662 | version = "1.0.83" 663 | source = "registry+https://github.com/rust-lang/crates.io-index" 664 | checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" 665 | dependencies = [ 666 | "jobserver", 667 | "libc", 668 | ] 669 | 670 | [[package]] 671 | name = "cfg-if" 672 | version = "1.0.0" 673 | source = "registry+https://github.com/rust-lang/crates.io-index" 674 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 675 | 676 | [[package]] 677 | name = "clap" 678 | version = "4.5.8" 679 | source = "registry+https://github.com/rust-lang/crates.io-index" 680 | checksum = "84b3edb18336f4df585bc9aa31dd99c036dfa5dc5e9a2939a722a188f3a8970d" 681 | dependencies = [ 682 | "clap_builder", 683 | "clap_derive", 684 | ] 685 | 686 | [[package]] 687 | name = "clap_builder" 688 | version = "4.5.8" 689 | source = "registry+https://github.com/rust-lang/crates.io-index" 690 | checksum = "c1c09dd5ada6c6c78075d6fd0da3f90d8080651e2d6cc8eb2f1aaa4034ced708" 691 | dependencies = [ 692 | "anstream", 693 | "anstyle", 694 | "clap_lex", 695 | "strsim", 696 | ] 697 | 698 | [[package]] 699 | name = "clap_derive" 700 | version = "4.5.8" 701 | source = "registry+https://github.com/rust-lang/crates.io-index" 702 | checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" 703 | dependencies = [ 704 | "heck 0.5.0", 705 | "proc-macro2", 706 | "quote", 707 | "syn 2.0.38", 708 | ] 709 | 710 | [[package]] 711 | name = "clap_lex" 712 | version = "0.7.1" 713 | source = "registry+https://github.com/rust-lang/crates.io-index" 714 | checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" 715 | 716 | [[package]] 717 | name = "colorchoice" 718 | version = "1.0.1" 719 | source = "registry+https://github.com/rust-lang/crates.io-index" 720 | checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" 721 | 722 | [[package]] 723 | name = "console_error_panic_hook" 724 | version = "0.1.7" 725 | source = "registry+https://github.com/rust-lang/crates.io-index" 726 | checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" 727 | dependencies = [ 728 | "cfg-if", 729 | "wasm-bindgen", 730 | ] 731 | 732 | [[package]] 733 | name = "console_log" 734 | version = "0.2.2" 735 | source = "registry+https://github.com/rust-lang/crates.io-index" 736 | checksum = "e89f72f65e8501878b8a004d5a1afb780987e2ce2b4532c562e367a72c57499f" 737 | dependencies = [ 738 | "log", 739 | "web-sys", 740 | ] 741 | 742 | [[package]] 743 | name = "constant_time_eq" 744 | version = "0.3.0" 745 | source = "registry+https://github.com/rust-lang/crates.io-index" 746 | checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" 747 | 748 | [[package]] 749 | name = "convert_case" 750 | version = "0.6.0" 751 | source = "registry+https://github.com/rust-lang/crates.io-index" 752 | checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" 753 | dependencies = [ 754 | "unicode-segmentation", 755 | ] 756 | 757 | [[package]] 758 | name = "cpufeatures" 759 | version = "0.2.12" 760 | source = "registry+https://github.com/rust-lang/crates.io-index" 761 | checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" 762 | dependencies = [ 763 | "libc", 764 | ] 765 | 766 | [[package]] 767 | name = "crossbeam-deque" 768 | version = "0.8.5" 769 | source = "registry+https://github.com/rust-lang/crates.io-index" 770 | checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" 771 | dependencies = [ 772 | "crossbeam-epoch", 773 | "crossbeam-utils", 774 | ] 775 | 776 | [[package]] 777 | name = "crossbeam-epoch" 778 | version = "0.9.18" 779 | source = "registry+https://github.com/rust-lang/crates.io-index" 780 | checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" 781 | dependencies = [ 782 | "crossbeam-utils", 783 | ] 784 | 785 | [[package]] 786 | name = "crossbeam-utils" 787 | version = "0.8.19" 788 | source = "registry+https://github.com/rust-lang/crates.io-index" 789 | checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" 790 | 791 | [[package]] 792 | name = "crunchy" 793 | version = "0.2.2" 794 | source = "registry+https://github.com/rust-lang/crates.io-index" 795 | checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" 796 | 797 | [[package]] 798 | name = "crypto-common" 799 | version = "0.1.6" 800 | source = "registry+https://github.com/rust-lang/crates.io-index" 801 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 802 | dependencies = [ 803 | "generic-array", 804 | "typenum", 805 | ] 806 | 807 | [[package]] 808 | name = "crypto-mac" 809 | version = "0.8.0" 810 | source = "registry+https://github.com/rust-lang/crates.io-index" 811 | checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" 812 | dependencies = [ 813 | "generic-array", 814 | "subtle", 815 | ] 816 | 817 | [[package]] 818 | name = "curve25519-dalek" 819 | version = "3.2.1" 820 | source = "registry+https://github.com/rust-lang/crates.io-index" 821 | checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" 822 | dependencies = [ 823 | "byteorder", 824 | "digest 0.9.0", 825 | "rand_core 0.5.1", 826 | "serde", 827 | "subtle", 828 | "zeroize", 829 | ] 830 | 831 | [[package]] 832 | name = "derivative" 833 | version = "2.2.0" 834 | source = "registry+https://github.com/rust-lang/crates.io-index" 835 | checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" 836 | dependencies = [ 837 | "proc-macro2", 838 | "quote", 839 | "syn 1.0.109", 840 | ] 841 | 842 | [[package]] 843 | name = "digest" 844 | version = "0.9.0" 845 | source = "registry+https://github.com/rust-lang/crates.io-index" 846 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" 847 | dependencies = [ 848 | "generic-array", 849 | ] 850 | 851 | [[package]] 852 | name = "digest" 853 | version = "0.10.7" 854 | source = "registry+https://github.com/rust-lang/crates.io-index" 855 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 856 | dependencies = [ 857 | "block-buffer 0.10.4", 858 | "crypto-common", 859 | "subtle", 860 | ] 861 | 862 | [[package]] 863 | name = "either" 864 | version = "1.9.0" 865 | source = "registry+https://github.com/rust-lang/crates.io-index" 866 | checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" 867 | 868 | [[package]] 869 | name = "equivalent" 870 | version = "1.0.1" 871 | source = "registry+https://github.com/rust-lang/crates.io-index" 872 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 873 | 874 | [[package]] 875 | name = "feature-probe" 876 | version = "0.1.1" 877 | source = "registry+https://github.com/rust-lang/crates.io-index" 878 | checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" 879 | 880 | [[package]] 881 | name = "form_urlencoded" 882 | version = "1.2.0" 883 | source = "registry+https://github.com/rust-lang/crates.io-index" 884 | checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" 885 | dependencies = [ 886 | "percent-encoding", 887 | ] 888 | 889 | [[package]] 890 | name = "from_variant" 891 | version = "0.1.6" 892 | source = "registry+https://github.com/rust-lang/crates.io-index" 893 | checksum = "03ec5dc38ee19078d84a692b1c41181ff9f94331c76cee66ff0208c770b5e54f" 894 | dependencies = [ 895 | "pmutil", 896 | "proc-macro2", 897 | "swc_macros_common", 898 | "syn 2.0.38", 899 | ] 900 | 901 | [[package]] 902 | name = "generic-array" 903 | version = "0.14.7" 904 | source = "registry+https://github.com/rust-lang/crates.io-index" 905 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 906 | dependencies = [ 907 | "serde", 908 | "typenum", 909 | "version_check", 910 | ] 911 | 912 | [[package]] 913 | name = "getrandom" 914 | version = "0.1.16" 915 | source = "registry+https://github.com/rust-lang/crates.io-index" 916 | checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" 917 | dependencies = [ 918 | "cfg-if", 919 | "js-sys", 920 | "libc", 921 | "wasi 0.9.0+wasi-snapshot-preview1", 922 | "wasm-bindgen", 923 | ] 924 | 925 | [[package]] 926 | name = "getrandom" 927 | version = "0.2.10" 928 | source = "registry+https://github.com/rust-lang/crates.io-index" 929 | checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" 930 | dependencies = [ 931 | "cfg-if", 932 | "js-sys", 933 | "libc", 934 | "wasi 0.11.0+wasi-snapshot-preview1", 935 | "wasm-bindgen", 936 | ] 937 | 938 | [[package]] 939 | name = "hashbrown" 940 | version = "0.11.2" 941 | source = "registry+https://github.com/rust-lang/crates.io-index" 942 | checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" 943 | dependencies = [ 944 | "ahash 0.7.8", 945 | ] 946 | 947 | [[package]] 948 | name = "hashbrown" 949 | version = "0.13.2" 950 | source = "registry+https://github.com/rust-lang/crates.io-index" 951 | checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" 952 | dependencies = [ 953 | "ahash 0.8.11", 954 | ] 955 | 956 | [[package]] 957 | name = "hashbrown" 958 | version = "0.15.1" 959 | source = "registry+https://github.com/rust-lang/crates.io-index" 960 | checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" 961 | 962 | [[package]] 963 | name = "heck" 964 | version = "0.3.3" 965 | source = "registry+https://github.com/rust-lang/crates.io-index" 966 | checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" 967 | dependencies = [ 968 | "unicode-segmentation", 969 | ] 970 | 971 | [[package]] 972 | name = "heck" 973 | version = "0.5.0" 974 | source = "registry+https://github.com/rust-lang/crates.io-index" 975 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 976 | 977 | [[package]] 978 | name = "hermit-abi" 979 | version = "0.1.19" 980 | source = "registry+https://github.com/rust-lang/crates.io-index" 981 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 982 | dependencies = [ 983 | "libc", 984 | ] 985 | 986 | [[package]] 987 | name = "hmac" 988 | version = "0.8.1" 989 | source = "registry+https://github.com/rust-lang/crates.io-index" 990 | checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" 991 | dependencies = [ 992 | "crypto-mac", 993 | "digest 0.9.0", 994 | ] 995 | 996 | [[package]] 997 | name = "hmac-drbg" 998 | version = "0.3.0" 999 | source = "registry+https://github.com/rust-lang/crates.io-index" 1000 | checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" 1001 | dependencies = [ 1002 | "digest 0.9.0", 1003 | "generic-array", 1004 | "hmac", 1005 | ] 1006 | 1007 | [[package]] 1008 | name = "idna" 1009 | version = "0.4.0" 1010 | source = "registry+https://github.com/rust-lang/crates.io-index" 1011 | checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" 1012 | dependencies = [ 1013 | "unicode-bidi", 1014 | "unicode-normalization", 1015 | ] 1016 | 1017 | [[package]] 1018 | name = "im" 1019 | version = "15.1.0" 1020 | source = "registry+https://github.com/rust-lang/crates.io-index" 1021 | checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9" 1022 | dependencies = [ 1023 | "bitmaps", 1024 | "rand_core 0.6.4", 1025 | "rand_xoshiro", 1026 | "rayon", 1027 | "serde", 1028 | "sized-chunks", 1029 | "typenum", 1030 | "version_check", 1031 | ] 1032 | 1033 | [[package]] 1034 | name = "indexmap" 1035 | version = "2.6.0" 1036 | source = "registry+https://github.com/rust-lang/crates.io-index" 1037 | checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" 1038 | dependencies = [ 1039 | "equivalent", 1040 | "hashbrown 0.15.1", 1041 | ] 1042 | 1043 | [[package]] 1044 | name = "is-macro" 1045 | version = "0.3.0" 1046 | source = "registry+https://github.com/rust-lang/crates.io-index" 1047 | checksum = "f4467ed1321b310c2625c5aa6c1b1ffc5de4d9e42668cf697a08fb033ee8265e" 1048 | dependencies = [ 1049 | "Inflector", 1050 | "pmutil", 1051 | "proc-macro2", 1052 | "quote", 1053 | "syn 2.0.38", 1054 | ] 1055 | 1056 | [[package]] 1057 | name = "is_terminal_polyfill" 1058 | version = "1.70.0" 1059 | source = "registry+https://github.com/rust-lang/crates.io-index" 1060 | checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" 1061 | 1062 | [[package]] 1063 | name = "itertools" 1064 | version = "0.10.5" 1065 | source = "registry+https://github.com/rust-lang/crates.io-index" 1066 | checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" 1067 | dependencies = [ 1068 | "either", 1069 | ] 1070 | 1071 | [[package]] 1072 | name = "itoa" 1073 | version = "1.0.11" 1074 | source = "registry+https://github.com/rust-lang/crates.io-index" 1075 | checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" 1076 | 1077 | [[package]] 1078 | name = "jobserver" 1079 | version = "0.1.31" 1080 | source = "registry+https://github.com/rust-lang/crates.io-index" 1081 | checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" 1082 | dependencies = [ 1083 | "libc", 1084 | ] 1085 | 1086 | [[package]] 1087 | name = "js-sys" 1088 | version = "0.3.69" 1089 | source = "registry+https://github.com/rust-lang/crates.io-index" 1090 | checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" 1091 | dependencies = [ 1092 | "wasm-bindgen", 1093 | ] 1094 | 1095 | [[package]] 1096 | name = "keccak" 1097 | version = "0.1.5" 1098 | source = "registry+https://github.com/rust-lang/crates.io-index" 1099 | checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" 1100 | dependencies = [ 1101 | "cpufeatures", 1102 | ] 1103 | 1104 | [[package]] 1105 | name = "lazy_static" 1106 | version = "1.4.0" 1107 | source = "registry+https://github.com/rust-lang/crates.io-index" 1108 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 1109 | 1110 | [[package]] 1111 | name = "libc" 1112 | version = "0.2.149" 1113 | source = "registry+https://github.com/rust-lang/crates.io-index" 1114 | checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" 1115 | 1116 | [[package]] 1117 | name = "libsecp256k1" 1118 | version = "0.6.0" 1119 | source = "registry+https://github.com/rust-lang/crates.io-index" 1120 | checksum = "c9d220bc1feda2ac231cb78c3d26f27676b8cf82c96971f7aeef3d0cf2797c73" 1121 | dependencies = [ 1122 | "arrayref", 1123 | "base64 0.12.3", 1124 | "digest 0.9.0", 1125 | "hmac-drbg", 1126 | "libsecp256k1-core", 1127 | "libsecp256k1-gen-ecmult", 1128 | "libsecp256k1-gen-genmult", 1129 | "rand 0.7.3", 1130 | "serde", 1131 | "sha2 0.9.9", 1132 | "typenum", 1133 | ] 1134 | 1135 | [[package]] 1136 | name = "libsecp256k1-core" 1137 | version = "0.2.2" 1138 | source = "registry+https://github.com/rust-lang/crates.io-index" 1139 | checksum = "d0f6ab710cec28cef759c5f18671a27dae2a5f952cdaaee1d8e2908cb2478a80" 1140 | dependencies = [ 1141 | "crunchy", 1142 | "digest 0.9.0", 1143 | "subtle", 1144 | ] 1145 | 1146 | [[package]] 1147 | name = "libsecp256k1-gen-ecmult" 1148 | version = "0.2.1" 1149 | source = "registry+https://github.com/rust-lang/crates.io-index" 1150 | checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3" 1151 | dependencies = [ 1152 | "libsecp256k1-core", 1153 | ] 1154 | 1155 | [[package]] 1156 | name = "libsecp256k1-gen-genmult" 1157 | version = "0.2.1" 1158 | source = "registry+https://github.com/rust-lang/crates.io-index" 1159 | checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d" 1160 | dependencies = [ 1161 | "libsecp256k1-core", 1162 | ] 1163 | 1164 | [[package]] 1165 | name = "light-poseidon" 1166 | version = "0.2.0" 1167 | source = "registry+https://github.com/rust-lang/crates.io-index" 1168 | checksum = "3c9a85a9752c549ceb7578064b4ed891179d20acd85f27318573b64d2d7ee7ee" 1169 | dependencies = [ 1170 | "ark-bn254", 1171 | "ark-ff", 1172 | "num-bigint", 1173 | "thiserror", 1174 | ] 1175 | 1176 | [[package]] 1177 | name = "lock_api" 1178 | version = "0.4.11" 1179 | source = "registry+https://github.com/rust-lang/crates.io-index" 1180 | checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" 1181 | dependencies = [ 1182 | "autocfg", 1183 | "scopeguard", 1184 | ] 1185 | 1186 | [[package]] 1187 | name = "log" 1188 | version = "0.4.21" 1189 | source = "registry+https://github.com/rust-lang/crates.io-index" 1190 | checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" 1191 | 1192 | [[package]] 1193 | name = "memchr" 1194 | version = "2.6.4" 1195 | source = "registry+https://github.com/rust-lang/crates.io-index" 1196 | checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" 1197 | 1198 | [[package]] 1199 | name = "memmap2" 1200 | version = "0.5.10" 1201 | source = "registry+https://github.com/rust-lang/crates.io-index" 1202 | checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" 1203 | dependencies = [ 1204 | "libc", 1205 | ] 1206 | 1207 | [[package]] 1208 | name = "memoffset" 1209 | version = "0.9.1" 1210 | source = "registry+https://github.com/rust-lang/crates.io-index" 1211 | checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" 1212 | dependencies = [ 1213 | "autocfg", 1214 | ] 1215 | 1216 | [[package]] 1217 | name = "new_debug_unreachable" 1218 | version = "1.0.4" 1219 | source = "registry+https://github.com/rust-lang/crates.io-index" 1220 | checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" 1221 | 1222 | [[package]] 1223 | name = "num-bigint" 1224 | version = "0.4.4" 1225 | source = "registry+https://github.com/rust-lang/crates.io-index" 1226 | checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" 1227 | dependencies = [ 1228 | "autocfg", 1229 | "num-integer", 1230 | "num-traits", 1231 | "serde", 1232 | ] 1233 | 1234 | [[package]] 1235 | name = "num-derive" 1236 | version = "0.3.3" 1237 | source = "registry+https://github.com/rust-lang/crates.io-index" 1238 | checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" 1239 | dependencies = [ 1240 | "proc-macro2", 1241 | "quote", 1242 | "syn 1.0.109", 1243 | ] 1244 | 1245 | [[package]] 1246 | name = "num-integer" 1247 | version = "0.1.45" 1248 | source = "registry+https://github.com/rust-lang/crates.io-index" 1249 | checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" 1250 | dependencies = [ 1251 | "autocfg", 1252 | "num-traits", 1253 | ] 1254 | 1255 | [[package]] 1256 | name = "num-traits" 1257 | version = "0.2.17" 1258 | source = "registry+https://github.com/rust-lang/crates.io-index" 1259 | checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" 1260 | dependencies = [ 1261 | "autocfg", 1262 | ] 1263 | 1264 | [[package]] 1265 | name = "once_cell" 1266 | version = "1.18.0" 1267 | source = "registry+https://github.com/rust-lang/crates.io-index" 1268 | checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" 1269 | 1270 | [[package]] 1271 | name = "opaque-debug" 1272 | version = "0.3.1" 1273 | source = "registry+https://github.com/rust-lang/crates.io-index" 1274 | checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" 1275 | 1276 | [[package]] 1277 | name = "parking_lot" 1278 | version = "0.12.1" 1279 | source = "registry+https://github.com/rust-lang/crates.io-index" 1280 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" 1281 | dependencies = [ 1282 | "lock_api", 1283 | "parking_lot_core", 1284 | ] 1285 | 1286 | [[package]] 1287 | name = "parking_lot_core" 1288 | version = "0.9.9" 1289 | source = "registry+https://github.com/rust-lang/crates.io-index" 1290 | checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" 1291 | dependencies = [ 1292 | "cfg-if", 1293 | "libc", 1294 | "redox_syscall", 1295 | "smallvec", 1296 | "windows-targets 0.48.5", 1297 | ] 1298 | 1299 | [[package]] 1300 | name = "paste" 1301 | version = "1.0.15" 1302 | source = "registry+https://github.com/rust-lang/crates.io-index" 1303 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" 1304 | 1305 | [[package]] 1306 | name = "pbkdf2" 1307 | version = "0.4.0" 1308 | source = "registry+https://github.com/rust-lang/crates.io-index" 1309 | checksum = "216eaa586a190f0a738f2f918511eecfa90f13295abec0e457cdebcceda80cbd" 1310 | dependencies = [ 1311 | "crypto-mac", 1312 | ] 1313 | 1314 | [[package]] 1315 | name = "percent-encoding" 1316 | version = "2.3.0" 1317 | source = "registry+https://github.com/rust-lang/crates.io-index" 1318 | checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" 1319 | 1320 | [[package]] 1321 | name = "phf_generator" 1322 | version = "0.10.0" 1323 | source = "registry+https://github.com/rust-lang/crates.io-index" 1324 | checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" 1325 | dependencies = [ 1326 | "phf_shared", 1327 | "rand 0.8.5", 1328 | ] 1329 | 1330 | [[package]] 1331 | name = "phf_shared" 1332 | version = "0.10.0" 1333 | source = "registry+https://github.com/rust-lang/crates.io-index" 1334 | checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" 1335 | dependencies = [ 1336 | "siphasher", 1337 | ] 1338 | 1339 | [[package]] 1340 | name = "pin-project-lite" 1341 | version = "0.2.13" 1342 | source = "registry+https://github.com/rust-lang/crates.io-index" 1343 | checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" 1344 | 1345 | [[package]] 1346 | name = "pmutil" 1347 | version = "0.6.1" 1348 | source = "registry+https://github.com/rust-lang/crates.io-index" 1349 | checksum = "52a40bc70c2c58040d2d8b167ba9a5ff59fc9dab7ad44771cfde3dcfde7a09c6" 1350 | dependencies = [ 1351 | "proc-macro2", 1352 | "quote", 1353 | "syn 2.0.38", 1354 | ] 1355 | 1356 | [[package]] 1357 | name = "poseidon" 1358 | version = "0.1.0" 1359 | dependencies = [ 1360 | "anchor-lang", 1361 | "anyhow", 1362 | "clap", 1363 | "convert_case", 1364 | "proc-macro2", 1365 | "quote", 1366 | "regex", 1367 | "rust-format", 1368 | "swc_common", 1369 | "swc_ecma_ast", 1370 | "swc_ecma_parser", 1371 | "thiserror", 1372 | "toml 0.8.19", 1373 | "walkdir", 1374 | ] 1375 | 1376 | [[package]] 1377 | name = "ppv-lite86" 1378 | version = "0.2.17" 1379 | source = "registry+https://github.com/rust-lang/crates.io-index" 1380 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 1381 | 1382 | [[package]] 1383 | name = "precomputed-hash" 1384 | version = "0.1.1" 1385 | source = "registry+https://github.com/rust-lang/crates.io-index" 1386 | checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" 1387 | 1388 | [[package]] 1389 | name = "prettyplease" 1390 | version = "0.1.25" 1391 | source = "registry+https://github.com/rust-lang/crates.io-index" 1392 | checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" 1393 | dependencies = [ 1394 | "proc-macro2", 1395 | "syn 1.0.109", 1396 | ] 1397 | 1398 | [[package]] 1399 | name = "proc-macro-crate" 1400 | version = "0.1.5" 1401 | source = "registry+https://github.com/rust-lang/crates.io-index" 1402 | checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" 1403 | dependencies = [ 1404 | "toml 0.5.11", 1405 | ] 1406 | 1407 | [[package]] 1408 | name = "proc-macro2" 1409 | version = "1.0.69" 1410 | source = "registry+https://github.com/rust-lang/crates.io-index" 1411 | checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" 1412 | dependencies = [ 1413 | "unicode-ident", 1414 | ] 1415 | 1416 | [[package]] 1417 | name = "psm" 1418 | version = "0.1.21" 1419 | source = "registry+https://github.com/rust-lang/crates.io-index" 1420 | checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" 1421 | dependencies = [ 1422 | "cc", 1423 | ] 1424 | 1425 | [[package]] 1426 | name = "quote" 1427 | version = "1.0.33" 1428 | source = "registry+https://github.com/rust-lang/crates.io-index" 1429 | checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" 1430 | dependencies = [ 1431 | "proc-macro2", 1432 | ] 1433 | 1434 | [[package]] 1435 | name = "rand" 1436 | version = "0.7.3" 1437 | source = "registry+https://github.com/rust-lang/crates.io-index" 1438 | checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" 1439 | dependencies = [ 1440 | "getrandom 0.1.16", 1441 | "libc", 1442 | "rand_chacha 0.2.2", 1443 | "rand_core 0.5.1", 1444 | "rand_hc", 1445 | ] 1446 | 1447 | [[package]] 1448 | name = "rand" 1449 | version = "0.8.5" 1450 | source = "registry+https://github.com/rust-lang/crates.io-index" 1451 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1452 | dependencies = [ 1453 | "libc", 1454 | "rand_chacha 0.3.1", 1455 | "rand_core 0.6.4", 1456 | ] 1457 | 1458 | [[package]] 1459 | name = "rand_chacha" 1460 | version = "0.2.2" 1461 | source = "registry+https://github.com/rust-lang/crates.io-index" 1462 | checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" 1463 | dependencies = [ 1464 | "ppv-lite86", 1465 | "rand_core 0.5.1", 1466 | ] 1467 | 1468 | [[package]] 1469 | name = "rand_chacha" 1470 | version = "0.3.1" 1471 | source = "registry+https://github.com/rust-lang/crates.io-index" 1472 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1473 | dependencies = [ 1474 | "ppv-lite86", 1475 | "rand_core 0.6.4", 1476 | ] 1477 | 1478 | [[package]] 1479 | name = "rand_core" 1480 | version = "0.5.1" 1481 | source = "registry+https://github.com/rust-lang/crates.io-index" 1482 | checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" 1483 | dependencies = [ 1484 | "getrandom 0.1.16", 1485 | ] 1486 | 1487 | [[package]] 1488 | name = "rand_core" 1489 | version = "0.6.4" 1490 | source = "registry+https://github.com/rust-lang/crates.io-index" 1491 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1492 | dependencies = [ 1493 | "getrandom 0.2.10", 1494 | ] 1495 | 1496 | [[package]] 1497 | name = "rand_hc" 1498 | version = "0.2.0" 1499 | source = "registry+https://github.com/rust-lang/crates.io-index" 1500 | checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" 1501 | dependencies = [ 1502 | "rand_core 0.5.1", 1503 | ] 1504 | 1505 | [[package]] 1506 | name = "rand_xoshiro" 1507 | version = "0.6.0" 1508 | source = "registry+https://github.com/rust-lang/crates.io-index" 1509 | checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" 1510 | dependencies = [ 1511 | "rand_core 0.6.4", 1512 | ] 1513 | 1514 | [[package]] 1515 | name = "rayon" 1516 | version = "1.10.0" 1517 | source = "registry+https://github.com/rust-lang/crates.io-index" 1518 | checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" 1519 | dependencies = [ 1520 | "either", 1521 | "rayon-core", 1522 | ] 1523 | 1524 | [[package]] 1525 | name = "rayon-core" 1526 | version = "1.12.1" 1527 | source = "registry+https://github.com/rust-lang/crates.io-index" 1528 | checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" 1529 | dependencies = [ 1530 | "crossbeam-deque", 1531 | "crossbeam-utils", 1532 | ] 1533 | 1534 | [[package]] 1535 | name = "redox_syscall" 1536 | version = "0.4.1" 1537 | source = "registry+https://github.com/rust-lang/crates.io-index" 1538 | checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" 1539 | dependencies = [ 1540 | "bitflags 1.3.2", 1541 | ] 1542 | 1543 | [[package]] 1544 | name = "regex" 1545 | version = "1.11.0" 1546 | source = "registry+https://github.com/rust-lang/crates.io-index" 1547 | checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" 1548 | dependencies = [ 1549 | "aho-corasick", 1550 | "memchr", 1551 | "regex-automata", 1552 | "regex-syntax", 1553 | ] 1554 | 1555 | [[package]] 1556 | name = "regex-automata" 1557 | version = "0.4.8" 1558 | source = "registry+https://github.com/rust-lang/crates.io-index" 1559 | checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" 1560 | dependencies = [ 1561 | "aho-corasick", 1562 | "memchr", 1563 | "regex-syntax", 1564 | ] 1565 | 1566 | [[package]] 1567 | name = "regex-syntax" 1568 | version = "0.8.5" 1569 | source = "registry+https://github.com/rust-lang/crates.io-index" 1570 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 1571 | 1572 | [[package]] 1573 | name = "rust-format" 1574 | version = "0.3.4" 1575 | source = "registry+https://github.com/rust-lang/crates.io-index" 1576 | checksum = "60e7c00b6c3bf5e38a880eec01d7e829d12ca682079f8238a464def3c4b31627" 1577 | dependencies = [ 1578 | "prettyplease", 1579 | "proc-macro2", 1580 | "syn 1.0.109", 1581 | ] 1582 | 1583 | [[package]] 1584 | name = "rustc-hash" 1585 | version = "1.1.0" 1586 | source = "registry+https://github.com/rust-lang/crates.io-index" 1587 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 1588 | 1589 | [[package]] 1590 | name = "rustc_version" 1591 | version = "0.4.0" 1592 | source = "registry+https://github.com/rust-lang/crates.io-index" 1593 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" 1594 | dependencies = [ 1595 | "semver", 1596 | ] 1597 | 1598 | [[package]] 1599 | name = "rustversion" 1600 | version = "1.0.16" 1601 | source = "registry+https://github.com/rust-lang/crates.io-index" 1602 | checksum = "092474d1a01ea8278f69e6a358998405fae5b8b963ddaeb2b0b04a128bf1dfb0" 1603 | 1604 | [[package]] 1605 | name = "ryu" 1606 | version = "1.0.18" 1607 | source = "registry+https://github.com/rust-lang/crates.io-index" 1608 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 1609 | 1610 | [[package]] 1611 | name = "same-file" 1612 | version = "1.0.6" 1613 | source = "registry+https://github.com/rust-lang/crates.io-index" 1614 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 1615 | dependencies = [ 1616 | "winapi-util", 1617 | ] 1618 | 1619 | [[package]] 1620 | name = "scoped-tls" 1621 | version = "1.0.1" 1622 | source = "registry+https://github.com/rust-lang/crates.io-index" 1623 | checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" 1624 | 1625 | [[package]] 1626 | name = "scopeguard" 1627 | version = "1.2.0" 1628 | source = "registry+https://github.com/rust-lang/crates.io-index" 1629 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1630 | 1631 | [[package]] 1632 | name = "semver" 1633 | version = "1.0.23" 1634 | source = "registry+https://github.com/rust-lang/crates.io-index" 1635 | checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" 1636 | 1637 | [[package]] 1638 | name = "serde" 1639 | version = "1.0.190" 1640 | source = "registry+https://github.com/rust-lang/crates.io-index" 1641 | checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" 1642 | dependencies = [ 1643 | "serde_derive", 1644 | ] 1645 | 1646 | [[package]] 1647 | name = "serde_bytes" 1648 | version = "0.11.14" 1649 | source = "registry+https://github.com/rust-lang/crates.io-index" 1650 | checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" 1651 | dependencies = [ 1652 | "serde", 1653 | ] 1654 | 1655 | [[package]] 1656 | name = "serde_derive" 1657 | version = "1.0.190" 1658 | source = "registry+https://github.com/rust-lang/crates.io-index" 1659 | checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" 1660 | dependencies = [ 1661 | "proc-macro2", 1662 | "quote", 1663 | "syn 2.0.38", 1664 | ] 1665 | 1666 | [[package]] 1667 | name = "serde_json" 1668 | version = "1.0.109" 1669 | source = "registry+https://github.com/rust-lang/crates.io-index" 1670 | checksum = "cb0652c533506ad7a2e353cce269330d6afd8bdfb6d75e0ace5b35aacbd7b9e9" 1671 | dependencies = [ 1672 | "itoa", 1673 | "ryu", 1674 | "serde", 1675 | ] 1676 | 1677 | [[package]] 1678 | name = "serde_spanned" 1679 | version = "0.6.8" 1680 | source = "registry+https://github.com/rust-lang/crates.io-index" 1681 | checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" 1682 | dependencies = [ 1683 | "serde", 1684 | ] 1685 | 1686 | [[package]] 1687 | name = "sha2" 1688 | version = "0.9.9" 1689 | source = "registry+https://github.com/rust-lang/crates.io-index" 1690 | checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" 1691 | dependencies = [ 1692 | "block-buffer 0.9.0", 1693 | "cfg-if", 1694 | "cpufeatures", 1695 | "digest 0.9.0", 1696 | "opaque-debug", 1697 | ] 1698 | 1699 | [[package]] 1700 | name = "sha2" 1701 | version = "0.10.8" 1702 | source = "registry+https://github.com/rust-lang/crates.io-index" 1703 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" 1704 | dependencies = [ 1705 | "cfg-if", 1706 | "cpufeatures", 1707 | "digest 0.10.7", 1708 | ] 1709 | 1710 | [[package]] 1711 | name = "sha3" 1712 | version = "0.10.8" 1713 | source = "registry+https://github.com/rust-lang/crates.io-index" 1714 | checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" 1715 | dependencies = [ 1716 | "digest 0.10.7", 1717 | "keccak", 1718 | ] 1719 | 1720 | [[package]] 1721 | name = "siphasher" 1722 | version = "0.3.11" 1723 | source = "registry+https://github.com/rust-lang/crates.io-index" 1724 | checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" 1725 | 1726 | [[package]] 1727 | name = "sized-chunks" 1728 | version = "0.6.5" 1729 | source = "registry+https://github.com/rust-lang/crates.io-index" 1730 | checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" 1731 | dependencies = [ 1732 | "bitmaps", 1733 | "typenum", 1734 | ] 1735 | 1736 | [[package]] 1737 | name = "smallvec" 1738 | version = "1.11.1" 1739 | source = "registry+https://github.com/rust-lang/crates.io-index" 1740 | checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" 1741 | 1742 | [[package]] 1743 | name = "smartstring" 1744 | version = "1.0.1" 1745 | source = "registry+https://github.com/rust-lang/crates.io-index" 1746 | checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" 1747 | dependencies = [ 1748 | "autocfg", 1749 | "static_assertions", 1750 | "version_check", 1751 | ] 1752 | 1753 | [[package]] 1754 | name = "solana-frozen-abi" 1755 | version = "1.17.14" 1756 | source = "registry+https://github.com/rust-lang/crates.io-index" 1757 | checksum = "8e2c5e5dde22cac045d29675b3fefa84817e1f63b0b911d094c599e80c0c07d9" 1758 | dependencies = [ 1759 | "ahash 0.8.11", 1760 | "blake3", 1761 | "block-buffer 0.10.4", 1762 | "bs58 0.4.0", 1763 | "bv", 1764 | "byteorder", 1765 | "cc", 1766 | "either", 1767 | "generic-array", 1768 | "im", 1769 | "lazy_static", 1770 | "log", 1771 | "memmap2", 1772 | "rustc_version", 1773 | "serde", 1774 | "serde_bytes", 1775 | "serde_derive", 1776 | "serde_json", 1777 | "sha2 0.10.8", 1778 | "solana-frozen-abi-macro", 1779 | "subtle", 1780 | "thiserror", 1781 | ] 1782 | 1783 | [[package]] 1784 | name = "solana-frozen-abi-macro" 1785 | version = "1.17.14" 1786 | source = "registry+https://github.com/rust-lang/crates.io-index" 1787 | checksum = "296e4cf0e2479e4c21afe4d17e32526f71f1bcd93b1c7c660900bc3e4233447a" 1788 | dependencies = [ 1789 | "proc-macro2", 1790 | "quote", 1791 | "rustc_version", 1792 | "syn 2.0.38", 1793 | ] 1794 | 1795 | [[package]] 1796 | name = "solana-program" 1797 | version = "1.17.14" 1798 | source = "registry+https://github.com/rust-lang/crates.io-index" 1799 | checksum = "8e3a3b9623f09e2c480b4e129c92d7a036f8614fd0fc7519791bd44e64061ce8" 1800 | dependencies = [ 1801 | "ark-bn254", 1802 | "ark-ec", 1803 | "ark-ff", 1804 | "ark-serialize", 1805 | "base64 0.21.7", 1806 | "bincode", 1807 | "bitflags 2.4.1", 1808 | "blake3", 1809 | "borsh 0.10.3", 1810 | "borsh 0.9.3", 1811 | "bs58 0.4.0", 1812 | "bv", 1813 | "bytemuck", 1814 | "cc", 1815 | "console_error_panic_hook", 1816 | "console_log", 1817 | "curve25519-dalek", 1818 | "getrandom 0.2.10", 1819 | "itertools", 1820 | "js-sys", 1821 | "lazy_static", 1822 | "libc", 1823 | "libsecp256k1", 1824 | "light-poseidon", 1825 | "log", 1826 | "memoffset", 1827 | "num-bigint", 1828 | "num-derive", 1829 | "num-traits", 1830 | "parking_lot", 1831 | "rand 0.8.5", 1832 | "rustc_version", 1833 | "rustversion", 1834 | "serde", 1835 | "serde_bytes", 1836 | "serde_derive", 1837 | "serde_json", 1838 | "sha2 0.10.8", 1839 | "sha3", 1840 | "solana-frozen-abi", 1841 | "solana-frozen-abi-macro", 1842 | "solana-sdk-macro", 1843 | "thiserror", 1844 | "tiny-bip39", 1845 | "wasm-bindgen", 1846 | "zeroize", 1847 | ] 1848 | 1849 | [[package]] 1850 | name = "solana-sdk-macro" 1851 | version = "1.17.14" 1852 | source = "registry+https://github.com/rust-lang/crates.io-index" 1853 | checksum = "60f58786e949f43b8c9b826fdfa5ad8586634b077ab04f989fb8e30535786712" 1854 | dependencies = [ 1855 | "bs58 0.4.0", 1856 | "proc-macro2", 1857 | "quote", 1858 | "rustversion", 1859 | "syn 2.0.38", 1860 | ] 1861 | 1862 | [[package]] 1863 | name = "stable_deref_trait" 1864 | version = "1.2.0" 1865 | source = "registry+https://github.com/rust-lang/crates.io-index" 1866 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 1867 | 1868 | [[package]] 1869 | name = "stacker" 1870 | version = "0.1.15" 1871 | source = "registry+https://github.com/rust-lang/crates.io-index" 1872 | checksum = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce" 1873 | dependencies = [ 1874 | "cc", 1875 | "cfg-if", 1876 | "libc", 1877 | "psm", 1878 | "winapi", 1879 | ] 1880 | 1881 | [[package]] 1882 | name = "static_assertions" 1883 | version = "1.1.0" 1884 | source = "registry+https://github.com/rust-lang/crates.io-index" 1885 | checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 1886 | 1887 | [[package]] 1888 | name = "string_cache" 1889 | version = "0.8.7" 1890 | source = "registry+https://github.com/rust-lang/crates.io-index" 1891 | checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" 1892 | dependencies = [ 1893 | "new_debug_unreachable", 1894 | "once_cell", 1895 | "parking_lot", 1896 | "phf_shared", 1897 | "precomputed-hash", 1898 | "serde", 1899 | ] 1900 | 1901 | [[package]] 1902 | name = "string_cache_codegen" 1903 | version = "0.5.2" 1904 | source = "registry+https://github.com/rust-lang/crates.io-index" 1905 | checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" 1906 | dependencies = [ 1907 | "phf_generator", 1908 | "phf_shared", 1909 | "proc-macro2", 1910 | "quote", 1911 | ] 1912 | 1913 | [[package]] 1914 | name = "string_enum" 1915 | version = "0.4.1" 1916 | source = "registry+https://github.com/rust-lang/crates.io-index" 1917 | checksum = "8fa4d4f81d7c05b9161f8de839975d3326328b8ba2831164b465524cc2f55252" 1918 | dependencies = [ 1919 | "pmutil", 1920 | "proc-macro2", 1921 | "quote", 1922 | "swc_macros_common", 1923 | "syn 2.0.38", 1924 | ] 1925 | 1926 | [[package]] 1927 | name = "strsim" 1928 | version = "0.11.1" 1929 | source = "registry+https://github.com/rust-lang/crates.io-index" 1930 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 1931 | 1932 | [[package]] 1933 | name = "subtle" 1934 | version = "2.5.0" 1935 | source = "registry+https://github.com/rust-lang/crates.io-index" 1936 | checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" 1937 | 1938 | [[package]] 1939 | name = "swc_atoms" 1940 | version = "0.6.0" 1941 | source = "registry+https://github.com/rust-lang/crates.io-index" 1942 | checksum = "ebf7a12229f0c0efb654a6a0f8cbfd94fbd320a57c764857a82d8abe9342b450" 1943 | dependencies = [ 1944 | "once_cell", 1945 | "rustc-hash", 1946 | "serde", 1947 | "string_cache", 1948 | "string_cache_codegen", 1949 | "triomphe", 1950 | ] 1951 | 1952 | [[package]] 1953 | name = "swc_common" 1954 | version = "0.33.2" 1955 | source = "registry+https://github.com/rust-lang/crates.io-index" 1956 | checksum = "c290470b7a9a4323c356208caf3c6c424b4c68e1d9aa63758b21d3e04e89cb07" 1957 | dependencies = [ 1958 | "ast_node", 1959 | "atty", 1960 | "better_scoped_tls", 1961 | "cfg-if", 1962 | "either", 1963 | "from_variant", 1964 | "new_debug_unreachable", 1965 | "num-bigint", 1966 | "once_cell", 1967 | "rustc-hash", 1968 | "serde", 1969 | "siphasher", 1970 | "string_cache", 1971 | "swc_atoms", 1972 | "swc_eq_ignore_macros", 1973 | "swc_visit", 1974 | "termcolor", 1975 | "tracing", 1976 | "unicode-width", 1977 | "url", 1978 | ] 1979 | 1980 | [[package]] 1981 | name = "swc_ecma_ast" 1982 | version = "0.110.2" 1983 | source = "registry+https://github.com/rust-lang/crates.io-index" 1984 | checksum = "2505e1bb74456695f6a92e68005a5fd1054fb3516e88268e81dbcfa4b26394b4" 1985 | dependencies = [ 1986 | "bitflags 2.4.1", 1987 | "is-macro", 1988 | "num-bigint", 1989 | "scoped-tls", 1990 | "string_enum", 1991 | "swc_atoms", 1992 | "swc_common", 1993 | "unicode-id", 1994 | ] 1995 | 1996 | [[package]] 1997 | name = "swc_ecma_parser" 1998 | version = "0.141.6" 1999 | source = "registry+https://github.com/rust-lang/crates.io-index" 2000 | checksum = "118da17ab64cf4842905ef661117f22bfbb9286424e14d9aaef537dcd66db085" 2001 | dependencies = [ 2002 | "either", 2003 | "num-bigint", 2004 | "num-traits", 2005 | "serde", 2006 | "smallvec", 2007 | "smartstring", 2008 | "stacker", 2009 | "swc_atoms", 2010 | "swc_common", 2011 | "swc_ecma_ast", 2012 | "tracing", 2013 | "typed-arena", 2014 | ] 2015 | 2016 | [[package]] 2017 | name = "swc_eq_ignore_macros" 2018 | version = "0.1.2" 2019 | source = "registry+https://github.com/rust-lang/crates.io-index" 2020 | checksum = "05a95d367e228d52484c53336991fdcf47b6b553ef835d9159db4ba40efb0ee8" 2021 | dependencies = [ 2022 | "pmutil", 2023 | "proc-macro2", 2024 | "quote", 2025 | "syn 2.0.38", 2026 | ] 2027 | 2028 | [[package]] 2029 | name = "swc_macros_common" 2030 | version = "0.3.8" 2031 | source = "registry+https://github.com/rust-lang/crates.io-index" 2032 | checksum = "7a273205ccb09b51fabe88c49f3b34c5a4631c4c00a16ae20e03111d6a42e832" 2033 | dependencies = [ 2034 | "pmutil", 2035 | "proc-macro2", 2036 | "quote", 2037 | "syn 2.0.38", 2038 | ] 2039 | 2040 | [[package]] 2041 | name = "swc_visit" 2042 | version = "0.5.7" 2043 | source = "registry+https://github.com/rust-lang/crates.io-index" 2044 | checksum = "e87c337fbb2d191bf371173dea6a957f01899adb8f189c6c31b122a6cfc98fc3" 2045 | dependencies = [ 2046 | "either", 2047 | "swc_visit_macros", 2048 | ] 2049 | 2050 | [[package]] 2051 | name = "swc_visit_macros" 2052 | version = "0.5.8" 2053 | source = "registry+https://github.com/rust-lang/crates.io-index" 2054 | checksum = "0f322730fb82f3930a450ac24de8c98523af7d34ab8cb2f46bcb405839891a99" 2055 | dependencies = [ 2056 | "Inflector", 2057 | "pmutil", 2058 | "proc-macro2", 2059 | "quote", 2060 | "swc_macros_common", 2061 | "syn 2.0.38", 2062 | ] 2063 | 2064 | [[package]] 2065 | name = "syn" 2066 | version = "1.0.109" 2067 | source = "registry+https://github.com/rust-lang/crates.io-index" 2068 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 2069 | dependencies = [ 2070 | "proc-macro2", 2071 | "quote", 2072 | "unicode-ident", 2073 | ] 2074 | 2075 | [[package]] 2076 | name = "syn" 2077 | version = "2.0.38" 2078 | source = "registry+https://github.com/rust-lang/crates.io-index" 2079 | checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" 2080 | dependencies = [ 2081 | "proc-macro2", 2082 | "quote", 2083 | "unicode-ident", 2084 | ] 2085 | 2086 | [[package]] 2087 | name = "termcolor" 2088 | version = "1.3.0" 2089 | source = "registry+https://github.com/rust-lang/crates.io-index" 2090 | checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" 2091 | dependencies = [ 2092 | "winapi-util", 2093 | ] 2094 | 2095 | [[package]] 2096 | name = "thiserror" 2097 | version = "1.0.50" 2098 | source = "registry+https://github.com/rust-lang/crates.io-index" 2099 | checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" 2100 | dependencies = [ 2101 | "thiserror-impl", 2102 | ] 2103 | 2104 | [[package]] 2105 | name = "thiserror-impl" 2106 | version = "1.0.50" 2107 | source = "registry+https://github.com/rust-lang/crates.io-index" 2108 | checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" 2109 | dependencies = [ 2110 | "proc-macro2", 2111 | "quote", 2112 | "syn 2.0.38", 2113 | ] 2114 | 2115 | [[package]] 2116 | name = "tiny-bip39" 2117 | version = "0.8.2" 2118 | source = "registry+https://github.com/rust-lang/crates.io-index" 2119 | checksum = "ffc59cb9dfc85bb312c3a78fd6aa8a8582e310b0fa885d5bb877f6dcc601839d" 2120 | dependencies = [ 2121 | "anyhow", 2122 | "hmac", 2123 | "once_cell", 2124 | "pbkdf2", 2125 | "rand 0.7.3", 2126 | "rustc-hash", 2127 | "sha2 0.9.9", 2128 | "thiserror", 2129 | "unicode-normalization", 2130 | "wasm-bindgen", 2131 | "zeroize", 2132 | ] 2133 | 2134 | [[package]] 2135 | name = "tinyvec" 2136 | version = "1.6.0" 2137 | source = "registry+https://github.com/rust-lang/crates.io-index" 2138 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 2139 | dependencies = [ 2140 | "tinyvec_macros", 2141 | ] 2142 | 2143 | [[package]] 2144 | name = "tinyvec_macros" 2145 | version = "0.1.1" 2146 | source = "registry+https://github.com/rust-lang/crates.io-index" 2147 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 2148 | 2149 | [[package]] 2150 | name = "toml" 2151 | version = "0.5.11" 2152 | source = "registry+https://github.com/rust-lang/crates.io-index" 2153 | checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" 2154 | dependencies = [ 2155 | "serde", 2156 | ] 2157 | 2158 | [[package]] 2159 | name = "toml" 2160 | version = "0.8.19" 2161 | source = "registry+https://github.com/rust-lang/crates.io-index" 2162 | checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" 2163 | dependencies = [ 2164 | "serde", 2165 | "serde_spanned", 2166 | "toml_datetime", 2167 | "toml_edit", 2168 | ] 2169 | 2170 | [[package]] 2171 | name = "toml_datetime" 2172 | version = "0.6.8" 2173 | source = "registry+https://github.com/rust-lang/crates.io-index" 2174 | checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" 2175 | dependencies = [ 2176 | "serde", 2177 | ] 2178 | 2179 | [[package]] 2180 | name = "toml_edit" 2181 | version = "0.22.22" 2182 | source = "registry+https://github.com/rust-lang/crates.io-index" 2183 | checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" 2184 | dependencies = [ 2185 | "indexmap", 2186 | "serde", 2187 | "serde_spanned", 2188 | "toml_datetime", 2189 | "winnow", 2190 | ] 2191 | 2192 | [[package]] 2193 | name = "tracing" 2194 | version = "0.1.40" 2195 | source = "registry+https://github.com/rust-lang/crates.io-index" 2196 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" 2197 | dependencies = [ 2198 | "pin-project-lite", 2199 | "tracing-attributes", 2200 | "tracing-core", 2201 | ] 2202 | 2203 | [[package]] 2204 | name = "tracing-attributes" 2205 | version = "0.1.27" 2206 | source = "registry+https://github.com/rust-lang/crates.io-index" 2207 | checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" 2208 | dependencies = [ 2209 | "proc-macro2", 2210 | "quote", 2211 | "syn 2.0.38", 2212 | ] 2213 | 2214 | [[package]] 2215 | name = "tracing-core" 2216 | version = "0.1.32" 2217 | source = "registry+https://github.com/rust-lang/crates.io-index" 2218 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" 2219 | dependencies = [ 2220 | "once_cell", 2221 | ] 2222 | 2223 | [[package]] 2224 | name = "triomphe" 2225 | version = "0.1.9" 2226 | source = "registry+https://github.com/rust-lang/crates.io-index" 2227 | checksum = "0eee8098afad3fb0c54a9007aab6804558410503ad676d4633f9c2559a00ac0f" 2228 | dependencies = [ 2229 | "serde", 2230 | "stable_deref_trait", 2231 | ] 2232 | 2233 | [[package]] 2234 | name = "typed-arena" 2235 | version = "2.0.2" 2236 | source = "registry+https://github.com/rust-lang/crates.io-index" 2237 | checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" 2238 | 2239 | [[package]] 2240 | name = "typenum" 2241 | version = "1.17.0" 2242 | source = "registry+https://github.com/rust-lang/crates.io-index" 2243 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 2244 | 2245 | [[package]] 2246 | name = "unicode-bidi" 2247 | version = "0.3.13" 2248 | source = "registry+https://github.com/rust-lang/crates.io-index" 2249 | checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" 2250 | 2251 | [[package]] 2252 | name = "unicode-id" 2253 | version = "0.3.4" 2254 | source = "registry+https://github.com/rust-lang/crates.io-index" 2255 | checksum = "b1b6def86329695390197b82c1e244a54a131ceb66c996f2088a3876e2ae083f" 2256 | 2257 | [[package]] 2258 | name = "unicode-ident" 2259 | version = "1.0.12" 2260 | source = "registry+https://github.com/rust-lang/crates.io-index" 2261 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 2262 | 2263 | [[package]] 2264 | name = "unicode-normalization" 2265 | version = "0.1.22" 2266 | source = "registry+https://github.com/rust-lang/crates.io-index" 2267 | checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" 2268 | dependencies = [ 2269 | "tinyvec", 2270 | ] 2271 | 2272 | [[package]] 2273 | name = "unicode-segmentation" 2274 | version = "1.10.1" 2275 | source = "registry+https://github.com/rust-lang/crates.io-index" 2276 | checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" 2277 | 2278 | [[package]] 2279 | name = "unicode-width" 2280 | version = "0.1.11" 2281 | source = "registry+https://github.com/rust-lang/crates.io-index" 2282 | checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" 2283 | 2284 | [[package]] 2285 | name = "url" 2286 | version = "2.4.1" 2287 | source = "registry+https://github.com/rust-lang/crates.io-index" 2288 | checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" 2289 | dependencies = [ 2290 | "form_urlencoded", 2291 | "idna", 2292 | "percent-encoding", 2293 | ] 2294 | 2295 | [[package]] 2296 | name = "utf8parse" 2297 | version = "0.2.2" 2298 | source = "registry+https://github.com/rust-lang/crates.io-index" 2299 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 2300 | 2301 | [[package]] 2302 | name = "version_check" 2303 | version = "0.9.4" 2304 | source = "registry+https://github.com/rust-lang/crates.io-index" 2305 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 2306 | 2307 | [[package]] 2308 | name = "walkdir" 2309 | version = "2.5.0" 2310 | source = "registry+https://github.com/rust-lang/crates.io-index" 2311 | checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" 2312 | dependencies = [ 2313 | "same-file", 2314 | "winapi-util", 2315 | ] 2316 | 2317 | [[package]] 2318 | name = "wasi" 2319 | version = "0.9.0+wasi-snapshot-preview1" 2320 | source = "registry+https://github.com/rust-lang/crates.io-index" 2321 | checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" 2322 | 2323 | [[package]] 2324 | name = "wasi" 2325 | version = "0.11.0+wasi-snapshot-preview1" 2326 | source = "registry+https://github.com/rust-lang/crates.io-index" 2327 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 2328 | 2329 | [[package]] 2330 | name = "wasm-bindgen" 2331 | version = "0.2.92" 2332 | source = "registry+https://github.com/rust-lang/crates.io-index" 2333 | checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" 2334 | dependencies = [ 2335 | "cfg-if", 2336 | "wasm-bindgen-macro", 2337 | ] 2338 | 2339 | [[package]] 2340 | name = "wasm-bindgen-backend" 2341 | version = "0.2.92" 2342 | source = "registry+https://github.com/rust-lang/crates.io-index" 2343 | checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" 2344 | dependencies = [ 2345 | "bumpalo", 2346 | "log", 2347 | "once_cell", 2348 | "proc-macro2", 2349 | "quote", 2350 | "syn 2.0.38", 2351 | "wasm-bindgen-shared", 2352 | ] 2353 | 2354 | [[package]] 2355 | name = "wasm-bindgen-macro" 2356 | version = "0.2.92" 2357 | source = "registry+https://github.com/rust-lang/crates.io-index" 2358 | checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" 2359 | dependencies = [ 2360 | "quote", 2361 | "wasm-bindgen-macro-support", 2362 | ] 2363 | 2364 | [[package]] 2365 | name = "wasm-bindgen-macro-support" 2366 | version = "0.2.92" 2367 | source = "registry+https://github.com/rust-lang/crates.io-index" 2368 | checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" 2369 | dependencies = [ 2370 | "proc-macro2", 2371 | "quote", 2372 | "syn 2.0.38", 2373 | "wasm-bindgen-backend", 2374 | "wasm-bindgen-shared", 2375 | ] 2376 | 2377 | [[package]] 2378 | name = "wasm-bindgen-shared" 2379 | version = "0.2.92" 2380 | source = "registry+https://github.com/rust-lang/crates.io-index" 2381 | checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" 2382 | 2383 | [[package]] 2384 | name = "web-sys" 2385 | version = "0.3.69" 2386 | source = "registry+https://github.com/rust-lang/crates.io-index" 2387 | checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" 2388 | dependencies = [ 2389 | "js-sys", 2390 | "wasm-bindgen", 2391 | ] 2392 | 2393 | [[package]] 2394 | name = "winapi" 2395 | version = "0.3.9" 2396 | source = "registry+https://github.com/rust-lang/crates.io-index" 2397 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 2398 | dependencies = [ 2399 | "winapi-i686-pc-windows-gnu", 2400 | "winapi-x86_64-pc-windows-gnu", 2401 | ] 2402 | 2403 | [[package]] 2404 | name = "winapi-i686-pc-windows-gnu" 2405 | version = "0.4.0" 2406 | source = "registry+https://github.com/rust-lang/crates.io-index" 2407 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 2408 | 2409 | [[package]] 2410 | name = "winapi-util" 2411 | version = "0.1.6" 2412 | source = "registry+https://github.com/rust-lang/crates.io-index" 2413 | checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" 2414 | dependencies = [ 2415 | "winapi", 2416 | ] 2417 | 2418 | [[package]] 2419 | name = "winapi-x86_64-pc-windows-gnu" 2420 | version = "0.4.0" 2421 | source = "registry+https://github.com/rust-lang/crates.io-index" 2422 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 2423 | 2424 | [[package]] 2425 | name = "windows-sys" 2426 | version = "0.52.0" 2427 | source = "registry+https://github.com/rust-lang/crates.io-index" 2428 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 2429 | dependencies = [ 2430 | "windows-targets 0.52.6", 2431 | ] 2432 | 2433 | [[package]] 2434 | name = "windows-targets" 2435 | version = "0.48.5" 2436 | source = "registry+https://github.com/rust-lang/crates.io-index" 2437 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 2438 | dependencies = [ 2439 | "windows_aarch64_gnullvm 0.48.5", 2440 | "windows_aarch64_msvc 0.48.5", 2441 | "windows_i686_gnu 0.48.5", 2442 | "windows_i686_msvc 0.48.5", 2443 | "windows_x86_64_gnu 0.48.5", 2444 | "windows_x86_64_gnullvm 0.48.5", 2445 | "windows_x86_64_msvc 0.48.5", 2446 | ] 2447 | 2448 | [[package]] 2449 | name = "windows-targets" 2450 | version = "0.52.6" 2451 | source = "registry+https://github.com/rust-lang/crates.io-index" 2452 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 2453 | dependencies = [ 2454 | "windows_aarch64_gnullvm 0.52.6", 2455 | "windows_aarch64_msvc 0.52.6", 2456 | "windows_i686_gnu 0.52.6", 2457 | "windows_i686_gnullvm", 2458 | "windows_i686_msvc 0.52.6", 2459 | "windows_x86_64_gnu 0.52.6", 2460 | "windows_x86_64_gnullvm 0.52.6", 2461 | "windows_x86_64_msvc 0.52.6", 2462 | ] 2463 | 2464 | [[package]] 2465 | name = "windows_aarch64_gnullvm" 2466 | version = "0.48.5" 2467 | source = "registry+https://github.com/rust-lang/crates.io-index" 2468 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 2469 | 2470 | [[package]] 2471 | name = "windows_aarch64_gnullvm" 2472 | version = "0.52.6" 2473 | source = "registry+https://github.com/rust-lang/crates.io-index" 2474 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 2475 | 2476 | [[package]] 2477 | name = "windows_aarch64_msvc" 2478 | version = "0.48.5" 2479 | source = "registry+https://github.com/rust-lang/crates.io-index" 2480 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 2481 | 2482 | [[package]] 2483 | name = "windows_aarch64_msvc" 2484 | version = "0.52.6" 2485 | source = "registry+https://github.com/rust-lang/crates.io-index" 2486 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 2487 | 2488 | [[package]] 2489 | name = "windows_i686_gnu" 2490 | version = "0.48.5" 2491 | source = "registry+https://github.com/rust-lang/crates.io-index" 2492 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 2493 | 2494 | [[package]] 2495 | name = "windows_i686_gnu" 2496 | version = "0.52.6" 2497 | source = "registry+https://github.com/rust-lang/crates.io-index" 2498 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 2499 | 2500 | [[package]] 2501 | name = "windows_i686_gnullvm" 2502 | version = "0.52.6" 2503 | source = "registry+https://github.com/rust-lang/crates.io-index" 2504 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 2505 | 2506 | [[package]] 2507 | name = "windows_i686_msvc" 2508 | version = "0.48.5" 2509 | source = "registry+https://github.com/rust-lang/crates.io-index" 2510 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 2511 | 2512 | [[package]] 2513 | name = "windows_i686_msvc" 2514 | version = "0.52.6" 2515 | source = "registry+https://github.com/rust-lang/crates.io-index" 2516 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 2517 | 2518 | [[package]] 2519 | name = "windows_x86_64_gnu" 2520 | version = "0.48.5" 2521 | source = "registry+https://github.com/rust-lang/crates.io-index" 2522 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 2523 | 2524 | [[package]] 2525 | name = "windows_x86_64_gnu" 2526 | version = "0.52.6" 2527 | source = "registry+https://github.com/rust-lang/crates.io-index" 2528 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 2529 | 2530 | [[package]] 2531 | name = "windows_x86_64_gnullvm" 2532 | version = "0.48.5" 2533 | source = "registry+https://github.com/rust-lang/crates.io-index" 2534 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 2535 | 2536 | [[package]] 2537 | name = "windows_x86_64_gnullvm" 2538 | version = "0.52.6" 2539 | source = "registry+https://github.com/rust-lang/crates.io-index" 2540 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 2541 | 2542 | [[package]] 2543 | name = "windows_x86_64_msvc" 2544 | version = "0.48.5" 2545 | source = "registry+https://github.com/rust-lang/crates.io-index" 2546 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 2547 | 2548 | [[package]] 2549 | name = "windows_x86_64_msvc" 2550 | version = "0.52.6" 2551 | source = "registry+https://github.com/rust-lang/crates.io-index" 2552 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 2553 | 2554 | [[package]] 2555 | name = "winnow" 2556 | version = "0.6.20" 2557 | source = "registry+https://github.com/rust-lang/crates.io-index" 2558 | checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" 2559 | dependencies = [ 2560 | "memchr", 2561 | ] 2562 | 2563 | [[package]] 2564 | name = "zerocopy" 2565 | version = "0.7.34" 2566 | source = "registry+https://github.com/rust-lang/crates.io-index" 2567 | checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" 2568 | dependencies = [ 2569 | "zerocopy-derive", 2570 | ] 2571 | 2572 | [[package]] 2573 | name = "zerocopy-derive" 2574 | version = "0.7.34" 2575 | source = "registry+https://github.com/rust-lang/crates.io-index" 2576 | checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" 2577 | dependencies = [ 2578 | "proc-macro2", 2579 | "quote", 2580 | "syn 2.0.38", 2581 | ] 2582 | 2583 | [[package]] 2584 | name = "zeroize" 2585 | version = "1.3.0" 2586 | source = "registry+https://github.com/rust-lang/crates.io-index" 2587 | checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" 2588 | dependencies = [ 2589 | "zeroize_derive", 2590 | ] 2591 | 2592 | [[package]] 2593 | name = "zeroize_derive" 2594 | version = "1.4.2" 2595 | source = "registry+https://github.com/rust-lang/crates.io-index" 2596 | checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" 2597 | dependencies = [ 2598 | "proc-macro2", 2599 | "quote", 2600 | "syn 2.0.38", 2601 | ] 2602 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "poseidon" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | anyhow = "1.0.75" 8 | convert_case = "0.6.0" 9 | swc_common = { version = "0.33.2", features=["tty-emitter"] } 10 | swc_ecma_parser = { version = "0.141.6", features = ["typescript"] } 11 | swc_ecma_ast = "0.110.2" 12 | thiserror = "1.0.50" 13 | quote = "1.0.33" 14 | proc-macro2 = "1.0.69" 15 | rust-format = { version = "0.3.4", features = ["pretty_please"] } 16 | anchor-lang = { version = "0.30.0", features = ["init-if-needed"]} 17 | clap = { version = "4.4.8", features = ["derive", "cargo"] } 18 | regex = "1.11.0" 19 | walkdir = "2.3" 20 | toml = "0.8.0" 21 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Poseidon 2 | 3 | Now you can write solana programs in Typescript 4 | 5 | poseidon is a transpiler that helps you to convert your Typescript solana programs to anchor. Which is especially convenient for people who are just getting started with solana. 6 | 7 | - [Installation](https://poseidon.turbin3.com/installation.html) 8 | - [Usage](https://poseidon.turbin3.com/usage.html) 9 | - [Quick Start & Examples](https://poseidon.turbin3.com/tutorial.html) 10 | 11 | ## Installation 12 | 13 | Make sure you have Rust and Cargo installed, then run the following command 14 | 15 | Clone the repository: 16 | 17 | ```sh 18 | cargo install --git https://github.com/Turbin3/poseidon 19 | ``` 20 | 21 | ## Usage 22 | 23 | ```sh 24 | poseidon compile --input "input.ts" --output "output.rs" 25 | ``` 26 | 27 | ## Tutorial & Examples 28 | 29 | Go to [docs/src/tutorial.md](./docs/src/tutorial.md) to learn how to write your first Solana program in TypeScript using Poseidon and Anchor! 30 | 31 | For more examples, check out the [examples](./examples) directory. You’ll find examples of [vote](./examples/vote), [vault](./examples/vault), [escrow](./examples/escrow), and [favorites](./examples/favorites) programs in both TypeScript and the corresponding Rust programs transpiled by Poseidon. 32 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | book 2 | -------------------------------------------------------------------------------- /docs/book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["Shrinath", "Dean", "Emerson"] 3 | language = "en" 4 | multilingual = false 5 | src = "src" 6 | title = "Poseidon Documentation" 7 | -------------------------------------------------------------------------------- /docs/src/README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | **`Poseidon`** is a **_transpiler_** that helps you to convert your TypeScript Solana programs into Anchor, which is especially convenient for people who are just getting started with Solana! 4 | 5 | > Now you can write Solana programs in Typescript and transpile them into Rust using Poseidon! 6 | -------------------------------------------------------------------------------- /docs/src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | [Introduction](./README.md) 4 | 5 | # User Guide 6 | 7 | - [Installation](./installation.md) 8 | - [Usage](./usage.md) 9 | - [Tutorial](./tutorial.md) 10 | 11 | # Deep Dive 12 | 13 | - [Mapping into Anchor](./mapping-into-anchor/README.md) 14 | 15 | - [Program](./mapping-into-anchor/program.md) 16 | - [Instruction](./mapping-into-anchor/instruction.md) 17 | - [State](./mapping-into-anchor/state.md) 18 | - [Program Derived Address](./mapping-into-anchor/pda.md) 19 | - [Account Constraints](./mapping-into-anchor/account-constraints.md) 20 | - [Cross Program Invocation](./mapping-into-anchor/cpi.md) 21 | 22 | - [Other Resources](./reference/other-resources.md) 23 | -------------------------------------------------------------------------------- /docs/src/installation.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | Make sure you have Rust and Cargo installed 4 | 5 | ### Installing with Cargo 6 | 7 | ```sh 8 | cargo install --git https://github.com/Turbin3/poseidon 9 | ``` 10 | 11 | That's it, you're done! 12 | 13 | ### Installing from source 14 | 15 | ```sh 16 | git clone https://github.com/Turbin3/poseidon 17 | ``` 18 | 19 | Navigate to the project directory: 20 | 21 | ```sh 22 | cd poseidon 23 | ``` 24 | 25 | Build `poseidon`: 26 | 27 | ```sh 28 | cargo build --release 29 | ``` 30 | 31 | This will create a binary named `poseidon` in the `target/release` directory. You can copy the binary to a location in your `$PATH` for easier access. 32 | -------------------------------------------------------------------------------- /docs/src/mapping-into-anchor/README.md: -------------------------------------------------------------------------------- 1 | # Mapping into Anchor 2 | 3 | In this section, we will dive deep into how TypeScript code is mapped to the Anchor framework in Rust. We will use the `escrow` program as the example to illustrate the differences and similarities between the two. 4 | 5 | ## Comparison Table 6 | 7 | | Solana Term | TypeScript (Poseidon) | Rust (Anchor) | 8 | | --------------- | --------------------- | ------------- | 9 | | Program | Class | Module | 10 | | Instruction | Method | Function | 11 | | Account (State) | Interface | Struct | 12 | 13 | ## `Escrow` Program 14 | 15 | You can find the code for the `escrow` program in the [`examples/escrow`](../../../examples/escrow/) directory of the Poseidon repository. 16 | 17 | ### TypeScript (Poseidon) 18 | 19 | Let's start with the TypeScript code for the `escrow` program. This code defines the structure and logic of the program using Poseidon. 20 | 21 | ```typescript 22 | import { 23 | Account, 24 | AssociatedTokenAccount, 25 | Mint, 26 | Pubkey, 27 | Seeds, 28 | Signer, 29 | SystemAccount, 30 | TokenAccount, 31 | TokenProgram, 32 | UncheckedAccount, 33 | u64, 34 | u8, 35 | } from "@solanaturbine/poseidon"; 36 | 37 | export default class EscrowProgram { 38 | static PROGRAM_ID = new Pubkey("11111111111111111111111111111111"); 39 | 40 | make( 41 | maker: Signer, 42 | makerMint: Mint, 43 | takerMint: Mint, 44 | makerAta: AssociatedTokenAccount, 45 | auth: UncheckedAccount, 46 | vault: TokenAccount, 47 | escrow: EscrowState, 48 | depositAmount: u64, 49 | offerAmount: u64, 50 | seed: u64 51 | ) { 52 | makerAta.derive(makerMint, maker.key); 53 | auth.derive(["auth"]); 54 | vault.derive(["vault", escrow.key], makerMint, auth.key).init(); 55 | escrow.derive(["escrow", maker.key, seed.toBytes()]).init(); 56 | 57 | escrow.authBump = auth.getBump(); 58 | escrow.vaultBump = vault.getBump(); 59 | escrow.escrowBump = escrow.getBump(); 60 | 61 | escrow.maker = maker.key; 62 | escrow.makerMint = makerMint.key; 63 | escrow.takerMint = takerMint.key; 64 | escrow.amount = offerAmount; 65 | escrow.seed = seed; 66 | 67 | TokenProgram.transfer( 68 | makerAta, // from 69 | vault, // to 70 | maker, // authority 71 | depositAmount // amount to transferred 72 | ); 73 | } 74 | 75 | refund( 76 | maker: Signer, 77 | makerMint: Mint, 78 | makerAta: AssociatedTokenAccount, 79 | auth: UncheckedAccount, 80 | vault: TokenAccount, 81 | escrow: EscrowState 82 | ) { 83 | makerAta.derive(makerMint, maker.key); 84 | auth.derive(["auth"]); 85 | vault.derive(["vault", escrow.key], makerMint, auth.key); 86 | escrow 87 | .derive(["escrow", maker.key, escrow.seed.toBytes()]) 88 | .has([maker]) 89 | .close(maker); 90 | 91 | TokenProgram.transfer( 92 | vault, 93 | makerAta, 94 | auth, 95 | vault.amount, 96 | ["auth", escrow.authBump.toBytes()] // Seeds for the PDA signing 97 | ); 98 | } 99 | 100 | take( 101 | taker: Signer, 102 | maker: SystemAccount, 103 | takerMint: Mint, 104 | makerMint: Mint, 105 | takerAta: AssociatedTokenAccount, 106 | takerReceiveAta: AssociatedTokenAccount, 107 | makerReceiveAta: AssociatedTokenAccount, 108 | auth: UncheckedAccount, 109 | vault: TokenAccount, 110 | escrow: EscrowState 111 | ) { 112 | takerAta.derive(takerMint, taker.key); 113 | takerReceiveAta.derive(makerMint, taker.key).initIfNeeded(); 114 | makerReceiveAta.derive(takerMint, maker.key).initIfNeeded(); 115 | auth.derive(["auth"]); 116 | vault.derive(["vault", escrow.key], makerMint, auth.key); 117 | escrow 118 | .derive(["escrow", maker.key, escrow.seed.toBytes()]) 119 | .has([maker, makerMint, takerMint]) 120 | .close(maker); 121 | 122 | TokenProgram.transfer(takerAta, makerReceiveAta, taker, escrow.amount); 123 | 124 | // Explicitly define the seeds for the PDA signing 125 | let seeds: Seeds = ["auth", escrow.authBump.toBytes()]; 126 | TokenProgram.transfer(vault, takerReceiveAta, auth, vault.amount, seeds); 127 | } 128 | } 129 | 130 | export interface EscrowState extends Account { 131 | maker: Pubkey; 132 | makerMint: Pubkey; 133 | takerMint: Pubkey; 134 | amount: u64; 135 | seed: u64; 136 | authBump: u8; 137 | escrowBump: u8; 138 | vaultBump: u8; 139 | } 140 | ``` 141 | 142 | ### Rust (Anchor) 143 | 144 | Now, let's look at the equivalent Rust code using the Anchor framework. 145 | 146 | ```rust,ignore 147 | use anchor_lang::prelude::*; 148 | use anchor_spl::{ 149 | token::{ 150 | TokenAccount, Mint, Token, transfer as transfer_spl, Transfer as TransferSPL, 151 | }, 152 | associated_token::AssociatedToken, 153 | }; 154 | declare_id!("11111111111111111111111111111111"); 155 | #[program] 156 | pub mod escrow_program { 157 | use super::*; 158 | pub fn make( 159 | ctx: Context, 160 | deposit_amount: u64, 161 | offer_amount: u64, 162 | seed: u64, 163 | ) -> Result<()> { 164 | ctx.accounts.escrow.auth_bump = ctx.bumps.auth; 165 | ctx.accounts.escrow.vault_bump = ctx.bumps.vault; 166 | ctx.accounts.escrow.escrow_bump = ctx.bumps.escrow; 167 | ctx.accounts.escrow.maker = ctx.accounts.maker.key(); 168 | ctx.accounts.escrow.maker_mint = ctx.accounts.maker_mint.key(); 169 | ctx.accounts.escrow.taker_mint = ctx.accounts.taker_mint.key(); 170 | ctx.accounts.escrow.amount = offer_amount; 171 | ctx.accounts.escrow.seed = seed; 172 | let cpi_accounts = TransferSPL { 173 | from: ctx.accounts.maker_ata.to_account_info(), 174 | to: ctx.accounts.vault.to_account_info(), 175 | authority: ctx.accounts.maker.to_account_info(), 176 | }; 177 | let cpi_ctx = CpiContext::new( 178 | ctx.accounts.token_program.to_account_info(), 179 | cpi_accounts, 180 | ); 181 | transfer_spl(cpi_ctx, deposit_amount)?; 182 | Ok(()) 183 | } 184 | pub fn refund(ctx: Context) -> Result<()> { 185 | let cpi_accounts = TransferSPL { 186 | from: ctx.accounts.vault.to_account_info(), 187 | to: ctx.accounts.maker_ata.to_account_info(), 188 | authority: ctx.accounts.auth.to_account_info(), 189 | }; 190 | let signer_seeds = &[&b"auth"[..], &[ctx.accounts.escrow.auth_bump]]; 191 | let binding = [&signer_seeds[..]]; 192 | let cpi_ctx = CpiContext::new_with_signer( 193 | ctx.accounts.token_program.to_account_info(), 194 | cpi_accounts, 195 | &binding, 196 | ); 197 | transfer_spl(cpi_ctx, ctx.accounts.vault.amount)?; 198 | Ok(()) 199 | } 200 | pub fn take(ctx: Context) -> Result<()> { 201 | let cpi_accounts = TransferSPL { 202 | from: ctx.accounts.taker_ata.to_account_info(), 203 | to: ctx.accounts.maker_receive_ata.to_account_info(), 204 | authority: ctx.accounts.taker.to_account_info(), 205 | }; 206 | let cpi_ctx = CpiContext::new( 207 | ctx.accounts.token_program.to_account_info(), 208 | cpi_accounts, 209 | ); 210 | transfer_spl(cpi_ctx, ctx.accounts.escrow.amount)?; 211 | let cpi_accounts = TransferSPL { 212 | from: ctx.accounts.vault.to_account_info(), 213 | to: ctx.accounts.taker_receive_ata.to_account_info(), 214 | authority: ctx.accounts.auth.to_account_info(), 215 | }; 216 | let signer_seeds = &[&b"auth"[..], &[ctx.accounts.escrow.auth_bump]]; 217 | let binding = [&signer_seeds[..]]; 218 | let cpi_ctx = CpiContext::new_with_signer( 219 | ctx.accounts.token_program.to_account_info(), 220 | cpi_accounts, 221 | &binding, 222 | ); 223 | transfer_spl(cpi_ctx, ctx.accounts.vault.amount)?; 224 | Ok(()) 225 | } 226 | } 227 | #[derive(Accounts)] 228 | #[instruction(seed:u64)] 229 | pub struct MakeContext<'info> { 230 | #[account( 231 | mut, 232 | associated_token::mint = maker_mint, 233 | associated_token::authority = maker, 234 | )] 235 | pub maker_ata: Account<'info, TokenAccount>, 236 | #[account(seeds = [b"auth"], bump)] 237 | /// CHECK: This acc is safe 238 | pub auth: UncheckedAccount<'info>, 239 | #[account(mut)] 240 | pub maker: Signer<'info>, 241 | #[account()] 242 | pub maker_mint: Account<'info, Mint>, 243 | #[account( 244 | init, 245 | payer = maker, 246 | seeds = [b"vault", 247 | escrow.key().as_ref()], 248 | token::mint = maker_mint, 249 | token::authority = auth, 250 | bump, 251 | )] 252 | pub vault: Account<'info, TokenAccount>, 253 | #[account()] 254 | pub taker_mint: Account<'info, Mint>, 255 | #[account( 256 | init, 257 | payer = maker, 258 | space = 123, 259 | seeds = [b"escrow", 260 | maker.key().as_ref(), 261 | seed.to_le_bytes().as_ref()], 262 | bump, 263 | )] 264 | pub escrow: Account<'info, EscrowState>, 265 | pub associated_token_program: Program<'info, AssociatedToken>, 266 | pub token_program: Program<'info, Token>, 267 | pub system_program: Program<'info, System>, 268 | } 269 | #[derive(Accounts)] 270 | pub struct RefundContext<'info> { 271 | #[account( 272 | mut, 273 | associated_token::mint = maker_mint, 274 | associated_token::authority = maker, 275 | )] 276 | pub maker_ata: Account<'info, TokenAccount>, 277 | #[account( 278 | mut, 279 | seeds = [b"vault", 280 | escrow.key().as_ref()], 281 | token::mint = maker_mint, 282 | token::authority = auth, 283 | bump, 284 | )] 285 | pub vault: Account<'info, TokenAccount>, 286 | #[account()] 287 | pub maker_mint: Account<'info, Mint>, 288 | #[account(mut)] 289 | pub maker: Signer<'info>, 290 | #[account( 291 | mut, 292 | seeds = [b"escrow", 293 | maker.key().as_ref(), 294 | escrow.seed.to_le_bytes().as_ref()], 295 | has_one = maker, 296 | bump, 297 | close = maker, 298 | )] 299 | pub escrow: Account<'info, EscrowState>, 300 | #[account(seeds = [b"auth"], bump)] 301 | /// CHECK: This acc is safe 302 | pub auth: UncheckedAccount<'info>, 303 | pub associated_token_program: Program<'info, AssociatedToken>, 304 | pub token_program: Program<'info, Token>, 305 | pub system_program: Program<'info, System>, 306 | } 307 | #[derive(Accounts)] 308 | pub struct TakeContext<'info> { 309 | #[account( 310 | init_if_needed, 311 | payer = taker, 312 | associated_token::mint = maker_mint, 313 | associated_token::authority = taker, 314 | )] 315 | pub taker_receive_ata: Account<'info, TokenAccount>, 316 | #[account(mut)] 317 | pub taker: Signer<'info>, 318 | #[account( 319 | mut, 320 | seeds = [b"vault", 321 | escrow.key().as_ref()], 322 | token::mint = maker_mint, 323 | token::authority = auth, 324 | bump, 325 | )] 326 | pub vault: Account<'info, TokenAccount>, 327 | #[account( 328 | mut, 329 | associated_token::mint = taker_mint, 330 | associated_token::authority = taker, 331 | )] 332 | pub taker_ata: Account<'info, TokenAccount>, 333 | #[account(seeds = [b"auth"], bump)] 334 | /// CHECK: This acc is safe 335 | pub auth: UncheckedAccount<'info>, 336 | #[account(mut)] 337 | pub maker: SystemAccount<'info>, 338 | #[account( 339 | mut, 340 | seeds = [b"escrow", 341 | maker.key().as_ref(), 342 | escrow.seed.to_le_bytes().as_ref()], 343 | has_one = maker, 344 | has_one = maker_mint, 345 | has_one = taker_mint, 346 | bump, 347 | close = maker, 348 | )] 349 | pub escrow: Account<'info, EscrowState>, 350 | #[account()] 351 | pub taker_mint: Account<'info, Mint>, 352 | #[account()] 353 | pub maker_mint: Account<'info, Mint>, 354 | #[account( 355 | init_if_needed, 356 | payer = taker, 357 | associated_token::mint = taker_mint, 358 | associated_token::authority = maker, 359 | )] 360 | pub maker_receive_ata: Account<'info, TokenAccount>, 361 | pub associated_token_program: Program<'info, AssociatedToken>, 362 | pub token_program: Program<'info, Token>, 363 | pub system_program: Program<'info, System>, 364 | } 365 | #[account] 366 | pub struct EscrowState { 367 | pub maker: Pubkey, 368 | pub maker_mint: Pubkey, 369 | pub taker_mint: Pubkey, 370 | pub amount: u64, 371 | pub seed: u64, 372 | pub auth_bump: u8, 373 | pub escrow_bump: u8, 374 | pub vault_bump: u8, 375 | } 376 | ``` 377 | -------------------------------------------------------------------------------- /docs/src/mapping-into-anchor/account-constraints.md: -------------------------------------------------------------------------------- 1 | # Account Constraints 2 | 3 | We have seen an example of how to define account constraints in previous sections while we're creating PDAs, e.g. `#[account(seeds = [b"auth"], bump)]`. In this section, we will discuss the constraints in more detail. 4 | 5 | Anchor provides a way to define constraints on accounts that are passed to the program by using the `#[account(..)]` attribute. These constraints are used to ensure that the account passed to the program is the correct account. This is done by checking the account's address and the account's data. 6 | 7 | Here are some commonly used constraints if you want to define them in TypeScript: 8 | 9 | ```typescript 10 | export default class EscrowProgram { 11 | static PROGRAM_ID = new Pubkey("11111111111111111111111111111111"); 12 | 13 | make( 14 | escrow: EscrowState, 15 | makerMint: Mint, 16 | auth: UncheckedAccount, 17 | vault: TokenAccount 18 | ) { 19 | // `init` constraint: create a new account 20 | vault.derive(["vault", escrow.key], makerMint, auth.key).init(); 21 | } 22 | 23 | refund(maker: Signer, escrow: EscrowState) { 24 | escrow 25 | .derive(["escrow", maker.key, escrow.seed.toBytes()]) 26 | .has([maker]) // `has_one` constraint: check if the data stored inside the `escrow.maker` is the same as the `maker` account 27 | .close(maker); // `close` constraint: close the account after the instruction is executed, transfer the remaining SOL to the `maker` account 28 | } 29 | 30 | take( 31 | taker: Signer, 32 | maker: SystemAccount, 33 | takerAta: AssociatedTokenAccount, 34 | makerMint: Mint, 35 | takerMint: Mint, 36 | escrow: EscrowState 37 | ) { 38 | takerAta 39 | .derive(makerMint, taker.key) // SPL constraints: check if the `taker` account has the same mint as the `makerMint` account and the authority is the `taker` account 40 | .initIfNeeded(); // `init_if_needed` constraint: initialize the account if it doesn't exist 41 | escrow 42 | .derive(["escrow", maker.key, escrow.seed.toBytes()]) 43 | .has([maker, makerMint, takerMint]) // `has_one` constraint: can specify multiple accounts to check 44 | .close(maker); 45 | } 46 | } 47 | 48 | export interface EscrowState extends Account { 49 | maker: Pubkey; 50 | makerMint: Pubkey; 51 | takerMint: Pubkey; 52 | amount: u64; 53 | seed: u64; 54 | authBump: u8; 55 | escrowBump: u8; 56 | vaultBump: u8; 57 | } 58 | ``` 59 | 60 | You can simply define the constraints by chaining the constraints methods after the account you want to check and make sure the `.derive()` method is called before the other constraints methods. 61 | 62 | ## Normal Constraints 63 | 64 | ### `init` (and `space`) 65 | 66 | `.init()` method is used to create a new account. It is used to create a new account with the given data. Poseidon will automatically calculate the space required for the account based on the how you define the account in the state interface and specify the space in Rust with `space` constraint. 67 | 68 | ### `initIfNeeded` 69 | 70 | Exact same functionality as the init constraint but only runs if the account does not exist yet[^note]. 71 | 72 | If you're using `.initIfNeeded()` method, you should add additional [feature flags](https://docs.rs/crate/anchor-lang/latest/features#init-if-needed) inside your `Cargo.toml` file under your program's directory: 73 | 74 | ```toml 75 | [features] 76 | anchor-lang = { version = "xxx", features = ["init-if-needed"]} 77 | ``` 78 | 79 | ### `seed` (and `bump`) 80 | 81 | This is the constraint we use to define PDAs. 82 | 83 | The `seed` constraint is used to derive a new address from the base address. The `bump` value is a number between 0 to 255 that is used to derive a new address. 84 | 85 | Use the `.derive([seed])` method to derive a new address and use the `.getBump()` method to get the bump value for the account. 86 | 87 | Use the `.deriveWithBump([seed], bump)` method to derive a new address with a bump value if you're creating a PDA with a bump. 88 | 89 | The `seed` and `bump` constraints are required to use together to derive a new address. 90 | 91 | ### `close` 92 | 93 | `.close(rentReceiver)` method is used to close the account after the instruction is executed. It will transfer the remaining SOL to the account(`rentReceiver`) passed to the method. 94 | 95 | ### `has` (or `has_one` in Anchor) 96 | 97 | `.has([])` in TypeScript (or `has_one` constraint in Anchor) is used to check if the data stored inside the account is the same as the data passed to the method. Like in the `refund` method, we're checking if the `maker` account's Pubkey is the same as the one stored inside `escrow.maker`. 98 | 99 | And `has` constraint allows you to check multiple accounts at once. Like in the `take` method, you can check if the `maker`, `makerMint`, and `takerMint` accounts are the same as the ones stored inside the `escrow` account. 100 | 101 | ## SPL Constraints 102 | 103 | ### `mint` and `authority` 104 | 105 | If the account is a `TokenAccount`, `.derive([seed], mint, authority)` method is used to check if the account has the same mint as the `mint` account and the authority is the `authority` account. 106 | 107 | You can use it with the `init` constraint to derive and initialize a new `TokenAccount`, like `vault` account in the `make` method. 108 | 109 | ```typescript 110 | vault.derive(["vault", escrow.key], makerMint, auth.key).init(); 111 | ``` 112 | 113 | For accounts of type `AssociatedTokenAccount`, `.derive(mint, authority)` is used instead. 114 | 115 | ```typescript 116 | vault.derive(makerMint, auth.key).initIfNeeded(); 117 | ``` 118 | 119 | [^note]: Check the [Anchor documentation](https://docs.rs/anchor-lang/latest/anchor_lang/derive.Accounts.html#constraints) for more information on constraints. 120 | -------------------------------------------------------------------------------- /docs/src/mapping-into-anchor/cpi.md: -------------------------------------------------------------------------------- 1 | # Cross Program Invocation (CPI) 2 | 3 | When a program invokes another program, it is called a cross program invocation (CPI). This is a powerful feature of Solana that allows programs to interact with each other. This is useful when you want to separate the logic of your program into multiple programs, or when you want to reuse the logic of another program. 4 | 5 | `@solanaturbine/poseidon` provides a few commonly used program like `TokenProgram` and `SystemProgram` for you to invoke the corresponding instructions. 6 | 7 | ## Invoking Token Program 8 | 9 | To transfer tokens inside your program, you can use the `transfer` method from the `TokenProgram`. Here's an example of how to transfer tokens from token accounts which controlled by different types of owner, one is a user's (associated) token account and the other is a PDA's token account: 10 | 11 | ```typescript 12 | // ... 13 | 14 | export default class EscrowProgram { 15 | static PROGRAM_ID = new Pubkey("11111111111111111111111111111111"); 16 | 17 | take( 18 | taker: Signer, 19 | maker: SystemAccount, 20 | makerReceiveAta: AssociatedTokenAccount, 21 | takerAta: AssociatedTokenAccount, 22 | takerReceiveAta: AssociatedTokenAccount, 23 | makerMint: Mint, 24 | takerMint: Mint, 25 | auth: UncheckedAccount, 26 | vault: TokenAccount, 27 | escrow: EscrowState 28 | ) { 29 | makerReceiveAta.derive(takerMint, maker.key).initIfNeeded(); // Check if the associated token account is initialized 30 | takerAta.derive(takerMint, taker.key); // Don't need to check if the ATA is initialized, because if it's not, the transfer will fail 31 | takerReceiveAta.derive(makerMint, taker.key).initIfNeeded(); // Check if the associated token account is initialized 32 | auth.derive(["auth"]); 33 | vault.derive(["vault", escrow.key], makerMint, auth.key); 34 | escrow 35 | .derive(["escrow", maker.key, escrow.seed.toBytes()]) 36 | .has([maker, makerMint, takerMint]) // Check if the expected accounts are the same as the provided accounts 37 | .close(maker); 38 | 39 | // Cross program invocation 40 | // Transfer tokens from taker's ATA to maker's ATA 41 | TokenProgram.transfer( 42 | takerAta, // from 43 | makerReceiveAta, // to 44 | taker, // authority 45 | escrow.amount // amount to be sent 46 | ); 47 | 48 | // Cross program invocation 49 | // Transfer tokens from `vault` account to taker's ATA 50 | // Seeds are used for signing the transaction since the `vault` account is owned by the `auth` PDA under the escrow program 51 | let seeds: Seeds = ["auth", escrow.authBump.toBytes()]; 52 | TokenProgram.transfer( 53 | vault, // from 54 | takerReceiveAta, // to 55 | auth, // authority 56 | vault.amount, // amount to be sent 57 | seeds // seeds will be at the last arguments if needed 58 | ); 59 | } 60 | } 61 | export interface EscrowState extends Account { 62 | maker: Pubkey; 63 | makerMint: Pubkey; 64 | takerMint: Pubkey; 65 | amount: u64; 66 | seed: u64; 67 | authBump: u8; 68 | escrowBump: u8; 69 | vaultBump: u8; 70 | } 71 | ``` 72 | 73 | In the example above, we transfer tokens from the taker's ATA to the maker's ATA and from the vault to the taker's ATA. We use the `TokenProgram` to transfer the tokens. 74 | 75 | Here's the corresponding Rust code for the `transfer` CPI: 76 | 77 | ```rust,ignore 78 | declare_id!("11111111111111111111111111111111"); 79 | #[program] 80 | pub mod escrow_program { 81 | use super::*; 82 | pub fn make( 83 | ctx: Context, 84 | deposit_amount: u64, 85 | offer_amount: u64, 86 | seed: u64, 87 | ) -> Result<()> { 88 | let cpi_accounts = TransferSPL { 89 | from: ctx.accounts.maker_ata.to_account_info(), 90 | to: ctx.accounts.vault.to_account_info(), 91 | authority: ctx.accounts.maker.to_account_info(), 92 | }; 93 | let cpi_ctx = CpiContext::new( 94 | ctx.accounts.token_program.to_account_info(), 95 | cpi_accounts, 96 | ); 97 | transfer_spl(cpi_ctx, deposit_amount)?; 98 | Ok(()) 99 | } 100 | pub fn refund(ctx: Context) -> Result<()> { 101 | let cpi_accounts = TransferSPL { 102 | from: ctx.accounts.vault.to_account_info(), 103 | to: ctx.accounts.maker_ata.to_account_info(), 104 | authority: ctx.accounts.auth.to_account_info(), 105 | }; 106 | let signer_seeds = &[&b"auth"[..], &[ctx.accounts.escrow.auth_bump]]; 107 | let binding = [&signer_seeds[..]]; 108 | let cpi_ctx = CpiContext::new_with_signer( 109 | ctx.accounts.token_program.to_account_info(), 110 | cpi_accounts, 111 | &binding, 112 | ); 113 | transfer_spl(cpi_ctx, ctx.accounts.vault.amount)?; 114 | Ok(()) 115 | } 116 | } 117 | ``` 118 | 119 | ## Invoking System Program 120 | 121 | It's quite similar to how you invoke the `TokenProgram`. Here's an example of how to invoke `transfer` instruction in `SystemProgram`: 122 | 123 | ```typescript 124 | // Invoke by normal account 125 | SystemProgram.transfer( 126 | owner, // from 127 | vault, // to 128 | amount // amount to be sent 129 | ); 130 | 131 | // Invoke by PDA 132 | SystemProgram.transfer( 133 | vault, // from 134 | owner, // to 135 | amount, // amount to be sent 136 | ["vault", state.key, state.authBump] // seeds will be at the last arguments if needed 137 | ); 138 | ``` 139 | 140 | Can check the full codebase in the [vault](../../../examples/vault/typescript/vault.ts) example. 141 | -------------------------------------------------------------------------------- /docs/src/mapping-into-anchor/instruction.md: -------------------------------------------------------------------------------- 1 | # Instruction 2 | 3 | To define instructions in TypeScript, you would typically define methods inside the program class. 4 | 5 | ```typescript 6 | import { Pubkey } from "@solanaturbine/poseidon"; 7 | 8 | export default class EscrowProgram { 9 | static PROGRAM_ID = new Pubkey("11111111111111111111111111111111"); 10 | 11 | make() {} 12 | refund() {} 13 | take() {} 14 | } 15 | ``` 16 | 17 | And the context for each instruction is implicit in the method parameters. 18 | 19 | ```typescript 20 | import { 21 | Account, 22 | AssociatedTokenAccount, 23 | Mint, 24 | Pubkey, 25 | Seeds, 26 | Signer, 27 | SystemAccount, 28 | TokenAccount, 29 | TokenProgram, 30 | UncheckedAccount, 31 | u64, 32 | u8, 33 | } from "@solanaturbine/poseidon"; 34 | 35 | export default class EscrowProgram { 36 | static PROGRAM_ID = new Pubkey("11111111111111111111111111111111"); 37 | 38 | make( 39 | maker: Signer, 40 | makerMint: Mint, 41 | takerMint: Mint, 42 | makerAta: AssociatedTokenAccount, 43 | auth: UncheckedAccount, 44 | vault: TokenAccount, 45 | escrow: EscrowState, // custom state account, will explain in the next section 46 | depositAmount: u64, 47 | offerAmount: u64, 48 | seed: u64 49 | ) {} 50 | refund( 51 | maker: Signer, 52 | makerMint: Mint, 53 | makerAta: AssociatedTokenAccount, 54 | auth: UncheckedAccount, 55 | vault: TokenAccount, 56 | escrow: EscrowState // custom state account, will explain in the next section 57 | ) {} 58 | take( 59 | taker: Signer, 60 | maker: SystemAccount, 61 | takerMint: Mint, 62 | makerMint: Mint, 63 | takerAta: AssociatedTokenAccount, 64 | takerReceiveAta: AssociatedTokenAccount, 65 | makerReceiveAta: AssociatedTokenAccount, 66 | auth: UncheckedAccount, 67 | vault: TokenAccount, 68 | escrow: EscrowState // custom state account, will explain in the next section 69 | ) {} 70 | } 71 | ``` 72 | 73 | `@solanaturbine/poseidon` package provides the necessary types for defining instructions in TypeScript, such as Rust types (`u8`, `u64`, `i8`, `i128`, `boolean`, `string`), SPL types (`Pubkey`, `AssociatedTokenAccount`, `Mint`, `TokenAccount`, `TokenProgram`), Anchor account types (`Signer`, `UncheckedAccount`, `SystemAccount`), etc. 74 | 75 | It will transpile the TypeScript code into the following Rust code. 76 | 77 | ```rust,ignore 78 | use anchor_lang::prelude::*; 79 | use anchor_spl::{ 80 | token::{TokenAccount, Mint, Token}, 81 | associated_token::AssociatedToken, 82 | }; 83 | declare_id!("11111111111111111111111111111111"); 84 | #[program] 85 | pub mod escrow_program { 86 | use super::*; 87 | pub fn make( 88 | ctx: Context, 89 | deposit_amount: u64, 90 | offer_amount: u64, 91 | seed: u64, 92 | ) -> Result<()> { 93 | Ok(()) 94 | } 95 | pub fn refund(ctx: Context) -> Result<()> { 96 | Ok(()) 97 | } 98 | pub fn take(ctx: Context) -> Result<()> { 99 | Ok(()) 100 | } 101 | } 102 | #[derive(Accounts)] 103 | pub struct MakeContext<'info> { 104 | pub escrow: Account<'info, EscrowState>, 105 | pub taker_mint: Account<'info, Mint>, 106 | #[account(mut)] 107 | pub maker: Signer<'info>, 108 | /// CHECK: This acc is safe 109 | pub auth: UncheckedAccount<'info>, 110 | pub maker_ata: Account<'info, TokenAccount>, 111 | pub vault: Account<'info, TokenAccount>, 112 | pub maker_mint: Account<'info, Mint>, 113 | pub associated_token_program: Program<'info, AssociatedToken>, 114 | pub token_program: Program<'info, Token>, 115 | pub system_program: Program<'info, System>, 116 | } 117 | #[derive(Accounts)] 118 | pub struct RefundContext<'info> { 119 | pub escrow: Account<'info, EscrowState>, 120 | pub maker_ata: Account<'info, TokenAccount>, 121 | #[account(mut)] 122 | pub maker: Signer<'info>, 123 | pub maker_mint: Account<'info, Mint>, 124 | /// CHECK: This acc is safe 125 | pub auth: UncheckedAccount<'info>, 126 | pub vault: Account<'info, TokenAccount>, 127 | pub associated_token_program: Program<'info, AssociatedToken>, 128 | pub token_program: Program<'info, Token>, 129 | pub system_program: Program<'info, System>, 130 | } 131 | #[derive(Accounts)] 132 | pub struct TakeContext<'info> { 133 | #[account(mut)] 134 | pub maker: SystemAccount<'info>, 135 | pub taker_ata: Account<'info, TokenAccount>, 136 | pub vault: Account<'info, TokenAccount>, 137 | pub escrow: Account<'info, EscrowState>, 138 | #[account(mut)] 139 | pub taker: Signer<'info>, 140 | pub maker_mint: Account<'info, Mint>, 141 | pub taker_mint: Account<'info, Mint>, 142 | pub taker_receive_ata: Account<'info, TokenAccount>, 143 | pub maker_receive_ata: Account<'info, TokenAccount>, 144 | /// CHECK: This acc is safe 145 | pub auth: UncheckedAccount<'info>, 146 | pub associated_token_program: Program<'info, AssociatedToken>, 147 | pub token_program: Program<'info, Token>, 148 | pub system_program: Program<'info, System>, 149 | } 150 | ``` 151 | 152 | You might notice that the accounts defined in TypeScript are automatically transpiled into the Rust account struct, which is how the instruction context is typically organized. 153 | 154 | If you have additional parameters that are not accounts, you can pass them as arguments **after** the accounts. Like `make` instruction, it has `depositAmount`, `offerAmount`, and `seed` as additional parameters. 155 | -------------------------------------------------------------------------------- /docs/src/mapping-into-anchor/pda.md: -------------------------------------------------------------------------------- 1 | # Program Derived Address (PDA) 2 | 3 | Program Derived Addresses (PDAs) are a way to derive a new address from a `seed` and a `program id`. This is useful for creating new accounts that are tied to a specific program. 4 | 5 | For example, in the escrow program, the `escrow` account is created as a PDA. This ensures that the `escrow` account is tied to the escrow program and cannot be controlled by any other program or entity. 6 | 7 | To define an account as a PDA with `@solanaturbine/poseidon`, you can use the `derive` method for every account by specifying your `seed` within an array (`[]`) as the first parameter. 8 | 9 | `seed` can be a string, a number, a Pubkey, or even the combination of them. 10 | 11 | ```typescript 12 | // ... 13 | export default class EscrowProgram { 14 | static PROGRAM_ID = new Pubkey("11111111111111111111111111111111"); 15 | 16 | make() { 17 | // Wrap the seed with an array 18 | auth.derive(["auth"]); // seed: string("auth") 19 | vault.derive(["vault", escrow.key]); // seed: string("vault") + Pubkey(escrow.key) 20 | escrow.derive(["escrow", maker.key, seed.toBytes()]); // seed: string("escrow") + Pubkey(maker.key) + number(seed.toBytes()) 21 | 22 | escrow.authBump = auth.getBump(); 23 | escrow.vaultBump = vault.getBump(); 24 | escrow.escrowBump = escrow.getBump(); 25 | } 26 | } 27 | ``` 28 | 29 | The magic behind PDA is that it uses the `program id` as the base address and the `seed`(as we created above) with a `bump`(a number between 0 to 255) as the offset to derive a new address, which is unique and **off** the Ed25519 curve, without a corresponding private key. This technique guarantees that the derived address is only controllable by the program that created it. 30 | 31 | Normally, we'll store the `bump` value in the state account to ensure that the program can always derive the same address and save the cost of bump calculation during the runtime. You can use the `getBump` method to get the bump value for the account. 32 | 33 | The corresponding Rust code will be generated as follows. 34 | 35 | ```rust,ignore 36 | // ... 37 | 38 | declare_id!("11111111111111111111111111111111"); 39 | 40 | #[program] 41 | pub mod escrow_program { 42 | use super::*; 43 | pub fn make( 44 | ctx: Context, 45 | ) -> Result<()> { 46 | ctx.accounts.escrow.auth_bump = ctx.bumps.auth; 47 | ctx.accounts.escrow.vault_bump = ctx.bumps.vault; 48 | ctx.accounts.escrow.escrow_bump = ctx.bumps.escrow; 49 | Ok(()) 50 | } 51 | } 52 | 53 | #[derive(Accounts)] 54 | #[instruction(seed:u64)] 55 | pub struct MakeContext<'info> { 56 | #[account(seeds = [b"auth"], bump)] 57 | /// CHECK: This acc is safe 58 | pub auth: UncheckedAccount<'info>, 59 | #[account( 60 | seeds = [b"vault", escrow.key().as_ref()], 61 | bump, 62 | )] 63 | pub vault: Account<'info, TokenAccount>, 64 | #[account( 65 | seeds = [b"escrow", maker.key().as_ref(), seed.to_le_bytes().as_ref()], 66 | bump, 67 | )] 68 | pub escrow: Account<'info, EscrowState>, 69 | } 70 | ``` 71 | 72 | If you're creating a PDA with a given `bump`, you can use the `deriveWithBump` method with the `bump` following the `seed` instead. See the example below or the [vault](../../../examples/vault/typescript/vault.ts) example for more details: 73 | 74 | ```typescript 75 | auth.deriveWithBump(["auth", state.key], state.authBump); 76 | ``` 77 | 78 | We highly recommend you to go through the [official documentation](https://solana.com/docs/core/pda) to understand the concept of PDAs in Solana. 79 | -------------------------------------------------------------------------------- /docs/src/mapping-into-anchor/program.md: -------------------------------------------------------------------------------- 1 | # Program 2 | 3 | In TypeScript, the program is defined as a class with a `static PROGRAM_ID` to specify the program ID. 4 | 5 | ```typescript 6 | import { Pubkey } from "@solanaturbine/poseidon"; 7 | export default class EscrowProgram { 8 | static PROGRAM_ID = new Pubkey("11111111111111111111111111111111"); 9 | } 10 | ``` 11 | 12 | And `poseidon` will transpile it into the following Rust code. 13 | 14 | ```rust,ignore 15 | use anchor_lang::prelude::*; 16 | declare_id!("11111111111111111111111111111111"); 17 | #[program] 18 | pub mod escrow_program { 19 | use super::*; 20 | } 21 | ``` 22 | 23 | Notice that Anchor will generate the program ID for you. 24 | 25 | Get your program IDs with this command inside your Anchor project. 26 | 27 | ```bash 28 | $ anchor keys list 29 | # Output 30 | # : 31 | ``` 32 | -------------------------------------------------------------------------------- /docs/src/mapping-into-anchor/state.md: -------------------------------------------------------------------------------- 1 | # State 2 | 3 | State is the data stored on Solana accounts. 4 | 5 | Notice that the term **_state_** is used to describe the data stored on Solana accounts, while the term **_account_** is used to describe the Solana account itself. 6 | 7 | ## Define Custom State Accounts 8 | 9 | In TypeScript, custom state accounts are defined as an `Interface` that extends `Account`. 10 | 11 | ```typescript 12 | import { Account, Pubkey, u64, u8 } from "@solanaturbine/poseidon"; 13 | 14 | export interface EscrowState extends Account { 15 | maker: Pubkey; 16 | makerMint: Pubkey; 17 | takerMint: Pubkey; 18 | amount: u64; 19 | seed: u64; 20 | authBump: u8; 21 | escrowBump: u8; 22 | vaultBump: u8; 23 | } 24 | ``` 25 | 26 | You can use types from the `@solanaturbine/poseidon` package to define the fields of the custom state account. 27 | 28 | After transpiling, the custom state account will be defined as a `struct` in Rust. 29 | 30 | ```rust,ignore 31 | #[account] 32 | pub struct EscrowState { 33 | pub maker: Pubkey, 34 | pub maker_mint: Pubkey, 35 | pub taker_mint: Pubkey, 36 | pub amount: u64, 37 | pub seed: u64, 38 | pub auth_bump: u8, 39 | pub escrow_bump: u8, 40 | pub vault_bump: u8, 41 | } 42 | ``` 43 | 44 | ## State Manipulation 45 | 46 | To set the state of an account, you can simply assign the values to the fields of the account. 47 | 48 | ```typescript 49 | // ... 50 | 51 | export default class EscrowProgram { 52 | static PROGRAM_ID = new Pubkey("11111111111111111111111111111111"); 53 | make( 54 | maker: Signer, 55 | escrow: EscrowState, 56 | makerAta: AssociatedTokenAccount, 57 | makerMint: Mint, 58 | takerMint: Mint, 59 | auth: UncheckedAccount, 60 | vault: TokenAccount, 61 | depositAmount: u64, 62 | offerAmount: u64, 63 | seed: u64 64 | ) { 65 | escrow.maker = maker.key; 66 | escrow.makerMint = makerMint.key; 67 | escrow.takerMint = takerMint.key; 68 | 69 | escrow.amount = offerAmount; 70 | escrow.seed = seed; 71 | } 72 | } 73 | ``` 74 | 75 | The corresponding Rust code will be generated as follows. 76 | 77 | ```rust,ignore 78 | // ... 79 | 80 | declare_id!("11111111111111111111111111111111"); 81 | #[program] 82 | pub mod escrow_program { 83 | use super::*; 84 | pub fn make( 85 | ctx: Context, 86 | deposit_amount: u64, 87 | offer_amount: u64, 88 | seed: u64, 89 | ) -> Result<()> { 90 | ctx.accounts.escrow.maker = ctx.accounts.maker.key(); 91 | ctx.accounts.escrow.maker_mint = ctx.accounts.maker_mint.key(); 92 | ctx.accounts.escrow.taker_mint = ctx.accounts.taker_mint.key(); 93 | 94 | ctx.accounts.escrow.amount = offer_amount; 95 | ctx.accounts.escrow.seed = seed; 96 | } 97 | } 98 | ``` 99 | 100 | Also if you want to do some arithmetic operations, `@solanaturbine/poseidon` package provides the necessary types for that. 101 | 102 | Check out [vote](../../../examples/vote/typescript/vote.ts) example to see how to use them. Here's a snippet from the example: 103 | 104 | ```typescript 105 | // initialize the state 106 | state.vote = new i64(0); 107 | // increment the state 108 | state.vote = state.vote.add(1); 109 | // decrement the state 110 | state.vote = state.vote.sub(1); 111 | ``` 112 | 113 | ## Poseidon Type Reference 114 | 115 | | Type | Anchor | Poseidon | 116 | | ------- | --- | --- | 117 | | Boolean | `bool` | `Boolean` | 118 | | Integer | `u8/u16/u32/i8/i16/i32` | `u8/u16/u32/i8/i16/i32` | 119 | | String | `String` | `String` | 120 | | Vector | `Vec` | `Vec` | 121 | 122 | where `N` is the max length of the type. 123 | -------------------------------------------------------------------------------- /docs/src/reference/other-resources.md: -------------------------------------------------------------------------------- 1 | # Other Resources 2 | 3 | - Solana Docs: [https://docs.solana.com/](https://docs.solana.com/) 4 | - Anchor Framework: [https://www.anchor-lang.com/](https://www.anchor-lang.com/) 5 | -------------------------------------------------------------------------------- /docs/src/tutorial.md: -------------------------------------------------------------------------------- 1 | # Tutorial 2 | 3 | 4 | 5 | - [Tutorial](#tutorial) 6 | - [Overview](#overview) 7 | - [Environment Setup](#environment-setup) 8 | - [Prerequisites](#prerequisites) 9 | - [Install Poseidon](#install-poseidon) 10 | - [Your First Solana Program with TypeScript](#your-first-solana-program-with-typescript) 11 | - [Test Your Program!](#test-your-program) 12 | - [Thoughts \& Takeaway](#thoughts--takeaway) 13 | - [Reference](#reference) 14 | 15 | 16 | 17 | ## Overview 18 | 19 | This tutorial is for people without experience in Rust who want to write a Solana program in TypeScript quickly. Poseidon will help you transpile your TypeScript code into Anchor (a Solana framework), allowing you to understand how Solana works through practical examples. 20 | 21 | Please note that if your goal is to become a protocol engineer on Solana, you'll eventually need to learn Anchor and Rust to understand how Solana works at a lower level. 22 | 23 | Without further ado, let’s get your hands dirty! 24 | 25 | ## Environment Setup 26 | 27 | ### Prerequisites 28 | 29 | > If you’ve already installed Solana and Anchor, feel free to skip the `prerequisites` part 30 | 31 | During this tutorial, we will be using the following tools: 32 | 33 | ```bash 34 | $ rustup --version 35 | rustup 1.27.1 (54dd3d00f 2024-04-24) 36 | $ solana --version 37 | solana-cli 1.18.17 (src:b685182a; feat:4215500110, client:SolanaLabs) 38 | $ yarn --version 39 | 1.22.19 40 | $ anchor --version 41 | anchor-cli 0.30.1 42 | ``` 43 | 44 | If you haven't installed all of them yet, go to [Solana Anchor Installation Guide](https://gist.github.com/emersonliuuu/81f1ce90bbaeef8bdb22b6e65f56b3b7) 45 | 46 | ### Install Poseidon 47 | 48 | ```bash 49 | git clone git@github.com:Turbin3/poseidon.git 50 | cd poseidon 51 | # Build poseidon binary file 52 | cargo build --release 53 | ``` 54 | 55 | You can copy `poseidon` from the `target/release` folder to your PATH or update your PATH in your profile file (`~/.bash_profile`, `~/.zshrc`, `~/.profile`, or `~/.bashrc`) for future use. 56 | 57 | To finish this tutorial, you can simply create an alias: 58 | 59 | ```bash 60 | $ pwd 61 | /path/to/poseidon/project 62 | $ alias poseidon='/path/to/poseidon/project/target/release/poseidon' 63 | # Check poseidon command works as expected 64 | $ poseidon --help 65 | ``` 66 | 67 | Congratulations! You’ve completed the most challenging part! Setting up the environment can be a hassle, but once it's done, the rest will be much simpler and easier. 68 | 69 | ## Your First Solana Program with TypeScript 70 | 71 | > We’ll build a simple vote program with three instructions: `initialize`, `upvote`, and `downvote`. 72 | 73 | Remember what Poseidon does for you? Here’s a quick recap: 74 | 75 | > Poseidon helps by transpiling your TypeScript code into Anchor. 76 | 77 | Let’s use `poseidon init` to set up a scaffold, and then we can start writing our program in TypeScript. 78 | 79 | ```bash 80 | # Feel free to switch to whereever you preferred. 81 | $ mkdir tutorial 82 | $ cd tutorial 83 | $ poseidon init vote-program 84 | ``` 85 | 86 | Open `vote-program/ts-programs/voteProgram.ts` in VS Code (or any IDE you prefer) and add the initial pieces of code (without the logic). 87 | 88 | ```typescript 89 | import { Account, Pubkey, type Result, i64, u8, Signer } from "@solanaturbine/poseidon"; 90 | 91 | export default class VoteProgram { 92 | static PROGRAM_ID = new Pubkey("11111111111111111111111111111111"); 93 | 94 | initialize(): Result {} 95 | upvote(): Result {} 96 | downvote(): Result {} 97 | } 98 | ``` 99 | 100 | As we mentioned at the beginning, this program will contain only three simple instructions (`initialize`, `upvote`, `downvote`). Here’s how it looks when using Poseidon. 101 | In Solana, programs are stateless, meaning the functions above are “pure functions”—you get the same output from the same input. But something is missing in the code, what it is? 102 | 103 | **State!** 104 | 105 | Ultimately, we need a place to store our voting results, just like storing data in a database in Web2. In Solana, we called it “Account.” Let’s add the account at the end of our program. 106 | 107 | ```typescript 108 | // ... 109 | 110 | export interface VoteState extends Account { 111 | vote: i64; // This field store the voting result 112 | bump: u8; // bump is for PDA (program derieved account, a special type of account which controlled by program on Solana) 113 | } 114 | ``` 115 | 116 | `i64` stands for signed integer with 64 bit and `u8` stands for unsigned integer with 8 bit in Rust. 117 | 118 | We’ll use the `vote` field to store the voting result, and we can ignore the `bump` field for now. You can find more information about it in the reference section after completing this tutorial. 119 | 120 | We’ve defined the `VoteState` account as our data structure, and now we're ready to implement the logic inside each instruction. Let’s start with the `initialize` instruction: 121 | 122 | ```typescript 123 | // Pass all the accounts we need as the parameters 124 | initialize(state: VoteState, user: Signer): Result { 125 | 126 | // Use `.derive([seed])` to define the PDA and chain the `.init(payer)` at the end for creating the account and pass the payer argument 127 | state.derive(["vote"]) 128 | .init(user); 129 | 130 | // Set the initial value to the `vote` field of the account 131 | state.vote = new i64(0); 132 | } 133 | ``` 134 | 135 | If a user wants to store anything on Solana, such as `VoteState` in this case, they’ll need to pay [rent](https://docs.solanalabs.com/implemented-proposals/rent) for the space they’re using, as validators need to store the data on their hardware. To cover this rent, we add `user` with the `Signer` type as a parameter, allowing the user to transfer their SOL to the `VoteState` account to pay for the rent. 136 | 137 | We’ve mentioned PDA several times, but what is it? [PDA](https://solana.com/docs/core/pda) (Program Derived Address) is an important concept on Solana. It allows an account to be controlled by a specified program. To construct a PDA, you need a seed—a byte array that can be derived from a string, public key, integer, or even combinations of these! In this case, we use the string `“vote”` as the seed. You can find more examples of different seed combinations in the provided [examples](../../examples). 138 | 139 | After the state account is initialized, we can assign an initial value, `new i64(0)`, to it. 140 | 141 | We’re almost done. Let’s update the `upvote` and `downvote` instructions: 142 | 143 | ```typescript 144 | upvote(state: VoteState): Result { 145 | state.derive(["vote"]); 146 | state.vote = state.vote.add(1); 147 | } 148 | 149 | downvote(state: VoteState): Result { 150 | state.derive(["vote"]); 151 | state.vote = state.vote.sub(1); 152 | } 153 | ``` 154 | 155 | Every time you use a PDA, you’ll need to specify its seed, but only when creating the account do you need to chain the `init()` at the end. 156 | When you're initializing account, Poseidon automatically adds the SystemProgram account to the account struct. Similarly in examples given in the repo, we can see that it also automatically adds Token Program and Associated Token Program accounts. 157 | 158 | The logic for `upvote` and `downvote` is quite simple—just add or subtract by 1. The only thing to be aware of is that you need to assign the result back to where it’s stored, e.g. `state.vote`. Otherwise, the value won’t be updated after the instruction is executed. 159 | 160 | The final step to complete this program is to run the command below to get your correct program ID and replace, if the program ID is not synced yet. 161 | 162 | ```bash 163 | $ poseidon sync 164 | ``` 165 | 166 | ## Test Your Program! 167 | 168 | It’s time to verify that the program works as expected! Let’s use the Poseidon command with Anchor to make the magic happen 😉 If you type `poseidon --help` in your terminal, you’ll see: 169 | 170 | ```bash 171 | poseidon --help 172 | Usage: poseidon 173 | 174 | Commands: 175 | build Build Typescript programs in workspace 176 | test Run anchor tests in the workspace 177 | sync Sync anchor keys in poseidon programs 178 | compile Transpile a Typescript program to a Rust program 179 | init Initializes a new workspace 180 | help Print this message or the help of the given subcommand(s) 181 | 182 | Options: 183 | -h, --help Print help 184 | -V, --version Print version 185 | ``` 186 | 187 | Obviously, we’ll use the TypeScript code to generate and replace the Rust code that Anchor generated for us. If you’ve followed this tutorial step-by-step, your program structure (under the `tutorial/vote_program` folder) should look like this: 188 | 189 | ```bash 190 | . 191 | ├── Anchor.toml 192 | ├── Cargo.toml 193 | ├── app 194 | ├── migrations 195 | │ └── deploy.ts 196 | ├── package.json 197 | ├── programs 198 | │ └── vote_program 199 | │ ├── Cargo.toml 200 | │ ├── Xargo.toml 201 | │ └── src 202 | │ └── lib.rs <--------- Output Rust file 203 | ├── target 204 | │ └── deploy 205 | │ └── vote_program-keypair.json 206 | ├── tests 207 | │ └── vote_program.ts 208 | ├── ts-programs 209 | │ ├── package.json 210 | │ └── src 211 | │ └── voteProgram.ts <--------- Input Typescript file 212 | ├── tsconfig.json 213 | └── yarn.lock 214 | ``` 215 | 216 | If you’re in the root directory of the program, use the following command: 217 | 218 | ```bash 219 | poseidon build 220 | ``` 221 | 222 | And if you're not in the root directory or just want to compile by specifying the location, use the following command: 223 | 224 | ```bash 225 | poseidon compile -i ts-programs/src/voteProgram.ts -o programs/vote-program/src/lib.rs 226 | ``` 227 | 228 | Once the code is transpiled to lib.rs 229 | 230 | ```bash 231 | anchor build 232 | ``` 233 | 234 | Let’s replace the contents of `tests/vote-program.ts` with the code below: 235 | 236 | ```typescript 237 | import * as anchor from "@coral-xyz/anchor"; 238 | import { Program } from "@coral-xyz/anchor"; 239 | import { VoteProgram } from "../target/types/vote_program"; 240 | import { assert } from "chai"; 241 | 242 | describe("vote program", () => { 243 | // Configure the client to use the local cluster. 244 | const provider = anchor.AnchorProvider.env(); 245 | anchor.setProvider(provider); 246 | const program = anchor.workspace.VoteProgram as Program; 247 | const voteState = anchor.web3.PublicKey.findProgramAddressSync( 248 | [anchor.utils.bytes.utf8.encode("vote")], 249 | program.programId 250 | )[0]; 251 | 252 | it("Create and initialize vote state", async () => { 253 | const txid = await program.methods 254 | .initialize() 255 | .accounts({ 256 | user: provider.wallet.publicKey, 257 | }) 258 | .rpc(); 259 | console.log("Initialize tx:", txid); 260 | 261 | const voteStateAccount = await program.account.voteState.fetch(voteState); 262 | assert.ok(voteStateAccount.vote.eq(new anchor.BN(0))); 263 | }); 264 | 265 | it("Upvote", async () => { 266 | const txid = await program.methods.upvote().accounts({}).rpc(); 267 | 268 | console.log("upvote tx:", txid); 269 | 270 | const voteStateAccount = await program.account.voteState.fetch(voteState); 271 | assert.ok(voteStateAccount.vote.eq(new anchor.BN(1))); 272 | }); 273 | 274 | it("Downvote", async () => { 275 | const txid = await program.methods.downvote().accounts({}).rpc(); 276 | 277 | console.log("downvote tx:", txid); 278 | 279 | const voteStateAccount = await program.account.voteState.fetch(voteState); 280 | assert.ok(voteStateAccount.vote.eq(new anchor.BN(0))); 281 | }); 282 | }); 283 | ``` 284 | 285 | For testing it locally, we can run 286 | 287 | ```bash 288 | poseidon test 289 | ``` 290 | 291 | This command will build the program, start a local validator with the program deployed, and run all the tests in the `tests` folder. This is a quick way to check if your program works correctly. Ideally, you should see all your tests pass like this: 292 | 293 | ```bash 294 | vote program 295 | Initialize tx: 4uNEPU1dTXnNDgs3thgbkqQhN11xscbgcV1362Wv2nXRJSCfsra6B1AP24y6qjCXGLWrqjrrzFrtCf7S1YF6tRkZ 296 | ✔ Create and initialize vote state (426ms) 297 | upvote tx: 2j7FypJmk5yyiugYVxPcgmWQkG7YYCUXdBEpzACJAv2UPXQj6b3tS47S3pN1dTr8JsCt3czYDMo62DuxjUjLNe78 298 | ✔ Upvote (471ms) 299 | downvote tx: pTKwbkU9NTFdLaRFRTZCwuYaAHrYX44dkLAHau7GsBWvaEjsV5U6gYX59Ku6DKrXENsyQd5cirtSwBtBC9zN9Ut 300 | ✔ Downvote (466ms) 301 | 302 | 3 passing (1s) 303 | ``` 304 | 305 | If you want to verify it on the Solana Devnet (a network for developers testing their programs), use this command: 306 | 307 | ```bash 308 | anchor test --provider.cluster devnet 309 | ``` 310 | 311 | After all the tests have passed, you can copy the transaction IDs and verify them on [Solana’s blockchain explorer](https://explorer.solana.com/?cluster=devnet). 312 | 313 | Here’s the example of the transaction ID ([ApCnLHqiAm...amxDb439jg](https://explorer.solana.com/tx/ApCnLHqiAmdxmihJcadA4TDd6NnbMsZia9hdXhbomzoFFZWm4G4VSTg61dbai33M3yXKstSJJfPV5amxDb439jg?cluster=devnet)) might look like in the explorer on Devnet. 314 | 315 | ## Thoughts & Takeaway 316 | 317 | Congratulations! 🎉 You've completed your first Solana program in TypeScript! 318 | 319 | Poseidon helps by transpiling your TypeScript program into Rust using the Anchor framework format. You can check out [examples/vote/rust/vote.rs](../../examples/vote/rust/vote.rs) to see what the code looks like in Rust. This will help you better understand Rust syntax and Solana’s design principles. 320 | 321 | After finishing this tutorial, we highly recommend going through all the resources in the reference section one-by-one. This will give you a more comprehensive understanding of how Solana works and help clarify some common jargon, such as account, PDA, rent, and more. 322 | 323 | We hope you enjoyed this tutorial, and we look forward to seeing you in the wild but exciting Solana space! 324 | 325 | ## Reference 326 | 327 | - [https://solana.com/docs/core/accounts](https://solana.com/docs/core/accounts) 328 | - [https://docs.solanalabs.com/implemented-proposals/rent](https://docs.solanalabs.com/implemented-proposals/rent) 329 | - [https://solana.com/docs/core/pda](https://solana.com/docs/core/pda) 330 | -------------------------------------------------------------------------------- /docs/src/usage.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | ```sh 4 | poseidon compile --input "input.ts" --output "output.rs" 5 | ``` 6 | 7 | Check out [examples](https://github.com/Turbin3/poseidon/tree/master/examples) in the repo to learn how to write Poseidon Typescript which can be transpiled to Anchor programs. 8 | 9 | ### Examples 10 | 11 | 1. Vote ([Rust](https://github.com/Turbin3/poseidon/blob/master/examples/vote/rust/vote.rs), [TypeScript](https://github.com/Turbin3/poseidon/blob/master/examples/vote/typescript/vote.ts)) 12 | 13 | 2. Vault ([Rust](https://github.com/Turbin3/poseidon/blob/master/examples/vault/rust/vault.rs), [TypeScript](https://github.com/Turbin3/poseidon/blob/master/examples/vault/typescript/vault.ts)) 14 | 15 | 3. Escrow ([Rust](https://github.com/Turbin3/poseidon/blob/master/examples/escrow/rust/escrow.rs), [TypeScript](https://github.com/Turbin3/poseidon/blob/master/examples/escrow/typescript/escrow.ts)) 16 | 17 | 4. Favorites ([Rust](https://github.com/Turbin3/poseidon/blob/master/examples/favorites/rust/favorites.rs), [TypeScript](https://github.com/Turbin3/poseidon/blob/master/examples/favorites/typescript/favorites.ts)) 18 | -------------------------------------------------------------------------------- /examples/escrow/rust/escrow.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::prelude::*; 2 | use anchor_spl::{ 3 | associated_token::AssociatedToken, 4 | token::{Transfer as TransferSPL, TokenAccount, Mint, transfer as transfer_spl, Token}, 5 | }; 6 | declare_id!("11111111111111111111111111111111"); 7 | #[program] 8 | pub mod escrow_program { 9 | use super::*; 10 | pub fn make( 11 | ctx: Context, 12 | deposit_amount: u64, 13 | offer_amount: u64, 14 | seed: u64, 15 | ) -> Result<()> { 16 | ctx.accounts.escrow.auth_bump = ctx.bumps.auth; 17 | ctx.accounts.escrow.vault_bump = ctx.bumps.vault; 18 | ctx.accounts.escrow.escrow_bump = ctx.bumps.escrow; 19 | ctx.accounts.escrow.maker = ctx.accounts.maker.key(); 20 | ctx.accounts.escrow.amount = offer_amount; 21 | ctx.accounts.escrow.seed = seed; 22 | ctx.accounts.escrow.maker_mint = ctx.accounts.maker_mint.key(); 23 | ctx.accounts.escrow.taker_mint = ctx.accounts.taker_mint.key(); 24 | let cpi_accounts = TransferSPL { 25 | from: ctx.accounts.maker_ata.to_account_info(), 26 | to: ctx.accounts.vault.to_account_info(), 27 | authority: ctx.accounts.maker.to_account_info(), 28 | }; 29 | let cpi_ctx = CpiContext::new( 30 | ctx.accounts.token_program.to_account_info(), 31 | cpi_accounts, 32 | ); 33 | transfer_spl(cpi_ctx, deposit_amount)?; 34 | Ok(()) 35 | } 36 | pub fn refund(ctx: Context) -> Result<()> { 37 | let cpi_accounts = TransferSPL { 38 | from: ctx.accounts.vault.to_account_info(), 39 | to: ctx.accounts.maker_ata.to_account_info(), 40 | authority: ctx.accounts.auth.to_account_info(), 41 | }; 42 | let signer_seeds = &[&b"auth"[..], &[ctx.accounts.escrow.auth_bump]]; 43 | let binding = [&signer_seeds[..]]; 44 | let cpi_ctx = CpiContext::new_with_signer( 45 | ctx.accounts.token_program.to_account_info(), 46 | cpi_accounts, 47 | &binding, 48 | ); 49 | transfer_spl(cpi_ctx, ctx.accounts.escrow.amount)?; 50 | Ok(()) 51 | } 52 | pub fn take(ctx: Context) -> Result<()> { 53 | let cpi_accounts = TransferSPL { 54 | from: ctx.accounts.taker_ata.to_account_info(), 55 | to: ctx.accounts.maker_ata.to_account_info(), 56 | authority: ctx.accounts.taker.to_account_info(), 57 | }; 58 | let cpi_ctx = CpiContext::new( 59 | ctx.accounts.token_program.to_account_info(), 60 | cpi_accounts, 61 | ); 62 | transfer_spl(cpi_ctx, ctx.accounts.escrow.amount)?; 63 | let cpi_accounts = TransferSPL { 64 | from: ctx.accounts.vault.to_account_info(), 65 | to: ctx.accounts.taker_receive_ata.to_account_info(), 66 | authority: ctx.accounts.auth.to_account_info(), 67 | }; 68 | let signer_seeds = &[&b"auth"[..], &[ctx.accounts.escrow.auth_bump]]; 69 | let binding = [&signer_seeds[..]]; 70 | let cpi_ctx = CpiContext::new_with_signer( 71 | ctx.accounts.token_program.to_account_info(), 72 | cpi_accounts, 73 | &binding, 74 | ); 75 | transfer_spl(cpi_ctx, ctx.accounts.escrow.amount)?; 76 | Ok(()) 77 | } 78 | } 79 | #[derive(Accounts)] 80 | #[instruction(seed:u64)] 81 | pub struct MakeContext<'info> { 82 | #[account( 83 | mut, 84 | associated_token::mint = maker_mint, 85 | associated_token::authority = maker, 86 | )] 87 | pub maker_ata: Account<'info, TokenAccount>, 88 | #[account()] 89 | pub maker_mint: Account<'info, Mint>, 90 | #[account()] 91 | pub taker_mint: Account<'info, Mint>, 92 | #[account(seeds = [b"auth"], bump)] 93 | /// CHECK: This acc is safe 94 | pub auth: UncheckedAccount<'info>, 95 | #[account(mut)] 96 | pub maker: Signer<'info>, 97 | #[account( 98 | init, 99 | payer = maker, 100 | seeds = [b"vault", 101 | escrow.key().as_ref()], 102 | token::mint = maker_mint, 103 | token::authority = auth, 104 | bump, 105 | )] 106 | pub vault: Account<'info, TokenAccount>, 107 | #[account( 108 | init, 109 | payer = maker, 110 | space = 123, 111 | seeds = [b"escrow", 112 | maker.key().as_ref(), 113 | seed.to_le_bytes().as_ref()], 114 | bump, 115 | )] 116 | pub escrow: Account<'info, EscrowState>, 117 | pub associated_token_program: Program<'info, AssociatedToken>, 118 | pub token_program: Program<'info, Token>, 119 | pub system_program: Program<'info, System>, 120 | } 121 | #[derive(Accounts)] 122 | pub struct RefundContext<'info> { 123 | #[account( 124 | mut, 125 | seeds = [b"vault", 126 | escrow.key().as_ref()], 127 | token::mint = maker_mint, 128 | token::authority = auth, 129 | bump, 130 | )] 131 | pub vault: Account<'info, TokenAccount>, 132 | #[account(seeds = [b"auth"], bump)] 133 | /// CHECK: This acc is safe 134 | pub auth: UncheckedAccount<'info>, 135 | #[account( 136 | mut, 137 | seeds = [b"escrow", 138 | maker.key().as_ref(), 139 | escrow.seed.to_le_bytes().as_ref()], 140 | has_one = maker, 141 | bump, 142 | close = maker, 143 | )] 144 | pub escrow: Account<'info, EscrowState>, 145 | #[account(mut)] 146 | pub maker: Signer<'info>, 147 | #[account( 148 | mut, 149 | associated_token::mint = maker_mint, 150 | associated_token::authority = maker, 151 | )] 152 | pub maker_ata: Account<'info, TokenAccount>, 153 | #[account()] 154 | pub maker_mint: Account<'info, Mint>, 155 | pub associated_token_program: Program<'info, AssociatedToken>, 156 | pub token_program: Program<'info, Token>, 157 | pub system_program: Program<'info, System>, 158 | } 159 | #[derive(Accounts)] 160 | pub struct TakeContext<'info> { 161 | #[account()] 162 | pub maker_mint: Account<'info, Mint>, 163 | #[account( 164 | init_if_needed, 165 | payer = taker, 166 | associated_token::mint = maker_mint, 167 | associated_token::authority = taker, 168 | )] 169 | pub taker_receive_ata: Account<'info, TokenAccount>, 170 | #[account(mut)] 171 | pub taker: Signer<'info>, 172 | #[account()] 173 | pub taker_mint: Account<'info, Mint>, 174 | #[account(mut)] 175 | pub maker: SystemAccount<'info>, 176 | #[account( 177 | init_if_needed, 178 | payer = taker, 179 | associated_token::mint = maker_mint, 180 | associated_token::authority = taker, 181 | )] 182 | pub taker_ata: Account<'info, TokenAccount>, 183 | #[account( 184 | mut, 185 | seeds = [b"vault", 186 | escrow.key().as_ref()], 187 | token::mint = maker_mint, 188 | token::authority = auth, 189 | bump, 190 | )] 191 | pub vault: Account<'info, TokenAccount>, 192 | #[account( 193 | mut, 194 | seeds = [b"escrow", 195 | maker.key().as_ref(), 196 | escrow.seed.to_le_bytes().as_ref()], 197 | has_one = maker, 198 | has_one = maker_mint, 199 | has_one = taker_mint, 200 | bump, 201 | close = maker, 202 | )] 203 | pub escrow: Account<'info, EscrowState>, 204 | #[account( 205 | mut, 206 | associated_token::mint = maker_mint, 207 | associated_token::authority = maker, 208 | )] 209 | pub maker_ata: Account<'info, TokenAccount>, 210 | #[account(seeds = [b"auth"], bump)] 211 | /// CHECK: This acc is safe 212 | pub auth: UncheckedAccount<'info>, 213 | pub associated_token_program: Program<'info, AssociatedToken>, 214 | pub token_program: Program<'info, Token>, 215 | pub system_program: Program<'info, System>, 216 | } 217 | #[account] 218 | pub struct EscrowState { 219 | pub maker: Pubkey, 220 | pub maker_mint: Pubkey, 221 | pub taker_mint: Pubkey, 222 | pub amount: u64, 223 | pub seed: u64, 224 | pub auth_bump: u8, 225 | pub escrow_bump: u8, 226 | pub vault_bump: u8, 227 | } 228 | -------------------------------------------------------------------------------- /examples/escrow/typescript/escrow.ts: -------------------------------------------------------------------------------- 1 | import { Account, AssociatedTokenAccount, Mint, Pubkey, Seeds, Signer, SystemAccount, TokenAccount, TokenProgram, UncheckedAccount, u64, u8 } from "@solanaturbine/poseidon"; 2 | 3 | export default class EscrowProgram { 4 | static PROGRAM_ID = new Pubkey("11111111111111111111111111111111"); 5 | 6 | make( 7 | maker: Signer, 8 | escrow: EscrowState, 9 | makerAta: AssociatedTokenAccount, 10 | makerMint: Mint, 11 | takerMint: Mint, 12 | auth: UncheckedAccount, 13 | vault: TokenAccount, 14 | depositAmount: u64, 15 | offerAmount: u64, 16 | seed: u64 17 | ) { 18 | makerAta.derive(makerMint, maker.key) 19 | 20 | auth.derive(["auth"]) 21 | 22 | // Here like we mentioned in counter we are deriving a PDA for TokenAccount 23 | // .derive([...], , ) 24 | vault.derive(["vault", escrow.key], makerMint, auth.key).init(maker) 25 | 26 | // here we can see that we are deriving using seed(u64), so we would do change it to bytes by .toBytes() which makes it consumable for derive 27 | escrow.derive(["escrow", maker.key, seed.toBytes()]) 28 | .init(maker) 29 | 30 | escrow.authBump = auth.getBump() 31 | escrow.vaultBump = vault.getBump() 32 | escrow.escrowBump = escrow.getBump() 33 | 34 | escrow.maker = maker.key; 35 | escrow.amount = offerAmount; 36 | escrow.seed = seed; 37 | escrow.makerMint = makerMint.key; 38 | escrow.takerMint = takerMint.key; 39 | 40 | TokenProgram.transfer( 41 | makerAta, // from 42 | vault, // to 43 | maker, // authority 44 | depositAmount, // amount to transfered 45 | ) 46 | } 47 | 48 | refund( 49 | maker: Signer, 50 | makerAta: AssociatedTokenAccount, 51 | makerMint: Mint, 52 | auth: UncheckedAccount, 53 | vault: TokenAccount, 54 | escrow: EscrowState 55 | ) { 56 | makerAta.derive(makerMint, maker.key); 57 | escrow.derive(["escrow", maker.key, escrow.seed.toBytes()]) 58 | .has([ maker ]) 59 | .close(maker) 60 | 61 | auth.derive(["auth"]) 62 | 63 | vault.derive(["vault", escrow.key], makerMint, auth.key) 64 | 65 | // similar to system program transfer, we are using seeds as the last arguement as we are tranfering from a PDA 66 | TokenProgram.transfer( 67 | vault, 68 | makerAta, 69 | auth, 70 | escrow.amount, 71 | ["auth", escrow.authBump] 72 | ) 73 | } 74 | 75 | take( 76 | taker: Signer, 77 | maker: SystemAccount, 78 | makerAta: AssociatedTokenAccount, 79 | takerAta: AssociatedTokenAccount, 80 | takerReceiveAta: AssociatedTokenAccount, 81 | makerMint: Mint, 82 | takerMint: Mint, 83 | auth: UncheckedAccount, 84 | vault: TokenAccount, 85 | escrow: EscrowState 86 | ) { 87 | // for AssociatedTokenAccount(takerAta) since its associated with a pubkey there is no need to pass the seeds list. we can just pass the mint and authority 88 | // .derive(, ) 89 | takerAta 90 | .derive(makerMint, taker.key) 91 | .initIfNeeded(taker); // if you're not sure that the Ata will exist, just chain initIfNeeded method instead of init 92 | 93 | takerReceiveAta 94 | .derive(makerMint, taker.key) 95 | .initIfNeeded(taker) 96 | 97 | makerAta.derive(makerMint, maker.key) 98 | 99 | escrow.derive(["escrow", maker.key, escrow.seed.toBytes()]) 100 | .has([ maker, makerMint, takerMint ]) // has method makes sure that all the pubkeys in the list which is the Custom_Acc(escrow) holds is same as Acc's pubkey in the function(in this case `take`) arguements 101 | .close(maker) 102 | 103 | auth.derive(["auth"]) 104 | 105 | vault.derive(["vault", escrow.key], makerMint, auth.key) 106 | 107 | TokenProgram.transfer( 108 | takerAta, 109 | makerAta, 110 | taker, 111 | escrow.amount, 112 | ) 113 | 114 | TokenProgram.transfer( 115 | vault, 116 | takerReceiveAta, 117 | auth, 118 | escrow.amount, 119 | ["auth", escrow.authBump] 120 | ) 121 | } 122 | } 123 | 124 | export interface EscrowState extends Account { 125 | maker: Pubkey 126 | makerMint: Pubkey 127 | takerMint: Pubkey 128 | amount: u64 129 | seed: u64 130 | authBump: u8 131 | escrowBump: u8 132 | vaultBump: u8 133 | } -------------------------------------------------------------------------------- /examples/favorites/rust/favorites.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::prelude::*; 2 | declare_id!("11111111111111111111111111111111"); 3 | #[program] 4 | pub mod favorites_program { 5 | use super::*; 6 | pub fn set_favorites( 7 | ctx: Context, 8 | number: u64, 9 | color: String, 10 | hobbies: Vec, 11 | ) -> Result<()> { 12 | ctx.accounts.favorites.number = number; 13 | ctx.accounts.favorites.color = color; 14 | ctx.accounts.favorites.hobbies = hobbies; 15 | Ok(()) 16 | } 17 | } 18 | #[derive(Accounts)] 19 | pub struct SetFavoritesContext<'info> { 20 | #[account( 21 | init_if_needed, 22 | payer = owner, 23 | space = 344, 24 | seeds = [b"favorites", 25 | owner.key().as_ref()], 26 | bump, 27 | )] 28 | pub favorites: Account<'info, Favorites>, 29 | #[account(mut)] 30 | pub owner: Signer<'info>, 31 | pub system_program: Program<'info, System>, 32 | } 33 | #[account] 34 | pub struct Favorites { 35 | pub number: u64, 36 | pub color: String, 37 | pub hobbies: Vec, 38 | } 39 | -------------------------------------------------------------------------------- /examples/favorites/typescript/favorites.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Account, 3 | Pubkey, 4 | Result, 5 | u64, 6 | Signer, 7 | Vec, 8 | Str, 9 | } from "@solanaturbine/poseidon"; 10 | 11 | export default class FavoritesProgram { 12 | static PROGRAM_ID = new Pubkey("11111111111111111111111111111111"); 13 | 14 | setFavorites( 15 | owner: Signer, 16 | number: u64, 17 | color: Str<50>, 18 | hobbies: Vec, 5>, 19 | favorites: Favorites, 20 | ): Result { 21 | favorites.derive(["favorites", owner.key]).initIfNeeded(owner); 22 | 23 | favorites.number = number; 24 | favorites.color = color; 25 | favorites.hobbies = hobbies; 26 | } 27 | } 28 | 29 | export interface Favorites extends Account { 30 | number: u64; 31 | color: Str<50>; 32 | hobbies: Vec, 5>; 33 | } -------------------------------------------------------------------------------- /examples/vault/rust/vault.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::prelude::*; 2 | use anchor_lang::system_program::{Transfer, transfer}; 3 | declare_id!("11111111111111111111111111111111"); 4 | #[program] 5 | pub mod vault_program { 6 | use super::*; 7 | pub fn initialize(ctx: Context) -> Result<()> { 8 | ctx.accounts.state.owner = ctx.accounts.owner.key(); 9 | ctx.accounts.state.state_bump = ctx.bumps.state; 10 | ctx.accounts.state.auth_bump = ctx.bumps.auth; 11 | ctx.accounts.state.vault_bump = ctx.bumps.vault; 12 | Ok(()) 13 | } 14 | pub fn deposit(ctx: Context, amount: u64) -> Result<()> { 15 | let transfer_accounts = Transfer { 16 | from: ctx.accounts.owner.to_account_info(), 17 | to: ctx.accounts.vault.to_account_info(), 18 | }; 19 | let cpi_ctx = CpiContext::new( 20 | ctx.accounts.system_program.to_account_info(), 21 | transfer_accounts, 22 | ); 23 | transfer(cpi_ctx, amount)?; 24 | Ok(()) 25 | } 26 | pub fn withdraw(ctx: Context, amount: u64) -> Result<()> { 27 | let transfer_accounts = Transfer { 28 | from: ctx.accounts.vault.to_account_info(), 29 | to: ctx.accounts.owner.to_account_info(), 30 | }; 31 | let seeds = &[ 32 | b"vault", 33 | ctx.accounts.auth.to_account_info().key.as_ref(), 34 | &[ctx.accounts.state.vault_bump], 35 | ]; 36 | let pda_signer = &[&seeds[..]]; 37 | let cpi_ctx = CpiContext::new_with_signer( 38 | ctx.accounts.system_program.to_account_info(), 39 | transfer_accounts, 40 | pda_signer, 41 | ); 42 | transfer(cpi_ctx, amount)?; 43 | Ok(()) 44 | } 45 | } 46 | #[derive(Accounts)] 47 | pub struct InitializeContext<'info> { 48 | #[account(mut)] 49 | pub owner: Signer<'info>, 50 | #[account( 51 | init, 52 | payer = owner, 53 | space = 43, 54 | seeds = [b"state", 55 | owner.key().as_ref()], 56 | bump, 57 | )] 58 | pub state: Account<'info, Vault>, 59 | #[account(seeds = [b"auth", state.key().as_ref()], bump)] 60 | /// CHECK: This acc is safe 61 | pub auth: UncheckedAccount<'info>, 62 | #[account(mut, seeds = [b"vault", auth.key().as_ref()], bump)] 63 | pub vault: SystemAccount<'info>, 64 | pub system_program: Program<'info, System>, 65 | } 66 | #[derive(Accounts)] 67 | pub struct DepositContext<'info> { 68 | #[account(mut)] 69 | pub owner: Signer<'info>, 70 | #[account(seeds = [b"auth", state.key().as_ref()], bump = state.auth_bump)] 71 | /// CHECK: This acc is safe 72 | pub auth: UncheckedAccount<'info>, 73 | #[account(seeds = [b"state", owner.key().as_ref()], bump = state.state_bump)] 74 | pub state: Account<'info, Vault>, 75 | #[account(mut, seeds = [b"vault", auth.key().as_ref()], bump = state.vault_bump)] 76 | pub vault: SystemAccount<'info>, 77 | pub system_program: Program<'info, System>, 78 | } 79 | #[derive(Accounts)] 80 | pub struct WithdrawContext<'info> { 81 | #[account(mut, seeds = [b"vault", auth.key().as_ref()], bump = state.vault_bump)] 82 | pub vault: SystemAccount<'info>, 83 | #[account(mut)] 84 | pub owner: Signer<'info>, 85 | #[account(seeds = [b"auth", state.key().as_ref()], bump = state.auth_bump)] 86 | /// CHECK: This acc is safe 87 | pub auth: UncheckedAccount<'info>, 88 | #[account(seeds = [b"state", owner.key().as_ref()], bump = state.state_bump)] 89 | pub state: Account<'info, Vault>, 90 | pub system_program: Program<'info, System>, 91 | } 92 | #[account] 93 | pub struct Vault { 94 | pub owner: Pubkey, 95 | pub state_bump: u8, 96 | pub auth_bump: u8, 97 | pub vault_bump: u8, 98 | } 99 | -------------------------------------------------------------------------------- /examples/vault/typescript/vault.ts: -------------------------------------------------------------------------------- 1 | import { Account, Pubkey, Result, Signer, SystemAccount, SystemProgram, UncheckedAccount, u64, u8 } from "@solanaturbine/poseidon"; 2 | 3 | export default class VaultProgram { 4 | static PROGRAM_ID = new Pubkey("11111111111111111111111111111111"); 5 | 6 | initialize( 7 | owner: Signer, 8 | state: Vault, 9 | auth: UncheckedAccount, 10 | vault: SystemAccount 11 | ): Result { 12 | 13 | auth.derive(['auth', state.key]) 14 | state.derive(['state', owner.key]).init(owner) 15 | vault.derive(['vault', auth.key]) 16 | 17 | // assigning a arguement of type Pubkey to the custom_Acc(state) by calling the key property 18 | state.owner = owner.key; 19 | 20 | // to store bumps in the custom_Acc(state), we can simply call getBump on the custom_Acc(state) 21 | state.stateBump = state.getBump() 22 | state.authBump = auth.getBump() 23 | state.vaultBump = vault.getBump() 24 | } 25 | 26 | deposit( 27 | owner: Signer, 28 | state: Vault, 29 | auth: UncheckedAccount, 30 | vault: SystemAccount, 31 | amount: u64 32 | ) { 33 | // if we have stored bump in the custom_Acc(state), we can derive PDAs with stored bumps by passing that as the 2nd arguement 34 | state.deriveWithBump(['state', owner.key], state.stateBump) 35 | auth.deriveWithBump(['auth', state.key], state.authBump) 36 | vault.deriveWithBump(['vault', auth.key], state.vaultBump) 37 | 38 | // we support a number for functions from SystemProgram and TokenProgram 39 | SystemProgram.transfer( 40 | owner, // from 41 | vault, // to 42 | amount // amount to be sent 43 | ) 44 | } 45 | 46 | withdraw( 47 | owner: Signer, 48 | state: Vault, 49 | auth: UncheckedAccount, 50 | vault: SystemAccount, 51 | amount: u64 52 | ) { 53 | state.deriveWithBump(['state', owner.key], state.stateBump) 54 | auth.deriveWithBump(['auth', state.key], state.authBump) 55 | vault.deriveWithBump(['vault', auth.key], state.vaultBump) 56 | 57 | // since here we are transfering from a PDA we have give seeds of the PDA as the last arguement 58 | SystemProgram.transfer( 59 | vault, 60 | owner, 61 | amount, 62 | ['vault', state.key, state.authBump] 63 | ) 64 | } 65 | } 66 | 67 | export interface Vault extends Account { 68 | owner: Pubkey 69 | stateBump: u8 70 | authBump: u8 71 | vaultBump: u8 72 | } 73 | -------------------------------------------------------------------------------- /examples/vote/rust/vote.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::prelude::*; 2 | declare_id!("HC2oqz2p6DEWfrahenqdq2moUcga9c9biqRBcdK3XKU1"); 3 | #[program] 4 | pub mod vote_program { 5 | use super::*; 6 | pub fn initialize(ctx: Context) -> Result<()> { 7 | ctx.accounts.state.vote = 0; 8 | Ok(()) 9 | } 10 | pub fn upvote(ctx: Context) -> Result<()> { 11 | ctx.accounts.state.vote = ctx.accounts.state.vote + 1; 12 | Ok(()) 13 | } 14 | pub fn downvote(ctx: Context) -> Result<()> { 15 | ctx.accounts.state.vote = ctx.accounts.state.vote - 1; 16 | Ok(()) 17 | } 18 | } 19 | #[derive(Accounts)] 20 | pub struct InitializeContext<'info> { 21 | #[account(init, payer = user, space = 17, seeds = [b"vote"], bump)] 22 | pub state: Account<'info, VoteState>, 23 | #[account(mut)] 24 | pub user: Signer<'info>, 25 | pub system_program: Program<'info, System>, 26 | } 27 | #[derive(Accounts)] 28 | pub struct UpvoteContext<'info> { 29 | #[account(mut, seeds = [b"vote"], bump)] 30 | pub state: Account<'info, VoteState>, 31 | pub system_program: Program<'info, System>, 32 | } 33 | #[derive(Accounts)] 34 | pub struct DownvoteContext<'info> { 35 | #[account(mut, seeds = [b"vote"], bump)] 36 | pub state: Account<'info, VoteState>, 37 | pub system_program: Program<'info, System>, 38 | } 39 | #[account] 40 | pub struct VoteState { 41 | pub vote: i64, 42 | pub bump: u8, 43 | } 44 | -------------------------------------------------------------------------------- /examples/vote/typescript/vote.ts: -------------------------------------------------------------------------------- 1 | import { Account, Pubkey, Result, i64, u8, Signer } from "@solanaturbine/poseidon"; 2 | 3 | // creating a class VoteProgram is similar to creating a creating a mod in anchor with all the instructions inside 4 | export default class VoteProgram { 5 | 6 | // define the progam id as a static constant like bellow 7 | static PROGRAM_ID = new Pubkey("HC2oqz2p6DEWfrahenqdq2moUcga9c9biqRBcdK3XKU1"); 8 | 9 | // we can pass in standard Accounts(Signer, TokenAccount, Mint, UncheckedAccount and so on), Custom Accounts(state in this case) and IX arguements(hash in this case) as parameters. 10 | initialize(state: VoteState, user: Signer): Result { 11 | 12 | // PDAs can be derived like .derive([...]) 13 | // where inside array we can pass string, Uint8Array, pubkey 14 | // we can also derive PDAs which are token account, associated token account which will be covered in vault and escrow 15 | state.derive(["vote"]) 16 | .init(user) // we can initialise PDA just by chaining a init method to the derive method 17 | 18 | // defining properties(vote) of custom_Acc(state) 19 | state.vote = new i64(0) 20 | } 21 | 22 | upvote(state: VoteState): Result { 23 | state.derive(["vote"]) 24 | // to do arithemtics we can chain methods like add, sub, mul, div, eq(equal), neq(not equal), lt(less than), lte(less than or equal) and so on 25 | state.vote = state.vote.add(1) 26 | } 27 | 28 | downvote(state: VoteState): Result { 29 | state.derive(["vote"]) 30 | state.vote = state.vote.sub(1) 31 | } 32 | } 33 | 34 | // define custom accounts by creating an interface which extends class Account 35 | export interface VoteState extends Account { 36 | // a variety of types are available like u8-u128, i8-i128, usize, boolean, string, Pubkey, etc... 37 | vote: i64 38 | bump: u8 39 | } -------------------------------------------------------------------------------- /images/solana-explorer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Turbin3/poseidon/6fdc2987ab26bf4c8a2cdc0429140431666902e1/images/solana-explorer.png -------------------------------------------------------------------------------- /src/cli.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | collections::HashMap, 3 | env, fs, 4 | io::{BufRead, BufReader}, 5 | path::{Path, PathBuf}, 6 | process::{Command, Stdio}, 7 | }; 8 | 9 | use anyhow::{Context, Result}; 10 | use convert_case::{Case, Casing}; 11 | use regex::{Regex, RegexBuilder}; 12 | use swc_ecma_ast::Module; 13 | use toml::Value; 14 | 15 | use crate::parse_ts::parse_ts; 16 | use crate::transpiler::transpile; 17 | 18 | pub fn init(name: &String) { 19 | println!("Initializing project: {}", name); 20 | 21 | if !anchor_installed() { 22 | println!("Anchor CLI not installed. Please install it before running this command."); 23 | return; 24 | } 25 | 26 | if !is_valid_project_name(&name) { 27 | println!("Invalid project name. Project names must start with a letter and contain only alphanumeric characters and hyphens."); 28 | return; 29 | } 30 | 31 | let project_name = name.to_case(Case::Kebab); 32 | 33 | execute_cmd(Command::new("anchor").args(["init", project_name.as_str()])); 34 | 35 | let project_path = Path::new(&project_name); 36 | 37 | // Create the ts-programs directory 38 | let ts_programs_path = project_path.join("ts-programs"); 39 | fs::create_dir(&ts_programs_path).unwrap_or_else(|_| { 40 | panic!( 41 | "Failed to create ts-programs directory at {:?}", 42 | ts_programs_path 43 | ) 44 | }); 45 | 46 | let original_dir = 47 | env::current_dir().unwrap_or_else(|_| panic!("Failed to get current directory")); 48 | 49 | env::set_current_dir(&ts_programs_path).unwrap_or_else(|_| { 50 | panic!( 51 | "Failed to change directory to: {}", 52 | project_path.join(ts_programs_path.clone()).display() 53 | ) 54 | }); 55 | 56 | execute_cmd(Command::new("npm").args(["init", "-y"])); 57 | 58 | execute_cmd(Command::new("npm").args(["add", "@solanaturbine/poseidon"])); 59 | 60 | env::set_current_dir(&original_dir).expect("Failed to change directory back to original"); 61 | 62 | // Create the ts-programs src directory 63 | let ts_programs_src_path = ts_programs_path.join("src"); 64 | fs::create_dir(&ts_programs_src_path).unwrap_or_else(|_| { 65 | panic!( 66 | "Failed to create ts-programs src directory at {:?}", 67 | ts_programs_src_path 68 | ) 69 | }); 70 | 71 | let ts_program_file_name = name.to_case(Case::Camel); 72 | let toml_program_name = name.to_case(Case::Snake); 73 | 74 | // Get the generated program ID from Anchor.toml 75 | let anchor_toml_path = project_path.join("Anchor.toml"); 76 | let anchor_toml = fs::read_to_string(&anchor_toml_path) 77 | .unwrap_or_else(|_| panic!("Failed to read Anchor.toml")); 78 | 79 | let program_ids = extract_program_ids(&anchor_toml) 80 | .unwrap_or_else(|_| panic!("Failed to extract program IDs from Anchor.toml")); 81 | 82 | let program_id = program_ids 83 | .get(&toml_program_name) 84 | .unwrap_or_else(|| panic!("Program ID not found for {}", name)); 85 | 86 | // Create the ts-programs src/{programName}.ts file and add default content 87 | let ts_programs_src_program_path = 88 | ts_programs_src_path.join(format!("{}.ts", ts_program_file_name)); 89 | fs::write( 90 | &ts_programs_src_program_path, 91 | get_default_program_content(&name, &program_id), 92 | ) 93 | .unwrap_or_else(|_| { 94 | panic!( 95 | "Failed to create {} file at {:?}", 96 | ts_program_file_name, ts_programs_src_program_path 97 | ) 98 | }); 99 | 100 | println!( 101 | "\n\nSetup successful!\n\nChange to your directory and start developing:\ncd {}", 102 | name 103 | ); 104 | } 105 | 106 | pub fn build_workspace() -> Result<()> { 107 | // Verify we're in a workspace root 108 | if !Path::new("Anchor.toml").exists() { 109 | return Err(anyhow::anyhow!( 110 | "Anchor.toml not found. Are you in the workspace root?" 111 | )); 112 | } 113 | 114 | // Get all programs from the programs directory 115 | let programs_dir = PathBuf::from("programs"); 116 | if !programs_dir.exists() { 117 | return Err(anyhow::anyhow!("programs directory not found")); 118 | } 119 | 120 | // Process each program in the programs directory 121 | for program_entry in fs::read_dir(&programs_dir)? { 122 | let program_dir = program_entry?.path(); 123 | if !program_dir.is_dir() { 124 | continue; 125 | } 126 | 127 | // Read program name from Cargo.toml 128 | let cargo_path = program_dir.join("Cargo.toml"); 129 | if !cargo_path.exists() { 130 | println!("Warning: Cargo.toml not found in {}", program_dir.display()); 131 | continue; 132 | } 133 | 134 | let program_name = get_program_name_from_cargo(&cargo_path)?; 135 | let ts_program_file_name = program_name.to_case(Case::Camel); 136 | 137 | println!("Found program: {}", program_name); 138 | 139 | // Create/ensure src directory exists 140 | let src_dir = program_dir.join("src"); 141 | fs::create_dir_all(&src_dir).context(format!( 142 | "Failed to create src directory for {}", 143 | program_name 144 | ))?; 145 | 146 | // Look for corresponding TypeScript file 147 | let ts_file = PathBuf::from("ts-programs") 148 | .join("src") 149 | .join(format!("{}.ts", ts_program_file_name)); 150 | 151 | if !ts_file.exists() { 152 | println!("Warning: No TypeScript file found at {}", ts_file.display()); 153 | continue; 154 | } 155 | 156 | // Compile TypeScript to Rust 157 | let rs_file = src_dir.join("lib.rs"); 158 | println!("Compiling {} to {}", ts_file.display(), rs_file.display()); 159 | 160 | let module: Module = parse_ts(&ts_file.to_string_lossy().to_string()); 161 | transpile(&module, &rs_file.to_string_lossy().to_string())?; 162 | 163 | println!("Successfully compiled {}", program_name); 164 | } 165 | 166 | println!("Build completed successfully!"); 167 | Ok(()) 168 | } 169 | 170 | pub fn run_tests() -> Result<()> { 171 | // Verify we're in a workspace root by checking for Anchor.toml 172 | if !Path::new("Anchor.toml").exists() { 173 | return Err(anyhow::anyhow!( 174 | "Anchor.toml not found. Are you in the workspace root?" 175 | )); 176 | } 177 | 178 | println!("Running anchor tests..."); 179 | 180 | // Build the workspace first 181 | build_workspace()?; 182 | 183 | // Execute anchor test 184 | let mut cmd = Command::new("anchor"); 185 | cmd.arg("test"); 186 | 187 | // Stream the test output 188 | let output = 189 | execute_cmd_with_output(&mut cmd).context("Failed to execute anchor test command")?; 190 | 191 | // Check if tests passed 192 | if output.status.success() { 193 | println!("\nTests completed successfully! ✨"); 194 | Ok(()) 195 | } else { 196 | Err(anyhow::anyhow!("Tests failed")) 197 | } 198 | } 199 | 200 | pub fn sync_program_ids() -> Result<()> { 201 | println!("Syncing program IDs..."); 202 | 203 | // First run anchor keys sync 204 | let mut cmd = Command::new("anchor"); 205 | cmd.args(["keys", "sync"]); 206 | 207 | let output = 208 | execute_cmd_with_output(&mut cmd).context("Failed to execute 'anchor keys sync'")?; 209 | 210 | if !output.status.success() { 211 | return Err(anyhow::anyhow!("Failed to run 'anchor keys sync'")); 212 | } 213 | 214 | // Read program IDs from Anchor.toml 215 | let anchor_toml = fs::read_to_string("Anchor.toml").context("Failed to read Anchor.toml")?; 216 | let program_ids = extract_program_ids(&anchor_toml)?; 217 | 218 | // Update TypeScript files 219 | let ts_programs_dir = PathBuf::from("ts-programs").join("src"); 220 | if !ts_programs_dir.exists() { 221 | return Err(anyhow::anyhow!("ts-programs/src directory not found")); 222 | } 223 | 224 | for (program_name, program_id) in program_ids { 225 | let ts_program_file_name = program_name.to_case(Case::Camel); 226 | let ts_file = ts_programs_dir.join(format!("{}.ts", ts_program_file_name)); 227 | if !ts_file.exists() { 228 | println!( 229 | "Warning: TypeScript file not found for program: {}", 230 | program_name 231 | ); 232 | continue; 233 | } 234 | 235 | update_program_id_in_ts(&ts_file, &program_id).context(format!( 236 | "Failed to update program ID in {}.ts", 237 | program_name 238 | ))?; 239 | 240 | println!("Updated program ID for {} to {}", program_name, program_id); 241 | } 242 | 243 | println!("Program IDs synced successfully! ✨"); 244 | Ok(()) 245 | } 246 | 247 | fn extract_program_ids(anchor_toml: &str) -> Result> { 248 | let toml_value: Value = anchor_toml.parse().context("Failed to parse Anchor.toml")?; 249 | 250 | let mut program_ids = HashMap::new(); 251 | 252 | if let Some(programs) = toml_value 253 | .get("programs") 254 | .and_then(|p| p.get("localnet")) 255 | .and_then(|l| l.as_table()) 256 | { 257 | for (name, value) in programs { 258 | if let Some(program_id) = value.as_str() { 259 | program_ids.insert(name.clone(), program_id.to_string()); 260 | } 261 | } 262 | } 263 | 264 | if program_ids.is_empty() { 265 | return Err(anyhow::anyhow!("No program IDs found in Anchor.toml")); 266 | } 267 | 268 | Ok(program_ids) 269 | } 270 | 271 | fn update_program_id_in_ts(file_path: &Path, program_id: &str) -> Result<()> { 272 | let content = fs::read_to_string(file_path).context("Failed to read TypeScript file")?; 273 | 274 | // Create a regex that matches both possible patterns 275 | let re = RegexBuilder::new(r#"static PROGRAM_ID = new Pubkey\(["']([^"']*)["']\)"#) 276 | .case_insensitive(true) 277 | .build() 278 | .context("Failed to create regex")?; 279 | 280 | let new_content = if let Some(capture) = re.captures(&content) { 281 | // Replace the program ID while preserving the exact casing and spacing 282 | content.replace( 283 | &capture[0], 284 | &format!(r#"static PROGRAM_ID = new Pubkey("{}")"#, program_id), 285 | ) 286 | } else { 287 | println!( 288 | "Warning: PROGRAM_ID not found in expected format in {}", 289 | file_path.display() 290 | ); 291 | content 292 | }; 293 | 294 | fs::write(file_path, new_content).context("Failed to write updated TypeScript file")?; 295 | 296 | Ok(()) 297 | } 298 | 299 | fn get_program_name_from_cargo(cargo_path: &Path) -> Result { 300 | let content = fs::read_to_string(cargo_path).context("Failed to read Cargo.toml")?; 301 | 302 | let cargo_toml: Value = content.parse().context("Failed to parse Cargo.toml")?; 303 | 304 | // Get the package name from Cargo.toml 305 | let package_name = cargo_toml 306 | .get("package") 307 | .and_then(|package| package.get("name")) 308 | .and_then(|name| name.as_str()) 309 | .ok_or_else(|| anyhow::anyhow!("Failed to get package name from Cargo.toml"))?; 310 | 311 | Ok(package_name.to_string()) 312 | } 313 | 314 | fn anchor_installed() -> bool { 315 | Command::new("anchor") 316 | .arg("--version") 317 | .output() 318 | .map_or(false, |output| output.status.success()) 319 | } 320 | 321 | fn is_valid_project_name(name: &str) -> bool { 322 | let re = Regex::new(r"^[a-zA-Z][a-zA-Z0-9\-]*$").unwrap(); 323 | re.is_match(name) 324 | } 325 | 326 | /// Executes a command and streams the output to stdout, returning the output 327 | fn execute_cmd_with_output(cmd: &mut Command) -> Result { 328 | let output = cmd 329 | .stdout(Stdio::inherit()) 330 | .stderr(Stdio::inherit()) 331 | .output() 332 | .context("Failed to execute command")?; 333 | 334 | Ok(output) 335 | } 336 | 337 | /// Executes a command and streams the output to stdout. 338 | fn execute_cmd(cmd: &mut Command) { 339 | let mut child = cmd 340 | .stdout(Stdio::piped()) 341 | .spawn() 342 | .expect("Failed to execute command"); 343 | 344 | let stdout = child.stdout.take().unwrap(); 345 | 346 | // Stream output. 347 | let lines = BufReader::new(stdout).lines(); 348 | for line in lines { 349 | println!("{}", line.unwrap()); 350 | } 351 | } 352 | 353 | fn get_default_program_content(program_name: &str, program_id: &str) -> String { 354 | format!( 355 | r#"import {{ Pubkey, type Result }} from "@solanaturbine/poseidon"; 356 | 357 | export default class {} {{ 358 | static PROGRAM_ID = new Pubkey("{}"); 359 | 360 | initialize(): Result {{ 361 | // Write your program here 362 | }} 363 | }}"#, 364 | program_name.to_case(Case::Pascal), 365 | program_id 366 | ) 367 | } 368 | -------------------------------------------------------------------------------- /src/errors.rs: -------------------------------------------------------------------------------- 1 | use anchor_lang::error; 2 | use thiserror::*; 3 | 4 | #[derive(Debug, Error)] 5 | pub enum PoseidonError { 6 | #[error("Invalid type: {0}")] 7 | InvalidType(String), 8 | #[error("Keyword type {0} is not supported")] 9 | KeyWordTypeNotSupported(String), 10 | #[error("expected a Member type")] 11 | MemberNotFound, 12 | #[error("expected a Expr type")] 13 | ExprNotFound, 14 | #[error("expected a Ident type")] 15 | IdentNotFound, 16 | #[error("expected a Array type")] 17 | ArrayNotFound, 18 | #[error("expected a Call type")] 19 | CallNotFound, 20 | #[error("expected a type reference")] 21 | TypeReferenceNotFound, 22 | #[error("expected a TS literal type")] 23 | TSLiteralTypeNotFound, 24 | #[error("expected a numeric literal for TS literal type")] 25 | NumericLiteralNotFound, 26 | #[error("expected a Atom type")] 27 | AtomNotFound, 28 | #[error("expected a authority for the Token account")] 29 | AuthorityNotFound, 30 | } 31 | -------------------------------------------------------------------------------- /src/helpers/extract_type.rs: -------------------------------------------------------------------------------- 1 | use swc_ecma_ast::{TsType, TsTypeParamInstantiation}; 2 | 3 | use crate::errors::PoseidonError; 4 | use anyhow::{Error, Ok, Result}; 5 | pub fn extract_ts_type( 6 | binding: Box, 7 | ) -> Result<(String, u32, bool), Error> { 8 | let ts_type: String; 9 | let length: u32; 10 | match binding.type_ann.as_ref() { 11 | TsType::TsTypeRef(_) => { 12 | let ident = binding 13 | .type_ann 14 | .as_ts_type_ref() 15 | .ok_or(PoseidonError::TypeReferenceNotFound)? 16 | .type_name 17 | .as_ident() 18 | .ok_or(PoseidonError::IdentNotFound)?; 19 | 20 | if let Some(type_params) = &binding 21 | .type_ann 22 | .as_ts_type_ref() 23 | .ok_or(PoseidonError::TypeReferenceNotFound)? 24 | .type_params 25 | { 26 | (ts_type, length) = 27 | extract_name_and_len_with_type_params(ident.sym.as_ref(), type_params)?; 28 | } else { 29 | ts_type = String::from(ident.sym.to_string()); 30 | length = 1; 31 | } 32 | 33 | Ok((ts_type, length, ident.optional)) 34 | } 35 | _ => Err(PoseidonError::KeyWordTypeNotSupported(format!( 36 | "{:?}", 37 | binding.type_ann.as_ref() 38 | )) 39 | .into()), 40 | } 41 | } 42 | 43 | fn extract_name_and_len_with_type_params( 44 | primary_type_ident: &str, 45 | type_params: &Box, 46 | ) -> Result<(String, u32), Error> { 47 | let ts_type: String; 48 | let mut length: u32 = 0; 49 | match primary_type_ident { 50 | "Str" => { 51 | length += type_params.params[0] 52 | .as_ts_lit_type() 53 | .ok_or(PoseidonError::TSLiteralTypeNotFound)? 54 | .lit 55 | .as_number() 56 | .ok_or(PoseidonError::NumericLiteralNotFound)? 57 | .value as u32; 58 | ts_type = String::from("Str"); 59 | } 60 | "Vec" => { 61 | let vec_type_name = type_params.params[0] 62 | .as_ts_type_ref() 63 | .ok_or(PoseidonError::TypeReferenceNotFound)? 64 | .type_name 65 | .as_ident() 66 | .ok_or(PoseidonError::IdentNotFound)? 67 | .sym 68 | .to_string(); 69 | 70 | let vec_len = type_params.params[1] 71 | .as_ts_lit_type() 72 | .ok_or(PoseidonError::TSLiteralTypeNotFound)? 73 | .lit 74 | .as_number() 75 | .ok_or(PoseidonError::NumericLiteralNotFound)? 76 | .value as u32; 77 | 78 | if let Some(type_params_layer) = &type_params.params[0] 79 | .as_ts_type_ref() 80 | .ok_or(PoseidonError::TypeReferenceNotFound)? 81 | .type_params 82 | { 83 | let type_ident_layer = type_params.params[0] 84 | .as_ts_type_ref() 85 | .ok_or(PoseidonError::TypeReferenceNotFound)? 86 | .type_name 87 | .as_ident() 88 | .ok_or(PoseidonError::IdentNotFound)? 89 | .sym 90 | .as_ref(); 91 | 92 | // for multiple nesting support recursion can be used 93 | // (type_name_layer, length_layer) = extract_name_and_len_with_type_params(type_ident_layer, type_params_layer)?; 94 | 95 | if type_ident_layer == "Str" { 96 | let string_length = type_params_layer.params[0] 97 | .as_ts_lit_type() 98 | .ok_or(PoseidonError::TSLiteralTypeNotFound)? 99 | .lit 100 | .as_number() 101 | .ok_or(PoseidonError::NumericLiteralNotFound)? 102 | .value as u32; 103 | 104 | length += vec_len * (4 + string_length); 105 | ts_type = format!("Vec"); 106 | } else { 107 | return Err(PoseidonError::KeyWordTypeNotSupported(format!( 108 | "{:?}", 109 | primary_type_ident 110 | )) 111 | .into()); 112 | } 113 | } else { 114 | length += vec_len; 115 | ts_type = format!("Vec<{}>", vec_type_name); 116 | } 117 | } 118 | _ => { 119 | return Err( 120 | PoseidonError::KeyWordTypeNotSupported(format!("{:?}", primary_type_ident)).into(), 121 | ) 122 | } 123 | } 124 | 125 | Ok((ts_type, length)) 126 | } 127 | -------------------------------------------------------------------------------- /src/helpers/format_account_struct.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{anyhow, Result}; 2 | use regex::Regex; 3 | 4 | pub fn extract_accounts_structs(input: &str) -> Vec { 5 | // Regex to capture structs with #[derive(Accounts)] 6 | let regex = Regex::new( 7 | r"(?s)#\[derive\(Accounts\)\](?:\s*#\[[^\]]*\])?\s*pub struct (\w+<'?\w*>) \{(.*?)\}", 8 | ) 9 | .unwrap(); 10 | 11 | regex 12 | .captures_iter(input) 13 | .map(|cap| format!("pub struct {} {{\n{}\n}}", &cap[1], &cap[2])) 14 | .collect() 15 | } 16 | 17 | pub fn reorder_struct(input: &str) -> Result<(String, String)> { 18 | let field_regex = Regex::new( 19 | r"(?ms)^(?P(\s*#\[[^\]]*\](\s*|.*?))*?)\s*pub\s+(?P\w+):\s+(?P[^\n]+),", 20 | ) 21 | .unwrap(); 22 | 23 | let mut init_fields = Vec::new(); 24 | let mut init_if_needed_fields = Vec::new(); 25 | let mut other_fields = Vec::new(); 26 | 27 | for cap in field_regex.captures_iter(input) { 28 | let attrs = cap.name("attrs").unwrap().as_str().trim(); 29 | 30 | let field = format!( 31 | "{}\n pub {}: {},", 32 | attrs, 33 | cap.name("name").unwrap().as_str(), 34 | cap.name("type").unwrap().as_str() 35 | ); 36 | 37 | if attrs.contains("init") && !attrs.contains("init_if_needed") { 38 | init_fields.push(field); 39 | } else if attrs.contains("init_if_needed") { 40 | init_if_needed_fields.push(field); 41 | } else { 42 | other_fields.push(field); 43 | } 44 | } 45 | 46 | let mut reordered_fields = String::new(); 47 | for field in init_fields { 48 | reordered_fields.push_str(&field); 49 | reordered_fields.push('\n'); 50 | } 51 | for field in init_if_needed_fields { 52 | reordered_fields.push_str(&field); 53 | reordered_fields.push('\n'); 54 | } 55 | for field in other_fields { 56 | reordered_fields.push_str(&field); 57 | reordered_fields.push('\n'); 58 | } 59 | 60 | let struct_regex = Regex::new(r"(?ms)^pub\s+struct\s+\w+<'\w+>\s*\{").unwrap(); 61 | if let Some(header) = struct_regex.find(input) { 62 | Ok(( 63 | header.as_str().to_string(), 64 | format!("{}\n{}\n}}", header.as_str(), reordered_fields), 65 | )) 66 | } else { 67 | Err(anyhow!("Invalid struct input")) 68 | } 69 | } 70 | 71 | pub fn replace_struct(code: &str, struct_header: &str, new_struct: &str) -> String { 72 | let struct_regex = Regex::new(&format!( 73 | r"(?ms)^{}.*?(}})", 74 | regex::escape(struct_header.trim()) 75 | )) 76 | .unwrap(); 77 | 78 | struct_regex.replace(code, new_struct).to_string() 79 | } 80 | -------------------------------------------------------------------------------- /src/helpers/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod extract_type; 2 | pub mod format_account_struct; 3 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | mod cli; 2 | mod errors; 3 | mod helpers; 4 | mod parse_ts; 5 | mod rs_types; 6 | mod transpiler; 7 | mod ts_types; 8 | 9 | use anyhow::Result; 10 | use clap::{Parser as ClapParser, Subcommand}; 11 | use parse_ts::parse_ts; 12 | use swc_ecma_ast::Module; 13 | 14 | use cli::{build_workspace, init, run_tests, sync_program_ids}; 15 | use transpiler::transpile; 16 | 17 | #[derive(ClapParser, Debug)] 18 | #[command(author, version, about, long_about = None)] 19 | #[command(propagate_version = true)] 20 | struct Cli { 21 | #[command(subcommand)] 22 | command: Commands, 23 | } 24 | 25 | #[derive(Subcommand, Debug)] 26 | enum Commands { 27 | /// Build Typescript programs in workspace 28 | Build, 29 | /// Run anchor tests in the workspace 30 | Test, 31 | /// Sync anchor keys in poseidon programs 32 | Sync, 33 | /// Transpile a Typescript program to a Rust program 34 | Compile { 35 | /// Input Typescript file path 36 | #[arg(short, long, help = "Input Typescript file")] 37 | input: String, 38 | /// Output Rust file path 39 | #[arg(short, long, help = "Output Rust file")] 40 | output: String, 41 | }, 42 | /// Initializes a new workspace 43 | Init { 44 | /// Workspace name 45 | name: String, 46 | }, 47 | } 48 | 49 | fn main() -> Result<()> { 50 | let cli = Cli::parse(); 51 | 52 | match &cli.command { 53 | Commands::Sync => { 54 | sync_program_ids()?; 55 | } 56 | Commands::Test => { 57 | run_tests()?; 58 | } 59 | Commands::Build => { 60 | build_workspace()?; 61 | } 62 | Commands::Compile { input, output } => { 63 | let module: Module = parse_ts(input); 64 | transpile(&module, output)?; 65 | } 66 | Commands::Init { name } => { 67 | init(name); 68 | } 69 | } 70 | 71 | Ok(()) 72 | } 73 | -------------------------------------------------------------------------------- /src/parse_ts.rs: -------------------------------------------------------------------------------- 1 | use std::path::Path; 2 | use swc_common::{ 3 | self, 4 | errors::{ColorConfig, Handler}, 5 | sync::Lrc, 6 | SourceMap, 7 | }; 8 | use swc_ecma_ast::Module; 9 | use swc_ecma_parser::{lexer::Lexer, Capturing, Parser, StringInput, Syntax}; 10 | 11 | pub fn parse_ts(input_file_name: &String) -> Module { 12 | let cm: Lrc = Default::default(); 13 | let handler = Handler::with_tty_emitter(ColorConfig::Auto, true, false, Some(cm.clone())); 14 | 15 | let fm = cm 16 | .load_file(Path::new(&input_file_name)) 17 | .expect(&format!("failed to load {}", input_file_name)); 18 | 19 | let lexer = Lexer::new( 20 | Syntax::Typescript(Default::default()), 21 | Default::default(), 22 | StringInput::from(&*fm), 23 | None, 24 | ); 25 | 26 | let capturing = Capturing::new(lexer); 27 | 28 | let mut parser = Parser::new_from(capturing); 29 | 30 | for e in parser.take_errors() { 31 | e.into_diagnostic(&handler).emit(); 32 | } 33 | 34 | let module = parser 35 | .parse_typescript_module() 36 | .map_err(|e| e.into_diagnostic(&handler).emit()) 37 | .expect("Failed to parse module."); 38 | 39 | return module; 40 | } 41 | -------------------------------------------------------------------------------- /src/rs_types/instruction_account.rs: -------------------------------------------------------------------------------- 1 | use convert_case::{Case, Casing}; 2 | use core::panic; 3 | use proc_macro2::{Ident, Literal, TokenStream}; 4 | use quote::quote; 5 | 6 | use crate::rs_types::{Mint, Ta}; 7 | 8 | #[derive(Clone, Debug)] 9 | pub struct InstructionAccount { 10 | pub name: String, 11 | pub of_type: TokenStream, 12 | pub type_str: String, 13 | pub optional: bool, 14 | pub is_mut: bool, 15 | pub is_init: bool, 16 | pub is_initifneeded: bool, 17 | pub is_close: bool, 18 | pub mint: Option, 19 | pub ta: Option, 20 | pub has_one: Vec, 21 | pub close: Option, 22 | pub seeds: Option>, 23 | pub bump: Option, 24 | pub payer: Option, 25 | pub space: Option, 26 | pub is_custom: bool, 27 | } 28 | 29 | impl InstructionAccount { 30 | pub fn new(name: String, of_type: TokenStream, type_str: String, optional: bool) -> Self { 31 | Self { 32 | name: name.to_case(Case::Snake), 33 | of_type, 34 | type_str, 35 | optional, 36 | is_mut: false, 37 | is_close: false, 38 | is_init: false, 39 | is_initifneeded: false, 40 | mint: None, 41 | ta: None, 42 | has_one: vec![], 43 | close: None, 44 | seeds: None, 45 | bump: None, 46 | payer: None, 47 | space: None, 48 | is_custom: false, 49 | } 50 | } 51 | 52 | pub fn to_tokens(&self) -> TokenStream { 53 | let name = Ident::new(&self.name, proc_macro2::Span::call_site()); 54 | let of_type = &self.of_type; 55 | let constraints: TokenStream; 56 | // this is evaluated this way coz, ta might not have seeds 57 | if (self.mint.is_none() & self.seeds.is_none() & self.ta.is_none()) 58 | & (self.is_close | self.is_init | self.is_initifneeded) 59 | { 60 | panic!( 61 | r##"use derive or deriveWithBump with all the necessary arguments while using "init" or "initIfNeeded" or "close" "## 62 | ); 63 | } 64 | let payer = match &self.payer { 65 | Some(s) => { 66 | let payer = Ident::new(&s.to_case(Case::Snake), proc_macro2::Span::call_site()); 67 | quote!( 68 | payer = #payer 69 | ) 70 | } 71 | None => quote!(), 72 | }; 73 | 74 | let ata = match &self.ta { 75 | Some(a) => { 76 | let mint = Ident::new(&a.mint, proc_macro2::Span::call_site()); 77 | let authority = Ident::new(&a.authority, proc_macro2::Span::call_site()); 78 | if a.is_ata { 79 | quote! { 80 | associated_token::mint = #mint, 81 | associated_token::authority = #authority, 82 | } 83 | } else { 84 | quote! { 85 | token::mint = #mint, 86 | token::authority = #authority, 87 | } 88 | } 89 | } 90 | None => quote!(), 91 | }; 92 | 93 | let mint = match &self.mint { 94 | Some(m) => { 95 | let decimal_token = &m.decimals_token; 96 | let mint_auth_token = &m.mint_authority_token; 97 | 98 | if let Some(freeze_auth) = &m.freeze_authority_token { 99 | quote! { 100 | mint::decimals = #decimal_token, 101 | mint::authority = #mint_auth_token, 102 | mint::freeze_authority = #freeze_auth, 103 | } 104 | } else { 105 | quote! { 106 | mint::decimals = #decimal_token, 107 | mint::authority = #mint_auth_token, 108 | } 109 | } 110 | } 111 | None => quote! {}, 112 | }; 113 | let close = match &self.close { 114 | Some(c) => { 115 | let close_acc = Ident::new(c, proc_macro2::Span::call_site()); 116 | 117 | quote! { 118 | close = #close_acc, 119 | } 120 | } 121 | None => quote!(), 122 | }; 123 | 124 | let seeds = match &self.seeds { 125 | Some(s) => { 126 | quote! { 127 | seeds = [#(#s),*], 128 | } 129 | } 130 | None => quote! {}, 131 | }; 132 | 133 | let bump = match &self.bump { 134 | Some(b) => { 135 | quote! { 136 | #b, 137 | } 138 | } 139 | None => quote! {}, 140 | }; 141 | let space = match self.space { 142 | Some(s) => { 143 | let s_literal = Literal::u32_unsuffixed(s); 144 | quote! {space = #s_literal,} 145 | } 146 | None => { 147 | quote! {} 148 | } 149 | }; 150 | 151 | let init = match self.is_init { 152 | true => quote! {init, #payer, #space}, 153 | false => quote! {}, 154 | }; 155 | 156 | let mutable = match self.is_mut && !(self.is_init || self.is_initifneeded) { 157 | true => quote! {mut,}, 158 | false => quote! {}, 159 | }; 160 | let mut has: TokenStream = quote! {}; 161 | if !self.has_one.is_empty() { 162 | let mut has_vec: Vec = vec![]; 163 | for h in &self.has_one { 164 | let h_ident = Ident::new(h, proc_macro2::Span::call_site()); 165 | has_vec.push(quote! { 166 | has_one = #h_ident 167 | }) 168 | } 169 | has = quote! { #(#has_vec),*,}; 170 | } 171 | let init_if_needed = match self.is_initifneeded { 172 | true => { 173 | if self.is_custom { 174 | quote! {init_if_needed, #payer, #space} 175 | } else { 176 | quote! {init_if_needed, #payer,} 177 | } 178 | } 179 | false => quote! {}, 180 | }; 181 | 182 | constraints = quote! { 183 | #[account( 184 | #init 185 | #init_if_needed 186 | #mutable 187 | #seeds 188 | #ata 189 | #mint 190 | #has 191 | #bump 192 | #close 193 | 194 | )] 195 | }; 196 | let check = if self.type_str == "UncheckedAccount" { 197 | quote! { 198 | /// CHECK: This acc is safe 199 | } 200 | } else { 201 | quote! {} 202 | }; 203 | quote!( 204 | #constraints 205 | #check 206 | pub #name: #of_type, 207 | ) 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /src/rs_types/mod.rs: -------------------------------------------------------------------------------- 1 | use proc_macro2::TokenStream; 2 | 3 | pub mod instruction_account; 4 | pub mod program_account; 5 | pub mod program_instruction; 6 | pub mod program_module; 7 | 8 | pub use program_account::*; 9 | pub use program_module::*; 10 | 11 | #[derive(Debug, Clone)] 12 | pub struct Ta { 13 | mint: String, 14 | authority: String, 15 | is_ata: bool, 16 | } 17 | 18 | #[derive(Debug, Clone)] 19 | pub struct Mint { 20 | mint_authority_token: TokenStream, 21 | decimals_token: TokenStream, 22 | freeze_authority_token: Option, 23 | } 24 | -------------------------------------------------------------------------------- /src/rs_types/program_account.rs: -------------------------------------------------------------------------------- 1 | use convert_case::{Case, Casing}; 2 | use core::panic; 3 | use proc_macro2::{Ident, TokenStream}; 4 | use quote::quote; 5 | use swc_ecma_ast::{TsExprWithTypeArgs, TsInterfaceDecl}; 6 | 7 | use crate::helpers::extract_type::extract_ts_type; 8 | use crate::ts_types::rs_type_from_str; 9 | 10 | #[derive(Debug, Clone)] 11 | pub struct ProgramAccountField { 12 | pub name: String, 13 | pub of_type: String, 14 | } 15 | 16 | #[derive(Debug, Clone)] 17 | pub struct ProgramAccount { 18 | pub name: String, 19 | pub fields: Vec, 20 | pub space: u32, 21 | } 22 | 23 | impl ProgramAccount { 24 | pub fn from_ts_expr(interface: TsInterfaceDecl) -> Self { 25 | match interface.extends.first() { 26 | Some(TsExprWithTypeArgs { expr, .. }) 27 | if expr.clone().ident().is_some() 28 | && expr.clone().ident().unwrap().sym == "Account" => {} 29 | _ => panic!("Custom accounts must extend Account type"), 30 | } 31 | let name: String = interface.id.sym.to_string(); 32 | let mut space: u32 = 8; // anchor discriminator 33 | let fields: Vec = interface 34 | .body 35 | .body 36 | .iter() 37 | .map(|f| { 38 | let field = f.clone().ts_property_signature().expect("Invalid property"); 39 | let field_name = field.key.ident().expect("Invalid property").sym.to_string(); 40 | let binding = field.type_ann.expect("Invalid type annotation"); 41 | let (field_type, len, _optional) = extract_ts_type(binding) 42 | .unwrap_or_else(|_| panic!("Keyword type is not supported")); 43 | 44 | if field_type.contains("Vec") | field_type.contains("Str") { 45 | space += 4; 46 | } 47 | 48 | if field_type.contains("Pubkey") { 49 | space += 32 * len; 50 | } else if field_type.contains("u64") | field_type.contains("i64") { 51 | space += 8 * len; 52 | } else if field_type.contains("u32") | field_type.contains("i32") { 53 | space += 4 * len; 54 | } else if field_type.contains("u16") | field_type.contains("i16") { 55 | space += 2 * len; 56 | } else if field_type.contains("u8") | field_type.contains("i8") { 57 | space += 1 * len; 58 | } else if field_type.contains("Str") { 59 | space += len; 60 | } else if field_type.contains("Boolean") { 61 | space += len; 62 | } 63 | 64 | ProgramAccountField { 65 | name: field_name, 66 | of_type: field_type.to_string(), 67 | } 68 | }) 69 | .collect(); 70 | Self { 71 | name, 72 | fields, 73 | space, 74 | } 75 | } 76 | 77 | pub fn to_tokens(&self) -> TokenStream { 78 | let struct_name = Ident::new(&self.name, proc_macro2::Span::call_site()); 79 | 80 | let fields: Vec<_> = self 81 | .fields 82 | .iter() 83 | .map(|field| { 84 | let field_name = Ident::new( 85 | &field.name.to_case(Case::Snake), 86 | proc_macro2::Span::call_site(), 87 | ); 88 | 89 | let field_type = rs_type_from_str(&field.of_type) 90 | .unwrap_or_else(|_| panic!("Invalid type: {}", field.of_type)); 91 | 92 | quote! { pub #field_name: #field_type } 93 | }) 94 | .collect(); 95 | 96 | quote! { 97 | #[account] 98 | pub struct #struct_name { 99 | #(#fields),* 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/rs_types/program_module.rs: -------------------------------------------------------------------------------- 1 | use convert_case::{Case, Casing}; 2 | use core::panic; 3 | use proc_macro2::{Ident, Literal, TokenStream}; 4 | use quote::quote; 5 | use std::collections::HashMap; 6 | use swc_ecma_ast::{ClassExpr, Lit}; 7 | 8 | use crate::rs_types::program_account::ProgramAccount; 9 | use crate::rs_types::program_instruction::ProgramInstruction; 10 | use anyhow::{anyhow, Ok, Result}; 11 | type SubMember = HashMap>; // submember_name : alias 12 | type Member = HashMap; // member_name : submembers 13 | type ProgramImport = HashMap; // src_pkg : members 14 | pub struct ProgramModule { 15 | pub id: String, 16 | pub name: String, 17 | pub custom_types: HashMap, 18 | pub instructions: Vec, 19 | pub accounts: Vec, 20 | pub imports: ProgramImport, 21 | } 22 | 23 | impl ProgramModule { 24 | pub fn new() -> Self { 25 | Self { 26 | id: "Poseidon11111111111111111111111111111111111".to_string(), 27 | name: "AnchorProgram".to_string(), 28 | custom_types: HashMap::new(), 29 | instructions: vec![], 30 | accounts: vec![], 31 | imports: HashMap::new(), 32 | } 33 | } 34 | pub fn add_import(&mut self, src_pkg: &str, member_name: &str, sub_member_name: &str) { 35 | let mut alias: Option = None; 36 | if sub_member_name == "Transfer" && member_name == "token" { 37 | alias = Some("TransferSPL".to_string()); 38 | } 39 | if sub_member_name == "transfer" && member_name == "token" { 40 | alias = Some("transfer_spl".to_string()); 41 | } 42 | if let Some(members) = self.imports.get_mut(src_pkg) { 43 | if !members.contains_key(member_name) { 44 | members.insert( 45 | member_name.to_string(), 46 | SubMember::from([(sub_member_name.to_string(), alias)]), 47 | ); 48 | } else if let Some(submembers) = members.get_mut(member_name) { 49 | if !submembers.contains_key(sub_member_name) { 50 | submembers.insert(sub_member_name.to_string(), alias); 51 | } 52 | } 53 | } else { 54 | self.imports.insert( 55 | src_pkg.to_string(), 56 | Member::from([( 57 | member_name.to_string(), 58 | SubMember::from([(sub_member_name.to_string(), alias)]), 59 | )]), 60 | ); 61 | } 62 | } 63 | 64 | pub fn populate_from_class_expr( 65 | &mut self, 66 | class: &ClassExpr, 67 | custom_accounts: &HashMap, 68 | ) -> Result<()> { 69 | self.name = class 70 | .ident 71 | .clone() 72 | .expect("Expected ident") 73 | .as_ref() 74 | .split("#") 75 | .next() 76 | .expect("Expected program to have a valid name") 77 | .to_string(); 78 | let class_members = &class.class.body; 79 | let _ = class_members 80 | .iter() 81 | .map(|c| { 82 | match c.as_class_prop() { 83 | Some(c) => { 84 | // Handle as a class prop 85 | if c.key.as_ident().expect("Invalid class property").sym == "PROGRAM_ID" { 86 | let val = c 87 | .value 88 | .as_ref() 89 | .expect("Invalid program ID") 90 | .as_new() 91 | .expect("Invalid program ID"); 92 | assert!( 93 | val.callee.clone().expect_ident().sym == "Pubkey", 94 | "Invalid program ID, expected new Pubkey(\"11111111111111.....\")" 95 | ); 96 | self.id = match val.args.clone().expect("Invalid program ID")[0] 97 | .expr 98 | .clone() 99 | .lit() 100 | .expect("Invalid program ID") 101 | { 102 | Lit::Str(s) => s.value.to_string(), 103 | _ => panic!("Invalid program ID"), 104 | }; 105 | } else { 106 | panic!("Invalid declaration") 107 | } 108 | } 109 | None => match c.as_method() { 110 | Some(c) => { 111 | let ix = 112 | ProgramInstruction::from_class_method(self, c, custom_accounts) 113 | .map_err(|e| anyhow!(e.to_string()))?; 114 | self.instructions.push(ix); 115 | } 116 | None => panic!("Invalid class property or member"), 117 | }, 118 | } 119 | Ok(()) 120 | }) 121 | .collect::>>(); 122 | Ok(()) 123 | } 124 | 125 | pub fn to_tokens(&self) -> Result { 126 | let program_name = Ident::new( 127 | &self.name.to_case(Case::Snake), 128 | proc_macro2::Span::call_site(), 129 | ); 130 | let program_id = Literal::string(&self.id); 131 | let serialized_instructions: Vec = 132 | self.instructions.iter().map(|x| x.to_tokens()).collect(); 133 | let serialized_account_structs: Vec = self 134 | .instructions 135 | .iter() 136 | .map(|x| x.accounts_to_tokens()) 137 | .collect(); 138 | 139 | let imports: TokenStream = match !self.imports.is_empty() { 140 | true => { 141 | let mut imports_vec: Vec = vec![]; 142 | for (src_pkg, members) in self.imports.iter() { 143 | let src_pkg_ident = Ident::new(src_pkg, proc_macro2::Span::call_site()); 144 | 145 | let mut member_tokens: Vec = vec![]; 146 | for (member_name, sub_members) in members.iter() { 147 | let member_name_ident = 148 | Ident::new(member_name, proc_macro2::Span::call_site()); 149 | let mut sub_member_tokens: Vec = vec![]; 150 | for (sub_member_name, alias) in sub_members { 151 | let sub_member_name_ident = 152 | Ident::new(sub_member_name, proc_macro2::Span::call_site()); 153 | if alias.is_none() { 154 | sub_member_tokens.push(quote! {#sub_member_name_ident}); 155 | } else { 156 | let alias_str = 157 | alias.to_owned().ok_or(anyhow!("invalid alias in import"))?; 158 | let alias_ident = 159 | Ident::new(&alias_str, proc_macro2::Span::call_site()); 160 | sub_member_tokens 161 | .push(quote! {#sub_member_name_ident as #alias_ident}); 162 | } 163 | } 164 | 165 | member_tokens.push(quote!(#member_name_ident :: {#(#sub_member_tokens),*})) 166 | } 167 | imports_vec.push(quote! {use #src_pkg_ident :: {#(#member_tokens),*};}); 168 | } 169 | 170 | quote! {#(#imports_vec),*} 171 | } 172 | false => { 173 | quote!() 174 | } 175 | }; 176 | let serialized_accounts: Vec = 177 | self.accounts.iter().map(|x| x.to_tokens()).collect(); 178 | let program = quote! { 179 | use anchor_lang::prelude::*; 180 | #imports 181 | declare_id!(#program_id); 182 | 183 | #[program] 184 | pub mod #program_name { 185 | use super::*; 186 | 187 | #(#serialized_instructions)* 188 | } 189 | 190 | #(#serialized_account_structs)* 191 | 192 | #(#serialized_accounts)* 193 | }; 194 | Ok(program) 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /src/transpiler.rs: -------------------------------------------------------------------------------- 1 | use core::panic; 2 | use rust_format::{Formatter, PrettyPlease}; 3 | use std::{ 4 | collections::HashMap, 5 | fs::{self}, 6 | }; 7 | 8 | use crate::{ 9 | helpers::format_account_struct::{extract_accounts_structs, reorder_struct, replace_struct}, 10 | rs_types::{ProgramAccount, ProgramModule}, 11 | }; 12 | use anyhow::Result; 13 | use swc_ecma_ast::*; 14 | 15 | pub fn transpile(module: &Module, output_file_name: &String) -> Result<()> { 16 | let mut imports = vec![]; 17 | let mut accounts: HashMap = HashMap::new(); 18 | let mut program_class: Option = None; 19 | let mut custom_types: HashMap = HashMap::new(); 20 | let mut program = ProgramModule::new(); 21 | let mut stack: Vec<&ModuleItem> = module.body.iter().collect(); 22 | 23 | while let Some(item) = stack.pop() { 24 | match item { 25 | // Extract imports 26 | ModuleItem::ModuleDecl(ModuleDecl::Import(import_decl)) => { 27 | let src = import_decl.src.value.to_string(); 28 | let mut names = Vec::new(); 29 | for specifier in &import_decl.specifiers { 30 | if let ImportSpecifier::Named(named_specifier) = specifier { 31 | names.push(named_specifier.local.sym.to_string()); 32 | } 33 | } 34 | imports.push((src, names)); 35 | } 36 | // Extract program class 37 | ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultDecl(default_export_decl)) => { 38 | program_class = match default_export_decl.clone().decl.class() { 39 | Some(p) => Some(p), 40 | None => panic!("Default export must be a Class"), 41 | }; 42 | } 43 | // Extract custom accounts 44 | ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(class_decl)) => { 45 | match class_decl.clone().decl { 46 | Decl::TsInterface(interface) => { 47 | let custom_account = ProgramAccount::from_ts_expr(*interface); 48 | custom_types.insert(custom_account.name.clone(), custom_account.clone()); 49 | accounts.insert(custom_account.name.clone(), custom_account.clone()); 50 | } 51 | _ => panic!("Invalid export statement"), 52 | } 53 | } 54 | _ => panic!("Invalid syntax, cannot match: {:?}", item), 55 | } 56 | } 57 | 58 | program.accounts = accounts.into_values().collect(); 59 | program.custom_types.clone_from(&custom_types); 60 | 61 | match program_class { 62 | Some(c) => { 63 | program.populate_from_class_expr(&c, &custom_types)?; 64 | } 65 | None => panic!("Program class undefined"), 66 | } 67 | let serialized_program = program.to_tokens()?.to_string(); 68 | 69 | let mut formatted_program = PrettyPlease::default().format_str(&serialized_program)?; 70 | 71 | let extracted_account_struct = extract_accounts_structs(&formatted_program); 72 | 73 | for account_struct in extracted_account_struct { 74 | let (header, reordered_account_struct) = reorder_struct(&account_struct)?; 75 | 76 | formatted_program = replace_struct(&formatted_program, &header, &reordered_account_struct); 77 | } 78 | 79 | fs::write( 80 | &output_file_name, 81 | PrettyPlease::default().format_str(formatted_program)?, 82 | )?; 83 | Ok(()) 84 | } 85 | -------------------------------------------------------------------------------- /src/ts_types.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{Error, Result}; 2 | use proc_macro2::TokenStream; 3 | use quote::quote; 4 | 5 | pub const STANDARD_TYPES: [&str; 16] = [ 6 | "u8", 7 | "i8", 8 | "u16", 9 | "i16", 10 | "u32", 11 | "i32", 12 | "u64", 13 | "i64", 14 | "u128", 15 | "i128", 16 | "usize", 17 | "isize", 18 | "Boolean", 19 | "Uint8Array", 20 | "Str", 21 | "Pubkey", 22 | ]; 23 | 24 | pub const STANDARD_ARRAY_TYPES: [&str; 13] = [ 25 | "Vec", 26 | "Vec", 27 | "Vec", 28 | "Vec", 29 | "Vec", 30 | "Vec", 31 | "Vec", 32 | "Vec", 33 | "Vec", 34 | "Vec", 35 | "Vec", 36 | "Vec", 37 | "Vec", 38 | ]; 39 | 40 | pub const STANDARD_ACCOUNT_TYPES: [&str; 7] = [ 41 | "Signer", 42 | "UncheckedAccount", 43 | "AccountInfo", 44 | "TokenAccount", 45 | "SystemAccount", 46 | "AssociatedTokenAccount", 47 | "Mint", 48 | ]; 49 | 50 | use crate::errors::PoseidonError; 51 | 52 | pub fn rs_type_from_str(str: &str) -> Result { 53 | match str { 54 | "Str" => Ok(quote! { String }), 55 | "Vec" => Ok(quote! { Vec }), 56 | "Vec" => Ok(quote! { Vec }), 57 | "Vec" => Ok(quote! { Vec }), 58 | "Vec" => Ok(quote! { Vec }), 59 | "Vec" => Ok(quote! { Vec }), 60 | "Vec" => Ok(quote! { Vec }), 61 | "Vec" => Ok(quote! { Vec }), 62 | "Vec" => Ok(quote! { Vec }), 63 | "Vec" => Ok(quote! { Vec }), 64 | "Vec" => Ok(quote! { Vec }), 65 | "Vec" => Ok(quote! { Vec }), 66 | "Vec" => Ok(quote! { Vec }), 67 | "Vec" => Ok(quote! { Vec }), 68 | "u8" => Ok(quote! { u8 }), 69 | "i8" => Ok(quote! { i8 }), 70 | "u16" => Ok(quote! { u16 }), 71 | "i16" => Ok(quote! { i16 }), 72 | "u32" => Ok(quote! { u32 }), 73 | "i32" => Ok(quote! { i32 }), 74 | "u64" => Ok(quote! { u64 }), 75 | "i64" => Ok(quote! { i64 }), 76 | "u128" => Ok(quote! { u128 }), 77 | "i128" => Ok(quote! { i128 }), 78 | "usize" => Ok(quote! { usize }), 79 | "isize" => Ok(quote! { isize }), 80 | "Boolean" => Ok(quote! { bool }), 81 | "Pubkey" => Ok(quote! { Pubkey }), 82 | "Uint8Array" => Ok(quote! { Vec }), 83 | // "Signer" => Ok(quote!{Signer}), 84 | _ => Err(PoseidonError::InvalidType(str.to_string()))?, 85 | } 86 | } 87 | --------------------------------------------------------------------------------