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):
FnE6VJT5QNZdedZPnCoLsARgBwoE6DeJNjBs2H1gySXA
- 로컬 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):
FnE6VJT5QNZdedZPnCoLsARgBwoE6DeJNjBs2H1gySXA
- 로컬 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을 수정할 수 있는 것은 소유자뿐입니다 - 접근 감사: 멤버 플래그를 사용해 접근을 감사하고 제어하세요
접근 제어
세밀한 접근 제어
온체인 프라이버시
프라이버시 메커니즘과 개념
인가
인가 프레임워크
컴플라이언스 프레임워크
컴플라이언스 기준 및 가이드라인

