Web3, DeFi & Blockchain Applications

Chapter 4
Smart Contracts and Decentralized Applications

Advance Diploma in Blockchain
Web3, DeFi & Blockchain Applications   •   Advance Diploma

Smart Contracts and Decentralized Applications

Introduction and Context

Smart contracts are programs deployed to a blockchain and executed by a replicated network of computers. They translate agreed rules into deterministic instructions: when specified conditions are satisfied, the program changes blockchain state. A decentralized application (dApp) combines such contracts with user interfaces, blockchain infrastructure, wallets, indexing services, and, where necessary, external data systems.

The significance of smart contracts lies not merely in automation. They provide shared execution and verification without requiring every participant to trust a single operator. However, they do not eliminate trust; instead, trust is redistributed among code, consensus protocols, key-management systems, data providers, governance mechanisms, and development teams. A defect in immutable code can be more consequential than a defect in conventional software because execution may be irreversible and financially valuable assets may be involved.

This chapter examines smart-contract architecture, virtual machines, oracles, events, dApp front ends and back ends, and the complete development lifecycle from requirements through maintenance and upgrading.

Learning Objectives

By the end of this chapter, students should be able to:

  1. Explain the architecture and execution model of smart contracts.
  2. Distinguish blockchain nodes, virtual machines, wallets, interfaces, indexers, and oracle systems.
  3. Explain transactions, calls, events, gas, state, and determinism.
  4. Design a secure dApp architecture and select appropriate data-flow patterns.
  5. Map requirements, testing, deployment, upgradeability, monitoring, and maintenance activities.
  6. Evaluate technical, economic, legal, ethical, and governance risks.

1. Smart-Contract Architecture

A smart contract has four related dimensions:

  • Code: functions, access-control rules, validation logic, and error handling.
  • State: persistent variables stored in blockchain storage, such as balances, ownership records, and configuration values.
  • Address: an identifier through which users and other contracts interact with it.
  • Execution context: information supplied by the blockchain, including the caller, transferred value, block information, and remaining computational resources.

A blockchain transaction is an authenticated request signed by a user or another authorized system. It may create a contract or invoke a state-changing function. Nodes validate the transaction, execute the relevant code, and reach consensus on the resulting state. A read-only call generally does not create a consensus transaction and can often be performed locally by a node or remote-provider service.

A useful distinction is between account-controlled actions and contract-controlled actions. An externally controlled account is operated through a private key. A contract account has code and state; it acts according to its programmed rules rather than possessing a private key. A user may call a contract, but the contract determines whether that request is valid.

State, storage, memory, and execution data

Persistent state is written to blockchain storage and is normally expensive because it increases the replicated data burden. Temporary memory exists only during execution. Call data contains input supplied with a transaction or message call. Logs are event records emitted during execution and are designed for off-chain observation; they are not a substitute for authoritative contract state.

The principle of checks-effects-interactions is a widely used pattern for reducing reentrancy risk:

  1. Check permissions and input conditions.
  2. Update internal state.
  3. Interact with external contracts or transfer assets.

For example, a withdrawal function should record that a balance has been withdrawn before calling an external recipient. A reentrancy guard may provide additional protection, but it should complement—not replace—correct state design.

Determinism and composability

Every validating node must obtain the same result from the same transaction and prior state. Contract code therefore cannot safely depend on local time, private databases, network responses, or random values that differ among nodes. Block timestamps and block metadata may be available, but they are not equivalent to a secure source of randomness.

Contracts can call other contracts, enabling composability. A lending contract may interact with a token contract, price oracle, collateral manager, and liquidation module. Composability creates powerful financial primitives but also creates dependency risk: an error or economic attack in one component can propagate through many applications.

Layered architecture of a decentralized application User interface and wallet RPC provider and application services Smart contracts and virtual machine Consensus network and blockchain state Read requests, signed transactions, events, indexed data and oracle inputs connect the layers.
Layered architecture of a decentralized application
Figure: Layered architecture of a decentralized application

Figure: A conceptual layered architecture for a decentralized application.

2. Virtual Machines and Gas

A blockchain virtual machine (VM) is the deterministic execution environment for contract bytecode. Developers commonly write in a higher-level language, compile the source into bytecode, and deploy that bytecode to the network. The VM defines available instructions, data types, error behavior, and resource accounting.

