Solidity

從 web3.py 執行合約函式

  • August 31, 2022

我在 Ropsten 上部署了一個合約,這個合約有一個函式名 testFunc(),我想從 python 腳本執行 testFunc()。

這就是我從 python 連接到契約的方式:

from web3 import Web3

def connect_to_contract(self):
   try:
       self.web3 = Web3(
           Web3.HTTPProvider(
               "https://" +
               self.network +
               ".infura.io/v3/" +
               os.getenv("WEB3_INFURA_PROJECT_ID")))
       self.contract = self.web3.eth.contract(
           address=self.contract_address, abi=self.contract_abi)
   except Exception as e:
       raise e

然後,這就是我第一次嘗試執行合約功能但沒有發生任何事情的方式:

self.contract.functions.testFunc().call()

我已經閱讀了我必須簽署交易以使其正常工作的不同主題。這就是我想要知道的方式:

txn = self.contract.functions.testFunc().buildTransaction({
           'gas': 70000,
           'gasPrice': self.web3.toWei('1', 'gwei'),
           'from': self.contract_address,
           'nonce': nonce
   })
private_key = "xxxxxxxxxx" 
signed_txn = self.web3.eth.account.signTransaction(txn, private_key=private_key)
self.web3.eth.sendRawTransaction(signed_txn.rawTransaction)

但這也不起作用,我收到錯誤消息:

TypeError: from field must match key’s 0x25c77Axxxxxxxxxxxxxxxxxxxxxxxx, but it was 0x7d8e0ea7axxxxxxxxxxxxxxxxxxxxxx

這裡提到的 0x25c77Axxxxxxxxxxxxxxxxxxxxxxxxxxx 地址是我用來部署合約的公鑰,第二個 0x7d8e0ea7axxxxxxxxxxxxxxxxxxxxxx 是具有 testFunc() 函式的合約。

所以我的問題是,如何從 python 腳本委託呼叫,或者如何獲取已部署合約的私鑰?我應該怎麼做 ?

Chainstack的開發倡導者在這裡!

當你用於web3.py與智能合約互動時,可以將腳本分為三部分:

  • 連接到網路。
  • 初始化智能合約和賬戶以簽署交易。
  • 呼叫函式和事務。

連接到網路

我總是使用這種語法將我的腳本連接到網路,您也可以使用環境變數,但對於測試腳本,我通常保持簡單。

from web3 import Web3

# Initialize endpoint URL
node_url = "CHAINSTACK_NODE_URL"

# Create the node connection
web3 = Web3(Web3.HTTPProvider(node_url))

我通常添加一個 if 語句來在控制台上給出一條消息,以驗證連接是否成功(非必需但對使用者來說非常好)。

# Verify if the connection is successful
if web3.isConnected():
   print("-" * 50)
   print("Connection Successful")
   print("-" * 50)
else:
   print("Connection Failed")

初始化智能合約和賬戶

要從智能合約呼叫函式,我們需要先指定其地址和 ABI。

# Initialize the address calling the functions/signing transactions
caller = "YOUR_ADDRESS"
private_key = "PRIVATE_KEY"  # To sign the transaction

# Initialize address nonce
nonce = web3.eth.getTransactionCount(caller)

# Initialize contract ABI and address
abi = '[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"balanceLeft","type":"uint256"}],"name":"balance","type":"event"},{"inputs":[{"internalType":"address payable","name":"recipient","type":"address"}],"name":"destroy","outputs":[],"stateMutability":"nonpayable","type":"function"}'

contract_address = "CONTRACT_ADDRESS"

# Create smart contract instance
contract = web3.eth.contract(address=contract_address, abi=abi)

呼叫函式和事務

現在我們可以開始呼叫函式了;我們可以通過兩種方式做到這一點:

  • .call如果該函式僅從區塊鏈中讀取(如果它是一個viewpure函式)
  • 建構一個事務來呼叫一個修改網路狀態的函式。

我注意到在您的程式碼中,您使用合約地址來呼叫該函式,而不是從您的帳戶中呼叫它。

# initialize the chain id, we need it to build the transaction for replay protection
Chain_id = web3.eth.chain_id

# Call your function
call_function = contract.functions.testFunc().buildTransaction({"chainId": Chain_id, "from": caller, "nonce": nonce})

# Sign transaction
signed_tx = web3.eth.account.sign_transaction(call_function, private_key=private_key)

# Send transaction
send_tx = web3.eth.send_raw_transaction(signed_tx.rawTransaction)

# Wait for transaction receipt
tx_receipt = web3.eth.wait_for_transaction_receipt(send_tx)
# print(tx_receipt) # Optional

然後,如果你想呼叫一個只從網路(viewpure)讀取的函式,你只需要“呼叫”它,因為它不會進行實際交易。

例如totalSupply()來自 ERC20 代幣合約的函式。

totalSupply = contract.functions.totalSupply().call()  # read the coin total supply - call means we are reading from the blockchain
print(totalSupply) 

您可以查看Chainstack 文件上的Node API 參考頁面web3.py以查看更多程式碼範例!

我希望這可以幫助你!

引用自:https://ethereum.stackexchange.com/questions/134720