Hedera
  • Welcome to Hedera — let’s build the future
  • Getting Started
    • Environment Setup
    • Web2 Developers
      • Transfer HBAR
      • Create a Token
      • Create a Topic
    • EVM Developers
      • Deploy a Contract
  • Tutorials
    • Smart Contracts
      • How to Mint & Burn an ERC-721 Token Using Hardhat and Ethers (Part 1)
      • How to Set Access Control, a Token URI, Pause, and Transfer an ERC-721 Token Using Hardhat (Part 2)
      • How to Upgrade an ERC-721 Token with OpenZeppelin UUPS Proxies and Hardhat (Part 3)
      • How to Verify a Smart Contract on HashScan
      • Deploy a Smart Contract Using Remix
      • Deploy a Smart Contract Using Hardhat and Hiero JSON-RPC Relay
      • Deploy Your First Smart Contract
      • Deploy a Contract Using the Hedera Token Service
      • Send and Receive HBAR Using Solidity Smart Contracts
      • Deploy By Leveraging Ethereum Developer Tools On Hedera
      • Deploy a Subgraph Using The Graph and Hedera JSON-RPC Relay
      • Deploy Smart Contracts on Hedera Using Truffle
      • The Power of Native Hedera Tokens as ERC-20 Tokens: A step-by-step guide
      • HTS x EVM - Part 1: How to Mint NFTs
      • HTS x EVM - Part 2: KYC & Update
      • HTS x EVM - Part 3: How to Pause, Freeze, Wipe, and Delete NFTs
      • Hedera Smart Contracts Workshop
        • Setup
        • Solidity
        • Hedera SDK JS
        • Hardhat and EthersJs
        • Outro
      • Foundry
        • How to Setup Foundry and Write a Basic Unit Test
        • How to Deploy and Verify a Hedera Smart Contract with Foundry
        • How to Test A Solidity Event
        • How to Fork Testnet on Latest Block
    • Consensus
      • Submit Your First Message
      • Submit Message to Private Topic
      • Query Messages with Mirror Node
    • Tokens
      • Create and Transfer Your First NFT
      • Create and Transfer Your First Fungible Token
      • Create and Transfer an NFT using a Solidity Contract
      • Structure Your Token Metadata Using JSON Schema V2
      • Hedera Token Service - Part 1: How to Mint NFTs
      • Hedera Token Service - Part 2: KYC, Update, and Scheduled Transactions
      • Hedera Token Service - Part 3: How to Pause, Freeze, Wipe, and Delete NFTs
      • Create Your First Frictionless Airdrop Campaign
    • Local Node
      • How to Run Hedera Local Node in a Cloud Development Environment (CDE)
        • Run a Local Node in Gitpod
        • Run a Local Node in Codespaces
      • How to Set Up a Hedera Local Node
      • Set Up a Hedera Local Node using the NPM CLI
    • More Tutorials
      • Create and Fund Your Hedera Testnet Account
      • How to Create a Personal Access Token (API Key) on the Hedera Portal
      • How to Auto-Create Hedera Accounts with HBAR and Token Transfers
      • How to Configure a Mirror Node and Query Data
      • How to Generate a Random Number on Hedera
      • Get Started with the Hedera Consensus Service Fabric Plugin
        • Virtual Environment Setup
      • Schedule Your First Transaction
      • How to Connect to Hedera Networks Over RPC
        • Configuring Hashio RPC endpoints
        • Configuring Hiero JSON-RPC Relay endpoints
        • Configuring Validation Cloud RPC endpoints
      • JavaScript Testing
      • Create a Hedera DApp Integrated with WalletConnect
      • How to Connect MetaMask to Hedera
    • Demo Applications
    • Starter Projects
    • Building on Hedera (course)
  • Networks
    • Mainnet
      • Mainnet Accounts
      • Mainnet Consensus Nodes
        • Node Requirements
          • FAQ
      • Fees
        • Transaction Records
    • Testnets
      • Testnet Accounts
      • Testnet Consensus Nodes
    • Localnet
      • Single Node Configuration
      • Multinode Configuration
    • Network Explorers and Tools
    • Release Notes
      • Consensus Node
      • Hedera Mirror Node
  • Core Concepts
    • Accounts
      • Account Creation
      • Auto Account Creation
      • Account Properties
    • Keys and Signatures
    • Schedule Transaction
    • Smart Contracts
      • Understanding Hedera's EVM Differences and Compatibility
        • For EVM Developers Migrating to Hedera
          • Accounts, Signature Verification & Keys (ECDSA vs. ED25519)
          • JSON-RPC Relay and EVM Tooling
          • Token Management with Hedera Token Service
          • Decimal Handling (8 vs. 18 Decimals)
          • Handling HBAR Transfers in Contracts
        • For Hedera-Native Developers Adding Smart Contract Functionality
          • Integrating ED25519 Accounts and Advanced Features Into Smart Contracts
          • JSON-RPC Relay and State Queries
          • Extending Token Management with Smart Contracts
      • Creating Smart Contracts
      • Compiling Smart Contracts
      • System Smart Contracts
        • Hedera Account Service
        • Hedera Schedule Service
      • Gas and Fees
      • JSON-RPC Relay
      • Deploying Smart Contracts
      • Smart Contract Addresses
      • Verifying Smart Contracts
      • Smart Contract Traceability
      • Tokens Managed by Smart Contracts
        • ERC-20 (Fungible Tokens)
        • ERC-721 (Non-Fungible Token)
        • ERC-3643 Real World Assets (RWA)
        • ERC-1363 (Payable Tokens)
        • Hedera Token Service System Contract
      • Wrapped HBAR (WHBAR)
      • Smart Contract Rent
      • Smart Contract Security
      • EVM Archive Node Queries
    • Tokens
      • Tokenization on Hedera
      • Hedera Token Service (HTS) Native Tokenization
        • Token Types and ID Formats
        • Token Properties
        • Token Creation
        • Custom Fee Schedule
        • Token Airdrops
      • ERC/EVM-Compatible Tokenization
      • Hybrid (HTS + EVM ) Tokenization
    • Staking
      • Staking Program
      • Stake HBAR
    • Hashgraph Consensus Algorithm
      • Gossip About Gossip
      • Virtual Voting
    • Transactions and Queries
      • Transaction Properties
    • State and History
    • Mirror Nodes
      • Hedera Mirror Node
      • One Click Mirror Node Deployment
      • Run Your Own Mirror Node
        • Run Your Own Mirror Node with Google Cloud Storage (GCS)
        • Run Your Mirror Node with Amazon Web Services S3 (AWS)
  • Open Source Solutions and Integrations
    • AI Studio on Hedera
      • ElizaOS Plugin for Hedera
      • Hedera AI Agent Kit
      • MCP Server
      • OpenConvAI
    • AI Tools for Developers
      • Hedera Hivemind
      • Kapa AI
    • Asset Tokenization Studio (ATS)
      • Web User Interface (UI)
      • Frequently Asked Questions (FAQs)
    • HashioDAO
      • Governance Token DAO
      • NFT DAO
      • Multisig DAO
      • DAO Proposals
      • Local Environment Setup
    • Hedera CLI
    • Hedera Contract Builder
    • Hedera Custodians Library
      • How to use it
    • Hedera Developers Code Repository
    • Hedera Developer Playground
    • Hedera Wallet Snap By MetaMask
      • Hedera Wallet Snap Documentation
      • Tutorial: MetaMask Snaps – What Are They and How to Use Them
    • Interoperability and Bridging
      • LayerZero
    • NFT Studio
      • Airdrop List Verifier
      • Metadata Validator
      • NFT Rarity Inspector
      • NFT Token Holders List Builder
      • NFT Risk Calculator
      • Token Balance Snapshot
      • Hedera NFT SDK
    • Oracle Networks
      • Chainlink Oracles
      • Pyth Oracles
      • Supra Oracles
    • Stablecoin Studio
      • Core Concepts
      • Web UI Application
      • CLI Management
      • TypeScript SDK
    • Hedera Guardian
    • Hedera WalletConnect
  • SDKs & APIs
    • SDKs
      • Build Your Hedera Client
      • Set Up Your Local Network
      • Network Address Book
      • Keys
        • Generate a new key pair
        • Import an existing key
        • Create a key list
        • Create a threshold key
        • Generate a mnemonic phrase
        • Recover keys from a mnemonic phrase
      • HBAR
      • Specialized Types
      • Pseudorandom Number Generator
      • Transactions
        • Create a Batch Transaction
        • Transaction ID
        • Modify transaction fields
        • Create an unsigned transaction
        • Manually sign a transaction
        • Submit a transaction
        • Sign a multisignature transaction
        • Get a transaction receipt
        • Get a transaction record
      • Schedule Transaction
        • Schedule ID
        • Create a schedule transaction
        • Sign a scheduled transaction
        • Delete a schedule transaction
        • Get schedule info
        • Network Response Messages
      • Queries
      • General Network Response Messages
      • Accounts and HBAR
        • Create an account
        • Update an account
        • Transfer cryptocurrency
        • Approve an allowance
        • Delete an allowance
        • Delete an account
        • Get account balance
        • Get account info
        • Network Response Messages
      • Consensus Service
        • Create a topic
        • Update a topic
        • Submit a message
        • Delete a topic
        • Get topic messages
        • Get topic info
        • Network Response
      • Token Service
        • Token ID
        • NFT ID
        • Token types
        • Create a token
        • Custom token fees
        • Update a token
        • Update token custom fees
        • Update NFT metadata
        • Transfer tokens
        • Airdrop a token
        • Claim a token
        • Cancel a token
        • Reject a token
        • Delete a token
        • Mint a token
        • Burn a token
        • Freeze an account
        • Unfreeze an account
        • Enable KYC account flag
        • Disable KYC account flag
        • Associate tokens to an account
        • Dissociate tokens from an account
        • Pause a token
        • Unpause a token
        • Wipe a token
        • Atomic swaps
        • Get account token balance
        • Get token info
        • Get NFT info
        • Network Response Messages
      • File Service
        • Create a file
        • Append to a file
        • Update a file
        • Delete a file
        • Get file contents
        • Get file info
        • Network Response Messages
      • Smart Contract Service
        • Delegate Contract ID
        • Create a smart contract
        • Update a smart contract
        • Delete a smart contract
        • Call a smart contract function
        • Ethereum transaction
        • Get a smart contract function
        • Get smart contract bytecode
        • Get smart contract info
        • Hedera Service Solidity Libraries
        • Network Response Messages
      • Signature Provider
        • Provider
        • Signer
        • Wallet
        • Local Provider
    • Mirror Node REST API
      • Accounts
      • Balances
      • Blocks
      • Schedule Transactions
      • Smart Contracts
      • Tokens
      • Topics
      • Transactions
      • Network
    • Hedera Consensus Service gRPC API
    • Hedera APIs
      • Basic Types
        • AccountAmount
        • AccountID
        • ContractID
        • CryptoAllowance
        • CurrentAndNextFeeSchedule
        • FeeComponents
        • FeeData
        • FeeSchedule
        • FileID
        • Fraction
        • HederaFunctionality
        • Key
        • KeyList
        • NftAllowance
        • NftTransfer
        • NodeAddress
        • NodeAddressBook
        • RealmID
        • ScheduleID
        • SemanticVersion
        • ServicesConfigurationList
        • ServiceEndpoint
        • Setting
        • ShardID
        • Signature
        • SignatureList
        • SignatureMap
        • SignaturePair
        • SubType
        • TransferList
        • TransactionID
        • ThresholdKey
        • ThresholdSignature
        • TokenAllowance
        • TokenBalance
        • TokenBalances
        • TokenFreezeStatus
        • TokenPauseStatus
        • TokenID
        • TokenKycStatus
        • TokenRelationship
        • TokenTransferList
        • TokenType
        • TokenSupplyType
        • TopicID
        • TransactionFeeSchedule
      • Cryptocurrency Accounts
        • CryptoService
        • CryptApproveAllowance
        • CryptoDeleteAllowance
        • CryptoCreate
        • CryptoTransfer
        • CryptoUpdate
        • CryptoDelete
        • CryptoGetAccountBalance
        • CryptoGetAccountRecords
        • CryptoGetInfo
        • CryptoGetStakers
      • Consensus Service
        • Consensus Service
        • ConsensusCreateTopic
        • ConsensusUpdateTopic
        • ConsensusSubmitMessage
        • ConsensusDeleteTopic
        • ConsensusTopicInfo
        • ConsensusGetTopicInfo
      • Schedule Service
        • ScheduleService
        • SchedulableTransactionBody
        • ScheduleCreate
        • ScheduleDelete
        • ScheduleSign
        • ScheduleGetInfo
      • Token Service
        • TokenService
        • CustomFees
          • AssessedCustomFee
          • CustomFee
          • FractionalFee
          • FixedFee
          • RoyaltyFee
        • TokenCreate
        • TokenUpdate
        • TokenFeeScheduleUpdate
        • TokenDelete
        • TokenMint
        • TokenBurn
        • TokenFreezeAccount
        • TokenUnfreezeAccount
        • TokenGrantKyc
        • TokenRevokeKyc
        • TokenAssociate
        • TokenDissociate
        • TokenWipeAccount
        • TokenPause
        • TokenUnpause
        • TokenGetInfo
        • TokenGetNftInfo
        • TokenGetNftInfos
        • TokenGetAccountNftInfo
      • File Service
        • FileService
        • FileCreate
        • FileAppend
        • FileUpdate
        • FileDelete
        • FileGetContents
        • FileGetInfo
      • Smart Contracts
        • SmartContractService
        • ContractCall
        • ContractCallLocal
        • ContractCreate
        • ContractUpdate
        • ContractDelete
        • ContractGetByteCode
        • ContractGetInfo
        • ContractGetRecords
      • Miscellaneous
        • Duration
        • ExchangeRate
        • Freeze
        • FreezeType
        • GetByKey
        • GetBySolidityID
        • NetworkGetVersionInfo
        • NetworkService
        • Query
        • QueryHeader
        • Response
        • ResponseCode
        • ResponseHeader
        • SystemDelete
        • SystemUndelete
        • TimeStamp
        • Transaction
        • TransactionBody
        • TransactionContents
        • TransactionGetFastRecord
        • TransactionGetReceipt
        • TransactionGetRecord
        • TransactionReceipt
        • TransactionRecord
        • TransactionResponse
        • UncheckedSubmit
    • Hedera Status API
  • Support & Community
    • Glossary
    • Contributing to Hedera documentation
      • Contribution Guidelines
        • Creating Issues
        • Creating Pull Requests
        • Hedera Improvement Proposal (HIP)
        • Submit Demo Applications
      • Style Guide
        • Understanding different types of documentation
        • Use of HBAR and tinybars
        • Use of web2 and web3
        • Language and grammar
        • Formatting
        • Punctuation
        • GitBook Markdown Syntax
    • Discord
    • GitHub
    • Stack Overflow
    • Hedera Blog
    • Bug Bounty
    • Hedera Help
    • Documentation Survey
    • Meetups
    • Brand Guidelines
    • Status Page
