关于 nft-blockchain
nft-blockchain 是面向 Decentraland 开发的 NFT 与 Ethereum 区块链参考资料,介绍 NFT 展示及链上功能。内容涵盖钱包检查、签名请求、智能合约、RPC 调用和 Sepolia 测试。
主要功能
- 01展示 ERC-721 NFT 艺术品
- 02检查玩家钱包及访客状态
- 03发送钱包签名的后端请求
- 04使用 eth-connect 与合约交互
- 05发起自定义 Ethereum RPC 调用
- 06在 Sepolia 上测试合约
适用场景
- 01在场景中添加带框 NFT 艺术品
- 02检查玩家是否能签署交易
- 03用钱包签名验证后端请求
- 04开发和测试智能合约交互
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ dcl-regenesislabs/ opendcl --skill nft-blockchain安装后在 Claude Code 中输入/nft-blockchain确认已加载。
详细介绍
Decentraland 中的 NFT 和区块链
显示 NFT 艺术品
NftShape 已在 main-entities.ts 中受支持——可直接声明带边框的 NFT。用户可以在可视化编辑器中拖动它。
// main-entities.ts
import type { Scene } from '@dcl/sdk/scene-types'
export const scene = {
hero_nft: {
components: {
Transform: { position: { x: 8, y: 2, z: 8 } },
NftShape: {
urn: 'urn:decentraland:ethereum:erc721:0x06012c8cf97bead5deae237070f9587f8e7a266d:558536',
color: { r: 1, g: 1, b: 1, a: 1 },
style: 0 // NftFrameType.NFT_CLASSIC — enum values are integers in the literal
}
}
}
} satisfies Scene
style 字段是一个数值枚举——不能直接在字面量中引用 NftFrameType.NFT_CLASSIC,因为 AST 遍历器只接受兼容 JSON 的表达式。请使用整数值(见下表),并添加注释。
NFT URN 格式
urn:decentraland:ethereum:erc721:<contractAddress>:<tokenId>
- 适用于 Ethereum 主网中的任何 ERC-721 NFT
- 系统会自动从 NFT 的元数据中加载图片
可用的边框样式
| value | enum name | description |
|---|---|---|
| 0 | NFT_CLASSIC | 简约经典边框 |
| 1 | NFT_BAROQUE_ORNAMENT | 华丽的巴洛克风格 |
| 2 | NFT_DIAMOND_ORNAMENT | 菱形图案 |
| 3 | NFT_MINIMAL_WIDE | 简约宽边框 |
| 4 | NFT_MINIMAL_GREY | 简约灰色边框 |
| 5 | NFT_BLOCKY | 像素化/方块风格 |
| 6 | NFT_GOLD_EDGES | 金色边缘装饰 |
| 7 | NFT_GOLD_CARVED | 雕刻金色边框 |
| 8 | NFT_GOLD_WIDE | 宽金色边框 |
| 9 | NFT_GOLD_ROUNDED | 圆角金色边框 |
| 10 | NFT_METAL_MEDIUM | 中等金属质感 |
| 11 | NFT_METAL_WIDE | 宽金属边框 |
| 12 | NFT_METAL_SLIM | 窄金属边框 |
| 13 | NFT_METAL_ROUNDED | 圆角金属边框 |
| 14 | NFT_PINS | 用图钉固定在墙上 |
| 15 | NFT_MINIMAL_BLACK | 简约黑色边框 |
| 16 | NFT_MINIMAL_WHITE | 简约白色边框 |
| 17 | NFT_TAPE | 用胶带贴在墙上 |
| 18 | NFT_WOOD_SLIM | 窄木质边框 |
| 19 | NFT_WOOD_WIDE | 宽木质边框 |
| 20 | NFT_WOOD_TWIGS | 树枝/枝条木质边框 |
| 21 | NFT_CANVAS | 画布风格 |
| 22 | NFT_NONE | 无边框 |
在允许使用枚举标识符的 src/index.ts 中,可直接使用 NftFrameType.NFT_CLASSIC 等标识符。
检查玩家钱包
import { getPlayer } from '@dcl/sdk/src/players'
function checkWallet() {
const player = getPlayer()
if (player && !player.isGuest) {
console.log('Player wallet address:', player.userId)
// userId is the Ethereum wallet address
} else {
console.log('Player is guest (no wallet)')
}
}
尝试进行任何区块链交互之前,务必先检查 isGuest——访客玩家没有连接的钱包。
签名请求
向后端发送使用玩家钱包签名的经过身份验证的请求:
import { signedFetch } from '~system/SignedFetch'
executeTask(async () => {
try {
const response = await signedFetch({
url: 'https://example.com/api/action',
init: {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
action: 'claimReward',
amount: 100
})
}
})
if (!response.ok) {
console.error('HTTP error:', response.status)
return
}
const result = JSON.parse(response.body)
console.log('Result:', result)
} catch (error) {
console.log('Request failed:', error)
}
})
signedFetch 会自动附加用于证明玩家身份的加密签名。后端可以验证此签名,以验证请求身份。
智能合约交互
需要安装 eth-connect 包:
npm install eth-connect
将 ABI 存储在单独的文件中
// contracts/myContract.ts
export default [
{
"constant": true,
"inputs": [{ "name": "_owner", "type": "address" }],
"name": "balanceOf",
"outputs": [{ "name": "balance", "type": "uint256" }],
"type": "function"
}
// ... rest of ABI
]
创建合约实例
import { RequestManager, ContractFactory } from 'eth-connect'
import { createEthereumProvider } from '@dcl/sdk/ethereum-provider'
import { abi } from '../contracts/myContract'
executeTask(async () => {
try {
// Create web3 provider
const provider = createEthereumProvider()
const requestManager = new RequestManager(provider)
// Create contract at a specific address
const factory = new ContractFactory(requestManager, abi)
const contract = await factory.at('0x2a8fd99c19271f4f04b1b7b9c4f7cf264b626edb') as any
// Read data (no gas required)
const balance = await contract.balanceOf('0x123...abc')
console.log('Balance:', balance)
} catch (error) {
console.log('Contract interaction failed:', error)
}
})
写入操作(需要 Gas)
executeTask(async () => {
try {
const userData = getPlayer()
if (userData.isGuest) return
// Write operation — prompts the player to sign the transaction
const writeResult = await contract.transfer(
'0xRecipientAddress',
100,
{
from: userData.userId,
gas: 100000,
gasPrice: await requestManager.eth_gasPrice()
}
)
console.log('Transaction hash:', writeResult)
} catch (error) {
console.log('Transaction failed:', error)
}
})
Gas 价格和余额检查
import { RequestManager } from 'eth-connect'
import { createEthereumProvider } from '@dcl/sdk/ethereum-provider'
executeTask(async () => {
const provider = createEthereumProvider()
const requestManager = new RequestManager(provider)
const gasPrice = await requestManager.eth_gasPrice()
console.log('Current gas price:', gasPrice)
const balance = await requestManager.eth_getBalance('0x123...abc', 'latest')
console.log('Account balance:', balance)
})
使用 Sepolia 测试
开发时,请使用 Sepolia 测试网:
- 将 MetaMask 设置为 Sepolia 网络
- 从 Sepolia 水龙头获取测试 ETH
- 将合约部署到 Sepolia
- 主网和测试网的合约地址不同——请使用环境检查
自定义 RPC 调用
对于 eth-connect 辅助工具未涵盖的底层 Ethereum RPC 调用,请使用 sendAsync:
import { sendAsync } from '~system/EthereumController'
const result = await sendAsync({ method: 'eth_blockNumber', params: [] })
console.log('Current block:', result.body)
打开 URL 和 NFT 对话框
使用受限操作打开外部链接和 NFT 详情视图:
import { openExternalUrl, openNftDialog } from '~system/RestrictedActions'
openExternalUrl({ url: 'https://opensea.io/collection/...' })
openNftDialog({ urn: 'urn:decentraland:ethereum:erc721:0x06012c8cf97BEaD5deAe237070F9587f8E7A266d:558536' })
最佳实践
- 任何区块链交互之前,务必检查
isGuest——访客玩家无法签署交易 - 所有异步区块链调用都使用
executeTask(async () => { ... }) - 将 ABI 文件单独存储(例如放在
contracts/中)——不要内联大型 ABI - 妥善处理错误——区块链操作可能失败(用户拒绝、Gas 不足、网络问题)
- 必须将
eth-connect安装为依赖项:npm install eth-connect - 使用
signedFetch进行后端身份验证,而非原始的fetch——它可以证明玩家身份 - 读取操作(view/pure 函数)不需要 Gas;写入操作会提示用户签名
- 部署到主网之前,先在 Sepolia 上测试
- NFT URN 仅适用于 Ethereum 主网的 ERC-721 代币
评论
支持 Markdown