Эх сурвалжийг харах

✨ Variable components number (#124)

Danilo Guanabara 9 сар өмнө
parent
commit
ea1de62983

+ 0 - 2
.github/workflows/publish-bolt-crates.yml

@@ -199,8 +199,6 @@ jobs:
           cargo publish $DRY_RUN_FLAG --manifest-path=crates/bolt-lang/attribute/arguments/Cargo.toml --token $CRATES_TOKEN $NO_VERIFY_FLAG
           cargo publish $DRY_RUN_FLAG --manifest-path=crates/bolt-lang/attribute/bolt-program/Cargo.toml --token $CRATES_TOKEN $NO_VERIFY_FLAG
           cargo publish $DRY_RUN_FLAG --manifest-path=crates/bolt-lang/attribute/delegate/Cargo.toml --token $CRATES_TOKEN $NO_VERIFY_FLAG
-          cargo publish $DRY_RUN_FLAG --manifest-path=crates/bolt-helpers/attribute/system-template/Cargo.toml --token $CRATES_TOKEN $NO_VERIFY_FLAG
-          cargo publish $DRY_RUN_FLAG --manifest-path=crates/bolt-helpers/attribute/world-apply/Cargo.toml --token $CRATES_TOKEN $NO_VERIFY_FLAG
           cargo publish $DRY_RUN_FLAG --manifest-path=crates/programs/bolt-system/Cargo.toml --token $CRATES_TOKEN $NO_VERIFY_FLAG
           cargo publish $DRY_RUN_FLAG --manifest-path=crates/programs/bolt-component/Cargo.toml --token $CRATES_TOKEN $NO_VERIFY_FLAG
           cargo publish $DRY_RUN_FLAG --manifest-path=crates/programs/world/Cargo.toml --token $CRATES_TOKEN $NO_VERIFY_FLAG

+ 2 - 26
Cargo.lock

@@ -1039,10 +1039,6 @@ dependencies = [
  "bolt-system 0.2.0",
 ]
 
-[[package]]
-name = "bolt-helpers"
-version = "0.0.1"
-
 [[package]]
 name = "bolt-helpers-system-template"
 version = "0.1.9"
@@ -1054,15 +1050,6 @@ dependencies = [
  "syn 1.0.109",
 ]
 
-[[package]]
-name = "bolt-helpers-system-template"
-version = "0.2.0"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
 [[package]]
 name = "bolt-helpers-world-apply"
 version = "0.1.9"
@@ -1074,15 +1061,6 @@ dependencies = [
  "syn 1.0.109",
 ]
 
-[[package]]
-name = "bolt-helpers-world-apply"
-version = "0.2.0"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
 [[package]]
 name = "bolt-lang"
 version = "0.1.9"
@@ -1136,7 +1114,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "465c09a5325776f50a1711aa7c1cc91a0cba91d0922658509e0f465119db49ba"
 dependencies = [
  "anchor-lang",
- "bolt-helpers-system-template 0.1.9",
+ "bolt-helpers-system-template",
 ]
 
 [[package]]
@@ -1144,7 +1122,6 @@ name = "bolt-system"
 version = "0.2.0"
 dependencies = [
  "anchor-lang",
- "bolt-helpers-system-template 0.2.0",
 ]
 
 [[package]]
@@ -6614,7 +6591,7 @@ checksum = "1d7064174d4ffb7bc2ebbd89516fbc09992820386d59176fe612c5ce4d605874"
 dependencies = [
  "anchor-lang",
  "bolt-component 0.1.9",
- "bolt-helpers-world-apply 0.1.9",
+ "bolt-helpers-world-apply",
  "bolt-system 0.1.9",
  "solana-security-txt",
  "tuple-conv",
@@ -6626,7 +6603,6 @@ version = "0.2.0"
 dependencies = [
  "anchor-lang",
  "bolt-component 0.2.0",
- "bolt-helpers-world-apply 0.2.0",
  "bolt-system 0.2.0",
  "solana-security-txt",
  "tuple-conv",

+ 0 - 3
Cargo.toml

@@ -3,7 +3,6 @@ resolver = "2"
 members = [
     "crates/bolt-cli",
     "crates/bolt-lang",
-    "crates/bolt-helpers",
     "crates/programs/bolt-component",
     "crates/programs/bolt-system",
     "crates/programs/world",
@@ -29,8 +28,6 @@ bolt-attribute-bolt-extra-accounts = { path = "crates/bolt-lang/attribute/extra-
 bolt-attribute-bolt-arguments = { path = "crates/bolt-lang/attribute/arguments", version = "=0.2.0" }
 bolt-attribute-bolt-component-deserialize = { path = "crates/bolt-lang/attribute/component-deserialize", version = "=0.2.0" }
 bolt-attribute-bolt-component-id = { path = "crates/bolt-lang/attribute/component-id", version = "=0.2.0" }
-bolt-helpers-system-template = { path = "crates/bolt-helpers/attribute/system-template", version = "=0.2.0" }
-bolt-helpers-world-apply = { path = "crates/bolt-helpers/attribute/world-apply", version = "=0.2.0" }
 bolt-utils = { path = "crates/bolt-lang/utils", version = "=0.2.0" }
 world = { path = "crates/programs/world", features = ["cpi"], version = "=0.2.0"}
 bolt-system = { path = "crates/programs/bolt-system", features = ["cpi"], version = "=0.2.0"}

+ 0 - 254
clients/bolt-sdk/idl/world.json

@@ -125,266 +125,12 @@
     },
     {
       "name": "apply",
-      "accounts": [
-        {
-          "name": "componentProgram",
-          "isMut": false,
-          "isSigner": false
-        },
-        {
-          "name": "boltSystem",
-          "isMut": false,
-          "isSigner": false
-        },
-        {
-          "name": "boltComponent",
-          "isMut": true,
-          "isSigner": false
-        },
-        {
-          "name": "authority",
-          "isMut": false,
-          "isSigner": false
-        },
-        {
-          "name": "instructionSysvarAccount",
-          "isMut": false,
-          "isSigner": false
-        }
-      ],
-      "args": [
-        {
-          "name": "args",
-          "type": "bytes"
-        }
-      ]
-    },
-    {
-      "name": "apply2",
       "accounts": [
         {
           "name": "boltSystem",
           "isMut": false,
           "isSigner": false
         },
-        {
-          "name": "componentProgram1",
-          "isMut": false,
-          "isSigner": false
-        },
-        {
-          "name": "boltComponent1",
-          "isMut": true,
-          "isSigner": false
-        },
-        {
-          "name": "componentProgram2",
-          "isMut": false,
-          "isSigner": false
-        },
-        {
-          "name": "boltComponent2",
-          "isMut": true,
-          "isSigner": false
-        },
-        {
-          "name": "authority",
-          "isMut": false,
-          "isSigner": false
-        },
-        {
-          "name": "instructionSysvarAccount",
-          "isMut": false,
-          "isSigner": false
-        }
-      ],
-      "args": [
-        {
-          "name": "args",
-          "type": "bytes"
-        }
-      ]
-    },
-    {
-      "name": "apply3",
-      "accounts": [
-        {
-          "name": "boltSystem",
-          "isMut": false,
-          "isSigner": false
-        },
-        {
-          "name": "componentProgram1",
-          "isMut": false,
-          "isSigner": false
-        },
-        {
-          "name": "boltComponent1",
-          "isMut": true,
-          "isSigner": false
-        },
-        {
-          "name": "componentProgram2",
-          "isMut": false,
-          "isSigner": false
-        },
-        {
-          "name": "boltComponent2",
-          "isMut": true,
-          "isSigner": false
-        },
-        {
-          "name": "componentProgram3",
-          "isMut": false,
-          "isSigner": false
-        },
-        {
-          "name": "boltComponent3",
-          "isMut": true,
-          "isSigner": false
-        },
-        {
-          "name": "authority",
-          "isMut": false,
-          "isSigner": false
-        },
-        {
-          "name": "instructionSysvarAccount",
-          "isMut": false,
-          "isSigner": false
-        }
-      ],
-      "args": [
-        {
-          "name": "args",
-          "type": "bytes"
-        }
-      ]
-    },
-    {
-      "name": "apply4",
-      "accounts": [
-        {
-          "name": "boltSystem",
-          "isMut": false,
-          "isSigner": false
-        },
-        {
-          "name": "componentProgram1",
-          "isMut": false,
-          "isSigner": false
-        },
-        {
-          "name": "boltComponent1",
-          "isMut": true,
-          "isSigner": false
-        },
-        {
-          "name": "componentProgram2",
-          "isMut": false,
-          "isSigner": false
-        },
-        {
-          "name": "boltComponent2",
-          "isMut": true,
-          "isSigner": false
-        },
-        {
-          "name": "componentProgram3",
-          "isMut": false,
-          "isSigner": false
-        },
-        {
-          "name": "boltComponent3",
-          "isMut": true,
-          "isSigner": false
-        },
-        {
-          "name": "componentProgram4",
-          "isMut": false,
-          "isSigner": false
-        },
-        {
-          "name": "boltComponent4",
-          "isMut": true,
-          "isSigner": false
-        },
-        {
-          "name": "authority",
-          "isMut": false,
-          "isSigner": false
-        },
-        {
-          "name": "instructionSysvarAccount",
-          "isMut": false,
-          "isSigner": false
-        }
-      ],
-      "args": [
-        {
-          "name": "args",
-          "type": "bytes"
-        }
-      ]
-    },
-    {
-      "name": "apply5",
-      "accounts": [
-        {
-          "name": "boltSystem",
-          "isMut": false,
-          "isSigner": false
-        },
-        {
-          "name": "componentProgram1",
-          "isMut": false,
-          "isSigner": false
-        },
-        {
-          "name": "boltComponent1",
-          "isMut": true,
-          "isSigner": false
-        },
-        {
-          "name": "componentProgram2",
-          "isMut": false,
-          "isSigner": false
-        },
-        {
-          "name": "boltComponent2",
-          "isMut": true,
-          "isSigner": false
-        },
-        {
-          "name": "componentProgram3",
-          "isMut": false,
-          "isSigner": false
-        },
-        {
-          "name": "boltComponent3",
-          "isMut": true,
-          "isSigner": false
-        },
-        {
-          "name": "componentProgram4",
-          "isMut": false,
-          "isSigner": false
-        },
-        {
-          "name": "boltComponent4",
-          "isMut": true,
-          "isSigner": false
-        },
-        {
-          "name": "componentProgram5",
-          "isMut": false,
-          "isSigner": false
-        },
-        {
-          "name": "boltComponent5",
-          "isMut": true,
-          "isSigner": false
-        },
         {
           "name": "authority",
           "isMut": false,

+ 8 - 248
clients/bolt-sdk/src/generated/idl/world.json

@@ -97,255 +97,10 @@
         162,
         225
       ],
-      "accounts": [
-        {
-          "name": "component_program"
-        },
-        {
-          "name": "bolt_system"
-        },
-        {
-          "name": "bolt_component",
-          "writable": true
-        },
-        {
-          "name": "authority",
-          "signer": true
-        },
-        {
-          "name": "instruction_sysvar_account",
-          "address": "Sysvar1nstructions1111111111111111111111111"
-        },
-        {
-          "name": "world"
-        }
-      ],
-      "args": [
-        {
-          "name": "args",
-          "type": "bytes"
-        }
-      ]
-    },
-    {
-      "name": "apply2",
-      "discriminator": [
-        120,
-        32,
-        116,
-        154,
-        158,
-        159,
-        208,
-        73
-      ],
-      "accounts": [
-        {
-          "name": "bolt_system"
-        },
-        {
-          "name": "component_program_1"
-        },
-        {
-          "name": "bolt_component_1",
-          "writable": true
-        },
-        {
-          "name": "component_program_2"
-        },
-        {
-          "name": "bolt_component_2",
-          "writable": true
-        },
-        {
-          "name": "authority",
-          "signer": true
-        },
-        {
-          "name": "instruction_sysvar_account",
-          "address": "Sysvar1nstructions1111111111111111111111111"
-        },
-        {
-          "name": "world"
-        }
-      ],
-      "args": [
-        {
-          "name": "args",
-          "type": "bytes"
-        }
-      ]
-    },
-    {
-      "name": "apply3",
-      "discriminator": [
-        254,
-        146,
-        49,
-        7,
-        236,
-        131,
-        105,
-        221
-      ],
-      "accounts": [
-        {
-          "name": "bolt_system"
-        },
-        {
-          "name": "component_program_1"
-        },
-        {
-          "name": "bolt_component_1",
-          "writable": true
-        },
-        {
-          "name": "component_program_2"
-        },
-        {
-          "name": "bolt_component_2",
-          "writable": true
-        },
-        {
-          "name": "component_program_3"
-        },
-        {
-          "name": "bolt_component_3",
-          "writable": true
-        },
-        {
-          "name": "authority",
-          "signer": true
-        },
-        {
-          "name": "instruction_sysvar_account",
-          "address": "Sysvar1nstructions1111111111111111111111111"
-        },
-        {
-          "name": "world"
-        }
-      ],
-      "args": [
-        {
-          "name": "args",
-          "type": "bytes"
-        }
-      ]
-    },
-    {
-      "name": "apply4",
-      "discriminator": [
-        223,
-        104,
-        24,
-        79,
-        252,
-        196,
-        14,
-        109
-      ],
-      "accounts": [
-        {
-          "name": "bolt_system"
-        },
-        {
-          "name": "component_program_1"
-        },
-        {
-          "name": "bolt_component_1",
-          "writable": true
-        },
-        {
-          "name": "component_program_2"
-        },
-        {
-          "name": "bolt_component_2",
-          "writable": true
-        },
-        {
-          "name": "component_program_3"
-        },
-        {
-          "name": "bolt_component_3",
-          "writable": true
-        },
-        {
-          "name": "component_program_4"
-        },
-        {
-          "name": "bolt_component_4",
-          "writable": true
-        },
-        {
-          "name": "authority",
-          "signer": true
-        },
-        {
-          "name": "instruction_sysvar_account",
-          "address": "Sysvar1nstructions1111111111111111111111111"
-        },
-        {
-          "name": "world"
-        }
-      ],
-      "args": [
-        {
-          "name": "args",
-          "type": "bytes"
-        }
-      ]
-    },
-    {
-      "name": "apply5",
-      "discriminator": [
-        70,
-        164,
-        214,
-        28,
-        136,
-        116,
-        84,
-        153
-      ],
       "accounts": [
         {
           "name": "bolt_system"
         },
-        {
-          "name": "component_program_1"
-        },
-        {
-          "name": "bolt_component_1",
-          "writable": true
-        },
-        {
-          "name": "component_program_2"
-        },
-        {
-          "name": "bolt_component_2",
-          "writable": true
-        },
-        {
-          "name": "component_program_3"
-        },
-        {
-          "name": "bolt_component_3",
-          "writable": true
-        },
-        {
-          "name": "component_program_4"
-        },
-        {
-          "name": "bolt_component_4",
-          "writable": true
-        },
-        {
-          "name": "component_program_5"
-        },
-        {
-          "name": "bolt_component_5",
-          "writable": true
-        },
         {
           "name": "authority",
           "signer": true
@@ -620,21 +375,26 @@
     },
     {
       "code": 6001,
+      "name": "InvalidSystemOutput",
+      "msg": "Invalid system output"
+    },
+    {
+      "code": 6002,
       "name": "WorldAccountMismatch",
       "msg": "The provided world account does not match the expected PDA."
     },
     {
-      "code": 6002,
+      "code": 6003,
       "name": "TooManyAuthorities",
       "msg": "Exceed the maximum number of authorities."
     },
     {
-      "code": 6003,
+      "code": 6004,
       "name": "AuthorityNotFound",
       "msg": "The provided authority not found"
     },
     {
-      "code": 6004,
+      "code": 6005,
       "name": "SystemNotApproved",
       "msg": "The system is not approved in this world instance"
     }

+ 8 - 212
clients/bolt-sdk/src/generated/types/world.ts

@@ -76,219 +76,10 @@ export type World = {
     {
       name: "apply";
       discriminator: [248, 243, 145, 24, 105, 50, 162, 225];
-      accounts: [
-        {
-          name: "componentProgram";
-        },
-        {
-          name: "boltSystem";
-        },
-        {
-          name: "boltComponent";
-          writable: true;
-        },
-        {
-          name: "authority";
-          signer: true;
-        },
-        {
-          name: "instructionSysvarAccount";
-          address: "Sysvar1nstructions1111111111111111111111111";
-        },
-        {
-          name: "world";
-        },
-      ];
-      args: [
-        {
-          name: "args";
-          type: "bytes";
-        },
-      ];
-    },
-    {
-      name: "apply2";
-      discriminator: [120, 32, 116, 154, 158, 159, 208, 73];
-      accounts: [
-        {
-          name: "boltSystem";
-        },
-        {
-          name: "componentProgram1";
-        },
-        {
-          name: "boltComponent1";
-          writable: true;
-        },
-        {
-          name: "componentProgram2";
-        },
-        {
-          name: "boltComponent2";
-          writable: true;
-        },
-        {
-          name: "authority";
-          signer: true;
-        },
-        {
-          name: "instructionSysvarAccount";
-          address: "Sysvar1nstructions1111111111111111111111111";
-        },
-        {
-          name: "world";
-        },
-      ];
-      args: [
-        {
-          name: "args";
-          type: "bytes";
-        },
-      ];
-    },
-    {
-      name: "apply3";
-      discriminator: [254, 146, 49, 7, 236, 131, 105, 221];
-      accounts: [
-        {
-          name: "boltSystem";
-        },
-        {
-          name: "componentProgram1";
-        },
-        {
-          name: "boltComponent1";
-          writable: true;
-        },
-        {
-          name: "componentProgram2";
-        },
-        {
-          name: "boltComponent2";
-          writable: true;
-        },
-        {
-          name: "componentProgram3";
-        },
-        {
-          name: "boltComponent3";
-          writable: true;
-        },
-        {
-          name: "authority";
-          signer: true;
-        },
-        {
-          name: "instructionSysvarAccount";
-          address: "Sysvar1nstructions1111111111111111111111111";
-        },
-        {
-          name: "world";
-        },
-      ];
-      args: [
-        {
-          name: "args";
-          type: "bytes";
-        },
-      ];
-    },
-    {
-      name: "apply4";
-      discriminator: [223, 104, 24, 79, 252, 196, 14, 109];
-      accounts: [
-        {
-          name: "boltSystem";
-        },
-        {
-          name: "componentProgram1";
-        },
-        {
-          name: "boltComponent1";
-          writable: true;
-        },
-        {
-          name: "componentProgram2";
-        },
-        {
-          name: "boltComponent2";
-          writable: true;
-        },
-        {
-          name: "componentProgram3";
-        },
-        {
-          name: "boltComponent3";
-          writable: true;
-        },
-        {
-          name: "componentProgram4";
-        },
-        {
-          name: "boltComponent4";
-          writable: true;
-        },
-        {
-          name: "authority";
-          signer: true;
-        },
-        {
-          name: "instructionSysvarAccount";
-          address: "Sysvar1nstructions1111111111111111111111111";
-        },
-        {
-          name: "world";
-        },
-      ];
-      args: [
-        {
-          name: "args";
-          type: "bytes";
-        },
-      ];
-    },
-    {
-      name: "apply5";
-      discriminator: [70, 164, 214, 28, 136, 116, 84, 153];
       accounts: [
         {
           name: "boltSystem";
         },
-        {
-          name: "componentProgram1";
-        },
-        {
-          name: "boltComponent1";
-          writable: true;
-        },
-        {
-          name: "componentProgram2";
-        },
-        {
-          name: "boltComponent2";
-          writable: true;
-        },
-        {
-          name: "componentProgram3";
-        },
-        {
-          name: "boltComponent3";
-          writable: true;
-        },
-        {
-          name: "componentProgram4";
-        },
-        {
-          name: "boltComponent4";
-          writable: true;
-        },
-        {
-          name: "componentProgram5";
-        },
-        {
-          name: "boltComponent5";
-          writable: true;
-        },
         {
           name: "authority";
           signer: true;
@@ -482,21 +273,26 @@ export type World = {
     },
     {
       code: 6001;
+      name: "invalidSystemOutput";
+      msg: "Invalid system output";
+    },
+    {
+      code: 6002;
       name: "worldAccountMismatch";
       msg: "The provided world account does not match the expected PDA.";
     },
     {
-      code: 6002;
+      code: 6003;
       name: "tooManyAuthorities";
       msg: "Exceed the maximum number of authorities.";
     },
     {
-      code: 6003;
+      code: 6004;
       name: "authorityNotFound";
       msg: "The provided authority not found";
     },
     {
-      code: 6004;
+      code: 6005;
       name: "systemNotApproved";
       msg: "The system is not approved in this world instance";
     },

+ 35 - 32
clients/bolt-sdk/src/world/transactions.ts

@@ -28,8 +28,6 @@ import {
 } from "../generated";
 import { type Idl, Program } from "@coral-xyz/anchor";
 
-const MAX_COMPONENTS = 5;
-
 export async function InitializeRegistry({
   payer,
   connection,
@@ -342,17 +340,6 @@ interface ApplySystemInstruction {
   extraAccounts?: web3.AccountMeta[];
   args?: object;
 }
-function getApplyInstructionFunctionName(componentsCount: number) {
-  return `apply${componentsCount > 1 ? componentsCount : ""}`;
-}
-function getBoltComponentName(index: number, componentsCount: number) {
-  if (componentsCount === 1) return "boltComponent";
-  return `boltComponent${index + 1}`;
-}
-function getBoltComponentProgramName(index: number, componentsCount: number) {
-  if (componentsCount === 1) return "componentProgram";
-  return `componentProgram${index + 1}`;
-}
 async function createApplySystemInstruction({
   authority,
   systemId,
@@ -371,11 +358,6 @@ async function createApplySystemInstruction({
   if (componentCount <= 0) {
     throw new Error("No components provided");
   }
-  if (componentCount > MAX_COMPONENTS) {
-    throw new Error(
-      `Not implemented for component counts outside 1-${MAX_COMPONENTS}`,
-    );
-  }
 
   const applyAccounts = {
     authority: authority ?? PROGRAM_ID,
@@ -383,27 +365,48 @@ async function createApplySystemInstruction({
     world,
   };
 
-  let componentIndex = 0;
-  entities.forEach(function (entity) {
-    entity.components.forEach(function (component) {
+  let remainingAccounts: web3.AccountMeta[] = [];
+  let components: { id: PublicKey; pda: PublicKey }[] = [];
+  for (const entity of entities) {
+    for (const component of entity.components) {
       const componentPda = FindComponentPda({
         componentId: component.componentId,
         entity: entity.entity,
         seed: component.seed,
       });
-      applyAccounts[
-        getBoltComponentProgramName(componentIndex, componentCount)
-      ] = component.componentId;
-      applyAccounts[getBoltComponentName(componentIndex, componentCount)] =
-        componentPda;
-      componentIndex++;
+      components.push({
+        id: component.componentId,
+        pda: componentPda,
+      });
+    }
+  }
+  for (const component of components) {
+    remainingAccounts.push({
+      pubkey: component.id,
+      isSigner: false,
+      isWritable: false,
     });
-  });
-  return program.methods[getApplyInstructionFunctionName(componentCount)](
-    SerializeArgs(args),
-  )
+    remainingAccounts.push({
+      pubkey: component.pda,
+      isSigner: false,
+      isWritable: true,
+    });
+  }
+  let extraAccountsInput = extraAccounts ?? [];
+  if (extraAccountsInput.length > 0) {
+    remainingAccounts.push({
+      pubkey: program.programId, // program id delimits the end of the component list
+      isSigner: false,
+      isWritable: false,
+    });
+    for (const account of extraAccountsInput) {
+      remainingAccounts.push(account);
+    }
+  }
+  return program.methods
+    .apply(SerializeArgs(args))
     .accounts(applyAccounts)
-    .remainingAccounts(extraAccounts ?? [])
+    .remainingAccounts(remainingAccounts)
     .instruction();
 }
 

+ 0 - 6
crates/bolt-helpers/Cargo.toml

@@ -1,6 +0,0 @@
-[package]
-name = "bolt-helpers"
-version = "0.0.1"
-edition = "2021"
-
-[dependencies]

+ 0 - 17
crates/bolt-helpers/attribute/system-template/Cargo.toml

@@ -1,17 +0,0 @@
-[package]
-name = "bolt-helpers-system-template"
-description = "A template helper for the bolt system"
-version = { workspace = true }
-authors = { workspace = true }
-repository = { workspace = true }
-homepage = { workspace = true }
-license = { workspace = true }
-edition = { workspace = true }
-
-[lib]
-proc-macro = true
-
-[dependencies]
-proc-macro2 = { workspace = true }
-quote = { workspace = true }
-syn = { workspace = true }

+ 0 - 90
crates/bolt-helpers/attribute/system-template/src/lib.rs

@@ -1,90 +0,0 @@
-extern crate proc_macro;
-
-use proc_macro::TokenStream;
-use quote::quote;
-use syn::parse::{Parse, ParseStream, Result};
-use syn::{parse_macro_input, Ident, LitInt, Token};
-
-/// This macro attribute is a helper used for defining BOLT systems execute proxy instructions.
-#[proc_macro_attribute]
-pub fn system_template(attr: TokenStream, item: TokenStream) -> TokenStream {
-    let attr_p = parse_macro_input!(attr as SystemTemplateInput);
-
-    let max_components = attr_p.max_components;
-
-    // Parse the original module content
-    let mut input: syn::ItemMod = syn::parse(item).expect("Failed to parse input module");
-
-    // Generate a function for execute instruction
-    let funcs = (2..=max_components).map(|i| {
-        let func_name = syn::Ident::new(&format!("execute_{}", i), proc_macro2::Span::call_site());
-        let data_struct = syn::Ident::new(&format!("SetData{}", i), proc_macro2::Span::call_site());
-        let return_values = vec![quote!(Vec::<u8>::new()); i];
-        let return_types = vec![quote!(Vec<u8>); i];
-        quote! {
-            pub fn #func_name(_ctx: Context<#data_struct>, _args: Vec<u8>) -> Result<(#(#return_types),*)> {
-                Ok((#(#return_values),*))
-            }
-        }
-    });
-
-    // Append each generated function to the module's items
-    if let Some((brace, mut content)) = input.content.take() {
-        for func in funcs {
-            let parsed_func: syn::Item =
-                syn::parse2(func).expect("Failed to parse generated function");
-            content.push(parsed_func);
-        }
-
-        input.content = Some((brace, content));
-    }
-
-    let data_def = (2..=max_components).map(|i| {
-        let data_struct = syn::Ident::new(&format!("SetData{}", i), proc_macro2::Span::call_site());
-        let fields = (1..=i).map(|n| {
-            let field_name =
-                syn::Ident::new(&format!("component{}", n), proc_macro2::Span::call_site());
-            quote! {
-                #[account()]
-                /// CHECK: unchecked account
-                pub #field_name: UncheckedAccount<'info>,
-            }
-        });
-        let struct_def = quote! {
-            #[derive(Accounts)]
-            pub struct #data_struct<'info> {
-                #(#fields)*
-                #[account()]
-                pub authority: Signer<'info>,
-            }
-        };
-        quote! {
-            #struct_def
-        }
-    });
-
-    // Return the modified module
-    let output = quote! {
-        #input
-        #(#data_def)*
-    };
-    output.into()
-}
-
-// Define a struct to parse macro input
-struct SystemTemplateInput {
-    max_components: usize,
-}
-
-// Implement parsing for the macro input
-impl Parse for SystemTemplateInput {
-    fn parse(input: ParseStream) -> Result<Self> {
-        let _ = input.parse::<Ident>()?; // Parse the key (e.g., "max_components")
-        let _ = input.parse::<Token![=]>()?; // Parse the '='
-        let max_components: LitInt = input.parse()?; // Parse the value
-        let max_value = max_components.base10_parse()?;
-        Ok(SystemTemplateInput {
-            max_components: max_value,
-        })
-    }
-}

+ 0 - 17
crates/bolt-helpers/attribute/world-apply/Cargo.toml

@@ -1,17 +0,0 @@
-[package]
-name = "bolt-helpers-world-apply"
-description = "A helper library for the bolt world apply istructions"
-version = { workspace = true }
-authors = { workspace = true }
-repository = { workspace = true }
-homepage = { workspace = true }
-license = { workspace = true }
-edition = { workspace = true }
-
-[lib]
-proc-macro = true
-
-[dependencies]
-proc-macro2 = { workspace = true }
-quote = { workspace = true }
-syn = { workspace = true }

+ 0 - 166
crates/bolt-helpers/attribute/world-apply/src/lib.rs

@@ -1,166 +0,0 @@
-extern crate proc_macro;
-
-use proc_macro::TokenStream;
-use quote::quote;
-use syn::parse::{Parse, ParseStream, Result};
-use syn::{parse_macro_input, Ident, LitInt, Token};
-
-/// This macro attribute is a helper used for defining BOLT apply proxy instructions.
-#[proc_macro_attribute]
-pub fn apply_system(attr: TokenStream, item: TokenStream) -> TokenStream {
-    let attr_p = parse_macro_input!(attr as SystemTemplateInput);
-
-    let max_components = attr_p.max_components;
-
-    // Parse the original module content
-    let mut input: syn::ItemMod = syn::parse(item).expect("Failed to parse input module");
-
-    // Generate a function for execute instruction
-    let funcs = (2..=max_components).map(|i| {
-        let apply_func_name = syn::Ident::new(&format!("apply{}", i), proc_macro2::Span::call_site());
-        let execute_func_name = syn::Ident::new(&format!("execute_{}", i), proc_macro2::Span::call_site());
-        let data_struct = syn::Ident::new(&format!("ApplySystem{}", i), proc_macro2::Span::call_site());
-
-        let updates = (1..=i).enumerate().map(|(index, n)| {
-            let component_program_name = syn::Ident::new(&format!("component_program_{}", n), proc_macro2::Span::call_site());
-            let bolt_component_name = syn::Ident::new(&format!("bolt_component_{}", n), proc_macro2::Span::call_site());
-
-            quote! {
-            let update_result = bolt_component::cpi::update(
-                build_update_context(
-                    ctx.accounts.#component_program_name.clone(),
-                    ctx.accounts.#bolt_component_name.clone(),
-                    ctx.accounts.authority.clone(),
-                    ctx.accounts.instruction_sysvar_account.clone(),
-                ),
-                res[#index].to_owned()
-            )?;
-        }
-        });
-
-        quote! {
-        pub fn #apply_func_name<'info>(ctx: Context<'_, '_, '_, 'info, #data_struct<'info>>, args: Vec<u8>) -> Result<()> {
-            if !ctx.accounts.authority.is_signer && ctx.accounts.authority.key != &ID {
-                return Err(WorldError::InvalidAuthority.into());
-            }
-            if !ctx.accounts.world.permissionless
-                && !ctx
-                    .accounts
-                    .world
-                    .systems()
-                    .approved_systems
-                    .contains(&ctx.accounts.bolt_system.key())
-            {
-                return Err(WorldError::SystemNotApproved.into());
-            }
-            let remaining_accounts: Vec<AccountInfo<'info>> = ctx.remaining_accounts.to_vec();
-            let res = bolt_system::cpi::#execute_func_name(
-                    ctx.accounts
-                    .build()
-                    .with_remaining_accounts(remaining_accounts),args)?.get().to_vec();
-            #(#updates)*
-            Ok(())
-        }
-    }
-    });
-
-    // Append each generated function to the module's items
-    if let Some((brace, mut content)) = input.content.take() {
-        for func in funcs {
-            let parsed_func: syn::Item =
-                syn::parse2(func).expect("Failed to parse generated function");
-            content.push(parsed_func);
-        }
-
-        input.content = Some((brace, content));
-    }
-
-    let data_def = (2..=max_components).map(|i| {
-        let data_struct =
-            syn::Ident::new(&format!("ApplySystem{}", i), proc_macro2::Span::call_site());
-        let fields = (1..=i).map(|n| {
-            let component_program_name = syn::Ident::new(
-                &format!("component_program_{}", n),
-                proc_macro2::Span::call_site(),
-            );
-            let component_name = syn::Ident::new(
-                &format!("bolt_component_{}", n),
-                proc_macro2::Span::call_site(),
-            );
-            quote! {
-                /// CHECK: bolt component program check
-                pub #component_program_name: UncheckedAccount<'info>,
-                #[account(mut)]
-                /// CHECK: component account
-                pub #component_name: UncheckedAccount<'info>,
-            }
-        });
-        let struct_def = quote! {
-            #[derive(Accounts)]
-            pub struct #data_struct<'info> {
-                /// CHECK: bolt system program check
-                pub bolt_system: UncheckedAccount<'info>,
-                #(#fields)*
-                 /// CHECK: authority check
-                pub authority: Signer<'info>,
-                #[account(address = anchor_lang::solana_program::sysvar::instructions::id())]
-                /// CHECK: instruction sysvar check
-                pub instruction_sysvar_account: UncheckedAccount<'info>,
-                #[account()]
-                pub world: Account<'info, World>,
-            }
-        };
-        quote! {
-            #struct_def
-        }
-    });
-
-    let impl_build_def = (2..=max_components).map(|i| {
-        let data_struct = syn::Ident::new(&format!("ApplySystem{}", i), proc_macro2::Span::call_site());
-        let set_data_struct = syn::Ident::new(&format!("SetData{}", i), proc_macro2::Span::call_site());
-        let fields: Vec<_> = (1..=i).map(|n| {
-            let component_key = syn::Ident::new(&format!("component{}", n), proc_macro2::Span::call_site());
-            let component_name = syn::Ident::new(&format!("bolt_component_{}", n), proc_macro2::Span::call_site());
-            quote! {
-                #component_key: self.#component_name.to_account_info(),
-            }
-        }).collect();
-        quote! {
-            impl<'info> #data_struct<'info> {
-                pub fn build(&self) -> CpiContext<'_, '_, '_, 'info, bolt_system::cpi::accounts::#set_data_struct<'info>> {
-                    let cpi_program = self.bolt_system.to_account_info();
-                    let cpi_accounts = bolt_system::cpi::accounts::#set_data_struct {
-                        #(#fields)*
-                        authority: self.authority.to_account_info(),
-                    };
-                    CpiContext::new(cpi_program, cpi_accounts)
-                }
-            }
-        }
-    });
-
-    // Return the modified module
-    let output = quote! {
-        #input
-        #(#data_def)*
-        #(#impl_build_def)*
-    };
-    output.into()
-}
-
-// Define a struct to parse macro input
-struct SystemTemplateInput {
-    max_components: usize,
-}
-
-impl Parse for SystemTemplateInput {
-    fn parse(input: ParseStream) -> Result<Self> {
-        let _ = input.parse::<Ident>()?;
-        let _ = input.parse::<Token![=]>()?;
-        let max_components: LitInt = input.parse()?;
-        let max_value = max_components.base10_parse()?;
-        Ok(SystemTemplateInput {
-            max_components: max_value,
-        })
-    }
-}

+ 0 - 1
crates/bolt-helpers/src/lib.rs

@@ -1 +0,0 @@
-

+ 1 - 1
crates/bolt-lang/attribute/extra-accounts/src/lib.rs

@@ -71,7 +71,7 @@ pub fn extra_accounts(_attr: TokenStream, item: TokenStream) -> TokenStream {
         let index = syn::Index::from(index); // Create a compile-time index representation
         quote! {
             fn #field_name(&self) -> Result<&'c AccountInfo<'info>> {
-                self.remaining_accounts.get(#index).ok_or_else(|| ErrorCode::ConstraintAccountIsNone.into())
+                self.remaining_accounts.get(Self::NUMBER_OF_COMPONENTS + #index).ok_or_else(|| ErrorCode::ConstraintAccountIsNone.into())
             }
         }
     });

+ 37 - 9
crates/bolt-lang/attribute/system-input/src/lib.rs

@@ -76,6 +76,7 @@ pub fn system_input(_attr: TokenStream, item: TokenStream) -> TokenStream {
         #[derive(Accounts)]
         pub struct #name<'info> {
             #(#transformed_fields)*
+            #[account()]
             pub authority: Signer<'info>,
         }
     };
@@ -88,20 +89,39 @@ pub fn system_input(_attr: TokenStream, item: TokenStream) -> TokenStream {
         }
     });
 
-    let tuple_elements = (0..try_to_vec_fields.len())
-        .map(|_| quote! {Vec<u8>})
-        .collect::<Vec<_>>();
-    let generated_tuple_type = match tuple_elements.len() {
-        0 => panic!("system_input macro only supports structs with named fields"),
-        1 => quote! { (Vec<u8>,) },
-        _ => quote! { (#(#tuple_elements),*) },
+    let try_from_fields = fields.iter().enumerate().map(|(i, f)| {
+        let field_name = &f.ident;
+        quote! {
+            #field_name: Account::try_from(context.remaining_accounts.as_ref().get(#i).ok_or_else(|| ErrorCode::ConstraintAccountIsNone)?)?,
+        }
+    });
+
+    let number_of_components = fields.len();
+
+    let output_trait = quote! {
+        pub trait NumberOfComponents<'a, 'b, 'c, 'info, T> {
+            const NUMBER_OF_COMPONENTS: usize;
+        }
+    };
+
+    let output_trait_implementation = quote! {
+        impl<'a, 'b, 'c, 'info, T: bolt_lang::Bumps> NumberOfComponents<'a, 'b, 'c, 'info, T> for Context<'a, 'b, 'c, 'info, T> {
+            const NUMBER_OF_COMPONENTS: usize = #number_of_components;
+        }
     };
 
     // Generate the implementation of try_to_vec for the struct
     let output_impl = quote! {
         impl<'info> #name<'info> {
-            pub fn try_to_vec(&self) -> Result<#generated_tuple_type> {
-                Ok((#(#try_to_vec_fields,)*))
+            pub fn try_to_vec(&self) -> Result<Vec<Vec<u8>>> {
+                Ok(vec![#(#try_to_vec_fields,)*])
+            }
+
+            fn try_from<'a, 'b>(context: &Context<'a, 'b, 'info, 'info, VariadicBoltComponents<'info>>) -> Result<Self> {
+                Ok(Self {
+                    authority: context.accounts.authority.clone(),
+                    #(#try_from_fields)*
+                })
             }
         }
     };
@@ -110,7 +130,15 @@ pub fn system_input(_attr: TokenStream, item: TokenStream) -> TokenStream {
     let output = quote! {
         #output_struct
         #output_impl
+        #output_trait
+        #output_trait_implementation
         #(#components_imports)*
+
+        #[derive(Accounts)]
+        pub struct VariadicBoltComponents<'info> {
+            #[account()]
+            pub authority: Signer<'info>,
+        }
     };
 
     TokenStream::from(output)

+ 18 - 29
crates/bolt-lang/attribute/system/src/lib.rs

@@ -7,9 +7,7 @@ use syn::{
 };
 
 #[derive(Default)]
-struct SystemTransform {
-    return_values: usize,
-}
+struct SystemTransform;
 
 #[derive(Default)]
 struct Extractor {
@@ -44,15 +42,14 @@ pub fn system(attr: TokenStream, item: TokenStream) -> TokenStream {
     let mut extractor = Extractor::default();
     extractor.visit_item_mod_mut(&mut ast);
 
-    if let Some(components_len) = extractor.field_count {
+    if extractor.field_count.is_some() {
         let use_super = syn::parse_quote! { use super::*; };
-        if let Some(ref mut content) = ast.content {
-            content.1.insert(0, syn::Item::Use(use_super));
+        if let Some((_, ref mut items)) = ast.content {
+            items.insert(0, syn::Item::Use(use_super));
+            SystemTransform::add_variadic_execute_function(items);
         }
 
-        let mut transform = SystemTransform {
-            return_values: components_len,
-        };
+        let mut transform = SystemTransform;
         transform.visit_item_mod_mut(&mut ast);
 
         // Add `#[program]` macro and try_to_vec implementation
@@ -130,14 +127,8 @@ impl VisitMut for SystemTransform {
             // Modify the return type to Result<Vec<u8>> if necessary
             if let ReturnType::Type(_, type_box) = &item_fn.sig.output {
                 if let Type::Path(type_path) = &**type_box {
-                    if self.return_values > 1 {
-                        item_fn.sig.ident = Ident::new(
-                            format!("execute_{}", self.return_values).as_str(),
-                            item_fn.sig.ident.span(),
-                        );
-                    }
                     if !Self::check_is_result_vec_u8(type_path) {
-                        Self::modify_fn_return_type(item_fn, self.return_values);
+                        item_fn.sig.output = parse_quote! { -> Result<Vec<Vec<u8>>> };
                         // Modify the return statement inside the function body
                         let block = &mut item_fn.block;
                         self.visit_stmts_mut(&mut block.stmts);
@@ -188,6 +179,17 @@ impl VisitMut for SystemTransform {
 }
 
 impl SystemTransform {
+    fn add_variadic_execute_function(content: &mut Vec<syn::Item>) {
+        content.push(syn::parse2(quote! {
+            pub fn bolt_execute<'info>(ctx: Context<'_, '_, 'info, 'info, VariadicBoltComponents<'info>>, args: Vec<u8>) -> Result<Vec<Vec<u8>>> {
+                let mut components = Components::try_from(&ctx)?;
+                let bumps = ComponentsBumps {};
+                let context = Context::new(ctx.program_id, &mut components, ctx.remaining_accounts, bumps);
+                execute(context, args)
+            }
+        }).unwrap());
+    }
+
     // Helper function to check if a type is `Vec<u8>` or `(Vec<u8>, Vec<u8>, ...)`
     fn check_is_result_vec_u8(ty: &TypePath) -> bool {
         if let Some(segment) = ty.path.segments.last() {
@@ -227,19 +229,6 @@ impl SystemTransform {
         false
     }
 
-    // Helper function to modify the return type of a function to be Result<Vec<u8>> or Result<(Vec<u8>, Vec<u8>, ...)>
-    fn modify_fn_return_type(item_fn: &mut ItemFn, ret_values: usize) {
-        item_fn.sig.output = if ret_values == 1 {
-            parse_quote! { -> Result<(Vec<u8>,)> }
-        } else {
-            let types = std::iter::repeat(quote! { Vec<u8> })
-                .take(ret_values)
-                .collect::<Vec<_>>();
-            let tuple = quote! { (#(#types),*) };
-            syn::parse2(quote! { -> Result<#tuple> }).unwrap()
-        };
-    }
-
     // Helper function to check if an expression is an `Ok(...)` or `return Ok(...);` variant
     fn extract_inner_ok_expression(expr: &Expr) -> Option<&Expr> {
         match expr {

+ 2 - 13
crates/programs/bolt-component/src/lib.rs

@@ -29,23 +29,12 @@ pub mod bolt_component {
         #[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>,
     }
 
-    impl<'info> Apply<'info> {
-        pub fn set_data_ctx(
-            &self,
-        ) -> CpiContext<'_, '_, '_, 'info, bolt_system::cpi::accounts::SetData<'info>> {
-            let cpi_program = self.bolt_system.to_account_info();
-            let cpi_accounts = bolt_system::cpi::accounts::SetData {
-                component: self.bolt_component.to_account_info().clone(),
-                authority: self.authority.to_account_info(),
-            };
-            CpiContext::new(cpi_program, cpi_accounts)
-        }
-    }
-
     pub fn update(ctx: Context<Update>, _data: Vec<u8>) -> Result<()> {
         let instruction =
             anchor_lang::solana_program::sysvar::instructions::get_instruction_relative(

+ 0 - 1
crates/programs/bolt-system/Cargo.toml

@@ -25,4 +25,3 @@ custom-panic = []
 
 [dependencies]
 anchor-lang.workspace = true
-bolt-helpers-system-template.workspace = true

+ 1 - 6
crates/programs/bolt-system/src/lib.rs

@@ -1,23 +1,18 @@
 use anchor_lang::prelude::borsh::{BorshDeserialize, BorshSerialize};
 use anchor_lang::prelude::*;
-use bolt_helpers_system_template::system_template;
 
 declare_id!("7X4EFsDJ5aYTcEjKzJ94rD8FRKgQeXC89fkpeTS4KaqP");
 
-#[system_template(max_components = 5)]
 #[program]
 pub mod bolt_system {
     use super::*;
-    pub fn execute(_ctx: Context<SetData>, _args: Vec<u8>) -> Result<Vec<u8>> {
+    pub fn bolt_execute(_ctx: Context<SetData>, _args: Vec<u8>) -> Result<Vec<Vec<u8>>> {
         Ok(Vec::new())
     }
 }
 
 #[derive(Accounts, Clone)]
 pub struct SetData<'info> {
-    #[account()]
-    /// CHECK: unchecked account
-    pub component: UncheckedAccount<'info>,
     #[account()]
     pub authority: Signer<'info>,
 }

+ 0 - 1
crates/programs/world/Cargo.toml

@@ -26,7 +26,6 @@ custom-panic = []
 [dependencies]
 anchor-lang.workspace = true
 bolt-component.workspace = true
-bolt-helpers-world-apply.workspace = true
 bolt-system.workspace = true
 solana-security-txt.workspace = true
 tuple-conv.workspace = true

+ 2 - 0
crates/programs/world/src/error.rs

@@ -4,6 +4,8 @@ use anchor_lang::prelude::*;
 pub enum WorldError {
     #[msg("Invalid authority for instruction")]
     InvalidAuthority,
+    #[msg("Invalid system output")]
+    InvalidSystemOutput,
     #[msg("The provided world account does not match the expected PDA.")]
     WorldAccountMismatch,
     #[msg("Exceed the maximum number of authorities.")]

+ 56 - 35
crates/programs/world/src/lib.rs

@@ -1,8 +1,6 @@
 #![allow(clippy::manual_unwrap_or_default)]
 use anchor_lang::prelude::*;
-use bolt_helpers_world_apply::apply_system;
 use std::collections::BTreeSet;
-use tuple_conv::RepeatedTuple;
 
 #[cfg(not(feature = "no-entrypoint"))]
 use solana_security_txt::security_txt;
@@ -21,7 +19,6 @@ security_txt! {
 
 mod error;
 
-#[apply_system(max_components = 5)]
 #[program]
 pub mod world {
     use super::*;
@@ -267,7 +264,7 @@ pub mod world {
     }
 
     pub fn apply<'info>(
-        ctx: Context<'_, '_, '_, 'info, ApplySystem<'info>>,
+        ctx: Context<'_, '_, '_, 'info, Apply<'info>>,
         args: Vec<u8>,
     ) -> Result<()> {
         if !ctx.accounts.authority.is_signer && ctx.accounts.authority.key != &ID {
@@ -283,53 +280,75 @@ pub mod world {
         {
             return Err(WorldError::SystemNotApproved.into());
         }
-        let remaining_accounts: Vec<AccountInfo<'info>> = ctx.remaining_accounts.to_vec();
-        let res = bolt_system::cpi::execute(
+
+        let mut remaining_accounts: Vec<AccountInfo<'info>> = ctx.remaining_accounts.to_vec();
+
+        let mut pairs = Vec::new();
+        while remaining_accounts.len() >= 2 {
+            let program = remaining_accounts.remove(0);
+            if program.key() == ID {
+                break;
+            }
+            let component = remaining_accounts.remove(0);
+            pairs.push((program, component));
+        }
+
+        let mut components_accounts = pairs
+            .iter()
+            .map(|(_, component)| component)
+            .cloned()
+            .collect::<Vec<_>>();
+        components_accounts.append(&mut remaining_accounts);
+        let remaining_accounts = components_accounts;
+
+        let results = bolt_system::cpi::bolt_execute(
             ctx.accounts
                 .build()
                 .with_remaining_accounts(remaining_accounts),
             args,
-        )?;
-
-        bolt_component::cpi::update(
-            build_update_context(
-                ctx.accounts.component_program.clone(),
-                ctx.accounts.bolt_component.clone(),
-                ctx.accounts.authority.clone(),
-                ctx.accounts.instruction_sysvar_account.clone(),
-            ),
-            res.get(),
-        )?;
+        )?
+        .get();
+
+        if results.len() != pairs.len() {
+            return Err(WorldError::InvalidSystemOutput.into());
+        }
+
+        for ((program, component), result) in pairs.into_iter().zip(results.into_iter()) {
+            bolt_component::cpi::update(
+                build_update_context(
+                    program,
+                    component,
+                    ctx.accounts.authority.clone(),
+                    ctx.accounts.instruction_sysvar_account.clone(),
+                ),
+                result,
+            )?;
+        }
         Ok(())
     }
 
     #[derive(Accounts)]
-    pub struct ApplySystem<'info> {
-        /// CHECK: bolt component program check
-        pub component_program: UncheckedAccount<'info>,
+    pub struct Apply<'info> {
         /// CHECK: bolt system program check
+        #[account()]
         pub bolt_system: UncheckedAccount<'info>,
-        #[account(mut)]
-        /// CHECK: component account
-        pub bolt_component: UncheckedAccount<'info>,
         /// CHECK: authority check
+        #[account()]
         pub authority: Signer<'info>,
-        #[account(address = anchor_lang::solana_program::sysvar::instructions::id())]
         /// CHECK: instruction sysvar check
+        #[account(address = anchor_lang::solana_program::sysvar::instructions::id())]
         pub instruction_sysvar_account: UncheckedAccount<'info>,
         #[account()]
         pub world: Account<'info, World>,
     }
 
-    impl<'info> ApplySystem<'info> {
+    impl<'info> Apply<'info> {
         pub fn build(
             &self,
         ) -> CpiContext<'_, '_, '_, 'info, bolt_system::cpi::accounts::SetData<'info>> {
+            let authority = self.authority.to_account_info();
             let cpi_program = self.bolt_system.to_account_info();
-            let cpi_accounts = bolt_system::cpi::accounts::SetData {
-                component: self.bolt_component.to_account_info(),
-                authority: self.authority.to_account_info(),
-            };
+            let cpi_accounts = bolt_system::cpi::accounts::SetData { authority };
             CpiContext::new(cpi_program, cpi_accounts)
         }
     }
@@ -567,16 +586,18 @@ impl SystemWhitelist {
 
 /// Builds the context for updating a component.
 pub fn build_update_context<'info>(
-    component_program: UncheckedAccount<'info>,
-    component: UncheckedAccount<'info>,
+    component_program: AccountInfo<'info>,
+    bolt_component: AccountInfo<'info>,
     authority: Signer<'info>,
     instruction_sysvar_account: UncheckedAccount<'info>,
 ) -> CpiContext<'info, 'info, 'info, 'info, bolt_component::cpi::accounts::Update<'info>> {
-    let cpi_program = component_program.to_account_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 {
-        bolt_component: component.to_account_info(),
-        authority: authority.to_account_info(),
-        instruction_sysvar_account: instruction_sysvar_account.to_account_info(),
+        bolt_component,
+        authority,
+        instruction_sysvar_account,
     };
     CpiContext::new(cpi_program, cpi_accounts)
 }

+ 145 - 27
tests/bolt.low-level.api.ts

@@ -478,10 +478,20 @@ describe("bolt", () => {
       .accounts({
         authority: provider.wallet.publicKey,
         boltSystem: exampleSystemSimpleMovement,
-        boltComponent: componentPositionEntity1Pda,
-        componentProgram: exampleComponentPosition.programId,
         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);
@@ -506,10 +516,20 @@ describe("bolt", () => {
       .accounts({
         authority: provider.wallet.publicKey,
         boltSystem: exampleSystemSimpleMovement,
-        boltComponent: componentPositionEntity1Pda,
-        componentProgram: exampleComponentPosition.programId,
         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);
@@ -534,10 +554,20 @@ describe("bolt", () => {
       .accounts({
         authority: provider.wallet.publicKey,
         boltSystem: exampleSystemSimpleMovement,
-        boltComponent: componentPositionEntity1Pda,
-        componentProgram: exampleComponentPosition.programId,
         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);
@@ -561,10 +591,20 @@ describe("bolt", () => {
       .accounts({
         authority: provider.wallet.publicKey,
         boltSystem: exampleSystemFly,
-        boltComponent: componentPositionEntity1Pda,
-        componentProgram: exampleComponentPosition.programId,
         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);
@@ -581,17 +621,34 @@ describe("bolt", () => {
 
   it("Apply System Velocity on Entity 1", async () => {
     const instruction = await worldProgram.methods
-      .apply2(SerializeArgs())
+      .apply(SerializeArgs())
       .accounts({
         authority: provider.wallet.publicKey,
         boltSystem: exampleSystemApplyVelocity,
-        boltComponent1: componentVelocityEntity1Pda,
-        componentProgram1: exampleComponentVelocity.programId,
-        boltComponent2: componentPositionEntity1Pda,
-        componentProgram2: exampleComponentPosition.programId,
         world: worldPda,
       })
-      .remainingAccounts([])
+      .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);
@@ -617,17 +674,38 @@ describe("bolt", () => {
 
   it("Apply System Velocity on Entity 1, with Clock external account", async () => {
     const instruction = await worldProgram.methods
-      .apply2(SerializeArgs())
+      .apply(SerializeArgs())
       .accounts({
         authority: provider.wallet.publicKey,
         boltSystem: exampleSystemApplyVelocity,
-        boltComponent1: componentVelocityEntity1Pda,
-        componentProgram1: exampleComponentVelocity.programId,
-        boltComponent2: componentPositionEntity1Pda,
-        componentProgram2: exampleComponentPosition.programId,
         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",
@@ -655,10 +733,20 @@ describe("bolt", () => {
       .accounts({
         authority: provider.wallet.publicKey,
         boltSystem: exampleSystemFly,
-        boltComponent: componentPositionEntity4Pda,
-        componentProgram: exampleComponentPosition.programId,
         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);
@@ -683,10 +771,20 @@ describe("bolt", () => {
       .accounts({
         authority: provider.wallet.publicKey,
         boltSystem: exampleSystemFly,
-        boltComponent: componentPositionEntity5Pda,
-        componentProgram: exampleComponentPosition.programId,
         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);
 
@@ -757,10 +855,20 @@ describe("bolt", () => {
       .accounts({
         authority: provider.wallet.publicKey,
         boltSystem: exampleSystemFly,
-        boltComponent: componentPositionEntity1Pda,
-        componentProgram: exampleComponentPosition.programId,
         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);
@@ -793,10 +901,20 @@ describe("bolt", () => {
       .accounts({
         authority: provider.wallet.publicKey,
         boltSystem: exampleSystemFly,
-        boltComponent: componentPositionEntity1Pda,
-        componentProgram: exampleComponentPosition.programId,
         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;