bolt.low-level.api.ts 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988
  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. world: worldPda,
  446. })
  447. .remainingAccounts([
  448. {
  449. pubkey: exampleComponentPosition.programId,
  450. isSigner: false,
  451. isWritable: false,
  452. },
  453. {
  454. pubkey: componentPositionEntity1Pda,
  455. isSigner: false,
  456. isWritable: true,
  457. },
  458. ])
  459. .instruction();
  460. const transaction = new anchor.web3.Transaction().add(instruction);
  461. const signature = await provider.sendAndConfirm(transaction);
  462. console.log(
  463. "Apply Simple Movement System (Up) on Entity 1 signature: ",
  464. signature,
  465. );
  466. const position = await exampleComponentPosition.account.position.fetch(
  467. componentPositionEntity1Pda,
  468. );
  469. logPosition("Movement System: Entity 1", position);
  470. expect(position.x.toNumber()).to.equal(0);
  471. expect(position.y.toNumber()).to.equal(1);
  472. expect(position.z.toNumber()).to.equal(0);
  473. });
  474. it("Apply Simple Movement System (Up) on Entity 1", async () => {
  475. const instruction = await worldProgram.methods
  476. .apply(SerializeArgs({ direction: Direction.Up }))
  477. .accounts({
  478. authority: provider.wallet.publicKey,
  479. boltSystem: exampleSystemSimpleMovement,
  480. world: worldPda,
  481. })
  482. .remainingAccounts([
  483. {
  484. pubkey: exampleComponentPosition.programId,
  485. isSigner: false,
  486. isWritable: false,
  487. },
  488. {
  489. pubkey: componentPositionEntity1Pda,
  490. isSigner: false,
  491. isWritable: true,
  492. },
  493. ])
  494. .instruction();
  495. const transaction = new anchor.web3.Transaction().add(instruction);
  496. const signature = await provider.sendAndConfirm(transaction);
  497. console.log(
  498. "Apply Simple Movement System (Up) on Entity 1 signature: ",
  499. signature,
  500. );
  501. const position = await exampleComponentPosition.account.position.fetch(
  502. componentPositionEntity1Pda,
  503. );
  504. logPosition("Movement System: Entity 1", position);
  505. expect(position.x.toNumber()).to.equal(0);
  506. expect(position.y.toNumber()).to.equal(2);
  507. expect(position.z.toNumber()).to.equal(0);
  508. });
  509. it("Apply Simple Movement System (Right) on Entity 1", async () => {
  510. const instruction = await worldProgram.methods
  511. .apply(SerializeArgs({ direction: Direction.Right }))
  512. .accounts({
  513. authority: provider.wallet.publicKey,
  514. boltSystem: exampleSystemSimpleMovement,
  515. world: worldPda,
  516. })
  517. .remainingAccounts([
  518. {
  519. pubkey: exampleComponentPosition.programId,
  520. isSigner: false,
  521. isWritable: false,
  522. },
  523. {
  524. pubkey: componentPositionEntity1Pda,
  525. isSigner: false,
  526. isWritable: true,
  527. },
  528. ])
  529. .instruction();
  530. const transaction = new anchor.web3.Transaction().add(instruction);
  531. const signature = await provider.sendAndConfirm(transaction);
  532. console.log(
  533. "Apply Simple Movement System (Right) on Entity 1 signature: ",
  534. signature,
  535. );
  536. const position = await exampleComponentPosition.account.position.fetch(
  537. componentPositionEntity1Pda,
  538. );
  539. logPosition("Movement System: Entity 1", position);
  540. expect(position.x.toNumber()).to.equal(1);
  541. expect(position.y.toNumber()).to.equal(2);
  542. expect(position.z.toNumber()).to.equal(0);
  543. });
  544. it("Apply Fly System on Entity 1", async () => {
  545. const instruction = await worldProgram.methods
  546. .apply(SerializeArgs())
  547. .accounts({
  548. authority: provider.wallet.publicKey,
  549. boltSystem: exampleSystemFly,
  550. world: worldPda,
  551. })
  552. .remainingAccounts([
  553. {
  554. pubkey: exampleComponentPosition.programId,
  555. isSigner: false,
  556. isWritable: false,
  557. },
  558. {
  559. pubkey: componentPositionEntity1Pda,
  560. isSigner: false,
  561. isWritable: true,
  562. },
  563. ])
  564. .instruction();
  565. const transaction = new anchor.web3.Transaction().add(instruction);
  566. const signature = await provider.sendAndConfirm(transaction);
  567. console.log("Apply Fly System on Entity 1 signature: ", signature);
  568. const position = await exampleComponentPosition.account.position.fetch(
  569. componentPositionEntity1Pda,
  570. );
  571. logPosition("Fly System: Entity 1", position);
  572. expect(position.x.toNumber()).to.equal(1);
  573. expect(position.y.toNumber()).to.equal(2);
  574. expect(position.z.toNumber()).to.equal(1);
  575. });
  576. it("Apply System Velocity on Entity 1", async () => {
  577. const instruction = await worldProgram.methods
  578. .apply(SerializeArgs())
  579. .accounts({
  580. authority: provider.wallet.publicKey,
  581. boltSystem: exampleSystemApplyVelocity,
  582. world: worldPda,
  583. })
  584. .remainingAccounts([
  585. {
  586. pubkey: exampleComponentVelocity.programId,
  587. isSigner: false,
  588. isWritable: false,
  589. },
  590. {
  591. pubkey: componentVelocityEntity1Pda,
  592. isSigner: false,
  593. isWritable: true,
  594. },
  595. {
  596. pubkey: exampleComponentPosition.programId,
  597. isSigner: false,
  598. isWritable: false,
  599. },
  600. {
  601. pubkey: componentPositionEntity1Pda,
  602. isSigner: false,
  603. isWritable: true,
  604. },
  605. ])
  606. .instruction();
  607. const transaction = new anchor.web3.Transaction().add(instruction);
  608. const signature = await provider.sendAndConfirm(transaction);
  609. console.log("Apply System Velocity on Entity 1 signature: ", signature);
  610. const velocity = await exampleComponentVelocity.account.velocity.fetch(
  611. componentVelocityEntity1Pda,
  612. );
  613. logVelocity("Apply System Velocity: Entity 1", velocity);
  614. expect(velocity.x.toNumber()).to.equal(10);
  615. expect(velocity.y.toNumber()).to.equal(0);
  616. expect(velocity.z.toNumber()).to.equal(0);
  617. expect(velocity.lastApplied.toNumber()).to.not.equal(0);
  618. const position = await exampleComponentPosition.account.position.fetch(
  619. componentPositionEntity1Pda,
  620. );
  621. logPosition("Apply System Velocity: Entity 1", position);
  622. expect(position.x.toNumber()).to.greaterThan(1);
  623. expect(position.y.toNumber()).to.equal(2);
  624. expect(position.z.toNumber()).to.equal(1);
  625. });
  626. it("Apply System Velocity on Entity 1, with Clock external account", async () => {
  627. const instruction = await worldProgram.methods
  628. .apply(SerializeArgs())
  629. .accounts({
  630. authority: provider.wallet.publicKey,
  631. boltSystem: exampleSystemApplyVelocity,
  632. world: worldPda,
  633. })
  634. .remainingAccounts([
  635. {
  636. pubkey: exampleComponentVelocity.programId,
  637. isSigner: false,
  638. isWritable: false,
  639. },
  640. {
  641. pubkey: componentVelocityEntity1Pda,
  642. isSigner: false,
  643. isWritable: true,
  644. },
  645. {
  646. pubkey: exampleComponentPosition.programId,
  647. isSigner: false,
  648. isWritable: false,
  649. },
  650. {
  651. pubkey: componentPositionEntity1Pda,
  652. isSigner: false,
  653. isWritable: true,
  654. },
  655. {
  656. pubkey: worldProgram.programId, // world program ID is the end of components delimiter
  657. isSigner: false,
  658. isWritable: false,
  659. },
  660. {
  661. pubkey: new web3.PublicKey(
  662. "SysvarC1ock11111111111111111111111111111111",
  663. ),
  664. isWritable: false,
  665. isSigner: false,
  666. },
  667. ])
  668. .instruction();
  669. const transaction = new anchor.web3.Transaction().add(instruction);
  670. await provider.sendAndConfirm(transaction);
  671. const position = await exampleComponentPosition.account.position.fetch(
  672. componentPositionEntity1Pda,
  673. );
  674. logPosition("Apply System Velocity: Entity 1", position);
  675. expect(position.x.toNumber()).to.greaterThan(1);
  676. expect(position.y.toNumber()).to.equal(2);
  677. expect(position.z.toNumber()).to.equal(300);
  678. });
  679. it("Apply Fly System on Entity 4", async () => {
  680. const instruction = await worldProgram.methods
  681. .apply(SerializeArgs())
  682. .accounts({
  683. authority: provider.wallet.publicKey,
  684. boltSystem: exampleSystemFly,
  685. world: worldPda,
  686. })
  687. .remainingAccounts([
  688. {
  689. pubkey: exampleComponentPosition.programId,
  690. isSigner: false,
  691. isWritable: false,
  692. },
  693. {
  694. pubkey: componentPositionEntity4Pda,
  695. isSigner: false,
  696. isWritable: true,
  697. },
  698. ])
  699. .instruction();
  700. const transaction = new anchor.web3.Transaction().add(instruction);
  701. await provider.sendAndConfirm(transaction);
  702. const position = await exampleComponentPosition.account.position.fetch(
  703. componentPositionEntity4Pda,
  704. );
  705. logPosition("Fly System: Entity 4", position);
  706. expect(position.x.toNumber()).to.equal(0);
  707. expect(position.y.toNumber()).to.equal(0);
  708. expect(position.z.toNumber()).to.equal(1);
  709. });
  710. it("Apply Fly System on Entity 5 (should fail with wrong authority)", async () => {
  711. const positionBefore =
  712. await exampleComponentPosition.account.position.fetch(
  713. componentPositionEntity5Pda,
  714. );
  715. const instruction = await worldProgram.methods
  716. .apply(SerializeArgs())
  717. .accounts({
  718. authority: provider.wallet.publicKey,
  719. boltSystem: exampleSystemFly,
  720. world: worldPda,
  721. })
  722. .remainingAccounts([
  723. {
  724. pubkey: exampleComponentPosition.programId,
  725. isSigner: false,
  726. isWritable: false,
  727. },
  728. {
  729. pubkey: componentPositionEntity5Pda,
  730. isSigner: false,
  731. isWritable: true,
  732. },
  733. ])
  734. .instruction();
  735. const transaction = new anchor.web3.Transaction().add(instruction);
  736. let failed = false;
  737. try {
  738. await provider.sendAndConfirm(transaction);
  739. } catch (error) {
  740. failed = true;
  741. // console.log("error", error);
  742. expect(error.logs.join("\n")).to.contain("Error Code: InvalidAuthority");
  743. }
  744. expect(failed).to.equal(true);
  745. const positionAfter = await exampleComponentPosition.account.position.fetch(
  746. componentPositionEntity5Pda,
  747. );
  748. expect(positionBefore.x.toNumber()).to.equal(positionAfter.x.toNumber());
  749. expect(positionBefore.y.toNumber()).to.equal(positionAfter.y.toNumber());
  750. expect(positionBefore.z.toNumber()).to.equal(positionAfter.z.toNumber());
  751. });
  752. it("Whitelist System", async () => {
  753. const instruction = await worldProgram.methods
  754. .approveSystem()
  755. .accounts({
  756. authority: provider.wallet.publicKey,
  757. system: exampleSystemFly,
  758. world: worldPda,
  759. })
  760. .instruction();
  761. const transaction = new anchor.web3.Transaction().add(instruction);
  762. const signature = await provider.sendAndConfirm(transaction, [], {
  763. skipPreflight: true,
  764. });
  765. console.log(`Whitelist 2 system approval signature: ${signature}`);
  766. // Get World and check permissionless and systems
  767. const worldAccount = await worldProgram.account.world.fetch(worldPda);
  768. expect(worldAccount.permissionless).to.equal(false);
  769. expect(worldAccount.systems.length).to.be.greaterThan(0);
  770. });
  771. it("Whitelist System 2", async () => {
  772. const instruction = await worldProgram.methods
  773. .approveSystem()
  774. .accounts({
  775. authority: provider.wallet.publicKey,
  776. system: exampleSystemApplyVelocity,
  777. world: worldPda,
  778. })
  779. .instruction();
  780. const transaction = new anchor.web3.Transaction().add(instruction);
  781. const signature = await provider.sendAndConfirm(transaction, [], {
  782. skipPreflight: true,
  783. });
  784. console.log(`Whitelist 2 system approval signature: ${signature}`);
  785. // Get World and check permissionless and systems
  786. const worldAccount = await worldProgram.account.world.fetch(worldPda);
  787. expect(worldAccount.permissionless).to.equal(false);
  788. expect(worldAccount.systems.length).to.be.greaterThan(0);
  789. });
  790. it("Apply Fly System on Entity 1", async () => {
  791. const instruction = await worldProgram.methods
  792. .apply(SerializeArgs())
  793. .accounts({
  794. authority: provider.wallet.publicKey,
  795. boltSystem: exampleSystemFly,
  796. world: worldPda,
  797. })
  798. .remainingAccounts([
  799. {
  800. pubkey: exampleComponentPosition.programId,
  801. isSigner: false,
  802. isWritable: false,
  803. },
  804. {
  805. pubkey: componentPositionEntity1Pda,
  806. isSigner: false,
  807. isWritable: true,
  808. },
  809. ])
  810. .instruction();
  811. const transaction = new anchor.web3.Transaction().add(instruction);
  812. await provider.sendAndConfirm(transaction);
  813. });
  814. it("Remove System 1", async () => {
  815. const instruction = await worldProgram.methods
  816. .removeSystem()
  817. .accounts({
  818. authority: provider.wallet.publicKey,
  819. system: exampleSystemFly,
  820. world: worldPda,
  821. })
  822. .instruction();
  823. const transaction = new anchor.web3.Transaction().add(instruction);
  824. const signature = await provider.sendAndConfirm(transaction, [], {
  825. skipPreflight: true,
  826. });
  827. console.log(`Remove System 1 signature: ${signature}`);
  828. // Get World and check permissionless and systems
  829. const worldAccount = await worldProgram.account.world.fetch(worldPda);
  830. expect(worldAccount.permissionless).to.equal(false);
  831. expect(worldAccount.systems.length).to.be.greaterThan(0);
  832. });
  833. it("Apply Invalid Fly System on Entity 1", async () => {
  834. const instruction = await worldProgram.methods
  835. .apply(SerializeArgs())
  836. .accounts({
  837. authority: provider.wallet.publicKey,
  838. boltSystem: exampleSystemFly,
  839. world: worldPda,
  840. })
  841. .remainingAccounts([
  842. {
  843. pubkey: exampleComponentPosition.programId,
  844. isSigner: false,
  845. isWritable: false,
  846. },
  847. {
  848. pubkey: componentPositionEntity1Pda,
  849. isSigner: false,
  850. isWritable: true,
  851. },
  852. ])
  853. .instruction();
  854. const transaction = new anchor.web3.Transaction().add(instruction);
  855. let invalid = false;
  856. try {
  857. await provider.sendAndConfirm(transaction);
  858. } catch (error) {
  859. expect(error.logs.join(" ")).to.contain("Error Code: SystemNotApproved");
  860. invalid = true;
  861. }
  862. expect(invalid).to.equal(true);
  863. });
  864. it("Check invalid component init without CPI", async () => {
  865. let invalid = false;
  866. try {
  867. await exampleComponentPosition.methods
  868. .initialize()
  869. .accounts({
  870. payer: provider.wallet.publicKey,
  871. data: componentPositionEntity5Pda,
  872. entity: entity5Pda,
  873. authority: provider.wallet.publicKey,
  874. })
  875. .rpc();
  876. } catch (error) {
  877. // console.log("error", error);
  878. expect(error.message).to.contain("Error Code: InvalidCaller");
  879. invalid = true;
  880. }
  881. expect(invalid).to.equal(true);
  882. });
  883. it("Check invalid component update without CPI", async () => {
  884. let invalid = false;
  885. try {
  886. await boltComponentProgram.methods
  887. .update(Buffer.from(""))
  888. .accounts({
  889. boltComponent: componentPositionEntity4Pda,
  890. authority: provider.wallet.publicKey,
  891. })
  892. .rpc();
  893. } catch (error) {
  894. // console.log("error", error);
  895. expect(error.message).to.contain(
  896. "bolt_component. Error Code: AccountOwnedByWrongProgram",
  897. );
  898. invalid = true;
  899. }
  900. expect(invalid).to.equal(true);
  901. });
  902. it("Check component delegation", async () => {
  903. const delegateComponent = await DelegateComponent({
  904. payer: provider.wallet.publicKey,
  905. entity: entity1Pda,
  906. componentId: exampleComponentPosition.programId,
  907. });
  908. const instruction = delegateComponent.transaction;
  909. const transaction = new anchor.web3.Transaction().add(instruction);
  910. const txSign = await provider.sendAndConfirm(transaction, [], {
  911. skipPreflight: true,
  912. commitment: "confirmed",
  913. });
  914. console.log(`Delegation signature: ${txSign}`);
  915. const acc = await provider.connection.getAccountInfo(
  916. delegateComponent.componentPda,
  917. );
  918. expect(acc?.owner.toBase58()).to.equal(DELEGATION_PROGRAM_ID.toBase58());
  919. });
  920. });