Explorar el Código

move shank to it's own product page (#376)

* move shank

* Apply suggestions from code review

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update src/pages/shank/index.md

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update src/pages/shank/index.md

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* move macros

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
MarkSackerberg hace 4 meses
padre
commit
e3ecab303d

+ 110 - 0
CLAUDE.md

@@ -0,0 +1,110 @@
+# CLAUDE.md
+
+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
+
+## Project Overview
+
+This is the Metaplex Developer Hub - a Next.js documentation website built with Markdoc for rendering documentation. The site serves as the central hub for all Metaplex-related documentation including Core, Candy Machine, UMI, Token Metadata, and other MPL products.
+
+## Development Commands
+
+```bash
+# Install dependencies
+pnpm install
+
+# Development server
+pnpm run dev
+
+# Build for production
+pnpm run build
+
+# Start production server
+pnpm start
+
+# Lint code
+pnpm run lint
+
+# Generate sitemap
+pnpm run sitemap
+```
+
+## Architecture
+
+### Core Stack
+- **Next.js 13.4.7** - React framework with file-based routing
+- **Markdoc** - Documentation-focused content management
+- **Tailwind CSS** - Utility-first CSS framework
+- **pnpm** - Package manager
+
+### Key Directories
+
+- `src/pages/` - Next.js pages and markdown documentation files
+- `src/components/` - Reusable React components
+- `src/components/products/` - Product-specific components and configurations
+- `src/shared/` - Shared utilities and hooks
+- `markdoc/` - Markdoc configuration for custom nodes and tags
+- `public/` - Static assets
+
+### Product Configuration System
+
+Each product (Core, Candy Machine, UMI, etc.) has its own configuration in `src/components/products/[product]/index.js` that defines:
+- Navigation structure
+- Hero components
+- Section organization
+- GitHub links
+- Styling themes
+
+Products are registered in `src/components/products/index.js` and sorted alphabetically.
+
+### Documentation Structure
+
+Documentation follows a consistent pattern:
+- **Documentation section** - Main docs (index page)
+- **Guides section** - Tutorials and how-tos
+- **References section** - API documentation (often external links)
+
+### Page System
+
+Pages use a custom `usePage` hook that processes:
+- Meta titles and descriptions
+- Navigation state
+- Active sections
+- Table of contents
+- Product-specific theming
+
+### Styling and Theming
+
+- Uses CSS custom properties for accent colors
+- Product-specific accent classes (e.g., `accent-green` for Core)
+- Dark mode support via Tailwind CSS classes
+- Custom typography plugin for documentation content
+
+### Content Management
+
+- Markdown files in `src/pages/` are automatically processed
+- Markdoc provides custom components for code blocks, tables, and more
+- Custom fence component for syntax highlighting with Prism
+- Support for multiple programming languages
+
+### Middleware
+
+URL redirects are handled in `src/middleware.js` for:
+- Legacy URL compatibility
+- Product reorganization
+- API endpoint redirects
+
+## Development Workflow
+
+1. Product documentation lives in `src/pages/[product]/`
+2. Add new products by creating configuration in `src/components/products/`
+3. Custom components go in `src/components/`
+4. Shared utilities in `src/shared/`
+5. Static assets in `public/`
+
+## Important Notes
+
+- Uses pnpm workspaces - always use `pnpm` not `npm`
+- Markdoc processes `.md` files in pages directory
+- Product configurations control navigation and theming
+- Environment variables for Algolia DocSearch and analytics
+- Hotjar integration for user analytics

+ 2 - 0
src/components/products/index.js

@@ -14,6 +14,7 @@ import { hydra } from './hydra';
 import { inscription } from './inscription';
 import { legacyDocumentation } from './legacyDocumentation';
 import { mplHybrid } from './mpl-hybrid';
+import { shank } from './shank';
 import { sugar } from './sugar';
 import { tokenAuthRules } from './tokenAuthRules';
 import { tokenMetadata } from './tokenMetadata';
