123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- use anchor_lang::prelude::*;
- use bolt_helpers_world_apply::apply_system;
- use tuple_conv::RepeatedTuple;
- #[cfg(not(feature = "no-entrypoint"))]
- use solana_security_txt::security_txt;
- declare_id!("WorLD15A7CrDwLcLy4fRqtaTb9fbd8o8iqiEMUDse2n");
- #[cfg(not(feature = "no-entrypoint"))]
- security_txt! {
- name: "Bolt",
- project_url: "https://magicblock.gg",
- contacts: "email:dev@magicblock.gg,twitter:@magicblock",
- policy: "",
- preferred_languages: "en",
- source_code: "https://github.com/magicblock-labs/bolt"
- }
- mod error;
- #[apply_system(max_components = 5)]
- #[program]
- pub mod world {
- use super::*;
- use crate::error::WorldError;
- pub fn initialize_registry(_ctx: Context<InitializeRegistry>) -> Result<()> {
- Ok(())
- }
- pub fn initialize_new_world(ctx: Context<InitializeNewWorld>) -> Result<()> {
- ctx.accounts.world.id = ctx.accounts.registry.worlds;
- ctx.accounts.registry.worlds += 1;
- Ok(())
- }
- #[allow(unused_variables)]
- pub fn add_entity(ctx: Context<AddEntity>, extra_seed: Option<String>) -> Result<()> {
- require!(
- ctx.accounts.world.key() == ctx.accounts.world.pda().0,
- WorldError::WorldAccountMismatch
- );
- ctx.accounts.entity.id = ctx.accounts.world.entities;
- ctx.accounts.world.entities += 1;
- Ok(())
- }
- pub fn initialize_component(ctx: Context<InitializeComponent>) -> Result<()> {
- if !ctx.accounts.authority.is_signer && ctx.accounts.authority.key != &ID {
- return Err(WorldError::InvalidAuthority.into());
- }
- bolt_component::cpi::initialize(ctx.accounts.build())?;
- Ok(())
- }
- pub fn apply<'info>(
- ctx: Context<'_, '_, '_, 'info, ApplySystem<'info>>,
- args: Vec<u8>,
- ) -> Result<()> {
- if !ctx.accounts.authority.is_signer && ctx.accounts.authority.key != &ID {
- return Err(WorldError::InvalidAuthority.into());
- }
- let remaining_accounts: Vec<AccountInfo<'info>> = ctx.remaining_accounts.to_vec();
- let res = bolt_system::cpi::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(),
- )?;
- Ok(())
- }
- #[derive(Accounts)]
- pub struct ApplySystem<'info> {
- /// CHECK: bolt component program check
- pub component_program: UncheckedAccount<'info>,
- /// CHECK: bolt system program check
- pub bolt_system: UncheckedAccount<'info>,
- #[account(mut)]
- /// CHECK: component account
- pub bolt_component: UncheckedAccount<'info>,
- /// 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>,
- }
- impl<'info> ApplySystem<'info> {
- pub fn build(
- &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(),
- authority: self.authority.to_account_info(),
- };
- CpiContext::new(cpi_program, cpi_accounts)
- }
- }
- }
- #[derive(Accounts)]
- pub struct InitializeRegistry<'info> {
- #[account(init, payer = payer, space = Registry::size(), seeds = [Registry::seed()], bump)]
- pub registry: Account<'info, Registry>,
- #[account(mut)]
- pub payer: Signer<'info>,
- pub system_program: Program<'info, System>,
- }
- #[derive(Accounts)]
- pub struct InitializeNewWorld<'info> {
- #[account(mut)]
- pub payer: Signer<'info>,
- #[account(init, payer = payer, space = World::size(), seeds = [World::seed(), ®istry.worlds.to_be_bytes()], bump)]
- pub world: Account<'info, World>,
- #[account(mut, address = Registry::pda().0)]
- pub registry: Account<'info, Registry>,
- pub system_program: Program<'info, System>,
- }
- #[derive(Accounts)]
- #[instruction(extra_seed: Option<String>)]
- pub struct AddEntity<'info> {
- #[account(mut)]
- pub payer: Signer<'info>,
- #[account(init, payer = payer, space = World::size(), seeds = [Entity::seed(), &world.id.to_be_bytes(),
- &match extra_seed {
- Some(ref seed) => [0; 8],
- None => world.entities.to_be_bytes()
- },
- match extra_seed {
- Some(ref seed) => seed.as_bytes(),
- None => &[],
- }], bump)]
- pub entity: Account<'info, Entity>,
- #[account(mut)]
- pub world: Account<'info, World>,
- pub system_program: Program<'info, System>,
- }
- #[derive(Accounts)]
- pub struct InitializeComponent<'info> {
- #[account(mut)]
- pub payer: Signer<'info>,
- #[account(mut)]
- /// CHECK: component data check
- pub data: AccountInfo<'info>,
- #[account()]
- pub entity: Account<'info, Entity>,
- /// CHECK: component program check
- 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>,
- pub system_program: Program<'info, System>,
- }
- impl<'info> InitializeComponent<'info> {
- pub fn build(
- &self,
- ) -> CpiContext<'_, '_, '_, 'info, bolt_component::cpi::accounts::Initialize<'info>> {
- let cpi_program = self.component_program.to_account_info();
- let cpi_accounts = bolt_component::cpi::accounts::Initialize {
- payer: self.payer.to_account_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(),
- system_program: self.system_program.to_account_info(),
- };
- CpiContext::new(cpi_program, cpi_accounts)
- }
- }
- #[account]
- #[derive(InitSpace, Default, Copy)]
- pub struct Registry {
- pub worlds: u64,
- }
- impl Registry {
- pub fn seed() -> &'static [u8] {
- b"registry"
- }
- pub fn size() -> usize {
- 8 + Registry::INIT_SPACE
- }
- pub fn pda() -> (Pubkey, u8) {
- Pubkey::find_program_address(&[Registry::seed()], &crate::ID)
- }
- }
- #[account]
- #[derive(InitSpace, Default, Copy)]
- pub struct World {
- pub id: u64,
- pub entities: u64,
- }
- impl World {
- pub fn seed() -> &'static [u8] {
- b"world"
- }
- pub fn size() -> usize {
- 8 + World::INIT_SPACE
- }
- pub fn pda(&self) -> (Pubkey, u8) {
- Pubkey::find_program_address(&[World::seed(), &self.id.to_be_bytes()], &crate::ID)
- }
- }
- #[account]
- #[derive(InitSpace, Default, Copy)]
- pub struct Entity {
- pub id: u64,
- }
- impl Entity {
- pub fn seed() -> &'static [u8] {
- b"entity"
- }
- }
- /// Builds the context for updating a component.
- pub fn build_update_context<'info>(
- component_program: UncheckedAccount<'info>,
- component: UncheckedAccount<'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 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(),
- };
- CpiContext::new(cpi_program, cpi_accounts)
- }
|