Hello Celo

In this guide we are going to learn how to connect to the Celo test network using ContractKit.

In this guide we are going to write a Node.js script to introduce some of the basic concepts that are important to understand how Celo works. This will get us started with connecting to the Celo network and learning how to develop more advanced applications.

We assume you already have Node.js and NPM installed on your computer.

Learning Objectives

At the end of this guide, you will be able to:

  • Connect to the Celo test network, called Alfajores

  • Get test CELO and cUSDs from the faucet

  • Read account and contract information from the test network

  • Send transactions to the network

Getting Started

To start, clone this GitHub repo. This is a Node.js application.

$ git clone https://github.com/critesjosh/helloCelo.git

We will be using the Celo ContractKit SDK to interact with the Celo test network. Let's install it. It is already defined in the package.json, so we can get it with

$ npm install

Importing ContractKit

We will be writing our Node.js app in the helloCello.js file.

Import the contract kit into our script with

// 1. Import contractkit
const ContractKit = require('@celo/contractkit')

Now we can use the ContractKit to connect to the network.

// 2. Init a new kit, connected to the alfajores testnet
const kit = ContractKit.newKit('https://alfajores-forno.celo-testnet.org')

At any point in the file you can console.log() variables to print their output when you run the script.

Reading Alfajores

ContractKit contains a contracts property that we can use to access certain information about deployed Celo contracts.

The Celo blockchain has two native assets, CELO (CELO) and the Celo Dollar (cUSD). Both of these assets implement the ERC20 token standard from Ethereum. The CELO asset is managed by the CELO smart contract. We can access the gold contract with the SDK with kit.contracts.getGoldToken(). This function returns a promise, so we have to wait for it to resolve before we can interact with the gold token contract. If you are unfamiliar with Promises in Javascript, check out this documentation. Promises are a common tool in blockchain development. In this guide, we use the async/await syntax for promises.

Let's read some token balances from the blockchain. Add the following line in the readAccount() function.

// 3. Get the Gold Token contract
let goldtoken = await kit.contracts.getGoldToken()

We can get the CELO balance of an account using the gold token wrapper with goldtoken.balanceOf(address). Let's check the balance of this address '0xD86518b29BB52a5DAC5991eACf09481CE4B0710d'

// 4. Address to look up
let anAddress = '0xD86518b29BB52a5DAC5991eACf09481CE4B0710d'
// 5. Get Gold Token balance
let balance = await goldtoken.balanceOf(anAddress)
// Print balance
console.log(`${anAddress} balance: ${balance.toString()}`)

The balanceOf(address) function also returns a Promise, so we wait for the promise to resolve then we print the result.

You may notice that we convert the balance to a string before we print it. This is because the balanceOf() function returns a BigNumber. Javascript does not have floating point numbers, so it is common to convert integers to large numbers before doing arithmetic. So 1 CELO = 10**18 base units of CELO. The balanceOf() function returns the account balance in these base units. Converting the BigNumber to a string converts the BigNumber object into a more legible string.

Reading all account balances is a powerful feature of blockchains. Next, let's see how we can send value to each other on the test net.

In order to do transfers (aka transactions), we need to:

  1. Create an account (by creating a private key)

  2. Fund it with test CELO and cUSDs

  3. Sign and send transactions to the network

Accounts

We are accessing the Celo network via a remote node via HTTP requests at 'https://alfajores-forno.celo-testnet.org'.

Don't worry about what this means right now, just understand that it is easier to get started using Celo by accessing remote nodes, rather than running them locally on your machine. You can read more about the details of the Celo network here.

Because we are accessing the network remotely, we need to generate an account to sign transactions and fund that account with test CELO.

There is a short script in getAccount.js to either get a Celo account from a mnemonic in the .secret file, or create a random account if the file is empty. In the script, we useweb3.js to create a new private key/account pair. Web3.js is a popular javascript library for handling Ethereum related functionality. Celo is a cousin of Ethereum, so this library works well for generating Celo accounts.

This is not the standard way of managing Celo accounts. In a production environment, the Celo Wallet will manage accounts for you. Accessing accounts from the Celo Wallet will be discussed in future guides.

We can now use this account to get account information (ie the private key and account address) and to send transactions from account.address. Add the following code to read the account balance. Continue adding to helloCelo.js.

//
// Create an Account
//
// 6. Import the getAccount function
const getAccount = require('./getAccount').getAccount
async function createAccount(){
// 7. Get your account
let account = await getAccount()
// 8. Get the Gold Token contract wrapper
let goldtoken = await kit.contracts.getGoldToken()
// 9. Get your CELO balance
let balance = await goldtoken.balanceOf(account.address)
// Print your account info
console.log(`Your account address: ${account.address}`)
console.log(`Your account balance: ${balance.toString()}`)
}

This will print 0, as we have not funded the associated account yet.

Using the faucet

