Răsfoiți Sursa

:sparkles: CPI Authentication using a World PDA (#196)

Danilo Guanabara 2 luni în urmă
părinte
comite
1463d8dad9

+ 8 - 8
clients/csharp/Solana.Unity.Bolt/WorldProgram/Generated.cs

@@ -277,7 +277,7 @@ namespace World
 
             public PublicKey Authority { get; set; }
 
-            public PublicKey InstructionSysvarAccount { get; set; } = new PublicKey("Sysvar1nstructions1111111111111111111111111");
+            public PublicKey CpiAuth { get; set; } = new PublicKey("B2f2y3QTBv346wE6nWKor72AUhUvFF6mPk7TWCF2QVhi");
             public PublicKey World { get; set; }
         }
 
@@ -287,7 +287,7 @@ namespace World
 
             public PublicKey Authority { get; set; }
 
-            public PublicKey InstructionSysvarAccount { get; set; } = new PublicKey("Sysvar1nstructions1111111111111111111111111");
+            public PublicKey CpiAuth { get; set; } = new PublicKey("B2f2y3QTBv346wE6nWKor72AUhUvFF6mPk7TWCF2QVhi");
             public PublicKey World { get; set; }
 
             public PublicKey SessionToken { get; set; }
@@ -318,7 +318,7 @@ namespace World
 
             public PublicKey Component { get; set; }
 
-            public PublicKey InstructionSysvarAccount { get; set; } = new PublicKey("Sysvar1nstructions1111111111111111111111111");
+            public PublicKey CpiAuth { get; set; } = new PublicKey("B2f2y3QTBv346wE6nWKor72AUhUvFF6mPk7TWCF2QVhi");
             public PublicKey SystemProgram { get; set; } = new PublicKey("11111111111111111111111111111111");
         }
 
@@ -334,7 +334,7 @@ namespace World
 
             public PublicKey Authority { get; set; }
 
-            public PublicKey InstructionSysvarAccount { get; set; } = new PublicKey("Sysvar1nstructions1111111111111111111111111");
+            public PublicKey CpiAuth { get; set; } = new PublicKey("B2f2y3QTBv346wE6nWKor72AUhUvFF6mPk7TWCF2QVhi");
             public PublicKey SystemProgram { get; set; } = new PublicKey("11111111111111111111111111111111");
         }
 
@@ -432,7 +432,7 @@ namespace World
             {
                 programId ??= new(ID);
                 List<Solana.Unity.Rpc.Models.AccountMeta> keys = new()
-                {Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.BoltSystem, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.Authority, true), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.InstructionSysvarAccount, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.World, false)};
+                {Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.BoltSystem, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.Authority, true), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.CpiAuth, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.World, false)};
                 byte[] _data = new byte[1200];
                 int offset = 0;
                 _data.WriteU64(16258613031726085112UL, offset);
@@ -450,7 +450,7 @@ namespace World
             {
                 programId ??= new(ID);
                 List<Solana.Unity.Rpc.Models.AccountMeta> keys = new()
-                {Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.BoltSystem, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.Authority, true), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.InstructionSysvarAccount, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.World, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.SessionToken, false)};
+                {Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.BoltSystem, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.Authority, true), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.CpiAuth, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.World, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.SessionToken, false)};
                 byte[] _data = new byte[1200];
                 int offset = 0;
                 _data.WriteU64(7459768094276011477UL, offset);
