bolt.low-level.api.ts 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870
  1. import { Keypair, type PublicKey } from "@solana/web3.js";
  2. import { type Position } from "../target/types/position";
  3. import { type Velocity } from "../target/types/velocity";
  4. import { type BoltComponent } from "../target/types/bolt_component";
  5. import { type SystemSimpleMovement } from "../target/types/system_simple_movement";
  6. import { type SystemFly } from "../target/types/system_fly";
  7. import { type SystemApplyVelocity } from "../target/types/system_apply_velocity";
  8. import { expect } from "chai";
  9. import BN from "bn.js";
  10. import {
  11. DELEGATION_PROGRAM_ID,
  12. DelegateComponent,
  13. type Program,
  14. anchor,
  15. web3,
  16. FindRegistryPda,
  17. FindWorldPda,
  18. FindEntityPda,
  19. FindComponentPda,
  20. SerializeArgs,
  21. WORLD_PROGRAM_IDL as World,
  22. } from "../clients/bolt-sdk";
  23. enum Direction {
  24. Left = "Left",
  25. Right = "Right",
  26. Up = "Up",
  27. Down = "Down",
  28. }
  29. function padCenter(value: string, width: number) {
  30. const length = value.length;
  31. if (width <= length) {
  32. return value;
  33. }
  34. const padding = (width - length) / 2;
  35. const align = width - padding;
  36. return value.padStart(align, " ").padEnd(width, " ");
  37. }
  38. function logPosition(title: string, { x, y, z }: { x: BN; y: BN; z: BN }) {
  39. console.log(" +----------------------------------+");
  40. console.log(` | ${padCenter(title, 32)} |`);
  41. console.log(" +-----------------+----------------+");
  42. console.log(` | X Position | ${String(x).padEnd(14, " ")} |`);
  43. console.log(` | Y Position | ${String(y).padEnd(14, " ")} |`);
  44. console.log(` | Z Position | ${String(z).padEnd(14, " ")} |`);
  45. console.log(" +-----------------+----------------+");
  46. }
  47. function logVelocity(
  48. title: string,
  49. { x, y, z, lastApplied }: { x: BN; y: BN; z: BN; lastApplied: BN },
  50. ) {
  51. console.log(" +----------------------------------+");
  52. console.log(` | ${padCenter(title, 32)} |`);
  53. console.log(" +-----------------+----------------+");
  54. console.log(` | X Velocity | ${String(x).padEnd(14, " ")} |`);
  55. console.log(` | Y Velocity | ${String(y).padEnd(14, " ")} |`);
  56. console.log(` | Z Velocity | ${String(z).padEnd(14, " ")} |`);
  57. console.log(` | Last Applied | ${String(lastApplied).padEnd(14, " ")} |`);
  58. console.log(" +-----------------+----------------+");
  59. }
  60. describe("bolt", () => {
  61. const provider = anchor.AnchorProvider.env();
  62. anchor.setProvider(provider);
  63. const worldProgram = anchor.workspace.World as Program<World>;
  64. const boltComponentProgram = anchor.workspace
  65. .BoltComponent as Program<BoltComponent>;
  66. const exampleComponentPosition = anchor.workspace
  67. .Position as Program<Position>;
  68. const exampleComponentVelocity = anchor.workspace
  69. .Velocity as Program<Velocity>;
  70. const exampleSystemSimpleMovement = (
  71. anchor.workspace.SystemSimpleMovement as Program<SystemSimpleMovement>
  72. ).programId;
  73. const exampleSystemFly = (anchor.workspace.SystemFly as Program<SystemFly>)
  74. .programId;
  75. const exampleSystemApplyVelocity = (
  76. anchor.workspace.SystemApplyVelocity as Program<SystemApplyVelocity>
  77. ).programId;
  78. let worldPda: PublicKey;
  79. let worldId: BN;
  80. let entity1Pda: PublicKey;
  81. let entity2Pda: PublicKey;
  82. let entity4Pda: PublicKey;
  83. let entity5Pda: PublicKey;
  84. let componentPositionEntity1Pda: PublicKey;
  85. let componentVelocityEntity1Pda: PublicKey;
  86. let componentPositionEntity4Pda: PublicKey;
  87. let componentPositionEntity5Pda: PublicKey;
  88. const secondAuthority = Keypair.generate().publicKey;
  89. it("InitializeRegistry", async () => {
  90. const registryPda = FindRegistryPda({});
  91. const instruction = await worldProgram.methods
  92. .initializeRegistry()
  93. .accounts({
  94. registry: registryPda,
  95. payer: provider.wallet.publicKey,
  96. })
  97. .instruction();
  98. const transaction = new anchor.web3.Transaction().add(instruction);
  99. await provider.sendAndConfirm(transaction);
  100. });
  101. it("InitializeNewWorld", async () => {
  102. const registryPda = FindRegistryPda({});
  103. const registry = await worldProgram.account.registry.fetch(registryPda);
  104. worldId = new BN(registry.worlds);
  105. worldPda = FindWorldPda({ worldId });
  106. const instruction = await worldProgram.methods
  107. .initializeNewWorld()
  108. .accounts({
  109. payer: provider.wallet.publicKey,
  110. world: worldPda,
  111. registry: registryPda,
  112. })
  113. .instruction();
  114. const transaction = new anchor.web3.Transaction().add(instruction);
  115. const signature = await provider.sendAndConfirm(transaction);
  116. console.log("InitializeNewWorld signature: ", signature);
  117. });
  118. it("Add authority", async () => {
  119. const instruction = await worldProgram.methods
  120. .addAuthority(worldId)
  121. .accounts({
  122. authority: provider.wallet.publicKey,
  123. newAuthority: provider.wallet.publicKey,
  124. world: worldPda,
  125. })
  126. .instruction();
  127. const transaction = new anchor.web3.Transaction().add(instruction);
  128. await provider.sendAndConfirm(transaction, [], { skipPreflight: true });
  129. const worldAccount = await worldProgram.account.world.fetch(worldPda);
  130. expect(
  131. worldAccount.authorities.some((auth) =>
  132. auth.equals(provider.wallet.publicKey),
  133. ),
  134. );
  135. });
  136. it("Add a second authority", async () => {
  137. const instruction = await worldProgram.methods
  138. .addAuthority(worldId)
  139. .accounts({
  140. authority: provider.wallet.publicKey,
  141. newAuthority: secondAuthority,
  142. world: worldPda,
  143. })
  144. .instruction();
  145. const transaction = new anchor.web3.Transaction().add(instruction);
  146. const signature = await provider.sendAndConfirm(transaction);
  147. console.log(`Add Authority signature: ${signature}`);
  148. const worldAccount = await worldProgram.account.world.fetch(worldPda);
  149. expect(
  150. worldAccount.authorities.some((auth) => auth.equals(secondAuthority)),
  151. );
  152. });
  153. it("Remove an authority", async () => {
  154. const instruction = await worldProgram.methods
  155. .removeAuthority(worldId)
  156. .accounts({
  157. authority: provider.wallet.publicKey,
  158. authorityToDelete: secondAuthority,
  159. world: worldPda,
  160. })
  161. .instruction();
  162. const transaction = new anchor.web3.Transaction().add(instruction);
  163. const signature = await provider.sendAndConfirm(transaction);
  164. console.log(`Remove Authority signature: ${signature}`);
  165. const worldAccount = await worldProgram.account.world.fetch(worldPda);
  166. expect(
  167. !worldAccount.authorities.some((auth) => auth.equals(secondAuthority)),
  168. );
  169. });
  170. it("InitializeNewWorld 2", async () => {
  171. const registryPda = FindRegistryPda({});
  172. const registry = await worldProgram.account.registry.fetch(registryPda);
  173. const worldId = new BN(registry.worlds);
  174. const worldPda = FindWorldPda({ worldId });
  175. const instruction = await worldProgram.methods
  176. .initializeNewWorld()
  177. .accounts({
  178. payer: provider.wallet.publicKey,
  179. world: worldPda,
  180. registry: registryPda,
  181. })
  182. .instruction();
  183. const transaction = new anchor.web3.Transaction().add(instruction);
  184. const signature = await provider.sendAndConfirm(transaction);
  185. console.log("InitializeNewWorld 2 signature: ", signature);
  186. });
  187. it("Add entity 1", async () => {
  188. const world = await worldProgram.account.world.fetch(worldPda);
  189. entity1Pda = FindEntityPda({ worldId: world.id, entityId: world.entities });
  190. const instruction = await worldProgram.methods
  191. .addEntity(null)
  192. .accounts({
  193. payer: provider.wallet.publicKey,
  194. world: worldPda,
  195. entity: entity1Pda,
  196. })
  197. .instruction();
  198. const transaction = new anchor.web3.Transaction().add(instruction);
  199. const signature = await provider.sendAndConfirm(transaction);
  200. console.log("Add Entity 1 signature: ", signature);
  201. });
  202. it("Add entity 2", async () => {
  203. const world = await worldProgram.account.world.fetch(worldPda);
  204. entity2Pda = FindEntityPda({ worldId: world.id, entityId: world.entities });
  205. const instruction = await worldProgram.methods
  206. .addEntity(null)
  207. .accounts({
  208. payer: provider.wallet.publicKey,
  209. world: worldPda,
  210. entity: entity2Pda,
  211. })
  212. .instruction();
  213. const transaction = new anchor.web3.Transaction().add(instruction);
  214. const signature = await provider.sendAndConfirm(transaction);
  215. console.log("Add Entity 2 signature: ", signature);
  216. });
  217. it("Add entity 3", async () => {
  218. const world = await worldProgram.account.world.fetch(worldPda);
  219. const entity3Pda = FindEntityPda({
  220. worldId: world.id,
  221. entityId: world.entities,
  222. });
  223. const instruction = await worldProgram.methods
  224. .addEntity(null)
  225. .accounts({
  226. payer: provider.wallet.publicKey,
  227. world: worldPda,
  228. entity: entity3Pda,
  229. })
  230. .instruction();
  231. const transaction = new anchor.web3.Transaction().add(instruction);
  232. const signature = await provider.sendAndConfirm(transaction);
  233. console.log("Add Entity 3 signature: ", signature);
  234. });
  235. it("Add entity 4 (with seed)", async () => {
  236. const world = await worldProgram.account.world.fetch(worldPda);
  237. const seed = Buffer.from("custom-seed");
  238. entity4Pda = FindEntityPda({ worldId: world.id, seed });
  239. const instruction = await worldProgram.methods
  240. .addEntity(seed)
  241. .accounts({
  242. payer: provider.wallet.publicKey,
  243. world: worldPda,
  244. entity: entity4Pda,
  245. })
  246. .instruction();
  247. const transaction = new anchor.web3.Transaction().add(instruction);
  248. const signature = await provider.sendAndConfirm(transaction);
  249. console.log("Add Entity 4 signature: ", signature);
  250. });
  251. it("Add entity 5", async () => {
  252. const world = await worldProgram.account.world.fetch(worldPda);
  253. entity5Pda = FindEntityPda({ worldId: world.id, entityId: world.entities });
  254. const instruction = await worldProgram.methods
  255. .addEntity(null)
  256. .accounts({
  257. payer: provider.wallet.publicKey,
  258. world: worldPda,
  259. entity: entity5Pda,
  260. })
  261. .instruction();
  262. const transaction = new anchor.web3.Transaction().add(instruction);
  263. const signature = await provider.sendAndConfirm(transaction);
  264. console.log("Add Entity 5 signature: ", signature);
  265. });
  266. it("Initialize Original Component on Entity 1, through the world instance", async () => {
  267. const componentId = boltComponentProgram.programId;
  268. const componentPda = FindComponentPda({
  269. componentId,
  270. entity: entity1Pda,
  271. seed: "origin-component",
  272. });
  273. const instruction = await worldProgram.methods
  274. .initializeComponent()
  275. .accounts({
  276. payer: provider.wallet.publicKey,
  277. entity: entity1Pda,
  278. data: componentPda,
  279. componentProgram: componentId,
  280. authority: provider.wallet.publicKey,
  281. })
  282. .instruction();
  283. const transaction = new anchor.web3.Transaction().add(instruction);
  284. const signature = await provider.sendAndConfirm(transaction);
  285. console.log(
  286. "Initialize Original Component on Entity 1 signature: ",
  287. signature,
  288. );
  289. });
  290. it("Initialize Original Component on Entity 2, trough the world instance", async () => {
  291. const componentId = boltComponentProgram.programId;
  292. const componentPda = FindComponentPda({
  293. componentId,
  294. entity: entity2Pda,
  295. seed: "origin-component",
  296. });
  297. const instruction = await worldProgram.methods
  298. .initializeComponent()
  299. .accounts({
  300. payer: provider.wallet.publicKey,
  301. entity: entity2Pda,
  302. data: componentPda,
  303. componentProgram: componentId,
  304. authority: provider.wallet.publicKey,
  305. })
  306. .instruction();
  307. const transaction = new anchor.web3.Transaction().add(instruction);
  308. const signature = await provider.sendAndConfirm(transaction);
  309. console.log(
  310. "Initialize Original Component on Entity 2 signature: ",
  311. signature,
  312. );
  313. });
  314. it("Initialize Position Component on Entity 1", async () => {
  315. const componentId = exampleComponentPosition.programId;
  316. componentPositionEntity1Pda = FindComponentPda({
  317. componentId,
  318. entity: entity1Pda,
  319. });
  320. const instruction = await worldProgram.methods
  321. .initializeComponent()
  322. .accounts({
  323. payer: provider.wallet.publicKey,
  324. entity: entity1Pda,
  325. data: componentPositionEntity1Pda,
  326. componentProgram: componentId,
  327. authority: worldProgram.programId,
  328. })
  329. .instruction();
  330. const transaction = new anchor.web3.Transaction().add(instruction);
  331. const signature = await provider.sendAndConfirm(transaction);
  332. console.log(
  333. "Initialize Position Component on Entity 1 signature: ",
  334. signature,
  335. );
  336. });
  337. it("Initialize Velocity Component on Entity 1 (with seed)", async () => {
  338. const componentId = exampleComponentVelocity.programId;
  339. componentVelocityEntity1Pda = FindComponentPda({
  340. componentId,
  341. entity: entity1Pda,
  342. seed: "component-velocity",
  343. });
  344. const instruction = await worldProgram.methods
  345. .initializeComponent()
  346. .accounts({
  347. payer: provider.wallet.publicKey,
  348. entity: entity1Pda,
  349. data: componentVelocityEntity1Pda,
  350. componentProgram: componentId,
  351. authority: worldProgram.programId,
  352. })
  353. .instruction();
  354. const transaction = new anchor.web3.Transaction().add(instruction);
  355. const signature = await provider.sendAndConfirm(transaction);
  356. console.log(
  357. "Initialize Velocity Component on Entity 1 signature: ",
  358. signature,
  359. );
  360. });
  361. it("Initialize Position Component on Entity 2", async () => {
  362. const componentId = exampleComponentPosition.programId;
  363. const componentPositionEntity2Pda = FindComponentPda({
  364. componentId,
  365. entity: entity2Pda,
  366. });
  367. const instruction = await worldProgram.methods
  368. .initializeComponent()
  369. .accounts({
  370. payer: provider.wallet.publicKey,
  371. entity: entity2Pda,
  372. data: componentPositionEntity2Pda,
  373. componentProgram: componentId,
  374. authority: worldProgram.programId,
  375. })
  376. .instruction();
  377. const transaction = new anchor.web3.Transaction().add(instruction);
  378. const signature = await provider.sendAndConfirm(transaction);
  379. console.log(
  380. "Initialize Position Component on Entity 2 signature: ",
  381. signature,
  382. );
  383. });
  384. it("Initialize Position Component on Entity 4", async () => {
  385. const componentId = exampleComponentPosition.programId;
  386. componentPositionEntity4Pda = FindComponentPda({
  387. componentId,
  388. entity: entity4Pda,
  389. });
  390. const instruction = await worldProgram.methods
  391. .initializeComponent()
  392. .accounts({
  393. payer: provider.wallet.publicKey,
  394. entity: entity4Pda,
  395. data: componentPositionEntity4Pda,
  396. componentProgram: componentId,
  397. authority: worldProgram.programId,
  398. })
  399. .instruction();
  400. const transaction = new anchor.web3.Transaction().add(instruction);
  401. const signature = await provider.sendAndConfirm(transaction);
  402. console.log(
  403. "Initialize Position Component on Entity 4 signature: ",
  404. signature,
  405. );
  406. });
  407. it("Initialize Position Component on Entity 5 (with authority)", async () => {
  408. const componentId = exampleComponentPosition.programId;
  409. componentPositionEntity5Pda = FindComponentPda({
  410. componentId,
  411. entity: entity5Pda,
  412. });
  413. const instruction = await worldProgram.methods
  414. .initializeComponent()
  415. .accounts({
  416. payer: provider.wallet.publicKey,
  417. entity: entity5Pda,
  418. data: componentPositionEntity5Pda,
  419. componentProgram: componentId,
  420. authority: provider.wallet.publicKey,
  421. })
  422. .instruction();
  423. const transaction = new anchor.web3.Transaction().add(instruction);
  424. const signature = await provider.sendAndConfirm(transaction);
  425. console.log(
  426. "Initialize Position Component on Entity 5 signature: ",
  427. signature,
  428. );
  429. });
  430. it("Check Position on Entity 1 is default", async () => {
  431. const position = await exampleComponentPosition.account.position.fetch(
  432. componentPositionEntity1Pda,
  433. );
  434. logPosition("Default State: Entity 1", position);
  435. expect(position.x.toNumber()).to.equal(0);
  436. expect(position.y.toNumber()).to.equal(0);
  437. expect(position.z.toNumber()).to.equal(0);
  438. });
  439. it("Apply Simple Movement System (Up) on Entity 1 using Apply", async () => {
  440. const instruction = await worldProgram.methods
  441. .apply(SerializeArgs({ direction: Direction.Up }))
  442. .accounts({
  443. authority: provider.wallet.publicKey,
  444. boltSystem: exampleSystemSimpleMovement,
  445. boltComponent: componentPositionEntity1Pda,
  446. componentProgram: exampleComponentPosition.programId,
  447. world: worldPda,
  448. })
  449. .instruction();
  450. const transaction = new anchor.web3.Transaction().add(instruction);
  451. const signature = await provider.sendAndConfirm(transaction);
  452. console.log(
  453. "Apply Simple Movement System (Up) on Entity 1 signature: ",
  454. signature,
  455. );
  456. const position = await exampleComponentPosition.account.position.fetch(
  457. componentPositionEntity1Pda,
  458. );
  459. logPosition("Movement System: Entity 1", position);
  460. expect(position.x.toNumber()).to.equal(0);
  461. expect(position.y.toNumber()).to.equal(1);
  462. expect(position.z.toNumber()).to.equal(0);
  463. });
  464. it("Apply Simple Movement System (Up) on Entity 1", async () => {
  465. const instruction = await worldProgram.methods
  466. .apply(SerializeArgs({ direction: Direction.Up }))
  467. .accounts({
  468. authority: provider.wallet.publicKey,
  469. boltSystem: exampleSystemSimpleMovement,
  470. boltComponent: componentPositionEntity1Pda,
  471. componentProgram: exampleComponentPosition.programId,
  472. world: worldPda,
  473. })
  474. .instruction();
  475. const transaction = new anchor.web3.Transaction().add(instruction);
  476. const signature = await provider.sendAndConfirm(transaction);
  477. console.log(
  478. "Apply Simple Movement System (Up) on Entity 1 signature: ",
  479. signature,
  480. );
  481. const position = await exampleComponentPosition.account.position.fetch(
  482. componentPositionEntity1Pda,
  483. );
  484. logPosition("Movement System: Entity 1", position);
  485. expect(position.x.toNumber()).to.equal(0);
  486. expect(position.y.toNumber()).to.equal(2);
  487. expect(position.z.toNumber()).to.equal(0);
  488. });
  489. it("Apply Simple Movement System (Right) on Entity 1", async () => {
  490. const instruction = await worldProgram.methods
  491. .apply(SerializeArgs({ direction: Direction.Right }))
  492. .accounts({
  493. authority: provider.wallet.publicKey,
  494. boltSystem: exampleSystemSimpleMovement,
  495. boltComponent: componentPositionEntity1Pda,
  496. componentProgram: exampleComponentPosition.programId,
  497. world: worldPda,
  498. })
  499. .instruction();
  500. const transaction = new anchor.web3.Transaction().add(instruction);
  501. const signature = await provider.sendAndConfirm(transaction);
  502. console.log(
  503. "Apply Simple Movement System (Right) on Entity 1 signature: ",
  504. signature,
  505. );
  506. const position = await exampleComponentPosition.account.position.fetch(
  507. componentPositionEntity1Pda,
  508. );
  509. logPosition("Movement System: Entity 1", position);
  510. expect(position.x.toNumber()).to.equal(1);
  511. expect(position.y.toNumber()).to.equal(2);
  512. expect(position.z.toNumber()).to.equal(0);
  513. });
  514. it("Apply Fly System on Entity 1", async () => {
  515. const instruction = await worldProgram.methods
  516. .apply(SerializeArgs())
  517. .accounts({
  518. authority: provider.wallet.publicKey,
  519. boltSystem: exampleSystemFly,
  520. boltComponent: componentPositionEntity1Pda,
  521. componentProgram: exampleComponentPosition.programId,
  522. world: worldPda,
  523. })
  524. .instruction();
  525. const transaction = new anchor.web3.Transaction().add(instruction);
  526. const signature = await provider.sendAndConfirm(transaction);
  527. console.log("Apply Fly System on Entity 1 signature: ", signature);
  528. const position = await exampleComponentPosition.account.position.fetch(
  529. componentPositionEntity1Pda,
  530. );
  531. logPosition("Fly System: Entity 1", position);
  532. expect(position.x.toNumber()).to.equal(1);
  533. expect(position.y.toNumber()).to.equal(2);
  534. expect(position.z.toNumber()).to.equal(1);
  535. });
  536. it("Apply System Velocity on Entity 1", async () => {
  537. const instruction = await worldProgram.methods
  538. .apply2(SerializeArgs())
  539. .accounts({
  540. authority: provider.wallet.publicKey,
  541. boltSystem: exampleSystemApplyVelocity,
  542. boltComponent1: componentVelocityEntity1Pda,
  543. componentProgram1: exampleComponentVelocity.programId,
  544. boltComponent2: componentPositionEntity1Pda,
  545. componentProgram2: exampleComponentPosition.programId,
  546. world: worldPda,
  547. })
  548. .remainingAccounts([])
  549. .instruction();
  550. const transaction = new anchor.web3.Transaction().add(instruction);
  551. const signature = await provider.sendAndConfirm(transaction);
  552. console.log("Apply System Velocity on Entity 1 signature: ", signature);
  553. const velocity = await exampleComponentVelocity.account.velocity.fetch(
  554. componentVelocityEntity1Pda,
  555. );
  556. logVelocity("Apply System Velocity: Entity 1", velocity);
  557. expect(velocity.x.toNumber()).to.equal(10);
  558. expect(velocity.y.toNumber()).to.equal(0);
  559. expect(velocity.z.toNumber()).to.equal(0);
  560. expect(velocity.lastApplied.toNumber()).to.not.equal(0);
  561. const position = await exampleComponentPosition.account.position.fetch(
  562. componentPositionEntity1Pda,
  563. );
  564. logPosition("Apply System Velocity: Entity 1", position);
  565. expect(position.x.toNumber()).to.greaterThan(1);
  566. expect(position.y.toNumber()).to.equal(2);
  567. expect(position.z.toNumber()).to.equal(1);
  568. });
  569. it("Apply System Velocity on Entity 1, with Clock external account", async () => {
  570. const instruction = await worldProgram.methods
  571. .apply2(SerializeArgs())
  572. .accounts({
  573. authority: provider.wallet.publicKey,
  574. boltSystem: exampleSystemApplyVelocity,
  575. boltComponent1: componentVelocityEntity1Pda,
  576. componentProgram1: exampleComponentVelocity.programId,
  577. boltComponent2: componentPositionEntity1Pda,
  578. componentProgram2: exampleComponentPosition.programId,
  579. world: worldPda,
  580. })
  581. .remainingAccounts([
  582. {
  583. pubkey: new web3.PublicKey(
  584. "SysvarC1ock11111111111111111111111111111111",
  585. ),
  586. isWritable: false,
  587. isSigner: false,
  588. },
  589. ])
  590. .instruction();
  591. const transaction = new anchor.web3.Transaction().add(instruction);
  592. await provider.sendAndConfirm(transaction);
  593. const position = await exampleComponentPosition.account.position.fetch(
  594. componentPositionEntity1Pda,
  595. );
  596. logPosition("Apply System Velocity: Entity 1", position);
  597. expect(position.x.toNumber()).to.greaterThan(1);
  598. expect(position.y.toNumber()).to.equal(2);
  599. expect(position.z.toNumber()).to.equal(300);
  600. });
  601. it("Apply Fly System on Entity 4", async () => {
  602. const instruction = await worldProgram.methods
  603. .apply(SerializeArgs())
  604. .accounts({
  605. authority: provider.wallet.publicKey,
  606. boltSystem: exampleSystemFly,
  607. boltComponent: componentPositionEntity4Pda,
  608. componentProgram: exampleComponentPosition.programId,
  609. world: worldPda,
  610. })
  611. .instruction();
  612. const transaction = new anchor.web3.Transaction().add(instruction);
  613. await provider.sendAndConfirm(transaction);
  614. const position = await exampleComponentPosition.account.position.fetch(
  615. componentPositionEntity4Pda,
  616. );
  617. logPosition("Fly System: Entity 4", position);
  618. expect(position.x.toNumber()).to.equal(0);
  619. expect(position.y.toNumber()).to.equal(0);
  620. expect(position.z.toNumber()).to.equal(1);
  621. });
  622. it("Apply Fly System on Entity 5 (should fail with wrong authority)", async () => {
  623. const positionBefore =
  624. await exampleComponentPosition.account.position.fetch(
  625. componentPositionEntity5Pda,
  626. );
  627. const instruction = await worldProgram.methods
  628. .apply(SerializeArgs())
  629. .accounts({
  630. authority: provider.wallet.publicKey,
  631. boltSystem: exampleSystemFly,
  632. boltComponent: componentPositionEntity5Pda,
  633. componentProgram: exampleComponentPosition.programId,
  634. world: worldPda,
  635. })
  636. .instruction();
  637. const transaction = new anchor.web3.Transaction().add(instruction);
  638. let failed = false;
  639. try {
  640. await provider.sendAndConfirm(transaction);
  641. } catch (error) {
  642. failed = true;
  643. // console.log("error", error);
  644. expect(error.logs.join("\n")).to.contain("Error Code: InvalidAuthority");
  645. }
  646. expect(failed).to.equal(true);
  647. const positionAfter = await exampleComponentPosition.account.position.fetch(
  648. componentPositionEntity5Pda,
  649. );
  650. expect(positionBefore.x.toNumber()).to.equal(positionAfter.x.toNumber());
  651. expect(positionBefore.y.toNumber()).to.equal(positionAfter.y.toNumber());
  652. expect(positionBefore.z.toNumber()).to.equal(positionAfter.z.toNumber());
  653. });
  654. it("Whitelist System", async () => {
  655. const instruction = await worldProgram.methods
  656. .approveSystem()
  657. .accounts({
  658. authority: provider.wallet.publicKey,
  659. system: exampleSystemFly,
  660. world: worldPda,
  661. })
  662. .instruction();
  663. const transaction = new anchor.web3.Transaction().add(instruction);
  664. const signature = await provider.sendAndConfirm(transaction, [], {
  665. skipPreflight: true,
  666. });
  667. console.log(`Whitelist 2 system approval signature: ${signature}`);
  668. // Get World and check permissionless and systems
  669. const worldAccount = await worldProgram.account.world.fetch(worldPda);
  670. expect(worldAccount.permissionless).to.equal(false);
  671. expect(worldAccount.systems.length).to.be.greaterThan(0);
  672. });
  673. it("Whitelist System 2", async () => {
  674. const instruction = await worldProgram.methods
  675. .approveSystem()
  676. .accounts({
  677. authority: provider.wallet.publicKey,
  678. system: exampleSystemApplyVelocity,
  679. world: worldPda,
  680. })
  681. .instruction();
  682. const transaction = new anchor.web3.Transaction().add(instruction);
  683. const signature = await provider.sendAndConfirm(transaction, [], {
  684. skipPreflight: true,
  685. });
  686. console.log(`Whitelist 2 system approval signature: ${signature}`);
  687. // Get World and check permissionless and systems
  688. const worldAccount = await worldProgram.account.world.fetch(worldPda);
  689. expect(worldAccount.permissionless).to.equal(false);
  690. expect(worldAccount.systems.length).to.be.greaterThan(0);
  691. });
  692. it("Apply Fly System on Entity 1", async () => {
  693. const instruction = await worldProgram.methods
  694. .apply(SerializeArgs())
  695. .accounts({
  696. authority: provider.wallet.publicKey,
  697. boltSystem: exampleSystemFly,
  698. boltComponent: componentPositionEntity1Pda,
  699. componentProgram: exampleComponentPosition.programId,
  700. world: worldPda,
  701. })
  702. .instruction();
  703. const transaction = new anchor.web3.Transaction().add(instruction);
  704. await provider.sendAndConfirm(transaction);
  705. });
  706. it("Remove System 1", async () => {
  707. const instruction = await worldProgram.methods
  708. .removeSystem()
  709. .accounts({
  710. authority: provider.wallet.publicKey,
  711. system: exampleSystemFly,
  712. world: worldPda,
  713. })
  714. .instruction();
  715. const transaction = new anchor.web3.Transaction().add(instruction);
  716. const signature = await provider.sendAndConfirm(transaction, [], {
  717. skipPreflight: true,
  718. });
  719. console.log(`Remove System 1 signature: ${signature}`);
  720. // Get World and check permissionless and systems
  721. const worldAccount = await worldProgram.account.world.fetch(worldPda);
  722. expect(worldAccount.permissionless).to.equal(false);
  723. expect(worldAccount.systems.length).to.be.greaterThan(0);
  724. });
  725. it("Apply Invalid Fly System on Entity 1", async () => {
  726. const instruction = await worldProgram.methods
  727. .apply(SerializeArgs())
  728. .accounts({
  729. authority: provider.wallet.publicKey,
  730. boltSystem: exampleSystemFly,
  731. boltComponent: componentPositionEntity1Pda,
  732. componentProgram: exampleComponentPosition.programId,
  733. world: worldPda,
  734. })
  735. .instruction();
  736. const transaction = new anchor.web3.Transaction().add(instruction);
  737. let invalid = false;
  738. try {
  739. await provider.sendAndConfirm(transaction);
  740. } catch (error) {
  741. expect(error.logs.join(" ")).to.contain("Error Code: SystemNotApproved");
  742. invalid = true;
  743. }
  744. expect(invalid).to.equal(true);
  745. });
  746. it("Check invalid component init without CPI", async () => {
  747. let invalid = false;
  748. try {
  749. await exampleComponentPosition.methods
  750. .initialize()
  751. .accounts({
  752. payer: provider.wallet.publicKey,
  753. data: componentPositionEntity5Pda,
  754. entity: entity5Pda,
  755. authority: provider.wallet.publicKey,
  756. })
  757. .rpc();
  758. } catch (error) {
  759. // console.log("error", error);
  760. expect(error.message).to.contain("Error Code: InvalidCaller");
  761. invalid = true;
  762. }
  763. expect(invalid).to.equal(true);
  764. });
  765. it("Check invalid component update without CPI", async () => {
  766. let invalid = false;
  767. try {
  768. await boltComponentProgram.methods
  769. .update(Buffer.from(""))
  770. .accounts({
  771. boltComponent: componentPositionEntity4Pda,
  772. authority: provider.wallet.publicKey,
  773. })
  774. .rpc();
  775. } catch (error) {
  776. // console.log("error", error);
  777. expect(error.message).to.contain(
  778. "bolt_component. Error Code: AccountOwnedByWrongProgram",
  779. );
  780. invalid = true;
  781. }
  782. expect(invalid).to.equal(true);
  783. });
  784. it("Check component delegation", async () => {
  785. const delegateComponent = await DelegateComponent({
  786. payer: provider.wallet.publicKey,
  787. entity: entity1Pda,
  788. componentId: exampleComponentPosition.programId,
  789. });
  790. const instruction = delegateComponent.transaction;
  791. const transaction = new anchor.web3.Transaction().add(instruction);
  792. const txSign = await provider.sendAndConfirm(transaction, [], {
  793. skipPreflight: true,
  794. commitment: "confirmed",
  795. });
  796. console.log(`Delegation signature: ${txSign}`);
  797. const acc = await provider.connection.getAccountInfo(
  798. delegateComponent.componentPda,
  799. );
  800. expect(acc?.owner.toBase58()).to.equal(DELEGATION_PROGRAM_ID.toBase58());
  801. });
  802. });