Back to homepage

How to send ETH from a web3 app to a smart contract

Published

Sending ETH from a user's account to a smart contract is one of the most commong things you'll have to deal with when creating web 3 apps so in this article I'm going to explain how to do it.

In summary, to send ETH to a smart contract you need:

  • A smart contract with a payable function
  • A web app to interact with the contract
  • A wallet with some ETH to send 🤑

Smart contract that receives ETH

In order for a smart contract function to be able to receive ETH, we need to use the identify that function as payable. Payable functions can receive an additional object parameter in which we can include multiple parameters like value, gasPrice, gasLimit and other transaction related options.

The example below is a contract with a payable function named playGame which receives as a number as a parameter.

pragma solidity ^0.8.4;

contract GameContract {

  uint256 secretNumber = 33;

  uint256 ticketPrice = 0.01 ether;

  function playGame(uint256 _number) public payable returns ( boolean memory){

        console.log("Current balance is ", address(this).balance);

        // Validate value received is at least the ticket price
        require(msg.value >= ticketPrice, "Minimum value is 0.01 ETH!");

        // if number sent is correct, send money and reset number
        if (_number == secretNumber) {
          // Winner
          // send 80% of contract's balance to the player
          (bool success, ) = (msg.sender).call{
                value: (address(this).balance * 80) / 100
            }("");

            console.log("Balance after win is ", address(this).balance);

            return true;
        }
        // User lost
        // received ETH is added to the contract balance
        console.log("Updated balance is ", address(this).balance);

        return false;
    }
}

This is a very basic game in which, if the user guess the secret number, he'll receive 80% of the ETH accumulated in the contract. If the player fails to guess the number, the ETH received is added to the contract's balance.

Sending ETH from a web app

From the web application point of view, I'll use Ethers.js to interact with the contract. Using Ethers, we can include an additional parameter when calling the smart contract function. This additional parameter contains transaction overrides and can contain value or gasPrice.

import { Contract, ethers } from 'ethers';
import GameContract from '@/artifacts/solidity/contracts/GameContract.sol/GameContract.json';

const provider = new ethers.providers.Web3Provider(window.ethereum);

const signer = provider.getSigner();

// address of the smart contract
const contractAddress = '0x4ed7c70C26B79c776995fC64377f0d4aB3B0e222';

// as the operation we're going to do is a transaction,
// we pass the signer instead of the provider
const contract = new ethers.Contract(contractAddress, GameContract.abi, signer);

// guessed number hardcoded here for this example
const guessNumber = 3;

try {
  const txOverrides = {
    // same as ticketPrice in the smart contract
    value: ethers.utils.parseEther('0.01'),
  };
  // call smart contract function passing the number and the overrides including the ETH value
  const transaction = await contract.playGame(guessNumber, txOverrides);

  console.log('transaction :>> ', transaction);
  // wait for the transaction to actually settle in the blockchain
  await transaction.wait();
} catch (err) {
  console.error(error);
}

Apart from the contract address (you can find how to deploy smart contracts in this article), we just need to get a signer to actually sign the transaction, as we'll be sending ETH from the user's wallet.

Notice that, even though the playGame function in our contract only receives a single parameter, I'm also passing the transaction overrides object that includes the ETH value. Once we call this function, the Metamask prompt to sign the transaction will include the amount of ETH that we indicated plus some fees.

Metamask send ETH transaction

You can get some ETH for the Rinkeby test net from the faucets mentioned here

TAGS

If you enjoyed this article consider sharing it on social media or buying me a coffee ✌️

Buy Me A Coffee