Tutorial: Create an Ethereum GraphQL Server with Node.js
Part 1—Create a Smart Contract with Solidity in Remix
You can find Part 2 of this tutorial here.
I’m a newbie in the field of Ethereum and blockchains. In my quest to learn, I looked at many apps that use different front-end technologies with Solidity. I ended up building a few apps myself using React and Vue with Web3, ganache-cli, Metamask, and Solidity.
Recently I had a thought: “Could I access Solidity contract methods using GraphQL and move most of the logic onto the server?” There was only one way to answer that question…
TL;DR; Check out my GitHub repo for the complete project:
https://github.com/redacademy/ethereum-graphql
In this two-part series of posts, we’ll implement a GraphQL server using Express and Node.js to talk to a simple Solidity Smart Contract designed to accept donations.
Getting Started
What you’ll need:
1. A code editor of your choice (I prefer VS Code)
2. The Metamask browser extension
3. ganache-cli (npm install -g ganache-cli)
4. Node.js installed on your machine
5. JavaScript knowledge (some Solidity knowledge will help too)
6. Some GraphQL knowledge
If you have experience with Solidity and Remix, great! If not, don’t worry about it. You’ll pick it up quickly.
Write the Contract
Open Remix and create a new file. Solidity syntax is similar to JavaScript which makes it easy to learn and understand. If you know JavaScript, great! If not, you’ll get a feeling for what it’s like to write Solidity next.
First, create a class with a constructor and an access modifier. If you don’t know what an “access modifier” is, you can read more about them here.
// declare what version of solidity you want to use
pragma solidity ^0.4.10;contract Ownable {
address owner;
constructor() public {
owner = msg.sender;
}
// access modifier
modifier Owned {
require(msg.sender == owner);
_;
}
}
Here, we create a var owner
of type address
in our constructor so we can store the address of the contract creator as the owner
. Adding an access modifier makes sure that only the owner’s Ethereum address can execute functions on our new contract.
Moving on, let’s create a way to “kill” our contract. If the owner calls this method, we’ll no longer be able to use this contract.
contract Mortal is Ownable {
function kill() public Owned {
selfdestruct(owner);
}
}
Our contract is named Mortal
— it inherits contract Ownable
. Only the owner of this contract can kill this contract because we’ve used the access modifier we created in the last step.
Now, let’s start writing a contract for taking donations in Ethereum:
contract Donate is Mortal { string prize;
event donation_made(uint _amount);
event show_prize(string _prize); // Make contract payable and public
constructor(string _prize) payable public { // Check if the prize exists
require(bytes(_prize).length > 0); // Assign initial value to the contract balance
balance Of[address(this)] = msg.value; prize = _prize;
}
}
Our contract Donate
inherits contract Mortal
(meaning the owner can kill this contract if need be) and has a constructor that takes in a prize
.
When creating an instance of this contract we check if prize
has a value, and if it does, we assign an initial value to the contract balance (more on this later).
We have also written two events to inform us when our contract receives a donation and what prize the user earns for donating ether. Lastly, we assign _prize
to prize
. Super simple!
We should also add the following anonymous function to our contract. This is a fallback function that will intercept invalid calls to non-existent functions on out contract and revert the operation, returning any sent funds. It’s a good idea to have this function on all of you contracts, or people may loose their ether if the misspell the contract name or method names when calling them.
function() public{
// Fallback
revert();
}
Now let’s write a function in our contract that will help us check the contract’s balance. This function returns a uint
value in wei that is our contract’s balance—only the contract owner can execute this method. (Thank you, access modifier!)
function checkContractBalance() Owned public view returns(uint) {
return balanceOf[address(this)];
}
Finally, let’s add a function to accept the donation and set a new balance for our contract:
function make_donation() payable public { // msg.value is the amount of eth being donated
uint donation = msg.value; // Make sure donation is more than 0 eth
require(donation > 0); // Set a new balance for our contract
balanceOf[address(this)] += donation; // Emit events here
emit donation_made(donation);
emit show_prize(prize);
}
payable
functions are functions that capture incoming ether. Here, we are checking if the msg.value
(the amount of ether donated) is more than 0. If it is, then we’ll add the donated ether to the existing balance of the contract and emit our events.
Test the Contract Code
Awesome! We are done writing the code for our Smart Contract. Now, click on Run tab in the top right-hand corner in Remix. Use the following settings:
Environment: JavaScript VM
Value: 10 ether
Everything else remains same:
Just beside the Deploy button, we can see a text input box. Enter the prize value (for example, “a free hug”) and then click on Deploy button.
If you click on the checkContractBalance
button, you should see 10 ether (in wei).
Let’s try donating some ether. Enter 5
in the Value field and click on make_donation
button. Check your logs! If you check balance again, it should be 15 ether (in wei). Great! We’ve made a donation to our contract on the Ethereum blockchain.
Congratulations! We finished writing our Donation
Smart Contract.
In part 2, we will create a GraphQL server (with the help of Express) to communicate with our new Smart Contract.
If you liked this post and want to keep learning about web and app development with RED Academy, be sure to follow us on Medium or check out our website.