The Ethereum Virtual Machine (EVM), for example, uses a stack-based execution model and provides persistent storage, transient memory during execution, and an execution stack. Other ecosystems use different virtual machines and programming languages, but the general requirement remains the same: all participating validators must be able to reproduce execution.

Gas is a unit of computational work. It limits resource consumption and discourages denial-of-service attacks. A transaction’s fee is commonly represented conceptually as:

Transaction fee = gas used × effective price per gas unit

Gas used is the amount of execution resource consumed; the effective price is denominated in the network’s native currency per gas unit. The formula applies to a particular transaction under a particular network fee mechanism. It excludes any separate application-level fee and should not be confused with a fixed monetary price, because the currency exchange rate and network fee conditions vary.

A transaction may fail while still consuming gas because validators performed computation before discovering a failed condition. Developers should therefore validate inputs early and avoid unbounded loops. Contract design must account for worst-case execution cost, not merely the average case.

3. Transactions, Calls, and Events

A transaction is a signed request that can change blockchain state and normally requires network consensus. A read call asks for information without committing state changes. A front end often uses read calls to display balances and sends signed transactions only when the user approves an action.

An event is a structured log emitted by a contract. It typically contains a name and indexed or non-indexed fields. Events are useful for activity feeds, analytics, notifications, and indexers. For example, a token contract can emit a transfer event after balances change. Events improve observability, but the contract’s storage and validated execution remain authoritative. An event should not be emitted to claim that an action occurred before the action has successfully completed.

Logs have limitations. They may be unavailable to a contract during normal execution, and applications must handle chain reorganizations, duplicate observations, and finality assumptions. An indexer should record block number, transaction identifier, log position, and confirmation status so that it can reconcile its database with the chain.

4. Oracles and External Data

Blockchains are closed deterministic systems. An oracle supplies information from outside the chain, such as an asset price, weather measurement, exchange rate, or sports result. The oracle itself becomes a trust and security boundary.

An oracle architecture commonly includes:

  • data sources;
  • a collection and aggregation process;
  • signed or otherwise authenticated reports;
  • an on-chain verification contract;
  • freshness, deviation, and emergency controls.

A price feed should not be accepted merely because it is present. Contracts may check whether the value is recent, whether it lies within expected bounds, and whether enough independent reporters participated. Median or weighted aggregation can reduce the impact of one faulty source, but it does not guarantee truth. The choice of sources, weights, update frequency, and fallback behavior is a governance decision.

Oracle manipulation is especially dangerous in lending and derivatives systems. A protocol should analyze thin liquidity, stale prices, sudden deviations, delayed updates, and the effect of a temporary incorrect value. Circuit breakers, conservative collateral ratios, time-weighted prices, and paused markets may reduce losses, although each introduces trade-offs.

5. dApp Front Ends and Back Ends

A dApp front end is the user-facing application, commonly a web or mobile interface. It displays blockchain state, requests wallet connection, prepares transactions, estimates costs, presents permissions, and reports pending, successful, or failed outcomes. It should never ask users to expose private keys.

The front end commonly interacts with:

  • a wallet for identity and transaction signing;
  • an RPC endpoint for blockchain reads and transaction submission;
  • contract addresses and interface descriptions;
  • an indexer for efficient historical and relational queries;
  • application services for notifications, search, or analytics.

A dApp back end is not necessarily decentralized. It may include an indexer, database, API, identity service, content-delivery layer, monitoring system, and administrative service. The architectural question is which functions require consensus and public verifiability and which functions can remain off-chain for performance, privacy, or cost reasons.

A practical design classifies data as follows:

Data or functionSuitable locationMain reason
Ownership and settlementOn-chain contractShared, auditable authority
Search and historical viewsIndexer/databaseEfficient querying
Private user preferencesOff-chain storagePrivacy and flexibility
Large media filesDecentralized or conventional storageCost and capacity
Signatures and approvalsUser walletKey custody and consent
External pricesOracle mechanismDeterministic on-chain access

A common anti-pattern is placing a trusted centralized database in control of an application while describing the system as fully decentralized. Decentralization should be stated precisely: control, execution, data availability, governance, and infrastructure may have different degrees of decentralization.

6. The dApp Development Lifecycle

6.1 Requirements and threat modelling

