如何基于CW721 NFT实现拍卖智能合约?
解决方案:让CW721持有者发送NFT时携带拍卖配置参数
核心思路:复用CW721标准的SendNft消息字段
CW721标准的SendNft消息本身支持在msg字段传入任意二进制数据,该数据会被完整转发到接收合约的ReceiveNft消息中。你不需要修改现有CW721合约的核心逻辑,只需让调用者在发送SendNft时把拍卖参数编码后放入msg字段,再由拍卖合约解码即可。
具体实现步骤
1. 定义拍卖配置的自定义结构体
在拍卖合约中定义包含必要参数的结构体:
use cosmwasm_std::{Uint128, Timestamp}; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] pub struct AuctionInitParams { pub start_time: Timestamp, pub duration: u64, // 单位:秒 pub min_bid: Uint128, // 可按需添加其他参数,比如手续费比例、预留出价地址等 }
2. 持有者调用SendNft时携带编码后的参数
用户(NFT持有者)调用CW721合约的SendNft时,将AuctionInitParams序列化为Base64编码字符串(或直接二进制,依客户端工具支持情况),放入msg字段。示例Rust客户端代码:
use cosmwasm_std::to_binary; use cw721::Cw721ExecuteMsg; // 构造拍卖参数 let auction_params = AuctionInitParams { start_time: Timestamp::from_seconds(1717248000), // 示例时间戳 duration: 86400, // 24小时 min_bid: Uint128::new(1000000), // 1个原生代币 }; // 序列化为二进制并转Base64 let encoded_params = base64::encode(to_binary(&auction_params).unwrap()); // 构造SendNft消息 let send_nft_msg = Cw721ExecuteMsg::SendNft { contract: "auction-contract-address".to_string(), token_id: "nft-123".to_string(), msg: Some(encoded_params), };
3. 拍卖合约解码ReceiveNft中的自定义数据
在拍卖合约的receive_nft处理函数中,提取Cw721ReceiveMsg的msg字段并解码为AuctionInitParams:
use cosmwasm_std::{Binary, DepsMut, Env, MessageInfo, Response, StdError}; use cw721::Cw721ReceiveMsg; pub fn receive_nft( deps: DepsMut, env: Env, info: MessageInfo, msg: Cw721ReceiveMsg, ) -> Result<Response, StdError> { // 解码自定义参数 let auction_params: AuctionInitParams = match msg.msg { Some(encoded) => { let binary = Binary::from_base64(&encoded)?; deps.api.addr_validate(&msg.sender)?; // 验证发送者地址合法性 serde_json::from_slice(&binary)? } None => return Err(StdError::generic_err("缺少拍卖初始化参数")), }; // 执行拍卖初始化逻辑:检查时间合法性、存储拍卖数据、设置状态等 // 示例: // let auction_id = format!("{}_{}", msg.token_id, env.block.time.nanos()); // save_auction(deps.storage, &auction_id, &auction_params, &msg.sender, &msg.token_id)?; Ok(Response::new() .add_attribute("action", "auction_initiated") .add_attribute("token_id", msg.token_id) .add_attribute("min_bid", auction_params.min_bid.to_string())) }
CW721合约架构建议
你当前的基础CW721实现完全满足需求,不需要修改核心逻辑——标准SendNft的msg字段已经能承载自定义参数。如果后续需要扩展(比如限制特定NFT可发起拍卖),再考虑在CW721合约中添加SendNftToAuction自定义执行消息,内部调用标准SendNft并做额外校验即可,现阶段优先复用标准字段实现核心功能。
避坑提示
- 必须在拍卖合约中验证参数合法性:比如
start_time不能早于当前区块时间、duration不能为0、min_bid必须大于0等。 - 确保编码解码格式一致:客户端和合约要统一使用相同的编码方式(如Base64+JSON或Protobuf二进制),避免解码失败。
- 二次验证发送者身份:虽然CW721合约已校验持有者身份,但拍卖合约再次验证
msg.sender的合法性更安全。
内容的提问来源于stack exchange,提问作者cowboy
相关产品推荐
相关产品推荐

