Jelajahi Sumber

✨ Session keys (#126)

Danilo Guanabara 8 bulan lalu
induk
melakukan
66b40affe2
42 mengubah file dengan 2579 tambahan dan 2008 penghapusan
  1. 7 5
      Anchor.toml
  2. 32 0
      Cargo.lock
  3. 1 0
      Cargo.toml
  4. 231 0
      clients/bolt-sdk/src/generated/idl/gpl_session.json
  5. 4 0
      clients/bolt-sdk/src/generated/idl/world.json
  6. 2 0
      clients/bolt-sdk/src/generated/index.ts
  7. 4 0
      clients/bolt-sdk/src/generated/types/world.ts
  8. 23 1
      clients/bolt-sdk/src/index.ts
  9. 42 0
      clients/bolt-sdk/src/session.ts
  10. 53 1
      clients/bolt-sdk/src/world/transactions.ts
  11. 79 203
      clients/bolt-sdk/yarn.lock
  12. 4 1
      crates/bolt-lang/Cargo.toml
  13. 21 9
      crates/bolt-lang/attribute/bolt-program/src/lib.rs
  14. 4 2
      crates/bolt-lang/attribute/system-input/src/lib.rs
  15. 15 8
      crates/bolt-lang/attribute/system/src/lib.rs
  16. 2 0
      crates/bolt-lang/src/lib.rs
  17. 29 63
      crates/programs/bolt-component/src/lib.rs
  18. 4 3
      crates/programs/bolt-system/src/lib.rs
  19. 18 7
      crates/programs/world/src/lib.rs
  20. 0 1
      examples/system-simple-movement/src/lib.rs
  21. 3 3
      scripts/lint.sh
  22. 0 713
      tests/bolt.intermediate-level.api.ts
  23. 0 988
      tests/bolt.low-level.api.ts
  24. TEMPAT SAMPAH
      tests/fixtures/session_keys.so
  25. 52 0
      tests/framework.ts
  26. 30 0
      tests/intermediate-level/acceleration.ts
  27. 286 0
      tests/intermediate-level/ecs.ts
  28. 15 0
      tests/intermediate-level/index.ts
  29. 115 0
      tests/intermediate-level/permissioning/component.ts
  30. 9 0
      tests/intermediate-level/permissioning/index.ts
  31. 168 0
      tests/intermediate-level/permissioning/world.ts
  32. 150 0
      tests/intermediate-level/session.ts
  33. 37 0
      tests/intermediate-level/world.ts
  34. 28 0
      tests/low-level/acceleration.ts
  35. 428 0
      tests/low-level/ecs.ts
  36. 15 0
      tests/low-level/index.ts
  37. 149 0
      tests/low-level/permissioning/component.ts
  38. 9 0
      tests/low-level/permissioning/index.ts
  39. 237 0
      tests/low-level/permissioning/world.ts
  40. 212 0
      tests/low-level/session.ts
  41. 59 0
      tests/low-level/world.ts
  42. 2 0
      tests/main.ts

+ 7 - 5
Anchor.toml

@@ -39,14 +39,11 @@ members = [
 test = """
 echo "Waiting for 2 seconds..."
 sleep 2
-echo "Running low level API tests..."
-yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/bolt.low-level.api.ts
-echo "Running intermediate level API tests..."
-yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/bolt.intermediate-level.api.ts
+yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/main.ts
 """
 
 [test]
-startup_wait = 5000
+startup_wait = 15000
 shutdown_wait = 2000
 upgradeable = false
 
@@ -55,6 +52,11 @@ address = "DELeGGvXpWV2fqJUhqcF5ZSYMS4JTLjteaAMARRSaeSh"
 program = "tests/fixtures/delegation.so"
 upgradeable = false
 
+[[test.genesis]]
+address="KeyspM2ssCJbqUhQ4k7sveSiY4WjnYsrXkC8oDbwde5"
+program="tests/fixtures/session_keys.so"
+upgradeable = false
+
 [test.validator]
 bind_address = "0.0.0.0"
 ledger = ".anchor/test-ledger"

+ 32 - 0
Cargo.lock

@@ -1104,6 +1104,7 @@ dependencies = [
  "ephemeral-rollups-sdk 0.2.1",
  "serde",
  "serde_json",
+ "session-keys",
  "world 0.2.0",
 ]
 
@@ -4210,6 +4211,37 @@ dependencies = [
  "unsafe-libyaml",
 ]
 
+[[package]]
+name = "session-keys"
+version = "2.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "059475c4228de6bcd7ef7dd9bb52c7329201d62dae701d73a71f2262c86dfc51"
+dependencies = [
+ "anchor-lang",
+ "session-keys-macros",
+ "solana-security-txt",
+]
+
+[[package]]
+name = "session-keys-macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6349e5cb01c08d3b3efad6cad6c63d622b703603812258ba6741cbc2c62ca39d"
+dependencies = [
+ "session-keys-macros-attribute",
+]
+
+[[package]]
+name = "session-keys-macros-attribute"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e07d122114bc5388a5440d62374b5b752f6013e270d100b479bb1b650d375d11"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
 [[package]]
 name = "sha1"
 version = "0.10.6"

+ 1 - 0
Cargo.toml

@@ -34,6 +34,7 @@ bolt-system = { path = "crates/programs/bolt-system", features = ["cpi"], versio
 bolt-component = { path = "crates/programs/bolt-component", features = ["cpi"], version = "=0.2.0"}
 
 ## External crates
+session-keys = { version = "=2.0.6", features = ["no-entrypoint"] }
 anchor-lang = { version = "=0.30.1", features = ["init-if-needed"] }
 anchor-cli = { version = "=0.30.1" }
 anchor-client = { version = "=0.30.1" }

+ 231 - 0
clients/bolt-sdk/src/generated/idl/gpl_session.json

@@ -0,0 +1,231 @@
+{
+  "address": "KeyspM2ssCJbqUhQ4k7sveSiY4WjnYsrXkC8oDbwde5",
+  "metadata": {
+    "name": "gpl_session",
+    "version": "2.0.6",
+    "spec": "0.1.0",
+    "description": "Gum Session Protocol (GPL Session)",
+    "repository": "https://github.com/magicblock-labs/gum-program-library"
+  },
+  "instructions": [
+    {
+      "name": "create_session",
+      "discriminator": [
+        242,
+        193,
+        143,
+        179,
+        150,
+        25,
+        122,
+        227
+      ],
+      "accounts": [
+        {
+          "name": "session_token",
+          "writable": true,
+          "pda": {
+            "seeds": [
+              {
+                "kind": "const",
+                "value": [
+                  115,
+                  101,
+                  115,
+                  115,
+                  105,
+                  111,
+                  110,
+                  95,
+                  116,
+                  111,
+                  107,
+                  101,
+                  110
+                ]
+              },
+              {
+                "kind": "account",
+                "path": "target_program"
+              },
+              {
+                "kind": "account",
+                "path": "session_signer"
+              },
+              {
+                "kind": "account",
+                "path": "authority"
+              }
+            ]
+          }
+        },
+        {
+          "name": "session_signer",
+          "writable": true,
+          "signer": true
+        },
+        {
+          "name": "authority",
+          "writable": true,
+          "signer": true
+        },
+        {
+          "name": "target_program",
+          "docs": [
+            "CHECK the target program is actually a program."
+          ]
+        },
+        {
+          "name": "system_program",
+          "address": "11111111111111111111111111111111"
+        }
+      ],
+      "args": [
+        {
+          "name": "top_up",
+          "type": {
+            "option": "bool"
+          }
+        },
+        {
+          "name": "valid_until",
+          "type": {
+            "option": "i64"
+          }
+        },
+        {
+          "name": "lamports",
+          "type": {
+            "option": "u64"
+          }
+        }
+      ]
+    },
+    {
+      "name": "revoke_session",
+      "discriminator": [
+        86,
+        92,
+        198,
+        120,
+        144,
+        2,
+        7,
+        194
+      ],
+      "accounts": [
+        {
+          "name": "session_token",
+          "writable": true,
+          "pda": {
+            "seeds": [
+              {
+                "kind": "const",
+                "value": [
+                  115,
+                  101,
+                  115,
+                  115,
+                  105,
+                  111,
+                  110,
+                  95,
+                  116,
+                  111,
+                  107,
+                  101,
+                  110
+                ]
+              },
+              {
+                "kind": "account",
+                "path": "session_token.target_program",
+                "account": "SessionToken"
+              },
+              {
+                "kind": "account",
+                "path": "session_token.session_signer",
+                "account": "SessionToken"
+              },
+              {
+                "kind": "account",
+                "path": "session_token.authority",
+                "account": "SessionToken"
+              }
+            ]
+          }
+        },
+        {
+          "name": "authority",
+          "writable": true,
+          "relations": [
+            "session_token"
+          ]
+        },
+        {
+          "name": "system_program",
+          "address": "11111111111111111111111111111111"
+        }
+      ],
+      "args": []
+    }
+  ],
+  "accounts": [
+    {
+      "name": "SessionToken",
+      "discriminator": [
+        233,
+        4,
+        115,
+        14,
+        46,
+        21,
+        1,
+        15
+      ]
+    }
+  ],
+  "errors": [
+    {
+      "code": 6000,
+      "name": "ValidityTooLong",
+      "msg": "Requested validity is too long"
+    },
+    {
+      "code": 6001,
+      "name": "InvalidToken",
+      "msg": "Invalid session token"
+    },
+    {
+      "code": 6002,
+      "name": "NoToken",
+      "msg": "No session token provided"
+    }
+  ],
+  "types": [
+    {
+      "name": "SessionToken",
+      "type": {
+        "kind": "struct",
+        "fields": [
+          {
+            "name": "authority",
+            "type": "pubkey"
+          },
+          {
+            "name": "target_program",
+            "type": "pubkey"
+          },
+          {
+            "name": "session_signer",
+            "type": "pubkey"
+          },
+          {
+            "name": "valid_until",
+            "type": "i64"
+          }
+        ]
+      }
+    }
+  ]
+}

+ 4 - 0
clients/bolt-sdk/src/generated/idl/world.json

@@ -111,6 +111,10 @@
         },
         {
           "name": "world"
+        },
+        {
+          "name": "session_token",
+          "optional": true
         }
       ],
       "args": [

+ 2 - 0
clients/bolt-sdk/src/generated/index.ts

@@ -8,6 +8,7 @@
 import { PublicKey } from "@solana/web3.js";
 import { type World as WorldProgram } from "./types/world";
 import idl from "./idl/world.json";
+import gpl_session from "./idl/gpl_session.json";
 export * from "./accounts";
 export * from "./errors";
 export * from "./instructions";
@@ -30,3 +31,4 @@ export const PROGRAM_ID = new PublicKey(PROGRAM_ADDRESS);
 
 export default WorldProgram;
 export { idl as worldIdl };
+export { gpl_session as sessionIdl };

+ 4 - 0
clients/bolt-sdk/src/generated/types/world.ts

@@ -91,6 +91,10 @@ export type World = {
         {
           name: "world";
         },
+        {
+          name: "sessionToken";
+          optional: true;
+        },
       ];
       args: [
         {

+ 23 - 1
clients/bolt-sdk/src/index.ts

@@ -1,7 +1,8 @@
 import { PublicKey } from "@solana/web3.js";
-import type BN from "bn.js";
+import BN from "bn.js";
 import { PROGRAM_ID as WORLD_PROGRAM_ID } from "./generated";
 import { World as WORLD_PROGRAM_IDL } from "./generated/types";
+export { BN };
 export * from "./generated/accounts";
 export * from "./generated/instructions";
 export * from "./world/transactions";
@@ -11,6 +12,7 @@ export { DELEGATION_PROGRAM_ID } from "@magicblock-labs/ephemeral-rollups-sdk";
 
 // Re-export anchor
 import * as anchor from "@coral-xyz/anchor";
+import { SessionProgram, Session } from "./session";
 export { anchor };
 export { Provider, Program, Wallet, web3, workspace } from "@coral-xyz/anchor";
 export { WORLD_PROGRAM_ID, WORLD_PROGRAM_IDL };
@@ -68,6 +70,24 @@ export function FindEntityPda({
   )[0];
 }
 
+export function FindSessionTokenPda({
+  sessionSigner,
+  authority,
+}: {
+  sessionSigner: PublicKey;
+  authority: PublicKey;
+}) {
+  return PublicKey.findProgramAddressSync(
+    [
+      Buffer.from("session_token"),
+      WORLD_PROGRAM_ID.toBytes(),
+      sessionSigner.toBytes(),
+      authority.toBytes(),
+    ],
+    SessionProgram.programId,
+  )[0];
+}
+
 // TODO: seed must be Uint8Array like the other FindPda functions
 export function FindComponentPda({
   componentId,
@@ -99,3 +119,5 @@ export function SerializeArgs(args: any = {}) {
     binaryData.byteLength,
   );
 }
+
+export { SessionProgram, Session };

+ 42 - 0
clients/bolt-sdk/src/session.ts

@@ -0,0 +1,42 @@
+import { Program, Idl } from "@coral-xyz/anchor";
+import { sessionIdl } from "./generated";
+import { Keypair, PublicKey } from "@solana/web3.js";
+let _actualInstance: Program | null = null;
+
+function getOrCreateInstance(): Program {
+  if (!_actualInstance) {
+    _actualInstance = new Program(sessionIdl as Idl);
+  }
+  return _actualInstance;
+}
+
+export const SessionProgram = new Proxy<Program>({} as Program, {
+  get(_target, property, receiver) {
+    // Ensure the real object is instantiated
+    const actual = getOrCreateInstance();
+
+    // Forward the property access to the real instance
+    return Reflect.get(actual, property, receiver);
+  },
+
+  set(_target, property, value, receiver) {
+    const actual = getOrCreateInstance();
+    return Reflect.set(actual, property, value, receiver);
+  },
+
+  // If you need to handle method calls specifically (Function type check),
+  // or other traps (has, apply, etc.), you can add them here as well.
+});
+
+export class Session {
+  public readonly signer: Keypair;
+  public readonly token: PublicKey;
+
+  constructor(
+    public readonly sessionSigner: Keypair,
+    public readonly sessionToken: PublicKey,
+  ) {
+    this.signer = sessionSigner;
+    this.token = sessionToken;
+  }
+}

+ 53 - 1
clients/bolt-sdk/src/world/transactions.ts

@@ -11,11 +11,16 @@ import {
   SerializeArgs,
   SYSVAR_INSTRUCTIONS_PUBKEY,
   World,
+  SessionProgram,
+  Session,
+  FindSessionTokenPda,
+  WORLD_PROGRAM_ID,
+  BN,
 } from "../index";
-import BN from "bn.js";
 import type web3 from "@solana/web3.js";
 import {
   type Connection,
+  Keypair,
   type PublicKey,
   Transaction,
   type TransactionInstruction,
@@ -47,6 +52,45 @@ export async function InitializeRegistry({
   };
 }
 
+export async function CreateSession({
+  sessionSigner,
+  authority,
+  topUp,
+  validity,
+}: {
+  sessionSigner?: Keypair;
+  authority: PublicKey;
+  topUp?: BN;
+  validity?: BN;
+}): Promise<{
+  instruction: TransactionInstruction;
+  transaction: Transaction;
+  session: Session;
+}> {
+  sessionSigner = sessionSigner ?? Keypair.generate();
+  const sessionToken = FindSessionTokenPda({
+    sessionSigner: sessionSigner.publicKey,
+    authority,
+  });
+  const lamports = topUp ?? null;
+  const shouldTopUp = topUp ? true : false;
+  let instruction = await SessionProgram.methods
+    .createSession(shouldTopUp, validity ?? null, lamports)
+    .accounts({
+      sessionSigner: sessionSigner.publicKey,
+      authority,
+      targetProgram: WORLD_PROGRAM_ID,
+      sessionToken,
+    })
+    .instruction();
+  const transaction = new Transaction().add(instruction);
+  return {
+    instruction,
+    transaction,
+    session: new Session(sessionSigner, sessionToken),
+  };
+}
+
 /**
  * Create the transaction to Initialize a new world
  * @param payer
@@ -337,6 +381,7 @@ interface ApplySystemInstruction {
   systemId: PublicKey;
   entities: ApplySystemEntity[];
   world: PublicKey;
+  session?: Session;
   extraAccounts?: web3.AccountMeta[];
   args?: object;
 }
@@ -345,6 +390,7 @@ async function createApplySystemInstruction({
   systemId,
   entities,
   world,
+  session,
   extraAccounts,
   args,
 }: ApplySystemInstruction): Promise<web3.TransactionInstruction> {
@@ -359,9 +405,12 @@ async function createApplySystemInstruction({
     throw new Error("No components provided");
   }
 
+  let sessionToken = session ? session.token : null;
+
   const applyAccounts = {
     authority: authority ?? PROGRAM_ID,
     boltSystem: systemId,
+    sessionToken,
     world,
   };
 
@@ -435,6 +484,7 @@ export async function ApplySystem({
   world,
   extraAccounts,
   args,
+  session,
 }: {
   authority: PublicKey;
   systemId: PublicKey;
@@ -442,6 +492,7 @@ export async function ApplySystem({
   world: PublicKey;
   extraAccounts?: web3.AccountMeta[];
   args?: object;
+  session?: Session;
 }): Promise<{ instruction: TransactionInstruction; transaction: Transaction }> {
   const instruction = await createApplySystemInstruction({
     authority,
@@ -450,6 +501,7 @@ export async function ApplySystem({
     world,
     extraAccounts,
     args,
+    session,
   });
   const transaction = new Transaction().add(instruction);
   return {

+ 79 - 203
clients/bolt-sdk/yarn.lock

@@ -2,28 +2,21 @@
 # yarn lockfile v1
 
 
-"@babel/runtime@^7.17.2", "@babel/runtime@^7.23.2":
-  version "7.23.6"
-  resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.6.tgz"
-  integrity sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ==
-  dependencies:
-    regenerator-runtime "^0.14.0"
-
 "@babel/runtime@^7.25.0":
-  version "7.25.7"
-  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.7.tgz#7ffb53c37a8f247c8c4d335e89cdf16a2e0d0fb6"
-  integrity sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==
+  version "7.26.7"
+  resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.7.tgz"
+  integrity sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ==
   dependencies:
     regenerator-runtime "^0.14.0"
 
 "@coral-xyz/anchor-errors@^0.30.1":
   version "0.30.1"
-  resolved "https://registry.yarnpkg.com/@coral-xyz/anchor-errors/-/anchor-errors-0.30.1.tgz#bdfd3a353131345244546876eb4afc0e125bec30"
+  resolved "https://registry.npmjs.org/@coral-xyz/anchor-errors/-/anchor-errors-0.30.1.tgz"
   integrity sha512-9Mkradf5yS5xiLWrl9WrpjqOrAV+/W2RQHDlbnAZBivoGpOs1ECjoDCkVk4aRG8ZdiFiB8zQEVlxf+8fKkmSfQ==
 
 "@coral-xyz/anchor@^0.30.1":
   version "0.30.1"
-  resolved "https://registry.yarnpkg.com/@coral-xyz/anchor/-/anchor-0.30.1.tgz#17f3e9134c28cd0ea83574c6bab4e410bcecec5d"
+  resolved "https://registry.npmjs.org/@coral-xyz/anchor/-/anchor-0.30.1.tgz"
   integrity sha512-gDXFoF5oHgpriXAaLpxyWBHdCs8Awgf/gLHIo6crv7Aqm937CNdY+x+6hoj7QR5vaJV7MxWSQ0NGFzL3kPbWEQ==
   dependencies:
     "@coral-xyz/anchor-errors" "^0.30.1"
@@ -44,7 +37,7 @@
 
 "@coral-xyz/borsh@^0.30.1":
   version "0.30.1"
-  resolved "https://registry.yarnpkg.com/@coral-xyz/borsh/-/borsh-0.30.1.tgz#869d8833abe65685c72e9199b8688477a4f6b0e3"
+  resolved "https://registry.npmjs.org/@coral-xyz/borsh/-/borsh-0.30.1.tgz"
   integrity sha512-aaxswpPrCFKl8vZTbxLssA2RvwX2zmKLlRCIktJOwW+VpVwYtXRtlWiIP+c2pPRKneiTiWCN2GEMSH9j1zTlWQ==
   dependencies:
     bn.js "^5.1.2"
@@ -64,7 +57,7 @@
 
 "@magicblock-labs/ephemeral-rollups-sdk@0.2.1":
   version "0.2.1"
-  resolved "https://registry.yarnpkg.com/@magicblock-labs/ephemeral-rollups-sdk/-/ephemeral-rollups-sdk-0.2.1.tgz#bf85a0725b9fe47bc96738a99bf9e84aa9e405d0"
+  resolved "https://registry.npmjs.org/@magicblock-labs/ephemeral-rollups-sdk/-/ephemeral-rollups-sdk-0.2.1.tgz"
   integrity sha512-s1j6kXLbg6hA5ysSkG1pGEutAdxPOymtl2I94pD5UVfWWILcR0rbqONOvNV1WKDGZbILqC1AjFl/7GJGRMKB5Q==
   dependencies:
     "@metaplex-foundation/beet" "^0.7.2"
@@ -83,7 +76,7 @@
 
 "@metaplex-foundation/beet-solana@^0.4.0":
   version "0.4.1"
-  resolved "https://registry.yarnpkg.com/@metaplex-foundation/beet-solana/-/beet-solana-0.4.1.tgz#255747aa7feee1c20202146a752c057feca1948f"
+  resolved "https://registry.npmjs.org/@metaplex-foundation/beet-solana/-/beet-solana-0.4.1.tgz"
   integrity sha512-/6o32FNUtwK8tjhotrvU/vorP7umBuRFvBZrC6XCk51aKidBHe5LPVPA5AjGPbV3oftMfRuXPNd9yAGeEqeCDQ==
   dependencies:
     "@metaplex-foundation/beet" ">=0.1.0"
@@ -102,7 +95,7 @@
 
 "@metaplex-foundation/beet@^0.7.2":
   version "0.7.2"
-  resolved "https://registry.yarnpkg.com/@metaplex-foundation/beet/-/beet-0.7.2.tgz#fa4726e4cfd4fb6fed6cddc9b5213c1c2a2d0b77"
+  resolved "https://registry.npmjs.org/@metaplex-foundation/beet/-/beet-0.7.2.tgz"
   integrity sha512-K+g3WhyFxKPc0xIvcIjNyV1eaTVJTiuaHZpig7Xx0MuYRMoJLLvhLTnUXhFdR5Tu2l2QSyKwfyXDgZlzhULqFg==
   dependencies:
     ansicolors "^0.3.2"
@@ -137,92 +130,33 @@
     snake-case "^3.0.4"
     spok "^1.4.3"
 
-"@noble/curves@^1.2.0":
-  version "1.3.0"
-  resolved "https://registry.npmjs.org/@noble/curves/-/curves-1.3.0.tgz"
-  integrity sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA==
-  dependencies:
-    "@noble/hashes" "1.3.3"
-
 "@noble/curves@^1.4.2":
-  version "1.6.0"
-  resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.6.0.tgz#be5296ebcd5a1730fccea4786d420f87abfeb40b"
-  integrity sha512-TlaHRXDehJuRNR9TfZDNQ45mMEd5dwUwmicsafcIX4SsNiqnCHKjE/1alYPd/lDRVhxdhUAlv8uEhMCI5zjIJQ==
+  version "1.8.1"
+  resolved "https://registry.npmjs.org/@noble/curves/-/curves-1.8.1.tgz"
+  integrity sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==
   dependencies:
-    "@noble/hashes" "1.5.0"
-
-"@noble/hashes@1.3.3", "@noble/hashes@^1.3.1":
-  version "1.3.3"
-  resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz"
-  integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==
-
-"@noble/hashes@1.5.0":
-  version "1.5.0"
-  resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.5.0.tgz#abadc5ca20332db2b1b2aa3e496e9af1213570b0"
-  integrity sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==
+    "@noble/hashes" "1.7.1"
 
-"@noble/hashes@^1.4.0":
-  version "1.4.0"
-  resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426"
-  integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==
+"@noble/hashes@1.7.1", "@noble/hashes@^1.3.1", "@noble/hashes@^1.4.0":
+  version "1.7.1"
+  resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.1.tgz"
+  integrity sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==
 
 "@pkgjs/parseargs@^0.11.0":
   version "0.11.0"
   resolved "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz"
   integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
 
-"@solana/buffer-layout@^4.0.0", "@solana/buffer-layout@^4.0.1":
+"@solana/buffer-layout@^4.0.1":
   version "4.0.1"
   resolved "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz"
   integrity sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==
   dependencies:
     buffer "~6.0.3"
 
-"@solana/web3.js@^1.56.2":
-  version "1.87.6"
-  resolved "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.87.6.tgz"
-  integrity sha512-LkqsEBgTZztFiccZZXnawWa8qNCATEqE97/d0vIwjTclmVlc8pBpD1DmjfVHtZ1HS5fZorFlVhXfpwnCNDZfyg==
-  dependencies:
-    "@babel/runtime" "^7.23.2"
-    "@noble/curves" "^1.2.0"
-    "@noble/hashes" "^1.3.1"
-    "@solana/buffer-layout" "^4.0.0"
-    agentkeepalive "^4.3.0"
-    bigint-buffer "^1.1.5"
-    bn.js "^5.2.1"
-    borsh "^0.7.0"
-    bs58 "^4.0.1"
-    buffer "6.0.3"
-    fast-stable-stringify "^1.0.0"
-    jayson "^4.1.0"
-    node-fetch "^2.6.12"
-    rpc-websockets "^7.5.1"
-    superstruct "^0.14.2"
-
-"@solana/web3.js@^1.68.0":
-  version "1.95.3"
-  resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.95.3.tgz#70b5f4d76823f56b5af6403da51125fffeb65ff3"
-  integrity sha512-O6rPUN0w2fkNqx/Z3QJMB9L225Ex10PRDH8bTaIUPZXMPV0QP8ZpPvjQnXK+upUczlRgzHzd6SjKIha1p+I6og==
-  dependencies:
-    "@babel/runtime" "^7.25.0"
-    "@noble/curves" "^1.4.2"
-    "@noble/hashes" "^1.4.0"
-    "@solana/buffer-layout" "^4.0.1"
-    agentkeepalive "^4.5.0"
-    bigint-buffer "^1.1.5"
-    bn.js "^5.2.1"
-    borsh "^0.7.0"
-    bs58 "^4.0.1"
-    buffer "6.0.3"
-    fast-stable-stringify "^1.0.0"
-    jayson "^4.1.1"
-    node-fetch "^2.7.0"
-    rpc-websockets "^9.0.2"
-    superstruct "^2.0.2"
-
-"@solana/web3.js@^1.98.0":
+"@solana/web3.js@^1.56.2", "@solana/web3.js@^1.68.0", "@solana/web3.js@^1.98.0":
   version "1.98.0"
-  resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.98.0.tgz#21ecfe8198c10831df6f0cfde7f68370d0405917"
+  resolved "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.98.0.tgz"
   integrity sha512-nz3Q5OeyGFpFCR+erX2f6JPt3sKhzhYcSycBCSPkWjzSVDh/Rr1FqTVMRe58FKO16/ivTUcuJjeS5MyBvpkbzA==
   dependencies:
     "@babel/runtime" "^7.25.0"
@@ -242,11 +176,11 @@
     superstruct "^2.0.2"
 
 "@swc/helpers@^0.5.11":
-  version "0.5.11"
-  resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.11.tgz#5bab8c660a6e23c13b2d23fcd1ee44a2db1b0cb7"
-  integrity sha512-YNlnKRWF2sVojTpIyzwou9XoTNbzbzONwRhOoniEioF1AtaitTvVZblaQRrAzChWQ1bLYyYSWzM18y4WwgzJ+A==
+  version "0.5.15"
+  resolved "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz"
+  integrity sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==
   dependencies:
-    tslib "^2.4.0"
+    tslib "^2.8.0"
 
 "@types/connect@^3.4.33":
   version "3.4.38"
@@ -255,21 +189,14 @@
   dependencies:
     "@types/node" "*"
 
-"@types/node@*":
-  version "20.10.4"
-  resolved "https://registry.npmjs.org/@types/node/-/node-20.10.4.tgz"
-  integrity sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==
-  dependencies:
-    undici-types "~5.26.4"
-
-"@types/node@^12.12.54":
+"@types/node@*", "@types/node@^12.12.54":
   version "12.20.55"
   resolved "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz"
   integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==
 
 "@types/uuid@^8.3.4":
   version "8.3.4"
-  resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc"
+  resolved "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz"
   integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==
 
 "@types/ws@^7.4.4":
@@ -280,9 +207,9 @@
     "@types/node" "*"
 
 "@types/ws@^8.2.2":
-  version "8.5.10"
-  resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.10.tgz#4acfb517970853fa6574a3a6886791d04a396787"
-  integrity sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==
+  version "8.5.14"
+  resolved "https://registry.npmjs.org/@types/ws/-/ws-8.5.14.tgz"
+  integrity sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw==
   dependencies:
     "@types/node" "*"
 
@@ -294,7 +221,7 @@ JSONStream@^1.3.5:
     jsonparse "^1.2.0"
     through ">=2.2.7 <3"
 
-agentkeepalive@^4.3.0, agentkeepalive@^4.5.0:
+agentkeepalive@^4.5.0:
   version "4.5.0"
   resolved "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz"
   integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==
@@ -340,7 +267,7 @@ ansicolors@^0.3.2, ansicolors@~0.3.2:
 
 assert@^2.1.0:
   version "2.1.0"
-  resolved "https://registry.yarnpkg.com/assert/-/assert-2.1.0.tgz#6d92a238d05dc02e7427c881fb8be81c8448b2dd"
+  resolved "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz"
   integrity sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==
   dependencies:
     call-bind "^1.0.2"
@@ -351,7 +278,7 @@ assert@^2.1.0:
 
 available-typed-arrays@^1.0.7:
   version "1.0.7"
-  resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846"
+  resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz"
   integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==
   dependencies:
     possible-typed-array-names "^1.0.0"
@@ -429,7 +356,7 @@ bs58@^5.0.0:
 
 buffer-layout@^1.2.0, buffer-layout@^1.2.2:
   version "1.2.2"
-  resolved "https://registry.yarnpkg.com/buffer-layout/-/buffer-layout-1.2.2.tgz#b9814e7c7235783085f9ca4966a0cfff112259d5"
+  resolved "https://registry.npmjs.org/buffer-layout/-/buffer-layout-1.2.2.tgz"
   integrity sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==
 
 buffer@6.0.3, buffer@^6.0.3, buffer@~6.0.3:
@@ -441,9 +368,9 @@ buffer@6.0.3, buffer@^6.0.3, buffer@~6.0.3:
     ieee754 "^1.2.1"
 
 bufferutil@^4.0.1:
-  version "4.0.8"
-  resolved "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz"
-  integrity sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==
+  version "4.0.9"
+  resolved "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.9.tgz"
+  integrity sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==
   dependencies:
     node-gyp-build "^4.3.0"
 
@@ -458,7 +385,7 @@ call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.5:
 
 call-bind@^1.0.7:
   version "1.0.7"
-  resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9"
+  resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz"
   integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==
   dependencies:
     es-define-property "^1.0.0"
@@ -504,7 +431,7 @@ commander@^5.1.0:
 
 cross-fetch@^3.1.5:
   version "3.1.8"
-  resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.8.tgz#0327eba65fd68a7d119f8fb2bf9334a1a7956f82"
+  resolved "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz"
   integrity sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==
   dependencies:
     node-fetch "^2.6.12"
@@ -520,7 +447,7 @@ cross-spawn@^7.0.0:
 
 crypto-hash@^1.3.0:
   version "1.3.0"
-  resolved "https://registry.yarnpkg.com/crypto-hash/-/crypto-hash-1.3.0.tgz#b402cb08f4529e9f4f09346c3e275942f845e247"
+  resolved "https://registry.npmjs.org/crypto-hash/-/crypto-hash-1.3.0.tgz"
   integrity sha512-lyAZ0EMyjDkVvz8WOeVnuCPvKVBXcMv1l5SVqO1yC7PzTwrD/pPje/BIRbWhMoPe436U+Y2nD7f5bFx0kt+Sbg==
 
 debug@^4.1.1, debug@^4.3.3, debug@^4.3.4:
@@ -541,7 +468,7 @@ define-data-property@^1.0.1, define-data-property@^1.1.1:
 
 define-data-property@^1.1.4:
   version "1.1.4"
-  resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e"
+  resolved "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz"
   integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==
   dependencies:
     es-define-property "^1.0.0"
@@ -587,14 +514,14 @@ emoji-regex@^9.2.2:
 
 es-define-property@^1.0.0:
   version "1.0.0"
-  resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845"
+  resolved "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz"
   integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==
   dependencies:
     get-intrinsic "^1.2.4"
 
 es-errors@^1.3.0:
   version "1.3.0"
-  resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
+  resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz"
   integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
 
 es6-promise@^4.0.3:
@@ -616,7 +543,7 @@ eventemitter3@^4.0.7:
 
 eventemitter3@^5.0.1:
   version "5.0.1"
-  resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4"
+  resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz"
   integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==
 
 eyes@^0.1.8:
@@ -675,7 +602,7 @@ get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2:
 
 get-intrinsic@^1.2.4:
   version "1.2.4"
-  resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd"
+  resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz"
   integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==
   dependencies:
     es-errors "^1.3.0"
@@ -728,7 +655,7 @@ has-property-descriptors@^1.0.0:
 
 has-property-descriptors@^1.0.2:
   version "1.0.2"
-  resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854"
+  resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz"
   integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==
   dependencies:
     es-define-property "^1.0.0"
@@ -752,7 +679,7 @@ has-tostringtag@^1.0.0:
 
 has-tostringtag@^1.0.2:
   version "1.0.2"
-  resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc"
+  resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz"
   integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==
   dependencies:
     has-symbols "^1.0.3"
@@ -778,12 +705,12 @@ ieee754@^1.2.1:
 
 inherits@^2.0.3:
   version "2.0.4"
-  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+  resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
   integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
 
 is-arguments@^1.0.4:
   version "1.1.1"
-  resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b"
+  resolved "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz"
   integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==
   dependencies:
     call-bind "^1.0.2"
@@ -801,14 +728,14 @@ is-fullwidth-code-point@^3.0.0:
 
 is-generator-function@^1.0.7:
   version "1.0.10"
-  resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72"
+  resolved "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz"
   integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==
   dependencies:
     has-tostringtag "^1.0.0"
 
 is-nan@^1.3.2:
   version "1.3.2"
-  resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d"
+  resolved "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz"
   integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==
   dependencies:
     call-bind "^1.0.0"
@@ -816,7 +743,7 @@ is-nan@^1.3.2:
 
 is-typed-array@^1.1.3:
   version "1.1.13"
-  resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229"
+  resolved "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz"
   integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==
   dependencies:
     which-typed-array "^1.1.14"
@@ -840,28 +767,10 @@ jackspeak@^2.3.5:
   optionalDependencies:
     "@pkgjs/parseargs" "^0.11.0"
 
-jayson@^4.1.0:
-  version "4.1.0"
-  resolved "https://registry.npmjs.org/jayson/-/jayson-4.1.0.tgz"
-  integrity sha512-R6JlbyLN53Mjku329XoRT2zJAE6ZgOQ8f91ucYdMCD4nkGCF9kZSrcGXpHIU4jeKj58zUZke2p+cdQchU7Ly7A==
-  dependencies:
-    "@types/connect" "^3.4.33"
-    "@types/node" "^12.12.54"
-    "@types/ws" "^7.4.4"
-    JSONStream "^1.3.5"
-    commander "^2.20.3"
-    delay "^5.0.0"
-    es6-promisify "^5.0.0"
-    eyes "^0.1.8"
-    isomorphic-ws "^4.0.1"
-    json-stringify-safe "^5.0.1"
-    uuid "^8.3.2"
-    ws "^7.4.5"
-
 jayson@^4.1.1:
-  version "4.1.2"
-  resolved "https://registry.yarnpkg.com/jayson/-/jayson-4.1.2.tgz#443c26a8658703e0b2e881117b09395d88b6982e"
-  integrity sha512-5nzMWDHy6f+koZOuYsArh2AXs73NfWYVlFyJJuCedr93GpY+Ku8qq10ropSXVfHK+H0T6paA88ww+/dV+1fBNA==
+  version "4.1.3"
+  resolved "https://registry.npmjs.org/jayson/-/jayson-4.1.3.tgz"
+  integrity sha512-LtXh5aYZodBZ9Fc3j6f2w+MTNcnxteMOrb+QgIouguGOulWi0lieEkOUg+HkjjFs0DGoWDds6bi4E9hpNFLulQ==
   dependencies:
     "@types/connect" "^3.4.33"
     "@types/node" "^12.12.54"
@@ -973,13 +882,13 @@ node-fetch@^2.6.12, node-fetch@^2.7.0:
     whatwg-url "^5.0.0"
 
 node-gyp-build@^4.3.0:
-  version "4.7.1"
-  resolved "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.7.1.tgz"
-  integrity sha512-wTSrZ+8lsRRa3I3H8Xr65dLWSgCvY2l4AOnaeKdPA9TB/WYMPaTcrzf3rXvFoVvjKNVnu0CcWSx54qq9GKRUYg==
+  version "4.8.4"
+  resolved "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz"
+  integrity sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==
 
 object-is@^1.1.5:
   version "1.1.6"
-  resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.6.tgz#1a6a53aed2dd8f7e6775ff870bea58545956ab07"
+  resolved "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz"
   integrity sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==
   dependencies:
     call-bind "^1.0.7"
@@ -1002,7 +911,7 @@ object.assign@^4.1.4:
 
 pako@^2.0.3:
   version "2.1.0"
-  resolved "https://registry.yarnpkg.com/pako/-/pako-2.1.0.tgz#266cc37f98c7d883545d11335c00fbd4062c9a86"
+  resolved "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz"
   integrity sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==
 
 path-key@^3.1.0:
@@ -1020,7 +929,7 @@ path-scurry@^1.10.1:
 
 possible-typed-array-names@^1.0.0:
   version "1.0.0"
-  resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f"
+  resolved "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz"
   integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==
 
 prettier@^2.5.1:
@@ -1030,13 +939,13 @@ prettier@^2.5.1:
 
 prettier@^3.3.3:
   version "3.3.3"
-  resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.3.tgz#30c54fe0be0d8d12e6ae61dbb10109ea00d53105"
+  resolved "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz"
   integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==
 
 regenerator-runtime@^0.14.0:
-  version "0.14.0"
-  resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz"
-  integrity sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==
+  version "0.14.1"
+  resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz"
+  integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==
 
 rimraf@^5.0.5:
   version "5.0.5"
@@ -1045,22 +954,9 @@ rimraf@^5.0.5:
   dependencies:
     glob "^10.3.7"
 
-rpc-websockets@^7.5.1:
-  version "7.8.0"
-  resolved "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-7.8.0.tgz"
-  integrity sha512-AStkq6KDvSAmA4WiwlK1pDvj/33BWmExTATUokC0v+NhWekXSTNzXS5OGXeYwq501/pj6lBZMofg/h4dx4/tCg==
-  dependencies:
-    "@babel/runtime" "^7.17.2"
-    eventemitter3 "^4.0.7"
-    uuid "^8.3.2"
-    ws "^8.5.0"
-  optionalDependencies:
-    bufferutil "^4.0.1"
-    utf-8-validate "^5.0.2"
-
 rpc-websockets@^9.0.2, rpc-websockets@^9.0.4:
   version "9.0.4"
-  resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-9.0.4.tgz#9d8ee82533b5d1e13d9ded729e3e38d0d8fa083f"
+  resolved "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-9.0.4.tgz"
   integrity sha512-yWZWN0M+bivtoNLnaDbtny4XchdAIF5Q4g/ZsC5UC61Ckbp0QczwO8fg44rV3uYmY4WHd+EZQbn90W1d8ojzqQ==
   dependencies:
     "@swc/helpers" "^0.5.11"
@@ -1098,7 +994,7 @@ set-function-length@^1.1.1:
 
 set-function-length@^1.2.1:
   version "1.2.2"
-  resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449"
+  resolved "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz"
   integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==
   dependencies:
     define-data-property "^1.1.4"
@@ -1204,19 +1100,14 @@ strip-ansi@^7.0.1:
   dependencies:
     ansi-regex "^6.0.1"
 
-superstruct@^0.14.2:
-  version "0.14.2"
-  resolved "https://registry.npmjs.org/superstruct/-/superstruct-0.14.2.tgz"
-  integrity sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ==
-
 superstruct@^0.15.4:
   version "0.15.5"
-  resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.15.5.tgz#0f0a8d3ce31313f0d84c6096cd4fa1bfdedc9dab"
+  resolved "https://registry.npmjs.org/superstruct/-/superstruct-0.15.5.tgz"
   integrity sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ==
 
 superstruct@^2.0.2:
   version "2.0.2"
-  resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-2.0.2.tgz#3f6d32fbdc11c357deff127d591a39b996300c54"
+  resolved "https://registry.npmjs.org/superstruct/-/superstruct-2.0.2.tgz"
   integrity sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==
 
 supports-color@^7.1.0:
@@ -1251,15 +1142,10 @@ tr46@~0.0.3:
   resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz"
   integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
 
-tslib@^2.0.3:
-  version "2.6.2"
-  resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz"
-  integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
-
-tslib@^2.4.0:
-  version "2.6.3"
-  resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0"
-  integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==
+tslib@^2.0.3, tslib@^2.8.0:
+  version "2.8.1"
+  resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz"
+  integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
 
 typedoc-plugin-markdown@^3.17.1:
   version "3.17.1"
@@ -1280,7 +1166,7 @@ typedoc@^0.25.4:
 
 typescript@^4.5.5:
   version "4.9.5"
-  resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a"
+  resolved "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz"
   integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
 
 uglify-js@^3.1.4:
@@ -1288,11 +1174,6 @@ uglify-js@^3.1.4:
   resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz"
   integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==
 
-undici-types@~5.26.4:
-  version "5.26.5"
-  resolved "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz"
-  integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
-
 utf-8-validate@^5.0.2:
   version "5.0.10"
   resolved "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz"
@@ -1302,7 +1183,7 @@ utf-8-validate@^5.0.2:
 
 util@^0.12.5:
   version "0.12.5"
-  resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc"
+  resolved "https://registry.npmjs.org/util/-/util-0.12.5.tgz"
   integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==
   dependencies:
     inherits "^2.0.3"
@@ -1341,7 +1222,7 @@ whatwg-url@^5.0.0:
 
 which-typed-array@^1.1.14, which-typed-array@^1.1.2:
   version "1.1.15"
-  resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d"
+  resolved "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz"
   integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==
   dependencies:
     available-typed-arrays "^1.0.7"
@@ -1380,20 +1261,15 @@ wrap-ansi@^8.1.0:
     string-width "^5.0.1"
     strip-ansi "^7.0.1"
 
-ws@^7.4.5:
-  version "7.5.9"
-  resolved "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz"
-  integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==
-
 ws@^7.5.10:
   version "7.5.10"
-  resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9"
+  resolved "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz"
   integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==
 
 ws@^8.5.0:
-  version "8.15.1"
-  resolved "https://registry.npmjs.org/ws/-/ws-8.15.1.tgz"
-  integrity sha512-W5OZiCjXEmk0yZ66ZN82beM5Sz7l7coYxpRkzS+p9PP+ToQry8szKh+61eNktr7EA9DOwvFGhfC605jDHbP6QQ==
+  version "8.18.0"
+  resolved "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz"
+  integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==
 
 yallist@^4.0.0:
   version "4.0.0"

+ 4 - 1
crates/bolt-lang/Cargo.toml

@@ -30,8 +30,11 @@ bolt-attribute-bolt-arguments = { workspace = true }
 world = { workspace = true }
 bolt-system = { workspace = true }
 
+# Session Keys
+session-keys = { workspace = true }
+
 # Delegation
-ephemeral-rollups-sdk = { workspace = true , features = ["anchor"]}
+ephemeral-rollups-sdk = { workspace = true, features = ["anchor"]}
 
 # Other dependencies
 serde = { workspace = true }

+ 21 - 9
crates/bolt-lang/attribute/bolt-program/src/lib.rs

@@ -148,17 +148,28 @@ fn generate_update(component_type: &Type) -> (TokenStream2, TokenStream2) {
         quote! {
             #[automatically_derived]
             pub fn update(ctx: Context<Update>, data: Vec<u8>) -> Result<()> {
+                if let Some(session_token) = &ctx.accounts.session_token {
+                    if ctx.accounts.bolt_component.bolt_metadata.authority == World::id() {
+                        require!(Clock::get()?.unix_timestamp < session_token.valid_until, bolt_lang::session_keys::SessionError::InvalidToken);
+                    } else {
+                        let validity_ctx = bolt_lang::session_keys::ValidityChecker {
+                            session_token: session_token.clone(),
+                            session_signer: ctx.accounts.authority.clone(),
+                            authority: ctx.accounts.bolt_component.bolt_metadata.authority.clone(),
+                            target_program: World::id(),
+                        };
+                        require!(session_token.validate(validity_ctx)?, bolt_lang::session_keys::SessionError::InvalidToken);
+                        require_eq!(ctx.accounts.bolt_component.bolt_metadata.authority, session_token.authority, bolt_lang::session_keys::SessionError::InvalidToken);
+                    }
+                } else {
+                    require!(ctx.accounts.bolt_component.bolt_metadata.authority == World::id() || (ctx.accounts.bolt_component.bolt_metadata.authority == *ctx.accounts.authority.key && ctx.accounts.authority.is_signer), BoltError::InvalidAuthority);
+                }
+
                 // Check if the instruction is called from the world program
                 let instruction = anchor_lang::solana_program::sysvar::instructions::get_instruction_relative(
                     0, &ctx.accounts.instruction_sysvar_account.to_account_info()
                 ).unwrap();
-                if instruction.program_id != World::id() {
-                    return Err(BoltError::InvalidCaller.into());
-                }
-                // Check if the authority is authorized to modify the data
-                if ctx.accounts.bolt_component.bolt_metadata.authority != World::id() && (ctx.accounts.bolt_component.bolt_metadata.authority != *ctx.accounts.authority.key || !ctx.accounts.authority.is_signer) {
-                    return Err(BoltError::InvalidAuthority.into());
-                }
+                require_eq!(instruction.program_id, World::id(), BoltError::InvalidCaller);
 
                 ctx.accounts.bolt_component.set_inner(<#component_type>::try_from_slice(&data)?);
                 Ok(())
@@ -171,10 +182,11 @@ fn generate_update(component_type: &Type) -> (TokenStream2, TokenStream2) {
                 #[account(mut)]
                 pub bolt_component: Account<'info, #component_type>,
                 #[account()]
-                /// CHECK: The authority of the component
-                pub authority: AccountInfo<'info>,
+                pub authority: Signer<'info>,
                 #[account(address = anchor_lang::solana_program::sysvar::instructions::id())]
                 pub instruction_sysvar_account: UncheckedAccount<'info>,
+                #[account(constraint = session_token.to_account_info().owner == &bolt_lang::session_keys::ID)]
+                pub session_token: Option<Account<'info, bolt_lang::session_keys::SessionToken>>,
             }
         },
     )

+ 4 - 2
crates/bolt-lang/attribute/system-input/src/lib.rs

@@ -76,8 +76,9 @@ pub fn system_input(_attr: TokenStream, item: TokenStream) -> TokenStream {
         #[derive(Accounts)]
         pub struct #name<'info> {
             #(#transformed_fields)*
+            /// CHECK: Authority check
             #[account()]
-            pub authority: Signer<'info>,
+            pub authority: AccountInfo<'info>,
         }
     };
 
@@ -136,8 +137,9 @@ pub fn system_input(_attr: TokenStream, item: TokenStream) -> TokenStream {
 
         #[derive(Accounts)]
         pub struct VariadicBoltComponents<'info> {
+            /// CHECK: Authority check
             #[account()]
-            pub authority: Signer<'info>,
+            pub authority: AccountInfo<'info>,
         }
     };
 

+ 15 - 8
crates/bolt-lang/attribute/system/src/lib.rs

@@ -1,6 +1,6 @@
 use proc_macro::TokenStream;
 use proc_macro2::Ident;
-use quote::{quote, ToTokens};
+use quote::{quote, ToTokens, TokenStreamExt};
 use syn::{
     parse_macro_input, parse_quote, visit_mut::VisitMut, Expr, FnArg, GenericArgument, ItemFn,
     ItemMod, ItemStruct, PathArguments, ReturnType, Stmt, Type, TypePath,
@@ -34,9 +34,8 @@ struct Extractor {
 /// }
 /// ```
 #[proc_macro_attribute]
-pub fn system(attr: TokenStream, item: TokenStream) -> TokenStream {
+pub fn system(_attr: TokenStream, item: TokenStream) -> TokenStream {
     let mut ast = parse_macro_input!(item as ItemMod);
-    let _attr = parse_macro_input!(attr as syn::AttributeArgs);
 
     // Extract the number of components from the module
     let mut extractor = Extractor::default();
@@ -153,14 +152,22 @@ impl VisitMut for SystemTransform {
         for item in content.iter_mut() {
             match item {
                 syn::Item::Fn(item_fn) => self.visit_item_fn_mut(item_fn),
-                syn::Item::Struct(item_struct)
+                syn::Item::Struct(item_struct) => {
+                    if let Some(attr) = item_struct
+                        .attrs
+                        .iter_mut()
+                        .find(|attr| attr.path.is_ident("system_input"))
+                    {
+                        attr.tokens.append_all(quote! { (session_key) });
+                    }
                     if item_struct
                         .attrs
                         .iter()
-                        .any(|attr| attr.path.is_ident("extra_accounts")) =>
-                {
-                    extra_accounts_struct_name = Some(&item_struct.ident);
-                    break;
+                        .any(|attr| attr.path.is_ident("extra_accounts"))
+                    {
+                        extra_accounts_struct_name = Some(&item_struct.ident);
+                        break;
+                    }
                 }
                 _ => {}
             }

+ 2 - 0
crates/bolt-lang/src/lib.rs

@@ -7,6 +7,8 @@ pub use anchor_lang::{
     AccountDeserialize, AccountSerialize, AnchorDeserialize, AnchorSerialize, Bumps, Result,
 };
 
+pub use session_keys;
+
 pub use bolt_attribute_bolt_arguments::arguments;
 pub use bolt_attribute_bolt_component::component;
 pub use bolt_attribute_bolt_component_deserialize::component_deserialize;

+ 29 - 63
crates/programs/bolt-component/src/lib.rs

@@ -6,58 +6,27 @@ declare_id!("CmP2djJgABZ4cRokm4ndxuq6LerqpNHLBsaUv2XKEJua");
 pub mod bolt_component {
     use super::*;
 
-    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
-        let instruction =
-            anchor_lang::solana_program::sysvar::instructions::get_instruction_relative(
-                0,
-                &ctx.accounts.instruction_sysvar_account.to_account_info(),
-            )
-            .unwrap();
-        if instruction.program_id == id() {
-            panic!("The instruction must be called from a CPI");
-        }
-        ctx.accounts.data.bolt_metadata.authority = *ctx.accounts.authority.key;
+    pub fn initialize(_ctx: Context<Initialize>) -> Result<()> {
         Ok(())
     }
 
-    pub fn apply(_ctx: Context<Apply>, _args: Vec<u8>) -> Result<()> {
-        Ok(())
-    }
-
-    #[derive(Accounts)]
-    pub struct Apply<'info> {
-        #[account(mut)]
-        pub bolt_component: Account<'info, Component>,
-        /// CHECK: The system can modify the data of the component
-        #[account()]
-        pub bolt_system: UncheckedAccount<'info>,
-        #[account()]
-        pub authority: Signer<'info>,
-    }
-
-    pub fn update(ctx: Context<Update>, _data: Vec<u8>) -> Result<()> {
-        let instruction =
-            anchor_lang::solana_program::sysvar::instructions::get_instruction_relative(
-                0,
-                &ctx.accounts.instruction_sysvar_account.to_account_info(),
-            )
-            .unwrap();
-        if instruction.program_id == id() {
-            panic!("The instruction must be called from a CPI");
-        }
+    pub fn update(_ctx: Context<Update>, _data: Vec<u8>) -> Result<()> {
         Ok(())
     }
 
     #[derive(Accounts)]
     pub struct Update<'info> {
         #[account(mut)]
-        pub bolt_component: Account<'info, Component>,
+        /// CHECK: The component to update
+        pub bolt_component: UncheckedAccount<'info>,
         #[account()]
         /// CHECK: The authority of the component
-        pub authority: AccountInfo<'info>,
+        pub authority: Signer<'info>,
         #[account(address = anchor_lang::solana_program::sysvar::instructions::id())]
         /// CHECK: The instruction sysvar
         pub instruction_sysvar_account: AccountInfo<'info>,
+        #[account()]
+        pub session_token: Option<UncheckedAccount<'info>>,
     }
 }
 
@@ -65,8 +34,9 @@ pub mod bolt_component {
 pub struct Initialize<'info> {
     #[account(mut)]
     pub payer: Signer<'info>,
-    #[account(init_if_needed, payer = payer, space = Component::size(), seeds = [Component::seed(), entity.key().as_ref()], bump)]
-    pub data: Account<'info, Component>,
+    #[account(mut)]
+    /// CHECK: The component to initialize
+    pub data: UncheckedAccount<'info>,
     #[account()]
     /// CHECK: A generic entity account
     pub entity: AccountInfo<'info>,
@@ -79,31 +49,27 @@ pub struct Initialize<'info> {
     pub system_program: Program<'info, System>,
 }
 
-// Component data
-#[account]
-#[derive(InitSpace, Default, Copy)]
-pub struct Component {
-    pub position: Position,
-    pub bolt_metadata: BoltMetadata,
-}
-
-impl Component {
-    pub fn size() -> usize {
-        8 + Component::INIT_SPACE
-    }
-    pub fn seed() -> &'static [u8] {
-        b"origin-component"
-    }
+#[derive(InitSpace, AnchorSerialize, AnchorDeserialize, Default, Copy, Clone)]
+pub struct BoltMetadata {
+    pub authority: Pubkey,
 }
 
-#[derive(InitSpace, AnchorSerialize, AnchorDeserialize, Default, Copy, Clone)]
-pub struct Position {
-    pub x: i64,
-    pub y: i64,
-    pub z: i64,
+#[cfg(feature = "cpi")]
+pub trait CpiContextBuilder<'info>: ToAccountMetas + ToAccountInfos<'info> + Sized {
+    fn build_cpi_context(
+        self,
+        program: AccountInfo<'info>,
+    ) -> CpiContext<'info, 'info, 'info, 'info, Self>;
 }
 
-#[derive(InitSpace, AnchorSerialize, AnchorDeserialize, Default, Copy, Clone)]
-pub struct BoltMetadata {
-    pub authority: Pubkey,
+#[cfg(feature = "cpi")]
+impl<'info> CpiContextBuilder<'info> for cpi::accounts::Update<'info> {
+    fn build_cpi_context(
+        mut self,
+        program: AccountInfo<'info>,
+    ) -> CpiContext<'info, 'info, 'info, 'info, Self> {
+        let cpi_program = program.to_account_info();
+        self.session_token = Some(self.session_token.unwrap_or(program.to_account_info()));
+        CpiContext::new(cpi_program, self)
+    }
 }

+ 4 - 3
crates/programs/bolt-system/src/lib.rs

@@ -6,13 +6,14 @@ declare_id!("7X4EFsDJ5aYTcEjKzJ94rD8FRKgQeXC89fkpeTS4KaqP");
 #[program]
 pub mod bolt_system {
     use super::*;
-    pub fn bolt_execute(_ctx: Context<SetData>, _args: Vec<u8>) -> Result<Vec<Vec<u8>>> {
+    pub fn bolt_execute(_ctx: Context<BoltExecute>, _args: Vec<u8>) -> Result<Vec<Vec<u8>>> {
         Ok(Vec::new())
     }
 }
 
 #[derive(Accounts, Clone)]
-pub struct SetData<'info> {
+pub struct BoltExecute<'info> {
+    /// CHECK: authority check
     #[account()]
-    pub authority: Signer<'info>,
+    pub authority: AccountInfo<'info>,
 }

+ 18 - 7
crates/programs/world/src/lib.rs

@@ -1,5 +1,6 @@
 #![allow(clippy::manual_unwrap_or_default)]
 use anchor_lang::prelude::*;
+use bolt_component::CpiContextBuilder;
 use std::collections::BTreeSet;
 
 #[cfg(not(feature = "no-entrypoint"))]
@@ -267,7 +268,10 @@ pub mod world {
         ctx: Context<'_, '_, '_, 'info, Apply<'info>>,
         args: Vec<u8>,
     ) -> Result<()> {
-        if !ctx.accounts.authority.is_signer && ctx.accounts.authority.key != &ID {
+        if !ctx.accounts.authority.is_signer
+            && ctx.accounts.authority.key != &ID
+            && ctx.accounts.session_token.is_none()
+        {
             return Err(WorldError::InvalidAuthority.into());
         }
         if !ctx.accounts.world.permissionless
@@ -320,6 +324,7 @@ pub mod world {
                     component,
                     ctx.accounts.authority.clone(),
                     ctx.accounts.instruction_sysvar_account.clone(),
+                    ctx.accounts.session_token.clone(),
                 ),
                 result,
             )?;
@@ -340,15 +345,18 @@ pub mod world {
         pub instruction_sysvar_account: UncheckedAccount<'info>,
         #[account()]
         pub world: Account<'info, World>,
+        #[account()]
+        pub session_token: Option<UncheckedAccount<'info>>,
     }
 
     impl<'info> Apply<'info> {
         pub fn build(
             &self,
-        ) -> CpiContext<'_, '_, '_, 'info, bolt_system::cpi::accounts::SetData<'info>> {
-            let authority = self.authority.to_account_info();
+        ) -> CpiContext<'_, '_, '_, 'info, bolt_system::cpi::accounts::BoltExecute<'info>> {
             let cpi_program = self.bolt_system.to_account_info();
-            let cpi_accounts = bolt_system::cpi::accounts::SetData { authority };
+            let cpi_accounts = bolt_system::cpi::accounts::BoltExecute {
+                authority: self.authority.to_account_info(),
+            };
             CpiContext::new(cpi_program, cpi_accounts)
         }
     }
@@ -590,14 +598,17 @@ pub fn build_update_context<'info>(
     bolt_component: AccountInfo<'info>,
     authority: Signer<'info>,
     instruction_sysvar_account: UncheckedAccount<'info>,
+    session_token: Option<UncheckedAccount<'info>>,
 ) -> CpiContext<'info, 'info, 'info, 'info, bolt_component::cpi::accounts::Update<'info>> {
     let authority = authority.to_account_info();
     let instruction_sysvar_account = instruction_sysvar_account.to_account_info();
     let cpi_program = component_program;
-    let cpi_accounts = bolt_component::cpi::accounts::Update {
+    let session_token = session_token.map(|x| x.to_account_info());
+    bolt_component::cpi::accounts::Update {
         bolt_component,
         authority,
         instruction_sysvar_account,
-    };
-    CpiContext::new(cpi_program, cpi_accounts)
+        session_token,
+    }
+    .build_cpi_context(cpi_program)
 }

+ 0 - 1
examples/system-simple-movement/src/lib.rs

@@ -4,7 +4,6 @@ declare_id!("FSa6qoJXFBR3a7ThQkTAMrC15p6NkchPEjBdd4n6dXxA");
 
 #[system]
 pub mod system_simple_movement {
-
     pub fn execute(ctx: Context<Components>, args: Args) -> Result<Components> {
         // Compute the new position based on the direction
         let (dx, dy) = match args.direction {

+ 3 - 3
scripts/lint.sh

@@ -3,11 +3,11 @@ SCRIPT_DIR=$(dirname "$0")
 PROJECT_DIR="$SCRIPT_DIR/.."
 pushd "$PROJECT_DIR"
 echo "### Checking formatting..."
-cargo fmt -- --check --verbose
+cargo fmt -- --verbose
 
 echo "### Checking clippy..."
-cargo clippy -- --deny=warnings
+cargo clippy --fix -- --deny=warnings
 
 echo "### Checking yarn lint..."
-yarn lint
+yarn lint --write
 popd

+ 0 - 713
tests/bolt.intermediate-level.api.ts

@@ -1,713 +0,0 @@
-import { Keypair, type PublicKey } from "@solana/web3.js";
-import { type Position } from "../target/types/position";
-import { type Velocity } from "../target/types/velocity";
-import { type BoltComponent } from "../target/types/bolt_component";
-import { type SystemSimpleMovement } from "../target/types/system_simple_movement";
-import { type SystemFly } from "../target/types/system_fly";
-import { type SystemApplyVelocity } from "../target/types/system_apply_velocity";
-import { expect } from "chai";
-import type BN from "bn.js";
-import {
-  AddEntity,
-  DELEGATION_PROGRAM_ID,
-  InitializeRegistry,
-  InitializeComponent,
-  InitializeNewWorld,
-  ApplySystem,
-  DelegateComponent,
-  AddAuthority,
-  RemoveAuthority,
-  ApproveSystem,
-  RemoveSystem,
-  type Program,
-  anchor,
-  web3,
-  WORLD_PROGRAM_IDL as World,
-} from "../clients/bolt-sdk";
-
-enum Direction {
-  Left = "Left",
-  Right = "Right",
-  Up = "Up",
-  Down = "Down",
-}
-
-function padCenter(value: string, width: number) {
-  const length = value.length;
-  if (width <= length) {
-    return value;
-  }
-  const padding = (width - length) / 2;
-  const align = width - padding;
-  return value.padStart(align, " ").padEnd(width, " ");
-}
-
-function logPosition(title: string, { x, y, z }: { x: BN; y: BN; z: BN }) {
-  console.log(" +----------------------------------+");
-  console.log(` | ${padCenter(title, 32)} |`);
-  console.log(" +-----------------+----------------+");
-  console.log(` | X Position      | ${String(x).padEnd(14, " ")} |`);
-  console.log(` | Y Position      | ${String(y).padEnd(14, " ")} |`);
-  console.log(` | Z Position      | ${String(z).padEnd(14, " ")} |`);
-  console.log(" +-----------------+----------------+");
-}
-
-function logVelocity(
-  title: string,
-  { x, y, z, lastApplied }: { x: BN; y: BN; z: BN; lastApplied: BN },
-) {
-  console.log(" +----------------------------------+");
-  console.log(` | ${padCenter(title, 32)} |`);
-  console.log(" +-----------------+----------------+");
-  console.log(` | X Velocity      | ${String(x).padEnd(14, " ")} |`);
-  console.log(` | Y Velocity      | ${String(y).padEnd(14, " ")} |`);
-  console.log(` | Z Velocity      | ${String(z).padEnd(14, " ")} |`);
-  console.log(` | Last Applied    | ${String(lastApplied).padEnd(14, " ")} |`);
-  console.log(" +-----------------+----------------+");
-}
-
-describe("bolt", () => {
-  const provider = anchor.AnchorProvider.env();
-  anchor.setProvider(provider);
-
-  const worldProgram = anchor.workspace.World as Program<World>;
-
-  const boltComponentProgram = anchor.workspace
-    .BoltComponent as Program<BoltComponent>;
-
-  const exampleComponentPosition = anchor.workspace
-    .Position as Program<Position>;
-  const exampleComponentVelocity = anchor.workspace
-    .Velocity as Program<Velocity>;
-
-  const exampleSystemSimpleMovement = (
-    anchor.workspace.SystemSimpleMovement as Program<SystemSimpleMovement>
-  ).programId;
-  const exampleSystemFly = (anchor.workspace.SystemFly as Program<SystemFly>)
-    .programId;
-  const exampleSystemApplyVelocity = (
-    anchor.workspace.SystemApplyVelocity as Program<SystemApplyVelocity>
-  ).programId;
-
-  let worldPda: PublicKey;
-
-  let entity1Pda: PublicKey;
-  let entity2Pda: PublicKey;
-  let entity4Pda: PublicKey;
-  let entity5Pda: PublicKey;
-
-  let componentPositionEntity1Pda: PublicKey;
-  let componentVelocityEntity1Pda: PublicKey;
-
-  let componentPositionEntity4Pda: PublicKey;
-  let componentPositionEntity5Pda: PublicKey;
-
-  const secondAuthority = Keypair.generate().publicKey;
-
-  it("InitializeRegistry", async () => {
-    const initializeRegistry = await InitializeRegistry({
-      payer: provider.wallet.publicKey,
-      connection: provider.connection,
-    });
-    try {
-      await provider.sendAndConfirm(initializeRegistry.transaction);
-    } catch (error) {
-      // This is expected to fail because the registry already exists if another api level test ran before
-    }
-  });
-
-  it("InitializeNewWorld", async () => {
-    const initializeNewWorld = await InitializeNewWorld({
-      payer: provider.wallet.publicKey,
-      connection: provider.connection,
-    });
-    const signature = await provider.sendAndConfirm(
-      initializeNewWorld.transaction,
-    );
-    console.log("InitializeNewWorld signature: ", signature);
-    worldPda = initializeNewWorld.worldPda; // Saved for later
-  });
-
-  it("Add authority", async () => {
-    const addAuthority = await AddAuthority({
-      authority: provider.wallet.publicKey,
-      newAuthority: provider.wallet.publicKey,
-      world: worldPda,
-      connection: provider.connection,
-    });
-    await provider.sendAndConfirm(addAuthority.transaction, [], {
-      skipPreflight: true,
-    });
-    const worldAccount = await worldProgram.account.world.fetch(worldPda);
-    expect(
-      worldAccount.authorities.some((auth) =>
-        auth.equals(provider.wallet.publicKey),
-      ),
-    );
-  });
-
-  it("Add a second authority", async () => {
-    const addAuthority = await AddAuthority({
-      authority: provider.wallet.publicKey,
-      newAuthority: secondAuthority,
-      world: worldPda,
-      connection: provider.connection,
-    });
-    const signature = await provider.sendAndConfirm(addAuthority.transaction);
-    console.log(`Add Authority signature: ${signature}`);
-    const worldAccount = await worldProgram.account.world.fetch(worldPda);
-    expect(
-      worldAccount.authorities.some((auth) => auth.equals(secondAuthority)),
-    );
-  });
-
-  it("Remove an authority", async () => {
-    const addAuthority = await RemoveAuthority({
-      authority: provider.wallet.publicKey,
-      authorityToDelete: secondAuthority,
-      world: worldPda,
-      connection: provider.connection,
-    });
-    const signature = await provider.sendAndConfirm(addAuthority.transaction);
-    console.log(`Add Authority signature: ${signature}`);
-    const worldAccount = await worldProgram.account.world.fetch(worldPda);
-    expect(
-      !worldAccount.authorities.some((auth) => auth.equals(secondAuthority)),
-    );
-  });
-
-  it("InitializeNewWorld 2", async () => {
-    const initializeNewWorld = await InitializeNewWorld({
-      payer: provider.wallet.publicKey,
-      connection: provider.connection,
-    });
-    await provider.sendAndConfirm(initializeNewWorld.transaction);
-  });
-
-  it("Add entity 1", async () => {
-    const addEntity = await AddEntity({
-      payer: provider.wallet.publicKey,
-      world: worldPda,
-      connection: provider.connection,
-    });
-    await provider.sendAndConfirm(addEntity.transaction);
-    entity1Pda = addEntity.entityPda; // Saved for later
-  });
-
-  it("Add entity 2", async () => {
-    const addEntity = await AddEntity({
-      payer: provider.wallet.publicKey,
-      world: worldPda,
-      connection: provider.connection,
-    });
-    await provider.sendAndConfirm(addEntity.transaction);
-    entity2Pda = addEntity.entityPda; // Saved for later
-  });
-
-  it("Add entity 3", async () => {
-    const addEntity = await AddEntity({
-      payer: provider.wallet.publicKey,
-      world: worldPda,
-      connection: provider.connection,
-    });
-    await provider.sendAndConfirm(addEntity.transaction);
-  });
-
-  it("Add entity 4 (with seed)", async () => {
-    const addEntity = await AddEntity({
-      payer: provider.wallet.publicKey,
-      world: worldPda,
-      seed: Buffer.from("custom-seed"),
-      connection: provider.connection,
-    });
-    await provider.sendAndConfirm(addEntity.transaction);
-    entity4Pda = addEntity.entityPda;
-  });
-
-  it("Add entity 5", async () => {
-    const addEntity = await AddEntity({
-      payer: provider.wallet.publicKey,
-      world: worldPda,
-      connection: provider.connection,
-    });
-    await provider.sendAndConfirm(addEntity.transaction);
-    entity5Pda = addEntity.entityPda; // Saved for later
-  });
-
-  it("Initialize Original Component on Entity 1, trough the world instance", async () => {
-    const initializeComponent = await InitializeComponent({
-      payer: provider.wallet.publicKey,
-      entity: entity1Pda,
-      seed: "origin-component",
-      componentId: boltComponentProgram.programId,
-    });
-    await provider.sendAndConfirm(initializeComponent.transaction);
-  });
-
-  it("Initialize Original Component on Entity 2, trough the world instance", async () => {
-    const initializeComponent = await InitializeComponent({
-      payer: provider.wallet.publicKey,
-      entity: entity2Pda,
-      seed: "origin-component",
-      componentId: boltComponentProgram.programId,
-    });
-    await provider.sendAndConfirm(initializeComponent.transaction);
-  });
-
-  it("Initialize Position Component on Entity 1", async () => {
-    const initializeComponent = await InitializeComponent({
-      payer: provider.wallet.publicKey,
-      entity: entity1Pda,
-      componentId: exampleComponentPosition.programId,
-    });
-    await provider.sendAndConfirm(initializeComponent.transaction);
-    componentPositionEntity1Pda = initializeComponent.componentPda; // Saved for later
-  });
-
-  it("Initialize Velocity Component on Entity 1 (with seed)", async () => {
-    const initializeComponent = await InitializeComponent({
-      payer: provider.wallet.publicKey,
-      entity: entity1Pda,
-      componentId: exampleComponentVelocity.programId,
-      seed: "component-velocity",
-    });
-    await provider.sendAndConfirm(initializeComponent.transaction);
-    componentVelocityEntity1Pda = initializeComponent.componentPda; // Saved for later
-  });
-
-  it("Initialize Position Component on Entity 2", async () => {
-    const initializeComponent = await InitializeComponent({
-      payer: provider.wallet.publicKey,
-      entity: entity2Pda,
-      componentId: exampleComponentPosition.programId,
-    });
-    await provider.sendAndConfirm(initializeComponent.transaction);
-  });
-
-  it("Initialize Position Component on Entity 4", async () => {
-    const initializeComponent = await InitializeComponent({
-      payer: provider.wallet.publicKey,
-      entity: entity4Pda,
-      componentId: exampleComponentPosition.programId,
-    });
-    await provider.sendAndConfirm(initializeComponent.transaction);
-    componentPositionEntity4Pda = initializeComponent.componentPda; // Saved for later
-  });
-
-  it("Initialize Position Component on Entity 5 (with authority)", async () => {
-    const initializeComponent = await InitializeComponent({
-      payer: provider.wallet.publicKey,
-      entity: entity5Pda,
-      componentId: exampleComponentPosition.programId,
-      authority: provider.wallet.publicKey,
-    });
-    await provider.sendAndConfirm(initializeComponent.transaction);
-    componentPositionEntity5Pda = initializeComponent.componentPda; // Saved for later
-  });
-
-  it("Check Position on Entity 1 is default", async () => {
-    const position = await exampleComponentPosition.account.position.fetch(
-      componentPositionEntity1Pda,
-    );
-    logPosition("Default State: Entity 1", position);
-    expect(position.x.toNumber()).to.equal(0);
-    expect(position.y.toNumber()).to.equal(0);
-    expect(position.z.toNumber()).to.equal(0);
-  });
-
-  it("Apply Simple Movement System (Up) on Entity 1 using Apply", async () => {
-    const apply = await ApplySystem({
-      authority: provider.wallet.publicKey,
-      systemId: exampleSystemSimpleMovement,
-      entities: [
-        {
-          entity: entity1Pda,
-          components: [{ componentId: exampleComponentPosition.programId }],
-        },
-      ],
-      world: worldPda,
-      args: { direction: Direction.Up },
-    });
-
-    await provider.sendAndConfirm(apply.transaction);
-
-    const position = await exampleComponentPosition.account.position.fetch(
-      componentPositionEntity1Pda,
-    );
-    logPosition("Movement System: Entity 1", position);
-    expect(position.x.toNumber()).to.equal(0);
-    expect(position.y.toNumber()).to.equal(1);
-    expect(position.z.toNumber()).to.equal(0);
-  });
-
-  it("Apply Simple Movement System (Up) on Entity 1", async () => {
-    const applySystem = await ApplySystem({
-      authority: provider.wallet.publicKey,
-      systemId: exampleSystemSimpleMovement,
-      world: worldPda,
-      entities: [
-        {
-          entity: entity1Pda,
-          components: [{ componentId: exampleComponentPosition.programId }],
-        },
-      ],
-      args: {
-        direction: Direction.Up,
-      },
-    });
-    const signature = await provider.sendAndConfirm(
-      applySystem.transaction,
-      [],
-      { skipPreflight: true },
-    );
-    console.log(`Signature: ${signature}`);
-
-    const position = await exampleComponentPosition.account.position.fetch(
-      componentPositionEntity1Pda,
-    );
-    logPosition("Movement System: Entity 1", position);
-    expect(position.x.toNumber()).to.equal(0);
-    expect(position.y.toNumber()).to.equal(2);
-    expect(position.z.toNumber()).to.equal(0);
-  });
-
-  it("Apply Simple Movement System (Right) on Entity 1", async () => {
-    const applySystem = await ApplySystem({
-      authority: provider.wallet.publicKey,
-      systemId: exampleSystemSimpleMovement,
-      world: worldPda,
-      entities: [
-        {
-          entity: entity1Pda,
-          components: [{ componentId: exampleComponentPosition.programId }],
-        },
-      ],
-      args: {
-        direction: Direction.Right,
-      },
-    });
-    await provider.sendAndConfirm(applySystem.transaction);
-
-    const position = await exampleComponentPosition.account.position.fetch(
-      componentPositionEntity1Pda,
-    );
-    logPosition("Movement System: Entity 1", position);
-    expect(position.x.toNumber()).to.equal(1);
-    expect(position.y.toNumber()).to.equal(2);
-    expect(position.z.toNumber()).to.equal(0);
-  });
-
-  it("Apply Fly System on Entity 1", async () => {
-    const applySystem = await ApplySystem({
-      authority: provider.wallet.publicKey,
-      systemId: exampleSystemFly,
-      world: worldPda,
-      entities: [
-        {
-          entity: entity1Pda,
-          components: [{ componentId: exampleComponentPosition.programId }],
-        },
-      ],
-    });
-    await provider.sendAndConfirm(applySystem.transaction);
-
-    const position = await exampleComponentPosition.account.position.fetch(
-      componentPositionEntity1Pda,
-    );
-    logPosition("Fly System: Entity 1", position);
-    expect(position.x.toNumber()).to.equal(1);
-    expect(position.y.toNumber()).to.equal(2);
-    expect(position.z.toNumber()).to.equal(1);
-  });
-
-  it("Apply System Velocity on Entity 1", async () => {
-    const applySystem = await ApplySystem({
-      authority: provider.wallet.publicKey,
-      systemId: exampleSystemApplyVelocity,
-      world: worldPda,
-      entities: [
-        {
-          entity: entity1Pda,
-          components: [
-            {
-              componentId: exampleComponentVelocity.programId,
-              seed: "component-velocity",
-            },
-            { componentId: exampleComponentPosition.programId },
-          ],
-        },
-      ],
-    });
-    await provider.sendAndConfirm(applySystem.transaction);
-
-    const velocity = await exampleComponentVelocity.account.velocity.fetch(
-      componentVelocityEntity1Pda,
-    );
-    logVelocity("Apply System Velocity: Entity 1", velocity);
-    expect(velocity.x.toNumber()).to.equal(10);
-    expect(velocity.y.toNumber()).to.equal(0);
-    expect(velocity.z.toNumber()).to.equal(0);
-    expect(velocity.lastApplied.toNumber()).to.not.equal(0);
-
-    const position = await exampleComponentPosition.account.position.fetch(
-      componentPositionEntity1Pda,
-    );
-    logPosition("Apply System Velocity: Entity 1", position);
-    expect(position.x.toNumber()).to.greaterThan(1);
-    expect(position.y.toNumber()).to.equal(2);
-    expect(position.z.toNumber()).to.equal(1);
-  });
-
-  it("Apply System Velocity on Entity 1, with Clock external account", async () => {
-    const applySystem = await ApplySystem({
-      authority: provider.wallet.publicKey,
-      systemId: exampleSystemApplyVelocity,
-      world: worldPda,
-      entities: [
-        {
-          entity: entity1Pda,
-          components: [
-            {
-              componentId: exampleComponentVelocity.programId,
-              seed: "component-velocity",
-            },
-            { componentId: exampleComponentPosition.programId },
-          ],
-        },
-      ],
-      extraAccounts: [
-        {
-          pubkey: new web3.PublicKey(
-            "SysvarC1ock11111111111111111111111111111111",
-          ),
-          isWritable: false,
-          isSigner: false,
-        },
-      ],
-    });
-    await provider.sendAndConfirm(applySystem.transaction);
-
-    const position = await exampleComponentPosition.account.position.fetch(
-      componentPositionEntity1Pda,
-    );
-    logPosition("Apply System Velocity: Entity 1", position);
-    expect(position.x.toNumber()).to.greaterThan(1);
-    expect(position.y.toNumber()).to.equal(2);
-    expect(position.z.toNumber()).to.equal(300);
-  });
-
-  it("Apply Fly System on Entity 4", async () => {
-    const applySystem = await ApplySystem({
-      authority: provider.wallet.publicKey,
-      systemId: exampleSystemFly,
-      world: worldPda,
-      entities: [
-        {
-          entity: entity4Pda,
-          components: [{ componentId: exampleComponentPosition.programId }],
-        },
-      ],
-    });
-    await provider.sendAndConfirm(applySystem.transaction);
-
-    const position = await exampleComponentPosition.account.position.fetch(
-      componentPositionEntity4Pda,
-    );
-    logPosition("Fly System: Entity 4", position);
-    expect(position.x.toNumber()).to.equal(0);
-    expect(position.y.toNumber()).to.equal(0);
-    expect(position.z.toNumber()).to.equal(1);
-  });
-
-  it("Apply Fly System on Entity 5 (should fail with wrong authority)", async () => {
-    const positionBefore =
-      await exampleComponentPosition.account.position.fetch(
-        componentPositionEntity5Pda,
-      );
-
-    const applySystem = await ApplySystem({
-      authority: provider.wallet.publicKey,
-      systemId: exampleSystemFly,
-      world: worldPda,
-      entities: [
-        {
-          entity: entity5Pda,
-          components: [{ componentId: exampleComponentPosition.programId }],
-        },
-      ],
-    });
-
-    let failed = false;
-    try {
-      await provider.sendAndConfirm(applySystem.transaction);
-    } catch (error) {
-      failed = true;
-      // console.log("error", error);
-      expect(error.logs.join("\n")).to.contain("Error Code: InvalidAuthority");
-    }
-    expect(failed).to.equal(true);
-
-    const positionAfter = await exampleComponentPosition.account.position.fetch(
-      componentPositionEntity5Pda,
-    );
-
-    expect(positionBefore.x.toNumber()).to.equal(positionAfter.x.toNumber());
-    expect(positionBefore.y.toNumber()).to.equal(positionAfter.y.toNumber());
-    expect(positionBefore.z.toNumber()).to.equal(positionAfter.z.toNumber());
-  });
-
-  it("Whitelist System", async () => {
-    const approveSystem = await ApproveSystem({
-      authority: provider.wallet.publicKey,
-      systemToApprove: exampleSystemFly,
-      world: worldPda,
-    });
-
-    const signature = await provider.sendAndConfirm(
-      approveSystem.transaction,
-      [],
-      { skipPreflight: true },
-    );
-    console.log(`Whitelist 2 system approval signature: ${signature}`);
-
-    // Get World and check permissionless and systems
-    const worldAccount = await worldProgram.account.world.fetch(worldPda);
-    expect(worldAccount.permissionless).to.equal(false);
-    expect(worldAccount.systems.length).to.be.greaterThan(0);
-  });
-
-  it("Whitelist System 2", async () => {
-    const approveSystem = await ApproveSystem({
-      authority: provider.wallet.publicKey,
-      systemToApprove: exampleSystemApplyVelocity,
-      world: worldPda,
-    });
-
-    const signature = await provider.sendAndConfirm(
-      approveSystem.transaction,
-      [],
-      { skipPreflight: true },
-    );
-    console.log(`Whitelist 2 system approval signature: ${signature}`);
-
-    // Get World and check permissionless and systems
-    const worldAccount = await worldProgram.account.world.fetch(worldPda);
-    expect(worldAccount.permissionless).to.equal(false);
-    expect(worldAccount.systems.length).to.be.greaterThan(0);
-  });
-
-  it("Apply Fly System on Entity 1", async () => {
-    const applySystem = await ApplySystem({
-      authority: provider.wallet.publicKey,
-      systemId: exampleSystemFly,
-      world: worldPda,
-      entities: [
-        {
-          entity: entity1Pda,
-          components: [{ componentId: exampleComponentPosition.programId }],
-        },
-      ],
-    });
-    await provider.sendAndConfirm(applySystem.transaction);
-  });
-
-  it("Remove System 1", async () => {
-    const approveSystem = await RemoveSystem({
-      authority: provider.wallet.publicKey,
-      systemToRemove: exampleSystemFly,
-      world: worldPda,
-    });
-
-    const signature = await provider.sendAndConfirm(
-      approveSystem.transaction,
-      [],
-      { skipPreflight: true },
-    );
-    console.log(`Whitelist 2 system approval signature: ${signature}`);
-
-    // Get World and check permissionless and systems
-    const worldAccount = await worldProgram.account.world.fetch(worldPda);
-    expect(worldAccount.permissionless).to.equal(false);
-    expect(worldAccount.systems.length).to.be.greaterThan(0);
-  });
-
-  it("Apply Invalid Fly System on Entity 1", async () => {
-    const applySystem = await ApplySystem({
-      authority: provider.wallet.publicKey,
-      systemId: exampleSystemFly,
-      world: worldPda,
-      entities: [
-        {
-          entity: entity1Pda,
-          components: [{ componentId: exampleComponentPosition.programId }],
-        },
-      ],
-    });
-    let invalid = false;
-    try {
-      await provider.sendAndConfirm(applySystem.transaction);
-    } catch (error) {
-      expect(error.logs.join(" ")).to.contain("Error Code: SystemNotApproved");
-      invalid = true;
-    }
-    expect(invalid).to.equal(true);
-  });
-
-  it("Check invalid component init without CPI", async () => {
-    let invalid = false;
-    try {
-      await exampleComponentPosition.methods
-        .initialize()
-        .accounts({
-          payer: provider.wallet.publicKey,
-          data: componentPositionEntity5Pda,
-          entity: entity5Pda,
-          authority: provider.wallet.publicKey,
-        })
-        .rpc();
-    } catch (error) {
-      // console.log("error", error);
-      expect(error.message).to.contain("Error Code: InvalidCaller");
-      invalid = true;
-    }
-    expect(invalid).to.equal(true);
-  });
-
-  it("Check invalid component update without CPI", async () => {
-    let invalid = false;
-    try {
-      await boltComponentProgram.methods
-        .update(Buffer.from(""))
-        .accounts({
-          boltComponent: componentPositionEntity4Pda,
-          authority: provider.wallet.publicKey,
-        })
-        .rpc();
-    } catch (error) {
-      // console.log("error", error);
-      expect(error.message).to.contain(
-        "bolt_component. Error Code: AccountOwnedByWrongProgram",
-      );
-      invalid = true;
-    }
-    expect(invalid).to.equal(true);
-  });
-
-  it("Check component delegation", async () => {
-    const delegateComponent = await DelegateComponent({
-      payer: provider.wallet.publicKey,
-      entity: entity1Pda,
-      componentId: exampleComponentPosition.programId,
-    });
-
-    const txSign = await provider.sendAndConfirm(
-      delegateComponent.transaction,
-      [],
-      { skipPreflight: true, commitment: "confirmed" },
-    );
-    const acc = await provider.connection.getAccountInfo(
-      delegateComponent.componentPda,
-    );
-    expect(acc?.owner.toBase58()).to.equal(DELEGATION_PROGRAM_ID.toBase58());
-  });
-});

+ 0 - 988
tests/bolt.low-level.api.ts

@@ -1,988 +0,0 @@
-import { Keypair, type PublicKey } from "@solana/web3.js";
-import { type Position } from "../target/types/position";
-import { type Velocity } from "../target/types/velocity";
-import { type BoltComponent } from "../target/types/bolt_component";
-import { type SystemSimpleMovement } from "../target/types/system_simple_movement";
-import { type SystemFly } from "../target/types/system_fly";
-import { type SystemApplyVelocity } from "../target/types/system_apply_velocity";
-import { expect } from "chai";
-import BN from "bn.js";
-import {
-  DELEGATION_PROGRAM_ID,
-  DelegateComponent,
-  type Program,
-  anchor,
-  web3,
-  FindRegistryPda,
-  FindWorldPda,
-  FindEntityPda,
-  FindComponentPda,
-  SerializeArgs,
-  WORLD_PROGRAM_IDL as World,
-} from "../clients/bolt-sdk";
-
-enum Direction {
-  Left = "Left",
-  Right = "Right",
-  Up = "Up",
-  Down = "Down",
-}
-
-function padCenter(value: string, width: number) {
-  const length = value.length;
-  if (width <= length) {
-    return value;
-  }
-  const padding = (width - length) / 2;
-  const align = width - padding;
-  return value.padStart(align, " ").padEnd(width, " ");
-}
-
-function logPosition(title: string, { x, y, z }: { x: BN; y: BN; z: BN }) {
-  console.log(" +----------------------------------+");
-  console.log(` | ${padCenter(title, 32)} |`);
-  console.log(" +-----------------+----------------+");
-  console.log(` | X Position      | ${String(x).padEnd(14, " ")} |`);
-  console.log(` | Y Position      | ${String(y).padEnd(14, " ")} |`);
-  console.log(` | Z Position      | ${String(z).padEnd(14, " ")} |`);
-  console.log(" +-----------------+----------------+");
-}
-
-function logVelocity(
-  title: string,
-  { x, y, z, lastApplied }: { x: BN; y: BN; z: BN; lastApplied: BN },
-) {
-  console.log(" +----------------------------------+");
-  console.log(` | ${padCenter(title, 32)} |`);
-  console.log(" +-----------------+----------------+");
-  console.log(` | X Velocity      | ${String(x).padEnd(14, " ")} |`);
-  console.log(` | Y Velocity      | ${String(y).padEnd(14, " ")} |`);
-  console.log(` | Z Velocity      | ${String(z).padEnd(14, " ")} |`);
-  console.log(` | Last Applied    | ${String(lastApplied).padEnd(14, " ")} |`);
-  console.log(" +-----------------+----------------+");
-}
-
-describe("bolt", () => {
-  const provider = anchor.AnchorProvider.env();
-  anchor.setProvider(provider);
-
-  const worldProgram = anchor.workspace.World as Program<World>;
-
-  const boltComponentProgram = anchor.workspace
-    .BoltComponent as Program<BoltComponent>;
-
-  const exampleComponentPosition = anchor.workspace
-    .Position as Program<Position>;
-  const exampleComponentVelocity = anchor.workspace
-    .Velocity as Program<Velocity>;
-
-  const exampleSystemSimpleMovement = (
-    anchor.workspace.SystemSimpleMovement as Program<SystemSimpleMovement>
-  ).programId;
-  const exampleSystemFly = (anchor.workspace.SystemFly as Program<SystemFly>)
-    .programId;
-  const exampleSystemApplyVelocity = (
-    anchor.workspace.SystemApplyVelocity as Program<SystemApplyVelocity>
-  ).programId;
-
-  let worldPda: PublicKey;
-  let worldId: BN;
-
-  let entity1Pda: PublicKey;
-  let entity2Pda: PublicKey;
-  let entity4Pda: PublicKey;
-  let entity5Pda: PublicKey;
-
-  let componentPositionEntity1Pda: PublicKey;
-  let componentVelocityEntity1Pda: PublicKey;
-
-  let componentPositionEntity4Pda: PublicKey;
-  let componentPositionEntity5Pda: PublicKey;
-
-  const secondAuthority = Keypair.generate().publicKey;
-
-  it("InitializeRegistry", async () => {
-    const registryPda = FindRegistryPda({});
-    const instruction = await worldProgram.methods
-      .initializeRegistry()
-      .accounts({
-        registry: registryPda,
-        payer: provider.wallet.publicKey,
-      })
-      .instruction();
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    await provider.sendAndConfirm(transaction);
-  });
-
-  it("InitializeNewWorld", async () => {
-    const registryPda = FindRegistryPda({});
-    const registry = await worldProgram.account.registry.fetch(registryPda);
-    worldId = new BN(registry.worlds);
-    worldPda = FindWorldPda({ worldId });
-    const instruction = await worldProgram.methods
-      .initializeNewWorld()
-      .accounts({
-        payer: provider.wallet.publicKey,
-        world: worldPda,
-        registry: registryPda,
-      })
-      .instruction();
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    const signature = await provider.sendAndConfirm(transaction);
-    console.log("InitializeNewWorld signature: ", signature);
-  });
-
-  it("Add authority", async () => {
-    const instruction = await worldProgram.methods
-      .addAuthority(worldId)
-      .accounts({
-        authority: provider.wallet.publicKey,
-        newAuthority: provider.wallet.publicKey,
-        world: worldPda,
-      })
-      .instruction();
-
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    await provider.sendAndConfirm(transaction, [], { skipPreflight: true });
-    const worldAccount = await worldProgram.account.world.fetch(worldPda);
-    expect(
-      worldAccount.authorities.some((auth) =>
-        auth.equals(provider.wallet.publicKey),
-      ),
-    );
-  });
-
-  it("Add a second authority", async () => {
-    const instruction = await worldProgram.methods
-      .addAuthority(worldId)
-      .accounts({
-        authority: provider.wallet.publicKey,
-        newAuthority: secondAuthority,
-        world: worldPda,
-      })
-      .instruction();
-
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    const signature = await provider.sendAndConfirm(transaction);
-    console.log(`Add Authority signature: ${signature}`);
-    const worldAccount = await worldProgram.account.world.fetch(worldPda);
-    expect(
-      worldAccount.authorities.some((auth) => auth.equals(secondAuthority)),
-    );
-  });
-
-  it("Remove an authority", async () => {
-    const instruction = await worldProgram.methods
-      .removeAuthority(worldId)
-      .accounts({
-        authority: provider.wallet.publicKey,
-        authorityToDelete: secondAuthority,
-        world: worldPda,
-      })
-      .instruction();
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    const signature = await provider.sendAndConfirm(transaction);
-    console.log(`Remove Authority signature: ${signature}`);
-    const worldAccount = await worldProgram.account.world.fetch(worldPda);
-    expect(
-      !worldAccount.authorities.some((auth) => auth.equals(secondAuthority)),
-    );
-  });
-
-  it("InitializeNewWorld 2", async () => {
-    const registryPda = FindRegistryPda({});
-    const registry = await worldProgram.account.registry.fetch(registryPda);
-    const worldId = new BN(registry.worlds);
-    const worldPda = FindWorldPda({ worldId });
-    const instruction = await worldProgram.methods
-      .initializeNewWorld()
-      .accounts({
-        payer: provider.wallet.publicKey,
-        world: worldPda,
-        registry: registryPda,
-      })
-      .instruction();
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    const signature = await provider.sendAndConfirm(transaction);
-    console.log("InitializeNewWorld 2 signature: ", signature);
-  });
-
-  it("Add entity 1", async () => {
-    const world = await worldProgram.account.world.fetch(worldPda);
-    entity1Pda = FindEntityPda({ worldId: world.id, entityId: world.entities });
-    const instruction = await worldProgram.methods
-      .addEntity(null)
-      .accounts({
-        payer: provider.wallet.publicKey,
-        world: worldPda,
-        entity: entity1Pda,
-      })
-      .instruction();
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    const signature = await provider.sendAndConfirm(transaction);
-    console.log("Add Entity 1 signature: ", signature);
-  });
-
-  it("Add entity 2", async () => {
-    const world = await worldProgram.account.world.fetch(worldPda);
-    entity2Pda = FindEntityPda({ worldId: world.id, entityId: world.entities });
-    const instruction = await worldProgram.methods
-      .addEntity(null)
-      .accounts({
-        payer: provider.wallet.publicKey,
-        world: worldPda,
-        entity: entity2Pda,
-      })
-      .instruction();
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    const signature = await provider.sendAndConfirm(transaction);
-    console.log("Add Entity 2 signature: ", signature);
-  });
-
-  it("Add entity 3", async () => {
-    const world = await worldProgram.account.world.fetch(worldPda);
-    const entity3Pda = FindEntityPda({
-      worldId: world.id,
-      entityId: world.entities,
-    });
-    const instruction = await worldProgram.methods
-      .addEntity(null)
-      .accounts({
-        payer: provider.wallet.publicKey,
-        world: worldPda,
-        entity: entity3Pda,
-      })
-      .instruction();
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    const signature = await provider.sendAndConfirm(transaction);
-    console.log("Add Entity 3 signature: ", signature);
-  });
-
-  it("Add entity 4 (with seed)", async () => {
-    const world = await worldProgram.account.world.fetch(worldPda);
-    const seed = Buffer.from("custom-seed");
-    entity4Pda = FindEntityPda({ worldId: world.id, seed });
-    const instruction = await worldProgram.methods
-      .addEntity(seed)
-      .accounts({
-        payer: provider.wallet.publicKey,
-        world: worldPda,
-        entity: entity4Pda,
-      })
-      .instruction();
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    const signature = await provider.sendAndConfirm(transaction);
-    console.log("Add Entity 4 signature: ", signature);
-  });
-
-  it("Add entity 5", async () => {
-    const world = await worldProgram.account.world.fetch(worldPda);
-    entity5Pda = FindEntityPda({ worldId: world.id, entityId: world.entities });
-    const instruction = await worldProgram.methods
-      .addEntity(null)
-      .accounts({
-        payer: provider.wallet.publicKey,
-        world: worldPda,
-        entity: entity5Pda,
-      })
-      .instruction();
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    const signature = await provider.sendAndConfirm(transaction);
-    console.log("Add Entity 5 signature: ", signature);
-  });
-
-  it("Initialize Original Component on Entity 1, through the world instance", async () => {
-    const componentId = boltComponentProgram.programId;
-    const componentPda = FindComponentPda({
-      componentId,
-      entity: entity1Pda,
-      seed: "origin-component",
-    });
-    const instruction = await worldProgram.methods
-      .initializeComponent()
-      .accounts({
-        payer: provider.wallet.publicKey,
-        entity: entity1Pda,
-        data: componentPda,
-        componentProgram: componentId,
-        authority: provider.wallet.publicKey,
-      })
-      .instruction();
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    const signature = await provider.sendAndConfirm(transaction);
-    console.log(
-      "Initialize Original Component on Entity 1 signature: ",
-      signature,
-    );
-  });
-
-  it("Initialize Original Component on Entity 2, trough the world instance", async () => {
-    const componentId = boltComponentProgram.programId;
-    const componentPda = FindComponentPda({
-      componentId,
-      entity: entity2Pda,
-      seed: "origin-component",
-    });
-    const instruction = await worldProgram.methods
-      .initializeComponent()
-      .accounts({
-        payer: provider.wallet.publicKey,
-        entity: entity2Pda,
-        data: componentPda,
-        componentProgram: componentId,
-        authority: provider.wallet.publicKey,
-      })
-      .instruction();
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    const signature = await provider.sendAndConfirm(transaction);
-    console.log(
-      "Initialize Original Component on Entity 2 signature: ",
-      signature,
-    );
-  });
-
-  it("Initialize Position Component on Entity 1", async () => {
-    const componentId = exampleComponentPosition.programId;
-    componentPositionEntity1Pda = FindComponentPda({
-      componentId,
-      entity: entity1Pda,
-    });
-    const instruction = await worldProgram.methods
-      .initializeComponent()
-      .accounts({
-        payer: provider.wallet.publicKey,
-        entity: entity1Pda,
-        data: componentPositionEntity1Pda,
-        componentProgram: componentId,
-        authority: worldProgram.programId,
-      })
-      .instruction();
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    const signature = await provider.sendAndConfirm(transaction);
-    console.log(
-      "Initialize Position Component on Entity 1 signature: ",
-      signature,
-    );
-  });
-
-  it("Initialize Velocity Component on Entity 1 (with seed)", async () => {
-    const componentId = exampleComponentVelocity.programId;
-    componentVelocityEntity1Pda = FindComponentPda({
-      componentId,
-      entity: entity1Pda,
-      seed: "component-velocity",
-    });
-    const instruction = await worldProgram.methods
-      .initializeComponent()
-      .accounts({
-        payer: provider.wallet.publicKey,
-        entity: entity1Pda,
-        data: componentVelocityEntity1Pda,
-        componentProgram: componentId,
-        authority: worldProgram.programId,
-      })
-      .instruction();
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    const signature = await provider.sendAndConfirm(transaction);
-    console.log(
-      "Initialize Velocity Component on Entity 1 signature: ",
-      signature,
-    );
-  });
-
-  it("Initialize Position Component on Entity 2", async () => {
-    const componentId = exampleComponentPosition.programId;
-    const componentPositionEntity2Pda = FindComponentPda({
-      componentId,
-      entity: entity2Pda,
-    });
-    const instruction = await worldProgram.methods
-      .initializeComponent()
-      .accounts({
-        payer: provider.wallet.publicKey,
-        entity: entity2Pda,
-        data: componentPositionEntity2Pda,
-        componentProgram: componentId,
-        authority: worldProgram.programId,
-      })
-      .instruction();
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    const signature = await provider.sendAndConfirm(transaction);
-    console.log(
-      "Initialize Position Component on Entity 2 signature: ",
-      signature,
-    );
-  });
-
-  it("Initialize Position Component on Entity 4", async () => {
-    const componentId = exampleComponentPosition.programId;
-    componentPositionEntity4Pda = FindComponentPda({
-      componentId,
-      entity: entity4Pda,
-    });
-    const instruction = await worldProgram.methods
-      .initializeComponent()
-      .accounts({
-        payer: provider.wallet.publicKey,
-        entity: entity4Pda,
-        data: componentPositionEntity4Pda,
-        componentProgram: componentId,
-        authority: worldProgram.programId,
-      })
-      .instruction();
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    const signature = await provider.sendAndConfirm(transaction);
-    console.log(
-      "Initialize Position Component on Entity 4 signature: ",
-      signature,
-    );
-  });
-
-  it("Initialize Position Component on Entity 5 (with authority)", async () => {
-    const componentId = exampleComponentPosition.programId;
-    componentPositionEntity5Pda = FindComponentPda({
-      componentId,
-      entity: entity5Pda,
-    });
-    const instruction = await worldProgram.methods
-      .initializeComponent()
-      .accounts({
-        payer: provider.wallet.publicKey,
-        entity: entity5Pda,
-        data: componentPositionEntity5Pda,
-        componentProgram: componentId,
-        authority: provider.wallet.publicKey,
-      })
-      .instruction();
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    const signature = await provider.sendAndConfirm(transaction);
-    console.log(
-      "Initialize Position Component on Entity 5 signature: ",
-      signature,
-    );
-  });
-
-  it("Check Position on Entity 1 is default", async () => {
-    const position = await exampleComponentPosition.account.position.fetch(
-      componentPositionEntity1Pda,
-    );
-    logPosition("Default State: Entity 1", position);
-    expect(position.x.toNumber()).to.equal(0);
-    expect(position.y.toNumber()).to.equal(0);
-    expect(position.z.toNumber()).to.equal(0);
-  });
-
-  it("Apply Simple Movement System (Up) on Entity 1 using Apply", async () => {
-    const instruction = await worldProgram.methods
-      .apply(SerializeArgs({ direction: Direction.Up }))
-      .accounts({
-        authority: provider.wallet.publicKey,
-        boltSystem: exampleSystemSimpleMovement,
-        world: worldPda,
-      })
-      .remainingAccounts([
-        {
-          pubkey: exampleComponentPosition.programId,
-          isSigner: false,
-          isWritable: false,
-        },
-        {
-          pubkey: componentPositionEntity1Pda,
-          isSigner: false,
-          isWritable: true,
-        },
-      ])
-      .instruction();
-
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    const signature = await provider.sendAndConfirm(transaction);
-    console.log(
-      "Apply Simple Movement System (Up) on Entity 1 signature: ",
-      signature,
-    );
-
-    const position = await exampleComponentPosition.account.position.fetch(
-      componentPositionEntity1Pda,
-    );
-    logPosition("Movement System: Entity 1", position);
-    expect(position.x.toNumber()).to.equal(0);
-    expect(position.y.toNumber()).to.equal(1);
-    expect(position.z.toNumber()).to.equal(0);
-  });
-
-  it("Apply Simple Movement System (Up) on Entity 1", async () => {
-    const instruction = await worldProgram.methods
-      .apply(SerializeArgs({ direction: Direction.Up }))
-      .accounts({
-        authority: provider.wallet.publicKey,
-        boltSystem: exampleSystemSimpleMovement,
-        world: worldPda,
-      })
-      .remainingAccounts([
-        {
-          pubkey: exampleComponentPosition.programId,
-          isSigner: false,
-          isWritable: false,
-        },
-        {
-          pubkey: componentPositionEntity1Pda,
-          isSigner: false,
-          isWritable: true,
-        },
-      ])
-      .instruction();
-
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    const signature = await provider.sendAndConfirm(transaction);
-    console.log(
-      "Apply Simple Movement System (Up) on Entity 1 signature: ",
-      signature,
-    );
-
-    const position = await exampleComponentPosition.account.position.fetch(
-      componentPositionEntity1Pda,
-    );
-    logPosition("Movement System: Entity 1", position);
-    expect(position.x.toNumber()).to.equal(0);
-    expect(position.y.toNumber()).to.equal(2);
-    expect(position.z.toNumber()).to.equal(0);
-  });
-
-  it("Apply Simple Movement System (Right) on Entity 1", async () => {
-    const instruction = await worldProgram.methods
-      .apply(SerializeArgs({ direction: Direction.Right }))
-      .accounts({
-        authority: provider.wallet.publicKey,
-        boltSystem: exampleSystemSimpleMovement,
-        world: worldPda,
-      })
-      .remainingAccounts([
-        {
-          pubkey: exampleComponentPosition.programId,
-          isSigner: false,
-          isWritable: false,
-        },
-        {
-          pubkey: componentPositionEntity1Pda,
-          isSigner: false,
-          isWritable: true,
-        },
-      ])
-      .instruction();
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    const signature = await provider.sendAndConfirm(transaction);
-    console.log(
-      "Apply Simple Movement System (Right) on Entity 1 signature: ",
-      signature,
-    );
-
-    const position = await exampleComponentPosition.account.position.fetch(
-      componentPositionEntity1Pda,
-    );
-    logPosition("Movement System: Entity 1", position);
-    expect(position.x.toNumber()).to.equal(1);
-    expect(position.y.toNumber()).to.equal(2);
-    expect(position.z.toNumber()).to.equal(0);
-  });
-
-  it("Apply Fly System on Entity 1", async () => {
-    const instruction = await worldProgram.methods
-      .apply(SerializeArgs())
-      .accounts({
-        authority: provider.wallet.publicKey,
-        boltSystem: exampleSystemFly,
-        world: worldPda,
-      })
-      .remainingAccounts([
-        {
-          pubkey: exampleComponentPosition.programId,
-          isSigner: false,
-          isWritable: false,
-        },
-        {
-          pubkey: componentPositionEntity1Pda,
-          isSigner: false,
-          isWritable: true,
-        },
-      ])
-      .instruction();
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    const signature = await provider.sendAndConfirm(transaction);
-    console.log("Apply Fly System on Entity 1 signature: ", signature);
-
-    const position = await exampleComponentPosition.account.position.fetch(
-      componentPositionEntity1Pda,
-    );
-    logPosition("Fly System: Entity 1", position);
-    expect(position.x.toNumber()).to.equal(1);
-    expect(position.y.toNumber()).to.equal(2);
-    expect(position.z.toNumber()).to.equal(1);
-  });
-
-  it("Apply System Velocity on Entity 1", async () => {
-    const instruction = await worldProgram.methods
-      .apply(SerializeArgs())
-      .accounts({
-        authority: provider.wallet.publicKey,
-        boltSystem: exampleSystemApplyVelocity,
-        world: worldPda,
-      })
-      .remainingAccounts([
-        {
-          pubkey: exampleComponentVelocity.programId,
-          isSigner: false,
-          isWritable: false,
-        },
-        {
-          pubkey: componentVelocityEntity1Pda,
-          isSigner: false,
-          isWritable: true,
-        },
-        {
-          pubkey: exampleComponentPosition.programId,
-          isSigner: false,
-          isWritable: false,
-        },
-        {
-          pubkey: componentPositionEntity1Pda,
-          isSigner: false,
-          isWritable: true,
-        },
-      ])
-      .instruction();
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    const signature = await provider.sendAndConfirm(transaction);
-    console.log("Apply System Velocity on Entity 1 signature: ", signature);
-
-    const velocity = await exampleComponentVelocity.account.velocity.fetch(
-      componentVelocityEntity1Pda,
-    );
-    logVelocity("Apply System Velocity: Entity 1", velocity);
-    expect(velocity.x.toNumber()).to.equal(10);
-    expect(velocity.y.toNumber()).to.equal(0);
-    expect(velocity.z.toNumber()).to.equal(0);
-    expect(velocity.lastApplied.toNumber()).to.not.equal(0);
-
-    const position = await exampleComponentPosition.account.position.fetch(
-      componentPositionEntity1Pda,
-    );
-    logPosition("Apply System Velocity: Entity 1", position);
-    expect(position.x.toNumber()).to.greaterThan(1);
-    expect(position.y.toNumber()).to.equal(2);
-    expect(position.z.toNumber()).to.equal(1);
-  });
-
-  it("Apply System Velocity on Entity 1, with Clock external account", async () => {
-    const instruction = await worldProgram.methods
-      .apply(SerializeArgs())
-      .accounts({
-        authority: provider.wallet.publicKey,
-        boltSystem: exampleSystemApplyVelocity,
-        world: worldPda,
-      })
-      .remainingAccounts([
-        {
-          pubkey: exampleComponentVelocity.programId,
-          isSigner: false,
-          isWritable: false,
-        },
-        {
-          pubkey: componentVelocityEntity1Pda,
-          isSigner: false,
-          isWritable: true,
-        },
-        {
-          pubkey: exampleComponentPosition.programId,
-          isSigner: false,
-          isWritable: false,
-        },
-        {
-          pubkey: componentPositionEntity1Pda,
-          isSigner: false,
-          isWritable: true,
-        },
-        {
-          pubkey: worldProgram.programId, // world program ID is the end of components delimiter
-          isSigner: false,
-          isWritable: false,
-        },
-        {
-          pubkey: new web3.PublicKey(
-            "SysvarC1ock11111111111111111111111111111111",
-          ),
-          isWritable: false,
-          isSigner: false,
-        },
-      ])
-      .instruction();
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    await provider.sendAndConfirm(transaction);
-
-    const position = await exampleComponentPosition.account.position.fetch(
-      componentPositionEntity1Pda,
-    );
-    logPosition("Apply System Velocity: Entity 1", position);
-    expect(position.x.toNumber()).to.greaterThan(1);
-    expect(position.y.toNumber()).to.equal(2);
-    expect(position.z.toNumber()).to.equal(300);
-  });
-
-  it("Apply Fly System on Entity 4", async () => {
-    const instruction = await worldProgram.methods
-      .apply(SerializeArgs())
-      .accounts({
-        authority: provider.wallet.publicKey,
-        boltSystem: exampleSystemFly,
-        world: worldPda,
-      })
-      .remainingAccounts([
-        {
-          pubkey: exampleComponentPosition.programId,
-          isSigner: false,
-          isWritable: false,
-        },
-        {
-          pubkey: componentPositionEntity4Pda,
-          isSigner: false,
-          isWritable: true,
-        },
-      ])
-      .instruction();
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    await provider.sendAndConfirm(transaction);
-
-    const position = await exampleComponentPosition.account.position.fetch(
-      componentPositionEntity4Pda,
-    );
-    logPosition("Fly System: Entity 4", position);
-    expect(position.x.toNumber()).to.equal(0);
-    expect(position.y.toNumber()).to.equal(0);
-    expect(position.z.toNumber()).to.equal(1);
-  });
-
-  it("Apply Fly System on Entity 5 (should fail with wrong authority)", async () => {
-    const positionBefore =
-      await exampleComponentPosition.account.position.fetch(
-        componentPositionEntity5Pda,
-      );
-
-    const instruction = await worldProgram.methods
-      .apply(SerializeArgs())
-      .accounts({
-        authority: provider.wallet.publicKey,
-        boltSystem: exampleSystemFly,
-        world: worldPda,
-      })
-      .remainingAccounts([
-        {
-          pubkey: exampleComponentPosition.programId,
-          isSigner: false,
-          isWritable: false,
-        },
-        {
-          pubkey: componentPositionEntity5Pda,
-          isSigner: false,
-          isWritable: true,
-        },
-      ])
-      .instruction();
-    const transaction = new anchor.web3.Transaction().add(instruction);
-
-    let failed = false;
-    try {
-      await provider.sendAndConfirm(transaction);
-    } catch (error) {
-      failed = true;
-      // console.log("error", error);
-      expect(error.logs.join("\n")).to.contain("Error Code: InvalidAuthority");
-    }
-    expect(failed).to.equal(true);
-
-    const positionAfter = await exampleComponentPosition.account.position.fetch(
-      componentPositionEntity5Pda,
-    );
-
-    expect(positionBefore.x.toNumber()).to.equal(positionAfter.x.toNumber());
-    expect(positionBefore.y.toNumber()).to.equal(positionAfter.y.toNumber());
-    expect(positionBefore.z.toNumber()).to.equal(positionAfter.z.toNumber());
-  });
-
-  it("Whitelist System", async () => {
-    const instruction = await worldProgram.methods
-      .approveSystem()
-      .accounts({
-        authority: provider.wallet.publicKey,
-        system: exampleSystemFly,
-        world: worldPda,
-      })
-      .instruction();
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    const signature = await provider.sendAndConfirm(transaction, [], {
-      skipPreflight: true,
-    });
-    console.log(`Whitelist 2 system approval signature: ${signature}`);
-
-    // Get World and check permissionless and systems
-    const worldAccount = await worldProgram.account.world.fetch(worldPda);
-    expect(worldAccount.permissionless).to.equal(false);
-    expect(worldAccount.systems.length).to.be.greaterThan(0);
-  });
-
-  it("Whitelist System 2", async () => {
-    const instruction = await worldProgram.methods
-      .approveSystem()
-      .accounts({
-        authority: provider.wallet.publicKey,
-        system: exampleSystemApplyVelocity,
-        world: worldPda,
-      })
-      .instruction();
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    const signature = await provider.sendAndConfirm(transaction, [], {
-      skipPreflight: true,
-    });
-    console.log(`Whitelist 2 system approval signature: ${signature}`);
-
-    // Get World and check permissionless and systems
-    const worldAccount = await worldProgram.account.world.fetch(worldPda);
-    expect(worldAccount.permissionless).to.equal(false);
-    expect(worldAccount.systems.length).to.be.greaterThan(0);
-  });
-
-  it("Apply Fly System on Entity 1", async () => {
-    const instruction = await worldProgram.methods
-      .apply(SerializeArgs())
-      .accounts({
-        authority: provider.wallet.publicKey,
-        boltSystem: exampleSystemFly,
-        world: worldPda,
-      })
-      .remainingAccounts([
-        {
-          pubkey: exampleComponentPosition.programId,
-          isSigner: false,
-          isWritable: false,
-        },
-        {
-          pubkey: componentPositionEntity1Pda,
-          isSigner: false,
-          isWritable: true,
-        },
-      ])
-      .instruction();
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    await provider.sendAndConfirm(transaction);
-  });
-
-  it("Remove System 1", async () => {
-    const instruction = await worldProgram.methods
-      .removeSystem()
-      .accounts({
-        authority: provider.wallet.publicKey,
-        system: exampleSystemFly,
-        world: worldPda,
-      })
-      .instruction();
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    const signature = await provider.sendAndConfirm(transaction, [], {
-      skipPreflight: true,
-    });
-    console.log(`Remove System 1 signature: ${signature}`);
-
-    // Get World and check permissionless and systems
-    const worldAccount = await worldProgram.account.world.fetch(worldPda);
-    expect(worldAccount.permissionless).to.equal(false);
-    expect(worldAccount.systems.length).to.be.greaterThan(0);
-  });
-
-  it("Apply Invalid Fly System on Entity 1", async () => {
-    const instruction = await worldProgram.methods
-      .apply(SerializeArgs())
-      .accounts({
-        authority: provider.wallet.publicKey,
-        boltSystem: exampleSystemFly,
-        world: worldPda,
-      })
-      .remainingAccounts([
-        {
-          pubkey: exampleComponentPosition.programId,
-          isSigner: false,
-          isWritable: false,
-        },
-        {
-          pubkey: componentPositionEntity1Pda,
-          isSigner: false,
-          isWritable: true,
-        },
-      ])
-      .instruction();
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    let invalid = false;
-    try {
-      await provider.sendAndConfirm(transaction);
-    } catch (error) {
-      expect(error.logs.join(" ")).to.contain("Error Code: SystemNotApproved");
-      invalid = true;
-    }
-    expect(invalid).to.equal(true);
-  });
-
-  it("Check invalid component init without CPI", async () => {
-    let invalid = false;
-    try {
-      await exampleComponentPosition.methods
-        .initialize()
-        .accounts({
-          payer: provider.wallet.publicKey,
-          data: componentPositionEntity5Pda,
-          entity: entity5Pda,
-          authority: provider.wallet.publicKey,
-        })
-        .rpc();
-    } catch (error) {
-      // console.log("error", error);
-      expect(error.message).to.contain("Error Code: InvalidCaller");
-      invalid = true;
-    }
-    expect(invalid).to.equal(true);
-  });
-
-  it("Check invalid component update without CPI", async () => {
-    let invalid = false;
-    try {
-      await boltComponentProgram.methods
-        .update(Buffer.from(""))
-        .accounts({
-          boltComponent: componentPositionEntity4Pda,
-          authority: provider.wallet.publicKey,
-        })
-        .rpc();
-    } catch (error) {
-      // console.log("error", error);
-      expect(error.message).to.contain(
-        "bolt_component. Error Code: AccountOwnedByWrongProgram",
-      );
-      invalid = true;
-    }
-    expect(invalid).to.equal(true);
-  });
-
-  it("Check component delegation", async () => {
-    const delegateComponent = await DelegateComponent({
-      payer: provider.wallet.publicKey,
-      entity: entity1Pda,
-      componentId: exampleComponentPosition.programId,
-    });
-    const instruction = delegateComponent.transaction;
-    const transaction = new anchor.web3.Transaction().add(instruction);
-    const txSign = await provider.sendAndConfirm(transaction, [], {
-      skipPreflight: true,
-      commitment: "confirmed",
-    });
-    console.log(`Delegation signature: ${txSign}`);
-    const acc = await provider.connection.getAccountInfo(
-      delegateComponent.componentPda,
-    );
-    expect(acc?.owner.toBase58()).to.equal(DELEGATION_PROGRAM_ID.toBase58());
-  });
-});

TEMPAT SAMPAH
tests/fixtures/session_keys.so


+ 52 - 0
tests/framework.ts

@@ -0,0 +1,52 @@
+export enum Direction {
+  Left = "Left",
+  Right = "Right",
+  Up = "Up",
+  Down = "Down",
+}
+
+import { anchor, BN } from "../clients/bolt-sdk/lib";
+import { type World } from "../target/types/world";
+import { type Position } from "../target/types/position";
+import { type Velocity } from "../target/types/velocity";
+import { type SystemSimpleMovement } from "../target/types/system_simple_movement";
+import { type SystemFly } from "../target/types/system_fly";
+import { type SystemApplyVelocity } from "../target/types/system_apply_velocity";
+import { Keypair, PublicKey } from "@solana/web3.js";
+
+export class Framework {
+  provider: anchor.AnchorProvider;
+  worldProgram: anchor.Program<World>;
+  exampleComponentPosition: anchor.Program<Position>;
+  exampleComponentVelocity: anchor.Program<Velocity>;
+  systemSimpleMovement: anchor.Program<SystemSimpleMovement>;
+  systemFly: anchor.Program<SystemFly>;
+  systemApplyVelocity: anchor.Program<SystemApplyVelocity>;
+
+  worldPda: PublicKey;
+  worldId: BN;
+
+  secondAuthority: PublicKey;
+
+  entity1Pda: PublicKey;
+  entity2Pda: PublicKey;
+  entity4Pda: PublicKey;
+
+  componentPositionEntity1Pda: PublicKey;
+  componentVelocityEntity1Pda: PublicKey;
+
+  componentPositionEntity4Pda: PublicKey;
+
+  constructor() {
+    this.secondAuthority = Keypair.generate().publicKey;
+    this.worldProgram = anchor.workspace.World;
+    this.exampleComponentPosition = anchor.workspace.Position;
+    this.exampleComponentVelocity = anchor.workspace.Velocity;
+    this.systemSimpleMovement = anchor.workspace.SystemSimpleMovement;
+    this.systemFly = anchor.workspace.SystemFly;
+    this.systemApplyVelocity = anchor.workspace.SystemApplyVelocity;
+
+    this.provider = anchor.AnchorProvider.env();
+    anchor.setProvider(this.provider);
+  }
+}

+ 30 - 0
tests/intermediate-level/acceleration.ts

@@ -0,0 +1,30 @@
+import {
+  DelegateComponent,
+  DELEGATION_PROGRAM_ID,
+} from "../../clients/bolt-sdk/lib";
+import { expect } from "chai";
+
+export function acceleration(framework) {
+  describe("Acceleration", () => {
+    it("Check component delegation to accelerator", async () => {
+      const delegateComponent = await DelegateComponent({
+        payer: framework.provider.wallet.publicKey,
+        entity: framework.entity1Pda,
+        componentId: framework.exampleComponentPosition.programId,
+      });
+
+      await framework.provider.sendAndConfirm(
+        delegateComponent.transaction,
+        [],
+        {
+          skipPreflight: true,
+          commitment: "confirmed",
+        },
+      );
+      const acc = await framework.provider.connection.getAccountInfo(
+        delegateComponent.componentPda,
+      );
+      expect(acc?.owner.toBase58()).to.equal(DELEGATION_PROGRAM_ID.toBase58());
+    });
+  });
+}

+ 286 - 0
tests/intermediate-level/ecs.ts

@@ -0,0 +1,286 @@
+import {
+  web3,
+  AddEntity,
+  ApplySystem,
+  InitializeComponent,
+} from "../../clients/bolt-sdk/lib";
+import { Direction, Framework } from "../framework";
+import { expect } from "chai";
+
+export function ecs(framework: Framework) {
+  describe("ECS", () => {
+    it("Add entity 1", async () => {
+      const addEntity = await AddEntity({
+        payer: framework.provider.wallet.publicKey,
+        world: framework.worldPda,
+        connection: framework.provider.connection,
+      });
+      await framework.provider.sendAndConfirm(addEntity.transaction);
+      framework.entity1Pda = addEntity.entityPda; // Saved for later
+    });
+
+    it("Add entity 2", async () => {
+      const addEntity = await AddEntity({
+        payer: framework.provider.wallet.publicKey,
+        world: framework.worldPda,
+        connection: framework.provider.connection,
+      });
+      await framework.provider.sendAndConfirm(addEntity.transaction);
+      framework.entity2Pda = addEntity.entityPda; // Saved for later
+    });
+
+    it("Add entity 3", async () => {
+      const addEntity = await AddEntity({
+        payer: framework.provider.wallet.publicKey,
+        world: framework.worldPda,
+        connection: framework.provider.connection,
+      });
+      await framework.provider.sendAndConfirm(addEntity.transaction);
+    });
+
+    it("Add entity 4 (with seed)", async () => {
+      const addEntity = await AddEntity({
+        payer: framework.provider.wallet.publicKey,
+        world: framework.worldPda,
+        seed: Buffer.from("custom-seed"),
+        connection: framework.provider.connection,
+      });
+      await framework.provider.sendAndConfirm(addEntity.transaction);
+      framework.entity4Pda = addEntity.entityPda;
+    });
+
+    it("Initialize Velocity Component on Entity 1 (with seed)", async () => {
+      const initializeComponent = await InitializeComponent({
+        payer: framework.provider.wallet.publicKey,
+        entity: framework.entity1Pda,
+        componentId: framework.exampleComponentVelocity.programId,
+        seed: "component-velocity",
+      });
+      await framework.provider.sendAndConfirm(initializeComponent.transaction);
+      framework.componentVelocityEntity1Pda = initializeComponent.componentPda; // Saved for later
+    });
+
+    it("Initialize Position Component on Entity 1", async () => {
+      const initializeComponent = await InitializeComponent({
+        payer: framework.provider.wallet.publicKey,
+        entity: framework.entity1Pda,
+        componentId: framework.exampleComponentPosition.programId,
+      });
+      await framework.provider.sendAndConfirm(initializeComponent.transaction);
+      framework.componentPositionEntity1Pda = initializeComponent.componentPda; // Saved for later
+    });
+
+    it("Initialize Position Component on Entity 2", async () => {
+      const initializeComponent = await InitializeComponent({
+        payer: framework.provider.wallet.publicKey,
+        entity: framework.entity2Pda,
+        componentId: framework.exampleComponentPosition.programId,
+      });
+      await framework.provider.sendAndConfirm(initializeComponent.transaction);
+    });
+
+    it("Initialize Position Component on Entity 4", async () => {
+      const initializeComponent = await InitializeComponent({
+        payer: framework.provider.wallet.publicKey,
+        entity: framework.entity4Pda,
+        componentId: framework.exampleComponentPosition.programId,
+      });
+      await framework.provider.sendAndConfirm(initializeComponent.transaction);
+      framework.componentPositionEntity4Pda = initializeComponent.componentPda; // Saved for later
+    });
+
+    it("Check Position on Entity 1 is default", async () => {
+      const position =
+        await framework.exampleComponentPosition.account.position.fetch(
+          framework.componentPositionEntity1Pda,
+        );
+      expect(position.x.toNumber()).to.equal(0);
+      expect(position.y.toNumber()).to.equal(0);
+      expect(position.z.toNumber()).to.equal(0);
+    });
+
+    it("Apply Simple Movement System (Up) on Entity 1", async () => {
+      const applySystem = await ApplySystem({
+        authority: framework.provider.wallet.publicKey,
+        systemId: framework.systemSimpleMovement.programId,
+        world: framework.worldPda,
+        entities: [
+          {
+            entity: framework.entity1Pda,
+            components: [
+              { componentId: framework.exampleComponentPosition.programId },
+            ],
+          },
+        ],
+        args: {
+          direction: Direction.Up,
+        },
+      });
+      await framework.provider.sendAndConfirm(applySystem.transaction, [], {
+        skipPreflight: true,
+      });
+
+      const position =
+        await framework.exampleComponentPosition.account.position.fetch(
+          framework.componentPositionEntity1Pda,
+        );
+      expect(position.x.toNumber()).to.equal(0);
+      expect(position.y.toNumber()).to.equal(1);
+      expect(position.z.toNumber()).to.equal(0);
+    });
+
+    it("Apply Simple Movement System (Right) on Entity 1", async () => {
+      const applySystem = await ApplySystem({
+        authority: framework.provider.wallet.publicKey,
+        systemId: framework.systemSimpleMovement.programId,
+        world: framework.worldPda,
+        entities: [
+          {
+            entity: framework.entity1Pda,
+            components: [
+              { componentId: framework.exampleComponentPosition.programId },
+            ],
+          },
+        ],
+        args: {
+          direction: Direction.Right,
+        },
+      });
+      await framework.provider.sendAndConfirm(applySystem.transaction);
+
+      const position =
+        await framework.exampleComponentPosition.account.position.fetch(
+          framework.componentPositionEntity1Pda,
+        );
+      expect(position.x.toNumber()).to.equal(1);
+      expect(position.y.toNumber()).to.equal(1);
+      expect(position.z.toNumber()).to.equal(0);
+    });
+
+    it("Apply Fly System on Entity 1", async () => {
+      const applySystem = await ApplySystem({
+        authority: framework.provider.wallet.publicKey,
+        systemId: framework.systemFly.programId,
+        world: framework.worldPda,
+        entities: [
+          {
+            entity: framework.entity1Pda,
+            components: [
+              { componentId: framework.exampleComponentPosition.programId },
+            ],
+          },
+        ],
+      });
+      await framework.provider.sendAndConfirm(applySystem.transaction);
+
+      const position =
+        await framework.exampleComponentPosition.account.position.fetch(
+          framework.componentPositionEntity1Pda,
+        );
+      expect(position.x.toNumber()).to.equal(1);
+      expect(position.y.toNumber()).to.equal(1);
+      expect(position.z.toNumber()).to.equal(1);
+    });
+
+    it("Apply System Velocity on Entity 1", async () => {
+      const applySystem = await ApplySystem({
+        authority: framework.provider.wallet.publicKey,
+        systemId: framework.systemApplyVelocity.programId,
+        world: framework.worldPda,
+        entities: [
+          {
+            entity: framework.entity1Pda,
+            components: [
+              {
+                componentId: framework.exampleComponentVelocity.programId,
+                seed: "component-velocity",
+              },
+              { componentId: framework.exampleComponentPosition.programId },
+            ],
+          },
+        ],
+      });
+      await framework.provider.sendAndConfirm(applySystem.transaction);
+
+      const velocity =
+        await framework.exampleComponentVelocity.account.velocity.fetch(
+          framework.componentVelocityEntity1Pda,
+        );
+      expect(velocity.x.toNumber()).to.equal(10);
+      expect(velocity.y.toNumber()).to.equal(0);
+      expect(velocity.z.toNumber()).to.equal(0);
+      expect(velocity.lastApplied.toNumber()).to.not.equal(0);
+
+      const position =
+        await framework.exampleComponentPosition.account.position.fetch(
+          framework.componentPositionEntity1Pda,
+        );
+      expect(position.x.toNumber()).to.greaterThan(1);
+      expect(position.y.toNumber()).to.equal(1);
+      expect(position.z.toNumber()).to.equal(1);
+    });
+
+    it("Apply System Velocity on Entity 1, with Clock external account", async () => {
+      const applySystem = await ApplySystem({
+        authority: framework.provider.wallet.publicKey,
+        systemId: framework.systemApplyVelocity.programId,
+        world: framework.worldPda,
+        entities: [
+          {
+            entity: framework.entity1Pda,
+            components: [
+              {
+                componentId: framework.exampleComponentVelocity.programId,
+                seed: "component-velocity",
+              },
+              { componentId: framework.exampleComponentPosition.programId },
+            ],
+          },
+        ],
+        extraAccounts: [
+          {
+            pubkey: new web3.PublicKey(
+              "SysvarC1ock11111111111111111111111111111111",
+            ),
+            isWritable: false,
+            isSigner: false,
+          },
+        ],
+      });
+      await framework.provider.sendAndConfirm(applySystem.transaction);
+
+      const position =
+        await framework.exampleComponentPosition.account.position.fetch(
+          framework.componentPositionEntity1Pda,
+        );
+      expect(position.x.toNumber()).to.greaterThan(1);
+      expect(position.y.toNumber()).to.equal(1);
+      expect(position.z.toNumber()).to.equal(300);
+    });
+
+    it("Apply Fly System on Entity 4", async () => {
+      const applySystem = await ApplySystem({
+        authority: framework.provider.wallet.publicKey,
+        systemId: framework.systemFly.programId,
+        world: framework.worldPda,
+        entities: [
+          {
+            entity: framework.entity4Pda,
+            components: [
+              { componentId: framework.exampleComponentPosition.programId },
+            ],
+          },
+        ],
+      });
+      await framework.provider.sendAndConfirm(applySystem.transaction);
+
+      const position =
+        await framework.exampleComponentPosition.account.position.fetch(
+          framework.componentPositionEntity4Pda,
+        );
+      expect(position.x.toNumber()).to.equal(0);
+      expect(position.y.toNumber()).to.equal(0);
+      expect(position.z.toNumber()).to.equal(1);
+    });
+  });
+}

+ 15 - 0
tests/intermediate-level/index.ts

@@ -0,0 +1,15 @@
+import { Framework } from "../framework";
+import { world } from "./world";
+import { ecs } from "./ecs";
+import { session } from "./session";
+import { permissioning } from "./permissioning";
+import { acceleration } from "./acceleration";
+
+describe("Intermediate level API", () => {
+  const framework: Framework = new Framework();
+  world(framework);
+  ecs(framework);
+  session(framework);
+  permissioning(framework);
+  acceleration(framework);
+});

+ 115 - 0
tests/intermediate-level/permissioning/component.ts

@@ -0,0 +1,115 @@
+import { assert, expect } from "chai";
+import {
+  anchor,
+  AddEntity,
+  ApplySystem,
+  InitializeComponent,
+} from "../../../clients/bolt-sdk/lib";
+import { Keypair } from "@solana/web3.js";
+
+export function component(framework) {
+  describe("Component authority", () => {
+    let entity: anchor.web3.PublicKey;
+    let component: anchor.web3.PublicKey;
+
+    it("Add authority test entity", async () => {
+      const addEntity = await AddEntity({
+        payer: framework.provider.wallet.publicKey,
+        world: framework.worldPda,
+        connection: framework.provider.connection,
+      });
+      await framework.provider.sendAndConfirm(addEntity.transaction);
+      entity = addEntity.entityPda; // Saved for later
+    });
+
+    it("Initialize position component with authority on authority test entity", async () => {
+      const initializeComponent = await InitializeComponent({
+        payer: framework.provider.wallet.publicKey,
+        entity: entity,
+        componentId: framework.exampleComponentPosition.programId,
+        authority: framework.provider.wallet.publicKey,
+      });
+      await framework.provider.sendAndConfirm(initializeComponent.transaction);
+      component = initializeComponent.componentPda; // Saved for later
+    });
+
+    it("Shouldn't apply fly system on authority test entity with wrong authority", async () => {
+      const positionBefore =
+        await framework.exampleComponentPosition.account.position.fetch(
+          component,
+        );
+
+      const keypair = Keypair.generate();
+
+      const applySystem = await ApplySystem({
+        authority: keypair.publicKey,
+        systemId: framework.systemFly.programId,
+        world: framework.worldPda,
+        entities: [
+          {
+            entity: entity,
+            components: [
+              { componentId: framework.exampleComponentPosition.programId },
+            ],
+          },
+        ],
+      });
+
+      try {
+        await framework.provider.sendAndConfirm(applySystem.transaction, [
+          keypair,
+        ]);
+        assert.fail(
+          "Shouldn't apply fly system on authority test entity with wrong authority",
+        );
+      } catch (error) {
+        expect(error.logs.join("\n")).to.contain(
+          "Error Code: InvalidAuthority",
+        );
+      }
+
+      const positionAfter =
+        await framework.exampleComponentPosition.account.position.fetch(
+          component,
+        );
+
+      expect(positionBefore.x.toNumber()).to.equal(positionAfter.x.toNumber());
+      expect(positionBefore.y.toNumber()).to.equal(positionAfter.y.toNumber());
+      expect(positionBefore.z.toNumber()).to.equal(positionAfter.z.toNumber());
+    });
+
+    it("Apply Fly System on authority test entity should succeed with correct authority", async () => {
+      const positionBefore =
+        await framework.exampleComponentPosition.account.position.fetch(
+          component,
+        );
+
+      const applySystem = await ApplySystem({
+        authority: framework.provider.wallet.publicKey,
+        systemId: framework.systemFly.programId,
+        world: framework.worldPda,
+        entities: [
+          {
+            entity,
+            components: [
+              { componentId: framework.exampleComponentPosition.programId },
+            ],
+          },
+        ],
+      });
+
+      await framework.provider.sendAndConfirm(applySystem.transaction);
+
+      const positionAfter =
+        await framework.exampleComponentPosition.account.position.fetch(
+          component,
+        );
+
+      expect(positionAfter.x.toNumber()).to.equal(positionBefore.x.toNumber());
+      expect(positionAfter.y.toNumber()).to.equal(positionBefore.y.toNumber());
+      expect(positionAfter.z.toNumber()).to.equal(
+        positionBefore.z.toNumber() + 1,
+      );
+    });
+  });
+}

+ 9 - 0
tests/intermediate-level/permissioning/index.ts

@@ -0,0 +1,9 @@
+import { component } from "./component";
+import { world } from "./world";
+
+export function permissioning(framework) {
+  describe("Permissioning", () => {
+    component(framework);
+    world(framework);
+  });
+}

+ 168 - 0
tests/intermediate-level/permissioning/world.ts

@@ -0,0 +1,168 @@
+import { expect } from "chai";
+import {
+  AddAuthority,
+  RemoveAuthority,
+  ApplySystem,
+  ApproveSystem,
+  RemoveSystem,
+} from "../../../clients/bolt-sdk/lib";
+
+export function world(framework) {
+  describe("World authority", () => {
+    it("Add authority", async () => {
+      const addAuthority = await AddAuthority({
+        authority: framework.provider.wallet.publicKey,
+        newAuthority: framework.provider.wallet.publicKey,
+        world: framework.worldPda,
+        connection: framework.provider.connection,
+      });
+      await framework.provider.sendAndConfirm(addAuthority.transaction, [], {
+        skipPreflight: true,
+      });
+      const worldAccount = await framework.worldProgram.account.world.fetch(
+        framework.worldPda,
+      );
+      expect(
+        worldAccount.authorities.some((auth) =>
+          auth.equals(framework.provider.wallet.publicKey),
+        ),
+      );
+    });
+
+    it("Add a second authority", async () => {
+      const addAuthority = await AddAuthority({
+        authority: framework.provider.wallet.publicKey,
+        newAuthority: framework.secondAuthority,
+        world: framework.worldPda,
+        connection: framework.provider.connection,
+      });
+      await framework.provider.sendAndConfirm(addAuthority.transaction);
+      const worldAccount = await framework.worldProgram.account.world.fetch(
+        framework.worldPda,
+      );
+      expect(
+        worldAccount.authorities.some((auth) =>
+          auth.equals(framework.secondAuthority),
+        ),
+      );
+    });
+
+    it("Remove an authority", async () => {
+      const removeAuthority = await RemoveAuthority({
+        authority: framework.provider.wallet.publicKey,
+        authorityToDelete: framework.secondAuthority,
+        world: framework.worldPda,
+        connection: framework.provider.connection,
+      });
+      await framework.provider.sendAndConfirm(removeAuthority.transaction);
+      const worldAccount = await framework.worldProgram.account.world.fetch(
+        framework.worldPda,
+      );
+      expect(
+        !worldAccount.authorities.some((auth) =>
+          auth.equals(framework.secondAuthority),
+        ),
+      );
+    });
+
+    it("Whitelist Fly System", async () => {
+      const approveSystem = await ApproveSystem({
+        authority: framework.provider.wallet.publicKey,
+        systemToApprove: framework.systemFly.programId,
+        world: framework.worldPda,
+      });
+
+      await framework.provider.sendAndConfirm(approveSystem.transaction, [], {
+        skipPreflight: true,
+      });
+
+      // Get World and check permissionless and systems
+      const worldAccount = await framework.worldProgram.account.world.fetch(
+        framework.worldPda,
+      );
+      expect(worldAccount.permissionless).to.equal(false);
+      expect(worldAccount.systems.length).to.be.greaterThan(0);
+    });
+
+    it("Whitelist Apply Velocity System system", async () => {
+      const approveSystem = await ApproveSystem({
+        authority: framework.provider.wallet.publicKey,
+        systemToApprove: framework.systemApplyVelocity.programId,
+        world: framework.worldPda,
+      });
+
+      await framework.provider.sendAndConfirm(approveSystem.transaction, [], {
+        skipPreflight: true,
+      });
+
+      // Get World and check permissionless and systems
+      const worldAccount = await framework.worldProgram.account.world.fetch(
+        framework.worldPda,
+      );
+      expect(worldAccount.permissionless).to.equal(false);
+      expect(worldAccount.systems.length).to.be.greaterThan(0);
+    });
+
+    it("Apply Fly System on Entity 1", async () => {
+      const applySystem = await ApplySystem({
+        authority: framework.provider.wallet.publicKey,
+        systemId: framework.systemFly.programId,
+        world: framework.worldPda,
+        entities: [
+          {
+            entity: framework.entity1Pda,
+            components: [
+              { componentId: framework.exampleComponentPosition.programId },
+            ],
+          },
+        ],
+      });
+      await framework.provider.sendAndConfirm(applySystem.transaction);
+    });
+
+    it("Remove Fly System", async () => {
+      const removeSystem = await RemoveSystem({
+        authority: framework.provider.wallet.publicKey,
+        systemToRemove: framework.systemFly.programId,
+        world: framework.worldPda,
+      });
+
+      await framework.provider.sendAndConfirm(removeSystem.transaction, [], {
+        skipPreflight: true,
+      });
+
+      // Get World and check permissionless and systems
+      const worldAccount = await framework.worldProgram.account.world.fetch(
+        framework.worldPda,
+      );
+      expect(worldAccount.permissionless).to.equal(false);
+      expect(worldAccount.systems.length).to.be.greaterThan(0);
+    });
+
+    it("Apply unauthorized Fly System on Entity 1", async () => {
+      const applySystem = await ApplySystem({
+        authority: framework.provider.wallet.publicKey,
+        systemId: framework.systemFly.programId,
+        world: framework.worldPda,
+        entities: [
+          {
+            entity: framework.entity1Pda,
+            components: [
+              { componentId: framework.exampleComponentPosition.programId },
+            ],
+          },
+        ],
+      });
+      let invalid = false;
+      try {
+        await framework.provider.sendAndConfirm(applySystem.transaction);
+      } catch (error) {
+        expect(error.logs.join(" ")).to.contain(
+          "Error Code: SystemNotApproved",
+        );
+        invalid = true;
+      }
+      expect(invalid).to.equal(true);
+    });
+  });
+}

+ 150 - 0
tests/intermediate-level/session.ts

@@ -0,0 +1,150 @@
+import { Keypair } from "@solana/web3.js";
+import {
+  AddEntity,
+  CreateSession,
+  InitializeComponent,
+  ApplySystem,
+  anchor,
+  BN,
+  Session,
+} from "../../clients/bolt-sdk/lib";
+import { expect } from "chai";
+
+// TODO: Create the API for it.
+export function session(framework) {
+  describe("Session", () => {
+    let session: Session;
+    let entity: anchor.web3.PublicKey;
+    let component: anchor.web3.PublicKey;
+    let entityWithAuthority: anchor.web3.PublicKey;
+    let componentWithAuthority: anchor.web3.PublicKey;
+
+    it("Create Session", async () => {
+      const createSession = await CreateSession({
+        authority: framework.provider.wallet.publicKey,
+        topUp: new BN(1000000000),
+      });
+      session = createSession.session;
+      await framework.provider.sendAndConfirm(createSession.transaction, [
+        session.signer,
+      ]);
+    });
+
+    it("Add entity 1", async () => {
+      const addEntity = await AddEntity({
+        payer: framework.provider.wallet.publicKey,
+        world: framework.worldPda,
+        connection: framework.provider.connection,
+      });
+      await framework.provider.sendAndConfirm(addEntity.transaction);
+      entity = addEntity.entityPda;
+    });
+
+    it("Initialize position component", async () => {
+      const initializeComponent = await InitializeComponent({
+        payer: session.signer.publicKey,
+        entity: entity,
+        componentId: framework.exampleComponentPosition.programId,
+      });
+      await framework.provider.sendAndConfirm(initializeComponent.transaction, [
+        session.signer,
+      ]);
+      component = initializeComponent.componentPda;
+    });
+
+    it("Apply Fly System on component using session token", async () => {
+      const positionBefore =
+        await framework.exampleComponentPosition.account.position.fetch(
+          component,
+        );
+
+      const applySystem = await ApplySystem({
+        authority: session.signer.publicKey,
+        systemId: framework.systemFly.programId,
+        world: framework.worldPda,
+        session,
+        entities: [
+          {
+            entity: entity,
+            components: [
+              { componentId: framework.exampleComponentPosition.programId },
+            ],
+          },
+        ],
+      });
+      await framework.provider.sendAndConfirm(applySystem.transaction, [
+        session.signer,
+      ]);
+
+      const positionAfter =
+        await framework.exampleComponentPosition.account.position.fetch(
+          component,
+        );
+
+      expect(positionAfter.x.toNumber()).to.equal(positionBefore.x.toNumber());
+      expect(positionAfter.y.toNumber()).to.equal(positionBefore.y.toNumber());
+      expect(positionAfter.z.toNumber()).to.equal(
+        positionBefore.z.toNumber() + 1,
+      );
+    });
+
+    it("Add entity for authority test", async () => {
+      const addEntity = await AddEntity({
+        payer: framework.provider.wallet.publicKey,
+        world: framework.worldPda,
+        connection: framework.provider.connection,
+      });
+      await framework.provider.sendAndConfirm(addEntity.transaction);
+      entityWithAuthority = addEntity.entityPda;
+    });
+
+    it("Initialize position component with authority", async () => {
+      const initializeComponent = await InitializeComponent({
+        payer: session.signer.publicKey,
+        entity: entityWithAuthority,
+        componentId: framework.exampleComponentPosition.programId,
+        authority: framework.provider.wallet.publicKey,
+      });
+      await framework.provider.sendAndConfirm(initializeComponent.transaction, [
+        session.signer,
+      ]);
+      componentWithAuthority = initializeComponent.componentPda;
+    });
+
+    it("Apply Fly System on component with authority using session token", async () => {
+      const positionBefore =
+        await framework.exampleComponentPosition.account.position.fetch(
+          componentWithAuthority,
+        );
+
+      const applySystem = await ApplySystem({
+        authority: session.signer.publicKey,
+        systemId: framework.systemFly.programId,
+        world: framework.worldPda,
+        session,
+        entities: [
+          {
+            entity: entityWithAuthority,
+            components: [
+              { componentId: framework.exampleComponentPosition.programId },
+            ],
+          },
+        ],
+      });
+      await framework.provider.sendAndConfirm(applySystem.transaction, [
+        session.signer,
+      ]);
+
+      const positionAfter =
+        await framework.exampleComponentPosition.account.position.fetch(
+          componentWithAuthority,
+        );
+
+      expect(positionAfter.x.toNumber()).to.equal(positionBefore.x.toNumber());
+      expect(positionAfter.y.toNumber()).to.equal(positionBefore.y.toNumber());
+      expect(positionAfter.z.toNumber()).to.equal(
+        positionBefore.z.toNumber() + 1,
+      );
+    });
+  });
+}

+ 37 - 0
tests/intermediate-level/world.ts

@@ -0,0 +1,37 @@
+import {
+  InitializeNewWorld,
+  InitializeRegistry,
+} from "../../clients/bolt-sdk/lib";
+
+export function world(framework) {
+  describe("World", () => {
+    it("Initialize registry", async () => {
+      const initializeRegistry = await InitializeRegistry({
+        payer: framework.provider.wallet.publicKey,
+        connection: framework.provider.connection,
+      });
+      try {
+        await framework.provider.sendAndConfirm(initializeRegistry.transaction);
+      } catch (error) {
+        // This is expected to fail because the registry already exists if another api level test ran before
+      }
+    });
+
+    it("Initialize world", async () => {
+      const initializeNewWorld = await InitializeNewWorld({
+        payer: framework.provider.wallet.publicKey,
+        connection: framework.provider.connection,
+      });
+      await framework.provider.sendAndConfirm(initializeNewWorld.transaction);
+      framework.worldPda = initializeNewWorld.worldPda; // Saved for later
+    });
+
+    it("Initialize second world", async () => {
+      const initializeNewWorld = await InitializeNewWorld({
+        payer: framework.provider.wallet.publicKey,
+        connection: framework.provider.connection,
+      });
+      await framework.provider.sendAndConfirm(initializeNewWorld.transaction);
+    });
+  });
+}

+ 28 - 0
tests/low-level/acceleration.ts

@@ -0,0 +1,28 @@
+import {
+  anchor,
+  DelegateComponent,
+  DELEGATION_PROGRAM_ID,
+} from "../../clients/bolt-sdk/lib";
+import { expect } from "chai";
+
+export function acceleration(framework) {
+  describe("Acceleration", () => {
+    it("Check component delegation to accelerator", async () => {
+      const delegateComponent = await DelegateComponent({
+        payer: framework.provider.wallet.publicKey,
+        entity: framework.entity1Pda,
+        componentId: framework.exampleComponentPosition.programId,
+      });
+      const instruction = delegateComponent.transaction;
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction, [], {
+        skipPreflight: true,
+        commitment: "confirmed",
+      });
+      const acc = await framework.provider.connection.getAccountInfo(
+        delegateComponent.componentPda,
+      );
+      expect(acc?.owner.toBase58()).to.equal(DELEGATION_PROGRAM_ID.toBase58());
+    });
+  });
+}

+ 428 - 0
tests/low-level/ecs.ts

@@ -0,0 +1,428 @@
+import { expect } from "chai";
+import {
+  anchor,
+  web3,
+  FindComponentPda,
+  FindEntityPda,
+  SerializeArgs,
+} from "../../clients/bolt-sdk/lib";
+import { Direction } from "../framework";
+
+export function ecs(framework) {
+  describe("ECS", () => {
+    it("Add entity 1", async () => {
+      const world = await framework.worldProgram.account.world.fetch(
+        framework.worldPda,
+      );
+      framework.entity1Pda = FindEntityPda({
+        worldId: world.id,
+        entityId: world.entities,
+      });
+      const instruction = await framework.worldProgram.methods
+        .addEntity(null)
+        .accounts({
+          payer: framework.provider.wallet.publicKey,
+          world: framework.worldPda,
+          entity: framework.entity1Pda,
+        })
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction);
+    });
+
+    it("Add entity 2", async () => {
+      const world = await framework.worldProgram.account.world.fetch(
+        framework.worldPda,
+      );
+      framework.entity2Pda = FindEntityPda({
+        worldId: world.id,
+        entityId: world.entities,
+      });
+      const instruction = await framework.worldProgram.methods
+        .addEntity(null)
+        .accounts({
+          payer: framework.provider.wallet.publicKey,
+          world: framework.worldPda,
+          entity: framework.entity2Pda,
+        })
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction);
+    });
+
+    it("Add entity 3", async () => {
+      const world = await framework.worldProgram.account.world.fetch(
+        framework.worldPda,
+      );
+      const entity3Pda = FindEntityPda({
+        worldId: world.id,
+        entityId: world.entities,
+      });
+      const instruction = await framework.worldProgram.methods
+        .addEntity(null)
+        .accounts({
+          payer: framework.provider.wallet.publicKey,
+          world: framework.worldPda,
+          entity: entity3Pda,
+        })
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction);
+    });
+
+    it("Add entity 4 (with seed)", async () => {
+      const world = await framework.worldProgram.account.world.fetch(
+        framework.worldPda,
+      );
+      const seed = Buffer.from("custom-seed");
+      framework.entity4Pda = FindEntityPda({ worldId: world.id, seed });
+      const instruction = await framework.worldProgram.methods
+        .addEntity(seed)
+        .accounts({
+          payer: framework.provider.wallet.publicKey,
+          world: framework.worldPda,
+          entity: framework.entity4Pda,
+        })
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction);
+    });
+
+    it("Initialize Velocity Component on Entity 1 (with seed)", async () => {
+      const componentId = framework.exampleComponentVelocity.programId;
+      framework.componentVelocityEntity1Pda = FindComponentPda({
+        componentId,
+        entity: framework.entity1Pda,
+        seed: "component-velocity",
+      });
+      const instruction = await framework.worldProgram.methods
+        .initializeComponent()
+        .accounts({
+          payer: framework.provider.wallet.publicKey,
+          entity: framework.entity1Pda,
+          data: framework.componentVelocityEntity1Pda,
+          componentProgram: componentId,
+          authority: framework.worldProgram.programId,
+        })
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction);
+    });
+
+    it("Initialize Position Component on Entity 1", async () => {
+      const componentId = framework.exampleComponentPosition.programId;
+      framework.componentPositionEntity1Pda = FindComponentPda({
+        componentId,
+        entity: framework.entity1Pda,
+      });
+      const instruction = await framework.worldProgram.methods
+        .initializeComponent()
+        .accounts({
+          payer: framework.provider.wallet.publicKey,
+          entity: framework.entity1Pda,
+          data: framework.componentPositionEntity1Pda,
+          componentProgram: componentId,
+          authority: framework.worldProgram.programId,
+        })
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction);
+    });
+
+    it("Initialize Position Component on Entity 2", async () => {
+      const componentId = framework.exampleComponentPosition.programId;
+      const componentPda = FindComponentPda({
+        componentId,
+        entity: framework.entity2Pda,
+      });
+      const instruction = await framework.worldProgram.methods
+        .initializeComponent()
+        .accounts({
+          payer: framework.provider.wallet.publicKey,
+          entity: framework.entity2Pda,
+          data: componentPda,
+          componentProgram: componentId,
+          authority: framework.worldProgram.programId,
+        })
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction);
+    });
+
+    it("Initialize Position Component on Entity 4", async () => {
+      const componentId = framework.exampleComponentPosition.programId;
+      framework.componentPositionEntity4Pda = FindComponentPda({
+        componentId,
+        entity: framework.entity4Pda,
+      });
+      const instruction = await framework.worldProgram.methods
+        .initializeComponent()
+        .accounts({
+          payer: framework.provider.wallet.publicKey,
+          entity: framework.entity4Pda,
+          data: framework.componentPositionEntity4Pda,
+          componentProgram: componentId,
+          authority: framework.worldProgram.programId,
+        })
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction);
+    });
+
+    it("Check Position on Entity 1 is default", async () => {
+      const position =
+        await framework.exampleComponentPosition.account.position.fetch(
+          framework.componentPositionEntity1Pda,
+        );
+      expect(position.x.toNumber()).to.equal(0);
+      expect(position.y.toNumber()).to.equal(0);
+      expect(position.z.toNumber()).to.equal(0);
+    });
+
+    it("Apply Simple Movement System (Up) on Entity 1", async () => {
+      const instruction = await framework.worldProgram.methods
+        .apply(SerializeArgs({ direction: Direction.Up }))
+        .accounts({
+          authority: framework.provider.wallet.publicKey,
+          boltSystem: framework.systemSimpleMovement.programId,
+          world: framework.worldPda,
+          sessionToken: null,
+        })
+        .remainingAccounts([
+          {
+            pubkey: framework.exampleComponentPosition.programId,
+            isSigner: false,
+            isWritable: false,
+          },
+          {
+            pubkey: framework.componentPositionEntity1Pda,
+            isSigner: false,
+            isWritable: true,
+          },
+        ])
+        .instruction();
+
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction);
+
+      const position =
+        await framework.exampleComponentPosition.account.position.fetch(
+          framework.componentPositionEntity1Pda,
+        );
+      expect(position.x.toNumber()).to.equal(0);
+      expect(position.y.toNumber()).to.equal(1);
+      expect(position.z.toNumber()).to.equal(0);
+    });
+
+    it("Apply Simple Movement System (Right) on Entity 1", async () => {
+      const instruction = await framework.worldProgram.methods
+        .apply(SerializeArgs({ direction: Direction.Right }))
+        .accounts({
+          authority: framework.provider.wallet.publicKey,
+          boltSystem: framework.systemSimpleMovement.programId,
+          world: framework.worldPda,
+          sessionToken: null,
+        })
+        .remainingAccounts([
+          {
+            pubkey: framework.exampleComponentPosition.programId,
+            isSigner: false,
+            isWritable: false,
+          },
+          {
+            pubkey: framework.componentPositionEntity1Pda,
+            isSigner: false,
+            isWritable: true,
+          },
+        ])
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction);
+
+      const position =
+        await framework.exampleComponentPosition.account.position.fetch(
+          framework.componentPositionEntity1Pda,
+        );
+      expect(position.x.toNumber()).to.equal(1);
+      expect(position.y.toNumber()).to.equal(1);
+      expect(position.z.toNumber()).to.equal(0);
+    });
+
+    it("Apply Fly System on Entity 1", async () => {
+      const instruction = await framework.worldProgram.methods
+        .apply(SerializeArgs())
+        .accounts({
+          authority: framework.provider.wallet.publicKey,
+          boltSystem: framework.systemFly.programId,
+          world: framework.worldPda,
+          sessionToken: null,
+        })
+        .remainingAccounts([
+          {
+            pubkey: framework.exampleComponentPosition.programId,
+            isSigner: false,
+            isWritable: false,
+          },
+          {
+            pubkey: framework.componentPositionEntity1Pda,
+            isSigner: false,
+            isWritable: true,
+          },
+        ])
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction);
+
+      const position =
+        await framework.exampleComponentPosition.account.position.fetch(
+          framework.componentPositionEntity1Pda,
+        );
+      expect(position.x.toNumber()).to.equal(1);
+      expect(position.y.toNumber()).to.equal(1);
+      expect(position.z.toNumber()).to.equal(1);
+    });
+
+    it("Apply System Velocity on Entity 1", async () => {
+      const instruction = await framework.worldProgram.methods
+        .apply(SerializeArgs())
+        .accounts({
+          authority: framework.provider.wallet.publicKey,
+          boltSystem: framework.systemApplyVelocity.programId,
+          world: framework.worldPda,
+          sessionToken: null,
+        })
+        .remainingAccounts([
+          {
+            pubkey: framework.exampleComponentVelocity.programId,
+            isSigner: false,
+            isWritable: false,
+          },
+          {
+            pubkey: framework.componentVelocityEntity1Pda,
+            isSigner: false,
+            isWritable: true,
+          },
+          {
+            pubkey: framework.exampleComponentPosition.programId,
+            isSigner: false,
+            isWritable: false,
+          },
+          {
+            pubkey: framework.componentPositionEntity1Pda,
+            isSigner: false,
+            isWritable: true,
+          },
+        ])
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction);
+
+      const velocity =
+        await framework.exampleComponentVelocity.account.velocity.fetch(
+          framework.componentVelocityEntity1Pda,
+        );
+      expect(velocity.x.toNumber()).to.equal(10);
+      expect(velocity.y.toNumber()).to.equal(0);
+      expect(velocity.z.toNumber()).to.equal(0);
+      expect(velocity.lastApplied.toNumber()).to.not.equal(0);
+
+      const position =
+        await framework.exampleComponentPosition.account.position.fetch(
+          framework.componentPositionEntity1Pda,
+        );
+      expect(position.x.toNumber()).to.greaterThan(1);
+      expect(position.y.toNumber()).to.equal(1);
+      expect(position.z.toNumber()).to.equal(1);
+    });
+
+    it("Apply System Velocity on Entity 1, with Clock external account", async () => {
+      const instruction = await framework.worldProgram.methods
+        .apply(SerializeArgs())
+        .accounts({
+          authority: framework.provider.wallet.publicKey,
+          boltSystem: framework.systemApplyVelocity.programId,
+          world: framework.worldPda,
+          sessionToken: null,
+        })
+        .remainingAccounts([
+          {
+            pubkey: framework.exampleComponentVelocity.programId,
+            isSigner: false,
+            isWritable: false,
+          },
+          {
+            pubkey: framework.componentVelocityEntity1Pda,
+            isSigner: false,
+            isWritable: true,
+          },
+          {
+            pubkey: framework.exampleComponentPosition.programId,
+            isSigner: false,
+            isWritable: false,
+          },
+          {
+            pubkey: framework.componentPositionEntity1Pda,
+            isSigner: false,
+            isWritable: true,
+          },
+          {
+            pubkey: framework.worldProgram.programId, // world program ID is the end of components delimiter
+            isSigner: false,
+            isWritable: false,
+          },
+          {
+            pubkey: new web3.PublicKey(
+              "SysvarC1ock11111111111111111111111111111111",
+            ),
+            isWritable: false,
+            isSigner: false,
+          },
+        ])
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction);
+
+      const position =
+        await framework.exampleComponentPosition.account.position.fetch(
+          framework.componentPositionEntity1Pda,
+        );
+      expect(position.x.toNumber()).to.greaterThan(1);
+      expect(position.y.toNumber()).to.equal(1);
+      expect(position.z.toNumber()).to.equal(300);
+    });
+
+    it("Apply Fly System on Entity 4", async () => {
+      const instruction = await framework.worldProgram.methods
+        .apply(SerializeArgs())
+        .accounts({
+          authority: framework.provider.wallet.publicKey,
+          boltSystem: framework.systemFly.programId,
+          world: framework.worldPda,
+          sessionToken: null,
+        })
+        .remainingAccounts([
+          {
+            pubkey: framework.exampleComponentPosition.programId,
+            isSigner: false,
+            isWritable: false,
+          },
+          {
+            pubkey: framework.componentPositionEntity4Pda,
+            isSigner: false,
+            isWritable: true,
+          },
+        ])
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction);
+
+      const position =
+        await framework.exampleComponentPosition.account.position.fetch(
+          framework.componentPositionEntity4Pda,
+        );
+      expect(position.x.toNumber()).to.equal(0);
+      expect(position.y.toNumber()).to.equal(0);
+      expect(position.z.toNumber()).to.equal(1);
+    });
+  });
+}

+ 15 - 0
tests/low-level/index.ts

@@ -0,0 +1,15 @@
+import { Framework } from "../framework";
+import { world } from "./world";
+import { ecs } from "./ecs";
+import { session } from "./session";
+import { permissioning } from "./permissioning";
+import { acceleration } from "./acceleration";
+
+describe("Low level API", () => {
+  const framework: Framework = new Framework();
+  world(framework);
+  ecs(framework);
+  session(framework);
+  permissioning(framework);
+  acceleration(framework);
+});

+ 149 - 0
tests/low-level/permissioning/component.ts

@@ -0,0 +1,149 @@
+import { Keypair } from "@solana/web3.js";
+import {
+  anchor,
+  FindEntityPda,
+  FindComponentPda,
+  SerializeArgs,
+} from "../../../clients/bolt-sdk/lib";
+import { assert, expect } from "chai";
+
+export function component(framework) {
+  let entity: anchor.web3.PublicKey;
+  let component: anchor.web3.PublicKey;
+
+  describe("Component authority", () => {
+    it("Add entity 5", async () => {
+      const world = await framework.worldProgram.account.world.fetch(
+        framework.worldPda,
+      );
+      entity = FindEntityPda({
+        worldId: world.id,
+        entityId: world.entities,
+      });
+      const instruction = await framework.worldProgram.methods
+        .addEntity(null)
+        .accounts({
+          payer: framework.provider.wallet.publicKey,
+          world: framework.worldPda,
+          entity: entity,
+        })
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction);
+    });
+
+    it("Initialize position component with authority on authority test entity", async () => {
+      const componentId = framework.exampleComponentPosition.programId;
+      component = FindComponentPda({
+        componentId,
+        entity: entity,
+      });
+      const instruction = await framework.worldProgram.methods
+        .initializeComponent()
+        .accounts({
+          payer: framework.provider.wallet.publicKey,
+          entity: entity,
+          data: component,
+          componentProgram: componentId,
+          authority: framework.provider.wallet.publicKey,
+        })
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction);
+    });
+
+    it("Shouldn't apply fly system on authority test entity with wrong authority", async () => {
+      const positionBefore =
+        await framework.exampleComponentPosition.account.position.fetch(
+          component,
+        );
+
+      const keypair = Keypair.generate();
+
+      const instruction = await framework.worldProgram.methods
+        .apply(SerializeArgs())
+        .accounts({
+          authority: keypair.publicKey,
+          boltSystem: framework.systemFly.programId,
+          world: framework.worldPda,
+          sessionToken: null,
+        })
+        .remainingAccounts([
+          {
+            pubkey: framework.exampleComponentPosition.programId,
+            isSigner: false,
+            isWritable: false,
+          },
+          {
+            pubkey: component,
+            isSigner: false,
+            isWritable: true,
+          },
+        ])
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+
+      try {
+        await framework.provider.sendAndConfirm(transaction, [keypair]);
+        assert.fail(
+          "Shouldn't apply fly system on authority test entity with wrong authority",
+        );
+      } catch (error) {
+        expect(error.logs.join("\n")).to.contain(
+          "Error Code: InvalidAuthority",
+        );
+      }
+
+      const positionAfter =
+        await framework.exampleComponentPosition.account.position.fetch(
+          component,
+        );
+
+      expect(positionBefore.x.toNumber()).to.equal(positionAfter.x.toNumber());
+      expect(positionBefore.y.toNumber()).to.equal(positionAfter.y.toNumber());
+      expect(positionBefore.z.toNumber()).to.equal(positionAfter.z.toNumber());
+    });
+
+    it("Apply Fly System on authority test entity should succeed with correct authority", async () => {
+      const positionBefore =
+        await framework.exampleComponentPosition.account.position.fetch(
+          component,
+        );
+
+      const instruction = await framework.worldProgram.methods
+        .apply(SerializeArgs())
+        .accounts({
+          authority: framework.provider.wallet.publicKey,
+          boltSystem: framework.systemFly.programId,
+          world: framework.worldPda,
+          sessionToken: null,
+        })
+        .remainingAccounts([
+          {
+            pubkey: framework.exampleComponentPosition.programId,
+            isSigner: false,
+            isWritable: false,
+          },
+          {
+            pubkey: component,
+            isSigner: false,
+            isWritable: true,
+          },
+        ])
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+
+      await framework.provider.sendAndConfirm(transaction);
+      const positionAfter =
+        await framework.exampleComponentPosition.account.position.fetch(
+          component,
+        );
+
+      expect(positionAfter.x.toNumber()).to.equal(positionBefore.x.toNumber());
+      expect(positionAfter.y.toNumber()).to.equal(positionBefore.y.toNumber());
+      expect(positionAfter.z.toNumber()).to.equal(
+        positionBefore.z.toNumber() + 1,
+      );
+    });
+  });
+}

+ 9 - 0
tests/low-level/permissioning/index.ts

@@ -0,0 +1,9 @@
+import { component } from "./component";
+import { world } from "./world";
+
+export function permissioning(framework) {
+  describe("Permissioning", () => {
+    component(framework);
+    world(framework);
+  });
+}

+ 237 - 0
tests/low-level/permissioning/world.ts

@@ -0,0 +1,237 @@
+import { expect } from "chai";
+import { anchor, SerializeArgs } from "../../../clients/bolt-sdk/lib";
+
+export function world(framework) {
+  describe("World authority", () => {
+    it("Add authority", async () => {
+      const instruction = await framework.worldProgram.methods
+        .addAuthority(framework.worldId)
+        .accounts({
+          authority: framework.provider.wallet.publicKey,
+          newAuthority: framework.provider.wallet.publicKey,
+          world: framework.worldPda,
+        })
+        .instruction();
+
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction, [], {
+        skipPreflight: true,
+      });
+      const worldAccount = await framework.worldProgram.account.world.fetch(
+        framework.worldPda,
+      );
+      expect(
+        worldAccount.authorities.some((auth) =>
+          auth.equals(framework.provider.wallet.publicKey),
+        ),
+      );
+    });
+
+    it("Add a second authority", async () => {
+      const instruction = await framework.worldProgram.methods
+        .addAuthority(framework.worldId)
+        .accounts({
+          authority: framework.provider.wallet.publicKey,
+          newAuthority: framework.secondAuthority,
+          world: framework.worldPda,
+        })
+        .instruction();
+
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction);
+      const worldAccount = await framework.worldProgram.account.world.fetch(
+        framework.worldPda,
+      );
+      expect(
+        worldAccount.authorities.some((auth) =>
+          auth.equals(framework.secondAuthority),
+        ),
+      );
+    });
+
+    it("Remove an authority", async () => {
+      const instruction = await framework.worldProgram.methods
+        .removeAuthority(framework.worldId)
+        .accounts({
+          authority: framework.provider.wallet.publicKey,
+          authorityToDelete: framework.secondAuthority,
+          world: framework.worldPda,
+        })
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction);
+      const worldAccount = await framework.worldProgram.account.world.fetch(
+        framework.worldPda,
+      );
+      expect(
+        !worldAccount.authorities.some((auth) =>
+          auth.equals(framework.secondAuthority),
+        ),
+      );
+    });
+
+    it("Whitelist Fly System", async () => {
+      const instruction = await framework.worldProgram.methods
+        .approveSystem()
+        .accounts({
+          authority: framework.provider.wallet.publicKey,
+          system: framework.systemFly.programId,
+          world: framework.worldPda,
+        })
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction, [], {
+        skipPreflight: true,
+      });
+
+      // Get World and check permissionless and systems
+      const worldAccount = await framework.worldProgram.account.world.fetch(
+        framework.worldPda,
+      );
+      expect(worldAccount.permissionless).to.equal(false);
+      expect(worldAccount.systems.length).to.be.greaterThan(0);
+    });
+
+    it("Whitelist Apply Velocity System system", async () => {
+      const instruction = await framework.worldProgram.methods
+        .approveSystem()
+        .accounts({
+          authority: framework.provider.wallet.publicKey,
+          system: framework.systemApplyVelocity.programId,
+          world: framework.worldPda,
+        })
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction, [], {
+        skipPreflight: true,
+      });
+
+      // Get World and check permissionless and systems
+      const worldAccount = await framework.worldProgram.account.world.fetch(
+        framework.worldPda,
+      );
+      expect(worldAccount.permissionless).to.equal(false);
+      expect(worldAccount.systems.length).to.be.greaterThan(0);
+    });
+
+    it("Apply Fly System on Entity 1", async () => {
+      const instruction = await framework.worldProgram.methods
+        .apply(SerializeArgs())
+        .accounts({
+          authority: framework.provider.wallet.publicKey,
+          boltSystem: framework.systemFly.programId,
+          world: framework.worldPda,
+          sessionToken: null,
+        })
+        .remainingAccounts([
+          {
+            pubkey: framework.exampleComponentPosition.programId,
+            isSigner: false,
+            isWritable: false,
+          },
+          {
+            pubkey: framework.componentPositionEntity1Pda,
+            isSigner: false,
+            isWritable: true,
+          },
+        ])
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction);
+    });
+
+    it("Remove Fly System", async () => {
+      const instruction = await framework.worldProgram.methods
+        .removeSystem()
+        .accounts({
+          authority: framework.provider.wallet.publicKey,
+          system: framework.systemFly.programId,
+          world: framework.worldPda,
+        })
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction, [], {
+        skipPreflight: true,
+      });
+
+      // Get World and check permissionless and systems
+      const worldAccount = await framework.worldProgram.account.world.fetch(
+        framework.worldPda,
+      );
+      expect(worldAccount.permissionless).to.equal(false);
+      expect(worldAccount.systems.length).to.be.greaterThan(0);
+    });
+
+    it("Apply unauthorized Fly System on Entity 1", async () => {
+      const instruction = await framework.worldProgram.methods
+        .apply(SerializeArgs())
+        .accounts({
+          authority: framework.provider.wallet.publicKey,
+          boltSystem: framework.systemFly.programId,
+          world: framework.worldPda,
+          sessionToken: null,
+        })
+        .remainingAccounts([
+          {
+            pubkey: framework.exampleComponentPosition.programId,
+            isSigner: false,
+            isWritable: false,
+          },
+          {
+            pubkey: framework.componentPositionEntity1Pda,
+            isSigner: false,
+            isWritable: true,
+          },
+        ])
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      let invalid = false;
+      try {
+        await framework.provider.sendAndConfirm(transaction);
+      } catch (error) {
+        expect(error.logs.join(" ")).to.contain(
+          "Error Code: SystemNotApproved",
+        );
+        invalid = true;
+      }
+      expect(invalid).to.equal(true);
+    });
+
+    it("Check invalid component init without CPI", async () => {
+      let invalid = false;
+      try {
+        await framework.exampleComponentPosition.methods
+          .initialize()
+          .accounts({
+            payer: framework.provider.wallet.publicKey,
+            data: framework.componentPositionEntity1Pda,
+            entity: framework.entity1Pda,
+            authority: framework.provider.wallet.publicKey,
+          })
+          .rpc();
+      } catch (error) {
+        expect(error.message).to.contain("Error Code: InvalidCaller");
+        invalid = true;
+      }
+      expect(invalid).to.equal(true);
+    });
+
+    it("Check invalid component update without CPI", async () => {
+      let invalid = false;
+      try {
+        await framework.exampleComponentPosition.methods
+          .update(Buffer.from(""))
+          .accounts({
+            boltComponent: framework.componentPositionEntity4Pda,
+            authority: framework.provider.wallet.publicKey,
+            sessionToken: null,
+          })
+          .rpc();
+      } catch (error) {
+        expect(error.message).to.contain("Error Code: InvalidCaller");
+        invalid = true;
+      }
+      expect(invalid).to.equal(true);
+    });
+  });
+}

+ 212 - 0
tests/low-level/session.ts

@@ -0,0 +1,212 @@
+import { expect } from "chai";
+import {
+  anchor,
+  FindComponentPda,
+  FindEntityPda,
+  SerializeArgs,
+  SessionProgram,
+  FindSessionTokenPda,
+  BN,
+} from "../../clients/bolt-sdk/lib";
+import { Keypair } from "@solana/web3.js";
+
+export function session(framework) {
+  describe("Session", () => {
+    const sessionSigner: Keypair = Keypair.generate();
+    let sessionToken: anchor.web3.PublicKey;
+    let entity: anchor.web3.PublicKey;
+    let component: anchor.web3.PublicKey;
+    let entityWithAuthority: anchor.web3.PublicKey;
+    let componentWithAuthority: anchor.web3.PublicKey;
+
+    it("Create Session", async () => {
+      sessionToken = FindSessionTokenPda({
+        sessionSigner: sessionSigner.publicKey,
+        authority: framework.provider.wallet.publicKey,
+      });
+      let instruction = await SessionProgram.methods
+        .createSession(true, null, new BN(1000000000))
+        .accounts({
+          sessionSigner: sessionSigner.publicKey,
+          authority: framework.provider.wallet.publicKey,
+          targetProgram: framework.worldProgram.programId,
+          sessionToken,
+        })
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction, [sessionSigner]);
+    });
+
+    it("Add entity", async () => {
+      const world = await framework.worldProgram.account.world.fetch(
+        framework.worldPda,
+      );
+      entity = FindEntityPda({
+        worldId: world.id,
+        entityId: world.entities,
+      });
+      const instruction = await framework.worldProgram.methods
+        .addEntity(null)
+        .accounts({
+          payer: sessionSigner.publicKey,
+          entity: entity,
+          world: framework.worldPda,
+        })
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction, [sessionSigner]);
+    });
+
+    it("Initialize position component", async () => {
+      const componentId = framework.exampleComponentPosition.programId;
+      component = FindComponentPda({
+        componentId,
+        entity,
+      });
+      const instruction = await framework.worldProgram.methods
+        .initializeComponent()
+        .accounts({
+          payer: sessionSigner.publicKey,
+          entity: entity,
+          data: component,
+          componentProgram: componentId,
+          authority: framework.worldProgram.programId,
+        })
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction, [sessionSigner]);
+    });
+
+    it("Apply Fly System on component using session token", async () => {
+      const positionBefore =
+        await framework.exampleComponentPosition.account.position.fetch(
+          component,
+        );
+
+      const instruction = await framework.worldProgram.methods
+        .apply(SerializeArgs())
+        .accounts({
+          authority: sessionSigner.publicKey,
+          boltSystem: framework.systemFly.programId,
+          world: framework.worldPda,
+          sessionToken,
+        })
+        .remainingAccounts([
+          {
+            pubkey: framework.exampleComponentPosition.programId,
+            isSigner: false,
+            isWritable: false,
+          },
+          {
+            pubkey: component,
+            isSigner: false,
+            isWritable: true,
+          },
+        ])
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+
+      let signature = await framework.provider.connection.sendTransaction(
+        transaction,
+        [sessionSigner],
+      );
+      await framework.provider.connection.confirmTransaction(signature);
+      const positionAfter =
+        await framework.exampleComponentPosition.account.position.fetch(
+          component,
+        );
+
+      expect(positionAfter.x.toNumber()).to.equal(positionBefore.x.toNumber());
+      expect(positionAfter.y.toNumber()).to.equal(positionBefore.y.toNumber());
+      expect(positionAfter.z.toNumber()).to.equal(
+        positionBefore.z.toNumber() + 1,
+      );
+    });
+
+    it("Add entity for authority test", async () => {
+      const world = await framework.worldProgram.account.world.fetch(
+        framework.worldPda,
+      );
+      entityWithAuthority = FindEntityPda({
+        worldId: world.id,
+        entityId: world.entities,
+      });
+      const instruction = await framework.worldProgram.methods
+        .addEntity(null)
+        .accounts({
+          payer: sessionSigner.publicKey,
+          world: framework.worldPda,
+          entity: entityWithAuthority,
+        })
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction, [sessionSigner]);
+    });
+
+    it("Initialize position component with authority", async () => {
+      const componentId = framework.exampleComponentPosition.programId;
+      componentWithAuthority = FindComponentPda({
+        componentId,
+        entity: entityWithAuthority,
+      });
+      const instruction = await framework.worldProgram.methods
+        .initializeComponent()
+        .accounts({
+          payer: sessionSigner.publicKey,
+          entity: entityWithAuthority,
+          data: componentWithAuthority,
+          componentProgram: componentId,
+          authority: framework.provider.wallet.publicKey,
+        })
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction, [sessionSigner]);
+    });
+
+    it("Apply Fly System on component with authority using session token", async () => {
+      const positionBefore =
+        await framework.exampleComponentPosition.account.position.fetch(
+          componentWithAuthority,
+        );
+
+      const instruction = await framework.worldProgram.methods
+        .apply(SerializeArgs())
+        .accounts({
+          authority: sessionSigner.publicKey,
+          boltSystem: framework.systemFly.programId,
+          world: framework.worldPda,
+          sessionToken,
+        })
+        .remainingAccounts([
+          {
+            pubkey: framework.exampleComponentPosition.programId,
+            isSigner: false,
+            isWritable: false,
+          },
+          {
+            pubkey: componentWithAuthority,
+            isSigner: false,
+            isWritable: true,
+          },
+        ])
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+
+      let signature = await framework.provider.connection.sendTransaction(
+        transaction,
+        [sessionSigner],
+      );
+      await framework.provider.connection.confirmTransaction(signature);
+      const positionAfter =
+        await framework.exampleComponentPosition.account.position.fetch(
+          componentWithAuthority,
+        );
+
+      expect(positionAfter.x.toNumber()).to.equal(positionBefore.x.toNumber());
+      expect(positionAfter.y.toNumber()).to.equal(positionBefore.y.toNumber());
+      expect(positionAfter.z.toNumber()).to.equal(
+        positionBefore.z.toNumber() + 1,
+      );
+    });
+  });
+}

+ 59 - 0
tests/low-level/world.ts

@@ -0,0 +1,59 @@
+import {
+  anchor,
+  FindRegistryPda,
+  FindWorldPda,
+  BN,
+} from "../../clients/bolt-sdk/lib";
+
+export function world(framework) {
+  describe("World", () => {
+    it("Initialize registry", async () => {
+      const registryPda = FindRegistryPda({});
+      const instruction = await framework.worldProgram.methods
+        .initializeRegistry()
+        .accounts({
+          registry: registryPda,
+          payer: framework.provider.wallet.publicKey,
+        })
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction);
+    });
+
+    it("Initialize world", async () => {
+      const registryPda = FindRegistryPda({});
+      const registry =
+        await framework.worldProgram.account.registry.fetch(registryPda);
+      framework.worldId = new BN(registry.worlds);
+      framework.worldPda = FindWorldPda({ worldId: framework.worldId });
+      const instruction = await framework.worldProgram.methods
+        .initializeNewWorld()
+        .accounts({
+          payer: framework.provider.wallet.publicKey,
+          world: framework.worldPda,
+          registry: registryPda,
+        })
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction);
+    });
+
+    it("Initialize second world", async () => {
+      const registryPda = FindRegistryPda({});
+      const registry =
+        await framework.worldProgram.account.registry.fetch(registryPda);
+      const worldId = new BN(registry.worlds);
+      const worldPda = FindWorldPda({ worldId });
+      const instruction = await framework.worldProgram.methods
+        .initializeNewWorld()
+        .accounts({
+          payer: framework.provider.wallet.publicKey,
+          world: worldPda,
+          registry: registryPda,
+        })
+        .instruction();
+      const transaction = new anchor.web3.Transaction().add(instruction);
+      await framework.provider.sendAndConfirm(transaction);
+    });
+  });
+}

+ 2 - 0
tests/main.ts

@@ -0,0 +1,2 @@
+import "./low-level";
+import "./intermediate-level";