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?
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;