@@ -41,6 +42,7 @@ export const products = [
   core,
   coreCandyMachine,
   legacyDocumentation,
+  shank,
   sugar,
   mplHybrid,
   guides,

+ 5 - 0
src/components/products/shank/Hero.jsx

@@ -0,0 +1,5 @@
+import { Hero as BaseHero } from '@/components/Hero'
+
+export function Hero({ page }) {
+  return <BaseHero page={page} />
+}

+ 43 - 0
src/components/products/shank/index.js

@@ -0,0 +1,43 @@
+import {
+  documentationSection
+} from '@/shared/sections';
+import { MapIcon } from '@heroicons/react/24/solid';
+import { Hero } from './Hero';
+
+export const shank = {
+  name: 'Shank',
+  headline: 'IDL Extraction for Solana Programs',
+  description: 'Extract IDLs from Rust Solana program code using attribute macros',
+  path: 'shank',
+  icon: <MapIcon />,
+  navigationMenuCatergory: 'Dev Tools',
+  github: 'https://github.com/metaplex-foundation/shank',
+  className: 'accent-orange',
+  heroes: [{ path: '/shank', component: Hero }],
+  sections: [
+    {
+      ...documentationSection('shank'),
+      navigation: [
+        {
+          title: 'Introduction',
+          links: [
+            { title: 'Overview', href: '/shank' },
+            {
+              title: 'Getting Started',
+              href: '/shank/getting-started',
+            },
+          ],
+        },
+        {
+          title: 'Reference',
+          links: [
+            {
+              title: 'Macros Reference',
+              href: '/shank/macros',
+            },
+          ],
+        },
+      ],
+    },
+  ],
+}

+ 4 - 0
src/middleware.js

@@ -51,6 +51,9 @@ const redirectRules = {
     '/api/v1/das/get-signatures-for-asset': '/das-api/methods/get-asset-signatures',
     '/api/v1/das/search-assets': '/das-api/methods/search-assets',
   },
+  '/legacy-documentation': {
+    '/developer-tools/shank': '/shank',
+  },
 }
 
 export function middleware(request) {
@@ -85,5 +88,6 @@ export const config = {
     '/core-candy-machine/:path*',
     '/bubblegum/:path*',
     '/aura/:path*',
+    '/legacy-documentation/:path*',
   ],
 }

+ 0 - 14
src/pages/legacy-documentation/developer-tools/shank.md

