Introduction to Solidity and web3 Smart Contracts

USDC Web3 Services Programmable Wallets Smart Contract Platform Developer


Smart contracts are programs that reside and run on a blockchain. You can think of them as self-executing digital agreements with rules directly written into their code

Stablecoins (such as Circle’s USDC) are an evolution of money—they allow you to move money almost instantly, at near-zero cost, all across the globe. If you want to future-proof your payments infrastructure, you need to understand and support these digital payments.

So how do you integrate digital currencies such as USDC into your stack? Luckily, with a little background understanding and the tools provided by Circle, it’s not only possible, but straightforward.

In this article, we’ll give you the information you need to integrate digital currencies. We’ll look at what blockchain is, how the Ethereum blockchain launched the era of smart contracts, how smart contracts and Solidity work, and how you can use stablecoins such as USDC to drive your payments tech forward.

Let’s start with a little background.


Blockchain, Digital Currency, and Web3


  • Web1 (1991-2004) was all about static web pages (Yahoo!, Netscape, and AOL).
  • Web2 (since 2004) saw the evolution to web as a platform (Facebook, Google, Uber).
  • Web3 is all about decentralization and blockchain.

It started with Bitcoin in 2008—the first system that allowed peer-to-peer transfer of money through the internet without needing a third, trusted party such as a bank, corporation, or government.

This was made possible by the breakthrough we now know as blockchain. Blockchains can be thought of as permissionless datastores where no one person or corporation owns or is in charge of the data. Even with this decentralization, the data is still guaranteed to be true. (For more background, here’s a good tutorial.)

Bitcoin continues to be at the forefront of public blockchains, but it’s only good for transferring bitcoin. Because of this limitation, a few developers decided to create a new blockchain with more capabilities: Ethereum. Think of Ethereum as a decentralized computer that can both transfer value between users (like Bitcoin) and also execute programs and store data.

These programs that run on Ethereum are called smart contracts. They may look similar to code you have seen elsewhere, but they have some important differences that make them ideal for powering decentralized apps (dapps) and enabling decentralized finance (DeFi).


What Are Smart Contracts?


Smart contracts are programs that reside and run on a blockchain. You can think of them as self-executing digital agreements with rules directly written into their code. These contracts are programmed to automatically execute and enforce the agreed-upon actions when predefined conditions are met. By doing so, smart contracts eliminate the need for intermediaries, such as lawyers or third-party institutions, to oversee or enforce the agreements and rules.

The easiest way to think about smart contracts is through the classic analogy of a vending machine. A vending machine is programmed to provide certain goods at certain prices if a user interacts with it in a certain way (i.e. putting in money and selecting the item they want). You don’t need a third party, such as a retailer, to act as an intermediary between the goods in the machine and yourself. In other words, by using the vending machine, you’ve removed the need for a third party.

The blockchain platform on which the smart contract resides provides the necessary infrastructure required for the contract’s execution. In the case of Ethereum (and blockchains such as Polygon and Avalanche) that infrastructure is known as the Ethereum Virtual Machine (or EVM).

When a smart contract is deployed on a blockchain, it becomes a part of the blockchain's history. The code and the data stored in the contract also becomes a part of the blockchain’s global state.

To ensure transparency, security, and tamper resistance, smart contracts on most blockchains are immutable. In other words, it is impossible to alter the code of a contract once it’s been deployed. (Note that it is still possible to alter the data stored in the contract through functions that allow modification of said data.)

Although smart contracts were first introduced by computer scientist and cryptographer Nick Szabo in the 1990s, they only became mainstream with the launch of Ethereum.


How Do Smart Contracts Work?


Here's how smart contracts work:

  • 1. Creation: A developer writes the code for a smart contract, specifying the rules, conditions, and actions that the contract should carry out.
  • 2. Deployment: The smart contract code is deployed to a blockchain network, becoming a permanent part of the blockchain's history. The contract is assigned a unique address that serves as its identifier on the network. In the case of contracts on Ethereum, a piece of code known as the constructor is executed. This happens only once and can never be invoked again.
  • 3. Execution: Once the contract has been deployed, anyone can invoke public functions within the contract. If specified conditions are met, the code is executed and state changes, if any, are carried out.

It’s important to emphasize that anyone can invoke public functions on a smart contract and that smart contracts are immutable. Once a smart contract is deployed—it’s out there forever (at least as long as the blockchain exists) and available to everyone.


Applications of Smart Contracts


An overwhelming majority of Web3 is powered by smart contracts including:

  • 1. Stablecoins: Digital currencies made to be stable in value (such as Circle’s USDC).
  • 2. Decentralized Finance: Decentralized exchanges, loan protocols, staking mechanisms, and even lotteries.
  • 3. NFTs: Store and verify non-fungible assets or NFTs
  • 4. Supply Chain: Track and verify movement of goods, reducing fraud and increasing transparency.
  • 5. Real Estate: Automate property transfers, rental agreements, and title management.
  • 6. Gaming: Implement games where owning and trading gaming assets is possible.
  • 7. DAOs: Create decentralized autonomous organizations, or DAOs and in turn, conduct voting, execute decisions, and enable community governance.


Introduction to Solidity


Most blockchains have a custom programming language used to create smart contracts. On Ethereum and EVM-based blockchains such as Polygon, Avalanche, and Arbitrum, that language is Solidity.

Solidity is a strongly typed language, and it takes inspiration from JavaScript, Python, C++, and Java. If you’re familiar with any of these languages, you should find picking up Solidity easy.

