浏览代码

update anchor tokens examples

John 2 年之前
父节点
当前提交
3fc0943095
共有 48 个文件被更改,包括 1349 次插入1617 次删除
  1. 243 86
      Cargo.lock
  2. 19 4
      tokens/create-token/anchor/Anchor.toml
  3. 13 13
      tokens/create-token/anchor/package.json
  4. 2 2
      tokens/create-token/anchor/programs/create-token/Cargo.toml
  5. 51 52
      tokens/create-token/anchor/programs/create-token/src/lib.rs
  6. 42 41
      tokens/create-token/anchor/tests/test.ts
  7. 17 5
      tokens/nft-minter/anchor/Anchor.toml
  8. 1 3
      tokens/nft-minter/anchor/Cargo.toml
  9. 14 13
      tokens/nft-minter/anchor/package.json
  10. 3 4
      tokens/nft-minter/anchor/programs/nft-minter/Cargo.toml
  11. 0 73
      tokens/nft-minter/anchor/programs/nft-minter/src/instructions/create.rs
  12. 0 126
      tokens/nft-minter/anchor/programs/nft-minter/src/instructions/mint.rs
  13. 132 12
      tokens/nft-minter/anchor/programs/nft-minter/src/lib.rs
  14. 59 79
      tokens/nft-minter/anchor/tests/test.ts
  15. 19 4
      tokens/pda-mint-authority/anchor/Anchor.toml
  16. 1 3
      tokens/pda-mint-authority/anchor/Cargo.toml
  17. 14 13
      tokens/pda-mint-authority/anchor/package.json
  18. 0 82
      tokens/pda-mint-authority/anchor/programs/nft-minter/src/instructions/create.rs
  19. 0 25
      tokens/pda-mint-authority/anchor/programs/nft-minter/src/instructions/init.rs
  20. 0 138
      tokens/pda-mint-authority/anchor/programs/nft-minter/src/instructions/mint.rs
  21. 0 7
      tokens/pda-mint-authority/anchor/programs/nft-minter/src/instructions/mod.rs
  22. 0 32
      tokens/pda-mint-authority/anchor/programs/nft-minter/src/lib.rs
  23. 0 11
      tokens/pda-mint-authority/anchor/programs/nft-minter/src/state/mod.rs
  24. 4 5
      tokens/pda-mint-authority/anchor/programs/token-minter/Cargo.toml
  25. 0 0
      tokens/pda-mint-authority/anchor/programs/token-minter/Xargo.toml
  26. 88 0
      tokens/pda-mint-authority/anchor/programs/token-minter/src/instructions/create.rs
  27. 65 0
      tokens/pda-mint-authority/anchor/programs/token-minter/src/instructions/mint.rs
  28. 0 0
      tokens/pda-mint-authority/anchor/programs/token-minter/src/instructions/mod.rs
  29. 25 0
      tokens/pda-mint-authority/anchor/programs/token-minter/src/lib.rs
  30. 64 98
      tokens/pda-mint-authority/anchor/tests/test.ts
  31. 17 5
      tokens/spl-token-minter/anchor/Anchor.toml
  32. 14 13
      tokens/spl-token-minter/anchor/package.json
  33. 3 3
      tokens/spl-token-minter/anchor/programs/spl-token-minter/Cargo.toml
  34. 63 58
      tokens/spl-token-minter/anchor/programs/spl-token-minter/src/instructions/create.rs
  35. 34 35
      tokens/spl-token-minter/anchor/programs/spl-token-minter/src/instructions/mint.rs
  36. 5 6
      tokens/spl-token-minter/anchor/programs/spl-token-minter/src/lib.rs
  37. 56 45
      tokens/spl-token-minter/anchor/tests/test.ts
  38. 19 4
      tokens/transfer-tokens/anchor/Anchor.toml
  39. 14 13
      tokens/transfer-tokens/anchor/package.json
  40. 3 3
      tokens/transfer-tokens/anchor/programs/transfer-tokens/Cargo.toml
  41. 64 66
      tokens/transfer-tokens/anchor/programs/transfer-tokens/src/instructions/create.rs
  42. 54 0
      tokens/transfer-tokens/anchor/programs/transfer-tokens/src/instructions/mint.rs
  43. 0 126
      tokens/transfer-tokens/anchor/programs/transfer-tokens/src/instructions/mint_nft.rs
  44. 0 55
      tokens/transfer-tokens/anchor/programs/transfer-tokens/src/instructions/mint_spl.rs
  45. 2 4
      tokens/transfer-tokens/anchor/programs/transfer-tokens/src/instructions/mod.rs
  46. 42 38
      tokens/transfer-tokens/anchor/programs/transfer-tokens/src/instructions/transfer.rs
  47. 6 11
      tokens/transfer-tokens/anchor/programs/transfer-tokens/src/lib.rs
  48. 77 201
      tokens/transfer-tokens/anchor/tests/test.ts

+ 243 - 86
Cargo.lock