Requirements should specify users, assets, permissions, invariants, failure behavior, governance powers, privacy expectations, supported networks, performance needs, and regulatory constraints. A useful invariant is a condition that must remain true after every successful state transition. Examples include “a user cannot withdraw more than the recorded balance” and “total issued supply equals the sum of authorized issuance changes.”

Threat modelling should identify asset flows, privileged roles, external calls, oracle dependencies, upgrade keys, denial-of-service possibilities, front-running, phishing, stolen credentials, and economic manipulation. The team should define assumptions explicitly—for example, whether a multisignature committee is trusted and what happens if it becomes unavailable.

6.2 Specification and design

The specification should define function behavior, state transitions, events, error conditions, access control, and gas-sensitive operations. State machines are useful for systems with stages such as proposed, approved, executed, cancelled, and expired.

Design decisions include:

  • role-based or capability-based authorization;
  • pull payments rather than unsolicited transfers where appropriate;
  • pausability and emergency recovery;
  • reentrancy protection;
  • safe handling of token standards and non-standard token behavior;
  • oracle validation;
  • limits on batch size and loops;
  • upgradeability or immutability;
  • transparency of administrator powers.

6.3 Implementation and testing

Development should use version control, reproducible builds, code review, static analysis, unit tests, integration tests, and deployment scripts. Tests should cover normal cases, boundary values, unauthorized calls, failed transfers, repeated calls, partial failures, malicious tokens, oracle outages, and unusual transaction ordering.

Important testing levels include:

  • Unit testing: individual functions and libraries.
  • Property-based testing: automatically generated inputs test general properties.
  • Fuzz testing: unexpected input sequences search for failures.
  • Integration testing: contracts interact with wallets, oracles, and other contracts.
  • Fork testing: behavior is tested against a copy of a live network state.
  • Economic testing: incentives, liquidation, slippage, and attack profitability are examined.
  • User-acceptance testing: real workflows and error messages are evaluated.

Formal verification can prove selected properties under a specified model, but it cannot prove that the requirements are morally, economically, or legally appropriate. An audit is an additional review, not a guarantee of safety.

6.4 Deployment and release management

Deployment should progress through local development, a public test network, staged production, and full release. Each deployment must record compiler version, source-code commit, configuration, contract addresses, network identifier, permissions, and verification status.

Before launch, teams should verify initialization, ownership transfer, oracle configuration, pause functions, upgrade controls, and monitoring alerts. Users should receive clear information about contract addresses, transaction risks, fees, and irreversible actions.

6.5 Upgradeability and governance

Immutable contracts reduce the risk of unilateral code changes but make defects difficult to correct. Upgradeable contracts provide flexibility through a proxy or modular architecture, but introduce administrative and technical risks.

A proxy pattern commonly separates:

  • an address holding user-facing state;
  • an implementation containing logic;
  • an administrator or governance process authorized to change the implementation.

Storage layout compatibility is essential. Changing variable order, type, or inheritance structure can corrupt state. Initializers must replace constructors where appropriate, and initialization must be protected against repeated execution.

Upgrade governance should define who can upgrade, required approvals, waiting periods, emergency powers, public notice, and the conditions for decentralizing or removing control. A multisignature wallet reduces dependence on one key but does not make a decision automatically legitimate. Timelocks allow users and monitoring systems time to respond, although emergencies may justify narrowly scoped pause powers.

6.6 Monitoring, incident response, and maintenance

Production maintenance includes monitoring events, failed transactions, unusual asset flows, oracle freshness, gas usage, administrative actions, and protocol invariants. Alerts should distinguish informational events from conditions requiring immediate intervention.

An incident plan should identify decision makers, communication channels, pause authority, evidence-preservation procedures, recovery options, and user-notification responsibilities. Teams should rehearse the plan. Post-incident analysis should address both the immediate defect and the organizational conditions that allowed it.

7. Worked Application: Illustrative Community Lending dApp

This fictional case illustrates design reasoning rather than a recommendation for production deployment.

Background and problem

A community wishes to lend a stable-value token against tokenized invoices. Borrowers need transparent collateral rules, while lenders need evidence that collateral cannot be withdrawn without repayment.

Analysis

The core authority must be on-chain: loan creation, collateral locking, repayment, and liquidation. Invoice documents contain private business information and therefore should not be placed directly on a public ledger. A price or valuation oracle is needed, but invoice valuation is difficult to automate and may require approved assessors.

