Level-729-易画行-复现
hgame 易画行复现
此题是为了让⼤家稍微了解⼀下区块链。需要的知识是区块链的⼀些基本知识和ipfs的⼀些知识。
这道题确实不难,可惜我没有认真学Blockchain,做这个题也没有投入精力,只是看了看,赛后9C±Void师傅给我写了一份解析,在此致谢!
题目给了一个Typescript文件
import { ethers } from 'ethers';
import config from './config.json';
const abi = [
'function safeTransferFrom(address from, address to, uint256 tokenId) external',
'function approve(address to, uint256 tokenId) external',
'function getApproved(uint256 tokenId) external view returns (address)',
'function ownerOf(uint256 tokenId) external view returns (address)',
];
async function transferNFT(tokenId: number, toAddress: string) {
const provider = new ethers.JsonRpcProvider('https://sepolia.drpc.org');
const wallet = new ethers.Wallet(config.privateKey, provider);
if (wallet.address.toLowerCase() !== config.fromAddress.toLowerCase()) {
throw new Error('私钥与发送方地址不匹配');
}
const nftContract = new ethers.Contract(config.nftAddress, abi, wallet);
try {
console.log('开始转移NFT...');
const tx = await nftContract.safeTransferFrom(
config.fromAddress,
toAddress,
tokenId
);
console.log('等待交易确认...');
const receipt = await tx.wait();
console.log(`NFT转移成功! 交易哈希: ${receipt.hash}`);
return receipt;
} catch (error) {
console.error('转移NFT时发生错误:', error);
throw error;
}
}
const tokenId = 1;
const toAddress = '0x74520Ad628600F7Cc9613345aee7afC0E06EFd84';
transferNFT(tokenId, toAddress)
.then(() => console.log('转移完成'))
.catch(console.error);
代码使用 ethers.js 进行智能合约交互,代码中使用了ethers.JsonRpcProvider('https://sepolia.drpc.org'),意味着这个脚本是连接Sepolia 测试网,并有NFT转移的操作,最后告诉了我们转移的NFT的TokenID和NFT接收方的地址,因此我们肯定是要从接收方地址开始下手。
用Etherscan浏览器搜索,不过是测试网,所以用这个https://sepolia.etherscan.io/

看到那个Vidar的NFT,获取NFT的 tokenURI 有2种做法
两种解法
第一种:纯粹的溯源
点击右下那个 NFT: Vidar#1 我们能进入
下面一共就只有铸
造(Mint)和转移(Transfer)两个操作,而一般来说对于一个NFT而言,它的Metadata只会在铸造的
时候进行设定,之后它的Metadata将不再发生改变,因此我们需要查看它的铸造操作

我们点击最下面那个
进入对应的交易详情页面,在Logs里面看到合约emit了MetadataUpdate事件,说明这个交易中的确发生了Metadata的改变


改变的数据我们可以直接查看交易中的 Input Data 栏,点击 Decode Input Data 我们就能够看到修改的tokenURI是什么了


用ipfs desktop打开ipfs地址

不下载这个也可,访问这个https://ipfs.io/ipfs/(Link Hash)
第二种:合约调用
这个是9C±Void师傅写的脚本,本人太菜,入门程度都未到
from web3 import Web3
# Configuration
RPC_URL = "https://sepolia.drpc.org"
NFT_ADDRESS = "0x0c5ABBB0743a3Ac77C2c301eD63810F3353c59F8"
# 初始化 Web3 连接
w3 = Web3(Web3.HTTPProvider(RPC_URL))
# 检查连接是否成功
if not w3.is_connected():
raise ConnectionError("无法连接到以太坊节点,请检查 RPC URL")
# 合约 ABI
ABI = [
{
"inputs": [
{"internalType": "uint256", "name": "tokenId", "type": "uint256"},
],
"name": "tokenURI",
"outputs": [{"internalType": "string", "name": "", "type": "string"}],
"stateMutability": "view", # 修正为 view
"type": "function",
},
]
# 绑定合约
nft = w3.eth.contract(address=NFT_ADDRESS, abi=ABI)
# 调用 tokenURI 方法
token_id = 1
try:
uri = nft.functions.tokenURI(token_id).call()
print(f"Token {token_id} URI: {uri}")
except Exception as e:
print(f"调用 tokenURI 失败: {e}")

接下来就和上面一样了
有关上面的MetadataUpdate事件,这个事件来自EIP5008: ERC-721 Nonce and Metadata
Update Extension - EIPs - Fellowship of Ethereum Magicians,直接去官网上看EIP-5008的话只
会看到它对Nonce拓展的定义,但是官网给出了通往上面这个链接的跳转

浙公网安备 33010602011771号