@@ -382,6 +382,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "78f860599da1c2354e7234c768783049eb42e2f54509ecfc942d2e0076a2da7b"
 dependencies = [
  "anchor-lang 0.28.0",
+ "mpl-token-metadata",
  "solana-program",
  "spl-associated-token-account 1.1.3",
  "spl-token 3.5.0",
@@ -805,22 +806,22 @@ dependencies = [
 
 [[package]]
 name = "bytemuck"
-version = "1.13.1"
+version = "1.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea"
+checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6"
 dependencies = [
  "bytemuck_derive",
 ]
 
 [[package]]
 name = "bytemuck_derive"
-version = "1.4.1"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192"
+checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.29",
+ "syn 2.0.31",
 ]
 
 [[package]]
@@ -868,9 +869,9 @@ dependencies = [
 
 [[package]]
 name = "chrono"
-version = "0.4.28"
+version = "0.4.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95ed24df0632f708f5f6d8082675bef2596f7084dee3dd55f632290bf35bfe0f"
+checksum = "defd4e7873dbddba6c7c91e199c7fcb946abc4a6a4ac3195400bcfb01b5de877"
 dependencies = [
  "num-traits",
 ]
@@ -1000,7 +1001,7 @@ dependencies = [
  "borsh-derive 0.9.3",
  "mpl-token-metadata",
  "solana-program",
- "spl-associated-token-account 2.0.0",
+ "spl-associated-token-account 2.1.0",
  "spl-token 4.0.0",
 ]
 
@@ -1164,7 +1165,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "strsim",
- "syn 2.0.29",
+ "syn 2.0.31",
 ]
 
 [[package]]
@@ -1175,7 +1176,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
 dependencies = [
  "darling_core",
  "quote",
- "syn 2.0.29",
+ "syn 2.0.31",
 ]
 
 [[package]]
@@ -1624,9 +1625,9 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
 
 [[package]]
 name = "memchr"
-version = "2.6.2"
+version = "2.6.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5486aed0026218e61b8a01d5fbd5a0a134649abb71a0e53b7bc088529dced86e"
+checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c"
 
 [[package]]
 name = "memmap2"
@@ -1682,7 +1683,7 @@ dependencies = [
  "borsh 0.9.3",
  "bytemuck",
  "mpl-token-metadata-context-derive 0.2.1",
- "num-derive",
+ "num-derive 0.3.3",
  "num-traits",
  "rmp-serde",
  "serde",
@@ -1703,11 +1704,11 @@ dependencies = [
  "mpl-token-auth-rules",
  "mpl-token-metadata-context-derive 0.3.0",
  "mpl-utils",
- "num-derive",
+ "num-derive 0.3.3",
  "num-traits",
  "shank 0.0.11",
  "solana-program",
- "spl-associated-token-account 2.0.0",
+ "spl-associated-token-account 2.1.0",
  "spl-token 4.0.0",
  "thiserror",
 ]
@@ -1750,7 +1751,6 @@ dependencies = [
  "anchor-lang 0.28.0",
  "anchor-spl",
  "mpl-token-metadata",
- "spl-token 4.0.0",
 ]
 
 [[package]]
@@ -1761,7 +1761,7 @@ dependencies = [
  "borsh-derive 0.9.3",
  "mpl-token-metadata",
  "solana-program",
- "spl-associated-token-account 2.0.0",
+ "spl-associated-token-account 2.1.0",
  "spl-token 4.0.0",
 ]
 
@@ -1787,6 +1787,17 @@ dependencies = [
  "syn 1.0.109",
 ]
 
+[[package]]
+name = "num-derive"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e6a0fd4f737c707bd9086cc16c925f294943eb62eb71499e9fd4cf71f8b9f4e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.31",
+]
+
 [[package]]
 name = "num-integer"
 version = "0.1.45"
@@ -1834,6 +1845,15 @@ dependencies = [
  "num_enum_derive 0.6.1",
 ]
 
+[[package]]
+name = "num_enum"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70bf6736f74634d299d00086f02986875b3c2d924781a6a2cb6c201e73da0ceb"
+dependencies = [
+ "num_enum_derive 0.7.0",
+]
+
 [[package]]
 name = "num_enum_derive"
 version = "0.5.11"
@@ -1855,7 +1875,19 @@ dependencies = [
  "proc-macro-crate 1.3.1",
  "proc-macro2",
  "quote",
- "syn 2.0.29",
+ "syn 2.0.31",
+]
+
+[[package]]
+name = "num_enum_derive"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56ea360eafe1022f7cc56cd7b869ed57330fb2453d0c7831d99b74c65d2f5597"
+dependencies = [
+ "proc-macro-crate 1.3.1",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.31",
 ]
 
 [[package]]
@@ -1924,7 +1956,6 @@ dependencies = [
  "anchor-lang 0.28.0",
  "anchor-spl",
  "mpl-token-metadata",
- "spl-token 4.0.0",
 ]
 
 [[package]]
@@ -1935,7 +1966,7 @@ dependencies = [
  "borsh-derive 0.9.3",
  "mpl-token-metadata",
  "solana-program",
- "spl-associated-token-account 2.0.0",
+ "spl-associated-token-account 2.1.0",
  "spl-token 4.0.0",
 ]
 
@@ -2077,7 +2108,7 @@ dependencies = [
  "borsh 0.10.3",
  "borsh-derive 0.10.3",
  "bytemuck",
- "num-derive",
+ "num-derive 0.3.3",
  "num-traits",
  "pyth-sdk",
  "serde",
@@ -2233,9 +2264,9 @@ dependencies = [
 
 [[package]]
 name = "regex"
-version = "1.9.4"
+version = "1.9.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29"
+checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -2245,9 +2276,9 @@ dependencies = [
 
 [[package]]
 name = "regex-automata"
-version = "0.3.7"
+version = "0.3.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629"
+checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -2387,7 +2418,7 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.29",
+ "syn 2.0.31",
 ]
 
 [[package]]
@@ -2431,7 +2462,7 @@ dependencies = [
  "darling",
  "proc-macro2",
  "quote",
- "syn 2.0.29",
+ "syn 2.0.31",
 ]
 
 [[package]]
@@ -2572,9 +2603,9 @@ checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
 
 [[package]]
 name = "solana-frozen-abi"
-version = "1.16.11"
+version = "1.16.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a5bea7d4af435e9dea1399e89cb1318d733abae64a5d5982cff6391d9c486a5d"
+checksum = "0447b0bb6ab6c6fc0e83bd106618c23d241c4fb8090de715a9811fb993fbfd07"
 dependencies = [
  "ahash 0.8.3",
  "blake3",
@@ -2605,21 +2636,21 @@ dependencies = [
 
 [[package]]
 name = "solana-frozen-abi-macro"
-version = "1.16.11"
+version = "1.16.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86c30e992a5ac91b85c07a64bfb5c70e7bf734cb6494289ca59963d03e788e7d"
+checksum = "9cc86a118888cef8a3878f6dc9c291787cb21ef50cd98e7271f1e0ff548153b8"
 dependencies = [
  "proc-macro2",
  "quote",
  "rustc_version",
- "syn 2.0.29",
+ "syn 2.0.31",
 ]
 
 [[package]]
 name = "solana-logger"
-version = "1.16.11"
+version = "1.16.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dee8421b323150e02409c3588da5796a853bba131df17e9ec1073818158e278f"
+checksum = "8ac77d7fc0144181d4f6c8eb4203bb5fe54d486fa19ccaab7615ccb4b874b0de"
 dependencies = [
  "env_logger",
  "lazy_static",
@@ -2628,9 +2659,9 @@ dependencies = [
 
 [[package]]
 name = "solana-program"
-version = "1.16.11"
+version = "1.16.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad831bc4fa40b061daf6f189c8764e8b1e0e340ea16e189166ef8f6b530c3679"
+checksum = "b3841458623bd80b8291e8991f7353d674bb39656b1db83ec1aa5916a1b6ed7c"
 dependencies = [
  "ark-bn254",
  "ark-ec",
@@ -2659,7 +2690,7 @@ dependencies = [
  "log",
  "memoffset",
  "num-bigint",
- "num-derive",
+ "num-derive 0.3.3",
  "num-traits",
  "parking_lot",
  "rand 0.7.3",
@@ -2683,9 +2714,9 @@ dependencies = [
 
 [[package]]
 name = "solana-sdk"
-version = "1.16.11"
+version = "1.16.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52dcc5c27c8bc49051ea413b75eb1a966e767a46988bd951eaf27552e9ca6e45"
+checksum = "87608d9cbf39d4f72cfb61179c320b3cea7f972671ec74dea99d255fd3a99ca9"
 dependencies = [
  "assert_matches",
  "base64 0.21.3",
@@ -2708,7 +2739,7 @@ dependencies = [
  "libsecp256k1",
  "log",
  "memmap2",
- "num-derive",
+ "num-derive 0.3.3",
  "num-traits",
  "num_enum 0.6.1",
  "pbkdf2 0.11.0",
@@ -2736,22 +2767,22 @@ dependencies = [
 
 [[package]]
 name = "solana-sdk-macro"
-version = "1.16.11"
+version = "1.16.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "691874c5e3ca1cc172421b8266b1bf96bfdb6d7e2685543e7604aa4de2fd07f3"
+checksum = "9077bd44586a902c9949d4e0cf4647ae2723ae2f0feca1e94d8fe9dcd4e2160d"
 dependencies = [
  "bs58 0.4.0",
  "proc-macro2",
  "quote",
  "rustversion",
- "syn 2.0.29",
+ "syn 2.0.31",
 ]
 
 [[package]]
 name = "solana-zk-token-sdk"
-version = "1.16.11"
+version = "1.16.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c69f98436696bc906c366a46394819c79f33731b1148d22080204a0b714c05b3"
+checksum = "c0d498188b9ff5dcef1f356888d128a9b583aee8bfe87bc6746db02b2d492f97"
 dependencies = [
  "aes-gcm-siv",
  "base64 0.21.3",
@@ -2763,7 +2794,7 @@ dependencies = [
  "itertools",
  "lazy_static",
  "merlin",
- "num-derive",
+ "num-derive 0.3.3",
  "num-traits",
  "rand 0.7.3",
  "serde",
@@ -2796,7 +2827,7 @@ checksum = "978dba3bcbe88d0c2c58366c254d9ea41c5f73357e72fc0bdee4d6b5fc99c8f4"
 dependencies = [
  "assert_matches",
  "borsh 0.9.3",
- "num-derive",
+ "num-derive 0.3.3",
  "num-traits",
  "solana-program",
  "spl-token 3.5.0",
@@ -2806,17 +2837,17 @@ dependencies = [
 
 [[package]]
 name = "spl-associated-token-account"
-version = "2.0.0"
+version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02693d7b36cea2b45318b87f22406909879226963296f31f4ebb0fc7f6e1aeb3"
+checksum = "477696277857a7b2c17a6f7f3095e835850ad1c0f11637b5bd2693ca777d8546"
 dependencies = [
  "assert_matches",
  "borsh 0.10.3",
- "num-derive",
+ "num-derive 0.4.0",
  "num-traits",
  "solana-program",
  "spl-token 4.0.0",
- "spl-token-2022 0.7.0",
+ "spl-token-2022 0.8.0",
  "thiserror",
 ]
 
@@ -2850,7 +2881,7 @@ checksum = "b4fa8f409b5c5e0ac571df17c981ae1424b204743daa4428430627d38717caf5"
 dependencies = [
  "quote",
  "spl-discriminator-syn",
- "syn 2.0.29",
+ "syn 2.0.31",
 ]
 
 [[package]]
@@ -2862,7 +2893,7 @@ dependencies = [
  "proc-macro2",
  "quote",
  "solana-program",
- "syn 2.0.29",
+ "syn 2.0.31",
  "thiserror",
 ]
 
@@ -2875,6 +2906,15 @@ dependencies = [
  "solana-program",
 ]
 
+[[package]]
+name = "spl-memo"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0f180b03318c3dbab3ef4e1e4d46d5211ae3c780940dd0a28695aba4b59a75a"
+dependencies = [
+ "solana-program",
+]
+
 [[package]]
 name = "spl-noop"
 version = "0.1.3"
@@ -2884,16 +2924,42 @@ dependencies = [
  "solana-program",
 ]
 
+[[package]]
+name = "spl-pod"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2881dddfca792737c0706fa0175345ab282b1b0879c7d877bad129645737c079"
+dependencies = [
+ "borsh 0.10.3",
+ "bytemuck",
+ "solana-program",
+ "solana-zk-token-sdk",
+ "spl-program-error 0.3.0",
+]
+
 [[package]]
 name = "spl-program-error"
 version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "af92f74cd3b0fdfda59fef4b571a92123e4df0f67cc43f73163975d31118ef82"
 dependencies = [
- "num-derive",
+ "num-derive 0.3.3",
  "num-traits",
  "solana-program",
- "spl-program-error-derive",
+ "spl-program-error-derive 0.2.0",
+ "thiserror",
+]
+
+[[package]]
+name = "spl-program-error"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "249e0318493b6bcf27ae9902600566c689b7dfba9f1bdff5893e92253374e78c"
+dependencies = [
+ "num-derive 0.4.0",
+ "num-traits",
+ "solana-program",
+ "spl-program-error-derive 0.3.0",
  "thiserror",
 ]
 
@@ -2905,7 +2971,19 @@ checksum = "173f3cc506847882189b3a5b67299f617fed2f9730f122dd197b82e1e213dee5"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.29",
+ "syn 2.0.31",
+]
+
+[[package]]
+name = "spl-program-error-derive"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6709c5f41fefb730f2bd8464da741079cf0efd1d0f522e041224b98d431b9b3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "solana-program",
+ "syn 2.0.31",
 ]
 
 [[package]]
@@ -2917,8 +2995,22 @@ dependencies = [
  "bytemuck",
  "solana-program",
  "spl-discriminator",
- "spl-program-error",
- "spl-type-length-value",
+ "spl-program-error 0.2.0",
+ "spl-type-length-value 0.2.0",
+]
+
+[[package]]
+name = "spl-tlv-account-resolution"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7960b1e1a41e4238807fca0865e72a341b668137a3f2ddcd770d04fd1b374c96"
+dependencies = [
+ "bytemuck",
+ "solana-program",
+ "spl-discriminator",
+ "spl-pod",
+ "spl-program-error 0.3.0",
+ "spl-type-length-value 0.3.0",
 ]
 
 [[package]]
@@ -2929,7 +3021,7 @@ checksum = "8e85e168a785e82564160dcb87b2a8e04cee9bfd1f4d488c729d53d6a4bd300d"
 dependencies = [
  "arrayref",
  "bytemuck",
- "num-derive",
+ "num-derive 0.3.3",
  "num-traits",
  "num_enum 0.5.11",
  "solana-program",
@@ -2944,7 +3036,7 @@ checksum = "08459ba1b8f7c1020b4582c4edf0f5c7511a5e099a7a97570c9698d4f2337060"
 dependencies = [
  "arrayref",
  "bytemuck",
- "num-derive",
+ "num-derive 0.3.3",
  "num-traits",
  "num_enum 0.6.1",
  "solana-program",
@@ -2959,12 +3051,12 @@ checksum = "0043b590232c400bad5ee9eb983ced003d15163c4c5d56b090ac6d9a57457b47"
 dependencies = [
  "arrayref",
  "bytemuck",
- "num-derive",
+ "num-derive 0.3.3",
  "num-traits",
  "num_enum 0.5.11",
  "solana-program",
  "solana-zk-token-sdk",
- "spl-memo",
+ "spl-memo 3.0.1",
  "spl-token 3.5.0",
  "thiserror",
 ]
@@ -2977,17 +3069,53 @@ checksum = "b24ac5786a3fefbf59f5606312c61abf87b23154e7a717e5d18216fbea4711db"
 dependencies = [
  "arrayref",
  "bytemuck",
- "num-derive",
+ "num-derive 0.3.3",
  "num-traits",
  "num_enum 0.6.1",
  "solana-program",
  "solana-zk-token-sdk",
- "spl-memo",
+ "spl-memo 3.0.1",
  "spl-token 4.0.0",
- "spl-transfer-hook-interface",
+ "spl-transfer-hook-interface 0.1.0",
  "thiserror",
 ]
 
+[[package]]
+name = "spl-token-2022"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "84fc0c7a763c3f53fa12581d07ed324548a771bb648a1217e4f330b1d0a59331"
+dependencies = [
+ "arrayref",
+ "bytemuck",
+ "num-derive 0.4.0",
+ "num-traits",
+ "num_enum 0.7.0",
+ "solana-program",
+ "solana-zk-token-sdk",
+ "spl-memo 4.0.0",
+ "spl-pod",
+ "spl-token 4.0.0",
+ "spl-token-metadata-interface",
+ "spl-transfer-hook-interface 0.2.0",
+ "spl-type-length-value 0.3.0",
+ "thiserror",
+]
+
+[[package]]
+name = "spl-token-metadata-interface"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c16ce3ba6979645fb7627aa1e435576172dd63088dc7848cb09aa331fa1fe4f"
+dependencies = [
+ "borsh 0.10.3",
+ "solana-program",
+ "spl-discriminator",
+ "spl-pod",
+ "spl-program-error 0.3.0",
+ "spl-type-length-value 0.3.0",
+]
+
 [[package]]
 name = "spl-token-minter"
 version = "0.1.0"
@@ -3005,7 +3133,7 @@ dependencies = [
  "borsh-derive 0.9.3",
  "mpl-token-metadata",
  "solana-program",
- "spl-associated-token-account 2.0.0",
+ "spl-associated-token-account 2.1.0",
  "spl-token 4.0.0",
 ]
 
@@ -3017,16 +3145,32 @@ checksum = "4a2326852adf88716fbac7f54cd6ee2c8a0b5a14ede24db3b4519c4ff13df04b"
 dependencies = [
  "arrayref",
  "bytemuck",
- "num-derive",
+ "num-derive 0.3.3",
  "num-traits",
  "num_enum 0.6.1",
  "solana-program",
  "spl-discriminator",
- "spl-tlv-account-resolution",
- "spl-type-length-value",
+ "spl-tlv-account-resolution 0.2.0",
+ "spl-type-length-value 0.2.0",
  "thiserror",
 ]
 
+[[package]]
+name = "spl-transfer-hook-interface"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7489940049417ae5ce909314bead0670e2a5ea5c82d43ab96dc15c8fcbbccba"
+dependencies = [
+ "arrayref",
+ "bytemuck",
+ "solana-program",
+ "spl-discriminator",
+ "spl-pod",
+ "spl-program-error 0.3.0",
+ "spl-tlv-account-resolution 0.3.0",
+ "spl-type-length-value 0.3.0",
+]
+
 [[package]]
 name = "spl-type-length-value"
 version = "0.2.0"
@@ -3036,7 +3180,20 @@ dependencies = [
  "bytemuck",
  "solana-program",
  "spl-discriminator",
- "spl-program-error",
+ "spl-program-error 0.2.0",
+]
+
+[[package]]
+name = "spl-type-length-value"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a468e6f6371f9c69aae760186ea9f1a01c2908351b06a5e0026d21cfc4d7ecac"
+dependencies = [
+ "bytemuck",
+ "solana-program",
+ "spl-discriminator",
+ "spl-pod",
+ "spl-program-error 0.3.0",
 ]
 
 [[package]]
@@ -3064,9 +3221,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.29"
+version = "2.0.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a"
+checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -3084,22 +3241,22 @@ dependencies = [
 
 [[package]]
 name = "thiserror"
-version = "1.0.47"
+version = "1.0.48"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f"
+checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.47"
+version = "1.0.48"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b"
+checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.29",
+ "syn 2.0.31",
 ]
 
 [[package]]
@@ -3153,7 +3310,7 @@ dependencies = [
  "borsh 0.9.3",
  "borsh-derive 0.9.3",
  "solana-program",
- "spl-associated-token-account 2.0.0",
+ "spl-associated-token-account 2.1.0",
  "spl-token-2022 0.7.0",
 ]
 
@@ -3164,7 +3321,7 @@ dependencies = [
  "borsh 0.9.3",
  "borsh-derive 0.9.3",
  "solana-program",
- "spl-associated-token-account 2.0.0",
+ "spl-associated-token-account 2.1.0",
  "spl-token-2022 0.7.0",
 ]
 
@@ -3175,7 +3332,7 @@ dependencies = [
  "borsh 0.9.3",
  "borsh-derive 0.9.3",
  "solana-program",
- "spl-associated-token-account 2.0.0",
+ "spl-associated-token-account 2.1.0",
  "spl-token-2022 0.7.0",
 ]
 
@@ -3186,7 +3343,7 @@ dependencies = [
  "borsh 0.9.3",
  "borsh-derive 0.9.3",
  "solana-program",
- "spl-associated-token-account 2.0.0",
+ "spl-associated-token-account 2.1.0",
  "spl-token-2022 0.7.0",
 ]
 
@@ -3197,7 +3354,7 @@ dependencies = [
  "borsh 0.9.3",
  "borsh-derive 0.9.3",
  "solana-program",
- "spl-associated-token-account 2.0.0",
+ "spl-associated-token-account 2.1.0",
  "spl-token-2022 0.7.0",
 ]
 
@@ -3260,7 +3417,7 @@ dependencies = [
  "borsh-derive 0.9.3",
  "mpl-token-metadata",
  "solana-program",
- "spl-associated-token-account 2.0.0",
+ "spl-associated-token-account 2.1.0",
  "spl-token 4.0.0",
 ]
 
@@ -3350,7 +3507,7 @@ dependencies = [
  "once_cell",
  "proc-macro2",
  "quote",
- "syn 2.0.29",
+ "syn 2.0.31",
  "wasm-bindgen-shared",
 ]
 
@@ -3372,7 +3529,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.29",
+ "syn 2.0.31",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
@@ -3513,5 +3670,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.29",
+ "syn 2.0.31",
 ]

+ 19 - 4
tokens/create-token/anchor/Anchor.toml

@@ -1,14 +1,29 @@
 [features]
 seeds = false
-[programs.devnet]
-create_token = "5yRmjtx87UJMJF4NEeqjpmgAu7MBJZACW6ksiCYqQxVh"
+skip-lint = false
+
+[programs.localnet]
+create_token = "2B6MrsKB2pVq6W6tY8dJLcnSd3Uv1KE7yRaboBjdQoEX"
 
 [registry]
-url = "https://anchor.projectserum.com"
+url = "https://api.apr.dev"
 
 [provider]
-cluster = "devnet"
+cluster = "localnet"
 wallet = "~/.config/solana/id.json"
 
 [scripts]
 test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
+
+[test]
+startup_wait = 5000
+shutdown_wait = 2000
+
+[test.validator]
+bind_address = "0.0.0.0"
+url = "https://api.mainnet-beta.solana.com"
+ledger = ".anchor/test-ledger"
+rpc_port = 8899
+
+[[test.validator.clone]]
+address = "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"

+ 13 - 13
tokens/create-token/anchor/package.json

@@ -1,15 +1,15 @@
 {
-    "dependencies": {
-        "@metaplex-foundation/mpl-token-metadata": "^2.5.2",
-        "@project-serum/anchor": "^0.24.2"
-    },
-    "devDependencies": {
-        "@types/bn.js": "^5.1.0",
-        "@types/chai": "^4.3.0",
-        "@types/mocha": "^9.0.0",
-        "chai": "^4.3.4",
-        "mocha": "^9.0.3",
-        "ts-mocha": "^10.0.0",
-        "typescript": "^4.3.5"
-    }
+  "dependencies": {
+    "@coral-xyz/anchor": "^0.28.1-beta.2",
+    "@metaplex-foundation/mpl-token-metadata": "^2.5.2"
+  },
+  "devDependencies": {
+    "@types/bn.js": "^5.1.0",
+    "@types/chai": "^4.3.0",
+    "@types/mocha": "^9.0.0",
+    "chai": "^4.3.4",
+    "mocha": "^9.0.3",
+    "ts-mocha": "^10.0.0",
+    "typescript": "^4.3.5"
+  }
 }

+ 2 - 2
tokens/create-token/anchor/programs/create-token/Cargo.toml

@@ -17,5 +17,5 @@ default = []
 
 [dependencies]
 anchor-lang = "0.28.0"
-anchor-spl = "0.28.0"
-mpl-token-metadata = { version = "1.11", features = [ "no-entrypoint" ] }
+anchor-spl = { version = "0.28.0", features = ["metadata"] }
+mpl-token-metadata = { version = "1.13.1", features = ["no-entrypoint"] }

+ 51 - 52
tokens/create-token/anchor/programs/create-token/src/lib.rs

@@ -1,12 +1,15 @@
 #![allow(clippy::result_large_err)]
 
 use {
-    anchor_lang::{prelude::*, solana_program::program::invoke},
-    anchor_spl::token,
-    mpl_token_metadata::instruction as mpl_instruction,
+    anchor_lang::prelude::*,
+    anchor_spl::{
+        metadata::{create_metadata_accounts_v3, CreateMetadataAccountsV3, Metadata},
+        token::{Mint, Token},
+    },
+    mpl_token_metadata::{pda::find_metadata_account, state::DataV2},
 };
 
-declare_id!("5yRmjtx87UJMJF4NEeqjpmgAu7MBJZACW6ksiCYqQxVh");
+declare_id!("2B6MrsKB2pVq6W6tY8dJLcnSd3Uv1KE7yRaboBjdQoEX");
 
 #[program]
 pub mod create_token {
@@ -14,7 +17,7 @@ pub mod create_token {
 
     pub fn create_token_mint(
         ctx: Context<CreateTokenMint>,
-        token_title: String,
+        token_name: String,
         token_symbol: String,
         token_uri: String,
         _token_decimals: u8,
@@ -24,33 +27,34 @@ pub mod create_token {
             "Metadata account address: {}",
             &ctx.accounts.metadata_account.key()
         );
-        invoke(
-            &mpl_instruction::create_metadata_accounts_v3(
-                ctx.accounts.token_metadata_program.key(), // Program ID (the Token Metadata Program)
-                ctx.accounts.metadata_account.key(),       // Metadata account
-                ctx.accounts.mint_account.key(),           // Mint account
-                ctx.accounts.mint_authority.key(),         // Mint authority
-                ctx.accounts.payer.key(),                  // Payer
-                ctx.accounts.mint_authority.key(),         // Update authority
-                token_title,                               // Name
-                token_symbol,                              // Symbol
-                token_uri,                                 // URI
-                None,                                      // Creators
-                0,                                         // Seller fee basis points
-                true,                                      // Update authority is signer
-                false,                                     // Is mutable
-                None,                                      // Collection
-                None,                                      // Uses
-                None,                                      // Collection Details
+
+        // Cross Program Invocation (CPI)
+        // Invoking the create_metadata_account_v3 instruction on the token metadata program
+        create_metadata_accounts_v3(
+            CpiContext::new(
+                ctx.accounts.token_metadata_program.to_account_info(),
+                CreateMetadataAccountsV3 {
+                    metadata: ctx.accounts.metadata_account.to_account_info(),
+                    mint: ctx.accounts.mint_account.to_account_info(),
+                    mint_authority: ctx.accounts.payer.to_account_info(),
+                    update_authority: ctx.accounts.payer.to_account_info(),
+                    payer: ctx.accounts.payer.to_account_info(),
+                    system_program: ctx.accounts.system_program.to_account_info(),
+                    rent: ctx.accounts.rent.to_account_info(),
+                },
             ),
-            &[
-                ctx.accounts.metadata_account.to_account_info(),
-                ctx.accounts.mint_account.to_account_info(),
-                ctx.accounts.mint_authority.to_account_info(),
-                ctx.accounts.payer.to_account_info(),
-                ctx.accounts.mint_authority.to_account_info(),
-                ctx.accounts.rent.to_account_info(),
-            ],
+            DataV2 {
+                name: token_name,
+                symbol: token_symbol,
+                uri: token_uri,
+                seller_fee_basis_points: 0,
+                creators: None,
+                collection: None,
+                uses: None,
+            },
+            false, // Is mutable
+            true,  // Update authority is signer
+            None,  // Collection details
         )?;
 
         msg!("Token mint created successfully.");
@@ -59,34 +63,29 @@ pub mod create_token {
     }
 }
 
-// The macros within the Account Context will create our
-//      Mint account and initialize it as a Mint
-//      We just have to do the metadata
-//
 #[derive(Accounts)]
-#[instruction(
-    token_title: String,
-    token_symbol: String,
-    token_uri: String,
-    token_decimals: u8,
-)]
+#[instruction(_token_decimals: u8)]
 pub struct CreateTokenMint<'info> {
-    /// CHECK: We're about to create this with Metaplex
     #[account(mut)]
+    pub payer: Signer<'info>,
+
+    /// CHECK: Address validated using constraint
+    #[account(
+        mut,
+        address=find_metadata_account(&mint_account.key()).0
+    )]
     pub metadata_account: UncheckedAccount<'info>,
+    // Create new mint account
     #[account(
         init,
         payer = payer,
-        mint::decimals = token_decimals,
-        mint::authority = mint_authority.key(),
+        mint::decimals = _token_decimals,
+        mint::authority = payer.key(),
     )]
-    pub mint_account: Account<'info, token::Mint>,
-    pub mint_authority: SystemAccount<'info>,
-    #[account(mut)]
-    pub payer: Signer<'info>,
-    pub rent: Sysvar<'info, Rent>,
+    pub mint_account: Account<'info, Mint>,
+
+    pub token_metadata_program: Program<'info, Metadata>,
+    pub token_program: Program<'info, Token>,
     pub system_program: Program<'info, System>,
-    pub token_program: Program<'info, token::Token>,
-    /// CHECK: Metaplex will check this
-    pub token_metadata_program: UncheckedAccount<'info>,
+    pub rent: Sysvar<'info, Rent>,
 }

+ 42 - 41
tokens/create-token/anchor/tests/test.ts

@@ -1,90 +1,91 @@
-import { 
-  PROGRAM_ID as TOKEN_METADATA_PROGRAM_ID
-} from '@metaplex-foundation/mpl-token-metadata';
-import * as anchor from "@project-serum/anchor";
+import { PROGRAM_ID as TOKEN_METADATA_PROGRAM_ID } from "@metaplex-foundation/mpl-token-metadata";
+import * as anchor from "@coral-xyz/anchor";
+import { TOKEN_PROGRAM_ID } from "@coral-xyz/anchor/dist/cjs/utils/token";
 import { CreateToken } from "../target/types/create_token";
-
+import {
+  PublicKey,
+  Keypair,
+  SYSVAR_RENT_PUBKEY,
+  SystemProgram,
+} from "@solana/web3.js";
 
 describe("Create Tokens", () => {
-  
   const provider = anchor.AnchorProvider.env();
   anchor.setProvider(provider);
   const payer = provider.wallet as anchor.Wallet;
   const program = anchor.workspace.CreateToken as anchor.Program<CreateToken>;
 
-  const tokenTitle = "Solana Gold";
-  const tokenSymbol = "GOLDSOL";
-  const tokenUri = "https://raw.githubusercontent.com/solana-developers/program-examples/new-examples/tokens/tokens/.assets/spl-token.json";
+  const metadata = {
+    name: "Solana Gold",
+    symbol: "GOLDSOL",
+    uri: "https://raw.githubusercontent.com/solana-developers/program-examples/new-examples/tokens/tokens/.assets/spl-token.json",
+  };
 
   it("Create an SPL Token!", async () => {
+    // Generate new keypair to use as address for mint account.
+    const mintKeypair = new Keypair();
 
-    const mintKeypair: anchor.web3.Keypair = anchor.web3.Keypair.generate();
-
-    const metadataAddress = (await anchor.web3.PublicKey.findProgramAddress(
+    // Derive the PDA of the metadata account for the mint.
+    const [metadataAddress] = PublicKey.findProgramAddressSync(
       [
         Buffer.from("metadata"),
         TOKEN_METADATA_PROGRAM_ID.toBuffer(),
         mintKeypair.publicKey.toBuffer(),
       ],
       TOKEN_METADATA_PROGRAM_ID
-    ))[0];
+    );
 
     // SPL Token default = 9 decimals
-    //
-    const sx = await program.methods.createTokenMint(
-      tokenTitle, tokenSymbol, tokenUri, 9
-    )
+    const transactionSignature = await program.methods
+      .createTokenMint(metadata.name, metadata.symbol, metadata.uri, 9)
       .accounts({
+        payer: payer.publicKey,
         metadataAccount: metadataAddress,
         mintAccount: mintKeypair.publicKey,
-        mintAuthority: payer.publicKey,
-        payer: payer.publicKey,
-        rent: anchor.web3.SYSVAR_RENT_PUBKEY,
-        systemProgram: anchor.web3.SystemProgram.programId,
-        tokenProgram: anchor.utils.token.TOKEN_PROGRAM_ID,
+        rent: SYSVAR_RENT_PUBKEY,
+        systemProgram: SystemProgram.programId,
+        tokenProgram: TOKEN_PROGRAM_ID,
         tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID,
       })
-      .signers([mintKeypair, payer.payer])
+      .signers([mintKeypair])
       .rpc();
 
     console.log("Success!");
-        console.log(`   Mint Address: ${mintKeypair.publicKey}`);
-        console.log(`   Tx Signature: ${sx}`);
+    console.log(`   Mint Address: ${mintKeypair.publicKey}`);
+    console.log(`   Transaction Signature: ${transactionSignature}`);
   });
 
   it("Create an NFT!", async () => {
-    
-    const mintKeypair: anchor.web3.Keypair = anchor.web3.Keypair.generate();
+    // Generate new keypair to use as address for mint account.
+    const mintKeypair = new Keypair();
 
-    const metadataAddress = (await anchor.web3.PublicKey.findProgramAddress(
+    // Derive the PDA of the metadata account for the mint.
+    const [metadataAddress] = PublicKey.findProgramAddressSync(
       [
         Buffer.from("metadata"),
         TOKEN_METADATA_PROGRAM_ID.toBuffer(),
         mintKeypair.publicKey.toBuffer(),
       ],
       TOKEN_METADATA_PROGRAM_ID
-    ))[0];
+    );
 
     // NFT default = 0 decimals
-    //
-    const sx = await program.methods.createTokenMint(
-      tokenTitle, tokenSymbol, tokenUri, 0
-    )
+    const transactionSignature = await program.methods
+      .createTokenMint(metadata.name, metadata.symbol, metadata.uri, 0)
       .accounts({
+        payer: payer.publicKey,
         metadataAccount: metadataAddress,
         mintAccount: mintKeypair.publicKey,
-        mintAuthority: payer.publicKey,
-        payer: payer.publicKey,
-        rent: anchor.web3.SYSVAR_RENT_PUBKEY,
-        systemProgram: anchor.web3.SystemProgram.programId,
-        tokenProgram: anchor.utils.token.TOKEN_PROGRAM_ID,
+        rent: SYSVAR_RENT_PUBKEY,
+        systemProgram: SystemProgram.programId,
+        tokenProgram: TOKEN_PROGRAM_ID,
         tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID,
       })
-      .signers([mintKeypair, payer.payer])
+      .signers([mintKeypair])
       .rpc();
 
     console.log("Success!");
-        console.log(`   Mint Address: ${mintKeypair.publicKey}`);
-        console.log(`   Tx Signature: ${sx}`);
+    console.log(`   Mint Address: ${mintKeypair.publicKey}`);
+    console.log(`   Transaction Signature: ${transactionSignature}`);
   });
 });

+ 17 - 5
tokens/nft-minter/anchor/Anchor.toml

@@ -1,14 +1,26 @@
 [features]
 seeds = false
-[programs.devnet]
-nft_minter = "A6itasS5iqANkC9yrzP1HJPBnJxj9tC8G5TmJzQGogGG"
+skip-lint = false
 
-[registry]
-url = "https://anchor.projectserum.com"
+[programs.localnet]
+nft_minter = "3qHNM98iLTaQtwmj2NkViXnHZQjNBS5PTHT2AuPxHXYN"
 
 [provider]
-cluster = "devnet"
+cluster = "localnet"
 wallet = "~/.config/solana/id.json"
 
 [scripts]
 test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
+
+[test]
+startup_wait = 5000
+shutdown_wait = 2000
+
+[test.validator]
+bind_address = "0.0.0.0"
+url = "https://api.mainnet-beta.solana.com"
+ledger = ".anchor/test-ledger"
+rpc_port = 8899
+
+[[test.validator.clone]]
+address = "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"

+ 1 - 3
tokens/nft-minter/anchor/Cargo.toml

@@ -1,7 +1,5 @@
 [workspace]
-members = [
-    "programs/*"
-]
+members = ["programs/*"]
 
 [profile.release]
 overflow-checks = true

+ 14 - 13
tokens/nft-minter/anchor/package.json

@@ -1,15 +1,16 @@
 {
-    "dependencies": {
-        "@metaplex-foundation/mpl-token-metadata": "^2.5.2",
-        "@project-serum/anchor": "^0.24.2"
-    },
-    "devDependencies": {
-        "@types/bn.js": "^5.1.0",
-        "@types/chai": "^4.3.0",
-        "@types/mocha": "^9.0.0",
-        "chai": "^4.3.4",
-        "mocha": "^9.0.3",
-        "ts-mocha": "^10.0.0",
-        "typescript": "^4.3.5"
-    }
+  "dependencies": {
+    "@coral-xyz/anchor": "^0.28.1-beta.2",
+    "@metaplex-foundation/mpl-token-metadata": "^2.5.2",
+    "@solana/spl-token": "^0.3.8"
+  },
+  "devDependencies": {
+    "@types/bn.js": "^5.1.0",
+    "@types/chai": "^4.3.0",
+    "@types/mocha": "^9.0.0",
+    "chai": "^4.3.4",
+    "mocha": "^9.0.3",
+    "ts-mocha": "^10.0.0",
+    "typescript": "^4.3.5"
+  }
 }

+ 3 - 4
tokens/nft-minter/anchor/programs/nft-minter/Cargo.toml

@@ -16,7 +16,6 @@ cpi = ["no-entrypoint"]
 default = []
 
 [dependencies]
-anchor-lang = { version = "0.28.0", features=["init-if-needed"] }
-anchor-spl = "0.28.0"
-mpl-token-metadata = { version = "1.11" }
-spl-token = "4.0.0"
+anchor-lang = { version = "0.28.0", features = ["init-if-needed"] }
+anchor-spl = { version = "0.28.0", features = ["metadata"] }
+mpl-token-metadata = { version = "1.13.1", features = ["no-entrypoint"] }

+ 0 - 73
tokens/nft-minter/anchor/programs/nft-minter/src/instructions/create.rs

@@ -1,73 +0,0 @@
-use {
-    anchor_lang::{prelude::*, solana_program::program::invoke},
-    anchor_spl::token,
-    mpl_token_metadata::instruction as mpl_instruction,
-};
-
-pub fn create_token(
-    ctx: Context<CreateToken>,
-    nft_title: String,
-    nft_symbol: String,
-    nft_uri: String,
-) -> Result<()> {
-    msg!("Creating metadata account...");
-    msg!(
-        "Metadata account address: {}",
-        &ctx.accounts.metadata_account.key()
-    );
-    invoke(
-        &mpl_instruction::create_metadata_accounts_v3(
-            ctx.accounts.token_metadata_program.key(), // Program ID (the Token Metadata Program)
-            ctx.accounts.metadata_account.key(),       // Metadata account
-            ctx.accounts.mint_account.key(),           // Mint account
-            ctx.accounts.mint_authority.key(),         // Mint authority
-            ctx.accounts.payer.key(),                  // Payer
-            ctx.accounts.mint_authority.key(),         // Update authority
-            nft_title,                                 // Name
-            nft_symbol,                                // Symbol
-            nft_uri,                                   // URI
-            None,                                      // Creators
-            0,                                         // Seller fee basis points
-            true,                                      // Update authority is signer
-            false,                                     // Is mutable
-            None,                                      // Collection
-            None,                                      // Uses
-            None,                                      // Collection Details
-        ),
-        &[
-            ctx.accounts.metadata_account.to_account_info(),
-            ctx.accounts.mint_account.to_account_info(),
-            ctx.accounts.mint_authority.to_account_info(),
-            ctx.accounts.payer.to_account_info(),
-            ctx.accounts.mint_authority.to_account_info(),
-            ctx.accounts.rent.to_account_info(),
-        ],
-    )?;
-
-    msg!("NFT created successfully.");
-
-    Ok(())
-}
-
-#[derive(Accounts)]
-pub struct CreateToken<'info> {
-    /// CHECK: We're about to create this with Metaplex
-    #[account(mut)]
-    pub metadata_account: UncheckedAccount<'info>,
-    #[account(
-        init,
-        payer = payer,
-        mint::decimals = 0,
-        mint::authority = mint_authority.key(),
-        mint::freeze_authority = mint_authority.key(),
-    )]
-    pub mint_account: Account<'info, token::Mint>,
-    pub mint_authority: SystemAccount<'info>,
-    #[account(mut)]
-    pub payer: Signer<'info>,
-    pub rent: Sysvar<'info, Rent>,
-    pub system_program: Program<'info, System>,
-    pub token_program: Program<'info, token::Token>,
-    /// CHECK: Metaplex will check this
-    pub token_metadata_program: UncheckedAccount<'info>,
-}

+ 0 - 126
tokens/nft-minter/anchor/programs/nft-minter/src/instructions/mint.rs

@@ -1,126 +0,0 @@
-use {
-    anchor_lang::{prelude::*, solana_program::program::invoke},
-    anchor_spl::{associated_token, token},
-    mpl_token_metadata::instruction as mpl_instruction,
-    // spl_token::instruction::AuthorityType,
-};
-
-pub fn mint_to(ctx: Context<MintTo>) -> Result<()> {
-    // Mint the NFT to the user's wallet
-    //
-    msg!("Minting NFT to associated token account...");
-    msg!(
-        "Mint: {}",
-        &ctx.accounts.mint_account.to_account_info().key()
-    );
-    msg!(
-        "Token Address: {}",
-        &ctx.accounts.associated_token_account.key()
-    );
-    token::mint_to(
-        CpiContext::new(
-            ctx.accounts.token_program.to_account_info(),
-            token::MintTo {
-                mint: ctx.accounts.mint_account.to_account_info(),
-                to: ctx.accounts.associated_token_account.to_account_info(),
-                authority: ctx.accounts.mint_authority.to_account_info(),
-            },
-        ),
-        1,
-    )?;
-
-    // We can make this a Limited Edition NFT through Metaplex,
-    //      which will disable minting by setting the Mint & Freeze Authorities to the
-    //      Edition Account.
-    //
-    msg!("Creating edition account...");
-    msg!(
-        "Edition account address: {}",
-        ctx.accounts.edition_account.key()
-    );
-    invoke(
-        &mpl_instruction::create_master_edition_v3(
-            ctx.accounts.token_metadata_program.key(), // Program ID
-            ctx.accounts.edition_account.key(),        // Edition
-            ctx.accounts.mint_account.key(),           // Mint
-            ctx.accounts.mint_authority.key(),         // Update Authority
-            ctx.accounts.mint_authority.key(),         // Mint Authority
-            ctx.accounts.metadata_account.key(),       // Metadata
-            ctx.accounts.payer.key(),                  // Payer
-            Some(1),                                   // Max Supply
-        ),
-        &[
-            ctx.accounts.edition_account.to_account_info(),
-            ctx.accounts.metadata_account.to_account_info(),
-            ctx.accounts.mint_account.to_account_info(),
-            ctx.accounts.mint_authority.to_account_info(),
-            ctx.accounts.payer.to_account_info(),
-            ctx.accounts.token_metadata_program.to_account_info(),
-            ctx.accounts.rent.to_account_info(),
-        ],
-    )?;
-
-    // If we don't use Metaplex Editions, we must disable minting manually
-    // -------------------------------------------------------------------
-    //
-    // msg!("Disabling future minting of this NFT...");
-    // token::set_authority(
-    //     CpiContext::new(
-    //         ctx.accounts.token_program.to_account_info(),
-    //         token::SetAuthority {
-    //             current_authority: ctx.accounts.payer.to_account_info(),
-    //             account_or_mint: ctx.accounts.mint_account.to_account_info(),
-    //         },
-    //     ),
-    //     AuthorityType::MintTokens,
-    //     None,
-    // )?;
-    // token::set_authority(
-    //     CpiContext::new(
-    //         ctx.accounts.token_program.to_account_info(),
-    //         token::SetAuthority {
-    //             current_authority: ctx.accounts.payer.to_account_info(),
-    //             account_or_mint: ctx.accounts.mint_account.to_account_info(),
-    //         },
-    //     ),
-    //     AuthorityType::FreezeAccount,
-    //     None,
-    // )?;
-
-    msg!("NFT minted successfully.");
-
-    Ok(())
-}
-
-#[derive(Accounts)]
-pub struct MintTo<'info> {
-    /// CHECK: Metaplex will check this
-    #[account(mut)]
-    pub edition_account: UncheckedAccount<'info>,
-    /// CHECK: Metaplex will check this
-    #[account(mut)]
-    pub metadata_account: UncheckedAccount<'info>,
-    #[account(
-        mut,
-        mint::decimals = 0,
-        mint::authority = mint_authority.key(),
-        mint::freeze_authority = mint_authority.key(),
-    )]
-    pub mint_account: Account<'info, token::Mint>,
-    pub mint_authority: SystemAccount<'info>,
-    #[account(
-        init_if_needed,
-        payer = payer,
-        associated_token::mint = mint_account,
-        associated_token::authority = payer,
-    )]
-    pub associated_token_account: Account<'info, token::TokenAccount>,
-    #[account(mut)]
-    pub payer: Signer<'info>,
-    pub rent: Sysvar<'info, Rent>,
-    pub system_program: Program<'info, System>,
-    pub token_program: Program<'info, token::Token>,
-    pub associated_token_program: Program<'info, associated_token::AssociatedToken>,
-    /// CHECK: Metaplex will check this
-    pub token_metadata_program: UncheckedAccount<'info>,
-}

+ 132 - 12
tokens/nft-minter/anchor/programs/nft-minter/src/lib.rs

@@ -1,27 +1,147 @@
 #![allow(clippy::result_large_err)]
 
-use anchor_lang::prelude::*;
+use {
+    anchor_lang::prelude::*,
+    anchor_spl::{
+        associated_token::AssociatedToken,
+        metadata::{
+            create_master_edition_v3, create_metadata_accounts_v3, CreateMasterEditionV3,
+            CreateMetadataAccountsV3, Metadata,
+        },
+        token::{mint_to, Mint, MintTo, Token, TokenAccount},
+    },
+    mpl_token_metadata::{
+        pda::{find_master_edition_account, find_metadata_account},
+        state::DataV2,
+    },
+};
 
-pub mod instructions;
-
-use instructions::*;
-
-declare_id!("JBBC7GafzY2CGkfnNEF8vCiwF3qSY31MYm15Q5iaEqXN");
+declare_id!("3qHNM98iLTaQtwmj2NkViXnHZQjNBS5PTHT2AuPxHXYN");
 
 #[program]
 pub mod nft_minter {
     use super::*;
 
-    pub fn create_token(
+    pub fn mint_nft(
         ctx: Context<CreateToken>,
-        nft_title: String,
+        nft_name: String,
         nft_symbol: String,
         nft_uri: String,
     ) -> Result<()> {
-        create::create_token(ctx, nft_title, nft_symbol, nft_uri)
-    }
+        msg!("Minting Token");
+        // Cross Program Invocation (CPI)
+        // Invoking the mint_to instruction on the token program
+        mint_to(
+            CpiContext::new(
+                ctx.accounts.token_program.to_account_info(),
+                MintTo {
+                    mint: ctx.accounts.mint_account.to_account_info(),
+                    to: ctx.accounts.associated_token_account.to_account_info(),
+                    authority: ctx.accounts.payer.to_account_info(),
+                },
+            ),
+            1,
+        )?;
+
+        msg!("Creating metadata account");
+        // Cross Program Invocation (CPI)
+        // Invoking the create_metadata_account_v3 instruction on the token metadata program
+        create_metadata_accounts_v3(
+            CpiContext::new(
+                ctx.accounts.token_metadata_program.to_account_info(),
+                CreateMetadataAccountsV3 {
+                    metadata: ctx.accounts.metadata_account.to_account_info(),
+                    mint: ctx.accounts.mint_account.to_account_info(),
+                    mint_authority: ctx.accounts.payer.to_account_info(),
+                    update_authority: ctx.accounts.payer.to_account_info(),
+                    payer: ctx.accounts.payer.to_account_info(),
+                    system_program: ctx.accounts.system_program.to_account_info(),
+                    rent: ctx.accounts.rent.to_account_info(),
+                },
+            ),
+            DataV2 {
+                name: nft_name,
+                symbol: nft_symbol,
+                uri: nft_uri,
+                seller_fee_basis_points: 0,
+                creators: None,
+                collection: None,
+                uses: None,
+            },
+            false, // Is mutable
+            true,  // Update authority is signer
+            None,  // Collection details
+        )?;
 
-    pub fn mint_to(ctx: Context<MintTo>) -> Result<()> {
-        mint::mint_to(ctx)
+        msg!("Creating master edition account");
+        // Cross Program Invocation (CPI)
+        // Invoking the create_master_edition_v3 instruction on the token metadata program
+        create_master_edition_v3(
+            CpiContext::new(
+                ctx.accounts.token_metadata_program.to_account_info(),
+                CreateMasterEditionV3 {
+                    edition: ctx.accounts.edition_account.to_account_info(),
+                    mint: ctx.accounts.mint_account.to_account_info(),
+                    update_authority: ctx.accounts.payer.to_account_info(),
+                    mint_authority: ctx.accounts.payer.to_account_info(),
+                    payer: ctx.accounts.payer.to_account_info(),
+                    metadata: ctx.accounts.metadata_account.to_account_info(),
+                    token_program: ctx.accounts.token_program.to_account_info(),
+                    system_program: ctx.accounts.system_program.to_account_info(),
+                    rent: ctx.accounts.rent.to_account_info(),
+                },
+            ),
+            None, // Max Supply
+        )?;
+
+        msg!("NFT minted successfully.");
+
+        Ok(())
     }
 }
+
+#[derive(Accounts)]
+pub struct CreateToken<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+
+    /// CHECK: Address validated using constraint
+    #[account(
+        mut,
+        address=find_metadata_account(&mint_account.key()).0
+    )]
+    pub metadata_account: UncheckedAccount<'info>,
+
+    /// CHECK: Address validated using constraint
+    #[account(
+        mut,
+        address=find_master_edition_account(&mint_account.key()).0
+    )]
+    pub edition_account: UncheckedAccount<'info>,
+
+    // Create new mint account, NFTs have 0 decimals
+    #[account(
+        init,
+        payer = payer,
+        mint::decimals = 0,
+        mint::authority = payer.key(),
+        mint::freeze_authority = payer.key(),
+    )]
+    pub mint_account: Account<'info, Mint>,
+
+    // Create associated token account, if needed
+    // This is the account that will hold the NFT
+    #[account(
+        init_if_needed,
+        payer = payer,
+        associated_token::mint = mint_account,
+        associated_token::authority = payer,
+    )]
+    pub associated_token_account: Account<'info, TokenAccount>,
+
+    pub token_program: Program<'info, Token>,
+    pub token_metadata_program: Program<'info, Metadata>,
+    pub associated_token_program: Program<'info, AssociatedToken>,
+    pub system_program: Program<'info, System>,
+    pub rent: Sysvar<'info, Rent>,
+}