@@ -1,14 +0,0 @@
----
-title: Shank
-metaTitle: Developer Tools | Shank
-description: extract IDLs from Rust Solana program code
----
-
-Shank makes it possible to extract IDLs from Rust Solana program code annotated with Shank attribute macros. This IDL
-can then be fed to [Solita](solita) in order to generate low level TypeScript SDK for that particular Rust program.
-
-🔗 **Helpful links:**
-
-- [GitHub Repository](https://github.com/metaplex-foundation/shank)
-- [Rust Crate](https://crates.io/crates/shank)
-- [CLI Rust Crate](https://crates.io/crates/shank-cli)

+ 215 - 0
src/pages/shank/getting-started.md

@@ -0,0 +1,215 @@
+---
+title: Getting Started with Shank
+metaTitle: Getting Started | Shank
+description: Learn how to install and set up Shank for IDL extraction from Rust Solana programs
+---
+
+This guide will walk you through setting up Shank and extracting your first IDL from a Rust Solana program.
+
+## Prerequisites
+
+Before getting started with Shank, ensure you have:
+
+- Rust toolchain installed (1.56.0 or later)
+- Cargo package manager
+- A Solana program written in Rust
+- Basic familiarity with Solana program development
+
+## Installation
+
+### Installing Shank CLI
+
+Install the Shank command-line tool using Cargo:
+
+```bash
+cargo install shank-cli
+```
+
+Verify the installation:
+
+```bash
+shank --version
+```
+
+### Adding Shank to Your Project
+
+Add Shank as a dependency in your `Cargo.toml`:
+
+```toml
+[dependencies]
+shank = "0.4"
+
+[build-dependencies]
+shank-cli = "0.4"
+```
+
+## Your First Shank Project
+
+### 1. Annotate Your Program
+
+Start by adding Shank derive macros to your existing Solana program:
+
+```rust
+use shank::ShankInstruction;
+
+#[derive(ShankInstruction)]
+#[rustfmt::skip]
+pub enum MyProgramInstruction {
+    /// Creates a new account with the given name
+    #[account(0, writable, signer, name="user", desc="User account")]
+    #[account(1, writable, name="account", desc="Account to create")]
+    #[account(2, name="system_program", desc="System program")]
+    CreateAccount {
+        name: String,
+        space: u64,
+    },
+    
+    /// Updates an existing account
+    #[account(0, writable, signer, name="authority", desc="Account authority")]
+    #[account(1, writable, name="account", desc="Account to update")]
+    UpdateAccount {
+        new_name: String,
+    },
+}
+```
+
+### 2. Annotate Account Structures
+
+Add `ShankAccount` to your account structs:
+
+```rust
+use shank::ShankAccount;
+
+#[derive(ShankAccount)]
+pub struct UserAccount {
+    pub name: String,
+    pub created_at: i64,
+    pub authority: Pubkey,
+}
+```
+
+### 3. Extract IDL
+
+Run the Shank CLI to extract the IDL:
+
+```bash
+shank idl --out-dir ./target/idl --crate-root ./
+```
+
+This will generate an IDL file (e.g., `my_program.json`) in the `./target/idl` directory.
+
+### 4. Verify the Output
+
+Check the generated IDL file:
+
+```bash
+cat ./target/idl/my_program.json
+```
+
+You should see a JSON structure containing your program's instructions, accounts, and types.
+
+## Project Structure
+
+A typical Shank-enabled project structure looks like:
+
+```
+my-solana-program/
+├── Cargo.toml
+├── src/
+│   ├── lib.rs
+│   ├── instruction.rs    # Contains ShankInstruction enums
+│   ├── state.rs         # Contains ShankAccount structs
+│   └── processor.rs     # Program logic
+├── target/
+│   └── idl/
+│       └── my_program.json  # Generated IDL
+└── sdk/                 # Generated TypeScript SDK (optional)
+    └── ...
+```
+
+## Core Components
+
+Shank consists of several interconnected crates:
+
+- **shank**: Top-level crate providing macro annotations
+- **shank-cli**: Command-line tool for IDL extraction
+- **shank-macro**: Derive macros for code generation
+- **shank-idl**: Processes files and converts annotations to IDL
+- **shank-render**: Generates Rust implementation blocks
+
+## Key Features
+
+### Derive Macros
+
+Shank provides five essential derive macros for annotating your Solana program code:
+
+1. **`ShankAccount`**: Annotates structs representing accounts with serializable data
+   - Supports `#[idl_type()]` for type overrides
+   - Supports `#[padding]` for padding fields
+   - Works with Borsh serialization
+
+2. **`ShankBuilder`**: Generates instruction builders for each annotated instruction
+   - Creates builder pattern implementations
+   - Simplifies instruction construction
+
+3. **`ShankContext`**: Creates account structs for instructions
+   - Generates context structures for program instructions
+   - Integrates with Anchor framework patterns
+
+4. **`ShankInstruction`**: Annotates the program's instruction enum
+   - Uses `#[account()]` attributes to specify account requirements
+   - Supports account mutability, signer requirements, and descriptions
+   - Generates comprehensive instruction metadata
+
+5. **`ShankType`**: Marks structs or enums with serializable data
+   - Used for custom types referenced in accounts or instructions
+   - Ensures proper IDL generation for complex data structures
+
+### Integration with Metaplex Ecosystem
+
+Shank integrates seamlessly with other Metaplex tools:
+
+- **[Kinobi](/umi/kinobi)**: Uses Shank JS library for IDL generation and client creation
+- **[Solita](/legacy-documentation/developer-tools/solita)**: Generates TypeScript SDKs from Shank-extracted IDLs
+
+## CLI Usage
+
+Once you have Shank installed and your program annotated, extract IDL with:
+
+```bash
+# Basic IDL extraction
+shank idl --out-dir ./target/idl --crate-root ./
+
+# Extract IDL for a specific crate
+shank idl --out-dir ./idl --crate-root ./my-program
+
+# Generate IDL with custom program ID
+shank idl --out-dir ./idl --crate-root ./ --program-id MyProgram111111111111111111111111111111
+```
+
+## Next Steps
+
+Now that you have Shank set up and generating IDL files, you can:
+
+1. **[Macros Reference](/shank/macros)**: Complete reference for all Shank macros and attributes
+2. **[Integration with Kinobi](/umi/kinobi)**: Generate modern TypeScript SDKs compatible with Umi (recommended)
+3. **[Solita](https://github.com/metaplex-foundation/solita)**: Generate legacy TypeScript SDKs compatible with web3.js
+
+## Troubleshooting
+
+### Common Issues
+
+**IDL generation fails with parsing errors:**
+- Ensure your Rust code compiles successfully
+- Check that all derive macros are properly imported
+- Verify account annotations are correctly formatted
+
+**Missing accounts in generated IDL:**
+- Make sure structs are annotated with `#[derive(ShankAccount)]`
+- Check that the struct is public and accessible
+
+**Build script errors:**
+- Ensure `shank-cli` is installed and available in PATH
+- Verify build script permissions and execution rights
+
+For more help, visit our [GitHub repository](https://github.com/metaplex-foundation/shank) or join the [Metaplex Discord](https://discord.gg/metaplex).

+ 41 - 0
src/pages/shank/index.md

@@ -0,0 +1,41 @@
+---
+title: Shank
+metaTitle: Shank | Metaplex Developer Hub
+description: Extract IDLs from Rust Solana program code using attribute macros
+---
+
+Shank is a collection of Rust crates designed to extract Interface Definition Language (IDL) from Solana program code annotated with Shank attribute macros. The extracted IDL can then be used to generate TypeScript SDKs and facilitate interaction with Solana programs.
+
+Shank simplifies the development workflow for Solana programs by automating the generation of IDL files, which serve as a bridge between your Rust program code and client-side SDKs.
+
+## Quick Start
+
+1. Install Shank CLI: `cargo install shank-cli`
+2. Add Shank to your project: `shank = "0.4"`
+3. Annotate your program with `ShankAccount` and `ShankInstruction` macros
+4. Extract IDL: `shank idl --out-dir ./target/idl --crate-root ./`
+
+## Key Features
+
+- **Five derive macros** for annotating Solana programs (`ShankAccount`, `ShankInstruction`, `ShankBuilder`, `ShankContext`, `ShankType`)
+- **Automatic IDL generation** from annotated Rust code
+- **TypeScript SDK generation** via integration with Solita and Kinobi
+- **Borsh serialization support** with type overrides and padding fields
+- **Comprehensive account metadata** including mutability, signer requirements, and descriptions
+
+## Documentation
+
+- **[Getting Started](/shank/getting-started)** - Installation, setup, detailed usage guide, and comprehensive examples
+
+## Integration
+
+Shank integrates seamlessly with other Metaplex tools:
+- **[Kinobi](/umi/kinobi)** - Modern IDL generation and client creation
+- **[Solita](/legacy-documentation/developer-tools/solita)** - TypeScript SDK generation
+
+## Resources
+
+- [GitHub Repository](https://github.com/metaplex-foundation/shank)
+- [Rust Crate](https://docs.rs/shank)
+- [CLI Crate](https://docs.rs/shank-cli)
+- [Discord Community](https://discord.gg/metaplex)

+ 221 - 0
src/pages/shank/macros.md

@@ -0,0 +1,221 @@
+---
+title: Shank Macros Reference
+metaTitle: Shank Macros Reference | Metaplex Developer Hub
+description: Complete reference for Shank derive macros and attributes used in Solana programs
+---
+
+Shank provides several macros used to annotate Solana Rust programs for IDL extraction:
+
+## ShankAccount
+
+Annotates a *struct* that shank will consider an account containing de/serializable data.
+
+```rust
+#[derive(Clone, BorshSerialize, BorshDeserialize, ShankAccount)]
+pub struct Metadata {
+    pub update_authority: Pubkey,
+    pub mint: Pubkey,
+    pub primary_sale_happened: bool,
+}
+```
+
+### Field Attributes
+
+#### `#[idl_type(...)]` Attribute
+
+This attribute allows overriding how Shank interprets a field's type when generating the IDL. Useful for:
+
+1. Fields with wrapper types that should be treated as their inner types
+2. Fields storing enum values as primitives
+3. Fields with complex types needing simpler representations
+
+Supports two formats:
+- String literal: `#[idl_type("TypeName")]`
+- Direct type: `#[idl_type(TypeName)]`
+
+```rust
+#[derive(Clone, BorshSerialize, BorshDeserialize, ShankAccount)]
+pub struct MyAccount {
+    // Field stored as u8 but representing an enum
+    #[idl_type("MyEnum")]
+    pub enum_as_byte: u8,
+
+    // Field with a wrapper type treated as a simpler type
+    #[idl_type("u64")]
+    pub wrapped_u64: CustomU64Wrapper,
+}
+```
+
+#### `#[padding]` Attribute
+
+Indicates that a field is used for padding and should be marked as such in the IDL.
+
+```rust
+#[derive(Clone, BorshSerialize, BorshDeserialize, ShankAccount)]
+pub struct PaddedAccount {
+    pub active_field: u64,
+    
+    #[padding]
+    pub unused_space: [u8; 32],
+    
+    pub another_field: String,
+}
+```
+
+**Note**: The fields of a *ShankAccount* struct can reference other types as long as they are annotated with `BorshSerialize`, `BorshDeserialize`, or `ShankType`.
+
+## ShankInstruction
+
+Annotates the program *Instruction* `Enum` to include `#[account]` attributes.
+
+```rust
+#[derive(Debug, Clone, ShankInstruction, BorshSerialize, BorshDeserialize)]
+#[rustfmt::skip]
+pub enum MyProgramInstruction {
+    /// Creates a new account with the given name
+    #[account(0, writable, signer, name="user", desc="User account")]
+    #[account(1, writable, name="account", desc="Account to create")]
+    #[account(2, name="system_program", desc="System program")]
+    CreateAccount {
+        name: String,
+        space: u64,
+    },
+    
+    /// Updates an existing account
+    #[account(0, writable, signer, name="authority", desc="Account authority")]
+    #[account(1, writable, name="account", desc="Account to update")]
+    UpdateAccount {
+        new_name: String,
+    },
+}
+```
+
+### `#[account]` Attribute
+
+Configures accounts for each instruction variant. The attribute follows this format:
+
+```rust
+#[account(index, mutability?, signer?, name="account_name", desc="Account description")]
+```
+
+Where:
+- `index`: The position of the account in the accounts array (0-based)
+- `mutability?`: Optional. Use `writable` if the account will be modified
+- `signer?`: Optional. Use `signer` if the account must sign the transaction
+- `name="account_name"`: Required. The name of the account
+- `desc="Account description"`: Optional. A description of the account's purpose
+
+### Account Attribute Examples
+
+```rust
+// Read-only account
+#[account(0, name="mint", desc="Mint account")]
+
+// Writable account
+#[account(1, writable, name="token_account", desc="Token account to modify")]
+
+// Signer account
+#[account(2, signer, name="owner", desc="Account owner")]
+
+// Writable signer account
+#[account(3, writable, signer, name="authority", desc="Program authority")]
+
+// Optional account
+#[account(4, optional, name="delegate", desc="Optional delegate account")]
+```
+
+## ShankType
+
+Marks structs or enums with serializable data that are used as custom types in accounts or instructions.
+
+```rust
+#[derive(Clone, BorshSerialize, BorshDeserialize, ShankType)]
+pub enum TokenState {
+    Uninitialized,
+    Initialized,
+    Frozen,
+}
+
+#[derive(Clone, BorshSerialize, BorshDeserialize, ShankType)]
+pub struct Creator {
+    pub address: Pubkey,
+    pub verified: bool,
+    pub share: u8,
+}
+```
+
+## ShankBuilder
+
+Generates instruction builders for each annotated instruction, creating builder pattern implementations that simplify instruction construction.
+
+```rust
+#[derive(Debug, Clone, ShankInstruction, ShankBuilder, BorshSerialize, BorshDeserialize)]
+pub enum MyInstruction {
+    CreateAccount { name: String, space: u64 },
+}
+```
+
+This generates builder methods that allow for fluent instruction creation.
+
+## ShankContext
+
+Creates account structs for instructions, generating context structures for program instructions that integrate with Anchor framework patterns.
+
+```rust
+#[derive(Debug, Clone, ShankInstruction, ShankContext, BorshSerialize, BorshDeserialize)]
+pub enum MyInstruction {
+    #[account(0, writable, signer, name="payer")]
+    #[account(1, writable, name="account")]
+    CreateAccount { name: String },
+}
+```
+
+This generates context structs that match the account requirements defined in the instruction.
+
+## Best Practices
+
+1. **Always use descriptive names** in `#[account]` attributes
+2. **Include descriptions** for better documentation
+3. **Use `#[idl_type()]` sparingly** - only when type overrides are necessary
+4. **Mark padding fields** appropriately with `#[padding]`
+5. **Ensure all referenced types** are properly annotated with Borsh traits
+6. **Group related macros** when they work together (e.g., `ShankInstruction` + `ShankBuilder`)
+
+## Common Patterns
+
+### Account with Custom Types
+
+```rust
+#[derive(Clone, BorshSerialize, BorshDeserialize, ShankAccount)]
+pub struct TokenAccount {
+    pub mint: Pubkey,
+    pub owner: Pubkey,
+    pub amount: u64,
+    pub state: TokenState, // References ShankType
+}
+
+#[derive(Clone, BorshSerialize, BorshDeserialize, ShankType)]
+pub enum TokenState {
+    Uninitialized,
+    Initialized,
+    Frozen,
+}
+```
+
+### Complete Instruction Definition
+
+```rust
+#[derive(Debug, Clone, ShankInstruction, BorshSerialize, BorshDeserialize)]
+#[rustfmt::skip]
+pub enum TokenInstruction {
+    /// Transfer tokens between accounts
+    #[account(0, writable, name="source", desc="Source token account")]
+    #[account(1, writable, name="destination", desc="Destination token account")]
+    #[account(2, signer, name="owner", desc="Owner of source account")]
+    Transfer {
+        amount: u64,
+    },
+}
+```
+
+This reference covers all the essential Shank macros and their usage patterns for effective IDL generation from Solana programs.