diff --git a/clients/csharp/Solana.Unity.Bolt/WorldProgram/Generated.cs b/clients/csharp/Solana.Unity.Bolt/WorldProgram/Generated.cs index 82ba99a4..9d5cf637 100644 --- a/clients/csharp/Solana.Unity.Bolt/WorldProgram/Generated.cs +++ b/clients/csharp/Solana.Unity.Bolt/WorldProgram/Generated.cs @@ -277,7 +277,7 @@ public class ApplyAccounts 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 @@ public class ApplyWithSessionAccounts 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 @@ public class DestroyComponentAccounts 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 @@ public class InitializeComponentAccounts 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 @@ public static Solana.Unity.Rpc.Models.TransactionInstruction Apply(ApplyAccounts { programId ??= new(ID); List 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 @@ public static Solana.Unity.Rpc.Models.TransactionInstruction ApplyWithSession(Ap { programId ??= new(ID); List 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 @@ public static Solana.Unity.Rpc.Models.TransactionInstruction DestroyComponent(De { programId ??= new(ID); List 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 @@ public static Solana.Unity.Rpc.Models.TransactionInstruction InitializeComponent { programId ??= new(ID); List 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); diff --git a/clients/typescript/src/generated/idl/world.json b/clients/typescript/src/generated/idl/world.json index 0e929457..3fc9bfcc 100644 --- a/clients/typescript/src/generated/idl/world.json +++ b/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", diff --git a/clients/typescript/src/generated/instructions/apply.ts b/clients/typescript/src/generated/instructions/apply.ts index 0de45d6b..3210443a 100644 --- a/clients/typescript/src/generated/instructions/apply.ts +++ b/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, }, diff --git a/clients/typescript/src/generated/instructions/initializeComponent.ts b/clients/typescript/src/generated/instructions/initializeComponent.ts index 5f379e9e..0d14c217 100644 --- a/clients/typescript/src/generated/instructions/initializeComponent.ts +++ b/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, }, diff --git a/clients/typescript/src/generated/types/world.ts b/clients/typescript/src/generated/types/world.ts index 8c8428b1..ac6ef36c 100644 --- a/clients/typescript/src/generated/types/world.ts +++ b/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"; diff --git a/clients/typescript/src/world/transactions.ts b/clients/typescript/src/world/transactions.ts index a99919de..f52c5a09 100644 --- a/clients/typescript/src/world/transactions.ts +++ b/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(); diff --git a/clients/typescript/test/low-level/ecs.ts b/clients/typescript/test/low-level/ecs.ts index 985f1390..43f7b8ca 100644 --- a/clients/typescript/test/low-level/ecs.ts +++ b/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); diff --git a/clients/typescript/test/low-level/permissioning/component.ts b/clients/typescript/test/low-level/permissioning/component.ts index dab52753..610cf03f 100644 --- a/clients/typescript/test/low-level/permissioning/component.ts +++ b/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([ { diff --git a/clients/typescript/test/low-level/permissioning/world.ts b/clients/typescript/test/low-level/permissioning/world.ts index 1d0426e0..3044ac00 100644 --- a/clients/typescript/test/low-level/permissioning/world.ts +++ b/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([ { diff --git a/clients/typescript/test/low-level/session.ts b/clients/typescript/test/low-level/session.ts index d86e63fb..f613ec29 100644 --- a/clients/typescript/test/low-level/session.ts +++ b/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([ { diff --git a/crates/bolt-lang/attribute/bolt-program/src/lib.rs b/crates/bolt-lang/attribute/bolt-program/src/lib.rs index 5dda3383..bd81804c 100644 --- a/crates/bolt-lang/attribute/bolt-program/src/lib.rs +++ b/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) -> 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, data: Vec) -> 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>, } diff --git a/crates/programs/bolt-component/src/lib.rs b/crates/programs/bolt-component/src/lib.rs index 3d22538c..8f826b46 100644 --- a/crates/programs/bolt-component/src/lib.rs +++ b/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) } } diff --git a/crates/programs/world/src/lib.rs b/crates/programs/world/src/lib.rs index 4d4e0f14..da532575 100644 --- a/crates/programs/world/src/lib.rs +++ b/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) -> 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) }