+ 59 - 79
tokens/nft-minter/anchor/tests/test.ts

@@ -1,101 +1,81 @@
-import { 
-  PROGRAM_ID as TOKEN_METADATA_PROGRAM_ID
-} from '@metaplex-foundation/mpl-token-metadata';
-import * as anchor from "@project-serum/anchor";
-import { ASSOCIATED_PROGRAM_ID } from '@project-serum/anchor/dist/cjs/utils/token';
+import { PROGRAM_ID as TOKEN_METADATA_PROGRAM_ID } from "@metaplex-foundation/mpl-token-metadata";
+import * as anchor from "@coral-xyz/anchor";
 import { NftMinter } from "../target/types/nft_minter";
-
+import {
+  Keypair,
+  PublicKey,
+  SYSVAR_RENT_PUBKEY,
+  SystemProgram,
+} from "@solana/web3.js";
+import {
+  getAssociatedTokenAddressSync,
+  ASSOCIATED_TOKEN_PROGRAM_ID,
+  TOKEN_PROGRAM_ID,
+} from "@solana/spl-token";
 
 describe("NFT Minter", () => {
-  
   const provider = anchor.AnchorProvider.env();
   anchor.setProvider(provider);
   const payer = provider.wallet as anchor.Wallet;
   const program = anchor.workspace.NftMinter as anchor.Program<NftMinter>;
 
-  const nftTitle = "Homer NFT";
-  const nftSymbol = "HOMR";
-  const nftUri = "https://raw.githubusercontent.com/solana-developers/program-examples/new-examples/tokens/tokens/.assets/nft.json";
+  // The metadata for our NFT
+  const metadata = {
+    name: "Homer NFT",
+    symbol: "HOMR",
+    uri: "https://raw.githubusercontent.com/solana-developers/program-examples/new-examples/tokens/tokens/.assets/nft.json",
+  };
 
-  const mintKeypair: anchor.web3.Keypair = anchor.web3.Keypair.generate();
-  
   it("Create an NFT!", async () => {
+    // Generate a keypair to use as the address of our mint account
+    const mintKeypair = new Keypair();
 
-    const metadataAddress = (anchor.web3.PublicKey.findProgramAddressSync(
-        [
-          Buffer.from("metadata"),
-          TOKEN_METADATA_PROGRAM_ID.toBuffer(),
-          mintKeypair.publicKey.toBuffer(),
-        ],
-        TOKEN_METADATA_PROGRAM_ID
-    ))[0];
-
-    const sx = await program.methods.createToken(
-      nftTitle, nftSymbol, nftUri
-    )
-      .accounts({
-        metadataAccount: metadataAddress,
-        mintAccount: mintKeypair.publicKey,
-        mintAuthority: payer.publicKey,
-        payer: payer.publicKey,
-        rent: anchor.web3.SYSVAR_RENT_PUBKEY,
-        systemProgram: anchor.web3.SystemProgram.programId,
-        tokenProgram: anchor.utils.token.TOKEN_PROGRAM_ID,
-        tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID,
-      })
-      .signers([mintKeypair, payer.payer])
-      .rpc();
-
-    console.log("Success!");
-        console.log(`   Mint Address: ${mintKeypair.publicKey}`);
-        console.log(`   Tx Signature: ${sx}`);
-  });
-
-  it("Mint the NFT to your wallet!", async () => {
-
-    const metadataAddress = (anchor.web3.PublicKey.findProgramAddressSync(
-        [
-          Buffer.from("metadata"),
-          TOKEN_METADATA_PROGRAM_ID.toBuffer(),
-          mintKeypair.publicKey.toBuffer(),
-        ],
-        TOKEN_METADATA_PROGRAM_ID
-    ))[0];
+    // Derive the PDA of the metadata account for the mint.
+    const [metadataAddress] = PublicKey.findProgramAddressSync(
+      [
+        Buffer.from("metadata"),
+        TOKEN_METADATA_PROGRAM_ID.toBuffer(),
+        mintKeypair.publicKey.toBuffer(),
+      ],
+      TOKEN_METADATA_PROGRAM_ID
+    );
 
-    const editionAddress = (anchor.web3.PublicKey.findProgramAddressSync(
-        [
-          Buffer.from("metadata"),
-          TOKEN_METADATA_PROGRAM_ID.toBuffer(),
-          mintKeypair.publicKey.toBuffer(),
-          Buffer.from("edition"),
-        ],
-        TOKEN_METADATA_PROGRAM_ID
-    ))[0];
+    // Derive the PDA of the master edition account for the mint.
+    const [editionAddress] = PublicKey.findProgramAddressSync(
+      [
+        Buffer.from("metadata"),
+        TOKEN_METADATA_PROGRAM_ID.toBuffer(),
+        mintKeypair.publicKey.toBuffer(),
+        Buffer.from("edition"),
+      ],
+      TOKEN_METADATA_PROGRAM_ID
+    );
 
-    const associatedTokenAccountAddress = await anchor.utils.token.associatedAddress({
-      mint: mintKeypair.publicKey,
-      owner: payer.publicKey,
-    });
+    // Derive the associated token address account for the mint and payer.
+    const associatedTokenAccountAddress = getAssociatedTokenAddressSync(
+      mintKeypair.publicKey,
+      payer.publicKey
+    );
 
-    const sx = await program.methods.mintTo()
+    const transactionSignature = await program.methods
+      .mintNft(metadata.name, metadata.symbol, metadata.uri)
       .accounts({
-        associatedTokenAccount: associatedTokenAccountAddress,
-        editionAccount: editionAddress,
+        payer: payer.publicKey,
         metadataAccount: metadataAddress,
+        editionAccount: editionAddress,
         mintAccount: mintKeypair.publicKey,
-        mintAuthority: payer.publicKey,
-        payer: payer.publicKey,
-        rent: anchor.web3.SYSVAR_RENT_PUBKEY,
-        systemProgram: anchor.web3.SystemProgram.programId,
-        tokenProgram: anchor.utils.token.TOKEN_PROGRAM_ID,
-        associatedTokenProgram: ASSOCIATED_PROGRAM_ID,
+        associatedTokenAccount: associatedTokenAccountAddress,
+        tokenProgram: TOKEN_PROGRAM_ID,
+        associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
         tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID,
+        systemProgram: SystemProgram.programId,
+        rent: SYSVAR_RENT_PUBKEY,
       })
-      .signers([payer.payer])
-      .rpc();
+      .signers([mintKeypair])
+      .rpc({ skipPreflight: true });
 
-      console.log("Success!");
-      console.log(`   ATA Address: ${associatedTokenAccountAddress}`);
-      console.log(`   Tx Signature: ${sx}`);
+    console.log("Success!");
+    console.log(`   Mint Address: ${mintKeypair.publicKey}`);
+    console.log(`   Transaction Signature: ${transactionSignature}`);
   });
 });

