我已经在 remix 中创建了智能合约,一切正常:
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;
import "./ReentrancyGuard.sol";
import "./SafeMath.sol";
import "./Ownable.sol";
import "./IERC20.sol";
contract MultiSend is Ownable, ReentrancyGuard {
using SafeMath for uint256;
event TokensSent(address token, address sender, uint256 total);
event TokenReceived(address token, address receiver, uint256 amount);
event ETHSent(address sender, uint256 total);
event ETHReceived(address sender, uint256 amount);
event TokenAddressChanged(address newAddress);
address public tokenAddress;
constructor(address _tokenAddress) public {
tokenAddress = _tokenAddress;
}
fallback() external {
revert();
}
function sendToken(
address _aa,
address _ba,
uint256 _av,
uint256 _bv
) public nonReentrant returns (bool) {
require(_aa != address(0), "please check address");
require(_ba != address(0), "please check address");
require(_av > 0, "please check amount");
require(_bv > 0, "please check amount");
IERC20 token = IERC20(tokenAddress);
require(
token.allowance(msg.sender, address(this)) >= _av + _bv,
"please check approve"
);
token.transferFrom(msg.sender, _aa, _av);
emit TokenReceived(tokenAddress, _aa, _av);
token.transferFrom(msg.sender, _ba, _bv);
emit TokenReceived(tokenAddress, _ba, _bv);
emit TokensSent(tokenAddress, msg.sender, _av + _bv);
return true;
}
function sendERC20(address[] memory _receiver, uint256[] memory _amount)
public
nonReentrant
returns (bool)
{
uint256 totalSend = 0;
IERC20 token = IERC20(tokenAddress);
require(_receiver.length <= 100, "receiver list is overload!");
require(
_receiver.length == _amount.length,
"lacking of amount infomation, please check again!"
);
for (uint256 j = 0; j < _receiver.length; j++) {
token.transferFrom(msg.sender, _receiver[j], _amount[j]);
emit TokenReceived(tokenAddress, _receiver[j], _amount[j]);
totalSend += _amount[j];
}
emit TokensSent(tokenAddress, msg.sender, totalSend);
return true;
}
function sendCoin(address[] memory _receiver, uint256[] memory _amount)
public
payable
nonReentrant
returns (bool)
{
require(_receiver.length <= 100, "receiver list is overload!");
require(
_receiver.length == _amount.length,
"lacking of amount infomation, please check again!"
);
uint256 total = msg.value;
for (uint256 i = 0; i < _receiver.length; i++) {
require(total >= _amount[i]);
(bool success, ) = payable(_receiver[i]).call{value: _amount[i]}(
""
);
require(success, "Transfer failed.");
emit ETHReceived(_receiver[i], _amount[i]);
total = total.sub(_amount[i]);
}
emit ETHSent(msg.sender, msg.value);
return true;
}
function setTokenAddress(address _tokenAddress)
external
onlyOwner
returns (bool)
{
tokenAddress = _tokenAddress;
emit TokenAddressChanged(_tokenAddress);
return true;
}
}
在开始时的混音中,我批准合约地址支付 x 数量的代币,之后我调用
sendERC20
发送多笔付款的功能以及我所做的一切。
但是当我想在反应中使用它时,它在元掩码和事务失败中向我显示此错误,我想知道问题是什么?
import React, { useState, useEffect } from 'react';
import Web3 from 'web3';
function MultiSendToken() {
const [web3, setWeb3] = useState(null);
const [account, setAccount] = useState('');
const [multiSendContractAddress, setMultiSendContractAddress] = useState('0xf5ba214d32Ac6f9F27e970207da342D299f325d7');
const [tokenAddress, setTokenAddress] = useState('0x3b7513042790a6e07729b40138cCB46547FB4e3A'); // Token contract address
const [addressA, setAddressA] = useState('0x8EC1E147971A9f4dA725CCc031E8F1c85c4E8F6a');
const [addressB, setAddressB] = useState('0x8EC1E147971A9f4dA725CCc031E8F1c85c4E8F6a');
const [amountA, setAmountA] = useState('1');
const [amountB, setAmountB] = useState('1');
useEffect(() => {
if (window.ethereum) {
const web3Instance = new Web3(window.ethereum);
setWeb3(web3Instance);
window.ethereum.request({ method: 'eth_requestAccounts' })
.then(accounts => {
setAccount(accounts[0]);
})
.catch(err => {
console.error('User denied account access or error occurred:', err);
});
} else {
alert('Please install MetaMask!');
}
}, []);
const approveTokens = async () => {
const totalAmount = (parseFloat(amountA) + parseFloat(amountB)).toString();
const tokenABI = [{
"constant": false,
"inputs": [{ "name": "_spender", "type": "address" }, { "name": "_value", "type": "uint256" }],
"name": "approve",
"outputs": [{ "name": "", "type": "bool" }],
"type": "function"
}];
const tokenContract = new web3.eth.Contract(tokenABI, tokenAddress);
const totalAmountInWei = web3.utils.toWei(totalAmount, 'mwei'); // Convert total amount to wei with 6 decimals
try {
await tokenContract.methods.approve(multiSendContractAddress, totalAmountInWei).call({ from: account });
console.log('Approval successful for total amount:', totalAmountInWei);
sendToken(); // Proceed to send tokens after approval
} catch (error) {
console.error('Approval failed:', error);
alert('Approval failed. Check console for more details.');
}
};
const sendToken = async () => {
const multiSendABI = [
{
"inputs": [
{ "name": "_aa", "type": "address" },
{ "name": "_ba", "type": "address" },
{ "name": "_av", "type": "uint256" },
{ "name": "_bv", "type": "uint256" }
],
"name": "sendToken",
"outputs": [{ "name": "", "type": "bool" }],
"type": "function",
"stateMutability": "nonpayable"
}
];
const contract = new web3.eth.Contract(multiSendABI, multiSendContractAddress);
const avInWei = web3.utils.toWei(amountA, 'mwei'); // Converting to smallest unit based on 6 decimals
const bvInWei = web3.utils.toWei(amountB, 'mwei');
try {
const response = await contract.methods.sendToken(addressA, addressB, avInWei, bvInWei).send({ from: account });
console.log('Transaction Successful:', response);
alert('Tokens sent successfully!');
} catch (error) {
console.error('Failed to send tokens:', error);
alert('Transaction failed! See console for details.');
}
};
return (
<div>
<h2>MultiSend Token Transfer</h2>
<input type="text" value={tokenAddress} onChange={e => setTokenAddress(e.target.value)} placeholder="Token Contract Address" />
<input type="text" value={multiSendContractAddress} onChange={e => setMultiSendContractAddress(e.target.value)} placeholder="MultiSend Contract Address" />
<input type="text" value={addressA} onChange={e => setAddressA(e.target.value)} placeholder="Address A" />
<input type="text" value={addressB} onChange={e => setAddressB(e.target.value)} placeholder="Address B" />
<input type="text" value={amountA} onChange={e => setAmountA(e.target.value)} placeholder="Amount for Address A" />
<input type="text" value={amountB} onChange={e => setAmountB(e.target.value)} placeholder="Amount for Address B" />
<button onClick={approveTokens}>Approve and Send Tokens</button>
</div>
);
}
错误信息:
export default MultiSendToken;
Failed to send tokens: TransactionRevertedWithoutReasonError: Transaction has been reverted by the EVM:
{"blockHash":"0xa4fccf0ecacf834f634b090ce0c6dbb1d6e14f18f3a61d3d7057984bdb185913","blockNumber":"6238953","cumulativeGasUsed":"219787","effectiveGasPrice":"2500000015","from":"0x53a1d6bab5d93e93b7be978f109967c581e4b683","gasUsed":"37505","logs":[{"address":"0x0000000000000000000000000000000000001010","topics":["0x4dfe1bbbcf077ddc3e01291eea2d5c70c2b422b415d95645b9adcfd678cb1d63","0x0000000000000000000000000000000000000000000000000000000000001010","0x00000000000000000000000053a1d6bab5d93e93b7be978f109967c581e4b683","0x00000000000000000000000009207a6efee346cb3e4a54ac18523e3715d38b3f"],"data":"0x00000000000000000000000000000000000000000000000000005546c881790000000000000000000000000000000000000000000000000006e84ce7162498310000000000000000000000000000000000000000000000c66c71f3e72ecad40900000000000000000000000000000000000000000000000006e7f7a04da31f310000000000000000000000000000000000000000000000c66c72492df74c4d09","blockNumber":"6238953","transactionHash":"0xe3fcda0fb3706298a2f5c43356f9076887b2f368a34d938ebdeaf2dca9a9abd9","transactionIndex":"2","blockHash":"0xa4fccf0ecacf834f634b090ce0c6dbb1d6e14f18f3a61d3d7057984bdb185913","logIndex":"6","removed":false}],"logsBloom":"0x00000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000008000000000000000010000000000000000000000000000000000000000800000000000000000000100000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000004000000004000000000000000000000000000200000000000000000000000000000000000000000000000000000000000004000000000000000000001000000400000000000000000000000100000000000000000000000000000000000010000000000000000000000000000000000100000","status":"0","to":"0xf5ba214d32ac6f9f27e970207da342d299f325d7","transactionHash":"0xe3fcda0fb3706298a2f5c43356f9076887b2f368a34d938ebdeaf2dca9a9abd9","transactionIndex":"2","type":"2","events":{}}
我之前也遇到过同样的错误,并询问过在以太坊上。来自答案:
可能发生的情况是 Metamask 对 具有相同参数的合约,以模拟如果 交易发生了。如果它注意到静态调用 恢复,它会给你这个错误 - 因为很可能是真正的 交易也会恢复。
sendToken
函数的参数之一类型错误。记录所有参数以查看它们的值。