场景
游戏账号(EVM系这个场景说烂了)
- 多签地址的签名地址。卖出DOB,即是卖出治理权。人变了,但是不需要更改多签地址的成员。
- 社区身份绑定在DOB上。卖出DOB,即是卖出社区身份(资历、荣誉等等)。
设计
- 基于DOB的CKB地址,其公钥可以由cluster id + spore id构成。
- 由DOB的所有者进行签名授权。
// src\dob_lock_args.mol
table DOBLockArgs {
// The code hash of the Spore type script.
spore_type_code_hash: Byte32,
// The hash type of the Spore type script (0: data, 1: type, 2: data1, 4: data2).
spore_type_hash_type: Byte,
// The ID of the Cluster that the required Spore must belong to.
cluster_id: Byte32,
// The ID of the Spore that is required to unlock this cell.
spore_id: Byte32,
}
//
#![no_std]
#![no_main]
#![feature(lang_items)]
#![feature(alloc_error_handler)]
#![feature(panic_info_message)]
// Import CKB syscalls and high-level APIs
use ckb_std::{
ckb_constants::Source,
ckb_types::core::ScriptHashType,
ckb_types::{bytes::Bytes, prelude::*},
high_level::*,
};
// Import the generated molecule code
mod dob_lock_args;
use dob_lock_args::DOBLockArgs;
// Import Spore/Cluster related constants or functions if needed
// For example, if Spore ID is stored in a specific part of the data
// or if Cluster ID needs specific parsing from Spore data.
// const SPORE_TYPE_SCRIPT_ARGS_CLUSTER_ID_OFFSET: usize = 32; // Example offset for Cluster ID in Spore type args
// const SPORE_TYPE_SCRIPT_ARGS_CLUSTER_ID_LEN: usize = 32; // Example length for Cluster ID
// Define error codes
#[repr(i8)]
enum Error {
IndexOutOfBound = 1,
ItemMissing,
LengthNotEnough,
Encoding,
// Add more error codes as needed
ArgsInvalid, // 5
SporeCellNotFound, // 6
InvalidHashType, // 7
ClusterIdMismatch, // 8
SporeIdMismatch, // 9
}
impl From<molecule::error::VerificationError> for Error {
fn from(_: molecule::error::VerificationError) -> Self {
Error::Encoding
}
}
fn verify_spore_in_inputs(
spore_type_code_hash: &[u8; 32],
spore_type_hash_type: ScriptHashType,
cluster_id: &[u8; 32],
spore_id: &[u8; 32],
) -> Result<(), Error> {
// Search for the specific Spore cell in the transaction inputs.
let spore_found = QueryIter::new(load_cell_type, Source::Input)
.enumerate()
.any(|(i, script_opt)| {
if let Some(script) = script_opt {
// 1. Check if the type script matches the Spore's type script.
if script.code_hash().raw_data().as_ref() == spore_type_code_hash
&& script.hash_type().into() == spore_type_hash_type
{
// 2. Verify Cluster ID from the Spore's type script arguments.
// Assumes the first 32 bytes of args is the Cluster ID.
let args: Bytes = script.args().unpack();
if args.len() < 32 || &args[..32] != cluster_id {
return false; // Cluster ID mismatch
}
// 3. Verify Spore ID from the Spore's cell data.
// Assumes the first 32 bytes of data is the Spore ID.
if let Ok(data) = load_cell_data(i, Source::Input) {
if data.len() < 32 || &data[..32] != spore_id {
return false; // Spore ID mismatch
}
} else {
return false; // Failed to load data
}
// If all checks pass, we've found the required Spore cell.
return true;
}
}
false
});
if spore_found {
Ok(())
} else {
Err(Error::SporeCellNotFound)
}
}
pub fn main() -> Result<(), Error> {
// Load the arguments of the current DOBLock script.
let script = load_script()?;
let args: Bytes = script.args().unpack();
let dob_lock_args = DOBLockArgs::from_slice(&args).map_err(|_| Error::ArgsInvalid)?;
// Extract the required Spore identification details from the arguments.
let spore_type_code_hash: [u8; 32] = dob_lock_args.spore_type_code_hash().into();
let spore_type_hash_type_byte: u8 = dob_lock_args.spore_type_hash_type().into();
let cluster_id: [u8; 32] = dob_lock_args.cluster_id().into();
let spore_id: [u8; 32] = dob_lock_args.spore_id().into();
let spore_type_hash_type = match spore_type_hash_type_byte {
0 => ScriptHashType::Data,
1 => ScriptHashType::Type,
2 => ScriptHashType::Data1,
4 => ScriptHashType::Data2, // CKB2023
_ => return Err(Error::InvalidHashType),
};
// The core logic: verify that the specific Spore cell, which acts as a 'key',
// is present in the transaction's inputs. This is sufficient to unlock the cell
// protected by this DOBLock script.
verify_spore_in_inputs(
&spore_type_code_hash,
spore_type_hash_type,
&cluster_id,
&spore_id,
)?;
Ok(())
}