+ 19 - 4
tokens/pda-mint-authority/anchor/Anchor.toml

@@ -1,14 +1,29 @@
 [features]
 seeds = false
-[programs.devnet]
-nft_minter = "DU92SqPvfiDVicA4ah3E9wP9Ci7ASog1VmJhZrYU3Hyk"
+skip-lint = false
+
+[programs.localnet]
+token_minter = "A5gNtapBvMLD6i7D2t3SSyJeFtBdfb6ibvZu1hoBLzCo"
 
 [registry]
-url = "https://anchor.projectserum.com"
+url = "https://api.apr.dev"
 
 [provider]
-cluster = "devnet"
+cluster = "Localnet"
 wallet = "~/.config/solana/id.json"
 
 [scripts]
 test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
+
+[test]
+startup_wait = 5000
+shutdown_wait = 2000
+
+[test.validator]
+bind_address = "0.0.0.0"
+url = "https://api.mainnet-beta.solana.com"
+ledger = ".anchor/test-ledger"
+rpc_port = 8899
+
+[[test.validator.clone]]
+address = "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"

+ 1 - 3
tokens/pda-mint-authority/anchor/Cargo.toml

@@ -1,7 +1,5 @@
 [workspace]
-members = [
-    "programs/*"
-]
+members = ["programs/*"]
 
 [profile.release]
 overflow-checks = true

+ 14 - 13
tokens/pda-mint-authority/anchor/package.json

@@ -1,15 +1,16 @@
 {
-    "dependencies": {
-        "@metaplex-foundation/mpl-token-metadata": "^2.5.2",
-        "@project-serum/anchor": "^0.24.2"
-    },
-    "devDependencies": {
-        "@types/bn.js": "^5.1.0",
-        "@types/chai": "^4.3.0",
-        "@types/mocha": "^9.0.0",
-        "chai": "^4.3.4",
-        "mocha": "^9.0.3",
-        "ts-mocha": "^10.0.0",
-        "typescript": "^4.3.5"
-    }
+  "dependencies": {
+    "@coral-xyz/anchor": "^0.28.1-beta.2",
+    "@metaplex-foundation/mpl-token-metadata": "^2.5.2",
+    "@solana/spl-token": "^0.3.8"
+  },
+  "devDependencies": {
+    "@types/bn.js": "^5.1.0",
+    "@types/chai": "^4.3.0",
+    "@types/mocha": "^9.0.0",
+    "chai": "^4.3.4",
+    "mocha": "^9.0.3",
+    "ts-mocha": "^10.0.0",
+    "typescript": "^4.3.5"
+  }
 }

+ 0 - 82
tokens/pda-mint-authority/anchor/programs/nft-minter/src/instructions/create.rs

@@ -1,82 +0,0 @@
-use {
-    anchor_lang::{prelude::*, solana_program::program::invoke_signed},
-    anchor_spl::token,
-    mpl_token_metadata::instruction as mpl_instruction,
-};
-
-use crate::state::MintAuthorityPda;
-
-pub fn create_token(
-    ctx: Context<CreateToken>,
-    nft_title: String,
-    nft_symbol: String,
-    nft_uri: String,
-) -> Result<()> {
-    let bump = ctx.accounts.mint_authority.bump;
-    msg!("Creating metadata account...");
-    msg!(
-        "Metadata account address: {}",
-        &ctx.accounts.metadata_account.key()
-    );
-    invoke_signed(
-        &mpl_instruction::create_metadata_accounts_v3(
-            ctx.accounts.token_metadata_program.key(), // Program ID (the Token Metadata Program)
-            ctx.accounts.metadata_account.key(),       // Metadata account
-            ctx.accounts.mint_account.key(),           // Mint account
-            ctx.accounts.mint_authority.key(),         // Mint authority
-            ctx.accounts.payer.key(),                  // Payer
-            ctx.accounts.mint_authority.key(),         // Update authority
-            nft_title,                                 // Name
-            nft_symbol,                                // Symbol
-            nft_uri,                                   // URI
-            None,                                      // Creators
-            0,                                         // Seller fee basis points
-            true,                                      // Update authority is signer
-            false,                                     // Is mutable
-            None,                                      // Collection
-            None,                                      // Uses
-            None,                                      // Collection Details
-        ),
-        &[
-            ctx.accounts.metadata_account.to_account_info(),
-            ctx.accounts.mint_account.to_account_info(),
-            ctx.accounts.mint_authority.to_account_info(),
-            ctx.accounts.payer.to_account_info(),
-            ctx.accounts.mint_authority.to_account_info(),
-            ctx.accounts.rent.to_account_info(),
-        ],
-        &[&[MintAuthorityPda::SEED_PREFIX.as_bytes(), &[bump]]],
-    )?;
-
-    msg!("NFT created successfully.");
-
-    Ok(())
-}
-
-#[derive(Accounts)]
-pub struct CreateToken<'info> {
-    /// CHECK: We're about to create this with Metaplex
-    #[account(mut)]
-    pub metadata_account: UncheckedAccount<'info>,
-    #[account(
-        init,
-        payer = payer,
-        mint::decimals = 0,
-        mint::authority = mint_authority.key(),
-        mint::freeze_authority = mint_authority.key(),
-    )]
-    pub mint_account: Account<'info, token::Mint>,
-    #[account(
-        mut,
-        seeds = [ MintAuthorityPda::SEED_PREFIX.as_bytes() ],
-        bump = mint_authority.bump,
-    )]
-    pub mint_authority: Account<'info, MintAuthorityPda>,
-    #[account(mut)]
-    pub payer: Signer<'info>,
-    pub rent: Sysvar<'info, Rent>,
-    pub system_program: Program<'info, System>,
-    pub token_program: Program<'info, token::Token>,
-    /// CHECK: Metaplex will check this
-    pub token_metadata_program: UncheckedAccount<'info>,
-}

+ 0 - 25
tokens/pda-mint-authority/anchor/programs/nft-minter/src/instructions/init.rs

@@ -1,25 +0,0 @@
-use anchor_lang::prelude::*;
-
-use crate::state::MintAuthorityPda;
-
-pub fn init(ctx: Context<Init>) -> Result<()> {
-    ctx.accounts.mint_authority.set_inner(MintAuthorityPda {
-        bump: *ctx.bumps.get("mint_authority").expect("Bump not found."),
-    });
-    Ok(())
-}
-
-#[derive(Accounts)]
-pub struct Init<'info> {
-    #[account(
-        init,
-        payer = payer,
-        space = MintAuthorityPda::SIZE,
-        seeds = [ MintAuthorityPda::SEED_PREFIX.as_bytes() ],
-        bump
-    )]
-    pub mint_authority: Account<'info, MintAuthorityPda>,
-    #[account(mut)]
-    pub payer: Signer<'info>,
-    pub system_program: Program<'info, System>,
-}

+ 0 - 138
tokens/pda-mint-authority/anchor/programs/nft-minter/src/instructions/mint.rs

@@ -1,138 +0,0 @@
-use {
-    anchor_lang::{prelude::*, solana_program::program::invoke_signed},
-    anchor_spl::{associated_token, token},
-    mpl_token_metadata::instruction as mpl_instruction,
-    // spl_token::instruction::AuthorityType,
-};
-
-use crate::state::MintAuthorityPda;
-
-pub fn mint_to(ctx: Context<MintTo>) -> Result<()> {
-    let bump = ctx.accounts.mint_authority.bump;
-    // Mint the NFT to the user's wallet
-    //
-    msg!("Minting NFT to associated token account...");
-    msg!(
-        "Mint: {}",
-        &ctx.accounts.mint_account.to_account_info().key()
-    );
-    msg!(
-        "Token Address: {}",
-        &ctx.accounts.associated_token_account.key()
-    );
-    token::mint_to(
-        CpiContext::new_with_signer(
-            ctx.accounts.token_program.to_account_info(),
-            token::MintTo {
-                mint: ctx.accounts.mint_account.to_account_info(),
-                to: ctx.accounts.associated_token_account.to_account_info(),
-                authority: ctx.accounts.mint_authority.to_account_info(),
-            },
-            &[&[MintAuthorityPda::SEED_PREFIX.as_bytes(), &[bump]]],
-        ),
-        1,
-    )?;
-
-    // We can make this a Limited Edition NFT through Metaplex,
-    //      which will disable minting by setting the Mint & Freeze Authorities to the
-    //      Edition Account.
-    //
-    msg!("Creating edition account...");
-    msg!(
-        "Edition account address: {}",
-        ctx.accounts.edition_account.key()
-    );
-    invoke_signed(
-        &mpl_instruction::create_master_edition_v3(
-            ctx.accounts.token_metadata_program.key(), // Program ID
-            ctx.accounts.edition_account.key(),        // Edition
-            ctx.accounts.mint_account.key(),           // Mint
-            ctx.accounts.mint_authority.key(),         // Update Authority
-            ctx.accounts.mint_authority.key(),         // Mint Authority
-            ctx.accounts.metadata_account.key(),       // Metadata
-            ctx.accounts.payer.key(),                  // Payer
-            Some(1),                                   // Max Supply
-        ),
-        &[
-            ctx.accounts.edition_account.to_account_info(),
-            ctx.accounts.metadata_account.to_account_info(),
-            ctx.accounts.mint_account.to_account_info(),
-            ctx.accounts.mint_authority.to_account_info(),
-            ctx.accounts.payer.to_account_info(),
-            ctx.accounts.token_metadata_program.to_account_info(),
-            ctx.accounts.rent.to_account_info(),
-        ],
-        &[&[MintAuthorityPda::SEED_PREFIX.as_bytes(), &[bump]]],
-    )?;
-
-    // If we don't use Metaplex Editions, we must disable minting manually
-    // -------------------------------------------------------------------
-    //
-    // msg!("Disabling future minting of this NFT...");
-    // token::set_authority(
-    //     CpiContext::new_with_signer(
-    //         ctx.accounts.token_program.to_account_info(),
-    //         token::SetAuthority {
-    //             current_authority: ctx.accounts.payer.to_account_info(),
-    //             account_or_mint: ctx.accounts.mint_account.to_account_info(),
-    //         },
-    //         &[&[MintAuthorityPda::SEED_PREFIX.as_bytes(), &[bump]]],
-    //     ),
-    //     AuthorityType::MintTokens,
-    //     None,
-    // )?;
-    // token::set_authority(
-    //     CpiContext::new_with_signer(
-    //         ctx.accounts.token_program.to_account_info(),
-    //         token::SetAuthority {
-    //             current_authority: ctx.accounts.payer.to_account_info(),
-    //             account_or_mint: ctx.accounts.mint_account.to_account_info(),
-    //         },
-    //         &[&[MintAuthorityPda::SEED_PREFIX.as_bytes(), &[bump]]],
-    //     ),
-    //     AuthorityType::FreezeAccount,
-    //     None,
-    // )?;
-
-    msg!("NFT minted successfully.");
-
-    Ok(())
-}
-
-#[derive(Accounts)]
-pub struct MintTo<'info> {
-    /// CHECK: Metaplex will check this
-    #[account(mut)]
-    pub edition_account: UncheckedAccount<'info>,
-    /// CHECK: Metaplex will check this
-    #[account(mut)]
-    pub metadata_account: UncheckedAccount<'info>,
-    #[account(
-        mut,
-        mint::decimals = 0,
-        mint::authority = mint_authority.key(),
-        mint::freeze_authority = mint_authority.key(),
-    )]
-    pub mint_account: Account<'info, token::Mint>,
-    #[account(
-        mut,
-        seeds = [ MintAuthorityPda::SEED_PREFIX.as_bytes() ],
-        bump = mint_authority.bump,
-    )]
-    pub mint_authority: Account<'info, MintAuthorityPda>,
-    #[account(
-        init_if_needed,
-        payer = payer,
-        associated_token::mint = mint_account,
-        associated_token::authority = payer,
-    )]
-    pub associated_token_account: Account<'info, token::TokenAccount>,
-    #[account(mut)]
-    pub payer: Signer<'info>,
-    pub rent: Sysvar<'info, Rent>,
-    pub system_program: Program<'info, System>,
-    pub token_program: Program<'info, token::Token>,
-    pub associated_token_program: Program<'info, associated_token::AssociatedToken>,
-    /// CHECK: Metaplex will check this
-    pub token_metadata_program: UncheckedAccount<'info>,
-}