@@ -482,7 +482,7 @@ namespace World
             {
                 programId ??= new(ID);
                 List<Solana.Unity.Rpc.Models.AccountMeta> keys = new()
-                {Solana.Unity.Rpc.Models.AccountMeta.Writable(accounts.Authority, true), Solana.Unity.Rpc.Models.AccountMeta.Writable(accounts.Receiver, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.ComponentProgram, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.ComponentProgramData, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.Entity, false), Solana.Unity.Rpc.Models.AccountMeta.Writable(accounts.Component, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.InstructionSysvarAccount, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.SystemProgram, false)};
+                {Solana.Unity.Rpc.Models.AccountMeta.Writable(accounts.Authority, true), Solana.Unity.Rpc.Models.AccountMeta.Writable(accounts.Receiver, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.ComponentProgram, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.ComponentProgramData, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.Entity, false), Solana.Unity.Rpc.Models.AccountMeta.Writable(accounts.Component, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.CpiAuth, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.SystemProgram, false)};
                 byte[] _data = new byte[1200];
                 int offset = 0;
                 _data.WriteU64(5321952129328727336UL, offset);
@@ -496,7 +496,7 @@ namespace World
             {
                 programId ??= new(ID);
                 List<Solana.Unity.Rpc.Models.AccountMeta> keys = new()
-                {Solana.Unity.Rpc.Models.AccountMeta.Writable(accounts.Payer, true), Solana.Unity.Rpc.Models.AccountMeta.Writable(accounts.Data, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.Entity, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.ComponentProgram, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.Authority, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.InstructionSysvarAccount, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.SystemProgram, false)};
+                {Solana.Unity.Rpc.Models.AccountMeta.Writable(accounts.Payer, true), Solana.Unity.Rpc.Models.AccountMeta.Writable(accounts.Data, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.Entity, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.ComponentProgram, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.Authority, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.CpiAuth, false), Solana.Unity.Rpc.Models.AccountMeta.ReadOnly(accounts.SystemProgram, false)};
                 byte[] _data = new byte[1200];
                 int offset = 0;
                 _data.WriteU64(2179155133888827172UL, offset);

+ 6 - 10
clients/typescript/src/generated/idl/world.json

@@ -1,8 +1,8 @@
 {
-  "address": "A61GccEkeYiQeRM5HbQW5SZwiicoPjFJaRcLt22qSnhP",
+  "address": "WorLD15A7CrDwLcLy4fRqtaTb9fbd8o8iqiEMUDse2n",
   "metadata": {
     "name": "world",
-    "version": "0.2.3",
+    "version": "0.2.4",
     "spec": "0.1.0",
     "description": "Bolt World program",
     "repository": "https://github.com/magicblock-labs/bolt"
@@ -124,8 +124,7 @@
           "signer": true
         },
         {
-          "name": "instruction_sysvar_account",
-          "address": "Sysvar1nstructions1111111111111111111111111"
+          "name": "cpi_auth"
         },
         {
           "name": "world"
@@ -159,8 +158,7 @@
           "signer": true
         },
         {
-          "name": "instruction_sysvar_account",
-          "address": "Sysvar1nstructions1111111111111111111111111"
+          "name": "cpi_auth"
         },
         {
           "name": "world"
@@ -244,8 +242,7 @@
           "writable": true
         },
         {
-          "name": "instruction_sysvar_account",
-          "address": "Sysvar1nstructions1111111111111111111111111"
+          "name": "cpi_auth"
         },
         {
           "name": "system_program",
@@ -286,8 +283,7 @@
           "name": "authority"
         },
         {
-          "name": "instruction_sysvar_account",
-          "address": "Sysvar1nstructions1111111111111111111111111"
+          "name": "cpi_auth"
         },
         {
           "name": "system_program",

+ 2 - 3
clients/typescript/src/generated/instructions/apply.ts

@@ -7,6 +7,7 @@
 
 import * as beet from "@metaplex-foundation/beet";
 import * as web3 from "@solana/web3.js";
+import { CPI_AUTH_ADDRESS } from "../../world/transactions";
 
 /**
  * @category Instructions
@@ -39,7 +40,6 @@ export const applyStruct = new beet.FixableBeetArgsStruct<
  * @property [] boltSystem
  * @property [_writable_] boltComponent
  * @property [] authority
- * @property [] instructionSysvarAccount
  * @category Instructions
  * @category Apply
  * @category generated
@@ -49,7 +49,6 @@ export interface ApplyInstructionAccounts {
   boltSystem: web3.PublicKey;
   boltComponent: web3.PublicKey;
   authority: web3.PublicKey;
-  instructionSysvarAccount: web3.PublicKey;
   world: web3.PublicKey;
   anchorRemainingAccounts?: web3.AccountMeta[];
 }
@@ -99,7 +98,7 @@ export function createApplyInstruction(
       isSigner: false,
     },
     {
-      pubkey: accounts.instructionSysvarAccount,
+      pubkey: CPI_AUTH_ADDRESS,
       isWritable: false,
       isSigner: false,
     },

+ 3 - 3
clients/typescript/src/generated/instructions/initializeComponent.ts

@@ -7,6 +7,7 @@
 
 import * as beet from "@metaplex-foundation/beet";
 import * as web3 from "@solana/web3.js";
+import { CPI_AUTH_ADDRESS } from "../../world/transactions";
 
 /**
  * @category Instructions
@@ -27,7 +28,7 @@ export const initializeComponentStruct = new beet.BeetArgsStruct<{
  * @property [] entity
  * @property [] componentProgram
  * @property [] authority
- * @property [] instructionSysvarAccount
+ * @property [] cpiAuth
  * @category Instructions
  * @category InitializeComponent
  * @category generated
@@ -38,7 +39,6 @@ export interface InitializeComponentInstructionAccounts {
   entity: web3.PublicKey;
   componentProgram: web3.PublicKey;
   authority: web3.PublicKey;
-  instructionSysvarAccount: web3.PublicKey;
   systemProgram?: web3.PublicKey;
   anchorRemainingAccounts?: web3.AccountMeta[];
 }
@@ -89,7 +89,7 @@ export function createInitializeComponentInstruction(
       isSigner: false,
     },
     {
-      pubkey: accounts.instructionSysvarAccount,
+      pubkey: CPI_AUTH_ADDRESS,
       isWritable: false,
       isSigner: false,
     },

+ 5 - 9
clients/typescript/src/generated/types/world.ts

@@ -8,7 +8,7 @@ export type World = {
   address: "WorLD15A7CrDwLcLy4fRqtaTb9fbd8o8iqiEMUDse2n";
   metadata: {
     name: "world";
-    version: "0.2.3";
+    version: "0.2.4";
     spec: "0.1.0";
     description: "Bolt World program";
     repository: "https://github.com/magicblock-labs/bolt";
@@ -97,8 +97,7 @@ export type World = {
           signer: true;
         },
         {
-          name: "instructionSysvarAccount";
-          address: "Sysvar1nstructions1111111111111111111111111";
+          name: "cpiAuth";
         },
         {
           name: "world";
@@ -123,8 +122,7 @@ export type World = {
           signer: true;
         },
         {
-          name: "instructionSysvarAccount";
-          address: "Sysvar1nstructions1111111111111111111111111";
+          name: "cpiAuth";
         },
         {
           name: "world";
@@ -190,8 +188,7 @@ export type World = {
           writable: true;
         },
         {
-          name: "instructionSysvarAccount";
-          address: "Sysvar1nstructions1111111111111111111111111";
+          name: "cpiAuth";
         },
         {
           name: "systemProgram";
@@ -223,8 +220,7 @@ export type World = {
           name: "authority";
         },
         {
-          name: "instructionSysvarAccount";
-          address: "Sysvar1nstructions1111111111111111111111111";
+          name: "cpiAuth";
         },
         {
           name: "systemProgram";

+ 8 - 2
clients/typescript/src/world/transactions.ts

@@ -18,7 +18,7 @@ import {
   BN,
   FindComponentProgramDataPda,
 } from "../index";
-import type web3 from "@solana/web3.js";
+import web3 from "@solana/web3.js";
 import {
   type Connection,
   Keypair,
@@ -34,6 +34,10 @@ import {
 } from "../generated";
 import { type Idl, Program } from "@coral-xyz/anchor";
 
+export const CPI_AUTH_ADDRESS = new web3.PublicKey(
+  "B2f2y3QTBv346wE6nWKor72AUhUvFF6mPk7TWCF2QVhi",
+);
+
 export async function InitializeRegistry({
   payer,
   connection,
@@ -371,6 +375,7 @@ export async function DestroyComponent({
       componentProgram,
       componentProgramData,
       receiver,
+      cpiAuth: CPI_AUTH_ADDRESS,
     })
     .instruction();
   const transaction = new Transaction().add(instruction);
@@ -416,7 +421,6 @@ export async function InitializeComponent({
     data: componentPda,
     componentProgram: componentId,
     authority: authority ?? PROGRAM_ID,
-    instructionSysvarAccount: SYSVAR_INSTRUCTIONS_PUBKEY,
     anchorRemainingAccounts,
   });
   const transaction = new Transaction().add(instruction);
@@ -503,6 +507,7 @@ async function createApplySystemInstruction({
         boltSystem: systemId,
         sessionToken: session.token,
         world,
+        cpiAuth: CPI_AUTH_ADDRESS,
       })
       .remainingAccounts(remainingAccounts)
       .instruction();
@@ -513,6 +518,7 @@ async function createApplySystemInstruction({
         authority: authority ?? PROGRAM_ID,
         boltSystem: systemId,
         world,
+        cpiAuth: CPI_AUTH_ADDRESS,
       })
       .remainingAccounts(remainingAccounts)
       .instruction();

+ 12 - 0
clients/typescript/test/low-level/ecs.ts

@@ -6,6 +6,7 @@ import {
   FindComponentProgramDataPda,
   FindEntityPda,
   SerializeArgs,
+  CPI_AUTH_ADDRESS,
 } from "../../lib";
 import { Direction } from "../framework";
 
@@ -104,6 +105,7 @@ export function ecs(framework) {
           data: framework.componentVelocityEntity1Pda,
           componentProgram: componentId,
           authority: framework.provider.wallet.publicKey,
+          cpiAuth: CPI_AUTH_ADDRESS,
         })
         .instruction();
       const transaction = new anchor.web3.Transaction().add(instruction);
@@ -124,6 +126,7 @@ export function ecs(framework) {
           data: framework.componentPositionEntity1Pda,
           componentProgram: componentId,
           authority: framework.worldProgram.programId,
+          cpiAuth: CPI_AUTH_ADDRESS,
         })
         .instruction();
       const transaction = new anchor.web3.Transaction().add(instruction);
@@ -144,6 +147,7 @@ export function ecs(framework) {
           data: componentPda,
           componentProgram: componentId,
           authority: framework.worldProgram.programId,
+          cpiAuth: CPI_AUTH_ADDRESS,
         })
         .instruction();
       const transaction = new anchor.web3.Transaction().add(instruction);
@@ -164,6 +168,7 @@ export function ecs(framework) {
           data: framework.componentPositionEntity4Pda,
           componentProgram: componentId,
           authority: framework.worldProgram.programId,
+          cpiAuth: CPI_AUTH_ADDRESS,
         })
         .instruction();
       const transaction = new anchor.web3.Transaction().add(instruction);
@@ -187,6 +192,7 @@ export function ecs(framework) {
           authority: framework.provider.wallet.publicKey,
           boltSystem: framework.systemSimpleMovement.programId,
           world: framework.worldPda,
+          cpiAuth: CPI_AUTH_ADDRESS,
         })
         .remainingAccounts([
           {
@@ -221,6 +227,7 @@ export function ecs(framework) {
           authority: framework.provider.wallet.publicKey,
           boltSystem: framework.systemSimpleMovement.programId,
           world: framework.worldPda,
+          cpiAuth: CPI_AUTH_ADDRESS,
         })
         .remainingAccounts([
           {
@@ -254,6 +261,7 @@ export function ecs(framework) {
           authority: framework.provider.wallet.publicKey,
           boltSystem: framework.systemFly.programId,
           world: framework.worldPda,
+          cpiAuth: CPI_AUTH_ADDRESS,
         })
         .remainingAccounts([
           {
@@ -287,6 +295,7 @@ export function ecs(framework) {
           authority: framework.provider.wallet.publicKey,
           boltSystem: framework.systemApplyVelocity.programId,
           world: framework.worldPda,
+          cpiAuth: CPI_AUTH_ADDRESS,
         })
         .remainingAccounts([
           {
@@ -339,6 +348,7 @@ export function ecs(framework) {
           authority: framework.provider.wallet.publicKey,
           boltSystem: framework.systemApplyVelocity.programId,
           world: framework.worldPda,
+          cpiAuth: CPI_AUTH_ADDRESS,
         })
         .remainingAccounts([
           {
@@ -394,6 +404,7 @@ export function ecs(framework) {
           authority: framework.provider.wallet.publicKey,
           boltSystem: framework.systemFly.programId,
           world: framework.worldPda,
+          cpiAuth: CPI_AUTH_ADDRESS,
         })
         .remainingAccounts([
           {
@@ -440,6 +451,7 @@ export function ecs(framework) {
           component: framework.componentVelocityEntity1Pda,
           componentProgramData: componentProgramData,
           receiver: keypair.publicKey,
+          cpiAuth: CPI_AUTH_ADDRESS,
         })
         .instruction();
       const transaction = new anchor.web3.Transaction().add(instruction);

+ 4 - 0
clients/typescript/test/low-level/permissioning/component.ts

@@ -4,6 +4,7 @@ import {
   FindEntityPda,
   FindComponentPda,
   SerializeArgs,
+  CPI_AUTH_ADDRESS,
 } from "../../../lib";
 import { assert, expect } from "chai";
 
@@ -46,6 +47,7 @@ export function component(framework) {
           data: component,
           componentProgram: componentId,
           authority: framework.provider.wallet.publicKey,
+          cpiAuth: CPI_AUTH_ADDRESS,
         })
         .instruction();
       const transaction = new anchor.web3.Transaction().add(instruction);
@@ -66,6 +68,7 @@ export function component(framework) {
           authority: keypair.publicKey,
           boltSystem: framework.systemFly.programId,
           world: framework.worldPda,
+          cpiAuth: CPI_AUTH_ADDRESS,
         })
         .remainingAccounts([
           {
@@ -115,6 +118,7 @@ export function component(framework) {
           authority: framework.provider.wallet.publicKey,
           boltSystem: framework.systemFly.programId,
           world: framework.worldPda,
+          cpiAuth: CPI_AUTH_ADDRESS,
         })
         .remainingAccounts([
           {

+ 3 - 1
clients/typescript/test/low-level/permissioning/world.ts

@@ -1,5 +1,5 @@
 import { expect } from "chai";
-import { anchor, SerializeArgs } from "../../../lib";
+import { anchor, CPI_AUTH_ADDRESS, SerializeArgs } from "../../../lib";
 
 export function world(framework) {
   describe("World authority", () => {
@@ -121,6 +121,7 @@ export function world(framework) {
           authority: framework.provider.wallet.publicKey,
           boltSystem: framework.systemFly.programId,
           world: framework.worldPda,
+          cpiAuth: CPI_AUTH_ADDRESS,
         })
         .remainingAccounts([
           {
@@ -168,6 +169,7 @@ export function world(framework) {
           authority: framework.provider.wallet.publicKey,
           boltSystem: framework.systemFly.programId,
           world: framework.worldPda,
+          cpiAuth: CPI_AUTH_ADDRESS,
         })
         .remainingAccounts([
           {

+ 8 - 0
clients/typescript/test/low-level/session.ts

@@ -7,6 +7,7 @@ import {
   SessionProgram,
   FindSessionTokenPda,
   BN,
+  CPI_AUTH_ADDRESS,
 } from "../../lib";
 import { Keypair } from "@solana/web3.js";
 
@@ -31,6 +32,7 @@ export function session(framework) {
           authority: framework.provider.wallet.publicKey,
           targetProgram: framework.worldProgram.programId,
           sessionToken,
+          cpiAuth: CPI_AUTH_ADDRESS,
         })
         .instruction();
       const transaction = new anchor.web3.Transaction().add(instruction);
@@ -51,6 +53,7 @@ export function session(framework) {
           payer: sessionSigner.publicKey,
           entity: entity,
           world: framework.worldPda,
+          cpiAuth: CPI_AUTH_ADDRESS,
         })
         .instruction();
       const transaction = new anchor.web3.Transaction().add(instruction);
@@ -71,6 +74,7 @@ export function session(framework) {
           data: component,
           componentProgram: componentId,
           authority: framework.worldProgram.programId,
+          cpiAuth: CPI_AUTH_ADDRESS,
         })
         .instruction();
       const transaction = new anchor.web3.Transaction().add(instruction);
@@ -90,6 +94,7 @@ export function session(framework) {
           boltSystem: framework.systemFly.programId,
           world: framework.worldPda,
           sessionToken,
+          cpiAuth: CPI_AUTH_ADDRESS,
         })
         .remainingAccounts([
           {
@@ -137,6 +142,7 @@ export function session(framework) {
           payer: sessionSigner.publicKey,
           world: framework.worldPda,
           entity: entityWithAuthority,
+          cpiAuth: CPI_AUTH_ADDRESS,
         })
         .instruction();
       const transaction = new anchor.web3.Transaction().add(instruction);
@@ -157,6 +163,7 @@ export function session(framework) {
           data: componentWithAuthority,
           componentProgram: componentId,
           authority: framework.provider.wallet.publicKey,
+          cpiAuth: CPI_AUTH_ADDRESS,
         })
         .instruction();
       const transaction = new anchor.web3.Transaction().add(instruction);
@@ -176,6 +183,7 @@ export function session(framework) {
           boltSystem: framework.systemFly.programId,
           world: framework.worldPda,
           sessionToken,
+          cpiAuth: CPI_AUTH_ADDRESS,
         })
         .remainingAccounts([
           {

+ 27 - 31
crates/bolt-lang/attribute/bolt-program/src/lib.rs

@@ -34,7 +34,9 @@ pub fn bolt_program(args: TokenStream, input: TokenStream) -> TokenStream {
         extract_type_name(&args).expect("Expected a component type in macro arguments");
     let modified = modify_component_module(ast, &component_type);
     let additional_macro: Attribute = parse_quote! { #[program] };
+    let cpi_checker = generate_cpi_checker();
     TokenStream::from(quote! {
+        #cpi_checker
         #additional_macro
         #modified
     })
@@ -44,7 +46,6 @@ pub fn bolt_program(args: TokenStream, input: TokenStream) -> TokenStream {
 fn modify_component_module(mut module: ItemMod, component_type: &Type) -> ItemMod {
     let (initialize_fn, initialize_struct) = generate_initialize(component_type);
     let (destroy_fn, destroy_struct) = generate_destroy(component_type);
-    //let (apply_fn, apply_struct, apply_impl, update_fn, update_struct) = generate_instructions(component_type);
     let (update_fn, update_with_session_fn, update_struct, update_with_session_struct) =
         generate_update(component_type);
 
@@ -118,6 +119,18 @@ fn create_check_attribute() -> Attribute {
     }
 }
 
+/// Generates the CPI checker function.
+fn generate_cpi_checker() -> TokenStream2 {
+    quote! {
+        fn cpi_checker<'info>(cpi_auth: &AccountInfo<'info>) -> Result<()> {
+            if !cpi_auth.is_signer || cpi_auth.key != &bolt_lang::world::World::cpi_auth_address() {
+                return Err(BoltError::InvalidCaller.into());
+            }
+            Ok(())
+        }
+    }
+}
+
 /// Generates the destroy function and struct.
 fn generate_destroy(component_type: &Type) -> (TokenStream2, TokenStream2) {
     (
@@ -147,12 +160,8 @@ fn generate_destroy(component_type: &Type) -> (TokenStream2, TokenStream2) {
                     return Err(BoltError::InvalidAuthority.into());
                 }
 
-                let instruction = anchor_lang::solana_program::sysvar::instructions::get_instruction_relative(
-                    0, &ctx.accounts.instruction_sysvar_account.to_account_info()
-                ).map_err(|_| BoltError::InvalidCaller)?;
-                if instruction.program_id != World::id() {
-                    return Err(BoltError::InvalidCaller.into());
-                }
+                cpi_checker(&ctx.accounts.cpi_auth.to_account_info())?;
+
                 Ok(())
             }
         },
@@ -160,6 +169,8 @@ fn generate_destroy(component_type: &Type) -> (TokenStream2, TokenStream2) {
             #[automatically_derived]
             #[derive(Accounts)]
             pub struct Destroy<'info> {
+                #[account()]
+                pub cpi_auth: Signer<'info>,
                 #[account()]
                 pub authority: Signer<'info>,
                 #[account(mut)]
@@ -170,8 +181,6 @@ fn generate_destroy(component_type: &Type) -> (TokenStream2, TokenStream2) {
                 pub component: Account<'info, #component_type>,
                 #[account()]
                 pub component_program_data: AccountInfo<'info>,
-                #[account(address = anchor_lang::solana_program::sysvar::instructions::id())]
-                pub instruction_sysvar_account: AccountInfo<'info>,
                 pub system_program: Program<'info, System>,
             }
         },
@@ -184,12 +193,7 @@ fn generate_initialize(component_type: &Type) -> (TokenStream2, TokenStream2) {
         quote! {
             #[automatically_derived]
             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()
-                ).map_err(|_| BoltError::InvalidCaller)?;
-                if instruction.program_id != World::id() {
-                    return Err(BoltError::InvalidCaller.into());
-                }
+                cpi_checker(&ctx.accounts.cpi_auth.to_account_info())?;
                 ctx.accounts.data.set_inner(<#component_type>::default());
                 ctx.accounts.data.bolt_metadata.authority = *ctx.accounts.authority.key;
                 Ok(())
@@ -199,6 +203,8 @@ fn generate_initialize(component_type: &Type) -> (TokenStream2, TokenStream2) {
             #[automatically_derived]
             #[derive(Accounts)]
             pub struct Initialize<'info>  {
+                #[account()]
+                pub cpi_auth: Signer<'info>,
                 #[account(mut)]
                 pub payer: Signer<'info>,
                 #[account(init_if_needed, payer = payer, space = <#component_type>::size(), seeds = [<#component_type>::seed(), entity.key().as_ref()], bump)]
@@ -207,8 +213,6 @@ fn generate_initialize(component_type: &Type) -> (TokenStream2, TokenStream2) {
                 pub entity: Account<'info, Entity>,
                 #[account()]
                 pub authority: AccountInfo<'info>,
-                #[account(address = anchor_lang::solana_program::sysvar::instructions::id())]
-                pub instruction_sysvar_account: UncheckedAccount<'info>,
                 pub system_program: Program<'info, System>,
             }
         },
@@ -225,11 +229,7 @@ fn generate_update(
             pub fn update(ctx: Context<Update>, data: Vec<u8>) -> Result<()> {
                 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()
-                ).map_err(|_| BoltError::InvalidCaller)?;
-                require_eq!(instruction.program_id, World::id(), BoltError::InvalidCaller);
+                cpi_checker(&ctx.accounts.cpi_auth.to_account_info())?;
 
                 ctx.accounts.bolt_component.set_inner(<#component_type>::try_from_slice(&data)?);
                 Ok(())
@@ -251,11 +251,7 @@ fn generate_update(
                     require_eq!(ctx.accounts.bolt_component.bolt_metadata.authority, ctx.accounts.session_token.authority, bolt_lang::session_keys::SessionError::InvalidToken);
                 }
 
-                // 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()
-                ).map_err(|_| BoltError::InvalidCaller)?;
-                require_eq!(instruction.program_id, World::id(), BoltError::InvalidCaller);
+                cpi_checker(&ctx.accounts.cpi_auth.to_account_info())?;
 
                 ctx.accounts.bolt_component.set_inner(<#component_type>::try_from_slice(&data)?);
                 Ok(())
@@ -265,24 +261,24 @@ fn generate_update(
             #[automatically_derived]
             #[derive(Accounts)]
             pub struct Update<'info> {
+                #[account()]
+                pub cpi_auth: Signer<'info>,
                 #[account(mut)]
                 pub bolt_component: Account<'info, #component_type>,
                 #[account()]
                 pub authority: Signer<'info>,
-                #[account(address = anchor_lang::solana_program::sysvar::instructions::id())]
-                pub instruction_sysvar_account: UncheckedAccount<'info>
             }
         },
         quote! {
             #[automatically_derived]
             #[derive(Accounts)]
             pub struct UpdateWithSession<'info> {
+                #[account()]
+                pub cpi_auth: Signer<'info>,
                 #[account(mut)]
                 pub bolt_component: Account<'info, #component_type>,
                 #[account()]
                 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: Account<'info, bolt_lang::session_keys::SessionToken>,
             }

+ 23 - 20
crates/programs/bolt-component/src/lib.rs

@@ -24,28 +24,26 @@ pub mod bolt_component {
 
     #[derive(Accounts)]
     pub struct Update<'info> {
+        #[account()]
+        pub cpi_auth: Signer<'info>,
         #[account(mut)]
         /// CHECK: The component to update
         pub bolt_component: UncheckedAccount<'info>,
         #[account()]
         /// CHECK: The authority of the component
         pub authority: Signer<'info>,
-        #[account(address = anchor_lang::solana_program::sysvar::instructions::id())]
-        /// CHECK: The instruction sysvar
-        pub instruction_sysvar_account: AccountInfo<'info>,
     }
 
     #[derive(Accounts)]
     pub struct UpdateWithSession<'info> {
+        #[account()]
+        pub cpi_auth: Signer<'info>,
         #[account(mut)]
         /// CHECK: The component to update
         pub bolt_component: UncheckedAccount<'info>,
         #[account()]
         /// CHECK: The authority of the component
         pub authority: Signer<'info>,
-        #[account(address = anchor_lang::solana_program::sysvar::instructions::id())]
-        /// CHECK: The instruction sysvar
-        pub instruction_sysvar_account: AccountInfo<'info>,
         #[account()]
         /// CHECK: The session token
         pub session_token: UncheckedAccount<'info>,
@@ -54,6 +52,8 @@ pub mod bolt_component {
 
 #[derive(Accounts)]
 pub struct Initialize<'info> {
+    #[account()]
+    pub cpi_auth: Signer<'info>,
     #[account(mut)]
     pub payer: Signer<'info>,
     #[account(mut)]
@@ -65,14 +65,13 @@ pub struct Initialize<'info> {
     #[account()]
     /// CHECK: The authority of the component
     pub authority: AccountInfo<'info>,
-    #[account(address = anchor_lang::solana_program::sysvar::instructions::id())]
-    /// CHECK: The instruction sysvar
-    pub instruction_sysvar_account: AccountInfo<'info>,
     pub system_program: Program<'info, System>,
 }
 
 #[derive(Accounts)]
 pub struct Destroy<'info> {
+    #[account()]
+    pub cpi_auth: Signer<'info>,
     #[account()]
     pub authority: Signer<'info>,
     #[account(mut)]
@@ -87,9 +86,6 @@ pub struct Destroy<'info> {
     #[account()]
     /// CHECK: The component program data
     pub component_program_data: AccountInfo<'info>,
-    #[account(address = anchor_lang::solana_program::sysvar::instructions::id())]
-    /// CHECK: The instruction sysvar
-    pub instruction_sysvar_account: AccountInfo<'info>,
     pub system_program: Program<'info, System>,
 }
 
@@ -99,31 +95,38 @@ pub struct BoltMetadata {
 }
 
 #[cfg(feature = "cpi")]
-pub trait CpiContextBuilder<'info>: ToAccountMetas + ToAccountInfos<'info> + Sized {
+pub trait CpiContextBuilder<'a, 'b, 'c, 'info>:
+    ToAccountMetas + ToAccountInfos<'info> + Sized
+{
     fn build_cpi_context(
         self,
         program: AccountInfo<'info>,
-    ) -> CpiContext<'info, 'info, 'info, 'info, Self>;
+        signer_seeds: &'a [&'b [&'c [u8]]],
+    ) -> CpiContext<'a, 'b, 'c, 'info, Self>;
 }
 
 #[cfg(feature = "cpi")]
-impl<'info> CpiContextBuilder<'info> for cpi::accounts::Update<'info> {
+impl<'a, 'b, 'c, 'info> CpiContextBuilder<'a, 'b, 'c, 'info> for cpi::accounts::Update<'info> {
     fn build_cpi_context(
         self,
         program: AccountInfo<'info>,
-    ) -> CpiContext<'info, 'info, 'info, 'info, Self> {
+        signer_seeds: &'a [&'b [&'c [u8]]],
+    ) -> CpiContext<'a, 'b, 'c, 'info, Self> {
         let cpi_program = program.to_account_info();
-        CpiContext::new(cpi_program, self)
+        CpiContext::new_with_signer(cpi_program, self, signer_seeds)
     }
 }
 
 #[cfg(feature = "cpi")]
-impl<'info> CpiContextBuilder<'info> for cpi::accounts::UpdateWithSession<'info> {
+impl<'a, 'b, 'c, 'info> CpiContextBuilder<'a, 'b, 'c, 'info>
+    for cpi::accounts::UpdateWithSession<'info>
+{
     fn build_cpi_context(
         self,
         program: AccountInfo<'info>,
-    ) -> CpiContext<'info, 'info, 'info, 'info, Self> {
+        signer_seeds: &'a [&'b [&'c [u8]]],
+    ) -> CpiContext<'a, 'b, 'c, 'info, Self> {
         let cpi_program = program.to_account_info();
-        CpiContext::new(cpi_program, self)
+        CpiContext::new_with_signer(cpi_program, self, signer_seeds)
     }
 }

+ 50 - 37
crates/programs/world/src/lib.rs

@@ -261,12 +261,12 @@ pub mod world {
         if !ctx.accounts.authority.is_signer && ctx.accounts.authority.key != &ID {
             return Err(WorldError::InvalidAuthority.into());
         }
-        bolt_component::cpi::initialize(ctx.accounts.build())?;
+        bolt_component::cpi::initialize(ctx.accounts.build(&[World::cpi_auth_seeds().as_slice()]))?;
         Ok(())
     }
 
     pub fn destroy_component(ctx: Context<DestroyComponent>) -> Result<()> {
-        bolt_component::cpi::destroy(ctx.accounts.build())?;
+        bolt_component::cpi::destroy(ctx.accounts.build(&[World::cpi_auth_seeds().as_slice()]))?;
         Ok(())
     }
 
@@ -288,7 +288,8 @@ pub mod world {
                     program,
                     component,
                     ctx.accounts.authority.clone(),
-                    ctx.accounts.instruction_sysvar_account.clone(),
+                    ctx.accounts.cpi_auth.clone(),
+                    &[World::cpi_auth_seeds().as_slice()],
                 ),
                 result,
             )?;
@@ -304,9 +305,9 @@ pub mod world {
         /// CHECK: authority check
         #[account()]
         pub authority: Signer<'info>,
-        /// CHECK: instruction sysvar check
-        #[account(address = anchor_lang::solana_program::sysvar::instructions::id())]
-        pub instruction_sysvar_account: UncheckedAccount<'info>,
+        #[account()]
+        /// CHECK: cpi auth check
+        pub cpi_auth: UncheckedAccount<'info>,
         #[account()]
         pub world: Account<'info, World>,
     }
@@ -341,8 +342,9 @@ pub mod world {
                     program,
                     component,
                     ctx.accounts.authority.clone(),
-                    ctx.accounts.instruction_sysvar_account.clone(),
+                    ctx.accounts.cpi_auth.clone(),
                     ctx.accounts.session_token.clone(),
+                    &[World::cpi_auth_seeds().as_slice()],
                 ),
                 result,
             )?;
@@ -358,9 +360,9 @@ pub mod world {
         /// CHECK: authority check
         #[account()]
         pub authority: Signer<'info>,
-        /// CHECK: instruction sysvar check
-        #[account(address = anchor_lang::solana_program::sysvar::instructions::id())]
-        pub instruction_sysvar_account: UncheckedAccount<'info>,
+        #[account()]
+        /// CHECK: cpi auth check
+        pub cpi_auth: UncheckedAccount<'info>,
         #[account()]
         pub world: Account<'info, World>,
         #[account()]
@@ -533,16 +535,17 @@ pub struct InitializeComponent<'info> {
     pub component_program: AccountInfo<'info>,
     /// CHECK: authority check
     pub authority: AccountInfo<'info>,
-    #[account(address = anchor_lang::solana_program::sysvar::instructions::id())]
-    /// CHECK: instruction sysvar check
-    pub instruction_sysvar_account: UncheckedAccount<'info>,
+    #[account()]
+    /// CHECK: cpi auth check
+    pub cpi_auth: UncheckedAccount<'info>,
     pub system_program: Program<'info, System>,
 }
 
 impl<'info> InitializeComponent<'info> {
-    pub fn build(
+    pub fn build<'a, 'b, 'c>(
         &self,
-    ) -> CpiContext<'_, '_, '_, 'info, bolt_component::cpi::accounts::Initialize<'info>> {
+        signer_seeds: &'a [&'b [&'c [u8]]],
+    ) -> CpiContext<'a, 'b, 'c, 'info, bolt_component::cpi::accounts::Initialize<'info>> {
         let cpi_program = self.component_program.to_account_info();
 
         let cpi_accounts = bolt_component::cpi::accounts::Initialize {
@@ -550,10 +553,10 @@ impl<'info> InitializeComponent<'info> {
             data: self.data.to_account_info(),
             entity: self.entity.to_account_info(),
             authority: self.authority.to_account_info(),
-            instruction_sysvar_account: self.instruction_sysvar_account.to_account_info(),
+            cpi_auth: self.cpi_auth.to_account_info(),
             system_program: self.system_program.to_account_info(),
         };
-        CpiContext::new(cpi_program, cpi_accounts)
+        CpiContext::new_with_signer(cpi_program, cpi_accounts, signer_seeds)
     }
 }
 
@@ -573,16 +576,17 @@ pub struct DestroyComponent<'info> {
     #[account(mut)]
     /// CHECK: component data check
     pub component: UncheckedAccount<'info>,
-    #[account(address = anchor_lang::solana_program::sysvar::instructions::id())]
-    /// CHECK: instruction sysvar check
-    pub instruction_sysvar_account: UncheckedAccount<'info>,
+    #[account()]
+    /// CHECK: cpi auth check
+    pub cpi_auth: UncheckedAccount<'info>,
     pub system_program: Program<'info, System>,
 }
 
 impl<'info> DestroyComponent<'info> {
-    pub fn build(
+    pub fn build<'a, 'b, 'c>(
         &self,
-    ) -> CpiContext<'_, '_, '_, 'info, bolt_component::cpi::accounts::Destroy<'info>> {
+        signer_seeds: &'a [&'b [&'c [u8]]],
+    ) -> CpiContext<'a, 'b, 'c, 'info, bolt_component::cpi::accounts::Destroy<'info>> {
         let cpi_program = self.component_program.to_account_info();
 
         let cpi_accounts = bolt_component::cpi::accounts::Destroy {
@@ -591,10 +595,10 @@ impl<'info> DestroyComponent<'info> {
             entity: self.entity.to_account_info(),
             component: self.component.to_account_info(),
             component_program_data: self.component_program_data.to_account_info(),
-            instruction_sysvar_account: self.instruction_sysvar_account.to_account_info(),
+            cpi_auth: self.cpi_auth.to_account_info(),
             system_program: self.system_program.to_account_info(),
         };
-        CpiContext::new(cpi_program, cpi_accounts)
+        CpiContext::new_with_signer(cpi_program, cpi_accounts, signer_seeds)
     }
 }
 
@@ -675,6 +679,14 @@ impl World {
     pub fn pda(&self) -> (Pubkey, u8) {
         Pubkey::find_program_address(&[World::seed(), &self.id.to_be_bytes()], &crate::ID)
     }
+
+    pub fn cpi_auth_seeds() -> [&'static [u8]; 2] {
+        [b"cpi_auth", &[251]] // 251 is the pre-computed bump for cpi_auth.
+    }
+
+    pub const fn cpi_auth_address() -> Pubkey {
+        Pubkey::from_str_const("B2f2y3QTBv346wE6nWKor72AUhUvFF6mPk7TWCF2QVhi") // This is the pre-computed address for cpi_auth.
+    }
 }
 
 #[account]
@@ -704,41 +716,42 @@ impl SystemWhitelist {
 }
 
 /// Builds the context for updating a component.
-pub fn build_update_context<'info>(
+pub fn build_update_context<'a, 'b, 'c, '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>> {
+    cpi_auth: UncheckedAccount<'info>,
+    signer_seeds: &'a [&'b [&'c [u8]]],
+) -> CpiContext<'a, 'b, 'c, '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_auth = cpi_auth.to_account_info();
     let cpi_program = component_program;
     bolt_component::cpi::accounts::Update {
         bolt_component,
         authority,
-        instruction_sysvar_account,
+        cpi_auth,
     }
-    .build_cpi_context(cpi_program)
+    .build_cpi_context(cpi_program, signer_seeds)
 }
 
 /// Builds the context for updating a component.
-pub fn build_update_context_with_session<'info>(
+pub fn build_update_context_with_session<'a, 'b, 'c, 'info>(
     component_program: AccountInfo<'info>,
     bolt_component: AccountInfo<'info>,
     authority: Signer<'info>,
-    instruction_sysvar_account: UncheckedAccount<'info>,
+    cpi_auth: UncheckedAccount<'info>,
     session_token: UncheckedAccount<'info>,
-) -> CpiContext<'info, 'info, 'info, 'info, bolt_component::cpi::accounts::UpdateWithSession<'info>>
-{
+    signer_seeds: &'a [&'b [&'c [u8]]],
+) -> CpiContext<'a, 'b, 'c, 'info, bolt_component::cpi::accounts::UpdateWithSession<'info>> {
     let authority = authority.to_account_info();
-    let instruction_sysvar_account = instruction_sysvar_account.to_account_info();
+    let cpi_auth = cpi_auth.to_account_info();
     let cpi_program = component_program;
     let session_token = session_token.to_account_info();
     bolt_component::cpi::accounts::UpdateWithSession {
         bolt_component,
         authority,
-        instruction_sysvar_account,
+        cpi_auth,
         session_token,
     }
-    .build_cpi_context(cpi_program)
+    .build_cpi_context(cpi_program, signer_seeds)
 }