以太坊智能合约可以用于实现去中心化的 NFT 市场合约,允许用户将 NFT 上架到市场,并由其他用户购买。这个过程需要依赖智能合约来托管交易资金,并确保所有步骤自动化和无信任化操作。
我们可以将 上架 NFT 和 购买 NFT 视为一个资金托管过程:卖家将 NFT 上架,买家支付资金,而智能合约在买家付款后完成 NFT 的转移并将资金发送给卖家。
# 关键步骤:
卖家上架 NFT:卖家将自己的 NFT 上架到市场,设定价格。NFT 由市场合约托管,直到有买家购买。
买家购买 NFT:买家支付指定的金额,资金通过智能合约托管。合约会确保资金到达后,将 NFT 从市场转移到买家账户,并将资金发送给卖家。
资金与 NFT 转移:智能合约负责在买家支付后,安全地转移 NFT 给买家,同时将资金转移给卖家。
# Solidity 合约示例:NFT 上架和购买
我们可以使用 ERC721
标准来处理 NFT,并结合托管和市场逻辑。以下是一个简单的实现,包括 NFT 上架和购买功能:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol";
import "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract NFTMarketplace is ERC721Holder, Ownable {
struct Listing {
address seller;
uint256 price;
address nftContract;
uint256 tokenId;
}
// 列出所有上架的 NFT
Listing[] public listings;
// 添加一个上架事件
event NFTListed(address indexed seller, address indexed nftContract, uint256 indexed tokenId, uint256 price);
event NFTPurchased(address indexed buyer, address indexed nftContract, uint256 indexed tokenId, uint256 price);
// 卖家上架 NFT
function listNFT(address nftContract, uint256 tokenId, uint256 price) external {
require(price > 0, "Price must be greater than zero");
// 将 NFT 从卖家转移到市场合约中进行托管
IERC721(nftContract).safeTransferFrom(msg.sender, address(this), tokenId);
// 记录上架信息
listings.push(Listing({
seller: msg.sender,
price: price,
nftContract: nftContract,
tokenId: tokenId
}));
// 触发上架事件
emit NFTListed(msg.sender, nftContract, tokenId, price);
}
// 买家购买 NFT
function purchaseNFT(uint256 listingIndex) external payable {
Listing memory listing = listings[listingIndex];
// 确保买家支付了正确的价格
require(msg.value >= listing.price, "Insufficient payment");
// 删除已购买的 listing
removeListing(listingIndex);
// 将资金转给卖家
payable(listing.seller).transfer(listing.price);
// 将 NFT 转移给买家
IERC721(listing.nftContract).safeTransferFrom(address(this), msg.sender, listing.tokenId);
// 触发购买事件
emit NFTPurchased(msg.sender, listing.nftContract, listing.tokenId, listing.price);
}
// 删除上架的 NFT(当 NFT 被购买后)
function removeListing(uint256 index) internal {
require(index < listings.length, "Index out of bounds");
listings[index] = listings[listings.length - 1];
listings.pop();
}
// 获取市场上所有上架的 NFT 列表
function getListings() external view returns (Listing[] memory) {
return listings;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# 功能解析
# 1. NFT 上架
卖家调用
listNFT
函数,将他们的 NFT 上架到市场:- NFT 被发送到市场合约,由合约进行托管,直到买家购买。
- 合约会记录卖家的地址、NFT 的价格和 NFT 的详细信息(如合约地址和 token ID)。
示例:
function listNFT(address nftContract, uint256 tokenId, uint256 price) external { require(price > 0, "Price must be greater than zero"); IERC721(nftContract).safeTransferFrom(msg.sender, address(this), tokenId); listings.push(Listing({ seller: msg.sender, price: price, nftContract: nftContract, tokenId: tokenId })); emit NFTListed(msg.sender, nftContract, tokenId, price); }
1
2
3
4
5
6
7
8
9
10
11- 这里使用了
IERC721.safeTransferFrom
将 NFT 从卖家账户转移到市场合约地址,这一步是典型的托管流程,确保在交易完成之前,卖家无法再对 NFT 进行操作。
# 2. 购买 NFT
买家通过
purchaseNFT
函数购买 NFT:- 买家支付指定的金额给市场合约。
- 市场合约检查支付金额是否满足要求。
- 合约将资金发送给卖家,并将 NFT 从合约转移给买家。
示例:
function purchaseNFT(uint256 listingIndex) external payable { Listing memory listing = listings[listingIndex]; require(msg.value >= listing.price, "Insufficient payment"); removeListing(listingIndex); payable(listing.seller).transfer(listing.price); IERC721(listing.nftContract).safeTransferFrom(address(this), msg.sender, listing.tokenId); emit NFTPurchased(msg.sender, listing.nftContract, listing.tokenId, listing.price); }
1
2
3
4
5
6
7
8
9
10
11- 这里使用了
payable
关键字接收买家的支付。通过transfer
函数将资金发送给卖家,并调用IERC721.safeTransferFrom
将 NFT 转移给买家。
# 3. 删除已售出的 NFT
- 当 NFT 被购买时,合约会通过
removeListing
函数从列表中删除该 NFT 的上架信息。删除操作将使用数组最后一个元素替换被移除的元素,确保删除操作高效执行。
# 4. 查询所有上架的 NFT
- 通过
getListings
函数,外部用户可以查看当前市场中所有上架的 NFT 信息。
# 资金托管的角色
在这个实现中,市场合约扮演了托管的角色:
- 当卖家上架 NFT 时,市场合约会接收并托管 NFT,确保卖家在购买完成之前无法再操作该 NFT。
- 买家支付资金后,合约会将资金托管,直到 NFT 被成功转移给买家,再将资金转给卖家。
# 改进和扩展
手续费机制:市场合约可以收取一部分手续费作为平台盈利的一部分,可以在
purchaseNFT
函数中扣除部分费用:uint public platformFee = 100; // 1% 平台手续费 function purchaseNFT(uint256 listingIndex) external payable { Listing memory listing = listings[listingIndex]; require(msg.value >= listing.price, "Insufficient payment"); removeListing(listingIndex); uint fee = listing.price * platformFee / 10000; payable(owner()).transfer(fee); // 平台费 payable(listing.seller).transfer(listing.price - fee); IERC721(listing.nftContract).safeTransferFrom(address(this), msg.sender, listing.tokenId); emit NFTPurchased(msg.sender, listing.nftContract, listing.tokenId, listing.price); }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16时间锁:可以在合约中增加时间锁机制,规定 NFT 必须上架一段时间后才能被取消或购买。
分期支付和部分支付:可以扩展合约允许买家进行分期或部分支付,等到支付完成后再转移 NFT。
# 总结
通过使用 Solidity 和 ERC721 标准,可以轻松实现一个简单的 NFT 市场合约,实现 NFT 的上架和购买功能。智能合约充当托管角色,确保买卖双方的资产和资金在去中心化的环境中得到保障。