Compose Smart-Contract Oriented Programming (SCOP)
website·Indexed 32 days ago
https://compose.diamondsA framework for building composable smart contract systems using Smart-Contract Oriented Programming (SCOP). Compose utilizes diamond contracts (ERC-2535) to replace source-code inheritance with on-chain composition, employing a library of reusable facets and Solidity modules to create modular, readable, and interoperable on-chain infrastructure.
What's inside Compose
- Compose is a smart contract library designed for ERC-2535 Diamonds, implementing a paradigm called Smart Contract Oriented Programming (SCOP). It emphasizes code clarity, reusability, and on-chain composability by favoring composition over inheritance—combining deployed facets rather than inheriting contracts. The project is currently in an early stage and is not yet production-ready.
Overview of Smart-Contract Oriented Programming (SCOP)
Smart-Contract Oriented Programming (SCOP) is a paradigm that treats smart contracts as a system of composable, stateless logic components rather than isolated monolithic programs. Key principles include:
- Readability as Design: Code is written for long-term auditability and trust, ensuring developers and auditors can understand component roles and system integration.
- Native On-Chain Composition: Deployed contracts are treated as infrastructure that can be referenced and executed on-chain without relying on off-chain coordinators.
- Architectural Reuse: Reuse is achieved by designing components with clear interfaces and predictable boundaries, allowing them to serve as shared on-chain infrastructure.
- Independent Evolution: Clear boundaries allow individual parts of a system to be added, replaced, or removed without redeploying the entire application.
- Flexible Immutability: Systems can be designed to be upgradeable during development and transitioned to an immutable state once stability is reached.
Overview of Smart Contract Oriented Programming (SCOP)
Smart Contract Oriented Programming (SCOP) is a development paradigm for building modular on-chain applications as composed systems rather than isolated deployments. It treats reusable logic, application identity, shared state, and lifecycle management as explicit parts of the system design.
SCOP is implemented via a composition layer using diamond-native architecture:
- Diamonds: Act as the application container.
- Facets: Provide reusable deployed functionality.
- Modules: Support storage access, initialization, and internal extension helpers.
Best practices for managing ownership in OwnerDataMod
To maintain security and accurate event logging in the diamond architecture:
- Initialization: Call
setContractOwneronly from trusted initialization paths. - Transfers: For transferring ownership, use
OwnerTransferMod.transferOwnershipor an equivalent facet to ensure events correctly record the previous owner. - Access Control: Guard all external entrypoints that perform restricted state changes with
requireOwner().
- Initialization: Call
Compose CLI project structure
The CLI follows a modular architecture. Key directories includesrc/modulesfor feature logic (init, info, validation),src/pipelinesfor execution flow, andsrc/adaptersfor dependency management. The entry point issrc/index.tsand argument parsing is handled insrc/comander.ts.cli/ ├── src/ │ ├── adapters/ # Dependency adapters │ ├── context/ # Shared context │ ├── modules/ # Feature modules (init, info, validation, etc.) │ ├── pipelines/ # Execution pipelines │ ├── resolver/ # Dependency resolution │ ├── templates/ # Local template files │ ├── utils/ │ ├── comander.ts # CLI argument parsing │ └── index.ts # Entrypoint ├── bases/ # Base preset configurations ├── bin/ # CLI executableUnderstand Diamond Contract architecture (ERC-2535)
A diamond contract is a modular smart contract architecture defined by ERC-2535. Unlike traditional contracts, a diamond exists at a single address and holds all state storage, but delegates its logic to multiple separate contracts called 'facets'.
Key characteristics include:
- Single Address: Users interact with one address regardless of how many facets are attached.
- Modular Logic: Functionality is split into small, focused facets.
- Upgradability: Facets can be added, replaced, or removed after deployment without changing the diamond's address or redeploying the entire system.
- Storage: The diamond itself maintains the data storage, while facets provide the logic to manipulate that data.
Understand the Compose Testing Philosophy (BTT)
Compose uses a behavior-first testing approach called Behavior Tree Testing (BTT). The source of truth for expected behavior is defined in specification files located in
test/trees/*.tree. Key principles include:- Maintaining parity between facet surfaces and modifier/module behavior.
- Ensuring no test-only code (getters or hooks) is added to production contracts in
src/. - Using behavior-oriented naming for tests that mirror the structure of the behavior trees.
Understand and use Solidity Modules for code reuse
Solidity modules are files containing reusable logic (functions, constants, structs, events, enums, errors, and interfaces) where the top-level code lives outside of contracts and libraries. Unlike contracts or libraries, modules produce no standalone bytecode and are never deployed on-chain; instead, their code is included into the bytecode of any contract that imports them at compile time.
Key benefits include:
- Clean Code Reuse: Avoids duplication and complex inheritance chains.
- Gas Efficiency: Since module functions are
internal, the compiler can inline them or use cheapJUMPcalls, avoiding the overhead of external calls or library deployments.
Manage diamond facets with DiamondUpgradeMod
DiamondUpgradeMod provides a suite of functions to mutate a diamond's selector routing and facet list. It interacts with the diamond's shared storage located atDIAMOND_STORAGE_POSITION(defined askeccak256("erc8153.diamond")). Changes made via these functions are immediately visible to the diamond and all facets accessing shared storage.Compose CLI Modular Architecture Overview
The Compose CLI uses a pipeline-oriented modular architecture to ensure components are replaceable and extensible. The architecture consists of four primary concepts:
- Context (
ctx): A shared object that carries command parameters, configuration, module state, and execution status through the workflow. - Pipelines: Orchestrators that define workflows, coordinate module execution, resolve adapters, and manage control flow.
- Modules: Implementations of focused CLI business logic.
- Adapters: Isolation layers for external tools, frameworks, libraries, APIs, and runtime-specific behavior.
Component Relationships:
- Pipelines decide which modules run.
- Modules handle feature logic and use adapters for external tooling.
- Shared context allows each step to understand the output of previous steps. Module changes must preserve existing
ctx.statefields to avoid breaking subsequent steps.
- Context (
Inspect diamond facet mappings with DiamondInspectFacet
TheDiamondInspectFacetallows external tools and indexers to analyze the structure of a Diamond contract. It provides methods to resolve which facet handles a specific function selector and to list all registered facets and their exported functions.Understand Diamond Proxy architecture
In a Diamond architecture, theDiamond.solproxy serves as the application entry point. It holds the storage state but contains no business logic. All calls are delegated to stateless 'facets' via a fallback function. Specifically,DiamondMod.diamondFallback()identifies the contract owning the function selector and forwards the call to that facet.