You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何序列化以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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 22:00:05