diff --git a/docs/cardano/uplc/_category_.json b/docs/cardano/uplc/_category_.json
new file mode 100644
index 0000000..5860169
--- /dev/null
+++ b/docs/cardano/uplc/_category_.json
@@ -0,0 +1,6 @@
+{
+ "label": "Untyped Plutus Core (UPLC)",
+ "position": 1,
+ "collapsible": true,
+ "collapsed": false
+}
\ No newline at end of file
diff --git a/docs/cardano/uplc/builtin-functions.md b/docs/cardano/uplc/builtin-functions.md
new file mode 100644
index 0000000..7b0a5ef
--- /dev/null
+++ b/docs/cardano/uplc/builtin-functions.md
@@ -0,0 +1,262 @@
+---
+title: Built-in Functions
+sidebar_position: 4
+---
+
+# Built-in Functions
+
+Built-in functions are the computational workhorses of UPLC. These natively implemented operations provide efficient implementations of common operations that would be impossible or prohibitively expensive to implement in pure UPLC.
+
+---
+
+## Why Built-ins Matter
+
+Built-in functions exist for three critical reasons:
+
+1. **Performance**: Native implementations are orders of magnitude faster than UPLC equivalents
+2. **Capabilities**: Some operations (like cryptographic functions) require system-level access
+3. **Cost Predictability**: Fixed costs for built-ins make transaction fees calculable
+
+Every built-in has a precisely defined cost model, ensuring that transaction fees remain predictable regardless of network conditions.
+
+---
+
+## Arithmetic Operations
+
+### Integer Arithmetic
+
+UPLC provides standard arithmetic operations for its arbitrary-precision integers:
+
+```
+addInteger : integer -> integer -> integer
+subtractInteger : integer -> integer -> integer
+multiplyInteger : integer -> integer -> integer
+divideInteger : integer -> integer -> integer
+quotientInteger : integer -> integer -> integer
+remainderInteger : integer -> integer -> integer
+modInteger : integer -> integer -> integer
+```
+
+The distinction between `divideInteger`, `quotientInteger`, and `modInteger` follows mathematical conventions:
+- `divideInteger` performs truncated division toward negative infinity
+- `quotientInteger` truncates toward zero
+- `remainderInteger` gives the remainder after `quotientInteger`
+- `modInteger` gives the remainder after `divideInteger`
+
+### Integer Comparison
+
+Comparison operations return boolean values:
+
+```
+equalsInteger : integer -> integer -> bool
+lessThanInteger : integer -> integer -> bool
+lessThanEqualsInteger : integer -> integer -> bool
+```
+
+You can derive other comparisons from these primitives. For example, "greater than" is just "less than" with swapped arguments.
+
+---
+
+## String and Bytestring Operations
+
+### String Manipulation
+
+```
+appendString : string -> string -> string
+equalsString : string -> string -> bool
+encodeUtf8 : string -> bytestring
+```
+
+String operations are limited because strings are intended for human-readable data, not computation. Most text processing should happen off-chain.
+
+### Bytestring Operations
+
+```
+appendByteString : bytestring -> bytestring -> bytestring
+consByteString : integer -> bytestring -> bytestring
+sliceByteString : integer -> integer -> bytestring -> bytestring
+lengthOfByteString : bytestring -> integer
+indexByteString : bytestring -> integer -> integer
+equalsByteString : bytestring -> bytestring -> bool
+lessThanByteString : bytestring -> bytestring -> bool
+lessThanEqualsByteString : bytestring -> bytestring -> bool
+```
+
+Bytestrings support more operations because they're the primary type for binary data manipulation. The `consByteString` function prepends a single byte (as an integer 0-255) to a bytestring.
+
+### Conversion
+
+```
+decodeUtf8 : bytestring -> string
+```
+
+This function can fail if the bytestring contains invalid UTF-8 sequences, making it one of the few built-ins that can cause runtime errors beyond type mismatches.
+
+---
+
+## Cryptographic Functions
+
+### Hash Functions
+
+UPLC supports three cryptographic hash functions, each producing a fixed-size bytestring output:
+
+```
+sha2_256 : bytestring -> bytestring -- 32 bytes output
+sha3_256 : bytestring -> bytestring -- 32 bytes output
+blake2b_256 : bytestring -> bytestring -- 32 bytes output
+blake2b_224 : bytestring -> bytestring -- 28 bytes output
+keccak_256 : bytestring -> bytestring -- 32 bytes output
+```
+
+These functions are essential for verifying data integrity and implementing cryptographic protocols.
+
+### Digital Signatures
+
+UPLC supports three signature schemes used across the blockchain ecosystem:
+
+```
+verifyEd25519Signature : bytestring -> bytestring -> bytestring -> bool
+verifyEcdsaSecp256k1Signature : bytestring -> bytestring -> bytestring -> bool
+verifySchnorrSecp256k1Signature : bytestring -> bytestring -> bytestring -> bool
+```
+
+All signature verification functions take three arguments:
+1. Public key (as bytestring)
+2. Message (as bytestring)
+3. Signature (as bytestring)
+
+They return `True` if the signature is valid, `False` otherwise. These functions never throw errors—invalid inputs simply return `False`.
+
+---
+
+## Data Structure Operations
+
+### List Operations
+
+```
+headList : list -> a
+tailList : list -> list
+nullList : list -> bool
+mkCons : a -> list -> list
+```
+
+These functions provide basic list manipulation. Note that `headList` and `tailList` will error on empty lists—always check with `nullList` first when the list might be empty.
+
+### Pair Operations
+
+```
+fstPair : pair -> a
+sndPair : pair -> b
+mkPairData : data -> data -> pair
+```
+
+Pair access is constant time, making pairs efficient for fixed-size data structures.
+
+### Data Type Conversions
+
+```
+iData : integer -> data
+unIData : data -> integer
+bData : bytestring -> data
+unBData : data -> bytestring
+constrData : integer -> list -> data
+unConstrData : data -> pair>
+mapData : list> -> data
+unMapData : data -> list>
+listData : list -> data
+unListData : data -> list
+equalsData : data -> data -> bool
+```
+
+These functions convert between UPLC's primitive types and the Data type used for datum and redeemer values. The `un*` versions will error if given Data of the wrong constructor type.
+
+---
+
+## Control Flow
+
+### Conditional Execution
+
+```
+ifThenElse : bool -> a -> a -> a
+```
+
+This is UPLC's only branching primitive. Both branches are provided as arguments, but only the selected branch is evaluated (lazy evaluation).
+
+### Error Handling
+
+```
+trace : string -> a -> a
+```
+
+The `trace` function outputs a string (for debugging) and returns its second argument. In production, traces are typically disabled for efficiency. When enabled, trace outputs appear in transaction validation logs.
+
+---
+
+## Special Operations
+
+### Type-Level Operations
+
+```
+chooseUnit : unit -> a -> a
+chooseList : list -> b -> b -> b
+chooseData : data -> a -> a -> a -> a -> a -> a
+```
+
+These functions provide type-case analysis, branching based on the shape of data structures. They're primarily used in generic programming patterns.
+
+### Serialization
+
+```
+serialiseData : data -> bytestring
+```
+
+Converts Data values to their canonical CBOR encoding. This is essential for computing hashes of structured data in a deterministic way.
+
+---
+
+## Working with Built-ins
+
+When using built-in functions, remember:
+
+1. **Type Sensitivity**: Built-ins enforce their type signatures strictly. Type mismatches cause immediate validation failure.
+
+2. **Cost Awareness**: Each built-in has a specific cost. Cryptographic operations are expensive; simple arithmetic is cheap.
+
+3. **Error Behavior**: Most built-ins that can fail (like `unIData` or `headList`) do so immediately. There's no error recovery.
+
+4. **Evaluation Order**: Built-ins evaluate their arguments left-to-right before executing.
+
+---
+
+## Example: Signature Verification
+
+Here's a complete example verifying an Ed25519 signature:
+
+```
+(program 2.0.0
+ (lam pubKey
+ (lam message
+ (lam signature
+ [ [ [ (builtin verifyEd25519Signature) pubKey ] message ] signature ]
+ )
+ )
+ )
+)
+```
+
+This program takes three bytestring arguments and returns a boolean indicating signature validity.
+
+---
+
+## Performance Guidelines
+
+For optimal performance:
+
+- **Minimize cryptographic operations**: They're the most expensive built-ins
+- **Prefer bytestrings over strings**: Bytestring operations are more efficient
+- **Use arithmetic sparingly**: Each operation has a cost
+- **Batch operations when possible**: Reduce the total number of built-in calls
+
+Understanding built-in functions and their costs is essential for writing efficient smart contracts that minimize transaction fees while maintaining security and correctness.
+
+---
\ No newline at end of file
diff --git a/docs/cardano/uplc/data-types.md b/docs/cardano/uplc/data-types.md
new file mode 100644
index 0000000..3788273
--- /dev/null
+++ b/docs/cardano/uplc/data-types.md
@@ -0,0 +1,176 @@
+---
+title: Data Types
+sidebar_position: 3
+---
+
+# Data Types
+
+UPLC supports seven primitive data types that form the foundation of all on-chain computations. Understanding these types and their behavior is crucial for writing efficient smart contracts and debugging validation failures.
+
+---
+
+## The Type System Paradox
+
+Despite being called "Untyped" Plutus Core, UPLC values are implicitly typed. The "untyped" designation means there's no compile-time type checking—types are erased from the high-level language during compilation. However, at runtime, operations still expect specific types and will fail if given incompatible values.
+
+This design keeps on-chain execution simple and predictable while pushing type safety to the compilation phase where it doesn't cost transaction fees.
+
+---
+
+## Primitive Types
+
+### Unit
+
+The unit type represents the absence of meaningful data, similar to `void` in other languages. It has exactly one value: `()`.
+
+```
+(con unit ())
+```
+
+Unit is commonly used as the return type for validator scripts, where success is indicated by returning `()` and failure by producing an error.
+
+### Boolean
+
+Booleans represent truth values with exactly two possible values:
+
+```
+(con bool True)
+(con bool False)
+```
+
+Boolean values are essential for conditional logic, particularly with the `ifThenElse` built-in function.
+
+### Integer
+
+Integers in UPLC are arbitrary-precision signed numbers. There's no overflow or underflow—numbers can grow as large as memory allows.
+
+```
+(con integer 42)
+(con integer -1000000000000)
+(con integer 0)
+```
+
+This arbitrary precision is crucial for financial calculations where rounding errors or overflow could have serious consequences.
+
+### Bytestring
+
+Bytestrings represent sequences of bytes, typically used for cryptographic operations, hashes, and binary data. In the textual representation, they're written as hexadecimal with a `#` prefix:
+
+```
+(con bytestring #48656c6c6f) -- "Hello" in ASCII
+(con bytestring #) -- Empty bytestring
+(con bytestring #deadbeef) -- Arbitrary hex data
+```
+
+Each pair of hexadecimal digits represents one byte. Bytestrings are the primary type for cryptographic operations like hashing and signature verification.
+
+### String
+
+Strings are UTF-8 encoded text, distinct from bytestrings:
+
+```
+(con string "Hello, World!")
+(con string "") -- Empty string
+(con string "Unicode: 🎉") -- Full UTF-8 support
+```
+
+While strings are more convenient for human-readable data, they're less efficient than bytestrings for most on-chain operations. Convert between strings and bytestrings using the `encodeUtf8` and `decodeUtf8` built-ins when needed.
+
+### Pair
+
+Pairs combine exactly two values of potentially different types. They're the building block for more complex data structures:
+
+```
+(con pair (42, True))
+(con pair ("key", #616263))
+(con pair , string> ((1, 2), "label"))
+```
+
+The type annotation `` is required in the textual representation to maintain parsing unambiguity. Access pair elements using the `fstPair` and `sndPair` built-in functions.
+
+### List
+
+Lists are homogeneous sequences where all elements share the same type:
+
+```
+(con list [1, 2, 3, 4, 5])
+(con list ["apple", "banana", "cherry"])
+(con list []) -- Empty list
+(con list > [(1, "one"), (2, "two")])
+```
+
+Lists support recursive operations through built-ins like `headList`, `tailList`, and `nullList`. They're the primary collection type for processing multiple values.
+
+---
+
+## The Data Type
+
+Beyond the seven primitive types, UPLC includes a special `Data` type that serves as a universal container. Data can encode any UPLC value into a standard format used for:
+
+- Datum and redeemer values in transactions
+- Script context information
+- Serialization between on-chain and off-chain code
+
+The Data type has five constructors:
+
+```
+Constr Integer [Data] -- Constructor with tag and fields
+Map [(Data, Data)] -- Associative array
+List [Data] -- Homogeneous list
+I Integer -- Integer value
+B ByteString -- Bytestring value
+```
+
+Conversion between primitive types and Data happens through built-in functions:
+
+- `iData` / `unIData` for integers
+- `bData` / `unBData` for bytestrings
+- `constrData` / `unConstrData` for constructors
+- `mapData` / `unMapData` for maps
+- `listData` / `unListData` for lists
+
+---
+
+## Type Safety in Practice
+
+While UPLC doesn't check types at compile time, type mismatches cause runtime failures. For example:
+
+```
+[ (builtin addInteger) (con string "not a number") ] -- Runtime error!
+```
+
+This operation fails because `addInteger` expects integer arguments. The error manifests as transaction validation failure, costing the user transaction fees despite the failure.
+
+---
+
+## Memory and Performance Considerations
+
+Different types have different memory and computational costs:
+
+**Integers**: Size grows with the number's magnitude. Small integers are cheap; massive numbers require more memory and computation.
+
+**Bytestrings**: Cost scales linearly with length. Preferred for binary data and cryptographic operations.
+
+**Strings**: More expensive than bytestrings due to UTF-8 encoding overhead. Use bytestrings when possible.
+
+**Lists**: Linear traversal cost. Accessing the nth element requires traversing n-1 elements first.
+
+**Pairs**: Constant-time access to both elements. Useful for building efficient data structures.
+
+**Data**: Additional encoding/decoding overhead. Necessary for transaction integration but avoid unnecessary conversions.
+
+---
+
+## Best Practices
+
+When working with UPLC data types, follow these guidelines for optimal performance:
+
+1. Use bytestrings instead of strings for data that doesn't require text processing
+2. Prefer pairs over lists for fixed-size collections
+3. Minimize Data conversions—only convert when interfacing with transaction data
+4. Keep integers reasonably sized to control memory usage
+5. Structure data to minimize traversal operations
+
+Understanding these types and their trade-offs helps you write smart contracts that execute efficiently on-chain, saving both computation costs and transaction fees.
+
+---
\ No newline at end of file
diff --git a/docs/cardano/uplc/evaluation_model.md b/docs/cardano/uplc/evaluation_model.md
new file mode 100644
index 0000000..4ada915
--- /dev/null
+++ b/docs/cardano/uplc/evaluation_model.md
@@ -0,0 +1,274 @@
+---
+title: Evaluation Model
+sidebar_position: 5
+---
+
+# Evaluation Model
+
+Understanding how UPLC programs execute is essential for writing efficient smart contracts and diagnosing validation failures. UPLC uses a deterministic evaluation model that ensures every validator on the Cardano network reaches the same conclusion about transaction validity.
+
+---
+
+## The CEK Machine
+
+UPLC evaluation is based on the CEK machine—a well-studied abstract machine for evaluating lambda calculus. CEK stands for:
+
+- **C**ontrol: The current term being evaluated
+- **E**nvironment: Bindings from variables to values
+- **K**ontinuation: What to do with the result (the "call stack")
+
+This machine provides a precise, step-by-step evaluation strategy that balances efficiency with predictability.
+
+---
+
+## Evaluation Strategy
+
+UPLC uses call-by-value evaluation with the following key characteristics:
+
+### Strict Evaluation
+
+Arguments are fully evaluated before being passed to functions. When you see:
+
+```
+[ (lam x body) argument ]
+```
+
+The `argument` is completely evaluated to a value before substitution into `body`. This strictness ensures predictable cost models but means you can't create infinite data structures.
+
+### Left-to-Right Order
+
+In applications with multiple arguments:
+
+```
+[ [ f a ] b ]
+```
+
+Evaluation proceeds left-to-right:
+1. Evaluate `f` to a value
+2. Evaluate `a` to a value
+3. Apply `f` to `a`, getting a new function
+4. Evaluate `b` to a value
+5. Apply the result of step 3 to `b`
+
+### Environment and Closures
+
+When a lambda abstraction is evaluated, it captures its current environment, creating a closure:
+
+```
+(let x = 5 in (lam y (addInteger x y)))
+```
+
+The lambda captures `x = 5` in its closure, so it can access this binding even when applied elsewhere in the program.
+
+---
+
+## Reduction Rules
+
+The CEK machine applies these reduction rules until reaching a value or error:
+
+### Beta Reduction
+
+The fundamental rule of lambda calculus:
+
+```
+[ (lam x body) value ] → body[x := value]
+```
+
+This substitutes the value for all occurrences of `x` in `body`.
+
+### Built-in Application
+
+When a built-in function has all its arguments:
+
+```
+[ [ (builtin addInteger) 2 ] 3 ] → 5
+```
+
+The built-in executes its native implementation.
+
+### Force-Delay
+
+These operations handle suspended computations:
+
+```
+(force (delay term)) → term
+```
+
+Delay wraps a computation; force unwraps and evaluates it.
+
+### Error Propagation
+
+If any subterm evaluates to an error, the entire program fails:
+
+```
+[ f (error) ] → error
+```
+
+Errors cannot be caught or handled—they immediately terminate evaluation.
+
+---
+
+## Cost Model
+
+Every evaluation step has an associated cost, measured in two dimensions:
+
+### CPU Units
+
+Computational steps consume CPU units based on:
+- Term inspection and pattern matching
+- Environment lookups
+- Built-in function execution
+- Memory allocation for intermediate values
+
+### Memory Units
+
+Memory consumption tracks:
+- Size of values in the environment
+- Intermediate values during computation
+- Stack depth for nested applications
+
+The cost model is deterministic—the same program always consumes the same resources, regardless of the machine executing it.
+
+---
+
+## Execution Phases
+
+A complete UPLC execution follows these phases:
+
+### 1. Deserialization
+
+The binary UPLC encoding is parsed into the term structure. This happens once per script, with the result cached for multiple validations in the same transaction.
+
+### 2. Application of Arguments
+
+For validator scripts, three arguments are applied:
+1. Datum (from the UTxO being spent)
+2. Redeemer (from the transaction input)
+3. Script context (transaction details)
+
+Each application follows standard evaluation rules.
+
+### 3. Evaluation to Normal Form
+
+The CEK machine reduces the term until reaching either:
+- A value (success for validators returning `()`)
+- An error (validation failure)
+- Resource exhaustion (exceeding CPU or memory limits)
+
+### 4. Result Interpretation
+
+For validator scripts:
+- Returning `()` means the transaction is valid
+- Any error means validation failed
+- Resource exhaustion also causes failure
+
+---
+
+## Common Evaluation Patterns
+
+### Recursive Functions
+
+Without built-in recursion, UPLC uses the Y combinator pattern:
+
+```
+Y = λf. (λx. f (x x)) (λx. f (x x))
+```
+
+This creates fixed points, enabling recursive definitions. However, recursion is expensive—each recursive call adds to the evaluation cost.
+
+### Short-Circuit Evaluation
+
+The `ifThenElse` built-in only evaluates the selected branch:
+
+```
+[ [ [ (builtin ifThenElse) True ] expensive ] cheap ]
+```
+
+Here, `expensive` is never evaluated, saving resources.
+
+### Partial Application
+
+Built-ins can be partially applied:
+
+```
+(let addFive = [ (builtin addInteger) 5 ] in ...)
+```
+
+This creates reusable partially-applied functions without repeatedly specifying common arguments.
+
+---
+
+## Performance Optimization
+
+Understanding evaluation helps optimize smart contracts:
+
+### Minimize Evaluation Steps
+
+Every reduction step costs CPU units. Simplify expressions where possible:
+
+```
+-- Expensive: evaluates addInteger twice
+[ [ (builtin addInteger) [ [ (builtin addInteger) 1 ] 2 ] ] 3 ]
+
+-- Cheaper: pre-compute constants off-chain
+[ [ (builtin addInteger) 3 ] 3 ]
+```
+
+### Share Common Subexpressions
+
+Use let-bindings (or their desugared lambda form) to evaluate expensive expressions once:
+
+```
+(lam x
+ [ [ (builtin addInteger) x ] x ] -- x evaluated once, used twice
+)
+```
+
+### Avoid Deep Recursion
+
+Each recursive call increases memory usage. Use tail recursion or accumulator patterns when possible.
+
+### Leverage Laziness Carefully
+
+While UPLC is strict, `delay` and `force` provide controlled laziness. Use them to defer expensive computations that might not be needed.
+
+---
+
+## Debugging Evaluation
+
+When scripts fail, understanding evaluation helps diagnose issues:
+
+1. **Type Mismatches**: Usually surface immediately when applying built-ins
+2. **Missing Arguments**: Partially applied functions waiting for more arguments
+3. **Resource Exhaustion**: Deep recursion or expensive operations exceeding limits
+4. **Logic Errors**: Correct types but wrong values, requiring trace analysis
+
+Tools like Aiken's UPLC evaluator can step through execution, showing each reduction and its cost.
+
+---
+
+## Determinism Guarantees
+
+UPLC evaluation is completely deterministic:
+
+- Same program + same inputs = same result
+- No randomness or external effects
+- No timing variations or race conditions
+- Identical evaluation across all network nodes
+
+This determinism is crucial for consensus—every node must agree on transaction validity.
+
+---
+
+## Practical Implications
+
+When writing high-level smart contracts, remember:
+
+1. Your code compiles to UPLC following these evaluation rules
+2. Optimization at the high level translates to UPLC efficiency
+3. Understanding evaluation helps predict and minimize costs
+4. Debugging often requires thinking about UPLC-level execution
+
+The evaluation model might seem complex, but its predictability and determinism provide the foundation for Cardano's reliable smart contract platform. Master these concepts, and you'll write more efficient, cost-effective smart contracts.
+
+---
\ No newline at end of file
diff --git a/docs/cardano/uplc/overview.md b/docs/cardano/uplc/overview.md
new file mode 100644
index 0000000..502d3c9
--- /dev/null
+++ b/docs/cardano/uplc/overview.md
@@ -0,0 +1,58 @@
+---
+title: Overview
+sidebar_position: 1
+---
+
+# What is UPLC?
+
+Untyped Plutus Core (UPLC) is the low-level programming language that powers all smart contracts on the Cardano blockchain. Think of it as the assembly language of Cardano—while you'll rarely write UPLC directly, understanding it helps you grasp how your smart contracts actually execute on-chain.
+
+---
+
+## The Foundation of Cardano Smart Contracts
+
+When you write a smart contract in Aiken, Plutus, or any other high-level language for Cardano, your code ultimately compiles down to UPLC. This compiled UPLC code is what validators on the Cardano network actually execute to determine whether a transaction should succeed or fail.
+
+UPLC serves as the common denominator for all Cardano smart contract languages. No matter which language you choose for development, they all compile to the same UPLC representation, ensuring consistent execution across the network.
+
+---
+
+## Why "Untyped"?
+
+The "untyped" in UPLC might seem counterintuitive if you're coming from typed languages like Haskell or TypeScript. In UPLC, there's no compile-time type checking—the language doesn't enforce that you're adding two integers or concatenating two strings. Instead, operations either succeed at runtime or fail with an error.
+
+This design choice makes UPLC simpler and more efficient to execute on-chain. Type checking happens in the high-level languages before compilation, not during on-chain execution where every computational step costs ADA.
+
+---
+
+## Core Characteristics
+
+UPLC is a functional programming language at its core. Every UPLC program is an expression that evaluates to a value. There are no statements, no mutable variables, and no side effects—just pure computation.
+
+The language is deliberately minimal. It includes only the essential features needed for smart contract execution: lambda abstractions (functions), function application, built-in functions for common operations, variables, and basic error handling. This minimalism keeps on-chain execution costs predictable and auditable.
+
+---
+
+## Execution Model
+
+UPLC programs execute through a process called reduction. The evaluator repeatedly applies reduction rules to simplify expressions until it reaches a final value or encounters an error. This deterministic evaluation ensures that every validator on the network reaches the same conclusion about whether a transaction is valid.
+
+The execution environment provides a set of built-in functions for operations like arithmetic, cryptographic verification, and data manipulation. These built-ins are implemented natively for efficiency, as they handle the computationally intensive operations that smart contracts commonly need.
+
+---
+
+## Practical Implications
+
+Understanding UPLC helps you write more efficient smart contracts. When you know that your high-level code compiles to UPLC, you can make informed decisions about algorithmic complexity and data structure choices. You'll understand why certain patterns are more gas-efficient than others.
+
+For debugging complex issues, being able to read UPLC can be invaluable. When a smart contract fails in unexpected ways, examining the compiled UPLC often reveals the root cause more clearly than debugging at the high-level language layer.
+
+---
+
+## Next Steps
+
+Now that you understand what UPLC is and why it matters, you're ready to explore its syntax and structure. The following sections will guide you through reading and understanding UPLC code, working with its data types, and using the available built-in functions.
+
+While you may never write UPLC by hand, the knowledge you gain here will make you a more effective Cardano developer, capable of optimizing your smart contracts and diagnosing issues at the deepest level of the execution stack.
+
+---
\ No newline at end of file
diff --git a/docs/cardano/uplc/syntax.md b/docs/cardano/uplc/syntax.md
new file mode 100644
index 0000000..8dcf93b
--- /dev/null
+++ b/docs/cardano/uplc/syntax.md
@@ -0,0 +1,160 @@
+---
+title: Syntax
+sidebar_position: 2
+---
+
+# Syntax
+
+Understanding UPLC syntax is essential for debugging smart contracts and optimizing their on-chain execution. While you'll rarely write UPLC by hand, recognizing its structure helps you interpret compiled output and diagnose issues at the lowest level of Cardano's execution stack.
+
+---
+
+## Program Structure
+
+Every UPLC program starts with a `program` declaration that specifies the Plutus Core version. The current version is 2.0.0, and this version information ensures compatibility across the Cardano network.
+
+```
+(program 2.0.0
+
+)
+```
+
+The program wraps a single term that represents your entire smart contract logic. This term evaluates to produce the final result.
+
+---
+
+## Terms and Expressions
+
+UPLC is built on lambda calculus, where everything is an expression that evaluates to a value. The language provides several fundamental constructs:
+
+### Variables
+
+Variables in UPLC use De Bruijn indices—a numbering system that refers to lambda bindings by their distance from the variable usage. This eliminates naming conflicts and simplifies the evaluation model.
+
+```
+(var 0) -- References the innermost lambda parameter
+(var 1) -- References the second innermost parameter
+```
+
+### Lambda Abstractions
+
+Functions in UPLC are created using the `lam` keyword. Each lambda takes exactly one parameter, but you can nest lambdas to create multi-parameter functions.
+
+```
+(lam x )
+```
+
+The parameter name (`x` in this example) is purely for readability in the textual representation. During evaluation, these names are converted to De Bruijn indices.
+
+### Function Application
+
+Function application uses square brackets to apply a function to an argument:
+
+```
+[ ]
+```
+
+For functions with multiple parameters, you apply arguments one at a time:
+
+```
+[ [ ] ]
+```
+
+### Constants
+
+UPLC supports seven primitive types as constants, each with specific syntax:
+
+```
+(con unit ()) -- Unit type
+(con bool True) -- Boolean
+(con integer 42) -- Integer
+(con bytestring #68656c6c6f) -- Bytestring (hex)
+(con string "hello") -- UTF-8 string
+(con pair < integer, bool > (42, True)) -- Pair
+(con list < integer > [1, 2, 3]) -- List
+```
+
+Notice how compound types (pairs and lists) specify their element types between angle brackets.
+
+### Built-in Functions
+
+Built-in functions provide essential operations that would be inefficient or impossible to implement in pure UPLC. They're invoked using the `builtin` keyword:
+
+```
+(builtin addInteger)
+(builtin sha2_256)
+(builtin verifyEd25519Signature)
+```
+
+### Force and Delay
+
+These special operations handle polymorphic types and control evaluation:
+
+- `delay` defers the evaluation of a term
+- `force` triggers the evaluation of a delayed term
+
+```
+(delay ) -- Wrap term for later evaluation
+(force ) -- Evaluate a delayed term
+```
+
+These operations are crucial for implementing recursive functions and handling polymorphic built-ins.
+
+### Error Handling
+
+UPLC provides a simple error mechanism. When an error occurs, evaluation stops immediately:
+
+```
+(error)
+```
+
+There's no error recovery or exception handling—errors are terminal.
+
+---
+
+## Complete Example
+
+Here's a simple UPLC program that adds two integers:
+
+```
+(program 2.0.0
+ [ [ (builtin addInteger) (con integer 2) ] (con integer 3) ]
+)
+```
+
+This program:
+1. Gets the `addInteger` built-in function
+2. Applies it to the integer constant 2
+3. Applies the result to the integer constant 3
+4. Returns 5
+
+---
+
+## Syntax Conventions
+
+When reading UPLC, remember these conventions:
+
+- Parentheses group expressions and aren't part of the syntax itself
+- Whitespace is insignificant except for separating tokens
+- Comments aren't supported in the core language
+- All operations are prefix notation (operator comes first)
+
+---
+
+## Textual vs Binary Representation
+
+The syntax shown here represents UPLC's human-readable form. On-chain, UPLC programs are encoded in a compact binary format called "flat" encoding. This binary representation:
+
+- Reduces storage size significantly
+- Eliminates parsing overhead during validation
+- Preserves the exact program semantics
+
+Tools like Aiken's CLI can convert between these representations, allowing you to inspect on-chain code in readable form.
+
+---
+
+## Next Steps
+
+Now that you understand UPLC syntax, you're ready to explore how these syntactic elements map to actual data types and values during execution. The next section covers UPLC's type system and how values are represented during smart contract execution.
+
+---
\ No newline at end of file