Solidity
使用 Hardhat 測試時出現錯誤恐慌程式碼 0x32 已解決
當我嘗試使用 Hardhat 測試此契約時,我收到與“批准 3 個帳戶的交易”測試相關的下一個錯誤。但我不知道為什麼會觸發此錯誤。
錯誤:處理事務時出現 VM 異常:使用緊急程式碼 0x32 恢復(在越界或負索引處訪問的數組)
有人可以幫忙嗎?請。
智能合約 MultiSigWallet.sol
pragma solidity ^0.8.10; contract MultiSigWallet { event Deposit(address indexed sender, uint256 amount, uint256 balance); event SubmitTransaction(uint256 indexed txId); event ApproveTransaction(address indexed owner, uint256 indexed txId); event RevokeTransaction(address indexed owner, uint256 indexed txId); event ExecuteTransaction(uint256 indexed txId); struct Transaction { address payable to; uint256 amount; bytes data; bool executed; uint256 numConfirmations; } Transaction[] public transactions; address[] owners; mapping(address => bool) isOwner; // mapping from tx index => owner => bool mapping(uint256 => mapping(address => bool)) approved; mapping(uint256 => bool) executed; uint256 confirmationsRequired; modifier onlyOwner() { require(isOwner[msg.sender], "You are not an owner"); _; } modifier txNotApproved(uint256 _txId) { require( !approved[_txId][msg.sender], "The transaction is already approved" ); _; } modifier txNotExecuted(uint256 _txId) { require( !transactions[_txId].executed, "The transaction has been already executed" ); _; } modifier txExists(uint256 _txId) { require( transactions.length >= _txId, "The transaction does not exists" ); _; } constructor(address[] memory _owners, uint256 _confirmationsRequired) { require(_owners.length > 0, "Owners needs to be greater than 0"); require( _confirmationsRequired > 0, "Owners required needs to be greater than 0" ); for (uint256 i = 0; _owners.length > i; i++) { address _owner = _owners[i]; require(_owner != address(0)); isOwner[_owners[i]] = true; } owners = _owners; confirmationsRequired = _confirmationsRequired; } receive() external payable { emit Deposit(msg.sender, msg.value, address(this).balance); } function submitTransaction( uint256 _amount, address payable _to, bytes memory _data ) public onlyOwner { transactions.push( Transaction({ to: _to, amount: _amount, data: _data, executed: false, numConfirmations: 0 }) ); uint256 txIndex = transactions.length; emit SubmitTransaction(txIndex); } function approveTransaction(uint256 _txId) public onlyOwner txExists(_txId) txNotApproved(_txId) txNotExecuted(_txId) { transactions[_txId].numConfirmations += 1; approved[_txId][msg.sender] = true; emit ApproveTransaction(msg.sender, _txId); } function revokeConfirmation(uint256 _txId) public onlyOwner txExists(_txId) txNotExecuted(_txId) { require( approved[_txId][msg.sender] = true, "This Transaction is not approved by the msg.sender" ); approved[_txId][msg.sender] = false; emit RevokeTransaction(msg.sender, _txId); } function executeTransaction(uint256 _txId) public payable onlyOwner txNotExecuted(_txId) txExists(_txId) { Transaction storage transaction = transactions[_txId]; require( transaction.numConfirmations >= confirmationsRequired, "Not enough confirmations from the Owners" ); transaction.executed = true; uint256 _transactionAmount = transaction.amount; address payable _to = transaction.to; _to.transfer(_transactionAmount); emit ExecuteTransaction(_txId); } function getOwners() public view returns (address[] memory) { return owners; } function checkExecuted(uint256 _txId) public view returns (bool) { return executed[_txId]; } function getTransactions() public view returns (uint256) { return transactions.length; } function getConfirmations(uint256 _txId) public view returns (uint256) { return transactions[_txId].numConfirmations; } }
測試腳本(安全帽)
const { ethers } = require("hardhat"); const { expect } = require("chai"); const { loadFixture } = require("ethereum-waffle"); const { TransactionDescription } = require("ethers/lib/utils"); // Ganache accounts (Testnet): // 1: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 // 2: 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 // 3: 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC // 4: 0x90F79bf6EB2c4f870365E785982E1f101E93b906 describe("MultiSigWallet", function () { async function deploy() { const MultiSigWallet = await ethers.getContractFactory("MultiSigWallet"); const multiSigWallet = await MultiSigWallet.deploy( [ "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC", ], 3 ); await multiSigWallet.deployed(); console.log("* MultiSigWallet contract has been deployed."); console.log("* MultiSigWallet contract address:", multiSigWallet.address); return { multiSigWallet }; } it("Check the Owners array length", async () => { const { multiSigWallet } = await loadFixture(deploy); const owners = await multiSigWallet.getOwners(); expect(owners.length).to.equal(3); }); it("Submit a new transaction", async () => { const { multiSigWallet } = await loadFixture(deploy); await multiSigWallet.submitTransaction( 6, "0x90F79bf6EB2c4f870365E785982E1f101E93b906", "0x6e65775f6d6963726f7761766500000000000000000000000000000000000000" ); const transactions = await multiSigWallet.getTransactions(); expect(transactions).to.equal(1); }); it("Transfer 5 ethers from the 3 owners to the contract and check SC balance", async () => { const { multiSigWallet } = await loadFixture(deploy); const [deployer, addr1, addr2] = await ethers.getSigners(); await deployer.sendTransaction({ to: multiSigWallet.address, value: ethers.utils.parseEther("2.0"), }); await addr1.sendTransaction({ to: multiSigWallet.address, value: ethers.utils.parseEther("2.0"), }); await addr2.sendTransaction({ to: multiSigWallet.address, value: ethers.utils.parseEther("2.0"), }); const ScBalance = await ethers.provider.getBalance(multiSigWallet.address); expect(ScBalance).to.equal("6000000000000000000"); // 6000000000000000000 = 6 ethers }); it("Approve Transaction with the 3 accounts", async () => { const { multiSigWallet } = await loadFixture(deploy); const [deployer, addr1, addr2] = await ethers.getSigners(); await multiSigWallet.connect(deployer).approveTransaction(1); await multiSigWallet.connect(addr1).approveTransaction(1); await multiSigWallet.connect(addr2).approveTransaction(1); const confirmations = await multiSigWallet.getConfirmations(1); expect(confirmations).to.equal(3); }); });
問題在第 51 行
require( transactions.length >= _txId, "The transaction does not exists" );
將其替換為
require( transactions.length > _txId, "The transaction does not exist" );
**我剛剛解決了這個問題。**我指向數組中的不同位置。
之前:
await multiSigWallet.connect(deployer).approveTransaction(1); await multiSigWallet.connect(addr1).approveTransaction(1); await multiSigWallet.connect(addr2).approveTransaction(1); const confirmations = await multiSigWallet.getConfirmations(1);
之後:
await multiSigWallet.connect(deployer).approveTransaction(0); await multiSigWallet.connect(addr1).approveTransaction(0); await multiSigWallet.connect(addr2).approveTransaction(0); const confirmations = await multiSigWallet.getConfirmations(0);
我把它留在這裡,以防將來有人遇到同樣的錯誤。