Powered by GitBook
LogoLogo

INTRODUCTION

  • Fees
  • Core Concepts
  • Network Information

TOOLS

  • Bridge
  • Oracles
  • Explorers
  • Developer Portal & Faucet

RESOURCES

  • Status
  • Bug Bounty
  • Build on Hedera (course)
  • Documentation Survey
On this page
  • Video
  • What smart contracts are, and are not
  • Comments
  • SPDX License
  • Step A1: Specify solc version number
  • Step A2: Specify name of smart contract
  • Step A3: Primitive type state variable
  • Step A4: Dynamic type state variable
  • Functions
  • Step A5: Specify function modifiers
  • Step A6: Specify function return values
  • Special values accessible within a function
  • Step A7: Specify condition for require
  • Step A8: Specify error message for require
  • Step A9: Update state
  • Step A10: Specify an event
  • Step A11: Emit an event

Was this helpful?

Edit on GitHub
  1. Tutorials
  2. Smart Contracts
  3. Hedera Smart Contracts Workshop

Solidity

Solidity tutorial - HSCS workshop. Learn how to enable custom logic & processing on Hedera through smart contracts.

PreviousSetupNextHedera SDK JS

Last updated 1 year ago

Was this helpful?

Video

What smart contracts are, and are not

The term "smart contracts" is kind of a poor choice for a name, and is the source of a lot of confusion: Smart contracts are neither smart, and neither are they contracts.

