AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL unreviewed MIT Self-run

Storage Plus Chain

skill-0gfoundation-0g-agent-skills-storage-plus-chain · by 0gfoundation

A Claude skill from 0gfoundation/0g-agent-skills.

No reviews yet
0 installs
23 views
0.0% view→install

Install

$ agentstack add skill-0gfoundation-0g-agent-skills-storage-plus-chain

Open-source listing, not yet scanned by AgentStack. Follow the source repository for install instructions.

Security review

⚠ Flagged

1 finding(s); flagged for manual review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures
  • high Reads credentials/environment and may exfiltrate them.

What it can access

  • Network access No
  • Filesystem access Used
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Reliability & compatibility

Not yet reviewed
0 installs to date
no reviews yet
5mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Storage Plus Chain? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Storage + Chain Integration

Metadata

  • Category: cross-layer
  • SDK: @0glabs/0g-ts-sdk ^0.3.3, ethers ^6.13.0
  • Activation Triggers: "on-chain reference", "NFT metadata on 0G", "store hash on-chain",

"registry contract", "chain and storage"

Purpose

Combine 0G Storage with 0G Chain smart contracts to create on-chain references to off-chain data. Common patterns include NFT metadata storage, content registries, and verifiable document systems.

Prerequisites

  • Node.js >= 18
  • @0glabs/0g-ts-sdk and ethers installed
  • Hardhat configured with evmVersion: "cancun"
  • Funded wallet with 0G tokens
  • .env with PRIVATE_KEY, RPC_URL, STORAGE_INDEXER

Quick Workflow

  1. Upload data to 0G Storage (get root hash)
  2. Deploy or interact with registry contract on 0G Chain
  3. Store the root hash on-chain
  4. Later: read root hash from chain, download from storage

Core Rules

ALWAYS

  • Upload to storage BEFORE registering on-chain
  • Store the root hash on-chain (not the full data)
  • Use evmVersion: "cancun" for contract compilation
  • Verify downloaded data matches on-chain root hash
  • Use ethers v6 syntax

NEVER

  • Store large data directly on-chain (expensive)
  • Register a root hash before upload completes
  • Hardcode private keys
  • Skip Merkle verification when downloading referenced data

Code Examples

Registry Contract

// contracts/StorageRegistry.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

contract StorageRegistry {
    struct FileRecord {
        bytes32 rootHash;
        address uploader;
        uint256 timestamp;
        string metadata;
    }

    mapping(uint256 => FileRecord) public files;
    uint256 public fileCount;

    event FileRegistered(uint256 indexed id, bytes32 rootHash, address uploader);

    function registerFile(bytes32 rootHash, string calldata metadata) external returns (uint256) {
        uint256 id = fileCount++;
        files[id] = FileRecord({
            rootHash: rootHash,
            uploader: msg.sender,
            timestamp: block.timestamp,
            metadata: metadata
        });
        emit FileRegistered(id, rootHash, msg.sender);
        return id;
    }

    function getFile(uint256 id) external view returns (FileRecord memory) {
        return files[id];
    }

    function verifyUploader(uint256 id, address uploader) external view returns (bool) {
        return files[id].uploader == uploader;
    }
}

Upload and Register

import { ZgFile, Indexer } from '@0glabs/0g-ts-sdk';
import { ethers } from 'ethers';
import 'dotenv/config';

async function uploadAndRegister(
  filePath: string,
  metadata: string,
  registryAddress: string,
  registryAbi: any[],
): Promise {
  const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
  const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);

  // Step 1: Upload to 0G Storage
  const indexer = new Indexer(process.env.STORAGE_INDEXER!);
  const file = await ZgFile.fromFilePath(filePath);

  let rootHash: string;
  try {
    const [tree, err] = await file.merkleTree();
    if (err) throw new Error(`Merkle tree error: ${err}`);
    rootHash = tree!.rootHash();
    const [, uploadErr] = await indexer.upload(file, process.env.RPC_URL!, wallet);
    if (uploadErr) throw new Error(`Upload failed: ${uploadErr.message}`);
    console.log('Uploaded to storage, root hash:', rootHash);
  } finally {
    await file.close();
  }

  // Step 2: Register on-chain
  const registry = new ethers.Contract(registryAddress, registryAbi, wallet);
  const tx = await registry.registerFile(rootHash, metadata);
  const receipt = await tx.wait();

  // Extract file ID from event
  const event = receipt.logs.find((log: any) => log.fragment?.name === 'FileRegistered');
  const fileId = Number(event?.args?.[0] ?? 0);

  console.log('Registered on-chain, file ID:', fileId);
  return { rootHash, fileId };
}

Retrieve from Chain + Storage