We can get free test CELO and cUSDs on the test network for development via the Celo Alfajores faucet.

Copy your randomly generated account address from the console output mentioned above, and paste it into the faucet.

Once your account has been funded, run $ node helloCelo.js again to see your updated balance.

Sending Value

We have an account with CELO in it, now how do we send it to another account. Remember the Gold Token wrapper we used to read account balances earlier? We can use the same wrapper to send tokens, you just need to add the private key associated with your account to ContractKit (see line 10).

The Gold Token wrapper has a method called transfer(address, amount) that allows you to send value to the specified address (line 14).

You need to send() the transaction to the network after you construct it. The send() method returns a transaction object. We will wait for the transaction receipt (which will be returned when the transaction has been included in the blockchain) and print it when we get it. This receipt contains information about the transaction.

After we read the receipt, we check the balance of our account again, using the balanceOf() function. The logs print our updated balance!

You may notice that the account balance is a bit smaller than the amount of tokens that we sent. This is because you have to pay for every update to the network.

Add the following code to the send() function in helloCelo.js to send a transaction.

async function send(){
// 10. Get your account
let account = await getAccount()
// 11. Add your account to ContractKit to sign transactions
kit.addAccount(account.privateKey)
// 12. Specify recipient Address
let anAddress = '0xD86518b29BB52a5DAC5991eACf09481CE4B0710d'
// 13. Specify an amount to send
let amount = 100000
// 14. Get the Gold Token contract wrapper
let goldtoken = await kit.contracts.getGoldToken()
// 15. Transfer gold from your account to anAddress
let tx = await goldtoken.transfer(anAddress, amount).send({from: account.address})
// 16. Wait for the transaction to be processed
let receipt = await tx.waitReceipt()
// 17. Print receipt
console.log('Transaction receipt: %o', receipt)
// 18. Get your new balance
let balance = await goldtoken.balanceOf(account.address)
// 19. Print new balance
console.log(`Your new account balance: ${balance.toString()}`)
}

Run $ node helloCelo.js again to send the transaction and see the printed output in the console.

Connecting to a Ledger Device from a Web Application

The above instructions apply to building NodeJS applications. If you want to build an integration with a web application, you can still use the ContractKit by following slightly modified instructions.

You will need to have the following npm libraries installed: web3, @celo/contractkit, @ledgerhq/hw-app-eth, @ledgerhq/hw-transport-u2f and @ledgerhq/hw-transport-webusb.

Then, you can create a new instance of the ContractKit with the following code:

import { ContractKit, newKitFromWeb3 } from "@celo/contractkit";
import { newLedgerWalletWithSetup } from "@celo/contractkit/lib/wallets/ledger-wallet";
import Eth from "@ledgerhq/hw-app-eth";
import TransportU2F from "@ledgerhq/hw-transport-u2f";
import TransportUSB from "@ledgerhq/hw-transport-webusb";
import Web3 from "web3";
// Handle getting the Celo Ledger transport.
const getCeloLedgerTransport = () => {
if (window.USB) {
return TransportUSB.create();
} else if (window.u2f) {
return TransportU2F.create();
}
throw new Error("Ledger Transport not support, please use Chrome, Firefox, Brave, Opera or Edge.");
};
// Handle creating a new Celo ContractKit
const getContractKit = async () => {
// Create a Web3 provider by passing in the testnet/mainnet URL
const web3 = new Web3("https://alfajores-forno.celo-testnet.org");
// Get the appropriate Ledger Transport
const transport = await getCeloLedgerTransport();
// Create a new instance of the ETH Ledger Wallet library
const eth = new Eth(transport);
// Use the Celo Ledger Wallet setup util
const wallet = await newLedgerWalletWithSetup(eth.transport);
// Instantiate the ContractKit
const kit: ContractKit = newKitFromWeb3(web3, wallet);
return kit;
};

Once you have successfully created the ContractKit, you can use the various Celo contracts to sign transactions with a connected Ledger device. For example, here's how to transfer gold tokens (just like above in the NodeJS example):

// Use the gold token contract to transfer tokens
const transfer = async (from, to, amount) => {
const goldTokenContract = await kit.contracts.getGoldToken();
const tx = await goldTokenContract.transfer(to, amount).send({ from });
const receipt = await tx.waitReceipt();
console.log("Transaction Receipt: ", receipt);
};

This is the basic setup to integrate the Celo Ledger App with a web application. You can also view the Celo Ledger App example codebase for some other examples of connecting to a Ledger Device from a web application.

Wrapping Up

Congratulations! You have accomplished a lot in this short introduction to developing on Celo.

We covered:

  • Installing and setting up ContractKit

  • Connecting to the Celo Alfajores network

  • Getting the CELO contract wrapper

  • Reading account balances using the CELO wrapper

  • Generating a new account in Celo

  • Funding an account using the Celo Alfajores Faucet

  • Sending CELO