Documentation Index
Fetch the complete documentation index at: https://docs.magicblock.gg/llms.txt
Use this file to discover all available pages before exploring further.
Permission Program
온체인 권한 관리(출시 예정)
Ephemeral Rollups SDK
Private Ephemeral Rollups용 SDK
개요
Private Ephemeral Rollups는 컴플라이언스를 핵심에 둔 Trusted Execution Environment 안에서 permissioned accounts에 대한 세밀한 권한 제어를 가능하게 하는 Ephemeral Rollups입니다. 각 permission account는 멤버 목록과 이들이 수행할 수 있는 작업을 결정하는 특정 플래그를 유지합니다.핵심 개념
- Permission Account: 특정 계정에 대한 접근 제어 규칙을 저장하는 PDA
- Members: 플래그를 통해 특정 권한이 부여된 주소
- Flags: 멤버가 무엇을 할 수 있는지(authority, 로그 보기, 잔액 보기 등)를 정의하는 비트마스크
- Public Permissions: 멤버가
None으로 설정되면 permissioned account가 일시적으로 보이게 됩니다
멤버 플래그
멤버 플래그는 각 멤버에 대한 세밀한 권한을 정의합니다. 플래그는 비트 OR로 결합해 여러 권한을 동시에 부여할 수 있습니다. 플래그 설명:- AUTHORITY: 멤버가 permission 설정을 업데이트하고 위임하며, 다른 멤버를 추가/제거하고 멤버 플래그를 업데이트할 수 있게 합니다.
- TX_LOGS: 멤버가 트랜잭션 실행 로그를 볼 수 있게 합니다.
- TX_BALANCES: 멤버가 계정 잔액 변화를 볼 수 있게 합니다.
- TX_MESSAGE: 멤버가 트랜잭션 메시지 데이터를 볼 수 있게 합니다.
- ACCOUNT_SIGNATURES: 멤버가 계정 서명을 볼 수 있게 합니다
- Rust SDK
- Pinocchio
- Web3.js
- Kit
use ephemeral_rollups_sdk::access_control::structs::{
Member,
AUTHORITY_FLAG,
TX_LOGS_FLAG,
TX_BALANCES_FLAG,
TX_MESSAGE_FLAG,
ACCOUNT_SIGNATURES_FLAG,
};
// Set flags by combining them with bitwise OR
let flags = AUTHORITY_FLAG | TX_LOGS_FLAG;
// Create a member with combined flags
let mut member = Member {
flags,
pubkey: user_pubkey,
};
// Check if member has a specific flag using bitwise AND
let is_authority = (member.flags & AUTHORITY_FLAG) != 0;
let can_see_logs = (member.flags & TX_LOGS_FLAG) != 0;
// Use helper methods to set/remove flags
member.set_flags(TX_BALANCES_FLAG); // Add a flag
member.remove_flags(TX_LOGS_FLAG); // Remove a flag
use ephemeral_rollups_pinocchio::types::{Member, MemberFlags};
use pinocchio::Address;
// Create and set flags using individual methods
let mut flags = MemberFlags::new();
flags.set(MemberFlags::AUTHORITY);
flags.set(MemberFlags::TX_LOGS);
flags.set(MemberFlags::TX_BALANCES);
// Create a member with flags
let member = Member {
flags,
pubkey: user_address,
};
// Remove a flag
flags.remove(MemberFlags::TX_LOGS);
// Create flags from individual boolean values
let flags = MemberFlags::from_acl_flags(
true, // authority
true, // tx_logs
false, // tx_balances
true, // tx_message
false, // account_signatures
);
// Convert flags to byte value
let flag_byte = flags.to_acl_flag_byte();
// Create flags from byte value
let flags = MemberFlags::from_acl_flag_byte(flag_byte);
import { PublicKey } from "@solana/web3.js";
import {
AUTHORITY_FLAG,
TX_LOGS_FLAG,
TX_BALANCES_FLAG,
TX_MESSAGE_FLAG,
ACCOUNT_SIGNATURES_FLAG,
type Member,
} from "@magicblock-labs/ephemeral-rollups-sdk";
// Set flags by combining them with bitwise OR
const flags = AUTHORITY_FLAG | TX_LOGS_FLAG;
// Create a member with combined flags
const member: Member = {
flags,
pubkey: new PublicKey(userAddress),
};
// Check if a flag is present using bitwise AND
const isAuthority = (member.flags & AUTHORITY_FLAG) !== 0;
const canSeeLogs = (member.flags & TX_LOGS_FLAG) !== 0;
const canSeeBalances = (member.flags & TX_BALANCES_FLAG) !== 0;
// Add a flag to existing flags
const updatedFlags = member.flags | TX_BALANCES_FLAG;
// Remove a flag from existing flags
const removedFlags = member.flags & ~TX_LOGS_FLAG;
import {
AUTHORITY_FLAG,
TX_LOGS_FLAG,
TX_BALANCES_FLAG,
TX_MESSAGE_FLAG,
ACCOUNT_SIGNATURES_FLAG,
isAuthority,
canSeeTxLogs,
canSeeTxBalances,
canSeeTxMessages,
canSeeAccountSignatures,
type Member,
} from "@magicblock-labs/ephemeral-rollups-sdk";
// Set flags by combining them with bitwise OR
const flags = AUTHORITY_FLAG | TX_LOGS_FLAG | TX_BALANCES_FLAG;
// Create a member with combined flags
const member: Member = {
flags,
pubkey: userAddress,
};
// Use helper functions to check specific permissions
const canModifyPermission = isAuthority(member, userAddress);
const canViewLogs = canSeeTxLogs(member, userAddress);
const canViewBalances = canSeeTxBalances(member, userAddress);
const canViewMessages = canSeeTxMessages(member, userAddress);
const canViewSignatures = canSeeAccountSignatures(member, userAddress);
// Add a flag to existing member
const updatedFlags = member.flags | TX_MESSAGE_FLAG;
// Remove a flag from existing member
const removedFlags = member.flags & ~TX_LOGS_FLAG;
Permission 라이프사이클
permissioned account의 일반적인 라이프사이클은 MagicBlock의 Permission ProgramACLseoPoyC3cBqoUtkbjZ4aDrkurZW86v19pXz2XQnp1 및 Delegation Program DELeGGvXpWV2fqJUhqcF5ZSYMS4JTLjteaAMARRSaeSh과의 상호작용을 필요로 합니다.
초기 멤버와 그 플래그를 포함한 새 permission account를 초기화합니다.
Private Ephemeral Rollup에 permission을 위임해 강제력 있는 실시간 접근 제어를 활성화합니다.
이 공용 검증자들은 개발용으로 지원됩니다. 위임 명령에 해당 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):
MTEWGuqxUpYZGFJQcp8tLN7x5v9BSeoFHYWQQ3n3xzo
- 로컬 ER (localhost:7799):
mAGicPQYBMvcYveUZA5F5UNNwyHvfYh5xkLS2Fr1mev
필요에 따라 멤버 권한을 추가, 제거, 수정합니다. 업데이트는 Private Ephemeral Rollup에서 실시간으로 수행할 수 있습니다.
요청을 수행하기 전에 TEE RPC 무결성을 검증하고 인가 토큰을 받아야 합니다. 적절한 플래그를 가진 멤버만 계정 상태에 접근하거나 수정할 수 있습니다.
최종 상태를 Solana로 동기화하고 계정을 Base Layer 제어로 되돌립니다.
더 이상 필요하지 않으면 permission account를 닫고 lamports를 회수합니다.
Permission 작업
- 1. 생성
- 2. 위임
- 3. 업데이트
- 4. 요청
- 5. 커밋 및 위임 해제
- 6. 닫기
프로그램을 만든 뒤 permission 및 delegation 훅을 추가해 계정 접근을 제어할 수 있습니다. 예시는 빠른 시작을 참고하세요.MagicBlock의 Permission Program 사용 사례:
ACLseoPoyC3cBqoUtkbjZ4aDrkurZW86v19pXz2XQnp1을 통해 초기 멤버와 플래그를 포함한 새 permission account를 생성합니다.- Rust SDK
- Pinocchio
- Kit
- Web3.js
use ephemeral_rollups_sdk::access_control::{
instructions::CreatePermissionCpiBuilder,
structs::{
Member,
MembersArgs,
AUTHORITY_FLAG, // Member can directly modify the permission
TX_LOGS_FLAG, // Member can view transaction logs
TX_BALANCES_FLAG // Member can view account balances
}
};
let members = Some(vec![
Member {
// AUTHORITY_FLAG allows this member to modify permission settings
// TX_LOGS_FLAG allows viewing transaction logs
flags: AUTHORITY_FLAG | TX_LOGS_FLAG,
pubkey: *payer.key,
},
]);
// Note: Either the authority or permissioned_account can sign the transaction
// The signer depends on who has AUTHORITY_FLAG in the members list
CreatePermissionCpiBuilder::new(&permission_program)
.permissioned_account(&permissioned_account)
.permission(&permission)
.payer(&payer)
.system_program(&system_program)
.args(MembersArgs { members })
.invoke_signed(&[seed_refs.as_slice()])?;
use ephemeral_rollups_pinocchio::instruction::create_permission;
use ephemeral_rollups_pinocchio::types::{
Member,
MemberFlags,
MembersArgs,
};
use pinocchio::AccountView;
// Create members with specific flags
// AUTHORITY - Member can directly modify the permission
// TX_LOGS - Member can view transaction logs
// TX_BALANCES - Member can view account balances
// TX_MESSAGE - Member can view transaction messages
// ACCOUNT_SIGNATURES - Member can view account signatures
let mut flags = MemberFlags::new();
flags.set(MemberFlags::AUTHORITY);
flags.set(MemberFlags::TX_LOGS);
let member = Member {
flags,
pubkey: payer_address,
};
let members = vec![member];
let members_args = MembersArgs {
members: Some(&members),
};
// Prepare accounts: [permissioned_account, permission, payer, system_program]
let accounts: &[&AccountView] = &[
&permissioned_account,
&permission,
&payer,
&system_program,
];
// Create the permission
// Pass signer_seeds if permissioned_account is a PDA owned by your program
// Pass None if permissioned_account is an on-curve signer
create_permission(
accounts,
&permission_program_id,
members_args,
pda_signer_seeds, // Or None if permissioned_account is on-curve
)?;
import {
createCreatePermissionInstruction,
type Member,
AUTHORITY_FLAG, // Member can directly modify the permission
TX_LOGS_FLAG, // Member can view transaction logs
TX_BALANCES_FLAG, // Member can view account balances
} from "@magicblock-labs/ephemeral-rollups-sdk";
import { transaction, sendAndConfirmTransaction } from "@solana/kit";
const members: Member[] = [
{
// AUTHORITY_FLAG allows this member to modify permission settings
// TX_LOGS_FLAG allows viewing transaction logs
flags: AUTHORITY_FLAG | TX_LOGS_FLAG,
pubkey: payer.address,
},
];
// Either the authority or permissioned_account can sign the transaction
// The signer depends on who has AUTHORITY_FLAG in the members list
const createPermissionIx = await createCreatePermissionInstruction(
{
permissionedAccount: permissionedAccount.address,
payer: payer.address,
},
{
members,
}
);
const tx = transaction([createPermissionIx]);
const signature = await sendAndConfirmTransaction(
client,
tx,
[payer]
);
console.log("TX:", signature);
import {
Member,
AUTHORITY_FLAG, // Member can directly modify the permission
TX_LOGS_FLAG, // Member can view transaction logs
TX_BALANCES_FLAG, // Member can view account balances
createCreatePermissionInstruction,
} from "@magicblock-labs/ephemeral-rollups-sdk";
import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js";
const members: Member[] = [
{
// AUTHORITY_FLAG allows this member to modify permission settings
// TX_LOGS_FLAG allows viewing transaction logs
flags: AUTHORITY_FLAG | TX_LOGS_FLAG,
pubkey: payer.publicKey,
},
];
// Either the authority or permissioned_account can sign the transaction
// The signer depends on who has AUTHORITY_FLAG in the members list
const createPermissionIx = createCreatePermissionInstruction(
{
permissionedAccount: permissionedAccount.publicKey,
payer: payer.publicKey,
},
{
members,
}
);
const tx = new Transaction().add(createPermissionIx);
const txSig = await sendAndConfirmTransaction(connection, tx, [payer]);
console.log("TX:", txSig);
- 새로 위임된 계정에 대한 접근 제어 초기화
- authority 멤버와 그 권한 설정
- 누가 트랜잭션 세부 정보를 볼 수 있는지 정의
MagicBlock의 Delegation Program 사용 사례:
DELeGGvXpWV2fqJUhqcF5ZSYMS4JTLjteaAMARRSaeSh을 통해 permissioned account를 위임해 저지연 Private Ephemeral Rollup 실행을 활성화합니다.이 공용 검증자들은 개발용으로 지원됩니다. 위임 명령에 해당 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):
MTEWGuqxUpYZGFJQcp8tLN7x5v9BSeoFHYWQQ3n3xzo
- 로컬 ER (localhost:7799):
mAGicPQYBMvcYveUZA5F5UNNwyHvfYh5xkLS2Fr1mev
- Rust SDK
- Pinocchio
- Kit
- Web3.js
use ephemeral_rollups_sdk::access_control::{
instructions::DelegatePermissionCpiBuilder
};
// Delegate the permission to enable low-latency Ephemeral Rollup execution
// Either authority (with AUTHORITY_FLAG) or permissioned_account can authorize
DelegatePermissionCpiBuilder::new(&permission_program)
.payer(&payer) // Pays for account creation
.authority(&payer, false) // Authority signer (has AUTHORITY_FLAG)
.permissioned_account(&permissioned_account, true) // or permissioned_account can sign
.permission(&permission)
.system_program(&system_program)
.owner_program(&owner_program)
.delegation_buffer(&delegation_buffer)
.delegation_record(&delegation_record)
.delegation_metadata(&delegation_metadata)
.delegation_program(&delegation_program)
.validator(&validator) // Validator that will execute the delegated state
.invoke_signed(&[seed_refs.as_slice()])?;
use ephemeral_rollups_pinocchio::instruction::delegate_permission;
use pinocchio::AccountView;
pub fn process_delegate_permission(
accounts: &[&AccountView],
permission_program: &pinocchio::Address,
authority_is_signer: bool,
permissioned_account_is_signer: bool,
) -> pinocchio::ProgramResult {
// Accounts: [payer, authority, permissioned_account, permission, system_program,
// owner_program, delegation_buffer, delegation_record,
// delegation_metadata, delegation_program, validator (optional)]
// Pass signer_seeds if permissioned_account is a PDA owned by your program
delegate_permission(
accounts,
permission_program,
authority_is_signer,
permissioned_account_is_signer,
signer_seeds, // Or None if permissioned_account is on-curve
)?;
Ok(())
}
import {
createDelegatePermissionInstruction,
PERMISSION_PROGRAM_ID,
} from "@magicblock-labs/ephemeral-rollups-sdk";
import { transaction, sendAndConfirmTransaction } from "@solana/kit";
// Delegate the permission to enable low-latency Ephemeral Rollup execution
// Either authority (with AUTHORITY_FLAG) or permissioned_account can authorize
const delegatePermissionIx = await createDelegatePermissionInstruction(
{
payer: payer.address, // Pays for account creation
authority: [payer.address, true], // Authority signer (has AUTHORITY_FLAG)
permissionedAccount: [permissionedAccount.address, false], // or permissioned_account can sign
ownerProgram: PERMISSION_PROGRAM_ID,
validator, // Validator that will execute the delegated state
}
);
const tx = transaction([delegatePermissionIx]);
const signature = await sendAndConfirmTransaction(
client,
tx,
[payer]
);
console.log("TX:", signature);
import {
PERMISSION_PROGRAM_ID,
createDelegatePermissionInstruction,
} from "@magicblock-labs/ephemeral-rollups-sdk";
import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js";
// Delegate the permission to enable low-latency Ephemeral Rollup execution
// Either authority (with AUTHORITY_FLAG) or permissioned_account can authorize
const delegatePermissionIx = createDelegatePermissionInstruction({
payer: payer.publicKey, // Pays for account creation
authority: [payer.publicKey, true], // Authority signer (has AUTHORITY_FLAG)
permissionedAccount: [permissionedAccount.publicKey, false], // or permissioned_account can sign
ownerProgram: PERMISSION_PROGRAM_ID,
validator, // Validator that will execute the delegated state
});
const tx = new Transaction().add(delegatePermissionIx);
const txSig = await sendAndConfirmTransaction(connection, tx, [payer]);
console.log("TX:", txSig);
- permissioned account의 ER 실행 활성화
- 상태 변경을 실행할 특정 검증기 지정
- 실시간 트랜잭션 처리를 위한 위임 설정
AUTHORITY_FLAG에 따라 authority 또는permissioned_account중 하나가 서명해야 합니다- 검증기는 ER 속도로 트랜잭션을 처리합니다
- 커밋 빈도는 상태가 Solana에 얼마나 자주 동기화되는지 결정합니다
- Private Ephemeral Rollup에 위임되는 즉시 permission이 강제됩니다. 적절한 플래그를 가진 멤버만 계정 상태에 접근하거나 수정할 수 있습니다
MagicBlock의 Permission Program 사용 사례:
ACLseoPoyC3cBqoUtkbjZ4aDrkurZW86v19pXz2XQnp1을 통해 permission account의 기존 멤버 또는 플래그를 수정합니다.- Rust SDK
- Pinocchio
- Kit
- Web3.js
use ephemeral_rollups_sdk::access_control::{
instructions::UpdatePermissionCpiBuilder,
structs::MembersArgs
};
// Update permission and modify members
// Either authority or permissioned_account must sign based on AUTHORITY_FLAG
UpdatePermissionCpiBuilder::new(&permission_program)
.authority(&payer, true) // authority can sign if they have AUTHORITY_FLAG
.permissioned_account(&permissioned_account, true) // or permissioned_account can sign
.permission(&permission)
// Setting members to None makes the permission public (temporarily visible)
// This is useful for transitional states during delegation/undeligation
.args(MembersArgs { members: None })
.invoke_signed(&[seed_refs.as_slice()])?;
use ephemeral_rollups_pinocchio::instruction::update_permission;
use ephemeral_rollups_pinocchio::types::{
Member,
MemberFlags,
MembersArgs,
};
use pinocchio::AccountView;
// Update permission with new member flags
// Either authority or permissioned_account must sign based on AUTHORITY_FLAG
let mut new_flags = MemberFlags::new();
new_flags.set(MemberFlags::TX_LOGS);
new_flags.set(MemberFlags::TX_BALANCES);
let updated_member = Member {
flags: new_flags,
pubkey: user_address,
};
let members = vec![updated_member];
let members_args = MembersArgs {
members: Some(&members),
};
// Prepare accounts: [authority, permissioned_account, permission]
let accounts: &[&AccountView] = &[
&authority,
&permissioned_account,
&permission,
];
// Update the permission
// Setting members to None makes the permission public (temporarily visible)
// Pass signer_seeds if permissioned_account is a PDA owned by your program
update_permission(
accounts,
&permission_program_id,
authority.is_signer(),
permissioned_account.is_signer(),
members_args,
signer_seeds, // Or None if permissioned_account is on-curve
)?;
import {
createUpdatePermissionInstruction,
type Member,
} from "@magicblock-labs/ephemeral-rollups-sdk";
import { transaction, sendAndConfirmTransaction } from "@solana/kit";
// Update permission and modify members
// Either authority or permissioned_account must sign based on AUTHORITY_FLAG
const updatePermissionIx = await createUpdatePermissionInstruction(
{
authority: [payer.address, true], // authority can sign if they have AUTHORITY_FLAG
permissionedAccount: [permissionedAccount.address, false], // or permissioned_account can sign
},
{
// Setting members to empty array or None makes the permission public (temporarily visible)
// This is useful for transitional states during delegation/undeligation
members: [],
}
);
const tx = transaction([updatePermissionIx]);
const signature = await sendAndConfirmTransaction(
client,
tx,
[payer]
);
console.log("TX:", signature);
import { createUpdatePermissionInstruction } from "@magicblock-labs/ephemeral-rollups-sdk";
import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js";
// Update permission and modify members
// Either authority or permissioned_account must sign based on AUTHORITY_FLAG
const updatePermissionIx = createUpdatePermissionInstruction(
{
authority: [payer.publicKey, true], // authority can sign if they have AUTHORITY_FLAG
permissionedAccount: [permissionedAccount.publicKey, false], // or permissioned_account can sign
},
{
// Setting members to empty array or None makes the permission public (temporarily visible)
// This is useful for transitional states during delegation/undeligation
members: [],
}
);
const tx = new Transaction().add(updatePermissionIx);
const txSig = await sendAndConfirmTransaction(connection, tx, [payer]);
console.log("TX:", txSig);
- permission group에 새 멤버 추가
- 멤버 제거를 통한 권한 철회
- 멤버 플래그 변경을 통한 접근 허용/제한
- 멤버를
None으로 설정해 계정을 일시적으로 공개 상태로 전환
Private Ephemeral Rollup에 요청할 때는 먼저 인가를 설정해야 합니다:인가 단계:계정 가시성:
Private Ephemeral Rollup(devnet) 엔드포인트:
https://devnet-tee.magicblock.app?token= {authToken}. 요청을 보내려면 {authToken}을 TEE RPC에서 받은 인가 토큰으로 바꾸세요.- TEE RPC 무결성 검증: TDX quote 및 Intel 발급 attestation certificates를 사용해 TEE RPC 서버가 정품 Intel TDX 하드웨어에서 실행되는지 확인합니다
- 인가 토큰 요청: challenge message에 서명해 인가 토큰을 받습니다
- 연결 생성: 인가 토큰을 header 또는 query parameter로 전달합니다
- Kit
- Web3.js
import {
verifyTeeRpcIntegrity,
getAuthToken,
} from "@magicblock-labs/ephemeral-rollups-sdk";
import { Connection } from "@magicblock-labs/ephemeral-rollups-kit";
import * as nacl from "tweetnacl";
const teeUrl = "https://devnet-tee.magicblock.app";
const teeWsUrl = "wss://tee.magicblock.app";
// 1. Verify the integrity of TEE RPC
const isVerified = await verifyTeeRpcIntegrity(teeUrl);
// 2. Get AuthToken before making request to TEE
const authToken = await getAuthToken(
teeUrl,
userPubkey,
(message: Uint8Array) =>
Promise.resolve(nacl.sign.detached(message, userSecretKey)),
);
// 3. Create connection with TEE using authorization token
const teeUserUrl = `${teeUrl}?token=${authToken.token}`;
const teeUserWsUrl = `${teeWsUrl}?token=${authToken.token}`;
const ephemeralConnection = await Connection.create(teeUserUrl, teeUserWsUrl);
import {
verifyTeeRpcIntegrity,
getAuthToken,
} from "@magicblock-labs/ephemeral-rollups-sdk";
import { Connection, Keypair } from "@solana/web3.js";
import * as nacl from "tweetnacl";
const teeUrl = "https://devnet-tee.magicblock.app";
const teeWsUrl = "wss://tee.magicblock.app";
// 1. Verify the integrity of TEE RPC
const isVerified = await verifyTeeRpcIntegrity(teeUrl);
// 2. Get AuthToken before making request to TEE
const authToken = await getAuthToken(
teeUrl,
userKeypair.publicKey,
(message: Uint8Array) =>
Promise.resolve(nacl.sign.detached(message, userKeypair.secretKey)),
);
// 3. Create connection with TEE
const teeUserUrl = `${teeUrl}?token=${authToken.token}`;
const teeUserWsUrl = `${teeWsUrl}?token=${authToken.token}`;
const connection = new Connection(teeUserUrl, {
wsEndpoint: teeUserWsUrl,
});
- 기본적으로: 모든 계정은 투명하며 인가된 모든 사용자가 접근할 수 있습니다
- 권한 적용 시: 계정이 permission system을 통해 보호되면 모든 요청에서 접근 제어 규칙이 강제됩니다
- 적절한 플래그를 가진 멤버만 permissioned accounts와 트랜잭션에 접근하거나 수정할 수 있습니다
- 요청은 검증기에서 실시간으로 실행됩니다
- 멤버 플래그가 각 사용자가 할 수 있는 작업을 결정합니다
- 실행 중에도 권한을 동적으로 업데이트할 수 있습니다
- 업데이트는 Private Ephemeral Rollup에 즉시 반영됩니다
Private Ephemeral Rollup의 최신 permission state는 접근 제어를 강제합니다. permission account를 닫으려면 permission을 Solana로 위임 해제하기 전에 permission members를 먼저 업데이트하세요.⬆️ 맨 위로
- Rust SDK
- Pinocchio
- Kit
- Web3.js
use ephemeral_rollups_sdk::access_control::{
instructions::CommitAndUndelegatePermissionCpiBuilder
};
CommitAndUndelegatePermissionCpiBuilder::new(&permission_program)
.authority(&payer, false)
.permissioned_account(&permissioned_account, true)
.permission(&permission)
.magic_program(&magic_program)
.magic_context(&magic_context)
.invoke_signed(&[seed_refs.as_slice()])?;
use ephemeral_rollups_pinocchio::instruction::commit_and_undelegate_permission;
use pinocchio::AccountView;
pub fn process_commit_and_undelegate_permission(
accounts: &[&AccountView],
permission_program: &pinocchio::Address,
authority_is_signer: bool,
permissioned_account_is_signer: bool,
) -> pinocchio::ProgramResult {
// Accounts: [authority, permissioned_account, permission, magic_program, magic_context]
// Pass signer_seeds if permissioned_account is a PDA owned by your program
commit_and_undelegate_permission(
accounts,
permission_program,
authority_is_signer,
permissioned_account_is_signer,
signer_seeds, // Or None if permissioned_account is on-curve
)?;
Ok(())
}
import {
createCommitAndUndelegatePermissionInstruction,
} from "@magicblock-labs/ephemeral-rollups-sdk";
import { transaction, sendAndConfirmTransaction } from "@solana/kit";
const commitAndUndelegatePermissionIx =
await createCommitAndUndelegatePermissionInstruction({
authority: [payer.address, true],
permissionedAccount: [permissionedAccount.address, false],
});
const tx = transaction([commitAndUndelegatePermissionIx]);
const signature = await sendAndConfirmTransaction(
client,
tx,
[payer]
);
console.log("TX:", signature);
import { createCommitAndUndelegatePermissionInstruction } from "@magicblock-labs/ephemeral-rollups-sdk";
import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js";
const commitAndUndelegatePermissionIx =
createCommitAndUndelegatePermissionInstruction({
authority: [payer.publicKey, true],
permissionedAccount: [permissionedAccount.publicKey, false],
});
const tx = new Transaction().add(commitAndUndelegatePermissionIx);
const txSig = await sendAndConfirmTransaction(connection, tx, [payer]);
console.log("TX:", txSig);
permissioned account를 닫고 Solana에서 lamports를 회수합니다.사용 사례:
- Rust SDK
- Pinocchio
- Kit
- Web3.js
use ephemeral_rollups_sdk::access_control::{
instructions::ClosePermissionCpiBuilder
};
// Close the permission account and reclaim lamports
// IMPORTANT: The permission must be undelegated to Solana first
// If delegated, call commit_and_undelegate before closing
ClosePermissionCpiBuilder::new(&permission_program)
.payer(&payer) // Receives reclaimed lamports
.authority(&payer, false) // Authority signer (has AUTHORITY_FLAG)
.permissioned_account(&permissioned_account, true) // or permissioned_account can sign
.permission(&permission) // The permission account to close
.invoke_signed(&[seed_refs.as_slice()])?;
use ephemeral_rollups_pinocchio::instruction::close_permission;
use pinocchio::AccountView;
pub fn process_close_permission(
accounts: &[&AccountView],
permission_program: &pinocchio::Address,
authority_is_signer: bool,
permissioned_account_is_signer: bool,
) -> pinocchio::ProgramResult {
// Accounts: [payer, authority, permissioned_account, permission]
// IMPORTANT: The permission must be undelegated to Solana first
// If the permission is still delegated, this operation will fail
// Pass signer_seeds if permissioned_account is a PDA owned by your program
close_permission(
accounts,
permission_program,
authority_is_signer,
permissioned_account_is_signer,
signer_seeds, // Or None if permissioned_account is on-curve
)?;
// The permission account lamports are transferred to the payer
Ok(())
}
import {
createClosePermissionInstruction,
} from "@magicblock-labs/ephemeral-rollups-sdk";
import { transaction, sendAndConfirmTransaction } from "@solana/kit";
// Close the permission account and reclaim lamports
// IMPORTANT: The permission must be undelegated to Solana first
// If delegated, call commit_and_undelegate before closing
const closePermissionIx = await createClosePermissionInstruction({
payer: payer.address, // Receives reclaimed lamports
authority: [payer.address, true], // Authority signer (has AUTHORITY_FLAG)
permissionedAccount: [permissionedAccount.address, false], // or permissioned_account can sign
});
const tx = transaction([closePermissionIx]);
const signature = await sendAndConfirmTransaction(
client,
tx,
[payer]
);
console.log("TX:", signature);
import { createClosePermissionInstruction } from "@magicblock-labs/ephemeral-rollups-sdk";
import { Transaction, sendAndConfirmTransaction } from "@solana/web3.js";
// Close the permission account and reclaim lamports
// IMPORTANT: The permission must be undelegated to Solana first
// If delegated, call commit_and_undelegate before closing
const closePermissionIx = createClosePermissionInstruction({
payer: payer.publicKey, // Receives reclaimed lamports
authority: [payer.publicKey, true], // Authority signer (has AUTHORITY_FLAG)
permissionedAccount: [permissionedAccount.publicKey, false], // or permissioned_account can sign
});
const tx = new Transaction().add(closePermissionIx);
const txSig = await sendAndConfirmTransaction(connection, tx, [payer]);
console.log("TX:", txSig);
- 사용하지 않는 permission accounts 정리
- 닫힌 계정에서 SOL 회수
- permission은 먼저 Solana로 위임 해제되어야 합니다
- 위임된 상태라면 닫기 전에
commit_and_undelegate를 호출하세요 - lamports는 payer에게 반환됩니다
모범 사례
- Authority 관리: 항상 최소 한 명의 신뢰할 수 있는 멤버에게
AUTHORITY_FLAG를 부여하세요 - 최소 권한 원칙: 각 멤버에게 필요한 플래그만 부여하세요
- 실시간 업데이트: 위임 해제 없이도 Private Ephemeral Rollup에서 permission을 실시간으로 업데이트해 동적 접근 제어 조정이 가능합니다
- 정리: 사용하지 않는 permission accounts를 위임 해제하고 닫아 SOL을 확보하세요
보안 고려 사항
- 서명자 검증:
AUTHORITY_FLAG를 가진 멤버 또는 permissioned account를 가진 프로그램만 변경을 인가할 수 있습니다 - 공개 계정: 멤버를
None으로 설정하면 계정이 공개적으로 보이게 됩니다 - 기본 Authority: 기본적으로 permissioned account의 소유자가 permission account의 members에 permission authority로 추가됩니다
- 빈 멤버 목록:
members필드가 빈 목록으로 설정되면 permissioned account는 완전히 제한되고 비공개가 됩니다. permission을 수정할 수 있는 것은 소유자뿐입니다 - 접근 감사: 멤버 플래그를 사용해 접근을 감사하고 제어하세요
접근 제어
세밀한 접근 제어
온체인 프라이버시
프라이버시 메커니즘과 개념
인가
인가 프레임워크
컴플라이언스 프레임워크
컴플라이언스 기준 및 가이드라인

