We want to understand which of the two mentioned technologies can better meet our needs. Let's go straight to the point; Let's write a simple project with the help of both technologies and have a small comparison of them at the end.
It’s a simple project that is written in Solidity and GoLang:
A simple bank smart contract that allows users to enroll, deposit, and withdraw Ether. The contract also rewards the first three users who enroll with 10 Ether each.
The Solidity code for the smart contract is:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract SimpleBank {
// State variables
mapping(address => uint) private balances;
address[] private accounts;
uint private rewardAmount = 10 ether;
uint private numEnrolled = 0;
// Events
event LogEnrolled(address accountAddress);
event LogDepositMade(address accountAddress, uint amount);
event LogWithdrawal(address accountAddress, uint withdrawAmount, uint newBalance);
// Constructor
constructor() payable {
require(msg.value == 30 ether, "30 ether initial funding required");
}
// Modifiers
modifier onlyEnrolled() {
require(balances[msg.sender] > 0, "Not enrolled");
_;
}
// Functions
function enroll() public returns (uint) {
require(balances[msg.sender] == 0, "Already enrolled");
if (numEnrolled < 3) {
balances[msg.sender] = rewardAmount;
numEnrolled++;
}
accounts.push(msg.sender);
emit LogEnrolled(msg.sender);
return balances[msg.sender];
}
function deposit() public payable onlyEnrolled returns (uint) {
balances[msg.sender] += msg.value;
emit LogDepositMade(msg.sender, msg.value);
return balances[msg.sender];
}
function withdraw(uint withdrawAmount) public onlyEnrolled returns (uint remainingBal) {
require(withdrawAmount <= balances[msg.sender], "Insufficient balance");
balances[msg.sender] -= withdrawAmount;
payable(msg.sender).transfer(withdrawAmount);
emit LogWithdrawal(msg.sender, withdrawAmount, balances[msg.sender]);
return balances[msg.sender];
}
function balance() public view onlyEnrolled returns (uint) {
return balances[msg.sender];
}
}
The GoLang code for interacting with the smart contract is:
package main
import (
"context"
"fmt"
"log"
"math/big"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
simplebank "./api" // for demo
)
func main() {
client, err := ethclient.Dial("http://127.0.0.1:7545")
if err != nil {
log.Fatal(err)
}
privateKey, err := crypto.HexToECDSA("c87509a1c067bbde78beb793e6fa76530b6382a4c0241e5e4a9ec0a0f44dc0d3") // ganache test key
if err != nil {
log.Fatal(err)
}
publicKey := privateKey.Public()
publicKeyECDSA, ok := publicKey.(*crypto.PublicKey)
if !ok {
log.Fatal("error casting public key to ECDSA")
}
fromAddress := crypto.PubkeyToAddress(*publicKeyECDSA)
nonce, err := client.PendingNonceAt(context.Background(), fromAddress)
if err != nil {
log.Fatal(err)
}
gasPrice, err := client.SuggestGasPrice(context.Background())
if err != nil {
log.Fatal(err)
}
auth := bind.NewKeyedTransactor(privateKey)
auth.Nonce = big.NewInt(int64(nonce))
auth.Value = big.NewInt(30 * 1e18) // in wei
auth.GasLimit = uint64(300000) // in units
auth.GasPrice = gasPrice
address, tx, instance, err := simplebank.DeploySimpleBank(auth, client)
if err != nil {
log.Fatal(err)
}
fmt.Println(address.Hex()) // 0x147B8eb97fD247D06C4006D269c90C1908Fb5D54
fmt.Println(tx.Hash().Hex()) // 0xdae8ba5444eefdc99dbbc14b432a6c75d24b2de934d0a1686a51d76c2f758f9f
_ = instance
}
The comparison between the two codes is:
The Solidity code defines the state variables, events, constructor, modifiers, and functions of the smart contract. It also uses the pragma directive to specify the Solidity version and the SPDX license identifier. It also uses the require function to check for preconditions and the emit function to trigger events.
The GoLang code uses the ethclient package to connect to a local Ethereum node, the crypto package to generate and sign transactions, and the bind package to deploy and interact with smart contracts. It also uses the simplebank package, which is generated by abigen from the compiled Solidity contract. It also uses big.Int to represent large numbers such as wei and gas.
Comments