+ 0 - 7
tokens/pda-mint-authority/anchor/programs/nft-minter/src/instructions/mod.rs

@@ -1,7 +0,0 @@
-pub mod create;
-pub mod init;
-pub mod mint;
-
-pub use create::*;
-pub use init::*;
-pub use mint::*;

+ 0 - 32
tokens/pda-mint-authority/anchor/programs/nft-minter/src/lib.rs

@@ -1,32 +0,0 @@
-#![allow(clippy::result_large_err)]
-
-use anchor_lang::prelude::*;
-
-pub mod instructions;
-pub mod state;
-
-use instructions::*;
-
-declare_id!("DU92SqPvfiDVicA4ah3E9wP9Ci7ASog1VmJhZrYU3Hyk");
-
-#[program]
-pub mod nft_minter {
-    use super::*;
-
-    pub fn init(ctx: Context<Init>) -> Result<()> {
-        init::init(ctx)
-    }
-
-    pub fn create_token(
-        ctx: Context<CreateToken>,
-        nft_title: String,
-        nft_symbol: String,
-        nft_uri: String,
-    ) -> Result<()> {
-        create::create_token(ctx, nft_title, nft_symbol, nft_uri)
-    }
-
-    pub fn mint_to(ctx: Context<MintTo>) -> Result<()> {
-        mint::mint_to(ctx)
-    }
-}

+ 0 - 11
tokens/pda-mint-authority/anchor/programs/nft-minter/src/state/mod.rs

@@ -1,11 +0,0 @@
-use anchor_lang::prelude::*;
-
-#[account]
-pub struct MintAuthorityPda {
-    pub bump: u8,
-}
-
-impl MintAuthorityPda {
-    pub const SEED_PREFIX: &'static str = "mint_authority";
-    pub const SIZE: usize = 8 + 8;
-}

+ 4 - 5
tokens/pda-mint-authority/anchor/programs/nft-minter/Cargo.toml → tokens/pda-mint-authority/anchor/programs/token-minter/Cargo.toml

@@ -6,7 +6,7 @@ edition = "2021"
 
 [lib]
 crate-type = ["cdylib", "lib"]
-name = "nft_minter"
+name = "token_minter"
 
 [features]
 no-entrypoint = []
@@ -16,7 +16,6 @@ cpi = ["no-entrypoint"]
 default = []
 
 [dependencies]
-anchor-lang = { version="0.28.0", features=["init-if-needed"] }
-anchor-spl = "0.28.0"
-mpl-token-metadata = { version="1.11", features = [ "no-entrypoint" ] }
-spl-token = "4.0.0"
+anchor-lang = { version = "0.28.0", features = ["init-if-needed"] }
+anchor-spl = { version = "0.28.0", features = ["metadata"] }
+mpl-token-metadata = { version = "1.13.1", features = ["no-entrypoint"] }

+ 0 - 0
tokens/pda-mint-authority/anchor/programs/nft-minter/Xargo.toml → tokens/pda-mint-authority/anchor/programs/token-minter/Xargo.toml


+ 88 - 0
tokens/pda-mint-authority/anchor/programs/token-minter/src/instructions/create.rs

@@ -0,0 +1,88 @@
+// In this example the same PDA is used as both the address of the mint account and the mint authority
+// This is to demonstrate that the same PDA can be used for both the address of an account and CPI signing
+use {
+    anchor_lang::prelude::*,
+    anchor_spl::{
+        metadata::{create_metadata_accounts_v3, CreateMetadataAccountsV3, Metadata},
+        token::{Mint, Token},
+    },
+    mpl_token_metadata::{pda::find_metadata_account, state::DataV2},
+};
+
+#[derive(Accounts)]
+pub struct CreateToken<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+
+    // Create mint account
+    // Same PDA as address of the account and mint/freeze authority
+    #[account(
+        init,
+        seeds = [b"mint"],
+        bump,
+        payer = payer,
+        mint::decimals = 9,
+        mint::authority = mint_account.key(),
+        mint::freeze_authority = mint_account.key(),
+        
+    )]
+    pub mint_account: Account<'info, Mint>,
+
+    /// CHECK: Address validated using constraint
+    #[account(
+        mut,
+        address=find_metadata_account(&mint_account.key()).0
+    )]
+    pub metadata_account: UncheckedAccount<'info>,
+
+    pub token_program: Program<'info, Token>,
+    pub token_metadata_program: Program<'info, Metadata>,
+    pub system_program: Program<'info, System>,
+    pub rent: Sysvar<'info, Rent>,
+}
+
+pub fn create_token(
+    ctx: Context<CreateToken>,
+    token_name: String,
+    token_symbol: String,
+    token_uri: String,
+) -> Result<()> {
+    msg!("Creating metadata account");
+
+    // PDA signer seeds
+    let signer_seeds: &[&[&[u8]]] = &[&[b"mint", &[*ctx.bumps.get("mint_account").unwrap()]]];
+
+    // Cross Program Invocation (CPI) signed by PDA
+    // Invoking the create_metadata_account_v3 instruction on the token metadata program
+    create_metadata_accounts_v3(
+        CpiContext::new(
+            ctx.accounts.token_metadata_program.to_account_info(),
+            CreateMetadataAccountsV3 {
+                metadata: ctx.accounts.metadata_account.to_account_info(),
+                mint: ctx.accounts.mint_account.to_account_info(),
+                mint_authority: ctx.accounts.mint_account.to_account_info(), // PDA is mint authority
+                update_authority: ctx.accounts.mint_account.to_account_info(), // PDA is update authority
+                payer: ctx.accounts.payer.to_account_info(),
+                system_program: ctx.accounts.system_program.to_account_info(),
+                rent: ctx.accounts.rent.to_account_info(),
+            },
+        )
+        .with_signer(signer_seeds),
+        DataV2 {
+            name: token_name,
+            symbol: token_symbol,
+            uri: token_uri,
+            seller_fee_basis_points: 0,
+            creators: None,
+            collection: None,
+            uses: None,
+        },
+        false, // Is mutable
+        true,  // Update authority is signer
+        None,  // Collection details
+    )?;
+
+    msg!("Token created successfully.");
+
+    Ok(())
+}

+ 65 - 0
tokens/pda-mint-authority/anchor/programs/token-minter/src/instructions/mint.rs

@@ -0,0 +1,65 @@
+use {
+    anchor_lang::prelude::*,
+    anchor_spl::{
+        associated_token::AssociatedToken,
+        token::{mint_to, Mint, MintTo, Token, TokenAccount},
+    },
+};
+
+#[derive(Accounts)]
+pub struct MintToken<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+
+    // Mint account address is a PDA
+    #[account(
+        mut,
+        seeds = [b"mint"],
+        bump
+    )]
+    pub mint_account: Account<'info, Mint>,
+
+    // Create Associated Token Account, if needed
+    // This is the account that will hold the minted tokens
+    #[account(
+        init_if_needed,
+        payer = payer,
+        associated_token::mint = mint_account,
+        associated_token::authority = payer,
+    )]
+    pub associated_token_account: Account<'info, TokenAccount>,
+
+    pub token_program: Program<'info, Token>,
+    pub associated_token_program: Program<'info, AssociatedToken>,
+    pub system_program: Program<'info, System>,
+}
+
+pub fn mint_token(ctx: Context<MintToken>, amount: u64) -> Result<()> {
+    msg!("Minting token to associated token account...");
+    msg!("Mint: {}", &ctx.accounts.mint_account.key());
+    msg!(
+        "Token Address: {}",
+        &ctx.accounts.associated_token_account.key()
+    );
+
+    // PDA signer seeds
+    let signer_seeds: &[&[&[u8]]] = &[&[b"mint", &[*ctx.bumps.get("mint_account").unwrap()]]];
+
+    // Invoke the mint_to instruction on the token program
+    mint_to(
+        CpiContext::new(
+            ctx.accounts.token_program.to_account_info(),
+            MintTo {
+                mint: ctx.accounts.mint_account.to_account_info(),
+                to: ctx.accounts.associated_token_account.to_account_info(),
+                authority: ctx.accounts.mint_account.to_account_info(), // PDA mint authority, required as signer
+            },
+        )
+        .with_signer(signer_seeds), // using PDA to sign
+        amount * 10u64.pow(ctx.accounts.mint_account.decimals as u32), // Mint tokens, adjust for decimals
+    )?;
+
+    msg!("Token minted successfully.");
+
+    Ok(())
+}

+ 0 - 0
tokens/nft-minter/anchor/programs/nft-minter/src/instructions/mod.rs → tokens/pda-mint-authority/anchor/programs/token-minter/src/instructions/mod.rs


+ 25 - 0
tokens/pda-mint-authority/anchor/programs/token-minter/src/lib.rs

@@ -0,0 +1,25 @@
+#![allow(clippy::result_large_err)]
+
+use anchor_lang::prelude::*;
+use instructions::*;
+pub mod instructions;
+
+declare_id!("A5gNtapBvMLD6i7D2t3SSyJeFtBdfb6ibvZu1hoBLzCo");
+
+#[program]
+pub mod token_minter {
+    use super::*;
+
+    pub fn create_token(
+        ctx: Context<CreateToken>,
+        token_name: String,
+        token_symbol: String,
+        token_uri: String,
+    ) -> Result<()> {
+        create::create_token(ctx, token_name, token_symbol, token_uri)
+    }
+
+    pub fn mint_token(ctx: Context<MintToken>, amount: u64) -> Result<()> {
+        mint::mint_token(ctx, amount)
+    }
+}

+ 64 - 98
tokens/pda-mint-authority/anchor/tests/test.ts

