javascript 为什么MetaMask在测试我的dApp时只显示gas fee作为交易?

1wnzp6jl  于 2023-09-29  发布在  Java
关注(0)|答案(1)|浏览(79)

我一直在BSC测试网上开发一个预售dApp,使用solidity部署合约并获取ABI,并使用Preact/Ethers.js构建接口。
我的构建中没有真实的的错误消息。buyButton按预期工作,MetaMask打开。控制台日志显示了与presaleContract的连接,并帮助显示了许多其他事情按预期工作。然而,我的问题是MetaMask交易只显示了gas费。交易中没有任何其他与支出货币或购买货币相关的内容。MM还确认presaleContract地址以及被调用的函数。我哪里做错了?
P.S.我一般都是编程新手,更不用说基于区块链的东西了,所以如果我的代码有点精神,我道歉!
metamask txn screengrab

document.getElementById("buyButton").addEventListener("click", async () => {
  const usdtEther = document.getElementById("usdtAmount");
  console.log(usdtAmount);

  try {
    const usdtX = usdtEther.value;
    const usdtAmount = ethers.parseUnits(usdtX, 6);
    const usdtString = usdtAmount.toString();
    console.log('USDT STRING:', usdtString);
    const buyProv = new ethers.BrowserProvider(window.ethereum);
    const buySign = await buyProv.getSigner();
    const buyContract = new ethers.Contract(presaleContractAddress, presaleContractAbi, buySign);
    const userAddress = await buySign.getAddress();
    const nonce = await provider.getTransactionCount(userAddress, 'latest');
    const data = presaleContract.interface.encodeFunctionData("buyTokens", [usdtAmount]);  // Encoded 'buyTokens' function data

    console.log('userAdd', userAddress);
    console.log(buyProv);
    console.log(buySign);
    console.log(buyContract);
    console.log(usdtAmount);

    // Transaction options (gasPrice, gasLimit, etc.)
    const txOptions = {
      from: userAddress,
      to: presaleContractAddress,
      gasLimit: 200000, 
      gasPrice: ethers.parseUnits("20", "gwei"),
      chainId: 97, 
      value: 0,
      nonce: nonce,
      data: data,
    };

    console.log('txOptions:', txOptions);

    txOptions.sendTransaction = true;

    await buySign.sendTransaction({
      to: presaleContractAddress,
      ...txOptions,
    });

   
    alert("Tokens purchased successfully!");
  } catch (error) {
    console.error("Error purchasing tokens:", error);
    alert("Error purchasing tokens. See console for details.");
  }
});
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

