为什么当我测试我的 dApp 时,MetaMask 只将 Gas 费显示为交易?

问题描述 投票:0回答:1

我一直在 BSC 测试网上开发预售 dApp,使用 Solidity 来部署合约并获取 ABI,并使用 Preact/Ethers.js 构建界面。

我的构建中没有真正的错误消息。 buyButton 按预期工作,MetaMask 打开。控制台日志显示与 presaleContract 的连接,并帮助显示许多其他内容按预期工作。然而我的问题是 MetaMask 交易仅显示汽油费。交易中没有任何与支出货币或购买货币相关的内容。 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 也没有帮助(但什么时候有!)如前所述,我对此很陌生,因此很难准确确定问题所在。

javascript solidity smartcontracts metamask ethers.js
1个回答
0
投票

要找出问题所在,您需要了解

usdtToken.transferFrom()
是如何工作的。

ERC20 合约或任何与此相关的智能合约需要与所有者钱包进行直接交互才能转移任何代币。但由于

usdtToken.transferFrom()
是从其他间接源调用的,因此在调用
usdtToken.approve()
之前需要调用另一个附带函数
usdtToken.transferFrom()

在调用任何内部调用

usdtToken.approve()
的函数之前,应单独调用
usdtToken.transferFrom()

解决方案

在调用

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

参考

https://ethereum.stackexchange.com/questions/145356/understanding-approve-and-transferfrom-confused

下次在 ethereum.stackexchange.com

发布您的问题
© www.soinside.com 2019 - 2024. All rights reserved.