diff --git a/README.md b/README.md index 820392e32..e76b9fca3 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ The **DNP_DAPPMANAGER** handles the Dappnode core DNPs and any user installed DN - :bust_in_silhouette: For user / usage documentation go to the [user guide](https://docs.dappnode.io/docs/user/getting-started/choose-your-path) - :wrench: For developers check the [technical documentation](https://docs.dappnode.io/docs/dev) +- :books: For repository management system documentation see the [wiki](./wiki/) - :speech_balloon: For feedback and reporting problems please [submit an issue](https://github.com/dappnode/dappnode/issues/new) or contact us on [Discord](https://discord.gg/dappnode) It is an AragonApp whose repo is deployed at this address: [0x0c564ca7b948008fb324268d8baedaeb1bd47bce](https://etherscan.io/address/0x0c564ca7b948008fb324268d8baedaeb1bd47bce) and whose ENS address is: [dappmanager.dnp.dappnode.eth](https://etherscan.io/enslookup?q=dappmanager.dnp.dappnode.eth]) diff --git a/wiki/README.md b/wiki/README.md new file mode 100644 index 000000000..9d7dd3389 --- /dev/null +++ b/wiki/README.md @@ -0,0 +1,17 @@ +# DAppNode Repository Management Wiki + +This wiki contains comprehensive documentation about how DAppNode's decentralized package management system works. + +## Table of Contents + +- [Repository Management System](./repository-management-system.md) - Complete guide to how DAppNode manages packages through smart contracts and IPFS +- [Smart Contracts Overview](./smart-contracts-overview.md) - Detailed information about the Directory, Registry, and Repository smart contracts +- [Package Distribution](./package-distribution.md) - How packages are discovered, downloaded, and installed + +## Quick Start + +If you're looking to understand how DAppNode manages packages, start with the [Repository Management System](./repository-management-system.md) document. + +## Contributing + +This documentation is maintained alongside the DAppNode DAPPMANAGER codebase. To contribute improvements or corrections, please submit a pull request. \ No newline at end of file diff --git a/wiki/package-distribution.md b/wiki/package-distribution.md new file mode 100644 index 000000000..27d60f0c5 --- /dev/null +++ b/wiki/package-distribution.md @@ -0,0 +1,408 @@ +# Package Distribution + +This document explains how DAppNode packages are discovered, downloaded, and installed through the decentralized distribution system. + +## Overview + +DAppNode's package distribution system combines Ethereum smart contracts for metadata and discovery with IPFS for content distribution. This creates a decentralized, censorship-resistant package management system that doesn't rely on centralized servers. + +## Package Discovery Process + +### 1. Registry Scanning + +The discovery process begins by scanning both registry smart contracts for packages: + +```typescript +// Example from packages/toolkit/src/registry/registry.ts +export class DappNodeRegistry { + public async queryGraphNewRepos(): Promise { + const query = this.constructGraphQLQuery(); + const data = await request(this.graphEndpoint, query); + return this.registry === "dnp" ? data.newRepos : data.newRepos; + } +} +``` + +**Process:** +1. **TheGraph Query:** Query subgraphs for NewRepo events +2. **Event Processing:** Parse events to extract package names and repository addresses +3. **Registry Filtering:** Separate packages by registry type (dnp vs public) +4. **ENS Validation:** Ensure package names follow proper ENS format + +### 2. Directory Filtering + +Once packages are discovered from registries, they are filtered through the Directory contract: + +```typescript +// Pseudocode for directory filtering +const allPackages = await registry.queryGraphNewRepos(); +const whitelistedPackages = await directory.getWhitelistedPackages(); +const featuredPackages = await directory.getFeaturedPackages(); + +const storePackages = allPackages.filter(pkg => + whitelistedPackages.includes(pkg.name) +); +``` + +**Directory Functions:** +- **Whitelist Check:** Only approved packages appear in DAppStore +- **Featured Status:** Determines which packages are highlighted +- **Ordering:** Controls package display order and categorization + +### 3. Package Metadata Resolution + +For each discovered package, metadata is resolved through ENS and Repository contracts: + +```typescript +// Example from packages/toolkit/src/repository/apmRepository.ts +export class ApmRepository { + public async getVersionAndIpfsHash({ + dnpNameOrHash, + version = "*" + }): Promise { + const repoContract = await this.getRepoContract(dnpNameOrHash); + const res = version && valid(version) + ? await repoContract.getBySemanticVersion(this.convertToUint16Array(version)) + : await repoContract.getLatest(); + + return { + version: this.convertToSemverString(res.semanticVersion), + contentUri: this.parseContentUri(res.contentURI), + origin: dnpNameOrHash + }; + } +} +``` + +## IPFS Content Structure + +Each package version is stored on IPFS with a standardized directory structure: + +``` +/ipfs/QmHash.../ +├── dappnode_package.json # Package manifest +├── docker-compose.yml # Container orchestration +├── avatar.png # Package icon +├── getting-started.md # User documentation +├── setup-wizard.json # Configuration UI +├── notifications.yaml # User alerts +├── grafana-dashboards/ # Monitoring dashboards +├── prometheus-targets.json # Metrics configuration +└── image.txz # Docker image archive +``` + +### Required Files + +**dappnode_package.json (Manifest):** +```json +{ + "name": "ethereum.dnp.dappnode.eth", + "version": "1.0.0", + "description": "Ethereum mainnet node", + "type": "service", + "architectures": ["linux/amd64", "linux/arm64"], + "image": { + "path": "ethereum.dnp.dappnode.eth_1.0.0.tar.xz", + "hash": "sha256:abc123...", + "size": 150000000 + }, + "dependencies": { + "bind.dnp.dappnode.eth": "latest" + } +} +``` + +**docker-compose.yml:** +```yaml +version: '3.8' +services: + ethereum: + image: ethereum.dnp.dappnode.eth:1.0.0 + container_name: DAppNodePackage-ethereum.dnp.dappnode.eth + restart: unless-stopped + ports: + - "30303:30303" + volumes: + - ethereum_data:/data +volumes: + ethereum_data: {} +``` + +### Optional Files + +**setup-wizard.json:** Provides configuration UI +**notifications.yaml:** Defines user alerts and messages +**getting-started.md:** User documentation and instructions +**grafana-dashboards/:** Monitoring and metrics dashboards +**prometheus-targets.json:** Metrics collection configuration + +## Content Download Process + +### 1. IPFS Hash Resolution + +When a user selects a package for installation: + +```typescript +// Example from packages/installer/src/dappnodeInstaller.ts +export class DappnodeInstaller extends DappnodeRepository { + async getRelease(name: string, version?: string): Promise { + const { contentUri } = await this.getVersionAndIpfsHash({ + dnpNameOrHash: name, + version + }); + + const pkgRelease = await this.getPkgRelease({ + dnpNameOrHash: contentUri, + trustedKeys: db.releaseKeysTrusted.get(), + os: process.arch, + version + }); + + return pkgRelease; + } +} +``` + +### 2. Content Validation + +Downloaded content undergoes several validation steps: + +**Schema Validation:** +```typescript +private validateSchemas(pkgRelease: PackageRelease): void { + validateManifestSchema(pkgRelease.manifest); + validateDappnodeCompose(pkgRelease.compose, pkgRelease.manifest); + if (pkgRelease.setupWizard) validateSetupWizardSchema(pkgRelease.setupWizard); + if (pkgRelease.notifications) validateNotificationsSchema(pkgRelease.notifications); +} +``` + +**Content Integrity:** +- IPFS DAG verification ensures content hasn't been tampered with +- File hash validation against manifest specifications +- Docker image integrity checks + +### 3. Asset Processing + +Once validated, package assets are processed: + +```typescript +// Metadata integration +pkgRelease.manifest = this.joinFilesInManifest({ + manifest: pkgRelease.manifest, + SetupWizard: pkgRelease.setupWizard, + disclaimer: pkgRelease.disclaimer, + gettingStarted: pkgRelease.gettingStarted, + grafanaDashboards: pkgRelease.grafanaDashboards, + prometheusTargets: pkgRelease.prometheusTargets, + notifications: pkgRelease.notifications +}); + +// Docker Compose processing +pkgRelease.compose = this.addCustomDefaultsAndLabels( + pkgRelease.compose, + pkgRelease.manifest, + pkgRelease.avatarFile, + pkgRelease.origin +); +``` + +## Multi-Architecture Support + +DAppNode supports multiple CPU architectures: + +### Architecture Detection + +```typescript +public async getPkgRelease({ + dnpNameOrHash, + trustedKeys, + os = "x64", // Default to x64 + version +}: { + dnpNameOrHash: string; + trustedKeys: TrustedReleaseKey[]; + os?: NodeJS.Architecture; + version?: string; +}): Promise +``` + +### Architecture-Specific Assets + +Packages can include different Docker images for different architectures: +- `linux/amd64` - Standard x86_64 systems +- `linux/arm64` - ARM64 systems (including Apple Silicon) +- `linux/arm/v7` - 32-bit ARM systems + +### Image Selection + +The installer automatically selects the appropriate image based on the host architecture: + +```typescript +private getArchTag = (arch: Architecture): string => + arch.replace(/\//g, "-"); + +// Example: "linux/arm64" becomes "linux-arm64" +``` + +## Dependency Resolution + +### DAppGet System + +Package dependencies are resolved using the DAppGet system: + +```typescript +import { DappGetState, DappgetOptions, dappGet } from "./dappGet/index.js"; + +// Dependency resolution with dappGet +const dappGetState = await dappGet(packages, dappgetOptions); +``` + +**Features:** +- Recursive dependency resolution +- Version conflict detection +- Dependency graph optimization +- Circular dependency prevention + +### Dependency Types + +**Required Dependencies:** Must be installed for package to function +**Optional Dependencies:** Enhance functionality but not required +**Peer Dependencies:** Expected to be provided by the environment + +## IPFS Integration + +### Gateway Support + +Multiple IPFS gateways provide redundancy: + +```typescript +// Primary IPFS node connection +const primaryGateway = "http://ipfs.dappnode:5001"; + +// Fallback public gateways +const fallbackGateways = [ + "https://ipfs.io", + "https://gateway.pinata.cloud", + "https://cloudflare-ipfs.com" +]; +``` + +### Content Verification + +**DAG Verification:** +```typescript +// Verify content using IPFS DAG +const dagResult = await ipfs.dag.get(contentHash); +if (!dagResult || !dagResult.value) { + throw new Error("Content verification failed"); +} +``` + +**Trust Model:** +- Content-addressed storage ensures immutability +- IPFS hashes provide cryptographic verification +- Optional trusted keys for additional validation + +### Performance Optimization + +**Content Pinning:** Important packages pinned to local IPFS node +**Caching:** Frequently accessed content cached locally +**Parallel Downloads:** Multiple gateway requests for faster downloads + +## Installation Process + +### 1. Pre-Installation Checks + +Before installation begins: +- System resource validation +- Port availability checking +- Dependency verification +- Version compatibility assessment + +### 2. Docker Integration + +Package installation leverages Docker: + +```typescript +// Docker Compose deployment +import { ComposeEditor, setDappnodeComposeDefaults } from "@dappnode/dockercompose"; + +const composeEditor = new ComposeEditor(pkgRelease.compose); +composeEditor.setDappnodeDefaults(); +await composeEditor.deploy(); +``` + +### 3. Post-Installation + +After successful installation: +- Service health checks +- Network configuration +- User notification +- Monitoring setup + +## Error Handling and Resilience + +### Network Failures + +**IPFS Unavailable:** +- Fallback to public gateways +- Retry with exponential backoff +- User notification of delays + +**Ethereum Node Unavailable:** +- Cached package metadata +- Offline mode for previously downloaded packages +- Background synchronization when connectivity restored + +### Content Issues + +**Invalid Package Structure:** +- Schema validation errors reported to user +- Installation aborted safely +- Cleanup of partial downloads + +**Version Conflicts:** +- Dependency resolution failures +- Alternative version suggestions +- User choice for conflict resolution + +### Recovery Mechanisms + +**Partial Download Recovery:** +- Resume interrupted downloads +- Verify partial content integrity +- Clean up corrupted files + +**Installation Rollback:** +- Restore previous package version +- Revert configuration changes +- Maintain system stability + +## Monitoring and Metrics + +### Package Usage Tracking + +- Installation success/failure rates +- Download performance metrics +- Popular package statistics +- Error pattern analysis + +### IPFS Network Health + +- Gateway response times +- Content availability monitoring +- Network connectivity status +- Peer connection quality + +### Performance Optimization + +Based on metrics collected: +- Gateway prioritization +- Content pre-caching +- Resource allocation optimization +- User experience improvements + +--- + +This document provides comprehensive coverage of DAppNode's package distribution system. For implementation details, refer to the source code in `packages/installer/` and `packages/toolkit/`. \ No newline at end of file diff --git a/wiki/repository-management-system.md b/wiki/repository-management-system.md new file mode 100644 index 000000000..cb5561c00 --- /dev/null +++ b/wiki/repository-management-system.md @@ -0,0 +1,286 @@ +# DAppNode Repository Management System + +DAppNode's repository management system is a decentralized package management infrastructure that leverages Ethereum smart contracts and IPFS for package discovery, versioning, and distribution. This document explains how the system works and the key components involved. + +## Architecture Overview + +The DAppNode repository management system consists of three main smart contract components working together: + +1. **Directory** - Manages the whitelist of packages available in the DAppStore +2. **Registry** - Manages ENS domains and package registration for different registries +3. **Repository** - Manages versioning and IPFS content hashes for individual packages + +## Core Components + +### 1. Directory Smart Contract + +The Directory serves as the **whitelist** and catalog system for DAppNode packages. + +**Purpose:** +- Defines which packages are available in the DAppStore +- Controls package positioning and display order +- Manages "featured" package status +- Works with both `dnp.dappnode.eth` and `public.dappnode.eth` registries + +**Key Features:** +- Whitelist management for package visibility +- Featured package indexing +- Package ordering and categorization + +**Implementation:** Located in `packages/toolkit/src/directory/` + +### 2. Registry Smart Contracts + +DAppNode operates **two separate registries**, each serving different purposes: + +#### `.dnp.dappnode.eth` Registry +- **Control:** Managed primarily by DAppNode organization +- **Purpose:** Official DAppNode packages and core infrastructure +- **Smart Contract Address:** `0x266bfdb2124a68beb6769dc887bd655f78778923` +- **ENS:** `dnp.dappnode.eth` + +#### `.public.dappnode.eth` Registry +- **Control:** Public registry - accessible to anyone +- **Purpose:** Community-contributed packages +- **Smart Contract Address:** `0x9f85ae5aefe4a3eff39d9a44212aae21dd15079a` +- **ENS:** `public.dappnode.eth` + +**Registry Functions:** +- Package ENS domain registration +- `NewRepo` event emission for package discovery +- Package ownership management +- Integration with TheGraph for efficient querying + +**Implementation:** Located in `packages/toolkit/src/registry/` + +### 3. Repository Smart Contracts + +Each DAppNode package has its **own Repository smart contract** that manages versions and content. + +**Key Responsibilities:** +- **Versioning:** Semantic versioning (semver) support +- **Content Storage:** IPFS hash management for each version +- **Event Emission:** `NewVersion` events when packages are updated +- **Version Retrieval:** Get latest, specific, or all versions + +**Smart Contract Functions:** +- `getLatest()` - Get the latest version and IPFS hash +- `getBySemanticVersion()` - Get specific version by semver +- `newVersion()` - Publish new version with IPFS hash +- `getVersionsCount()` - Get total number of versions + +**Implementation:** Located in `packages/toolkit/src/repository/` + +## Package Discovery and Distribution Flow + +### 1. Package Discovery + +```mermaid +graph TD + A[Ethereum Node] --> B[Query Registry Smart Contracts] + B --> C[NewRepo Events] + C --> D[Package List with ENS names] + D --> E[Directory Smart Contract] + E --> F[Filtered Whitelist] + F --> G[DAppStore Package List] +``` + +**Process:** +1. **Ethereum Connection Required:** DAppNode needs an Ethereum node to discover packages +2. **Registry Querying:** Query both `.dnp.dappnode.eth` and `.public.dappnode.eth` registries +3. **Event Scanning:** Look for `NewRepo` events to find new packages +4. **TheGraph Integration:** Use TheGraph for efficient event querying +5. **Directory Filtering:** Check Directory smart contract for whitelisted packages +6. **Package Listing:** Display available packages in DAppStore + +### 2. Version Discovery + +```mermaid +graph TD + A[Package ENS] --> B[Resolve to Repository Contract] + B --> C[Query Repository Smart Contract] + C --> D[NewVersion Events] + D --> E[Version List with IPFS Hashes] +``` + +**Process:** +1. **ENS Resolution:** Resolve package ENS to Repository smart contract address +2. **Version Events:** Scan for `NewVersion` events from the Repository contract +3. **IPFS Hash Retrieval:** Each version contains an IPFS hash pointing to package content +4. **Version Validation:** Validate semantic versioning format + +### 3. Package Content Download + +```mermaid +graph TD + A[Select Package Version] --> B[Get IPFS Hash] + B --> C[IPFS Node Connection] + C --> D[Download Package Content] + D --> E[Validate Content Structure] + E --> F[Extract Assets] + F --> G[Install Package] +``` + +**Content Structure:** +Each IPFS hash contains a standardized package structure: +- **Manifest** (`dappnode_package.json`) - Package metadata +- **Docker Compose** (`docker-compose.yml`) - Container orchestration +- **Docker Image** - Containerized application +- **Setup Wizard** (optional) - Configuration interface +- **Notifications** (optional) - User alerts and messages +- **Getting Started** (optional) - Documentation +- **Grafana Dashboards** (optional) - Monitoring dashboards +- **Prometheus Targets** (optional) - Metrics configuration + +## Key Modules + +### Toolkit Module (`packages/toolkit/`) + +The **central module** for interacting with smart contracts and IPFS. + +**Key Classes:** +- `DappNodeRegistry` - Registry smart contract interaction +- `DappnodeRepository` - Repository smart contract interaction with IPFS +- `ApmRepository` - Base APM (Aragon Package Manager) functionality + +**Features:** +- TheGraph integration for efficient querying +- IPFS content validation with DAG verification +- Multiple IPFS gateway support +- Typed smart contract interactions with TypeChain + +### Installer Module (`packages/installer/`) + +**Extends** `DappnodeRepository` to provide package installation capabilities. + +**Key Class:** +- `DappnodeInstaller` - Complete package installation workflow + +**Features:** +- Package content validation (manifest, compose, schemas) +- Dependency resolution with `dappGet` +- Docker Compose processing +- Metadata integration +- Multi-architecture support + +## Integration Points + +### Ethereum Node Dependency + +**Required for:** +- Smart contract interactions +- Event querying and scanning +- ENS resolution +- Package and version discovery + +**Configuration:** Ethereum node URL configurable in `packages/params/src/params.ts` + +### IPFS Node Dependency + +**Required for:** +- Package content download +- Content validation and verification +- Asset extraction + +**Features:** +- Multiple IPFS gateway support +- DAG-based content verification +- Fallback gateway mechanisms + +### TheGraph Integration + +**Purpose:** Efficient blockchain event querying + +**Subgraphs:** +- DNP Registry subgraph - for `dnp.dappnode.eth` packages +- Public Registry subgraph - for `public.dappnode.eth` packages + +**Benefits:** +- Faster package discovery +- Reduced Ethereum node load +- Structured event data + +## Security and Trust + +### Content Verification + +- **IPFS DAG Verification:** Ensures content integrity +- **Schema Validation:** Validates manifest and compose files +- **Trusted Keys:** Support for trusted release keys +- **ENS Security:** Leverages Ethereum's ENS security model + +### Package Trust Model + +- **Registry Control:** `.dnp` registry controlled by DAppNode +- **Public Registry:** Community packages in `.public` registry +- **Directory Whitelist:** Additional layer of package approval +- **Content Hashing:** Immutable IPFS content addressing + +## Development and Testing + +### Testing Infrastructure + +The toolkit provides comprehensive tests for: +- **Registry Integration:** TheGraph querying and event processing +- **Directory Integration:** Smart contract interaction +- **Repository Integration:** Version and content retrieval +- **IPFS Integration:** Content download and verification + +### Development Tools + +- **TypeChain:** Typed smart contract interfaces +- **Truffle Integration:** Smart contract compilation +- **Mock Backends:** Development and testing support + +## Configuration + +### Key Parameters + +Located in `packages/params/src/params.ts`: +- Ethereum node URLs +- IPFS gateway URLs +- Registry smart contract addresses +- TheGraph endpoint URLs + +### Environment Variables + +- `ETHEREUM_URL` - Ethereum node connection +- `IPFS_URL` - IPFS node connection +- Custom gateway configurations + +## Error Handling + +### Common Issues + +1. **Ethereum Node Unavailable:** Package discovery fails +2. **IPFS Node Unavailable:** Package download fails +3. **Invalid Package Structure:** Installation validation errors +4. **Network Connectivity:** Gateway fallback mechanisms +5. **Smart Contract Changes:** ABI compatibility issues + +### Resilience Features + +- Multiple IPFS gateway support +- Retry mechanisms for network operations +- Graceful degradation when services unavailable +- Comprehensive error reporting and logging + +## Future Considerations + +### Planned Improvements + +- Enhanced content verification mechanisms +- Additional registry support +- Improved caching strategies +- Performance optimizations for large package catalogs + +### Scalability + +- TheGraph integration reduces blockchain load +- IPFS provides distributed content delivery +- Registry separation allows for different governance models +- Modular architecture supports additional features + +--- + +This document provides a comprehensive overview of DAppNode's repository management system. For implementation details, refer to the source code in `packages/toolkit/` and `packages/installer/`. \ No newline at end of file diff --git a/wiki/smart-contracts-overview.md b/wiki/smart-contracts-overview.md new file mode 100644 index 000000000..ec91eb7d1 --- /dev/null +++ b/wiki/smart-contracts-overview.md @@ -0,0 +1,344 @@ +# Smart Contracts Overview + +This document provides detailed technical information about the three types of smart contracts that power DAppNode's repository management system: Directory, Registry, and Repository contracts. + +## Directory Smart Contract + +The Directory smart contract acts as a centralized whitelist and catalog management system for DAppNode packages. + +### Purpose + +- **Package Whitelisting:** Controls which packages appear in the DAppStore +- **Featured Packages:** Manages which packages are highlighted as "featured" +- **Package Ordering:** Determines the display order of packages in the store +- **Cross-Registry Support:** Works with both `dnp` and `public` registries + +### Key Functions + +The Directory contract provides functions to: +- Get the list of whitelisted packages +- Check if a package is featured +- Retrieve package positioning information +- Manage package categories and groupings + +### Implementation + +Located in `packages/toolkit/src/directory/`, the Directory module provides: +- Direct smart contract interaction +- Package filtering and validation +- Integration with the DAppStore UI + +## Registry Smart Contracts + +DAppNode operates two distinct registry smart contracts, each serving different governance and access models. + +### DNP Registry (`dnp.dappnode.eth`) + +**Smart Contract Address:** `0x266bfdb2124a68beb6769dc887bd655f78778923` + +**Governance:** Controlled by DAppNode organization + +**Purpose:** +- Official DAppNode packages +- Core infrastructure components +- Curated package ecosystem + +**Package Examples:** +- `dappmanager.dnp.dappnode.eth` +- `bind.dnp.dappnode.eth` +- `ipfs.dnp.dappnode.eth` +- `ethereum.dnp.dappnode.eth` + +### Public Registry (`public.dappnode.eth`) + +**Smart Contract Address:** `0x9f85ae5aefe4a3eff39d9a44212aae21dd15079a` + +**Governance:** Open to public participation + +**Purpose:** +- Community-contributed packages +- Third-party applications +- Experimental packages + +**Package Examples:** +- `rotki.public.dappnode.eth` +- `tornado.public.dappnode.eth` +- `custom-app.public.dappnode.eth` + +### Registry Contract Functions + +Both registry contracts implement the Aragon Package Manager (APM) interface: + +```solidity +// Key functions available in registry contracts +function newRepo(string _name, address _dev, uint16[3] _initialSemanticVersion, + address _contractAddress, bytes _contentURI) returns (address) + +function getRepo(bytes32 _name) view returns (address) + +function CREATE_REPO_ROLE() view returns (bytes32) +``` + +### Events + +**NewRepo Event:** +```solidity +event NewRepo(bytes32 indexed name, string name, address repo) +``` + +This event is emitted when a new package is registered and is crucial for package discovery. + +### TheGraph Integration + +Both registries are indexed by TheGraph subgraphs for efficient querying: + +**DNP Registry Subgraph:** +- Indexes all `NewRepo` events from the DNP registry +- Provides structured data for package discovery +- Endpoint configured in `packages/toolkit/src/registry/params.ts` + +**Public Registry Subgraph:** +- Indexes all `NewRepo` events from the public registry +- Enables efficient community package discovery +- Separate endpoint for public registry events + +### Implementation Details + +The registry implementation in `packages/toolkit/src/registry/` includes: + +**DappNodeRegistry Class:** +```typescript +export class DappNodeRegistry { + private registry: Registry; + private graphEndpoint: string; + private nameSuffix: string; + + constructor(registry: Registry) { + this.registry = registry; + if (registry === "dnp") this.graphEndpoint = dnpRegistryGraphEndpoint; + else this.graphEndpoint = publicRegistryGraphEndpoint; + + this.nameSuffix = this.registry === "dnp" ? + ".dnp.dappnode.eth" : ".public.dappnode.eth"; + } + + public async queryGraphNewRepos(): Promise { + // GraphQL query to fetch all NewRepo events + } +} +``` + +## Repository Smart Contracts + +Each DAppNode package has its own individual Repository smart contract that manages versions and content hashes. + +### Contract Address Resolution + +Package ENS names resolve to their Repository contract addresses: +- `rotki.dnp.dappnode.eth` → Repository contract for Rotki package +- `ethereum.dnp.dappnode.eth` → Repository contract for Ethereum package + +### Repository Contract ABI + +The Repository contracts implement a standard ABI defined in `packages/toolkit/src/repository/params.ts`: + +```typescript +export const repositoryAbi: Abi = [ + { + constant: true, + inputs: [{ name: "_semanticVersion", type: "uint16[3]" }], + name: "getBySemanticVersion", + outputs: [ + { name: "semanticVersion", type: "uint16[3]" }, + { name: "contractAddress", type: "address" }, + { name: "contentURI", type: "bytes" } + ], + type: "function" + }, + { + constant: true, + inputs: [], + name: "getLatest", + outputs: [ + { name: "semanticVersion", type: "uint16[3]" }, + { name: "contractAddress", type: "address" }, + { name: "contentURI", type: "bytes" } + ], + type: "function" + }, + // ... additional functions +]; +``` + +### Key Repository Functions + +**getLatest():** +- Returns the most recent version of the package +- Provides semantic version and IPFS content hash +- Used for automatic updates and initial installations + +**getBySemanticVersion(uint16[3] version):** +- Retrieves specific version by semantic version array +- Enables installation of specific package versions +- Supports downgrade and version pinning scenarios + +**newVersion():** +- Adds a new version to the package (admin only) +- Emits NewVersion event +- Links semantic version to IPFS content hash + +**getVersionsCount():** +- Returns total number of published versions +- Used for pagination and version discovery + +### Version Events + +**NewVersion Event:** +```solidity +event NewVersion(uint256 indexed versionId, uint16[3] semanticVersion) +``` + +This event is emitted whenever a new package version is published and contains: +- **versionId:** Incremental version identifier +- **semanticVersion:** Semantic version as [major, minor, patch] array + +### Semantic Versioning + +Repository contracts use semantic versioning with a uint16[3] array format: +- `[1, 0, 0]` = v1.0.0 +- `[2, 3, 1]` = v2.3.1 +- `[0, 1, 0]` = v0.1.0 + +### Content URI Format + +The `contentURI` field contains the IPFS hash pointing to package content: +- Format: Bytes representation of IPFS hash +- Content: Complete package bundle (manifest, docker image, compose file, etc.) +- Immutability: Content is immutable once published + +### Implementation + +The Repository interaction is handled by the `ApmRepository` and `DappnodeRepository` classes: + +**ApmRepository (Base Class):** +```typescript +export class ApmRepository { + public async getVersionAndIpfsHash({ + dnpNameOrHash, + version = "*", + contractAddress + }): Promise { + // ENS resolution and contract interaction + // Version validation and retrieval + // IPFS hash extraction + } +} +``` + +**DappnodeRepository (Extended Class):** +```typescript +export class DappnodeRepository extends ApmRepository { + public async getManifestFromDir(dnpName: string, version?: string): Promise { + // IPFS content retrieval + // Manifest parsing and validation + // Content structure verification + } + + public async getPkgRelease({ + dnpNameOrHash, + trustedKeys, + os = "x64", + version + }): Promise { + // Complete package asset retrieval + // Multi-architecture support + // Content validation and parsing + } +} +``` + +## Smart Contract Interaction Flow + +### Package Discovery Flow + +1. **Registry Query:** Query Registry contracts for NewRepo events +2. **ENS Resolution:** Resolve package ENS to Repository contract address +3. **Directory Check:** Verify package is whitelisted in Directory contract +4. **Package Listing:** Display available packages to user + +### Version Discovery Flow + +1. **Repository Query:** Query Repository contract for NewVersion events +2. **Version Parsing:** Convert uint16[3] arrays to semantic version strings +3. **Content Hash:** Extract IPFS hashes for each version +4. **Version Selection:** Present available versions to user + +### Package Installation Flow + +1. **Version Selection:** User selects specific version or latest +2. **Repository Query:** Get IPFS content hash for selected version +3. **Content Download:** Retrieve package content from IPFS +4. **Validation:** Verify content structure and schemas +5. **Installation:** Deploy package using Docker Compose + +## Error Handling + +### Common Smart Contract Errors + +**ENS Resolution Failures:** +- Package ENS doesn't resolve to valid contract +- Contract address is invalid or doesn't implement Repository ABI + +**Version Not Found:** +- Requested semantic version doesn't exist +- Version format is invalid (not uint16[3]) + +**Content URI Issues:** +- IPFS hash is malformed or empty +- Content is not available on IPFS network + +### Resilience Strategies + +**Multiple Provider Support:** +- Fallback to different Ethereum nodes if primary fails +- Provider switching for improved reliability + +**Event Caching:** +- Cache NewRepo and NewVersion events locally +- Reduce smart contract calls for frequently accessed data + +**Content Verification:** +- Validate IPFS content matches expected package structure +- Use DAG verification for content integrity + +## Development Tools + +### TypeChain Integration + +Smart contract types are generated using TypeChain: +```typescript +// Generated types for type-safe contract interaction +import { Repository } from '@dappnode/types/contracts'; + +const contract: Repository = new ethers.Contract(address, repositoryAbi, provider); +const latest = await contract.getLatest(); +``` + +### Testing Infrastructure + +Comprehensive tests cover: +- Registry event querying and parsing +- Repository version retrieval and validation +- IPFS content download and verification +- Error handling and edge cases + +### Mock Contracts + +Development environment includes: +- Mock registry contracts for testing +- Simulated event emission +- Local IPFS node for content testing + +--- + +This document provides detailed technical information about DAppNode's smart contract infrastructure. For implementation examples, see the source code in `packages/toolkit/src/`. \ No newline at end of file