At the end of the lesson we were given two challenges to complete on our own to further reinforce our understanding.

  1. Allow your smart contract to update the withdrawal address.
  2. Allow your smart contract to buyLargeCoffee for 0.003 ETH, and create a button on the frontend website that shows a “Buy Large Coffee for 0.003ETH” button.

Challenge #1 — Allow your smart contract to update the withdrawal address.

I first defined a new payable address labeled withdrawAddress.

  
// Challenge 1
// add another withdraw address
address payable withdrawAddress;

Then in my constructor I set this withdrawAddress equal to the contract deployer similar to how we defined the owner.

    constructor() {
// Store the address of the deployer as a payable address.
// When we withdraw funds, we'll withdraw here.
owner = payable(msg.sender);
//Challenge 1
//set withdrawAddress to deployer to start
withdrawAddress = payable(msg.sender);
}

Then in the withdraw function I changed the require statement from the owner to my new withdrawAddress

    function withdrawTips() public {
//Previous code
// require(owner.send(address(this).balance));

//Challenge 1
// change to withdrawAddress
require(withdrawAddress.send(address(this).balance));

}

In order to change the withdraw address, I needed to create a new function, changeWithdrawAddress. The argument needed for the function will be which address we want to change the withdrawAddress to.

Since I do not want just anyone to be changing the withdrawAddress, I required that only the owner can call.

    function changeWithdrawAddress(address payable _withdrawAddress) public {
require(msg.sender == owner,
'Only the owner can change the withdraw address'
);
withdrawAddress = _withdrawAddress;
}

In order to test my new contract out, I went back and made changes to our original buy-coffee.js script.

In the position where we previously performed the withdraw, I inserted new code to call the changeWithdrawAddress function with the tipper.address as the input. Then I withdrew the tips using the tipper address.


// Change Withdraw address
await buyMeACoffee.connect(owner).changeWithdrawAddress(tipper.address);
// Withdraw to tipper
await buyMeACoffee.connect(tipper).withdrawTips();
// Previous Withdraw code.
// await buyMeACoffee.connect(owner).withdrawTips();

I then ran the script, and verified that the balance of Address 1 (tipper) increased after withdraw and Address 0 (owner) did not change.

Success 🎉🎉

Challenge #2 — Allow your smart contract to buyLargeCoffee for 0.003 ETH, and create a button on the frontend website that shows a “Buy Large Coffee for 0.003ETH” button.

In our current contract there is only one buyCoffee function that allows you to pass any value of ETH to it. For this challenge we were asked to create a specific function called buyLargeCoffee that requires the value to be at or above 0.003 ETH.

To accomplish this I simply copy and pasted the existing buyCoffee function, renamed it to buyLargeCoffee, and required the value to be above 0.003 ETH before transferring any value.

Note that I needed to calculate the integer value for 0.003 ETH by multiplying it by 10¹⁸(3000000000000000).

function buyLargeCoffee(string memory _name, string memory _message) public payable {
// Must accept more than 0.003 ETH for a large coffee.
require(msg.value >= 3000000000000000, "can't buy large coffee for less than 0.003!");

After changing my contract (and testing in hardhat), I redeployed it to the Goerli blockchain using the command line. I was given a new contract address.

The next step in the challenge was to create a new button on my front-end that would allow tippers to use my buy large coffee function.

For this step, I headed back to Replit, and specifically to my index.jsx file.

My first step was to copy/paste my existing buyCoffee variable and paste into a new buyLargeCoffee variable.

The first part I needed to change was the section that passed the value to the transaction. Instead of 0.001 I changed to 0.003. The second part was the function from the contract I needed to call, buyLargeCoffee.

console.log("buying coffee..")
// const coffeeTxn = await buyMeACoffee.buyCoffee(
// Challenge 2
const coffeeTxn = await buyMeACoffee.buyLargeCoffee(
name ? name : "anon",
message ? message : "Enjoy your coffee!",
// { value: ethers.utils.parseEther("0.001") }
// Challenge 2
{ value: ethers.utils.parseEther("0.003") }
);

My next step was to change the contract that was being called to my newly deployed contract.

export default function Home() {
// Contract Address & ABI
// const contractAddress = "0x199bd68020a1dbD791935432E335EFbdf057953D";
// Challenge 2
const contractAddress = "0x9DF5c24A6909fA05d36cB8f723F7047C5369B706"

Finally, I needed to create the button to actually initiate the transaction. I copy/pasted the section from my existing button, and made just a couple modifications.

The first change was the variable that the button was referencing, buyLargeCoffee. The second change was the message that appeared on the button, “Send 1 Large Coffee for 0.003ETH”.

//Code for the Buy Large Coffee button
</div>
<div>
<button
type="button"
onClick={buyLargeCoffee}
>
Send 1 Large Coffee for 0.003ETH
</button>
</div>

One last change I made, which I’m not sure is required is the contract ABI stored in the BuyMeCoffee.json file located in the utils folder. Since I have a new function in my contract, I better make sure my site knows what arguments/inputs to pass to it.

I copy/pasted my buyCoffee code (copy/paste is my best friend) and modified it for buyLargeCoffee. It was only necessary to change the name as all of the arguments/inputs are the same.

    //BuyMeCoffee.json file
{
"inputs": [
{
"internalType": "string",
"name": "_name",
"type": "string"
},
{
"internalType": "string",
"name": "_message",
"type": "string"
}
],
// Change to buyLargeCoffee
"name": "buyLargeCoffee",
"outputs": [],
"stateMutability": "payable"
"type": "function"
},

To test my changes I copied my Replit URL to a browser and after connecting my wallet, selected the “Buy Large Coffee” button. The first positive sign was that the Metamask transaction was in fact for 0.003ETH.

I approved the transaction and awaited successful confirmation. After confirming, I headed to Goerliscan to verify that the BuyLargeCoffee function was called and 0.003 ETH was transferred to the contract from my wallet.

Success 🎉🎉

I feel confident that understand the process and code from this lesson. Since I am just started out with both Solidity and JavaScript there was a lot to digest, but all in all this was very informative and makes me excited for the remaining 8 weeks of my lessons. 🤓

--

--