They are, at their core, simply computer programs that are executable. So what is the big deal about them then? What makes them different from "regular" computer programs? The biggest one, that you probably know already, is that they are executed on blockchains/ DLTs. But there are a few others to be aware of:

  • They are typically executed within a Virtual Machine (VM)

  • Any state changes need to be agreed upon through network consensus

  • Any state queries return values agreed upon by network consensus

  • While their state is mutable, their code is not

Combine the above with the decentralized nature of blockchains/ DLTs, and you get a special breed of computer programs like no other: Deterministic, p2p execution, that is censorship resistant and interruption resistant.

You can use this powerful technology within the Hedera network too, via the Hedera Smart Contract Service. This workshop will show you how!

To start, open and edit intro/trogdor.sol.

Comments

In Solidity, comment syntax is similar to what you might be familiar with from Javascript. Single line comments use //, and extend till the rest of the line. Multi-line comments use /* to begin, and */ to end.

// single line comment

/* this is a
multi-line
comment. */

SPDX License

// SPDX-License-Identifier: MIT

Step A1: Specify solc version number

Near the top of the file, you should see the following comment:

// NOTE: specify solc version number
// Step (A1) in the accompanying tutorial

Note that this type of comment will be present throughout the tutorial repo that accompanies this written tutorial. Each numbered step of a section heading here corresponds to the the same number in a comment there. In the subsequent steps of this tutorial, you will follow the same pattern as above. However, this tutorial does not repeat the comments marking the steps for the remainder of the tutorial and instead only include the new/changed lines of code.