Threats include oracle manipulation, borrower default, unauthorized assessor actions, reentrancy during repayment, and administrative key compromise. The protocol must specify what happens when an oracle is unavailable or an invoice is disputed.

Approach and solution

The system uses a collateral contract, a loan manager, a token contract, an assessor registry, and a price-oracle adapter. The front end displays loan terms and requests explicit wallet signatures. An indexer supplies searchable loan histories. Private invoice data is stored off-chain, while a cryptographic commitment or document hash can be recorded on-chain to support integrity checks.

The loan manager checks collateral value, loan-to-value limits, maturity, and repayment status. It updates state before external token calls. Assessors are governed by a multisignature committee with a timelocked change process. A pause function can stop new loans but cannot arbitrarily confiscate already settled assets.

Outcome

The design improves auditability and reduces reliance on a single database, but it does not remove valuation risk or legal questions concerning ownership and enforcement of invoices. The application remains dependent on assessors, oracle quality, wallet security, and governance.

Learning points

  1. Decentralization should be allocated according to the required trust model.
  2. Off-chain information needs an explicit integrity and availability strategy.
  3. Oracle and governance failures can be as serious as coding defects.
  4. Upgrade and emergency powers must be disclosed to users.
  5. Technical settlement does not itself establish legal ownership or enforceability.

8. Limitations, Ethics, and Regulation

Smart contracts can reduce ambiguity but cannot determine whether an agreement is socially fair. Automated liquidation may be technically valid yet harmful during volatile markets. Transparent ledgers may expose financial relationships and enable surveillance. Developers should minimize personal data, use privacy-preserving designs where appropriate, and explain what information is public and permanent.

Regulatory treatment varies by jurisdiction and may depend on the asset, service, marketing, custody arrangement, and degree of control. Anti-money-laundering, consumer-protection, securities, tax, data-protection, and financial-market rules may apply. Legal review should occur before deployment rather than after a product has acquired users.

Artificial intelligence can assist with code review, test generation, anomaly detection, and documentation. It must not be treated as an authority: generated code can contain subtle vulnerabilities, and confidential keys or proprietary data must not be submitted to unsuitable systems. Human review, reproducible builds, and independent testing remain necessary.

Best-Practice Checklist

  • Define the trust model and decentralization claims precisely.
  • Specify invariants, permissions, failure modes, and upgrade powers.
  • Minimize persistent storage and avoid unbounded computation.
  • Follow checks-effects-interactions and validate external-call results.
  • Use reputable oracle designs with freshness and fallback controls.
  • Treat events as observability records, not authoritative state.
  • Test adversarial sequences and economic incentives, not only happy paths.
  • Verify deployment configuration and source code.
  • Protect upgrade and pause keys with appropriate governance.
  • Monitor production behavior and rehearse incident response.
  • Communicate risks, fees, permanence, and administrative powers clearly.

Chapter Summary

Smart contracts are deterministic programs whose code and persistent state are replicated by a blockchain network. Virtual machines execute bytecode and use gas to meter computational resources. Transactions can change state, whereas read calls usually do not; events provide structured logs for off-chain observation. Oracles connect deterministic contracts to external information but create important trust and manipulation risks.

A dApp combines contracts with wallets, front ends, RPC services, indexers, storage, monitoring, and sometimes centralized back ends. Effective development proceeds from requirements and threat modelling through specification, implementation, testing, staged deployment, governance, upgrade management, monitoring, and incident response. Upgradeability offers flexibility at the cost of administrative and storage-layout risks. Security, privacy, ethics, regulation, and user communication are integral design concerns rather than post-launch additions.

Key Terms

Smart contract: A blockchain-resident program that executes rules and changes state.

Decentralized application: An application combining blockchain contracts with user and infrastructure components.

Virtual machine: A deterministic execution environment for contract bytecode.

Bytecode: Low-level instructions executed by a blockchain virtual machine.

State: Persistent data representing the current condition of contracts and accounts.

Transaction: A signed request that may change blockchain state.

Read call: A non-state-changing request for blockchain information.

Gas: A unit used to measure and price computational work.

Event: A structured contract log intended for off-chain observation.

Oracle: A mechanism that supplies external data to a blockchain.

RPC provider: A service or node interface used to submit requests to a blockchain.

Indexer: A system that organizes blockchain data for efficient application queries.

