DEV Community

Cover image for How to create a smart contract to receive payments
Emanuel Ferreira
Emanuel Ferreira

Posted on • Updated on

How to create a smart contract to receive payments

With the ascendancy of blockchains and cryptocurrencies you do not want to be left out of this right?

In this article I will teach to you how to create a smart contract to receive donations using solidity.

What is Solidity?

Solidity is an object-oriented programming language for writing smart contracts. It is used for implementing smart contracts on various blockchain platforms, most notably, Ethereum. Wikipedia

Pragma Version

First thing we will do after creating a .sol file(solidity extension) is define a pragma version, this is for solidity to understand which version our contract is in and to compile it correctly.

DonateContract.sol

pragma solidity ^0.8.0;
Enter fullscreen mode Exit fullscreen mode

Starting the contract

Now we are going to start our contract, for this we need to call contract + ContractName for solidity to understand where our contract code will be.

DonateContract.sol

pragma solidity ^0.8.0;

contract DonateContract {
 //the code will stay here
}

Enter fullscreen mode Exit fullscreen mode

Variables

Solidity supports three types of variables:

  1. State variables: variables whose values are permanently stored in a contract storage.
  2. Local variables: variables whose values are present till function is executing.
  3. Global variables: special variables exists in the global namespace used to get information about the blockchain.

We are going to create two types of state variables:

The variables are written as follows: type + variableName

  1. totalDonations: totalDonations is a uint that stores the amount of donations that have already been made.
  2. owner: owner is of the payable address type that will be the creator of the contract that will receive the donations.

Obs: all addresses that will accept payment or make payment must be of the payable type.

DonateContract.sol

pragma solidity ^0.8.0;

contract DonateContract {

  uint totalDonations; // the amount of donations
  address payable owner; // contract creator's address

}

Enter fullscreen mode Exit fullscreen mode

Using the constructor

In our solidity contract we have a constructor to set up our contract and set some standards.

We will define who will be the owner of our contract and that it will be of the payable type, in this case the creator of the contract.

DonateContract.sol

pragma solidity ^0.8.0;

contract DonateContract {

  uint totalDonations; // the amount of donations
  address payable owner; // contract creator's address

  //contract settings
  constructor() {
    owner = payable(msg.sender); // setting the contract creator
  }

}
Enter fullscreen mode Exit fullscreen mode

Creating our first function

Now we are going to create a simple function to return the amount of donations.

DonateContract.sol

pragma solidity ^0.8.0;

contract DonateContract {

  uint totalDonations; // the amount of donations
  address payable owner; // contract creator's address

  //contract settings
  constructor() {
    owner = payable(msg.sender); // setting the contract creator
  }

  // public function to return the amount of donations
  function getTotalDonations() view public returns(uint) {
    return totalDonations;
  }
}
Enter fullscreen mode Exit fullscreen mode

Our function takes three parameters:

  1. public: This function is of the public type and can be called by anyone.
  2. view: It means that this function is a view-only function and does not do any transactions and you don't need to pay gas to use it.
  3. returns(uint): Here we are saying that the function will return something of type uint.

Creating function to make donation

Now we are going to make a function to make the donation, we need say that it is public and payable.

DonateContract.sol

pragma solidity ^0.8.0;

contract DonateContract {

  uint totalDonations; // the amount of donations
  address payable owner; // contract creator's address

  //contract settings
  constructor() {
    owner = payable(msg.sender); // setting the contract creator
  }

  //public function to make donate
  function donate() public payable {
    (bool success,) = owner.call{value: msg.value}("");
    require(success, "Failed to send money");
  }

  // public function to return total of donations
  function getTotalDonations() view public returns(uint) {
    return totalDonations;
  }
}
Enter fullscreen mode Exit fullscreen mode

Obs: you can use nonReentrant to give more secure to your contract.

In our donate function we use owner.call{value: msg.value}("") to make a payment to owner of contract, where msg.value(global variable) is the value we want to send as a donation.

Then we get the call return to check if the transfer was successful using require.

The require takes as the first parameter the variable success saying whether a transaction was successful or not, thus returning an error or proceeding. The second parameter will be the message sent in case of error.

Ready!! we have our first contract ready. 😁🥳

For more content you can follow me here and on my twitter:
Twitter

Discussion (14)

Collapse
cibrax profile image
Cibrax

A few things. The owner might be who deployed the contract but not the one expecting the donations. Anyone can call your donate method. If the address points to another contract that could give errors, your eth will be burned/lost. Transfer is not recommended anymore. You should use Call and check for the result. If the result is false, you revert the transaction. Great start anyways!

Collapse
emanuelferreira profile image
Emanuel Ferreira Author

thanks, i will make these fixes!!

Collapse
emanuelferreira profile image
Emanuel Ferreira Author

I made these corrections in case you want to check

Collapse
cibrax profile image
Cibrax

Yes, that is perfect!

Collapse
victorquanlam profile image
Victor Quan Lam

It would be amazing if there're a bit more details on hosting the contract on testnest and mainnest. But it's still a great article. Keep up the good work mate

Collapse
emanuelferreira profile image
Emanuel Ferreira Author

Thanks for the feedback, I will create an article to make a deploy for the testnet!!

Collapse
victorquanlam profile image
Victor Quan Lam

cool! deploying to the main nest is a pain actually. The gas fee is insane nowadays.

Collapse
roni_sommerfeld profile image
RoNi Sommerfeld

Hello, is it possible to use an ERC20 token inside a function of an ERC721 token?
To better explain what I want to do is as follows.
Before minting an ERC721 token (Item of my game) I want to check if the player has my token (ERC20) in his wallet, if he has he could mint it...
Is it possible to do that? Thanks.

Collapse
emanuelferreira profile image
Emanuel Ferreira Author

Hey RoNi, yes!

on your ERC721 mint function you need to connect with your ERC20 contract and verify the balance of the user

Collapse
olanetsoft profile image
Olubisi Idris Ayinde💡

Nice post.

I have a questiopn please, i tried running the test locally to test my contract but i keep getting this error "Failed to send money" what do you think could be the casue pls. @emanuelferreira

Collapse
emanuelferreira profile image
Emanuel Ferreira Author

Thank you!

how are you sending money using the web3? you need to pass the value on your web3 call function.

Collapse
eed6d7872f6537 profile image
Ben Sigman

Thanks for the example. I was trying to out this contract, but I keep getting a weird error - I'm sure it's something simple that I'm missing here.

I deployed to Rinkeby Testnet using remix... then I loaded the contract and ABI into app.mycrypto.com/interact-with-con... - but when I try to send a donation, I keep getting this error:

"Something went wrong: insufficient funds for intrinsic transaction cost. Make sure you've filled everything out correctly and try again. If this error persists, please visit our Knowledge Base for further assistance."

I have plenty of test ETH in my account. I have tried to send ETH directly to the contract and it also fails. What am I doing wrong?

Collapse
eed6d7872f6537 profile image
Ben Sigman

One strange thing is that I can make a donation of "0 ETH" but if I add ANY amount - such as 0.0001 ETH - I get the same error as above. Gas costs are only 0.000094ETH so it really can't be the issue. Does my contract need to be deployed with ETH in it?

Collapse
juliomerisio profile image
Julio Merisio

sick bro! Keep going!