@@ -1,121 +1,87 @@
-import { 
-  PROGRAM_ID as TOKEN_METADATA_PROGRAM_ID
-} from '@metaplex-foundation/mpl-token-metadata';
-import * as anchor from "@project-serum/anchor";
-import { ASSOCIATED_PROGRAM_ID } from '@project-serum/anchor/dist/cjs/utils/token';
-import { NftMinter } from "../target/types/nft_minter";
-
+import { PROGRAM_ID as TOKEN_METADATA_PROGRAM_ID } from "@metaplex-foundation/mpl-token-metadata";
+import * as anchor from "@coral-xyz/anchor";
+import { TokenMinter } from "../target/types/token_minter";
+import { PublicKey, SYSVAR_RENT_PUBKEY, SystemProgram } from "@solana/web3.js";
+import {
+  getAssociatedTokenAddressSync,
+  ASSOCIATED_TOKEN_PROGRAM_ID,
+  TOKEN_PROGRAM_ID,
+} from "@solana/spl-token";
 
 describe("NFT Minter", () => {
-  
   const provider = anchor.AnchorProvider.env();
   anchor.setProvider(provider);
   const payer = provider.wallet as anchor.Wallet;
-  const program = anchor.workspace.NftMinter as anchor.Program<NftMinter>;
-
-  const mintAuthorityPublicKey = anchor.web3.PublicKey.findProgramAddressSync(
-    [Buffer.from("mint_authority")],
-    program.programId,
-  )[0];
-
-  const nftTitle = "Homer NFT";
-  const nftSymbol = "HOMR";
-  const nftUri = "https://raw.githubusercontent.com/solana-developers/program-examples/new-examples/tokens/tokens/.assets/nft.json";
-
-  const mintKeypair: anchor.web3.Keypair = anchor.web3.Keypair.generate();
-
-  it("Init Mint Authority PDA", async () => {
-
-    const sx = await program.methods.init()
+  const program = anchor.workspace.TokenMinter as anchor.Program<TokenMinter>;
+
+  // Derive the PDA to use as mint account address.
+  // This same PDA is also used as the mint authority.
+  const [mintPDA] = PublicKey.findProgramAddressSync(
+    [Buffer.from("mint")],
+    program.programId
+  );
+
+  const metadata = {
+    name: "Solana Gold",
+    symbol: "GOLDSOL",
+    uri: "https://raw.githubusercontent.com/solana-developers/program-examples/new-examples/tokens/tokens/.assets/spl-token.json",
+  };
+
+  it("Create a token!", async () => {
+    // Derive the metadata account address.
+    const [metadataAddress] = PublicKey.findProgramAddressSync(
+      [
+        Buffer.from("metadata"),
+        TOKEN_METADATA_PROGRAM_ID.toBuffer(),
+        mintPDA.toBuffer(),
+      ],
+      TOKEN_METADATA_PROGRAM_ID
+    );
+
+    const transactionSignature = await program.methods
+      .createToken(metadata.name, metadata.symbol, metadata.uri)
       .accounts({
-        mintAuthority: mintAuthorityPublicKey,
         payer: payer.publicKey,
-      })
-      .signers([payer.payer])
-      .rpc();
-
-    console.log("Success!");
-        console.log(`   Mint Authority: ${mintKeypair.publicKey}`);
-        console.log(`   Tx Signature  : ${sx}`);
-  });
-  
-  it("Create an NFT!", async () => {
-
-    const metadataAddress = (anchor.web3.PublicKey.findProgramAddressSync(
-        [
-          Buffer.from("metadata"),
-          TOKEN_METADATA_PROGRAM_ID.toBuffer(),
-          mintKeypair.publicKey.toBuffer(),
-        ],
-        TOKEN_METADATA_PROGRAM_ID
-    ))[0];
-
-    const sx = await program.methods.createToken(
-      nftTitle, nftSymbol, nftUri
-    )
-      .accounts({
+        mintAccount: mintPDA,
         metadataAccount: metadataAddress,
-        mintAccount: mintKeypair.publicKey,
-        mintAuthority: mintAuthorityPublicKey,
-        payer: payer.publicKey,
-        rent: anchor.web3.SYSVAR_RENT_PUBKEY,
-        systemProgram: anchor.web3.SystemProgram.programId,
-        tokenProgram: anchor.utils.token.TOKEN_PROGRAM_ID,
+        tokenProgram: TOKEN_PROGRAM_ID,
         tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID,
+        systemProgram: SystemProgram.programId,
+        rent: SYSVAR_RENT_PUBKEY,
       })
-      .signers([mintKeypair, payer.payer])
-      .rpc({skipPreflight: true});
+      .rpc();
 
     console.log("Success!");
-        console.log(`   Mint Address: ${mintKeypair.publicKey}`);
-        console.log(`   Tx Signature: ${sx}`);
+    console.log(`   Mint Address: ${mintPDA}`);
+    console.log(`   Transaction Signature: ${transactionSignature}`);
   });
 
-  it("Mint the NFT to your wallet!", async () => {
-
-    const metadataAddress = (anchor.web3.PublicKey.findProgramAddressSync(
-        [
-          Buffer.from("metadata"),
-          TOKEN_METADATA_PROGRAM_ID.toBuffer(),
-          mintKeypair.publicKey.toBuffer(),
-        ],
-        TOKEN_METADATA_PROGRAM_ID
-    ))[0];
-
-    const editionAddress = (anchor.web3.PublicKey.findProgramAddressSync(
-        [
-          Buffer.from("metadata"),
-          TOKEN_METADATA_PROGRAM_ID.toBuffer(),
-          mintKeypair.publicKey.toBuffer(),
-          Buffer.from("edition"),
-        ],
-        TOKEN_METADATA_PROGRAM_ID
-    ))[0];
+  it("Mint 1 Token!", async () => {
+    // Derive the associated token address account for the mint and payer.
+    const associatedTokenAccountAddress = getAssociatedTokenAddressSync(
+      mintPDA,
+      payer.publicKey
+    );
 
-    const associatedTokenAccountAddress = await anchor.utils.token.associatedAddress({
-      mint: mintKeypair.publicKey,
-      owner: payer.publicKey,
-    });
+    // Amount of tokens to mint.
+    const amount = new anchor.BN(100);
 
-    const sx = await program.methods.mintTo()
+    const transactionSignature = await program.methods
+      .mintToken(amount)
       .accounts({
-        associatedTokenAccount: associatedTokenAccountAddress,
-        editionAccount: editionAddress,
-        metadataAccount: metadataAddress,
-        mintAccount: mintKeypair.publicKey,
-        mintAuthority: mintAuthorityPublicKey,
         payer: payer.publicKey,
-        rent: anchor.web3.SYSVAR_RENT_PUBKEY,
-        systemProgram: anchor.web3.SystemProgram.programId,
-        tokenProgram: anchor.utils.token.TOKEN_PROGRAM_ID,
-        associatedTokenProgram: ASSOCIATED_PROGRAM_ID,
-        tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID,
+        mintAccount: mintPDA,
+        associatedTokenAccount: associatedTokenAccountAddress,
+        tokenProgram: TOKEN_PROGRAM_ID,
+        associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
+        systemProgram: SystemProgram.programId,
       })
-      .signers([payer.payer])
       .rpc();
 
-      console.log("Success!");
-      console.log(`   ATA Address: ${associatedTokenAccountAddress}`);
-      console.log(`   Tx Signature: ${sx}`);
+    console.log("Success!");
+    console.log(
+      `   Associated Token Account Address: ${associatedTokenAccountAddress}`
+    );
+    console.log(`   Transaction Signature: ${transactionSignature}`);
   });
 });

+ 17 - 5
tokens/spl-token-minter/anchor/Anchor.toml

@@ -1,14 +1,26 @@
 [features]
 seeds = false
-[programs.devnet]
-spl_token_minter = "5BStrknWEiQWHmDGdDBaG7j9qegfN2Nq83M3hXajjgXY"
+skip-lint = false
 
-[registry]
-url = "https://anchor.projectserum.com"
+[programs.localnet]
+spl_token_minter = "77p9WmpzQW29RUEzTEef2ym7AHePBE9yNWJ9acikXfZS"
 
 [provider]
-cluster = "devnet"
+cluster = "localnet"
 wallet = "~/.config/solana/id.json"
 
 [scripts]
 test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
+
+[test]
+startup_wait = 5000
+shutdown_wait = 2000
+
+[test.validator]
+bind_address = "0.0.0.0"
+url = "https://api.mainnet-beta.solana.com"
+ledger = ".anchor/test-ledger"
+rpc_port = 8899
+
+[[test.validator.clone]]
+address = "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"

+ 14 - 13
tokens/spl-token-minter/anchor/package.json

@@ -1,15 +1,16 @@
 {
-    "dependencies": {
-        "@metaplex-foundation/mpl-token-metadata": "^2.5.2",
-        "@project-serum/anchor": "^0.24.2"
-    },
-    "devDependencies": {
-        "@types/bn.js": "^5.1.0",
-        "@types/chai": "^4.3.0",
-        "@types/mocha": "^9.0.0",
-        "chai": "^4.3.4",
-        "mocha": "^9.0.3",
-        "ts-mocha": "^10.0.0",
-        "typescript": "^4.3.5"
-    }
+  "dependencies": {
+    "@coral-xyz/anchor": "^0.28.1-beta.2",
+    "@metaplex-foundation/mpl-token-metadata": "^2.5.2",
+    "@solana/spl-token": "^0.3.8"
+  },
+  "devDependencies": {
+    "@types/bn.js": "^5.1.0",
+    "@types/chai": "^4.3.0",
+    "@types/mocha": "^9.0.0",
+    "chai": "^4.3.4",
+    "mocha": "^9.0.3",
+    "ts-mocha": "^10.0.0",
+    "typescript": "^4.3.5"
+  }
 }

+ 3 - 3
tokens/spl-token-minter/anchor/programs/spl-token-minter/Cargo.toml

@@ -16,6 +16,6 @@ cpi = ["no-entrypoint"]
 default = []
 
 [dependencies]
-anchor-lang = { version="0.28.0", features=["init-if-needed"] }
-anchor-spl = "0.28.0"
-mpl-token-metadata = { version="1.11.0", features = [ "no-entrypoint" ] }
+anchor-lang = { version = "0.28.0", features = ["init-if-needed"] }
+anchor-spl = { version = "0.28.0", features = ["metadata"] }
+mpl-token-metadata = { version = "1.13.1", features = ["no-entrypoint"] }

+ 63 - 58
tokens/spl-token-minter/anchor/programs/spl-token-minter/src/instructions/create.rs

@@ -1,72 +1,77 @@
 use {
-    anchor_lang::{prelude::*, solana_program::program::invoke},
-    anchor_spl::token,
-    mpl_token_metadata::instruction as mpl_instruction,
+    anchor_lang::prelude::*,
+    anchor_spl::{
+        metadata::{create_metadata_accounts_v3, CreateMetadataAccountsV3, Metadata},
+        token::{Mint, Token},
+    },
+    mpl_token_metadata::{pda::find_metadata_account, state::DataV2},
 };
 
+#[derive(Accounts)]
+pub struct CreateToken<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+
+    #[account(
+        init,
+        payer = payer,
+        mint::decimals = 9,
+        mint::authority = payer.key(),
+        mint::freeze_authority = payer.key(),
+        
+    )]
+    pub mint_account: Account<'info, Mint>,
+    /// CHECK: Address validated using constraint
+    #[account(
+        mut,
+        address=find_metadata_account(&mint_account.key()).0
+    )]
+    pub metadata_account: UncheckedAccount<'info>,
+
+    pub token_program: Program<'info, Token>,
+    pub token_metadata_program: Program<'info, Metadata>,
+    pub system_program: Program<'info, System>,
+    pub rent: Sysvar<'info, Rent>,
+}
+
 pub fn create_token(
     ctx: Context<CreateToken>,
-    token_title: String,
+    token_name: String,
     token_symbol: String,
     token_uri: String,
 ) -> Result<()> {
-    msg!("Creating metadata account...");
-    msg!(
-        "Metadata account address: {}",
-        &ctx.accounts.metadata_account.key()
-    );
-    invoke(
-        &mpl_instruction::create_metadata_accounts_v3(
-            ctx.accounts.token_metadata_program.key(), // Program ID (the Token Metadata Program)
-            ctx.accounts.metadata_account.key(),       // Metadata account
-            ctx.accounts.mint_account.key(),           // Mint account
-            ctx.accounts.mint_authority.key(),         // Mint authority
-            ctx.accounts.payer.key(),                  // Payer
-            ctx.accounts.mint_authority.key(),         // Update authority
-            token_title,                               // Name
-            token_symbol,                              // Symbol
-            token_uri,                                 // URI
-            None,                                      // Creators
-            0,                                         // Seller fee basis points
-            true,                                      // Update authority is signer
-            false,                                     // Is mutable
-            None,                                      // Collection
-            None,                                      // Uses
-            None,                                      // Collection Details
+    msg!("Creating metadata account");
+
+    // Cross Program Invocation (CPI)
+    // Invoking the create_metadata_account_v3 instruction on the token metadata program
+    create_metadata_accounts_v3(
+        CpiContext::new(
+            ctx.accounts.token_metadata_program.to_account_info(),
+            CreateMetadataAccountsV3 {
+                metadata: ctx.accounts.metadata_account.to_account_info(),
+                mint: ctx.accounts.mint_account.to_account_info(),
+                mint_authority: ctx.accounts.payer.to_account_info(), 
+                update_authority: ctx.accounts.payer.to_account_info(),
+                payer: ctx.accounts.payer.to_account_info(),
+                system_program: ctx.accounts.system_program.to_account_info(),
+                rent: ctx.accounts.rent.to_account_info(),
+            },
         ),
-        &[
-            ctx.accounts.metadata_account.to_account_info(),
-            ctx.accounts.mint_account.to_account_info(),
-            ctx.accounts.mint_authority.to_account_info(),
-            ctx.accounts.payer.to_account_info(),
-            ctx.accounts.mint_authority.to_account_info(),
-            ctx.accounts.rent.to_account_info(),
-        ],
+        DataV2 {
+            name: token_name,
+            symbol: token_symbol,
+            uri: token_uri,
+            seller_fee_basis_points: 0,
+            creators: None,
+            collection: None,
+            uses: None,
+        },
+        false, // Is mutable
+        true,  // Update authority is signer
+        None,  // Collection details
     )?;
 
-    msg!("Token mint created successfully.");
+    msg!("Token created successfully.");
 
     Ok(())
 }
-
-#[derive(Accounts)]
-pub struct CreateToken<'info> {
-    /// CHECK: We're about to create this with Metaplex
-    #[account(mut)]
-    pub metadata_account: UncheckedAccount<'info>,
-    #[account(
-        init,
-        payer = payer,
-        mint::decimals = 9,
-        mint::authority = mint_authority.key(),
-    )]
-    pub mint_account: Account<'info, token::Mint>,
-    pub mint_authority: SystemAccount<'info>,
-    #[account(mut)]
-    pub payer: Signer<'info>,
-    pub rent: Sysvar<'info, Rent>,
-    pub system_program: Program<'info, System>,
-    pub token_program: Program<'info, token::Token>,
-    /// CHECK: Metaplex will check this
-    pub token_metadata_program: UncheckedAccount<'info>,
-}

+ 34 - 35
tokens/spl-token-minter/anchor/programs/spl-token-minter/src/instructions/mint.rs

@@ -1,55 +1,54 @@
 use {
     anchor_lang::prelude::*,
-    anchor_spl::{associated_token, token},
+    anchor_spl::{
+        associated_token::AssociatedToken,
+        token::{mint_to, Mint, MintTo, Token, TokenAccount},
+    },
 };
 
-pub fn mint_to(ctx: Context<MintTo>, quantity: u64) -> Result<()> {
-    msg!("Minting token to token account...");
-    msg!(
-        "Mint: {}",
-        &ctx.accounts.mint_account.to_account_info().key()
-    );
+#[derive(Accounts)]
+pub struct MintToken<'info> {
+    #[account(mut)]
+    pub mint_authority: Signer<'info>,
+
+    pub recepient: SystemAccount<'info>,
+    #[account(mut)]
+    pub mint_account: Account<'info, Mint>,
+    #[account(
+        init_if_needed,
+        payer = mint_authority,
+        associated_token::mint = mint_account,
+        associated_token::authority = recepient,
+    )]
+    pub associated_token_account: Account<'info, TokenAccount>,
+
+    pub token_program: Program<'info, Token>,
+    pub associated_token_program: Program<'info, AssociatedToken>,
+    pub system_program: Program<'info, System>,
+}
+
+pub fn mint_token(ctx: Context<MintToken>, amount: u64) -> Result<()> {
+    msg!("Minting tokens to associated token account...");
+    msg!("Mint: {}", &ctx.accounts.mint_account.key());
     msg!(
         "Token Address: {}",
         &ctx.accounts.associated_token_account.key()
     );
-    token::mint_to(
+
+    // Invoke the mint_to instruction on the token program
+    mint_to(
         CpiContext::new(
             ctx.accounts.token_program.to_account_info(),
-            token::MintTo {
+            MintTo {
                 mint: ctx.accounts.mint_account.to_account_info(),
                 to: ctx.accounts.associated_token_account.to_account_info(),
                 authority: ctx.accounts.mint_authority.to_account_info(),
             },
         ),
-        quantity,
+        amount * 10u64.pow(ctx.accounts.mint_account.decimals as u32), // Mint tokens, adjust for decimals
     )?;
 
-    msg!("Token minted to wallet successfully.");
+    msg!("Token minted successfully.");
 
     Ok(())
 }
-
-#[derive(Accounts)]
-pub struct MintTo<'info> {
-    #[account(
-        mut,
-        mint::decimals = 9,
-        mint::authority = mint_authority.key(),
-    )]
-    pub mint_account: Account<'info, token::Mint>,
-    pub mint_authority: SystemAccount<'info>,
-    #[account(
-        init_if_needed,
-        payer = payer,
-        associated_token::mint = mint_account,
-        associated_token::authority = payer,
-    )]
-    pub associated_token_account: Account<'info, token::TokenAccount>,
-    #[account(mut)]
-    pub payer: Signer<'info>,
-    pub rent: Sysvar<'info, Rent>,
-    pub system_program: Program<'info, System>,
-    pub token_program: Program<'info, token::Token>,
-    pub associated_token_program: Program<'info, associated_token::AssociatedToken>,
-}

+ 5 - 6
tokens/spl-token-minter/anchor/programs/spl-token-minter/src/lib.rs

@@ -3,10 +3,9 @@
 use anchor_lang::prelude::*;
 
 pub mod instructions;
-
 use instructions::*;
 