Reentrancy: An attack in which external execution re-enters a function before state is safely updated.

Invariant: A condition that should remain true across valid state transitions.

Upgradeability: The ability to change contract logic after deployment.

Proxy: An architectural component that delegates calls to an implementation contract.

Multisignature wallet: A wallet requiring approval from multiple authorized signers.

Timelock: A delay between approving and executing a privileged action.

Finality: The point at which a transaction is considered sufficiently irreversible under a network’s consensus assumptions.

Review Questions

Short Answer Questions

  1. What is the difference between a transaction and a read call?
  2. Why must smart-contract execution be deterministic?
  3. What role does an oracle perform?
  4. Why are events useful to dApp developers?
  5. State the three stages of checks-effects-interactions.

Long Answer Questions

  1. Explain the layered architecture of a dApp, including the roles of wallets, contracts, RPC providers, and indexers.
  2. Discuss the benefits and risks of upgradeable smart contracts.
  3. Describe a comprehensive testing strategy for a financial smart contract.
  4. Explain how oracle failure can affect a lending protocol and identify suitable mitigations.
  5. Describe the complete lifecycle from requirements analysis to production maintenance.

Analytical / Application Questions

  1. Design an architecture for a ticketing dApp in which ownership is public but customer contact information is private. Justify what belongs on-chain and off-chain.
  2. A contract transfers tokens to an external recipient before reducing the recipient’s recorded balance. Analyze the vulnerability and propose a safer sequence.
  3. A protocol’s price oracle stops updating during a market crash. Evaluate the possible outcomes and design an emergency and recovery policy.

Multiple Choice Questions with Answers

Question 1

Which component is primarily responsible for executing deployed smart-contract bytecode?

A. Blockchain virtual machine

B. Web browser

C. Indexing database

D. Multisignature wallet

Correct Answer: A. Blockchain virtual machine

Question 2

Which statement best describes gas?

A. A unit used to measure and price computational work

B. A private key used to sign transactions

C. A database containing user profiles

D. A guarantee that a transaction will succeed

Correct Answer: A. A unit used to measure and price computational work

Question 3

Why must smart-contract execution be deterministic?

A. So validating nodes can reach the same resulting state

B. So users never need wallets

C. So contracts can freely access private websites

D. So all transactions have identical fees

Correct Answer: A. So validating nodes can reach the same resulting state

Question 4

What is the principal purpose of an oracle?

A. To provide external data to a blockchain application

B. To replace the blockchain consensus mechanism

C. To store users’ private keys

D. To compile front-end code

Correct Answer: A. To provide external data to a blockchain application

Question 5

Which sequence reflects checks-effects-interactions?

A. Validate conditions, update state, then call external systems

B. Call external systems, display a message, then validate conditions

C. Update a database, ignore permissions, then emit an event

D. Emit an event, transfer funds, then decide whether the request is valid

Correct Answer: A. Validate conditions, update state, then call external systems

Question 6

What is a major limitation of blockchain events?

A. They are not a substitute for authoritative contract state

B. They can only be created by wallets

C. They permanently prevent chain reorganizations

D. They cannot contain structured fields

Correct Answer: A. They are not a substitute for authoritative contract state

Question 7

Which component is generally best suited to provide efficient historical search over blockchain activity?

A. An indexer

B. A private key

C. A compiler

D. A pause modifier

Correct Answer: A. An indexer

Question 8

What is a significant risk of upgradeable proxy contracts?

A. Incompatible storage layouts can corrupt persistent state

B. They cannot emit events

C. They eliminate all governance requirements

D. They make testing unnecessary

Correct Answer: A. Incompatible storage layouts can corrupt persistent state

Question 9

Which activity belongs most directly to threat modelling?

A. Identifying privileged roles, external dependencies, and attack paths

B. Choosing a website color palette

C. Removing all event logs

D. Assuming administrators cannot be compromised

Correct Answer: A. Identifying privileged roles, external dependencies, and attack paths

Question 10

Why should a production dApp monitor administrative actions and oracle freshness?

A. To detect governance or data failures that may threaten users and assets

B. To ensure every user has the same browser

C. To make private keys public

D. To avoid writing any tests

Correct Answer: A. To detect governance or data failures that may threaten users and assets

Web3, DeFi & Blockchain Applications
Chapter 4 of 15