bolt.ts 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618
  1. import * as anchor from "@coral-xyz/anchor";
  2. import { type Program } from "@coral-xyz/anchor";
  3. import { type PublicKey } from "@solana/web3.js";
  4. import { type Position } from "../target/types/position";
  5. import { type Velocity } from "../target/types/velocity";
  6. import { type BoltComponent } from "../target/types/bolt_component";
  7. import { type SystemSimpleMovement } from "../target/types/system_simple_movement";
  8. import { type SystemFly } from "../target/types/system_fly";
  9. import { type SystemApplyVelocity } from "../target/types/system_apply_velocity";
  10. import { type World } from "../target/types/world";
  11. import { expect } from "chai";
  12. import BN from "bn.js";
  13. import {
  14. createInitializeRegistryInstruction,
  15. FindComponentPda,
  16. FindEntityPda,
  17. FindWorldPda,
  18. FindWorldRegistryPda,
  19. SYSVAR_INSTRUCTIONS_PUBKEY,
  20. } from "../clients/bolt-sdk";
  21. enum Direction {
  22. Left = "Left",
  23. Right = "Right",
  24. Up = "Up",
  25. Down = "Down",
  26. }
  27. function serializeArgs(args: any = {}) {
  28. const jsonString = JSON.stringify(args);
  29. const encoder = new TextEncoder();
  30. const binaryData = encoder.encode(jsonString);
  31. return Buffer.from(
  32. binaryData.buffer,
  33. binaryData.byteOffset,
  34. binaryData.byteLength
  35. );
  36. }
  37. describe("bolt", () => {
  38. const provider = anchor.AnchorProvider.env();
  39. anchor.setProvider(provider);
  40. const worldProgram = anchor.workspace.World as Program<World>;
  41. const boltComponentPositionProgram = anchor.workspace
  42. .Position as Program<Position>;
  43. const boltComponentVelocityProgram = anchor.workspace
  44. .Velocity as Program<Velocity>;
  45. const boltComponentProgramOrigin = anchor.workspace
  46. .BoltComponent as Program<BoltComponent>;
  47. const systemSimpleMovement = (
  48. anchor.workspace.SystemSimpleMovement as Program<SystemSimpleMovement>
  49. ).programId;
  50. const systemFly = (anchor.workspace.SystemFly as Program<SystemFly>)
  51. .programId;
  52. const applyVelocity = (
  53. anchor.workspace.SystemApplyVelocity as Program<SystemApplyVelocity>
  54. ).programId;
  55. let entity1: PublicKey;
  56. let entity2: PublicKey;
  57. let entity5: PublicKey;
  58. let componentPositionEntity1: PublicKey;
  59. let componentPositionEntity2: PublicKey;
  60. let componentPositionEntity5: PublicKey;
  61. let componentVelocityEntity1: PublicKey;
  62. it("InitializeWorldsRegistry", async () => {
  63. const registryPda = FindWorldRegistryPda(worldProgram.programId);
  64. const initializeRegistryIx = createInitializeRegistryInstruction({
  65. registry: registryPda,
  66. payer: provider.wallet.publicKey,
  67. });
  68. const tx = new anchor.web3.Transaction().add(initializeRegistryIx);
  69. await provider.sendAndConfirm(tx);
  70. });
  71. it("InitializeNewWorld", async () => {
  72. const registryPda = FindWorldRegistryPda(worldProgram.programId);
  73. const worldPda = FindWorldPda(new BN(0), worldProgram.programId);
  74. await worldProgram.methods
  75. .initializeNewWorld()
  76. .accounts({
  77. world: worldPda,
  78. registry: registryPda,
  79. payer: provider.wallet.publicKey,
  80. })
  81. .rpc();
  82. });
  83. it("InitializeNewWorld 2", async () => {
  84. const registryPda = FindWorldRegistryPda(worldProgram.programId);
  85. const worldPda = FindWorldPda(new BN(1), worldProgram.programId);
  86. await worldProgram.methods
  87. .initializeNewWorld()
  88. .accounts({
  89. world: worldPda,
  90. registry: registryPda,
  91. payer: provider.wallet.publicKey,
  92. })
  93. .rpc();
  94. });
  95. it("Add entity 1", async () => {
  96. const worldPda = FindWorldPda(new BN(0), worldProgram.programId);
  97. entity1 = FindEntityPda(new BN(0), new BN(0), null, worldProgram.programId);
  98. await worldProgram.methods
  99. .addEntity(null)
  100. .accounts({
  101. world: worldPda,
  102. entity: entity1,
  103. payer: provider.wallet.publicKey,
  104. })
  105. .rpc();
  106. });
  107. it("Add entity 2", async () => {
  108. const worldPda = FindWorldPda(new BN(0), worldProgram.programId);
  109. entity2 = FindEntityPda(new BN(0), new BN(1), null, worldProgram.programId);
  110. await worldProgram.methods
  111. .addEntity(null)
  112. .accounts({
  113. world: worldPda,
  114. entity: entity2,
  115. payer: provider.wallet.publicKey,
  116. })
  117. .rpc();
  118. });
  119. it("Add entity 3", async () => {
  120. const worldPda = FindWorldPda(new BN(0), worldProgram.programId);
  121. const entityPda = FindEntityPda(
  122. new BN(0),
  123. new BN(2),
  124. null,
  125. worldProgram.programId
  126. );
  127. await worldProgram.methods
  128. .addEntity(null)
  129. .accounts({
  130. world: worldPda,
  131. entity: entityPda,
  132. payer: provider.wallet.publicKey,
  133. })
  134. .rpc();
  135. });
  136. it("Add entity 4 with extra seeds", async () => {
  137. const worldPda = FindWorldPda(new BN(0), worldProgram.programId);
  138. const seed = "extra-seed";
  139. const entity4 = FindEntityPda(
  140. new BN(0),
  141. new BN(3),
  142. seed,
  143. worldProgram.programId
  144. );
  145. await worldProgram.methods
  146. .addEntity(seed)
  147. .accounts({
  148. world: worldPda,
  149. entity: entity4,
  150. payer: provider.wallet.publicKey,
  151. })
  152. .rpc();
  153. });
  154. it("Add entity 5", async () => {
  155. const worldPda = FindWorldPda(new BN(0), worldProgram.programId);
  156. entity5 = FindEntityPda(new BN(0), new BN(4), null, worldProgram.programId);
  157. await worldProgram.methods
  158. .addEntity(null)
  159. .accounts({
  160. world: worldPda,
  161. entity: entity5,
  162. payer: provider.wallet.publicKey,
  163. })
  164. .rpc();
  165. });
  166. it("Initialize Original Component on Entity 1, trough the world instance", async () => {
  167. const componentEntity1 = FindComponentPda(
  168. boltComponentProgramOrigin.programId,
  169. entity1,
  170. "origin-component"
  171. );
  172. await worldProgram.methods
  173. .initializeComponent()
  174. .accounts({
  175. payer: provider.wallet.publicKey,
  176. data: componentEntity1,
  177. componentProgram: boltComponentProgramOrigin.programId,
  178. entity: entity1,
  179. instructionSysvarAccount: SYSVAR_INSTRUCTIONS_PUBKEY,
  180. authority: provider.wallet.publicKey,
  181. })
  182. .rpc();
  183. });
  184. it("Initialize Original Component on Entity 2, trough the world instance", async () => {
  185. const componentEntity2 = FindComponentPda(
  186. boltComponentProgramOrigin.programId,
  187. entity2,
  188. "origin-component"
  189. );
  190. await worldProgram.methods
  191. .initializeComponent()
  192. .accounts({
  193. payer: provider.wallet.publicKey,
  194. data: componentEntity2,
  195. componentProgram: boltComponentProgramOrigin.programId,
  196. entity: entity2,
  197. instructionSysvarAccount: SYSVAR_INSTRUCTIONS_PUBKEY,
  198. authority: provider.wallet.publicKey,
  199. })
  200. .rpc();
  201. });
  202. it("Initialize Position Component on Entity 1", async () => {
  203. componentPositionEntity1 = FindComponentPda(
  204. boltComponentPositionProgram.programId,
  205. entity1
  206. );
  207. console.log("Component Position E1: ", componentPositionEntity1.toBase58());
  208. await worldProgram.methods
  209. .initializeComponent()
  210. .accounts({
  211. payer: provider.wallet.publicKey,
  212. data: componentPositionEntity1,
  213. componentProgram: boltComponentPositionProgram.programId,
  214. entity: entity1,
  215. instructionSysvarAccount: SYSVAR_INSTRUCTIONS_PUBKEY,
  216. authority: worldProgram.programId,
  217. })
  218. .rpc();
  219. });
  220. it("Initialize Velocity Component on Entity 1", async () => {
  221. componentVelocityEntity1 = FindComponentPda(
  222. boltComponentVelocityProgram.programId,
  223. entity1,
  224. "component-velocity"
  225. );
  226. await worldProgram.methods
  227. .initializeComponent()
  228. .accounts({
  229. payer: provider.wallet.publicKey,
  230. data: componentVelocityEntity1,
  231. componentProgram: boltComponentVelocityProgram.programId,
  232. entity: entity1,
  233. instructionSysvarAccount: SYSVAR_INSTRUCTIONS_PUBKEY,
  234. authority: worldProgram.programId,
  235. })
  236. .rpc();
  237. });
  238. it("Initialize Position Component on Entity 2", async () => {
  239. componentPositionEntity2 = FindComponentPda(
  240. boltComponentPositionProgram.programId,
  241. entity2
  242. );
  243. await worldProgram.methods
  244. .initializeComponent()
  245. .accounts({
  246. payer: provider.wallet.publicKey,
  247. data: componentPositionEntity2,
  248. componentProgram: boltComponentPositionProgram.programId,
  249. entity: entity2,
  250. instructionSysvarAccount: SYSVAR_INSTRUCTIONS_PUBKEY,
  251. authority: worldProgram.programId,
  252. })
  253. .rpc();
  254. });
  255. it("Initialize Position Component on Entity 5", async () => {
  256. componentPositionEntity5 = FindComponentPda(
  257. boltComponentPositionProgram.programId,
  258. entity5
  259. );
  260. await worldProgram.methods
  261. .initializeComponent()
  262. .accounts({
  263. payer: provider.wallet.publicKey,
  264. data: componentPositionEntity5,
  265. componentProgram: boltComponentPositionProgram.programId,
  266. entity: entity5,
  267. instructionSysvarAccount: SYSVAR_INSTRUCTIONS_PUBKEY,
  268. authority: provider.wallet.publicKey,
  269. })
  270. .rpc();
  271. });
  272. it("Check Position on Entity 1 is default", async () => {
  273. expect(
  274. (
  275. await boltComponentPositionProgram.account.position.fetch(
  276. componentPositionEntity1
  277. )
  278. ).x.toNumber()
  279. ).to.equal(0);
  280. expect(
  281. (
  282. await boltComponentPositionProgram.account.position.fetch(
  283. componentPositionEntity1
  284. )
  285. ).y.toNumber()
  286. ).to.equal(0);
  287. expect(
  288. (
  289. await boltComponentPositionProgram.account.position.fetch(
  290. componentPositionEntity1
  291. )
  292. ).z.toNumber()
  293. ).to.equal(0);
  294. });
  295. it("Simple Movement System and Up direction on Entity 1", async () => {
  296. const args = {
  297. direction: Direction.Up,
  298. };
  299. await worldProgram.methods
  300. .apply(serializeArgs(args)) // Move Up
  301. .accounts({
  302. componentProgram: boltComponentPositionProgram.programId,
  303. boltSystem: systemSimpleMovement,
  304. boltComponent: componentPositionEntity1,
  305. instructionSysvarAccount: SYSVAR_INSTRUCTIONS_PUBKEY,
  306. authority: worldProgram.programId,
  307. })
  308. .rpc({ skipPreflight: true });
  309. expect(
  310. (
  311. await boltComponentPositionProgram.account.position.fetch(
  312. componentPositionEntity1
  313. )
  314. ).y.toNumber()
  315. ).to.equal(1);
  316. const componentData =
  317. await boltComponentPositionProgram.account.position.fetch(
  318. componentPositionEntity1
  319. );
  320. const x = componentData.x.toNumber();
  321. const y = componentData.y.toNumber();
  322. const z = componentData.z.toNumber();
  323. console.log("+-----------------------------+");
  324. console.log("| Movement System: Entity 1 |");
  325. console.log("+----------------+------------+");
  326. console.log("| Coordinate | Value |");
  327. console.log("+----------------+------------+");
  328. console.log(`| X Position | ${String(x).padEnd(10, " ")} |`);
  329. console.log("| | |");
  330. console.log(`| Y Position | ${String(y).padEnd(10, " ")} |`);
  331. console.log("| | |");
  332. console.log(`| Z Position | ${String(z).padEnd(10, " ")} |`);
  333. console.log("+----------------+------------+");
  334. console.log("| |");
  335. console.log("+-----------------------------+");
  336. console.log("Component Position: ", componentPositionEntity1.toString());
  337. });
  338. it("Simple Movement System and Right direction on Entity 1", async () => {
  339. const args = {
  340. direction: Direction.Right,
  341. };
  342. await worldProgram.methods
  343. .apply(serializeArgs(args)) // Move Right
  344. .accounts({
  345. componentProgram: boltComponentPositionProgram.programId,
  346. boltSystem: systemSimpleMovement,
  347. boltComponent: componentPositionEntity1,
  348. instructionSysvarAccount: SYSVAR_INSTRUCTIONS_PUBKEY,
  349. authority: worldProgram.programId,
  350. })
  351. .rpc();
  352. expect(
  353. (
  354. await boltComponentPositionProgram.account.position.fetch(
  355. componentPositionEntity1
  356. )
  357. ).y.toNumber()
  358. ).to.equal(1);
  359. expect(
  360. (
  361. await boltComponentPositionProgram.account.position.fetch(
  362. componentPositionEntity1
  363. )
  364. ).y.toNumber()
  365. ).to.equal(1);
  366. const componentData =
  367. await boltComponentPositionProgram.account.position.fetch(
  368. componentPositionEntity1
  369. );
  370. const x = componentData.x.toNumber();
  371. const y = componentData.y.toNumber();
  372. const z = componentData.z.toNumber();
  373. console.log("+-----------------------------+");
  374. console.log("| Movement System: Entity 1 |");
  375. console.log("+----------------+------------+");
  376. console.log("| Coordinate | Value |");
  377. console.log("+----------------+------------+");
  378. console.log(`| X Position | ${String(x).padEnd(10, " ")} |`);
  379. console.log("| | |");
  380. console.log(`| Y Position | ${String(y).padEnd(10, " ")} |`);
  381. console.log("| | |");
  382. console.log(`| Z Position | ${String(z).padEnd(10, " ")} |`);
  383. console.log("+----------------+------------+");
  384. console.log("| |");
  385. console.log("+-----------------------------+");
  386. });
  387. it("Fly System on Entity 1", async () => {
  388. await worldProgram.methods
  389. .apply(Buffer.alloc(0)) // Move Up
  390. .accounts({
  391. componentProgram: boltComponentPositionProgram.programId,
  392. boltSystem: systemFly,
  393. boltComponent: componentPositionEntity1,
  394. instructionSysvarAccount: SYSVAR_INSTRUCTIONS_PUBKEY,
  395. authority: worldProgram.programId,
  396. })
  397. .rpc();
  398. expect(
  399. (
  400. await boltComponentPositionProgram.account.position.fetch(
  401. componentPositionEntity1
  402. )
  403. ).z.toNumber()
  404. ).to.equal(1);
  405. const componentData =
  406. await boltComponentPositionProgram.account.position.fetch(
  407. componentPositionEntity1
  408. );
  409. const x = componentData.x.toNumber();
  410. const y = componentData.y.toNumber();
  411. const z = componentData.z.toNumber();
  412. console.log("+-----------------------------+");
  413. console.log("| Fly: Position Entity 1 |");
  414. console.log("+----------------+------------+");
  415. console.log("| Coordinate | Value |");
  416. console.log("+----------------+------------+");
  417. console.log(`| X Position | ${String(x).padEnd(10, " ")} |`);
  418. console.log("| | |");
  419. console.log(`| Y Position | ${String(y).padEnd(10, " ")} |`);
  420. console.log("| | |");
  421. console.log(`| Z Position | ${String(z).padEnd(10, " ")} |`);
  422. console.log("+----------------+------------+");
  423. console.log("| |");
  424. console.log("+-----------------------------+");
  425. });
  426. it("Apply Velocity on Entity 1", async () => {
  427. await worldProgram.methods
  428. .apply2(Buffer.alloc(0))
  429. .accounts({
  430. componentProgram1: boltComponentVelocityProgram.programId,
  431. componentProgram2: boltComponentPositionProgram.programId,
  432. boltSystem: applyVelocity,
  433. boltComponent1: componentVelocityEntity1,
  434. boltComponent2: componentPositionEntity1,
  435. instructionSysvarAccount: SYSVAR_INSTRUCTIONS_PUBKEY,
  436. authority: worldProgram.programId,
  437. })
  438. .remainingAccounts([
  439. {
  440. pubkey: componentPositionEntity1,
  441. isWritable: false,
  442. isSigner: false,
  443. },
  444. ])
  445. .rpc();
  446. console.log("Component Velocity: ", componentVelocityEntity1.toBase58());
  447. const componentData =
  448. await boltComponentVelocityProgram.account.velocity.fetch(
  449. componentVelocityEntity1
  450. );
  451. let x = componentData.x.toNumber();
  452. let y = componentData.y.toNumber();
  453. let z = componentData.z.toNumber();
  454. const tmp = componentData.lastApplied.toNumber();
  455. console.log("+-----------------------------+");
  456. console.log("| Apply Velocity: Velocity Entity 1 |");
  457. console.log("+----------------+------------+");
  458. console.log("| Coordinate | Value |");
  459. console.log("+----------------+------------+");
  460. console.log(`| X Position | ${String(x).padEnd(10, " ")} |`);
  461. console.log("| | |");
  462. console.log(`| Y Position | ${String(y).padEnd(10, " ")} |`);
  463. console.log("| | |");
  464. console.log(`| Z Position | ${String(z).padEnd(10, " ")} |`);
  465. console.log("| | |");
  466. console.log(`| Timestamp | ${String(tmp).padEnd(10, " ")} |`);
  467. console.log("+----------------+------------+");
  468. console.log("| |");
  469. console.log("+-----------------------------+");
  470. const positionData =
  471. await boltComponentPositionProgram.account.position.fetch(
  472. componentPositionEntity1
  473. );
  474. x = positionData.x.toNumber();
  475. y = positionData.y.toNumber();
  476. z = positionData.z.toNumber();
  477. console.log("+-----------------------------+");
  478. console.log("| Apply Velocity: Position Entity 1 |");
  479. console.log("+----------------+------------+");
  480. console.log("| Coordinate | Value |");
  481. console.log("+----------------+------------+");
  482. console.log(`| X Position | ${String(x).padEnd(10, " ")} |`);
  483. console.log("| | |");
  484. console.log(`| Y Position | ${String(y).padEnd(10, " ")} |`);
  485. console.log("| | |");
  486. console.log(`| Z Position | ${String(z).padEnd(10, " ")} |`);
  487. console.log("+----------------+------------+");
  488. console.log("| |");
  489. console.log("+-----------------------------+");
  490. });
  491. // Check illegal authority usage
  492. it("Check invalid component update", async () => {
  493. const componentDataPrev =
  494. await boltComponentPositionProgram.account.position.fetch(
  495. componentPositionEntity5
  496. );
  497. try {
  498. await worldProgram.methods
  499. .apply(Buffer.alloc(0)) // Move Up
  500. .accounts({
  501. componentProgram: boltComponentPositionProgram.programId,
  502. boltSystem: systemFly,
  503. boltComponent: componentPositionEntity5,
  504. instructionSysvarAccount: SYSVAR_INSTRUCTIONS_PUBKEY,
  505. authority: worldProgram.programId,
  506. })
  507. .rpc();
  508. } catch (e) {
  509. expect(e.message).to.contain("Invalid authority");
  510. }
  511. const componentData =
  512. await boltComponentPositionProgram.account.position.fetch(
  513. componentPositionEntity5
  514. );
  515. expect(
  516. componentDataPrev.x.toNumber() === componentData.x.toNumber() &&
  517. componentDataPrev.y.toNumber() === componentData.y.toNumber() &&
  518. componentDataPrev.z.toNumber() === componentData.z.toNumber()
  519. ).to.equal(true);
  520. });
  521. // Check illegal call, without CPI
  522. it("Check invalid init without CPI", async () => {
  523. let invalid = false;
  524. const componentVelocityEntity5 = FindComponentPda(
  525. boltComponentVelocityProgram.programId,
  526. entity5
  527. );
  528. try {
  529. await boltComponentProgramOrigin.methods
  530. .initialize()
  531. .accounts({
  532. payer: provider.wallet.publicKey,
  533. data: componentVelocityEntity5,
  534. entity: entity5,
  535. instructionSysvarAccount: SYSVAR_INSTRUCTIONS_PUBKEY,
  536. systemProgram: anchor.web3.SystemProgram.programId,
  537. authority: provider.wallet.publicKey,
  538. })
  539. .rpc();
  540. } catch (e) {
  541. invalid = true;
  542. }
  543. expect(invalid).to.equal(true);
  544. });
  545. // Check illegal call, without CPI
  546. it("Check invalid update without CPI", async () => {
  547. let invalid = false;
  548. const componentVelocityEntity5 = FindComponentPda(
  549. boltComponentVelocityProgram.programId,
  550. entity5
  551. );
  552. try {
  553. await boltComponentProgramOrigin.methods
  554. .update(null)
  555. .accounts({
  556. boltComponent: componentVelocityEntity5,
  557. instructionSysvarAccount: SYSVAR_INSTRUCTIONS_PUBKEY,
  558. authority: provider.wallet.publicKey,
  559. })
  560. .rpc();
  561. } catch (e) {
  562. invalid = true;
  563. }
  564. expect(invalid).to.equal(true);
  565. });
  566. });