Smart Contracts and Money - Code as Financial Law
Learning Objectives
Explain how smart contracts work at a conceptual level, including state machines, determinism, and execution environments
Identify what smart contracts can do well (escrow, conditional logic, automated workflows) and what they cannot do (access external data directly, force real-world compliance, exercise judgment)
Analyze the oracle problem and evaluate different oracle solutions for programmable money applications
Assess smart contract security risks using real exploit case studies and understand why billions have been lost
Evaluate appropriate smart contract complexity for different programmable money use cases
In 2016, a piece of code called "The DAO" (Decentralized Autonomous Organization) held $150 million worth of cryptocurrency. The code had a bug. An attacker exploited that bug and drained $60 million before being stopped. The code executed exactly as written—but not as intended.
This incident crystallized a fundamental truth about smart contracts: code is law, not justice. The smart contract did precisely what the code specified. The problem was that the code didn't specify what the authors meant.
This lesson explores the power and peril of smart contracts as the foundation for programmable money. The technology enables unprecedented automation of financial agreements. But it also introduces new risks that traditional finance doesn't face—risks that have already cost billions and will continue to cause losses as programmable money expands.
Understanding both the capability and the limitations is essential for realistic assessment of programmable money's potential.
- Has defined states (possible conditions)
- Responds to inputs (transactions, messages)
- Transitions between states according to rules
- Produces outputs based on current state and inputs
Example: Simple Escrow Contract
AWAITING_PAYMENT: Initial state, waiting for buyer to deposit
AWAITING_DELIVERY: Buyer deposited, waiting for delivery confirmation
COMPLETE: Delivery confirmed, seller paid
REFUNDED: Dispute resolved in buyer's favor
deposit() → AWAITING_PAYMENT → AWAITING_DELIVERY
confirmDelivery() → AWAITING_DELIVERY → COMPLETE (sends funds to seller)
dispute() → AWAITING_DELIVERY → [arbitration process]
refund() → [after arbitration] → REFUNDED (sends funds to buyer)
- Its current state
- The input received (function called, parameters provided)
- The transition rules (code)
There's no discretion, no judgment, no context beyond what's programmed. This determinism is both the power and the limitation.
Smart contracts must be deterministic—given the same inputs, they must always produce the same outputs. This is essential for distributed systems where multiple validators must agree on results.
Why determinism matters:
If Node A executes contract and gets Result X
And Node B executes same contract and gets Result Y
Then: The network cannot reach consensus—system breaks
Therefore: All operations must be deterministic
```
- Random number generation (different results each execution)
- Accessing current time directly (nodes might have different clocks)
- Reading external data (different nodes might get different values)
- Floating-point arithmetic (can produce different results on different hardware)
- Randomness: Derived from blockchain data (block hash) or external randomness sources
- Time: Use block numbers/timestamps agreed upon by consensus
- External data: Oracles provide data on-chain (Section 3)
- Math: Fixed-point arithmetic or integer-only operations
Smart contracts run in isolated execution environments that provide:
Contract can only access its own storage and explicitly provided data
Cannot read files, make network calls, or access system resources
Other contracts are accessed through defined interfaces
Every operation costs computational resources (gas on Ethereum)
Transactions specify maximum gas willing to spend
If gas runs out, transaction reverts (no partial execution)
Prevents infinite loops and resource exhaustion
Transactions either complete fully or not at all
No partial execution states
Failure reverts all changes
Prevents inconsistent states
- Gas budget specified (e.g., 100,000 gas)
- Contract code loaded
- Execution begins, consuming gas per operation
- If successful: State changes committed, remaining gas refunded
- If out of gas: All changes reverted, gas consumed
- If error: Reverted, gas consumed
Once deployed, smart contract code typically cannot be modified. The code you deploy is the code that runs—forever.
- Bugs cannot be patched by updating code
- "Upgradeable" contracts are possible but introduce trust assumptions
- Decisions made at deployment persist
- Testing is critical—there's no post-launch fix
- **Proxy contracts**: User interacts with proxy that delegates to implementation; implementation can be changed
- **Migration**: Deploy new contract, convince users to switch
- **Governance**: Community votes on changes (still requires architecture supporting changes)
Each pattern introduces trust: someone can change the code. This contradicts the "code is law" philosophy. Most production systems make pragmatic compromises, accepting some upgradeability to enable bug fixes and improvements.
1. Escrow and Conditional Release
Contract holds funds
Conditions specify when funds release
When conditions met: Automatic, trustless release
No intermediary needed
- Milestone-based payments (release 25% at each project phase)
- Atomic swaps (I give you X if and only if you give me Y)
- Time-locked releases (funds available after date)
2. Multi-Signature Requirements
Action requires M of N signatures
Contract verifies cryptographic signatures
Proceeds only when threshold met
- Organizational treasury (3 of 5 executives must approve)
- Recovery mechanisms (2 of 3 family members can recover funds)
- Security (attacker needs multiple keys)
3. Automated Payment Flows
Trigger events cause payments
No manual intervention needed
Guaranteed execution if conditions met
- Streaming payments (continuous per-second salary)
- Revenue sharing (automatic split of incoming funds)
- Subscription payments (recurring conditional transfers)
4. Programmable Financial Instruments
Complex financial logic encoded
Positions represented as tokens
Automatic rebalancing, liquidation, settlement
- Collateralized lending (automatic liquidation if ratio falls)
- Synthetic assets (tokens tracking external prices)
- Options and derivatives (automatic exercise conditions)
5. Transparent, Auditable Logic
Code visible to all participants
Execution verifiable by anyone
No hidden terms or discretionary changes
- Public financial protocols (anyone can verify DeFi rules)
- Governance (voting rules are publicly verifiable)
- Compliance (auditors can verify rule enforcement)
1. Access External Data Directly
Smart contract wants current ETH price
Contract cannot make HTTP request to price API
Contract can only read on-chain data
External data must be brought on-chain (oracles)
Why this matters:
Most useful conditions depend on real-world information—prices, weather, election results, delivery confirmations. Smart contracts are blind to all of this without oracles.
2. Force Real-World Compliance
Contract says: "Car title transfers when payment received"
Contract can: Release payment when triggered
Contract cannot: Physically give you the car
Contract cannot: Update DMV records
Contract cannot: Stop seller from driving away with both
Why this matters:
Smart contracts control digital assets on their platform. They cannot enforce anything in the physical world. "Smart contract for real estate" still requires legal system, courts, and physical enforcement.
3. Exercise Judgment
Contract has rule: "Payment if satisfactory work"
What is "satisfactory"?
Contract cannot: Evaluate subjective quality
Contract can only: Check binary conditions
Why this matters:
Human agreements often contain deliberately vague terms that rely on reasonable interpretation. Smart contracts cannot interpret—they can only evaluate precisely defined conditions.
4. Recover from Errors
Bug in code causes wrong execution
Traditional contract: Go to court, get remedy
Smart contract: Execution is final
Funds may be lost, stolen, or locked forever
Why this matters:
Traditional legal systems have error correction. Smart contracts execute exactly as coded, even if that's wrong. There's no court of appeals for code.
5. Adapt to Unforeseen Circumstances
Contract written for normal conditions
Black swan event occurs
Traditional contract: Force majeure, renegotiation
Smart contract: Executes as coded regardless
Why this matters:
Smart contracts are rigid. They can't account for circumstances not anticipated at coding time. This rigidity is a feature for simple conditions but a bug for complex agreements.
The core limitation: smart contracts eliminate discretion.
- Handling unforeseen circumstances
- Interpreting ambiguous language
- Providing mercy when strict enforcement causes injustice
- Adapting to changing contexts
- Consistency (same outcome every time)
- Speed (no deliberation needed)
- Cost reduction (no intermediary fees for judgment)
- Predictability (participants know exactly what will happen)
- Fairness (no adjustment for hardship)
- Adaptability (can't handle the unexpected)
- Context-sensitivity (binary conditions only)
- Error correction (mistakes are permanent)
For programmable money:
Simple, objective conditions (time, amount, balance checks) work well with smart contracts. Complex, subjective conditions (satisfactory performance, good faith, reasonable effort) don't translate to code.
Smart contracts can only access on-chain data. But useful programmable money often needs external information:
| Condition | External Data Needed | Oracle Required |
|---|---|---|
| "Pay if price > $100" | Current market price | Yes |
| "Release funds when delivered" | Delivery confirmation | Yes |
| "Insurance payout if flight delayed" | Flight status | Yes |
| "Adjust rate based on inflation" | CPI data | Yes |
| "Bonus if sales target met" | Sales figures | Yes |
- Time passed (block number)
- Balance thresholds
- Other contract states
- Transaction history
With oracles, programmable money can respond to real-world events—but at the cost of trust assumptions.
Oracles reintroduce trust:
Smart contract claim: "Trustless—code executes automatically"
Reality: Oracle operator can manipulate outcome
If oracle says "X happened" when X didn't → Contract executes wrongly
Oracle operator has power that code was supposed to eliminate
- Lending protocol uses oracle for collateral pricing
- Attacker manipulates oracle to report inflated price
- Protocol thinks collateral is worth more than it is
- Attacker borrows against inflated collateral
- Attacker drains protocol before price correction
This is not hypothetical—oracle attacks have stolen hundreds of millions.
- One entity provides data
- Simple but centralized
- Trust in operator required
- Suitable for private/enterprise settings
- Several oracles report same data
- Contract takes median or majority
- Harder to manipulate (need multiple conspirators)
- More expensive (multiple data sources)
- Many reporters stake tokens
- Majority answer wins
- Minority loses stake
- Economic incentive for truthfulness
- Network of independent oracle nodes
- Aggregation across multiple sources
- Reputation and staking for reliability
- Most widely used for DeFi
- Hardware guarantees oracle code execution
- Data fetched and processed in secure enclave
- Attestation proves correct execution
- Trust in hardware, not operators
All oracles involve trust—the question is who to trust:
| Oracle Type | Trust Assumption | Tradeoff |
|---|---|---|
| Single trusted | One entity honest | Centralized, efficient |
| Multi-sig | Majority honest | Semi-decentralized |
| Schelling | Economic incentive > manipulation cost | Game-theoretically sound, complex |
| Chainlink | Network majority honest, staking sufficient | Popular, not fully decentralized |
| TEE | Hardware secure, manufacturer honest | Hardware trust required |
Key insight
The oracle doesn't eliminate trust—it shifts and distributes it. For programmable money at scale, oracle reliability is critical infrastructure. A CBDC depending on oracles for monetary policy would be trusting oracle operators with monetary policy power.
Smart contract exploits have caused billions in losses:
| Year | Notable Exploits | Approximate Losses |
|---|---|---|
| 2016 | The DAO | $60M |
| 2020 | Multiple DeFi | $500M+ |
| 2021 | Poly Network, Cream, Compound | $1B+ |
| 2022 | Ronin, Wormhole, Nomad | $2B+ |
| 2023 | Euler, Multichain | $500M+ |
| 2024 | Various | Hundreds of millions |
Cumulative losses: $5-10+ billion
These aren't user errors or phishing—they're exploits of the contract code itself.
1. Reentrancy Attacks
The vulnerability that drained The DAO. When a contract calls an external contract, the external contract can call back before the first call completes.
- User requests withdrawal
- Contract sends funds (external call)
- Before recording withdrawal, attacker reenters
- Attacker repeats withdrawal (balance not yet updated)
- Attacker drains contract
The DAO lost $60M this way
```
2. Integer Overflow/Underflow
Before Solidity 0.8, arithmetic didn't check for overflow:
uint8 max = 255
255 + 1 = 0 (overflow wraps around)
0 - 1 = 255 (underflow wraps around)
Exploit: Make balance underflow to maximum value
3. Flash Loan Attacks
- Borrow $100M (flash loan, no collateral)
- Use funds to manipulate low-liquidity oracle
- Trigger protocol action based on manipulated price
- Profit from manipulation
- Repay loan with profit
- Single transaction—if any step fails, all reverts
4. Logic Errors
Simple bugs in business logic:
Intended: Only admin can withdraw
Actual: Anyone can call withdraw function (missing check)
Intended: Require collateral > debt
Actual: Code checks collateral > 0 (wrong comparison)
5. Access Control Failures
Wrong permissions on critical functions:
function setAdmin(address _admin) public {
admin = _admin; // No access control!
// Anyone can make themselves admin
}
Case Study 1: The DAO (2016, $60M)
The DAO was a decentralized investment fund
Reentrancy vulnerability in withdrawal function
Attacker repeatedly withdrew before balance updated
Drained $60M before community response
Ethereum hard forked to reverse the theft
Created Ethereum Classic (fork that didn't reverse)
Demonstrated that "code is law" has limits when losses are large enough
Even heavily funded, reviewed code can have bugs
Reentrancy is subtle and dangerous
Community may override "code is law" for major incidents
Case Study 2: Wormhole (2022, $320M)
Wormhole is a cross-chain bridge
Bug in signature verification allowed fake deposits
Attacker minted tokens without depositing collateral
Extracted $320M in Ethereum
Jump Crypto (Wormhole backer) replaced the funds
Attacker (now known) negotiated partial return
Bridge rebuilt with additional security
Cross-chain bridges are high-risk attack surfaces
Verification logic is critical and subtle
Even "audited" code can have critical bugs
Case Study 3: Euler Finance (2023, $197M)
Logic error in health factor calculation
Attacker could create under-collateralized position
Drained lending pools
Attacker negotiated return of most funds
Protocol rebuilt with improved auditing
Demonstrated that negotiation sometimes works
Complex financial logic creates subtle bugs
Even established DeFi protocols are vulnerable
White-hat negotiation as incident response
- Stakes are too high for complex smart contracts
- Simple, heavily audited logic preferred
- Likely to limit programmability to avoid bugs
- Central authority can intervene if problems arise
- Smart contract bugs can break the peg
- Centralized control provides safety net
- Decentralized stablecoins have higher risk
- "Move fast and break things" means real losses
- Security audits help but don't eliminate risk
- Insurance and risk management becoming standard
- Expect continued hacks as complexity increases
- Hooks are deliberately limited to reduce attack surface
- Less programmability = fewer vulnerabilities
- Conservative design choice for payment focus
- Tradeoff: Less capability, more security
More complexity → More code → More potential bugs → More attack surface
Simple contract: Few lines, limited functionality, easier to secure
Complex contract: Many lines, rich functionality, hard to secure
```
- Lines of code correlate with bug count
- Bug density (bugs per 1000 lines) roughly constant
- More features = more bugs = more exploits
- Basic payment conditions (time locks, thresholds)
- Simple multi-sig
- Straightforward escrow
- CBDC retail payments
- Trade finance with document verification
- Collateralized lending
- Automated market making
- Complex revenue sharing
- Derivatives and options
- Complex DeFi protocols
- Cross-chain bridges
- DAO governance
Key question: Does the use case justify the risk of complexity?
- Begin with minimal viable conditions
- Add complexity only when proven necessary
- Resist feature creep
- Simple contracts that interact
- Each component auditable independently
- Complexity emerges from combination, not single contracts
- Fewer functions = fewer attack vectors
- Minimal external calls
- Carefully controlled permissions
- Pause mechanisms for emergencies
- Upgrade paths (with appropriate governance)
- Recovery procedures documented
- Multiple security layers
- Audits + formal verification + bug bounties + monitoring
- Assume each layer might fail
XRPL deliberately limits programmability:
Intercept transactions
Apply conditions (approve/reject)
Modify transaction behavior within limits
Emit transactions
Arbitrary loops (bounded only)
Complex state management
Recursive calls
Turing-complete computation
Smaller attack surface than Ethereum
Easier to audit and verify
Optimized for payment conditions, not general computing
Security prioritized over flexibility
This is a legitimate architectural choice—security over capability. For payment-focused programmable money, XRPL's approach may be more appropriate than Ethereum's maximum flexibility.
✅ Smart contracts can automate financial logic reliably: Billions flow through DeFi daily with contracts executing as intended.
✅ Security failures are common and costly: $5-10B+ in losses demonstrates real, ongoing risk.
✅ The oracle problem is fundamental: External data requires trust that smart contracts were supposed to eliminate.
✅ Complexity correlates with risk: Simpler contracts are easier to secure; complex protocols get exploited.
⚠️ Whether security will improve faster than attack sophistication: Auditing, formal verification, and bug bounties are improving, but so are attackers.
⚠️ Appropriate complexity level for CBDCs: Central banks may be too conservative or too aggressive—we don't know yet.
⚠️ Whether oracle solutions are sufficient for programmable money at scale: Current solutions work for DeFi; unclear for national-scale CBDCs.
⚠️ How insurance and risk management will evolve: Still early for smart contract insurance and structured risk management.
📌 Assuming "audited" means "secure": Audited contracts get hacked regularly.
📌 Over-engineering programmable money: More features mean more bugs; simpler is safer.
📌 Trusting oracles blindly: Oracle manipulation is a major attack vector.
📌 "Code is law" absolutism: When code has bugs, pure "code is law" means accepting losses.
Smart contracts provide genuine capability for automating financial agreements—a real innovation for programmable money. But they also introduce new risks that traditional finance doesn't face: bugs that steal billions, oracles that reintroduce trust, and rigidity that can cause injustice.
For programmable money, the question isn't whether to use smart contracts but how much complexity is appropriate. CBDCs will likely use minimal programmability—simple, heavily audited logic. DeFi will continue pushing complexity boundaries, accepting hacks as cost of innovation. XRP/XRPL's constrained approach may be most appropriate for payment-focused applications.
Analyze smart contract risks for programmable money applications and develop a risk framework for evaluating implementations.
Part 1: Exploit Analysis (35%)
- Select one from each category: DeFi lending, bridge/cross-chain, and other
- For each exploit, document:
Part 2: Risk Framework Development (40%)
Create a framework for evaluating smart contract risk in programmable money:
Code Risk
Oracle Risk (if applicable)
Operational Risk
Economic Risk
- Define specific indicators to assess
- Create rating scale (1-5 or Low/Medium/High)
- Specify red flags that indicate high risk
- Identify best practices that reduce risk
Part 3: Application (25%)
- One DeFi protocol handling significant value
- XRPL Hooks (based on architecture, not specific application)
Document ratings and reasoning for each category.
- Depth of exploit analysis (25%)
- Comprehensiveness of framework (30%)
- Practical applicability of framework (20%)
- Quality of application analysis (15%)
- Writing clarity (10%)
4-5 hours
This framework becomes a tool for evaluating any programmable money implementation's smart contract risk. As CBDCs, stablecoins, and DeFi protocols proliferate, the ability to assess risk distinguishes sophisticated analysts.
A company wants to use a smart contract to automatically enforce "satisfactory completion" of a consulting engagement before releasing payment. What is the fundamental limitation they face?
A) Smart contracts cannot handle payment release conditions
B) Smart contracts cannot evaluate subjective conditions like "satisfactory" without a trusted oracle or predefined objective criteria
C) Smart contracts are too slow for business applications
D) Smart contracts cannot handle payments larger than certain thresholds
Correct Answer: B
Explanation: Smart contracts can only evaluate precisely defined, objective conditions. "Satisfactory" is subjective—different people might disagree on whether work meets the standard. The contract would need either: (1) a trusted oracle (person or system) to certify satisfaction, which reintroduces trust, or (2) objective criteria (delivered by date, passed tests, met specifications) that don't fully capture "satisfactory." This is the judgment gap—smart contracts cannot exercise discretion.
A CBDC implements a programmable feature that adjusts interest rates based on inflation. The inflation data comes from a government statistics agency that feeds data on-chain. What is the primary risk this introduces?
A) The blockchain cannot process inflation data
B) Inflation data is too volatile for smart contracts
C) Trust in the statistics agency becomes trust in the monetary policy—the oracle operator can manipulate monetary outcomes
D) Smart contracts cannot perform interest rate calculations
Correct Answer: C
Explanation: By depending on the statistics agency's data feed, the CBDC trusts that agency with effective monetary policy power. If the oracle (statistics agency) reports manipulated inflation data, the smart contract will execute based on false information. The code executes correctly—but with incorrect inputs, producing incorrect outputs. This is the oracle problem: external data reintroduces trust that smart contracts were supposed to eliminate. The statistics agency becomes a critical trusted component of monetary policy.
An Ethereum DeFi protocol has suffered multiple exploits despite audits. The team proposes moving to XRPL Hooks for better security. What is the most accurate assessment of this tradeoff?
A) XRPL Hooks are universally more secure than Ethereum smart contracts for all applications
B) XRPL Hooks have deliberately limited programmability which reduces attack surface, but this means the protocol may not be able to implement all its current features
C) Ethereum exploits are due to the blockchain, not the smart contracts, so changing platforms won't help
D) XRPL has no security risks because Hooks are new technology
Correct Answer: B
Explanation: XRPL Hooks are deliberately constrained—no Turing-complete computation, bounded loops, limited state management. This reduces attack surface (simpler code, fewer vulnerability types) but also limits capability. A complex DeFi protocol might not be implementable with Hooks' constraints. The tradeoff is security vs. functionality. Option A overstates (Hooks aren't universally better—just different tradeoffs). Option C misattributes exploits (most are contract bugs, not blockchain issues). Option D is naïve (all technology has risks; newness adds uncertainty).
In the context of smart contract security, what makes reentrancy attacks possible?
A) Smart contracts running out of gas before completing execution
B) When a contract makes an external call, the called contract can call back into the original contract before the original transaction completes
C) Oracle data being delayed between transactions
D) Users submitting transactions too quickly
Correct Answer: B
Explanation: Reentrancy occurs when Contract A calls Contract B, and Contract B (or another contract it calls) calls back into Contract A before Contract A's original function completes. If Contract A updates its state after the external call, the reentering call sees the pre-update state. Classic example: Contract sends funds before marking withdrawal as complete—attacker reenters and withdraws again, repeatedly. The DAO lost $60M to reentrancy. This is why "checks-effects-interactions" pattern exists—update state before external calls.
A central bank is designing a retail CBDC with spending category restrictions (e.g., food, entertainment, utilities). Based on smart contract security considerations, what approach would minimize risk?
A) Implement all category logic in a single comprehensive smart contract for efficiency
B) Use Turing-complete smart contracts to enable future flexibility
C) Implement simple, heavily audited category checking with minimal on-chain logic and clear, objective category definitions
D) Avoid any programmability since all smart contracts are insecure
Correct Answer: C
Explanation: For a national-scale CBDC, security is paramount. Simple logic with minimal on-chain execution reduces attack surface. Heavy auditing of limited code is more effective than lighter auditing of extensive code. Objective category definitions avoid the judgment problem. Option A (comprehensive single contract) increases complexity and risk. Option B (Turing-complete) adds unnecessary capability and attack surface. Option D (no programmability) throws away the feature entirely—overly conservative. The goal is minimal complexity for the required functionality.
- Buterin, V. (2014). "Ethereum White Paper" - Original smart contract platform
- Szabo, N. (1997). "Formalizing and Securing Relationships on Public Networks" - Original smart contract concept
- Trail of Bits. "Not So Smart Contracts" - Repository of common vulnerabilities
- OpenZeppelin. "Security Best Practices" - Industry-standard guidelines
- Consensys Diligence. "Ethereum Smart Contract Best Practices" - Comprehensive security resource
- rekt.news - Chronicle of DeFi exploits
- Chainlink Documentation. "Introduction to Data Feeds" - Leading oracle solution
- Peterson, J. et al. (2015). "Augur: A Decentralized Oracle and Prediction Market Platform"
- Gemini. "The DAO Hack Explained" - Detailed DAO hack analysis
- Certik Blog. Various post-mortems of major exploits
For Next Lesson:
We'll explore the economics of programmable money—how programmability affects monetary policy transmission, creates new efficiency opportunities, enables financial inclusion (or exclusion), and redistributes power between money issuers and holders.
End of Lesson 4
Total words: ~5,400
Estimated completion time: 55 minutes reading + 4-5 hours for deliverable
- Previous: Lesson 3 - Technical Architectures for Programmable Money
- Next: Lesson 5 - The Economics of Programmable Money
- Course Overview: Course 64 - Future of Programmable Money
- Track: CBDC (Capstone Course)
Key Takeaways
Smart contracts are deterministic state machines
: They execute exactly as coded—no more, no less. This provides consistency and automation but eliminates discretion and judgment.
Smart contracts excel at objective, on-chain conditions
: Escrow, multi-sig, time locks, and balance checks work well. Subjective conditions (quality, reasonableness) and external data (prices, events) require additional infrastructure.
The oracle problem reintroduces trust
: External data requires oracles, and oracles require trusting someone. This doesn't eliminate the need for trust—it shifts and distributes it.
Security is an unsolved problem at scale
: Billions have been lost to smart contract exploits. Audits, formal verification, and bug bounties help but don't eliminate risk. Complexity increases attack surface.
Appropriate complexity depends on use case
: CBDCs should use simple, heavily audited logic. Complex DeFi accepts higher risk for more functionality. XRPL's deliberately limited Hooks represent a security-first approach. ---