contract Presale is Ownable, Pausable, ReentrancyGuard {
    IERC20 public kooToken;
    IERC20 public usdtToken;

    uint256 public constant presalePrice = 793700000000000; // This represents 0.0007937 USDT with 7 decimal precision
    uint256 public constant tokensToSell = 6300000000000000000000000000; // 6.3 billion KOO with 18 decimals

    uint256 public totalTokensSold;

    event TokensPurchased(address indexed buyer, uint256 amount);
    event TokensWithdrawn(address indexed owner, uint256 amount);
    event FundsWithdrawn(address indexed owner, uint256 amount);

    constructor(address _kooToken, address _usdtToken) {
        kooToken = IERC20(_kooToken);
        usdtToken = IERC20(_usdtToken);
    }

    function buyTokens(uint256 usdtAmount) external whenNotPaused nonReentrant {
        require(usdtAmount > 0, "Amount must be greater than 0");

        uint256 tokensToBuy = usdtAmount * 10**7 / presalePrice; // Calculate tokens to buy using the 7 decimal precision of the price
        uint256 remainingTokens = tokensToSell - totalTokensSold;

        require(tokensToBuy <= remainingTokens, "Not enough tokens left for sale");

        // Transfer USDT from buyer to this contract
        require(usdtToken.transferFrom(msg.sender, address(this), usdtAmount), "USDT transfer failed");

        // Transfer KOO tokens from this contract to the buyer
        kooToken.transfer(msg.sender, tokensToBuy);

        totalTokensSold += tokensToBuy;

        emit TokensPurchased(msg.sender, tokensToBuy);
    }

    function withdrawUnsoldTokens() external onlyOwner {
        uint256 unsoldTokens = tokensToSell - totalTokensSold;
        require(unsoldTokens > 0, "No unsold tokens left");

        kooToken.transfer(owner(), unsoldTokens);

        emit TokensWithdrawn(owner(), unsoldTokens);
    }

    function withdrawUSDT() external onlyOwner {
        uint256 contractBalance = usdtToken.balanceOf(address(this));
        require(contractBalance > 0, "No USDT to withdraw");

        usdtToken.transfer(owner(), contractBalance);

        emit FundsWithdrawn(owner(), contractBalance);
    }

    function withdrawAccidentallySentTokens(address _tokenAddress) external onlyOwner {
        IERC20 token = IERC20(_tokenAddress);
        uint256 contractBalance = token.balanceOf(address(this));
        require(contractBalance > 0, "No tokens to withdraw");

        token.transfer(owner(), contractBalance);

        emit TokensWithdrawn(owner(), contractBalance);
    }

    function pause() external onlyOwner {
        _pause();
    }

    function unpause() external onlyOwner {
        _unpause();
    }

    // Fallback function to receive Ether (if needed)
    receive() external payable {}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

contract kooToken is ERC20Burnable, Ownable, Pausable, ReentrancyGuard {
    using SafeMath for uint256;

    address public presaleContract;
    address public liquidityWallet;
    address public rewardsWallet;

    uint256 public buyFeePercent = 1;
    uint256 public sellFeePercent = 1;

    constructor() ERC20("HATO", "KOO") {
        _mint(msg.sender, 21 * 10**9 * 10**18); // 21 billion initial supply
    }

    function setPresaleContract(address _presaleContract) external onlyOwner {
        presaleContract = _presaleContract;
    }

    function setLiquidityWallet(address _liquidityWallet) external onlyOwner {
        liquidityWallet = _liquidityWallet;
    }

    function setRewardsWallet(address _rewardsWallet) external onlyOwner {
        rewardsWallet = _rewardsWallet;
    }

    function setBuyFeePercent(uint256 _percent) external onlyOwner {
        require(_percent <= 1, "Buy fee cannot exceed 1%");
        buyFeePercent = _percent;
    }

    function setSellFeePercent(uint256 _percent) external onlyOwner {
        require(_percent <= 1, "Sell fee cannot exceed 1%");
        sellFeePercent = _percent;
    }

    function _transfer(
        address sender,
        address recipient,
        uint256 amount
    ) internal override nonReentrant {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");

        uint256 fee = 0;
        if (
            msg.sender == presaleContract ||
            msg.sender == owner() ||
            msg.sender == address(this) || // Allow the contract itself to use tokens during buy/sell
            paused() // Allow both owner and presale contract to use tokens when paused
        ) {
            fee = 0; // No fees for owner, presale contract, and the contract itself
        } else if (recipient == address(this)) {
            fee = amount.mul(buyFeePercent).div(100); // Buy fee
        } else if (sender == address(this)) {
            fee = amount.mul(sellFeePercent).div(100); // Sell fee
        }

        uint256 transferAmount = amount.sub(fee);

        // Check if the sender has a sufficient balance to cover the transfer and fees
        require(balanceOf(sender) >= amount, "Insufficient balance");
        require(balanceOf(sender) >= fee, "Insufficient balance for fees");

        super._transfer(sender, recipient, transferAmount);

        if (fee > 0) {
            super._transfer(sender, liquidityWallet, fee.div(2));
            super._transfer(sender, rewardsWallet, fee.div(2));
        }
    }

    function pause() external onlyOwner {
        _pause();
    }

    function unpause() external onlyOwner {
        _unpause();
    }
}

我对这个有点不知所措,我花了一段时间才达到这一点,进行了大量的故障排除和错误处理-感觉就像我几乎在那里,但我无法找出问题是什么。在网上搜索已经存在的帖子并没有帮助,ChatGPT也没有帮助(但是什么时候有过!)正如前面提到的,我是新手,所以很难准确地确定问题可能是什么。

h7wcgrx3

h7wcgrx31#

要找出问题所在,您需要了解usdtToken.transferFrom()是如何工作的。
ERC20合约或任何智能合约都需要与所有者钱包直接交互才能转移任何代币。但是由于usdtToken.transferFrom()是从其他间接源调用的,因此在调用usdtToken.transferFrom()之前需要调用另一个附带的函数usdtToken.approve()
usdtToken.approve()将在调用任何将在内部调用usdtToken.transferFrom()的函数之前单独调用。

  • 解决方案 *

在调用PreSaleContract.buyTokens(uint256 _value)之前,需要在JS中调用USDTContract.approve(address _spender, uint256 _value)

  • 参考 *

https://ethereum.stackexchange.com/questions/145356/understanding-approve-and-transferfrom-confused
下一次在ethereum.stackexchange.com中发布您的问题

相关问题