token-proxy.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. const anchor = require("@coral-xyz/anchor");
  2. const { assert } = require("chai");
  3. const {
  4. splTokenProgram,
  5. SPL_TOKEN_PROGRAM_ID,
  6. } = require("@coral-xyz/spl-token");
  7. describe("program", () => {
  8. const provider = anchor.AnchorProvider.local();
  9. const TEST_PROGRAM_IDS = [
  10. SPL_TOKEN_PROGRAM_ID,
  11. new anchor.web3.PublicKey("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"),
  12. ];
  13. const TOKEN_PROGRAMS = TEST_PROGRAM_IDS.map((programId) =>
  14. splTokenProgram({
  15. provider,
  16. programId,
  17. })
  18. );
  19. // Configure the client to use the local cluster.
  20. anchor.setProvider(provider);
  21. const program = anchor.workspace.TokenProxy;
  22. TOKEN_PROGRAMS.forEach((tokenProgram) => {
  23. const name = tokenProgram.programId.equals(SPL_TOKEN_PROGRAM_ID)
  24. ? "token"
  25. : "token-2022";
  26. describe(name, () => {
  27. let mint = null;
  28. let from = null;
  29. let to = null;
  30. it("Initializes test state", async () => {
  31. mint = await createMint(tokenProgram);
  32. from = await createTokenAccount(
  33. tokenProgram,
  34. mint,
  35. provider.wallet.publicKey
  36. );
  37. to = await createTokenAccount(
  38. tokenProgram,
  39. mint,
  40. provider.wallet.publicKey
  41. );
  42. });
  43. it("Creates a token account", async () => {
  44. const newMint = await createMint(tokenProgram);
  45. const authority = provider.wallet.publicKey;
  46. const [tokenAccount] = anchor.web3.PublicKey.findProgramAddressSync(
  47. [
  48. authority.toBytes(),
  49. newMint.toBytes(),
  50. Buffer.from("token-proxy-account"),
  51. ],
  52. program.programId
  53. );
  54. await program.rpc.proxyCreateTokenAccount({
  55. accounts: {
  56. authority,
  57. mint: newMint,
  58. tokenAccount,
  59. systemProgram: anchor.web3.SystemProgram.programId,
  60. tokenProgram: tokenProgram.programId,
  61. },
  62. });
  63. const account = await getTokenAccount(provider, tokenAccount);
  64. assert.isTrue(account.amount.eq(new anchor.BN(0)));
  65. });
  66. it("Creates an associated token account", async () => {
  67. const newMint = await createMint(tokenProgram);
  68. const authority = provider.wallet.publicKey;
  69. const associatedTokenProgram = new anchor.web3.PublicKey(
  70. "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"
  71. );
  72. const [tokenAccount] = anchor.web3.PublicKey.findProgramAddressSync(
  73. [
  74. authority.toBytes(),
  75. tokenProgram.programId.toBytes(),
  76. newMint.toBytes(),
  77. ],
  78. associatedTokenProgram
  79. );
  80. await program.rpc.proxyCreateAssociatedTokenAccount({
  81. accounts: {
  82. tokenAccount,
  83. mint: newMint,
  84. authority,
  85. systemProgram: anchor.web3.SystemProgram.programId,
  86. tokenProgram: tokenProgram.programId,
  87. associatedTokenProgram,
  88. },
  89. });
  90. const account = await getTokenAccount(provider, tokenAccount);
  91. assert.isTrue(account.amount.eq(new anchor.BN(0)));
  92. });
  93. it("Creates a mint", async () => {
  94. const authority = provider.wallet.publicKey;
  95. const [newMint] = anchor.web3.PublicKey.findProgramAddressSync(
  96. [
  97. authority.toBytes(),
  98. Buffer.from(name),
  99. Buffer.from("token-proxy-mint"),
  100. ],
  101. program.programId
  102. );
  103. await program.rpc.proxyCreateMint(name, {
  104. accounts: {
  105. authority,
  106. mint: newMint,
  107. systemProgram: anchor.web3.SystemProgram.programId,
  108. tokenProgram: tokenProgram.programId,
  109. },
  110. });
  111. });
  112. it("Mints a token", async () => {
  113. await program.rpc.proxyMintTo(new anchor.BN(1000), {
  114. accounts: {
  115. authority: provider.wallet.publicKey,
  116. mint,
  117. to: from,
  118. tokenProgram: tokenProgram.programId,
  119. },
  120. });
  121. const fromAccount = await getTokenAccount(provider, from);
  122. assert.isTrue(fromAccount.amount.eq(new anchor.BN(1000)));
  123. });
  124. it("Transfers a token", async () => {
  125. const preFromAccount = await getTokenAccount(provider, from);
  126. const preToAccount = await getTokenAccount(provider, to);
  127. const transferAmount = new anchor.BN(400);
  128. await program.rpc.proxyTransfer(transferAmount, {
  129. accounts: {
  130. authority: provider.wallet.publicKey,
  131. to,
  132. from,
  133. tokenProgram: tokenProgram.programId,
  134. },
  135. });
  136. const postFromAccount = await getTokenAccount(provider, from);
  137. const postToAccount = await getTokenAccount(provider, to);
  138. assert.isTrue(
  139. postFromAccount.amount.eq(preFromAccount.amount.sub(transferAmount))
  140. );
  141. assert.isTrue(
  142. postToAccount.amount.eq(preToAccount.amount.add(transferAmount))
  143. );
  144. });
  145. it("Transfers a token with optional accounts", async () => {
  146. const preFromAccount = await getTokenAccount(provider, from);
  147. const preToAccount = await getTokenAccount(provider, to);
  148. const transferAmount = new anchor.BN(10);
  149. await program.rpc.proxyOptionalTransfer(transferAmount, {
  150. accounts: {
  151. authority: provider.wallet.publicKey,
  152. to,
  153. from,
  154. mint,
  155. tokenProgram: tokenProgram.programId,
  156. },
  157. });
  158. const postFromAccount = await getTokenAccount(provider, from);
  159. const postToAccount = await getTokenAccount(provider, to);
  160. assert.isTrue(
  161. postFromAccount.amount.eq(preFromAccount.amount.sub(transferAmount))
  162. );
  163. assert.isTrue(
  164. postToAccount.amount.eq(preToAccount.amount.add(transferAmount))
  165. );
  166. });
  167. it("Does not transfer a token without optional accounts", async () => {
  168. const preFromAccount = await getTokenAccount(provider, from);
  169. const preToAccount = await getTokenAccount(provider, to);
  170. const optionalTransferIx = await program.methods
  171. .proxyOptionalTransfer(new anchor.BN(10))
  172. .accounts({
  173. authority: provider.wallet.publicKey,
  174. to,
  175. from,
  176. mint: null,
  177. tokenProgram: null,
  178. })
  179. .instruction();
  180. const tx = new anchor.web3.Transaction().add(optionalTransferIx);
  181. await provider.sendAndConfirm(tx);
  182. const postFromAccount = await getTokenAccount(provider, from);
  183. const postToAccount = await getTokenAccount(provider, to);
  184. assert.isTrue(postFromAccount.amount.eq(preFromAccount.amount));
  185. assert.isTrue(postToAccount.amount.eq(preToAccount.amount));
  186. });
  187. it("Burns a token", async () => {
  188. const preAccount = await getTokenAccount(provider, to);
  189. const burnAmount = new anchor.BN(300);
  190. await program.rpc.proxyBurn(burnAmount, {
  191. accounts: {
  192. authority: provider.wallet.publicKey,
  193. mint,
  194. from: to,
  195. tokenProgram: tokenProgram.programId,
  196. },
  197. });
  198. const postAccount = await getTokenAccount(provider, to);
  199. assert.isTrue(postAccount.amount.eq(preAccount.amount.sub(burnAmount)));
  200. });
  201. it("Set new mint authority", async () => {
  202. const newMintAuthority = anchor.web3.Keypair.generate();
  203. await program.rpc.proxySetAuthority(
  204. { mintTokens: {} },
  205. newMintAuthority.publicKey,
  206. {
  207. accounts: {
  208. accountOrMint: mint,
  209. currentAuthority: provider.wallet.publicKey,
  210. tokenProgram: tokenProgram.programId,
  211. },
  212. }
  213. );
  214. const mintInfo = await getMintInfo(provider, mint);
  215. assert.isTrue(
  216. mintInfo.mintAuthority.equals(newMintAuthority.publicKey)
  217. );
  218. });
  219. });
  220. });
  221. });
  222. // SPL token client boilerplate for test initialization. Everything below here is
  223. // mostly irrelevant to the point of the example.
  224. const serumCmn = require("@project-serum/common");
  225. async function getTokenAccount(provider, addr) {
  226. return await serumCmn.getTokenAccount(provider, addr);
  227. }
  228. async function getMintInfo(provider, mintAddr) {
  229. return await serumCmn.getMintInfo(provider, mintAddr);
  230. }
  231. async function createMint(tokenProgram) {
  232. const mint = anchor.web3.Keypair.generate();
  233. const authority = tokenProgram.provider.wallet.publicKey;
  234. const createMintIx = await tokenProgram.account.mint.createInstruction(mint);
  235. const initMintIx = await tokenProgram.methods
  236. .initializeMint2(0, authority, null)
  237. .accounts({ mint: mint.publicKey })
  238. .instruction();
  239. const tx = new anchor.web3.Transaction();
  240. tx.add(createMintIx, initMintIx);
  241. await tokenProgram.provider.sendAndConfirm(tx, [mint]);
  242. return mint.publicKey;
  243. }
  244. async function createTokenAccount(tokenProgram, mint, owner) {
  245. const vault = anchor.web3.Keypair.generate();
  246. const tx = new anchor.web3.Transaction();
  247. const createTokenAccountIx =
  248. await tokenProgram.account.account.createInstruction(vault);
  249. const initTokenAccountIx = await tokenProgram.methods
  250. .initializeAccount3(owner)
  251. .accounts({ account: vault.publicKey, mint })
  252. .instruction();
  253. tx.add(createTokenAccountIx, initTokenAccountIx);
  254. await tokenProgram.provider.sendAndConfirm(tx, [vault]);
  255. return vault.publicKey;
  256. }