dd_shared_types/
lib.rs

1//! DD 统一共享类型库
2//!
3//! 为去中心化决策生态系统提供统一的类型定义、接口和工具函数
4//! 合并了原有的 decentralized_decision_types 和 shared-interfaces 功能
5
6use cosmwasm_schema::cw_serde;
7use cosmwasm_std::{Addr, Binary, StdError, Timestamp, Uint128};
8use cw_storage_plus::{Key, KeyDeserialize, PrimaryKey};
9
10// ==================== 核心类型定义 ====================
11
12#[cw_serde]
13/// 去中心化决策算法类型
14pub enum DDAlgorithmType {
15    /// 单目标抽奖决策
16    SingleTargetLottery,
17    /// 多目标抽奖决策
18    MultiTargetLottery,
19    /// 多等级抽奖决策
20    MultiLevelLottery,
21    /// 多目标投票决策
22    MultiTargetVoting,
23    /// 多等级分层分配决策
24    HierarchicalDistribution,
25    /// 单目标抽奖与补偿机制
26    SingleTargetWithCompensation,
27    /// 扑克牌洗牌与一次性分配
28    PokerShuffleOneTime,
29    /// 扑克牌洗牌与顺序多次分配
30    PokerShuffleSequential,
31}
32
33impl DDAlgorithmType {
34    /// 将算法类型转换为字符串表示
35    pub fn as_str(&self) -> &'static str {
36        match self {
37            DDAlgorithmType::SingleTargetLottery => "single_target_lottery",
38            DDAlgorithmType::MultiTargetLottery => "multi_target_lottery",
39            DDAlgorithmType::MultiLevelLottery => "multi_level_lottery",
40            DDAlgorithmType::MultiTargetVoting => "multi_target_voting",
41            DDAlgorithmType::HierarchicalDistribution => "hierarchical_distribution",
42            DDAlgorithmType::SingleTargetWithCompensation => "single_target_with_compensation",
43            DDAlgorithmType::PokerShuffleOneTime => "poker_shuffle_one_time",
44            DDAlgorithmType::PokerShuffleSequential => "poker_shuffle_sequential",
45        }
46    }
47
48    /// 返回所有已知的算法变体
49    pub fn all() -> &'static [DDAlgorithmType] {
50        use DDAlgorithmType::*;
51        const VARIANTS: [DDAlgorithmType; 8] = [
52            SingleTargetLottery,
53            MultiTargetLottery,
54            MultiLevelLottery,
55            MultiTargetVoting,
56            HierarchicalDistribution,
57            SingleTargetWithCompensation,
58            PokerShuffleOneTime,
59            PokerShuffleSequential,
60        ];
61        &VARIANTS
62    }
63}
64
65impl<'a> PrimaryKey<'a> for DDAlgorithmType {
66    type Prefix = ();
67    type SubPrefix = ();
68    type Suffix = Self;
69    type SuperSuffix = Self;
70
71    /// 将算法类型转换为存储键
72    fn key(&self) -> Vec<Key<'_>> {
73        vec![Key::Ref(self.as_str().as_bytes())]
74    }
75}
76
77impl KeyDeserialize for DDAlgorithmType {
78    type Output = Self;
79    const KEY_ELEMS: u16 = 1;
80
81    /// 从字节向量反序列化算法类型
82    fn from_vec(value: Vec<u8>) -> Result<Self, StdError> {
83        let s = String::from_utf8(value)
84            .map_err(|_| StdError::generic_err("DDAlgorithmType: invalid utf8"))?;
85        match s.as_str() {
86            "single_target_lottery" => Ok(DDAlgorithmType::SingleTargetLottery),
87            "multi_target_lottery" => Ok(DDAlgorithmType::MultiTargetLottery),
88            "multi_level_lottery" => Ok(DDAlgorithmType::MultiLevelLottery),
89            "multi_target_voting" => Ok(DDAlgorithmType::MultiTargetVoting),
90            "hierarchical_distribution" => Ok(DDAlgorithmType::HierarchicalDistribution),
91            "single_target_with_compensation" => Ok(DDAlgorithmType::SingleTargetWithCompensation),
92            "poker_shuffle_one_time" => Ok(DDAlgorithmType::PokerShuffleOneTime),
93            "poker_shuffle_sequential" => Ok(DDAlgorithmType::PokerShuffleSequential),
94            _ => Err(StdError::generic_err("DDAlgorithmType: unknown variant")),
95        }
96    }
97}
98
99// ==================== 奖品和奖励相关 ====================
100
101#[cw_serde]
102/// 奖励属性
103pub struct RewardAttribute {
104    /// 属性名称
105    pub trait_type: String,
106    /// 属性值
107    pub value: String,
108    /// 显示类型
109    pub display_type: Option<String>,
110}
111
112#[cw_serde]
113/// 投票奖励信息
114pub struct VotingReward {
115    /// 奖品名称
116    pub name: String,
117    /// 奖品描述
118    pub description: String,
119    /// 奖品图片URI
120    pub image_uri: Option<String>,
121    /// 奖品外部链接
122    pub external_link: Option<String>,
123    /// 奖品属性
124    pub attributes: Option<Vec<RewardAttribute>>,
125    /// 奖品背景颜色
126    pub background_color: Option<String>,
127    /// 奖品动画URL
128    pub animation_url: Option<String>,
129    /// 奖品YouTube视频URL
130    pub youtube_url: Option<String>,
131}
132
133#[cw_serde]
134/// 奖品元数据(存储在区块链上)
135pub struct RewardMetadata {
136    /// 奖品名称
137    pub name: String,
138    /// 奖品描述
139    pub description: String,
140    /// 奖品图片URI
141    pub image_uri: Option<String>,
142    /// 奖品外部链接
143    pub external_link: Option<String>,
144    /// 奖品属性
145    pub attributes: Option<Vec<RewardAttribute>>,
146    /// 奖品背景颜色
147    pub background_color: Option<String>,
148    /// 奖品动画URL
149    pub animation_url: Option<String>,
150    /// 奖品YouTube视频URL
151    pub youtube_url: Option<String>,
152    /// 铸造时间
153    pub minted_at: Timestamp,
154    /// 关联的抽奖会话ID
155    pub lottery_session_id: String,
156    /// 获奖者地址
157    pub winner: String,
158}
159
160#[cw_serde]
161/// 奖品分配策略
162pub enum DistributionStrategy {
163    /// 随机分配:随机选择获奖者
164    Random,
165    /// 按排名分配:按排名顺序分配奖品
166    ByRank,
167    /// 按权重分配:按权重比例分配奖品
168    ByWeight,
169    /// 自定义分配:由合约定义分配规则
170    Custom(String),
171}
172
173#[cw_serde]
174/// 奖品分配结果
175pub struct RewardDistribution {
176    /// 获奖者地址
177    pub winner: String,
178    /// 关联 token id
179    pub token_id: String,
180}
181
182// ==================== 时间控制 ====================
183
184#[cw_serde]
185/// 时间控制模式
186pub enum TimeControlMode {
187    /// 基于区块高度的时间控制
188    BlockHeight {
189        /// 承诺阶段结束的区块高度
190        commitment_height: u64,
191        /// 揭示阶段结束的区块高度
192        reveal_height: u64,
193    },
194    /// 基于时间间隔的时间控制
195    TimeInterval {
196        /// 承诺阶段持续时间(秒)
197        commitment_duration: u64,
198        /// 揭示阶段持续时间(秒)
199        reveal_duration: u64,
200    },
201}
202
203// ==================== 抽奖会话相关 ====================
204
205#[cw_serde]
206/// 抽奖会话状态
207pub enum LotteryStatus {
208    /// 已创建
209    Created,
210    /// 承诺阶段
211    CommitmentPhase,
212    /// 揭示阶段
213    RevealPhase,
214    /// 已完成
215    Completed,
216    /// 已取消
217    Cancelled,
218}
219
220#[cw_serde]
221/// 抽奖会话信息
222pub struct LotterySessionInfo {
223    /// 会话ID
224    pub session_id: String,
225    /// 会话标题
226    pub title: String,
227    /// 会话描述
228    pub description: String,
229    /// 创建者地址
230    pub creator: String,
231    /// 创建时间
232    pub created_at: Timestamp,
233    /// 奖品总数
234    pub total_rewards: u32,
235    /// 已铸造奖品数
236    pub minted_rewards: u32,
237}
238
239#[cw_serde]
240/// 抽奖会话
241pub struct LotterySession {
242    /// 会话ID
243    pub session_id: String,
244    /// 会话标题
245    pub title: String,
246    /// 会话描述
247    pub description: String,
248    /// 参与者地址列表
249    pub participants: Vec<String>,
250    /// 关联的NFT合约地址
251    pub nft_contract: Option<String>,
252    /// 创建者地址
253    pub creator: String,
254    /// 会话状态
255    pub status: LotteryStatus,
256    /// 创建时间
257    pub created_at: Timestamp,
258    /// 创建时的区块高度
259    pub created_height: u64,
260    /// 时间控制模式
261    pub time_control: TimeControlMode,
262    /// 承诺阶段截止时间
263    pub commitment_deadline: Option<Timestamp>,
264    /// 揭示阶段截止时间
265    pub reveal_deadline: Option<Timestamp>,
266    /// 承诺阶段截止区块高度
267    pub commitment_deadline_height: Option<u64>,
268    /// 揭示阶段截止区块高度
269    pub reveal_deadline_height: Option<u64>,
270    /// 奖品信息
271    pub reward: VotingReward,
272    /// 抽奖结果
273    pub result: Option<LotteryResult>,
274}
275
276#[cw_serde]
277/// 抽奖结果
278pub struct LotteryResult {
279    /// 会话ID
280    pub session_id: String,
281    /// 获奖者地址
282    pub winner: String,
283    /// 随机种子
284    pub random_seed: u64,
285    /// 随机数
286    pub random_number: u64,
287    /// 结果哈希
288    pub result_hash: String,
289    /// 总参与者数量
290    pub total_participants: u32,
291    /// 执行时间
292    pub executed_at: Timestamp,
293    /// 算法类型
294    pub algorithm_type: String,
295}
296
297// ==================== NFT合约接口 ====================
298
299#[cw_serde]
300/// NFT合约实例化消息
301pub struct NftInstantiateMsg {
302    /// 合约名称
303    pub name: String,
304    /// 合约符号
305    pub symbol: String,
306    /// 铸造者地址
307    pub minter: String,
308    /// 参与者地址列表
309    pub participants: Vec<String>,
310    /// 最大参与者数量
311    pub max_participants: u32,
312    /// 会话是否激活
313    pub session_active: Option<bool>,
314}
315
316#[cw_serde]
317/// NFT合约执行消息
318pub enum NftExecuteMsg {
319    // 投票相关
320    /// 提交承诺
321    SubmitCommitment {
322        /// 承诺哈希
323        commitment_hash: String,
324        /// 盐值
325        salt: String,
326    },
327    /// 提交揭示
328    SubmitReveal {
329        /// 投票数据
330        vote_data: Binary,
331        /// 盐值
332        salt: String,
333    },
334
335    // 参与者管理(仅管理员)
336    /// 添加单个参与者
337    AddParticipant {
338        /// 参与者地址
339        participant: String,
340    },
341    /// 批量添加参与者
342    AddParticipants {
343        /// 参与者地址列表
344        participants: Vec<String>,
345    },
346    /// 移除参与者
347    RemoveParticipant {
348        /// 参与者地址
349        participant: String,
350    },
351
352    // NFT转移控制(仅管理员)
353    /// 设置转移锁定状态
354    SetTransfersLocked {
355        /// 是否锁定
356        locked: bool,
357    },
358    /// 设置会话激活状态
359    SetSessionActive {
360        /// 是否激活
361        active: bool,
362    },
363
364    // NFT转移(公开)
365    /// 转移NFT
366    TransferNft {
367        /// 接收者地址
368        recipient: String,
369        /// Token ID
370        token_id: String,
371    },
372}
373
374#[cw_serde]
375/// NFT合约查询消息
376pub enum NftQueryMsg {
377    // 参与者相关
378    /// 获取所有参与者
379    GetParticipants {},
380    /// 检查是否为参与者
381    IsParticipant { participant: String },
382    /// 获取参与者数量
383    GetParticipantCount {},
384    /// 获取最大参与者数量
385    GetMaxParticipants {},
386    /// 获取参与者索引
387    GetParticipantIndex { address: String },
388
389    // 投票数据相关
390    /// 获取参与者的承诺
391    GetCommitment { participant: String },
392    /// 获取参与者的揭示
393    GetReveal { participant: String },
394    /// 获取所有承诺
395    GetAllCommitments {},
396    /// 获取所有揭示
397    GetAllReveals {},
398    /// 检查是否有承诺
399    HasCommitment { participant: String },
400    /// 检查是否有揭示
401    HasReveal { participant: String },
402
403    // 会话状态
404    /// 获取会话激活状态
405    GetSessionActive {},
406    /// 获取转移锁定状态
407    GetTransfersLocked {},
408    /// 获取会话元数据
409    GetSessionMeta {},
410
411    // NFT相关
412    /// 获取NFT所有者
413    OwnerOf { token_id: String },
414
415    // 时间相关
416    /// 获取当前时间
417    GetCurrentTime {},
418    /// 获取当前区块高度
419    GetCurrentHeight {},
420
421    // 批量查询
422    /// 检查是否可以添加参与者
423    CanAddParticipants { count: u32 },
424    /// 获取投票状态
425    GetVotingStatus {},
426}
427
428#[cw_serde]
429/// 会话元数据
430pub struct NftSessionMeta {
431    /// 参与者地址列表
432    pub participants: Vec<String>,
433    /// 最大参与者数量
434    pub max_participants: u32,
435    /// 会话是否激活
436    pub session_active: bool,
437}
438
439#[cw_serde]
440/// 承诺信息
441pub struct CommitmentInfo {
442    /// 参与者地址
443    pub participant: String,
444    /// 承诺哈希
445    pub commitment_hash: String,
446    /// 盐值
447    pub salt: String,
448    /// 提交时间
449    pub submitted_at: u64,
450}
451
452#[cw_serde]
453/// 揭示信息
454pub struct RevealInfo {
455    /// 参与者地址
456    pub participant: String,
457    /// 投票数据
458    pub vote_data: Binary,
459    /// 盐值
460    pub salt: String,
461    /// 提交时间
462    pub submitted_at: u64,
463}
464
465#[cw_serde]
466/// 投票状态
467pub struct VotingStatus {
468    /// 总参与者数量
469    pub total_participants: u32,
470    /// 承诺数量
471    pub commitments_count: u32,
472    /// 揭示数量
473    pub reveals_count: u32,
474    /// 会话是否激活
475    pub session_active: bool,
476    /// 是否所有参与者都已承诺
477    pub all_committed: bool,
478    /// 是否所有参与者都已揭示
479    pub all_revealed: bool,
480}
481
482// ==================== 主控合约接口 ====================
483
484#[cw_serde]
485/// 主控合约实例化消息
486pub struct MainInstantiateMsg {
487    /// 管理员地址
488    pub admin: String,
489    /// 最小参与者数量
490    pub min_participants: u32,
491    /// 最大参与者数量
492    pub max_participants: u32,
493    /// 默认时间控制模式
494    pub default_time_control: TimeControlMode,
495    /// 费用金额
496    pub fee_amount: Option<Uint128>,
497    /// 奖品NFT合约地址
498    pub reward_nft_contract: Option<String>,
499}
500
501#[cw_serde]
502/// 主控合约执行消息
503pub enum MainExecuteMsg {
504    // 会话管理
505    /// 从NFT合约创建抽奖
506    CreateLotteryFromNft {
507        /// 标题
508        title: String,
509        /// 描述
510        description: String,
511        /// NFT合约地址
512        nft_contract: String,
513        /// 时间控制模式
514        time_control: Option<TimeControlMode>,
515        /// 奖品信息
516        reward: VotingReward,
517    },
518    /// 执行抽奖
519    ExecuteLottery {
520        /// 会话ID
521        session_id: String,
522        /// 随机种子
523        random_seed: Option<u64>,
524    },
525    /// 取消抽奖
526    CancelLottery {
527        /// 会话ID
528        session_id: String,
529    },
530
531    // 奖品管理
532    /// 创建奖品NFT
533    CreateRewardNft {
534        /// 会话ID
535        session_id: String,
536    },
537
538    // 配置管理(仅管理员)
539    /// 更新配置
540    UpdateConfig {
541        /// 最小参与者数量
542        min_participants: Option<u32>,
543        /// 最大参与者数量
544        max_participants: Option<u32>,
545        /// 默认时间控制模式
546        default_time_control: Option<TimeControlMode>,
547        /// 费用金额
548        fee_amount: Option<Uint128>,
549    },
550    /// 暂停合约
551    PauseContract {},
552    /// 恢复合约
553    ResumeContract {},
554}
555
556#[cw_serde]
557/// 主控合约查询消息
558pub enum MainQueryMsg {
559    /// 获取抽奖会话
560    GetLotterySession { session_id: String },
561    /// 获取抽奖结果
562    GetLotteryResult { session_id: String },
563    /// 列出会话
564    ListSessions {
565        /// 起始位置
566        start_after: Option<String>,
567        /// 限制数量
568        limit: Option<u32>,
569        /// 状态过滤
570        status: Option<LotteryStatus>,
571    },
572    /// 获取合约统计
573    GetContractStats {},
574    /// 获取配置
575    GetConfig {},
576    /// 获取参与者
577    GetParticipants { session_id: String },
578    /// 检查承诺阶段是否结束
579    IsCommitmentPhaseEnded { session_id: String },
580    /// 检查揭示阶段是否结束
581    IsRevealPhaseEnded { session_id: String },
582    /// 获取当前时间
583    GetCurrentTime {},
584    /// 获取当前区块高度
585    GetCurrentHeight {},
586
587    // 从NFT合约查询投票数据
588    /// 获取NFT参与者
589    GetNftParticipants { nft_contract: String },
590    /// 检查是否为NFT参与者
591    IsNftParticipant {
592        nft_contract: String,
593        participant: String,
594    },
595    /// 获取NFT投票状态
596    GetNftVotingStatus { nft_contract: String },
597}
598
599#[cw_serde]
600/// 合约配置
601pub struct Config {
602    /// 管理员地址
603    pub admin: Addr,
604    /// 最小参与者数量
605    pub min_participants: u32,
606    /// 最大参与者数量
607    pub max_participants: u32,
608    /// 默认时间控制模式
609    pub default_time_control: TimeControlMode,
610    /// 费用金额
611    pub fee_amount: Option<Uint128>,
612    /// 是否暂停
613    pub paused: bool,
614    /// 奖品NFT合约地址
615    pub reward_nft_contract: Option<String>,
616}
617
618#[cw_serde]
619/// 合约统计
620pub struct ContractStats {
621    /// 总会话数
622    pub total_sessions: u64,
623    /// 活跃会话数
624    pub active_sessions: u64,
625    /// 已完成会话数
626    pub completed_sessions: u64,
627    /// 已取消会话数
628    pub cancelled_sessions: u64,
629    /// 总参与者数
630    pub total_participants: u64,
631}
632
633// ==================== 奖品NFT合约接口 ====================
634
635#[cw_serde]
636/// 奖品NFT元数据
637pub struct RewardNftMetadata {
638    /// 名称
639    pub name: String,
640    /// 描述
641    pub description: String,
642    /// 图片URI
643    pub image_uri: Option<String>,
644    /// 外部链接
645    pub external_link: Option<String>,
646    /// 属性列表
647    pub attributes: Option<Vec<RewardNftAttribute>>,
648    /// 背景颜色
649    pub background_color: Option<String>,
650    /// 动画URL
651    pub animation_url: Option<String>,
652    /// YouTube视频URL
653    pub youtube_url: Option<String>,
654    /// 铸造时间
655    pub minted_at: Timestamp,
656    /// 抽奖会话ID
657    pub lottery_session_id: String,
658    /// 获奖者地址
659    pub winner: String,
660}
661
662#[cw_serde]
663/// 奖品NFT属性
664pub struct RewardNftAttribute {
665    /// 属性类型
666    pub trait_type: String,
667    /// 属性值
668    pub value: String,
669    /// 显示类型
670    pub display_type: Option<String>,
671}
672
673#[cw_serde]
674/// 奖品NFT执行消息
675pub enum RewardExecuteMsg {
676    /// 铸造奖品
677    MintReward {
678        /// Token ID
679        token_id: String,
680        /// 获奖者地址
681        winner: String,
682        /// 抽奖会话ID
683        lottery_session_id: String,
684        /// 元数据
685        metadata: RewardNftMetadata,
686    },
687}
688
689// ==================== 算法相关 ====================
690
691#[cw_serde]
692/// 单目标算法参数
693pub struct SingleTargetParams {
694    /// 参与者地址列表
695    pub participants: Vec<String>,
696    /// 投票值列表(揭示值)- 必需,用于累加计算
697    pub vote_values: Option<Vec<u64>>,
698    /// 随机种子
699    pub random_seed: Option<u64>,
700    /// 权重列表
701    pub weights: Option<Vec<u32>>,
702}
703
704#[cw_serde]
705/// 单目标算法结果
706pub struct SingleTargetResult {
707    /// 获奖者地址
708    pub winner: String,
709    /// 随机种子
710    pub random_seed: u64,
711    /// 结果哈希
712    pub result_hash: String,
713    /// 随机数
714    pub random_number: u64,
715    /// 总参与者数量
716    pub total_participants: u32,
717}
718
719// ==================== 错误类型 ====================
720
721#[cw_serde]
722/// 合约错误类型
723pub enum ContractError {
724    /// 未授权
725    Unauthorized,
726    /// 会话未找到
727    SessionNotFound,
728    /// 参与者未找到
729    ParticipantNotFound,
730    /// 无效状态
731    InvalidState,
732    /// 时间未到
733    TimeNotReached,
734    /// 已投票
735    AlreadyVoted,
736    /// 无效承诺
737    InvalidCommitment,
738    /// 参与者不足
739    InsufficientParticipants,
740    /// 参与者过多
741    TooManyParticipants,
742    /// 合约已暂停
743    ContractPaused,
744    /// 无效地址
745    InvalidAddress,
746    /// 重复参与者
747    DuplicateParticipant,
748    /// 无法移除已投票参与者
749    CannotRemoveVotedParticipant,
750    /// 达到最大参与者数量
751    MaximumParticipantsReached,
752    /// 奖品NFT未配置
753    RewardNftNotConfigured,
754    /// 仅管理员可执行
755    OnlyAdminCanExecute,
756    /// 仅创建者可取消
757    OnlyCreatorCanCancel,
758    /// 无法取消已完成的抽奖
759    CannotCancelCompletedLottery,
760    /// 完成后无法创建奖品
761    CannotCreateRewardAfterCompletion,
762    /// 并非所有参与者都已揭示
763    NotAllParticipantsRevealed,
764    /// 无效承诺验证
765    InvalidCommitmentVerification,
766    /// 必须先提交承诺
767    MustSubmitCommitmentFirst,
768    /// 承诺已提交
769    CommitmentAlreadySubmitted,
770    /// 揭示已提交
771    RevealAlreadySubmitted,
772    /// 会话未激活
773    SessionNotActive,
774    /// 转移已锁定
775    TransfersLocked,
776    /// 仅管理员可设置锁定
777    OnlyAdminCanSetLock,
778    /// 仅管理员可设置会话激活
779    OnlyAdminCanSetSessionActive,
780    /// 仅管理员可添加参与者
781    OnlyAdminCanAddParticipants,
782    /// 仅管理员可移除参与者
783    OnlyAdminCanRemoveParticipants,
784    /// 仅管理员可更新配置
785    OnlyAdminCanUpdateConfig,
786    /// 仅管理员可暂停合约
787    OnlyAdminCanPauseContract,
788    /// 仅管理员可恢复合约
789    OnlyAdminCanResumeContract,
790    /// 仅管理员可创建奖品NFT
791    OnlyAdminCanCreateRewardNft,
792    /// 通用错误
793    Generic(String),
794}
795
796impl From<ContractError> for cosmwasm_std::StdError {
797    /// 将合约错误转换为标准错误
798    fn from(err: ContractError) -> Self {
799        match err {
800            ContractError::Unauthorized => StdError::generic_err("Unauthorized"),
801            ContractError::SessionNotFound => StdError::generic_err("Session not found"),
802            ContractError::ParticipantNotFound => StdError::generic_err("Participant not found"),
803            ContractError::InvalidState => StdError::generic_err("Invalid state"),
804            ContractError::TimeNotReached => StdError::generic_err("Time not reached"),
805            ContractError::AlreadyVoted => StdError::generic_err("Already voted"),
806            ContractError::InvalidCommitment => StdError::generic_err("Invalid commitment"),
807            ContractError::InsufficientParticipants => {
808                StdError::generic_err("Insufficient participants")
809            }
810            ContractError::TooManyParticipants => StdError::generic_err("Too many participants"),
811            ContractError::ContractPaused => StdError::generic_err("Contract is paused"),
812            ContractError::InvalidAddress => StdError::generic_err("Invalid address"),
813            ContractError::DuplicateParticipant => StdError::generic_err("Duplicate participant"),
814            ContractError::CannotRemoveVotedParticipant => {
815                StdError::generic_err("Cannot remove voted participant")
816            }
817            ContractError::MaximumParticipantsReached => {
818                StdError::generic_err("Maximum participants reached")
819            }
820            ContractError::RewardNftNotConfigured => {
821                StdError::generic_err("Reward NFT not configured")
822            }
823            ContractError::OnlyAdminCanExecute => StdError::generic_err("Only admin can execute"),
824            ContractError::OnlyCreatorCanCancel => StdError::generic_err("Only creator can cancel"),
825            ContractError::CannotCancelCompletedLottery => {
826                StdError::generic_err("Cannot cancel completed lottery")
827            }
828            ContractError::CannotCreateRewardAfterCompletion => {
829                StdError::generic_err("Cannot create reward after completion")
830            }
831            ContractError::NotAllParticipantsRevealed => {
832                StdError::generic_err("Not all participants revealed")
833            }
834            ContractError::InvalidCommitmentVerification => {
835                StdError::generic_err("Invalid commitment verification")
836            }
837            ContractError::MustSubmitCommitmentFirst => {
838                StdError::generic_err("Must submit commitment first")
839            }
840            ContractError::CommitmentAlreadySubmitted => {
841                StdError::generic_err("Commitment already submitted")
842            }
843            ContractError::RevealAlreadySubmitted => {
844                StdError::generic_err("Reveal already submitted")
845            }
846            ContractError::SessionNotActive => StdError::generic_err("Session not active"),
847            ContractError::TransfersLocked => StdError::generic_err("Transfers locked"),
848            ContractError::OnlyAdminCanSetLock => StdError::generic_err("Only admin can set lock"),
849            ContractError::OnlyAdminCanSetSessionActive => {
850                StdError::generic_err("Only admin can set session active")
851            }
852            ContractError::OnlyAdminCanAddParticipants => {
853                StdError::generic_err("Only admin can add participants")
854            }
855            ContractError::OnlyAdminCanRemoveParticipants => {
856                StdError::generic_err("Only admin can remove participants")
857            }
858            ContractError::OnlyAdminCanUpdateConfig => {
859                StdError::generic_err("Only admin can update config")
860            }
861            ContractError::OnlyAdminCanPauseContract => {
862                StdError::generic_err("Only admin can pause contract")
863            }
864            ContractError::OnlyAdminCanResumeContract => {
865                StdError::generic_err("Only admin can resume contract")
866            }
867            ContractError::OnlyAdminCanCreateRewardNft => {
868                StdError::generic_err("Only admin can create reward NFT")
869            }
870            ContractError::Generic(msg) => StdError::generic_err(msg),
871        }
872    }
873}
874
875// ==================== 工具函数 ====================
876
877/// 验证承诺哈希
878pub fn verify_commitment(commitment_hash: &str, vote_data: &[u8], salt: &str) -> bool {
879    use sha2::{Digest, Sha256};
880    let mut hasher = Sha256::new();
881    hasher.update(vote_data);
882    hasher.update(salt.as_bytes());
883    let calculated_hash = format!("{:x}", hasher.finalize());
884    calculated_hash == commitment_hash
885}
886
887/// 生成承诺哈希
888pub fn generate_commitment_hash(vote_data: &[u8], salt: &str) -> String {
889    use sha2::{Digest, Sha256};
890    let mut hasher = Sha256::new();
891    hasher.update(vote_data);
892    hasher.update(salt.as_bytes());
893    format!("{:x}", hasher.finalize())
894}
895
896/// 生成随机种子
897pub fn generate_random_seed(block_hash: &str, timestamp: u64) -> u64 {
898    use sha2::{Digest, Sha256};
899    let mut hasher = Sha256::new();
900    hasher.update(block_hash.as_bytes());
901    hasher.update(timestamp.to_be_bytes());
902    let hash = hasher.finalize();
903
904    let mut seed_bytes = [0u8; 8];
905    seed_bytes.copy_from_slice(&hash[0..8]);
906    u64::from_be_bytes(seed_bytes)
907}
908
909/// 验证参与者地址唯一性(CosmWasm 兼容版本)
910pub fn validate_unique_participants(participants: &[String]) -> Result<(), ContractError> {
911    for i in 0..participants.len() {
912        for j in (i + 1)..participants.len() {
913            if participants[i] == participants[j] {
914                return Err(ContractError::DuplicateParticipant);
915            }
916        }
917    }
918    Ok(())
919}
920
921/// 验证参与者数量
922pub fn validate_participant_count(
923    participants: &[String],
924    min_participants: u32,
925    max_participants: u32,
926) -> Result<(), ContractError> {
927    let count = participants.len() as u32;
928
929    if count < min_participants {
930        return Err(ContractError::InsufficientParticipants);
931    }
932
933    if count > max_participants {
934        return Err(ContractError::TooManyParticipants);
935    }
936
937    Ok(())
938}
939
940/// 创建默认奖品信息
941pub fn create_default_reward() -> VotingReward {
942    VotingReward {
943        name: "Default Reward".to_string(),
944        description: "A default reward for lottery winners".to_string(),
945        image_uri: None,
946        external_link: None,
947        attributes: None,
948        background_color: None,
949        animation_url: None,
950        youtube_url: None,
951    }
952}
953
954/// 创建示例奖品信息
955pub fn create_example_reward() -> VotingReward {
956    VotingReward {
957        name: "Lucky Winner NFT".to_string(),
958        description: "A special NFT for the lottery winner".to_string(),
959        image_uri: Some("https://example.com/winner-nft.png".to_string()),
960        external_link: Some("https://example.com/winner-info".to_string()),
961        attributes: Some(vec![
962            RewardAttribute {
963                trait_type: "Rarity".to_string(),
964                value: "Legendary".to_string(),
965                display_type: Some("string".to_string()),
966            },
967            RewardAttribute {
968                trait_type: "Power Level".to_string(),
969                value: "100".to_string(),
970                display_type: Some("number".to_string()),
971            },
972        ]),
973        background_color: Some("#FFD700".to_string()),
974        animation_url: Some("https://example.com/winner-animation.mp4".to_string()),
975        youtube_url: Some("https://youtube.com/watch?v=winner".to_string()),
976    }
977}