async function retrieveFile(
  fileId: number,
  outputPath: string,
  registryAddress: string,
  registryAbi: any[],
): Promise {
  const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
  const registry = new ethers.Contract(registryAddress, registryAbi, provider);

  // Step 1: Get root hash from chain
  const record = await registry.getFile(fileId);
  const rootHash = record.rootHash;
  console.log('Root hash from chain:', rootHash);
  console.log('Uploader:', record.uploader);
  console.log('Timestamp:', new Date(Number(record.timestamp) * 1000));

  // Step 2: Download from storage with verification
  // Note: download() can throw or return errors — handle both
  const indexer = new Indexer(process.env.STORAGE_INDEXER!);
  try {
    const dlErr = await indexer.download(rootHash, outputPath, true);
    if (dlErr) throw dlErr;
  } catch (error: any) {
    throw new Error(`Download failed: ${error.message}`);
  }
  console.log('Downloaded and verified:', outputPath);
}

NFT Metadata Pattern

async function storeNFTMetadata(
  imageFilePath: string,
  name: string,
  description: string,
): Promise {
  const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);
  const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, provider);
  const indexer = new Indexer(process.env.STORAGE_INDEXER!);

  // Upload image to 0G Storage
  const imageFile = await ZgFile.fromFilePath(imageFilePath);
  let imageRootHash: string;
  try {
    const [tree, err] = await imageFile.merkleTree();
    if (err) throw err;
    imageRootHash = tree!.rootHash();
    const [, imgErr] = await indexer.upload(imageFile, process.env.RPC_URL!, wallet);
    if (imgErr) throw new Error(`Image upload failed: ${imgErr.message}`);
  } finally {
    await imageFile.close();
  }

  // Create metadata JSON pointing to 0G Storage
  const metadata = {
    name,
    description,
    image: `0g://${imageRootHash}`,
    properties: {
      storageLayer: '0G',
      imageRootHash,
    },
  };

  // Upload metadata to 0G Storage
  const fs = await import('fs');
  const os = await import('os');
  const path = await import('path');
  const tempPath = path.join(os.tmpdir(), `metadata-${Date.now()}.json`);
  fs.writeFileSync(tempPath, JSON.stringify(metadata, null, 2));

  const metadataFile = await ZgFile.fromFilePath(tempPath);
  let metadataRootHash: string;
  try {
    const [tree, err] = await metadataFile.merkleTree();
    if (err) throw err;
    metadataRootHash = tree!.rootHash();
    const [, metaErr] = await indexer.upload(metadataFile, process.env.RPC_URL!, wallet);
    if (metaErr) throw new Error(`Metadata upload failed: ${metaErr.message}`);
  } finally {
    await metadataFile.close();
    fs.unlinkSync(tempPath);
  }

  console.log('Image root hash:', imageRootHash);
  console.log('Metadata root hash:', metadataRootHash);
  return metadataRootHash;
}

Architecture

┌──────────────────────┐     ┌──────────────────────┐
│    0G Chain           │     │    0G Storage         │
│                       │     │                       │
│  Registry Contract    │────▶│  Files (root hashes)  │
│  - rootHash (bytes32) │     │  - Data chunks        │
│  - uploader (address) │     │  - Merkle proofs      │
│  - metadata (string)  │     │                       │
└──────────────────────┘     └──────────────────────┘
       On-chain                    Off-chain
     (small refs)               (large data)

Anti-Patterns

// BAD: Storing full file data on-chain
await contract.storeFile(fileBuffer); // Extremely expensive!

// BAD: Registering before upload completes
const rootHash = tree.rootHash();
await registry.registerFile(rootHash, metadata);
await indexer.upload(file, process.env.RPC_URL!, wallet); // Upload AFTER register — data not available!

// BAD: Skipping verification on download
await indexer.download(rootHash, outputPath, false); // Unverified!

Common Errors & Fixes

| Error | Cause | Fix | | --------------------- | ------------------------ | --------------------------- | | invalid opcode | Wrong evmVersion | Set evmVersion: "cancun" | | file not found | Registered before upload | Upload first, then register | | verification failed | Data tampered | Re-download from 0G Storage | | insufficient funds | Wallet empty | Fund wallet |

Related Skills

  • [Upload File](../../storage/upload-file/SKILL.md) — storage upload
  • [Download File](../../storage/download-file/SKILL.md) — storage download
  • [Deploy Contract](../../chain/deploy-contract/SKILL.md) — deploy registry
  • [Interact Contract](../../chain/interact-contract/SKILL.md) — read/write registry

References

  • [Storage Patterns](../../../patterns/STORAGE.md)
  • [Chain Patterns](../../../patterns/CHAIN.md)
  • [Security Patterns](../../../patterns/SECURITY.md)

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.