关于web3.py集成Metamask的问题,web3.py官方也明确指明:只是把测试网络的账号秘钥导入,然后连接Metamask的测试网络进行转账,似乎无法集成Metamask。毕竟Metamask是支持js浏览器的用法,也正常!如果要开发基于Metamask的应用,直接用web3.js即可!
注:使用web3.js的时候,Metamask会自动嵌入一段js代码进入网站,所以我们网站可以自动识别是不是Metamask提供者!
说明:这里是使用Flask-web3作为案例!
Flask-web3仅对web3.py做了一个封装,用法还是和web3.py一样,只是为了符合flask框架,增加了一个全局对象current_web3,并把区块链服务器配置写入了配置文件中!
Flask-web3内部配置实现之源代码:
一个完整测试成功的案例
(建议使用ganache-cli来测试,而geth,我创建了私有区块链测试,可能是区块同步的问题,geth的console命令行转账测试都没成功,开启挖矿也测试了,没成功.........)
from flask_web3 import FlaskWeb3
import json
# 这些import仅仅用来方便注释type:类型,智能提示作用!
from requests import Timeout
from web3 import Web3
from web3.eth import Eth, Contract
from web3.personal import Personal
class Web3Contract:
def __init__(self):
self.web3 = FlaskWeb3() # type:Web3
self.eth = self.web3.eth # type:Eth
self.personal = self.web3.personal # type:Personal
self.abi_json_file_path = 'app/api/v1/eth/truffle/build/contracts/FirstContract.json'
self.from_addr = self.eth.accounts[0]
self.private_key_for_senders_account = "longmai123456"
self.start()
def start(self):
# 这里很重要,defaultAccount默认为null,设置一个默认交易转账账号(如果transaction没指定from地址,那么这里是必须的)
self.eth.defaultAccount = self.eth.accounts[0]
# 交易转账参数(如果不指定发送者,from为默认账号eth.defaultAccount)
transaction = {
"from": self.from_addr
}
# 读取合约的abi-json文件
contract_interface = self.get_contract_json(self.abi_json_file_path)
# 部署合约地址
contract_address = self.deploy_contract_address(contract_interface, transaction)
# 获取合约实例
store_var_instance = self.get_contract_instance(contract_address, contract_interface)
# 调用合约实例方法
self.invoke_contract_methods(store_var_instance, transaction)
@staticmethod
def get_contract_json(json_file_path):
# 通过with上下文管理器读取json文件,更安全!
with open(json_file_path, 'r', encoding="UTF-8") as f:
source = json.load(f)
return source
def deploy_contract_address(self, contract_interface, transaction):
self.unlockAccount()
# 注:如果没有设置web.eth.defaultAccount默认账号的话,这里合约部署必须在指定transaction中指定from发送地址!
tx_hash = self.eth.contract(
abi=contract_interface['abi'],
bytecode=contract_interface['bytecode']).constructor().transact(transaction=transaction)
tx_receipt = self.wait_for_receipt(tx_hash, 120)
return tx_receipt["contractAddress"]
def get_contract_instance(self, contract_address, contract_interface):
# 获取合约实例!
instance = self.eth.contract(
address=contract_address,
abi=contract_interface['abi'])
return instance
def invoke_contract_methods(self, contract_instance, transaction):
# 这里仅方便pycharm智能语法提示使用!
instance = contract_instance # type:Contract
# 发送交易之前必须解锁账户!
self.unlockAccount()
# 调用合约的setInfo方法,并获取交易的hash值!
tx_hash = instance.functions.setInfo("kirin", 18).transact(transaction=transaction)
# 获取hash值解码的收据凭证(其中包含当前hash的全部信息,如合约地址,交易账号,gas.....)
tx_receipt = self.wait_for_receipt(tx_hash, 120)
# 返回solidity的事件log
event_logs = instance.events.eventInfo().processReceipt(tx_receipt)
name, age = instance.functions.getInfo().call()
print("调用solidity返回的值", name, age)
def wait_for_receipt(self, tx_hash, max_seconds):
try:
tx_receipt = self.eth.waitForTransactionReceipt(tx_hash, max_seconds)
except Timeout:
raise Timeout("合约部署请求超时!!!")
return tx_receipt
def transfer_to(self):
self.unlockAccount()
self.eth.sendTransaction({
"from": self.from_addr,
"to": self.eth.accounts[1],
"value": self.web3.toWei(1, 'ether')
})
print("账户收到金额:", self.eth.getBalance(self.eth.accounts[1]))
def unlockAccount(self):
self.personal.unlockAccount(self.from_addr, self.private_key_for_senders_account, 3600)