クイックアクセス
サンプルを見る:GitHub
Anchor 実装
dApp(近日公開)
今すぐ試す
MagicBlock の Private Ephemeral Rollup は、ノードレベルの IP ジオフェンシング、
OFAC 制裁リスト、および制限法域に基づくコンプライアンスを入口で強制し、
いかなるトランザクションも受理または実行される前に適用します。
詳しく見る
ステップごとのガイド
プログラムを構築し、MagicBlock の Permission ProgramACLseoPoyC3cBqoUtkbjZ4aDrkurZW86v19pXz2XQnp1 と Delegation Program DELeGGvXpWV2fqJUhqcF5ZSYMS4JTLjteaAMARRSaeSh を利用する権限および委任フックで拡張します。
いつもどおりに Solana プログラムを書きます。
アクセス制御を作成・管理する権限フックを追加します。詳細を見る。
権限と permissioned accounts に対する委任フックを追加し、制限を強制します。
これらの公開バリデータは開発用として利用できます。委任命令には、 対象となる ER バリデータを必ず追加してください。
メインネット- アジア (as.magicblock.app):
MAS1Dt9qreoRMQ14YQuhg8UTZMMzDdKhmkZMECCzk57 - EU (eu.magicblock.app):
MEUGGrYPxKk17hCr7wpT6s8dtNokZj5U2L57vjYMS8e - 米国 (us.magicblock.app):
MUS3hc9TCw4cGC12vHNoYcCGzJG1txjgQLZWVoeNHNd - TEE (mainnet-tee.magicblock.app):
MTEWGuqxUpYZGFJQcp8tLN7x5v9BSeoFHYWQQ3n3xzo
- アジア (devnet-as.magicblock.app):
MAS1Dt9qreoRMQ14YQuhg8UTZMMzDdKhmkZMECCzk57 - EU (devnet-eu.magicblock.app):
MEUGGrYPxKk17hCr7wpT6s8dtNokZj5U2L57vjYMS8e - 米国 (devnet-us.magicblock.app):
MUS3hc9TCw4cGC12vHNoYcCGzJG1txjgQLZWVoeNHNd - TEE (devnet-tee.magicblock.app):
FnE6VJT5QNZdedZPnCoLsARgBwoE6DeJNjBs2H1gySXA
- ローカル ER (localhost:7799):
mAGicPQYBMvcYveUZA5F5UNNwyHvfYh5xkLS2Fr1mev
Anchor CLI を使って Solana プログラムをデプロイします。
ユーザーメッセージに署名し、TEE エンドポイントから認可トークンを取得します。
認可トークンを取得し、機密トランザクションを送信します。
じゃんけんサンプル
以下のソフトウェアパッケージが必要になる場合があります。ほかのバージョンでも互換性がある可能性があります。| ソフトウェア | バージョン | インストールガイド |
|---|---|---|
| Solana | 2.3.13 | Solana をインストール |
| Rust | 1.85.0 | Rust をインストール |
| Anchor | 0.32.1 | Anchor をインストール |
| Node | 24.10.0 | Node をインストール |
コードスニペット
- 1. プログラムを書く
- 2. 制限を追加する
- 3. 委任する
- 4. デプロイする
- 5. 認可する
- 6. テストする
プレイヤーが手を選び、結果を公開するシンプルなじゃんけんプログラム:⬆️ トップに戻る
#[program]
pub mod anchor_rock_paper_scissor {
use super::*;
// 1️⃣ Create and auto-join as Player 1
pub fn create_game(ctx: Context<CreateGame>, game_id: u64) -> Result<()> {
let game = &mut ctx.accounts.game;
let player1 = ctx.accounts.player1.key();
game.game_id = game_id;
game.player1 = Some(player1);
game.player2 = None;
game.result = GameResult::None;
msg!("Game ID: {}", game_id);
msg!("Player 1 PDA: {}", player1);
// initialize PlayerChoice for player 1
let player_choice = &mut ctx.accounts.player_choice;
player_choice.game_id = game_id;
player_choice.player = player1;
player_choice.choice = None;
msg!("Game {} created and joined by {}", game_id, player1);
Ok(())
}
// 2️⃣ Player 2 joins the game
pub fn join_game(ctx: Context<JoinGame>, game_id: u64) -> Result<()> {
let game = &mut ctx.accounts.game;
let player = ctx.accounts.player.key();
require!(game.player1 != Some(player), GameError::CannotJoinOwnGame);
require!(game.player2.is_none(), GameError::GameFull);
game.player2 = Some(player);
// Create PlayerChoice PDA for player 2
let player_choice = &mut ctx.accounts.player_choice;
player_choice.game_id = game_id;
player_choice.player = player;
player_choice.choice = None;
msg!("{} joined Game {} as player 2", player, game_id);
Ok(())
}
// 3️⃣ Player makes a choice
pub fn make_choice(ctx: Context<MakeChoice>, _game_id: u64, choice: Choice) -> Result<()> {
let player_choice = &mut ctx.accounts.player_choice;
require!(player_choice.choice.is_none(), GameError::AlreadyChose);
player_choice.choice = choice.into();
msg!(
"Player {:?} made choice {:?}",
player_choice.player,
player_choice.choice
);
Ok(())
}
// 4️⃣ Reveal and record the winner
pub fn reveal_winner(ctx: Context<RevealWinner>) -> Result<()> {
let game = &mut ctx.accounts.game;
let player1_choice = &ctx.accounts.player1_choice;
let player2_choice = &ctx.accounts.player2_choice;
// 1️⃣ Clone choices into game
game.player1_choice = player1_choice.choice.clone().into();
game.player2_choice = player2_choice.choice.clone().into();
// 2️⃣ Ensure both players exist
let player1 = game.player1.ok_or(GameError::MissingOpponent)?;
let player2 = game.player2.ok_or(GameError::MissingOpponent)?;
// 3️⃣ Ensure both players made a choice
let choice1 = game
.player1_choice
.clone()
.ok_or(GameError::MissingChoice)?;
let choice2 = game
.player2_choice
.clone()
.ok_or(GameError::MissingChoice)?;
// 4️⃣ Determine winner based on choices
game.result = match (choice1, choice2) {
(Choice::Rock, Choice::Scissors)
| (Choice::Paper, Choice::Rock)
| (Choice::Scissors, Choice::Paper) => GameResult::Winner(player1),
(Choice::Rock, Choice::Paper)
| (Choice::Paper, Choice::Scissors)
| (Choice::Scissors, Choice::Rock) => GameResult::Winner(player2),
_ => GameResult::Tie,
};
msg!("Result: {:?}", &game.result);
Ok(())
}
}
#[derive(Accounts)]
#[instruction(game_id: u64)]
pub struct CreateGame<'info> {
#[account(
init_if_needed,
payer = player1,
space = 8 + Game::LEN,
seeds = [GAME_SEED, &game_id.to_le_bytes()],
bump
)]
pub game: Account<'info, Game>,
#[account(
init_if_needed,
payer = player1,
space = 8 + PlayerChoice::LEN,
seeds = [PLAYER_CHOICE_SEED, &game_id.to_le_bytes(), player1.key().as_ref()],
bump
)]
pub player_choice: Account<'info, PlayerChoice>,
#[account(mut)]
pub player1: Signer<'info>,
pub system_program: Program<'info, System>,
}
#[derive(Accounts)]
#[instruction(game_id: u64)]
pub struct JoinGame<'info> {
#[account(
mut,
seeds = [GAME_SEED, &game_id.to_le_bytes()],
bump
)]
pub game: Account<'info, Game>,
#[account(
init_if_needed,
payer = player,
space = 8 + PlayerChoice::LEN,
seeds = [PLAYER_CHOICE_SEED, &game_id.to_le_bytes(), player.key().as_ref()],
bump
)]
pub player_choice: Account<'info, PlayerChoice>,
#[account(mut)]
pub player: Signer<'info>,
pub system_program: Program<'info, System>,
}
#[derive(Accounts)]
#[instruction(game_id: u64)]
pub struct MakeChoice<'info> {
#[account(
mut,
seeds = [PLAYER_CHOICE_SEED, &game_id.to_le_bytes(), player.key().as_ref()],
bump
)]
pub player_choice: Account<'info, PlayerChoice>,
#[account(mut)]
pub player: Signer<'info>,
}
#[derive(Accounts)]
pub struct RevealWinner<'info> {
#[account(mut, seeds = [GAME_SEED, &game.game_id.to_le_bytes()], bump)]
pub game: Account<'info, Game>,
/// Player1's choice PDA (derived automatically)
#[account(
mut,
seeds = [PLAYER_CHOICE_SEED, &game.game_id.to_le_bytes(), game.player1.unwrap().as_ref()],
bump
)]
pub player1_choice: Account<'info, PlayerChoice>,
/// Player2's choice PDA (derived automatically)
#[account(
mut,
seeds = [PLAYER_CHOICE_SEED, &game.game_id.to_le_bytes(), game.player2.unwrap().as_ref()],
bump
)]
pub player2_choice: Account<'info, PlayerChoice>,
#[account(mut)]
pub payer: Signer<'info>,
}
#[account]
pub struct Game {
pub game_id: u64,
pub player1: Option<Pubkey>,
pub player2: Option<Pubkey>,
pub player1_choice: Option<Choice>,
pub player2_choice: Option<Choice>,
pub result: GameResult,
}
impl Game {
pub const LEN: usize = 8 // game_id
+ (32 + 1) * 2 // player1, player2
+ (1 + 1) * 2 // player1_choice, player2_choice
+ (1 + 32); // result (1 byte tag + 32 bytes pubkey for Winner variant)
}
#[derive(AnchorSerialize, AnchorDeserialize, Clone, PartialEq, Eq, Debug)]
pub enum GameResult {
Winner(Pubkey),
Tie,
None,
}
#[account]
pub struct PlayerChoice {
pub game_id: u64,
pub player: Pubkey,
pub choice: Option<Choice>,
}
impl PlayerChoice {
pub const LEN: usize = 8 + 8 + 32 + 2;
}
#[derive(AnchorSerialize, AnchorDeserialize, Clone, PartialEq, Eq, Debug)]
pub enum Choice {
Rock,
Paper,
Scissors,
}
#[error_code]
pub enum GameError {
#[msg("You already made your choice.")]
AlreadyChose,
#[msg("You cannot join your own game.")]
CannotJoinOwnGame,
#[msg("Both players must make a choice first.")]
MissingChoice,
#[msg("Opponent not found.")]
MissingOpponent,
#[msg("Game is already full.")]
GameFull,
}
/// ... Other context and accounts for delegation and privacy
MagicBlock の Permission Program ⬆️ トップに戻る
ACLseoPoyC3cBqoUtkbjZ4aDrkurZW86v19pXz2XQnp1 を通じて、メンバー付きのアカウントレベル権限を作成・更新します。詳細を見る:#[program]
pub mod anchor_rock_paper_scissor {
use super::*;
// 4️⃣ Reveal and record the winner
pub fn reveal_winner(ctx: Context<RevealWinner>) -> Result<()> {
let game = &mut ctx.accounts.game;
let player1_choice = &ctx.accounts.player1_choice;
let player2_choice = &ctx.accounts.player2_choice;
let permission_program = &ctx.accounts.permission_program.to_account_info();
let permission_game = &ctx.accounts.permission_game.to_account_info();
let permission1 = &ctx.accounts.permission1.to_account_info();
let permission2 = &ctx.accounts.permission2.to_account_info();
let magic_program = &ctx.accounts.magic_program.to_account_info();
let magic_context = &ctx.accounts.magic_context.to_account_info();
// 1️⃣ Clone choices into game
game.player1_choice = player1_choice.choice.clone().into();
game.player2_choice = player2_choice.choice.clone().into();
// 2️⃣ Ensure both players exist
let player1 = game.player1.ok_or(GameError::MissingOpponent)?;
let player2 = game.player2.ok_or(GameError::MissingOpponent)?;
// 3️⃣ Ensure both players made a choice
let choice1 = game
.player1_choice
.clone()
.ok_or(GameError::MissingChoice)?;
let choice2 = game
.player2_choice
.clone()
.ok_or(GameError::MissingChoice)?;
// 4️⃣ Determine winner based on choices
game.result = match (choice1, choice2) {
(Choice::Rock, Choice::Scissors)
| (Choice::Paper, Choice::Rock)
| (Choice::Scissors, Choice::Paper) => GameResult::Winner(player1),
(Choice::Rock, Choice::Paper)
| (Choice::Paper, Choice::Scissors)
| (Choice::Scissors, Choice::Rock) => GameResult::Winner(player2),
_ => GameResult::Tie,
};
// Update Permissions for reveal
UpdatePermissionCpiBuilder::new(&permission_program)
.permissioned_account(&game.to_account_info(), true)
.authority(&game.to_account_info(), false)
.permission(&permission_game.to_account_info())
.args(MembersArgs { members: None })
.invoke_signed(&[&[GAME_SEED, &game.game_id.to_le_bytes(), &[ctx.bumps.game]]])?;
UpdatePermissionCpiBuilder::new(&permission_program)
.permissioned_account(&player1_choice.to_account_info(), true)
.authority(&player1_choice.to_account_info(), false)
.permission(&permission1.to_account_info())
.args(MembersArgs { members: None })
.invoke_signed(&[&[
PLAYER_CHOICE_SEED,
&player1_choice.game_id.to_le_bytes(),
&player1_choice.player.as_ref(),
&[ctx.bumps.player1_choice],
]])?;
UpdatePermissionCpiBuilder::new(&permission_program)
.permissioned_account(&player2_choice.to_account_info(), true)
.authority(&player2_choice.to_account_info(), false)
.permission(&permission2.to_account_info())
.args(MembersArgs { members: None })
.invoke_signed(&[&[
PLAYER_CHOICE_SEED,
&player2_choice.game_id.to_le_bytes(),
&player2_choice.player.as_ref(),
&[ctx.bumps.player2_choice],
]])?;
msg!("Result: {:?}", &game.result);
Ok(())
}
/// Creates a permission based on account type input.
/// Derives the bump from the account type and seeds, then calls the permission program.
pub fn create_permission(
ctx: Context<CreatePermission>,
account_type: AccountType,
members: Option<Vec<Member>>,
) -> Result<()> {
let CreatePermission {
permissioned_account,
permission,
payer,
permission_program,
system_program,
} = ctx.accounts;
let seed_data = derive_seeds_from_account_type(&account_type);
let (_, bump) = Pubkey::find_program_address(
&seed_data.iter().map(|s| s.as_slice()).collect::<Vec<_>>(),
&crate::ID,
);
let mut seeds = seed_data.clone();
seeds.push(vec![bump]);
let seed_refs: Vec<&[u8]> = seeds.iter().map(|s| s.as_slice()).collect();
CreatePermissionCpiBuilder::new(&permission_program)
.permissioned_account(&permissioned_account.to_account_info())
.permission(&permission)
.payer(&payer)
.system_program(&system_program)
.args(MembersArgs { members })
.invoke_signed(&[seed_refs.as_slice()])?;
Ok(())
}
}
#[derive(Accounts)]
pub struct RevealWinner<'info> {
#[account(mut, seeds = [GAME_SEED, &game.game_id.to_le_bytes()], bump)]
pub game: Account<'info, Game>,
/// Player1's choice PDA (derived automatically)
#[account(
mut,
seeds = [PLAYER_CHOICE_SEED, &game.game_id.to_le_bytes(), game.player1.unwrap().as_ref()],
bump
)]
pub player1_choice: Account<'info, PlayerChoice>,
/// Player2's choice PDA (derived automatically)
#[account(
mut,
seeds = [PLAYER_CHOICE_SEED, &game.game_id.to_le_bytes(), game.player2.unwrap().as_ref()],
bump
)]
pub player2_choice: Account<'info, PlayerChoice>,
/// CHECK: Checked by the permission program
#[account(mut)]
pub permission_game: UncheckedAccount<'info>,
/// CHECK: Checked by the permission program
#[account(mut)]
pub permission1: UncheckedAccount<'info>,
/// CHECK: Checked by the permission program
#[account(mut)]
pub permission2: UncheckedAccount<'info>,
/// Anyone can trigger this
#[account(mut)]
pub payer: Signer<'info>,
/// CHECK: PERMISSION PROGRAM
#[account(address = PERMISSION_PROGRAM_ID)]
pub permission_program: UncheckedAccount<'info>,
}
#[derive(Accounts)]
pub struct CreatePermission<'info> {
/// CHECK: Validated via permission program CPI
pub permissioned_account: UncheckedAccount<'info>,
/// CHECK: Checked by the permission program
#[account(mut)]
pub permission: UncheckedAccount<'info>,
#[account(mut)]
pub payer: Signer<'info>,
/// CHECK: PERMISSION PROGRAM
#[account(address = PERMISSION_PROGRAM_ID)]
pub permission_program: UncheckedAccount<'info>,
pub system_program: Program<'info, System>,
}
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub enum AccountType {
Game { game_id: u64 },
PlayerChoice { game_id: u64, player: Pubkey },
}
fn derive_seeds_from_account_type(account_type: &AccountType) -> Vec<Vec<u8>> {
match account_type {
AccountType::Game { game_id } => {
vec![GAME_SEED.to_vec(), game_id.to_le_bytes().to_vec()]
}
AccountType::PlayerChoice { game_id, player } => {
vec![
PLAYER_CHOICE_SEED.to_vec(),
game_id.to_le_bytes().to_vec(),
player.to_bytes().to_vec(),
]
}
}
}
/// Other context and accounts ...
MagicBlock の Delegation Program ⬆️ トップに戻る
DELeGGvXpWV2fqJUhqcF5ZSYMS4JTLjteaAMARRSaeSh を通じて TEE バリデータへ委任し、アカウントのプライバシーを強制します。permission と permissioned_account の両方を委任する必要があります。これらの公開バリデータは開発用として利用できます。委任命令には、 対象となる ER バリデータを必ず追加してください。
メインネット- アジア (as.magicblock.app):
MAS1Dt9qreoRMQ14YQuhg8UTZMMzDdKhmkZMECCzk57 - EU (eu.magicblock.app):
MEUGGrYPxKk17hCr7wpT6s8dtNokZj5U2L57vjYMS8e - 米国 (us.magicblock.app):
MUS3hc9TCw4cGC12vHNoYcCGzJG1txjgQLZWVoeNHNd - TEE (mainnet-tee.magicblock.app):
MTEWGuqxUpYZGFJQcp8tLN7x5v9BSeoFHYWQQ3n3xzo
- アジア (devnet-as.magicblock.app):
MAS1Dt9qreoRMQ14YQuhg8UTZMMzDdKhmkZMECCzk57 - EU (devnet-eu.magicblock.app):
MEUGGrYPxKk17hCr7wpT6s8dtNokZj5U2L57vjYMS8e - 米国 (devnet-us.magicblock.app):
MUS3hc9TCw4cGC12vHNoYcCGzJG1txjgQLZWVoeNHNd - TEE (devnet-tee.magicblock.app):
FnE6VJT5QNZdedZPnCoLsARgBwoE6DeJNjBs2H1gySXA
- ローカル ER (localhost:7799):
mAGicPQYBMvcYveUZA5F5UNNwyHvfYh5xkLS2Fr1mev
#[ephemeral] // This adds undelegation instruction for ER validator
#[program]
pub mod anchor_rock_paper_scissor {
use super::*;
// Other instructions
// 4️⃣ Reveal and record the winner
pub fn reveal_winner(ctx: Context<RevealWinner>) -> Result<()> {
let game = &mut ctx.accounts.game;
let player1_choice = &ctx.accounts.player1_choice;
let player2_choice = &ctx.accounts.player2_choice;
let permission_program = &ctx.accounts.permission_program.to_account_info();
let permission_game = &ctx.accounts.permission_game.to_account_info();
let permission1 = &ctx.accounts.permission1.to_account_info();
let permission2 = &ctx.accounts.permission2.to_account_info();
let magic_program = &ctx.accounts.magic_program.to_account_info();
let magic_context = &ctx.accounts.magic_context.to_account_info();
// 1️⃣ Clone choices into game
game.player1_choice = player1_choice.choice.clone().into();
game.player2_choice = player2_choice.choice.clone().into();
// 2️⃣ Ensure both players exist
let player1 = game.player1.ok_or(GameError::MissingOpponent)?;
let player2 = game.player2.ok_or(GameError::MissingOpponent)?;
// 3️⃣ Ensure both players made a choice
let choice1 = game
.player1_choice
.clone()
.ok_or(GameError::MissingChoice)?;
let choice2 = game
.player2_choice
.clone()
.ok_or(GameError::MissingChoice)?;
// 4️⃣ Determine winner based on choices
game.result = match (choice1, choice2) {
(Choice::Rock, Choice::Scissors)
| (Choice::Paper, Choice::Rock)
| (Choice::Scissors, Choice::Paper) => GameResult::Winner(player1),
(Choice::Rock, Choice::Paper)
| (Choice::Paper, Choice::Scissors)
| (Choice::Scissors, Choice::Rock) => GameResult::Winner(player2),
_ => GameResult::Tie,
};
UpdatePermissionCpiBuilder::new(&permission_program)
.permissioned_account(&game.to_account_info(), true)
.authority(&game.to_account_info(), false)
.permission(&permission_game.to_account_info())
.args(MembersArgs { members: None })
.invoke_signed(&[&[GAME_SEED, &game.game_id.to_le_bytes(), &[ctx.bumps.game]]])?;
UpdatePermissionCpiBuilder::new(&permission_program)
.permissioned_account(&player1_choice.to_account_info(), true)
.authority(&player1_choice.to_account_info(), false)
.permission(&permission1.to_account_info())
.args(MembersArgs { members: None })
.invoke_signed(&[&[
PLAYER_CHOICE_SEED,
&player1_choice.game_id.to_le_bytes(),
&player1_choice.player.as_ref(),
&[ctx.bumps.player1_choice],
]])?;
UpdatePermissionCpiBuilder::new(&permission_program)
.permissioned_account(&player2_choice.to_account_info(), true)
.authority(&player2_choice.to_account_info(), false)
.permission(&permission2.to_account_info())
.args(MembersArgs { members: None })
.invoke_signed(&[&[
PLAYER_CHOICE_SEED,
&player2_choice.game_id.to_le_bytes(),
&player2_choice.player.as_ref(),
&[ctx.bumps.player2_choice],
]])?;
msg!("Result: {:?}", &game.result);
game.exit(&crate::ID)?;
commit_and_undelegate_accounts(
&ctx.accounts.payer,
vec![&game.to_account_info()],
magic_context,
magic_program,
)?;
Ok(())
}
/// Delegate account to the delegation program based on account type
/// Set specific validator based on ER, see https://docs.magicblock.gg/pages/get-started/how-integrate-your-program/local-setup
pub fn delegate_pda(ctx: Context<DelegatePda>, account_type: AccountType) -> Result<()> {
let seed_data = derive_seeds_from_account_type(&account_type);
let seeds_refs: Vec<&[u8]> = seed_data.iter().map(|s| s.as_slice()).collect();
let validator = ctx.accounts.validator.as_ref().map(|v| v.key());
ctx.accounts.delegate_pda(
&ctx.accounts.payer,
&seeds_refs,
DelegateConfig {
validator,
..Default::default()
},
)?;
Ok(())
}
}
#[commit] // adding magic_context and magic_program accounts to context
#[derive(Accounts)]
pub struct RevealWinner<'info> {
#[account(mut, seeds = [GAME_SEED, &game.game_id.to_le_bytes()], bump)]
pub game: Account<'info, Game>,
/// Player1's choice PDA (derived automatically)
#[account(
mut,
seeds = [PLAYER_CHOICE_SEED, &game.game_id.to_le_bytes(), game.player1.unwrap().as_ref()],
bump
)]
pub player1_choice: Account<'info, PlayerChoice>,
/// Player2's choice PDA (derived automatically)
#[account(
mut,
seeds = [PLAYER_CHOICE_SEED, &game.game_id.to_le_bytes(), game.player2.unwrap().as_ref()],
bump
)]
pub player2_choice: Account<'info, PlayerChoice>,
/// CHECK: Checked by the permission program
#[account(mut)]
pub permission_game: UncheckedAccount<'info>,
/// CHECK: Checked by the permission program
#[account(mut)]
pub permission1: UncheckedAccount<'info>,
/// CHECK: Checked by the permission program
#[account(mut)]
pub permission2: UncheckedAccount<'info>,
/// Anyone can trigger this
#[account(mut)]
pub payer: Signer<'info>,
/// CHECK: PERMISSION PROGRAM
#[account(address = PERMISSION_PROGRAM_ID)]
pub permission_program: UncheckedAccount<'info>,
}
/// Unified delegate PDA context
#[delegate] // enable delegation
#[derive(Accounts)]
pub struct DelegatePda<'info> {
/// CHECK: The PDA to delegate
#[account(mut, del)]
pub pda: AccountInfo<'info>,
pub payer: Signer<'info>,
/// CHECK: Checked by the delegate program
pub validator: Option<AccountInfo<'info>>,
}
#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub enum AccountType {
Game { game_id: u64 },
PlayerChoice { game_id: u64, player: Pubkey },
}
fn derive_seeds_from_account_type(account_type: &AccountType) -> Vec<Vec<u8>> {
match account_type {
AccountType::Game { game_id } => {
vec![GAME_SEED.to_vec(), game_id.to_le_bytes().to_vec()]
}
AccountType::PlayerChoice { game_id, player } => {
vec![
PLAYER_CHOICE_SEED.to_vec(),
game_id.to_le_bytes().to_vec(),
player.to_bytes().to_vec(),
]
}
}
}
TEE 内の ER RPC との接続を設定します:⬆️ トップに戻る
https://pccs.phala.network/tdx/certification/v4を通じて TEE RPC の完全性を検証する- ユーザーが TEE エンドポイントとやり取りするための認可トークンを要求する
Web3.js
import {
verifyTeeRpcIntegrity,
getAuthToken,
} from "@magicblock-labs/ephemeral-rollups-sdk";
// Verify the integrity of TEE RPC
const isVerified = await verifyTeeRpcIntegrity(EPHEMERAL_RPC_URL);
// Get AuthToken before making request to TEE
const token = await getAuthToken(
EPHEMERAL_RPC_URL,
wallet.publicKey,
(message: Uint8Array) =>
Promise.resolve(nacl.sign.detached(message, wallet.secretKey))
);
Private Ephemeral Rollup 接続でプログラムをテストします:⬆️ トップに戻る
https://devnet-tee.magicblock.app?token=${token}これらの公開バリデータは開発用として利用できます。委任命令には、 対象となる ER バリデータを必ず追加してください。
メインネット- アジア (as.magicblock.app):
MAS1Dt9qreoRMQ14YQuhg8UTZMMzDdKhmkZMECCzk57 - EU (eu.magicblock.app):
MEUGGrYPxKk17hCr7wpT6s8dtNokZj5U2L57vjYMS8e - 米国 (us.magicblock.app):
MUS3hc9TCw4cGC12vHNoYcCGzJG1txjgQLZWVoeNHNd - TEE (mainnet-tee.magicblock.app):
MTEWGuqxUpYZGFJQcp8tLN7x5v9BSeoFHYWQQ3n3xzo
- アジア (devnet-as.magicblock.app):
MAS1Dt9qreoRMQ14YQuhg8UTZMMzDdKhmkZMECCzk57 - EU (devnet-eu.magicblock.app):
MEUGGrYPxKk17hCr7wpT6s8dtNokZj5U2L57vjYMS8e - 米国 (devnet-us.magicblock.app):
MUS3hc9TCw4cGC12vHNoYcCGzJG1txjgQLZWVoeNHNd - TEE (devnet-tee.magicblock.app):
FnE6VJT5QNZdedZPnCoLsARgBwoE6DeJNjBs2H1gySXA
- ローカル ER (localhost:7799):
mAGicPQYBMvcYveUZA5F5UNNwyHvfYh5xkLS2Fr1mev
クイックアクセス
サンプルを見る:GitHub
Anchor 実装
dApp(近日公開)
今すぐ試す
アクセス制御
きめ細かなアクセス制御
オンチェーンプライバシー
プライバシーの仕組みと概念
認可
認可フレームワーク
コンプライアンスフレームワーク
コンプライアンス基準とガイドライン
Solana エクスプローラー
Solana 上のトランザクションとアカウントの情報を確認できます。Solana エクスプローラー
公式 Solana エクスプローラー
Solscan
Solana ブロックチェーンを探索する
Solana RPC プロバイダー
既存の RPC プロバイダーを通じてトランザクションやリクエストを送信します。Solana
Free Public Nodes
Helius
Free Shared Nodes
Triton
Dedicated High-Performance Nodes
Solana バリデータダッシュボード
Solana バリデータインフラのリアルタイム更新を確認できます。Solana Beach
Get Validator Insights
Validators App
Discover Validator Metrics
サーバーステータス
Solana と MagicBlock のサーバーステータスを確認しましょう。Solana Status
Subscribe to Solana Server Updates
MagicBlock Status
Subscribe to MagicBlock Server Status
MagicBlock 製品
エフェメラルロールアップ(ER)
Solana 上でリアルタイムかつ手数料ゼロのトランザクションを安全に実行します。
プライベート・エフェメラルロールアップ(PER)
プライバシー保護計算で機密データを守ります。
プライベート決済 API
Solana 上で安全かつコンプライアンスに配慮したプライベート送金を実現します。
検証可能ランダム関数(VRF)
証明可能に公平なランダム性をオンチェーンで直接生成します。
価格オラクル
取引や DeFi 向けの低遅延オンチェーン価格フィードにアクセスできます。

