如何在Django中通过web3.py与Metamask实现以太坊合约交易
解决方案
首先明确:后端(Django视图)无法直接触发浏览器端的Metamask签名请求,因为Metamask是运行在浏览器中的扩展,只能由前端JavaScript代码调用。你需要调整实现逻辑,采用「前端处理签名+后端辅助验证」的模式,具体步骤如下:
核心实现步骤
步骤1:后端准备合约关键数据
在Django视图中,提前准备好合约的ABI、合约地址、参与彩票所需的固定参数(比如彩票金额),将这些数据传递给前端模板。示例代码:# Django视图函数 from django.shortcuts import render def lottery_participate(request): contract_address = "0xD5d56C139848A0E55DC5C616D04a0CeD98D8BeA3" # 简化的合约ABI(仅保留参与函数) contract_abi = [ { "inputs": [], "name": "enterLottery", "outputs": [], "stateMutability": "payable", "type": "function" } ] lottery_entry_amount = "0.01" # 参与彩票所需ETH金额(测试网) return render(request, 'participate.html', { 'contract_address': contract_address, 'contract_abi': contract_abi, 'entry_amount': lottery_entry_amount })步骤2:前端JavaScript处理交易签名与发送
在前端模板中,编写JS代码监听「参与彩票」按钮的点击事件,通过Metamask的eth_requestAccounts获取用户账户,然后构造交易并调用Metamask请求签名:// 前端JS代码 document.getElementById('join-lottery-btn').addEventListener('click', async () => { if (typeof window.ethereum !== 'undefined') { try { // 确保用户已连接钱包 const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' }); const web3 = new Web3(window.ethereum); // 从后端获取的合约数据 const contractAddress = "{{ contract_address }}"; const contractAbi = JSON.parse('{{ contract_abi|escapejs }}'); const entryAmount = web3.utils.toWei("{{ entry_amount }}", 'ether'); // 初始化合约实例 const lotteryContract = new web3.eth.Contract(contractAbi, contractAddress); // 构造交易并请求签名 const txResponse = await lotteryContract.methods.enterLottery().send({ from: accounts[0], value: entryAmount }); // 交易发送成功后,可将txHash发送给后端记录 fetch('/record-transaction/', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCSRFToken() // Django的CSRF令牌 }, body: JSON.stringify({ tx_hash: txResponse.transactionHash }) }); alert('参与成功!交易哈希:' + txResponse.transactionHash); } catch (error) { console.error('交易失败:', error); alert('交易失败,请检查钱包设置'); } } else { alert('请安装Metamask钱包'); } }); // 获取Django CSRF令牌的辅助函数 function getCSRFToken() { return document.querySelector('[name=csrfmiddlewaretoken]').value; }步骤3:后端验证交易状态(可选)
如果需要后端确认用户参与成功,可以在接收交易哈希的视图中,使用web3.py查询链上交易状态:# Django接收交易哈希的视图 from django.http import JsonResponse from web3 import Web3 def record_transaction(request): if request.method == 'POST': tx_hash = request.POST.get('tx_hash') w3 = Web3(Web3.HTTPProvider('https://sepolia.infura.io/v3/YOUR_INFURA_KEY')) tx_receipt = w3.eth.get_transaction_receipt(tx_hash) if tx_receipt.status == 1: # 交易成功,可更新数据库记录用户参与状态 return JsonResponse({'status': 'success', 'message': '交易已确认'}) else: return JsonResponse({'status': 'failed', 'message': '交易执行失败'}) return JsonResponse({'status': 'error', 'message': '无效请求'})
关键注意事项
- 确保前端引入
web3.js库(可以通过CDN加载:<script src="https://cdn.jsdelivr.net/npm/web3@latest/dist/web3.min.js"></script>) - 处理Metamask的网络切换问题,确保用户当前连接的是Sepolia测试网
- 后端不要存储用户的私钥或签名信息,所有签名操作必须由前端Metamask完成
内容的提问来源于stack exchange,提问作者Nilesh
相关产品推荐
相关产品推荐

