I implemented the smart contract as follows.
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;
contract Trade {
enum TradeState {
Start,
Proceeding,
Shipping,
Cancel,
Complete,
Return
}
address payable public seller;
address payable public buyer;
uint256 public productID;
uint256 public price;
uint256 public trackingNumber;
uint256 public depositAmount;
TradeState public currentTradeState;
constructor(address _buyer, uint256 _productID, uint256 _price) payable {
seller = payable(msg.sender);
depositAmount = msg.value;
buyer = payable(_buyer);
productID = _productID;
price = _price; // * (10 ** 18);
trackingNumber = 0;
currentTradeState = TradeState.Start;
}
function setTrackingNumber(uint256 _trackingNumber) public {
require(msg.sender == seller);
trackingNumber = _trackingNumber;
currentTradeState = TradeState.Shipping;
}
function makePayment() public payable returns (bool result) {
require(msg.sender == buyer && msg.value == price, "Not enough ETH");
currentTradeState = TradeState.Proceeding;
return true;
}
function completeTrade() public payable {
require(msg.sender == buyer, "msg.sender is not buyer!");
require(trackingNumber != 0, "trackingNumber has not been set.");
seller.transfer(price + depositAmount);
if (address(this).balance > 0) {
buyer.transfer(address(this).balance);
}
currentTradeState = TradeState.Complete;
}
function cancel() public payable {
require(currentTradeState != TradeState.Shipping, "Already shipped.");
//buyer.transfer(price);
seller.transfer(depositAmount);
if (address(this).balance > 0) {
buyer.transfer(address(this).balance);
}
currentTradeState = TradeState.Cancel;
}
function returnProduct() public payable {
require(msg.sender == buyer, "caller must be buyer.");
buyer.transfer(address(this).balance);
currentTradeState = TradeState.Return;
}
function transferWithoutPayingFee(address payable addr, uint256 amount) internal {
addr.transfer(amount);
}
}
Then, the contract was deployed and accessed using the ethers.js library. There is no problem with contract deployment and accessing other methods. However, when sending a transaction that calls cancel() or returnProduct(), it is not executed normally with the following error.
The two methods are called as follows.
async function cancel(contractAddress, privateKey) {
let wallet = new ethers.Wallet(privateKey, provider);
let contract = new ethers.Contract(contractAddress, contractABI, provider);
let contractWithSigner = contract.connect(wallet);
let tx = await contractWithSigner.cancel(option);
await tx.wait();
}
async function returnProduct(contractAddress, privateKey) {
let wallet = new ethers.Wallet(privateKey, provider);
let contract = new ethers.Contract(contractAddress, contractABI, provider);
let contractWithSigner = contract.connect(wallet);
let tx = await contractWithSigner.returnProduct();
await tx.wait();
}
The error log that occurs is as follows.
Error: cannot estimate gas; transaction may fail or may require manual gas limit [ See: https://links.ethers.org/v5-errors-UNPREDICTABLE_GAS_LIMIT ] (error={"reason":"processing response error","code":"SERVER_ERROR","body":"{\"id\":65,\"jsonrpc\":\"2.0\",\"error\":{\"message\":\"VM Exception while processing transaction: revert\",\"code\":-32000,\"data\":{\"stack\":\"RuntimeError: VM Exception while processing transaction: revert\\n at Function.RuntimeError.fromResults (C:\\\\Program Files\\\\WindowsApps\\\\GanacheUI_2.5.4.0_x64__5dg5pnz03psnj\\\\app\\\\resources\\\\static\\\\node\\\\node_modules\\\\ganache-core\\\\lib\\\\utils\\\\runtimeerror.js:94:13)\\n at module.exports (C:\\\\Program Files\\\\WindowsApps\\\\GanacheUI_2.5.4.0_x64__5dg5pnz03psnj\\\\app\\\\resources\\\\static\\\\node\\\\node_modules\\\\ganache-core\\\\lib\\\\utils\\\\gas\\\\guestimation.js:142:32)\",\"name\":\"RuntimeError\"}}}","error":{"code":-32000,"data":{"stack":"RuntimeError: VM Exception while processing transaction: revert\n at Function.RuntimeError.fromResults (C:\\Program Files\\WindowsApps\\GanacheUI_2.5.4.0_x64__5dg5pnz03psnj\\app\\resources\\static\\node\\node_modules\\ganache-core\\lib\\utils\\runtimeerror.js:94:13)\n at module.exports (C:\\Program Files\\WindowsApps\\GanacheUI_2.5.4.0_x64__5dg5pnz03psnj\\app\\resources\\static\\node\\node_modules\\ganache-core\\lib\\utils\\gas\\guestimation.js:142:32)","name":"RuntimeError"}},"requestBody":"{\"method\":\"eth_estimateGas\",\"params\":[{\"gasPrice\":\"0x4a817c800\",\"from\":\"0xb55a7a6d8cf909e938cd003c453ea7987fd4014a\",\"to\":\"0x21436e17d53fc0e34609883ad095c3c6d0ad79e5\",\"data\":\"0x056baaba\"}],\"id\":65,\"jsonrpc\":\"2.0\"}","requestMethod":"POST","url":"HTTP://127.0.0.1:7545"}, tx={"data":"0x056baaba","to":{},"from":"0xB55A7A6d8cf909E938cd003c453ea7987fd4014a","gasPrice":{"type":"BigNumber","hex":"0x04a817c800"},"type":0,"nonce":{},"gasLimit":{},"chainId":{}}, code=UNPREDICTABLE_GAS_LIMIT, version=abstract-signer/5.6.2)
at Logger.makeError (C:\Users\yang\Desktop\졸업과제\Offchain-Backend\node_modules\@ethersproject\logger\lib\index.js:233:21)
at Logger.throwError (C:\Users\yang\Desktop\졸업과제\Offchain-Backend\node_modules\@ethersproject\logger\lib\index.js:242:20)
at C:\Users\yang\Desktop\졸업과제\Offchain-Backend\node_modules\@ethersproject\abstract-signer\lib\index.js:365:47
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async Promise.all (index 6) {
reason: 'cannot estimate gas; transaction may fail or may require manual gas limit',
code: 'UNPREDICTABLE_GAS_LIMIT',
...
When the test code was written and tested on the truffle framework, it worked normally. My guess is that require(...) seems to be causing the problem. Please advise on how to solve this problem.