Here are a few salient features of Solidity:

  • 1. Contract-oriented: Solidity's design revolves around the concept of contracts, which encapsulate the code and data of the application. Contracts can contain functions, state variables, and events. The closest thing to Solidity contracts is Java classes.
  • 2. Data Types: Solidity supports a range of data types, including integers (uint256), booleans (bool), strings (string), arrays, and user-defined structures (struct). Like other strongly typed languages such as C++, every piece of data should be explicitly tagged to a data type.
  • 3. Events: Solidity contracts can emit events, which serve as a communication mechanism between the contract and external applications. Events provide a way to notify external systems about important occurrences within the contract (such as transfer of an NFT).
  • 4. Inheritance and Modularity: Solidity supports inheritance, allowing developers to create modular contracts that inherit properties and methods from parent contracts. This promotes code reusability and organization.
  • 5. Composability: Solidity also allows you to interact with any contract already deployed on the blockchain. This is arguably its most powerful feature, allowing you to build on top of what is already available.
  • 6. Security Measures: Solidity provides features such as access control, visibility specifiers, and modifiers to ensure that contracts are executed securely.
  • 7. Development Ecosystem: Solidity is backed by a robust ecosystem of development tools. The Solidity compiler converts Solidity code into bytecode that can be executed on the blockchain. Integrated development environments (IDEs) and testing frameworks like Hardhat and Truffle facilitate the writing, deployment, and testing of smart contracts.
  • 8. Upgrades: Contracts on the blockchain are immutable once deployed. To handle changes and improvements, developers use versioning and proxy contract patterns to facilitate contract upgrades while maintaining compatibility with existing systems.

Let’s next look at some sample contracts so that you can get a sense of how Solidity works.

Example 1: A Simple Voting Contract


Example 1: A Simple Voting Contract


In this example, we’ll implement a voting system. This is a common use case for blockchain (though this is an extremely simplified example). Here we’ll allow the public to vote for a candidate and then allow them to check the number of votes per candidate.

// SPDX-License-Identifier: MIT
// Define the version of solidity we’re using pragma solidity ^0.8.0;
// Core code goes into the Contract
contract VotingContract { // Mapping to store the vote count for each candidate mapping (string => uint256) public votes; // Function to vote for a candidate function voteForCandidate(string memory candidate) public { // Increment the vote count for the candidate votes[candidate] += 1; } // Function to retrieve the vote count for a candidate function getVotesForCandidate(string memory candidate) public view returns (uint256) { return votes[candidate]; } }

Let’s walk through this code step by step:

  • 1. We define the licensing of this contract, which is common practice in Ethereum.
  • 2. We define the version of Solidity that we’re using. Remember that we won’t be able to change this later as the contract is immutable.
  • 3. We define a contract, which is something like a Java class. This is where our application data and logic resides.
  • 4. We define a state variable called votes which is a mapping. Think of mapping as dictionaries. This particular mapping has keys of type string and values of type integer. Effectively, it stores a list of candidates and the number of votes they’ve garnered.
  • 5. The voteForCandidate function can be invoked after the contract has been deployed. If you call this function with a candidate as a parameter, the number of votes for the candidate increases by 1.
  • 6. The getVotesForCandidate function can also be invoked publicly. This is a read-only function as it doesn’t mutate state. As a result, the function is marked view. It simply returns the number of votes garnered by the candidate requested.


Example 2: A Simple Token


Now let’s look at something slightly more complicated. In this example, we’ll create a simple fungible token from scratch. Some of the logic you see here can also be found in the ERC-20 standard, which is the protocol that powers all fungible tokens on Ethereum and EVM-based chains—including USDC.


// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0; contract SimpleToken { string public name = "Simple Token"; string public symbol = "ST"; uint8 public decimals = 18; // You can adjust the number of decimal places uint256 public totalSupply; mapping(address => uint256) public balances; // Create an initial supply of tokens constructor(uint256 initialSupply) { totalSupply = initialSupply * 10 ** uint256(decimals); balances[msg.sender] = totalSupply; } // Transfer tokens function transfer(address recipient, uint256 amount) public { require(recipient != address(0), "Transfer to the zero address is not allowed"); require(balances[msg.sender] >= amount, "Insufficient balance"); balances[msg.sender] -= amount; balances[recipient] += amount; } // Check balance of tokens function balanceOf(address account) public view returns (uint256) { return balances[account]; } }

Example code for creating a new wallet

This code, although more complex than its predecessor, should still be fairly simple to understand. A few points to note:

  • 1. We initialize variables to store our token’s name, symbol, decimals, and total supply. Note that unlike most other programming languages, Solidity does not support floating point numbers. The workaround is to create a small unit of your token (usually 10^-18). This is similar to wei which is 1/10^18 of an ETH.
  • 2. We have a mapping that stores the balances of our token available with all addresses.
  • 3. We have a constructor that creates an initial supply of coins and sends them to the deployer of the contract (i.e. you). Note that this is done only once: when the contract is deployed.
  • 4. The transferTokens function allows a user to transfer tokens from one wallet to another. Note the use of require statements to enforce certain rules such as the sender having enough balance to make the transfer possible.
  • 5. Finally, the balanceOf function tells us the number of tokens that belong to a particular address.


Circle and USDC


You now have a solid foundation of what you need to know in order to integrate digital currencies into your stack. And when you hear that Circle's USDC is a stablecoin (or token) implemented as a smart contract—you now know what that means! USDC is not only a stablecoin on Ethereum (and other blockchains such as Algorand, Arbitrum, Flow, and Solana) but is also open-source, composable, and accessible for anyone to build on. You can see the source code in the GitHub repo.

To learn more about how to integrate USDC into your applications, check out the documentation and use cases on the Circle website.

New call-to-action

*Programmable Wallets application programming interface (“API”) is offered by Circle Technology Services, LLC (“CTS”). CTS is not a regulated financial services company and the API does not include financial, investment, tax, legal, regulatory, accounting, business, or other advice. For additional details, please click here to see the Circle Developer terms of service.

Back to top