1/5
## Adding Withdraw Functionality to Your dApp Frontend Welcome back! In our previous steps, we built the core functionality for users to "buy coffee" by sending funds to our smart contract. However, those funds are currently locked in the contract. In this lesson, we'll implement the crucial `withdraw` function on our dApp's frontend, allowing the contract owner (you!) to retrieve the deposited Ether. We'll also touch upon leveraging AI assistance responsibly and the critical importance of code review in web3 development. ## Setting Up Your Development Environment Before we start coding, let's ensure our local development environment is ready. If you've stopped your local blockchain node since the last session, you'll need to restart it. We'll use Anvil and load our previously saved state to ensure our deployed contract is available. Open your terminal and run: ```bash anvil --load-state fundme-anvil.json ``` Once Anvil is running, navigate to your dApp's frontend page in your browser (e.g., `127.0.0.1:5500/index.html`) and refresh it. 1. **Connect Wallet:** Click the "Connect" button and authorize the connection in MetaMask. 2. **Check Initial Balance:** Use the "Get Balance" button. It should initially show 0 ETH if the contract state was freshly loaded. 3. **Fund the Contract:** Click the "Buy Coffee" button and send some test Ether (e.g., 1 ETH) to the contract. 4. **Verify Funding:** Click "Get Balance" again *immediately*. You might still see 0 ETH. This is because, on a local node like Anvil, blocks are often mined only when a new transaction occurs. Send another small amount of ETH (or wait a moment if your node mines periodically). Check the balance again; it should now reflect the deposited amount. This confirms our contract has funds ready for withdrawal. ## Generating the Withdraw Function with AI Assistance We already have a working `fund` function in our `index-js.js` file. This function handles connecting to the wallet, preparing the transaction, and sending it. The `withdraw` function will follow a very similar pattern. Instead of writing it from scratch, we can leverage an AI coding assistant (like DeepSeek Chat, GitHub Copilot, or others) to adapt our existing code. This is a powerful technique: provide the AI with a working example and ask it to modify it for a new purpose. Here’s an example prompt structure: "Here is the JavaScript code I use to call the `fund` function on my smart contract from my website using viem/ethers.js (specify your library): ```javascript // Paste your entire existing async function fund() { ... } code here ``` Can you please use this as a template to create a `withdraw` function that calls the smart contract's `withdraw` function? The key difference is that this new function should send 0 value (no Ether) with the transaction." The AI will use the structure, variable names, and logic from your `fund` function to generate a candidate `withdraw` function. ## The Critical Importance of Reviewing AI-Generated Code in web3 Before integrating *any* AI-generated code, especially in web3, **you must understand every single line.** web3 development carries significantly higher stakes than traditional web development. A bug in a simple website might lead to inconvenience, but a vulnerability in a dApp frontend or smart contract can lead to catastrophic financial loss – potentially millions or even billions of dollars. Consider real-world examples: Major hacks have occurred not just through smart contract exploits, but through **frontend vulnerabilities** where malicious code intercepts user transactions or drains funds directly via compromised frontend interactions. The FBI has even issued alerts regarding such incidents (e.g., PSA 250226 related to TraderTraitor activity). **Never blindly copy and paste code generated by AI into a web3 project.** Use AI as a powerful assistant, a pair programmer, or a tool to accelerate development, but **you** are ultimately responsible for the security and correctness of the code. Review it meticulously. If you don't understand a line, ask the AI to explain it or consult the relevant documentation (e.g., viem, ethers.js). ## Integrating and Reviewing the AI-Generated Code Let's take the code provided by the AI and integrate it into our `index-js.js` file. Place the new `async function withdraw() { ... }` alongside your existing functions. Now, perform a careful review. A great way to do this is using your code editor's split view feature (like in VS Code) to compare the new `withdraw` function side-by-side with the original `fund` function. Walk through the `withdraw` function line by line: 1. **Function Signature:** `async function withdraw() { ... }` - Looks correct. 2. **Logging:** `console.log("Withdrawing funds...")` - Simple, helpful logging. 3. **Provider Check:** `if (typeof window.ethereum !== "undefined") { ... }` - Standard check for MetaMask or other providers. Same as `fund`. 4. **Wallet Client & Account:** `createWalletClient`, `requestAddresses` - Standard setup to get the connected wallet and account. Same as `fund`. 5. **Chain & Public Client:** `getCurrentChain`, `createPublicClient` - Necessary setup for interacting with the blockchain. Same as `fund`. 6. **Transaction Simulation (`simulateContract`):** This is the core interaction. * `address: contractAddress`: Correct contract address. * `abi: coffeeAbi`: Correct ABI. * `functionName: "withdraw"`: **Crucial change!** Ensure it correctly targets the `withdraw` function in your ABI, not `fund`. * `account: connectedAccount`: Correct account sending the transaction. * `chain: currentChain`: Correct chain information. * `value: parseEther("0")`: The AI likely included this based on our prompt ("send 0 value"). While correct, sending 0 value is the default behavior if the `value` property is omitted. To keep the code slightly cleaner and rely on defaults, **you can safely remove this line.** The transaction will still send 0 ETH. 7. **Executing Transaction (`writeContract`):** `await walletClient.writeContract(request)` - Sends the transaction after successful simulation. Same pattern as `fund`. 8. **Logging Hash:** `console.log("Withdrawal transaction hash:", hash)` - Updated log message for clarity. 9. **Error Handling:** `else { connectButton.innerHTML = "..." }` - Basic fallback if no provider is found. Same as `fund`. After reviewing and making any minor adjustments (like removing the unnecessary `value: parseEther("0")`), the AI-generated code should be ready. ## Adding the Withdraw Button to the Frontend Now we need a way for the user (the contract owner) to trigger this new function. 1. **Add HTML Button:** Open your `index.html` file and add a new button element: ```html <button id="withdrawButton">Withdraw</button> ``` Place it near your other buttons. 2. **Get Button Element in JS:** Go back to `index-js.js`. At the top, where you select other elements like `connectButton`, add a line to get a reference to this new button: ```javascript const withdrawButton = document.getElementById("withdrawButton"); ``` 3. **Add Event Listener:** At the bottom of `index-js.js`, add an event listener to call our `withdraw` function when the button is clicked: ```javascript withdrawButton.onclick = withdraw; ``` ## Testing the Withdraw Functionality Let's test the complete flow: 1. **Refresh Frontend:** Go back to your browser tab with the dApp and refresh the page. 2. **Connect & Check Balance:** Connect your wallet if needed. Click "Get Balance" to confirm the amount currently held by the contract (e.g., 2 ETH from our earlier setup). 3. **Initiate Withdrawal:** Click the newly added "Withdraw" button. 4. **Confirm in Wallet:** MetaMask (or your wallet) should pop up, asking you to confirm the transaction. Verify it's calling the `withdraw` function and sending 0 ETH. Confirm the transaction. 5. **Check Console:** Observe the browser's developer console. You should see the "Withdrawing funds..." message, followed by the "Withdrawal transaction hash: ..." message once submitted. 6. **Check Balance (Immediate):** Click "Get Balance" again *immediately* after confirming in MetaMask. The balance will likely *still* show the pre-withdrawal amount (e.g., 2 ETH). This is expected because the transaction hasn't been mined into a block on your local Anvil node yet. 7. **Mine Block:** To force Anvil to mine the pending withdrawal transaction, initiate another transaction. The easiest way is often to use the "Buy Coffee" button again, sending a negligible amount (e.g., 0.0001 ETH). This forces Anvil to create a new block, including our withdrawal. 8. **Check Balance (Final):** Click "Get Balance" one more time. Now, the balance should correctly show 0 ETH, confirming the funds were successfully transferred from the contract to the owner's wallet. ## Conclusion and Next Steps Congratulations! You've successfully implemented and tested the `withdraw` functionality on the dApp frontend. We saw how AI can assist in generating code based on existing patterns, but underscored the absolute necessity of careful review and understanding in the high-stakes environment of web3. Always verify AI-generated code before deploying it. With both deposit and withdrawal functions working, our core dApp logic is complete. The next logical step is to enhance the codebase's robustness and maintainability by refactoring our JavaScript code into TypeScript.
A guided walkthrough to adding withdraw functionality to your dApp frontend. Implement the crucial `withdraw` function on a dApp frontend, enabling fund retrieval from a smart contract. Learn to leverage AI assistance for code generation while understanding the critical importance of manual review in web3.
Previous lesson
Previous
Next lesson
Next
Give us feedback
Course Overview
About the course
How to build full-stack web3 applications on ZKsync
JavaScript/TypeScript: viem, wagmi, synpress
Nodejs and pnpm
rindexer
Circle Compliance Engine and USDC
Fleek site hosting and CLI
How to build a static and dynamic React/Next.js site
How to leverage AI to code faster and more securely
Smart Contract Auditor
$100,000 - $200,000 (avg. salary)
DeFi Developer
$75,000 - $200,000 (avg. salary)
Smart Contract Engineer
$100,000 - $150,000 (avg. salary)
Web3 developer
$60,000 - $150,000 (avg. salary)
Web3 Developer Relations
$85,000 - $125,000 (avg. salary)
Security researcher
$49,999 - $120,000 (avg. salary)
Last updated on May 15, 2025
Solidity Developer
Full-Stack Web3 Development Crash CourseDuration: 1h 12min
Duration: 1h 39min
Duration: 3h 08min
Duration: 1h 44min
Course Overview
About the course
How to build full-stack web3 applications on ZKsync
JavaScript/TypeScript: viem, wagmi, synpress
Nodejs and pnpm
rindexer
Circle Compliance Engine and USDC
Fleek site hosting and CLI
How to build a static and dynamic React/Next.js site
How to leverage AI to code faster and more securely
Smart Contract Auditor
$100,000 - $200,000 (avg. salary)
DeFi Developer
$75,000 - $200,000 (avg. salary)
Smart Contract Engineer
$100,000 - $150,000 (avg. salary)
Web3 developer
$60,000 - $150,000 (avg. salary)
Web3 Developer Relations
$85,000 - $125,000 (avg. salary)
Security researcher
$49,999 - $120,000 (avg. salary)
Last updated on May 15, 2025