0

I have a vite-project in typescript that I want to have eth deposit and withdrawal capability. I'm new to the crypto space and trying to implement a simple wallet contract using Truffle on the ETH Goerli test network to deposit eth and withdraw eth to any user defined wallet address.

For some reason, my deposit to the contract address works as it will generate a ETH transaction to the contract address and update its balance (Ex: https://goerli.etherscan.io/address/0xbd7876ff30ab7640292c3d592599e3d48fcb5df9) Deposits showing up in metamask and on etherscan But the console errors out this even though the deposit goes through: Deposit pop-up showing Deposit error in console

My withdrawal on the other hand, will open the metamask pop-up and ask the user to confirm a withdrawal to given address but instead performs some sort of reverse deposit where the ETH on the contract address disappears. See here: https://goerli.etherscan.io/tx/0x8d97879322edb43af87f38d19be442d030af0a52a690bdfbbbce3cbdcad7b9dd

^^You can see I am calling the withdraw function in my .sol file but it comes up as a deposit?

Withdrawal from Metamask

I really need help here as I'm not sure why my app is behaving like this and would greatly appreciate help. I've provided my code below:

SimpleWallet.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IERC20 {
    function transfer(address _to, uint256 _amount) external returns (bool);
}

contract SimpleWallet {
    event Deposit(address indexed sender, uint amount);
    event Withdrawal(address indexed from, address indexed to, uint amount);

    mapping(address => uint) public balances;

    receive() external payable {
        balances[msg.sender] += msg.value;
        emit Deposit(msg.sender, msg.value);
    }

    function withdrawETH(uint256 _amount) external {
        require(balances[msg.sender] >= _amount, "Insufficient balance");
        balances[msg.sender] -= _amount;
        payable(msg.sender).transfer(_amount);
        emit Withdrawal(address(this), msg.sender, _amount);
}

    function getBalance() public view returns (uint) {
        return balances[msg.sender];
    }
}`

2_deploy_contracts.js in my migrations folder (truffle created directory)

const SimpleWallet = artifacts.require("SimpleWallet");

module.exports = function (deployer) {
  deployer.deploy(SimpleWallet);
};

App.tsx

import { useState, useEffect } from 'react';
import reactLogo from './assets/react.svg';
import viteLogo from '/vite.svg';
import { ethers } from 'ethers';
import SimpleWalletABI from './SimpleWalletABI.json';
import './App.css';

const contractAddress = "0x737132D90B63957b664CE7D4Ad759AFDB38E7eE9";

function App() {
  const [count, setCount] = useState(0);
  const [currentAccount, setCurrentAccount] = useState(String);
  const [depositAmount, setDepositAmount] = useState('');
  const [walletBalance, setWalletBalance] = useState('');
  const [withdrawalAmount, setWithdrawalAmount] = useState('');
  const [recipientAddress, setRecipientAddress] = useState('');

  // Check if the wallet is connected when the component mounts
  useEffect(() => {
    checkIfWalletIsConnected();
  }, []);

  // Check for wallet connection
  const checkIfWalletIsConnected = async () => {
    try {
      const { ethereum } = window;
      if (!ethereum) {
        console.log("Make sure you have MetaMask installed!");
        return;
      }

      const accounts = await ethereum.request({ method: 'eth_accounts' });
      if (accounts.length !== 0) {
        const account = accounts[0];
        setCurrentAccount(account);
        if (account) {
          await getWalletBalance(account);
        }
      } else {
        console.log("No authorized account found");
      }
    } catch (error) {
      console.error(error);
    }
  };

  // Connect to MetaMask wallet
  const connectWalletHandler = async () => {
    const { ethereum } = window;
    if (!ethereum) {
      alert("Please install MetaMask!");
      return;
    }

    try {
      const accounts = await ethereum.request({ method: 'eth_requestAccounts' });
      if (accounts.length > 0) {
        setCurrentAccount(accounts[0]);
        if (accounts[0]) {
          await getWalletBalance(accounts[0]);
        }
      }
      else {
        console.log("No authorized accounts found");
      }
    } catch (err) {
      console.error(err);
    }
  };

  // Create a function to get the wallet balance
  const getWalletBalance = async (account: string) => {
    if (!window.ethereum) return;
    const provider = new ethers.BrowserProvider(window.ethereum);
    const contract = new ethers.Contract(contractAddress, SimpleWalletABI.abi, provider);
    
    try {
      const balance = await contract.getBalance();
      setWalletBalance(ethers.formatEther(balance));
    } catch (error) {
      console.error('Error:', error);
    }
  };

  // Handle deposit
  const handleDeposit = async () => {
    if (!depositAmount || !window.ethereum) return;
    const provider = new ethers.BrowserProvider(window.ethereum);
    const signer = await provider.getSigner();
    try {
      const tx = await signer.sendTransaction({
        to: contractAddress, // Send to the contract address
        value: ethers.parseEther(depositAmount)
      });
      await tx.wait();
      alert(`Deposited ${depositAmount} ETH`); // Notify user of successful deposit
      console.log(`Deposited ${depositAmount} ETH`);
      getWalletBalance(currentAccount); // Update wallet balance
    } catch (error) {
      console.error('Error:', error);
    }
  };

  const handleWithdraw = async () => {
    if (!withdrawalAmount || !recipientAddress || !window.ethereum) return;
    const provider = new ethers.BrowserProvider(window.ethereum);
    const signer = await provider.getSigner();
    const contract = new ethers.Contract(contractAddress, SimpleWalletABI.abi, signer);
  
    try {
      const tx = await contract.withdrawETH(
        ethers.parseEther(withdrawalAmount)
      );
      await tx.wait();
      alert(`Withdrawn ${withdrawalAmount} ETH to ${recipientAddress}`);
      // Optionally, update the balance
    } catch (error) {
      console.error('Error:', error);
    }
  };

  const logout = () => {
    setCurrentAccount('');
  }
  
    return (
      <>
        <div>
          <a href="https://vitejs.dev" target="_blank">
            <img src={viteLogo} className="logo" alt="Vite logo" />
          </a>
          <a href="https://react.dev" target="_blank">
            <img src={reactLogo} className="logo react" alt="React logo" />
          </a>
        </div>
        <h1>WEB3 TURKOMODE</h1>
        <div className="card">
          <button onClick={() => setCount((count) => count + 1)}>
            count is {count}
          </button>
          <p>
            Please connect your MetaMask wallet below // BUTTON TO BET HERE?
          </p>
          {!currentAccount && (
            <button onClick={connectWalletHandler}>Connect to MetaMask</button>
          )}
          {currentAccount && (
            <>
              <input
                type="text"
                value={depositAmount}
                onChange={(e) => setDepositAmount(e.target.value)}
                placeholder="Amount in ETH"
              />
              <button onClick={handleDeposit}>Deposit ETH</button>
              {depositAmount && <p>Amount to Deposit: {depositAmount} ETH</p>}
              {currentAccount && <p>Wallet Balance: {walletBalance} ETH</p>}

              <button onClick={logout}>Logout of {currentAccount} wallet</button>

              <input
                type="text"
                value={withdrawalAmount}
                onChange={(e) => setWithdrawalAmount(e.target.value)}
                placeholder="Amount in ETH to withdraw"
              />
              <input
                type="text"
                value={recipientAddress}
                onChange={(e) => setRecipientAddress(e.target.value)}
                placeholder="Recipient address"
              />
        <button onClick={handleWithdraw}>Withdraw ETH</button>
            </>
          )}
        </div>
        <p className="read-the-docs">
          Crypto coming soon!
        </p>
      </>
    )
  }
  
  export default App;

1 Answer 1

0

It doesn't disappear, the eth is transferred via an internal call. Can check your balance/state changes at that block.

As far explorers go you can usually see it on the internal transaction tab, or the log page, as well as under the interacted with section on the first page of the transaction breakdown.

enter image description here enter image description here

You won't see it in metamask as you aren't the one sending it, you are making a call to the contract which makes a call transferring the eth to you from its balance.

Can confirm you do withdraw to your address looking at the internal transaction tab for your account: enter image description here

Looks like you could be passing event args incorrectly, amount in place of address but I think that is just mismatch by explorer where the contract isn't verified.

  • 9184e72A000 == 10000000000000 enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.