如何序列化以String为键的near-sdk-rs LookUpMap?是否有更优实现方案?
NEAR Sputnik DAO合约令牌权重映射序列化问题解决
报错根因
NEAR SDK中LookupMap、UnorderedSet、UnorderedMap这类链上持久化存储结构仅实现了Borsh序列化(用于链上状态存储),未实现Serde的JSON序列化/反序列化能力:
- 不能作为合约方法(含构造函数)的入参,外部调用无法传递符合JSON序列化要求的参数
- 直接放在合约主结构体中如果未跳过Serde序列化,会触发编译报错
改造方案
不需要尝试给LookupMap实现Serde序列化,只需调整入参设计,在合约内部初始化存储结构即可,完整修改代码如下:
1. 补充存储键与结构体定义
use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize, BorshStorageKey}; use near_sdk::{near_bindgen, AccountId, LookupMap, UnorderedMap, UnorderedSet, U128, U64}; // 存储键枚举,新增令牌权重的存储前缀 #[derive(BorshSerialize, BorshStorageKey)] enum StorageKeys { Users, ValidNFTs, VoteTokenIds, TokenVoteWeights, } #[near_bindgen] #[derive(BorshDeserialize, BorshSerialize)] pub struct Contract { pub owner_id: AccountId, pub vote_token_ids: UnorderedSet<String>, pub users: LookupMap<AccountId, /* 替换为你实际定义的用户结构体类型 */>, pub total_amount: UnorderedMap<String, U128>, pub unstake_period: u64, pub token_vote_weights: LookupMap<String, U128>, }
2. 修改构造函数逻辑
#[ext_contract(ext_self)] pub trait Contract { fn exchange_callback_post_withdraw(&mut self, sender_id: AccountId, token_id: String, amount: U128); } #[near_bindgen] impl Contract { #[init] pub fn new( owner_id: AccountId, token_ids: Vec<String>, unstake_period: U64, token_vote_weights: Vec<(String, U128)>, ) -> Self { // 内部初始化可投票令牌集合 let mut vote_token_ids = UnorderedSet::new(StorageKeys::VoteTokenIds); for token_id in token_ids { vote_token_ids.insert(&token_id); } // 内部初始化令牌权重映射,写入传入的权重配置 let mut token_vote_weights_map = LookupMap::new(StorageKeys::TokenVoteWeights); for (token_id, weight) in token_vote_weights { token_vote_weights_map.insert(&token_id, &weight); } Self { owner_id: owner_id.into(), vote_token_ids, users: LookupMap::new(StorageKeys::Users), total_amount: UnorderedMap::new(StorageKeys::ValidNFTs), unstake_period: unstake_period.0, token_vote_weights: token_vote_weights_map, } } }
3. 可选:增加权重查询视图方法
如果需要对外暴露权重查询能力,不要直接返回LookupMap,单独封装查询方法:
#[near_bindgen] impl Contract { // 查询单个令牌的投票权重 pub fn get_token_vote_weight(&self, token_id: String) -> Option<U128> { self.token_vote_weights.get(&token_id) } // 查询所有已配置令牌的投票权重 pub fn list_all_token_weights(&self) -> Vec<(String, U128)> { self.vote_token_ids.iter().map(|token_id| { (token_id.clone(), self.token_vote_weights.get(&token_id).unwrap_or(U128(0))) }).collect() } }
内容的提问来源于stack exchange,提问作者Rashi Abramson
相关产品推荐
相关产品推荐

