misc.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. const anchor = require("@project-serum/anchor");
  2. const PublicKey = anchor.web3.PublicKey;
  3. const assert = require("assert");
  4. const { TOKEN_PROGRAM_ID, Token } = require("@solana/spl-token");
  5. describe("misc", () => {
  6. // Configure the client to use the local cluster.
  7. anchor.setProvider(anchor.Provider.env());
  8. const program = anchor.workspace.Misc;
  9. const misc2Program = anchor.workspace.Misc2;
  10. it("Can allocate extra space for a state constructor", async () => {
  11. const tx = await program.state.rpc.new();
  12. const addr = await program.state.address();
  13. const state = await program.state.fetch();
  14. const accountInfo = await program.provider.connection.getAccountInfo(addr);
  15. assert.ok(state.v.equals(Buffer.from([])));
  16. assert.ok(accountInfo.data.length === 99);
  17. });
  18. it("Can use remaining accounts for a state instruction", async () => {
  19. await program.state.rpc.remainingAccounts({
  20. remainingAccounts: [
  21. { pubkey: misc2Program.programId, isWritable: false, isSigner: false },
  22. ],
  23. });
  24. });
  25. const data = anchor.web3.Keypair.generate();
  26. it("Can use u128 and i128", async () => {
  27. const tx = await program.rpc.initialize(
  28. new anchor.BN(1234),
  29. new anchor.BN(22),
  30. {
  31. accounts: {
  32. data: data.publicKey,
  33. rent: anchor.web3.SYSVAR_RENT_PUBKEY,
  34. },
  35. signers: [data],
  36. instructions: [await program.account.data.createInstruction(data)],
  37. }
  38. );
  39. const dataAccount = await program.account.data.fetch(data.publicKey);
  40. assert.ok(dataAccount.udata.eq(new anchor.BN(1234)));
  41. assert.ok(dataAccount.idata.eq(new anchor.BN(22)));
  42. });
  43. it("Can use u16", async () => {
  44. const data = anchor.web3.Keypair.generate();
  45. const tx = await program.rpc.testU16(99, {
  46. accounts: {
  47. myAccount: data.publicKey,
  48. rent: anchor.web3.SYSVAR_RENT_PUBKEY,
  49. },
  50. signers: [data],
  51. instructions: [await program.account.dataU16.createInstruction(data)],
  52. });
  53. const dataAccount = await program.account.dataU16.fetch(data.publicKey);
  54. assert.ok(dataAccount.data === 99);
  55. });
  56. it("Can embed programs into genesis from the Anchor.toml", async () => {
  57. const pid = new anchor.web3.PublicKey(
  58. "FtMNMKp9DZHKWUyVAsj3Q5QV8ow4P3fUPP7ZrWEQJzKr"
  59. );
  60. let accInfo = await anchor.getProvider().connection.getAccountInfo(pid);
  61. assert.ok(accInfo.executable);
  62. });
  63. it("Can use the owner constraint", async () => {
  64. await program.rpc.testOwner({
  65. accounts: {
  66. data: data.publicKey,
  67. misc: program.programId,
  68. },
  69. });
  70. await assert.rejects(
  71. async () => {
  72. await program.rpc.testOwner({
  73. accounts: {
  74. data: program.provider.wallet.publicKey,
  75. misc: program.programId,
  76. },
  77. });
  78. },
  79. (err) => {
  80. return true;
  81. }
  82. );
  83. });
  84. it("Can use the executable attribute", async () => {
  85. await program.rpc.testExecutable({
  86. accounts: {
  87. program: program.programId,
  88. },
  89. });
  90. await assert.rejects(
  91. async () => {
  92. await program.rpc.testExecutable({
  93. accounts: {
  94. program: program.provider.wallet.publicKey,
  95. },
  96. });
  97. },
  98. (err) => {
  99. return true;
  100. }
  101. );
  102. });
  103. it("Can CPI to state instructions", async () => {
  104. const oldData = new anchor.BN(0);
  105. await misc2Program.state.rpc.new({
  106. accounts: {
  107. authority: program.provider.wallet.publicKey,
  108. },
  109. });
  110. let stateAccount = await misc2Program.state.fetch();
  111. assert.ok(stateAccount.data.eq(oldData));
  112. assert.ok(stateAccount.auth.equals(program.provider.wallet.publicKey));
  113. const newData = new anchor.BN(2134);
  114. await program.rpc.testStateCpi(newData, {
  115. accounts: {
  116. authority: program.provider.wallet.publicKey,
  117. cpiState: await misc2Program.state.address(),
  118. misc2Program: misc2Program.programId,
  119. },
  120. });
  121. stateAccount = await misc2Program.state.fetch();
  122. assert.ok(stateAccount.data.eq(newData));
  123. assert.ok(stateAccount.auth.equals(program.provider.wallet.publicKey));
  124. });
  125. it("Can init an associated program account", async () => {
  126. const state = await program.state.address();
  127. // Manual associated address calculation for test only. Clients should use
  128. // the generated methods.
  129. const [
  130. associatedAccount,
  131. nonce,
  132. ] = await anchor.web3.PublicKey.findProgramAddress(
  133. [
  134. anchor.utils.bytes.utf8.encode("anchor"),
  135. program.provider.wallet.publicKey.toBuffer(),
  136. state.toBuffer(),
  137. data.publicKey.toBuffer(),
  138. anchor.utils.bytes.utf8.encode("my-seed"),
  139. ],
  140. program.programId
  141. );
  142. await assert.rejects(
  143. async () => {
  144. await program.account.testData.fetch(associatedAccount);
  145. },
  146. (err) => {
  147. assert.ok(
  148. err.toString() ===
  149. `Error: Account does not exist ${associatedAccount.toString()}`
  150. );
  151. return true;
  152. }
  153. );
  154. await program.rpc.testInitAssociatedAccount(new anchor.BN(1234), {
  155. accounts: {
  156. myAccount: associatedAccount,
  157. authority: program.provider.wallet.publicKey,
  158. state,
  159. data: data.publicKey,
  160. rent: anchor.web3.SYSVAR_RENT_PUBKEY,
  161. systemProgram: anchor.web3.SystemProgram.programId,
  162. },
  163. });
  164. // Try out the generated associated method.
  165. const account = await program.account.testData.associated(
  166. program.provider.wallet.publicKey,
  167. state,
  168. data.publicKey,
  169. anchor.utils.bytes.utf8.encode("my-seed")
  170. );
  171. assert.ok(account.data.toNumber() === 1234);
  172. });
  173. it("Can use an associated program account", async () => {
  174. const state = await program.state.address();
  175. const [
  176. associatedAccount,
  177. nonce,
  178. ] = await anchor.web3.PublicKey.findProgramAddress(
  179. [
  180. anchor.utils.bytes.utf8.encode("anchor"),
  181. program.provider.wallet.publicKey.toBuffer(),
  182. state.toBuffer(),
  183. data.publicKey.toBuffer(),
  184. anchor.utils.bytes.utf8.encode("my-seed"),
  185. ],
  186. program.programId
  187. );
  188. await program.rpc.testAssociatedAccount(new anchor.BN(5), {
  189. accounts: {
  190. myAccount: associatedAccount,
  191. authority: program.provider.wallet.publicKey,
  192. state,
  193. data: data.publicKey,
  194. },
  195. });
  196. // Try out the generated associated method.
  197. const account = await program.account.testData.associated(
  198. program.provider.wallet.publicKey,
  199. state,
  200. data.publicKey,
  201. anchor.utils.bytes.utf8.encode("my-seed")
  202. );
  203. assert.ok(account.data.toNumber() === 5);
  204. });
  205. it("Can retrieve events when simulating a transaction", async () => {
  206. const resp = await program.simulate.testSimulate(44);
  207. const expectedRaw = [
  208. "Program Z2Ddx1Lcd8CHTV9tkWtNnFQrSz6kxz2H38wrr18zZRZ invoke [1]",
  209. "Program log: NgyCA9omwbMsAAAA",
  210. "Program log: fPhuIELK/k7SBAAA",
  211. "Program log: jvbowsvlmkcJAAAA",
  212. "Program Z2Ddx1Lcd8CHTV9tkWtNnFQrSz6kxz2H38wrr18zZRZ consumed 4819 of 200000 compute units",
  213. "Program Z2Ddx1Lcd8CHTV9tkWtNnFQrSz6kxz2H38wrr18zZRZ success",
  214. ];
  215. assert.ok(JSON.stringify(expectedRaw), resp.raw);
  216. assert.ok(resp.events[0].name === "E1");
  217. assert.ok(resp.events[0].data.data === 44);
  218. assert.ok(resp.events[1].name === "E2");
  219. assert.ok(resp.events[1].data.data === 1234);
  220. assert.ok(resp.events[2].name === "E3");
  221. assert.ok(resp.events[2].data.data === 9);
  222. });
  223. it("Can retrieve events when associated account is initialized in simulated transaction", async () => {
  224. const myAccount = await program.account.testData.associatedAddress(
  225. program.provider.wallet.publicKey
  226. );
  227. await assert.rejects(
  228. async () => {
  229. await program.account.testData.fetch(myAccount);
  230. },
  231. (err) => {
  232. assert.ok(
  233. err.toString() ===
  234. `Error: Account does not exist ${myAccount.toString()}`
  235. );
  236. return true;
  237. }
  238. );
  239. const resp = await program.simulate.testSimulateAssociatedAccount(44, {
  240. accounts: {
  241. myAccount,
  242. authority: program.provider.wallet.publicKey,
  243. rent: anchor.web3.SYSVAR_RENT_PUBKEY,
  244. systemProgram: anchor.web3.SystemProgram.programId,
  245. },
  246. });
  247. const expectedRaw = [
  248. "Program Fv6oRfzWETatiMymBvTs1JpRspZz3DbBfjZJEvUTDL1g invoke [1]",
  249. "Program 11111111111111111111111111111111 invoke [2]",
  250. "Program 11111111111111111111111111111111 success",
  251. "Program log: NgyCA9omwbMsAAAA",
  252. "Program log: fPhuIELK/k7SBAAA",
  253. "Program log: jvbowsvlmkcJAAAA",
  254. "Program log: mg+zq/K0sXRV+N/AsG9XLERDZ+J6eQAnnzoQVHlicBQBnGr65KE5Kw==",
  255. "Program Fv6oRfzWETatiMymBvTs1JpRspZz3DbBfjZJEvUTDL1g consumed 20460 of 200000 compute units",
  256. "Program Fv6oRfzWETatiMymBvTs1JpRspZz3DbBfjZJEvUTDL1g success",
  257. ];
  258. assert.ok(JSON.stringify(expectedRaw), resp.raw);
  259. assert.ok(resp.events[0].name === "E1");
  260. assert.ok(resp.events[0].data.data === 44);
  261. assert.ok(resp.events[1].name === "E2");
  262. assert.ok(resp.events[1].data.data === 1234);
  263. assert.ok(resp.events[2].name === "E3");
  264. assert.ok(resp.events[2].data.data === 9);
  265. assert.ok(resp.events[3].name === "E4");
  266. assert.ok(resp.events[3].data.data.toBase58() === myAccount.toBase58());
  267. });
  268. it("Can use i8 in the idl", async () => {
  269. const data = anchor.web3.Keypair.generate();
  270. await program.rpc.testI8(-3, {
  271. accounts: {
  272. data: data.publicKey,
  273. rent: anchor.web3.SYSVAR_RENT_PUBKEY,
  274. },
  275. instructions: [await program.account.dataI8.createInstruction(data)],
  276. signers: [data],
  277. });
  278. const dataAccount = await program.account.dataI8.fetch(data.publicKey);
  279. assert.ok(dataAccount.data === -3);
  280. });
  281. let dataPubkey;
  282. it("Can use i16 in the idl", async () => {
  283. const data = anchor.web3.Keypair.generate();
  284. await program.rpc.testI16(-2048, {
  285. accounts: {
  286. data: data.publicKey,
  287. rent: anchor.web3.SYSVAR_RENT_PUBKEY,
  288. },
  289. instructions: [await program.account.dataI16.createInstruction(data)],
  290. signers: [data],
  291. });
  292. const dataAccount = await program.account.dataI16.fetch(data.publicKey);
  293. assert.ok(dataAccount.data === -2048);
  294. dataPubkey = data.publicKey;
  295. });
  296. it("Can use base58 strings to fetch an account", async () => {
  297. const dataAccount = await program.account.dataI16.fetch(
  298. dataPubkey.toString()
  299. );
  300. assert.ok(dataAccount.data === -2048);
  301. });
  302. it("Should fail to close an account when sending lamports to itself", async () => {
  303. try {
  304. await program.rpc.testClose({
  305. accounts: {
  306. data: data.publicKey,
  307. solDest: data.publicKey,
  308. },
  309. });
  310. assert.ok(false);
  311. } catch (err) {
  312. const errMsg = "A close constraint was violated";
  313. assert.equal(err.toString(), errMsg);
  314. assert.equal(err.msg, errMsg);
  315. assert.equal(err.code, 151);
  316. }
  317. });
  318. it("Can close an account", async () => {
  319. const openAccount = await program.provider.connection.getAccountInfo(
  320. data.publicKey
  321. );
  322. assert.ok(openAccount !== null);
  323. let beforeBalance = (
  324. await program.provider.connection.getAccountInfo(
  325. program.provider.wallet.publicKey
  326. )
  327. ).lamports;
  328. await program.rpc.testClose({
  329. accounts: {
  330. data: data.publicKey,
  331. solDest: program.provider.wallet.publicKey,
  332. },
  333. });
  334. let afterBalance = (
  335. await program.provider.connection.getAccountInfo(
  336. program.provider.wallet.publicKey
  337. )
  338. ).lamports;
  339. // Retrieved rent exemption sol.
  340. assert.ok(afterBalance > beforeBalance);
  341. const closedAccount = await program.provider.connection.getAccountInfo(
  342. data.publicKey
  343. );
  344. assert.ok(closedAccount === null);
  345. });
  346. it("Can use instruction data in accounts constraints", async () => {
  347. // b"my-seed"
  348. const seed = Buffer.from([109, 121, 45, 115, 101, 101, 100]);
  349. const [myPda, nonce] = await PublicKey.findProgramAddress(
  350. [seed, anchor.web3.SYSVAR_RENT_PUBKEY.toBuffer()],
  351. program.programId
  352. );
  353. await program.rpc.testInstructionConstraint(nonce, {
  354. accounts: {
  355. myPda,
  356. myAccount: anchor.web3.SYSVAR_RENT_PUBKEY,
  357. },
  358. });
  359. });
  360. it("Can create a PDA account with instruction data", async () => {
  361. const seed = Buffer.from([1, 2, 3, 4]);
  362. const domain = "my-domain";
  363. const foo = anchor.web3.SYSVAR_RENT_PUBKEY;
  364. const [myPda, nonce] = await PublicKey.findProgramAddress(
  365. [
  366. Buffer.from(anchor.utils.bytes.utf8.encode("my-seed")),
  367. Buffer.from(anchor.utils.bytes.utf8.encode(domain)),
  368. foo.toBuffer(),
  369. seed,
  370. ],
  371. program.programId
  372. );
  373. await program.rpc.testPdaInit(domain, seed, nonce, {
  374. accounts: {
  375. myPda,
  376. myPayer: program.provider.wallet.publicKey,
  377. foo,
  378. rent: anchor.web3.SYSVAR_RENT_PUBKEY,
  379. systemProgram: anchor.web3.SystemProgram.programId,
  380. },
  381. });
  382. const myPdaAccount = await program.account.dataU16.fetch(myPda);
  383. assert.ok(myPdaAccount.data === 6);
  384. });
  385. it("Can create a zero copy PDA account", async () => {
  386. const [myPda, nonce] = await PublicKey.findProgramAddress(
  387. [Buffer.from(anchor.utils.bytes.utf8.encode("my-seed"))],
  388. program.programId
  389. );
  390. await program.rpc.testPdaInitZeroCopy(nonce, {
  391. accounts: {
  392. myPda,
  393. myPayer: program.provider.wallet.publicKey,
  394. rent: anchor.web3.SYSVAR_RENT_PUBKEY,
  395. systemProgram: anchor.web3.SystemProgram.programId,
  396. },
  397. });
  398. const myPdaAccount = await program.account.dataZeroCopy.fetch(myPda);
  399. assert.ok(myPdaAccount.data === 9);
  400. assert.ok((myPdaAccount.bump = nonce));
  401. });
  402. it("Can write to a zero copy PDA account", async () => {
  403. const [myPda, bump] = await PublicKey.findProgramAddress(
  404. [Buffer.from(anchor.utils.bytes.utf8.encode("my-seed"))],
  405. program.programId
  406. );
  407. await program.rpc.testPdaMutZeroCopy({
  408. accounts: {
  409. myPda,
  410. myPayer: program.provider.wallet.publicKey,
  411. },
  412. });
  413. const myPdaAccount = await program.account.dataZeroCopy.fetch(myPda);
  414. assert.ok(myPdaAccount.data === 1234);
  415. assert.ok((myPdaAccount.bump = bump));
  416. });
  417. it("Can create a token account from seeds pda", async () => {
  418. const mint = await Token.createMint(
  419. program.provider.connection,
  420. program.provider.wallet.payer,
  421. program.provider.wallet.publicKey,
  422. null,
  423. 0,
  424. TOKEN_PROGRAM_ID
  425. );
  426. const [myPda, bump] = await PublicKey.findProgramAddress(
  427. [Buffer.from(anchor.utils.bytes.utf8.encode("my-token-seed"))],
  428. program.programId
  429. );
  430. await program.rpc.testTokenSeedsInit(bump, {
  431. accounts: {
  432. myPda,
  433. mint: mint.publicKey,
  434. authority: program.provider.wallet.publicKey,
  435. systemProgram: anchor.web3.SystemProgram.programId,
  436. rent: anchor.web3.SYSVAR_RENT_PUBKEY,
  437. tokenProgram: TOKEN_PROGRAM_ID,
  438. },
  439. });
  440. const account = await mint.getAccountInfo(myPda);
  441. assert.ok(account.state === 1);
  442. assert.ok(account.amount.toNumber() === 0);
  443. assert.ok(account.isInitialized);
  444. assert.ok(account.owner.equals(program.provider.wallet.publicKey));
  445. assert.ok(account.mint.equals(mint.publicKey));
  446. });
  447. it("Can execute a fallback function", async () => {
  448. await assert.rejects(
  449. async () => {
  450. await anchor.utils.rpc.invoke(program.programId);
  451. },
  452. (err) => {
  453. assert.ok(err.toString().includes("custom program error: 0x4d2"));
  454. return true;
  455. }
  456. );
  457. });
  458. });