-declare_id!("5BStrknWEiQWHmDGdDBaG7j9qegfN2Nq83M3hXajjgXY");
+declare_id!("77p9WmpzQW29RUEzTEef2ym7AHePBE9yNWJ9acikXfZS");
 
 #[program]
 pub mod spl_token_minter {
@@ -14,14 +13,14 @@ pub mod spl_token_minter {
 
     pub fn create_token(
         ctx: Context<CreateToken>,
-        token_title: String,
+        token_name: String,
         token_symbol: String,
         token_uri: String,
     ) -> Result<()> {
-        create::create_token(ctx, token_title, token_symbol, token_uri)
+        create::create_token(ctx, token_name, token_symbol, token_uri)
     }
 
-    pub fn mint_to(ctx: Context<MintTo>, quantity: u64) -> Result<()> {
-        mint::mint_to(ctx, quantity)
+    pub fn mint_token(ctx: Context<MintToken>, amount: u64) -> Result<()> {
+        mint::mint_token(ctx, amount)
     }
 }

+ 56 - 45
tokens/spl-token-minter/anchor/tests/test.ts

@@ -1,81 +1,92 @@
-import { 
-  PROGRAM_ID as TOKEN_METADATA_PROGRAM_ID
-} from '@metaplex-foundation/mpl-token-metadata';
-import * as anchor from "@project-serum/anchor";
-import { ASSOCIATED_PROGRAM_ID } from '@project-serum/anchor/dist/cjs/utils/token';
+import { PROGRAM_ID as TOKEN_METADATA_PROGRAM_ID } from "@metaplex-foundation/mpl-token-metadata";
+import * as anchor from "@coral-xyz/anchor";
 import { SplTokenMinter } from "../target/types/spl_token_minter";
-
+import {
+  PublicKey,
+  Keypair,
+  SYSVAR_RENT_PUBKEY,
+  SystemProgram,
+} from "@solana/web3.js";
+import {
+  getAssociatedTokenAddressSync,
+  ASSOCIATED_TOKEN_PROGRAM_ID,
+  TOKEN_PROGRAM_ID,
+} from "@solana/spl-token";
 
 describe("SPL Token Minter", () => {
-  
   const provider = anchor.AnchorProvider.env();
   anchor.setProvider(provider);
   const payer = provider.wallet as anchor.Wallet;
-  const program = anchor.workspace.SplTokenMinter as anchor.Program<SplTokenMinter>;
+  const program = anchor.workspace
+    .SplTokenMinter as anchor.Program<SplTokenMinter>;
 
-  const tokenTitle = "Solana Gold";
-  const tokenSymbol = "GOLDSOL";
-  const tokenUri = "https://raw.githubusercontent.com/solana-developers/program-examples/new-examples/tokens/tokens/.assets/spl-token.json";
+  const metadata = {
+    name: "Solana Gold",
+    symbol: "GOLDSOL",
+    uri: "https://raw.githubusercontent.com/solana-developers/program-examples/new-examples/tokens/tokens/.assets/spl-token.json",
+  };
 
-  const mintKeypair: anchor.web3.Keypair = anchor.web3.Keypair.generate();
-  
-  it("Create an SPL Token!", async () => {
+  // Generate new keypair to use as address for mint account.
+  const mintKeypair = new Keypair();
 
-    const metadataAddress = (await anchor.web3.PublicKey.findProgramAddress(
+  it("Create an SPL Token!", async () => {
+    // Derive the metadata account address.
+    const [metadataAddress] = PublicKey.findProgramAddressSync(
       [
         Buffer.from("metadata"),
         TOKEN_METADATA_PROGRAM_ID.toBuffer(),
         mintKeypair.publicKey.toBuffer(),
       ],
       TOKEN_METADATA_PROGRAM_ID
-    ))[0];
+    );
 
-    const sx = await program.methods.createToken(
-      tokenTitle, tokenSymbol, tokenUri
-    )
+    const transactionSignature = await program.methods
+      .createToken(metadata.name, metadata.symbol, metadata.uri)
       .accounts({
-        metadataAccount: metadataAddress,
-        mintAccount: mintKeypair.publicKey,
-        mintAuthority: payer.publicKey,
         payer: payer.publicKey,
-        rent: anchor.web3.SYSVAR_RENT_PUBKEY,
-        systemProgram: anchor.web3.SystemProgram.programId,
-        tokenProgram: anchor.utils.token.TOKEN_PROGRAM_ID,
+        mintAccount: mintKeypair.publicKey,
+        metadataAccount: metadataAddress,
+        tokenProgram: TOKEN_PROGRAM_ID,
         tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID,
+        systemProgram: SystemProgram.programId,
+        rent: SYSVAR_RENT_PUBKEY,
       })
-      .signers([mintKeypair, payer.payer])
+      .signers([mintKeypair])
       .rpc();
 
     console.log("Success!");
-        console.log(`   Mint Address: ${mintKeypair.publicKey}`);
-        console.log(`   Tx Signature: ${sx}`);
+    console.log(`   Mint Address: ${mintKeypair.publicKey}`);
+    console.log(`   Transaction Signature: ${transactionSignature}`);
   });
 
   it("Mint some tokens to your wallet!", async () => {
+    // Derive the associated token address account for the mint and payer.
+    const associatedTokenAccountAddress = getAssociatedTokenAddressSync(
+      mintKeypair.publicKey,
+      payer.publicKey
+    );
 
-    const associatedTokenAccountAddress = await anchor.utils.token.associatedAddress({
-      mint: mintKeypair.publicKey,
-      owner: payer.publicKey,
-    });
+    // Amount of tokens to mint.
+    const amount = new anchor.BN(100);
 
-    const sx = await program.methods.mintTo(
-      new anchor.BN(150)
-    )
+    // Mint the tokens to the associated token account.
+    const transactionSignature = await program.methods
+      .mintToken(amount)
       .accounts({
-        associatedTokenAccount: associatedTokenAccountAddress,
-        mintAccount: mintKeypair.publicKey,
         mintAuthority: payer.publicKey,
-        payer: payer.publicKey,
-        rent: anchor.web3.SYSVAR_RENT_PUBKEY,
-        systemProgram: anchor.web3.SystemProgram.programId,
-        tokenProgram: anchor.utils.token.TOKEN_PROGRAM_ID,
-        associatedTokenProgram: ASSOCIATED_PROGRAM_ID,
+        recepient: payer.publicKey,
+        mintAccount: mintKeypair.publicKey,
+        associatedTokenAccount: associatedTokenAccountAddress,
+        tokenProgram: TOKEN_PROGRAM_ID,
+        associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
+        systemProgram: SystemProgram.programId,
       })
-      .signers([payer.payer])
       .rpc();
 
     console.log("Success!");
-        console.log(`   Mint Address: ${mintKeypair.publicKey}`);
-        console.log(`   Tx Signature: ${sx}`);
+    console.log(
+      `   Associated Token Account Address: ${associatedTokenAccountAddress}`
+    );
+    console.log(`   Transaction Signature: ${transactionSignature}`);
   });
 });

+ 19 - 4
tokens/transfer-tokens/anchor/Anchor.toml

@@ -1,14 +1,29 @@
 [features]
 seeds = false
-[programs.devnet]
-transfer_tokens = "7p8osL5uUKUFM8sUxRYfmFVGN264PxeBSDEdNv36Khe3"
+skip-lint = false
+
+[programs.localnet]
+transfer_tokens = "2W7B8C5skxyVaAA1LfYAsRHiv26LL5j88GJ9XYyybWqc"
 
 [registry]
-url = "https://anchor.projectserum.com"
+url = "https://api.apr.dev"
 
 [provider]
-cluster = "devnet"
+cluster = "Localnet"
 wallet = "~/.config/solana/id.json"
 
 [scripts]
 test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
+
+[test]
+startup_wait = 5000
+shutdown_wait = 2000
+
+[test.validator]
+bind_address = "0.0.0.0"
+url = "https://api.mainnet-beta.solana.com"
+ledger = ".anchor/test-ledger"
+rpc_port = 8899
+
+[[test.validator.clone]]
+address = "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s"

+ 14 - 13
tokens/transfer-tokens/anchor/package.json

@@ -1,15 +1,16 @@
 {
-    "dependencies": {
-        "@metaplex-foundation/mpl-token-metadata": "^2.5.2",
-        "@project-serum/anchor": "^0.24.2"
-    },
-    "devDependencies": {
-        "@types/bn.js": "^5.1.0",
-        "@types/chai": "^4.3.0",
-        "@types/mocha": "^9.0.0",
-        "chai": "^4.3.4",
-        "mocha": "^9.0.3",
-        "ts-mocha": "^10.0.0",
-        "typescript": "^4.3.5"
-    }
+  "dependencies": {
+    "@coral-xyz/anchor": "^0.28.1-beta.2",
+    "@metaplex-foundation/mpl-token-metadata": "^2.5.2",
+    "@solana/spl-token": "^0.3.8"
+  },
+  "devDependencies": {
+    "@types/bn.js": "^5.1.0",
+    "@types/chai": "^4.3.0",
+    "@types/mocha": "^9.0.0",
+    "chai": "^4.3.4",
+    "mocha": "^9.0.3",
+    "ts-mocha": "^10.0.0",
+    "typescript": "^4.3.5"
+  }
 }

+ 3 - 3
tokens/transfer-tokens/anchor/programs/transfer-tokens/Cargo.toml

@@ -16,6 +16,6 @@ cpi = ["no-entrypoint"]
 default = []
 
 [dependencies]
-anchor-lang = { version = "0.28.0", features=["init-if-needed"] }
-anchor-spl = "0.28.0"
-mpl-token-metadata = { version="1.11", features = ["no-entrypoint"] }
+anchor-lang = { version = "0.28.0", features = ["init-if-needed"] }
+anchor-spl = { version = "0.28.0", features = ["metadata"] }
+mpl-token-metadata = { version = "1.13.1", features = ["no-entrypoint"] }

+ 64 - 66
tokens/transfer-tokens/anchor/programs/transfer-tokens/src/instructions/create.rs

@@ -1,80 +1,78 @@
 use {
-    anchor_lang::{prelude::*, solana_program::program::invoke},
-    anchor_spl::token,
-    mpl_token_metadata::instruction as mpl_instruction,
+    anchor_lang::prelude::*,
+    anchor_spl::{
+        metadata::{create_metadata_accounts_v3, CreateMetadataAccountsV3, Metadata},
+        token::{Mint, Token},
+    },
+    mpl_token_metadata::{pda::find_metadata_account, state::DataV2},
 };
 
+#[derive(Accounts)]
+pub struct CreateToken<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+
+    #[account(
+        init,
+        payer = payer,
+        mint::decimals = 9,
+        mint::authority = payer.key(),
+        mint::freeze_authority = payer.key(),
+        
+    )]
+    pub mint_account: Account<'info, Mint>,
+
+    /// CHECK: Address validated using constraint
+    #[account(
+        mut,
+        address=find_metadata_account(&mint_account.key()).0
+    )]
+    pub metadata_account: UncheckedAccount<'info>,
+
+    pub token_program: Program<'info, Token>,
+    pub token_metadata_program: Program<'info, Metadata>,
+    pub system_program: Program<'info, System>,
+    pub rent: Sysvar<'info, Rent>,
+}
+
 pub fn create_token(
     ctx: Context<CreateToken>,
-    token_title: String,
+    token_name: String,
     token_symbol: String,
     token_uri: String,
-    _decimals: u8,
 ) -> Result<()> {
-    msg!("Creating metadata account...");
-    msg!(
-        "Metadata account address: {}",
-        &ctx.accounts.metadata_account.key()
-    );
-    invoke(
-        &mpl_instruction::create_metadata_accounts_v3(
-            ctx.accounts.token_metadata_program.key(), // Program ID (the Token Metadata Program)
-            ctx.accounts.metadata_account.key(),       // Metadata account
-            ctx.accounts.mint_account.key(),           // Mint account
-            ctx.accounts.mint_authority.key(),         // Mint authority
-            ctx.accounts.payer.key(),                  // Payer
-            ctx.accounts.mint_authority.key(),         // Update authority
-            token_title,                               // Name
-            token_symbol,                              // Symbol
-            token_uri,                                 // URI
-            None,                                      // Creators
-            0,                                         // Seller fee basis points
-            true,                                      // Update authority is signer
-            false,                                     // Is mutable
-            None,                                      // Collection
-            None,                                      // Uses
-            None,                                      // Collection Details
+    msg!("Creating metadata account");
+
+    // Cross Program Invocation (CPI)
+    // Invoking the create_metadata_account_v3 instruction on the token metadata program
+    create_metadata_accounts_v3(
+        CpiContext::new(
+            ctx.accounts.token_metadata_program.to_account_info(),
+            CreateMetadataAccountsV3 {
+                metadata: ctx.accounts.metadata_account.to_account_info(),
+                mint: ctx.accounts.mint_account.to_account_info(),
+                mint_authority: ctx.accounts.payer.to_account_info(), 
+                update_authority: ctx.accounts.payer.to_account_info(),
+                payer: ctx.accounts.payer.to_account_info(),
+                system_program: ctx.accounts.system_program.to_account_info(),
+                rent: ctx.accounts.rent.to_account_info(),
+            },
         ),
-        &[
-            ctx.accounts.metadata_account.to_account_info(),
-            ctx.accounts.mint_account.to_account_info(),
-            ctx.accounts.mint_authority.to_account_info(),
-            ctx.accounts.payer.to_account_info(),
-            ctx.accounts.mint_authority.to_account_info(),
-            ctx.accounts.rent.to_account_info(),
-        ],
+        DataV2 {
+            name: token_name,
+            symbol: token_symbol,
+            uri: token_uri,
+            seller_fee_basis_points: 0,
+            creators: None,
+            collection: None,
+            uses: None,
+        },
+        false, // Is mutable
+        true,  // Update authority is signer
+        None,  // Collection details
     )?;
 
-    msg!("Token mint created successfully.");
+    msg!("Token created successfully.");
 
     Ok(())
 }
-
-#[derive(Accounts)]
-#[instruction(
-    token_title: String,
-    token_symbol: String,
-    token_uri: String,
-    decimals: u8,
-)]
-pub struct CreateToken<'info> {
-    /// CHECK: We're about to create this with Metaplex
-    #[account(mut)]
-    pub metadata_account: UncheckedAccount<'info>,
-    #[account(
-        init,
-        payer = payer,
-        mint::decimals = decimals,
-        mint::authority = mint_authority.key(),
-        mint::freeze_authority = mint_authority.key(),
-    )]
-    pub mint_account: Account<'info, token::Mint>,
-    pub mint_authority: SystemAccount<'info>,
-    #[account(mut)]
-    pub payer: Signer<'info>,
-    pub rent: Sysvar<'info, Rent>,
-    pub system_program: Program<'info, System>,
-    pub token_program: Program<'info, token::Token>,
-    /// CHECK: Metaplex will check this
-    pub token_metadata_program: UncheckedAccount<'info>,
-}

+ 54 - 0
tokens/transfer-tokens/anchor/programs/transfer-tokens/src/instructions/mint.rs

@@ -0,0 +1,54 @@
+use {
+    anchor_lang::prelude::*,
+    anchor_spl::{
+        associated_token::AssociatedToken,
+        token::{mint_to, Mint, MintTo, Token, TokenAccount},
+    },
+};
+
+#[derive(Accounts)]
+pub struct MintToken<'info> {
+    #[account(mut)]
+    pub mint_authority: Signer<'info>,
+
+    pub recepient: SystemAccount<'info>,
+    #[account(mut)]
+    pub mint_account: Account<'info, Mint>,
+    #[account(
+        init_if_needed,
+        payer = mint_authority,
+        associated_token::mint = mint_account,
+        associated_token::authority = recepient,
+    )]
+    pub associated_token_account: Account<'info, TokenAccount>,
+
+    pub token_program: Program<'info, Token>,
+    pub associated_token_program: Program<'info, AssociatedToken>,
+    pub system_program: Program<'info, System>,
+}
+
+pub fn mint_token(ctx: Context<MintToken>, amount: u64) -> Result<()> {
+    msg!("Minting tokens to associated token account...");
+    msg!("Mint: {}", &ctx.accounts.mint_account.key());
+    msg!(
+        "Token Address: {}",
+        &ctx.accounts.associated_token_account.key()
+    );
+
+    // Invoke the mint_to instruction on the token program
+    mint_to(
+        CpiContext::new(
+            ctx.accounts.token_program.to_account_info(),
+            MintTo {
+                mint: ctx.accounts.mint_account.to_account_info(),
+                to: ctx.accounts.associated_token_account.to_account_info(),
+                authority: ctx.accounts.mint_authority.to_account_info(),
+            },
+        ),
+        amount * 10u64.pow(ctx.accounts.mint_account.decimals as u32), // Mint tokens
+    )?;
+
+    msg!("Token minted successfully.");
+
+    Ok(())
+}

+ 0 - 126
tokens/transfer-tokens/anchor/programs/transfer-tokens/src/instructions/mint_nft.rs

@@ -1,126 +0,0 @@
-use {
-    anchor_lang::{prelude::*, solana_program::program::invoke},
-    anchor_spl::{associated_token, token},
-    mpl_token_metadata::instruction as mpl_instruction,
-    // spl_token::instruction::AuthorityType,
-};
-
-pub fn mint_nft(ctx: Context<MintNft>) -> Result<()> {
-    // Mint the NFT to the user's wallet
-    //
-    msg!("Minting NFT to associated token account...");
-    msg!(
-        "Mint: {}",
-        &ctx.accounts.mint_account.to_account_info().key()
-    );
-    msg!(
-        "Token Address: {}",
-        &ctx.accounts.associated_token_account.key()
-    );
-    token::mint_to(
-        CpiContext::new(
-            ctx.accounts.token_program.to_account_info(),
-            token::MintTo {
-                mint: ctx.accounts.mint_account.to_account_info(),
-                to: ctx.accounts.associated_token_account.to_account_info(),
-                authority: ctx.accounts.mint_authority.to_account_info(),
-            },
-        ),
-        1,
-    )?;
-
-    // We can make this a Limited Edition NFT through Metaplex,
-    //      which will disable minting by setting the Mint & Freeze Authorities to the
-    //      Edition Account.
-    //
-    msg!("Creating edition account...");
-    msg!(
-        "Edition account address: {}",
-        ctx.accounts.edition_account.key()
-    );
-    invoke(
-        &mpl_instruction::create_master_edition_v3(
-            ctx.accounts.token_metadata_program.key(), // Program ID
-            ctx.accounts.edition_account.key(),        // Edition
-            ctx.accounts.mint_account.key(),           // Mint
-            ctx.accounts.mint_authority.key(),         // Update Authority
-            ctx.accounts.mint_authority.key(),         // Mint Authority
-            ctx.accounts.metadata_account.key(),       // Metadata
-            ctx.accounts.payer.key(),                  // Payer
-            Some(1),                                   // Max Supply
-        ),
-        &[
-            ctx.accounts.edition_account.to_account_info(),
-            ctx.accounts.metadata_account.to_account_info(),
-            ctx.accounts.mint_account.to_account_info(),
-            ctx.accounts.mint_authority.to_account_info(),
-            ctx.accounts.payer.to_account_info(),
-            ctx.accounts.token_metadata_program.to_account_info(),
-            ctx.accounts.rent.to_account_info(),
-        ],
-    )?;
-
-    // If we don't use Metaplex Editions, we must disable minting manually
-    // -------------------------------------------------------------------
-    //
-    // msg!("Disabling future minting of this NFT...");
-    // token::set_authority(
-    //     CpiContext::new(
-    //         ctx.accounts.token_program.to_account_info(),
-    //         token::SetAuthority {
-    //             current_authority: ctx.accounts.payer.to_account_info(),
-    //             account_or_mint: ctx.accounts.mint_account.to_account_info(),
-    //         },
-    //     ),
-    //     AuthorityType::MintTokens,
-    //     None,
-    // )?;
-    // token::set_authority(
-    //     CpiContext::new(
-    //         ctx.accounts.token_program.to_account_info(),
-    //         token::SetAuthority {
-    //             current_authority: ctx.accounts.payer.to_account_info(),
-    //             account_or_mint: ctx.accounts.mint_account.to_account_info(),
-    //         },
-    //     ),
-    //     AuthorityType::FreezeAccount,
-    //     None,
-    // )?;
-
-    msg!("NFT minted successfully.");
-
-    Ok(())
-}
-
-#[derive(Accounts)]
-pub struct MintNft<'info> {
-    /// CHECK: Metaplex will check this
-    #[account(mut)]
-    pub edition_account: UncheckedAccount<'info>,
-    /// CHECK: Metaplex will check this
-    #[account(mut)]
-    pub metadata_account: UncheckedAccount<'info>,
-    #[account(
-        mut,
-        mint::decimals = 0,
-        mint::authority = mint_authority.key(),
-        mint::freeze_authority = mint_authority.key(),
-    )]
-    pub mint_account: Account<'info, token::Mint>,
-    pub mint_authority: SystemAccount<'info>,
-    #[account(
-        init_if_needed,
-        payer = payer,
-        associated_token::mint = mint_account,
-        associated_token::authority = payer,
-    )]
-    pub associated_token_account: Account<'info, token::TokenAccount>,
-    #[account(mut)]
-    pub payer: Signer<'info>,
-    pub rent: Sysvar<'info, Rent>,
-    pub system_program: Program<'info, System>,
-    pub token_program: Program<'info, token::Token>,
-    pub associated_token_program: Program<'info, associated_token::AssociatedToken>,
-    /// CHECK: Metaplex will check this
-    pub token_metadata_program: UncheckedAccount<'info>,
-}

+ 0 - 55
tokens/transfer-tokens/anchor/programs/transfer-tokens/src/instructions/mint_spl.rs

@@ -1,55 +0,0 @@
-use {
-    anchor_lang::prelude::*,
-    anchor_spl::{associated_token, token},
-};
-
-pub fn mint_spl(ctx: Context<MintSpl>, quantity: u64) -> Result<()> {
-    msg!("Minting token to token account...");
-    msg!(
-        "Mint: {}",
-        &ctx.accounts.mint_account.to_account_info().key()
-    );
-    msg!(
-        "Token Address: {}",
-        &ctx.accounts.associated_token_account.key()
-    );
-    token::mint_to(
-        CpiContext::new(
-            ctx.accounts.token_program.to_account_info(),
-            token::MintTo {
-                mint: ctx.accounts.mint_account.to_account_info(),
-                to: ctx.accounts.associated_token_account.to_account_info(),
-                authority: ctx.accounts.mint_authority.to_account_info(),
-            },
-        ),
-        quantity,
-    )?;
-
-    msg!("Token minted to wallet successfully.");
-
-    Ok(())
-}
-
-#[derive(Accounts)]
-pub struct MintSpl<'info> {
-    #[account(
-        mut,
-        mint::decimals = 9,
-        mint::authority = mint_authority.key(),
-    )]
-    pub mint_account: Account<'info, token::Mint>,
-    pub mint_authority: SystemAccount<'info>,
-    #[account(
-        init_if_needed,
-        payer = payer,
-        associated_token::mint = mint_account,
-        associated_token::authority = payer,
-    )]
-    pub associated_token_account: Account<'info, token::TokenAccount>,
-    #[account(mut)]
-    pub payer: Signer<'info>,
-    pub rent: Sysvar<'info, Rent>,
-    pub system_program: Program<'info, System>,
-    pub token_program: Program<'info, token::Token>,
-    pub associated_token_program: Program<'info, associated_token::AssociatedToken>,
-}

+ 2 - 4
tokens/transfer-tokens/anchor/programs/transfer-tokens/src/instructions/mod.rs

@@ -1,9 +1,7 @@
 pub mod create;
-pub mod mint_nft;
-pub mod mint_spl;
+pub mod mint;
 pub mod transfer;
 
 pub use create::*;
-pub use mint_nft::*;
-pub use mint_spl::*;
+pub use mint::*;
 pub use transfer::*;

+ 42 - 38
tokens/transfer-tokens/anchor/programs/transfer-tokens/src/instructions/transfer.rs

@@ -1,9 +1,39 @@
 use {
     anchor_lang::prelude::*,
-    anchor_spl::{associated_token, token},
+    anchor_spl::{
+        associated_token::AssociatedToken,
+        token::{transfer, Mint, Token, TokenAccount, Transfer},
+    },
 };
 
