misc.js 14 KB

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