The pragmas simply defines the which version of the Solidity compiler, solc, it is intended to be compiled with.

pragma solidity 0.8.17;

Here we simply specify that this file should be compiled with version 0.8.17 only. You may specify more complex rules, similar to semver used by npm.

Step A2: Specify name of smart contract

A smart contract is a grouping of state variables, functions, and other things. The solidity code needs to group them, and does so by surrounding them with a pair of squiggly brackets ({ and }). It also needs a name - and we'll name this one Trogdor.

contract Trogdor {

Step A3: Primitive type state variable

A smart contract persists its state on the virtual machine, and may only be modified during a successful transaction on the network. Solidity supports many different primitive types, here let's use uint256 as we'll be representing an unsigned integer value.

	uint256 public MIN_FEE = 100;

The above would work, but in this case, we know that we will not be modifying its value, so instead of a state variable, let's use a state constant instead. This is achieved by adding the constant keyword to it.

	uint256 public constant MIN_FEE = 100;

Step A4: Dynamic type state variable

Smart contracts can also persist more complex types of data in its state, and this is accomplished using dynamic state variables. A mapping is used to represent key-value pairs, and is analogous to a Hashmap in other programming languages.

	mapping(address => uint256) public amounts;

This mapping stores key-value pairs where the keys are of type address, and the values are of type uint256.

Note that both MIN_FEE and amounts have a visibility modifier of public. In other cases you might want internal or private,

Functions

Functions are the main part of the smart contract where things actually happen: Code is executed, and perhaps state is accessed or updated. The syntax of a function is somewhat similar to Javascript, with the main differences being the addition of types, and of modifiers.

function doSomething(uint256 param1)
	public
	pure
	returns(uint256)
{
	return param1;
}

In the above example:

  • Name: doSomething

  • Modifiers: public and pure

  • Parameter name: param1

  • Parameter type: uint256

  • Return type: uint256

Step A5: Specify function modifiers

The burninate function modifies the state of the smart contract, and also accepts payment (in HBAR), so let's go with public, payable for its modifiers.

        public
        payable

The totalBurnt function does not modify the state of the smart contract, but does access the state. It does not accept any payment. It is intended to only be called by an Externally Owned Account (EOA) or another smart contract. For this let's go with external, view for its modifiers.

        external
        view

Just like state variables, functions may have the have visibility modifiers public, private, and internal; however external is a new one, and may apply only to functions.

Step A6: Specify function return values

The totalBurnt function performs a query of the smart contract's state. Therefore it should reply with this information. This is done through the returns keyword, which specifies the type of the returned value.

		returns(uint256)

In this case, the function returns a single value of type uint256. which specifies one or more return values. Note that Solidity allows functions to return multiple return values, for example returns(uint256, address) would mean that it returns both a uint256 and an address.

Special values accessible within a function

When a smart contract function is invoked, it has access to values that are passed in as parameters. It also has access to the state variables persisted by the smart contract.

Additionally, there are also several special values that are specific to the current block (group of transactions) or specific to the current transaction that are also accessible. Two of these are msg.sender and msg.value.

Step A7: Specify condition for require

The require function is used to check for specific conditions within a function invocation. If these conditions are not met, it throws an exception. This causes the function invocation to be reverted, meaning the state of the smart contract would remain as it was before, as if the function invocation was never made.

        require(msg.sender != address(0), "zero address not allowed");

Within the burninate function, we use a require to ensure that the transaction is seemingly not from the null address, also known as the zero address. This essentially disallows any transactions sent from that particular address

Technically it should not be possible for a transaction to be sent by the zero address. This is done here purely for illustrative purposes.

Step A8: Specify error message for require

We have another require in this function to ensure that the amount paid (in HBAR) is at least above a certain threshold (the MIN_FEE constant).

        require(msg.value >= MIN_FEE, "pay at least minimum fee");

This function is payable, meaning that any value (of HBAR) sent along with the function gets deducted from the balance of the sender's account, and gets added to the balance of the smart contract's account. In other words: The transaction sender pays into the smart contract via this function.

The numeric value of msg.value is not denominated in HBAR, but rather tinybar, when a smart contract is deployed on a Hedera network. This is consistent with msg.value being denominated not in Ether, but rather in wei, when a smart contract is deployed on an Ethereum network.

There is a key difference though:

  • 1 HBAR = 10^8 tinybar (10 million)

  • 1 Ether = 10^18 wei (1 billion billion)

In functions which are not payable, msg.value is guaranteed to be zero. Whereas in functions which are payable, msg.value could be zero or more. In this case, the intent is for the function to reject any function invocations which do not pay enough.

Step A9: Update state

After the checks have been completed successfully, by the require statements, we're ready to update the persisted state of this smart contract. In this case, we are keeping track, as a running tally, of the total amount paid by each different address that this function has been invoked with.

        amounts[msg.sender] = amounts[msg.sender] + msg.value;

This statement increments the current value by the amount paid into the function, keyed on the address that invoked this function.

Step A10: Specify an event

The EVM outputs logs, which essentially is information that is persisted on the network, but not accessible by smart contracts. Instead they are intended to be accessed by client applications (such as DApps), which typically search for specific events, or listen for specific events.

The canonical use case for events within a smart contract is to create a "history" of actions performed by that smart contract. In this case, let's commemorate each time the burninate function is successfully invoked.

    event Burnination(address who, uint256 amount);

This event is named Burnination, and whenever it is produced, it is added to the EVM logs, and will contain an address and a uint256.

Step A11: Emit an event

Once the event has been defined, the smart contract should specify exactly when it should be added to the EVM logs. This is done using emit.

        emit Burnination(msg.sender, msg.value);

Thus, based on where this emit statement is located within the function, this event is added to the logs upon each time the burninate function is invoked, only if both of the require statements are satisfied. When it gets added the transaction sender's address and the amount that they paid into the function are logged.

Note that this particular smart contract does not include any means to take out the HBAR balance that accrues within it over time each time burninate is invoked. This effectively means that the HBAR sent into it is stuck there forever, and hence is effectively lost.

Trogdor would be proud ;)

defines a list of software licenses, and allows you to reference one using a standard short identifier. The solidity compiler will explicitly check for this as a comment in the first line of any Solidity file. If it is missing, it will output a warning.

SPDX
Ref: Solidity version pragma
Ref: Solidity value types
Ref: Solidity mapping type
Ref: Solidity State Variable Visibility
Ref: Solidity function visibility modifiers
Ref: Solidity block and transaction properties
Ref: Solidity panic and require
Ref: Solidity Ether units
Ref: Stackoverflow full unit of HBAR
Ref: Solidity operators
Ref: Solidity mapping types
Hedera Smart Contract Service Workshop Part 3/6 | Solidity