-pub fn transfer_tokens(ctx: Context<TransferTokens>, quantity: u64) -> Result<()> {
+#[derive(Accounts)]
+pub struct TransferTokens<'info> {
+    #[account(mut)]
+    pub sender: Signer<'info>,
+    pub recipient: SystemAccount<'info>,
+
+    #[account(mut)]
+    pub mint_account: Account<'info, Mint>,
+    #[account(
+        mut,
+        associated_token::mint = mint_account,
+        associated_token::authority = sender,
+    )]
+    pub sender_token_account: Account<'info, TokenAccount>,
+    #[account(
+        init_if_needed,
+        payer = sender,
+        associated_token::mint = mint_account,
+        associated_token::authority = recipient,
+    )]
+    pub recipient_token_account: Account<'info, TokenAccount>,
+
+    pub token_program: Program<'info, Token>,
+    pub associated_token_program: Program<'info, AssociatedToken>,
+    pub system_program: Program<'info, System>,
+}
+
+pub fn transfer_tokens(ctx: Context<TransferTokens>, amount: u64) -> Result<()> {
     msg!("Transferring tokens...");
     msg!(
         "Mint: {}",
@@ -11,53 +41,27 @@ pub fn transfer_tokens(ctx: Context<TransferTokens>, quantity: u64) -> Result<()
     );
     msg!(
         "From Token Address: {}",
-        &ctx.accounts.from_associated_token_account.key()
+        &ctx.accounts.sender_token_account.key()
     );
     msg!(
         "To Token Address: {}",
-        &ctx.accounts.to_associated_token_account.key()
+        &ctx.accounts.recipient_token_account.key()
     );
-    token::transfer(
+
+    // Invoke the transfer instruction on the token program
+    transfer(
         CpiContext::new(
             ctx.accounts.token_program.to_account_info(),
-            token::Transfer {
-                from: ctx.accounts.from_associated_token_account.to_account_info(),
-                to: ctx.accounts.to_associated_token_account.to_account_info(),
-                authority: ctx.accounts.owner.to_account_info(),
+            Transfer {
+                from: ctx.accounts.sender_token_account.to_account_info(),
+                to: ctx.accounts.recipient_token_account.to_account_info(),
+                authority: ctx.accounts.sender.to_account_info(),
             },
         ),
-        quantity,
+        amount * 10u64.pow(ctx.accounts.mint_account.decimals as u32), // Transfer amount, adjust for decimals
     )?;
 
     msg!("Tokens transferred successfully.");
 
     Ok(())
 }
-
-#[derive(Accounts)]
-pub struct TransferTokens<'info> {
-    #[account(mut)]
-    pub mint_account: Account<'info, token::Mint>,
-    #[account(
-        init_if_needed,
-        payer = payer,
-        associated_token::mint = mint_account,
-        associated_token::authority = owner,
-    )]
-    pub from_associated_token_account: Account<'info, token::TokenAccount>,
-    pub owner: SystemAccount<'info>,
-    #[account(
-        init_if_needed,
-        payer = payer,
-        associated_token::mint = mint_account,
-        associated_token::authority = recipient,
-    )]
-    pub to_associated_token_account: Account<'info, token::TokenAccount>,
-    pub recipient: SystemAccount<'info>,
-    #[account(mut)]
-    pub payer: Signer<'info>,
-    pub rent: Sysvar<'info, Rent>,
-    pub system_program: Program<'info, System>,
-    pub token_program: Program<'info, token::Token>,
-    pub associated_token_program: Program<'info, associated_token::AssociatedToken>,
-}

+ 6 - 11
tokens/transfer-tokens/anchor/programs/transfer-tokens/src/lib.rs

@@ -6,7 +6,7 @@ pub mod instructions;
 
 use instructions::*;
 
-declare_id!("7p8osL5uUKUFM8sUxRYfmFVGN264PxeBSDEdNv36Khe3");
+declare_id!("2W7B8C5skxyVaAA1LfYAsRHiv26LL5j88GJ9XYyybWqc");
 
 #[program]
 pub mod transfer_tokens {
@@ -17,20 +17,15 @@ pub mod transfer_tokens {
         token_title: String,
         token_symbol: String,
         token_uri: String,
-        decimals: u8,
     ) -> Result<()> {
-        create::create_token(ctx, token_title, token_symbol, token_uri, decimals)
+        create::create_token(ctx, token_title, token_symbol, token_uri)
     }
 
-    pub fn mint_spl(ctx: Context<MintSpl>, quantity: u64) -> Result<()> {
-        mint_spl::mint_spl(ctx, quantity)
+    pub fn mint_token(ctx: Context<MintToken>, amount: u64) -> Result<()> {
+        mint::mint_token(ctx, amount)
     }
 
-    pub fn mint_nft(ctx: Context<MintNft>) -> Result<()> {
-        mint_nft::mint_nft(ctx)
-    }
-
-    pub fn transfer_tokens(ctx: Context<TransferTokens>, quantity: u64) -> Result<()> {
-        transfer::transfer_tokens(ctx, quantity)
+    pub fn transfer_tokens(ctx: Context<TransferTokens>, amount: u64) -> Result<()> {
+        transfer::transfer_tokens(ctx, amount)
     }
 }

+ 77 - 201
tokens/transfer-tokens/anchor/tests/test.ts

@@ -1,245 +1,121 @@
-import { 
-  PROGRAM_ID as TOKEN_METADATA_PROGRAM_ID
-} from '@metaplex-foundation/mpl-token-metadata';
-import * as anchor from "@project-serum/anchor";
-import { ASSOCIATED_PROGRAM_ID } from '@project-serum/anchor/dist/cjs/utils/token';
+import { PROGRAM_ID as TOKEN_METADATA_PROGRAM_ID } from "@metaplex-foundation/mpl-token-metadata";
+import * as anchor from "@coral-xyz/anchor";
 import { TransferTokens } from "../target/types/transfer_tokens";
-
+import {
+  PublicKey,
+  Keypair,
+  SYSVAR_RENT_PUBKEY,
+  SystemProgram,
+} from "@solana/web3.js";
+import {
+  getAssociatedTokenAddressSync,
+  ASSOCIATED_TOKEN_PROGRAM_ID,
+  TOKEN_PROGRAM_ID,
+} from "@solana/spl-token";
 
 describe("Transfer Tokens", () => {
-  
   const provider = anchor.AnchorProvider.env();
   anchor.setProvider(provider);
   const payer = provider.wallet as anchor.Wallet;
-  const program = anchor.workspace.TransferTokens as anchor.Program<TransferTokens>;
+  const program = anchor.workspace
+    .TransferTokens as anchor.Program<TransferTokens>;
 
-  const tokenMintKeypair: anchor.web3.Keypair = anchor.web3.Keypair.generate();
-  const nftMintKeypair: anchor.web3.Keypair = anchor.web3.Keypair.generate();
-  
-  const recipientWallet: anchor.web3.Keypair = anchor.web3.Keypair.generate();
+  const metadata = {
+    name: "Solana Gold",
+    symbol: "GOLDSOL",
+    uri: "https://raw.githubusercontent.com/solana-developers/program-examples/new-examples/tokens/tokens/.assets/spl-token.json",
+  };
 
-  it("Create an SPL Token!", async () => {
+  // Generate new keypair to use as address for mint account.
+  const mintKeypair = new Keypair();
 
-    const metadataAddress = anchor.web3.PublicKey.findProgramAddressSync(
-      [
-        Buffer.from("metadata"),
-        TOKEN_METADATA_PROGRAM_ID.toBuffer(),
-        tokenMintKeypair.publicKey.toBuffer(),
-      ],
-      TOKEN_METADATA_PROGRAM_ID
-    )[0];
+  // Generate new keypair to use as address for recipient wallet.
+  const recipient = new Keypair();
 
-    const sx = await program.methods.createToken(
-      "Solana Gold",
-      "GOLDSOL",
-      "https://raw.githubusercontent.com/solana-developers/program-examples/new-examples/tokens/tokens/.assets/spl-token.json",
-      9,
-    )
-      .accounts({
-        metadataAccount: metadataAddress,
-        mintAccount: tokenMintKeypair.publicKey,
-        mintAuthority: payer.publicKey,
-        payer: payer.publicKey,
-        rent: anchor.web3.SYSVAR_RENT_PUBKEY,
-        systemProgram: anchor.web3.SystemProgram.programId,
-        tokenProgram: anchor.utils.token.TOKEN_PROGRAM_ID,
-        tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID,
-      })
-      .signers([tokenMintKeypair, payer.payer])
-      .rpc();
+  // Derive the associated token address account for the mint and payer.
+  const senderTokenAddress = getAssociatedTokenAddressSync(
+    mintKeypair.publicKey,
+    payer.publicKey
+  );
 
-    console.log("Success!");
-        console.log(`   Mint Address: ${tokenMintKeypair.publicKey}`);
-        console.log(`   Tx Signature: ${sx}`);
-  });
+  // Derive the associated token address account for the mint and recipient.
+  const recepientTokenAddress = getAssociatedTokenAddressSync(
+    mintKeypair.publicKey,
+    recipient.publicKey
+  );
 
-  it("Create an NFT!", async () => {
-
-    const metadataAddress = anchor.web3.PublicKey.findProgramAddressSync(
+  it("Create an SPL Token!", async () => {
+    // Derive the metadata account address.
+    const [metadataAddress] = PublicKey.findProgramAddressSync(
       [
         Buffer.from("metadata"),
         TOKEN_METADATA_PROGRAM_ID.toBuffer(),
-        nftMintKeypair.publicKey.toBuffer(),
+        mintKeypair.publicKey.toBuffer(),
       ],
       TOKEN_METADATA_PROGRAM_ID
-    )[0];
+    );
 
-    const sx = await program.methods.createToken(
-      "Homer NFT",
-      "HOMR",
-      "https://raw.githubusercontent.com/solana-developers/program-examples/new-examples/tokens/tokens/.assets/nft.json",
-      0,
-    )
+    const transactionSignature = await program.methods
+      .createToken(metadata.name, metadata.symbol, metadata.uri)
       .accounts({
-        metadataAccount: metadataAddress,
-        mintAccount: nftMintKeypair.publicKey,
-        mintAuthority: payer.publicKey,
         payer: payer.publicKey,
-        rent: anchor.web3.SYSVAR_RENT_PUBKEY,
-        systemProgram: anchor.web3.SystemProgram.programId,
-        tokenProgram: anchor.utils.token.TOKEN_PROGRAM_ID,
+        mintAccount: mintKeypair.publicKey,
+        metadataAccount: metadataAddress,
+        tokenProgram: TOKEN_PROGRAM_ID,
         tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID,
+        systemProgram: SystemProgram.programId,
+        rent: SYSVAR_RENT_PUBKEY,
       })
-      .signers([nftMintKeypair, payer.payer])
+      .signers([mintKeypair])
       .rpc();
 
     console.log("Success!");
-        console.log(`   Mint Address: ${nftMintKeypair.publicKey}`);
-        console.log(`   Tx Signature: ${sx}`);
+    console.log(`   Mint Address: ${mintKeypair.publicKey}`);
+    console.log(`   Transaction Signature: ${transactionSignature}`);
   });
 
-  it("Mint some tokens to your wallet!", async () => {
-
-    const associatedTokenAccountAddress = await anchor.utils.token.associatedAddress({
-      mint: tokenMintKeypair.publicKey,
-      owner: payer.publicKey,
-    });
+  it("Mint tokens!", async () => {
+    // Amount of tokens to mint.
+    const amount = new anchor.BN(100);
 
-    const sx = await program.methods.mintSpl(
-      new anchor.BN(150)
-    )
+    // Mint the tokens to the associated token account.
+    const transactionSignature = await program.methods
+      .mintToken(amount)
       .accounts({
-        associatedTokenAccount: associatedTokenAccountAddress,
-        mintAccount: tokenMintKeypair.publicKey,
         mintAuthority: payer.publicKey,
-        payer: payer.publicKey,
-        rent: anchor.web3.SYSVAR_RENT_PUBKEY,
-        systemProgram: anchor.web3.SystemProgram.programId,
-        tokenProgram: anchor.utils.token.TOKEN_PROGRAM_ID,
-        associatedTokenProgram: ASSOCIATED_PROGRAM_ID,
+        recepient: payer.publicKey,
+        mintAccount: mintKeypair.publicKey,
+        associatedTokenAccount: senderTokenAddress,
+        tokenProgram: TOKEN_PROGRAM_ID,
+        associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
+        systemProgram: SystemProgram.programId,
       })
-      .signers([payer.payer])
       .rpc();
 
     console.log("Success!");
-        console.log(`   Mint Address: ${tokenMintKeypair.publicKey}`);
-        console.log(`   Tx Signature: ${sx}`);
+    console.log(`   Associated Token Account Address: ${senderTokenAddress}`);
+    console.log(`   Transaction Signature: ${transactionSignature}`);
   });
 
-  it("Mint the NFT to your wallet!", async () => {
-
-    const metadataAddress = (anchor.web3.PublicKey.findProgramAddressSync(
-        [
-          Buffer.from("metadata"),
-          TOKEN_METADATA_PROGRAM_ID.toBuffer(),
-          nftMintKeypair.publicKey.toBuffer(),
-        ],
-        TOKEN_METADATA_PROGRAM_ID
-    ))[0];
-
-    const editionAddress = (anchor.web3.PublicKey.findProgramAddressSync(
-        [
-          Buffer.from("metadata"),
-          TOKEN_METADATA_PROGRAM_ID.toBuffer(),
-          nftMintKeypair.publicKey.toBuffer(),
-          Buffer.from("edition"),
-        ],
-        TOKEN_METADATA_PROGRAM_ID
-    ))[0];
-
-    const associatedTokenAccountAddress = await anchor.utils.token.associatedAddress({
-      mint: nftMintKeypair.publicKey,
-      owner: payer.publicKey,
-    });
+  it("Transfer tokens!", async () => {
+    // Amount of tokens to transfer.
+    const amount = new anchor.BN(50);
 
-    const sx = await program.methods.mintNft()
+    const transactionSignature = await program.methods
+      .transferTokens(amount)
       .accounts({
-        associatedTokenAccount: associatedTokenAccountAddress,
-        editionAccount: editionAddress,
-        metadataAccount: metadataAddress,
-        mintAccount: nftMintKeypair.publicKey,
-        mintAuthority: payer.publicKey,
-        payer: payer.publicKey,
-        rent: anchor.web3.SYSVAR_RENT_PUBKEY,
-        systemProgram: anchor.web3.SystemProgram.programId,
-        tokenProgram: anchor.utils.token.TOKEN_PROGRAM_ID,
-        associatedTokenProgram: ASSOCIATED_PROGRAM_ID,
-        tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID,
-      })
-      .signers([payer.payer])
-      .rpc();
-
-      console.log("Success!");
-      console.log(`   ATA Address: ${associatedTokenAccountAddress}`);
-      console.log(`   Tx Signature: ${sx}`);
-  });
-
-  it("Prep a new test wallet for transfers", async () => {
-        
-    await provider.connection.confirmTransaction(
-        await provider.connection.requestAirdrop(
-            recipientWallet.publicKey, 
-            await provider.connection.getMinimumBalanceForRentExemption(0),
-        )
-    );
-    console.log(`Recipient Pubkey: ${recipientWallet.publicKey}`);
-  });
-
-  it("Transfer some tokens to another wallet!", async () => {
-
-    const fromAssociatedTokenAccountAddress = await anchor.utils.token.associatedAddress({
-      mint: tokenMintKeypair.publicKey,
-      owner: payer.publicKey,
-    });
-    const toAssociatedTokenAccountAddress = await anchor.utils.token.associatedAddress({
-      mint: tokenMintKeypair.publicKey,
-      owner: recipientWallet.publicKey,
-    });
-
-    const sx = await program.methods.transferTokens(
-      new anchor.BN(150)
-    )
-      .accounts({
-        mintAccount: tokenMintKeypair.publicKey,
-        fromAssociatedTokenAccount: fromAssociatedTokenAccountAddress,
-        owner: payer.publicKey,
-        toAssociatedTokenAccount: toAssociatedTokenAccountAddress,
-        recipient: recipientWallet.publicKey,
-        payer: payer.publicKey,
-        rent: anchor.web3.SYSVAR_RENT_PUBKEY,
-        systemProgram: anchor.web3.SystemProgram.programId,
-        tokenProgram: anchor.utils.token.TOKEN_PROGRAM_ID,
-        associatedTokenProgram: ASSOCIATED_PROGRAM_ID,
-      })
-      .signers([payer.payer])
-      .rpc();
-
-    console.log("Success!");
-        console.log(`   Mint Address: ${tokenMintKeypair.publicKey}`);
-        console.log(`   Tx Signature: ${sx}`);
-  });
-
-  it("Transfer the NFT to another wallet!", async () => {
-
-    const fromAssociatedTokenAccountAddress = await anchor.utils.token.associatedAddress({
-      mint: nftMintKeypair.publicKey,
-      owner: payer.publicKey,
-    });
-    const toAssociatedTokenAccountAddress = await anchor.utils.token.associatedAddress({
-      mint: nftMintKeypair.publicKey,
-      owner: recipientWallet.publicKey,
-    });
-
-    const sx = await program.methods.transferTokens(
-      new anchor.BN(1)
-    )
-      .accounts({
-        mintAccount: nftMintKeypair.publicKey,
-        fromAssociatedTokenAccount: fromAssociatedTokenAccountAddress,
-        owner: payer.publicKey,
-        toAssociatedTokenAccount: toAssociatedTokenAccountAddress,
-        recipient: recipientWallet.publicKey,
-        payer: payer.publicKey,
-        rent: anchor.web3.SYSVAR_RENT_PUBKEY,
-        systemProgram: anchor.web3.SystemProgram.programId,
-        tokenProgram: anchor.utils.token.TOKEN_PROGRAM_ID,
-        associatedTokenProgram: ASSOCIATED_PROGRAM_ID,
+        sender: payer.publicKey,
+        recipient: recipient.publicKey,
+        mintAccount: mintKeypair.publicKey,
+        senderTokenAccount: senderTokenAddress,
+        recipientTokenAccount: recepientTokenAddress,
+        tokenProgram: TOKEN_PROGRAM_ID,
+        associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
+        systemProgram: SystemProgram.programId,
       })
-      .signers([payer.payer])
       .rpc();
 
     console.log("Success!");
-        console.log(`   Mint Address: ${nftMintKeypair.publicKey}`);
-        console.log(`   Tx Signature: ${sx}`);
+    console.log(`   Transaction Signature: ${transactionSignature}`);
   });
 });