From 3dd9cb3c4a68e8675fa17fdb261d52e42a66d44f Mon Sep 17 00:00:00 2001 From: Dustin Brickwood Date: Mon, 6 Oct 2025 13:49:30 -0500 Subject: [PATCH 01/18] test: reviewing mintlify docs --- docs/LICENSE | 21 + docs/README.md | 43 ++ docs/ai-tools/claude-code.mdx | 76 ++++ docs/ai-tools/cursor.mdx | 420 ++++++++++++++++++ docs/ai-tools/windsurf.mdx | 96 ++++ docs/api-reference/endpoint/create.mdx | 4 + docs/api-reference/endpoint/delete.mdx | 4 + docs/api-reference/endpoint/get.mdx | 4 + docs/api-reference/endpoint/webhook.mdx | 4 + docs/api-reference/introduction.mdx | 33 ++ docs/api-reference/openapi.json | 217 +++++++++ docs/development.mdx | 94 ++++ docs/docs.json | 122 +++++ docs/essentials/code.mdx | 35 ++ docs/essentials/images.mdx | 59 +++ docs/essentials/markdown.mdx | 88 ++++ docs/essentials/navigation.mdx | 87 ++++ docs/essentials/reusable-snippets.mdx | 110 +++++ docs/essentials/settings.mdx | 318 +++++++++++++ docs/favicon.svg | 19 + docs/images/checks-passed.png | Bin 0 -> 160724 bytes docs/images/hero-dark.png | Bin 0 -> 110614 bytes docs/images/hero-light.png | Bin 0 -> 104264 bytes docs/index.mdx | 97 ++++ docs/logo/dark.svg | 21 + docs/logo/light.svg | 21 + docs/quickstart.mdx | 80 ++++ docs/snippets/snippet-intro.mdx | 4 + {docs => docss}/book.toml | 0 {docs => docss}/mdbook-admonish.css | 0 .../snippets/ethers/deposit-erc20.ts | 0 .../snippets/ethers/deposit-eth.ts | 0 .../snippets/ethers/withdrawals-erc20.ts | 0 .../snippets/ethers/withdrawals-eth.ts | 0 .../snippets/viem/deposit-erc20.ts | 0 {docs => docss}/snippets/viem/deposit-eth.ts | 0 .../snippets/viem/withdrawals-erc20.ts | 0 .../snippets/viem/withdrawals-eth.ts | 0 {docs => docss}/src/SUMMARY.md | 0 {docs => docss}/src/concepts/finalization.md | 0 {docs => docss}/src/concepts/index.md | 0 .../src/concepts/status-vs-wait.md | 0 {docs => docss}/src/guides/deposits/ethers.md | 0 {docs => docss}/src/guides/deposits/index.md | 0 {docs => docss}/src/guides/deposits/viem.md | 0 {docs => docss}/src/guides/index.md | 0 .../src/guides/withdrawals/ethers.md | 0 .../src/guides/withdrawals/index.md | 0 .../src/guides/withdrawals/viem.md | 0 {docs => docss}/src/index.md | 0 {docs => docss}/src/overview/adapters.md | 0 {docs => docss}/src/overview/index.md | 0 {docs => docss}/src/overview/mental-model.md | 0 {docs => docss}/src/overview/what-it-does.md | 0 .../src/quickstart/choose-adapter.md | 0 {docs => docss}/src/quickstart/ethers.md | 0 {docs => docss}/src/quickstart/index.md | 0 {docs => docss}/src/quickstart/viem.md | 0 {docs => docss}/src/reference/helpers.md | 0 {docs => docss}/src/reference/index.md | 0 {docs => docss}/src/reference/methods.md | 0 61 files changed, 2077 insertions(+) create mode 100644 docs/LICENSE create mode 100644 docs/README.md create mode 100644 docs/ai-tools/claude-code.mdx create mode 100644 docs/ai-tools/cursor.mdx create mode 100644 docs/ai-tools/windsurf.mdx create mode 100644 docs/api-reference/endpoint/create.mdx create mode 100644 docs/api-reference/endpoint/delete.mdx create mode 100644 docs/api-reference/endpoint/get.mdx create mode 100644 docs/api-reference/endpoint/webhook.mdx create mode 100644 docs/api-reference/introduction.mdx create mode 100644 docs/api-reference/openapi.json create mode 100644 docs/development.mdx create mode 100644 docs/docs.json create mode 100644 docs/essentials/code.mdx create mode 100644 docs/essentials/images.mdx create mode 100644 docs/essentials/markdown.mdx create mode 100644 docs/essentials/navigation.mdx create mode 100644 docs/essentials/reusable-snippets.mdx create mode 100644 docs/essentials/settings.mdx create mode 100644 docs/favicon.svg create mode 100644 docs/images/checks-passed.png create mode 100644 docs/images/hero-dark.png create mode 100644 docs/images/hero-light.png create mode 100644 docs/index.mdx create mode 100644 docs/logo/dark.svg create mode 100644 docs/logo/light.svg create mode 100644 docs/quickstart.mdx create mode 100644 docs/snippets/snippet-intro.mdx rename {docs => docss}/book.toml (100%) rename {docs => docss}/mdbook-admonish.css (100%) rename {docs => docss}/snippets/ethers/deposit-erc20.ts (100%) rename {docs => docss}/snippets/ethers/deposit-eth.ts (100%) rename {docs => docss}/snippets/ethers/withdrawals-erc20.ts (100%) rename {docs => docss}/snippets/ethers/withdrawals-eth.ts (100%) rename {docs => docss}/snippets/viem/deposit-erc20.ts (100%) rename {docs => docss}/snippets/viem/deposit-eth.ts (100%) rename {docs => docss}/snippets/viem/withdrawals-erc20.ts (100%) rename {docs => docss}/snippets/viem/withdrawals-eth.ts (100%) rename {docs => docss}/src/SUMMARY.md (100%) rename {docs => docss}/src/concepts/finalization.md (100%) rename {docs => docss}/src/concepts/index.md (100%) rename {docs => docss}/src/concepts/status-vs-wait.md (100%) rename {docs => docss}/src/guides/deposits/ethers.md (100%) rename {docs => docss}/src/guides/deposits/index.md (100%) rename {docs => docss}/src/guides/deposits/viem.md (100%) rename {docs => docss}/src/guides/index.md (100%) rename {docs => docss}/src/guides/withdrawals/ethers.md (100%) rename {docs => docss}/src/guides/withdrawals/index.md (100%) rename {docs => docss}/src/guides/withdrawals/viem.md (100%) rename {docs => docss}/src/index.md (100%) rename {docs => docss}/src/overview/adapters.md (100%) rename {docs => docss}/src/overview/index.md (100%) rename {docs => docss}/src/overview/mental-model.md (100%) rename {docs => docss}/src/overview/what-it-does.md (100%) rename {docs => docss}/src/quickstart/choose-adapter.md (100%) rename {docs => docss}/src/quickstart/ethers.md (100%) rename {docs => docss}/src/quickstart/index.md (100%) rename {docs => docss}/src/quickstart/viem.md (100%) rename {docs => docss}/src/reference/helpers.md (100%) rename {docs => docss}/src/reference/index.md (100%) rename {docs => docss}/src/reference/methods.md (100%) diff --git a/docs/LICENSE b/docs/LICENSE new file mode 100644 index 0000000..5411374 --- /dev/null +++ b/docs/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Mintlify + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..055c983 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,43 @@ +# Mintlify Starter Kit + +Use the starter kit to get your docs deployed and ready to customize. + +Click the green **Use this template** button at the top of this repo to copy the Mintlify starter kit. The starter kit contains examples with + +- Guide pages +- Navigation +- Customizations +- API reference pages +- Use of popular components + +**[Follow the full quickstart guide](https://starter.mintlify.com/quickstart)** + +## Development + +Install the [Mintlify CLI](https://www.npmjs.com/package/mint) to preview your documentation changes locally. To install, use the following command: + +``` +npm i -g mint +``` + +Run the following command at the root of your documentation, where your `docs.json` is located: + +``` +mint dev +``` + +View your local preview at `http://localhost:3000`. + +## Publishing changes + +Install our GitHub app from your [dashboard](https://dashboard.mintlify.com/settings/organization/github-app) to propagate changes from your repo to your deployment. Changes are deployed to production automatically after pushing to the default branch. + +## Need help? + +### Troubleshooting + +- If your dev environment isn't running: Run `mint update` to ensure you have the most recent version of the CLI. +- If a page loads as a 404: Make sure you are running in a folder with a valid `docs.json`. + +### Resources +- [Mintlify documentation](https://mintlify.com/docs) diff --git a/docs/ai-tools/claude-code.mdx b/docs/ai-tools/claude-code.mdx new file mode 100644 index 0000000..bdc4e04 --- /dev/null +++ b/docs/ai-tools/claude-code.mdx @@ -0,0 +1,76 @@ +--- +title: "Claude Code setup" +description: "Configure Claude Code for your documentation workflow" +icon: "asterisk" +--- + +Claude Code is Anthropic's official CLI tool. This guide will help you set up Claude Code to help you write and maintain your documentation. + +## Prerequisites + +- Active Claude subscription (Pro, Max, or API access) + +## Setup + +1. Install Claude Code globally: + + ```bash + npm install -g @anthropic-ai/claude-code +``` + +2. Navigate to your docs directory. +3. (Optional) Add the `CLAUDE.md` file below to your project. +4. Run `claude` to start. + +## Create `CLAUDE.md` + +Create a `CLAUDE.md` file at the root of your documentation repository to train Claude Code on your specific documentation standards: + +````markdown +# Mintlify documentation + +## Working relationship +- You can push back on ideas-this can lead to better documentation. Cite sources and explain your reasoning when you do so +- ALWAYS ask for clarification rather than making assumptions +- NEVER lie, guess, or make up information + +## Project context +- Format: MDX files with YAML frontmatter +- Config: docs.json for navigation, theme, settings +- Components: Mintlify components + +## Content strategy +- Document just enough for user success - not too much, not too little +- Prioritize accuracy and usability of information +- Make content evergreen when possible +- Search for existing information before adding new content. Avoid duplication unless it is done for a strategic reason +- Check existing patterns for consistency +- Start by making the smallest reasonable changes + +## Frontmatter requirements for pages +- title: Clear, descriptive page title +- description: Concise summary for SEO/navigation + +## Writing standards +- Second-person voice ("you") +- Prerequisites at start of procedural content +- Test all code examples before publishing +- Match style and formatting of existing pages +- Include both basic and advanced use cases +- Language tags on all code blocks +- Alt text on all images +- Relative paths for internal links + +## Git workflow +- NEVER use --no-verify when committing +- Ask how to handle uncommitted changes before starting +- Create a new branch when no clear branch exists for changes +- Commit frequently throughout development +- NEVER skip or disable pre-commit hooks + +## Do not +- Skip frontmatter on any MDX file +- Use absolute URLs for internal links +- Include untested code examples +- Make assumptions - always ask for clarification +```` diff --git a/docs/ai-tools/cursor.mdx b/docs/ai-tools/cursor.mdx new file mode 100644 index 0000000..fbb7761 --- /dev/null +++ b/docs/ai-tools/cursor.mdx @@ -0,0 +1,420 @@ +--- +title: "Cursor setup" +description: "Configure Cursor for your documentation workflow" +icon: "arrow-pointer" +--- + +Use Cursor to help write and maintain your documentation. This guide shows how to configure Cursor for better results on technical writing tasks and using Mintlify components. + +## Prerequisites + +- Cursor editor installed +- Access to your documentation repository + +## Project rules + +Create project rules that all team members can use. In your documentation repository root: + +```bash +mkdir -p .cursor +``` + +Create `.cursor/rules.md`: + +````markdown +# Mintlify technical writing rule + +You are an AI writing assistant specialized in creating exceptional technical documentation using Mintlify components and following industry-leading technical writing practices. + +## Core writing principles + +### Language and style requirements + +- Use clear, direct language appropriate for technical audiences +- Write in second person ("you") for instructions and procedures +- Use active voice over passive voice +- Employ present tense for current states, future tense for outcomes +- Avoid jargon unless necessary and define terms when first used +- Maintain consistent terminology throughout all documentation +- Keep sentences concise while providing necessary context +- Use parallel structure in lists, headings, and procedures + +### Content organization standards + +- Lead with the most important information (inverted pyramid structure) +- Use progressive disclosure: basic concepts before advanced ones +- Break complex procedures into numbered steps +- Include prerequisites and context before instructions +- Provide expected outcomes for each major step +- Use descriptive, keyword-rich headings for navigation and SEO +- Group related information logically with clear section breaks + +### User-centered approach + +- Focus on user goals and outcomes rather than system features +- Anticipate common questions and address them proactively +- Include troubleshooting for likely failure points +- Write for scannability with clear headings, lists, and white space +- Include verification steps to confirm success + +## Mintlify component reference + +### Callout components + +#### Note - Additional helpful information + + +Supplementary information that supports the main content without interrupting flow + + +#### Tip - Best practices and pro tips + + +Expert advice, shortcuts, or best practices that enhance user success + + +#### Warning - Important cautions + + +Critical information about potential issues, breaking changes, or destructive actions + + +#### Info - Neutral contextual information + + +Background information, context, or neutral announcements + + +#### Check - Success confirmations + + +Positive confirmations, successful completions, or achievement indicators + + +### Code components + +#### Single code block + +Example of a single code block: + +```javascript config.js +const apiConfig = { + baseURL: 'https://api.example.com', + timeout: 5000, + headers: { + 'Authorization': `Bearer ${process.env.API_TOKEN}` + } +}; +``` + +#### Code group with multiple languages + +Example of a code group: + + +```javascript Node.js +const response = await fetch('/api/endpoint', { + headers: { Authorization: `Bearer ${apiKey}` } +}); +``` + +```python Python +import requests +response = requests.get('/api/endpoint', + headers={'Authorization': f'Bearer {api_key}'}) +``` + +```curl cURL +curl -X GET '/api/endpoint' \ + -H 'Authorization: Bearer YOUR_API_KEY' +``` + + +#### Request/response examples + +Example of request/response documentation: + + +```bash cURL +curl -X POST 'https://api.example.com/users' \ + -H 'Content-Type: application/json' \ + -d '{"name": "John Doe", "email": "john@example.com"}' +``` + + + +```json Success +{ + "id": "user_123", + "name": "John Doe", + "email": "john@example.com", + "created_at": "2024-01-15T10:30:00Z" +} +``` + + +### Structural components + +#### Steps for procedures + +Example of step-by-step instructions: + + + + Run `npm install` to install required packages. + + + Verify installation by running `npm list`. + + + + + Create a `.env` file with your API credentials. + + ```bash + API_KEY=your_api_key_here + ``` + + + Never commit API keys to version control. + + + + +#### Tabs for alternative content + +Example of tabbed content: + + + + ```bash + brew install node + npm install -g package-name + ``` + + + + ```powershell + choco install nodejs + npm install -g package-name + ``` + + + + ```bash + sudo apt install nodejs npm + npm install -g package-name + ``` + + + +#### Accordions for collapsible content + +Example of accordion groups: + + + + - **Firewall blocking**: Ensure ports 80 and 443 are open + - **Proxy configuration**: Set HTTP_PROXY environment variable + - **DNS resolution**: Try using 8.8.8.8 as DNS server + + + + ```javascript + const config = { + performance: { cache: true, timeout: 30000 }, + security: { encryption: 'AES-256' } + }; + ``` + + + +### Cards and columns for emphasizing information + +Example of cards and card groups: + + +Complete walkthrough from installation to your first API call in under 10 minutes. + + + + + Learn how to authenticate requests using API keys or JWT tokens. + + + + Understand rate limits and best practices for high-volume usage. + + + +### API documentation components + +#### Parameter fields + +Example of parameter documentation: + + +Unique identifier for the user. Must be a valid UUID v4 format. + + + +User's email address. Must be valid and unique within the system. + + + +Maximum number of results to return. Range: 1-100. + + + +Bearer token for API authentication. Format: `Bearer YOUR_API_KEY` + + +#### Response fields + +Example of response field documentation: + + +Unique identifier assigned to the newly created user. + + + +ISO 8601 formatted timestamp of when the user was created. + + + +List of permission strings assigned to this user. + + +#### Expandable nested fields + +Example of nested field documentation: + + +Complete user object with all associated data. + + + + User profile information including personal details. + + + + User's first name as entered during registration. + + + + URL to user's profile picture. Returns null if no avatar is set. + + + + + + +### Media and advanced components + +#### Frames for images + +Wrap all images in frames: + + +Main dashboard showing analytics overview + + + +Analytics dashboard with charts + + +#### Videos + +Use the HTML video element for self-hosted video content: + + + +Embed YouTube videos using iframe elements: + + + +#### Tooltips + +Example of tooltip usage: + + +API + + +#### Updates + +Use updates for changelogs: + + +## New features +- Added bulk user import functionality +- Improved error messages with actionable suggestions + +## Bug fixes +- Fixed pagination issue with large datasets +- Resolved authentication timeout problems + + +## Required page structure + +Every documentation page must begin with YAML frontmatter: + +```yaml +--- +title: "Clear, specific, keyword-rich title" +description: "Concise description explaining page purpose and value" +--- +``` + +## Content quality standards + +### Code examples requirements + +- Always include complete, runnable examples that users can copy and execute +- Show proper error handling and edge case management +- Use realistic data instead of placeholder values +- Include expected outputs and results for verification +- Test all code examples thoroughly before publishing +- Specify language and include filename when relevant +- Add explanatory comments for complex logic +- Never include real API keys or secrets in code examples + +### API documentation requirements + +- Document all parameters including optional ones with clear descriptions +- Show both success and error response examples with realistic data +- Include rate limiting information with specific limits +- Provide authentication examples showing proper format +- Explain all HTTP status codes and error handling +- Cover complete request/response cycles + +### Accessibility requirements + +- Include descriptive alt text for all images and diagrams +- Use specific, actionable link text instead of "click here" +- Ensure proper heading hierarchy starting with H2 +- Provide keyboard navigation considerations +- Use sufficient color contrast in examples and visuals +- Structure content for easy scanning with headers and lists + +## Component selection logic + +- Use **Steps** for procedures and sequential instructions +- Use **Tabs** for platform-specific content or alternative approaches +- Use **CodeGroup** when showing the same concept in multiple programming languages +- Use **Accordions** for progressive disclosure of information +- Use **RequestExample/ResponseExample** specifically for API endpoint documentation +- Use **ParamField** for API parameters, **ResponseField** for API responses +- Use **Expandable** for nested object properties or hierarchical information +```` diff --git a/docs/ai-tools/windsurf.mdx b/docs/ai-tools/windsurf.mdx new file mode 100644 index 0000000..fce12bf --- /dev/null +++ b/docs/ai-tools/windsurf.mdx @@ -0,0 +1,96 @@ +--- +title: "Windsurf setup" +description: "Configure Windsurf for your documentation workflow" +icon: "water" +--- + +Configure Windsurf's Cascade AI assistant to help you write and maintain documentation. This guide shows how to set up Windsurf specifically for your Mintlify documentation workflow. + +## Prerequisites + +- Windsurf editor installed +- Access to your documentation repository + +## Workspace rules + +Create workspace rules that provide Windsurf with context about your documentation project and standards. + +Create `.windsurf/rules.md` in your project root: + +````markdown +# Mintlify technical writing rule + +## Project context + +- This is a documentation project on the Mintlify platform +- We use MDX files with YAML frontmatter +- Navigation is configured in `docs.json` +- We follow technical writing best practices + +## Writing standards + +- Use second person ("you") for instructions +- Write in active voice and present tense +- Start procedures with prerequisites +- Include expected outcomes for major steps +- Use descriptive, keyword-rich headings +- Keep sentences concise but informative + +## Required page structure + +Every page must start with frontmatter: + +```yaml +--- +title: "Clear, specific title" +description: "Concise description for SEO and navigation" +--- +``` + +## Mintlify components + +### Callouts + +- `` for helpful supplementary information +- `` for important cautions and breaking changes +- `` for best practices and expert advice +- `` for neutral contextual information +- `` for success confirmations + +### Code examples + +- When appropriate, include complete, runnable examples +- Use `` for multiple language examples +- Specify language tags on all code blocks +- Include realistic data, not placeholders +- Use `` and `` for API docs + +### Procedures + +- Use `` component for sequential instructions +- Include verification steps with `` components when relevant +- Break complex procedures into smaller steps + +### Content organization + +- Use `` for platform-specific content +- Use `` for progressive disclosure +- Use `` and `` for highlighting content +- Wrap images in `` components with descriptive alt text + +## API documentation requirements + +- Document all parameters with `` +- Show response structure with `` +- Include both success and error examples +- Use `` for nested object properties +- Always include authentication examples + +## Quality standards + +- Test all code examples before publishing +- Use relative paths for internal links +- Include alt text for all images +- Ensure proper heading hierarchy (start with h2) +- Check existing patterns for consistency +```` diff --git a/docs/api-reference/endpoint/create.mdx b/docs/api-reference/endpoint/create.mdx new file mode 100644 index 0000000..5689f1b --- /dev/null +++ b/docs/api-reference/endpoint/create.mdx @@ -0,0 +1,4 @@ +--- +title: 'Create Plant' +openapi: 'POST /plants' +--- diff --git a/docs/api-reference/endpoint/delete.mdx b/docs/api-reference/endpoint/delete.mdx new file mode 100644 index 0000000..657dfc8 --- /dev/null +++ b/docs/api-reference/endpoint/delete.mdx @@ -0,0 +1,4 @@ +--- +title: 'Delete Plant' +openapi: 'DELETE /plants/{id}' +--- diff --git a/docs/api-reference/endpoint/get.mdx b/docs/api-reference/endpoint/get.mdx new file mode 100644 index 0000000..56aa09e --- /dev/null +++ b/docs/api-reference/endpoint/get.mdx @@ -0,0 +1,4 @@ +--- +title: 'Get Plants' +openapi: 'GET /plants' +--- diff --git a/docs/api-reference/endpoint/webhook.mdx b/docs/api-reference/endpoint/webhook.mdx new file mode 100644 index 0000000..3291340 --- /dev/null +++ b/docs/api-reference/endpoint/webhook.mdx @@ -0,0 +1,4 @@ +--- +title: 'New Plant' +openapi: 'WEBHOOK /plant/webhook' +--- diff --git a/docs/api-reference/introduction.mdx b/docs/api-reference/introduction.mdx new file mode 100644 index 0000000..c835b78 --- /dev/null +++ b/docs/api-reference/introduction.mdx @@ -0,0 +1,33 @@ +--- +title: 'Introduction' +description: 'Example section for showcasing API endpoints' +--- + + + If you're not looking to build API reference documentation, you can delete + this section by removing the api-reference folder. + + +## Welcome + +There are two ways to build API documentation: [OpenAPI](https://mintlify.com/docs/api-playground/openapi/setup) and [MDX components](https://mintlify.com/docs/api-playground/mdx/configuration). For the starter kit, we are using the following OpenAPI specification. + + + View the OpenAPI specification file + + +## Authentication + +All API endpoints are authenticated using Bearer tokens and picked up from the specification file. + +```json +"security": [ + { + "bearerAuth": [] + } +] +``` diff --git a/docs/api-reference/openapi.json b/docs/api-reference/openapi.json new file mode 100644 index 0000000..da5326e --- /dev/null +++ b/docs/api-reference/openapi.json @@ -0,0 +1,217 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "OpenAPI Plant Store", + "description": "A sample API that uses a plant store as an example to demonstrate features in the OpenAPI specification", + "license": { + "name": "MIT" + }, + "version": "1.0.0" + }, + "servers": [ + { + "url": "http://sandbox.mintlify.com" + } + ], + "security": [ + { + "bearerAuth": [] + } + ], + "paths": { + "/plants": { + "get": { + "description": "Returns all plants from the system that the user has access to", + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "The maximum number of results to return", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Plant response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Plant" + } + } + } + } + }, + "400": { + "description": "Unexpected error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + } + }, + "post": { + "description": "Creates a new plant in the store", + "requestBody": { + "description": "Plant to add to the store", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewPlant" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "plant response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Plant" + } + } + } + }, + "400": { + "description": "unexpected error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + } + } + }, + "/plants/{id}": { + "delete": { + "description": "Deletes a single plant based on the ID supplied", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "ID of plant to delete", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "204": { + "description": "Plant deleted", + "content": {} + }, + "400": { + "description": "unexpected error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Error" + } + } + } + } + } + } + } + }, + "webhooks": { + "/plant/webhook": { + "post": { + "description": "Information about a new plant added to the store", + "requestBody": { + "description": "Plant added to the store", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NewPlant" + } + } + } + }, + "responses": { + "200": { + "description": "Return a 200 status to indicate that the data was received successfully" + } + } + } + } + }, + "components": { + "schemas": { + "Plant": { + "required": [ + "name" + ], + "type": "object", + "properties": { + "name": { + "description": "The name of the plant", + "type": "string" + }, + "tag": { + "description": "Tag to specify the type", + "type": "string" + } + } + }, + "NewPlant": { + "allOf": [ + { + "$ref": "#/components/schemas/Plant" + }, + { + "required": [ + "id" + ], + "type": "object", + "properties": { + "id": { + "description": "Identification number of the plant", + "type": "integer", + "format": "int64" + } + } + } + ] + }, + "Error": { + "required": [ + "error", + "message" + ], + "type": "object", + "properties": { + "error": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } + } + }, + "securitySchemes": { + "bearerAuth": { + "type": "http", + "scheme": "bearer" + } + } + } +} \ No newline at end of file diff --git a/docs/development.mdx b/docs/development.mdx new file mode 100644 index 0000000..ac633ba --- /dev/null +++ b/docs/development.mdx @@ -0,0 +1,94 @@ +--- +title: 'Development' +description: 'Preview changes locally to update your docs' +--- + + + **Prerequisites**: + - Node.js version 19 or higher + - A docs repository with a `docs.json` file + + +Follow these steps to install and run Mintlify on your operating system. + + + + +```bash +npm i -g mint +``` + + + + +Navigate to your docs directory where your `docs.json` file is located, and run the following command: + +```bash +mint dev +``` + +A local preview of your documentation will be available at `http://localhost:3000`. + + + + +## Custom ports + +By default, Mintlify uses port 3000. You can customize the port Mintlify runs on by using the `--port` flag. For example, to run Mintlify on port 3333, use this command: + +```bash +mint dev --port 3333 +``` + +If you attempt to run Mintlify on a port that's already in use, it will use the next available port: + +```md +Port 3000 is already in use. Trying 3001 instead. +``` + +## Mintlify versions + +Please note that each CLI release is associated with a specific version of Mintlify. If your local preview does not align with the production version, please update the CLI: + +```bash +npm mint update +``` + +## Validating links + +The CLI can assist with validating links in your documentation. To identify any broken links, use the following command: + +```bash +mint broken-links +``` + +## Deployment + +If the deployment is successful, you should see the following: + + + Screenshot of a deployment confirmation message that says All checks have passed. + + +## Code formatting + +We suggest using extensions on your IDE to recognize and format MDX. If you're a VSCode user, consider the [MDX VSCode extension](https://marketplace.visualstudio.com/items?itemName=unifiedjs.vscode-mdx) for syntax highlighting, and [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) for code formatting. + +## Troubleshooting + + + + + This may be due to an outdated version of node. Try the following: + 1. Remove the currently-installed version of the CLI: `npm remove -g mint` + 2. Upgrade to Node v19 or higher. + 3. Reinstall the CLI: `npm i -g mint` + + + + + Solution: Go to the root of your device and delete the `~/.mintlify` folder. Then run `mint dev` again. + + + +Curious about what changed in the latest CLI version? Check out the [CLI changelog](https://www.npmjs.com/package/mintlify?activeTab=versions). diff --git a/docs/docs.json b/docs/docs.json new file mode 100644 index 0000000..46b44cc --- /dev/null +++ b/docs/docs.json @@ -0,0 +1,122 @@ +{ + "$schema": "https://mintlify.com/docs.json", + "theme": "mint", + "name": "Mint Starter Kit", + "colors": { + "primary": "#16A34A", + "light": "#07C983", + "dark": "#15803D" + }, + "favicon": "/favicon.svg", + "navigation": { + "tabs": [ + { + "tab": "Guides", + "groups": [ + { + "group": "Getting started", + "pages": [ + "index", + "quickstart", + "development" + ] + }, + { + "group": "Customization", + "pages": [ + "essentials/settings", + "essentials/navigation" + ] + }, + { + "group": "Writing content", + "pages": [ + "essentials/markdown", + "essentials/code", + "essentials/images", + "essentials/reusable-snippets" + ] + }, + { + "group": "AI tools", + "pages": [ + "ai-tools/cursor", + "ai-tools/claude-code", + "ai-tools/windsurf" + ] + } + ] + }, + { + "tab": "API reference", + "groups": [ + { + "group": "API documentation", + "pages": [ + "api-reference/introduction" + ] + }, + { + "group": "Endpoint examples", + "pages": [ + "api-reference/endpoint/get", + "api-reference/endpoint/create", + "api-reference/endpoint/delete", + "api-reference/endpoint/webhook" + ] + } + ] + } + ], + "global": { + "anchors": [ + { + "anchor": "Documentation", + "href": "https://mintlify.com/docs", + "icon": "book-open-cover" + }, + { + "anchor": "Blog", + "href": "https://mintlify.com/blog", + "icon": "newspaper" + } + ] + } + }, + "logo": { + "light": "/logo/light.svg", + "dark": "/logo/dark.svg" + }, + "navbar": { + "links": [ + { + "label": "Support", + "href": "mailto:hi@mintlify.com" + } + ], + "primary": { + "type": "button", + "label": "Dashboard", + "href": "https://dashboard.mintlify.com" + } + }, + "contextual": { + "options": [ + "copy", + "view", + "chatgpt", + "claude", + "perplexity", + "mcp", + "cursor", + "vscode" + ] + }, + "footer": { + "socials": { + "x": "https://x.com/mintlify", + "github": "https://github.com/mintlify", + "linkedin": "https://linkedin.com/company/mintlify" + } + } +} diff --git a/docs/essentials/code.mdx b/docs/essentials/code.mdx new file mode 100644 index 0000000..ae2abbf --- /dev/null +++ b/docs/essentials/code.mdx @@ -0,0 +1,35 @@ +--- +title: 'Code blocks' +description: 'Display inline code and code blocks' +icon: 'code' +--- + +## Inline code + +To denote a `word` or `phrase` as code, enclose it in backticks (`). + +``` +To denote a `word` or `phrase` as code, enclose it in backticks (`). +``` + +## Code blocks + +Use [fenced code blocks](https://www.markdownguide.org/extended-syntax/#fenced-code-blocks) by enclosing code in three backticks and follow the leading ticks with the programming language of your snippet to get syntax highlighting. Optionally, you can also write the name of your code after the programming language. + +```java HelloWorld.java +class HelloWorld { + public static void main(String[] args) { + System.out.println("Hello, World!"); + } +} +``` + +````md +```java HelloWorld.java +class HelloWorld { + public static void main(String[] args) { + System.out.println("Hello, World!"); + } +} +``` +```` diff --git a/docs/essentials/images.mdx b/docs/essentials/images.mdx new file mode 100644 index 0000000..1144eb2 --- /dev/null +++ b/docs/essentials/images.mdx @@ -0,0 +1,59 @@ +--- +title: 'Images and embeds' +description: 'Add image, video, and other HTML elements' +icon: 'image' +--- + + + +## Image + +### Using Markdown + +The [markdown syntax](https://www.markdownguide.org/basic-syntax/#images) lets you add images using the following code + +```md +![title](/path/image.jpg) +``` + +Note that the image file size must be less than 5MB. Otherwise, we recommend hosting on a service like [Cloudinary](https://cloudinary.com/) or [S3](https://aws.amazon.com/s3/). You can then use that URL and embed. + +### Using embeds + +To get more customizability with images, you can also use [embeds](/writing-content/embed) to add images + +```html + +``` + +## Embeds and HTML elements + + + +
+ + + +Mintlify supports [HTML tags in Markdown](https://www.markdownguide.org/basic-syntax/#html). This is helpful if you prefer HTML tags to Markdown syntax, and lets you create documentation with infinite flexibility. + + + +### iFrames + +Loads another HTML page within the document. Most commonly used for embedding videos. + +```html + +``` diff --git a/docs/essentials/markdown.mdx b/docs/essentials/markdown.mdx new file mode 100644 index 0000000..a45c1d5 --- /dev/null +++ b/docs/essentials/markdown.mdx @@ -0,0 +1,88 @@ +--- +title: 'Markdown syntax' +description: 'Text, title, and styling in standard markdown' +icon: 'text-size' +--- + +## Titles + +Best used for section headers. + +```md +## Titles +``` + +### Subtitles + +Best used for subsection headers. + +```md +### Subtitles +``` + + + +Each **title** and **subtitle** creates an anchor and also shows up on the table of contents on the right. + + + +## Text formatting + +We support most markdown formatting. Simply add `**`, `_`, or `~` around text to format it. + +| Style | How to write it | Result | +| ------------- | ----------------- | --------------- | +| Bold | `**bold**` | **bold** | +| Italic | `_italic_` | _italic_ | +| Strikethrough | `~strikethrough~` | ~strikethrough~ | + +You can combine these. For example, write `**_bold and italic_**` to get **_bold and italic_** text. + +You need to use HTML to write superscript and subscript text. That is, add `` or `` around your text. + +| Text Size | How to write it | Result | +| ----------- | ------------------------ | ---------------------- | +| Superscript | `superscript` | superscript | +| Subscript | `subscript` | subscript | + +## Linking to pages + +You can add a link by wrapping text in `[]()`. You would write `[link to google](https://google.com)` to [link to google](https://google.com). + +Links to pages in your docs need to be root-relative. Basically, you should include the entire folder path. For example, `[link to text](/writing-content/text)` links to the page "Text" in our components section. + +Relative links like `[link to text](../text)` will open slower because we cannot optimize them as easily. + +## Blockquotes + +### Singleline + +To create a blockquote, add a `>` in front of a paragraph. + +> Dorothy followed her through many of the beautiful rooms in her castle. + +```md +> Dorothy followed her through many of the beautiful rooms in her castle. +``` + +### Multiline + +> Dorothy followed her through many of the beautiful rooms in her castle. +> +> The Witch bade her clean the pots and kettles and sweep the floor and keep the fire fed with wood. + +```md +> Dorothy followed her through many of the beautiful rooms in her castle. +> +> The Witch bade her clean the pots and kettles and sweep the floor and keep the fire fed with wood. +``` + +### LaTeX + +Mintlify supports [LaTeX](https://www.latex-project.org) through the Latex component. + +8 x (vk x H1 - H2) = (0,1) + +```md +8 x (vk x H1 - H2) = (0,1) +``` diff --git a/docs/essentials/navigation.mdx b/docs/essentials/navigation.mdx new file mode 100644 index 0000000..60adeff --- /dev/null +++ b/docs/essentials/navigation.mdx @@ -0,0 +1,87 @@ +--- +title: 'Navigation' +description: 'The navigation field in docs.json defines the pages that go in the navigation menu' +icon: 'map' +--- + +The navigation menu is the list of links on every website. + +You will likely update `docs.json` every time you add a new page. Pages do not show up automatically. + +## Navigation syntax + +Our navigation syntax is recursive which means you can make nested navigation groups. You don't need to include `.mdx` in page names. + + + +```json Regular Navigation +"navigation": { + "tabs": [ + { + "tab": "Docs", + "groups": [ + { + "group": "Getting Started", + "pages": ["quickstart"] + } + ] + } + ] +} +``` + +```json Nested Navigation +"navigation": { + "tabs": [ + { + "tab": "Docs", + "groups": [ + { + "group": "Getting Started", + "pages": [ + "quickstart", + { + "group": "Nested Reference Pages", + "pages": ["nested-reference-page"] + } + ] + } + ] + } + ] +} +``` + + + +## Folders + +Simply put your MDX files in folders and update the paths in `docs.json`. + +For example, to have a page at `https://yoursite.com/your-folder/your-page` you would make a folder called `your-folder` containing an MDX file called `your-page.mdx`. + + + +You cannot use `api` for the name of a folder unless you nest it inside another folder. Mintlify uses Next.js which reserves the top-level `api` folder for internal server calls. A folder name such as `api-reference` would be accepted. + + + +```json Navigation With Folder +"navigation": { + "tabs": [ + { + "tab": "Docs", + "groups": [ + { + "group": "Group Name", + "pages": ["your-folder/your-page"] + } + ] + } + ] +} +``` + +## Hidden pages + +MDX files not included in `docs.json` will not show up in the sidebar but are accessible through the search bar and by linking directly to them. diff --git a/docs/essentials/reusable-snippets.mdx b/docs/essentials/reusable-snippets.mdx new file mode 100644 index 0000000..376e27b --- /dev/null +++ b/docs/essentials/reusable-snippets.mdx @@ -0,0 +1,110 @@ +--- +title: "Reusable snippets" +description: "Reusable, custom snippets to keep content in sync" +icon: "recycle" +--- + +import SnippetIntro from '/snippets/snippet-intro.mdx'; + + + +## Creating a custom snippet + +**Pre-condition**: You must create your snippet file in the `snippets` directory. + + + Any page in the `snippets` directory will be treated as a snippet and will not + be rendered into a standalone page. If you want to create a standalone page + from the snippet, import the snippet into another file and call it as a + component. + + +### Default export + +1. Add content to your snippet file that you want to re-use across multiple + locations. Optionally, you can add variables that can be filled in via props + when you import the snippet. + +```mdx snippets/my-snippet.mdx +Hello world! This is my content I want to reuse across pages. My keyword of the +day is {word}. +``` + + + The content that you want to reuse must be inside the `snippets` directory in + order for the import to work. + + +2. Import the snippet into your destination file. + +```mdx destination-file.mdx +--- +title: My title +description: My Description +--- + +import MySnippet from '/snippets/path/to/my-snippet.mdx'; + +## Header + +Lorem impsum dolor sit amet. + + +``` + +### Reusable variables + +1. Export a variable from your snippet file: + +```mdx snippets/path/to/custom-variables.mdx +export const myName = 'my name'; + +export const myObject = { fruit: 'strawberries' }; +``` + +2. Import the snippet from your destination file and use the variable: + +```mdx destination-file.mdx +--- +title: My title +description: My Description +--- + +import { myName, myObject } from '/snippets/path/to/custom-variables.mdx'; + +Hello, my name is {myName} and I like {myObject.fruit}. +``` + +### Reusable components + +1. Inside your snippet file, create a component that takes in props by exporting + your component in the form of an arrow function. + +```mdx snippets/custom-component.mdx +export const MyComponent = ({ title }) => ( +
+

{title}

+

... snippet content ...

+
+); +``` + + + MDX does not compile inside the body of an arrow function. Stick to HTML + syntax when you can or use a default export if you need to use MDX. + + +2. Import the snippet into your destination file and pass in the props + +```mdx destination-file.mdx +--- +title: My title +description: My Description +--- + +import { MyComponent } from '/snippets/custom-component.mdx'; + +Lorem ipsum dolor sit amet. + + +``` diff --git a/docs/essentials/settings.mdx b/docs/essentials/settings.mdx new file mode 100644 index 0000000..884de13 --- /dev/null +++ b/docs/essentials/settings.mdx @@ -0,0 +1,318 @@ +--- +title: 'Global Settings' +description: 'Mintlify gives you complete control over the look and feel of your documentation using the docs.json file' +icon: 'gear' +--- + +Every Mintlify site needs a `docs.json` file with the core configuration settings. Learn more about the [properties](#properties) below. + +## Properties + + +Name of your project. Used for the global title. + +Example: `mintlify` + + + + + An array of groups with all the pages within that group + + + The name of the group. + + Example: `Settings` + + + + The relative paths to the markdown files that will serve as pages. + + Example: `["customization", "page"]` + + + + + + + + Path to logo image or object with path to "light" and "dark" mode logo images + + + Path to the logo in light mode + + + Path to the logo in dark mode + + + Where clicking on the logo links you to + + + + + + Path to the favicon image + + + + Hex color codes for your global theme + + + The primary color. Used for most often for highlighted content, section + headers, accents, in light mode + + + The primary color for dark mode. Used for most often for highlighted + content, section headers, accents, in dark mode + + + The primary color for important buttons + + + The color of the background in both light and dark mode + + + The hex color code of the background in light mode + + + The hex color code of the background in dark mode + + + + + + + + Array of `name`s and `url`s of links you want to include in the topbar + + + The name of the button. + + Example: `Contact us` + + + The url once you click on the button. Example: `https://mintlify.com/docs` + + + + + + + + + Link shows a button. GitHub shows the repo information at the url provided including the number of GitHub stars. + + + If `link`: What the button links to. + + If `github`: Link to the repository to load GitHub information from. + + + Text inside the button. Only required if `type` is a `link`. + + + + + + + Array of version names. Only use this if you want to show different versions + of docs with a dropdown in the navigation bar. + + + + An array of the anchors, includes the `icon`, `color`, and `url`. + + + The [Font Awesome](https://fontawesome.com/search?q=heart) icon used to feature the anchor. + + Example: `comments` + + + The name of the anchor label. + + Example: `Community` + + + The start of the URL that marks what pages go in the anchor. Generally, this is the name of the folder you put your pages in. + + + The hex color of the anchor icon background. Can also be a gradient if you pass an object with the properties `from` and `to` that are each a hex color. + + + Used if you want to hide an anchor until the correct docs version is selected. + + + Pass `true` if you want to hide the anchor until you directly link someone to docs inside it. + + + One of: "brands", "duotone", "light", "sharp-solid", "solid", or "thin" + + + + + + + Override the default configurations for the top-most anchor. + + + The name of the top-most anchor + + + Font Awesome icon. + + + One of: "brands", "duotone", "light", "sharp-solid", "solid", or "thin" + + + + + + An array of navigational tabs. + + + The name of the tab label. + + + The start of the URL that marks what pages go in the tab. Generally, this + is the name of the folder you put your pages in. + + + + + + Configuration for API settings. Learn more about API pages at [API Components](/api-playground/demo). + + + The base url for all API endpoints. If `baseUrl` is an array, it will enable for multiple base url + options that the user can toggle. + + + + + + The authentication strategy used for all API endpoints. + + + The name of the authentication parameter used in the API playground. + + If method is `basic`, the format should be `[usernameName]:[passwordName]` + + + The default value that's designed to be a prefix for the authentication input field. + + E.g. If an `inputPrefix` of `AuthKey` would inherit the default input result of the authentication field as `AuthKey`. + + + + + + Configurations for the API playground + + + + Whether the playground is showing, hidden, or only displaying the endpoint with no added user interactivity `simple` + + Learn more at the [playground guides](/api-playground/demo) + + + + + + Enabling this flag ensures that key ordering in OpenAPI pages matches the key ordering defined in the OpenAPI file. + + This behavior will soon be enabled by default, at which point this field will be deprecated. + + + + + + + A string or an array of strings of URL(s) or relative path(s) pointing to your + OpenAPI file. + + Examples: + + ```json Absolute + "openapi": "https://example.com/openapi.json" + ``` + ```json Relative + "openapi": "/openapi.json" + ``` + ```json Multiple + "openapi": ["https://example.com/openapi1.json", "/openapi2.json", "/openapi3.json"] + ``` + + + + + + An object of social media accounts where the key:property pair represents the social media platform and the account url. + + Example: + ```json + { + "x": "https://x.com/mintlify", + "website": "https://mintlify.com" + } + ``` + + + One of the following values `website`, `facebook`, `x`, `discord`, `slack`, `github`, `linkedin`, `instagram`, `hacker-news` + + Example: `x` + + + The URL to the social platform. + + Example: `https://x.com/mintlify` + + + + + + Configurations to enable feedback buttons + + + + Enables a button to allow users to suggest edits via pull requests + + + Enables a button to allow users to raise an issue about the documentation + + + + + + Customize the dark mode toggle. + + + Set if you always want to show light or dark mode for new users. When not + set, we default to the same mode as the user's operating system. + + + Set to true to hide the dark/light mode toggle. You can combine `isHidden` with `default` to force your docs to only use light or dark mode. For example: + + + ```json Only Dark Mode + "modeToggle": { + "default": "dark", + "isHidden": true + } + ``` + + ```json Only Light Mode + "modeToggle": { + "default": "light", + "isHidden": true + } + ``` + + + + + + + + + A background image to be displayed behind every page. See example with + [Infisical](https://infisical.com/docs) and [FRPC](https://frpc.io). + diff --git a/docs/favicon.svg b/docs/favicon.svg new file mode 100644 index 0000000..b785c73 --- /dev/null +++ b/docs/favicon.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/docs/images/checks-passed.png b/docs/images/checks-passed.png new file mode 100644 index 0000000000000000000000000000000000000000..3303c773646ca12fb6852356663540e3ed048115 GIT binary patch literal 160724 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ɊgP+1Kmq9C+NW`N{6BwF_FKP% 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

f_Qe2@sz@M2$uLLxR{EU6s^ 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 + Follow our three step quickstart guide. + + +## Make it yours + +Design a docs site that looks great and empowers your users. + + + + Edit your docs locally and preview them in real time. + + + Customize the design and colors of your site to match your brand. + + + Organize your docs to help users find what they need and succeed with your product. + + + Auto-generate API documentation from OpenAPI specifications. + + + +## Create beautiful pages + +Everything you need to create world-class documentation. + + + + Use MDX to style your docs pages. + + + Add sample code to demonstrate how to use your product. + + + Display images and other media. + + + Write once and reuse across your docs. + + + +## Need inspiration? + + + Browse our showcase of exceptional documentation sites. + diff --git a/docs/logo/dark.svg b/docs/logo/dark.svg new file mode 100644 index 0000000..8b343cd --- /dev/null +++ b/docs/logo/dark.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/logo/light.svg b/docs/logo/light.svg new file mode 100644 index 0000000..03e62bf --- /dev/null +++ b/docs/logo/light.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/quickstart.mdx b/docs/quickstart.mdx new file mode 100644 index 0000000..c711458 --- /dev/null +++ b/docs/quickstart.mdx @@ -0,0 +1,80 @@ +--- +title: "Quickstart" +description: "Start building awesome documentation in minutes" +--- + +## Get started in three steps + +Get your documentation site running locally and make your first customization. + +### Step 1: Set up your local environment + + + + During the onboarding process, you created a GitHub repository with your docs content if you didn't already have one. You can find a link to this repository in your [dashboard](https://dashboard.mintlify.com). + + To clone the repository locally so that you can make and preview changes to your docs, follow the [Cloning a repository](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository) guide in the GitHub docs. + + + 1. Install the Mintlify CLI: `npm i -g mint` + 2. Navigate to your docs directory and run: `mint dev` + 3. Open `http://localhost:3000` to see your docs live! + + Your preview updates automatically as you edit files. + + + +### Step 2: Deploy your changes + + + + Install the Mintlify GitHub app from your [dashboard](https://dashboard.mintlify.com/settings/organization/github-app). + + Our GitHub app automatically deploys your changes to your docs site, so you don't need to manage deployments yourself. + + + For a first change, let's update the name and colors of your docs site. + + 1. Open `docs.json` in your editor. + 2. Change the `"name"` field to your project name. + 3. Update the `"colors"` to match your brand. + 4. Save and see your changes instantly at `http://localhost:3000`. + + Try changing the primary color to see an immediate difference! + + + +### Step 3: Go live + + + 1. Commit and push your changes. + 2. Your docs will update and be live in moments! + + +## Next steps + +Now that you have your docs running, explore these key features: + + + + + Learn MDX syntax and start writing your documentation. + + + + Make your docs match your brand perfectly. + + + + Include syntax-highlighted code blocks. + + + + Auto-generate API docs from OpenAPI specs. + + + + + + **Need help?** See our [full documentation](https://mintlify.com/docs) or join our [community](https://mintlify.com/community). + diff --git a/docs/snippets/snippet-intro.mdx b/docs/snippets/snippet-intro.mdx new file mode 100644 index 0000000..e20fbb6 --- /dev/null +++ b/docs/snippets/snippet-intro.mdx @@ -0,0 +1,4 @@ +One of the core principles of software development is DRY (Don't Repeat +Yourself). This is a principle that applies to documentation as +well. If you find yourself repeating the same content in multiple places, you +should consider creating a custom snippet to keep your content in sync. diff --git a/docs/book.toml b/docss/book.toml similarity index 100% rename from docs/book.toml rename to docss/book.toml diff --git a/docs/mdbook-admonish.css b/docss/mdbook-admonish.css similarity index 100% rename from docs/mdbook-admonish.css rename to docss/mdbook-admonish.css diff --git a/docs/snippets/ethers/deposit-erc20.ts b/docss/snippets/ethers/deposit-erc20.ts similarity index 100% rename from docs/snippets/ethers/deposit-erc20.ts rename to docss/snippets/ethers/deposit-erc20.ts diff --git a/docs/snippets/ethers/deposit-eth.ts b/docss/snippets/ethers/deposit-eth.ts similarity index 100% rename from docs/snippets/ethers/deposit-eth.ts rename to docss/snippets/ethers/deposit-eth.ts diff --git a/docs/snippets/ethers/withdrawals-erc20.ts b/docss/snippets/ethers/withdrawals-erc20.ts similarity index 100% rename from docs/snippets/ethers/withdrawals-erc20.ts rename to docss/snippets/ethers/withdrawals-erc20.ts diff --git a/docs/snippets/ethers/withdrawals-eth.ts b/docss/snippets/ethers/withdrawals-eth.ts similarity index 100% rename from docs/snippets/ethers/withdrawals-eth.ts rename to docss/snippets/ethers/withdrawals-eth.ts diff --git a/docs/snippets/viem/deposit-erc20.ts b/docss/snippets/viem/deposit-erc20.ts similarity index 100% rename from docs/snippets/viem/deposit-erc20.ts rename to docss/snippets/viem/deposit-erc20.ts diff --git a/docs/snippets/viem/deposit-eth.ts b/docss/snippets/viem/deposit-eth.ts similarity index 100% rename from docs/snippets/viem/deposit-eth.ts rename to docss/snippets/viem/deposit-eth.ts diff --git a/docs/snippets/viem/withdrawals-erc20.ts b/docss/snippets/viem/withdrawals-erc20.ts similarity index 100% rename from docs/snippets/viem/withdrawals-erc20.ts rename to docss/snippets/viem/withdrawals-erc20.ts diff --git a/docs/snippets/viem/withdrawals-eth.ts b/docss/snippets/viem/withdrawals-eth.ts similarity index 100% rename from docs/snippets/viem/withdrawals-eth.ts rename to docss/snippets/viem/withdrawals-eth.ts diff --git a/docs/src/SUMMARY.md b/docss/src/SUMMARY.md similarity index 100% rename from docs/src/SUMMARY.md rename to docss/src/SUMMARY.md diff --git a/docs/src/concepts/finalization.md b/docss/src/concepts/finalization.md similarity index 100% rename from docs/src/concepts/finalization.md rename to docss/src/concepts/finalization.md diff --git a/docs/src/concepts/index.md b/docss/src/concepts/index.md similarity index 100% rename from docs/src/concepts/index.md rename to docss/src/concepts/index.md diff --git a/docs/src/concepts/status-vs-wait.md b/docss/src/concepts/status-vs-wait.md similarity index 100% rename from docs/src/concepts/status-vs-wait.md rename to docss/src/concepts/status-vs-wait.md diff --git a/docs/src/guides/deposits/ethers.md b/docss/src/guides/deposits/ethers.md similarity index 100% rename from docs/src/guides/deposits/ethers.md rename to docss/src/guides/deposits/ethers.md diff --git a/docs/src/guides/deposits/index.md b/docss/src/guides/deposits/index.md similarity index 100% rename from docs/src/guides/deposits/index.md rename to docss/src/guides/deposits/index.md diff --git a/docs/src/guides/deposits/viem.md b/docss/src/guides/deposits/viem.md similarity index 100% rename from docs/src/guides/deposits/viem.md rename to docss/src/guides/deposits/viem.md diff --git a/docs/src/guides/index.md b/docss/src/guides/index.md similarity index 100% rename from docs/src/guides/index.md rename to docss/src/guides/index.md diff --git a/docs/src/guides/withdrawals/ethers.md b/docss/src/guides/withdrawals/ethers.md similarity index 100% rename from docs/src/guides/withdrawals/ethers.md rename to docss/src/guides/withdrawals/ethers.md diff --git a/docs/src/guides/withdrawals/index.md b/docss/src/guides/withdrawals/index.md similarity index 100% rename from docs/src/guides/withdrawals/index.md rename to docss/src/guides/withdrawals/index.md diff --git a/docs/src/guides/withdrawals/viem.md b/docss/src/guides/withdrawals/viem.md similarity index 100% rename from docs/src/guides/withdrawals/viem.md rename to docss/src/guides/withdrawals/viem.md diff --git a/docs/src/index.md b/docss/src/index.md similarity index 100% rename from docs/src/index.md rename to docss/src/index.md diff --git a/docs/src/overview/adapters.md b/docss/src/overview/adapters.md similarity index 100% rename from docs/src/overview/adapters.md rename to docss/src/overview/adapters.md diff --git a/docs/src/overview/index.md b/docss/src/overview/index.md similarity index 100% rename from docs/src/overview/index.md rename to docss/src/overview/index.md diff --git a/docs/src/overview/mental-model.md b/docss/src/overview/mental-model.md similarity index 100% rename from docs/src/overview/mental-model.md rename to docss/src/overview/mental-model.md diff --git a/docs/src/overview/what-it-does.md b/docss/src/overview/what-it-does.md similarity index 100% rename from docs/src/overview/what-it-does.md rename to docss/src/overview/what-it-does.md diff --git a/docs/src/quickstart/choose-adapter.md b/docss/src/quickstart/choose-adapter.md similarity index 100% rename from docs/src/quickstart/choose-adapter.md rename to docss/src/quickstart/choose-adapter.md diff --git a/docs/src/quickstart/ethers.md b/docss/src/quickstart/ethers.md similarity index 100% rename from docs/src/quickstart/ethers.md rename to docss/src/quickstart/ethers.md diff --git a/docs/src/quickstart/index.md b/docss/src/quickstart/index.md similarity index 100% rename from docs/src/quickstart/index.md rename to docss/src/quickstart/index.md diff --git a/docs/src/quickstart/viem.md b/docss/src/quickstart/viem.md similarity index 100% rename from docs/src/quickstart/viem.md rename to docss/src/quickstart/viem.md diff --git a/docs/src/reference/helpers.md b/docss/src/reference/helpers.md similarity index 100% rename from docs/src/reference/helpers.md rename to docss/src/reference/helpers.md diff --git a/docs/src/reference/index.md b/docss/src/reference/index.md similarity index 100% rename from docs/src/reference/index.md rename to docss/src/reference/index.md diff --git a/docs/src/reference/methods.md b/docss/src/reference/methods.md similarity index 100% rename from docs/src/reference/methods.md rename to docss/src/reference/methods.md From 43bd597137dd56504c3752d1d2b5607010f3d4a9 Mon Sep 17 00:00:00 2001 From: Dustin Brickwood Date: Mon, 6 Oct 2025 16:21:38 -0500 Subject: [PATCH 02/18] chore: experimenting with new docs framework --- docs/README.md | 2 +- docs/development.mdx | 94 -------------------- docs/docs.json | 131 +++++++++++++++------------- docs/favicon.svg | 22 +---- docs/index.mdx | 115 ++++++++----------------- docs/logo/dark.svg | 52 +++++++---- docs/logo/light.svg | 52 +++++++---- docs/overview/adapters.mdx | 116 +++++++++++++++++++++++++ docs/overview/index.mdx | 123 ++++++++++++++++++++++++++ docs/overview/mental-model.mdx | 153 +++++++++++++++++++++++++++++++++ docs/quickstart.mdx | 80 ----------------- docs/quickstart/ethers.mdx | 132 ++++++++++++++++++++++++++++ docs/quickstart/index.mdx | 49 +++++++++++ docs/quickstart/viem.mdx | 118 +++++++++++++++++++++++++ docs/style.css | 67 +++++++++++++++ 15 files changed, 940 insertions(+), 366 deletions(-) delete mode 100644 docs/development.mdx create mode 100644 docs/overview/adapters.mdx create mode 100644 docs/overview/index.mdx create mode 100644 docs/overview/mental-model.mdx delete mode 100644 docs/quickstart.mdx create mode 100644 docs/quickstart/ethers.mdx create mode 100644 docs/quickstart/index.mdx create mode 100644 docs/quickstart/viem.mdx create mode 100644 docs/style.css diff --git a/docs/README.md b/docs/README.md index 055c983..5297803 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,4 +1,4 @@ -# Mintlify Starter Kit +# ss Use the starter kit to get your docs deployed and ready to customize. diff --git a/docs/development.mdx b/docs/development.mdx deleted file mode 100644 index ac633ba..0000000 --- a/docs/development.mdx +++ /dev/null @@ -1,94 +0,0 @@ ---- -title: 'Development' -description: 'Preview changes locally to update your docs' ---- - - - **Prerequisites**: - - Node.js version 19 or higher - - A docs repository with a `docs.json` file - - -Follow these steps to install and run Mintlify on your operating system. - - - - -```bash -npm i -g mint -``` - - - - -Navigate to your docs directory where your `docs.json` file is located, and run the following command: - -```bash -mint dev -``` - -A local preview of your documentation will be available at `http://localhost:3000`. - - - - -## Custom ports - -By default, Mintlify uses port 3000. You can customize the port Mintlify runs on by using the `--port` flag. For example, to run Mintlify on port 3333, use this command: - -```bash -mint dev --port 3333 -``` - -If you attempt to run Mintlify on a port that's already in use, it will use the next available port: - -```md -Port 3000 is already in use. Trying 3001 instead. -``` - -## Mintlify versions - -Please note that each CLI release is associated with a specific version of Mintlify. If your local preview does not align with the production version, please update the CLI: - -```bash -npm mint update -``` - -## Validating links - -The CLI can assist with validating links in your documentation. To identify any broken links, use the following command: - -```bash -mint broken-links -``` - -## Deployment - -If the deployment is successful, you should see the following: - - - Screenshot of a deployment confirmation message that says All checks have passed. - - -## Code formatting - -We suggest using extensions on your IDE to recognize and format MDX. If you're a VSCode user, consider the [MDX VSCode extension](https://marketplace.visualstudio.com/items?itemName=unifiedjs.vscode-mdx) for syntax highlighting, and [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) for code formatting. - -## Troubleshooting - - - - - This may be due to an outdated version of node. Try the following: - 1. Remove the currently-installed version of the CLI: `npm remove -g mint` - 2. Upgrade to Node v19 or higher. - 3. Reinstall the CLI: `npm i -g mint` - - - - - Solution: Go to the root of your device and delete the `~/.mintlify` folder. Then run `mint dev` again. - - - -Curious about what changed in the latest CLI version? Check out the [CLI changelog](https://www.npmjs.com/package/mintlify?activeTab=versions). diff --git a/docs/docs.json b/docs/docs.json index 46b44cc..93538d4 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -1,87 +1,102 @@ { "$schema": "https://mintlify.com/docs.json", - "theme": "mint", - "name": "Mint Starter Kit", + "theme": "palm", + "name": "ZKsyncOS SDK", "colors": { - "primary": "#16A34A", - "light": "#07C983", - "dark": "#15803D" + "primary": "#1755F4", + "light": "#13D5D3", + "dark": "#0C18EC" }, "favicon": "/favicon.svg", - "navigation": { +"navigation": { "tabs": [ { - "tab": "Guides", + "tab": "Home", + "icon": "house", "groups": [ { - "group": "Getting started", + "group": "Overview", "pages": [ - "index", - "quickstart", - "development" + "index" ] - }, - { - "group": "Customization", - "pages": [ - "essentials/settings", - "essentials/navigation" - ] - }, + } + ] + }, + { + "tab": "Getting Started", + "icon": "play", + "groups": [ + { + "group": "Overview", + "pages": [ + "overview/index", + "overview/mental-model", + "overview/adapters" + ] + }, + { + "group": "Quickstart", + "pages": [ + "quickstart/index", + "quickstart/viem", + "quickstart/ethers" + ] + }, + { + "group": "Guides", + "pages": [ + "guides/index", + "guides/deposits/viem", + "guides/deposits/ethers", + "guides/withdrawals/viem", + "guides/withdrawals/ethers" + ] + }, + { + "group": "Concepts", + "pages": [ + "concepts/index", + "concepts/status-vs-wait", + "concepts/finalization" + ] + } + ] + }, + { + "tab": "API Reference", + "icon": "code", + "groups": [ { - "group": "Writing content", + "group": "Core", "pages": [ - "essentials/markdown", - "essentials/code", - "essentials/images", - "essentials/reusable-snippets" + "api-reference/introduction", + "api-reference/core/client", + "api-reference/core/types", + "api-reference/core/errors" ] }, { - "group": "AI tools", + "group": "Adapters", "pages": [ - "ai-tools/cursor", - "ai-tools/claude-code", - "ai-tools/windsurf" + "api-reference/adapters/ethers", + "api-reference/adapters/viem" ] } ] }, { - "tab": "API reference", + "tab": "Changelog", + "icon": "calendar", "groups": [ { - "group": "API documentation", - "pages": [ - "api-reference/introduction" - ] - }, - { - "group": "Endpoint examples", + "group": "Releases", "pages": [ - "api-reference/endpoint/get", - "api-reference/endpoint/create", - "api-reference/endpoint/delete", - "api-reference/endpoint/webhook" + "changelog" ] } ] } - ], - "global": { - "anchors": [ - { - "anchor": "Documentation", - "href": "https://mintlify.com/docs", - "icon": "book-open-cover" - }, - { - "anchor": "Blog", - "href": "https://mintlify.com/blog", - "icon": "newspaper" - } - ] - } + ] }, "logo": { "light": "/logo/light.svg", @@ -114,9 +129,9 @@ }, "footer": { "socials": { - "x": "https://x.com/mintlify", - "github": "https://github.com/mintlify", - "linkedin": "https://linkedin.com/company/mintlify" + "x": "https://x.com/zksync", + "github": "https://github.com/dutterbutter/zksync-sdk", + "linkedin": "https://linkedin.com/company/matter-labs" } } } diff --git a/docs/favicon.svg b/docs/favicon.svg index b785c73..5261fc4 100644 --- a/docs/favicon.svg +++ b/docs/favicon.svg @@ -1,19 +1,5 @@ - - - - - - - - - - - - - - - - - - + + + + diff --git a/docs/index.mdx b/docs/index.mdx index 15c23fb..43eda51 100644 --- a/docs/index.mdx +++ b/docs/index.mdx @@ -1,97 +1,54 @@ --- -title: "Introduction" -description: "Welcome to the new home for your documentation" +title: "Custom page title" +mode: "center" --- -## Setting up +

-Get your documentation site up and running in minutes. - - - Follow our three step quickstart guide. - - -## Make it yours +--- -Design a docs site that looks great and empowers your users. +## Quickstart guides - - - Edit your docs locally and preview them in real time. + + + Send ETH from Ethereum to ZKsync, then track inclusion on L1 and execution on L2. + + + Create the withdrawal on ZKsync, monitor execution, and finalize back on Ethereum. + + + Install the viem adapter, connect clients, and run your first deposit. - - Customize the design and colors of your site to match your brand. + + Use an ethers v6 signer to perform a deposit and wait for finality. - - Organize your docs to help users find what they need and succeed with your product. + + Understand statuses vs waits and how to poll each phase of a flow. - - Auto-generate API documentation from OpenAPI specifications. + + Utilities like getBridgehubAddress, getL2ToL1LogProof, and enhanced receipts. -## Create beautiful pages +--- -Everything you need to create world-class documentation. +## Resources - - - Use MDX to style your docs pages. - - - Add sample code to demonstrate how to use your product. + + + Fully typed clients, methods, and errors for core and adapters. - - Display images and other media. + + See what’s new, fixed, and changed across releases. - - Write once and reuse across your docs. + + Questions or issues? Reach out and we’ll help you integrate quickly. - -## Need inspiration? - - - Browse our showcase of exceptional documentation sites. - diff --git a/docs/logo/dark.svg b/docs/logo/dark.svg index 8b343cd..2377d63 100644 --- a/docs/logo/dark.svg +++ b/docs/logo/dark.svg @@ -1,21 +1,37 @@ - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + diff --git a/docs/logo/light.svg b/docs/logo/light.svg index 03e62bf..a662169 100644 --- a/docs/logo/light.svg +++ b/docs/logo/light.svg @@ -1,21 +1,37 @@ - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + diff --git a/docs/overview/adapters.mdx b/docs/overview/adapters.mdx new file mode 100644 index 0000000..7f86f07 --- /dev/null +++ b/docs/overview/adapters.mdx @@ -0,0 +1,116 @@ +--- +title: Adapters (viem & ethers) +description: Learn how the SDK extends your existing viem or ethers setup with ZKsync-specific functionality. +--- + +# Adapters: `viem` & `ethers` + +The SDK is designed to work _with_ the tools you already know and love. +It’s not a standalone library — it’s an **extension** that plugs directly into your existing [`viem`](https://viem.sh) or [`ethers.js`](https://docs.ethers.io/) setup. + + +This design means you can keep your existing provider, signer, and connection logic. +The SDK simply layers ZKsync-specific actions on top. + + +## Why an Adapter Model? + +- **Bring Your Own Stack:** Integrates directly with `viem` (`PublicClient`, `WalletClient`) or `ethers` providers and signers. +- **Familiar Developer Experience:** Keep your existing connection and signing flow unchanged. +- **Lightweight & Focused:** Only adds ZKsync-specific functionality like deposits, withdrawals, and soon interop — nothing more. + +## Installation + +```bash +# For viem users +npm install @dutterbutter/zksync-sdk viem + +# For ethers.js users +npm install @dutterbutter/zksync-sdk ethers +```` + + +You install the **core SDK** plus the adapter matching your stack. + + +## How to Use + +The SDK extends your existing client. Configure **viem** or **ethers** normally, then wrap them with the SDK’s adapter factory. + + +```ts viem.ts +import { createPublicClient, http, createWalletClient, parseEther } from "viem"; +import { createViemSdk, createViemClient } from "@dutterbutter/zksync-sdk/viem"; +import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; + +const l1 = createPublicClient({ transport: http(L1_RPC) }); +const l2 = createPublicClient({ transport: http(L2_RPC) }); + +const l1Wallet: WalletClient = createWalletClient({ + account, + transport: http(L1_RPC), + }); + +const client = createViemClient({ l1, l2, l1Wallet }); +const sdk = createViemSdk(client); + +const me = account.address as Address; +const params = { + amount: parseEther('0.01'), + token: ETH_ADDRESS, + to: me, + // optional: + // l2GasLimit: 300_000n, + // gasPerPubdata: 800n, + // operatorTip: 0n, + // refundRecipient: me, +} as const; + +const handle = await sdk.deposits.create({ params }); +await sdk.deposits.wait(handle, { for: 'l1' }); // L1 included +await sdk.deposits.wait(handle, { for: 'l2' }); // L2 executed + +console.log('Deposit complete ✅'); +``` + +```ts ethers.ts +import { JsonRpcProvider, Wallet, parseEther } from 'ethers'; +import { createEthersClient, createEthersSdk } from '@dutterbutter/zksync-sdk/ethers'; +import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; + +const L1_RPC = new JsonRpcProvider('https://sepolia.infura.io/v3/...'); +const L2_RPC = new JsonRpcProvider('https://zksync-testnet.rpc'); +const signer = new Wallet(process.env.PRIVATE_KEY!, L1_RPC); + +const client = await createEthersClient({ l1Provider: L1_RPC, l2Provider: L2_RPC, signer }); +const sdk = createEthersSdk(client); + +const params = { + amount: parseEther('0.01'), + token: ETH_ADDRESS, + to: signer.address, + // optional: + // l2GasLimit: 300_000n, + // gasPerPubdata: 800n, + // operatorTip: 0n, + // refundRecipient: me, +} as const; + +const handle = await sdk.deposits.create({ params }); +await sdk.deposits.wait(handle, { for: 'l1' }); // L1 included +await sdk.deposits.wait(handle, { for: 'l2' }); // L2 executed + +console.log('Deposit complete ✅'); +``` + + +## Key Principles + +* **No Key Management:** The SDK never asks for or stores private keys — signing stays with your `WalletClient` or `Signer`. +* **API Parity:** Both adapters expose the same API. Calling `sdk.deposits.quote()` works identically with `viem` or `ethers`. +* **Easy Migration:** Switch between `ethers` and `viem` by only changing the initialization code. + + diff --git a/docs/overview/index.mdx b/docs/overview/index.mdx new file mode 100644 index 0000000..3ae83e0 --- /dev/null +++ b/docs/overview/index.mdx @@ -0,0 +1,123 @@ +--- +title: Welcome +description: Learn what the `@zksync-sdk` is and how it simplifies ZKsync cross-chain flows for viem and ethers. +--- + +# Introduction + +The **`@zksync-sdk`** is a lightweight extension for [`viem`](https://viem.sh) and [`ethers`](https://docs.ethers.io/) that makes ZKsync cross-chain actions simple and consistent. + +Instead of re-implementing accounts or low-level RPC logic, this SDK focuses only on **ZKsync-specific flows**: + +- Deposits (L1 → L2) +- Withdrawals (L2 → L1, including finalization) +- Try variants for functional error handling (e.g. ) +- Status & wait helpers +- ZKsync-specific JSON-RPC methods + + +The SDK doesn’t replace your existing Ethereum libraries — it **extends** them with ZKsync-only capabilities while keeping your current tooling intact. + + +### Key Supported Features + +- **Deposits (L1 → L2)** — ETH, Custom Base Token and ERC-20 + - **Initiate on L1:** build and send the deposit transaction from Ethereum. + - **Track progress:** query intermediate states (queued, included, executed). + - **Verify completion on L2:** confirm funds credited/available on ZKsync. + +- **Withdrawals (L2 → L1)** — ETH, Custom Base Token and ERC-20 + - **Initiate on L2:** create the withdrawal transaction on ZKsync. + - **Track progress:** monitor execution and finalization availability. + - **Finalize on L1:** finalize withdrawal to release funds back to Ethereum. + +- **ZKsync RPC Enhancements** + - **`getBridgehubAddress`** (`zks_getBridgehubContract`) – resolve the canonical Bridgehub contract address. + - **`getL2ToL1LogProof`** (`zks_getL2ToL1LogProof`) – retrieve the log proof for an L2 → L1 transaction. + - **`getReceiptWithL2ToL1`** *(receipt extension)* – returns a standard Ethereum `TransactionReceipt` **augmented** with `l2ToL1Logs`. + +## What you’ll find here + +- [**What this SDK does**](./what-it-does) — the purpose, scope, and non-goals. +- [**Mental model**](./mental-model) — how to think about the core methods (`quote → prepare → create → status → wait → finalize`). +- [**Adapters (viem & ethers)**](./adapters) — how the SDK integrates with your existing stack. + +## Quick Example + +Here's how a simple deposit looks like using both **`viem`** and **`ethers`** adapters: + + +```ts viem.ts +import { createPublicClient, http, createWalletClient, parseEther } from "viem"; +import { createViemSdk, createViemClient } from "@dutterbutter/zksync-sdk/viem"; +import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; + +const l1 = createPublicClient({ transport: http(L1_RPC) }); +const l2 = createPublicClient({ transport: http(L2_RPC) }); + +const l1Wallet: WalletClient = createWalletClient({ + account, + transport: http(L1_RPC), + }); + +const client = createViemClient({ l1, l2, l1Wallet }); +const sdk = createViemSdk(client); + +const me = account.address as Address; +const params = { + amount: parseEther('0.01'), + token: ETH_ADDRESS, + to: me, + // optional: + // l2GasLimit: 300_000n, + // gasPerPubdata: 800n, + // operatorTip: 0n, + // refundRecipient: me, +} as const; + +const handle = await sdk.deposits.create({ params }); +await sdk.deposits.wait(handle, { for: 'l1' }); // L1 included +await sdk.deposits.wait(handle, { for: 'l2' }); // L2 executed + +console.log('Deposit complete ✅'); +``` + +```ts ethers.ts +import { JsonRpcProvider, Wallet, parseEther } from 'ethers'; +import { createEthersClient, createEthersSdk } from '@dutterbutter/zksync-sdk/ethers'; +import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; + +const L1_RPC = new JsonRpcProvider('https://sepolia.infura.io/v3/...'); +const L2_RPC = new JsonRpcProvider('https://zksync-testnet.rpc'); +const signer = new Wallet(process.env.PRIVATE_KEY!, L1_RPC); + +const client = await createEthersClient({ l1Provider: L1_RPC, l2Provider: L2_RPC, signer }); +const sdk = createEthersSdk(client); + +const params = { + amount: parseEther('0.01'), + token: ETH_ADDRESS, + to: signer.address, + // optional: + // l2GasLimit: 300_000n, + // gasPerPubdata: 800n, + // operatorTip: 0n, + // refundRecipient: me, +} as const; + +const handle = await sdk.deposits.create({ params }); +await sdk.deposits.wait(handle, { for: 'l1' }); // L1 included +await sdk.deposits.wait(handle, { for: 'l2' }); // L2 executed + +console.log('Deposit complete ✅'); +``` + + +## Next steps + +👉 Ready to build? Jump to the [Quickstart](../quickstart/index). + + diff --git a/docs/overview/mental-model.mdx b/docs/overview/mental-model.mdx new file mode 100644 index 0000000..ae9d669 --- /dev/null +++ b/docs/overview/mental-model.mdx @@ -0,0 +1,153 @@ +--- +title: Mental model +description: Understand the predictable lifecycle (`quote → prepare → create → status → wait → finalize`) that powers every L1–L2 and L2–L1 action in the SDK. +--- + +# Mental Model + +The SDK is designed around a **predictable, layered API** for handling L1 → L2 and L2 → L1 operations. +Every action — whether a deposit or a withdrawal — follows a consistent lifecycle. +Understanding this lifecycle is key to using the SDK effectively. + +```bash +quote → prepare → create → status → wait → (finalize*) +```` + +* The first five steps are common to both **Deposits** and **Withdrawals**. +* Withdrawals require an additional **`finalize`** step to prove and claim funds on L1. + + +You can enter this lifecycle at **different stages** depending on how much control you need. + + +## The Core API: A Layered Approach + +The core methods give you **progressively more automation**. +Start by just gathering info (`quote`), move to building transactions yourself (`prepare`), or execute the entire flow with a single call (`create`). + +### `quote(params)` + +> *"What will this operation involve and cost?"* + +* **Read-only dry run**: performs no transactions and has no side effects. +* Returns a `Quote` object with estimated fees, gas costs, and the planned steps. + + +Best for **displaying a confirmation screen** or cost estimate to a user before committing. + + +### `prepare(params)` + +> *"Build the transactions for me, but let me send them."* + +* Constructs all necessary transactions as an array of `TransactionRequest` objects inside a `Plan`. +* Does **not** sign or send them. + + +Best for **custom workflows** (e.g., multisigs or when you want to review the raw tx data before signing). + + +### `create(params)` + +> *"Prepare, sign, and send in one go."* + +* Calls `prepare` internally, then signs & dispatches the txs using your configured signer. +* Returns a `Handle` — a lightweight tracker for later `status` or `wait`. + + +Best for **standard use cases** where you just want to kick off a deposit or withdrawal. + + +### `status(handle | txHash)` + +> *"Where is my transaction right now?"* + +* Non-blocking: returns the **current state** of an operation. +* Works with a `Handle` or raw transaction hash. + +Example return values: + +```ts +// Deposits +{ phase: 'L1_PENDING' | 'L2_EXECUTED' } + +// Withdrawals +{ phase: 'L1_INCLUDED' | 'L2_PENDING' | 'READY_TO_FINALIZE' | 'FINALIZED' } +``` + + +Best for **polling in a UI** to show live progress without blocking. + + +### `wait(handle, { for })` + +> *"Pause until a specific checkpoint is reached."* + +* Blocking async method: polls until the desired checkpoint, then resolves with the tx receipt. + +Common checkpoints: + +* **Deposits:** `'l1'` (included on L1) or `'l2'` (executed on L2). +* **Withdrawals:** `'l2'` (included), `'ready'` (ready to finalize), `'finalized'` (L1 finalization done). + + +Best for **scripts or backends** that need to ensure one step is complete before the next. + + +### `finalize(l2TxHash)` *(Withdrawals Only)* + +> *"My funds are ready on L1. Finalize and release them."* + +* Executes the **final step** of a withdrawal after `status` reports `READY_TO_FINALIZE`. + + +Best for **claiming funds back to Ethereum** once the withdrawal is ready. + + +## Error Handling: The `try*` Philosophy + +For functional-style error handling (no `try/catch`), every core method has a **`try*` variant** (`tryQuote`, `tryCreate`, etc.). + +```ts +// Imperative style +try { + const handle = await sdk.withdrawals.create(params); + // happy path +} catch (error) { + // sad path +} + +// Functional style +const result = await sdk.withdrawals.tryCreate(params); + +if (result.ok) { + const handle = result.value; +} else { + console.error('Withdrawal failed:', result.error); +} +``` + + +Best for **applications that want explicit, predictable error handling** and to avoid uncaught exceptions. + + +## Putting It All Together + +You can compose flows as simple or complex as needed. + +### Simple Flow + +```ts +// 1. Create the deposit +const depositHandle = await sdk.deposits.create(params); + +// 2. Wait for it to be finalized on L2 +const receipt = await sdk.deposits.wait(depositHandle, { for: 'l2' }); + +console.log('Deposit complete!'); +``` + + diff --git a/docs/quickstart.mdx b/docs/quickstart.mdx deleted file mode 100644 index c711458..0000000 --- a/docs/quickstart.mdx +++ /dev/null @@ -1,80 +0,0 @@ ---- -title: "Quickstart" -description: "Start building awesome documentation in minutes" ---- - -## Get started in three steps - -Get your documentation site running locally and make your first customization. - -### Step 1: Set up your local environment - - - - During the onboarding process, you created a GitHub repository with your docs content if you didn't already have one. You can find a link to this repository in your [dashboard](https://dashboard.mintlify.com). - - To clone the repository locally so that you can make and preview changes to your docs, follow the [Cloning a repository](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository) guide in the GitHub docs. - - - 1. Install the Mintlify CLI: `npm i -g mint` - 2. Navigate to your docs directory and run: `mint dev` - 3. Open `http://localhost:3000` to see your docs live! - - Your preview updates automatically as you edit files. - - - -### Step 2: Deploy your changes - - - - Install the Mintlify GitHub app from your [dashboard](https://dashboard.mintlify.com/settings/organization/github-app). - - Our GitHub app automatically deploys your changes to your docs site, so you don't need to manage deployments yourself. - - - For a first change, let's update the name and colors of your docs site. - - 1. Open `docs.json` in your editor. - 2. Change the `"name"` field to your project name. - 3. Update the `"colors"` to match your brand. - 4. Save and see your changes instantly at `http://localhost:3000`. - - Try changing the primary color to see an immediate difference! - - - -### Step 3: Go live - - - 1. Commit and push your changes. - 2. Your docs will update and be live in moments! - - -## Next steps - -Now that you have your docs running, explore these key features: - - - - - Learn MDX syntax and start writing your documentation. - - - - Make your docs match your brand perfectly. - - - - Include syntax-highlighted code blocks. - - - - Auto-generate API docs from OpenAPI specs. - - - - - - **Need help?** See our [full documentation](https://mintlify.com/docs) or join our [community](https://mintlify.com/community). - diff --git a/docs/quickstart/ethers.mdx b/docs/quickstart/ethers.mdx new file mode 100644 index 0000000..c09873c --- /dev/null +++ b/docs/quickstart/ethers.mdx @@ -0,0 +1,132 @@ +--- +title: Ethers Deposits +description: Get your first ETH deposit from Ethereum to ZKsync using the ethers adapter of @zksync-sdk. +--- + +# Quickstart (ethers): ETH Deposit (L1 → L2) + +This guide walks you through sending your first **ETH deposit** from Ethereum (L1) to ZKsync (L2) using the **ethers** adapter. + +## 1. Prerequisites + +- You have [Bun](https://bun.sh/) installed. +- A funded **L1 wallet** with ETH for both the deposit amount and L1 gas fees + + +Use a test network like **Sepolia** for experimentation. + + +## 2. Installation + +```bash +bun install @dutterbutter/zksync-sdk ethers dotenv +``` + +Create a `.env` file in your project root: + +```env +# Your funded L1 private key (0x + 64 hex) +PRIVATE_KEY=0xYOUR_PRIVATE_KEY_HERE + +# RPC endpoints +L1_RPC_URL=https://sepolia.infura.io/v3/YOUR_INFURA_ID +L2_RPC_URL=ZKSYNC-OS-TESTNET-RPC +``` + + +Never commit your `.env` file to source control. + + +## 3. Write the deposit script + +Save as **`deposit-ethers.ts`**: + +```ts +import 'dotenv/config'; // Load environment variables from .env +import { JsonRpcProvider, Wallet, parseEther } from 'ethers'; +import { createEthersClient, createEthersSdk } from '@dutterbutter/zksync-sdk/ethers'; +import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; + +const PRIVATE_KEY = process.env.PRIVATE_KEY; +const L1_RPC_URL = process.env.L1_RPC_URL; +const L2_RPC_URL = process.env.L2_RPC_URL; + +async function main() { + if (!PRIVATE_KEY || !L1_RPC_URL || !L2_RPC_URL) { + throw new Error('Please set your PRIVATE_KEY, L1_RPC_URL, and L2_RPC_URL in a .env file'); + } + + // 1. SET UP PROVIDERS AND SIGNER + // The SDK needs connections to both L1 and L2 to function. + const l1Provider = new JsonRpcProvider(L1_RPC_URL); + const l2Provider = new JsonRpcProvider(L2_RPC_URL); + const signer = new Wallet(PRIVATE_KEY, l1Provider); + + // 2. INITIALIZE THE SDK CLIENT + // The client is the low-level interface for interacting with the API. + const client = await createEthersClient({ + l1Provider, + l2Provider, + signer, + }); + const sdk = createEthersSdk(client); + + const L1balance = await l1.getBalance({ address: signer.address }); + const L2balance = await l2.getBalance({ address: signer.address }); + + console.log('Wallet balance on L1:', L1balance); + console.log('Wallet balance on L2:', L2balance); + + // 3. PERFORM THE DEPOSIT + // The create() method prepares and sends the transaction. + // The wait() method polls until the transaction is complete. + console.log('Sending deposit transaction...'); + const depositHandle = await sdk.deposits.create({ + token: ETH_ADDRESS, + amount: parseEther('0.001'), // 0.001 ETH + to: account.address, + }); + + console.log(`L1 transaction hash: ${depositHandle.l1TxHash}`); + console.log('Waiting for the deposit to be confirmed on L1...'); + + // Wait for L1 inclusion + const l1Receipt = await sdk.deposits.wait(depositHandle, { for: 'l1' }); + console.log(`Deposit confirmed on L1 in block ${l1Receipt?.blockNumber}`); + + console.log('Waiting for the deposit to be executed on L2...'); + + // Wait for L2 execution + const l2Receipt = await sdk.deposits.wait(depositHandle, { for: 'l2' }); + console.log(`Deposit executed on L2 in block ${l2Receipt?.blockNumber}`); + console.log('Deposit complete! ✅'); + + const L1balanceAfter = await l1.getBalance({ address: signer.address }); + const L2balanceAfter = await l2.getBalance({ address: signer.address }); + + console.log('Wallet balance on L1 after:', L1balanceAfter); + console.log('Wallet balance on L2 after:', L2balanceAfter); +} + +main().catch((error) => { + console.error('An error occurred:', error); + process.exit(1); +}); +``` + +## 4. Run it + +Execute the script using `bun`. + +```bash bun +bun run deposit-ethers.ts +``` + +You’ll see logs for the L1 transaction, then L2 execution, followed by updated balances. + +## 5. Troubleshooting + +- **Insufficient funds on L1:** Ensure enough ETH for the deposit **and** L1 gas. - **Invalid PRIVATE_KEY:** Must be 0x + 64 hex chars. +- **Invalid PRIVATE_KEY:** Must be 0x + 64 hex chars. +- **Stuck at wait(..., `{ for: 'l2' }`):** Verify L2_RPC_URL and network health; check sdk.deposits.status(handle) to see the current phase. +- **ERC-20 deposits:** Make sure you have an L1 token deployed and a sufficient balance. diff --git a/docs/quickstart/index.mdx b/docs/quickstart/index.mdx new file mode 100644 index 0000000..f9cbefd --- /dev/null +++ b/docs/quickstart/index.mdx @@ -0,0 +1,49 @@ +--- +title: Adapter Choice +description: Get your first ZKsync deposit done using the @zksync-sdk. +--- + +# Choosing Your Adapter: `viem` vs. `ethers` + +The SDK is designed to work with both `viem` and `ethers.js`, the two most popular Ethereum libraries. Since the SDK offers **identical functionality** for both, the choice comes down to your project's needs and your personal preference. + +## The Short Answer (TL;DR) + +- **If you're adding the SDK to an existing project:** Use the adapter for the library you're already using. +- **If you're starting a new project:** The choice is yours. `viem` is generally recommended for new projects due to its modern design, smaller bundle size, and excellent TypeScript support. + +You can't make a wrong choice. Both adapters are fully supported and provide the same features. + + + + For projects using **viem**. Learn how to install the `viem` adapter, + connect an L1 + L2 client, and send your first deposit. + + + + For projects using **ethers v6**. Learn how to install the `ethers` adapter, + connect an L1 + L2 client, and send your first deposit. + + + +## What you’ll do + +Each Quickstart walks you through: + +1. **Install** the adapter package. +2. **Configure** a client or signer. +3. **Run** a deposit (L1 → L2) as a working example. +4. **Track** the status until it’s complete. + + +Once you’re set up, continue to the +[How-to Guides](../guides/index.md) for deeper usage patterns and advanced flows. + diff --git a/docs/quickstart/viem.mdx b/docs/quickstart/viem.mdx new file mode 100644 index 0000000..3421ce7 --- /dev/null +++ b/docs/quickstart/viem.mdx @@ -0,0 +1,118 @@ +--- +title: Viem Deposits +description: Get your first ETH deposit from Ethereum to ZKsync using the viem adapter of @zksync-sdk. +--- + +# Quickstart (viem): ETH Deposit (L1 → L2) + +This guide walks you through sending your first **ETH deposit** from Ethereum (L1) to ZKsync (L2) using the **viem** adapter. + +## 1. Prerequisites + +- [Bun](https://bun.sh/) installed +- A funded **L1 wallet** with ETH for both the deposit amount and L1 gas fees + + +Use a test network like **Sepolia** for experimentation. + + +## 2. Install dependencies + +```bash bun +bun install @dutterbutter/zksync-sdk viem dotenv +``` + +Create a `.env` file in your project root: + +```env +# Your funded L1 private key (0x + 64 hex) +PRIVATE_KEY=0xYOUR_PRIVATE_KEY_HERE + +# RPC endpoints +L1_RPC_URL=https://sepolia.infura.io/v3/YOUR_INFURA_ID +L2_RPC_URL=ZKSYNC-OS-TESTNET-RPC +``` + + +Never commit your `.env` file to source control. + + +## 3. Write the deposit script + +Save as **`deposit-viem.ts`**: + +```ts +import 'dotenv/config'; +import { createPublicClient, createWalletClient, http, parseEther } from 'viem'; +import { privateKeyToAccount } from 'viem/accounts'; +import { createViemClient, createViemSdk } from '@dutterbutter/zksync-sdk/viem'; +import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; + +const PRIVATE_KEY = process.env.PRIVATE_KEY; +const L1_RPC_URL = process.env.L1_RPC_URL; +const L2_RPC_URL = process.env.L2_RPC_URL; + +async function main() { + if (!PRIVATE_KEY || !L1_RPC_URL || !L2_RPC_URL) { + throw new Error('Please set PRIVATE_KEY, L1_RPC_URL, and L2_RPC_URL in your .env file'); + } + + // 1. Set up clients + const account = privateKeyToAccount(PRIVATE_KEY as `0x${string}`); + const l1 = createPublicClient({ transport: http(L1_RPC_URL) }); + const l2 = createPublicClient({ transport: http(L2_RPC_URL) }); + const l1Wallet = createWalletClient({ account, transport: http(L1_RPC_URL) }); + + // 2. Initialize the SDK + const client = createViemClient({ l1, l2, l1Wallet }); + const sdk = createViemSdk(client); + + console.log('Wallet balances:'); + console.log(' L1:', await l1.getBalance({ address: account.address })); + console.log(' L2:', await l2.getBalance({ address: account.address })); + + // 3. Perform the deposit + console.log('Sending deposit transaction...'); + const depositHandle = await sdk.deposits.create({ + token: ETH_ADDRESS, + amount: parseEther('0.001'), + to: account.address, + }); + + console.log(`L1 transaction hash: ${depositHandle.l1TxHash}`); + + console.log('Waiting for confirmation on L1...'); + const l1Receipt = await sdk.deposits.wait(depositHandle, { for: 'l1' }); + console.log(`✔️ Confirmed on L1 at block ${l1Receipt?.blockNumber}`); + + console.log('Waiting for execution on L2...'); + const l2Receipt = await sdk.deposits.wait(depositHandle, { for: 'l2' }); + console.log(`✔️ Executed on L2 at block ${l2Receipt?.blockNumber}`); + + console.log('Deposit complete ✅'); + + console.log('Updated balances:'); + console.log(' L1:', await l1.getBalance({ address: account.address })); + console.log(' L2:', await l2.getBalance({ address: account.address })); +} + +main().catch((err) => { + console.error('An error occurred:', err); + process.exit(1); +}); +``` + +## 4. Run it + +```bash bun +bun run deposit-viem.ts +``` + +You’ll see logs for the L1 transaction, then L2 execution, followed by updated balances. + +## 5. Troubleshooting + +- **Insufficient funds on L1:** Ensure enough ETH for the deposit **and** L1 gas. - **Invalid PRIVATE_KEY:** Must be 0x + 64 hex chars. +- **Invalid PRIVATE_KEY:** Must be 0x + 64 hex chars. +- **Stuck at wait(..., `{ for: 'l2' }`):** Verify L2_RPC_URL and network health; check sdk.deposits.status(handle) to see the current phase. +- **ERC-20 deposits:** Make sure you have an L1 token deployed and a sufficient balance. diff --git a/docs/style.css b/docs/style.css new file mode 100644 index 0000000..75a32d5 --- /dev/null +++ b/docs/style.css @@ -0,0 +1,67 @@ +/* ===== Hero (Bridge-style) ===== */ +.hero { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + padding: 120px 16px 96px; + margin: -24px -24px 0; /* stretch to page edges if your theme pads content */ +} + +/* Dot grid + soft gradient (light) */ +.hero { + background: + radial-gradient(rgba(19,213,211,0.28) 1px, transparent 1.2px) 0 0 / 16px 16px, + linear-gradient(180deg, rgba(19,213,211,0.14), rgba(19,213,211,0) 60%); +} + +/* Dark mode variant */ +:root.dark .hero, +.dark .hero { + background: + radial-gradient(rgba(23,85,244,0.28) 1px, transparent 1.2px) 0 0 / 16px 16px, + linear-gradient(180deg, rgba(23,85,244,0.18), rgba(23,85,244,0) 60%); +} + +.hero h1 { + font-size: clamp(2.5rem, 6vw, 4rem); + line-height: 1.1; + letter-spacing: -0.02em; + margin: 0 0 16px; + font-weight: 800; +} + +.hero-subtitle { + max-width: 880px; + font-size: clamp(1.05rem, 2vw, 1.25rem); + line-height: 1.65; + opacity: 0.9; + margin: 0 0 32px; +} + +/* CTA button; uses your palette (fallbacks included) */ +.hero-cta { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 8px; + padding: 14px 22px; + border-radius: 12px; + font-weight: 600; + text-decoration: none; + color: #ffffff; + background: var(--color-primary, #1755F4); + box-shadow: 0 6px 16px rgba(0,0,0,0.08); + transition: transform .06s ease, box-shadow .2s ease, background-color .2s ease; +} +.hero-cta:hover { + transform: translateY(-1px); + box-shadow: 0 10px 20px rgba(0,0,0,0.12); + background: var(--color-primary-dark, #0C18EC); +} + +/* optional: larger hero on wide screens */ +@media (min-width: 1024px) { + .hero { padding: 140px 16px 110px; } +} From 16a9196ff75968c5ff4a79b94507c4bb96857cb6 Mon Sep 17 00:00:00 2001 From: Dustin Brickwood Date: Mon, 6 Oct 2025 16:30:45 -0500 Subject: [PATCH 03/18] chore: experimenting with new docs framework --- docs/index.mdx | 83 +++++++++++++++++++++++++------------------------- docs/style.css | 57 +++++++++++++++++++++++++--------- 2 files changed, 84 insertions(+), 56 deletions(-) diff --git a/docs/index.mdx b/docs/index.mdx index 43eda51..7d41dad 100644 --- a/docs/index.mdx +++ b/docs/index.mdx @@ -1,9 +1,10 @@ --- -title: "Custom page title" -mode: "center" +title: ZKsyncOS SDK +description: Lightweight adapters for viem and ethers to build ZKsync L1↔L2 flows fast. +mode: "custom" --- -
+

Build with @zksync-sdk.

Extend viem and ethers with ZKsync-specific flows — deposits, @@ -12,43 +13,41 @@ mode: "center" Get started →

---- - -## Quickstart guides - - - - Send ETH from Ethereum to ZKsync, then track inclusion on L1 and execution on L2. - - - Create the withdrawal on ZKsync, monitor execution, and finalize back on Ethereum. - - - Install the viem adapter, connect clients, and run your first deposit. - - - Use an ethers v6 signer to perform a deposit and wait for finality. - - - Understand statuses vs waits and how to poll each phase of a flow. - - - Utilities like getBridgehubAddress, getL2ToL1LogProof, and enhanced receipts. - - - ---- - -## Resources +
+

Quickstart guides

+ + + Send ETH from Ethereum to ZKsync, then track inclusion on L1 and execution on L2. + + + Create the withdrawal on ZKsync, monitor execution, and finalize back on Ethereum. + + + Install the viem adapter, connect clients, and run your first deposit. + + + Use an ethers v6 signer to perform a deposit and wait for finality. + + + Understand statuses vs waits and how to poll each phase of a flow. + + + Utilities like getBridgehubAddress, getL2ToL1LogProof, and enhanced receipts. + + +
- - - Fully typed clients, methods, and errors for core and adapters. - - - See what’s new, fixed, and changed across releases. - - - Questions or issues? Reach out and we’ll help you integrate quickly. - - +
+

Resources

+ + + Fully typed clients, methods, and errors for core and adapters. + + + See what’s new, fixed, and changed across releases. + + + Questions or issues? Reach out and we’ll help you integrate quickly. + + +
diff --git a/docs/style.css b/docs/style.css index 75a32d5..7b8fb32 100644 --- a/docs/style.css +++ b/docs/style.css @@ -1,3 +1,6 @@ +/* Prevent sideways scroll caused by full-bleed sections */ +html, body { overflow-x: hidden; } + /* ===== Hero (Bridge-style) ===== */ .hero { position: relative; @@ -5,30 +8,40 @@ flex-direction: column; align-items: center; text-align: center; + gap: 18px; padding: 120px 16px 96px; - margin: -24px -24px 0; /* stretch to page edges if your theme pads content */ + min-height: 68vh; /* nice tall hero */ } -/* Dot grid + soft gradient (light) */ -.hero { +/* Make ONLY the hero full-bleed (no negative margins) */ +.hero--bleed { + width: 100vw; + margin-left: calc(50% - 50vw); + margin-right: calc(50% - 50vw); + border-radius: 0; + border-bottom: 1px solid rgba(255,255,255,.06); +} +:root.light .hero--bleed { border-bottom-color: rgba(0,0,0,.06); } + +/* Dot grid + soft gradient */ +.hero--bleed { background: radial-gradient(rgba(19,213,211,0.28) 1px, transparent 1.2px) 0 0 / 16px 16px, linear-gradient(180deg, rgba(19,213,211,0.14), rgba(19,213,211,0) 60%); } - -/* Dark mode variant */ -:root.dark .hero, -.dark .hero { +/* Dark mode */ +:root.dark .hero--bleed, +.dark .hero--bleed { background: radial-gradient(rgba(23,85,244,0.28) 1px, transparent 1.2px) 0 0 / 16px 16px, linear-gradient(180deg, rgba(23,85,244,0.18), rgba(23,85,244,0) 60%); } .hero h1 { - font-size: clamp(2.5rem, 6vw, 4rem); - line-height: 1.1; + font-size: clamp(2.6rem, 6vw, 4.5rem); + line-height: 1.08; letter-spacing: -0.02em; - margin: 0 0 16px; + margin: 0; font-weight: 800; } @@ -37,10 +50,10 @@ font-size: clamp(1.05rem, 2vw, 1.25rem); line-height: 1.65; opacity: 0.9; - margin: 0 0 32px; + margin: 4px 0 8px; } -/* CTA button; uses your palette (fallbacks included) */ +/* CTA button; uses docs.json colors if present */ .hero-cta { display: inline-flex; align-items: center; @@ -50,7 +63,7 @@ border-radius: 12px; font-weight: 600; text-decoration: none; - color: #ffffff; + color: #fff; background: var(--color-primary, #1755F4); box-shadow: 0 6px 16px rgba(0,0,0,0.08); transition: transform .06s ease, box-shadow .2s ease, background-color .2s ease; @@ -61,7 +74,23 @@ background: var(--color-primary-dark, #0C18EC); } -/* optional: larger hero on wide screens */ +/* ===== Landing page content container (for custom mode) ===== */ +.lp-container { + max-width: 1200px; /* 1040–1280px all fine */ + margin: 0 auto; + padding: 40px 24px 56px; +} + +.lp-container > h2 { + font-size: clamp(1.25rem, 2vw, 1.5rem); + font-weight: 600; + margin: 0 0 16px; +} + +/* If an
appears after the hero, hide it */ +.hero--bleed + hr { display: none; } + +/* Optional: a bit taller hero on widescreens */ @media (min-width: 1024px) { .hero { padding: 140px 16px 110px; } } From 0df905c4c50ca7cf640cb71681fac7af0696e1f7 Mon Sep 17 00:00:00 2001 From: Dustin Brickwood Date: Tue, 7 Oct 2025 10:39:22 -0500 Subject: [PATCH 04/18] chore: play around with hero docs --- docs/docs.json | 2 +- docs/index.mdx | 41 ++++++-- docs/style.css | 275 ++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 278 insertions(+), 40 deletions(-) diff --git a/docs/docs.json b/docs/docs.json index 93538d4..67aa45c 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -1,6 +1,6 @@ { "$schema": "https://mintlify.com/docs.json", - "theme": "palm", + "theme": "aspen", "name": "ZKsyncOS SDK", "colors": { "primary": "#1755F4", diff --git a/docs/index.mdx b/docs/index.mdx index 7d41dad..4a93ad4 100644 --- a/docs/index.mdx +++ b/docs/index.mdx @@ -4,28 +4,47 @@ description: Lightweight adapters for viem and ethers to build ZKsync L1↔L2 fl mode: "custom" --- -
-

Build with @zksync-sdk.

-

- Extend viem and ethers with ZKsync-specific flows — deposits, - withdrawals, and status/wait helpers — at the speed and scale of the Elastic Network. -

- Get started → +
+
+
+ + Next-gen ZK development +
+ +

ZKsync SDK

+ +

+ Extend viem and ethers with ZKsync-specific flows — deposits, + withdrawals, and status/wait helpers — at the speed and scale of the Elastic Network. +

+ +
+ ```bash + bun add @dutterbutter/zksync-sdk + ``` +
+ +

Quickstart guides

- + Send ETH from Ethereum to ZKsync, then track inclusion on L1 and execution on L2. - + Create the withdrawal on ZKsync, monitor execution, and finalize back on Ethereum. Install the viem adapter, connect clients, and run your first deposit. - + Use an ethers v6 signer to perform a deposit and wait for finality. @@ -46,7 +65,7 @@ mode: "custom" See what’s new, fixed, and changed across releases. - + Questions or issues? Reach out and we’ll help you integrate quickly. diff --git a/docs/style.css b/docs/style.css index 7b8fb32..5f02fad 100644 --- a/docs/style.css +++ b/docs/style.css @@ -1,42 +1,83 @@ /* Prevent sideways scroll caused by full-bleed sections */ html, body { overflow-x: hidden; } -/* ===== Hero (Bridge-style) ===== */ +/* ==== Brand tokens ==== */ +:root{ + --zk-blue: #1755F4; /* primary blue */ + --zk-royal: #0C18EC; /* deep blue */ + --zk-teal: #13D5D3; /* accent dots */ + --zk-lime: #BFF351; /* lime accent */ + --zk-black: #000000; + --zk-white: #FFFFFF; +} + +/* ===== Hero (full-bleed, stacked) ===== */ .hero { position: relative; display: flex; flex-direction: column; - align-items: center; - text-align: center; gap: 18px; padding: 120px 16px 96px; - min-height: 68vh; /* nice tall hero */ + min-height: 68vh; + text-align: center; } -/* Make ONLY the hero full-bleed (no negative margins) */ .hero--bleed { width: 100vw; margin-left: calc(50% - 50vw); margin-right: calc(50% - 50vw); border-radius: 0; - border-bottom: 1px solid rgba(255,255,255,.06); + border-bottom: 1px solid rgba(191,243,81,0.14); } -:root.light .hero--bleed { border-bottom-color: rgba(0,0,0,.06); } -/* Dot grid + soft gradient */ +/* Backgrounds */ .hero--bleed { background: - radial-gradient(rgba(19,213,211,0.28) 1px, transparent 1.2px) 0 0 / 16px 16px, - linear-gradient(180deg, rgba(19,213,211,0.14), rgba(19,213,211,0) 60%); + radial-gradient(rgba(19,213,211,0.18) 1px, transparent 1.2px) 0 0 / 16px 16px, + linear-gradient(180deg, rgba(23,85,244,0.12), rgba(23,85,244,0) 60%), + var(--zk-white); } -/* Dark mode */ -:root.dark .hero--bleed, -.dark .hero--bleed { +:root.dark .hero--bleed, .dark .hero--bleed { + border-bottom-color: rgba(191,243,81,0.18); background: - radial-gradient(rgba(23,85,244,0.28) 1px, transparent 1.2px) 0 0 / 16px 16px, - linear-gradient(180deg, rgba(23,85,244,0.18), rgba(23,85,244,0) 60%); + radial-gradient(rgba(19,213,211,0.20) 1px, transparent 1.2px) 0 0 / 16px 16px, + linear-gradient(180deg, rgba(12,24,236,0.55) 0%, rgba(12,24,236,0.25) 35%, transparent 70%), + var(--zk-black); +} + +/* --- stacked layout container --- */ +.hero--stack .hero-inner{ + max-width: 960px; + margin: 0 auto; + padding: 0 24px; + display: flex; + flex-direction: column; + align-items: center; + gap: 18px; } +/* Pill tag (eyebrow) */ +.pill-tag{ + display: inline-flex; + align-items: center; + gap: 8px; + padding: 8px 14px; + border-radius: 999px; + font-size: 0.95rem; + font-weight: 600; + color: var(--zk-white); + border: 1px solid rgba(191,243,81,0.65); /* lime border */ + background: color-mix(in srgb, var(--zk-royal) 22%, transparent); + backdrop-filter: blur(2px); +} +:root.light .pill-tag{ + color: #0b1226; + background: color-mix(in srgb, var(--zk-blue) 12%, transparent); + border-color: rgba(191,243,81,0.55); +} +.pill-icon{ font-size: 1rem; line-height: 1; } + +/* Type scale */ .hero h1 { font-size: clamp(2.6rem, 6vw, 4.5rem); line-height: 1.08; @@ -44,7 +85,6 @@ html, body { overflow-x: hidden; } margin: 0; font-weight: 800; } - .hero-subtitle { max-width: 880px; font-size: clamp(1.05rem, 2vw, 1.25rem); @@ -53,8 +93,37 @@ html, body { overflow-x: hidden; } margin: 4px 0 8px; } -/* CTA button; uses docs.json colors if present */ -.hero-cta { +/* Dev install card — single bordered, rounded */ +.dev-card{ + width: 100%; + max-width: 720px; + border-radius: 16px; + padding: 14px 16px; + border: 1px solid rgba(255,255,255,0.18); + background: + linear-gradient(135deg, rgba(23,85,244,0.18), rgba(12,24,236,0.12)); +} +:root.light .dev-card{ + border-color: rgba(0,0,0,0.10); + background: + linear-gradient(135deg, rgba(23,85,244,0.06), rgba(12,24,236,0.04), rgba(0,0,0,0)); +} +.dev-label{ + font-size: 0.9rem; + font-weight: 600; + opacity: 0.85; + margin: 2px 0 8px; +} +.dev-card pre{ margin: 0 !important; } /* snug code block */ + +/* CTA group */ +.hero-actions{ + display: flex; + gap: 12px; + justify-content: center; + margin-top: 6px; +} +.hero-cta{ display: inline-flex; align-items: center; justify-content: center; @@ -64,33 +133,183 @@ html, body { overflow-x: hidden; } font-weight: 600; text-decoration: none; color: #fff; - background: var(--color-primary, #1755F4); + background: var(--color-primary, var(--zk-blue)); box-shadow: 0 6px 16px rgba(0,0,0,0.08); - transition: transform .06s ease, box-shadow .2s ease, background-color .2s ease; + transition: transform .06s ease, box-shadow .2s ease, background-color .2s ease, border-color .2s ease; } -.hero-cta:hover { +.hero-cta:hover{ transform: translateY(-1px); box-shadow: 0 10px 20px rgba(0,0,0,0.12); - background: var(--color-primary-dark, #0C18EC); + background: var(--color-primary-dark, var(--zk-royal)); +} +.hero-cta.ghost{ + background: transparent; + color: var(--zk-white); + border: 1px solid rgba(255,255,255,0.28); + box-shadow: none; +} +:root.light .hero-cta.ghost{ + color: #0b1226; + border-color: rgba(0,0,0,0.22); +} +.hero-cta.ghost:hover{ + border-color: color-mix(in srgb, var(--zk-lime) 50%, #ffffff); } -/* ===== Landing page content container (for custom mode) ===== */ +/* Landing page content container */ .lp-container { - max-width: 1200px; /* 1040–1280px all fine */ + max-width: 1200px; margin: 0 auto; padding: 40px 24px 56px; } - .lp-container > h2 { font-size: clamp(1.25rem, 2vw, 1.5rem); font-weight: 600; margin: 0 0 16px; } -/* If an
appears after the hero, hide it */ +/* Hide stray hr after hero */ .hero--bleed + hr { display: none; } -/* Optional: a bit taller hero on widescreens */ -@media (min-width: 1024px) { +/* Taller hero on widescreens */ +@media (min-width: 1024px){ .hero { padding: 140px 16px 110px; } } + +/* ========================= + DARK MODE BEAUTIFICATION + ========================= */ + +/* Better dark palette tokens */ +:root.dark { + --text-1: #E8EDFF; /* headings */ + --text-2: #A7B1D6; /* body/subtitles */ + --ink-0: #05060A; /* deep background */ + --ring: rgba(23,85,244,.45); + --ring2: rgba(23,85,244,.22); +} + +/* Hero: richer blue glow, subtler dot grid, gentle bottom vignette */ +:root.dark .hero--bleed, +.dark .hero--bleed { + border-bottom-color: rgba(23,85,244,.28); + background: + /* subtle teal dot grid */ + radial-gradient(rgba(19,213,211,.12) 1px, transparent 1.2px) 0 0 / 18px 18px, + /* top blue glow */ + radial-gradient(1200px 600px at 50% -10%, rgba(23,85,244,.55), transparent 60%), + /* bottom vignette */ + radial-gradient(1000px 520px at 50% 100%, rgba(0,0,0,0), rgba(0,0,0,.65)), + var(--ink-0); +} + +/* Type contrast in dark */ +:root.dark .hero h1 { color: var(--text-1); text-shadow: 0 1px 0 rgba(255,255,255,.02); } +:root.dark .hero-subtitle { color: var(--text-2); opacity: 1; } + +/* Eyebrow pill */ +:root.dark .pill-tag{ + color: #EAF2FF; + background: linear-gradient(180deg, rgba(12,24,236,.28), rgba(12,24,236,.12)); + border-color: rgba(191,243,81,.55); /* lime ring */ + box-shadow: + inset 0 0 0 1px rgba(255,255,255,.03), + 0 0 0 6px rgba(12,24,236,.08); /* soft aura */ +} + +/* Install card: single border, no inner pills, gentle blue wash */ +:root.dark .dev-card{ + background: linear-gradient(180deg, rgba(12,24,236,.16), rgba(5,6,10,.42)); + border-color: rgba(23,85,244,.35); + box-shadow: 0 12px 36px rgba(0,0,0,.6), 0 0 0 1px rgba(5,12,255,.06) inset; +} +:root.dark .dev-label{ color:#AFBEFF; opacity:.9; } + +/* Remove the inner code block “second border”/background */ +.dev-card pre, +.dev-card pre[class*="language-"], +.dev-card .shiki, +.dev-card .code-block, +.dev-card pre code { + background: transparent !important; + border: 0 !important; + box-shadow: none !important; +} +.dev-card pre { margin: 0 !important; padding: 14px 18px !important; border-radius: 10px !important; outline: none !important; } + +/* Dark code color for command */ +:root.dark .dev-card pre code { color: #DFF2FF; } + +/* Copy button minimal */ +.dev-card [aria-label="Copy code"], +.dev-card .copy, +.dev-card button[class*="copy"]{ + background: transparent !important; + border: 0 !important; + box-shadow: none !important; + opacity: .9; +} + +/* CTAs: saturated gradient primary, crisp ghost */ +:root.dark .hero-cta{ + background: linear-gradient(90deg, #1755F4, #0C18EC); + box-shadow: 0 8px 24px rgba(23,85,244,.35); + color: #fff; +} +:root.dark .hero-cta:hover{ + filter: brightness(1.06); + transform: translateY(-2px); + box-shadow: 0 16px 40px rgba(23,85,244,.45); +} +:root.dark .hero-cta.ghost{ + background: rgba(255,255,255,.02); + color: #E8EDFF; + border: 1px solid rgba(232,237,255,.22); +} +:root.dark .hero-cta.ghost:hover{ + border-color: var(--zk-teal); + box-shadow: 0 0 0 3px rgba(191,243,81,.12); +} + +/* Teal CTA variant (matches nav link) */ +:root{ + /* slightly darker teals than #13D5D3 for contrast with white text */ + --teal-600: #0FBEBB; + --teal-700: #0BA3A1; +} + +/* default + light mode */ +.hero-cta.teal{ + background: linear-gradient(90deg, var(--teal-700), var(--teal-600)); + color: #FFFFFF; + border: 1px solid rgba(19,213,211,.35); + box-shadow: + 0 8px 20px rgba(19,213,211,.25), + 0 1px 0 rgba(255,255,255,.06) inset; +} +.hero-cta.teal:hover{ + transform: translateY(-2px); + filter: saturate(1.06) brightness(1.03); + box-shadow: + 0 14px 36px rgba(19,213,211,.35), + 0 1px 0 rgba(255,255,255,.08) inset; +} +.hero-cta.teal:focus-visible{ + outline: none; + box-shadow: + 0 0 0 3px rgba(19,213,211,.35), + 0 10px 28px rgba(19,213,211,.30); +} + +/* dark mode tune: a hair deeper for readability */ +:root.dark .hero-cta.teal, +.dark .hero-cta.teal{ + background: linear-gradient(90deg, #0A8887, #0FBEBB); + border-color: rgba(19,213,211,.45); + box-shadow: 0 10px 28px rgba(19,213,211,.32); +} +:root.dark .hero-cta.teal:hover, +.dark .hero-cta.teal:hover{ + filter: brightness(1.06) saturate(1.08); + box-shadow: 0 18px 44px rgba(19,213,211,.42); +} From 989744fed02ac66b9168df87e18ba568bb67db75 Mon Sep 17 00:00:00 2001 From: Dustin Brickwood Date: Tue, 7 Oct 2025 21:53:02 -0500 Subject: [PATCH 05/18] init --- docs/docs.json | 18 +- docs/guides/deposits.mdx | 116 +++++++ docs/guides/withdrawals.mdx | 0 docs/index.mdx | 70 +++-- docs/snippets/deposits/ethers.mdx | 88 ++++++ docs/snippets/deposits/viem.mdx | 106 +++++++ docs/snippets/withdrawals/ethers.mdx | 0 docs/snippets/withdrawals/viem.mdx | 0 docs/style.css | 448 ++++++++++++--------------- 9 files changed, 555 insertions(+), 291 deletions(-) create mode 100644 docs/guides/deposits.mdx create mode 100644 docs/guides/withdrawals.mdx create mode 100644 docs/snippets/deposits/ethers.mdx create mode 100644 docs/snippets/deposits/viem.mdx create mode 100644 docs/snippets/withdrawals/ethers.mdx create mode 100644 docs/snippets/withdrawals/viem.mdx diff --git a/docs/docs.json b/docs/docs.json index 67aa45c..5d8b3a9 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -42,16 +42,14 @@ "quickstart/ethers" ] }, - { - "group": "Guides", - "pages": [ - "guides/index", - "guides/deposits/viem", - "guides/deposits/ethers", - "guides/withdrawals/viem", - "guides/withdrawals/ethers" - ] - }, + { + "group": "Guides", + "pages": [ + "guides/deposits", + "guides/withdrawals", + "guides/finalization" + ] + }, { "group": "Concepts", "pages": [ diff --git a/docs/guides/deposits.mdx b/docs/guides/deposits.mdx new file mode 100644 index 0000000..4243f8d --- /dev/null +++ b/docs/guides/deposits.mdx @@ -0,0 +1,116 @@ +--- +title: Deposits +description: Deposit ETH from L1 → ZKsync (L2). +--- + +import { ViemDeposit } from '/snippets/deposits/viem.mdx'; +import { EthersDeposit } from '/snippets/deposits/ethers.mdx'; + +A fast path to deposit **ETH** from L1 → ZKsync (L2). Toggle your adapter below. + +## Prerequisites + +- A funded **L1** account (gas + amount). +- RPC URLs: `L1_RPC_URL`, `L2_RPC_URL`. +- Installed: `@dutterbutter/zksync-sdk` + **one** adapter: `viem` **or** `ethers`. + +## Parameters + +| Param | Required | Meaning | +| ----------------- | -------- | -------------------------------------- | +| `token` | Yes | `ETH_ADDRESS` or ERC-20 address | +| `amount` | Yes | BigInt/wei (e.g. `parseEther('0.01')`) | +| `to` | Yes | L2 recipient address | +| `l2GasLimit` | No | L2 execution gas cap | +| `gasPerPubdata` | No | Pubdata price hint | +| `operatorTip` | No | Optional tip to operator | +| `refundRecipient` | No | L2 address to receive fee refunds | + +## Fast path (one-shot) + + + + + + + + + +- `create()` prepares **and** sends. +- `wait(..., { for: 'l1' })` ⇒ included on **L1**. +- `wait(..., { for: 'l2' })` ⇒ executed on **L2** (funds available). + +## Inspect & customize (quote → prepare → create) + +**1) Quote (no side-effects)** — preview fees/steps and whether an approval is required: + +```ts +const quote = await sdk.deposits.quote(params); +``` + +**2) Prepare (build txs, don’t send)** — get `TransactionRequest[]` for custom signing/UX: + +```ts +const plan = await sdk.deposits.prepare(params); +``` + +**3) Create (send)** — use defaults, or send your prepared transactions: + +```ts +const handle = await sdk.deposits.create(params); +``` + +## Track progress (status vs wait) + +**Non-blocking snapshot** + +```ts +const s = await sdk.deposits.status(handle /* or l1TxHash */); +// 'UNKNOWN' | 'L1_PENDING' | 'L1_INCLUDED' | 'L2_PENDING' | 'L2_EXECUTED' | 'L2_FAILED' +``` + +**Block until checkpoint** + +```ts +const l1Receipt = await sdk.deposits.wait(handle, { for: 'l1' }); +const l2Receipt = await sdk.deposits.wait(handle, { for: 'l2' }); +``` + +## Error handling patterns + +**Exceptions** + +```ts +try { + const handle = await sdk.deposits.create(params); +} catch (e) { + // normalized error envelope (type, operation, message, context, optional revert) +} +``` + +**No-throw style** + +Every method has a `try*` variant (`tryQuote`, `tryPrepare`, `tryCreate`) returning `{ ok, value | error }`. + +```ts +const r = await sdk.deposits.tryCreate(params); +if (!r.ok) { + console.error('Deposit failed:', r.error); + // show a toast, retry, or branch UX… +} else { + console.log('Deposit sent. L1 tx hash:', r.value.l1TxHash); +} +``` + +## Troubleshooting + +- **Stuck at L1:** check L1 gas and RPC health. +- **No L2 execution:** verify L2 RPC; re-check `status()` (should move to `L2_EXECUTED`). +- **L2 failed:** if `phase === 'L2_FAILED'`, inspect the revert info via your error envelope/logs. + +--- + +## See also + +- [Status vs Wait](/concepts/status-vs-wait) +- [ZKsync RPC Helpers](/zks/methods) diff --git a/docs/guides/withdrawals.mdx b/docs/guides/withdrawals.mdx new file mode 100644 index 0000000..e69de29 diff --git a/docs/index.mdx b/docs/index.mdx index 4a93ad4..03b53bc 100644 --- a/docs/index.mdx +++ b/docs/index.mdx @@ -4,41 +4,57 @@ description: Lightweight adapters for viem and ethers to build ZKsync L1↔L2 fl mode: "custom" --- -
-

Quickstart guides

- - Send ETH from Ethereum to ZKsync, then track inclusion on L1 and execution on L2. + + Send ETH or ERC-20 from Ethereum to ZKsync, then track L1 inclusion and L2 execution. - + Create the withdrawal on ZKsync, monitor execution, and finalize back on Ethereum. @@ -50,7 +66,7 @@ mode: "custom" Understand statuses vs waits and how to poll each phase of a flow. - + Utilities like getBridgehubAddress, getL2ToL1LogProof, and enhanced receipts. diff --git a/docs/snippets/deposits/ethers.mdx b/docs/snippets/deposits/ethers.mdx new file mode 100644 index 0000000..c5daad5 --- /dev/null +++ b/docs/snippets/deposits/ethers.mdx @@ -0,0 +1,88 @@ +export const EthersDeposits = () => { + return ( +```ts ethers.ts +// examples/deposit-eth.ts +import { JsonRpcProvider, Wallet, parseEther } from 'ethers'; +import { createEthersClient, createEthersSdk } from '@dutterbutter/zksync-sdk/ethers'; +import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; + +const L1_RPC = 'http://localhost:8545'; // e.g. https://sepolia.infura.io/v3/XXX +const L2_RPC = 'http://localhost:3050'; // your L2 RPC +const PRIVATE_KEY = process.env.PRIVATE_KEY || ''; + +async function main() { + if (!PRIVATE_KEY) { + throw new Error('Set your PRIVATE_KEY in the .env file'); + } + const l1 = new JsonRpcProvider(L1_RPC); + const l2 = new JsonRpcProvider(L2_RPC); + const signer = new Wallet(PRIVATE_KEY, l1); + + const balance = await l1.getBalance(signer.address); + console.log('L1 balance:', balance.toString()); + + const balanceL2 = await l2.getBalance(signer.address); + console.log('L2 balance:', balanceL2.toString()); + + const client = await createEthersClient({ l1, l2, signer }); + const sdk = createEthersSdk(client); + + const me = (await signer.getAddress()); + const params = { + amount: parseEther('.01'), // 0.01 ETH + to: me, + token: ETH_ADDRESS, + // optional: + // l2GasLimit: 300_000n, + // gasPerPubdata: 800n, + // operatorTip: 0n, + // refundRecipient: me, + } as const; + + // Quote + const quote = await sdk.deposits.quote(params); + console.log('QUOTE response: ', quote); + + const prepare = await sdk.deposits.prepare(params); + console.log('PREPARE response: ', prepare); + + // Create (prepare + send) + const create = await sdk.deposits.create(params); + console.log('CREATE response: ', create); + + const status = await sdk.deposits.status(create); + console.log('STATUS response: ', status); + + // Wait (for now, L1 inclusion) + const receipt = await sdk.deposits.wait(create, { for: 'l1' }); + console.log( + 'Included at block:', + receipt?.blockNumber, + 'status:', + receipt?.status, + 'hash:', + receipt?.hash, + ); + + const status2 = await sdk.deposits.status(create); + console.log('STATUS2 response: ', status2); + + // Wait (for now, L2 inclusion) + const l2Receipt = await sdk.deposits.wait(create, { for: 'l2' }); + console.log( + 'Included at block:', + l2Receipt?.blockNumber, + 'status:', + l2Receipt?.status, + 'hash:', + l2Receipt?.hash, + ); +} + +main().catch((e) => { + console.error(e); + process.exit(1); +}); +``` + ); +} \ No newline at end of file diff --git a/docs/snippets/deposits/viem.mdx b/docs/snippets/deposits/viem.mdx new file mode 100644 index 0000000..c0b4af5 --- /dev/null +++ b/docs/snippets/deposits/viem.mdx @@ -0,0 +1,106 @@ +export const ViemDeposits = () => { + return ( +```ts viem.ts +// viem deposit (ETH) — minimal example + +import { createPublicClient, createWalletClient, http, parseEther } from 'viem'; +import type { Account, Chain, Transport, WalletClient } from 'viem'; +import { privateKeyToAccount } from 'viem/accounts'; + +import { createViemSdk, createViemClient } from '@dutterbutter/zksync-sdk/viem'; +import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; + +const L1_RPC = 'http://localhost:8545'; // e.g. https://sepolia.infura.io/v3/XXX +const L2_RPC = 'http://localhost:3050'; // your L2 RPC +const PRIVATE_KEY = process.env.PRIVATE_KEY || ''; + +async function main() { + if (!PRIVATE_KEY || PRIVATE_KEY.length !== 66) { + throw new Error('Set your PRIVATE_KEY in the .env file (0x-prefixed, 32 bytes)'); + } + + // --- Viem clients --- + const account = privateKeyToAccount(PRIVATE_KEY); + + const l1 = createPublicClient({ transport: http(L1_RPC) }); + const l2 = createPublicClient({ transport: http(L2_RPC) }); + + const l1Wallet: WalletClient = createWalletClient({ + account, + transport: http(L1_RPC), + }); + + // Check balances + const [balL1, balL2] = await Promise.all([ + l1.getBalance({ address: account.address }), + l2.getBalance({ address: account.address }), + ]); + console.log('L1 balance:', balL1.toString()); + console.log('L2 balance:', balL2.toString()); + + // client + sdk + const client = createViemClient({ l1, l2, l1Wallet }); + const sdk = createViemSdk(client); + + const me = account.address; + const params = { + amount: parseEther('0.01'), // 0.01 ETH + to: me, + token: ETH_ADDRESS, + // optional: + // l2GasLimit: 300_000n, + // gasPerPubdata: 800n, + // operatorTip: 0n, + // refundRecipient: me, + } as const; + + // Quote + const quote = await sdk.deposits.quote(params); + console.log('QUOTE response:', quote); + + // Prepare (route + steps, no sends) + const prepared = await sdk.deposits.prepare(params); + console.log('PREPARE response:', prepared); + + // Create (prepare + send) + const created = await sdk.deposits.create(params); + console.log('CREATE response:', created); + + // Status (quick check) + const status = await sdk.deposits.status(created); + console.log('STATUS response:', status); + + // Wait (L1 inclusion) + const l1Receipt = await sdk.deposits.wait(created, { for: 'l1' }); + console.log( + 'L1 Included at block:', + l1Receipt?.blockNumber, + 'status:', + l1Receipt?.status, + 'hash:', + l1Receipt?.transactionHash, + ); + + // Status again + const status2 = await sdk.deposits.status(created); + console.log('STATUS2 response:', status2); + + // Wait for L2 execution + const l2Receipt = await sdk.deposits.wait(created, { for: 'l2' }); + console.log( + 'L2 Included at block:', + l2Receipt?.blockNumber, + 'status:', + l2Receipt?.status, + 'hash:', + l2Receipt?.transactionHash, + ); +} + +main().catch((e) => { + console.error(e); + process.exit(1); +}); +``` + ); +} \ No newline at end of file diff --git a/docs/snippets/withdrawals/ethers.mdx b/docs/snippets/withdrawals/ethers.mdx new file mode 100644 index 0000000..e69de29 diff --git a/docs/snippets/withdrawals/viem.mdx b/docs/snippets/withdrawals/viem.mdx new file mode 100644 index 0000000..e69de29 diff --git a/docs/style.css b/docs/style.css index 5f02fad..00bdc58 100644 --- a/docs/style.css +++ b/docs/style.css @@ -1,315 +1,255 @@ -/* Prevent sideways scroll caused by full-bleed sections */ +/* ========================= + Base / Tokens / Resets + ========================= */ html, body { overflow-x: hidden; } -/* ==== Brand tokens ==== */ :root{ - --zk-blue: #1755F4; /* primary blue */ - --zk-royal: #0C18EC; /* deep blue */ - --zk-teal: #13D5D3; /* accent dots */ - --zk-lime: #BFF351; /* lime accent */ - --zk-black: #000000; - --zk-white: #FFFFFF; -} + /* Brand */ + --zk-blue: #1755F4; + --zk-royal: #0C18EC; + --zk-teal: #13D5D3; + --zk-lime: #BFF351; -/* ===== Hero (full-bleed, stacked) ===== */ -.hero { - position: relative; - display: flex; - flex-direction: column; - gap: 18px; - padding: 120px 16px 96px; - min-height: 68vh; - text-align: center; + /* UI neutrals */ + --white: #FFFFFF; + --surface:#FFFFFF; + --ink-0: #05060A; /* dark bg */ + --ink-1: #0b1226; /* heading */ + --ink-2: #334155; /* body */ + --line: rgba(2,6,23,.10); + + /* CTA teal */ + --teal-700:#0BA3A1; + --teal-600:#0FBEBB; } -.hero--bleed { +/* ========================= + Hero layout + ========================= */ +.hero { position: relative; padding: 96px 16px; } + +/* “Apple-style” background with subtle dot grid */ +.hero--ai{ width: 100vw; margin-left: calc(50% - 50vw); margin-right: calc(50% - 50vw); - border-radius: 0; - border-bottom: 1px solid rgba(191,243,81,0.14); -} - -/* Backgrounds */ -.hero--bleed { + border-bottom: 1px solid var(--line); background: - radial-gradient(rgba(19,213,211,0.18) 1px, transparent 1.2px) 0 0 / 16px 16px, - linear-gradient(180deg, rgba(23,85,244,0.12), rgba(23,85,244,0) 60%), - var(--zk-white); + radial-gradient(rgba(23,85,244,.06) 1px, transparent 1.2px) 0 0 / 18px 18px, + radial-gradient(1200px 700px at 85% -10%, rgba(12,24,236,.26), transparent 60%), + radial-gradient(1100px 600px at 10% 80%, rgba(19,213,211,.24), transparent 60%), + radial-gradient(900px 580px at 30% 20%, rgba(239,109,242,.20), transparent 60%), + radial-gradient(900px 520px at 70% 70%, rgba(253,64,44,.16), transparent 60%), + radial-gradient(1200px 520px at -10% -20%, rgba(191,243,81,.18), transparent 60%), + var(--surface); } -:root.dark .hero--bleed, .dark .hero--bleed { - border-bottom-color: rgba(191,243,81,0.18); + +:root.dark .hero--ai{ + border-bottom-color: rgba(23,85,244,.28); background: - radial-gradient(rgba(19,213,211,0.20) 1px, transparent 1.2px) 0 0 / 16px 16px, - linear-gradient(180deg, rgba(12,24,236,0.55) 0%, rgba(12,24,236,0.25) 35%, transparent 70%), - var(--zk-black); + radial-gradient(rgba(23,85,244,.13) 1px, transparent 1.2px) 0 0 / 18px 18px, + radial-gradient(1250px 720px at 62% -10%, rgba(12,24,236,.60), transparent 62%), + radial-gradient(1100px 650px at 10% 86%, rgba(19,213,211,.25), transparent 62%), + radial-gradient(900px 600px at 26% 28%, rgba(239,109,242,.25), transparent 62%), + radial-gradient(900px 560px at 76% 72%, rgba(253,64,44,.18), transparent 62%), + radial-gradient(1100px 540px at -10% -20%, rgba(191,243,81,.16), transparent 62%), + var(--ink-0); } -/* --- stacked layout container --- */ -.hero--stack .hero-inner{ - max-width: 960px; - margin: 0 auto; - padding: 0 24px; - display: flex; - flex-direction: column; - align-items: center; - gap: 18px; +/* Grid + split */ +.hero--split .hero-inner{ + max-width: 1200px; margin: 0 auto; display: grid; + grid-template-columns: 1.05fr 0.95fr; gap: 40px; align-items: center; padding: 0 24px; } +.promo-left { display: flex; flex-direction: column; gap: 18px; align-items: flex-start; } +.promo-right{ display: flex; justify-content: flex-end; } -/* Pill tag (eyebrow) */ +/* ========================= + Pill (eyebrow) + ========================= */ .pill-tag{ - display: inline-flex; - align-items: center; - gap: 8px; - padding: 8px 14px; - border-radius: 999px; - font-size: 0.95rem; - font-weight: 600; - color: var(--zk-white); - border: 1px solid rgba(191,243,81,0.65); /* lime border */ - background: color-mix(in srgb, var(--zk-royal) 22%, transparent); - backdrop-filter: blur(2px); + align-self:flex-start; position:relative; + display:inline-flex; align-items:center; gap:8px; + padding:8px 14px; border-radius:999px; + font-size:.95rem; font-weight:600; color: var(--ink-1); + border:1px solid rgba(191,243,81,.45); + background: color-mix(in srgb, var(--zk-blue) 8%, #fff); +} +.pill-icon{ font-size:1rem; line-height:1; } +.pill-tag--ring{ + border:1px solid transparent; + background: + linear-gradient(#fff,#fff) padding-box, + conic-gradient(#BFF351, #1755F4, #EF6DF2, #FD402C, #13D5D3, #BFF351) border-box; } -:root.light .pill-tag{ - color: #0b1226; - background: color-mix(in srgb, var(--zk-blue) 12%, transparent); - border-color: rgba(191,243,81,0.55); +:root.dark .pill-tag{ + color:#F1F5FF; + background: linear-gradient(180deg, rgba(12,24,236,.32), rgba(12,24,236,.16)); + border-color: rgba(191,243,81,.60); +} +:root.dark .pill-tag--ring{ + background: + linear-gradient(#0C1322, #0C1322) padding-box, + conic-gradient(#BFF351, #1755F4, #EF6DF2, #FD402C, #13D5D3, #BFF351) border-box; + border: 1px solid transparent; } -.pill-icon{ font-size: 1rem; line-height: 1; } -/* Type scale */ -.hero h1 { - font-size: clamp(2.6rem, 6vw, 4.5rem); - line-height: 1.08; +/* ========================= + Headline (no gradient text) + ========================= */ +.promo-title{ + font-size: clamp(2.6rem, 6vw, 4.4rem); + line-height: .95; letter-spacing: -0.02em; - margin: 0; font-weight: 800; + margin: 0; + max-width: 12ch; + color: var(--ink-1); /* LIGHT default for “in your favorite libraries” */ } -.hero-subtitle { - max-width: 880px; +.promo-title .zk-strong{ color: var(--zk-blue); } /* LIGHT: “ZKsync power” */ + +/* DARK: flip the colors per your spec */ +:root.dark .promo-title{ color: var(--zk-blue); } /* “in your favorite libraries” */ +:root.dark .promo-title .zk-strong{ color: var(--white); } /* “ZKsync power” */ + +/* ========================= + Subtitle + ========================= */ +.hero-subtitle{ + max-width: 680px; font-size: clamp(1.05rem, 2vw, 1.25rem); line-height: 1.65; - opacity: 0.9; - margin: 4px 0 8px; -} - -/* Dev install card — single bordered, rounded */ -.dev-card{ - width: 100%; - max-width: 720px; - border-radius: 16px; - padding: 14px 16px; - border: 1px solid rgba(255,255,255,0.18); - background: - linear-gradient(135deg, rgba(23,85,244,0.18), rgba(12,24,236,0.12)); -} -:root.light .dev-card{ - border-color: rgba(0,0,0,0.10); - background: - linear-gradient(135deg, rgba(23,85,244,0.06), rgba(12,24,236,0.04), rgba(0,0,0,0)); + margin: 6px 0 4px; + color: var(--ink-2); } -.dev-label{ - font-size: 0.9rem; - font-weight: 600; - opacity: 0.85; - margin: 2px 0 8px; -} -.dev-card pre{ margin: 0 !important; } /* snug code block */ +:root.dark .hero-subtitle{ color:#A7B1D6; } -/* CTA group */ -.hero-actions{ - display: flex; - gap: 12px; - justify-content: center; - margin-top: 6px; -} +/* ========================= + CTAs + ========================= */ +.hero-actions{ display:flex; gap:12px; flex-wrap:wrap; margin-top:6px; } .hero-cta{ - display: inline-flex; - align-items: center; - justify-content: center; - gap: 8px; - padding: 14px 22px; - border-radius: 12px; - font-weight: 600; - text-decoration: none; - color: #fff; - background: var(--color-primary, var(--zk-blue)); + display:inline-flex; align-items:center; justify-content:center; gap:8px; + padding:14px 22px; border-radius:12px; font-weight:600; text-decoration:none; + color:#fff; background: var(--zk-blue); box-shadow: 0 6px 16px rgba(0,0,0,0.08); transition: transform .06s ease, box-shadow .2s ease, background-color .2s ease, border-color .2s ease; } -.hero-cta:hover{ - transform: translateY(-1px); - box-shadow: 0 10px 20px rgba(0,0,0,0.12); - background: var(--color-primary-dark, var(--zk-royal)); -} -.hero-cta.ghost{ - background: transparent; - color: var(--zk-white); - border: 1px solid rgba(255,255,255,0.28); - box-shadow: none; -} -:root.light .hero-cta.ghost{ - color: #0b1226; - border-color: rgba(0,0,0,0.22); -} -.hero-cta.ghost:hover{ - border-color: color-mix(in srgb, var(--zk-lime) 50%, #ffffff); -} - -/* Landing page content container */ -.lp-container { - max-width: 1200px; - margin: 0 auto; - padding: 40px 24px 56px; -} -.lp-container > h2 { - font-size: clamp(1.25rem, 2vw, 1.5rem); - font-weight: 600; - margin: 0 0 16px; +.hero-cta:hover{ transform: translateY(-1px); box-shadow: 0 10px 20px rgba(0,0,0,0.12); } +.hero-cta.ghost{ background:#fff; color:var(--ink-1); border:1px solid var(--line); box-shadow:none; } +.hero-cta.ghost:hover{ background:#f8fafc; border-color: rgba(2,6,23,.14); } +.hero-cta.teal{ + background: linear-gradient(90deg, var(--teal-700), var(--teal-600)); + color:#fff; border:1px solid rgba(19,213,211,.35); } - -/* Hide stray hr after hero */ -.hero--bleed + hr { display: none; } - -/* Taller hero on widescreens */ -@media (min-width: 1024px){ - .hero { padding: 140px 16px 110px; } +:root.dark .hero-cta{ + background: linear-gradient(90deg, #1755F4, #0C18EC); + box-shadow: 0 8px 24px rgba(23,85,244,.35); } /* ========================= - DARK MODE BEAUTIFICATION + Installer card ========================= */ - -/* Better dark palette tokens */ -:root.dark { - --text-1: #E8EDFF; /* headings */ - --text-2: #A7B1D6; /* body/subtitles */ - --ink-0: #05060A; /* deep background */ - --ring: rgba(23,85,244,.45); - --ring2: rgba(23,85,244,.22); -} - -/* Hero: richer blue glow, subtler dot grid, gentle bottom vignette */ -:root.dark .hero--bleed, -.dark .hero--bleed { - border-bottom-color: rgba(23,85,244,.28); - background: - /* subtle teal dot grid */ - radial-gradient(rgba(19,213,211,.12) 1px, transparent 1.2px) 0 0 / 18px 18px, - /* top blue glow */ - radial-gradient(1200px 600px at 50% -10%, rgba(23,85,244,.55), transparent 60%), - /* bottom vignette */ - radial-gradient(1000px 520px at 50% 100%, rgba(0,0,0,0), rgba(0,0,0,.65)), - var(--ink-0); -} - -/* Type contrast in dark */ -:root.dark .hero h1 { color: var(--text-1); text-shadow: 0 1px 0 rgba(255,255,255,.02); } -:root.dark .hero-subtitle { color: var(--text-2); opacity: 1; } - -/* Eyebrow pill */ -:root.dark .pill-tag{ - color: #EAF2FF; - background: linear-gradient(180deg, rgba(12,24,236,.28), rgba(12,24,236,.12)); - border-color: rgba(191,243,81,.55); /* lime ring */ - box-shadow: - inset 0 0 0 1px rgba(255,255,255,.03), - 0 0 0 6px rgba(12,24,236,.08); /* soft aura */ -} - -/* Install card: single border, no inner pills, gentle blue wash */ -:root.dark .dev-card{ - background: linear-gradient(180deg, rgba(12,24,236,.16), rgba(5,6,10,.42)); - border-color: rgba(23,85,244,.35); - box-shadow: 0 12px 36px rgba(0,0,0,.6), 0 0 0 1px rgba(5,12,255,.06) inset; +.dev-card{ + width:100%; max-width:520px; border-radius:16px; padding:16px; + border:1px solid var(--line); + background:#fff; + box-shadow: 0 8px 26px rgba(2,6,23,.06); } -:root.dark .dev-label{ color:#AFBEFF; opacity:.9; } +.dev-label{ font-size:.9rem; font-weight:600; color:#64748b; margin-bottom:8px; } +.dev-footnote{ margin-top:10px; font-size:.85rem; color:#94a3b8; } -/* Remove the inner code block “second border”/background */ +/* single-border look for code block */ .dev-card pre, .dev-card pre[class*="language-"], .dev-card .shiki, .dev-card .code-block, -.dev-card pre code { - background: transparent !important; - border: 0 !important; - box-shadow: none !important; +.dev-card pre code{ + background:transparent !important; border:0 !important; box-shadow:none !important; } -.dev-card pre { margin: 0 !important; padding: 14px 18px !important; border-radius: 10px !important; outline: none !important; } +.dev-card pre{ margin:0 !important; padding:14px 16px !important; border-radius:10px !important; } -/* Dark code color for command */ -:root.dark .dev-card pre code { color: #DFF2FF; } - -/* Copy button minimal */ -.dev-card [aria-label="Copy code"], -.dev-card .copy, -.dev-card button[class*="copy"]{ - background: transparent !important; - border: 0 !important; - box-shadow: none !important; - opacity: .9; +/* optional gradient ring variant */ +.dev-card--gradient{ + position:relative; border:1px solid transparent; border-radius:16px; + background: + linear-gradient(#fff,#fff) padding-box, + linear-gradient(135deg, #1755F4, #EF6DF2, #FD402C, #13D5D3) border-box; + box-shadow: 0 12px 32px rgba(2,6,23,.10); } - -/* CTAs: saturated gradient primary, crisp ghost */ -:root.dark .hero-cta{ - background: linear-gradient(90deg, #1755F4, #0C18EC); - box-shadow: 0 8px 24px rgba(23,85,244,.35); - color: #fff; +:root.dark .dev-card{ + background: linear-gradient(180deg, rgba(12,24,236,.18), rgba(12,16,28,.30)); + border-color: rgba(232,237,255,.16); + box-shadow: 0 14px 40px rgba(0,0,0,.55), 0 0 0 1px rgba(5,12,255,.06) inset; } -:root.dark .hero-cta:hover{ - filter: brightness(1.06); - transform: translateY(-2px); - box-shadow: 0 16px 40px rgba(23,85,244,.45); +:root.dark .dev-card--gradient{ + background: + linear-gradient(#0C1322, #0C1322) padding-box, + linear-gradient(135deg, #1755F4, #EF6DF2, #FD402C, #13D5D3) border-box; + border: 1px solid transparent; } -:root.dark .hero-cta.ghost{ - background: rgba(255,255,255,.02); - color: #E8EDFF; - border: 1px solid rgba(232,237,255,.22); +:root.dark .dev-card pre code{ color:#F3FAFF; } + +/* ========================= + Sections & responsive + ========================= */ +.lp-container{ max-width:1200px; margin:0 auto; padding:40px 24px 56px; } +.lp-container > h2{ font-size:clamp(1.25rem, 2vw, 1.5rem); font-weight:600; margin:0 0 16px; } + +@media (max-width: 960px){ + .hero--split .hero-inner{ grid-template-columns:1fr; gap:28px; } + .promo-right{ justify-content:flex-start; } } -:root.dark .hero-cta.ghost:hover{ - border-color: var(--zk-teal); - box-shadow: 0 0 0 3px rgba(191,243,81,.12); +@media (min-width: 1280px){ + .hero--split .hero-inner{ gap:44px; } + .promo-right{ transform: translateY(6px); } + .dev-card{ max-width:520px; } } -/* Teal CTA variant (matches nav link) */ -:root{ - /* slightly darker teals than #13D5D3 for contrast with white text */ - --teal-600: #0FBEBB; - --teal-700: #0BA3A1; + +/* Base CTA styles (unchanged) */ +.hero-cta{ + display:inline-flex; align-items:center; justify-content:center; gap:8px; + padding:14px 22px; border-radius:12px; font-weight:600; text-decoration:none; + color:#fff; background: var(--zk-blue); + box-shadow: 0 6px 16px rgba(0,0,0,0.08); + transition: transform .06s ease, box-shadow .2s ease, background-color .2s ease, border-color .2s ease; } +.hero-cta:hover{ transform: translateY(-1px); box-shadow: 0 10px 20px rgba(0,0,0,0.12); } -/* default + light mode */ +/* Variants (light) */ .hero-cta.teal{ background: linear-gradient(90deg, var(--teal-700), var(--teal-600)); - color: #FFFFFF; - border: 1px solid rgba(19,213,211,.35); - box-shadow: - 0 8px 20px rgba(19,213,211,.25), - 0 1px 0 rgba(255,255,255,.06) inset; + color:#fff; border:1px solid rgba(19,213,211,.35); } -.hero-cta.teal:hover{ - transform: translateY(-2px); - filter: saturate(1.06) brightness(1.03); - box-shadow: - 0 14px 36px rgba(19,213,211,.35), - 0 1px 0 rgba(255,255,255,.08) inset; +.hero-cta.ghost{ + background:#fff; color:var(--ink-1); border:1px solid var(--line); box-shadow:none; } -.hero-cta.teal:focus-visible{ - outline: none; - box-shadow: - 0 0 0 3px rgba(19,213,211,.35), - 0 10px 28px rgba(19,213,211,.30); +.hero-cta.ghost:hover{ background:#f8fafc; border-color: rgba(2,6,23,.14); } + +/* ---------- Dark mode overrides ---------- */ +/* Default CTA stays blue unless a variant below overrides it */ +:root.dark .hero-cta{ + background: linear-gradient(90deg, #1755F4, #0C18EC); + color:#fff; box-shadow: 0 8px 24px rgba(23,85,244,.35); } -/* dark mode tune: a hair deeper for readability */ -:root.dark .hero-cta.teal, -.dark .hero-cta.teal{ - background: linear-gradient(90deg, #0A8887, #0FBEBB); - border-color: rgba(19,213,211,.45); +/* Keep "Get started" teal in dark too */ +:root.dark .hero-cta.teal{ + background: linear-gradient(90deg, var(--teal-700), var(--teal-600)); + color:#fff; + border:1px solid rgba(19,213,211,.45); box-shadow: 0 10px 28px rgba(19,213,211,.32); } -:root.dark .hero-cta.teal:hover, -.dark .hero-cta.teal:hover{ - filter: brightness(1.06) saturate(1.08); - box-shadow: 0 18px 44px rgba(19,213,211,.42); + +/* Make "View on GitHub" white in dark as well */ +:root.dark .hero-cta.ghost{ + background:#fff; + color:#0b1226; + border:1px solid rgba(2,6,23,.28); + box-shadow:none; +} +:root.dark .hero-cta.ghost:hover{ + background:#f8fafc; + border-color: rgba(2,6,23,.40); } From 1c24ddd007764f264878682eb7bc4d32d9180080 Mon Sep 17 00:00:00 2001 From: Dustin Brickwood Date: Wed, 8 Oct 2025 09:55:14 -0500 Subject: [PATCH 06/18] feat: added changelog --- docs/changelog.mdx | 74 +++++++++ docs/docs.json | 20 +-- docs/overview/finalization.mdx | 114 ++++++++++++++ docs/overview/index.mdx | 71 --------- docs/overview/status-vs-wait.mdx | 156 +++++++++++++++++++ docs/quickstart/deposits.mdx | 203 ++++++++++++++++++++++++ docs/quickstart/ethers.mdx | 132 ---------------- docs/quickstart/index.mdx | 16 +- docs/quickstart/viem.mdx | 118 -------------- docs/quickstart/withdrawals.mdx | 208 +++++++++++++++++++++++++ docss/snippets/viem/withdrawals-eth.ts | 2 +- 11 files changed, 770 insertions(+), 344 deletions(-) create mode 100644 docs/changelog.mdx create mode 100644 docs/overview/finalization.mdx create mode 100644 docs/overview/status-vs-wait.mdx create mode 100644 docs/quickstart/deposits.mdx delete mode 100644 docs/quickstart/ethers.mdx delete mode 100644 docs/quickstart/viem.mdx create mode 100644 docs/quickstart/withdrawals.mdx diff --git a/docs/changelog.mdx b/docs/changelog.mdx new file mode 100644 index 0000000..f4156cd --- /dev/null +++ b/docs/changelog.mdx @@ -0,0 +1,74 @@ +--- +title: Changelog +description: New releases and improvements for the ZKsyncOS SDK. +rss: true +--- + + + ### Features + - Add **custom base token** support ([#39](https://github.com/dutterbutter/zksync-sdk/issues/39)) ([a1bab03](https://github.com/dutterbutter/zksync-sdk/commit/a1bab034e6d133c74c43422533d5780165608e3f)) + Compare diff + + + + ### Features + - E2E tests for **ERC-20** across **ethers** and **viem** adapters ([#38](https://github.com/dutterbutter/zksync-sdk/issues/38)) ([763587a](https://github.com/dutterbutter/zksync-sdk/commit/763587a3035da61d7764864efe1048e8f4144062)) + + ### Bug Fixes + - Reported **code coverage** ([#32](https://github.com/dutterbutter/zksync-sdk/issues/32)) ([98834dc](https://github.com/dutterbutter/zksync-sdk/commit/98834dc722559e38da270395591145f4d91ea2e4)) + - Docs tweak ([#28](https://github.com/dutterbutter/zksync-sdk/issues/28)) ([533eb70](https://github.com/dutterbutter/zksync-sdk/commit/533eb70a61c33718a3f56850ba8db65a7f3204af)) + - CI env for E2E tests ([#31](https://github.com/dutterbutter/zksync-sdk/issues/31)) ([5d4df64](https://github.com/dutterbutter/zksync-sdk/commit/5d4df64c7a3307ec02ff9d6158f6b535af4f98b5)) + - Published build/types fixes ([#35](https://github.com/dutterbutter/zksync-sdk/issues/35)) ([901a0ea](https://github.com/dutterbutter/zksync-sdk/commit/901a0ea717e16076323f5c37b6e98ca5b2540578)) + - Ethers ERC-20 withdrawal overload fix ([#37](https://github.com/dutterbutter/zksync-sdk/issues/37)) ([2403a9c](https://github.com/dutterbutter/zksync-sdk/commit/2403a9c122e7a6e8c1f24cd407eef57abf3b076a)) + + Compare diff + + + + ### Bug Fixes + - Adjust READMEs ([#25](https://github.com/dutterbutter/zksync-sdk/issues/25)) ([eacd5ae](https://github.com/dutterbutter/zksync-sdk/commit/eacd5ae6f27332ad8c756d67276e24fbdd3187df)) + Compare diff + + + + ### Bug Fixes + - Remove JSON in favor of TS ([#23](https://github.com/dutterbutter/zksync-sdk/issues/23)) ([dca83b6](https://github.com/dutterbutter/zksync-sdk/commit/dca83b6e34c7dbf0d866e27dc9c7fa4f58bc5656)) + Compare diff + + + + ### Bug Fixes + - Additional build fixes ([#21](https://github.com/dutterbutter/zksync-sdk/issues/21)) ([65475b2](https://github.com/dutterbutter/zksync-sdk/commit/65475b23b0acf8bbf8454e1ff39f59a09fd68aa9)) + Compare diff + + + + ### Features + - Release & publishing pipeline ([#4](https://github.com/dutterbutter/zksync-sdk/issues/4)) ([d253c8c](https://github.com/dutterbutter/zksync-sdk/commit/d253c8c19ac0184af6825764ade7b23a14bf6798)) + - **Status polling** for deposits ([5eefe8d](https://github.com/dutterbutter/zksync-sdk/commit/5eefe8d83a5d674cdf486cef2e4467507dcf6d20)) + - **Ethers** adapter unit tests ([fccb3a5](https://github.com/dutterbutter/zksync-sdk/commit/fccb3a56dd380626af93d16b36b8bd68441159a2)) + - **viem** support ([3a5c559](https://github.com/dutterbutter/zksync-sdk/commit/3a5c5598b49f909b334c597f06d18678155fdf5f)) + - Docs scaffolding ([ab152df](https://github.com/dutterbutter/zksync-sdk/commit/ab152df33d57f0e1567742f0f5bef256c2974f44)) + - Deposit flow + `wait()` improvements ([de6d6c0](https://github.com/dutterbutter/zksync-sdk/commit/de6d6c0ce391fe29f9c92603b9cbc2e088dbfe8a)) + - Deposits in **viem** ([e7267cb](https://github.com/dutterbutter/zksync-sdk/commit/e7267cb001f06ffbafadfea3dbe7a935375fcb2d)) + - E2E test cleanups + docs ([252b18a](https://github.com/dutterbutter/zksync-sdk/commit/252b18adce979dc337fc81a993c216d4592082af)) + - E2E tests for **ETH** ([8e7d453](https://github.com/dutterbutter/zksync-sdk/commit/8e7d453493202e605f0f8b95e9c0a3cf99fdfea4), [31b43c6](https://github.com/dutterbutter/zksync-sdk/commit/31b43c62f70731f2c762214cb63689c0c6e44094)) + - **Error envelope** groundwork + integration ([0c9ea07](https://github.com/dutterbutter/zksync-sdk/commit/0c9ea078d3130095896406c943b363d1ac476e43), [e496cc8](https://github.com/dutterbutter/zksync-sdk/commit/e496cc8a98cfe7e3512288ff861110c34ede04e0)) + - **Finalization** interfacing completed ([a026203](https://github.com/dutterbutter/zksync-sdk/commit/a0262033809cb8505a20511edc39083f820a439a)) + - Prep for alpha.1 ([c6c15e1](https://github.com/dutterbutter/zksync-sdk/commit/c6c15e12fba16a355171e30db42995600fad106b)) + - E2E green ✅ ([c65c5b1](https://github.com/dutterbutter/zksync-sdk/commit/c65c5b1976a940ac8f8ff4f82cb7b74cd8d37f5b)) + + ### Bug Fixes + - Export fixes in build ([#18](https://github.com/dutterbutter/zksync-sdk/issues/18)) ([5afbcbd](https://github.com/dutterbutter/zksync-sdk/commit/5afbcbdf13a3e15da94c8b66bc38e643097f917a)) + - Build stability improvements ([1a24cf7](https://github.com/dutterbutter/zksync-sdk/commit/1a24cf76d61ee9c172fb0428c5b2386f4553f736)) + + Compare diff + + + + ### Highlights + - **Initial alpha** release: core flows, **viem** + **ethers** adapters, deposits/withdrawals, status/wait helpers. + - CI/release scaffolding and early docs. + + Compare diff + diff --git a/docs/docs.json b/docs/docs.json index 5d8b3a9..d61fe90 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -31,15 +31,17 @@ "pages": [ "overview/index", "overview/mental-model", - "overview/adapters" + "overview/adapters", + "overview/status-vs-wait", + "overview/finalization" ] }, { "group": "Quickstart", "pages": [ "quickstart/index", - "quickstart/viem", - "quickstart/ethers" + "quickstart/deposits", + "quickstart/withdrawals" ] }, { @@ -49,15 +51,7 @@ "guides/withdrawals", "guides/finalization" ] - }, - { - "group": "Concepts", - "pages": [ - "concepts/index", - "concepts/status-vs-wait", - "concepts/finalization" - ] - } + } ] }, { @@ -104,7 +98,7 @@ "links": [ { "label": "Support", - "href": "mailto:hi@mintlify.com" + "href": "https://github.com/zkSync-Community-Hub/zksync-developers/discussions/categories/sdks" } ], "primary": { diff --git a/docs/overview/finalization.mdx b/docs/overview/finalization.mdx new file mode 100644 index 0000000..57e94b2 --- /dev/null +++ b/docs/overview/finalization.mdx @@ -0,0 +1,114 @@ +--- +title: Finalization (Withdrawals) +description: Withdrawals from ZKsync (L2) only complete on Ethereum (L1) after you explicitly call `finalize`. +--- + +When withdrawing from ZKsync (L2) back to Ethereum (L1), **funds are _not_ automatically released on L1** after your L2 tx is included. + +Withdrawals are a **two-step process**: + +1. **Initiate on L2** — call `withdraw()` (via the SDK’s `create`) to start the withdrawal. + This burns/locks funds on L2 and emits logs; **funds are still unavailable on L1**. +2. **Finalize on L1** — call **`finalize(l2TxHash)`** to release funds on L1. + This submits an L1 tx; only then does your ETH or token balance increase on Ethereum. + + + If you **never finalize**, your funds remain locked: visible as “ready to withdraw,” but unavailable on L1. + Anyone can finalize on your behalf, but you typically do it. + + +## Why finalization matters + +- **Funds remain locked** until you (or anyone) finalizes. +- **Anyone can finalize** — typically the withdrawer does. +- **Finalization costs L1 gas** — budget for it. + +## Finalization methods + +| Method | Purpose | Returns | +| --- | --- | --- | +| `withdrawals.status(h \| l2TxHash)` | Snapshot phase (`UNKNOWN` → `FINALIZED`) | `WithdrawalStatus` | +| `withdrawals.wait(h \| l2TxHash, { for })` | Block until a checkpoint (`'l2' \| 'ready' \| 'finalized'`) | Receipt or `null` | +| `withdrawals.finalize(l2TxHash)` | **Send** the L1 finalize tx | `{ status, receipt }` | + + + All methods accept either a **handle** (from `create`) or a **raw L2 tx hash**. If you only have the hash, you can still finalize. + + +## Phases + +| Phase | Meaning | +| --- | --- | +| `UNKNOWN` | Handle doesn’t contain an L2 hash yet. | +| `L2_PENDING` | L2 tx not yet included. | +| `PENDING` | L2 included, but not yet ready to finalize on L1. | +| `READY_TO_FINALIZE` | Finalization on L1 would succeed now. | +| `FINALIZED` | Finalized on L1; funds released. | + +## Examples + + +```ts finalize-by-handle.ts theme={null} +// 1) Create on L2 +const withdrawal = await sdk.withdrawals.create({ + token: ETH_ADDRESS, + amount: parseEther('0.1'), + to: myAddress, +}); + +// 2) Wait until finalizable (no side effects) +await sdk.withdrawals.wait(withdrawal, { for: 'ready', pollMs: 5500 }); + +// 3) Finalize on L1 +const { status, receipt } = await sdk.withdrawals.finalize(withdrawal.l2TxHash); + +console.log(status.phase); // "FINALIZED" +console.log(receipt?.transactionHash); // L1 finalize tx hash +``` + +```ts finalize-by-hash.ts theme={null} +// If you only have the L2 tx hash: +const l2TxHash = '0x...'; + +// Optionally confirm readiness first +const s = await sdk.withdrawals.status(l2TxHash); +if (s.phase !== 'READY_TO_FINALIZE') { + await sdk.withdrawals.wait(l2TxHash, { for: 'ready', timeoutMs: 30 * 60_000 }); +} + +// Then finalize +const { status, receipt } = await sdk.withdrawals.finalize(l2TxHash); +``` + + + +Prefer the **no-throw** variants in UIs/services that want explicit flow control: + + +```ts try-finalize.ts theme={null} +const r = await sdk.withdrawals.tryFinalize(l2TxHash); +if (!r.ok) { + // Show a toast / retry UI + console.error('Finalize failed:', r.error); +} else { + console.log('Finalized on L1:', r.value.receipt?.transactionHash); +} +``` + +## Operational tips + +* **Gate UX with phases:** Display a **Finalize** button only when `status.phase === 'READY_TO_FINALIZE'`. +* **Polling cadence:** `wait(..., { for: 'ready' })` defaults to ~**5500 ms**. Adjust with `pollMs` if needed. +* **Timeouts:** Use `timeoutMs` for long windows and fall back to `status(...)` to keep the UI responsive. +* **Receipts can be `null`:** `wait(..., { for: 'finalized' })` can resolve `null` if finalized but receipt isn’t retrievable; consider showing a link to the L1 explorer based on the tx hash you submitted. + +## Common errors + +* **RPC/network hiccups:** thrown `ZKsyncError` with kind **`RPC`**. Retry with backoff. +* **Internal decode issues:** thrown `ZKsyncError` with kind **`INTERNAL`**. Capture logs and report. + +## See also + +* [Status vs Wait](/concepts/status-vs-wait) +* [Withdrawals guide](/guides/withdrawals) + diff --git a/docs/overview/index.mdx b/docs/overview/index.mdx index 3ae83e0..a11d308 100644 --- a/docs/overview/index.mdx +++ b/docs/overview/index.mdx @@ -42,77 +42,6 @@ The SDK doesn’t replace your existing Ethereum libraries — it **extends** th - [**Mental model**](./mental-model) — how to think about the core methods (`quote → prepare → create → status → wait → finalize`). - [**Adapters (viem & ethers)**](./adapters) — how the SDK integrates with your existing stack. -## Quick Example - -Here's how a simple deposit looks like using both **`viem`** and **`ethers`** adapters: - - -```ts viem.ts -import { createPublicClient, http, createWalletClient, parseEther } from "viem"; -import { createViemSdk, createViemClient } from "@dutterbutter/zksync-sdk/viem"; -import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; - -const l1 = createPublicClient({ transport: http(L1_RPC) }); -const l2 = createPublicClient({ transport: http(L2_RPC) }); - -const l1Wallet: WalletClient = createWalletClient({ - account, - transport: http(L1_RPC), - }); - -const client = createViemClient({ l1, l2, l1Wallet }); -const sdk = createViemSdk(client); - -const me = account.address as Address; -const params = { - amount: parseEther('0.01'), - token: ETH_ADDRESS, - to: me, - // optional: - // l2GasLimit: 300_000n, - // gasPerPubdata: 800n, - // operatorTip: 0n, - // refundRecipient: me, -} as const; - -const handle = await sdk.deposits.create({ params }); -await sdk.deposits.wait(handle, { for: 'l1' }); // L1 included -await sdk.deposits.wait(handle, { for: 'l2' }); // L2 executed - -console.log('Deposit complete ✅'); -``` - -```ts ethers.ts -import { JsonRpcProvider, Wallet, parseEther } from 'ethers'; -import { createEthersClient, createEthersSdk } from '@dutterbutter/zksync-sdk/ethers'; -import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; - -const L1_RPC = new JsonRpcProvider('https://sepolia.infura.io/v3/...'); -const L2_RPC = new JsonRpcProvider('https://zksync-testnet.rpc'); -const signer = new Wallet(process.env.PRIVATE_KEY!, L1_RPC); - -const client = await createEthersClient({ l1Provider: L1_RPC, l2Provider: L2_RPC, signer }); -const sdk = createEthersSdk(client); - -const params = { - amount: parseEther('0.01'), - token: ETH_ADDRESS, - to: signer.address, - // optional: - // l2GasLimit: 300_000n, - // gasPerPubdata: 800n, - // operatorTip: 0n, - // refundRecipient: me, -} as const; - -const handle = await sdk.deposits.create({ params }); -await sdk.deposits.wait(handle, { for: 'l1' }); // L1 included -await sdk.deposits.wait(handle, { for: 'l2' }); // L2 executed - -console.log('Deposit complete ✅'); -``` - - ## Next steps 👉 Ready to build? Jump to the [Quickstart](../quickstart/index). diff --git a/docs/overview/status-vs-wait.mdx b/docs/overview/status-vs-wait.mdx new file mode 100644 index 0000000..0ee0a9a --- /dev/null +++ b/docs/overview/status-vs-wait.mdx @@ -0,0 +1,156 @@ +--- +title: Status vs Wait +description: Snapshot progress with `status(...)` or block until a checkpoint with `wait(..., { for })` for deposits and withdrawals. +--- + +The SDK exposes two complementary ways to track progress: + +- **`status(...)`** — returns a **non-blocking snapshot** of where an operation is. +- **`wait(..., { for })`** — **blocks/polls** until a specified checkpoint is reached. + +Both apply to **deposits** and **withdrawals**. Use `status(...)` for UI refreshes; use `wait(...)` when you need to gate logic on inclusion/finality. + + + You can pass **either** a handle returned from `create(...)` **or** a raw transaction hash. + + +## Withdrawals + +### `withdrawals.status(h | l2TxHash): Promise` + +**Input** +- `h`: a `WithdrawalWaitable` (e.g., from `create`) **or** the L2 tx hash `Hex`. + +**Phases** +| Phase | Meaning | +| -------------------- | ----------------------------------------------------------- | +| `UNKNOWN` | Handle doesn’t contain an L2 hash yet. | +| `L2_PENDING` | L2 tx not yet included. | +| `PENDING` | L2 included, **not** yet ready to finalize on L1. | +| `READY_TO_FINALIZE` | Finalization on L1 would succeed now. | +| `FINALIZED` | Finalized on L1; funds released. | + +**Notes** +- No L2 receipt ⇒ `L2_PENDING`. +- Finalization key derivable but not ready ⇒ `PENDING`. +- Already finalized ⇒ `FINALIZED`. + +```ts withdrawals-status.ts theme={null} +const s = await sdk.withdrawals.status(handleOrHash); +// s.phase ∈ 'UNKNOWN' | 'L2_PENDING' | 'PENDING' | 'READY_TO_FINALIZE' | 'FINALIZED' +```` + +### `withdrawals.wait(h | l2TxHash, { for, pollMs?, timeoutMs? })` + +**Targets** + +| Target | Resolves with | +| ---------------------- | --------------------------------------------------------------------------- | +| `{ for: 'l2' }` | **L2 receipt** (`TransactionReceipt \| null`) | +| `{ for: 'ready' }` | **`null`** when finalization becomes possible | +| `{ for: 'finalized' }` | **L1 receipt** when finalized, or `null` if finalized but receipt not found | + +**Behavior** + +* If the handle has **no L2 hash**, returns `null` immediately. +* Default polling: **5500 ms** (override via `pollMs`). +* `timeoutMs` returns `null` on deadline. + +```ts withdrawals-wait.ts theme={null} +// Wait for L2 inclusion → get L2 receipt (augmented with l2ToL1Logs if available) +const l2Rcpt = await sdk.withdrawals.wait(handle, { for: 'l2', pollMs: 5000 }); + +// Wait until it becomes finalizable (no side effects) +await sdk.withdrawals.wait(handle, { for: 'ready' }); + +// Wait for L1 finalization → L1 receipt (or null if not retrievable) +const l1Rcpt = await sdk.withdrawals.wait(handle, { for: 'finalized', timeoutMs: 15 * 60_000 }); +``` + + + Building a UI? Use `status(...)` to paint current phase and enable/disable the **Finalize** button when phase is `READY_TO_FINALIZE`. + + +## Deposits + +### `deposits.status(h | l1TxHash): Promise` + +**Input** + +* `h`: `DepositWaitable` (from `create`) **or** L1 tx hash `Hex`. + +**Phases** + +| Phase | Meaning | +| ------------- | ------------------------------------------------- | +| `UNKNOWN` | No L1 hash present on the handle. | +| `L1_PENDING` | L1 receipt missing. | +| `L1_INCLUDED` | L1 included; L2 hash not yet derivable from logs. | +| `L2_PENDING` | L2 hash known but L2 receipt missing. | +| `L2_EXECUTED` | L2 receipt present with `status === 1`. | +| `L2_FAILED` | L2 receipt present with `status !== 1`. | + +```ts deposits-status.ts theme={null} +const s = await sdk.deposits.status(handleOrL1Hash); +// s.phase ∈ 'UNKNOWN' | 'L1_PENDING' | 'L1_INCLUDED' | 'L2_PENDING' | 'L2_EXECUTED' | 'L2_FAILED' +``` + +### `deposits.wait(h | l1TxHash, { for: 'l1' | 'l2' })` + +**Targets** + +| Target | Resolves with | +| --------------- | ------------------------------------------------------------------- | +| `{ for: 'l1' }` | **L1 receipt** or `null` | +| `{ for: 'l2' }` | **L2 receipt** or `null` (waits L1 inclusion **then** L2 execution) | + +```ts deposits-wait.ts theme={null} +const l1Rcpt = await sdk.deposits.wait(handle, { for: 'l1' }); +const l2Rcpt = await sdk.deposits.wait(handle, { for: 'l2' }); +``` + + + `wait(..., { for: 'l2' })` waits for both **L1 inclusion** and **canonical L2 execution**. + + +## Practical patterns + +### Pick the right tool + +* **Use `status(...)`** for **poll-less UI refreshes** (e.g., on page focus or interval timers you control). +* **Use `wait(...)`** for **workflow gating** (scripts, jobs, “continue when X happens”). + +### Timeouts & polling + +```ts polling.ts theme={null} +const ready = await sdk.withdrawals.wait(handle, { + for: 'ready', + pollMs: 5500, // minimum enforced internally + timeoutMs: 30 * 60_000, // 30 minutes; returns null on deadline +}); +if (ready === null) { + // timeout or not yet finalizable — decide whether to retry or show a hint +} +``` + +### Error handling + +* Network hiccup while fetching receipts ⇒ throws `ZKsyncError` of kind **`RPC`**. +* Internal decode issue ⇒ throws `ZKsyncError` of kind **`INTERNAL`**. + +Prefer no-throw variants if you want explicit flow control: + +```ts no-throw.ts theme={null} +const r = await sdk.withdrawals.tryWait(handle, { for: 'finalized' }); +if (!r.ok) { + console.error('Finalize wait failed:', r.error); +} else { + console.log('Finalized L1 receipt:', r.value); +} +``` + +## Tips & edge cases + +* **Handles vs hashes:** Passing a handle without the relevant hash yields `UNKNOWN`/`null`. If you already have a hash, pass the hash directly. +* **Finalization windows:** For withdrawals, `READY_TO_FINALIZE` can take a while. Use `status(...)` to keep the UI responsive and `wait(..., { for: 'finalized' })` only where blocking makes sense. +* **Retries:** If a wait returns `null` due to `timeoutMs`, you can safely call `status(...)` to decide whether to keep waiting or surface guidance to the user. diff --git a/docs/quickstart/deposits.mdx b/docs/quickstart/deposits.mdx new file mode 100644 index 0000000..b506eb9 --- /dev/null +++ b/docs/quickstart/deposits.mdx @@ -0,0 +1,203 @@ +--- +title: ETH Deposit (L1 → L2) +description: Get your first ETH deposit from Ethereum (L1) to ZKsync (L2). +--- + +## 1. Prerequisites + +- You have [Bun](https://bun.sh/) installed. +- A funded **L1 wallet** with ETH for both the deposit amount and L1 gas fees + + +Use a test network like **Sepolia** for experimentation. + + +## 2. Installation + +Choose your adapter and install the SDK + adapter package: + + + ```bash title="viem" + bun install @dutterbutter/zksync-sdk viem dotenv + ``` + + ```bash title="ethers" + bun install @dutterbutter/zksync-sdk ethers dotenv + ``` + + +Create a `.env` file in your project root: + +```env +# Your funded L1 private key (0x + 64 hex) +PRIVATE_KEY=0xYOUR_PRIVATE_KEY_HERE + +# RPC endpoints +L1_RPC_URL=https://sepolia.infura.io/v3/YOUR_INFURA_ID +L2_RPC_URL=ZKSYNC-OS-TESTNET-RPC +``` + + +Never commit your `.env` file to source control. + + +## 3. Write the deposit script + + + ```ts title="deposit/viem.ts" + import 'dotenv/config'; + import { createPublicClient, createWalletClient, http, parseEther } from 'viem'; + import { privateKeyToAccount } from 'viem/accounts'; + import { createViemClient, createViemSdk } from '@dutterbutter/zksync-sdk/viem'; + import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; + + const PRIVATE_KEY = process.env.PRIVATE_KEY; + const L1_RPC_URL = process.env.L1_RPC_URL; + const L2_RPC_URL = process.env.L2_RPC_URL; + + async function main() { + if (!PRIVATE_KEY || !L1_RPC_URL || !L2_RPC_URL) { + throw new Error('Please set PRIVATE_KEY, L1_RPC_URL, and L2_RPC_URL in your .env file'); + } + + // 1. Set up clients + const account = privateKeyToAccount(PRIVATE_KEY as `0x${string}`); + const l1 = createPublicClient({ transport: http(L1_RPC_URL) }); + const l2 = createPublicClient({ transport: http(L2_RPC_URL) }); + const l1Wallet = createWalletClient({ account, transport: http(L1_RPC_URL) }); + + // 2. Initialize the SDK + const client = createViemClient({ l1, l2, l1Wallet }); + const sdk = createViemSdk(client); + + console.log('Wallet balances:'); + console.log(' L1:', await l1.getBalance({ address: account.address })); + console.log(' L2:', await l2.getBalance({ address: account.address })); + + // 3. Perform the deposit + console.log('Sending deposit transaction...'); + const depositHandle = await sdk.deposits.create({ + token: ETH_ADDRESS, + amount: parseEther('0.001'), + to: account.address, + }); + + console.log(`L1 transaction hash: ${depositHandle.l1TxHash}`); + + console.log('Waiting for confirmation on L1...'); + const l1Receipt = await sdk.deposits.wait(depositHandle, { for: 'l1' }); + console.log(`✔️ Confirmed on L1 at block ${l1Receipt?.blockNumber}`); + + console.log('Waiting for execution on L2...'); + const l2Receipt = await sdk.deposits.wait(depositHandle, { for: 'l2' }); + console.log(`✔️ Executed on L2 at block ${l2Receipt?.blockNumber}`); + + console.log('Deposit complete ✅'); + + console.log('Updated balances:'); + console.log(' L1:', await l1.getBalance({ address: account.address })); + console.log(' L2:', await l2.getBalance({ address: account.address })); + } + + main().catch((err) => { + console.error('An error occurred:', err); + process.exit(1); + }); + ``` + + ```tsx title="deposit/ethers.ts" + import 'dotenv/config'; // Load environment variables from .env + import { JsonRpcProvider, Wallet, parseEther } from 'ethers'; + import { createEthersClient, createEthersSdk } from '@dutterbutter/zksync-sdk/ethers'; + import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; + + const PRIVATE_KEY = process.env.PRIVATE_KEY; + const L1_RPC_URL = process.env.L1_RPC_URL; + const L2_RPC_URL = process.env.L2_RPC_URL; + + async function main() { + if (!PRIVATE_KEY || !L1_RPC_URL || !L2_RPC_URL) { + throw new Error('Please set your PRIVATE_KEY, L1_RPC_URL, and L2_RPC_URL in a .env file'); + } + + // 1. SET UP PROVIDERS AND SIGNER + // The SDK needs connections to both L1 and L2 to function. + const l1Provider = new JsonRpcProvider(L1_RPC_URL); + const l2Provider = new JsonRpcProvider(L2_RPC_URL); + const signer = new Wallet(PRIVATE_KEY, l1Provider); + + // 2. INITIALIZE THE SDK CLIENT + // The client is the low-level interface for interacting with the API. + const client = await createEthersClient({ + l1Provider, + l2Provider, + signer, + }); + const sdk = createEthersSdk(client); + + const L1balance = await l1.getBalance({ address: signer.address }); + const L2balance = await l2.getBalance({ address: signer.address }); + + console.log('Wallet balance on L1:', L1balance); + console.log('Wallet balance on L2:', L2balance); + + // 3. PERFORM THE DEPOSIT + // The create() method prepares and sends the transaction. + // The wait() method polls until the transaction is complete. + console.log('Sending deposit transaction...'); + const depositHandle = await sdk.deposits.create({ + token: ETH_ADDRESS, + amount: parseEther('0.001'), // 0.001 ETH + to: account.address, + }); + + console.log(`L1 transaction hash: ${depositHandle.l1TxHash}`); + console.log('Waiting for the deposit to be confirmed on L1...'); + + // Wait for L1 inclusion + const l1Receipt = await sdk.deposits.wait(depositHandle, { for: 'l1' }); + console.log(`Deposit confirmed on L1 in block ${l1Receipt?.blockNumber}`); + + console.log('Waiting for the deposit to be executed on L2...'); + + // Wait for L2 execution + const l2Receipt = await sdk.deposits.wait(depositHandle, { for: 'l2' }); + console.log(`Deposit executed on L2 in block ${l2Receipt?.blockNumber}`); + console.log('Deposit complete! ✅'); + + const L1balanceAfter = await l1.getBalance({ address: signer.address }); + const L2balanceAfter = await l2.getBalance({ address: signer.address }); + + console.log('Wallet balance on L1 after:', L1balanceAfter); + console.log('Wallet balance on L2 after:', L2balanceAfter); + } + + main().catch((error) => { + console.error('An error occurred:', error); + process.exit(1); + }); + ``` + + +## 4. Run it + +Execute the script using `bun`. + + + ``` bash title="viem" + bun run deposit/viem.ts + ``` + + ```bash title="ethers" + bun run deposit/ethers.ts + ``` + + +You’ll see logs for the L1 transaction, then L2 execution, followed by updated balances. + +## 5. Troubleshooting + +- **Insufficient funds on L1:** Ensure enough ETH for the deposit **and** L1 gas. +- **Invalid PRIVATE_KEY:** Must be 0x + 64 hex chars. +- **Stuck at wait(..., `{ for: 'l2' }`):** Verify L2_RPC_URL and network health; check sdk.deposits.status(handle) to see the current phase. +- **ERC-20 deposits:** Make sure you have an L1 token deployed and a sufficient balance. diff --git a/docs/quickstart/ethers.mdx b/docs/quickstart/ethers.mdx deleted file mode 100644 index c09873c..0000000 --- a/docs/quickstart/ethers.mdx +++ /dev/null @@ -1,132 +0,0 @@ ---- -title: Ethers Deposits -description: Get your first ETH deposit from Ethereum to ZKsync using the ethers adapter of @zksync-sdk. ---- - -# Quickstart (ethers): ETH Deposit (L1 → L2) - -This guide walks you through sending your first **ETH deposit** from Ethereum (L1) to ZKsync (L2) using the **ethers** adapter. - -## 1. Prerequisites - -- You have [Bun](https://bun.sh/) installed. -- A funded **L1 wallet** with ETH for both the deposit amount and L1 gas fees - - -Use a test network like **Sepolia** for experimentation. - - -## 2. Installation - -```bash -bun install @dutterbutter/zksync-sdk ethers dotenv -``` - -Create a `.env` file in your project root: - -```env -# Your funded L1 private key (0x + 64 hex) -PRIVATE_KEY=0xYOUR_PRIVATE_KEY_HERE - -# RPC endpoints -L1_RPC_URL=https://sepolia.infura.io/v3/YOUR_INFURA_ID -L2_RPC_URL=ZKSYNC-OS-TESTNET-RPC -``` - - -Never commit your `.env` file to source control. - - -## 3. Write the deposit script - -Save as **`deposit-ethers.ts`**: - -```ts -import 'dotenv/config'; // Load environment variables from .env -import { JsonRpcProvider, Wallet, parseEther } from 'ethers'; -import { createEthersClient, createEthersSdk } from '@dutterbutter/zksync-sdk/ethers'; -import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; - -const PRIVATE_KEY = process.env.PRIVATE_KEY; -const L1_RPC_URL = process.env.L1_RPC_URL; -const L2_RPC_URL = process.env.L2_RPC_URL; - -async function main() { - if (!PRIVATE_KEY || !L1_RPC_URL || !L2_RPC_URL) { - throw new Error('Please set your PRIVATE_KEY, L1_RPC_URL, and L2_RPC_URL in a .env file'); - } - - // 1. SET UP PROVIDERS AND SIGNER - // The SDK needs connections to both L1 and L2 to function. - const l1Provider = new JsonRpcProvider(L1_RPC_URL); - const l2Provider = new JsonRpcProvider(L2_RPC_URL); - const signer = new Wallet(PRIVATE_KEY, l1Provider); - - // 2. INITIALIZE THE SDK CLIENT - // The client is the low-level interface for interacting with the API. - const client = await createEthersClient({ - l1Provider, - l2Provider, - signer, - }); - const sdk = createEthersSdk(client); - - const L1balance = await l1.getBalance({ address: signer.address }); - const L2balance = await l2.getBalance({ address: signer.address }); - - console.log('Wallet balance on L1:', L1balance); - console.log('Wallet balance on L2:', L2balance); - - // 3. PERFORM THE DEPOSIT - // The create() method prepares and sends the transaction. - // The wait() method polls until the transaction is complete. - console.log('Sending deposit transaction...'); - const depositHandle = await sdk.deposits.create({ - token: ETH_ADDRESS, - amount: parseEther('0.001'), // 0.001 ETH - to: account.address, - }); - - console.log(`L1 transaction hash: ${depositHandle.l1TxHash}`); - console.log('Waiting for the deposit to be confirmed on L1...'); - - // Wait for L1 inclusion - const l1Receipt = await sdk.deposits.wait(depositHandle, { for: 'l1' }); - console.log(`Deposit confirmed on L1 in block ${l1Receipt?.blockNumber}`); - - console.log('Waiting for the deposit to be executed on L2...'); - - // Wait for L2 execution - const l2Receipt = await sdk.deposits.wait(depositHandle, { for: 'l2' }); - console.log(`Deposit executed on L2 in block ${l2Receipt?.blockNumber}`); - console.log('Deposit complete! ✅'); - - const L1balanceAfter = await l1.getBalance({ address: signer.address }); - const L2balanceAfter = await l2.getBalance({ address: signer.address }); - - console.log('Wallet balance on L1 after:', L1balanceAfter); - console.log('Wallet balance on L2 after:', L2balanceAfter); -} - -main().catch((error) => { - console.error('An error occurred:', error); - process.exit(1); -}); -``` - -## 4. Run it - -Execute the script using `bun`. - -```bash bun -bun run deposit-ethers.ts -``` - -You’ll see logs for the L1 transaction, then L2 execution, followed by updated balances. - -## 5. Troubleshooting - -- **Insufficient funds on L1:** Ensure enough ETH for the deposit **and** L1 gas. - **Invalid PRIVATE_KEY:** Must be 0x + 64 hex chars. -- **Invalid PRIVATE_KEY:** Must be 0x + 64 hex chars. -- **Stuck at wait(..., `{ for: 'l2' }`):** Verify L2_RPC_URL and network health; check sdk.deposits.status(handle) to see the current phase. -- **ERC-20 deposits:** Make sure you have an L1 token deployed and a sufficient balance. diff --git a/docs/quickstart/index.mdx b/docs/quickstart/index.mdx index f9cbefd..bacef37 100644 --- a/docs/quickstart/index.mdx +++ b/docs/quickstart/index.mdx @@ -16,21 +16,19 @@ You can't make a wrong choice. Both adapters are fully supported and provide the - For projects using **viem**. Learn how to install the `viem` adapter, - connect an L1 + L2 client, and send your first deposit. + L1 → L2 deposit — submit a deposit, and monitor until confirmed. - For projects using **ethers v6**. Learn how to install the `ethers` adapter, - connect an L1 + L2 client, and send your first deposit. + L2 → L1 withdrawal — submit a withdrawal, and monitor until readied. @@ -40,7 +38,7 @@ Each Quickstart walks you through: 1. **Install** the adapter package. 2. **Configure** a client or signer. -3. **Run** a deposit (L1 → L2) as a working example. +3. **Run** a deposit (L1 → L2) or withdrawal (L2 → L1) as a working example. 4. **Track** the status until it’s complete. diff --git a/docs/quickstart/viem.mdx b/docs/quickstart/viem.mdx deleted file mode 100644 index 3421ce7..0000000 --- a/docs/quickstart/viem.mdx +++ /dev/null @@ -1,118 +0,0 @@ ---- -title: Viem Deposits -description: Get your first ETH deposit from Ethereum to ZKsync using the viem adapter of @zksync-sdk. ---- - -# Quickstart (viem): ETH Deposit (L1 → L2) - -This guide walks you through sending your first **ETH deposit** from Ethereum (L1) to ZKsync (L2) using the **viem** adapter. - -## 1. Prerequisites - -- [Bun](https://bun.sh/) installed -- A funded **L1 wallet** with ETH for both the deposit amount and L1 gas fees - - -Use a test network like **Sepolia** for experimentation. - - -## 2. Install dependencies - -```bash bun -bun install @dutterbutter/zksync-sdk viem dotenv -``` - -Create a `.env` file in your project root: - -```env -# Your funded L1 private key (0x + 64 hex) -PRIVATE_KEY=0xYOUR_PRIVATE_KEY_HERE - -# RPC endpoints -L1_RPC_URL=https://sepolia.infura.io/v3/YOUR_INFURA_ID -L2_RPC_URL=ZKSYNC-OS-TESTNET-RPC -``` - - -Never commit your `.env` file to source control. - - -## 3. Write the deposit script - -Save as **`deposit-viem.ts`**: - -```ts -import 'dotenv/config'; -import { createPublicClient, createWalletClient, http, parseEther } from 'viem'; -import { privateKeyToAccount } from 'viem/accounts'; -import { createViemClient, createViemSdk } from '@dutterbutter/zksync-sdk/viem'; -import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; - -const PRIVATE_KEY = process.env.PRIVATE_KEY; -const L1_RPC_URL = process.env.L1_RPC_URL; -const L2_RPC_URL = process.env.L2_RPC_URL; - -async function main() { - if (!PRIVATE_KEY || !L1_RPC_URL || !L2_RPC_URL) { - throw new Error('Please set PRIVATE_KEY, L1_RPC_URL, and L2_RPC_URL in your .env file'); - } - - // 1. Set up clients - const account = privateKeyToAccount(PRIVATE_KEY as `0x${string}`); - const l1 = createPublicClient({ transport: http(L1_RPC_URL) }); - const l2 = createPublicClient({ transport: http(L2_RPC_URL) }); - const l1Wallet = createWalletClient({ account, transport: http(L1_RPC_URL) }); - - // 2. Initialize the SDK - const client = createViemClient({ l1, l2, l1Wallet }); - const sdk = createViemSdk(client); - - console.log('Wallet balances:'); - console.log(' L1:', await l1.getBalance({ address: account.address })); - console.log(' L2:', await l2.getBalance({ address: account.address })); - - // 3. Perform the deposit - console.log('Sending deposit transaction...'); - const depositHandle = await sdk.deposits.create({ - token: ETH_ADDRESS, - amount: parseEther('0.001'), - to: account.address, - }); - - console.log(`L1 transaction hash: ${depositHandle.l1TxHash}`); - - console.log('Waiting for confirmation on L1...'); - const l1Receipt = await sdk.deposits.wait(depositHandle, { for: 'l1' }); - console.log(`✔️ Confirmed on L1 at block ${l1Receipt?.blockNumber}`); - - console.log('Waiting for execution on L2...'); - const l2Receipt = await sdk.deposits.wait(depositHandle, { for: 'l2' }); - console.log(`✔️ Executed on L2 at block ${l2Receipt?.blockNumber}`); - - console.log('Deposit complete ✅'); - - console.log('Updated balances:'); - console.log(' L1:', await l1.getBalance({ address: account.address })); - console.log(' L2:', await l2.getBalance({ address: account.address })); -} - -main().catch((err) => { - console.error('An error occurred:', err); - process.exit(1); -}); -``` - -## 4. Run it - -```bash bun -bun run deposit-viem.ts -``` - -You’ll see logs for the L1 transaction, then L2 execution, followed by updated balances. - -## 5. Troubleshooting - -- **Insufficient funds on L1:** Ensure enough ETH for the deposit **and** L1 gas. - **Invalid PRIVATE_KEY:** Must be 0x + 64 hex chars. -- **Invalid PRIVATE_KEY:** Must be 0x + 64 hex chars. -- **Stuck at wait(..., `{ for: 'l2' }`):** Verify L2_RPC_URL and network health; check sdk.deposits.status(handle) to see the current phase. -- **ERC-20 deposits:** Make sure you have an L1 token deployed and a sufficient balance. diff --git a/docs/quickstart/withdrawals.mdx b/docs/quickstart/withdrawals.mdx new file mode 100644 index 0000000..aa136ac --- /dev/null +++ b/docs/quickstart/withdrawals.mdx @@ -0,0 +1,208 @@ +--- +title: ETH Withdrawal (L2 → L1) +description: Get your first ETH withdrawal from ZKsync (L2) to Ethereum (L1). +--- + +## 1. Prerequisites + +- You have [Bun](https://bun.sh/) installed. +- A funded **L1 wallet** with ETH for both the withdrawal amount and L1 gas fees + + +Use a test network like **Sepolia** for experimentation. + + +## 2. Installation + +Choose your adapter and install the SDK + adapter package: + + + ```bash title="viem" + bun install @dutterbutter/zksync-sdk viem dotenv + ``` + + ```bash title="ethers" + bun install @dutterbutter/zksync-sdk ethers dotenv + ``` + + +Create a `.env` file in your project root: + +```env +# Your funded L1 private key (0x + 64 hex) +PRIVATE_KEY=0xYOUR_PRIVATE_KEY_HERE + +# RPC endpoints +L1_RPC_URL=https://sepolia.infura.io/v3/YOUR_INFURA_ID +L2_RPC_URL=ZKSYNC-OS-TESTNET-RPC +``` + + +Never commit your `.env` file to source control. + + +## 3. Write the withdrawal script + + + ```ts title="withdrawals/viem.ts" + import { + createPublicClient, + createWalletClient, + http, + parseEther, + type Account, + type Chain, + type Transport, + type WalletClient, + } from 'viem'; + import { privateKeyToAccount } from 'viem/accounts'; + + import { createViemClient, createViemSdk } from '@dutterbutter/zksync-sdk/viem'; + import type { Address } from '@dutterbutter/zksync-sdk/core'; + import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; + + const L1_RPC = 'http://localhost:8545'; // e.g. https://sepolia.infura.io/v3/XXX + const L2_RPC = 'http://localhost:3050'; // your L2 RPC + const PRIVATE_KEY = process.env.PRIVATE_KEY || ''; + + async function main() { + if (!PRIVATE_KEY) throw new Error('Set your PRIVATE_KEY in the environment'); + + // Clients + const account = privateKeyToAccount(PRIVATE_KEY as `0x${string}`); + const l1 = createPublicClient({ transport: http(L1_RPC) }); + const l2 = createPublicClient({ transport: http(L2_RPC) }); + const l1Wallet: WalletClient = createWalletClient({ + account, + transport: http(L1_RPC), + }); + // Need to provide an L2 wallet client for sending L2 withdraw tx + const l2Wallet = createWalletClient({ + account, + transport: http(L2_RPC), + }); + + const client = createViemClient({ l1, l2, l1Wallet, l2Wallet }); + const sdk = createViemSdk(client); + + const me = account.address as Address; + + const params = { + token: ETH_ADDRESS, // ETH Address + amount: parseEther('0.01'), + to: me, + } as const; + + const quote = await sdk.withdrawals.quote(params); + console.log('QUOTE:', quote); + + const prepared = await sdk.withdrawals.prepare(params); + console.log('PREPARE:', prepared); + + const created = await sdk.withdrawals.create(params); + console.log('CREATE:', created); + + console.log('STATUS (initial):', await sdk.withdrawals.status(created)); + + const l2Receipt = await sdk.withdrawals.wait(created, { for: 'l2' }); + console.log('L2 included tx:', l2Receipt?.transactionHash); + + await sdk.withdrawals.wait(created, { for: 'ready' }); + console.log('STATUS (ready):', await sdk.withdrawals.status(created)); + + const fin = await sdk.withdrawals.tryFinalize(created.l2TxHash); + console.log('TRY FINALIZE:', fin); + + const l1Receipt = await sdk.withdrawals.wait(created.l2TxHash, { for: 'finalized' }); + console.log('Finalized. L1 receipt:', l1Receipt?.transactionHash); + } + + main().catch((e) => { + console.error(e); + process.exit(1); + }); + ``` + + ```tsx title="withdrawals/ethers.ts" + import { JsonRpcProvider, Wallet, parseEther } from 'ethers'; + import { createEthersClient, createEthersSdk } from '@dutterbutter/zksync-sdk/ethers'; + import type { Address } from '@dutterbutter/zksync-sdk/core'; + import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; + + const L1_RPC = 'http://localhost:8545'; + const L2_RPC = 'http://localhost:3050'; + const PRIVATE_KEY = process.env.PRIVATE_KEY || ''; + + async function main() { + if (!PRIVATE_KEY) throw new Error('Set your PRIVATE_KEY in the environment'); + + const l1 = new JsonRpcProvider(L1_RPC); + const l2 = new JsonRpcProvider(L2_RPC); + const signer = new Wallet(PRIVATE_KEY, l1); + + const client = await createEthersClient({ l1, l2, signer }); + const sdk = createEthersSdk(client); + + const me = (await signer.getAddress()) as Address; + + const params = { + token: ETH_ADDRESS, // ETH token on this chain + amount: parseEther('1'), + to: me, + // l2GasLimit?: 300_000n, fee overrides, etc... + } as const; + + const quote = await sdk.withdrawals.quote(params); + console.log('QUOTE:', quote); + + const prepared = await sdk.withdrawals.prepare(params); + console.log('PREPARE:', prepared); + + const created = await sdk.withdrawals.create(params); + console.log('CREATE:', created); + + console.log('STATUS (initial):', await sdk.withdrawals.status(created)); + + // Wait for L2 inclusion + const l2Receipt = await sdk.withdrawals.wait(created, { for: 'l2' }); + console.log('L2 included:', l2Receipt?.hash); + + // Wait until ready to finalize + await sdk.withdrawals.wait(created, { for: 'ready' }); + console.log('STATUS (ready):', await sdk.withdrawals.status(created)); + + // Try to finalize (no-op if already finalized by someone else) + const fin = await sdk.withdrawals.tryFinalize(created.l2TxHash); + console.log('TRY FINALIZE:', fin); + + // Wait for finalization + const l1Receipt = await sdk.withdrawals.wait(created.l2TxHash, { for: 'finalized' }); + console.log('Finalized. L1 receipt:', l1Receipt?.hash); + } + + main().catch((e) => { + console.error(e); + process.exit(1); + }); + ``` + + +## 4. Run it + + + ``` bash title="viem" + bun run withdrawals/viem.ts + ``` + ```bash title="ethers" + bun run withdrawals/ethers.ts + ``` + + +You’ll see logs for the L2 transaction, then L1 finalization readiness, L1 finalization execution, followed by updated balances. + +## 5. Troubleshooting + +- **Insufficient funds on L2:** Ensure enough ETH for the withdrawal **and** L1 gas. +- **Invalid PRIVATE_KEY:** Must be 0x + 64 hex chars. +- **Stuck at wait(..., `{ for: 'l1' }`):** Verify L2_RPC_URL and network health; check sdk.deposits.status(handle) to see the current phase. + diff --git a/docss/snippets/viem/withdrawals-eth.ts b/docss/snippets/viem/withdrawals-eth.ts index 7e640ec..d88bb01 100644 --- a/docss/snippets/viem/withdrawals-eth.ts +++ b/docss/snippets/viem/withdrawals-eth.ts @@ -8,7 +8,7 @@ import { type Chain, type Transport, } from 'viem'; -import { privateKeyToAccount, nonceManager } from 'viem/accounts'; +import { privateKeyToAccount } from 'viem/accounts'; import { createViemSdk, createViemClient } from '@dutterbutter/zksync-sdk/viem'; import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; From dc5b264339bd263ef16adb83096d998f03742373 Mon Sep 17 00:00:00 2001 From: Dustin Brickwood Date: Wed, 8 Oct 2025 20:56:33 -0500 Subject: [PATCH 07/18] feat: start on api reference --- .github/workflows/ci-docs.yaml | 89 ----- docs/api-reference/core/errors.mdx | 0 docs/api-reference/core/rpc.mdx | 0 docs/api-reference/core/types.mdx | 0 docs/api-reference/endpoint/create.mdx | 4 - docs/api-reference/endpoint/delete.mdx | 4 - docs/api-reference/endpoint/get.mdx | 4 - docs/api-reference/endpoint/webhook.mdx | 4 - docs/api-reference/ethers/client.mdx | 127 +++++++ docs/api-reference/ethers/deposits.mdx | 249 ++++++++++++++ docs/api-reference/ethers/overview.mdx | 0 docs/api-reference/ethers/sdk.mdx | 125 +++++++ docs/api-reference/ethers/withdrawals.mdx | 255 ++++++++++++++ docs/api-reference/viem/client.mdx | 156 +++++++++ docs/api-reference/viem/deposits.mdx | 253 ++++++++++++++ docs/api-reference/viem/overview.mdx | 0 docs/api-reference/viem/sdk.mdx | 135 ++++++++ docs/api-reference/viem/withdrawals.mdx | 260 +++++++++++++++ docs/docs.json | 91 +++-- docss/book.toml | 18 - docss/mdbook-admonish.css | 368 --------------------- docss/snippets/ethers/deposit-erc20.ts | 63 ---- docss/snippets/ethers/deposit-eth.ts | 82 ----- docss/snippets/ethers/withdrawals-erc20.ts | 80 ----- docss/snippets/ethers/withdrawals-eth.ts | 74 ----- docss/snippets/viem/deposit-erc20.ts | 95 ------ docss/snippets/viem/deposit-eth.ts | 98 ------ docss/snippets/viem/withdrawals-erc20.ts | 103 ------ docss/snippets/viem/withdrawals-eth.ts | 98 ------ docss/src/SUMMARY.md | 40 --- docss/src/concepts/finalization.md | 44 --- docss/src/concepts/index.md | 13 - docss/src/concepts/status-vs-wait.md | 117 ------- docss/src/guides/deposits/ethers.md | 124 ------- docss/src/guides/deposits/index.md | 1 - docss/src/guides/deposits/viem.md | 121 ------- docss/src/guides/index.md | 22 -- docss/src/guides/withdrawals/ethers.md | 127 ------- docss/src/guides/withdrawals/index.md | 1 - docss/src/guides/withdrawals/viem.md | 138 -------- docss/src/index.md | 6 - docss/src/overview/adapters.md | 88 ----- docss/src/overview/index.md | 20 -- docss/src/overview/mental-model.md | 121 ------- docss/src/overview/what-it-does.md | 47 --- docss/src/quickstart/choose-adapter.md | 68 ---- docss/src/quickstart/ethers.md | 146 -------- docss/src/quickstart/index.md | 22 -- docss/src/quickstart/viem.md | 144 -------- docss/src/reference/helpers.md | 77 ----- docss/src/reference/index.md | 19 -- docss/src/reference/methods.md | 84 ----- src/adapters/ethers/sdk.ts | 76 ++++- typedoc.json | 6 +- 54 files changed, 1707 insertions(+), 2800 deletions(-) delete mode 100644 .github/workflows/ci-docs.yaml create mode 100644 docs/api-reference/core/errors.mdx create mode 100644 docs/api-reference/core/rpc.mdx create mode 100644 docs/api-reference/core/types.mdx delete mode 100644 docs/api-reference/endpoint/create.mdx delete mode 100644 docs/api-reference/endpoint/delete.mdx delete mode 100644 docs/api-reference/endpoint/get.mdx delete mode 100644 docs/api-reference/endpoint/webhook.mdx create mode 100644 docs/api-reference/ethers/client.mdx create mode 100644 docs/api-reference/ethers/deposits.mdx create mode 100644 docs/api-reference/ethers/overview.mdx create mode 100644 docs/api-reference/ethers/sdk.mdx create mode 100644 docs/api-reference/ethers/withdrawals.mdx create mode 100644 docs/api-reference/viem/client.mdx create mode 100644 docs/api-reference/viem/deposits.mdx create mode 100644 docs/api-reference/viem/overview.mdx create mode 100644 docs/api-reference/viem/sdk.mdx create mode 100644 docs/api-reference/viem/withdrawals.mdx delete mode 100644 docss/book.toml delete mode 100644 docss/mdbook-admonish.css delete mode 100644 docss/snippets/ethers/deposit-erc20.ts delete mode 100644 docss/snippets/ethers/deposit-eth.ts delete mode 100644 docss/snippets/ethers/withdrawals-erc20.ts delete mode 100644 docss/snippets/ethers/withdrawals-eth.ts delete mode 100644 docss/snippets/viem/deposit-erc20.ts delete mode 100644 docss/snippets/viem/deposit-eth.ts delete mode 100644 docss/snippets/viem/withdrawals-erc20.ts delete mode 100644 docss/snippets/viem/withdrawals-eth.ts delete mode 100644 docss/src/SUMMARY.md delete mode 100644 docss/src/concepts/finalization.md delete mode 100644 docss/src/concepts/index.md delete mode 100644 docss/src/concepts/status-vs-wait.md delete mode 100644 docss/src/guides/deposits/ethers.md delete mode 100644 docss/src/guides/deposits/index.md delete mode 100644 docss/src/guides/deposits/viem.md delete mode 100644 docss/src/guides/index.md delete mode 100644 docss/src/guides/withdrawals/ethers.md delete mode 100644 docss/src/guides/withdrawals/index.md delete mode 100644 docss/src/guides/withdrawals/viem.md delete mode 100644 docss/src/index.md delete mode 100644 docss/src/overview/adapters.md delete mode 100644 docss/src/overview/index.md delete mode 100644 docss/src/overview/mental-model.md delete mode 100644 docss/src/overview/what-it-does.md delete mode 100644 docss/src/quickstart/choose-adapter.md delete mode 100644 docss/src/quickstart/ethers.md delete mode 100644 docss/src/quickstart/index.md delete mode 100644 docss/src/quickstart/viem.md delete mode 100644 docss/src/reference/helpers.md delete mode 100644 docss/src/reference/index.md delete mode 100644 docss/src/reference/methods.md diff --git a/.github/workflows/ci-docs.yaml b/.github/workflows/ci-docs.yaml deleted file mode 100644 index 52fd46f..0000000 --- a/.github/workflows/ci-docs.yaml +++ /dev/null @@ -1,89 +0,0 @@ -name: ci-run-docs - -on: - push: - branches: [main] - paths: - - 'docs/**' - - '.github/workflows/docs.yml' - workflow_dispatch: - -# Required for Pages & commenting on PRs -permissions: - contents: read - pages: write - id-token: write - pull-requests: write - -concurrency: - group: pages-${{ github.ref }} - cancel-in-progress: true - -jobs: - build-docs: - name: build-docs 📘 - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Rust - uses: dtolnay/rust-toolchain@stable - - - name: Cache cargo (mdBook) - uses: actions/cache@v4 - with: - path: | - ~/.cargo/bin - ~/.cargo/registry - ~/.cargo/git - key: ${{ runner.os }}-cargo-mdbook-${{ hashFiles('docs/**') }} - restore-keys: | - ${{ runner.os }}-cargo-mdbook- - - - name: Install mdBook - run: | - if ! command -v mdbook >/dev/null 2>&1; then - cargo install mdbook --version "^0.4" --locked - cargo install mdbook-admonish - fi - - - name: Build book - run: mdbook build docs - - - name: Upload Pages artifact - uses: actions/upload-pages-artifact@v4 - with: - path: docs/book - - deploy-docs: - name: deploy-docs 📘 - runs-on: ubuntu-latest - needs: build-docs - steps: - - name: Configure Pages - uses: actions/configure-pages@v5 - - - name: Deploy - id: deploy - uses: actions/deploy-pages@v4 - - # Comment the preview URL on PRs - - name: Comment preview link - if: ${{ github.event_name == 'pull_request' }} - uses: actions/github-script@v7 - with: - script: | - const url = `${{ steps.deploy.outputs.page_url }}`; - const body = `📚 **Docs preview** ready: ${url}`; - const {owner, repo} = context.repo; - const issue_number = context.payload.pull_request.number; - - // Upsert a single bot comment - const list = await github.rest.issues.listComments({owner, repo, issue_number}); - const existing = list.data.find(c => c.user?.type === 'Bot' && c.body?.includes('Docs preview')); - if (existing) { - await github.rest.issues.updateComment({owner, repo, comment_id: existing.id, body}); - } else { - await github.rest.issues.createComment({owner, repo, issue_number, body}); - } diff --git a/docs/api-reference/core/errors.mdx b/docs/api-reference/core/errors.mdx new file mode 100644 index 0000000..e69de29 diff --git a/docs/api-reference/core/rpc.mdx b/docs/api-reference/core/rpc.mdx new file mode 100644 index 0000000..e69de29 diff --git a/docs/api-reference/core/types.mdx b/docs/api-reference/core/types.mdx new file mode 100644 index 0000000..e69de29 diff --git a/docs/api-reference/endpoint/create.mdx b/docs/api-reference/endpoint/create.mdx deleted file mode 100644 index 5689f1b..0000000 --- a/docs/api-reference/endpoint/create.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Create Plant' -openapi: 'POST /plants' ---- diff --git a/docs/api-reference/endpoint/delete.mdx b/docs/api-reference/endpoint/delete.mdx deleted file mode 100644 index 657dfc8..0000000 --- a/docs/api-reference/endpoint/delete.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Delete Plant' -openapi: 'DELETE /plants/{id}' ---- diff --git a/docs/api-reference/endpoint/get.mdx b/docs/api-reference/endpoint/get.mdx deleted file mode 100644 index 56aa09e..0000000 --- a/docs/api-reference/endpoint/get.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Get Plants' -openapi: 'GET /plants' ---- diff --git a/docs/api-reference/endpoint/webhook.mdx b/docs/api-reference/endpoint/webhook.mdx deleted file mode 100644 index 3291340..0000000 --- a/docs/api-reference/endpoint/webhook.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'New Plant' -openapi: 'WEBHOOK /plant/webhook' ---- diff --git a/docs/api-reference/ethers/client.mdx b/docs/api-reference/ethers/client.mdx new file mode 100644 index 0000000..a0d3c01 --- /dev/null +++ b/docs/api-reference/ethers/client.mdx @@ -0,0 +1,127 @@ +--- +title: EthersClient +description: Low-level client that carries providers/signer, resolves core contract addresses, and exposes convenience contract instances for the Ethers adapter. +group: API Reference / Ethers +--- + +## Import + +```ts +import { + createEthersClient, +} from '@dutterbutter/zksync-sdk/ethers'; +``` + +## Quick start + +```ts +import { JsonRpcProvider, Wallet } from 'ethers'; +import { createEthersClient } from '@dutterbutter/zksync-sdk/ethers'; + +const l1 = new JsonRpcProvider(process.env.ETH_RPC!); +const l2 = new JsonRpcProvider(process.env.ZKSYNC_RPC!); +const signer = new Wallet(process.env.PRIVATE_KEY!, l1); + +const client = createEthersClient({ l1, l2, signer }); + +// Resolve core addresses once (cached) +const addrs = await client.ensureAddresses(); + +// Grab connected Contract instances +const { bridgehub, l1AssetRouter } = await client.contracts(); +``` + +## `createEthersClient(args) → EthersClient` + + + L1 provider used for address resolution and L1 transactions. + + + L2 provider (target ZK chain). Used for ZK RPC and reads. + + + Signer used for sends. If not already connected to args.l1, it will be connected. + + + Optional manual contract-address overrides (useful for forks or testing). + + + + The signer is force-bound to the L1 provider to ensure finalize transactions work out of the box. + + +## EthersClient interface + + + Discriminator for the adapter. + + + Read/write L1 provider. + + + Read-only L2 provider (target ZK chain). + + + Signer used for sends; connected to l1. + + + ZKsync-specific RPC surface bound to l2. + + +### Methods + +#### `ensureAddresses() → Promise` + +Resolves and caches core contract addresses via on-chain lookups (and optional overrides). + +```ts +const a = await client.ensureAddresses(); +/* +a = { + bridgehub, l1AssetRouter, l1Nullifier, l1NativeTokenVault, + l2AssetRouter, l2NativeTokenVault, l2BaseTokenSystem +} +*/ +``` + +#### `contracts() → Promise<{ ...contracts }>` + +Returns connected `ethers.Contract` instances for all core contracts. + +```ts +const c = await client.contracts(); +const bh = c.bridgehub; +``` + +#### `refresh(): void` + +Clears cached addresses/contracts. Next calls will re-resolve. + +```ts +client.refresh(); +await client.ensureAddresses(); // re-fetches +``` + +#### `baseToken(chainId: bigint) → Promise
` + +Looks up the **L1 address** of the base token for a given L2 chain via `Bridgehub.baseToken(chainId)`. + +```ts +const base = await client.baseToken( BigInt(324) /* ZKsync Era */ ); +``` + +## Types + +### `ResolvedAddresses` + +```ts +type ResolvedAddresses = { + bridgehub: Address; + l1AssetRouter: Address; + l1Nullifier: Address; + l1NativeTokenVault: Address; + l2AssetRouter: Address; + l2NativeTokenVault: Address; + l2BaseTokenSystem: Address; +}; +``` diff --git a/docs/api-reference/ethers/deposits.mdx b/docs/api-reference/ethers/deposits.mdx new file mode 100644 index 0000000..9ee1c78 --- /dev/null +++ b/docs/api-reference/ethers/deposits.mdx @@ -0,0 +1,249 @@ +--- +title: Deposits +description: L1 → L2 deposits for ETH and ERC-20 with quote, prepare, create, status, and wait helpers. +group: API Reference / Ethers +--- + +## Import + +The Deposits resource is available via the Ethers SDK: + +```ts +import { JsonRpcProvider, Wallet, parseEther } from "ethers"; +import { createEthersClient, createEthersSdk } from "@dutterbutter/zksync-sdk/ethers"; + +const l1 = new JsonRpcProvider(process.env.ETH_RPC!); +const l2 = new JsonRpcProvider(process.env.ZKSYNC_RPC!); +const signer = new Wallet(process.env.PRIVATE_KEY!, l1); + +const client = createEthersClient({ l1, l2, signer }); +const sdk = createEthersSdk(client); +// sdk.deposits → DepositsResource +``` + +## Quick start + +Deposit **0.1 ETH** from L1 → L2 and wait for **L2 execution**: + +```ts +const handle = await sdk.deposits.create({ + token: ETH_ADDRESS, + amount: parseEther("0.1"), + to: await signer.getAddress(), +}); + +// Wait for canonical L2 execution; returns L2 receipt or null +const l2Receipt = await sdk.deposits.wait(handle, { for: "l2" }); +``` + +## Routes (auto-selected) + +The SDK automatically selects a route based on the **asset** and the **L2 base token**: + +* `eth-base` — Deposit ETH when L2 base token is **ETH** +* `eth-nonbase` — Deposit ETH when L2 base token is **not ETH** +* `erc20-base` — Deposit ERC-20 that **is** the L2 base token +* `erc20-nonbase` — Deposit ERC-20 that **is not** the L2 base token + +You don’t need to pass a route; it’s derived internally. + +## Methods + +### `quote(p: DepositParams) → Promise` + +Get a **non-executing** summary of the deposit (route, approvals, gas hints). + + + L1 token address (use 0x…00 for ETH). + + + Amount in wei. + + + Recipient on L2. + + +```ts +const q = await sdk.deposits.quote({ + token: ETH_L1, + amount: parseEther("0.25"), + to: await signer.getAddress(), +}); +/* +q = { + route: "eth-base" | "eth-nonbase" | "erc20-base" | "erc20-nonbase", + approvalsNeeded: [{ token, spender, amount }, ...], + baseCost, // bigint (bridge/base cost estimate if applicable) + mintValue, // bigint (if applicable on route) + suggestedL2GasLimit, // bigint + gasPerPubdata // bigint +} +*/ +``` + + + If approvalsNeeded is non-empty for ERC-20 deposits, the SDK will include + approval steps during create. These are approved automatically. + + +### `tryQuote(p) → Promise<{ ok: true; value: DepositQuote } | { ok: false; error }>;` + +Result-style version of `quote`. + +### `prepare(p: DepositParams) → Promise>` + +Build the **plan** (route + ordered steps) without sending transactions. + +```ts +const plan = await sdk.deposits.prepare({ token: ETH_L1, amount: parseEther("0.05"), to }); +/* +plan = { + route, + summary: { ...same shape as DepositQuote }, + steps: [ + // Each step has a unique .key, a .kind (e.g., "approve" | "bridge"), + // and a prebuilt ethers TransactionRequest in .tx + ] +} +*/ +``` + +### `tryPrepare(p) → Promise<{ ok: true; value: DepositPlan } | { ok: false; error }>;` + +Result-style version of `prepare`. + +### `create(p: DepositParams) → Promise>` + +Prepare and **execute** all required steps on **L1**. Returns a handle with the L1 hash. + +```ts +const handle = await sdk.deposits.create({ token, amount, to }); +/* +handle = { + kind: "deposit", + l1TxHash, // Hex + stepHashes: Record, // tx hashes per step + plan // DepositPlan returned by prepare() +} +*/ +``` + + + If any step reverts on L1, create throws a typed error. + Use tryCreate if you prefer a result object. + + +### `tryCreate(p) → Promise<{ ok: true; value: DepositHandle } | { ok: false; error }>;` + +Result-style version of `create`. + +### `status(h | l1TxHash) → Promise` + +Check a deposit’s current phase. Accepts the **handle** from `create` or a raw **L1 tx hash**. + +Phases: + +* `UNKNOWN` — no L1 hash on input +* `L1_PENDING` — L1 receipt not found yet +* `L1_INCLUDED` — included on L1 but L2 hash not yet derivable +* `L2_PENDING` — L2 hash known but L2 receipt missing +* `L2_EXECUTED` — L2 receipt found with `status === 1` +* `L2_FAILED` — L2 receipt found with `status !== 1` + +```ts +const s = await sdk.deposits.status(handle); +/* +s = { phase, l1TxHash, l2TxHash? } +*/ +``` + +### `wait(h | l1TxHash, { for: 'l1' | 'l2' }) → Promise` + +Block until a checkpoint: + +* `{ for: 'l1' }` → resolves the **L1 receipt** (or `null` if no L1 hash on input) +* `{ for: 'l2' }` → resolves the **L2 receipt** after canonical execution (or `null` if no L1 hash) + +```ts +const l1Receipt = await sdk.deposits.wait(handle, { for: "l1" }); +const l2Receipt = await sdk.deposits.wait(handle, { for: "l2" }); +``` + +### `tryWait(h, { for }) → Promise<{ ok: true; value: TransactionReceipt } | { ok: false; error }>;` + +Result-style version of `wait`. + +## End-to-end examples + +### ETH deposit (most common) + +```ts +const handle = await sdk.deposits.create({ + token: ETH_ADDRESS, + amount: parseEther("0.1"), + to: await signer.getAddress(), +}); + +await sdk.deposits.wait(handle, { for: "l2" }); // get L2 receipt when executed +``` + +### ERC-20 deposit with approvals + +```ts +const handle = await sdk.deposits.create({ + token: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // example ERC-20 + amount: 1000000n, // 1e6 (USDC 6 decimals) + to: await signer.getAddress(), +}); + +// Wait for L1 inclusion only, if you need to chain logic at that point +const l1Receipt = await sdk.deposits.wait(handle, { for: "l1" }); +``` + +## Types (shape overview) + +These types live in `core/types` and are summarized here for convenience. + +```ts +type DepositParams = { + token: Address; // L1 token (0x…00 for ETH) + amount: bigint; // in wei + to: Address; // L2 recipient + // ...additional fields may exist; see core/types for the full spec +}; + +type DepositQuote = { + route: "eth-base" | "eth-nonbase" | "erc20-base" | "erc20-nonbase"; + approvalsNeeded: Array<{ token: Address; spender: Address; amount: bigint }>; + baseCost?: bigint; + mintValue?: bigint; + suggestedL2GasLimit?: bigint; + gasPerPubdata?: bigint; +}; + +type DepositPlan = { + route: DepositQuote["route"]; + summary: DepositQuote; + steps: Array<{ key: string; kind: string; tx: TTx }>; +}; + +type DepositHandle = { + kind: "deposit"; + l1TxHash: Hex; + stepHashes: Record; + plan: DepositPlan; +}; + +type DepositStatus = + | { phase: "UNKNOWN"; l1TxHash: Hex } + | { phase: "L1_PENDING"; l1TxHash: Hex } + | { phase: "L1_INCLUDED"; l1TxHash: Hex } + | { phase: "L2_PENDING"; l1TxHash: Hex; l2TxHash: Hex } + | { phase: "L2_EXECUTED"; l1TxHash: Hex; l2TxHash: Hex } + | { phase: "L2_FAILED"; l1TxHash: Hex; l2TxHash: Hex }; +``` + + + Prefer the try* variants if you want to avoid exceptions and work with result objects. + + diff --git a/docs/api-reference/ethers/overview.mdx b/docs/api-reference/ethers/overview.mdx new file mode 100644 index 0000000..e69de29 diff --git a/docs/api-reference/ethers/sdk.mdx b/docs/api-reference/ethers/sdk.mdx new file mode 100644 index 0000000..49426a2 --- /dev/null +++ b/docs/api-reference/ethers/sdk.mdx @@ -0,0 +1,125 @@ +--- +title: EthersSdk +description: High-level SDK for deposits, withdrawals, and helpers using the Ethers adapter. +group: API Reference / Ethers +--- + +## Import + +```ts +import { + createEthersClient, + createEthersSdk, +} from '@dutterbutter/zksync-sdk/ethers'; +``` + +## Quick start + +```ts +import { JsonRpcProvider, Wallet } from 'ethers'; +import { createEthersClient, createEthersSdk } from '@dutterbutter/zksync-sdk/ethers'; + +const l1 = new JsonRpcProvider(process.env.ETH_RPC!); +const l2 = new JsonRpcProvider(process.env.ZKSYNC_RPC!); +const signer = new Wallet(process.env.PRIVATE_KEY!, l1); + +const client = createEthersClient({ l1, l2, signer }); +const sdk = createEthersSdk(client); + +// Example: get contracts and the L2 address for an L1 token +const { l1NativeTokenVault } = await sdk.helpers.contracts(); +const l1_crown_address = await sdk.helpers.l1TokenAddress(CROWN_ERC20_ADDRESS); +``` + +## `createEthersSdk(client) → EthersSdk` + + + Instance created by createEthersClient. + + + + The SDK composes the client with high-level resources: deposits, withdrawals, and convenience helpers. + + +## EthersSdk interface + + + L1 → L2 flows (quote, prepare, create, status, wait). See Deposits. + + + + L2 → L1 flows (quote, prepare, create, status, wait, finalize). See Withdrawals. + + +### `helpers` + +Utilities for addresses, contracts, and token mapping. + +#### `addresses() → Promise` + +Resolves core addresses (Bridgehub, routers, vaults, base token system). + +```ts +const a = await sdk.helpers.addresses(); +``` + +#### `contracts() → Promise<{ ...contracts }>` + +Connected `ethers.Contract` instances for all core contracts. + +```ts +const c = await sdk.helpers.contracts(); +``` + +#### `l1AssetRouter() / l1NativeTokenVault() / l1Nullifier() → Promise` + +One-off getters if you only need a specific contract. + +```ts +const nullifier = await sdk.helpers.l1Nullifier(); +``` + +#### `baseToken(chainId?: bigint) → Promise
` + +L1 address of the base token for a given **L2 chain**. If omitted, uses the current L2 provider’s chain id. + +```ts +const base = await sdk.helpers.baseToken(); // infer from client.l2 +``` + +#### `l2TokenAddress(l1Token: Address) → Promise
` + +Returns the **L2 token address** for a given **L1 token**. + +* Handles ETH special-case (L2 ETH placeholder). +* If the token equals the chain’s base token, returns the L2 base-token system address. +* Otherwise queries `IL2NativeTokenVault.l2TokenAddress`. + +```ts +const l2_crown_address = await sdk.helpers.l2TokenAddress(CROWN_ERC20_ADDRESS); +``` + +#### `l1TokenAddress(l2Token: Address) → Promise
` + +Returns the **L1 token address** from an **L2 token** using `IL2AssetRouter.l1TokenAddress`. + +* ETH placeholder on L2 resolves to the canonical ETH address. + +```ts +const l1_crown_address = await sdk.helpers.l1TokenAddress(CROWN_ERC20_ADDRESS); +``` + +#### `assetId(l1Token: Address) → Promise` + +Computes the `bytes32` asset identifier for an L1 token via `L1NativeTokenVault.assetId`. + +* Treats canonical ETH appropriately. + +```ts +const id = await sdk.helpers.assetId(CROWN_ERC20_ADDRESS); +``` + +## Notes + +* The SDK defers to on-chain sources where possible; results may depend on the connected chain(s). +* Errors surface as typed envelopes (see **Error Model** in API Reference intro). Use the try* variants on resources if you prefer result objects over exceptions. diff --git a/docs/api-reference/ethers/withdrawals.mdx b/docs/api-reference/ethers/withdrawals.mdx new file mode 100644 index 0000000..4493a6d --- /dev/null +++ b/docs/api-reference/ethers/withdrawals.mdx @@ -0,0 +1,255 @@ +--- +title: Withdrawals +description: L2 → L1 withdrawals for ETH and ERC-20 with quote, prepare, create, status, wait, and finalize helpers. +group: API Reference / Ethers +--- + +## Import + +```ts +import { JsonRpcProvider, Wallet, parseEther } from "ethers"; +import { createEthersClient, createEthersSdk } from "@dutterbutter/zksync-sdk/ethers"; + +const l1 = new JsonRpcProvider(process.env.ETH_RPC!); +const l2 = new JsonRpcProvider(process.env.ZKSYNC_RPC!); +const signer = new Wallet(process.env.PRIVATE_KEY!, l1); + +const client = createEthersClient({ l1, l2, signer }); +const sdk = createEthersSdk(client); +// sdk.withdrawals → WithdrawalsResource +``` + +## Quick start + +Withdraw **0.1 ETH** from L2 → L1, then finalize: + +```ts +const handle = await sdk.withdrawals.create({ + token: ETH_ADDRESS, + amount: parseEther("0.1"), + to: await signer.getAddress(), // L1 recipient +}); + +// 1) Wait until included on L2 (adds l2ToL1Logs if available) +const l2Receipt = await sdk.withdrawals.wait(handle, { for: "l2" }); + +// 2) Wait until finalizable (no side effects) +await sdk.withdrawals.wait(handle, { for: "ready", pollMs: 6000 }); + +// 3) Send the L1 finalize tx (if not already finalized) +const { status, receipt: l1Receipt } = await sdk.withdrawals.finalize(handle.l2TxHash); +``` + + + Withdrawals are a two-step process: include on L2, then finalize on L1. You can wait for ready before calling finalize, or call finalize directly— it will throw if not yet ready. + + +## Routes (auto-selected) + +Based on the asset and the L2 base token: + +* `eth-base` — Base token is **ETH** on L2 +* `eth-nonbase` — Base token is **not ETH** on L2 +* `erc20-nonbase` — Withdrawing an ERC-20 that is **not** the base token + +No route argument is needed; it’s derived internally. + +## Methods + +### `quote(p: WithdrawParams) → Promise` + +Dry-run summary of a withdrawal (route, approvals, gas hints). + + + L2 token address equivalent (ETH handled by the SDK). + + + Amount in wei. + + + Recipient on L1. + + +```ts +const q = await sdk.withdrawals.quote({ token, amount, to }); +/* +q = { + route: "eth-base" | "eth-nonbase" | "erc20-nonbase", + approvalsNeeded: [{ token, spender, amount }, ...], + suggestedL2GasLimit: bigint +} +*/ +``` + +### `tryQuote(p) → Promise<{ ok: true; value: WithdrawQuote } | { ok: false; error }>` + +Result-style version of `quote`. + +### `prepare(p: WithdrawParams) → Promise>` + +Build the plan (route + ordered L2 steps), no sends. + +```ts +const plan = await sdk.withdrawals.prepare({ token, amount, to }); +/* +plan = { + route, + summary: WithdrawQuote, + steps: [{ key, kind, tx: TransactionRequest }, ...] +} +*/ +``` + +### `tryPrepare(p) → Promise<{ ok: true; value: WithdrawPlan } | { ok: false; error }>` + +Result-style version of `prepare`. + +### `create(p: WithdrawParams) → Promise>` + +Prepare + **send** L2 steps. Returns a handle with the **L2 tx hash**. + +```ts +const handle = await sdk.withdrawals.create({ token, amount, to }); +/* +handle = { + kind: "withdrawal", + l2TxHash: Hex, + stepHashes: Record, + plan +} +*/ +``` + + + If any step reverts on L2, create throws a typed error. Prefer tryCreate if you want a result object. + + +### `tryCreate(p) → Promise<{ ok: true; value: WithdrawHandle } | { ok: false; error }>` + +Result-style version of `create`. + +### `status(h | l2TxHash) → Promise` + +Report current phase. Accepts the **handle** from `create` or a raw **L2 tx hash**. + +Phases: + +* `UNKNOWN` — no L2 hash on input +* `L2_PENDING` — L2 receipt missing +* `PENDING` — included on L2 but not yet finalizable +* `READY_TO_FINALIZE` — can be finalized on L1 now +* `FINALIZED` — already finalized on L1 + +```ts +const s = await sdk.withdrawals.status(handle); +/* +s = { phase, l2TxHash, key? } // key identifies the canonical message for finalization +*/ +``` + +### `wait(h | l2TxHash, { for: 'l2' | 'ready' | 'finalized', pollMs?, timeoutMs? })` + +Block until a target is reached. + +* `{ for: 'l2' }` → resolves **L2 receipt** (`TransactionReceiptZKsyncOS`) or `null` + (SDK augments with `l2ToL1Logs` if available). +* `{ for: 'ready' }` → resolves `null` when finalization becomes possible. +* `{ for: 'finalized' }` → resolves **L1 receipt** when found, otherwise `null` (even if finalized). + +```ts +// 1) L2 inclusion +const l2Rcpt = await sdk.withdrawals.wait(handle, { for: "l2" }); + +// 2) Finalization readiness (no side effects) +await sdk.withdrawals.wait(handle, { for: "ready", pollMs: 6000, timeoutMs: 15 * 60_000 }); + +// 3) Wait for finalized (returns L1 receipt or null) +const l1Rcpt = await sdk.withdrawals.wait(handle, { for: "finalized", pollMs: 7000 }); +``` + + + Default polling is 5500ms (minimum 1000ms). Use timeoutMs for long windows. + + +### `finalize(l2TxHash: Hex) → Promise<{ status: WithdrawalStatus; receipt?: TransactionReceipt }>` + +Sends the **L1 finalize** transaction **if** ready. If already finalized, returns the status without sending. + +```ts +const { status, receipt } = await sdk.withdrawals.finalize(handle.l2TxHash); +if (status.phase === "FINALIZED") { + console.log("L1 tx:", receipt?.transactionHash); +} +``` + + + Behavior: If the withdrawal is not ready, finalize throws a typed STATE error. + Use status(...) or `wait(..., { for: 'ready' })` to check first. + + +### `tryFinalize(l2TxHash) → Promise<{ ok: true; value: { status; receipt? } } | { ok: false; error }>` + +Result-style version of `finalize`. + +## End-to-end examples + +### Minimal happy path + +```ts +const handle = await sdk.withdrawals.create({ token, amount, to }); + +// Wait L2 inclusion +await sdk.withdrawals.wait(handle, { for: "l2" }); + +// Either finalize immediately… +const { status, receipt } = await sdk.withdrawals.finalize(handle.l2TxHash); + +// …or wait for readiness first, then finalize +await sdk.withdrawals.wait(handle, { for: "ready" }); +const done = await sdk.withdrawals.finalize(handle.l2TxHash); +``` + +## Types (shape overview) + +These types live in `core/types` and are summarized here for convenience. + +```ts +type WithdrawParams = { + token: Address; // L2 token (ETH handled internally) + amount: bigint; // in wei + to: Address; // L1 recipient +}; + +type WithdrawQuote = { + route: "eth-base" | "eth-nonbase" | "erc20-nonbase"; + approvalsNeeded: Array<{ token: Address; spender: Address; amount: bigint }>; + suggestedL2GasLimit?: bigint; +}; + +type WithdrawPlan = { + route: WithdrawQuote["route"]; + summary: WithdrawQuote; + steps: Array<{ key: string; kind: string; tx: TTx }>; +}; + +type WithdrawHandle = { + kind: "withdrawal"; + l2TxHash: Hex; + stepHashes: Record; + plan: WithdrawPlan; +}; + +type WithdrawalStatus = + | { phase: "UNKNOWN"; l2TxHash: Hex } + | { phase: "L2_PENDING"; l2TxHash: Hex } + | { phase: "PENDING"; l2TxHash: Hex; key?: unknown } + | { phase: "READY_TO_FINALIZE"; l2TxHash: Hex; key: unknown } + | { phase: "FINALIZED"; l2TxHash: Hex; key: unknown }; + +// The L2 receipt returned by wait({ for: 'l2' }) is augmented: +type TransactionReceiptZKsyncOS = TransactionReceipt & { l2ToL1Logs?: Array }; +``` + + + Prefer the try* variants if you want result objects instead of exceptions. + diff --git a/docs/api-reference/viem/client.mdx b/docs/api-reference/viem/client.mdx new file mode 100644 index 0000000..d70f8ae --- /dev/null +++ b/docs/api-reference/viem/client.mdx @@ -0,0 +1,156 @@ +--- +title: ViemClient +description: Low-level client that carries viem public/wallet clients, resolves core contract addresses, and exposes convenience contract instances for the Viem adapter. +group: API Reference / Viem +--- + +## Import + +```ts +import { + createViemClient, +} from '@dutterbutter/zksync-sdk/viem'; +``` + +## Quick start + +```ts +import { createPublicClient, createWalletClient, http } from 'viem'; +// import { mainnet } from 'viem/chains' // or your own chain objects + +// Minimal example — provide your chain objects & RPCs. +const l1 = createPublicClient({ /* chain: mainnet, */ transport: http(process.env.ETH_RPC!) }); +const l2 = createPublicClient({ /* chain: zkSync, */ transport: http(process.env.ZKSYNC_RPC!) }); + +// l1 wallet must have an account +const l1Wallet = createWalletClient({ + account: /* your Account */, + /* chain: mainnet, */ transport: http(process.env.ETH_RPC!), +}); + +// (optional) a dedicated L2 wallet; if omitted, ViemClient can derive one via getL2Wallet() +const l2Wallet = createWalletClient({ + account: l1Wallet.account, + /* chain: zkSync, */ transport: http(process.env.ZKSYNC_RPC!), +}); + +const client = createViemClient({ l1, l2, l1Wallet, l2Wallet }); + +// Resolve core addresses once (cached) +const addrs = await client.ensureAddresses(); + +// Grab connected Contract instances (typed viem contracts) +const { bridgehub, l1AssetRouter } = await client.contracts(); +``` + + + l1Wallet.account is required. If you omit l2Wallet, the client will lazily create one that reuses the L1 account over the L2 transport via getL2Wallet(). + + +## `createViemClient(args) → ViemClient` + + + L1 client used for address resolution and L1 reads. + + + L2 client (target ZK chain). Used for ZK RPC and reads. + + + Wallet used for sends; must include an account. + + + Optional dedicated L2 wallet. If omitted, call getL2Wallet() to obtain a lazily created one. + + + Optional manual contract-address overrides (useful for forks or testing). + + +## ViemClient interface + + + Discriminator for the adapter. + + + Read/write L1 client. + + + Read-only L2 client (target ZK chain). + + + Wallet bound to L1 RPC; carries the default account for sends. + + + Optional pre-supplied L2 wallet. If not provided, use getL2Wallet(). + + + The default account (from l1Wallet). + + + ZKsync-specific RPC surface bound to l2. + + +### Methods + +#### `ensureAddresses() → Promise` + +Resolves and caches core contract addresses via on-chain lookups (and optional overrides). + +```ts +const a = await client.ensureAddresses(); +/* +a = { + bridgehub, l1AssetRouter, l1Nullifier, l1NativeTokenVault, + l2AssetRouter, l2NativeTokenVault, l2BaseTokenSystem +} +*/ +``` + +#### `contracts() → Promise<{ ...contracts }>` + +Returns connected **typed viem contracts** (`getContract(...)`) for all core contracts. + +```ts +const c = await client.contracts(); +const bh = c.bridgehub; +``` + +#### `refresh(): void` + +Clears cached addresses/contracts. Next calls will re-resolve. + +```ts +client.refresh(); +await client.ensureAddresses(); // re-fetches +``` + +#### `baseToken(chainId: bigint) → Promise
` + +Looks up the **L1 address** of the base token for a given L2 chain via `Bridgehub.baseToken(chainId)`. + +```ts +const base = await client.baseToken( BigInt(324) /* e.g., zk chain id */ ); +``` + +#### `getL2Wallet() → WalletClient` + +Returns the L2 wallet. If one wasn’t passed at construction, it lazily creates a wallet using the **same account** as `l1Wallet` with the L2 transport. + +```ts +const l2W = client.getL2Wallet(); +``` + +## Types + +### `ResolvedAddresses` + +```ts +type ResolvedAddresses = { + bridgehub: Address; + l1AssetRouter: Address; + l1Nullifier: Address; + l1NativeTokenVault: Address; + l2AssetRouter: Address; + l2NativeTokenVault: Address; + l2BaseTokenSystem: Address; +}; +``` diff --git a/docs/api-reference/viem/deposits.mdx b/docs/api-reference/viem/deposits.mdx new file mode 100644 index 0000000..b5733d7 --- /dev/null +++ b/docs/api-reference/viem/deposits.mdx @@ -0,0 +1,253 @@ +--- +title: Deposits +description: L1 → L2 deposits for ETH and ERC-20 with quote, prepare, create, status, and wait helpers (Viem adapter). +group: API Reference / Viem +--- + +## Import + +The Deposits resource is available via the **Viem** SDK: + +```ts +import { parseEther } from "viem"; +import { + createViemClient, + createViemSdk, +} from "@dutterbutter/zksync-sdk/viem"; + +// Constants (ETH_ADDRESS, etc.) are re-exported by the SDK: +import { ETH_ADDRESS } from "@dutterbutter/zksync-sdk/constants"; +```` + +## Quick start + +Deposit **0.1 ETH** from L1 → L2 and wait for **L2 execution**: + +```ts +const sdk = createViemSdk( + createViemClient({ l1, l2, l1Wallet, l2Wallet }) +); + +const handle = await sdk.deposits.create({ + token: ETH_ADDRESS, + amount: parseEther("0.1"), + to: /* L2 recipient address */, +}); + +// Wait for canonical L2 execution; returns a viem TransactionReceipt or null +const l2Receipt = await sdk.deposits.wait(handle, { for: "l2" }); +``` + +## Routes (auto-selected) + +The SDK automatically selects a route based on the **asset** and the **L2 base token**: + +* `eth-base` — Deposit ETH when L2 base token is **ETH** +* `eth-nonbase` — Deposit ETH when L2 base token is **not ETH** +* `erc20-base` — Deposit ERC-20 that **is** the L2 base token +* `erc20-nonbase` — Deposit ERC-20 that **is not** the L2 base token + +You don’t need to pass a route; it’s derived internally. + +## Methods + +### `quote(p: DepositParams) → Promise` + +Get a **non-executing** summary of the deposit (route, approvals, gas hints). + + + L1 token address (use 0x…00 or ETH_ADDRESS for ETH). + + + Amount in wei (e.g., parseEther("0.25")). + + + Recipient on L2. + + +```ts +const q = await sdk.deposits.quote({ + token: ETH_ADDRESS, + amount: parseEther("0.25"), + to: /* L2 recipient */, +}); +/* +q = { + route: "eth-base" | "eth-nonbase" | "erc20-base" | "erc20-nonbase", + approvalsNeeded: [{ token, spender, amount }, ...], + baseCost?: bigint, + mintValue?: bigint, + suggestedL2GasLimit?: bigint, + gasPerPubdata?: bigint +} +*/ +``` + + + If approvalsNeeded is non-empty for ERC-20 deposits, the SDK will include approval steps during create. + + +### `tryQuote(p) → Promise<{ ok: true; value } | { ok: false; error }>` + +Result-style version of `quote`. + +### `prepare(p: DepositParams) → Promise>` + +Build the **plan** (route + ordered steps) without sending transactions. + +```ts +const plan = await sdk.deposits.prepare({ + token: ETH_ADDRESS, + amount: parseEther("0.05"), + to: /* L2 recipient */, +}); +/* +plan = { + route, + summary: { ...DepositQuote }, + steps: [ + // Each step has a unique .key, a .kind + // and a Viem "writeContract" request in .tx (ViemPlanWriteRequest) + ] +} +*/ +``` + +### `tryPrepare(p) → Promise<{ ok: true; value } | { ok: false; error }>` + +Result-style version of `prepare`. + +### `create(p: DepositParams) → Promise>` + +Prepare and **execute** all required steps on **L1** (via Viem `writeContract`). Returns a handle with the L1 hash. + +```ts +const handle = await sdk.deposits.create({ token, amount, to }); +/* +handle = { + kind: "deposit", + l1TxHash, // Hex + stepHashes: Record, // tx hashes per step + plan // DepositPlan returned by prepare() +} +*/ +``` + + + If any step reverts on L1, create throws a typed error. + Use tryCreate if you prefer a result object. + + +### `tryCreate(p) → Promise<{ ok: true; value } | { ok: false; error }>` + +Result-style version of `create`. + +### `status(h | l1TxHash) → Promise` + +Check a deposit’s current phase. Accepts the **handle** from `create` or a raw **L1 tx hash**. + +Phases: + +* `UNKNOWN` — no L1 hash on input +* `L1_PENDING` — L1 receipt not found yet +* `L1_INCLUDED` — included on L1 but L2 hash not yet derivable +* `L2_PENDING` — L2 hash known but L2 receipt missing +* `L2_EXECUTED` — L2 receipt found with `status === 'success'` +* `L2_FAILED` — L2 receipt found with `status !== 'success'` + +```ts +const s = await sdk.deposits.status(handle); +/* +s = { phase, l1TxHash, l2TxHash? } +*/ +``` + +### `wait(h | l1TxHash, { for: 'l1' | 'l2' }) → Promise` + +Block until a checkpoint: + +* `{ for: 'l1' }` → resolves the **L1 receipt** (or `null` if no L1 hash on input) +* `{ for: 'l2' }` → resolves the **L2 receipt** after canonical execution (or `null` if no L1 hash) + +```ts +const l1Receipt = await sdk.deposits.wait(handle, { for: "l1" }); +const l2Receipt = await sdk.deposits.wait(handle, { for: "l2" }); +``` + +### `tryWait(h, { for }) → Promise<{ ok: true; value } | { ok: false; error }>` + +Result-style version of `wait`. + +## End-to-end examples + +### ETH deposit (most common) + +```ts +const handle = await sdk.deposits.create({ + token: ETH_ADDRESS, + amount: parseEther("0.1"), + to: /* L2 recipient */, +}); + +await sdk.deposits.wait(handle, { for: "l2" }); // get L2 receipt when executed +``` + +### ERC-20 deposit with approvals + +```ts +const handle = await sdk.deposits.create({ + token: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // erc20 token example + amount: 1_000_000n, // USDC 6 decimals + to: /* L2 recipient */, +}); + +// Wait for L1 inclusion only, if you need to chain logic at that point +const l1Receipt = await sdk.deposits.wait(handle, { for: "l1" }); +``` + +## Types (shape overview) + +These types live in `core/types` and are summarized here for convenience. + +```ts +type DepositParams = { + token: Address; // L1 token (0x…00 for ETH) + amount: bigint; // in wei + to: Address; // L2 recipient + // ...see core/types for full spec +}; + +type DepositQuote = { + route: "eth-base" | "eth-nonbase" | "erc20-base" | "erc20-nonbase"; + approvalsNeeded: Array<{ token: Address; spender: Address; amount: bigint }>; + baseCost?: bigint; + mintValue?: bigint; + suggestedL2GasLimit?: bigint; + gasPerPubdata?: bigint; +}; + +type DepositPlan = { + route: DepositQuote["route"]; + summary: DepositQuote; + steps: Array<{ key: string; kind: string; tx: TTx }>; +}; + +type DepositHandle = { + kind: "deposit"; + l1TxHash: Hex; + stepHashes: Record; + plan: DepositPlan; +}; + +type DepositStatus = + | { phase: "UNKNOWN"; l1TxHash: Hex } + | { phase: "L1_PENDING"; l1TxHash: Hex } + | { phase: "L1_INCLUDED"; l1TxHash: Hex } + | { phase: "L2_PENDING"; l1TxHash: Hex; l2TxHash: Hex } + | { phase: "L2_EXECUTED"; l1TxHash: Hex; l2TxHash: Hex } + | { phase: "L2_FAILED"; l1TxHash: Hex; l2TxHash: Hex }; +``` + + + Prefer the try* variants if you want to avoid exceptions and work with result objects. + diff --git a/docs/api-reference/viem/overview.mdx b/docs/api-reference/viem/overview.mdx new file mode 100644 index 0000000..e69de29 diff --git a/docs/api-reference/viem/sdk.mdx b/docs/api-reference/viem/sdk.mdx new file mode 100644 index 0000000..6065a36 --- /dev/null +++ b/docs/api-reference/viem/sdk.mdx @@ -0,0 +1,135 @@ +--- +title: ViemSdk +description: High-level SDK for deposits, withdrawals, and helpers using the Viem adapter. +group: API Reference / Viem +--- + +## Import + +```ts +import { + createViemClient, + createViemSdk, +} from '@dutterbutter/zksync-sdk/viem'; +``` + +## Quick start + +```ts +import { createPublicClient, createWalletClient, http } from 'viem'; +import { createViemClient, createViemSdk } from '@dutterbutter/zksync-sdk/viem'; + +// Provide your chain objects & RPC URLs as needed +const l1 = createPublicClient({ transport: http(process.env.ETH_RPC!) }); +const l2 = createPublicClient({ transport: http(process.env.ZKSYNC_RPC!) }); + +const l1Wallet = createWalletClient({ + account: /* your Account */, + transport: http(process.env.ETH_RPC!), +}); + +// (optional) pass an L2 wallet; needed during withdrawals to finalize +const l2Wallet = createWalletClient({ + account: l1Wallet.account, + transport: http(process.env.ZKSYNC_RPC!), +}); + +const client = createViemClient({ l1, l2, l1Wallet, l2Wallet }); +const sdk = createViemSdk(client); + +// Example: get contracts and the L2 address for an L1 token +const { l1NativeTokenVault } = await sdk.helpers.contracts(); +const l2_crown_address = await sdk.helpers.l2TokenAddress(CROWN_ERC20_ADDRESS); +``` + + + The SDK composes the Viem client with high-level resources: deposits, withdrawals, and convenience helpers. + + +## `createViemSdk(client) → ViemSdk` + + + Instance created by createViemClient. + + +## ViemSdk interface + + + L1 → L2 flows (quote, prepare, create, status, wait). See Deposits. + + + + L2 → L1 flows (quote, prepare, create, status, wait, finalize). See Withdrawals. + + +### `helpers` + +Utilities for addresses, contracts, and token mapping. + +#### `addresses() → Promise` + +Resolves core addresses (Bridgehub, routers, vaults, base token system). + +```ts +const a = await sdk.helpers.addresses(); +``` + +#### `contracts() → Promise<{ ...contracts }>` + +Returns **typed viem contracts** for all core contracts (each exposes `.read` / `.write` / `.simulate`). + +```ts +const c = await sdk.helpers.contracts(); +const bridgehub = c.bridgehub; +``` + +#### `l1AssetRouter() / l1NativeTokenVault() / l1Nullifier()` + +One-off getters if you only need a specific contract. + +```ts +const nullifier = await sdk.helpers.l1Nullifier(); +``` + +#### `baseToken(chainId?: bigint) → Promise
` + +L1 address of the base token for a given **L2 chain**. If omitted, uses the current L2 client’s chain id. + +```ts +const base = await sdk.helpers.baseToken(); // infers from client.l2.getChainId() +``` + +#### `l2TokenAddress(l1Token: Address) → Promise
` + +Returns the **L2 token address** for a given **L1 token**. + +* Handles ETH special-case (L2 ETH placeholder). +* If the token equals the chain’s base token, returns the L2 base-token system address. +* Otherwise queries `IL2NativeTokenVault.l2TokenAddress`. + +```ts +const l2_crown_address = await sdk.helpers.l2TokenAddress(CROWN_ERC20_ADDRESS); +``` + +#### `l1TokenAddress(l2Token: Address) → Promise
` + +Returns the **L1 token address** from an **L2 token** using `IL2AssetRouter.l1TokenAddress`. + +* ETH is treated as a special case. + +```ts +const l1_crown_address = await sdk.helpers.l1TokenAddress(CROWN_ERC20_ADDRESS); +``` + +#### `assetId(l1Token: Address) → Promise` + +Computes the `bytes32` asset identifier for an L1 token via `L1NativeTokenVault.assetId`. + +```ts +const id = await sdk.helpers.assetId(CROWN_ERC20_ADDRESS); +``` + +## Notes + +* All results depend on the connected chains (L1/L2 RPCs) and any overrides supplied to the client. +* Errors surface as typed envelopes (see **Error Model** in API Reference intro). Prefer the try* variants on resources if you want result objects instead of exceptions. diff --git a/docs/api-reference/viem/withdrawals.mdx b/docs/api-reference/viem/withdrawals.mdx new file mode 100644 index 0000000..7fd4d56 --- /dev/null +++ b/docs/api-reference/viem/withdrawals.mdx @@ -0,0 +1,260 @@ +--- +title: Withdrawals +description: L2 → L1 withdrawals for ETH and ERC-20 with quote, prepare, create, status, wait, and finalize helpers (Viem adapter). +group: API Reference / Viem +--- + +## Import + +```ts +import { parseEther } from "viem"; +import { + createViemClient, + createViemSdk, +} from "@dutterbutter/zksync-sdk/viem"; + +// Useful constants +import { ETH_ADDRESS } from "@dutterbutter/zksync-sdk/constants"; +```` + +## Quick start + +Withdraw **0.1 ETH** from L2 → L1, then finalize: + +```ts +const client = createViemClient({ l1, l2, l1Wallet, l2Wallet }); +const sdk = createViemSdk(client); + +const handle = await sdk.withdrawals.create({ + token: ETH_ADDRESS, + amount: parseEther("0.1"), + to: /* L1 recipient address */, +}); + +// 1) Wait until included on L2 (returns TransactionReceipt with l2ToL1Logs if available) +const l2Receipt = await sdk.withdrawals.wait(handle, { for: "l2" }); + +// 2) Wait until finalizable (no side effects) +await sdk.withdrawals.wait(handle, { for: "ready", pollMs: 6000 }); + +// 3) Send the L1 finalize tx (if not already finalized) +const { status, receipt: l1Receipt } = await sdk.withdrawals.finalize(handle.l2TxHash); +``` + + + Withdrawals are a two-step process: include on **L2**, then finalize on **L1**. You can either + wait for ready before calling finalize, or call finalize directly— it will throw if not yet ready. + + +--- + +## Routes (auto-selected) + +Based on the asset and the L2 base token: + +* `eth-base` — Base token is **ETH** on L2 +* `eth-nonbase` — Base token is **not ETH** on L2 +* `erc20-nonbase` — Withdrawing an ERC-20 that is **not** the base token + +No route argument is needed; it’s derived internally. + +## Methods + +### `quote(p: WithdrawParams) → Promise` + +Dry-run summary of a withdrawal (route, approvals, gas hints). + + + L2 token address (ETH handled by the SDK). + + + Amount in wei (e.g., parseEther("0.1")). + + + Recipient on L1. + + +```ts +const q = await sdk.withdrawals.quote({ token, amount, to }); +/* +q = { + route: "eth-base" | "eth-nonbase" | "erc20-nonbase", + approvalsNeeded: [{ token, spender, amount }, ...], + suggestedL2GasLimit?: bigint +} +*/ +``` + +### `tryQuote(p) → Promise<{ ok: true; value: WithdrawQuote } | { ok: false; error }>` + +Result-style version of `quote`. + +### `prepare(p: WithdrawParams) → Promise>` + +Build the plan (route + ordered **L2** steps), no sends. + +```ts +const plan = await sdk.withdrawals.prepare({ token, amount, to }); +/* +plan = { + route, + summary: WithdrawQuote, + steps: [{ key, kind, tx: ViemPlanWriteRequest }, ...] +} +*/ +``` + +### `tryPrepare(p) → Promise<{ ok: true; value } | { ok: false; error }>` + +Result-style version of `prepare`. + +### `create(p: WithdrawParams) → Promise>` + +Prepare + **send** L2 steps via Viem `writeContract`. Returns a handle with the **L2 tx hash**. + +```ts +const handle = await sdk.withdrawals.create({ token, amount, to }); +/* +handle = { + kind: "withdrawal", + l2TxHash: Hex, + stepHashes: Record, + plan +} +*/ +``` + + + If any step reverts on L2, create throws a typed error. + Prefer tryCreate if you want a result object. + + +### `tryCreate(p) → Promise<{ ok: true; value: WithdrawHandle } | { ok: false; error }>` + +Result-style version of `create`. + +### `status(h | l2TxHash) → Promise` + +Report current phase. Accepts the **handle** from `create` or a raw **L2 tx hash**. + +Phases: + +* `UNKNOWN` — no L2 hash on input +* `L2_PENDING` — L2 receipt missing +* `PENDING` — included on L2 but not yet finalizable +* `READY_TO_FINALIZE` — can be finalized on L1 now +* `FINALIZED` — already finalized on L1 + +```ts +const s = await sdk.withdrawals.status(handle); +/* +s = { phase, l2TxHash, key? } // key identifies the canonical message for finalization +*/ +``` + +### `wait(h | l2TxHash, { for: 'l2' | 'ready' | 'finalized', pollMs?, timeoutMs? })` + +Block until a target is reached. + +* `{ for: 'l2' }` → resolves **L2 receipt** (`TransactionReceiptZKsyncOS`) or `null` + (SDK augments with `l2ToL1Logs` if available). +* `{ for: 'ready' }` → resolves `null` when finalization becomes possible. +* `{ for: 'finalized' }` → resolves **L1 receipt** when found, otherwise `null` (even if finalized). + +```ts +// 1) L2 inclusion +const l2Rcpt = await sdk.withdrawals.wait(handle, { for: "l2" }); + +// 2) Finalization readiness (no side effects) +await sdk.withdrawals.wait(handle, { for: "ready", pollMs: 6000, timeoutMs: 15 * 60_000 }); + +// 3) Wait for finalized (returns L1 receipt or null) +const l1Rcpt = await sdk.withdrawals.wait(handle, { for: "finalized", pollMs: 7000 }); +``` + + + Default polling is 5500ms (minimum 1000ms). Use timeoutMs for long windows. + + +### `finalize(l2TxHash: Hex) → Promise<{ status: WithdrawalStatus; receipt?: TransactionReceipt }>` + +Sends the **L1 finalize** transaction **if** ready. If already finalized, returns the status without sending. + +```ts +const { status, receipt } = await sdk.withdrawals.finalize(handle.l2TxHash); +if (status.phase === "FINALIZED") { + console.log("L1 tx:", receipt?.transactionHash); +} +``` + + + Behavior: If the withdrawal is not ready, finalize throws a typed STATE error. + Use status(...) or `wait(..., { for: 'ready' })` to check first. + + +### `tryFinalize(l2TxHash) → Promise<{ ok: true; value: { status; receipt? } } | { ok: false; error }>` + +Result-style version of `finalize`. + +## End-to-end examples + +### Minimal happy path + +```ts +const handle = await sdk.withdrawals.create({ token, amount, to }); + +// Wait L2 inclusion +await sdk.withdrawals.wait(handle, { for: "l2" }); + +// Either finalize immediately… +const { status, receipt } = await sdk.withdrawals.finalize(handle.l2TxHash); + +// …or wait for readiness first, then finalize +await sdk.withdrawals.wait(handle, { for: "ready" }); +const done = await sdk.withdrawals.finalize(handle.l2TxHash); +``` + +## Types (shape overview) + +These types live in `core/types` and are summarized here for convenience. + +```ts +type WithdrawParams = { + token: Address; // L2 token (ETH handled internally) + amount: bigint; // in wei + to: Address; // L1 recipient +}; + +type WithdrawQuote = { + route: "eth-base" | "eth-nonbase" | "erc20-nonbase"; + approvalsNeeded: Array<{ token: Address; spender: Address; amount: bigint }>; + suggestedL2GasLimit?: bigint; +}; + +type WithdrawPlan = { + route: WithdrawQuote["route"]; + summary: WithdrawQuote; + steps: Array<{ key: string; kind: string; tx: TTx }>; +}; + +type WithdrawHandle = { + kind: "withdrawal"; + l2TxHash: Hex; + stepHashes: Record; + plan: WithdrawPlan; +}; + +type WithdrawalStatus = + | { phase: "UNKNOWN"; l2TxHash: Hex } + | { phase: "L2_PENDING"; l2TxHash: Hex } + | { phase: "PENDING"; l2TxHash: Hex; key?: unknown } + | { phase: "READY_TO_FINALIZE"; l2TxHash: Hex; key: unknown } + | { phase: "FINALIZED"; l2TxHash: Hex; key: unknown }; + +// The L2 receipt returned by wait({ for: 'l2' }) is augmented: +type TransactionReceiptZKsyncOS = TransactionReceipt & { l2ToL1Logs?: Array }; +``` + + + Prefer the try* variants if you want result objects instead of exceptions. + diff --git a/docs/docs.json b/docs/docs.json index d61fe90..5325657 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -4,11 +4,23 @@ "name": "ZKsyncOS SDK", "colors": { "primary": "#1755F4", - "light": "#13D5D3", + "light": "#BFF351", "dark": "#0C18EC" }, "favicon": "/favicon.svg", -"navigation": { + "appearance": { + "default": "dark" + }, + "styling": { + "eyebrows": "breadcrumbs", + "codeblocks": { + "theme": { + "light": "vitesse-light", + "dark": "tokyo-night" + } + } + }, + "navigation": { "tabs": [ { "tab": "Home", @@ -59,19 +71,27 @@ "icon": "code", "groups": [ { - "group": "Core", + "group": "Overview", + "pages": [ + "api-reference/introduction" + ] + }, + { + "group": "Ethers", "pages": [ - "api-reference/introduction", - "api-reference/core/client", - "api-reference/core/types", - "api-reference/core/errors" + "api-reference/ethers/client", + "api-reference/ethers/sdk", + "api-reference/ethers/deposits", + "api-reference/ethers/withdrawals" ] }, { - "group": "Adapters", + "group": "Viem", "pages": [ - "api-reference/adapters/ethers", - "api-reference/adapters/viem" + "api-reference/viem/client", + "api-reference/viem/sdk", + "api-reference/viem/deposits", + "api-reference/viem/withdrawals" ] } ] @@ -92,20 +112,25 @@ }, "logo": { "light": "/logo/light.svg", - "dark": "/logo/dark.svg" + "dark": "/logo/dark.svg", + "href": "https://zksync.io" + }, + "search": { + "prompt": "Search ZKsyncOS SDK..." }, "navbar": { "links": [ { "label": "Support", - "href": "https://github.com/zkSync-Community-Hub/zksync-developers/discussions/categories/sdks" + "href": "https://github.com/zkSync-Community-Hub/zksync-developers/discussions/categories/sdks", + "icon": "arrow-up-right-from-square" + }, + { + "label": "Examples", + "href": "https://github.com/dutterbutter/zksync-sdk/tree/main/examples", + "icon": "arrow-up-right-from-square" } - ], - "primary": { - "type": "button", - "label": "Dashboard", - "href": "https://dashboard.mintlify.com" - } + ] }, "contextual": { "options": [ @@ -124,6 +149,34 @@ "x": "https://x.com/zksync", "github": "https://github.com/dutterbutter/zksync-sdk", "linkedin": "https://linkedin.com/company/matter-labs" - } + }, + "links": [ + { + "header": "Community", + "items": [ + { + "label": "Discord", + "href": "https://join.zksync.dev/" + }, + { + "label": "GitHub Discussions", + "href": "https://github.com/zkSync-Community-Hub/zksync-developers/discussions" + } + ] + }, + { + "header": "Resources", + "items": [ + { + "label": "Block Explorer", + "href": "https://explorer.zksync.io/" + }, + { + "label": "Website", + "href": "https://zksync.io/" + } + ] + } + ] } } diff --git a/docss/book.toml b/docss/book.toml deleted file mode 100644 index 1e197e4..0000000 --- a/docss/book.toml +++ /dev/null @@ -1,18 +0,0 @@ -[book] -title = "ZKsync SDK" -author = "Matter Labs" -language = "en" -multilingual = false -src = "src" - -[build] -build-dir = "book" # output folder (docs/book) - -[preprocessor.admonish] -command = "mdbook-admonish" -assets_version = "3.0.3" # do not edit: managed by `mdbook-admonish install` - -[output.html] -additional-css = ["./mdbook-admonish.css"] -default-theme = "light" -preferred-dark-theme = "navy" diff --git a/docss/mdbook-admonish.css b/docss/mdbook-admonish.css deleted file mode 100644 index b6df9b0..0000000 --- a/docss/mdbook-admonish.css +++ /dev/null @@ -1,368 +0,0 @@ -@charset "UTF-8"; -:is(.admonition) { - display: flow-root; - margin: 1.5625em 0; - padding: 0 1.2rem; - color: var(--fg); - page-break-inside: avoid; - background-color: var(--bg); - border: 0 solid black; - border-inline-start-width: 0.4rem; - border-radius: 0.2rem; - box-shadow: - 0 0.2rem 1rem rgba(0, 0, 0, 0.05), - 0 0 0.1rem rgba(0, 0, 0, 0.1); -} -@media print { - :is(.admonition) { - box-shadow: none; - } -} -:is(.admonition) > * { - box-sizing: border-box; -} -:is(.admonition) :is(.admonition) { - margin-top: 1em; - margin-bottom: 1em; -} -:is(.admonition) > .tabbed-set:only-child { - margin-top: 0; -} -html :is(.admonition) > :last-child { - margin-bottom: 1.2rem; -} - -a.admonition-anchor-link { - display: none; - position: absolute; - left: -1.2rem; - padding-right: 1rem; -} -a.admonition-anchor-link:link, -a.admonition-anchor-link:visited { - color: var(--fg); -} -a.admonition-anchor-link:link:hover, -a.admonition-anchor-link:visited:hover { - text-decoration: none; -} -a.admonition-anchor-link::before { - content: '§'; -} - -:is(.admonition-title, summary.admonition-title) { - position: relative; - min-height: 4rem; - margin-block: 0; - margin-inline: -1.6rem -1.2rem; - padding-block: 0.8rem; - padding-inline: 4.4rem 1.2rem; - font-weight: 700; - background-color: rgba(68, 138, 255, 0.1); - print-color-adjust: exact; - -webkit-print-color-adjust: exact; - display: flex; -} -:is(.admonition-title, summary.admonition-title) p { - margin: 0; -} -html :is(.admonition-title, summary.admonition-title):last-child { - margin-bottom: 0; -} -:is(.admonition-title, summary.admonition-title)::before { - position: absolute; - top: 0.625em; - inset-inline-start: 1.6rem; - width: 2rem; - height: 2rem; - background-color: #448aff; - print-color-adjust: exact; - -webkit-print-color-adjust: exact; - mask-image: url('data:image/svg+xml;charset=utf-8,'); - -webkit-mask-image: url('data:image/svg+xml;charset=utf-8,'); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-size: contain; - content: ''; -} -:is(.admonition-title, summary.admonition-title):hover a.admonition-anchor-link { - display: initial; -} - -details.admonition > summary.admonition-title::after { - position: absolute; - top: 0.625em; - inset-inline-end: 1.6rem; - height: 2rem; - width: 2rem; - background-color: currentcolor; - mask-image: var(--md-details-icon); - -webkit-mask-image: var(--md-details-icon); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-size: contain; - content: ''; - transform: rotate(0deg); - transition: transform 0.25s; -} -details[open].admonition > summary.admonition-title::after { - transform: rotate(90deg); -} -summary.admonition-title::-webkit-details-marker { - display: none; -} - -:root { - --md-details-icon: url("data:image/svg+xml;charset=utf-8,"); -} - -:root { - --md-admonition-icon--admonish-note: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-abstract: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-info: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-tip: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-success: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-question: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-warning: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-failure: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-danger: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-bug: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-example: url("data:image/svg+xml;charset=utf-8,"); - --md-admonition-icon--admonish-quote: url("data:image/svg+xml;charset=utf-8,"); -} - -:is(.admonition):is(.admonish-note) { - border-color: #448aff; -} - -:is(.admonish-note) > :is(.admonition-title, summary.admonition-title) { - background-color: rgba(68, 138, 255, 0.1); -} -:is(.admonish-note) > :is(.admonition-title, summary.admonition-title)::before { - background-color: #448aff; - mask-image: var(--md-admonition-icon--admonish-note); - -webkit-mask-image: var(--md-admonition-icon--admonish-note); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.admonish-abstract, .admonish-summary, .admonish-tldr) { - border-color: #00b0ff; -} - -:is(.admonish-abstract, .admonish-summary, .admonish-tldr) - > :is(.admonition-title, summary.admonition-title) { - background-color: rgba(0, 176, 255, 0.1); -} -:is(.admonish-abstract, .admonish-summary, .admonish-tldr) - > :is(.admonition-title, summary.admonition-title)::before { - background-color: #00b0ff; - mask-image: var(--md-admonition-icon--admonish-abstract); - -webkit-mask-image: var(--md-admonition-icon--admonish-abstract); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.admonish-info, .admonish-todo) { - border-color: #00b8d4; -} - -:is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title) { - background-color: rgba(0, 184, 212, 0.1); -} -:is(.admonish-info, .admonish-todo) > :is(.admonition-title, summary.admonition-title)::before { - background-color: #00b8d4; - mask-image: var(--md-admonition-icon--admonish-info); - -webkit-mask-image: var(--md-admonition-icon--admonish-info); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.admonish-tip, .admonish-hint, .admonish-important) { - border-color: #00bfa5; -} - -:is(.admonish-tip, .admonish-hint, .admonish-important) - > :is(.admonition-title, summary.admonition-title) { - background-color: rgba(0, 191, 165, 0.1); -} -:is(.admonish-tip, .admonish-hint, .admonish-important) - > :is(.admonition-title, summary.admonition-title)::before { - background-color: #00bfa5; - mask-image: var(--md-admonition-icon--admonish-tip); - -webkit-mask-image: var(--md-admonition-icon--admonish-tip); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.admonish-success, .admonish-check, .admonish-done) { - border-color: #00c853; -} - -:is(.admonish-success, .admonish-check, .admonish-done) - > :is(.admonition-title, summary.admonition-title) { - background-color: rgba(0, 200, 83, 0.1); -} -:is(.admonish-success, .admonish-check, .admonish-done) - > :is(.admonition-title, summary.admonition-title)::before { - background-color: #00c853; - mask-image: var(--md-admonition-icon--admonish-success); - -webkit-mask-image: var(--md-admonition-icon--admonish-success); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.admonish-question, .admonish-help, .admonish-faq) { - border-color: #64dd17; -} - -:is(.admonish-question, .admonish-help, .admonish-faq) - > :is(.admonition-title, summary.admonition-title) { - background-color: rgba(100, 221, 23, 0.1); -} -:is(.admonish-question, .admonish-help, .admonish-faq) - > :is(.admonition-title, summary.admonition-title)::before { - background-color: #64dd17; - mask-image: var(--md-admonition-icon--admonish-question); - -webkit-mask-image: var(--md-admonition-icon--admonish-question); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.admonish-warning, .admonish-caution, .admonish-attention) { - border-color: #ff9100; -} - -:is(.admonish-warning, .admonish-caution, .admonish-attention) - > :is(.admonition-title, summary.admonition-title) { - background-color: rgba(255, 145, 0, 0.1); -} -:is(.admonish-warning, .admonish-caution, .admonish-attention) - > :is(.admonition-title, summary.admonition-title)::before { - background-color: #ff9100; - mask-image: var(--md-admonition-icon--admonish-warning); - -webkit-mask-image: var(--md-admonition-icon--admonish-warning); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.admonish-failure, .admonish-fail, .admonish-missing) { - border-color: #ff5252; -} - -:is(.admonish-failure, .admonish-fail, .admonish-missing) - > :is(.admonition-title, summary.admonition-title) { - background-color: rgba(255, 82, 82, 0.1); -} -:is(.admonish-failure, .admonish-fail, .admonish-missing) - > :is(.admonition-title, summary.admonition-title)::before { - background-color: #ff5252; - mask-image: var(--md-admonition-icon--admonish-failure); - -webkit-mask-image: var(--md-admonition-icon--admonish-failure); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.admonish-danger, .admonish-error) { - border-color: #ff1744; -} - -:is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title) { - background-color: rgba(255, 23, 68, 0.1); -} -:is(.admonish-danger, .admonish-error) > :is(.admonition-title, summary.admonition-title)::before { - background-color: #ff1744; - mask-image: var(--md-admonition-icon--admonish-danger); - -webkit-mask-image: var(--md-admonition-icon--admonish-danger); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.admonish-bug) { - border-color: #f50057; -} - -:is(.admonish-bug) > :is(.admonition-title, summary.admonition-title) { - background-color: rgba(245, 0, 87, 0.1); -} -:is(.admonish-bug) > :is(.admonition-title, summary.admonition-title)::before { - background-color: #f50057; - mask-image: var(--md-admonition-icon--admonish-bug); - -webkit-mask-image: var(--md-admonition-icon--admonish-bug); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.admonish-example) { - border-color: #7c4dff; -} - -:is(.admonish-example) > :is(.admonition-title, summary.admonition-title) { - background-color: rgba(124, 77, 255, 0.1); -} -:is(.admonish-example) > :is(.admonition-title, summary.admonition-title)::before { - background-color: #7c4dff; - mask-image: var(--md-admonition-icon--admonish-example); - -webkit-mask-image: var(--md-admonition-icon--admonish-example); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -:is(.admonition):is(.admonish-quote, .admonish-cite) { - border-color: #9e9e9e; -} - -:is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title) { - background-color: rgba(158, 158, 158, 0.1); -} -:is(.admonish-quote, .admonish-cite) > :is(.admonition-title, summary.admonition-title)::before { - background-color: #9e9e9e; - mask-image: var(--md-admonition-icon--admonish-quote); - -webkit-mask-image: var(--md-admonition-icon--admonish-quote); - mask-repeat: no-repeat; - -webkit-mask-repeat: no-repeat; - mask-size: contain; - -webkit-mask-repeat: no-repeat; -} - -.navy :is(.admonition) { - background-color: var(--sidebar-bg); -} - -.ayu :is(.admonition), -.coal :is(.admonition) { - background-color: var(--theme-hover); -} - -.rust :is(.admonition) { - background-color: var(--sidebar-bg); - color: var(--sidebar-fg); -} -.rust .admonition-anchor-link:link, -.rust .admonition-anchor-link:visited { - color: var(--sidebar-fg); -} diff --git a/docss/snippets/ethers/deposit-erc20.ts b/docss/snippets/ethers/deposit-erc20.ts deleted file mode 100644 index effabc7..0000000 --- a/docss/snippets/ethers/deposit-erc20.ts +++ /dev/null @@ -1,63 +0,0 @@ -// examples/deposit-erc20.ts -import { JsonRpcProvider, Wallet, parseUnits, type Signer } from 'ethers'; -import { createEthersClient, createEthersSdk } from '@dutterbutter/zksync-sdk/ethers'; - -const L1_RPC = 'http://localhost:8545'; // e.g. https://sepolia.infura.io/v3/XXX -const L2_RPC = 'http://localhost:3050'; // your L2 RPC -const PRIVATE_KEY = process.env.PRIVATE_KEY || ''; - -async function main() { - const l1 = new JsonRpcProvider(L1_RPC); - const l2 = new JsonRpcProvider(L2_RPC); - const signer = new Wallet(PRIVATE_KEY, l1); - - const client = await createEthersClient({ l1, l2, signer }); - const sdk = createEthersSdk(client); - - // ERC20 on sepolia - // Deploy your own if you can not use this one - const TOKEN = '0x42E331a2613Fd3a5bc18b47AE3F01e1537fD8873'; - - const me = (await signer.getAddress()); - const depositAmount = parseUnits('250', 18); - - // quote - const quote = await sdk.deposits.quote({ token: TOKEN, to: me, amount: depositAmount }); - console.log('QUOTE:', quote); - - const prepare = await sdk.deposits.prepare({ token: TOKEN, to: me, amount: depositAmount }); - console.log('PREPARE:', prepare); - - const create = await sdk.deposits.create({ token: TOKEN, to: me, amount: depositAmount }); - console.log('CREATE:', create); - - const status = await sdk.deposits.status(create); - console.log('STATUS (immediate):', status); - - // Wait until the L1 tx is included - const receipt = await sdk.deposits.wait(create, { for: 'l1' }); - console.log( - 'Included at block:', - receipt?.blockNumber, - 'status:', - receipt?.status, - 'hash:', - receipt?.hash, - ); - - // Wait until the L2 tx is included - const l2Receipt = await sdk.deposits.wait(create, { for: 'l2' }); - console.log( - 'Included at block:', - l2Receipt?.blockNumber, - 'status:', - l2Receipt?.status, - 'hash:', - l2Receipt?.hash, - ); -} - -main().catch((e) => { - console.error(e); - process.exit(1); -}); diff --git a/docss/snippets/ethers/deposit-eth.ts b/docss/snippets/ethers/deposit-eth.ts deleted file mode 100644 index 47067c6..0000000 --- a/docss/snippets/ethers/deposit-eth.ts +++ /dev/null @@ -1,82 +0,0 @@ -// examples/deposit-eth.ts -import { JsonRpcProvider, Wallet, parseEther } from 'ethers'; -import { createEthersClient, createEthersSdk } from '@dutterbutter/zksync-sdk/ethers'; -import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; - -const L1_RPC = 'http://localhost:8545'; // e.g. https://sepolia.infura.io/v3/XXX -const L2_RPC = 'http://localhost:3050'; // your L2 RPC -const PRIVATE_KEY = process.env.PRIVATE_KEY || ''; - -async function main() { - if (!PRIVATE_KEY) { - throw new Error('Set your PRIVATE_KEY in the .env file'); - } - const l1 = new JsonRpcProvider(L1_RPC); - const l2 = new JsonRpcProvider(L2_RPC); - const signer = new Wallet(PRIVATE_KEY, l1); - - const balance = await l1.getBalance(signer.address); - console.log('L1 balance:', balance.toString()); - - const balanceL2 = await l2.getBalance(signer.address); - console.log('L2 balance:', balanceL2.toString()); - - const client = await createEthersClient({ l1, l2, signer }); - const sdk = createEthersSdk(client); - - const me = (await signer.getAddress()); - const params = { - amount: parseEther('.01'), // 0.01 ETH - to: me, - token: ETH_ADDRESS, - // optional: - // l2GasLimit: 300_000n, - // gasPerPubdata: 800n, - // operatorTip: 0n, - // refundRecipient: me, - } as const; - - // Quote - const quote = await sdk.deposits.quote(params); - console.log('QUOTE response: ', quote); - - const prepare = await sdk.deposits.prepare(params); - console.log('PREPARE response: ', prepare); - - // Create (prepare + send) - const create = await sdk.deposits.create(params); - console.log('CREATE response: ', create); - - const status = await sdk.deposits.status(create); - console.log('STATUS response: ', status); - - // Wait (for now, L1 inclusion) - const receipt = await sdk.deposits.wait(create, { for: 'l1' }); - console.log( - 'Included at block:', - receipt?.blockNumber, - 'status:', - receipt?.status, - 'hash:', - receipt?.hash, - ); - - const status2 = await sdk.deposits.status(create); - console.log('STATUS2 response: ', status2); - - // Wait (for now, L2 inclusion) - const l2Receipt = await sdk.deposits.wait(create, { for: 'l2' }); - console.log( - 'Included at block:', - l2Receipt?.blockNumber, - 'status:', - l2Receipt?.status, - 'hash:', - l2Receipt?.hash, - ); -} - -main().catch((e) => { - console.error(e); - process.exit(1); -}); diff --git a/docss/snippets/ethers/withdrawals-erc20.ts b/docss/snippets/ethers/withdrawals-erc20.ts deleted file mode 100644 index 9a29ba8..0000000 --- a/docss/snippets/ethers/withdrawals-erc20.ts +++ /dev/null @@ -1,80 +0,0 @@ -// examples/withdrawals-erc20.ts -import { JsonRpcProvider, Wallet, parseUnits } from 'ethers'; -import { createEthersClient, createEthersSdk } from '@dutterbutter/zksync-sdk/ethers'; - -const L1_RPC = 'http://localhost:8545'; // e.g. https://sepolia.infura.io/v3/XXX -const L2_RPC = 'http://localhost:3050'; // your L2 RPC -const PRIVATE_KEY = process.env.PRIVATE_KEY || ''; - -// Replace with a real **L2 ERC-20 token address** you hold on L2 -const L1_ERC20_TOKEN = '0x42E331a2613Fd3a5bc18b47AE3F01e1537fD8873'; - -async function main() { - const l1 = new JsonRpcProvider(L1_RPC); - const l2 = new JsonRpcProvider(L2_RPC); - const signer = new Wallet(PRIVATE_KEY, l1); - - const client = createEthersClient({ l1, l2, signer }); - const sdk = createEthersSdk(client); - - const me = (await signer.getAddress()); - const l2Token = await sdk.helpers.l2TokenAddress(L1_ERC20_TOKEN); - - // Prepare withdraw params - const params = { - token: l2Token, // L2 ERC-20 - amount: parseUnits('25', 18), // withdraw 25 tokens - to: me, - // l2GasLimit: 300_000n, - } as const; - - // -------- Dry runs / planning -------- - console.log('TRY QUOTE:', await sdk.withdrawals.tryQuote(params)); - console.log('QUOTE:', await sdk.withdrawals.quote(params)); - console.log('TRY PREPARE:', await sdk.withdrawals.tryPrepare(params)); - console.log('PREPARE:', await sdk.withdrawals.prepare(params)); - - // -------- Create (L2 approvals if needed + withdraw) -------- - const created = await sdk.withdrawals.create(params); - console.log('CREATE:', created); - - // Wait for L2 inclusion - const l2Receipt = await sdk.withdrawals.wait(created, { for: 'l2' }); - console.log( - 'L2 included: block=', - l2Receipt?.blockNumber, - 'status=', - l2Receipt?.status, - 'hash=', - l2Receipt?.hash, - ); - - console.log('STATUS (ready):', await sdk.withdrawals.status(created.l2TxHash)); - - // Wait until the withdrawal is ready to finalize - await sdk.withdrawals.wait(created.l2TxHash, { for: 'ready' }); - - // Finalize on L1 - const fin = await sdk.withdrawals.tryFinalize(created.l2TxHash); - if (!fin.ok) { - console.error('FINALIZE failed:', fin.error); - return; - } - console.log( - 'FINALIZE status:', - fin.value.status, - fin.value.receipt?.hash ?? '(already finalized)', - ); - - const l1Receipt = await sdk.withdrawals.wait(created.l2TxHash, { for: 'finalized' }); - if (l1Receipt) { - console.log('L1 finalize receipt:', l1Receipt.hash); - } else { - console.log('Finalized (no local L1 receipt available, possibly finalized by another actor).'); - } -} - -main().catch((e) => { - console.error(e); - process.exit(1); -}); diff --git a/docss/snippets/ethers/withdrawals-eth.ts b/docss/snippets/ethers/withdrawals-eth.ts deleted file mode 100644 index fe4f085..0000000 --- a/docss/snippets/ethers/withdrawals-eth.ts +++ /dev/null @@ -1,74 +0,0 @@ -// examples/withdrawals-eth.ts -import { JsonRpcProvider, Wallet, parseEther } from 'ethers'; -import { createEthersClient, createEthersSdk } from '@dutterbutter/zksync-sdk/ethers'; -import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; - -const L1_RPC = 'http://localhost:8545'; // e.g. https://sepolia.infura.io/v3/XXX -const L2_RPC = 'http://localhost:3050'; // your L2 RPC -const PRIVATE_KEY = process.env.PRIVATE_KEY || ''; - -async function main() { - const l1 = new JsonRpcProvider(L1_RPC); - const l2 = new JsonRpcProvider(L2_RPC); - const signer = new Wallet(PRIVATE_KEY, l1); - - const client = createEthersClient({ l1, l2, signer }); - const sdk = createEthersSdk(client); - - const me = (await signer.getAddress()); - - // Withdraw params (ETH) - const params = { - token: ETH_ADDRESS, - amount: parseEther('0.01'), // 0.001 ETH - to: me, - // l2GasLimit: 300_000n, - } as const; - - // Quote (dry-run only) - const quote = await sdk.withdrawals.quote(params); - console.log('QUOTE: ', quote); - - const prepare = await sdk.withdrawals.prepare(params); - console.log('PREPARE: ', prepare); - - const created = await sdk.withdrawals.create(params); - console.log('CREATE:', created); - - // Quick status check - console.log('STATUS (initial):', await sdk.withdrawals.status(created.l2TxHash)); - - // wait for L2 inclusion - const l2Receipt = await sdk.withdrawals.wait(created, { for: 'l2' }); - console.log( - 'L2 included: block=', - l2Receipt?.blockNumber, - 'status=', - l2Receipt?.status, - 'hash=', - l2Receipt?.hash, - ); - - // Optional: check status again - console.log('STATUS (post-L2):', await sdk.withdrawals.status(created.l2TxHash)); - - // finalize on L1 - // Use tryFinalize to avoid throwing in an example script - await sdk.withdrawals.wait(created.l2TxHash, { for: 'ready' }); - console.log('STATUS (ready):', await sdk.withdrawals.status(created.l2TxHash)); - - const fin = await sdk.withdrawals.tryFinalize(created.l2TxHash); - console.log('TRY FINALIZE: ', fin); - - const l1Receipt = await sdk.withdrawals.wait(created.l2TxHash, { for: 'finalized' }); - if (l1Receipt) { - console.log('L1 finalize receipt:', l1Receipt.hash); - } else { - console.log('Finalized (no local L1 receipt available, possibly finalized by another actor).'); - } -} - -main().catch((e) => { - console.error(e); - process.exit(1); -}); diff --git a/docss/snippets/viem/deposit-erc20.ts b/docss/snippets/viem/deposit-erc20.ts deleted file mode 100644 index 8bb5edc..0000000 --- a/docss/snippets/viem/deposit-erc20.ts +++ /dev/null @@ -1,95 +0,0 @@ -// examples/deposit-erc20.ts -import { - Account, - Chain, - createPublicClient, - createWalletClient, - http, - parseUnits, - Transport, - WalletClient, -} from 'viem'; -import { privateKeyToAccount } from 'viem/accounts'; -import { createViemSdk, createViemClient } from '@dutterbutter/zksync-sdk/viem'; - -const L1_RPC = 'http://localhost:8545'; // e.g. https://sepolia.infura.io/v3/XXX -const L2_RPC = 'http://localhost:3050'; // your L2 RPC -const PRIVATE_KEY = process.env.PRIVATE_KEY || ''; - -async function main() { - if (!PRIVATE_KEY) { - throw new Error('Set your PRIVATE_KEY in the .env file'); - } - - // --- Viem clients --- - const account = privateKeyToAccount(PRIVATE_KEY as `0x${string}`); - const l1 = createPublicClient({ transport: http(L1_RPC) }); - const l2 = createPublicClient({ transport: http(L2_RPC) }); - const l1Wallet: WalletClient = createWalletClient({ - account, - transport: http(L1_RPC), - }); - - // --- SDK --- - const client = createViemClient({ l1, l2, l1Wallet }); - const sdk = createViemSdk(client); - - // sepolia example - const TOKEN = '0x42E331a2613Fd3a5bc18b47AE3F01e1537fD8873'; - - const me = account.address; - const depositAmount = parseUnits('250', 18); - - // Optional (local): mint some tokens first if your ERC-20 supports `mint(address,uint256)` - // const { request } = await l1.simulateContract({ - // address: TOKEN, - // abi: IERC20ABI as const, - // functionName: 'mint', - // args: [me, amount] as const, - // account, - // }); - // await l1Wallet.writeContract(request); - - // --- Quote --- - const quote = await sdk.deposits.quote({ token: TOKEN, to: me, amount: depositAmount }); - console.log('QUOTE:', quote); - - // --- Prepare (route + steps, no sends) --- - const prepared = await sdk.deposits.prepare({ token: TOKEN, to: me, amount: depositAmount }); - console.log('PREPARE:', prepared); - - // --- Create (prepare + send all steps) --- - const created = await sdk.deposits.create({ token: TOKEN, to: me, amount: depositAmount }); - console.log('CREATE:', created); - - // Immediate status - const status = await sdk.deposits.status(created); - console.log('STATUS (immediate):', status); - - // Wait for L1 inclusion - const l1Receipt = await sdk.deposits.wait(created, { for: 'l1' }); - console.log( - 'L1 Included at block:', - l1Receipt?.blockNumber, - 'status:', - l1Receipt?.status, - 'hash:', - l1Receipt?.transactionHash, - ); - - // Wait for L2 execution - const l2Receipt = await sdk.deposits.wait(created, { for: 'l2' }); - console.log( - 'L2 Included at block:', - l2Receipt?.blockNumber, - 'status:', - l2Receipt?.status, - 'hash:', - l2Receipt?.transactionHash, - ); -} - -main().catch((e) => { - console.error(e); - process.exit(1); -}); diff --git a/docss/snippets/viem/deposit-eth.ts b/docss/snippets/viem/deposit-eth.ts deleted file mode 100644 index 92da8a3..0000000 --- a/docss/snippets/viem/deposit-eth.ts +++ /dev/null @@ -1,98 +0,0 @@ -// examples/deposit-eth.ts -import { createPublicClient, createWalletClient, http, parseEther, WalletClient } from 'viem'; -import type { Account, Chain, Transport } from 'viem'; -import { privateKeyToAccount } from 'viem/accounts'; - -import { createViemSdk, createViemClient } from '@dutterbutter/zksync-sdk/viem'; -import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; - -const L1_RPC = 'http://localhost:8545'; // e.g. https://sepolia.infura.io/v3/XXX -const L2_RPC = 'http://localhost:3050'; // your L2 RPC -const PRIVATE_KEY = process.env.PRIVATE_KEY || ''; - -async function main() { - if (!PRIVATE_KEY || PRIVATE_KEY.length !== 66) { - throw new Error('Set your PRIVATE_KEY in the .env file'); - } - - // --- Viem clients --- - const account = privateKeyToAccount(PRIVATE_KEY as `0x${string}`); - - const l1 = createPublicClient({ transport: http(L1_RPC) }); - const l2 = createPublicClient({ transport: http(L2_RPC) }); - const l1Wallet: WalletClient = createWalletClient({ - account, - transport: http(L1_RPC), - }); - - // Check balances - const [balL1, balL2] = await Promise.all([ - l1.getBalance({ address: account.address }), - l2.getBalance({ address: account.address }), - ]); - console.log('L1 balance:', balL1.toString()); - console.log('L2 balance:', balL2.toString()); - - // client + sdk - const client = createViemClient({ l1, l2, l1Wallet }); - const sdk = createViemSdk(client); - - const me = account.address; - const params = { - amount: parseEther('0.01'), // 0.01 ETH - to: me, - token: ETH_ADDRESS, - // optional: - // l2GasLimit: 300_000n, - // gasPerPubdata: 800n, - // operatorTip: 0n, - // refundRecipient: me, - } as const; - - // Quote - const quote = await sdk.deposits.quote(params); - console.log('QUOTE response:', quote); - - // Prepare (route + steps, no sends) - const prepared = await sdk.deposits.prepare(params); - console.log('PREPARE response:', prepared); - - // Create (prepare + send) - const created = await sdk.deposits.create(params); - console.log('CREATE response:', created); - - // Status (quick check) - const status = await sdk.deposits.status(created); - console.log('STATUS response:', status); - - // Wait (L1 inclusion) - const l1Receipt = await sdk.deposits.wait(created, { for: 'l1' }); - console.log( - 'L1 Included at block:', - l1Receipt?.blockNumber, - 'status:', - l1Receipt?.status, - 'hash:', - l1Receipt?.transactionHash, - ); - - // Status again - const status2 = await sdk.deposits.status(created); - console.log('STATUS2 response:', status2); - - // Wait for L2 execution - const l2Receipt = await sdk.deposits.wait(created, { for: 'l2' }); - console.log( - 'L2 Included at block:', - l2Receipt?.blockNumber, - 'status:', - l2Receipt?.status, - 'hash:', - l2Receipt?.transactionHash, - ); -} - -main().catch((e) => { - console.error(e); - process.exit(1); -}); diff --git a/docss/snippets/viem/withdrawals-erc20.ts b/docss/snippets/viem/withdrawals-erc20.ts deleted file mode 100644 index d5d0fd5..0000000 --- a/docss/snippets/viem/withdrawals-erc20.ts +++ /dev/null @@ -1,103 +0,0 @@ -// examples/withdraw-erc20.ts -import { - createPublicClient, - createWalletClient, - http, - parseUnits, - type Account, - type Chain, - type Transport, - type WalletClient, -} from 'viem'; -import { privateKeyToAccount } from 'viem/accounts'; -import { createViemSdk, createViemClient } from '@dutterbutter/zksync-sdk/viem'; - -const L1_RPC = 'http://localhost:8545'; // e.g. https://sepolia.infura.io/v3/XXX -const L2_RPC = 'http://localhost:3050'; // your L2 RPC -const PRIVATE_KEY = process.env.PRIVATE_KEY || ''; - -// Replace with a real **L1 ERC-20 token address** you hold on L2 -const L1_ERC20_TOKEN = '0x42E331a2613Fd3a5bc18b47AE3F01e1537fD8873'; - -async function main() { - if (!PRIVATE_KEY) { - throw new Error('Set PRIVATE_KEY (0x-prefixed) in your environment.'); - } - - // --- Viem clients --- - const account = privateKeyToAccount(PRIVATE_KEY as `0x${string}`); - const l1 = createPublicClient({ transport: http(L1_RPC) }); - const l2 = createPublicClient({ transport: http(L2_RPC) }); - - const l1Wallet: WalletClient = createWalletClient({ - account, - transport: http(L1_RPC), - }); - // Need to provide an L2 wallet client for sending L2 tx - const l2Wallet = createWalletClient({ - account, - transport: http(L2_RPC), - }); - const client = createViemClient({ l1, l2, l1Wallet, l2Wallet }); - const sdk = createViemSdk(client); - - const me = account.address; - - // Resolve the L2-mapped token for an L1 ERC-20 - const l2Token = await sdk.helpers.l2TokenAddress(L1_ERC20_TOKEN); - - // Withdraw params - const params = { - token: l2Token, - amount: parseUnits('25', 18), // withdraw 25 tokens - to: me, - // l2GasLimit: 300_000n, - } as const; - - // -------- Dry runs / planning -------- - console.log('TRY QUOTE:', await sdk.withdrawals.tryQuote(params)); - console.log('QUOTE:', await sdk.withdrawals.quote(params)); - console.log('TRY PREPARE:', await sdk.withdrawals.tryPrepare(params)); - console.log('PREPARE:', await sdk.withdrawals.prepare(params)); - - // -------- Create (L2 approvals if needed + withdraw) -------- - const created = await sdk.withdrawals.create(params); - console.log('CREATE:', created); - - // Wait for L2 inclusion - const l2Receipt = await sdk.withdrawals.wait(created, { for: 'l2' }); - console.log( - 'L2 included: block=', - l2Receipt?.blockNumber, - 'status=', - l2Receipt?.status, - 'hash=', - l2Receipt?.transactionHash, - ); - - console.log('STATUS (post-L2):', await sdk.withdrawals.status(created.l2TxHash)); - - // Wait until the withdrawal is ready to finalize - await sdk.withdrawals.wait(created.l2TxHash, { for: 'ready' }); - console.log('STATUS (ready):', await sdk.withdrawals.status(created.l2TxHash)); - - // Finalize on L1 - const fin = await sdk.withdrawals.tryFinalize(created.l2TxHash); - console.log( - 'FINALIZE:', - fin.ok ? fin.value.status : fin.error, - fin.ok ? (fin.value.receipt?.transactionHash ?? '(already finalized)') : '', - ); - - const l1Receipt = await sdk.withdrawals.wait(created.l2TxHash, { for: 'finalized' }); - if (l1Receipt) { - console.log('L1 finalize receipt:', l1Receipt.transactionHash); - } else { - console.log('Finalized (no local L1 receipt available, possibly finalized by another actor).'); - } -} - -main().catch((e) => { - console.error(e); - process.exit(1); -}); diff --git a/docss/snippets/viem/withdrawals-eth.ts b/docss/snippets/viem/withdrawals-eth.ts deleted file mode 100644 index d88bb01..0000000 --- a/docss/snippets/viem/withdrawals-eth.ts +++ /dev/null @@ -1,98 +0,0 @@ -// examples/viem/withdrawals-eth.ts -import { - createPublicClient, - createWalletClient, - http, - parseEther, - type Account, - type Chain, - type Transport, -} from 'viem'; -import { privateKeyToAccount } from 'viem/accounts'; - -import { createViemSdk, createViemClient } from '@dutterbutter/zksync-sdk/viem'; -import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; - -const L1_RPC = 'http://localhost:8545'; // e.g. https://sepolia.infura.io/v3/XXX -const L2_RPC = 'http://localhost:3050'; // your L2 RPC -const PRIVATE_KEY = process.env.PRIVATE_KEY || ''; - -async function main() { - if (!PRIVATE_KEY) { - throw new Error('Set your PRIVATE_KEY (0x-prefixed 32-byte) in env'); - } - - // --- Viem clients --- - const account = privateKeyToAccount(PRIVATE_KEY as `0x${string}`); - - const l1 = createPublicClient({ transport: http(L1_RPC) }); - const l2 = createPublicClient({ transport: http(L2_RPC) }); - - const l1Wallet = createWalletClient({ - account, - transport: http(L1_RPC), - }); - const l2Wallet = createWalletClient({ - account, - transport: http(L2_RPC), - }); - - const client = createViemClient({ l1, l2, l1Wallet, l2Wallet }); - const sdk = createViemSdk(client); - - const me = account.address; - - // Withdraw ETH - const params = { - token: ETH_ADDRESS, - amount: parseEther('0.01'), - to: me, - // l2GasLimit: 300_000n, // optional - } as const; - - // Quote (dry run) - const quote = await sdk.withdrawals.quote(params); - console.log('QUOTE:', quote); - - // Prepare (no sends) - const plan = await sdk.withdrawals.prepare(params); - console.log('PREPARE:', plan); - - // Create (send L2 withdraw) - const created = await sdk.withdrawals.create(params); - console.log('CREATE:', created); - - // Quick status - console.log('STATUS (initial):', await sdk.withdrawals.status(created.l2TxHash)); - - // Wait for L2 inclusion - const l2Receipt = await sdk.withdrawals.wait(created, { for: 'l2' }); - console.log( - 'L2 included: block=', - l2Receipt?.blockNumber, - 'status=', - l2Receipt?.status, - 'hash=', - l2Receipt?.transactionHash, - ); - - // Wait until ready to finalize - await sdk.withdrawals.wait(created.l2TxHash, { for: 'ready' }); - console.log('STATUS (ready):', await sdk.withdrawals.status(created.l2TxHash)); - - // Try to finalize on L1 - const fin = await sdk.withdrawals.tryFinalize(created.l2TxHash); - console.log('TRY FINALIZE:', fin); - - const l1Receipt = await sdk.withdrawals.wait(created.l2TxHash, { for: 'finalized' }); - if (l1Receipt) { - console.log('L1 finalize receipt:', l1Receipt.transactionHash); - } else { - console.log('Finalized (no local L1 receipt — possibly finalized by someone else).'); - } -} - -main().catch((e) => { - console.error(e); - process.exit(1); -}); diff --git a/docss/src/SUMMARY.md b/docss/src/SUMMARY.md deleted file mode 100644 index 6ed786b..0000000 --- a/docss/src/SUMMARY.md +++ /dev/null @@ -1,40 +0,0 @@ -# Summary - -- [Overview](overview/index.md) - - [What this SDK does](overview/what-it-does.md) - - [Mental model](overview/mental-model.md) - - [Adapters (viem & ethers)](overview/adapters.md) - -- [Quickstart](quickstart/index.md) - - [Choose your adapter](quickstart/choose-adapter.md) - - [Quickstart (viem)](quickstart/viem.md) - - [Quickstart (ethers)](quickstart/ethers.md) - -- [How-to Guides](guides/index.md) - - [Deposits]() - - [viem](guides/deposits/viem.md) - - [ethers](guides/deposits/ethers.md) - - [Withdrawals]() - - [viem](guides/withdrawals/viem.md) - - [ethers](guides/withdrawals/ethers.md) - -- [Concepts](concepts/index.md) - - [Status vs Wait](concepts/status-vs-wait.md) - - [Finalization](concepts/finalization.md) - -- [Reference](reference/index.md) - - [ZKsync RPC Helpers](reference/methods.md) - - [Common Helpers](reference/helpers.md) - - diff --git a/docss/src/concepts/finalization.md b/docss/src/concepts/finalization.md deleted file mode 100644 index d0792fb..0000000 --- a/docss/src/concepts/finalization.md +++ /dev/null @@ -1,44 +0,0 @@ -# Finalization (Withdrawals) - -When withdrawing from ZKsync (L2) back to Ethereum (L1), **your funds are not automatically released on L1** once the L2 transaction is included. - -Withdrawals are always a **two-step process**: - -1. **Initiate on L2** — you call `withdraw()` (via the SDK’s `create`) to start the withdrawal. - - This burns/locks the funds on L2. - - At this point, your withdrawal is visible in L2 receipts and logs, but **your funds are not yet available on L1**. - -2. **Finalize on L1** — you must explicitly call `finalize` to release your funds on L1. - - This submits an L1 transaction. - - Only after this step does your ETH or token balance increase on Ethereum. - -## Why finalization matters - -- **Funds remain locked** until finalization. -- **Anyone can finalize** — not just the withdrawer. In practice, most users will finalize their own withdrawals. -- **Finalization costs gas on L1**, so plan for this when withdrawing. - -If you **forget to finalize**, your funds will stay in limbo: visible as “ready to withdraw,” but unavailable on Ethereum. - -## SDK methods - -- **`finalize(l2TxHash)`** - Actively sends the L1 transaction to finalize the withdrawal. Returns the updated `status` and the L1 receipt. - -## Example: Explicit finalize - -```ts -// Step 1: Create withdrawal on L2 -const withdrawal = await sdk.withdrawals.create({ - token: ETH_ADDRESS, - amount: parseEther('0.1'), - to: myAddress, -}); - -// Step 2: Finalize on L1 -await sdk.withdrawals.wait(withdrawal, { for: 'ready' }); // block until finalizable -const { status, receipt } = await sdk.withdrawals.finalize(withdrawal.l2TxHash); - -console.log(status.phase); // "FINALIZED" -console.log(receipt?.transactionHash); // L1 finalize tx -``` diff --git a/docss/src/concepts/index.md b/docss/src/concepts/index.md deleted file mode 100644 index 12b7325..0000000 --- a/docss/src/concepts/index.md +++ /dev/null @@ -1,13 +0,0 @@ -# Concepts - -This section explains the small set of ideas you need to use the SDK confidently. Keep these in mind as you read the guides and API reference. - -## What’s here - -- **[Status vs Wait](status-vs-wait.md)** - When to take a quick, non-blocking snapshot (`status`) vs when to block until a checkpoint (`wait`). - Covers deposit phases (`L1_PENDING → L2_EXECUTED/FAILED`) and withdrawal phases (`L2_PENDING → READY_TO_FINALIZE → FINALIZED`), polling options, and return shapes. - -- **[Finalization](finalization.md)** - Withdrawals are **two-step**: initiate on L2, then **you must call `finalize` on L1** to release funds. - Explains readiness, how to detect `READY_TO_FINALIZE`, and how to use `finalize`. diff --git a/docss/src/concepts/status-vs-wait.md b/docss/src/concepts/status-vs-wait.md deleted file mode 100644 index 80acc58..0000000 --- a/docss/src/concepts/status-vs-wait.md +++ /dev/null @@ -1,117 +0,0 @@ -# Status vs Wait - -The SDK exposes two complementary ways to track progress: - -- **`status(...)`** — returns a **non-blocking snapshot** of where an operation is. -- **`wait(..., { for })`** — **blocks/polls** until a specified checkpoint is reached. - -Both methods work for **Deposits** and **Withdrawals**, but Withdrawals add finalization-specific states and targets. - -## Withdrawals - -### `withdrawals.status(h | l2TxHash) → Promise` - -**Input** - -- `h`: a `WithdrawalWaitable` (e.g., from `create`) **or** the L2 tx hash `Hex`. - -**Phases returned** - -- `UNKNOWN` — no L2 hash available on the handle. -- `L2_PENDING` — L2 tx not yet included. -- `PENDING` — L2 included, but not yet ready to finalize. -- `READY_TO_FINALIZE` — finalization would succeed now. -- `FINALIZED` — finalized on L1 (funds released). - -**Notes** - -- When L2 receipt is missing → `L2_PENDING`. -- When finalization key can be derived but not ready → `PENDING`. -- When already finalized → `FINALIZED`. - -**Example** - -```ts -const s = await sdk.withdrawals.status(handleOrHash); -// s.phase in: 'UNKNOWN' | 'L2_PENDING' | 'PENDING' | 'READY_TO_FINALIZE' | 'FINALIZED' -``` - -### `withdrawals.wait(h | l2TxHash, { for, pollMs?, timeoutMs? })` - -**Targets** - -- `{ for: 'l2' }` → resolves with **L2 receipt** (`TransactionReceiptZKsyncOS | null`) -- `{ for: 'ready' }` → resolves **`null`** when finalization becomes possible -- `{ for: 'finalized' }` → resolves **L1 receipt** when finalized, or `null` if finalized but receipt not found - -**Behavior** - -- If the handle has **no L2 tx hash**, returns `null` immediately. -- Default polling interval: 5500ms default or set explicitly if you want. -- Optional `timeoutMs` returns `null` on deadline. - -**Example** - -```ts -// wait for inclusion on L2, get L2 receipt (augmented with l2ToL1Logs if available) -const l2Rcpt = await sdk.withdrawals.wait(handle, { for: 'l2', pollMs: 5000 }); - -// wait until it's available to finalize (no side-effects) -await sdk.withdrawals.wait(handle, { for: 'ready' }); - -// wait until finalized; returns L1 receipt (or null if finalized but receipt not retrievable) -const l1Rcpt = await sdk.withdrawals.wait(handle, { for: 'finalized' }); -``` - -**Common Troubleshooting** - -- Network hiccup while fetching receipts → thrown `ZKsyncError` (`RPC` kind). -- Internal decode issue → thrown `ZKsyncError` (`INTERNAL` kind). - ---- - -## Deposits - -### `deposits.status(h | l1TxHash) → Promise` - -**Input** - -- `h`: `DepositWaitable` (from `create`) **or** L1 tx hash `Hex`. - -**Phases returned** - -- `UNKNOWN` — no L1 hash. -- `L1_PENDING` — L1 receipt missing. -- `L1_INCLUDED` — L1 included, but L2 hash not yet derivable from logs. -- `L2_PENDING` — L2 hash known but receipt missing. -- `L2_EXECUTED` — L2 receipt present with `status === 1`. -- `L2_FAILED` — L2 receipt present with `status !== 1`. - -**Example** - -```ts -const s = await sdk.deposits.status(handleOrL1Hash); -// s.phase in: 'UNKNOWN' | 'L1_PENDING' | 'L1_INCLUDED' | 'L2_PENDING' | 'L2_EXECUTED' | 'L2_FAILED' -``` - -### `deposits.wait(h | l1TxHash, { for: 'l1' | 'l2' })` - -**Targets** - -- `{ for: 'l1' }` → waits for L1 inclusion → **L1 receipt** or `null` -- `{ for: 'l2' }` → waits L1 inclusion **and** canonical L2 execution → **L2 receipt** or `null` - -**Example** - -```ts -const l1Rcpt = await sdk.deposits.wait(handle, { for: 'l1' }); -const l2Rcpt = await sdk.deposits.wait(handle, { for: 'l2' }); -``` - ---- - -## Tips & edge cases - -- **Handles vs hashes:** Both methods accept either a handle (from `create`) or a raw tx hash (`Hex`). If you pass a handle without the relevant hash, you’ll get `UNKNOWN`/`null`. -- **Polling:** For withdrawals, set `pollMs` explicitly if you want tighter/looser polling; minimum enforced is **5500ms**. -- **Timeouts:** Use `timeoutMs` for long waits (e.g., finalization windows) to avoid hanging scripts. diff --git a/docss/src/guides/deposits/ethers.md b/docss/src/guides/deposits/ethers.md deleted file mode 100644 index 8b220ec..0000000 --- a/docss/src/guides/deposits/ethers.md +++ /dev/null @@ -1,124 +0,0 @@ -# Deposits (ethers) - -A fast path to deposit **ETH / ERC-20** from L1 → ZKsync (L2) using the **ethers** adapter. - -## Prerequisites - -- A funded **L1** account (gas + amount). -- RPC URLs: `L1_RPC_URL`, `L2_RPC_URL`. -- Installed: `@dutterbutter/zksync-sdk` + `ethers`. - ---- - -## Parameters (quick reference) - -| Param | Required | Meaning | -| ----------------- | -------- | -------------------------------------- | -| `token` | Yes | `ETH_ADDRESS` or ERC-20 address | -| `amount` | Yes | BigInt/wei (e.g. `parseEther('0.01')`) | -| `to` | Yes | L2 recipient address | -| `l2GasLimit` | No | L2 execution gas cap | -| `gasPerPubdata` | No | Pubdata price hint | -| `operatorTip` | No | Optional tip to operator | -| `refundRecipient` | No | L2 address to receive fee refunds | - -> ERC-20 deposits may require an L1 `approve()`. **`quote()`** surfaces required steps. - ---- - -## Fast path (one-shot) - -```ts -{{#include ../../../snippets/ethers/deposit-eth.ts}} -``` - -- `create()` prepares **and** sends. -- `wait(..., { for: 'l1' })` ⇒ included on L1. -- `wait(..., { for: 'l2' })` ⇒ executed on L2 (funds available). - -## Inspect & customize (quote → prepare → create) - -**1. Quote (no side-effects)** -Preview fees/steps and whether an approve is required. - -```ts -const quote = await sdk.deposits.quote(params); -``` - -**2. Prepare (build txs, don’t send)** -Get `TransactionRequest[]` for signing/UX. - -```ts -const plan = await sdk.deposits.prepare(params); -``` - -**3. Create (send)** -Use defaults, or send your prepared txs if you customized. - -```ts -const handle = await sdk.deposits.create(params); -``` - -## Track progress (status vs wait) - -**Non-blocking snapshot** - -```ts -const s = await sdk.deposits.status(handle /* or l1TxHash */); -// 'UNKNOWN' | 'L1_PENDING' | 'L1_INCLUDED' | 'L2_PENDING' | 'L2_EXECUTED' | 'L2_FAILED' -``` - -**Block until checkpoint** - -```ts -const l1Receipt = await sdk.deposits.wait(handle, { for: 'l1' }); -const l2Receipt = await sdk.deposits.wait(handle, { for: 'l2' }); -``` - ---- - -## Error handling patterns - -**Exceptions** - -```ts -try { - const handle = await sdk.deposits.create(params); -} catch (e) { - // normalized error envelope (type, operation, message, context, revert?) -} -``` - -**No-throw style** - -Every method has a `try*` variant (e.g. `tryQuote`, `tryPrepare`, `tryCreate`). -These never throw—so you don’t need a `try/catch`. Instead they return: - -- `{ ok: true, value: ... }` on success -- `{ ok: false, error: ... }` on failure - -This is useful for **UI flows** or **services** where you want explicit control over errors. - -```ts -const r = await sdk.deposits.tryCreate(params); - -if (!r.ok) { - // handle the error gracefully - console.error('Deposit failed:', r.error); - // maybe show a toast, retry, etc. -} else { - const handle = r.value; - console.log('Deposit sent. L1 tx hash:', handle.l1TxHash); -} -``` - -## Troubleshooting - -- **Stuck at L1:** check L1 gas and RPC health. -- **No L2 execution:** verify L2 RPC; re-check `status()` (should move to `L2_EXECUTED`). -- **L2 failed:** `status.phase === 'L2_FAILED'` → inspect revert info via your error envelope/logs. - -## See also - -- [Status vs Wait](../../concepts/status-vs-wait.md) -- [ZKsync RPC Helpers](../../zks/methods.md) diff --git a/docss/src/guides/deposits/index.md b/docss/src/guides/deposits/index.md deleted file mode 100644 index ccd3f0a..0000000 --- a/docss/src/guides/deposits/index.md +++ /dev/null @@ -1 +0,0 @@ -# Deposits diff --git a/docss/src/guides/deposits/viem.md b/docss/src/guides/deposits/viem.md deleted file mode 100644 index dbb19b8..0000000 --- a/docss/src/guides/deposits/viem.md +++ /dev/null @@ -1,121 +0,0 @@ -# Deposits (viem) - -A fast path to deposit **ETH / ERC-20** from L1 → ZKsync (L2) using the **viem** adapter. - -## Prerequisites - -- A funded **L1** account (gas + amount). -- RPC URLs: `L1_RPC_URL`, `L2_RPC_URL`. -- Installed: `@dutterbutter/zksync-sdk` + `viem`. - ---- - -## Parameters (quick reference) - -| Param | Required | Meaning | -| ----------------- | -------- | -------------------------------------- | -| `token` | Yes | `ETH_ADDRESS` or ERC-20 address | -| `amount` | Yes | BigInt/wei (e.g. `parseEther('0.01')`) | -| `to` | Yes | L2 recipient address | -| `l2GasLimit` | No | L2 execution gas cap | -| `gasPerPubdata` | No | Pubdata price hint | -| `operatorTip` | No | Optional tip to operator | -| `refundRecipient` | No | L2 address to receive fee refunds | - -> ERC-20 deposits may require an L1 `approve()`. **`quote()`** surfaces required steps. - -## Fast path (one-shot) - -```ts -{{#include ../../../snippets/viem/deposit-eth.ts}} -``` - -- `create()` prepares **and** sends. -- `wait(..., { for: 'l1' })` ⇒ included on L1. -- `wait(..., { for: 'l2' })` ⇒ executed on L2 (funds available). - -## Inspect & customize (quote → prepare → create) - -**1. Quote (no side-effects)** - -Preview fees/steps and whether an approve is required. - -```ts -const quote = await sdk.deposits.quote(params); -``` - -**2. Prepare (build txs, don’t send)** -Get `TransactionRequest[]` for signing/UX. - -```ts -const plan = await sdk.deposits.prepare(params); -``` - -**3. Create (send)** -Use defaults, or send your prepared txs if you customized. - -```ts -const handle = await sdk.deposits.create(params); -``` - -## Track progress (status vs wait) - -**Non-blocking snapshot** - -```ts -const s = await sdk.deposits.status(handle /* or l1TxHash */); -// 'UNKNOWN' | 'L1_PENDING' | 'L1_INCLUDED' | 'L2_PENDING' | 'L2_EXECUTED' | 'L2_FAILED' -``` - -**Block until checkpoint** - -```ts -const l1Receipt = await sdk.deposits.wait(handle, { for: 'l1' }); -const l2Receipt = await sdk.deposits.wait(handle, { for: 'l2' }); -``` - -## Error handling patterns - -**Exceptions** - -```ts -try { - const handle = await sdk.deposits.create(params); -} catch (e) { - // normalized error envelope (type, operation, message, context, revert?) -} -``` - -**No-throw style** - -Every method has a `try*` variant (e.g. `tryQuote`, `tryPrepare`, `tryCreate`). -These never throw—so you don’t need a `try/catch`. Instead they return: - -- `{ ok: true, value: ... }` on success -- `{ ok: false, error: ... }` on failure - -This is useful for **UI flows** or **services** where you want explicit control over errors. - -```ts -const r = await sdk.deposits.tryCreate(params); - -if (!r.ok) { - // handle the error gracefully - console.error('Deposit failed:', r.error); - // maybe show a toast, retry, etc. -} else { - const handle = r.value; - console.log('Deposit sent. L1 tx hash:', handle.l1TxHash); -} -``` - -## Troubleshooting - -- **Stuck at L1:** check L1 gas and RPC health. -- **No L2 execution:** verify L2 RPC; re-check `status()` (should move to `L2_EXECUTED`). -- **L2 failed:** `status.phase === 'L2_FAILED'` → inspect revert info via your error envelope/logs. - -## See also - -- [Status vs Wait](../../concepts/status-vs-wait.md) -- [ZKsync RPC Helpers](../../zks/methods.md) diff --git a/docss/src/guides/index.md b/docss/src/guides/index.md deleted file mode 100644 index 7d51c99..0000000 --- a/docss/src/guides/index.md +++ /dev/null @@ -1,22 +0,0 @@ -# How-to Guides - -This section provides **task-focused recipes** for deposits and withdrawals with the adapter of your choice. - -Each guide shows the minimal steps to accomplish a task using the SDK, with real code you can copy, paste, and run. - -## When to use Guides - -- Use these guides if you want to **get something working quickly** (e.g., deposit ETH, withdraw ERC-20). -- If you need a deeper explanation of the SDK’s design, check [Concepts](../concepts/index.md). - -## Available Guides - -### Deposits - -- [Deposits with viem](./deposits/viem.md) -- [Deposits with ethers](./deposits/ethers.md) - -### Withdrawals - -- [Withdrawals with viem](./withdrawals/viem.md) -- [Withdrawals with ethers](./withdrawals/ethers.md) diff --git a/docss/src/guides/withdrawals/ethers.md b/docss/src/guides/withdrawals/ethers.md deleted file mode 100644 index a5832ad..0000000 --- a/docss/src/guides/withdrawals/ethers.md +++ /dev/null @@ -1,127 +0,0 @@ -# Withdrawals (ethers) - -A fast path to withdraw **ETH / ERC-20** from ZKsync (L2) → Ethereum (L1) using the **ethers** adapter. - -Withdrawals are a **two-step process**: - -1. **Initiate** on L2. -2. **Finalize** on L1 to release funds. - -## Prerequisites - -- A funded **L2** account to initiate the withdrawal. -- A funded **L1** account for finalization. -- RPC URLs: `L1_RPC_URL`, `L2_RPC_URL`. -- Installed: `@dutterbutter/zksync-sdk` + `ethers`. - ---- - -## Parameters (quick reference) - -| Param | Required | Meaning | -| ----------------- | -------- | ------------------------------------------------- | -| `token` | Yes | `ETH_ADDRESS` or ERC-20 address | -| `amount` | Yes | BigInt/wei (e.g. `parseEther('0.01')`) | -| `to` | Yes | L1 recipient address | -| `refundRecipient` | No | L2 address to receive fee refunds (if applicable) | - -## Fast path (one-shot) - -```ts -{{#include ../../../snippets/ethers/withdrawals-eth.ts}} -``` - -- `create()` prepares **and** sends the L2 withdrawal. -- `wait(..., { for: 'l2' })` ⇒ included on L2. -- `wait(..., { for: 'ready' })` ⇒ ready for finalization. -- `finalize(l2TxHash)` ⇒ required to release funds on L1. - -## Inspect & customize (quote → prepare → create) - -**1. Quote (no side-effects)** - -```ts -const quote = await sdk.withdrawals.quote(params); -``` - -**2. Prepare (build txs, don’t send)** - -```ts -const plan = await sdk.withdrawals.prepare(params); -``` - -**3. Create (send)** - -```ts -const handle = await sdk.withdrawals.create(params); -``` - -## Track progress (status vs wait) - -**Non-blocking snapshot** - -```ts -const s = await sdk.withdrawals.status(handle /* or l2TxHash */); -// 'UNKNOWN' | 'L2_PENDING' | 'PENDING' | 'READY_TO_FINALIZE' | 'FINALIZED' -``` - -**Block until checkpoint** - -```ts -const l2Receipt = await sdk.withdrawals.wait(handle, { for: 'l2' }); -await sdk.withdrawals.wait(handle, { for: 'ready' }); -``` - -## Finalization (required step) - -```ts -const result = await sdk.withdrawals.finalize(handle.l2TxHash); -console.log('Finalization result:', result); -``` - -## Error handling patterns - -**Exceptions** - -```ts -try { - const handle = await sdk.withdrawals.create(params); -} catch (e) { - // normalized error envelope (type, operation, message, context, optional revert) -} -``` - -**No-throw style** - -Use `try*` methods to avoid exceptions. They return `{ ok, value }` or `{ ok, error }`. -Perfect for UIs or services that prefer explicit flow control. - -```ts -const r = await sdk.withdrawals.tryCreate(params); - -if (!r.ok) { - console.error('Withdrawal failed:', r.error); -} else { - const handle = r.value; - const f = await sdk.withdrawals.tryFinalize(handle.l2TxHash); - if (!f.ok) { - console.error('Finalize failed:', f.error); - } else { - console.log('Withdrawal finalized on L1:', f.value.receipt?.transactionHash); - } -} -``` - -## Troubleshooting - -- **Never reaches READY_TO_FINALIZE:** proofs may not be available yet. -- **Finalize reverts:** ensure enough L1 gas; inspect revert info. -- **Finalized but no receipt:** `wait(..., { for: 'finalized' })` may return `null`; retry or rely on `finalize()` result. - ---- - -## See also - -- [Status vs Wait](../../concepts/status-vs-wait.md) -- [Finalization](../../concepts/finalization.md) -- [ZKsync RPC Helpers](../../zks/methods.md) diff --git a/docss/src/guides/withdrawals/index.md b/docss/src/guides/withdrawals/index.md deleted file mode 100644 index f0bfe8a..0000000 --- a/docss/src/guides/withdrawals/index.md +++ /dev/null @@ -1 +0,0 @@ -# Withdrawals diff --git a/docss/src/guides/withdrawals/viem.md b/docss/src/guides/withdrawals/viem.md deleted file mode 100644 index 3324a3a..0000000 --- a/docss/src/guides/withdrawals/viem.md +++ /dev/null @@ -1,138 +0,0 @@ -# Withdrawals (viem) - -A fast path to withdraw **ETH / ERC-20** from ZKsync (L2) → Ethereum (L1) using the **viem** adapter. - -Withdrawals are a **two-step process**: - -1. **Initiate** on L2. -2. **Finalize** on L1 to release funds. - -## Prerequisites - -- A funded **L2** account to initiate the withdrawal. -- A funded **L1** account for finalization. -- RPC URLs: `L1_RPC_URL`, `L2_RPC_URL`. -- Installed: `@dutterbutter/zksync-sdk` + `viem`. - ---- - -## Parameters (quick reference) - -| Param | Required | Meaning | -| ----------------- | -------- | ------------------------------------------------- | -| `token` | Yes | `ETH_ADDRESS` or ERC-20 address | -| `amount` | Yes | BigInt/wei (e.g. `parseEther('0.01')`) | -| `to` | Yes | L1 recipient address | -| `refundRecipient` | No | L2 address to receive fee refunds (if applicable) | - -## Fast path (one-shot) - -```ts -{{#include ../../../snippets/viem/withdrawals-eth.ts}} -``` - -- `create()` prepares **and** sends the L2 withdrawal. -- `wait(..., { for: 'l2' })` ⇒ included on L2. -- `wait(..., { for: 'ready' })` ⇒ ready for finalization. -- `finalize(l2TxHash)` ⇒ required to release funds on L1. - -## Inspect & customize (quote → prepare → create) - -**1. Quote (no side-effects)** - -Preview fees/steps and whether extra approvals are required. - -```ts -const quote = await sdk.withdrawals.quote(params); -``` - -**2. Prepare (build txs, don’t send)** - -Get `TransactionRequest[]` for signing/UX. - -```ts -const plan = await sdk.withdrawals.prepare(params); -``` - -**3. Create (send)** - -Use defaults, or send your prepared txs if you customized. - -```ts -const handle = await sdk.withdrawals.create(params); -``` - -## Track progress (status vs wait) - -**Non-blocking snapshot** - -```ts -const s = await sdk.withdrawals.status(handle /* or l2TxHash */); -// 'UNKNOWN' | 'L2_PENDING' | 'PENDING' | 'READY_TO_FINALIZE' | 'FINALIZED' -``` - -**Block until checkpoint** - -```ts -const l2Receipt = await sdk.withdrawals.wait(handle, { for: 'l2' }); -await sdk.withdrawals.wait(handle, { for: 'ready' }); // becomes finalizable -``` - -## Finalization (required step) - -To actually release funds on L1, call `finalize`. Note -the transaction needs to be ready for finalization. - -```ts -const result = await sdk.withdrawals.finalize(handle.l2TxHash); -console.log('Finalization status:', result.status.phase); -``` - -## Error handling patterns - -**Exceptions** - -```ts -try { - const handle = await sdk.withdrawals.create(params); -} catch (e) { - // normalized error envelope (type, operation, message, context, optional revert) -} -``` - -**No-throw style** - -Every method has a `try*` variant (e.g. `tryQuote`, `tryPrepare`, `tryCreate`, `tryFinalize`). -These never throw—so you don’t need `try/catch`. Instead they return: - -- `{ ok: true, value: ... }` on success -- `{ ok: false, error: ... }` on failure - -This is useful for **UI flows** or **services** where you want explicit control over errors. - -```ts -const r = await sdk.withdrawals.tryCreate(params); - -if (!r.ok) { - console.error('Withdrawal failed:', r.error); -} else { - const handle = r.value; - const f = await sdk.withdrawals.tryFinalize(handle.l2TxHash); - if (!f.ok) { - console.error('Finalize failed:', f.error); - } else { - console.log('Withdrawal finalized on L1:', f.value.receipt?.transactionHash); - } -} -``` - -## Troubleshooting - -- **Never reaches READY_TO_FINALIZE:** proofs may not be available yet; poll `status()` or `wait(..., { for: 'ready' })`. -- **Finalize fails:** ensure you have L1 gas and check revert info in the error envelope. - -## See also - -- [Status vs Wait](../../concepts/status-vs-wait.md) -- [Finalization](../../concepts/finalization.md) -- [ZKsync RPC Helpers](../../zks/methods.md) diff --git a/docss/src/index.md b/docss/src/index.md deleted file mode 100644 index 6a4b980..0000000 --- a/docss/src/index.md +++ /dev/null @@ -1,6 +0,0 @@ -# ZKsync SDK - -Welcome! Use the sidebar for API reference. - -- **Core**: encoding, attributes, bundle builders. -- **Ethers**: high-level send helpers. diff --git a/docss/src/overview/adapters.md b/docss/src/overview/adapters.md deleted file mode 100644 index 30c24fd..0000000 --- a/docss/src/overview/adapters.md +++ /dev/null @@ -1,88 +0,0 @@ -# Adapters: `viem` & `ethers` - -The SDK is designed to work _with_ the tools you already know and love. It's not a standalone library, but rather an extension that plugs into your existing `viem` or `ethers.js` setup. - -Think of it like a power adapter 🔌. You have your device (`viem` or `ethers` client), and this SDK adapts it to work seamlessly with zkSync's unique features. You bring your own client, and the SDK enhances it. - -## Why an Adapter Model? - -This approach offers several key advantages: - -- ✅ **Bring Your Own Stack:** You don't have to replace your existing setup. The SDK integrates directly with the `viem` clients (`PublicClient`, `WalletClient`) or `ethers` providers and signers you're already using. -- 📚 **Familiar Developer Experience (DX):** You continue to handle connections, accounts, and signing just as you always have. -- 🧩 **Lightweight & Focused:** The SDK remains small and focused on one thing: providing a robust API for ZKsync-specific actions like deposits and withdrawals. - -## Installation - -First, install the core SDK, then add the adapter that matches your project's stack. - -```bash -# For viem users -npm install @dutterbutter/zksync-sdk viem - -# For ethers.js users -npm install @dutterbutter/zksync-sdk ethers -``` - -## How to Use - -The SDK extends your existing client. Configure **viem** or **ethers** as you normally would, then pass them into the adapter’s client factory and create the SDK surface. - -### viem (public + wallet client) - -```ts -import { createPublicClient, createWalletClient, http, parseEther } from 'viem'; -import { privateKeyToAccount } from 'viem/accounts'; -import { createViemClient, createViemSdk } from '@dutterbutter/zksync-sdk/viem'; -import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; - -const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`); - -const l1 = createPublicClient({ transport: http(process.env.L1_RPC!) }); -const l2 = createPublicClient({ transport: http(process.env.L2_RPC!) }); -const l1Wallet = createWalletClient({ account, transport: http(process.env.L1_RPC!) }); - -const client = createViemClient({ l1, l2, l1Wallet }); -const sdk = createViemSdk(client); - -const params = { - amount: parseEther('0.01'), - to: account.address, - token: ETH_ADDRESS, -} as const; - -const handle = await sdk.deposits.create(params); -await sdk.deposits.wait(handle, { for: 'l2' }); // funds available on L2 -``` - -### ethers (providers + signer) - -```ts -import { JsonRpcProvider, Wallet, parseEther } from 'ethers'; -import { createEthersClient, createEthersSdk } from '@dutterbutter/zksync-sdk/ethers'; -import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; - -const l1 = new JsonRpcProvider(process.env.L1_RPC!); -const l2 = new JsonRpcProvider(process.env.L2_RPC!); -const signer = new Wallet(process.env.PRIVATE_KEY!, l1); - -const client = await createEthersClient({ l1, l2, signer }); -const sdk = createEthersSdk(client); - -const params = { - amount: parseEther('0.01'), - to: await signer.getAddress(), - token: ETH_ADDRESS, -} as const; - -const handle = await sdk.deposits.create(params); -await sdk.deposits.wait(handle, { for: 'l2' }); // funds available on L2 -``` - ---- - -## Key Principles - -- **No Key Management:** The SDK never asks for or stores private keys. All signing operations are delegated to the `viem` `WalletClient` or `ethers` `Signer` you provide. -- **API Parity:** Both adapters expose the exact same API. The code you write to call `client.deposits.quote()` is identical whether you're using `viem` or `ethers`. -- **Easy Migration:** Because the API is the same, switching your project from `ethers` to `viem` (or vice versa) is incredibly simple. You only need to change the initialization code. diff --git a/docss/src/overview/index.md b/docss/src/overview/index.md deleted file mode 100644 index 2af46b8..0000000 --- a/docss/src/overview/index.md +++ /dev/null @@ -1,20 +0,0 @@ -# Overview - -The `@zksync-sdk` is a lightweight extension for `viem` and `ethers` that makes ZKsync cross-chain actions simple and consistent. - -Instead of re-implementing accounts or RPC logic, this SDK focuses only on **ZKsync-specific flows**: - -- Deposits (L1 → L2) -- Withdrawals (L2 → L1, with finalization) -- Status & wait helpers -- ZKsync specific JSON-RPC methods - -## What you’ll find here - -- [**What this SDK does**](./what-it-does.md) — the purpose, scope, and non-goals. -- [**Mental model**](./mental-model.md) — how to think about the core methods (`quote → prepare → create → status → wait → finalize`). -- [**Adapters (viem & ethers)**](./adapters.md) — how the SDK integrates with your existing stack. - -## Next steps - -👉 If you want to get hands-on right away, jump to the [Quickstart](../quickstart/index.md). diff --git a/docss/src/overview/mental-model.md b/docss/src/overview/mental-model.md deleted file mode 100644 index 1b9426c..0000000 --- a/docss/src/overview/mental-model.md +++ /dev/null @@ -1,121 +0,0 @@ -# Mental Model - -The SDK is designed around a predictable and layered API for handling L1-L2, and L2-L1 operations. Every action, whether it's a deposit or a withdrawal, follows a consistent lifecycle. Understanding this lifecycle is key to using the SDK effectively. - -The complete lifecycle for any action is: - -```bash -quote → prepare → create → status → wait → (finalize*) -``` - -- The first five steps are common to both **Deposits** and **Withdrawals**. -- Withdrawals require an additional **`finalize`** step to prove and claim the funds on L1. - -You can enter this lifecycle at different stages depending on how much control you need. - -## The Core API: A Layered Approach - -The core methods are designed to give you progressively more automation. You can start by just getting information (`quote`), move to building transactions without sending them (`prepare`), or execute the entire flow with a single call (`create`). - -### `quote(params)` - -_"What will this operation involve and cost?"_ - -This is a **read-only** dry run. It performs no transactions and has no side effects. It inspects the parameters and returns a `Quote` object containing the estimated fees, gas costs, and the steps the SDK will take to complete the action. - -➡️ **Best for:** Displaying a confirmation screen to a user with a cost estimate before they commit. - -### `prepare(params)` - -_"Build the transactions for me, but let me send them."_ - -This method constructs all the necessary transactions for the operation and returns them as an array of `TransactionRequest` objects in a `Plan`. It does **not** sign or send them. This gives you full control over the final execution. - -➡️ **Best for:** Custom workflows where you need to inspect transactions before signing, use a unique signing method, or submit them through a separate system (like a multisig). - -### `create(params)` - -_"Prepare, sign, and send in one go."_ - -This is the most common entry point for a one-shot operation. It internally calls `prepare`, then uses your configured signer to sign and dispatch the transactions. It returns a `Handle` object, which is a lightweight tracker containing the transaction hash(es) needed for the next steps. - -➡️ **Best for:** Most standard use cases where you simply want to initiate the deposit or withdrawal. - -### `status(handle | txHash)` - -_"Where is my transaction right now?"_ - -This is a **non-blocking** check to get the current state of an operation. It takes a `Handle` from the `create` method or a transaction hash and returns a structured status object, such as: - -- **Deposits:** `{ phase: 'L1_PENDING' | 'L2_EXECUTED' }` -- **Withdrawals:** `{ phase: 'L1_INCLUDED','L2_PENDING' | 'READY_TO_FINALIZE' | 'FINALIZED' }` - -➡️ **Best for:** Polling in a UI to show a user the live progress of their transaction without blocking the interface. - -### `wait(handle, { for })` - -_"Pause until a specific checkpoint is reached."_ - -This is a **blocking** (asynchronous) method that polls for you. It pauses execution until the operation reaches a desired checkpoint and then resolves with the relevant transaction receipt. - -- **Deposits:** Wait for L1 inclusion (`'l1'`) or L2 execution (`'l2'`). -- **Withdrawals:** Wait for L2 inclusion (`'l2'`), finalization availability (`'ready'`), or final L1 finalization (`'finalized'`). - -➡️ **Best for:** Scripts or backend processes where you need to ensure one step is complete before starting the next. - -### `finalize(l2TxHash)` - -_(Withdrawals Only)_ - -_"My funds are ready on L1. Finalize and release them."_ - -This method executes the final step of a withdrawal. After `status` reports `READY_TO_FINALIZE`, you call this method with the L2 transaction hash to submit the finalization transaction on L1, which releases the funds to the recipient. - -➡️ **Best for:** The final step of any withdrawal flow. - -## Error Handling: The `try*` Philosophy - -For more robust error handling without `try/catch` blocks, **every core method has a `try*` variant** (e.g., `tryQuote`, `tryCreate`). - -Instead of throwing an error on failure, these methods return a result object that enforces explicit error handling: - -```ts -// Instead of this: -try { - const handle = await sdk.withdrawals.create(params); - // ... happy path -} catch (error) { - // ... sad path -} - -// You can do this: -const result = await sdk.withdrawals.tryCreate(params); - -if (result.ok) { - // Safe to use result.value, which is the WithdrawHandle - const handle = result.value; -} else { - // Handle the error explicitly - console.error('Withdrawal failed:', result.error); -} -``` - -➡️ **Best for:** Applications that prefer a functional error-handling pattern and want to avoid uncaught exceptions. - -## Putting It All Together - -These primitives allow you to compose flows that are as simple or as complex as you need. - -#### Simple Flow - -Use `create` and `wait` for the most straightforward path. - -```ts -// 1. Create the deposit -const depositHandle = await sdk.deposits.create(params); - -// 2. Wait for it to be finalized on L2 -const receipt = await sdk.deposits.wait(depositHandle, { for: 'l2' }); - -console.log('Deposit complete!'); -``` diff --git a/docss/src/overview/what-it-does.md b/docss/src/overview/what-it-does.md deleted file mode 100644 index d937396..0000000 --- a/docss/src/overview/what-it-does.md +++ /dev/null @@ -1,47 +0,0 @@ -# What this SDK Does - -The `@zksync-sdk` is a lightweight, powerful extension for the popular `ethers.js` and `viem` libraries. Its purpose is to simplify the development of applications on ZKsync by providing straightforward access to ZKsync-specific features that are not natively available in the core Ethereum SDKs. - -Think of it as a specialized toolkit that sits on top of the tools you already know and love, enabling you to seamlessly interact with both L1 and L2 functionalities of the Elastic Network. - -## Audience - -This SDK is designed for **Web3 developers, dApp builders, and infrastructure engineers** who are building applications on or interacting with the Elastic Network. If you're comfortable with `ethers.js` or `viem` and need to implement ZKsync-specific actions, this library is for you. - -## Scope - -The SDK currently supports ZKsync specific actions, primarily L1-L2, and L2-L1 transactions. - -### Key Supported Features - -- **Deposits (L1 → L2)** — ETH and ERC-20 - - **Initiate on L1:** build and send the deposit transaction from Ethereum. - - **Track progress:** query intermediate states (queued, included, executed). - - **Verify completion on L2:** confirm funds credited/available on ZKsync (L2). - -- **Withdrawals (L2 → L1)** — ETH and ERC-20 - - **Initiate on L2:** create the withdrawal transaction on ZKsync (L2). - - **Track progress:** monitor execution and finalization availability. - - **Finalize on L1:** Finalize withdrawal to release funds (L1). - -- **ZKsync RPC** - - **`getBridgehubAddress`** (`zks_getBridgehubContract`) - Resolve the canonical Bridgehub contract address. - - **`getL2ToL1LogProof`** (`zks_getL2ToL1LogProof`) - Retrieves the log proof for an L2 to L1 transaction. - - **`getReceiptWithL2ToL1`** _(receipt extension)_ - Returns an Ethereum `TransactionReceipt` **augmented** with `l2ToL1Logs`. - -## Non-Goals - -To maintain its focus and lightweight nature, this SDK explicitly avoids duplicating functionality that is already well-handled by `ethers.js`, `viem`, or other dedicated libraries. - -The following are **out of scope**: - -- **Wallet Management & Signing:** The SDK does not manage private keys, mnemonics, or other sensitive credentials. It expects a pre-configured Signer or Wallet Client from `ethers` or `viem`. Key storage and transaction signing are delegated to these underlying libraries. -- **Generic Ethereum Interactions:** Standard Ethereum transactions, contract calls, or RPC methods that are not specific to ZKsync should be handled directly by `ethers` or `viem`. - ---- - -ℹ️ Runtime compatibility follows the adapter you choose (`viem` or `ethers`). -See their docs for environment support. diff --git a/docss/src/quickstart/choose-adapter.md b/docss/src/quickstart/choose-adapter.md deleted file mode 100644 index bc3f191..0000000 --- a/docss/src/quickstart/choose-adapter.md +++ /dev/null @@ -1,68 +0,0 @@ -# Choosing Your Adapter: `viem` vs. `ethers` - -The SDK is designed to work with both `viem` and `ethers.js`, the two most popular Ethereum libraries. Since the SDK offers **identical functionality** for both, the choice comes down to your project's needs and your personal preference. - -## The Short Answer (TL;DR) - -- **If you're adding the SDK to an existing project:** Use the adapter for the library you're already using. -- **If you're starting a new project:** The choice is yours. `viem` is generally recommended for new projects due to its modern design, smaller bundle size, and excellent TypeScript support. - -You can't make a wrong choice. Both adapters are fully supported and provide the same features. - -## Code Comparison - -The only difference in your code is the initial setup. **All subsequent SDK calls are identical.** - -#### viem - -```ts -import { createPublicClient, createWalletClient, http } from 'viem'; -import { privateKeyToAccount } from 'viem/accounts'; -import { createViemClient, createViemSdk } from '@dutterbutter/zksync-sdk/viem'; - -const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`); - -const l1 = createPublicClient({ transport: http(process.env.L1_RPC!) }); -const l2 = createPublicClient({ transport: http(process.env.L2_RPC!) }); -const l1Wallet = createWalletClient({ account, transport: http(process.env.L1_RPC!) }); - -const client = createViemClient({ l1, l2, l1Wallet }); -const sdk = createViemSdk(client); -``` - -#### ethers - -```ts -import { JsonRpcProvider, Wallet } from 'ethers'; -import { createEthersClient, createEthersSdk } from '@dutterbutter/zksync-sdk/ethers'; - -const l1 = new JsonRpcProvider(process.env.L1_RPC!); -const l2 = new JsonRpcProvider(process.env.L2_RPC!); -const signer = new Wallet(process.env.PRIVATE_KEY!, l1); - -const client = await createEthersClient({ l1, l2, signer }); -const sdk = createEthersSdk(client); -``` - -### Identical SDK Usage - -Once the adapter is set up, **your application logic is the same**: - -```ts -const quote = await sdk.deposits.quote({ - token: ETH_ADDRESS, - amount: parseEther('0.1'), - to: '0xYourAddress', -}); - -console.log('Total fee:', quote.totalFee.toString()); -``` - -## Conclusion - -The adapter model is designed to give you flexibility without adding complexity. Your choice of adapter is a low-stakes decision that's easy to change later. - -**Ready to start building?** 🚀 - -- [**Go to Quickstart (viem)**](./viem.md) -- [**Go to Quickstart (ethers)**](./ethers.md) diff --git a/docss/src/quickstart/ethers.md b/docss/src/quickstart/ethers.md deleted file mode 100644 index 4fce499..0000000 --- a/docss/src/quickstart/ethers.md +++ /dev/null @@ -1,146 +0,0 @@ -# Quickstart (ethers): ETH Deposit (L1 → L2) - -This guide will get you from zero to a working **ETH deposit from Ethereum to ZKsync (L2)** in minutes using the **ethers** adapter. 🚀 - -You'll set up your environment, write a short script to make a deposit, and run it. - -## 1. Prerequisites - -- You have [Bun](https://bun.sh/) installed. -- You have an L1 wallet (e.g., Sepolia testnet) funded with some ETH to pay for gas and the deposit. - -## 2. Installation & Setup - -First, install the necessary packages. - -```bash -bun install @dutterbutter/zksync-sdk ethers dotenv -``` - -Next, create a `.env` file in your project's root directory to store your private key and RPC endpoints. **Never commit this file to Git.** - -**`.env` file:** - -```env -# Your funded L1 wallet private key (e.g., from MetaMask) -PRIVATE_KEY=0xYOUR_PRIVATE_KEY_HERE - -# RPC endpoints -L1_RPC_URL=https://sepolia.infura.io/v3/YOUR_INFURA_ID -L2_RPC_URL="ZKSYNC-OS-TESTNET-RPC" -``` - -## 3. The Deposit Script - -The following script will connect to the networks, create a deposit transaction, send it, and wait for it to be confirmed on both L1 and L2. - -Save this code as `deposit-ethers.ts`: - -```ts -import 'dotenv/config'; // Load environment variables from .env -import { JsonRpcProvider, Wallet, parseEther } from 'ethers'; -import { createEthersClient } from '@dutterbutter/zksync-sdk/ethers'; -import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; - -const PRIVATE_KEY = process.env.PRIVATE_KEY; -const L1_RPC_URL = process.env.L1_RPC_URL; -const L2_RPC_URL = process.env.L2_RPC_URL; - -async function main() { - if (!PRIVATE_KEY || !L1_RPC_URL || !L2_RPC_URL) { - throw new Error('Please set your PRIVATE_KEY, L1_RPC_URL, and L2_RPC_URL in a .env file'); - } - - // 1. SET UP PROVIDERS AND SIGNER - // The SDK needs connections to both L1 and L2 to function. - const l1Provider = new JsonRpcProvider(L1_RPC_URL); - const l2Provider = new JsonRpcProvider(L2_RPC_URL); - const signer = new Wallet(PRIVATE_KEY, l1Provider); - - // 2. INITIALIZE THE SDK CLIENT - // The client is the low-level interface for interacting with the API. - const client = await createEthersClient({ - l1Provider, - l2Provider, - signer, - }); - - const L1balance = await l1.getBalance({ address: signer.address }); - const L2balance = await l2.getBalance({ address: signer.address }); - - console.log('Wallet balance on L1:', L1balance); - console.log('Wallet balance on L2:', L2balance); - - // 3. PERFORM THE DEPOSIT - // The create() method prepares and sends the transaction. - // The wait() method polls until the transaction is complete. - console.log('Sending deposit transaction...'); - const depositHandle = await sdk.deposits.create({ - token: ETH_ADDRESS, - amount: parseEther('0.001'), // 0.001 ETH - to: account.address, - }); - - console.log(`L1 transaction hash: ${depositHandle.l1TxHash}`); - console.log('Waiting for the deposit to be confirmed on L1...'); - - // Wait for L1 inclusion - const l1Receipt = await sdk.deposits.wait(depositHandle, { for: 'l1' }); - console.log(`Deposit confirmed on L1 in block ${l1Receipt?.blockNumber}`); - - console.log('Waiting for the deposit to be executed on L2...'); - - // Wait for L2 execution - const l2Receipt = await sdk.deposits.wait(depositHandle, { for: 'l2' }); - console.log(`Deposit executed on L2 in block ${l2Receipt?.blockNumber}`); - console.log('Deposit complete! ✅'); - - const L1balanceAfter = await l1.getBalance({ address: signer.address }); - const L2balanceAfter = await l2.getBalance({ address: signer.address }); - - console.log('Wallet balance on L1 after:', L1balanceAfter); - console.log('Wallet balance on L2 after:', L2balanceAfter); - - /* - // OPTIONAL: ADVANCED CONTROL - // The SDK also lets you inspect a transaction before sending it. - // This follows the Mental Model: quote -> prepare -> create. - // Uncomment the code below to see it in action. - - const params = { - token: ETH_ADDRESS, - amount: parseEther('0.001'), - to: account.address, - }; - - // Get a quote for the fees - const quote = await sdk.deposits.quote(params); - console.log('Fee quote:', quote); - - // Prepare the transaction without sending - const plan = await sdk.deposits.prepare(params); - console.log('Transaction plan:', plan); - */ -} - -main().catch((error) => { - console.error('An error occurred:', error); - process.exit(1); -}); -``` - -## 4. Run the Script - -Execute the script using `bun`. - -```bash -bun run deposit-ethers.ts -``` - -You should see output confirming the L1 transaction, the wait periods, and finally the successful L2 verification. - -## 5. Troubleshooting - -- **Insufficient funds on L1:** Make sure your wallet has enough ETH on L1 to cover both the deposit amount (`0.001` ETH) and the L1 gas fees. -- **Invalid `PRIVATE_KEY`:** Ensure it’s a 64-character hex string, prefixed with `0x`. -- **Stuck waiting for L2:** This can take a few minutes. If it takes too long, check that your `L2_RPC_URL` is correct and the network is operational. diff --git a/docss/src/quickstart/index.md b/docss/src/quickstart/index.md deleted file mode 100644 index 49db31b..0000000 --- a/docss/src/quickstart/index.md +++ /dev/null @@ -1,22 +0,0 @@ -# Quickstart - -The Quickstart guides help you get your first ZKsync deposit action running in minutes. -You’ll learn how to install the SDK, connect a client, and perform a deposit. - -## Choose your adapter - -This SDK extends existing Ethereum libraries. Pick the Quickstart that matches your stack: - -- [Quickstart (viem)](viem.md) — for projects already using **viem**. -- [Quickstart (ethers)](ethers.md) — for projects using **ethers v6**. - -## What you’ll do - -Each Quickstart walks you through: - -1. **Install** the adapter package. -2. **Configure** a client or signer. -3. **Run** a deposit (L1 → L2) as a working example. -4. **Track** the status until it’s complete. - -👉 Once you’re set up, continue to the [How-to Guides](../guides/index.md) for more detailed usage. diff --git a/docss/src/quickstart/viem.md b/docss/src/quickstart/viem.md deleted file mode 100644 index 3276dea..0000000 --- a/docss/src/quickstart/viem.md +++ /dev/null @@ -1,144 +0,0 @@ -# Quickstart (viem): ETH Deposit (L1 → L2) - -This guide gets you to a working **ETH deposit from Ethereum to ZKsync (L2)** using the **viem** adapter. - -You’ll set up your environment, write a short script, and run it. - -## 1. Prerequisites - -- You have [Bun](https://bun.sh/) (or Node + tsx) installed. -- You have an **L1 wallet** funded with ETH to cover the deposit amount **and** L1 gas. - -## 2. Installation & Setup - -Install packages: - -```bash -bun install @dutterbutter/zksync-sdk viem dotenv -# or: npm i @dutterbutter/zksync-sdk viem dotenv -``` - -Create an `.env` in your project root (never commit this): - -```env -# Your funded L1 private key (0x + 64 hex) -PRIVATE_KEY=0xYOUR_PRIVATE_KEY_HERE - -# RPC endpoints -L1_RPC_URL=https://sepolia.infura.io/v3/YOUR_INFURA_ID -L2_RPC_URL=ZKSYNC-OS-TESTNET-RPC -``` - -## 3. The Deposit Script - -Save as `deposit-viem.ts`: - -```ts -import 'dotenv/config'; // Load environment variables from .env -import { createPublicClient, createWalletClient, http, parseEther } from 'viem'; -import { privateKeyToAccount } from 'viem/accounts'; -import { createViemClient, createViemSdk } from '@dutterbutter/zksync-sdk/viem'; -import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; - -const PRIVATE_KEY = process.env.PRIVATE_KEY; -const L1_RPC_URL = process.env.L1_RPC_URL; -const L2_RPC_URL = process.env.L2_RPC_URL; - -async function main() { - if (!PRIVATE_KEY || !L1_RPC_URL || !L2_RPC_URL) { - throw new Error('Please set your PRIVATE_KEY, L1_RPC_URL, and L2_RPC_URL in a .env file'); - } - - // 1. SET UP CLIENTS AND ACCOUNT - // The SDK needs connections to both L1 and L2 to function. - const account = privateKeyToAccount(PRIVATE_KEY as `0x${string}`); - - const l1 = createPublicClient({ transport: http(L1_RPC_URL) }); - const l2 = createPublicClient({ transport: http(L2_RPC_URL) }); - const l1Wallet = createWalletClient({ account, transport: http(L1_RPC_URL) }); - - // 2. INITIALIZE THE SDK CLIENT - // The client bundles your viem clients; the SDK surface exposes deposits/withdrawals helpers. - const client = createViemClient({ l1, l2, l1Wallet }); - const sdk = createViemSdk(client); - - const L1balance = await l1.getBalance({ address: account.address }); - const L2balance = await l2.getBalance({ address: account.address }); - - console.log('Wallet balance on L1:', L1balance); - console.log('Wallet balance on L2:', L2balance); - - // 3. PERFORM THE DEPOSIT - // The create() method prepares and sends the transaction. - // The wait() method polls until the transaction is complete. - console.log('Sending deposit transaction...'); - const depositHandle = await sdk.deposits.create({ - token: ETH_ADDRESS, - amount: parseEther('0.001'), // 0.001 ETH - to: account.address, - }); - - console.log(`L1 transaction hash: ${depositHandle.l1TxHash}`); - console.log('Waiting for the deposit to be confirmed on L1...'); - - // Wait for L1 inclusion - const l1Receipt = await sdk.deposits.wait(depositHandle, { for: 'l1' }); - console.log(`Deposit confirmed on L1 in block ${l1Receipt?.blockNumber}`); - - console.log('Waiting for the deposit to be executed on L2...'); - - // Wait for L2 execution - const l2Receipt = await sdk.deposits.wait(depositHandle, { for: 'l2' }); - console.log(`Deposit executed on L2 in block ${l2Receipt?.blockNumber}`); - console.log('Deposit complete! ✅'); - - const L1balanceAfter = await l1.getBalance({ address: account.address }); - const L2balanceAfter = await l2.getBalance({ address: account.address }); - - console.log('Wallet balance on L1 after:', L1balanceAfter); - console.log('Wallet balance on L2 after:', L2balanceAfter); - - /* - // OPTIONAL: ADVANCED CONTROL - // The SDK also lets you inspect a transaction before sending it. - // This follows the Mental Model: quote -> prepare -> create. - // Uncomment the code below to see it in action. - - const params = { - token: ETH_ADDRESS, - amount: parseEther('0.001'), - to: account.address, - }; - - // Get a quote for the fees - const quote = await sdk.deposits.quote(params); - console.log('Fee quote:', quote); - - // Prepare the transaction without sending - const plan = await sdk.deposits.prepare(params); - console.log('Transaction plan:', plan); - */ -} - -main().catch((error) => { - console.error('An error occurred:', error); - process.exit(1); -}); -``` - -## 4. Run the Script - -```bash -bun run deposit-viem.ts -# or with tsx: -# npx tsx deposit-viem.ts -``` - -You’ll see logs for the L1 transaction, then L2 execution, and a final status snapshot. - -## 5. Troubleshooting - -- **Insufficient funds on L1:** Ensure enough ETH for the deposit **and** L1 gas. -- **Invalid `PRIVATE_KEY`:** Must be `0x` + 64 hex chars. -- **Stuck at `wait(..., { for: 'l2' })`:** Verify `L2_RPC_URL` and network health; check `sdk.deposits.status(handle)` to see the current phase. -- **ERC-20 deposits:** May require an L1 `approve()`; `quote()` will surface required steps. diff --git a/docss/src/reference/helpers.md b/docss/src/reference/helpers.md deleted file mode 100644 index 0825271..0000000 --- a/docss/src/reference/helpers.md +++ /dev/null @@ -1,77 +0,0 @@ -# Common Helpers - -Convenience APIs for **addresses, contracts, and token mapping**. -Available under `sdk.helpers` (`ethers` and `viem` adapter). - -## Addresses - -```ts -const addresses = await sdk.helpers.addresses(); -console.log(addresses.bridgehub); -``` - -Resolves and caches core contract addresses (Bridgehub, routers, vaults, core contracts). -Call `client.refresh()` to clear the cache if networks/overrides change. - -## Contracts - -```ts -const contracts = await sdk.helpers.contracts(); -console.log(await contracts.l1AssetRouter.paused()); -``` - -Returns connected `ethers.Contract` instances (`viem` equivalents) for all core contracts. -You can also call individual shortcuts: - -```ts -const router = await sdk.helpers.l1AssetRouter(); -const vault = await sdk.helpers.l1NativeTokenVault(); -const nullifier = await sdk.helpers.l1Nullifier(); -``` - -## Base Token - -```ts -const base = await sdk.helpers.baseToken(); -const baseOther = await sdk.helpers.baseToken(BigInt(300)); -``` - -Reads the **base token** for the current L2 network, or a specific chain id. - -## Token Mapping - -**L1 → L2** - -```ts -import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; - -const l2Eth = await sdk.helpers.l2TokenAddress(ETH_ADDRESS); -const l2Usdc = await sdk.helpers.l2TokenAddress('0x...'); -``` - -- ETH maps to the special ETH placeholder on L2. -- If the L1 token is the base token, you get the L2 base-token system address. - -**L2 → L1** - -```ts -const l1Token = await sdk.helpers.l1TokenAddress('0x...L2Token'); -``` - -Maps an L2 token back to its L1 token. - -## Asset ID - -```ts -import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; - -const ethId = await sdk.helpers.assetId(ETH_ADDRESS); -const tokenId = await sdk.helpers.assetId('0x...'); -``` - -Fetches the **assetId (bytes32)** for a token. -ETH is handled automatically. - -## Behavior & Notes - -- **Caching:** `addresses()` and `contracts()` results are cached; use `client.refresh()` to reset. diff --git a/docss/src/reference/index.md b/docss/src/reference/index.md deleted file mode 100644 index 3608e3a..0000000 --- a/docss/src/reference/index.md +++ /dev/null @@ -1,19 +0,0 @@ -# Reference - -This section documents the **low-level APIs** exposed by the SDK. -Unlike the high-level flows (`deposits`, `withdrawals`), these helpers give you direct access to ZKsync-specific contracts and RPC methods. - -## What you’ll find here - -- **ZKsync RPC Helpers** - A typed interface around ZKsync `zks_` JSON-RPC methods such as: - - `getBridgehubAddress()` - - `getL2ToL1LogProof()` - - `getReceiptWithL2ToL1()` - -- **Common Helpers** - Utility getters for frequently used contracts and addresses, such as: - - `l1AssetRouter()`, `l1Nullifier()`, `l1NativeTokenVault()` - - `baseToken(chainId)` - - `l1TokenAddress(l2Token)`, `l2TokenAddress(l1Token)` - - `assetId(l1Token)` diff --git a/docss/src/reference/methods.md b/docss/src/reference/methods.md deleted file mode 100644 index 79220c8..0000000 --- a/docss/src/reference/methods.md +++ /dev/null @@ -1,84 +0,0 @@ -# ZKsync `zks_` RPC Helpers - -These helpers expose ZKsync-specific RPC methods through the SDK’s client. -They work the same whether you’re using the **viem** or **ethers** adapter. - -> In all examples below, assume you’ve already created a `client` (via `createViemClient` or `createEthersClient`). -> Calls are identical across adapters: `client.zks.*`. - ---- - -## `getBridgehubAddress()` - -**What it does** -Returns the canonical **Bridgehub** contract address. - -**Example** - -```ts -const bridgehub = await client.zks.getBridgehubAddress(); -console.log('Bridgehub:', bridgehub); // 0x... -``` - -**Returns** -`Address` (EVM address string, `0x…`) - -## `getReceiptWithL2ToL1(txHash)` - -**What it does** -Fetches the transaction receipt for an **L2** tx and includes `l2ToL1Logs` as an array. -This makes it easy to locate L2→L1 messages without guessing the shape. - -**Example** - -```ts -const l2TxHash = '0x...'; // L2 transaction hash -const receipt = await client.zks.getReceiptWithL2ToL1(l2TxHash); - -if (!receipt) { - console.log('Receipt not found yet'); -} else { - console.log('l2ToL1Logs count:', receipt.l2ToL1Logs.length); - // e.g. find the first L1MessageSent-like entry here if you need raw data -} -``` - -**Returns** -`ReceiptWithL2ToL1 | null` - -- Same fields as a normal receipt, plus **`l2ToL1Logs: any[]`** (always present; empty if none). -- `null` when the node does not yet have the receipt. - -## `getL2ToL1LogProof(txHash, index)` - -**What it does** -Fetches the **proof** for an L2→L1 log at a given `index` in the transaction’s messenger logs. -The SDK normalizes the response to a consistent shape. - -**Example** - -```ts -const l2TxHash = '0x...'; -const messengerLogIndex = 0; // whichever log index you intend to finalize - -try { - const proof = await client.zks.getL2ToL1LogProof(l2TxHash, messengerLogIndex); - // proof.id, proof.batchNumber, proof.proof (Hex[]) - console.log('Proof id:', proof.id.toString()); - console.log('Batch number:', proof.batchNumber.toString()); - console.log('Proof length:', proof.proof.length); -} catch (e) { - // If the proof is not yet available, the SDK raises a STATE error with a clear message. - console.error('Proof unavailable yet or RPC error:', e); -} -``` - -**Returns** - -```ts -type ProofNormalized = { - id: bigint; - batchNumber: bigint; - proof: `0x${string}`[]; -}; -``` diff --git a/src/adapters/ethers/sdk.ts b/src/adapters/ethers/sdk.ts index 5547738..5bb343f 100644 --- a/src/adapters/ethers/sdk.ts +++ b/src/adapters/ethers/sdk.ts @@ -13,13 +13,36 @@ import { type Address, type Hex } from '../../core/types'; import { isAddressEq } from '../../core/utils/addr'; import { L2_BASE_TOKEN_ADDRESS, ETH_ADDRESS, FORMAL_ETH_ADDRESS } from '../../core/constants'; -// SDK interface, combining deposits, withdrawals, and helpers +/** + * @summary The main entry point for interacting with the ZKsync network using the Ethers.js adapter. + * @description This SDK object provides access to all major functionalities, including deposits, + * withdrawals, and various utility helpers for address and contract resolution. + */ export interface EthersSdk { + /** + * @summary Provides methods for depositing assets from L1 to L2. + * @see DepositsResourceType for a full list of methods. + */ deposits: DepositsResourceType; + /** + * @summary Provides methods for withdrawing assets from L2 to L1. + * @see WithdrawalsResourceType for a full list of methods. + */ withdrawals: WithdrawalsResourceType; + /** + * @summary A collection of utility functions for common tasks like resolving addresses, + * fetching contracts, and converting token addresses. + */ helpers: { - // addresses & contracts + /** + * @summary Retrieves the resolved L1 and L2 contract addresses used by the SDK. + * @returns A Promise that resolves to the set of contract addresses. + */ addresses(): Promise; + /** + * @summary Retrieves the Ethers.js Contract instances for all SDK-related contracts. + * @returns A Promise that resolves to an object containing all relevant contract instances. + */ contracts(): Promise<{ bridgehub: Contract; l1AssetRouter: Contract; @@ -30,17 +53,62 @@ export interface EthersSdk { l2BaseTokenSystem: Contract; }>; - // common getters + /** + * @summary Gets the L1 Asset Router contract instance. + * @returns A Promise resolving to the `Contract` instance. + */ l1AssetRouter(): Promise; + /** + * @summary Gets the L1 Native Token Vault contract instance. + * @returns A Promise resolving to the `Contract` instance. + */ l1NativeTokenVault(): Promise; + /** + * @summary Gets the L1 Nullifier contract instance. + * @returns A Promise resolving to the `Contract` instance. + */ l1Nullifier(): Promise; + /** + * @summary Retrieves the L1 address of the base token for a given L2 chain. + * @param chainId The L2 chain ID. If not provided, it's fetched from the L2 provider. + * @returns A Promise resolving to the base token's L1 address. + */ baseToken(chainId?: bigint): Promise
; + /** + * @summary Gets the corresponding L2 token address for a given L1 token. + * @notice This method correctly handles special cases for ETH and the official base token. + * @param l1Token The address of the token on L1. + * @returns A Promise resolving to the corresponding token address on L2. + * @example + * ```typescript + * const l1EthAddress = '0x0000000000000000000000000000000000000000'; + * const l2EthAddress = await sdk.helpers.l2TokenAddress(l1EthAddress); + * console.log(l2EthAddress); // 0x000000000000000000000000000000000000800a + * ``` + */ l2TokenAddress(l1Token: Address): Promise
; + /** + * @summary Gets the corresponding L1 token address for a given L2 token. + * @notice This method correctly handles the placeholder address for ETH on L2. + * @param l2Token The address of the token on L2. + * @returns A Promise resolving to the corresponding token address on L1. + */ l1TokenAddress(l2Token: Address): Promise
; + /** + * @summary Calculates the unique asset identifier (`bytes32`) for a given L1 token. + * @param l1Token The address of the token on L1. + * @returns A Promise that resolves to the `bytes32` asset ID as a hex string. + */ assetId(l1Token: Address): Promise; }; } +/** + * @summary Creates an instance of the EthersSdk. + * @param client An instance of `EthersClient` used for communication with the network. + * @returns A fully configured `EthersSdk` instance. + * @internal + */ export function createEthersSdk(client: EthersClient): EthersSdk { return { deposits: createDepositsResource(client), @@ -54,7 +122,7 @@ export function createEthersSdk(client: EthersClient): EthersSdk { async l1AssetRouter() { const { l1AssetRouter } = await client.contracts(); return l1AssetRouter; - }, + }, async l1NativeTokenVault() { const { l1NativeTokenVault } = await client.contracts(); return l1NativeTokenVault; diff --git a/typedoc.json b/typedoc.json index 3059ea8..5c06609 100644 --- a/typedoc.json +++ b/typedoc.json @@ -1,11 +1,11 @@ { - "entryPoints": ["packages/core/src/index.ts", "packages/ethers/src/index.ts"], + "entryPoints": ["src/adapters/ethers/sdk.ts"], "entryPointStrategy": "resolve", "tsconfig": "tsconfig.build.json", - "out": "docs/src/api", + "out": "docs/src/api-reference", "excludePrivate": true, "excludeExternals": false, "readme": "none", "plugin": ["typedoc-plugin-markdown"], "hideGenerator": true -} +} \ No newline at end of file From 17772aba58efdd842311d6f51ee97dff42c8c71c Mon Sep 17 00:00:00 2001 From: Dustin Brickwood Date: Thu, 9 Oct 2025 14:06:56 -0500 Subject: [PATCH 08/18] chore: finalize api-reference --- docs/api-reference/core/errors.mdx | 207 ++++++++++++++++++++++ docs/api-reference/core/rpc.mdx | 119 +++++++++++++ docs/api-reference/core/types.mdx | 0 docs/api-reference/ethers/withdrawals.mdx | 4 +- docs/api-reference/introduction.mdx | 134 +++++++++++--- docs/api-reference/viem/withdrawals.mdx | 4 +- docs/docs.json | 13 +- docs/favicon.svg | 7 +- docs/index.mdx | 4 +- docs/logo/dark.svg | 37 ---- docs/logo/light.svg | 37 ---- docs/logo/zksync-dark.svg | 10 ++ docs/logo/zksync-light.svg | 10 ++ docs/overview/index.mdx | 2 +- src/core/constants.ts | 2 +- src/core/types/errors.ts | 3 +- 16 files changed, 480 insertions(+), 113 deletions(-) delete mode 100644 docs/api-reference/core/types.mdx delete mode 100644 docs/logo/dark.svg delete mode 100644 docs/logo/light.svg create mode 100644 docs/logo/zksync-dark.svg create mode 100644 docs/logo/zksync-light.svg diff --git a/docs/api-reference/core/errors.mdx b/docs/api-reference/core/errors.mdx index e69de29..e8807f0 100644 --- a/docs/api-reference/core/errors.mdx +++ b/docs/api-reference/core/errors.mdx @@ -0,0 +1,207 @@ +--- +title: Error model +description: Typed, structured errors with a stable envelope across viem and ethers adapters. +group: API Reference / Core +--- + +## Overview + +All SDK operations either: + +1. **Throw** a `ZKsyncError` whose `.envelope` gives you a structured, stable payload, or +2. Return a **result object** from the `try*` variants: `{ ok: true, value } | { ok: false, error }`. + +This is consistent across both **ethers** and **viem** adapters. + + +Prefer the try* variants when you want to avoid exceptions and branch on success/failure. + + +## What gets thrown + +When the SDK throws, it throws an instance of `ZKsyncError`. Use `isZKsyncError(e)` to narrow and read the **error envelope**. + +```ts +import { isZKsyncError } from '@dutterbutter/zksync-sdk/core'; + +try { + const handle = await sdk.deposits.create(params); +} catch (e) { + if (isZKsyncError(e)) { + const err = e; // type-narrowed + const { type, resource, operation, message, context, revert } = err.envelope; + + // Example: route on category + switch (type) { + case 'VALIDATION': + case 'STATE': + // user/action fixable (bad input, not-ready, etc.) + break; + case 'EXECUTION': + case 'RPC': + // network/tx/provider issues + break; + } + + // Optional: log structured data + console.error(JSON.stringify(err.toJSON())); + } else { + // Non-SDK error (framework, userland) + throw e; + } +} +``` + +## Envelope shape + + + Instance type for all SDK-thrown errors. + + +### `ZKsyncError.envelope: ErrorEnvelope` + +```ts +type ErrorEnvelope = { + /** Resource surface that raised the error. */ + resource: 'deposits' | 'withdrawals' | 'withdrawal-finalization' | 'helpers' | 'zksrpc'; + + /** Specific operation, e.g. "withdrawals.finalize" or "deposits.create". */ + operation: string; + + /** Broad category (see table below). */ + type: 'VALIDATION' | 'STATE' | 'EXECUTION' | 'RPC' | 'INTERNAL' | 'VERIFICATION' | 'CONTRACT'; + + /** Stable, human-readable message for developers. */ + message: string; + + /** Optional contextual fields (tx hash, nonce, step key, etc.). */ + context?: Record; + + /** If the error is a contract revert, adapters include decoded info when available. */ + revert?: { + selector: `0x${string}`; // 4-byte selector + name?: string; // Decoded Solidity error name + args?: unknown[]; // Decoded args + contract?: string; // Best-effort contract label + fn?: string; // Best-effort function label + }; + + /** Originating error (provider/transport/etc.), sanitized for safe logging. */ + cause?: unknown; +}; +``` + +### Categories (when to expect them) + +| Type | Meaning (how you should react) | +| :------------- | :----------------------------------------------------------------------------------------- | +| `VALIDATION` | Inputs are invalid (fix parameters and retry). | +| `STATE` | Operation not possible **yet** (e.g., not finalizable). Wait or change state. | +| `EXECUTION` | A send/revert happened (tx reverted or couldn’t be confirmed). Inspect `revert` / `cause`. | +| `RPC` | Provider/transport failure (endpoint/network issue). Retry with backoff / check infra. | +| `VERIFICATION` | Proof/verification step issue. Usually indicates unable to find deposit log. | +| `CONTRACT` | A contract read/encode/allowance failed. Check addresses & ABI compatibility. | +| `INTERNAL` | SDK internal error (please report with `operation` + `selector` if present). | + +## Result style (`try*`) helpers + +Every resource method has a `try*` sibling that never throws and returns a `TryResult`. + +```ts +const res = await sdk.withdrawals.tryCreate(params); +if (!res.ok) { + // res.error is a ZKsyncError + console.warn(res.error.envelope.message, res.error.envelope.operation); +} else { + // res.value is the success payload + console.log('l2TxHash', res.value.l2TxHash); +} +``` + +This is especially handy for UI flows where you want to surface inline validation/state messages without a `try/catch`. + +## Revert details (when transactions fail) + +If the provider exposes revert data, the adapters will decode common error types and ABIs so you can branch on them: + +```ts +try { + await sdk.withdrawals.finalize(l2TxHash); +} catch (e) { + if (isZKsyncError(e) && e.envelope.revert) { + const { selector, name, args } = e.envelope.revert; + // e.g., name === 'InvalidProof' or 'TransferAmountExceedsBalance' + } +} +``` + +Notes: + +* The SDK always includes the **4-byte selector**. +* `name`/`args` appear when decodable against known ABIs; coverage will expand over time. +* When a revert implies “not ready yet,” you’ll typically see a `STATE` error with a clarifying `message`. + +## Ethers & viem examples + + + +```ts title="Ethers" +import { JsonRpcProvider, Wallet } from 'ethers'; +import { createEthersClient, createEthersSdk } from '@dutterbutter/zksync-sdk/ethers'; +import { isZKsyncError } from '@dutterbutter/zksync-sdk/core'; + +const l1 = new JsonRpcProvider(process.env.ETH_RPC!); +const l2 = new JsonRpcProvider(process.env.ZKSYNC_RPC!); +const signer = new Wallet(process.env.PRIVATE_KEY!, l1); + +const client = createEthersClient({ l1, l2, signer }); +const sdk = createEthersSdk(client); + +const res = await sdk.deposits.tryCreate({ token, amount, to }); +if (!res.ok) { + // report envelope + console.error(res.error.envelope); +} +``` + +```ts title="Viem" +import { createPublicClient, http, createWalletClient, privateKeyToAccount } from 'viem'; +import { createViemClient, createViemSdk } from '@dutterbutter/zksync-sdk/viem'; +import { isZKsyncError } from '@dutterbutter/zksync-sdk/core'; + +const account = privateKeyToAccount(process.env.PRIVATE_KEY! as `0x${string}`); +const l1 = createPublicClient({ transport: http(process.env.ETH_RPC!) }); +const l2 = createPublicClient({ transport: http(process.env.ZKSYNC_RPC!) }); +const l1Wallet: WalletClient = createWalletClient({ + account, + transport: http(ETH_RPC), +}); +const l2Wallet = createWalletClient({ + account, + transport: http(ZKSYNC_RPC), +}); + +const client = createViemClient({ l1, l2, l1Wallet, l2Wallet }); +const sdk = createViemSdk(client); + +try { + await sdk.withdrawals.finalize(l2TxHash); +} catch (e) { + if (isZKsyncError(e)) { + console.log(e.envelope.message, e.envelope.operation); + } else { + throw e; + } +} +``` + + + +## Logging & observability + +* `err.toJSON()` returns a safe, structured object you can ship to logs/telemetry. +* For local debugging, printing `err` shows a compact, human-readable view (category, operation, context, optional revert/cause). + + +Avoid parsing err.message for logic. Use the typed fields on err.envelope instead. + diff --git a/docs/api-reference/core/rpc.mdx b/docs/api-reference/core/rpc.mdx index e69de29..8dddee4 100644 --- a/docs/api-reference/core/rpc.mdx +++ b/docs/api-reference/core/rpc.mdx @@ -0,0 +1,119 @@ +--- +title: zks_ RPC +description: Public ZKsync zks_ RPC methods exposed on the adapters via client.zks (Bridgehub address, L2→L1 log proofs, receipts with l2ToL1Logs). +group: API Reference / Core +--- + +### Standard Ethereum RPC (`eth_*`) + +Use your base library for all `eth_*` methods. +The client.zks +surface only covers ZKsync-specific RPC (zks_*). +For standard Ethereum JSON-RPC (e.g., eth_call, eth_getLogs, eth_getBalance), +call them through your chosen library (`ethers` or `viem`). + +## zks_ Interface + +```ts +interface ZksRpc { + getBridgehubAddress(): Promise
; + getL2ToL1LogProof(txHash: Hex, index: number): Promise; + getReceiptWithL2ToL1(txHash: Hex): Promise; +} +``` + +## Methods + +### `getBridgehubAddress() → Promise
` + +Fetch the on-chain **Bridgehub** contract address. + +```ts +const addr = await client.zks.getBridgehubAddress(); +``` + +### `getL2ToL1LogProof(txHash: Hex, index: number) → Promise` + +Return a normalized proof for the **L2→L1 log** at `index` in `txHash`. + + + L2 transaction hash that emitted one or more L2→L1 logs. + + + Zero-based index of the target L2→L1 log within the transaction. + + +```ts +const proof = await client.zks.getL2ToL1LogProof(l2TxHash, 0); +/* +{ + id: bigint, + batchNumber: bigint, + proof: Hex[] +} +*/ +``` + + +If a proof isn’t available yet, this method throws a typed STATE error. Poll based on your app’s cadence. + + +### `getReceiptWithL2ToL1(txHash: Hex) → Promise` + +Fetch the transaction receipt; the returned object **always** includes `l2ToL1Logs` (empty array if none). + +```ts +const rcpt = await client.zks.getReceiptWithL2ToL1(l2TxHash); +console.log(rcpt?.l2ToL1Logs); // always an array +``` + +## Types (overview) + +```ts +type ProofNormalized = { + id: bigint; + batchNumber: bigint; + proof: Hex[]; +}; + +type ReceiptWithL2ToL1 = { + // …standard receipt fields… + l2ToL1Logs: unknown[]; +}; +``` + +## Usage + +### ethers + +```ts +import { JsonRpcProvider, Wallet } from "ethers"; +import { createEthersClient } from "@dutterbutter/zksync-sdk/ethers"; + +const l1 = new JsonRpcProvider(process.env.ETH_RPC!); +const l2 = new JsonRpcProvider(process.env.ZKSYNC_RPC!); +const signer = new Wallet(process.env.PRIVATE_KEY!, l1); + +const client = createEthersClient({ l1, l2, signer }); + +// Public RPC surface: +const bridgehub = await client.zks.getBridgehubAddress(); +``` + +### viem + +```ts +import { createPublicClient, http } from "viem"; +import { createViemClient } from "@dutterbutter/zksync-sdk/viem"; + +const l1 = createPublicClient({ transport: http(process.env.ETH_RPC!) }); +const l2 = createPublicClient({ transport: http(process.env.ZKSYNC_RPC!) }); + +// Provide a WalletClient with an account for L1 operations. +const l1Wallet = /* your WalletClient w/ account */; + +const client = createViemClient({ l1, l2, l1Wallet }); + +// Public RPC surface: +const bridgehub = await client.zks.getBridgehubAddress(); +``` diff --git a/docs/api-reference/core/types.mdx b/docs/api-reference/core/types.mdx deleted file mode 100644 index e69de29..0000000 diff --git a/docs/api-reference/ethers/withdrawals.mdx b/docs/api-reference/ethers/withdrawals.mdx index 4493a6d..3b977bc 100644 --- a/docs/api-reference/ethers/withdrawals.mdx +++ b/docs/api-reference/ethers/withdrawals.mdx @@ -182,10 +182,10 @@ if (status.phase === "FINALIZED") { } ``` - + Behavior: If the withdrawal is not ready, finalize throws a typed STATE error. Use status(...) or `wait(..., { for: 'ready' })` to check first. - + ### `tryFinalize(l2TxHash) → Promise<{ ok: true; value: { status; receipt? } } | { ok: false; error }>` diff --git a/docs/api-reference/introduction.mdx b/docs/api-reference/introduction.mdx index c835b78..39b62d1 100644 --- a/docs/api-reference/introduction.mdx +++ b/docs/api-reference/introduction.mdx @@ -1,33 +1,121 @@ --- -title: 'Introduction' -description: 'Example section for showcasing API endpoints' +title: Introduction +description: Public, typed API surface for the ZKsyncOS SDK — Incorruptible Financial Infrastructure. +group: API Reference / Overview --- - - If you're not looking to build API reference documentation, you can delete - this section by removing the api-reference folder. - +## What is this? -## Welcome +The **ZKsyncOS SDK** provides lightweight adapters for **ethers** and **viem** to build L1 ↔ L2 flows—**deposits** and **withdrawals**—with a small, focused API. You’ll work with: -There are two ways to build API documentation: [OpenAPI](https://mintlify.com/docs/api-playground/openapi/setup) and [MDX components](https://mintlify.com/docs/api-playground/mdx/configuration). For the starter kit, we are using the following OpenAPI specification. +* Adapter-level **Clients** (providers/wallets, resolved addresses, convenience contracts) +* High-level **SDKs** (resources for deposits & withdrawals + helpers) +* ZKsync-specific **RPC** helpers (`client.zks.*`) +* A consistent, typed **Error model** (`ZKsyncError`, `try*` results) - - View the OpenAPI specification file - +## Quick start -## Authentication + + -All API endpoints are authenticated using Bearer tokens and picked up from the specification file. +```ts +import { JsonRpcProvider, Wallet, parseEther } from 'ethers'; +import { createEthersClient, createEthersSdk, ETH_ADDRESS } from '@dutterbutter/zksync-sdk/ethers'; -```json -"security": [ - { - "bearerAuth": [] - } -] +const l1 = new JsonRpcProvider(process.env.ETH_RPC!); +const l2 = new JsonRpcProvider(process.env.ZKSYNC_RPC!); +const signer = new Wallet(process.env.PRIVATE_KEY!, l1); + +// Low-level client + high-level SDK +const client = createEthersClient({ l1, l2, signer }); +const sdk = createEthersSdk(client); + +// Deposit 0.05 ETH L1 → L2 and wait for L2 execution +const handle = await sdk.deposits.create({ + token: ETH_ADDRESS, + amount: parseEther('0.05'), + to: await signer.getAddress(), +}); + +const l2Receipt = await sdk.deposits.wait(handle, { for: 'l2' }); + +// ZKsync-specific RPC is available via client.zks +const bridgehub = await client.zks.getBridgehubAddress(); ``` + + + + +```ts +import { createPublicClient, http, createWalletClient, privateKeyToAccount, parseEther } from 'viem'; +import { createViemClient, createViemSdk, ETH_ADDRESS } from '@dutterbutter/zksync-sdk/viem'; + +const account = privateKeyToAccount(process.env.PRIVATE_KEY! as `0x${string}`); +const l1 = createPublicClient({ transport: http(process.env.ETH_RPC!) }); +const l2 = createPublicClient({ transport: http(process.env.ZKSYNC_RPC!) }); +const l1Wallet = createWalletClient({ account, transport: http(process.env.ETH_RPC!) }); + +const client = createViemClient({ l1, l2, l1Wallet }); +const sdk = createViemSdk(client); + +const handle = await sdk.withdrawals.create({ + token: ETH_ADDRESS, + amount: parseEther('0.05'), + to: account.address, // L1 recipient +}); + +await sdk.withdrawals.wait(handle, { for: 'l2' }); // inclusion on L2 +const { status } = await sdk.withdrawals.finalize(handle.l2TxHash); // finalize on L1 + +const bridgehub = await client.zks.getBridgehubAddress(); +``` + + + + +## What’s documented here + + + + Low-level handle: providers/signer, resolved addresses, convenience contracts, ZK RPC access. + + + High-level deposits/withdrawals plus helpers for addresses, contracts, and token mapping. + + + L1 → L2 flow with quote, prepare, create, status, and wait. + + + L2 → L1 flow with quote, prepare, create, status, wait, and finalize. + + + + PublicClient/WalletClient integration, resolved addresses, contracts, ZK RPC access. + + + Same high-level surface as ethers, typed to viem contracts. + + + L1 → L2 flow with quote, prepare, create, status, and wait. + + + L2 → L1 flow with quote, prepare, create, status, wait, and finalize. + + + + ZKsync-specific RPC: getBridgehubAddress, getL2ToL1LogProof, enhanced receipts. + + + Typed ZKsyncError envelope and try* result helpers. + + + +## Notes & conventions + +- **Standard eth_* RPC** should be performed through your chosen base library (**ethers** / **viem**). +The SDK only adds ZKsync-specific RPC via client.zks.* (e.g., getBridgehubAddress, getL2ToL1LogProof, enhanced receipts). + +- Every resource method has a try* variant (e.g., tryCreate) that returns a result object instead of throwing. +When errors occur, the SDK throws ZKsyncError with a stable envelope (see Error model). + +- Address resolution comes from on-chain lookups and well-known constants. You can override addresses in the client constructor for forks/tests. diff --git a/docs/api-reference/viem/withdrawals.mdx b/docs/api-reference/viem/withdrawals.mdx index 7fd4d56..7419754 100644 --- a/docs/api-reference/viem/withdrawals.mdx +++ b/docs/api-reference/viem/withdrawals.mdx @@ -187,10 +187,10 @@ if (status.phase === "FINALIZED") { } ``` - + Behavior: If the withdrawal is not ready, finalize throws a typed STATE error. Use status(...) or `wait(..., { for: 'ready' })` to check first. - + ### `tryFinalize(l2TxHash) → Promise<{ ok: true; value: { status; receipt? } } | { ok: false; error }>` diff --git a/docs/docs.json b/docs/docs.json index 5325657..b054644 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -93,6 +93,13 @@ "api-reference/viem/deposits", "api-reference/viem/withdrawals" ] + }, + { + "group": "Core", + "pages": [ + "api-reference/core/rpc", + "api-reference/core/errors" + ] } ] }, @@ -111,12 +118,12 @@ ] }, "logo": { - "light": "/logo/light.svg", - "dark": "/logo/dark.svg", + "light": "/logo/zksync-dark.svg", + "dark": "/logo/zksync-light.svg", "href": "https://zksync.io" }, "search": { - "prompt": "Search ZKsyncOS SDK..." + "prompt": "Search ZKsync SDK..." }, "navbar": { "links": [ diff --git a/docs/favicon.svg b/docs/favicon.svg index 5261fc4..2791d9f 100644 --- a/docs/favicon.svg +++ b/docs/favicon.svg @@ -1,5 +1,4 @@ - - - - + + + diff --git a/docs/index.mdx b/docs/index.mdx index 03b53bc..d119929 100644 --- a/docs/index.mdx +++ b/docs/index.mdx @@ -14,8 +14,8 @@ mode: "custom"

- ZKsync - power
+ Incorruptible + ZKsync power
in your favorite
libraries

diff --git a/docs/logo/dark.svg b/docs/logo/dark.svg deleted file mode 100644 index 2377d63..0000000 --- a/docs/logo/dark.svg +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/logo/light.svg b/docs/logo/light.svg deleted file mode 100644 index a662169..0000000 --- a/docs/logo/light.svg +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/logo/zksync-dark.svg b/docs/logo/zksync-dark.svg new file mode 100644 index 0000000..1b42473 --- /dev/null +++ b/docs/logo/zksync-dark.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/docs/logo/zksync-light.svg b/docs/logo/zksync-light.svg new file mode 100644 index 0000000..1e28358 --- /dev/null +++ b/docs/logo/zksync-light.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/docs/overview/index.mdx b/docs/overview/index.mdx index a11d308..1c8015c 100644 --- a/docs/overview/index.mdx +++ b/docs/overview/index.mdx @@ -31,7 +31,7 @@ The SDK doesn’t replace your existing Ethereum libraries — it **extends** th - **Track progress:** monitor execution and finalization availability. - **Finalize on L1:** finalize withdrawal to release funds back to Ethereum. -- **ZKsync RPC Enhancements** +- **ZKsync RPC** - **`getBridgehubAddress`** (`zks_getBridgehubContract`) – resolve the canonical Bridgehub contract address. - **`getL2ToL1LogProof`** (`zks_getL2ToL1LogProof`) – retrieve the log proof for an L2 → L1 transaction. - **`getReceiptWithL2ToL1`** *(receipt extension)* – returns a standard Ethereum `TransactionReceipt` **augmented** with `l2ToL1Logs`. diff --git a/src/core/constants.ts b/src/core/constants.ts index 79ef115..48fe7c5 100644 --- a/src/core/constants.ts +++ b/src/core/constants.ts @@ -56,7 +56,7 @@ export const TOPIC_L1_MESSAGE_SENT_LEG = k256hex('L1MessageSent(address,bytes32, export const TOPIC_BRIDGEHUB_NEW_PRIORITY = '0x0f87e1ea5eb1f034a6071ef630c174063e3d48756f853efaaf4292b929298240'; -// Optional canonical markers (some OS builds) +// Optional canonical markers export const TOPIC_CANONICAL_ASSIGNED = '0x779f441679936c5441b671969f37400b8c3ed0071cb47444431bf985754560df'; // hash in topics[2] export const TOPIC_CANONICAL_SUCCESS = diff --git a/src/core/types/errors.ts b/src/core/types/errors.ts index c231330..b2e5021 100644 --- a/src/core/types/errors.ts +++ b/src/core/types/errors.ts @@ -53,7 +53,8 @@ export interface ErrorEnvelope { cause?: unknown; } -/** Error class. +// TODO: move to errors/ +/** Error class. * Represents an error that occurs within the ZKsync SDK. * It encapsulates an ErrorEnvelope which provides detailed information about the error, * From f6d0430c0791bc39fd9d3eaafbcd2ef9ebbd6c5f Mon Sep 17 00:00:00 2001 From: Dustin Brickwood Date: Thu, 9 Oct 2025 14:14:00 -0500 Subject: [PATCH 09/18] chore: minor adjustments --- docs/api-reference/core/rpc.mdx | 10 +++++----- docs/index.mdx | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/api-reference/core/rpc.mdx b/docs/api-reference/core/rpc.mdx index 8dddee4..3f35e32 100644 --- a/docs/api-reference/core/rpc.mdx +++ b/docs/api-reference/core/rpc.mdx @@ -84,9 +84,9 @@ type ReceiptWithL2ToL1 = { ## Usage -### ethers + -```ts +```ts title="ethers" import { JsonRpcProvider, Wallet } from "ethers"; import { createEthersClient } from "@dutterbutter/zksync-sdk/ethers"; @@ -100,9 +100,7 @@ const client = createEthersClient({ l1, l2, signer }); const bridgehub = await client.zks.getBridgehubAddress(); ``` -### viem - -```ts +```ts title="viem" import { createPublicClient, http } from "viem"; import { createViemClient } from "@dutterbutter/zksync-sdk/viem"; @@ -117,3 +115,5 @@ const client = createViemClient({ l1, l2, l1Wallet }); // Public RPC surface: const bridgehub = await client.zks.getBridgehubAddress(); ``` + + diff --git a/docs/index.mdx b/docs/index.mdx index d119929..c0ea9d5 100644 --- a/docs/index.mdx +++ b/docs/index.mdx @@ -82,7 +82,7 @@ mode: "custom" See what’s new, fixed, and changed across releases. - Questions or issues? Reach out and we’ll help you integrate quickly. + Questions or issues? Reach out and we’ll help you.
From 5136b2277f22821891ae7ebdd89d71d22d6572fc Mon Sep 17 00:00:00 2001 From: Dustin Brickwood Date: Fri, 10 Oct 2025 09:12:44 -0500 Subject: [PATCH 10/18] chore: minor adjustments --- docs/api-reference/ethers/deposits.mdx | 161 +++++++++++----------- docs/api-reference/ethers/withdrawals.mdx | 150 ++++++++++---------- docs/docs.json | 6 +- docs/style.css | 51 ++++++- 4 files changed, 210 insertions(+), 158 deletions(-) diff --git a/docs/api-reference/ethers/deposits.mdx b/docs/api-reference/ethers/deposits.mdx index 9ee1c78..9944645 100644 --- a/docs/api-reference/ethers/deposits.mdx +++ b/docs/api-reference/ethers/deposits.mdx @@ -1,12 +1,17 @@ --- title: Deposits description: L1 → L2 deposits for ETH and ERC-20 with quote, prepare, create, status, and wait helpers. -group: API Reference / Ethers +group: SDK Reference / Ethers --- -## Import +## At a glance + +- **Resource:** `sdk.deposits` +- **Most common flow:** `quote → create → wait({ for: 'l2' })` +- **Auto-routing:** ETH vs ERC-20 and base-token vs non-base handled internally +- **Error style:** Throwing methods (`quote`, `prepare`, `create`, `wait`) + result variants (`tryQuote`, `tryPrepare`, `tryCreate`, `tryWait`) -The Deposits resource is available via the Ethers SDK: +## Import ```ts import { JsonRpcProvider, Wallet, parseEther } from "ethers"; @@ -27,41 +32,36 @@ Deposit **0.1 ETH** from L1 → L2 and wait for **L2 execution**: ```ts const handle = await sdk.deposits.create({ - token: ETH_ADDRESS, + token: ETH_ADDRESS, // 0x…00 for ETH amount: parseEther("0.1"), to: await signer.getAddress(), }); -// Wait for canonical L2 execution; returns L2 receipt or null -const l2Receipt = await sdk.deposits.wait(handle, { for: "l2" }); +const l2Receipt = await sdk.deposits.wait(handle, { for: "l2" }); // null only if no L1 hash ``` -## Routes (auto-selected) + +For UX that never throws, use the try* variants and branch on ok. + -The SDK automatically selects a route based on the **asset** and the **L2 base token**: +## Route selection (automatic) -* `eth-base` — Deposit ETH when L2 base token is **ETH** -* `eth-nonbase` — Deposit ETH when L2 base token is **not ETH** -* `erc20-base` — Deposit ERC-20 that **is** the L2 base token -* `erc20-nonbase` — Deposit ERC-20 that **is not** the L2 base token +* `eth-base` — ETH when L2 base token **is ETH** +* `eth-nonbase` — ETH when L2 base token **≠ ETH** +* `erc20-base` — ERC-20 that **is** the L2 base token +* `erc20-nonbase` — ERC-20 that **is not** the L2 base token -You don’t need to pass a route; it’s derived internally. +You **do not** pass a route; it’s derived from network metadata + `token`. -## Methods +## Method reference ### `quote(p: DepositParams) → Promise` -Get a **non-executing** summary of the deposit (route, approvals, gas hints). +Estimate the operation (route, approvals, gas hints). Does **not** send txs. - - L1 token address (use 0x…00 for ETH). - - - Amount in wei. - - - Recipient on L2. - +L1 token (use 0x…00 for ETH). Amount in wei. L2 recipient. + +**Returns:** `DepositQuote` ```ts const q = await sdk.deposits.quote({ @@ -70,112 +70,112 @@ const q = await sdk.deposits.quote({ to: await signer.getAddress(), }); /* -q = { +{ route: "eth-base" | "eth-nonbase" | "erc20-base" | "erc20-nonbase", - approvalsNeeded: [{ token, spender, amount }, ...], - baseCost, // bigint (bridge/base cost estimate if applicable) - mintValue, // bigint (if applicable on route) - suggestedL2GasLimit, // bigint - gasPerPubdata // bigint + approvalsNeeded: [{ token, spender, amount }], + baseCost?: bigint, + mintValue?: bigint, + suggestedL2GasLimit?: bigint, + gasPerPubdata?: bigint } */ ``` - If approvalsNeeded is non-empty for ERC-20 deposits, the SDK will include - approval steps during create. These are approved automatically. +If approvalsNeeded is non-empty (ERC-20), create will include those steps automatically. -### `tryQuote(p) → Promise<{ ok: true; value: DepositQuote } | { ok: false; error }>;` +### `tryQuote(p) → Promise<{ ok: true; value: DepositQuote } | { ok: false; error }>` -Result-style version of `quote`. +Result-style `quote`. ### `prepare(p: DepositParams) → Promise>` -Build the **plan** (route + ordered steps) without sending transactions. +Builds the plan (ordered steps + unsigned txs) without sending. + +**Returns:** `DepositPlan` ```ts const plan = await sdk.deposits.prepare({ token: ETH_L1, amount: parseEther("0.05"), to }); /* -plan = { +{ route, - summary: { ...same shape as DepositQuote }, + summary: DepositQuote, steps: [ - // Each step has a unique .key, a .kind (e.g., "approve" | "bridge"), - // and a prebuilt ethers TransactionRequest in .tx + { key: "approve:USDC", kind: "approve", tx: TransactionRequest }, + { key: "bridge", kind: "bridge", tx: TransactionRequest } ] } */ ``` -### `tryPrepare(p) → Promise<{ ok: true; value: DepositPlan } | { ok: false; error }>;` +### `tryPrepare(p) → Promise<{ ok: true; value: DepositPlan } | { ok: false; error }>` -Result-style version of `prepare`. +Result-style `prepare`. ### `create(p: DepositParams) → Promise>` -Prepare and **execute** all required steps on **L1**. Returns a handle with the L1 hash. +Prepares and **executes** all required L1 steps. Returns a handle (with L1 tx hash and per-step hashes). + +**Returns:** `DepositHandle` ```ts const handle = await sdk.deposits.create({ token, amount, to }); /* -handle = { +{ kind: "deposit", - l1TxHash, // Hex - stepHashes: Record, // tx hashes per step - plan // DepositPlan returned by prepare() + l1TxHash: Hex, + stepHashes: Record, + plan: DepositPlan } */ ``` - If any step reverts on L1, create throws a typed error. - Use tryCreate if you prefer a result object. +If any step reverts, create throws a typed error. Prefer tryCreate to avoid exceptions. -### `tryCreate(p) → Promise<{ ok: true; value: DepositHandle } | { ok: false; error }>;` +### `tryCreate(p) → Promise<{ ok: true; value: DepositHandle } | { ok: false; error }>` -Result-style version of `create`. +Result-style `create`. -### `status(h | l1TxHash) → Promise` +### `status(handleOrHash) → Promise` -Check a deposit’s current phase. Accepts the **handle** from `create` or a raw **L1 tx hash**. +Resolve current phase for a deposit. Accepts the `DepositHandle` from `create` **or** a raw L1 tx hash. -Phases: +**Phases** -* `UNKNOWN` — no L1 hash on input -* `L1_PENDING` — L1 receipt not found yet -* `L1_INCLUDED` — included on L1 but L2 hash not yet derivable -* `L2_PENDING` — L2 hash known but L2 receipt missing +* `UNKNOWN` — no L1 hash provided +* `L1_PENDING` — L1 receipt not yet found +* `L1_INCLUDED` — included on L1; L2 hash not derivable yet +* `L2_PENDING` — L2 hash known; waiting for L2 receipt * `L2_EXECUTED` — L2 receipt found with `status === 1` * `L2_FAILED` — L2 receipt found with `status !== 1` ```ts const s = await sdk.deposits.status(handle); -/* -s = { phase, l1TxHash, l2TxHash? } -*/ +// { phase, l1TxHash, l2TxHash? } ``` -### `wait(h | l1TxHash, { for: 'l1' | 'l2' }) → Promise` +### `wait(handleOrHash, { for: 'l1' | 'l2' }) → Promise` -Block until a checkpoint: +Block until the chosen checkpoint. -* `{ for: 'l1' }` → resolves the **L1 receipt** (or `null` if no L1 hash on input) -* `{ for: 'l2' }` → resolves the **L2 receipt** after canonical execution (or `null` if no L1 hash) +* `{ for: 'l1' }` → L1 receipt (or `null` if no L1 hash available) +* `{ for: 'l2' }` → L2 receipt after canonical execution (or `null` if no L1 hash) ```ts const l1Receipt = await sdk.deposits.wait(handle, { for: "l1" }); const l2Receipt = await sdk.deposits.wait(handle, { for: "l2" }); ``` -### `tryWait(h, { for }) → Promise<{ ok: true; value: TransactionReceipt } | { ok: false; error }>;` +### `tryWait(handleOrHash, opts) → Result` -Result-style version of `wait`. +Result-style `wait`. ## End-to-end examples -### ETH deposit (most common) +### ETH deposit (typical) ```ts const handle = await sdk.deposits.create({ @@ -184,32 +184,28 @@ const handle = await sdk.deposits.create({ to: await signer.getAddress(), }); -await sdk.deposits.wait(handle, { for: "l2" }); // get L2 receipt when executed +await sdk.deposits.wait(handle, { for: "l2" }); ``` -### ERC-20 deposit with approvals +### ERC-20 deposit (with automatic approvals) ```ts const handle = await sdk.deposits.create({ - token: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // example ERC-20 - amount: 1000000n, // 1e6 (USDC 6 decimals) + token: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // example: USDC + amount: 1_000_000n, // 1.0 USDC (6 dp) to: await signer.getAddress(), }); -// Wait for L1 inclusion only, if you need to chain logic at that point const l1Receipt = await sdk.deposits.wait(handle, { for: "l1" }); ``` -## Types (shape overview) - -These types live in `core/types` and are summarized here for convenience. +## Types (overview) ```ts type DepositParams = { - token: Address; // L1 token (0x…00 for ETH) - amount: bigint; // in wei - to: Address; // L2 recipient - // ...additional fields may exist; see core/types for the full spec + token: Address; // 0x…00 for ETH + amount: bigint; // wei + to: Address; // L2 recipient }; type DepositQuote = { @@ -244,6 +240,11 @@ type DepositStatus = ``` - Prefer the try* variants if you want to avoid exceptions and work with result objects. +Prefer the try* variants if you want to avoid exceptions and work with result objects. +## Notes & pitfalls + +* **ETH sentinel:** use the canonical `0x…00` address when passing ETH as `token`. +* **Receipts timing:** `wait({ for: 'l2' })` resolves on canonical L2 execution; it can take longer than L1 inclusion. +* **Gas hints:** `suggestedL2GasLimit` and `gasPerPubdata` are hints; advanced users may override via low-level calls from the plan. diff --git a/docs/api-reference/ethers/withdrawals.mdx b/docs/api-reference/ethers/withdrawals.mdx index 3b977bc..2364333 100644 --- a/docs/api-reference/ethers/withdrawals.mdx +++ b/docs/api-reference/ethers/withdrawals.mdx @@ -1,9 +1,16 @@ --- title: Withdrawals description: L2 → L1 withdrawals for ETH and ERC-20 with quote, prepare, create, status, wait, and finalize helpers. -group: API Reference / Ethers +group: SDK Reference / Ethers --- +## At a glance + +- **Resource:** `sdk.withdrawals` +- **Typical flow:** `quote → create → wait({ for: 'l2' }) → wait({ for: 'ready' }) → finalize` +- **Auto-routing:** ETH vs ERC-20 and base-token vs non-base handled internally +- **Error style:** Throwing methods (`quote`, `prepare`, `create`, `status`, `wait`, `finalize`) + result variants (`tryQuote`, `tryPrepare`, `tryCreate`, `tryWait`, `tryFinalize`) + ## Import ```ts @@ -21,120 +28,119 @@ const sdk = createEthersSdk(client); ## Quick start -Withdraw **0.1 ETH** from L2 → L1, then finalize: +Withdraw **0.1 ETH** from L2 → L1 and finalize on L1: ```ts const handle = await sdk.withdrawals.create({ - token: ETH_ADDRESS, + token: ETH_ADDRESS, // ETH sentinel supported amount: parseEther("0.1"), - to: await signer.getAddress(), // L1 recipient + to: await signer.getAddress(), // L1 recipient }); -// 1) Wait until included on L2 (adds l2ToL1Logs if available) -const l2Receipt = await sdk.withdrawals.wait(handle, { for: "l2" }); +// 1) L2 inclusion (adds l2ToL1Logs if available) +await sdk.withdrawals.wait(handle, { for: "l2" }); // 2) Wait until finalizable (no side effects) await sdk.withdrawals.wait(handle, { for: "ready", pollMs: 6000 }); -// 3) Send the L1 finalize tx (if not already finalized) +// 3) Finalize on L1 (no-op if already finalized) const { status, receipt: l1Receipt } = await sdk.withdrawals.finalize(handle.l2TxHash); ``` - - Withdrawals are a two-step process: include on L2, then finalize on L1. You can wait for ready before calling finalize, or call finalize directly— it will throw if not yet ready. - - -## Routes (auto-selected) + +Withdrawals are two-phase: inclusion on **L2**, then **finalization on L1**. You can call finalize directly; it will throw if not yet ready. Prefer `wait(..., { for: 'ready' })` to avoid that. + -Based on the asset and the L2 base token: +## Route selection (automatic) * `eth-base` — Base token is **ETH** on L2 * `eth-nonbase` — Base token is **not ETH** on L2 * `erc20-nonbase` — Withdrawing an ERC-20 that is **not** the base token -No route argument is needed; it’s derived internally. +You **do not** pass a route; it’s derived from network metadata + `token`. -## Methods +## Method reference ### `quote(p: WithdrawParams) → Promise` -Dry-run summary of a withdrawal (route, approvals, gas hints). +Estimate the operation (route, approvals, gas hints). Does **not** send txs. + +L2 token (ETH handled by the SDK; ETH sentinel supported). Amount in wei. L1 recipient. - - L2 token address equivalent (ETH handled by the SDK). - - - Amount in wei. - - - Recipient on L1. - +**Returns:** `WithdrawQuote` ```ts const q = await sdk.withdrawals.quote({ token, amount, to }); /* -q = { +{ route: "eth-base" | "eth-nonbase" | "erc20-nonbase", - approvalsNeeded: [{ token, spender, amount }, ...], - suggestedL2GasLimit: bigint + approvalsNeeded: [{ token, spender, amount }], + suggestedL2GasLimit?: bigint } */ ``` ### `tryQuote(p) → Promise<{ ok: true; value: WithdrawQuote } | { ok: false; error }>` -Result-style version of `quote`. +Result-style `quote`. ### `prepare(p: WithdrawParams) → Promise>` -Build the plan (route + ordered L2 steps), no sends. +Builds the plan (ordered L2 steps + unsigned txs) without sending. + +**Returns:** `WithdrawPlan` ```ts const plan = await sdk.withdrawals.prepare({ token, amount, to }); /* -plan = { +{ route, summary: WithdrawQuote, - steps: [{ key, kind, tx: TransactionRequest }, ...] + steps: [ + { key, kind, tx: TransactionRequest }, + // … + ] } */ ``` ### `tryPrepare(p) → Promise<{ ok: true; value: WithdrawPlan } | { ok: false; error }>` -Result-style version of `prepare`. +Result-style `prepare`. ### `create(p: WithdrawParams) → Promise>` -Prepare + **send** L2 steps. Returns a handle with the **L2 tx hash**. +Prepares and **executes** required **L2** steps. Returns a handle with the **L2 tx hash**. + +**Returns:** `WithdrawHandle` ```ts const handle = await sdk.withdrawals.create({ token, amount, to }); /* -handle = { +{ kind: "withdrawal", l2TxHash: Hex, stepHashes: Record, - plan + plan: WithdrawPlan } */ ``` - If any step reverts on L2, create throws a typed error. Prefer tryCreate if you want a result object. +If any L2 step reverts, create throws a typed error. Prefer tryCreate for a result object. ### `tryCreate(p) → Promise<{ ok: true; value: WithdrawHandle } | { ok: false; error }>` -Result-style version of `create`. +Result-style `create`. -### `status(h | l2TxHash) → Promise` +### `status(handleOrHash) → Promise` -Report current phase. Accepts the **handle** from `create` or a raw **L2 tx hash**. +Report current phase for a withdrawal. Accepts the `WithdrawHandle` from `create` **or** a raw **L2 tx hash**. -Phases: +**Phases** -* `UNKNOWN` — no L2 hash on input +* `UNKNOWN` — no L2 hash provided * `L2_PENDING` — L2 receipt missing * `PENDING` — included on L2 but not yet finalizable * `READY_TO_FINALIZE` — can be finalized on L1 now @@ -142,35 +148,31 @@ Phases: ```ts const s = await sdk.withdrawals.status(handle); -/* -s = { phase, l2TxHash, key? } // key identifies the canonical message for finalization -*/ +// { phase, l2TxHash, key? } ``` -### `wait(h | l2TxHash, { for: 'l2' | 'ready' | 'finalized', pollMs?, timeoutMs? })` +### `wait(handleOrHash, { for: 'l2' | 'ready' | 'finalized', pollMs?, timeoutMs? })` Block until a target is reached. * `{ for: 'l2' }` → resolves **L2 receipt** (`TransactionReceiptZKsyncOS`) or `null` - (SDK augments with `l2ToL1Logs` if available). -* `{ for: 'ready' }` → resolves `null` when finalization becomes possible. -* `{ for: 'finalized' }` → resolves **L1 receipt** when found, otherwise `null` (even if finalized). +* `{ for: 'ready' }` → resolves `null` when finalizable +* `{ for: 'finalized' }` → resolves **L1 receipt** (if found) or `null` ```ts -// 1) L2 inclusion const l2Rcpt = await sdk.withdrawals.wait(handle, { for: "l2" }); - -// 2) Finalization readiness (no side effects) await sdk.withdrawals.wait(handle, { for: "ready", pollMs: 6000, timeoutMs: 15 * 60_000 }); - -// 3) Wait for finalized (returns L1 receipt or null) const l1Rcpt = await sdk.withdrawals.wait(handle, { for: "finalized", pollMs: 7000 }); ``` - Default polling is 5500ms (minimum 1000ms). Use timeoutMs for long windows. +Default polling is 5500 ms (min 1000 ms). Use timeoutMs for long windows. +### `tryWait(handleOrHash, opts) → Result` + +Result-style `wait`. + ### `finalize(l2TxHash: Hex) → Promise<{ status: WithdrawalStatus; receipt?: TransactionReceipt }>` Sends the **L1 finalize** transaction **if** ready. If already finalized, returns the status without sending. @@ -183,13 +185,12 @@ if (status.phase === "FINALIZED") { ``` - Behavior: If the withdrawal is not ready, finalize throws a typed STATE error. - Use status(...) or `wait(..., { for: 'ready' })` to check first. +If not ready, finalize throws a typed STATE error. Use status(...) or `wait(..., { for: 'ready' })` first to avoid throws. -### `tryFinalize(l2TxHash) → Promise<{ ok: true; value: { status; receipt? } } | { ok: false; error }>` +### `tryFinalize(l2TxHash) → Promise<{ ok: true; value: { status: WithdrawalStatus; receipt?: TransactionReceipt } } | { ok: false; error }>` -Result-style version of `finalize`. +Result-style `finalize`. ## End-to-end examples @@ -198,25 +199,23 @@ Result-style version of `finalize`. ```ts const handle = await sdk.withdrawals.create({ token, amount, to }); -// Wait L2 inclusion +// L2 inclusion await sdk.withdrawals.wait(handle, { for: "l2" }); -// Either finalize immediately… -const { status, receipt } = await sdk.withdrawals.finalize(handle.l2TxHash); +// Option A: finalize immediately (will throw if not ready) +await sdk.withdrawals.finalize(handle.l2TxHash); -// …or wait for readiness first, then finalize +// Option B: wait for readiness, then finalize await sdk.withdrawals.wait(handle, { for: "ready" }); -const done = await sdk.withdrawals.finalize(handle.l2TxHash); +await sdk.withdrawals.finalize(handle.l2TxHash); ``` -## Types (shape overview) - -These types live in `core/types` and are summarized here for convenience. +## Types (overview) ```ts type WithdrawParams = { - token: Address; // L2 token (ETH handled internally) - amount: bigint; // in wei + token: Address; // L2 token (ETH sentinel supported) + amount: bigint; // wei to: Address; // L1 recipient }; @@ -246,10 +245,13 @@ type WithdrawalStatus = | { phase: "READY_TO_FINALIZE"; l2TxHash: Hex; key: unknown } | { phase: "FINALIZED"; l2TxHash: Hex; key: unknown }; -// The L2 receipt returned by wait({ for: 'l2' }) is augmented: -type TransactionReceiptZKsyncOS = TransactionReceipt & { l2ToL1Logs?: Array }; +// L2 receipt augmentation returned by wait({ for: 'l2' }) +type TransactionReceiptZKsyncOS = + TransactionReceipt & { l2ToL1Logs?: Array }; ``` - - Prefer the try* variants if you want result objects instead of exceptions. - +## Notes & pitfalls + +* **Two chains, two receipts:** inclusion on **L2** and finalization on **L1** are independent events. +* **Polling strategy:** for production UIs, prefer `wait({ for: 'ready' })` then finalize; it avoids premature finalize calls. +* **Approvals:** if withdrawing ERC-20 requires approvals, `create` will include those steps automatically. diff --git a/docs/docs.json b/docs/docs.json index b054644..8dc4ac9 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -1,7 +1,7 @@ { "$schema": "https://mintlify.com/docs.json", "theme": "aspen", - "name": "ZKsyncOS SDK", + "name": "ZKsync SDK", "colors": { "primary": "#1755F4", "light": "#BFF351", @@ -67,8 +67,8 @@ ] }, { - "tab": "API Reference", - "icon": "code", + "tab": "SDK Reference", + "icon": "brackets-curly", "groups": [ { "group": "Overview", diff --git a/docs/style.css b/docs/style.css index 00bdc58..20e827a 100644 --- a/docs/style.css +++ b/docs/style.css @@ -206,7 +206,6 @@ html, body { overflow-x: hidden; } .dev-card{ max-width:520px; } } - /* Base CTA styles (unchanged) */ .hero-cta{ display:inline-flex; align-items:center; justify-content:center; gap:8px; @@ -253,3 +252,53 @@ html, body { overflow-x: hidden; } background:#f8fafc; border-color: rgba(2,6,23,.40); } + +/* ---- Top-only gradient bleed for non-hero pages (scrolls away) ---- */ + +:root { --zk-bleed-height: min(38vh, 560px); } + +body { /* create a containing block for the pseudo */ + position: relative; + background: var(--surface); +} +:root.dark body { background: var(--ink-0); } + +/* Only on pages WITHOUT the hero */ +body:not(.has-hero)::before { + content: ""; + position: absolute; /* <-- was fixed; now scrolls with page */ + top: 0; left: 0; right: 0; + height: var(--zk-bleed-height); + pointer-events: none; + z-index: 0; + + /* same gradients as your hero--ai (light) */ + background: + radial-gradient(rgba(23,85,244,.06) 1px, transparent 1.2px) 0 0 / 18px 18px, + radial-gradient(1200px 700px at 85% -10%, rgba(12,24,236,.26), transparent 60%), + radial-gradient(1100px 600px at 10% 80%, rgba(19,213,211,.24), transparent 60%), + radial-gradient(900px 580px at 30% 20%, rgba(239,109,242,.20), transparent 60%), + radial-gradient(900px 520px at 70% 70%, rgba(253,64,44,.16), transparent 60%), + radial-gradient(1200px 520px at -10% -20%, rgba(191,243,81,.18), transparent 60%), + transparent; + /* soft fade */ + mask-image: linear-gradient(to bottom, rgba(0,0,0,.95) 58%, rgba(0,0,0,0)); + -webkit-mask-image: linear-gradient(to bottom, rgba(0,0,0,.95) 58%, rgba(0,0,0,0)); + /* bottom divider */ + box-shadow: inset 0 -1px 0 var(--line); +} + +/* Dark mode */ +:root.dark body:not(.has-hero)::before { + background: + radial-gradient(rgba(23,85,244,.13) 1px, transparent 1.2px) 0 0 / 18px 18px, + radial-gradient(1250px 720px at 62% -10%, rgba(12,24,236,.60), transparent 62%), + radial-gradient(1100px 650px at 10% 86%, rgba(19,213,211,.25), transparent 62%), + radial-gradient(900px 600px at 26% 28%, rgba(239,109,242,.25), transparent 62%), + radial-gradient(900px 560px at 76% 72%, rgba(253,64,44,.18), transparent 62%), + radial-gradient(1100px 540px at -10% -20%, rgba(191,243,81,.16), transparent 62%), + transparent; +} + +/* Ensure page content paints above the pseudo without fiddling z-index everywhere */ +body > * { position: relative; } From c9fe2b077e242fd69262e90dca65680d8f642f31 Mon Sep 17 00:00:00 2001 From: Dustin Brickwood Date: Fri, 10 Oct 2025 15:00:12 -0500 Subject: [PATCH 11/18] chore: finalize docs --- docs/api-reference/ethers/client.mdx | 92 +++-- docs/api-reference/ethers/overview.mdx | 0 docs/api-reference/ethers/sdk.mdx | 99 +++--- docs/api-reference/openapi.json | 217 ------------ docs/api-reference/viem/client.mdx | 126 +++---- docs/api-reference/viem/deposits.mdx | 226 +++++++------ docs/api-reference/viem/overview.mdx | 0 docs/api-reference/viem/sdk.mdx | 115 ++++--- docs/api-reference/viem/withdrawals.mdx | 194 ++++++----- docs/docs.json | 3 +- docs/essentials/code.mdx | 35 -- docs/essentials/images.mdx | 59 ---- docs/essentials/markdown.mdx | 88 ----- docs/essentials/navigation.mdx | 87 ----- docs/essentials/reusable-snippets.mdx | 110 ------ docs/essentials/settings.mdx | 318 ------------------ docs/guides/deposits.mdx | 429 ++++++++++++++++++++---- docs/guides/withdrawals.mdx | 412 +++++++++++++++++++++++ docs/index.mdx | 6 +- docs/snippets/deposits/ethers.mdx | 88 ----- docs/snippets/deposits/viem.mdx | 106 ------ docs/snippets/withdrawals/ethers.mdx | 0 docs/snippets/withdrawals/viem.mdx | 0 23 files changed, 1216 insertions(+), 1594 deletions(-) delete mode 100644 docs/api-reference/ethers/overview.mdx delete mode 100644 docs/api-reference/openapi.json delete mode 100644 docs/api-reference/viem/overview.mdx delete mode 100644 docs/essentials/code.mdx delete mode 100644 docs/essentials/images.mdx delete mode 100644 docs/essentials/markdown.mdx delete mode 100644 docs/essentials/navigation.mdx delete mode 100644 docs/essentials/reusable-snippets.mdx delete mode 100644 docs/essentials/settings.mdx delete mode 100644 docs/snippets/deposits/ethers.mdx delete mode 100644 docs/snippets/deposits/viem.mdx delete mode 100644 docs/snippets/withdrawals/ethers.mdx delete mode 100644 docs/snippets/withdrawals/viem.mdx diff --git a/docs/api-reference/ethers/client.mdx b/docs/api-reference/ethers/client.mdx index a0d3c01..9a85114 100644 --- a/docs/api-reference/ethers/client.mdx +++ b/docs/api-reference/ethers/client.mdx @@ -1,22 +1,26 @@ --- title: EthersClient -description: Low-level client that carries providers/signer, resolves core contract addresses, and exposes convenience contract instances for the Ethers adapter. -group: API Reference / Ethers +description: Low-level client for the Ethers adapter. Carries providers/signer, resolves core contract addresses, and exposes connected ethers.Contract instances. +group: SDK Reference / Ethers --- +## At a glance + +- **Factory:** `createEthersClient({ l1, l2, signer, overrides? }) → EthersClient` +- **What it provides:** cached core **addresses**, connected **contracts**, L2-bound **ZKsync RPC** (`zks`), and a signer force-bound to **L1**. +- **When to use:** create this first; then pass into `createEthersSdk(client)`. + ## Import ```ts -import { - createEthersClient, -} from '@dutterbutter/zksync-sdk/ethers'; +import { createEthersClient } from "@dutterbutter/zksync-sdk/ethers"; ``` ## Quick start ```ts -import { JsonRpcProvider, Wallet } from 'ethers'; -import { createEthersClient } from '@dutterbutter/zksync-sdk/ethers'; +import { JsonRpcProvider, Wallet } from "ethers"; +import { createEthersClient } from "@dutterbutter/zksync-sdk/ethers"; const l1 = new JsonRpcProvider(process.env.ETH_RPC!); const l2 = new JsonRpcProvider(process.env.ZKSYNC_RPC!); @@ -24,90 +28,67 @@ const signer = new Wallet(process.env.PRIVATE_KEY!, l1); const client = createEthersClient({ l1, l2, signer }); -// Resolve core addresses once (cached) +// Resolve core addresses (cached) const addrs = await client.ensureAddresses(); -// Grab connected Contract instances +// Connected contracts const { bridgehub, l1AssetRouter } = await client.contracts(); ``` + +The signer is force-bound to the **L1** provider to make L1 finalization flows work out of the box. + + ## `createEthersClient(args) → EthersClient` - - L1 provider used for address resolution and L1 transactions. - - - L2 provider (target ZK chain). Used for ZK RPC and reads. - - - Signer used for sends. If not already connected to args.l1, it will be connected. - - - Optional manual contract-address overrides (useful for forks or testing). - +L1 provider for reads and L1 transactions. L2 (ZKsync) provider for reads and ZK RPC. Signer for sends. If not connected to args.l1, it will be connected. Optional address overrides (forks/tests). - - The signer is force-bound to the L1 provider to ensure finalize transactions work out of the box. - +**Returns:** `EthersClient` ## EthersClient interface - - Discriminator for the adapter. - - - Read/write L1 provider. - - - Read-only L2 provider (target ZK chain). - - - Signer used for sends; connected to l1. - - - ZKsync-specific RPC surface bound to l2. - +Adapter discriminator. Public L1 provider. Public L2 (ZKsync) provider. Signer (bound to l1 for sends). ZKsync-specific RPC surface bound to l2. -### Methods +## Methods -#### `ensureAddresses() → Promise` +### `ensureAddresses() → Promise` -Resolves and caches core contract addresses via on-chain lookups (and optional overrides). +Resolve and cache core contract addresses from chain state (merges any `overrides`). ```ts const a = await client.ensureAddresses(); /* -a = { +{ bridgehub, l1AssetRouter, l1Nullifier, l1NativeTokenVault, l2AssetRouter, l2NativeTokenVault, l2BaseTokenSystem } */ ``` -#### `contracts() → Promise<{ ...contracts }>` +### `contracts() → Promise<{ ...contracts }>` -Returns connected `ethers.Contract` instances for all core contracts. +Return connected `ethers.Contract` instances for all core contracts. ```ts const c = await client.contracts(); -const bh = c.bridgehub; +const bh = c.bridgehub; // call bh.getAddress(), bh.interface, bh.functions.*, etc. ``` -#### `refresh(): void` +### `refresh(): void` -Clears cached addresses/contracts. Next calls will re-resolve. +Clear cached addresses/contracts. Subsequent calls re-resolve. ```ts client.refresh(); -await client.ensureAddresses(); // re-fetches +await client.ensureAddresses(); ``` -#### `baseToken(chainId: bigint) → Promise
` +### `baseToken(chainId: bigint) → Promise
` -Looks up the **L1 address** of the base token for a given L2 chain via `Bridgehub.baseToken(chainId)`. +Return the **L1 base-token address** for a given L2 chain via `Bridgehub.baseToken(chainId)`. ```ts -const base = await client.baseToken( BigInt(324) /* ZKsync Era */ ); +const base = await client.baseToken(324n /* e.g., Era */); ``` ## Types @@ -125,3 +106,10 @@ type ResolvedAddresses = { l2BaseTokenSystem: Address; }; ``` + +## Notes & pitfalls + +* **Provider roles:** `l1` is used for L1 lookups and finalization sends; `l2` is used for ZKsync reads/RPC via `zks`. +* **Signer binding:** The signer is connected to `l1` to ensure L1 transactions (e.g., finalize) succeed without extra wiring. +* **Caching:** `ensureAddresses()` and `contracts()` are cached. Call `refresh()` after network changes or when using new overrides. +* **Overrides:** For forks or custom deployments, pass `overrides` at construction; they are merged with on-chain resolution. diff --git a/docs/api-reference/ethers/overview.mdx b/docs/api-reference/ethers/overview.mdx deleted file mode 100644 index e69de29..0000000 diff --git a/docs/api-reference/ethers/sdk.mdx b/docs/api-reference/ethers/sdk.mdx index 49426a2..a527259 100644 --- a/docs/api-reference/ethers/sdk.mdx +++ b/docs/api-reference/ethers/sdk.mdx @@ -1,23 +1,29 @@ --- title: EthersSdk -description: High-level SDK for deposits, withdrawals, and helpers using the Ethers adapter. -group: API Reference / Ethers +description: High-level SDK composed over the Ethers adapter - deposits, withdrawals, and chain-aware helpers. +group: SDK Reference / Ethers --- +## At a glance + +- **Factory:** `createEthersSdk(client) → EthersSdk` +- **Composed resources:** `sdk.deposits`, `sdk.withdrawals`, `sdk.helpers` +- **Client vs SDK:** the **client** wires RPC/signing; the **sdk** adds high-level flows (quote → prepare → create → wait) and convenience helpers. + ## Import ```ts import { createEthersClient, createEthersSdk, -} from '@dutterbutter/zksync-sdk/ethers'; +} from "@dutterbutter/zksync-sdk/ethers"; ``` ## Quick start ```ts -import { JsonRpcProvider, Wallet } from 'ethers'; -import { createEthersClient, createEthersSdk } from '@dutterbutter/zksync-sdk/ethers'; +import { JsonRpcProvider, Wallet, parseEther } from "ethers"; +import { createEthersClient, createEthersSdk } from "@dutterbutter/zksync-sdk/ethers"; const l1 = new JsonRpcProvider(process.env.ETH_RPC!); const l2 = new JsonRpcProvider(process.env.ZKSYNC_RPC!); @@ -26,44 +32,54 @@ const signer = new Wallet(process.env.PRIVATE_KEY!, l1); const client = createEthersClient({ l1, l2, signer }); const sdk = createEthersSdk(client); -// Example: get contracts and the L2 address for an L1 token +// Example: deposit 0.05 ETH L1 → L2, wait for L2 execution +const handle = await sdk.deposits.create({ + token: ETH_ADDRESS, // 0x…00 sentinel for ETH supported + amount: parseEther("0.05"), + to: await signer.getAddress(), +}); + +await sdk.deposits.wait(handle, { for: "l2" }); + +// Example: resolve core contracts const { l1NativeTokenVault } = await sdk.helpers.contracts(); -const l1_crown_address = await sdk.helpers.l1TokenAddress(CROWN_ERC20_ADDRESS); ``` ## `createEthersSdk(client) → EthersSdk` - Instance created by createEthersClient. + Instance returned by `createEthersClient({ l1, l2, signer })`. +**Returns:** `EthersSdk` + - The SDK composes the client with high-level resources: deposits, withdrawals, and convenience helpers. +The SDK composes the client with resources: deposits, withdrawals, and convenience helpers. ## EthersSdk interface - - L1 → L2 flows (quote, prepare, create, status, wait). See Deposits. - +### `deposits: DepositsResource` - - L2 → L1 flows (quote, prepare, create, status, wait, finalize). See Withdrawals. - +L1 → L2 flows. See **[Deposits](/api-reference/ethers/deposits)**. -### `helpers` +### `withdrawals: WithdrawalsResource` -Utilities for addresses, contracts, and token mapping. +L2 → L1 flows. See **[Withdrawals](/api-reference/ethers/withdrawals)**. -#### `addresses() → Promise` +## helpers -Resolves core addresses (Bridgehub, routers, vaults, base token system). +Utilities for chain addresses, connected contracts, and L1↔L2 token mapping. + +### `addresses() → Promise` + +Resolve core addresses (Bridgehub, routers, vaults, base-token system). ```ts const a = await sdk.helpers.addresses(); ``` -#### `contracts() → Promise<{ ...contracts }>` +### `contracts() → Promise<{ ...contracts }>` Connected `ethers.Contract` instances for all core contracts. @@ -71,55 +87,54 @@ Connected `ethers.Contract` instances for all core contracts. const c = await sdk.helpers.contracts(); ``` -#### `l1AssetRouter() / l1NativeTokenVault() / l1Nullifier() → Promise` +### One-off contract getters -One-off getters if you only need a specific contract. +`l1AssetRouter() → Promise` +`l1NativeTokenVault() → Promise` +`l1Nullifier() → Promise` ```ts const nullifier = await sdk.helpers.l1Nullifier(); ``` -#### `baseToken(chainId?: bigint) → Promise
` +### `baseToken(chainId?: bigint) → Promise
` -L1 address of the base token for a given **L2 chain**. If omitted, uses the current L2 provider’s chain id. +L1 address of the **base token** for the current (or supplied) L2 chain. ```ts -const base = await sdk.helpers.baseToken(); // infer from client.l2 +const base = await sdk.helpers.baseToken(); // infers from client.l2 ``` -#### `l2TokenAddress(l1Token: Address) → Promise
` +### `l2TokenAddress(l1Token: Address) → Promise
` -Returns the **L2 token address** for a given **L1 token**. +L2 token address for an L1 token. -* Handles ETH special-case (L2 ETH placeholder). -* If the token equals the chain’s base token, returns the L2 base-token system address. +* Handles ETH special case (L2 ETH placeholder). +* If token is the chain’s base token, returns the L2 base-token system address. * Otherwise queries `IL2NativeTokenVault.l2TokenAddress`. ```ts -const l2_crown_address = await sdk.helpers.l2TokenAddress(CROWN_ERC20_ADDRESS); +const l2Crown = await sdk.helpers.l2TokenAddress(CROWN_ERC20_ADDRESS); ``` -#### `l1TokenAddress(l2Token: Address) → Promise
` +### `l1TokenAddress(l2Token: Address) → Promise
` -Returns the **L1 token address** from an **L2 token** using `IL2AssetRouter.l1TokenAddress`. - -* ETH placeholder on L2 resolves to the canonical ETH address. +L1 token for an L2 token via `IL2AssetRouter.l1TokenAddress`. ETH placeholder resolves to canonical ETH. ```ts -const l1_crown_address = await sdk.helpers.l1TokenAddress(CROWN_ERC20_ADDRESS); +const l1Crown = await sdk.helpers.l1TokenAddress(L2_CROWN_ADDRESS); ``` -#### `assetId(l1Token: Address) → Promise` - -Computes the `bytes32` asset identifier for an L1 token via `L1NativeTokenVault.assetId`. +### `assetId(l1Token: Address) → Promise` -* Treats canonical ETH appropriately. +`bytes32` asset ID via `L1NativeTokenVault.assetId` (ETH handled canonically). ```ts const id = await sdk.helpers.assetId(CROWN_ERC20_ADDRESS); ``` -## Notes +## Notes & pitfalls -* The SDK defers to on-chain sources where possible; results may depend on the connected chain(s). -* Errors surface as typed envelopes (see **Error Model** in API Reference intro). Use the try* variants on resources if you prefer result objects over exceptions. +* **Client first:** You must construct the **client** with `{ l1, l2, signer }` before creating the SDK. +* **Chain-derived behavior:** helpers pull from on-chain sources; results depend on the connected networks. +* **Error model:** resource methods throw typed errors; prefer try* variants on resources for result objects. diff --git a/docs/api-reference/openapi.json b/docs/api-reference/openapi.json deleted file mode 100644 index da5326e..0000000 --- a/docs/api-reference/openapi.json +++ /dev/null @@ -1,217 +0,0 @@ -{ - "openapi": "3.1.0", - "info": { - "title": "OpenAPI Plant Store", - "description": "A sample API that uses a plant store as an example to demonstrate features in the OpenAPI specification", - "license": { - "name": "MIT" - }, - "version": "1.0.0" - }, - "servers": [ - { - "url": "http://sandbox.mintlify.com" - } - ], - "security": [ - { - "bearerAuth": [] - } - ], - "paths": { - "/plants": { - "get": { - "description": "Returns all plants from the system that the user has access to", - "parameters": [ - { - "name": "limit", - "in": "query", - "description": "The maximum number of results to return", - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Plant response", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Plant" - } - } - } - } - }, - "400": { - "description": "Unexpected error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - } - } - }, - "post": { - "description": "Creates a new plant in the store", - "requestBody": { - "description": "Plant to add to the store", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/NewPlant" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "plant response", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Plant" - } - } - } - }, - "400": { - "description": "unexpected error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - } - } - } - }, - "/plants/{id}": { - "delete": { - "description": "Deletes a single plant based on the ID supplied", - "parameters": [ - { - "name": "id", - "in": "path", - "description": "ID of plant to delete", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "204": { - "description": "Plant deleted", - "content": {} - }, - "400": { - "description": "unexpected error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Error" - } - } - } - } - } - } - } - }, - "webhooks": { - "/plant/webhook": { - "post": { - "description": "Information about a new plant added to the store", - "requestBody": { - "description": "Plant added to the store", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/NewPlant" - } - } - } - }, - "responses": { - "200": { - "description": "Return a 200 status to indicate that the data was received successfully" - } - } - } - } - }, - "components": { - "schemas": { - "Plant": { - "required": [ - "name" - ], - "type": "object", - "properties": { - "name": { - "description": "The name of the plant", - "type": "string" - }, - "tag": { - "description": "Tag to specify the type", - "type": "string" - } - } - }, - "NewPlant": { - "allOf": [ - { - "$ref": "#/components/schemas/Plant" - }, - { - "required": [ - "id" - ], - "type": "object", - "properties": { - "id": { - "description": "Identification number of the plant", - "type": "integer", - "format": "int64" - } - } - } - ] - }, - "Error": { - "required": [ - "error", - "message" - ], - "type": "object", - "properties": { - "error": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - } - } - } - }, - "securitySchemes": { - "bearerAuth": { - "type": "http", - "scheme": "bearer" - } - } - } -} \ No newline at end of file diff --git a/docs/api-reference/viem/client.mdx b/docs/api-reference/viem/client.mdx index d70f8ae..ef6d220 100644 --- a/docs/api-reference/viem/client.mdx +++ b/docs/api-reference/viem/client.mdx @@ -1,142 +1,113 @@ --- title: ViemClient -description: Low-level client that carries viem public/wallet clients, resolves core contract addresses, and exposes convenience contract instances for the Viem adapter. -group: API Reference / Viem +description: Low-level client for the Viem adapter. Carries viem public/wallet clients, resolves core contract addresses, and exposes typed contract instances. +group: SDK Reference / Viem --- +## At a glance + +- **Factory:** `createViemClient({ l1, l2, l1Wallet, l2Wallet?, overrides? }) → ViemClient` +- **What it provides:** cached core **addresses**, typed **contracts**, convenience **wallet access** (L2 wallet derivation), and ZKsync **RPC** bound to `l2`. +- **When to use:** create this first; then pass into `createViemSdk(client)`. + ## Import ```ts -import { - createViemClient, -} from '@dutterbutter/zksync-sdk/viem'; +import { createViemClient } from "@dutterbutter/zksync-sdk/viem"; ``` ## Quick start ```ts -import { createPublicClient, createWalletClient, http } from 'viem'; -// import { mainnet } from 'viem/chains' // or your own chain objects +import { createPublicClient, createWalletClient, http } from "viem"; -// Minimal example — provide your chain objects & RPCs. -const l1 = createPublicClient({ /* chain: mainnet, */ transport: http(process.env.ETH_RPC!) }); -const l2 = createPublicClient({ /* chain: zkSync, */ transport: http(process.env.ZKSYNC_RPC!) }); +// Public clients (reads) +const l1 = createPublicClient({ transport: http(process.env.ETH_RPC!) }); +const l2 = createPublicClient({ transport: http(process.env.ZKSYNC_RPC!) }); -// l1 wallet must have an account +// Wallet clients (writes) const l1Wallet = createWalletClient({ - account: /* your Account */, - /* chain: mainnet, */ transport: http(process.env.ETH_RPC!), + account: /* your L1 Account */, + transport: http(process.env.ETH_RPC!), }); -// (optional) a dedicated L2 wallet; if omitted, ViemClient can derive one via getL2Wallet() +// Optional dedicated L2 wallet. Required for L2 sends (withdrawals). const l2Wallet = createWalletClient({ - account: l1Wallet.account, - /* chain: zkSync, */ transport: http(process.env.ZKSYNC_RPC!), + account: /* can be same key as L1 */, + transport: http(process.env.ZKSYNC_RPC!), }); const client = createViemClient({ l1, l2, l1Wallet, l2Wallet }); -// Resolve core addresses once (cached) +// Resolve core addresses (cached) const addrs = await client.ensureAddresses(); -// Grab connected Contract instances (typed viem contracts) +// Typed contracts (viem getContract) const { bridgehub, l1AssetRouter } = await client.contracts(); ``` - l1Wallet.account is required. If you omit l2Wallet, the client will lazily create one that reuses the L1 account over the L2 transport via getL2Wallet(). +l1Wallet.account is required. If you omit l2Wallet, use client.getL2Wallet(); it lazily reuses the L1 account over the L2 transport. ## `createViemClient(args) → ViemClient` - - L1 client used for address resolution and L1 reads. - - - L2 client (target ZK chain). Used for ZK RPC and reads. - - - Wallet used for sends; must include an account. - - - Optional dedicated L2 wallet. If omitted, call getL2Wallet() to obtain a lazily created one. - - - Optional manual contract-address overrides (useful for forks or testing). - +L1 client for reads and chain metadata. L2 (ZKsync) client for reads and ZK RPC. L1 wallet (must include account) used for L1 sends. Optional L2 wallet for L2 sends; otherwise derived via getL2Wallet(). Optional contract-address overrides (forks/tests). + +**Returns:** `ViemClient` ## ViemClient interface - - Discriminator for the adapter. - - - Read/write L1 client. - - - Read-only L2 client (target ZK chain). - - - Wallet bound to L1 RPC; carries the default account for sends. - - - Optional pre-supplied L2 wallet. If not provided, use getL2Wallet(). - - - The default account (from l1Wallet). - - - ZKsync-specific RPC surface bound to l2. - - -### Methods - -#### `ensureAddresses() → Promise` - -Resolves and caches core contract addresses via on-chain lookups (and optional overrides). +Adapter discriminator. Public L1 client. Public L2 (ZKsync) client. Wallet bound to L1 (carries default account). Optional pre-supplied L2 wallet. Default account (from l1Wallet). ZKsync-specific RPC bound to l2. + +## Methods + +### `ensureAddresses() → Promise` + +Resolve and cache core contract addresses from chain state (merges any `overrides`). ```ts const a = await client.ensureAddresses(); /* -a = { +{ bridgehub, l1AssetRouter, l1Nullifier, l1NativeTokenVault, l2AssetRouter, l2NativeTokenVault, l2BaseTokenSystem } */ ``` -#### `contracts() → Promise<{ ...contracts }>` +### `contracts() → Promise<{ ...contracts }>` -Returns connected **typed viem contracts** (`getContract(...)`) for all core contracts. +Return **typed** viem contracts (`getContract`) connected to the current clients. ```ts const c = await client.contracts(); -const bh = c.bridgehub; +const bh = c.bridgehub; // bh.read.*, bh.write.*, bh.simulate.* ``` -#### `refresh(): void` +### `refresh(): void` -Clears cached addresses/contracts. Next calls will re-resolve. +Clear cached addresses/contracts. Subsequent calls re-resolve. ```ts client.refresh(); -await client.ensureAddresses(); // re-fetches +await client.ensureAddresses(); ``` -#### `baseToken(chainId: bigint) → Promise
` +### `baseToken(chainId: bigint) → Promise
` -Looks up the **L1 address** of the base token for a given L2 chain via `Bridgehub.baseToken(chainId)`. +Return the **L1 base-token address** for a given L2 chain via `Bridgehub.baseToken(chainId)`. ```ts -const base = await client.baseToken( BigInt(324) /* e.g., zk chain id */ ); +const base = await client.baseToken(324n /* example L2 chain id */); ``` -#### `getL2Wallet() → WalletClient` +### `getL2Wallet() → viem.WalletClient` -Returns the L2 wallet. If one wasn’t passed at construction, it lazily creates a wallet using the **same account** as `l1Wallet` with the L2 transport. +Return the L2 wallet. If not provided at construction, lazily creates one from the **same account** as `l1Wallet` over the L2 transport. ```ts -const l2W = client.getL2Wallet(); +const w = client.getL2Wallet(); // ensures L2 writes are possible ``` ## Types @@ -154,3 +125,10 @@ type ResolvedAddresses = { l2BaseTokenSystem: Address; }; ``` + +## Notes & pitfalls + +* **Wallet placement:** Deposits sign on **L1**; withdrawals sign on **L2**; finalization signs on **L1** (via SDK). +* **Caching:** `ensureAddresses()` and `contracts()` are cached. Use `refresh()` after network/override changes. +* **Overrides:** For forks or custom deployments, pass `overrides` at construction; they’ll be merged with on-chain lookups. +* **Error surface:** Methods may throw typed errors; use the SDK’s `try*` variants (on resources) if you prefer result objects. diff --git a/docs/api-reference/viem/deposits.mdx b/docs/api-reference/viem/deposits.mdx index b5733d7..3e0a2b0 100644 --- a/docs/api-reference/viem/deposits.mdx +++ b/docs/api-reference/viem/deposits.mdx @@ -4,77 +4,90 @@ description: L1 → L2 deposits for ETH and ERC-20 with quote, prepare, create, group: API Reference / Viem --- -## Import +## At a glance + +- **Resource:** `sdk.deposits` +- **Most common flow:** `quote → create → wait({ for: 'l2' })` +- **Auto-routing:** ETH vs ERC-20 and base-token vs non-base handled internally +- **Error style:** Throwing methods (`quote`, `prepare`, `create`, `wait`) + result variants (`tryQuote`, `tryPrepare`, `tryCreate`, `tryWait`) -The Deposits resource is available via the **Viem** SDK: +## Import ```ts -import { parseEther } from "viem"; import { - createViemClient, - createViemSdk, -} from "@dutterbutter/zksync-sdk/viem"; + createPublicClient, + createWalletClient, + http, + parseEther, + type Account, + type Chain, + type Transport, + type WalletClient, +} from 'viem'; +import { privateKeyToAccount } from 'viem/accounts'; +import { createViemClient, createViemSdk } from '@dutterbutter/zksync-sdk/viem'; + +const account = privateKeyToAccount(PRIVATE_KEY as `0x${string}`); +const l1 = createPublicClient({ transport: http(L1_RPC) }); +const l2 = createPublicClient({ transport: http(L2_RPC) }); +const l1Wallet: WalletClient = createWalletClient({ + account, + transport: http(L1_RPC), +}); -// Constants (ETH_ADDRESS, etc.) are re-exported by the SDK: -import { ETH_ADDRESS } from "@dutterbutter/zksync-sdk/constants"; -```` +// --- 2. Initialize the SDK --- +const client = createViemClient({ l1, l2, l1Wallet }); +const sdk = createViemSdk(client); +// sdk.deposits → DepositsResource +``` ## Quick start Deposit **0.1 ETH** from L1 → L2 and wait for **L2 execution**: ```ts -const sdk = createViemSdk( - createViemClient({ l1, l2, l1Wallet, l2Wallet }) -); - const handle = await sdk.deposits.create({ - token: ETH_ADDRESS, + token: ETH_ADDRESS, // 0x…00 for ETH amount: parseEther("0.1"), - to: /* L2 recipient address */, + to: await signer.getAddress(), }); -// Wait for canonical L2 execution; returns a viem TransactionReceipt or null -const l2Receipt = await sdk.deposits.wait(handle, { for: "l2" }); +const l2Receipt = await sdk.deposits.wait(handle, { for: "l2" }); // null only if no L1 hash ``` -## Routes (auto-selected) + +For UX that never throws, use the try* variants and branch on ok. + -The SDK automatically selects a route based on the **asset** and the **L2 base token**: +## Route selection (automatic) -* `eth-base` — Deposit ETH when L2 base token is **ETH** -* `eth-nonbase` — Deposit ETH when L2 base token is **not ETH** -* `erc20-base` — Deposit ERC-20 that **is** the L2 base token -* `erc20-nonbase` — Deposit ERC-20 that **is not** the L2 base token +* `eth-base` — ETH when L2 base token **is ETH** +* `eth-nonbase` — ETH when L2 base token **≠ ETH** +* `erc20-base` — ERC-20 that **is** the L2 base token +* `erc20-nonbase` — ERC-20 that **is not** the L2 base token -You don’t need to pass a route; it’s derived internally. +You **do not** pass a route; it’s derived from network metadata + `token`. -## Methods +## Method reference ### `quote(p: DepositParams) → Promise` -Get a **non-executing** summary of the deposit (route, approvals, gas hints). +Estimate the operation (route, approvals, gas hints). Does **not** send txs. + +L1 token (use 0x…00 for ETH). Amount in wei. L2 recipient. - - L1 token address (use 0x…00 or ETH_ADDRESS for ETH). - - - Amount in wei (e.g., parseEther("0.25")). - - - Recipient on L2. - +**Returns:** `DepositQuote` ```ts const q = await sdk.deposits.quote({ - token: ETH_ADDRESS, + token: ETH_L1, amount: parseEther("0.25"), - to: /* L2 recipient */, + to: await signer.getAddress(), }); /* -q = { +{ route: "eth-base" | "eth-nonbase" | "erc20-base" | "erc20-nonbase", - approvalsNeeded: [{ token, spender, amount }, ...], + approvalsNeeded: [{ token, spender, amount }], baseCost?: bigint, mintValue?: bigint, suggestedL2GasLimit?: bigint, @@ -84,137 +97,130 @@ q = { ``` - If approvalsNeeded is non-empty for ERC-20 deposits, the SDK will include approval steps during create. +If approvalsNeeded is non-empty (ERC-20), create will include those steps automatically. -### `tryQuote(p) → Promise<{ ok: true; value } | { ok: false; error }>` +### `tryQuote(p) → Promise<{ ok: true; value: DepositQuote } | { ok: false; error }>` + +Result-style `quote`. -Result-style version of `quote`. +### `prepare(p: DepositParams) → Promise>` -### `prepare(p: DepositParams) → Promise>` +Builds the plan (ordered steps + unsigned txs) without sending. -Build the **plan** (route + ordered steps) without sending transactions. +**Returns:** `DepositPlan` ```ts -const plan = await sdk.deposits.prepare({ - token: ETH_ADDRESS, - amount: parseEther("0.05"), - to: /* L2 recipient */, -}); +const plan = await sdk.deposits.prepare({ token: ETH_L1, amount: parseEther("0.05"), to }); /* -plan = { +{ route, - summary: { ...DepositQuote }, + summary: DepositQuote, steps: [ - // Each step has a unique .key, a .kind - // and a Viem "writeContract" request in .tx (ViemPlanWriteRequest) + { key: "approve:USDC", kind: "approve", tx: TransactionRequest }, + { key: "bridge", kind: "bridge", tx: TransactionRequest } ] } */ ``` -### `tryPrepare(p) → Promise<{ ok: true; value } | { ok: false; error }>` +### `tryPrepare(p) → Promise<{ ok: true; value: DepositPlan } | { ok: false; error }>` + +Result-style `prepare`. -Result-style version of `prepare`. +### `create(p: DepositParams) → Promise>` -### `create(p: DepositParams) → Promise>` +Prepares and **executes** all required L1 steps. Returns a handle (with L1 tx hash and per-step hashes). -Prepare and **execute** all required steps on **L1** (via Viem `writeContract`). Returns a handle with the L1 hash. +**Returns:** `DepositHandle` ```ts const handle = await sdk.deposits.create({ token, amount, to }); /* -handle = { +{ kind: "deposit", - l1TxHash, // Hex - stepHashes: Record, // tx hashes per step - plan // DepositPlan returned by prepare() + l1TxHash: Hex, + stepHashes: Record, + plan: DepositPlan } */ ``` - If any step reverts on L1, create throws a typed error. - Use tryCreate if you prefer a result object. +If any step reverts, create throws a typed error. Prefer tryCreate to avoid exceptions. -### `tryCreate(p) → Promise<{ ok: true; value } | { ok: false; error }>` +### `tryCreate(p) → Promise<{ ok: true; value: DepositHandle } | { ok: false; error }>` -Result-style version of `create`. +Result-style `create`. -### `status(h | l1TxHash) → Promise` +### `status(handleOrHash) → Promise` -Check a deposit’s current phase. Accepts the **handle** from `create` or a raw **L1 tx hash**. +Resolve current phase for a deposit. Accepts the `DepositHandle` from `create` **or** a raw L1 tx hash. -Phases: +**Phases** -* `UNKNOWN` — no L1 hash on input -* `L1_PENDING` — L1 receipt not found yet -* `L1_INCLUDED` — included on L1 but L2 hash not yet derivable -* `L2_PENDING` — L2 hash known but L2 receipt missing -* `L2_EXECUTED` — L2 receipt found with `status === 'success'` -* `L2_FAILED` — L2 receipt found with `status !== 'success'` +* `UNKNOWN` — no L1 hash provided +* `L1_PENDING` — L1 receipt not yet found +* `L1_INCLUDED` — included on L1; L2 hash not derivable yet +* `L2_PENDING` — L2 hash known; waiting for L2 receipt +* `L2_EXECUTED` — L2 receipt found with `status === 1` +* `L2_FAILED` — L2 receipt found with `status !== 1` ```ts const s = await sdk.deposits.status(handle); -/* -s = { phase, l1TxHash, l2TxHash? } -*/ +// { phase, l1TxHash, l2TxHash? } ``` -### `wait(h | l1TxHash, { for: 'l1' | 'l2' }) → Promise` +### `wait(handleOrHash, { for: 'l1' | 'l2' }) → Promise` -Block until a checkpoint: +Block until the chosen checkpoint. -* `{ for: 'l1' }` → resolves the **L1 receipt** (or `null` if no L1 hash on input) -* `{ for: 'l2' }` → resolves the **L2 receipt** after canonical execution (or `null` if no L1 hash) +* `{ for: 'l1' }` → L1 receipt (or `null` if no L1 hash available) +* `{ for: 'l2' }` → L2 receipt after canonical execution (or `null` if no L1 hash) ```ts const l1Receipt = await sdk.deposits.wait(handle, { for: "l1" }); const l2Receipt = await sdk.deposits.wait(handle, { for: "l2" }); ``` -### `tryWait(h, { for }) → Promise<{ ok: true; value } | { ok: false; error }>` +### `tryWait(handleOrHash, opts) → Result` -Result-style version of `wait`. +Result-style `wait`. ## End-to-end examples -### ETH deposit (most common) +### ETH deposit (typical) ```ts const handle = await sdk.deposits.create({ token: ETH_ADDRESS, amount: parseEther("0.1"), - to: /* L2 recipient */, + to: await signer.getAddress(), }); -await sdk.deposits.wait(handle, { for: "l2" }); // get L2 receipt when executed +await sdk.deposits.wait(handle, { for: "l2" }); ``` -### ERC-20 deposit with approvals +### ERC-20 deposit (with automatic approvals) ```ts const handle = await sdk.deposits.create({ - token: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // erc20 token example - amount: 1_000_000n, // USDC 6 decimals - to: /* L2 recipient */, + token: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // example: USDC + amount: 1_000_000n, // 1.0 USDC (6 dp) + to: await signer.getAddress(), }); -// Wait for L1 inclusion only, if you need to chain logic at that point const l1Receipt = await sdk.deposits.wait(handle, { for: "l1" }); ``` -## Types (shape overview) - -These types live in `core/types` and are summarized here for convenience. +## Types (overview) ```ts type DepositParams = { - token: Address; // L1 token (0x…00 for ETH) - amount: bigint; // in wei - to: Address; // L2 recipient - // ...see core/types for full spec + token: Address; // 0x…00 for ETH + amount: bigint; // wei + to: Address; // L2 recipient }; type DepositQuote = { @@ -226,13 +232,13 @@ type DepositQuote = { gasPerPubdata?: bigint; }; -type DepositPlan = { +type DepositPlan = { route: DepositQuote["route"]; summary: DepositQuote; steps: Array<{ key: string; kind: string; tx: TTx }>; }; -type DepositHandle = { +type DepositHandle = { kind: "deposit"; l1TxHash: Hex; stepHashes: Record; @@ -240,14 +246,20 @@ type DepositHandle = { }; type DepositStatus = - | { phase: "UNKNOWN"; l1TxHash: Hex } - | { phase: "L1_PENDING"; l1TxHash: Hex } - | { phase: "L1_INCLUDED"; l1TxHash: Hex } - | { phase: "L2_PENDING"; l1TxHash: Hex; l2TxHash: Hex } - | { phase: "L2_EXECUTED"; l1TxHash: Hex; l2TxHash: Hex } - | { phase: "L2_FAILED"; l1TxHash: Hex; l2TxHash: Hex }; + | { phase: "UNKNOWN"; l1TxHash: Hex } + | { phase: "L1_PENDING"; l1TxHash: Hex } + | { phase: "L1_INCLUDED"; l1TxHash: Hex } + | { phase: "L2_PENDING"; l1TxHash: Hex; l2TxHash: Hex } + | { phase: "L2_EXECUTED"; l1TxHash: Hex; l2TxHash: Hex } + | { phase: "L2_FAILED"; l1TxHash: Hex; l2TxHash: Hex }; ``` - Prefer the try* variants if you want to avoid exceptions and work with result objects. +Prefer the try* variants if you want to avoid exceptions and work with result objects. + +## Notes & pitfalls + +* **ETH sentinel:** use the canonical `0x…00` address when passing ETH as `token`. +* **Receipts timing:** `wait({ for: 'l2' })` resolves on canonical L2 execution; it can take longer than L1 inclusion. +* **Gas hints:** `suggestedL2GasLimit` and `gasPerPubdata` are hints; advanced users may override via low-level calls from the plan. diff --git a/docs/api-reference/viem/overview.mdx b/docs/api-reference/viem/overview.mdx deleted file mode 100644 index e69de29..0000000 diff --git a/docs/api-reference/viem/sdk.mdx b/docs/api-reference/viem/sdk.mdx index 6065a36..a167792 100644 --- a/docs/api-reference/viem/sdk.mdx +++ b/docs/api-reference/viem/sdk.mdx @@ -1,135 +1,160 @@ --- title: ViemSdk -description: High-level SDK for deposits, withdrawals, and helpers using the Viem adapter. -group: API Reference / Viem +description: High-level SDK composed over the Viem adapter - deposits, withdrawals, and chain-aware helpers. +group: SDK Reference / Viem --- +## At a glance + +- **Factory:** `createViemSdk(client) → ViemSdk` +- **Composed resources:** `sdk.deposits`, `sdk.withdrawals`, `sdk.helpers` +- **Client vs SDK:** the **client** wires RPC/signing; the **sdk** adds high-level flows (quote → prepare → create → wait) and convenience helpers. +- **Wallets by flow:** + - **Deposits (L1 tx):** `l1Wallet` required + - **Withdrawals (L2 tx):** `l2Wallet` required + - **Finalize (L1 tx):** `l1Wallet` required + ## Import ```ts import { createViemClient, createViemSdk, -} from '@dutterbutter/zksync-sdk/viem'; +} from "@dutterbutter/zksync-sdk/viem"; ``` ## Quick start ```ts -import { createPublicClient, createWalletClient, http } from 'viem'; -import { createViemClient, createViemSdk } from '@dutterbutter/zksync-sdk/viem'; +import { createPublicClient, createWalletClient, http } from "viem"; +import { createViemClient, createViemSdk } from "@dutterbutter/zksync-sdk/viem"; -// Provide your chain objects & RPC URLs as needed +// Public clients (reads) const l1 = createPublicClient({ transport: http(process.env.ETH_RPC!) }); const l2 = createPublicClient({ transport: http(process.env.ZKSYNC_RPC!) }); +// Wallet clients (writes) const l1Wallet = createWalletClient({ - account: /* your Account */, + account: /* your L1 Account */, transport: http(process.env.ETH_RPC!), }); -// (optional) pass an L2 wallet; needed during withdrawals to finalize const l2Wallet = createWalletClient({ - account: l1Wallet.account, + account: /* your L2 Account (can be the same key) */, transport: http(process.env.ZKSYNC_RPC!), }); const client = createViemClient({ l1, l2, l1Wallet, l2Wallet }); const sdk = createViemSdk(client); -// Example: get contracts and the L2 address for an L1 token +// Example: deposit 0.05 ETH L1 → L2, wait for L2 execution +const handle = await sdk.deposits.create({ + token: ETH_ADDRESS, // 0x…00 sentinel for ETH supported + amount: 50_000_000_000_000_000n, // 0.05 ETH in wei + to: l2Wallet.account.address, +}); +await sdk.deposits.wait(handle, { for: "l2" }); + +// Example: resolve contracts and map an L1 token to its L2 address const { l1NativeTokenVault } = await sdk.helpers.contracts(); -const l2_crown_address = await sdk.helpers.l2TokenAddress(CROWN_ERC20_ADDRESS); +const l2Crown = await sdk.helpers.l2TokenAddress(CROWN_ERC20_ADDRESS); ``` - The SDK composes the Viem client with high-level resources: deposits, withdrawals, and convenience helpers. +You can construct the client with only the wallets you need for a given flow (e.g., just l2Wallet to create withdrawals; add l1Wallet when you plan to finalize). ## `createViemSdk(client) → ViemSdk` - Instance created by createViemClient. +Instance returned by `createViemClient({ l1, l2, l1Wallet?, l2Wallet? })`. +**Returns:** `ViemSdk` + + +The SDK composes the client with resources: deposits, withdrawals, and convenience helpers. + + ## ViemSdk interface - - L1 → L2 flows (quote, prepare, create, status, wait). See Deposits. - +### `deposits: DepositsResource` + +L1 → L2 flows. See **[Deposits](/api-reference/viem/deposits)**. - - L2 → L1 flows (quote, prepare, create, status, wait, finalize). See Withdrawals. - +### `withdrawals: WithdrawalsResource` -### `helpers` +L2 → L1 flows. See **[Withdrawals](/api-reference/viem/withdrawals)**. -Utilities for addresses, contracts, and token mapping. +## helpers -#### `addresses() → Promise` +Utilities for chain addresses, connected contracts, and L1↔L2 token mapping. -Resolves core addresses (Bridgehub, routers, vaults, base token system). +### `addresses() → Promise` + +Resolve core addresses (Bridgehub, routers, vaults, base-token system). ```ts const a = await sdk.helpers.addresses(); ``` -#### `contracts() → Promise<{ ...contracts }>` +### `contracts() → Promise<{ ...contracts }>` -Returns **typed viem contracts** for all core contracts (each exposes `.read` / `.write` / `.simulate`). +**Typed** Viem contracts for all core components (each exposes `.read` / `.write` / `.simulate`). ```ts const c = await sdk.helpers.contracts(); const bridgehub = c.bridgehub; ``` -#### `l1AssetRouter() / l1NativeTokenVault() / l1Nullifier()` +### One-off contract getters -One-off getters if you only need a specific contract. +`l1AssetRouter() → Promise` +`l1NativeTokenVault() → Promise` +`l1Nullifier() → Promise` ```ts const nullifier = await sdk.helpers.l1Nullifier(); ``` -#### `baseToken(chainId?: bigint) → Promise
` +### `baseToken(chainId?: bigint) → Promise
` -L1 address of the base token for a given **L2 chain**. If omitted, uses the current L2 client’s chain id. +L1 address of the **base token** for the current (or supplied) L2 chain. ```ts -const base = await sdk.helpers.baseToken(); // infers from client.l2.getChainId() +const base = await sdk.helpers.baseToken(); // infers from the L2 client ``` -#### `l2TokenAddress(l1Token: Address) → Promise
` +### `l2TokenAddress(l1Token: Address) → Promise
` -Returns the **L2 token address** for a given **L1 token**. +L2 token address for an L1 token. -* Handles ETH special-case (L2 ETH placeholder). -* If the token equals the chain’s base token, returns the L2 base-token system address. +* Handles ETH special case (L2 ETH placeholder). +* If the token is the chain’s base token, returns the L2 base-token system address. * Otherwise queries `IL2NativeTokenVault.l2TokenAddress`. ```ts -const l2_crown_address = await sdk.helpers.l2TokenAddress(CROWN_ERC20_ADDRESS); +const l2Crown = await sdk.helpers.l2TokenAddress(CROWN_ERC20_ADDRESS); ``` -#### `l1TokenAddress(l2Token: Address) → Promise
` - -Returns the **L1 token address** from an **L2 token** using `IL2AssetRouter.l1TokenAddress`. +### `l1TokenAddress(l2Token: Address) → Promise
` -* ETH is treated as a special case. +L1 token for an L2 token via `IL2AssetRouter.l1TokenAddress`. ETH placeholder resolves to canonical ETH. ```ts -const l1_crown_address = await sdk.helpers.l1TokenAddress(CROWN_ERC20_ADDRESS); +const l1Crown = await sdk.helpers.l1TokenAddress(L2_CROWN_ADDRESS); ``` -#### `assetId(l1Token: Address) → Promise` +### `assetId(l1Token: Address) → Promise` -Computes the `bytes32` asset identifier for an L1 token via `L1NativeTokenVault.assetId`. +`bytes32` asset ID via `L1NativeTokenVault.assetId` (ETH handled canonically). ```ts const id = await sdk.helpers.assetId(CROWN_ERC20_ADDRESS); ``` -## Notes +## Notes & pitfalls -* All results depend on the connected chains (L1/L2 RPCs) and any overrides supplied to the client. -* Errors surface as typed envelopes (see **Error Model** in API Reference intro). Prefer the try* variants on resources if you want result objects instead of exceptions. +* **Wallet placement matters:** deposits sign on **L1**; withdrawals sign on **L2**; finalization signs on **L1**. +* **Chain-derived behavior:** helpers read from on-chain sources; results depend on connected networks. +* **Error model:** resource methods throw typed errors; prefer try* variants on resources for result objects. diff --git a/docs/api-reference/viem/withdrawals.mdx b/docs/api-reference/viem/withdrawals.mdx index 7419754..51823ff 100644 --- a/docs/api-reference/viem/withdrawals.mdx +++ b/docs/api-reference/viem/withdrawals.mdx @@ -4,82 +4,92 @@ description: L2 → L1 withdrawals for ETH and ERC-20 with quote, prepare, creat group: API Reference / Viem --- +## At a glance + +- **Resource:** `sdk.withdrawals` +- **Typical flow:** `quote → create → wait({ for: 'l2' }) → wait({ for: 'ready' }) → finalize` +- **Auto-routing:** ETH vs ERC-20 and base-token vs non-base handled internally +- **Error style:** Throwing methods (`quote`, `prepare`, `create`, `status`, `wait`, `finalize`) + result variants (`tryQuote`, `tryPrepare`, `tryCreate`, `tryWait`, `tryFinalize`) + ## Import ```ts -import { parseEther } from "viem"; import { - createViemClient, - createViemSdk, -} from "@dutterbutter/zksync-sdk/viem"; + createPublicClient, + createWalletClient, + http, + parseEther, + type Account, + type Chain, + type Transport, + type WalletClient, +} from 'viem'; +import { privateKeyToAccount } from 'viem/accounts'; +import { createViemClient, createViemSdk } from '@dutterbutter/zksync-sdk/viem'; + +const account = privateKeyToAccount(PRIVATE_KEY as `0x${string}`); +const l1 = createPublicClient({ transport: http(L1_RPC) }); +const l2 = createPublicClient({ transport: http(L2_RPC) }); +const l1Wallet: WalletClient = createWalletClient({ + account, + transport: http(L1_RPC), +}); -// Useful constants -import { ETH_ADDRESS } from "@dutterbutter/zksync-sdk/constants"; -```` +// --- 2. Initialize the SDK --- +const client = createViemClient({ l1, l2, l1Wallet }); +const sdk = createViemSdk(client); +// sdk.withdrawals → WithdrawalsResource +``` ## Quick start -Withdraw **0.1 ETH** from L2 → L1, then finalize: +Withdraw **0.1 ETH** from L2 → L1 and finalize on L1: ```ts -const client = createViemClient({ l1, l2, l1Wallet, l2Wallet }); -const sdk = createViemSdk(client); - const handle = await sdk.withdrawals.create({ - token: ETH_ADDRESS, + token: ETH_ADDRESS, // ETH sentinel supported amount: parseEther("0.1"), - to: /* L1 recipient address */, + to: await signer.getAddress(), // L1 recipient }); -// 1) Wait until included on L2 (returns TransactionReceipt with l2ToL1Logs if available) -const l2Receipt = await sdk.withdrawals.wait(handle, { for: "l2" }); +// 1) L2 inclusion (adds l2ToL1Logs if available) +await sdk.withdrawals.wait(handle, { for: "l2" }); // 2) Wait until finalizable (no side effects) await sdk.withdrawals.wait(handle, { for: "ready", pollMs: 6000 }); -// 3) Send the L1 finalize tx (if not already finalized) +// 3) Finalize on L1 (no-op if already finalized) const { status, receipt: l1Receipt } = await sdk.withdrawals.finalize(handle.l2TxHash); ``` - - Withdrawals are a two-step process: include on **L2**, then finalize on **L1**. You can either - wait for ready before calling finalize, or call finalize directly— it will throw if not yet ready. - - ---- - -## Routes (auto-selected) + +Withdrawals are two-phase: inclusion on **L2**, then **finalization on L1**. You can call finalize directly; it will throw if not yet ready. Prefer `wait(..., { for: 'ready' })` to avoid that. + -Based on the asset and the L2 base token: +## Route selection (automatic) * `eth-base` — Base token is **ETH** on L2 * `eth-nonbase` — Base token is **not ETH** on L2 * `erc20-nonbase` — Withdrawing an ERC-20 that is **not** the base token -No route argument is needed; it’s derived internally. +You **do not** pass a route; it’s derived from network metadata + `token`. -## Methods +## Method reference ### `quote(p: WithdrawParams) → Promise` -Dry-run summary of a withdrawal (route, approvals, gas hints). +Estimate the operation (route, approvals, gas hints). Does **not** send txs. - - L2 token address (ETH handled by the SDK). - - - Amount in wei (e.g., parseEther("0.1")). - - - Recipient on L1. - +L2 token (ETH handled by the SDK; ETH sentinel supported). Amount in wei. L1 recipient. + +**Returns:** `WithdrawQuote` ```ts const q = await sdk.withdrawals.quote({ token, amount, to }); /* -q = { +{ route: "eth-base" | "eth-nonbase" | "erc20-nonbase", - approvalsNeeded: [{ token, spender, amount }, ...], + approvalsNeeded: [{ token, spender, amount }], suggestedL2GasLimit?: bigint } */ @@ -87,59 +97,65 @@ q = { ### `tryQuote(p) → Promise<{ ok: true; value: WithdrawQuote } | { ok: false; error }>` -Result-style version of `quote`. +Result-style `quote`. + +### `prepare(p: WithdrawParams) → Promise>` -### `prepare(p: WithdrawParams) → Promise>` +Builds the plan (ordered L2 steps + unsigned txs) without sending. -Build the plan (route + ordered **L2** steps), no sends. +**Returns:** `WithdrawPlan` ```ts const plan = await sdk.withdrawals.prepare({ token, amount, to }); /* -plan = { +{ route, summary: WithdrawQuote, - steps: [{ key, kind, tx: ViemPlanWriteRequest }, ...] + steps: [ + { key, kind, tx: TransactionRequest }, + // … + ] } */ ``` -### `tryPrepare(p) → Promise<{ ok: true; value } | { ok: false; error }>` +### `tryPrepare(p) → Promise<{ ok: true; value: WithdrawPlan } | { ok: false; error }>` -Result-style version of `prepare`. +Result-style `prepare`. -### `create(p: WithdrawParams) → Promise>` +### `create(p: WithdrawParams) → Promise>` -Prepare + **send** L2 steps via Viem `writeContract`. Returns a handle with the **L2 tx hash**. +Prepares and **executes** required **L2** steps. Returns a handle with the **L2 tx hash**. + +**Returns:** `WithdrawHandle` ```ts const handle = await sdk.withdrawals.create({ token, amount, to }); /* -handle = { +{ kind: "withdrawal", l2TxHash: Hex, stepHashes: Record, - plan + plan: WithdrawPlan } */ ``` - If any step reverts on L2, create throws a typed error. - Prefer tryCreate if you want a result object. +If any L2 step reverts, create throws a typed error. Prefer tryCreate for a result object. ### `tryCreate(p) → Promise<{ ok: true; value: WithdrawHandle } | { ok: false; error }>` -Result-style version of `create`. +Result-style `create`. -### `status(h | l2TxHash) → Promise` +### `status(handleOrHash) → Promise` -Report current phase. Accepts the **handle** from `create` or a raw **L2 tx hash**. +Report current phase for a withdrawal. Accepts the `WithdrawHandle` from `create` **or** a raw **L2 tx hash**. -Phases: +**Phases** -* `UNKNOWN` — no L2 hash on input +* `UNKNOWN` — no L2 hash provided * `L2_PENDING` — L2 receipt missing * `PENDING` — included on L2 but not yet finalizable * `READY_TO_FINALIZE` — can be finalized on L1 now @@ -147,35 +163,31 @@ Phases: ```ts const s = await sdk.withdrawals.status(handle); -/* -s = { phase, l2TxHash, key? } // key identifies the canonical message for finalization -*/ +// { phase, l2TxHash, key? } ``` -### `wait(h | l2TxHash, { for: 'l2' | 'ready' | 'finalized', pollMs?, timeoutMs? })` +### `wait(handleOrHash, { for: 'l2' | 'ready' | 'finalized', pollMs?, timeoutMs? })` Block until a target is reached. * `{ for: 'l2' }` → resolves **L2 receipt** (`TransactionReceiptZKsyncOS`) or `null` - (SDK augments with `l2ToL1Logs` if available). -* `{ for: 'ready' }` → resolves `null` when finalization becomes possible. -* `{ for: 'finalized' }` → resolves **L1 receipt** when found, otherwise `null` (even if finalized). +* `{ for: 'ready' }` → resolves `null` when finalizable +* `{ for: 'finalized' }` → resolves **L1 receipt** (if found) or `null` ```ts -// 1) L2 inclusion const l2Rcpt = await sdk.withdrawals.wait(handle, { for: "l2" }); - -// 2) Finalization readiness (no side effects) await sdk.withdrawals.wait(handle, { for: "ready", pollMs: 6000, timeoutMs: 15 * 60_000 }); - -// 3) Wait for finalized (returns L1 receipt or null) const l1Rcpt = await sdk.withdrawals.wait(handle, { for: "finalized", pollMs: 7000 }); ``` - Default polling is 5500ms (minimum 1000ms). Use timeoutMs for long windows. +Default polling is 5500 ms (min 1000 ms). Use timeoutMs for long windows. +### `tryWait(handleOrHash, opts) → Result` + +Result-style `wait`. + ### `finalize(l2TxHash: Hex) → Promise<{ status: WithdrawalStatus; receipt?: TransactionReceipt }>` Sends the **L1 finalize** transaction **if** ready. If already finalized, returns the status without sending. @@ -188,13 +200,12 @@ if (status.phase === "FINALIZED") { ``` - Behavior: If the withdrawal is not ready, finalize throws a typed STATE error. - Use status(...) or `wait(..., { for: 'ready' })` to check first. +If not ready, finalize throws a typed STATE error. Use status(...) or `wait(..., { for: 'ready' })` first to avoid throws. -### `tryFinalize(l2TxHash) → Promise<{ ok: true; value: { status; receipt? } } | { ok: false; error }>` +### `tryFinalize(l2TxHash) → Promise<{ ok: true; value: { status: WithdrawalStatus; receipt?: TransactionReceipt } } | { ok: false; error }>` -Result-style version of `finalize`. +Result-style `finalize`. ## End-to-end examples @@ -203,25 +214,23 @@ Result-style version of `finalize`. ```ts const handle = await sdk.withdrawals.create({ token, amount, to }); -// Wait L2 inclusion +// L2 inclusion await sdk.withdrawals.wait(handle, { for: "l2" }); -// Either finalize immediately… -const { status, receipt } = await sdk.withdrawals.finalize(handle.l2TxHash); +// Option A: finalize immediately (will throw if not ready) +await sdk.withdrawals.finalize(handle.l2TxHash); -// …or wait for readiness first, then finalize +// Option B: wait for readiness, then finalize await sdk.withdrawals.wait(handle, { for: "ready" }); -const done = await sdk.withdrawals.finalize(handle.l2TxHash); +await sdk.withdrawals.finalize(handle.l2TxHash); ``` -## Types (shape overview) - -These types live in `core/types` and are summarized here for convenience. +## Types (overview) ```ts type WithdrawParams = { - token: Address; // L2 token (ETH handled internally) - amount: bigint; // in wei + token: Address; // L2 token (ETH sentinel supported) + amount: bigint; // wei to: Address; // L1 recipient }; @@ -231,13 +240,13 @@ type WithdrawQuote = { suggestedL2GasLimit?: bigint; }; -type WithdrawPlan = { +type WithdrawPlan = { route: WithdrawQuote["route"]; summary: WithdrawQuote; steps: Array<{ key: string; kind: string; tx: TTx }>; }; -type WithdrawHandle = { +type WithdrawHandle = { kind: "withdrawal"; l2TxHash: Hex; stepHashes: Record; @@ -251,10 +260,13 @@ type WithdrawalStatus = | { phase: "READY_TO_FINALIZE"; l2TxHash: Hex; key: unknown } | { phase: "FINALIZED"; l2TxHash: Hex; key: unknown }; -// The L2 receipt returned by wait({ for: 'l2' }) is augmented: -type TransactionReceiptZKsyncOS = TransactionReceipt & { l2ToL1Logs?: Array }; +// L2 receipt augmentation returned by wait({ for: 'l2' }) +type TransactionReceiptZKsyncOS = + TransactionReceipt & { l2ToL1Logs?: Array }; ``` - - Prefer the try* variants if you want result objects instead of exceptions. - +## Notes & pitfalls + +* **Two chains, two receipts:** inclusion on **L2** and finalization on **L1** are independent events. +* **Polling strategy:** for production UIs, prefer `wait({ for: 'ready' })` then finalize; it avoids premature finalize calls. +* **Approvals:** if withdrawing ERC-20 requires approvals, `create` will include those steps automatically. diff --git a/docs/docs.json b/docs/docs.json index 8dc4ac9..019a016 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -60,8 +60,7 @@ "group": "Guides", "pages": [ "guides/deposits", - "guides/withdrawals", - "guides/finalization" + "guides/withdrawals" ] } ] diff --git a/docs/essentials/code.mdx b/docs/essentials/code.mdx deleted file mode 100644 index ae2abbf..0000000 --- a/docs/essentials/code.mdx +++ /dev/null @@ -1,35 +0,0 @@ ---- -title: 'Code blocks' -description: 'Display inline code and code blocks' -icon: 'code' ---- - -## Inline code - -To denote a `word` or `phrase` as code, enclose it in backticks (`). - -``` -To denote a `word` or `phrase` as code, enclose it in backticks (`). -``` - -## Code blocks - -Use [fenced code blocks](https://www.markdownguide.org/extended-syntax/#fenced-code-blocks) by enclosing code in three backticks and follow the leading ticks with the programming language of your snippet to get syntax highlighting. Optionally, you can also write the name of your code after the programming language. - -```java HelloWorld.java -class HelloWorld { - public static void main(String[] args) { - System.out.println("Hello, World!"); - } -} -``` - -````md -```java HelloWorld.java -class HelloWorld { - public static void main(String[] args) { - System.out.println("Hello, World!"); - } -} -``` -```` diff --git a/docs/essentials/images.mdx b/docs/essentials/images.mdx deleted file mode 100644 index 1144eb2..0000000 --- a/docs/essentials/images.mdx +++ /dev/null @@ -1,59 +0,0 @@ ---- -title: 'Images and embeds' -description: 'Add image, video, and other HTML elements' -icon: 'image' ---- - - - -## Image - -### Using Markdown - -The [markdown syntax](https://www.markdownguide.org/basic-syntax/#images) lets you add images using the following code - -```md -![title](/path/image.jpg) -``` - -Note that the image file size must be less than 5MB. Otherwise, we recommend hosting on a service like [Cloudinary](https://cloudinary.com/) or [S3](https://aws.amazon.com/s3/). You can then use that URL and embed. - -### Using embeds - -To get more customizability with images, you can also use [embeds](/writing-content/embed) to add images - -```html - -``` - -## Embeds and HTML elements - - - -
- - - -Mintlify supports [HTML tags in Markdown](https://www.markdownguide.org/basic-syntax/#html). This is helpful if you prefer HTML tags to Markdown syntax, and lets you create documentation with infinite flexibility. - - - -### iFrames - -Loads another HTML page within the document. Most commonly used for embedding videos. - -```html - -``` diff --git a/docs/essentials/markdown.mdx b/docs/essentials/markdown.mdx deleted file mode 100644 index a45c1d5..0000000 --- a/docs/essentials/markdown.mdx +++ /dev/null @@ -1,88 +0,0 @@ ---- -title: 'Markdown syntax' -description: 'Text, title, and styling in standard markdown' -icon: 'text-size' ---- - -## Titles - -Best used for section headers. - -```md -## Titles -``` - -### Subtitles - -Best used for subsection headers. - -```md -### Subtitles -``` - - - -Each **title** and **subtitle** creates an anchor and also shows up on the table of contents on the right. - - - -## Text formatting - -We support most markdown formatting. Simply add `**`, `_`, or `~` around text to format it. - -| Style | How to write it | Result | -| ------------- | ----------------- | --------------- | -| Bold | `**bold**` | **bold** | -| Italic | `_italic_` | _italic_ | -| Strikethrough | `~strikethrough~` | ~strikethrough~ | - -You can combine these. For example, write `**_bold and italic_**` to get **_bold and italic_** text. - -You need to use HTML to write superscript and subscript text. That is, add `` or `` around your text. - -| Text Size | How to write it | Result | -| ----------- | ------------------------ | ---------------------- | -| Superscript | `superscript` | superscript | -| Subscript | `subscript` | subscript | - -## Linking to pages - -You can add a link by wrapping text in `[]()`. You would write `[link to google](https://google.com)` to [link to google](https://google.com). - -Links to pages in your docs need to be root-relative. Basically, you should include the entire folder path. For example, `[link to text](/writing-content/text)` links to the page "Text" in our components section. - -Relative links like `[link to text](../text)` will open slower because we cannot optimize them as easily. - -## Blockquotes - -### Singleline - -To create a blockquote, add a `>` in front of a paragraph. - -> Dorothy followed her through many of the beautiful rooms in her castle. - -```md -> Dorothy followed her through many of the beautiful rooms in her castle. -``` - -### Multiline - -> Dorothy followed her through many of the beautiful rooms in her castle. -> -> The Witch bade her clean the pots and kettles and sweep the floor and keep the fire fed with wood. - -```md -> Dorothy followed her through many of the beautiful rooms in her castle. -> -> The Witch bade her clean the pots and kettles and sweep the floor and keep the fire fed with wood. -``` - -### LaTeX - -Mintlify supports [LaTeX](https://www.latex-project.org) through the Latex component. - -8 x (vk x H1 - H2) = (0,1) - -```md -8 x (vk x H1 - H2) = (0,1) -``` diff --git a/docs/essentials/navigation.mdx b/docs/essentials/navigation.mdx deleted file mode 100644 index 60adeff..0000000 --- a/docs/essentials/navigation.mdx +++ /dev/null @@ -1,87 +0,0 @@ ---- -title: 'Navigation' -description: 'The navigation field in docs.json defines the pages that go in the navigation menu' -icon: 'map' ---- - -The navigation menu is the list of links on every website. - -You will likely update `docs.json` every time you add a new page. Pages do not show up automatically. - -## Navigation syntax - -Our navigation syntax is recursive which means you can make nested navigation groups. You don't need to include `.mdx` in page names. - - - -```json Regular Navigation -"navigation": { - "tabs": [ - { - "tab": "Docs", - "groups": [ - { - "group": "Getting Started", - "pages": ["quickstart"] - } - ] - } - ] -} -``` - -```json Nested Navigation -"navigation": { - "tabs": [ - { - "tab": "Docs", - "groups": [ - { - "group": "Getting Started", - "pages": [ - "quickstart", - { - "group": "Nested Reference Pages", - "pages": ["nested-reference-page"] - } - ] - } - ] - } - ] -} -``` - - - -## Folders - -Simply put your MDX files in folders and update the paths in `docs.json`. - -For example, to have a page at `https://yoursite.com/your-folder/your-page` you would make a folder called `your-folder` containing an MDX file called `your-page.mdx`. - - - -You cannot use `api` for the name of a folder unless you nest it inside another folder. Mintlify uses Next.js which reserves the top-level `api` folder for internal server calls. A folder name such as `api-reference` would be accepted. - - - -```json Navigation With Folder -"navigation": { - "tabs": [ - { - "tab": "Docs", - "groups": [ - { - "group": "Group Name", - "pages": ["your-folder/your-page"] - } - ] - } - ] -} -``` - -## Hidden pages - -MDX files not included in `docs.json` will not show up in the sidebar but are accessible through the search bar and by linking directly to them. diff --git a/docs/essentials/reusable-snippets.mdx b/docs/essentials/reusable-snippets.mdx deleted file mode 100644 index 376e27b..0000000 --- a/docs/essentials/reusable-snippets.mdx +++ /dev/null @@ -1,110 +0,0 @@ ---- -title: "Reusable snippets" -description: "Reusable, custom snippets to keep content in sync" -icon: "recycle" ---- - -import SnippetIntro from '/snippets/snippet-intro.mdx'; - - - -## Creating a custom snippet - -**Pre-condition**: You must create your snippet file in the `snippets` directory. - - - Any page in the `snippets` directory will be treated as a snippet and will not - be rendered into a standalone page. If you want to create a standalone page - from the snippet, import the snippet into another file and call it as a - component. - - -### Default export - -1. Add content to your snippet file that you want to re-use across multiple - locations. Optionally, you can add variables that can be filled in via props - when you import the snippet. - -```mdx snippets/my-snippet.mdx -Hello world! This is my content I want to reuse across pages. My keyword of the -day is {word}. -``` - - - The content that you want to reuse must be inside the `snippets` directory in - order for the import to work. - - -2. Import the snippet into your destination file. - -```mdx destination-file.mdx ---- -title: My title -description: My Description ---- - -import MySnippet from '/snippets/path/to/my-snippet.mdx'; - -## Header - -Lorem impsum dolor sit amet. - - -``` - -### Reusable variables - -1. Export a variable from your snippet file: - -```mdx snippets/path/to/custom-variables.mdx -export const myName = 'my name'; - -export const myObject = { fruit: 'strawberries' }; -``` - -2. Import the snippet from your destination file and use the variable: - -```mdx destination-file.mdx ---- -title: My title -description: My Description ---- - -import { myName, myObject } from '/snippets/path/to/custom-variables.mdx'; - -Hello, my name is {myName} and I like {myObject.fruit}. -``` - -### Reusable components - -1. Inside your snippet file, create a component that takes in props by exporting - your component in the form of an arrow function. - -```mdx snippets/custom-component.mdx -export const MyComponent = ({ title }) => ( -
-

{title}

-

... snippet content ...

-
-); -``` - - - MDX does not compile inside the body of an arrow function. Stick to HTML - syntax when you can or use a default export if you need to use MDX. - - -2. Import the snippet into your destination file and pass in the props - -```mdx destination-file.mdx ---- -title: My title -description: My Description ---- - -import { MyComponent } from '/snippets/custom-component.mdx'; - -Lorem ipsum dolor sit amet. - - -``` diff --git a/docs/essentials/settings.mdx b/docs/essentials/settings.mdx deleted file mode 100644 index 884de13..0000000 --- a/docs/essentials/settings.mdx +++ /dev/null @@ -1,318 +0,0 @@ ---- -title: 'Global Settings' -description: 'Mintlify gives you complete control over the look and feel of your documentation using the docs.json file' -icon: 'gear' ---- - -Every Mintlify site needs a `docs.json` file with the core configuration settings. Learn more about the [properties](#properties) below. - -## Properties - - -Name of your project. Used for the global title. - -Example: `mintlify` - - - - - An array of groups with all the pages within that group - - - The name of the group. - - Example: `Settings` - - - - The relative paths to the markdown files that will serve as pages. - - Example: `["customization", "page"]` - - - - - - - - Path to logo image or object with path to "light" and "dark" mode logo images - - - Path to the logo in light mode - - - Path to the logo in dark mode - - - Where clicking on the logo links you to - - - - - - Path to the favicon image - - - - Hex color codes for your global theme - - - The primary color. Used for most often for highlighted content, section - headers, accents, in light mode - - - The primary color for dark mode. Used for most often for highlighted - content, section headers, accents, in dark mode - - - The primary color for important buttons - - - The color of the background in both light and dark mode - - - The hex color code of the background in light mode - - - The hex color code of the background in dark mode - - - - - - - - Array of `name`s and `url`s of links you want to include in the topbar - - - The name of the button. - - Example: `Contact us` - - - The url once you click on the button. Example: `https://mintlify.com/docs` - - - - - - - - - Link shows a button. GitHub shows the repo information at the url provided including the number of GitHub stars. - - - If `link`: What the button links to. - - If `github`: Link to the repository to load GitHub information from. - - - Text inside the button. Only required if `type` is a `link`. - - - - - - - Array of version names. Only use this if you want to show different versions - of docs with a dropdown in the navigation bar. - - - - An array of the anchors, includes the `icon`, `color`, and `url`. - - - The [Font Awesome](https://fontawesome.com/search?q=heart) icon used to feature the anchor. - - Example: `comments` - - - The name of the anchor label. - - Example: `Community` - - - The start of the URL that marks what pages go in the anchor. Generally, this is the name of the folder you put your pages in. - - - The hex color of the anchor icon background. Can also be a gradient if you pass an object with the properties `from` and `to` that are each a hex color. - - - Used if you want to hide an anchor until the correct docs version is selected. - - - Pass `true` if you want to hide the anchor until you directly link someone to docs inside it. - - - One of: "brands", "duotone", "light", "sharp-solid", "solid", or "thin" - - - - - - - Override the default configurations for the top-most anchor. - - - The name of the top-most anchor - - - Font Awesome icon. - - - One of: "brands", "duotone", "light", "sharp-solid", "solid", or "thin" - - - - - - An array of navigational tabs. - - - The name of the tab label. - - - The start of the URL that marks what pages go in the tab. Generally, this - is the name of the folder you put your pages in. - - - - - - Configuration for API settings. Learn more about API pages at [API Components](/api-playground/demo). - - - The base url for all API endpoints. If `baseUrl` is an array, it will enable for multiple base url - options that the user can toggle. - - - - - - The authentication strategy used for all API endpoints. - - - The name of the authentication parameter used in the API playground. - - If method is `basic`, the format should be `[usernameName]:[passwordName]` - - - The default value that's designed to be a prefix for the authentication input field. - - E.g. If an `inputPrefix` of `AuthKey` would inherit the default input result of the authentication field as `AuthKey`. - - - - - - Configurations for the API playground - - - - Whether the playground is showing, hidden, or only displaying the endpoint with no added user interactivity `simple` - - Learn more at the [playground guides](/api-playground/demo) - - - - - - Enabling this flag ensures that key ordering in OpenAPI pages matches the key ordering defined in the OpenAPI file. - - This behavior will soon be enabled by default, at which point this field will be deprecated. - - - - - - - A string or an array of strings of URL(s) or relative path(s) pointing to your - OpenAPI file. - - Examples: - - ```json Absolute - "openapi": "https://example.com/openapi.json" - ``` - ```json Relative - "openapi": "/openapi.json" - ``` - ```json Multiple - "openapi": ["https://example.com/openapi1.json", "/openapi2.json", "/openapi3.json"] - ``` - - - - - - An object of social media accounts where the key:property pair represents the social media platform and the account url. - - Example: - ```json - { - "x": "https://x.com/mintlify", - "website": "https://mintlify.com" - } - ``` - - - One of the following values `website`, `facebook`, `x`, `discord`, `slack`, `github`, `linkedin`, `instagram`, `hacker-news` - - Example: `x` - - - The URL to the social platform. - - Example: `https://x.com/mintlify` - - - - - - Configurations to enable feedback buttons - - - - Enables a button to allow users to suggest edits via pull requests - - - Enables a button to allow users to raise an issue about the documentation - - - - - - Customize the dark mode toggle. - - - Set if you always want to show light or dark mode for new users. When not - set, we default to the same mode as the user's operating system. - - - Set to true to hide the dark/light mode toggle. You can combine `isHidden` with `default` to force your docs to only use light or dark mode. For example: - - - ```json Only Dark Mode - "modeToggle": { - "default": "dark", - "isHidden": true - } - ``` - - ```json Only Light Mode - "modeToggle": { - "default": "light", - "isHidden": true - } - ``` - - - - - - - - - A background image to be displayed behind every page. See example with - [Infisical](https://infisical.com/docs) and [FRPC](https://frpc.io). - diff --git a/docs/guides/deposits.mdx b/docs/guides/deposits.mdx index 4243f8d..ae413ff 100644 --- a/docs/guides/deposits.mdx +++ b/docs/guides/deposits.mdx @@ -1,116 +1,405 @@ --- -title: Deposits -description: Deposit ETH from L1 → ZKsync (L2). +title: "Deposits (L1 → L2)" +description: "Fast, developer-focused deposits with validation, observability, and battle-tested patterns." --- -import { ViemDeposit } from '/snippets/deposits/viem.mdx'; -import { EthersDeposit } from '/snippets/deposits/ethers.mdx'; +# Guide: Depositing funds L1 to L2 -A fast path to deposit **ETH** from L1 → ZKsync (L2). Toggle your adapter below. +This guide provides a complete walkthrough for depositing funds from a L1 (Ethereum) to a L2 (ZKsync). We will use the `@dutterbutter/zksync-sdk` to simplify the process. -## Prerequisites +The SDK intelligently handles the deposit flow, automatically selecting the correct contract and route based on the token being used. -- A funded **L1** account (gas + amount). -- RPC URLs: `L1_RPC_URL`, `L2_RPC_URL`. -- Installed: `@dutterbutter/zksync-sdk` + **one** adapter: `viem` **or** `ethers`. +### Prerequisites -## Parameters +Before you begin, ensure you have the following: -| Param | Required | Meaning | -| ----------------- | -------- | -------------------------------------- | -| `token` | Yes | `ETH_ADDRESS` or ERC-20 address | -| `amount` | Yes | BigInt/wei (e.g. `parseEther('0.01')`) | -| `to` | Yes | L2 recipient address | -| `l2GasLimit` | No | L2 execution gas cap | -| `gasPerPubdata` | No | Pubdata price hint | -| `operatorTip` | No | Optional tip to operator | -| `refundRecipient` | No | L2 address to receive fee refunds | +1. **Node.js v20+** or **Bun.sh** installed. -## Fast path (one-shot) +2. An L1 wallet (private key) with some ETH to pay for the deposit and gas fees. - - +3. RPC endpoints for both the L1 and L2 you are targeting. + +4. A project set up with `viem` or `ethers` and `@dutterbutter/zksync-sdk` installed. + + + ```bash title="viem" + npm install viem @dutterbutter/zksync-sdk dotenv + ``` + ```bash title="ethers" + npm install ethers @dutterbutter/zksync-sdk dotenv + ``` + + +5. An `.env` file in your project's root directory with the following variables: + + ```ini + # .env + L1_RPC_URL="YOUR_L1_RPC_ENDPOINT" + L2_RPC_URL="YOUR_L2_RPC_ENDPOINT" + PRIVATE_KEY="YOUR_WALLET_PRIVATE_KEY" + ``` + +### The Deposit Process: Step-by-Step + +The process can be broken down into 5 key steps after initial setup. + +#### Step 0: Setup and SDK Initialization + +First, we need to connect to the L1 and L2 networks using your preferred library (`viem` or `ethers`) and then initialize the ZKsync SDK. - - +```typescript title="viem" +import 'dotenv/config'; +import { + createPublicClient, + createWalletClient, + http, + parseEther, + type Account, + type Chain, + type Transport, + type WalletClient, +} from 'viem'; +import { privateKeyToAccount } from 'viem/accounts'; +import { createViemClient, createViemSdk } from '@dutterbutter/zksync-sdk/viem'; +import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; + +// Load configuration from .env file +const L1_RPC = process.env.L1_RPC_URL!; +const L2_RPC = process.env.L2_RPC_URL!; +const PRIVATE_KEY = process.env.PRIVATE_KEY!; + +// --- Clients (Viem) --- +const account = privateKeyToAccount(PRIVATE_KEY as `0x${string}`); +const l1 = createPublicClient({ transport: http(L1_RPC) }); +const l2 = createPublicClient({ transport: http(L2_RPC) }); +const l1Wallet: WalletClient = createWalletClient({ + account, + transport: http(L1_RPC), +}); + +// --- 2. Initialize the SDK --- +const client = createViemClient({ l1, l2, l1Wallet }); +const sdk = createViemSdk(client); + +console.log(`Using account: ${account.address}`); +``` +```typescript title="ethers" +import 'dotenv/config'; +import { JsonRpcProvider, Wallet, parseEther } from 'ethers'; +import { createEthersClient, createEthersSdk } from '@dutterbutter/zksync-sdk/ethers'; +import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; + +// Load configuration from .env file +const L1_RPC = process.env.L1_RPC_URL!; +const L2_RPC = process.env.L2_RPC_URL!; +const PRIVATE_KEY = process.env.PRIVATE_KEY!; + +// --- 1. Initialize Providers and Signer --- +const l1Provider = new JsonRpcProvider(L1_RPC); +const l2Provider = new JsonRpcProvider(L2_RPC); +const signer = new Wallet(PRIVATE_KEY, l1Provider); + +// --- 2. Initialize the SDK --- +const client = await createEthersClient({ l1: l1Provider, l2: l2Provider, signer }); +const sdk = createEthersSdk(client); + +console.log(`Using account: ${signer.address}`); +``` -- `create()` prepares **and** sends. -- `wait(..., { for: 'l1' })` ⇒ included on **L1**. -- `wait(..., { for: 'l2' })` ⇒ executed on **L2** (funds available). - -## Inspect & customize (quote → prepare → create) +#### Step 1: Define Deposit Parameters -**1) Quote (no side-effects)** — preview fees/steps and whether an approval is required: +Next, define the parameters for your deposit in an object. You’ll specify the deposit amount, the token address — which can represent ETH, a chain’s Base Token (like L1_SOPH_TOKEN_ADDRESS), or any ERC-20 — and the recipient’s address on L2. -```ts -const quote = await sdk.deposits.quote(params); + +```typescript title="ETH Token Deposit" +const me = signer.address as Address; + +const depositParams = { + amount: parseEther('0.01'), // The amount of ETH to deposit (e.g., 0.01 ETH) + token: ETH_ADDRESS, // The address for native ETH + to: me, // The recipient address on L2 (in this case, our own address) +} as const; +``` +```typescript title="ERC20 Token Deposit" +const me = signer.address as Address; + +const depositParams = { + amount: parseEther('0.01'), // The amount of ERC20 to deposit (e.g., 0.01 ERC20) + token: ERC20_TOKEN_ADDRESS, // The address for the ERC20 token + to: me, // The recipient address on L2 (in this case, our own address) +} as const; +``` +```typescript title="Base Token Deposit" +const me = signer.address as Address; + +const depositParams = { + amount: parseEther('0.01'), // The amount of SOPH to deposit (e.g., 0.01 SOPH) + token: L1_SOPH_TOKEN_ADDRESS, // The address for SOPH (or your chain's base token on L1) + to: me, // The recipient address on L2 (in this case, our own address) +} as const; ``` + + + + +You can also specify advanced options for finer control over the transaction: + + * `l2GasLimit`: The gas limit for the L2 part of the transaction. + * `gasPerPubdata`: The gas price per byte of public data. + * `operatorTip`: A tip for the L2 operator. + * `refundRecipient`: An address to receive any L1 gas refunds. + + + +#### Step 2: Quote the Deposit + +Before sending, it's best practice to get a cost estimate using `sdk.deposits.quote`. This returns information about fees and the expected gas required. -**2) Prepare (build txs, don’t send)** — get `TransactionRequest[]` for custom signing/UX: + +Users can skip this step and go directly to `create`, but quoting helps avoid surprises. + -```ts -const plan = await sdk.deposits.prepare(params); +```typescript +// --- STEP 2: QUOTE --- +const quote = await sdk.deposits.quote(depositParams); +console.log('DEPOSIT QUOTE →', quote); +// Outputs estimated costs and gas limits ``` -**3) Create (send)** — use defaults, or send your prepared transactions: +#### Step 3: Prepare the Transaction -```ts -const handle = await sdk.deposits.create(params); +The `sdk.deposits.prepare` method builds the final transaction plan. This step is useful for inspecting the transaction details before execution. + +```typescript +// --- STEP 3: PREPARE --- +const plan = await sdk.deposits.prepare(depositParams); +console.log('TRANSACTION PLAN →', plan); +// Outputs the prepared transaction objects ``` -## Track progress (status vs wait) +#### Step 4: Create the Deposit -**Non-blocking snapshot** +The `sdk.deposits.create` method executes the plan by sending the transaction to the L1 network. It returns a `handle` which is a unique identifier used to track the deposit's progress. -```ts -const s = await sdk.deposits.status(handle /* or l1TxHash */); -// 'UNKNOWN' | 'L1_PENDING' | 'L1_INCLUDED' | 'L2_PENDING' | 'L2_EXECUTED' | 'L2_FAILED' +```typescript +// --- STEP 4: CREATE (send tx) --- +const handle = await sdk.deposits.create(depositParams); +console.log('TRANSACTION CREATED →', handle); +// Outputs the handle, e.g., { type: 'deposit', hash: '0x...' } ``` -**Block until checkpoint** +#### Step 5: Track the Transaction Status + +A deposit is a two-stage process: inclusion on L1 and then execution on L2. The SDK provides tools to track both stages. + + * **`sdk.deposits.status(handle)`:** Check the current status of the deposit at any time. + * **`sdk.deposits.wait(handle, options)`:** Pause execution until the deposit reaches a specific stage. -```ts +```typescript +// --- STEP 5: TRACK --- +console.log('⏳ Waiting for L1 inclusion...'); const l1Receipt = await sdk.deposits.wait(handle, { for: 'l1' }); +console.log('✅ L1 included at block:', l1Receipt?.blockNumber); + +// Check the status again after L1 inclusion +const statusAfterL1 = await sdk.deposits.status(handle); +console.log('STATUS (after L1) →', statusAfterL1); + +console.log('⏳ Waiting for L2 execution...'); const l2Receipt = await sdk.deposits.wait(handle, { for: 'l2' }); +console.log('✅ L2 executed at block:', l2Receipt?.blockNumber); ``` -## Error handling patterns +Once the `wait` for L2 execution completes, your ETH has successfully been deposited to your L2 address. -**Exceptions** +### Full Code Example -```ts -try { +Here is the complete, runnable script for your reference. + + + + + +```typescript title="viem" +/** + * Example: Deposit ETH into an L2 + */ +import 'dotenv/config'; +import { + createPublicClient, + createWalletClient, + http, + parseEther, + type Account, + type Chain, + type Transport, + type WalletClient, +} from 'viem'; +import { privateKeyToAccount } from 'viem/accounts'; + +import { createViemClient, createViemSdk } from '@dutterbutter/zksync-sdk/viem'; +import type { Address } from '@dutterbutter/zksync-sdk/core'; +import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; + +// --- CONFIG --- +// Use env if available, otherwise fall back to local dev defaults. +const L1_RPC = process.env.L1_RPC_URL ?? 'http://localhost:8545'; +const L2_RPC = process.env.L2_RPC_URL ?? 'http://localhost:3050'; +const PRIVATE_KEY = process.env.PRIVATE_KEY ?? ''; + +async function main() { + if (!PRIVATE_KEY || PRIVATE_KEY.length !== 66) { + throw new Error('⚠️ Set a 0x-prefixed 32-byte PRIVATE_KEY in your .env'); + } + + // --- Clients (Viem) --- + const account = privateKeyToAccount(PRIVATE_KEY as `0x${string}`); + const l1 = createPublicClient({ transport: http(L1_RPC) }); + const l2 = createPublicClient({ transport: http(L2_RPC) }); + + const l1Wallet: WalletClient = createWalletClient({ + account, + transport: http(L1_RPC), + }); + + // Show balances for sanity + const [balL1, balL2] = await Promise.all([ + l1.getBalance({ address: account.address }), + l2.getBalance({ address: account.address }), + ]); + console.log('Using account:', account.address); + console.log('L1 balance:', balL1.toString()); + console.log('L2 balance:', balL2.toString()); + + // --- Init SDK --- + const client = createViemClient({ l1, l2, l1Wallet }); + const sdk = createViemSdk(client); + + // --- Deposit params --- + const me = account.address as Address; + const params = { + amount: parseEther('0.01'), + token: ETH_ADDRESS, // ETH sentinel + to: me, + // optional: + // l2GasLimit: 300_000n, + // gasPerPubdata: 800n, + // operatorTip: 0n, + // refundRecipient: me, + } as const; + + // 1) QUOTE + const quote = await sdk.deposits.quote(params); + console.log('QUOTE →', quote); + + // 2) PREPARE (no txs sent) + const plan = await sdk.deposits.prepare(params); + console.log('PREPARE →', plan); + + // 3) CREATE (send deposit) const handle = await sdk.deposits.create(params); -} catch (e) { - // normalized error envelope (type, operation, message, context, optional revert) -} -``` + console.log('CREATE →', handle); + + // 4) STATUS + const status = await sdk.deposits.status(handle); + console.log('STATUS →', status); -**No-throw style** + // 5) WAIT: L1 inclusion + console.log('⏳ Waiting for L1 inclusion...'); + const l1Receipt = await sdk.deposits.wait(handle, { for: 'l1' }); + console.log('✅ L1 included at block:', l1Receipt?.blockNumber); -Every method has a `try*` variant (`tryQuote`, `tryPrepare`, `tryCreate`) returning `{ ok, value | error }`. + const statusAfterL1 = await sdk.deposits.status(handle); + console.log('STATUS (after L1) →', statusAfterL1); -```ts -const r = await sdk.deposits.tryCreate(params); -if (!r.ok) { - console.error('Deposit failed:', r.error); - // show a toast, retry, or branch UX… -} else { - console.log('Deposit sent. L1 tx hash:', r.value.l1TxHash); + // 6) WAIT: L2 execution + console.log('⏳ Waiting for L2 execution...'); + const l2Receipt = await sdk.deposits.wait(handle, { for: 'l2' }); + console.log('✅ L2 executed at block:', l2Receipt?.blockNumber); } + +main().catch((err) => { + console.error(err); + process.exit(1); +}); ``` +```typescript title="ethers" +/** + * Example: Deposit ETH from L1 into a ZKsync L2 + */ +import 'dotenv/config'; +import { JsonRpcProvider, Wallet, parseEther } from 'ethers'; +import { createEthersClient, createEthersSdk } from '@dutterbutter/zksync-sdk/ethers'; +import type { Address } from '@dutterbutter/zksync-sdk/core'; +import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; + +// --- CONFIG --- +const L1_RPC = process.env.L1_RPC_URL ?? 'http://localhost:8545'; +const L2_RPC = process.env.L2_RPC_URL ?? 'http://localhost:3050'; +const PRIVATE_KEY = process.env.PRIVATE_KEY ?? ''; + +async function main() { + if (!PRIVATE_KEY) throw new Error('⚠️ Set your PRIVATE_KEY in the .env file'); + + const l1 = new JsonRpcProvider(L1_RPC); + const l2 = new JsonRpcProvider(L2_RPC); + const signer = new Wallet(PRIVATE_KEY, l1); + + const me = signer.address as Address; + console.log('Using account:', me); + + // --- INIT SDK --- + const client = await createEthersClient({ l1, l2, signer }); + const sdk = createEthersSdk(client); + + // --- DEPOSIT PARAMS --- + const params = { + amount: parseEther('0.01'), + token: ETH_ADDRESS, + to: me, + } as const; + + // --- STEP 1: QUOTE --- + const quote = await sdk.deposits.quote(params); + console.log('QUOTE →', quote); + + // --- STEP 2: PREPARE --- + const plan = await sdk.deposits.prepare(params); + console.log('PREPARE →', plan); + + // --- STEP 3: CREATE (send tx) --- + const handle = await sdk.deposits.create(params); + console.log('CREATE →', handle); -## Troubleshooting + // --- STEP 4 & 5: TRACK --- + console.log('⏳ Waiting for L1 inclusion...'); + const l1Receipt = await sdk.deposits.wait(handle, { for: 'l1' }); + console.log('✅ L1 included at block:', l1Receipt?.blockNumber); -- **Stuck at L1:** check L1 gas and RPC health. -- **No L2 execution:** verify L2 RPC; re-check `status()` (should move to `L2_EXECUTED`). -- **L2 failed:** if `phase === 'L2_FAILED'`, inspect the revert info via your error envelope/logs. + console.log('⏳ Waiting for L2 execution...'); + const l2Receipt = await sdk.deposits.wait(handle, { for: 'l2' }); + console.log('✅ L2 executed at block:', l2Receipt?.blockNumber); ---- + const finalStatus = await sdk.deposits.status(handle); + console.log('FINAL STATUS →', finalStatus); +} + +main().catch((err) => { + console.error(err); + process.exit(1); +}); +``` + + + +### Related API Reference -## See also +For more detailed information on the methods used in this guide, see the official API reference: -- [Status vs Wait](/concepts/status-vs-wait) -- [ZKsync RPC Helpers](/zks/methods) + * [`sdk.deposits.quote()`](https://zksync-sdk.mintlify.app/api-reference/ethers/deposits#quote-p%3A-depositparams-%E2%86%92-promise%3Cdepositquote%3E) + * [`sdk.deposits.prepare()`](https://zksync-sdk.mintlify.app/api-reference/ethers/deposits#prepare-p%3A-depositparams-%E2%86%92-promise%3Cdepositplan%3Ctransactionrequest%3E%3E) + * [`sdk.deposits.create()`](https://zksync-sdk.mintlify.app/api-reference/ethers/deposits#create-p%3A-depositparams-%E2%86%92-promise%3Cdeposithandle%3Ctransactionrequest%3E%3E) + * [`sdk.deposits.status()`](https://zksync-sdk.mintlify.app/api-reference/ethers/deposits#status-handleorhash-%E2%86%92-promise%3Cdepositstatus%3E) + * [`sdk.deposits.wait()`](https://zksync-sdk.mintlify.app/api-reference/ethers/deposits#wait-handleorhash%2C-%7B-for%3A-l1-%7C-l2-%7D-%E2%86%92-promise%3Ctransactionreceipt-%7C-null%3E) diff --git a/docs/guides/withdrawals.mdx b/docs/guides/withdrawals.mdx index e69de29..69868f9 100644 --- a/docs/guides/withdrawals.mdx +++ b/docs/guides/withdrawals.mdx @@ -0,0 +1,412 @@ +--- +title: "Withdrawals (L2 → L1)" +description: "Fast, developer-focused withdrawals with validation, observability, and battle-tested patterns." +--- + +# Guide: Withdrawing funds L2 to L1 + +This guide provides a complete walkthrough for withdrawing funds from an L2 (ZKsync) back to L1 (Ethereum). We will use the `@dutterbutter/zksync-sdk` to simplify the process. + +The SDK intelligently handles the withdrawal flow, automatically selecting the correct route and approval requirements based on the token being used. + +### Prerequisites + +Before you begin, ensure you have the following: + +1. **Node.js v20+** or **Bun.sh** installed. + +2. An account with **sufficient L2 balance** of the asset you want to withdraw and **L2 gas** for the withdrawal transaction. + +3. RPC endpoints for both the **L2** you’re withdrawing from and the **L1** you’re withdrawing to. + +4. A project set up with `viem` or `ethers` and `@dutterbutter/zksync-sdk` installed. + + + ```bash title="viem" + npm install viem @dutterbutter/zksync-sdk dotenv + ``` + ```bash title="ethers" + npm install ethers @dutterbutter/zksync-sdk dotenv + ``` + + +5. An `.env` file in your project's root directory with the following variables: + + ```ini + # .env + L1_RPC_URL="YOUR_L1_RPC_ENDPOINT" + L2_RPC_URL="YOUR_L2_RPC_ENDPOINT" + PRIVATE_KEY="YOUR_WALLET_PRIVATE_KEY" + ``` + +### The Withdrawal Process: Step-by-Step + +Withdrawals generally follow **two phases**: + +* An **L2 transaction** that burns/transfers the token and emits the L2→L1 message. +* A **finalization on L1** (after the message is ready) to release funds on L1. + The SDK exposes `wait(..., { for: 'ready' })`, `tryFinalize(...)`, and `wait(..., { for: 'finalized' })`. + +#### Step 0: Setup and SDK Initialization + +Connect to L1 and L2 using your preferred library (`viem` or `ethers`) and initialize the ZKsync SDK. + + +```typescript title="viem" +import 'dotenv/config'; +import { + createPublicClient, + createWalletClient, + http, + parseEther, + type Account, + type Chain, + type Transport, + type WalletClient, +} from 'viem'; +import { privateKeyToAccount } from 'viem/accounts'; +import { createViemClient, createViemSdk } from '@dutterbutter/zksync-sdk/viem'; + +// Load configuration from .env file +const L1_RPC = process.env.L1_RPC_URL!; +const L2_RPC = process.env.L2_RPC_URL!; +const PRIVATE_KEY = process.env.PRIVATE_KEY!; + +// --- 1. Initialize Clients and Wallet --- +const account = privateKeyToAccount(PRIVATE_KEY as `0x${string}`); +const l1 = createPublicClient({ transport: http(L1_RPC) }); +const l2 = createPublicClient({ transport: http(L2_RPC) }); +const l1Wallet: WalletClient = createWalletClient({ + account, + transport: http(L1_RPC), +}); +// Need to provide an L2 wallet client for sending L2 withdraw tx +const l2Wallet = createWalletClient({ + account, + transport: http(L2_RPC), +}); + +// --- 2. Initialize the SDK --- +const client = createViemClient({ l1, l2, l2Wallet }); +const sdk = createViemSdk(client); + +console.log(`Using account: ${account.address}`); +``` +```typescript title="ethers" +import 'dotenv/config'; +import { JsonRpcProvider, Wallet, parseEther } from 'ethers'; +import { createEthersClient, createEthersSdk } from '@dutterbutter/zksync-sdk/ethers'; + +// Load configuration from .env file +const L1_RPC = process.env.L1_RPC_URL!; +const L2_RPC = process.env.L2_RPC_URL!; +const PRIVATE_KEY = process.env.PRIVATE_KEY!; + +// --- 1. Initialize Providers and Signer --- +// You’ll send the withdraw tx on L2. +const l1Provider = new JsonRpcProvider(L1_RPC); +const l2Provider = new JsonRpcProvider(L2_RPC); +const signer = new Wallet(PRIVATE_KEY, l1Provider); + +// --- 2. Initialize the SDK --- +const client = await createEthersClient({ l1: l1Provider, l2: l2Provider, signer }); +const sdk = createEthersSdk(client); + +console.log(`Using account: ${await signer.getAddress()}`); +``` + + + +#### Step 1: Define Withdrawal Parameters + +Next, define the parameters for your withdrawal in an object. You’ll specify the **amount**, the **L2 token address** (or `ETH_ADDRESS` for native ETH on ETH-based L2s), and the **recipient’s address on L1**. + + +```typescript title="ETH — Base L2" +import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; +import type { Address } from '@dutterbutter/zksync-sdk/core'; + +const withdrawalParams = { + amount: parseEther('0.02'), + token: ETH_ADDRESS, // 👈 For ETH-based L2s, use the ETH sentinel + to: await signer.getAddress(), // L1 recipient (can be different from the L2 sender) +} as const; +``` + +```typescript title="ETH — Non-Base L2" +import type { Address } from '@dutterbutter/zksync-sdk/core'; + +// Example: an L2-ETH token address on your L2 (replace with the correct L2 token) +// You can store/resolve this via config or a helper. +const L2_ETH_TOKEN = process.env.L2_ETH_TOKEN as Address; + +const withdrawalParams = { + amount: parseEther('0.02'), + token: L2_ETH_TOKEN, // 👈 L2 representation of ETH on non-ETH-base chains + to: await signer.getAddress(), +} as const; +``` + +```typescript title="ERC-20" +import type { Address } from '@dutterbutter/zksync-sdk/core'; + +// If you have an L1 token and need its L2 counterpart: +// const l2Token = await sdk.helpers.l2TokenAddress(L1_ERC20_TOKEN); +// Otherwise, use your known L2 token address directly: +const L2_ERC20_TOKEN = process.env.L2_ERC20_TOKEN as Address; + +const withdrawalParams = { + amount: parseEther('10'), // or use parseUnits('amount', decimals) if not 18 + token: L2_ERC20_TOKEN, // 👈 L2 token address for the ERC-20 + to: await signer.getAddress(), +} as const; +``` + +```typescript title="Base Token" +import { L2_BASE_TOKEN_ADDRESS } from '@dutterbutter/zksync-sdk/core'; +import type { Address } from '@dutterbutter/zksync-sdk/core'; + +const withdrawalParams = { + amount: parseEther('5'), // adjust to your base token decimals if not 18 + token: L2_BASE_TOKEN_ADDRESS, // 👈 L2 address of the chain’s Base Token (ERC-20) + to: await signer.getAddress(), +} as const; +``` + + + + + +You can also specify advanced options for finer control over the transaction: + +* `l2GasLimit`: The gas limit for the L2 withdrawal transaction. +* `operatorTip`: A tip for the L2 operator (if supported). +* `refundRecipient`: An L1 address to receive any L1 finalize-phase refunds (chain-specific). + + + +#### Step 2: Quote the Withdrawal + +Before sending, get an estimate with `sdk.withdrawals.quote`. This returns expected fees and gas for the L2 step and any finalize phase hints. + + +You can skip straight to `create`, but quoting helps avoid surprises. + + +```typescript +// --- STEP 2: QUOTE --- +const quote = await sdk.withdrawals.quote(withdrawalParams); +console.log('WITHDRAW QUOTE →', quote); +``` + +#### Step 3: Prepare the Transaction + +Build the execution plan with `sdk.withdrawals.prepare`. For non-base ERC-20s or non-ETH L2-ETH, this may include **L2 approvals**. + +```typescript +// --- STEP 3: PREPARE --- +const plan = await sdk.withdrawals.prepare(withdrawalParams); +console.log('TRANSACTION PLAN →', plan); +``` + +#### Step 4: Create the Withdrawal + +Execute the plan with `sdk.withdrawals.create`. You’ll get a `handle` you can use to track the withdrawal across phases. + +```typescript +// --- STEP 4: CREATE (send L2 tx) --- +const handle = await sdk.withdrawals.create(withdrawalParams); +console.log('TRANSACTION CREATED →', handle); +``` + +#### Step 5: Track the Withdrawal Lifecycle + +Use `status` and `wait` to track all phases: + +* `wait(handle, { for: 'l2' })` → L2 inclusion +* `wait(handle, { for: 'ready' })` → message proven/ready on L1 +* `tryFinalize(l2TxHash)` → submit finalize on L1 (no-op if already finalized) +* `wait(l2TxHash, { for: 'finalized' })` → finalized on L1 + +```typescript +// --- STEP 5: TRACK --- +// L2 inclusion +console.log('⏳ Waiting for L2 inclusion...'); +const l2Receipt = await sdk.withdrawals.wait(handle, { for: 'l2' }); +console.log('✅ L2 included at block:', l2Receipt?.blockNumber); + +// Ready to finalize on L1 +console.log('⏳ Waiting until ready to finalize on L1...'); +await sdk.withdrawals.wait(handle, { for: 'ready' }); +console.log('STATUS (ready):', await sdk.withdrawals.status(handle)); + +// Submit finalize (safe to call even if someone else already finalized) +const finalizeResult = await sdk.withdrawals.tryFinalize(handle.l2TxHash); +console.log('TRY FINALIZE →', finalizeResult); + +// Confirm finalization +console.log('⏳ Waiting for L1 finalization...'); +const l1Receipt = await sdk.withdrawals.wait(handle.l2TxHash, { for: 'finalized' }); +console.log('✅ Finalized on L1. Receipt:', l1Receipt?.transactionHash ?? '(finalized elsewhere)'); +``` + +Once the `finalized` phase completes, your funds are available on L1 at the `to` address. + +### Full Code Example + +Here is the complete, runnable script for your reference. + + + + + +```typescript title="viem" +/** + * Example: Withdraw ETH (ETH-based L2) → L1 + */ +import 'dotenv/config'; +import { + createPublicClient, + createWalletClient, + http, + parseEther, + type Account, + type Chain, + type Transport, + type WalletClient, +} from 'viem'; +import { privateKeyToAccount } from 'viem/accounts'; + +import { createViemClient, createViemSdk } from '@dutterbutter/zksync-sdk/viem'; +import type { Address } from '@dutterbutter/zksync-sdk/core'; +import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; + +const L1_RPC = process.env.L1_RPC_URL ?? 'http://localhost:8545'; +const L2_RPC = process.env.L2_RPC_URL ?? 'http://localhost:3050'; +const PRIVATE_KEY = process.env.PRIVATE_KEY ?? ''; + +async function main() { + if (!PRIVATE_KEY || PRIVATE_KEY.length !== 66) { + throw new Error('⚠️ Set a 0x-prefixed 32-byte PRIVATE_KEY in your .env'); + } + + const account = privateKeyToAccount(PRIVATE_KEY as `0x${string}`); + const l1 = createPublicClient({ transport: http(L1_RPC) }); + const l2 = createPublicClient({ transport: http(L2_RPC) }); + const l2Wallet: WalletClient = createWalletClient({ + account, + transport: http(L2_RPC), + }); + + const client = createViemClient({ l1, l2, l2Wallet }); + const sdk = createViemSdk(client); + + const meL1 = account.address as Address; + const params = { + amount: parseEther('0.02'), + token: ETH_ADDRESS, + to: meL1, + } as const; + + const quote = await sdk.withdrawals.quote(params); + console.log('QUOTE →', quote); + + const plan = await sdk.withdrawals.prepare(params); + console.log('PREPARE →', plan); + + const handle = await sdk.withdrawals.create(params); + console.log('CREATE →', handle); + + const l2Receipt = await sdk.withdrawals.wait(handle, { for: 'l2' }); + console.log('✅ L2 included at block:', l2Receipt?.blockNumber); + + await sdk.withdrawals.wait(handle, { for: 'ready' }); + console.log('STATUS (ready) →', await sdk.withdrawals.status(handle)); + + const fin = await sdk.withdrawals.tryFinalize(handle.l2TxHash); + console.log('TRY FINALIZE →', fin); + + const l1Receipt = await sdk.withdrawals.wait(handle.l2TxHash, { for: 'finalized' }); + console.log('✅ Finalized on L1:', l1Receipt?.transactionHash ?? '(finalized elsewhere)'); +} + +main().catch((err) => { + console.error(err); + process.exit(1); +}); +``` + +```typescript title="ethers" +/** + * Example: Withdraw Base Token (ERC-20 base) or ETH → L1 + */ +import 'dotenv/config'; +import { JsonRpcProvider, Wallet, parseEther } from 'ethers'; +import { createEthersClient, createEthersSdk } from '@dutterbutter/zksync-sdk/ethers'; +import type { Address } from '@dutterbutter/zksync-sdk/core'; +import { ETH_ADDRESS, L2_BASE_TOKEN_ADDRESS } from '@dutterbutter/zksync-sdk/core'; + +const L1_RPC = process.env.L1_RPC_URL ?? 'http://localhost:8545'; +const L2_RPC = process.env.L2_RPC_URL ?? 'http://localhost:3050'; +const PRIVATE_KEY = process.env.PRIVATE_KEY ?? ''; + +async function main() { + if (!PRIVATE_KEY) throw new Error('⚠️ Set your PRIVATE_KEY in the .env file'); + + const l1 = new JsonRpcProvider(L1_RPC); + const l2 = new JsonRpcProvider(L2_RPC); + const signer = new Wallet(PRIVATE_KEY, l2); // withdraw is sent on L2 + + const client = await createEthersClient({ l1, l2, signer }); + const sdk = createEthersSdk(client); + + const meL1 = (await signer.getAddress()) as Address; + + // Toggle either ETH or the L2 base token address: + const params = { + amount: parseEther('1'), + token: ETH_ADDRESS /* or L2_BASE_TOKEN_ADDRESS */, + to: meL1, + } as const; + + const quote = await sdk.withdrawals.quote(params); + console.log('QUOTE →', quote); + + const plan = await sdk.withdrawals.prepare(params); + console.log('PREPARE →', plan); + + const handle = await sdk.withdrawals.create(params); + console.log('CREATE →', handle); + + const l2Receipt = await sdk.withdrawals.wait(handle, { for: 'l2' }); + console.log('✅ L2 included at block:', l2Receipt?.blockNumber); + + await sdk.withdrawals.wait(handle, { for: 'ready' }); + console.log('STATUS (ready) →', await sdk.withdrawals.status(handle)); + + const fin = await sdk.withdrawals.tryFinalize(handle.l2TxHash); + console.log('TRY FINALIZE →', fin); + + const l1Receipt = await sdk.withdrawals.wait(handle.l2TxHash, { for: 'finalized' }); + console.log('✅ Finalized on L1:', l1Receipt?.transactionHash ?? '(finalized elsewhere)'); +} + +main().catch((err) => { + console.error(err); + process.exit(1); +}); +``` + + + + +### Related API Reference + +For more detailed information on the methods used in this guide, see the official API reference: + +* [`sdk.withdrawals.quote()`](/api-reference/ethers/withdrawals#quote) +* [`sdk.withdrawals.prepare()`](/api-reference/ethers/withdrawals#prepare) +* [`sdk.withdrawals.create()`](/api-reference/ethers/withdrawals#create) +* [`sdk.withdrawals.status()`](/api-reference/ethers/withdrawals#status) +* [`sdk.withdrawals.wait()`](/api-reference/ethers/withdrawals#wait) +* [`sdk.withdrawals.tryFinalize()`](/api-reference/ethers/withdrawals#tryfinalize) diff --git a/docs/index.mdx b/docs/index.mdx index c0ea9d5..48fbde5 100644 --- a/docs/index.mdx +++ b/docs/index.mdx @@ -63,10 +63,10 @@ mode: "custom" Use an ethers v6 signer to perform a deposit and wait for finality. - + Understand statuses vs waits and how to poll each phase of a flow. - + Utilities like getBridgehubAddress, getL2ToL1LogProof, and enhanced receipts. @@ -81,7 +81,7 @@ mode: "custom" See what’s new, fixed, and changed across releases. - + Questions or issues? Reach out and we’ll help you. diff --git a/docs/snippets/deposits/ethers.mdx b/docs/snippets/deposits/ethers.mdx deleted file mode 100644 index c5daad5..0000000 --- a/docs/snippets/deposits/ethers.mdx +++ /dev/null @@ -1,88 +0,0 @@ -export const EthersDeposits = () => { - return ( -```ts ethers.ts -// examples/deposit-eth.ts -import { JsonRpcProvider, Wallet, parseEther } from 'ethers'; -import { createEthersClient, createEthersSdk } from '@dutterbutter/zksync-sdk/ethers'; -import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; - -const L1_RPC = 'http://localhost:8545'; // e.g. https://sepolia.infura.io/v3/XXX -const L2_RPC = 'http://localhost:3050'; // your L2 RPC -const PRIVATE_KEY = process.env.PRIVATE_KEY || ''; - -async function main() { - if (!PRIVATE_KEY) { - throw new Error('Set your PRIVATE_KEY in the .env file'); - } - const l1 = new JsonRpcProvider(L1_RPC); - const l2 = new JsonRpcProvider(L2_RPC); - const signer = new Wallet(PRIVATE_KEY, l1); - - const balance = await l1.getBalance(signer.address); - console.log('L1 balance:', balance.toString()); - - const balanceL2 = await l2.getBalance(signer.address); - console.log('L2 balance:', balanceL2.toString()); - - const client = await createEthersClient({ l1, l2, signer }); - const sdk = createEthersSdk(client); - - const me = (await signer.getAddress()); - const params = { - amount: parseEther('.01'), // 0.01 ETH - to: me, - token: ETH_ADDRESS, - // optional: - // l2GasLimit: 300_000n, - // gasPerPubdata: 800n, - // operatorTip: 0n, - // refundRecipient: me, - } as const; - - // Quote - const quote = await sdk.deposits.quote(params); - console.log('QUOTE response: ', quote); - - const prepare = await sdk.deposits.prepare(params); - console.log('PREPARE response: ', prepare); - - // Create (prepare + send) - const create = await sdk.deposits.create(params); - console.log('CREATE response: ', create); - - const status = await sdk.deposits.status(create); - console.log('STATUS response: ', status); - - // Wait (for now, L1 inclusion) - const receipt = await sdk.deposits.wait(create, { for: 'l1' }); - console.log( - 'Included at block:', - receipt?.blockNumber, - 'status:', - receipt?.status, - 'hash:', - receipt?.hash, - ); - - const status2 = await sdk.deposits.status(create); - console.log('STATUS2 response: ', status2); - - // Wait (for now, L2 inclusion) - const l2Receipt = await sdk.deposits.wait(create, { for: 'l2' }); - console.log( - 'Included at block:', - l2Receipt?.blockNumber, - 'status:', - l2Receipt?.status, - 'hash:', - l2Receipt?.hash, - ); -} - -main().catch((e) => { - console.error(e); - process.exit(1); -}); -``` - ); -} \ No newline at end of file diff --git a/docs/snippets/deposits/viem.mdx b/docs/snippets/deposits/viem.mdx deleted file mode 100644 index c0b4af5..0000000 --- a/docs/snippets/deposits/viem.mdx +++ /dev/null @@ -1,106 +0,0 @@ -export const ViemDeposits = () => { - return ( -```ts viem.ts -// viem deposit (ETH) — minimal example - -import { createPublicClient, createWalletClient, http, parseEther } from 'viem'; -import type { Account, Chain, Transport, WalletClient } from 'viem'; -import { privateKeyToAccount } from 'viem/accounts'; - -import { createViemSdk, createViemClient } from '@dutterbutter/zksync-sdk/viem'; -import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; - -const L1_RPC = 'http://localhost:8545'; // e.g. https://sepolia.infura.io/v3/XXX -const L2_RPC = 'http://localhost:3050'; // your L2 RPC -const PRIVATE_KEY = process.env.PRIVATE_KEY || ''; - -async function main() { - if (!PRIVATE_KEY || PRIVATE_KEY.length !== 66) { - throw new Error('Set your PRIVATE_KEY in the .env file (0x-prefixed, 32 bytes)'); - } - - // --- Viem clients --- - const account = privateKeyToAccount(PRIVATE_KEY); - - const l1 = createPublicClient({ transport: http(L1_RPC) }); - const l2 = createPublicClient({ transport: http(L2_RPC) }); - - const l1Wallet: WalletClient = createWalletClient({ - account, - transport: http(L1_RPC), - }); - - // Check balances - const [balL1, balL2] = await Promise.all([ - l1.getBalance({ address: account.address }), - l2.getBalance({ address: account.address }), - ]); - console.log('L1 balance:', balL1.toString()); - console.log('L2 balance:', balL2.toString()); - - // client + sdk - const client = createViemClient({ l1, l2, l1Wallet }); - const sdk = createViemSdk(client); - - const me = account.address; - const params = { - amount: parseEther('0.01'), // 0.01 ETH - to: me, - token: ETH_ADDRESS, - // optional: - // l2GasLimit: 300_000n, - // gasPerPubdata: 800n, - // operatorTip: 0n, - // refundRecipient: me, - } as const; - - // Quote - const quote = await sdk.deposits.quote(params); - console.log('QUOTE response:', quote); - - // Prepare (route + steps, no sends) - const prepared = await sdk.deposits.prepare(params); - console.log('PREPARE response:', prepared); - - // Create (prepare + send) - const created = await sdk.deposits.create(params); - console.log('CREATE response:', created); - - // Status (quick check) - const status = await sdk.deposits.status(created); - console.log('STATUS response:', status); - - // Wait (L1 inclusion) - const l1Receipt = await sdk.deposits.wait(created, { for: 'l1' }); - console.log( - 'L1 Included at block:', - l1Receipt?.blockNumber, - 'status:', - l1Receipt?.status, - 'hash:', - l1Receipt?.transactionHash, - ); - - // Status again - const status2 = await sdk.deposits.status(created); - console.log('STATUS2 response:', status2); - - // Wait for L2 execution - const l2Receipt = await sdk.deposits.wait(created, { for: 'l2' }); - console.log( - 'L2 Included at block:', - l2Receipt?.blockNumber, - 'status:', - l2Receipt?.status, - 'hash:', - l2Receipt?.transactionHash, - ); -} - -main().catch((e) => { - console.error(e); - process.exit(1); -}); -``` - ); -} \ No newline at end of file diff --git a/docs/snippets/withdrawals/ethers.mdx b/docs/snippets/withdrawals/ethers.mdx deleted file mode 100644 index e69de29..0000000 diff --git a/docs/snippets/withdrawals/viem.mdx b/docs/snippets/withdrawals/viem.mdx deleted file mode 100644 index e69de29..0000000 From 3f24696751f16b119bed1251334cb0439894c730 Mon Sep 17 00:00:00 2001 From: Dustin Brickwood Date: Fri, 10 Oct 2025 15:00:23 -0500 Subject: [PATCH 12/18] chore: address lint issue --- src/adapters/ethers/sdk.ts | 10 +++++----- src/core/types/errors.ts | 2 +- typedoc.json | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/adapters/ethers/sdk.ts b/src/adapters/ethers/sdk.ts index 5bb343f..2686ad1 100644 --- a/src/adapters/ethers/sdk.ts +++ b/src/adapters/ethers/sdk.ts @@ -24,10 +24,10 @@ export interface EthersSdk { * @see DepositsResourceType for a full list of methods. */ deposits: DepositsResourceType; - /** - * @summary Provides methods for withdrawing assets from L2 to L1. - * @see WithdrawalsResourceType for a full list of methods. - */ + /** + * @summary Provides methods for withdrawing assets from L2 to L1. + * @see WithdrawalsResourceType for a full list of methods. + */ withdrawals: WithdrawalsResourceType; /** * @summary A collection of utility functions for common tasks like resolving addresses, @@ -122,7 +122,7 @@ export function createEthersSdk(client: EthersClient): EthersSdk { async l1AssetRouter() { const { l1AssetRouter } = await client.contracts(); return l1AssetRouter; - }, + }, async l1NativeTokenVault() { const { l1NativeTokenVault } = await client.contracts(); return l1NativeTokenVault; diff --git a/src/core/types/errors.ts b/src/core/types/errors.ts index b2e5021..0762bae 100644 --- a/src/core/types/errors.ts +++ b/src/core/types/errors.ts @@ -54,7 +54,7 @@ export interface ErrorEnvelope { } // TODO: move to errors/ -/** Error class. +/** Error class. * Represents an error that occurs within the ZKsync SDK. * It encapsulates an ErrorEnvelope which provides detailed information about the error, * diff --git a/typedoc.json b/typedoc.json index 5c06609..28e6436 100644 --- a/typedoc.json +++ b/typedoc.json @@ -8,4 +8,4 @@ "readme": "none", "plugin": ["typedoc-plugin-markdown"], "hideGenerator": true -} \ No newline at end of file +} From b45fb32053c5a0095e57432bd602123d1c35b7a6 Mon Sep 17 00:00:00 2001 From: Dustin Brickwood Date: Fri, 10 Oct 2025 15:13:43 -0500 Subject: [PATCH 13/18] fix: clean up css --- docs/images/checks-passed.png | Bin 160724 -> 0 bytes docs/images/hero-dark.png | Bin 110614 -> 0 bytes docs/images/hero-light.png | Bin 104264 -> 0 bytes docs/snippets/snippet-intro.mdx | 4 - docs/style.css | 163 ++++++++++---------------------- 5 files changed, 50 insertions(+), 117 deletions(-) delete mode 100644 docs/images/checks-passed.png delete mode 100644 docs/images/hero-dark.png delete mode 100644 docs/images/hero-light.png delete mode 100644 docs/snippets/snippet-intro.mdx diff --git a/docs/images/checks-passed.png b/docs/images/checks-passed.png deleted file mode 100644 index 3303c773646ca12fb6852356663540e3ed048115..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 160724 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ɊgP+1Kmq9C+NW`N{6BwF_FKP% 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

f_Qe2@sz@M2$uLLxR{EU6s^ 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 * { position: relative; } From 1caebe199ceb65751f848d4b8b3bec52e9efd1d0 Mon Sep 17 00:00:00 2001 From: Dustin Brickwood Date: Fri, 10 Oct 2025 16:06:19 -0500 Subject: [PATCH 14/18] fix: example script error --- .github/workflows/ci-test.yaml | 10 ++++++++-- examples/ethers/withdrawals/eth.ts | 2 +- .../ethers/resources/withdrawals/routes/eth.ts | 1 - 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-test.yaml b/.github/workflows/ci-test.yaml index a025e7c..765285a 100644 --- a/.github/workflows/ci-test.yaml +++ b/.github/workflows/ci-test.yaml @@ -66,8 +66,14 @@ jobs: with: version: v1.3.4 - - name: Clone zksync-os-server - run: git clone https://github.com/matter-labs/zksync-os-server.git + - name: Checkout zksync-os-server v0.8.0 + uses: actions/checkout@v4 + with: + repository: matter-labs/zksync-os-server + ref: v0.8.0 + path: zksync-os-server + fetch-depth: 1 + submodules: recursive - name: Cache cargo uses: actions/cache@v4 diff --git a/examples/ethers/withdrawals/eth.ts b/examples/ethers/withdrawals/eth.ts index 5ec1c25..cb571c4 100644 --- a/examples/ethers/withdrawals/eth.ts +++ b/examples/ethers/withdrawals/eth.ts @@ -42,7 +42,7 @@ async function main() { const params = { token: ETH_ADDRESS, // ETH token on this chain - amount: parseEther('1'), + amount: parseEther('.0001'), to: me, // l2GasLimit?: 300_000n, fee overrides, etc... } as const; diff --git a/src/adapters/ethers/resources/withdrawals/routes/eth.ts b/src/adapters/ethers/resources/withdrawals/routes/eth.ts index 37a29ff..d198df3 100644 --- a/src/adapters/ethers/resources/withdrawals/routes/eth.ts +++ b/src/adapters/ethers/resources/withdrawals/routes/eth.ts @@ -18,7 +18,6 @@ export function routeEthBase(): WithdrawRouteStrategy { const base = new Contract( L2_BASE_TOKEN_ADDRESS, - new Interface(IBaseTokenABI), ctx.client.l2, ); From 19b4e82dbf489401a9f55bbe42022413e425f626 Mon Sep 17 00:00:00 2001 From: Dustin Brickwood Date: Mon, 13 Oct 2025 07:31:58 -0500 Subject: [PATCH 15/18] chore: address lint issue --- src/adapters/ethers/resources/withdrawals/routes/eth.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/adapters/ethers/resources/withdrawals/routes/eth.ts b/src/adapters/ethers/resources/withdrawals/routes/eth.ts index d198df3..fd0a6de 100644 --- a/src/adapters/ethers/resources/withdrawals/routes/eth.ts +++ b/src/adapters/ethers/resources/withdrawals/routes/eth.ts @@ -16,11 +16,7 @@ export function routeEthBase(): WithdrawRouteStrategy { async build(p, ctx) { const steps: Array> = []; - const base = new Contract( - L2_BASE_TOKEN_ADDRESS, - new Interface(IBaseTokenABI), - ctx.client.l2, - ); + const base = new Contract(L2_BASE_TOKEN_ADDRESS, new Interface(IBaseTokenABI), ctx.client.l2); const toL1 = p.to ?? ctx.sender; const data = await wrapAs( From 00f4e881a982f592373dc6706d4866794a524467 Mon Sep 17 00:00:00 2001 From: Dustin Brickwood Date: Tue, 14 Oct 2025 08:08:55 -0500 Subject: [PATCH 16/18] fix: bump zksync-os-server version --- .github/workflows/ci-test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-test.yaml b/.github/workflows/ci-test.yaml index 765285a..28a4419 100644 --- a/.github/workflows/ci-test.yaml +++ b/.github/workflows/ci-test.yaml @@ -70,7 +70,7 @@ jobs: uses: actions/checkout@v4 with: repository: matter-labs/zksync-os-server - ref: v0.8.0 + ref: v0.8.2 path: zksync-os-server fetch-depth: 1 submodules: recursive From ab02fdd3cb8aa451770e4ce39b0ee3ac8bcd1a64 Mon Sep 17 00:00:00 2001 From: Dustin Brickwood Date: Mon, 20 Oct 2025 10:10:00 -0500 Subject: [PATCH 17/18] docs: fix links --- docs/README.md | 1 + docs/ai-tools/claude-code.mdx | 21 +- docs/ai-tools/cursor.mdx | 29 +- docs/ai-tools/windsurf.mdx | 16 +- docs/api-reference/core/errors.mdx | 37 +- docs/api-reference/core/rpc.mdx | 13 +- docs/api-reference/ethers/client.mdx | 46 ++- docs/api-reference/ethers/deposits.mdx | 103 +++--- docs/api-reference/ethers/sdk.mdx | 32 +- docs/api-reference/ethers/withdrawals.mdx | 96 +++--- docs/api-reference/introduction.mdx | 50 +-- docs/api-reference/viem/client.mdx | 51 ++- docs/api-reference/viem/deposits.mdx | 99 +++--- docs/api-reference/viem/sdk.mdx | 23 +- docs/api-reference/viem/withdrawals.mdx | 92 ++--- docs/changelog.mdx | 73 ++-- docs/docs.json | 87 ++--- docs/guides/deposits.mdx | 65 ++-- docs/guides/withdrawals.mdx | 82 +++-- docs/index.mdx | 27 +- docs/overview/adapters.mdx | 54 +-- docs/overview/finalization.mdx | 58 ++-- docs/overview/index.mdx | 36 +- docs/overview/mental-model.mdx | 78 ++--- docs/overview/status-vs-wait.mdx | 43 +-- docs/quickstart/deposits.mdx | 11 +- docs/quickstart/index.mdx | 7 +- docs/quickstart/withdrawals.mdx | 19 +- docs/style.css | 390 +++++++++++++++------- 29 files changed, 991 insertions(+), 748 deletions(-) diff --git a/docs/README.md b/docs/README.md index 5297803..4981553 100644 --- a/docs/README.md +++ b/docs/README.md @@ -40,4 +40,5 @@ Install our GitHub app from your [dashboard](https://dashboard.mintlify.com/sett - If a page loads as a 404: Make sure you are running in a folder with a valid `docs.json`. ### Resources + - [Mintlify documentation](https://mintlify.com/docs) diff --git a/docs/ai-tools/claude-code.mdx b/docs/ai-tools/claude-code.mdx index bdc4e04..20be6cd 100644 --- a/docs/ai-tools/claude-code.mdx +++ b/docs/ai-tools/claude-code.mdx @@ -1,7 +1,7 @@ --- -title: "Claude Code setup" -description: "Configure Claude Code for your documentation workflow" -icon: "asterisk" +title: 'Claude Code setup' +description: 'Configure Claude Code for your documentation workflow' +icon: 'asterisk' --- Claude Code is Anthropic's official CLI tool. This guide will help you set up Claude Code to help you write and maintain your documentation. @@ -14,8 +14,8 @@ Claude Code is Anthropic's official CLI tool. This guide will help you set up Cl 1. Install Claude Code globally: - ```bash - npm install -g @anthropic-ai/claude-code +```bash +npm install -g @anthropic-ai/claude-code ``` 2. Navigate to your docs directory. @@ -26,20 +26,23 @@ Claude Code is Anthropic's official CLI tool. This guide will help you set up Cl Create a `CLAUDE.md` file at the root of your documentation repository to train Claude Code on your specific documentation standards: -````markdown +```markdown # Mintlify documentation ## Working relationship + - You can push back on ideas-this can lead to better documentation. Cite sources and explain your reasoning when you do so - ALWAYS ask for clarification rather than making assumptions - NEVER lie, guess, or make up information ## Project context + - Format: MDX files with YAML frontmatter - Config: docs.json for navigation, theme, settings - Components: Mintlify components ## Content strategy + - Document just enough for user success - not too much, not too little - Prioritize accuracy and usability of information - Make content evergreen when possible @@ -48,10 +51,12 @@ Create a `CLAUDE.md` file at the root of your documentation repository to train - Start by making the smallest reasonable changes ## Frontmatter requirements for pages + - title: Clear, descriptive page title - description: Concise summary for SEO/navigation ## Writing standards + - Second-person voice ("you") - Prerequisites at start of procedural content - Test all code examples before publishing @@ -62,6 +67,7 @@ Create a `CLAUDE.md` file at the root of your documentation repository to train - Relative paths for internal links ## Git workflow + - NEVER use --no-verify when committing - Ask how to handle uncommitted changes before starting - Create a new branch when no clear branch exists for changes @@ -69,8 +75,9 @@ Create a `CLAUDE.md` file at the root of your documentation repository to train - NEVER skip or disable pre-commit hooks ## Do not + - Skip frontmatter on any MDX file - Use absolute URLs for internal links - Include untested code examples - Make assumptions - always ask for clarification -```` +``` diff --git a/docs/ai-tools/cursor.mdx b/docs/ai-tools/cursor.mdx index fbb7761..6ec6152 100644 --- a/docs/ai-tools/cursor.mdx +++ b/docs/ai-tools/cursor.mdx @@ -1,7 +1,7 @@ --- -title: "Cursor setup" -description: "Configure Cursor for your documentation workflow" -icon: "arrow-pointer" +title: 'Cursor setup' +description: 'Configure Cursor for your documentation workflow' +icon: 'arrow-pointer' --- Use Cursor to help write and maintain your documentation. This guide shows how to configure Cursor for better results on technical writing tasks and using Mintlify components. @@ -102,8 +102,8 @@ const apiConfig = { baseURL: 'https://api.example.com', timeout: 5000, headers: { - 'Authorization': `Bearer ${process.env.API_TOKEN}` - } + Authorization: `Bearer ${process.env.API_TOKEN}`, + }, }; ``` @@ -120,7 +120,7 @@ const response = await fetch('/api/endpoint', { ```python Python import requests -response = requests.get('/api/endpoint', +response = requests.get('/api/endpoint', headers={'Authorization': f'Bearer {api_key}'}) ``` @@ -128,6 +128,7 @@ response = requests.get('/api/endpoint', curl -X GET '/api/endpoint' \ -H 'Authorization: Bearer YOUR_API_KEY' ``` + #### Request/response examples @@ -328,10 +329,11 @@ Wrap all images in frames: Use the HTML video element for self-hosted video content: +controls +className="w-full aspect-video rounded-xl" +src="link-to-your-video.com" + +> Embed YouTube videos using iframe elements: @@ -362,9 +364,10 @@ Use updates for changelogs: - Improved error messages with actionable suggestions ## Bug fixes + - Fixed pagination issue with large datasets - Resolved authentication timeout problems - + ## Required page structure @@ -372,8 +375,8 @@ Every documentation page must begin with YAML frontmatter: ```yaml --- -title: "Clear, specific, keyword-rich title" -description: "Concise description explaining page purpose and value" +title: 'Clear, specific, keyword-rich title' +description: 'Concise description explaining page purpose and value' --- ``` diff --git a/docs/ai-tools/windsurf.mdx b/docs/ai-tools/windsurf.mdx index fce12bf..44d6882 100644 --- a/docs/ai-tools/windsurf.mdx +++ b/docs/ai-tools/windsurf.mdx @@ -1,7 +1,7 @@ --- -title: "Windsurf setup" -description: "Configure Windsurf for your documentation workflow" -icon: "water" +title: 'Windsurf setup' +description: 'Configure Windsurf for your documentation workflow' +icon: 'water' --- Configure Windsurf's Cascade AI assistant to help you write and maintain documentation. This guide shows how to set up Windsurf specifically for your Mintlify documentation workflow. @@ -23,7 +23,7 @@ Create `.windsurf/rules.md` in your project root: ## Project context - This is a documentation project on the Mintlify platform -- We use MDX files with YAML frontmatter +- We use MDX files with YAML frontmatter - Navigation is configured in `docs.json` - We follow technical writing best practices @@ -42,8 +42,8 @@ Every page must start with frontmatter: ```yaml --- -title: "Clear, specific title" -description: "Concise description for SEO and navigation" +title: 'Clear, specific title' +description: 'Concise description for SEO and navigation' --- ``` @@ -53,7 +53,7 @@ description: "Concise description for SEO and navigation" - `` for helpful supplementary information - `` for important cautions and breaking changes -- `` for best practices and expert advice +- `` for best practices and expert advice - `` for neutral contextual information - `` for success confirmations @@ -80,7 +80,7 @@ description: "Concise description for SEO and navigation" ## API documentation requirements -- Document all parameters with `` +- Document all parameters with `` - Show response structure with `` - Include both success and error examples - Use `` for nested object properties diff --git a/docs/api-reference/core/errors.mdx b/docs/api-reference/core/errors.mdx index e8807f0..7b947ed 100644 --- a/docs/api-reference/core/errors.mdx +++ b/docs/api-reference/core/errors.mdx @@ -14,7 +14,8 @@ All SDK operations either: This is consistent across both **ethers** and **viem** adapters. -Prefer the try* variants when you want to avoid exceptions and branch on success/failure. + Prefer the try* variants when you want to avoid exceptions and branch on + success/failure. ## What gets thrown @@ -79,11 +80,11 @@ type ErrorEnvelope = { /** If the error is a contract revert, adapters include decoded info when available. */ revert?: { - selector: `0x${string}`; // 4-byte selector - name?: string; // Decoded Solidity error name - args?: unknown[]; // Decoded args - contract?: string; // Best-effort contract label - fn?: string; // Best-effort function label + selector: `0x${string}`; // 4-byte selector + name?: string; // Decoded Solidity error name + args?: unknown[]; // Decoded args + contract?: string; // Best-effort contract label + fn?: string; // Best-effort function label }; /** Originating error (provider/transport/etc.), sanitized for safe logging. */ @@ -99,7 +100,7 @@ type ErrorEnvelope = { | `STATE` | Operation not possible **yet** (e.g., not finalizable). Wait or change state. | | `EXECUTION` | A send/revert happened (tx reverted or couldn’t be confirmed). Inspect `revert` / `cause`. | | `RPC` | Provider/transport failure (endpoint/network issue). Retry with backoff / check infra. | -| `VERIFICATION` | Proof/verification step issue. Usually indicates unable to find deposit log. | +| `VERIFICATION` | Proof/verification step issue. Usually indicates unable to find deposit log. | | `CONTRACT` | A contract read/encode/allowance failed. Check addresses & ABI compatibility. | | `INTERNAL` | SDK internal error (please report with `operation` + `selector` if present). | @@ -137,9 +138,9 @@ try { Notes: -* The SDK always includes the **4-byte selector**. -* `name`/`args` appear when decodable against known ABIs; coverage will expand over time. -* When a revert implies “not ready yet,” you’ll typically see a `STATE` error with a clarifying `message`. +- The SDK always includes the **4-byte selector**. +- `name`/`args` appear when decodable against known ABIs; coverage will expand over time. +- When a revert implies “not ready yet,” you’ll typically see a `STATE` error with a clarifying `message`. ## Ethers & viem examples @@ -159,10 +160,11 @@ const sdk = createEthersSdk(client); const res = await sdk.deposits.tryCreate({ token, amount, to }); if (!res.ok) { - // report envelope - console.error(res.error.envelope); +// report envelope +console.error(res.error.envelope); } -``` + +```` ```ts title="Viem" import { createPublicClient, http, createWalletClient, privateKeyToAccount } from 'viem'; @@ -193,15 +195,16 @@ try { throw e; } } -``` +```` ## Logging & observability -* `err.toJSON()` returns a safe, structured object you can ship to logs/telemetry. -* For local debugging, printing `err` shows a compact, human-readable view (category, operation, context, optional revert/cause). +- `err.toJSON()` returns a safe, structured object you can ship to logs/telemetry. +- For local debugging, printing `err` shows a compact, human-readable view (category, operation, context, optional revert/cause). -Avoid parsing err.message for logic. Use the typed fields on err.envelope instead. + Avoid parsing err.message for logic. Use the typed fields on{' '} + err.envelope instead. diff --git a/docs/api-reference/core/rpc.mdx b/docs/api-reference/core/rpc.mdx index 3f35e32..9b43017 100644 --- a/docs/api-reference/core/rpc.mdx +++ b/docs/api-reference/core/rpc.mdx @@ -5,14 +5,14 @@ group: API Reference / Core --- ### Standard Ethereum RPC (`eth_*`) - + Use your base library for all `eth_*` methods. The client.zks -surface only covers ZKsync-specific RPC (zks_*). +surface only covers ZKsync-specific RPC (zks\_\*). For standard Ethereum JSON-RPC (e.g., eth_call, eth_getLogs, eth_getBalance), call them through your chosen library (`ethers` or `viem`). -## zks_ Interface +## zks\_ Interface ```ts interface ZksRpc { @@ -55,7 +55,8 @@ const proof = await client.zks.getL2ToL1LogProof(l2TxHash, 0); ``` -If a proof isn’t available yet, this method throws a typed STATE error. Poll based on your app’s cadence. + If a proof isn’t available yet, this method throws a typed STATE error. Poll based on + your app’s cadence. ### `getReceiptWithL2ToL1(txHash: Hex) → Promise` @@ -87,8 +88,8 @@ type ReceiptWithL2ToL1 = { ```ts title="ethers" -import { JsonRpcProvider, Wallet } from "ethers"; -import { createEthersClient } from "@dutterbutter/zksync-sdk/ethers"; +import { JsonRpcProvider, Wallet } from 'ethers'; +import { createEthersClient } from '@dutterbutter/zksync-sdk/ethers'; const l1 = new JsonRpcProvider(process.env.ETH_RPC!); const l2 = new JsonRpcProvider(process.env.ZKSYNC_RPC!); diff --git a/docs/api-reference/ethers/client.mdx b/docs/api-reference/ethers/client.mdx index 9a85114..8f99823 100644 --- a/docs/api-reference/ethers/client.mdx +++ b/docs/api-reference/ethers/client.mdx @@ -13,14 +13,14 @@ group: SDK Reference / Ethers ## Import ```ts -import { createEthersClient } from "@dutterbutter/zksync-sdk/ethers"; +import { createEthersClient } from '@dutterbutter/zksync-sdk/ethers'; ``` ## Quick start ```ts -import { JsonRpcProvider, Wallet } from "ethers"; -import { createEthersClient } from "@dutterbutter/zksync-sdk/ethers"; +import { JsonRpcProvider, Wallet } from 'ethers'; +import { createEthersClient } from '@dutterbutter/zksync-sdk/ethers'; const l1 = new JsonRpcProvider(process.env.ETH_RPC!); const l2 = new JsonRpcProvider(process.env.ZKSYNC_RPC!); @@ -36,18 +36,44 @@ const { bridgehub, l1AssetRouter } = await client.contracts(); ``` -The signer is force-bound to the **L1** provider to make L1 finalization flows work out of the box. + The signer is force-bound to the **L1** provider to make L1 finalization flows work out of the + box. ## `createEthersClient(args) → EthersClient` -L1 provider for reads and L1 transactions. L2 (ZKsync) provider for reads and ZK RPC. Signer for sends. If not connected to args.l1, it will be connected. Optional address overrides (forks/tests). + + L1 provider for reads and L1 transactions. + + + L2 (ZKsync) provider for reads and ZK RPC. + + + Signer for sends. If not connected to args.l1, it will be connected. + + + Optional address overrides (forks/tests). + **Returns:** `EthersClient` ## EthersClient interface -Adapter discriminator. Public L1 provider. Public L2 (ZKsync) provider. Signer (bound to l1 for sends). ZKsync-specific RPC surface bound to l2. + + Adapter discriminator. + + + Public L1 provider. + + + Public L2 (ZKsync) provider. + + + Signer (bound to l1 for sends). + + + ZKsync-specific RPC surface bound to l2. + ## Methods @@ -109,7 +135,7 @@ type ResolvedAddresses = { ## Notes & pitfalls -* **Provider roles:** `l1` is used for L1 lookups and finalization sends; `l2` is used for ZKsync reads/RPC via `zks`. -* **Signer binding:** The signer is connected to `l1` to ensure L1 transactions (e.g., finalize) succeed without extra wiring. -* **Caching:** `ensureAddresses()` and `contracts()` are cached. Call `refresh()` after network changes or when using new overrides. -* **Overrides:** For forks or custom deployments, pass `overrides` at construction; they are merged with on-chain resolution. +- **Provider roles:** `l1` is used for L1 lookups and finalization sends; `l2` is used for ZKsync reads/RPC via `zks`. +- **Signer binding:** The signer is connected to `l1` to ensure L1 transactions (e.g., finalize) succeed without extra wiring. +- **Caching:** `ensureAddresses()` and `contracts()` are cached. Call `refresh()` after network changes or when using new overrides. +- **Overrides:** For forks or custom deployments, pass `overrides` at construction; they are merged with on-chain resolution. diff --git a/docs/api-reference/ethers/deposits.mdx b/docs/api-reference/ethers/deposits.mdx index 9944645..460cf16 100644 --- a/docs/api-reference/ethers/deposits.mdx +++ b/docs/api-reference/ethers/deposits.mdx @@ -14,8 +14,8 @@ group: SDK Reference / Ethers ## Import ```ts -import { JsonRpcProvider, Wallet, parseEther } from "ethers"; -import { createEthersClient, createEthersSdk } from "@dutterbutter/zksync-sdk/ethers"; +import { JsonRpcProvider, Wallet, parseEther } from 'ethers'; +import { createEthersClient, createEthersSdk } from '@dutterbutter/zksync-sdk/ethers'; const l1 = new JsonRpcProvider(process.env.ETH_RPC!); const l2 = new JsonRpcProvider(process.env.ZKSYNC_RPC!); @@ -32,24 +32,24 @@ Deposit **0.1 ETH** from L1 → L2 and wait for **L2 execution**: ```ts const handle = await sdk.deposits.create({ - token: ETH_ADDRESS, // 0x…00 for ETH - amount: parseEther("0.1"), + token: ETH_ADDRESS, // 0x…00 for ETH + amount: parseEther('0.1'), to: await signer.getAddress(), }); -const l2Receipt = await sdk.deposits.wait(handle, { for: "l2" }); // null only if no L1 hash +const l2Receipt = await sdk.deposits.wait(handle, { for: 'l2' }); // null only if no L1 hash ``` -For UX that never throws, use the try* variants and branch on ok. + For UX that never throws, use the try* variants and branch on ok. ## Route selection (automatic) -* `eth-base` — ETH when L2 base token **is ETH** -* `eth-nonbase` — ETH when L2 base token **≠ ETH** -* `erc20-base` — ERC-20 that **is** the L2 base token -* `erc20-nonbase` — ERC-20 that **is not** the L2 base token +- `eth-base` — ETH when L2 base token **is ETH** +- `eth-nonbase` — ETH when L2 base token **≠ ETH** +- `erc20-base` — ERC-20 that **is** the L2 base token +- `erc20-nonbase` — ERC-20 that **is not** the L2 base token You **do not** pass a route; it’s derived from network metadata + `token`. @@ -59,14 +59,22 @@ You **do not** pass a route; it’s derived from network metadata + `token`. Estimate the operation (route, approvals, gas hints). Does **not** send txs. -L1 token (use 0x…00 for ETH). Amount in wei. L2 recipient. + + L1 token (use 0x…00 for ETH). + + + Amount in wei. + + + L2 recipient. + **Returns:** `DepositQuote` ```ts const q = await sdk.deposits.quote({ token: ETH_L1, - amount: parseEther("0.25"), + amount: parseEther('0.25'), to: await signer.getAddress(), }); /* @@ -82,7 +90,8 @@ const q = await sdk.deposits.quote({ ``` -If approvalsNeeded is non-empty (ERC-20), create will include those steps automatically. + If approvalsNeeded is non-empty (ERC-20), create will include those + steps automatically. ### `tryQuote(p) → Promise<{ ok: true; value: DepositQuote } | { ok: false; error }>` @@ -96,7 +105,7 @@ Builds the plan (ordered steps + unsigned txs) without sending. **Returns:** `DepositPlan` ```ts -const plan = await sdk.deposits.prepare({ token: ETH_L1, amount: parseEther("0.05"), to }); +const plan = await sdk.deposits.prepare({ token: ETH_L1, amount: parseEther('0.05'), to }); /* { route, @@ -132,7 +141,8 @@ const handle = await sdk.deposits.create({ token, amount, to }); ``` -If any step reverts, create throws a typed error. Prefer tryCreate to avoid exceptions. + If any step reverts, create throws a typed error. Prefer tryCreate to + avoid exceptions. ### `tryCreate(p) → Promise<{ ok: true; value: DepositHandle } | { ok: false; error }>` @@ -145,12 +155,12 @@ Resolve current phase for a deposit. Accepts the `DepositHandle` from `create` * **Phases** -* `UNKNOWN` — no L1 hash provided -* `L1_PENDING` — L1 receipt not yet found -* `L1_INCLUDED` — included on L1; L2 hash not derivable yet -* `L2_PENDING` — L2 hash known; waiting for L2 receipt -* `L2_EXECUTED` — L2 receipt found with `status === 1` -* `L2_FAILED` — L2 receipt found with `status !== 1` +- `UNKNOWN` — no L1 hash provided +- `L1_PENDING` — L1 receipt not yet found +- `L1_INCLUDED` — included on L1; L2 hash not derivable yet +- `L2_PENDING` — L2 hash known; waiting for L2 receipt +- `L2_EXECUTED` — L2 receipt found with `status === 1` +- `L2_FAILED` — L2 receipt found with `status !== 1` ```ts const s = await sdk.deposits.status(handle); @@ -161,12 +171,12 @@ const s = await sdk.deposits.status(handle); Block until the chosen checkpoint. -* `{ for: 'l1' }` → L1 receipt (or `null` if no L1 hash available) -* `{ for: 'l2' }` → L2 receipt after canonical execution (or `null` if no L1 hash) +- `{ for: 'l1' }` → L1 receipt (or `null` if no L1 hash available) +- `{ for: 'l2' }` → L2 receipt after canonical execution (or `null` if no L1 hash) ```ts -const l1Receipt = await sdk.deposits.wait(handle, { for: "l1" }); -const l2Receipt = await sdk.deposits.wait(handle, { for: "l2" }); +const l1Receipt = await sdk.deposits.wait(handle, { for: 'l1' }); +const l2Receipt = await sdk.deposits.wait(handle, { for: 'l2' }); ``` ### `tryWait(handleOrHash, opts) → Result` @@ -180,36 +190,36 @@ Result-style `wait`. ```ts const handle = await sdk.deposits.create({ token: ETH_ADDRESS, - amount: parseEther("0.1"), + amount: parseEther('0.1'), to: await signer.getAddress(), }); -await sdk.deposits.wait(handle, { for: "l2" }); +await sdk.deposits.wait(handle, { for: 'l2' }); ``` ### ERC-20 deposit (with automatic approvals) ```ts const handle = await sdk.deposits.create({ - token: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // example: USDC - amount: 1_000_000n, // 1.0 USDC (6 dp) + token: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // example: USDC + amount: 1_000_000n, // 1.0 USDC (6 dp) to: await signer.getAddress(), }); -const l1Receipt = await sdk.deposits.wait(handle, { for: "l1" }); +const l1Receipt = await sdk.deposits.wait(handle, { for: 'l1' }); ``` ## Types (overview) ```ts type DepositParams = { - token: Address; // 0x…00 for ETH - amount: bigint; // wei - to: Address; // L2 recipient + token: Address; // 0x…00 for ETH + amount: bigint; // wei + to: Address; // L2 recipient }; type DepositQuote = { - route: "eth-base" | "eth-nonbase" | "erc20-base" | "erc20-nonbase"; + route: 'eth-base' | 'eth-nonbase' | 'erc20-base' | 'erc20-nonbase'; approvalsNeeded: Array<{ token: Address; spender: Address; amount: bigint }>; baseCost?: bigint; mintValue?: bigint; @@ -218,33 +228,34 @@ type DepositQuote = { }; type DepositPlan = { - route: DepositQuote["route"]; + route: DepositQuote['route']; summary: DepositQuote; steps: Array<{ key: string; kind: string; tx: TTx }>; }; type DepositHandle = { - kind: "deposit"; + kind: 'deposit'; l1TxHash: Hex; stepHashes: Record; plan: DepositPlan; }; type DepositStatus = - | { phase: "UNKNOWN"; l1TxHash: Hex } - | { phase: "L1_PENDING"; l1TxHash: Hex } - | { phase: "L1_INCLUDED"; l1TxHash: Hex } - | { phase: "L2_PENDING"; l1TxHash: Hex; l2TxHash: Hex } - | { phase: "L2_EXECUTED"; l1TxHash: Hex; l2TxHash: Hex } - | { phase: "L2_FAILED"; l1TxHash: Hex; l2TxHash: Hex }; + | { phase: 'UNKNOWN'; l1TxHash: Hex } + | { phase: 'L1_PENDING'; l1TxHash: Hex } + | { phase: 'L1_INCLUDED'; l1TxHash: Hex } + | { phase: 'L2_PENDING'; l1TxHash: Hex; l2TxHash: Hex } + | { phase: 'L2_EXECUTED'; l1TxHash: Hex; l2TxHash: Hex } + | { phase: 'L2_FAILED'; l1TxHash: Hex; l2TxHash: Hex }; ``` -Prefer the try* variants if you want to avoid exceptions and work with result objects. + Prefer the try* variants if you want to avoid exceptions and work with result + objects. ## Notes & pitfalls -* **ETH sentinel:** use the canonical `0x…00` address when passing ETH as `token`. -* **Receipts timing:** `wait({ for: 'l2' })` resolves on canonical L2 execution; it can take longer than L1 inclusion. -* **Gas hints:** `suggestedL2GasLimit` and `gasPerPubdata` are hints; advanced users may override via low-level calls from the plan. +- **ETH sentinel:** use the canonical `0x…00` address when passing ETH as `token`. +- **Receipts timing:** `wait({ for: 'l2' })` resolves on canonical L2 execution; it can take longer than L1 inclusion. +- **Gas hints:** `suggestedL2GasLimit` and `gasPerPubdata` are hints; advanced users may override via low-level calls from the plan. diff --git a/docs/api-reference/ethers/sdk.mdx b/docs/api-reference/ethers/sdk.mdx index a527259..5202cb2 100644 --- a/docs/api-reference/ethers/sdk.mdx +++ b/docs/api-reference/ethers/sdk.mdx @@ -13,17 +13,14 @@ group: SDK Reference / Ethers ## Import ```ts -import { - createEthersClient, - createEthersSdk, -} from "@dutterbutter/zksync-sdk/ethers"; +import { createEthersClient, createEthersSdk } from '@dutterbutter/zksync-sdk/ethers'; ``` ## Quick start ```ts -import { JsonRpcProvider, Wallet, parseEther } from "ethers"; -import { createEthersClient, createEthersSdk } from "@dutterbutter/zksync-sdk/ethers"; +import { JsonRpcProvider, Wallet, parseEther } from 'ethers'; +import { createEthersClient, createEthersSdk } from '@dutterbutter/zksync-sdk/ethers'; const l1 = new JsonRpcProvider(process.env.ETH_RPC!); const l2 = new JsonRpcProvider(process.env.ZKSYNC_RPC!); @@ -34,12 +31,12 @@ const sdk = createEthersSdk(client); // Example: deposit 0.05 ETH L1 → L2, wait for L2 execution const handle = await sdk.deposits.create({ - token: ETH_ADDRESS, // 0x…00 sentinel for ETH supported - amount: parseEther("0.05"), + token: ETH_ADDRESS, // 0x…00 sentinel for ETH supported + amount: parseEther('0.05'), to: await signer.getAddress(), }); -await sdk.deposits.wait(handle, { for: "l2" }); +await sdk.deposits.wait(handle, { for: 'l2' }); // Example: resolve core contracts const { l1NativeTokenVault } = await sdk.helpers.contracts(); @@ -48,13 +45,14 @@ const { l1NativeTokenVault } = await sdk.helpers.contracts(); ## `createEthersSdk(client) → EthersSdk` - Instance returned by `createEthersClient({ l1, l2, signer })`. + Instance returned by `createEthersClient({(l1, l2, signer)})`. **Returns:** `EthersSdk` -The SDK composes the client with resources: deposits, withdrawals, and convenience helpers. + The SDK composes the client with resources: deposits, withdrawals, and + convenience helpers. ## EthersSdk interface @@ -109,9 +107,9 @@ const base = await sdk.helpers.baseToken(); // infers from client.l2 L2 token address for an L1 token. -* Handles ETH special case (L2 ETH placeholder). -* If token is the chain’s base token, returns the L2 base-token system address. -* Otherwise queries `IL2NativeTokenVault.l2TokenAddress`. +- Handles ETH special case (L2 ETH placeholder). +- If token is the chain’s base token, returns the L2 base-token system address. +- Otherwise queries `IL2NativeTokenVault.l2TokenAddress`. ```ts const l2Crown = await sdk.helpers.l2TokenAddress(CROWN_ERC20_ADDRESS); @@ -135,6 +133,6 @@ const id = await sdk.helpers.assetId(CROWN_ERC20_ADDRESS); ## Notes & pitfalls -* **Client first:** You must construct the **client** with `{ l1, l2, signer }` before creating the SDK. -* **Chain-derived behavior:** helpers pull from on-chain sources; results depend on the connected networks. -* **Error model:** resource methods throw typed errors; prefer try* variants on resources for result objects. +- **Client first:** You must construct the **client** with `{ l1, l2, signer }` before creating the SDK. +- **Chain-derived behavior:** helpers pull from on-chain sources; results depend on the connected networks. +- **Error model:** resource methods throw typed errors; prefer try\* variants on resources for result objects. diff --git a/docs/api-reference/ethers/withdrawals.mdx b/docs/api-reference/ethers/withdrawals.mdx index 2364333..80416a4 100644 --- a/docs/api-reference/ethers/withdrawals.mdx +++ b/docs/api-reference/ethers/withdrawals.mdx @@ -14,8 +14,8 @@ group: SDK Reference / Ethers ## Import ```ts -import { JsonRpcProvider, Wallet, parseEther } from "ethers"; -import { createEthersClient, createEthersSdk } from "@dutterbutter/zksync-sdk/ethers"; +import { JsonRpcProvider, Wallet, parseEther } from 'ethers'; +import { createEthersClient, createEthersSdk } from '@dutterbutter/zksync-sdk/ethers'; const l1 = new JsonRpcProvider(process.env.ETH_RPC!); const l2 = new JsonRpcProvider(process.env.ZKSYNC_RPC!); @@ -32,16 +32,16 @@ Withdraw **0.1 ETH** from L2 → L1 and finalize on L1: ```ts const handle = await sdk.withdrawals.create({ - token: ETH_ADDRESS, // ETH sentinel supported - amount: parseEther("0.1"), - to: await signer.getAddress(), // L1 recipient + token: ETH_ADDRESS, // ETH sentinel supported + amount: parseEther('0.1'), + to: await signer.getAddress(), // L1 recipient }); // 1) L2 inclusion (adds l2ToL1Logs if available) -await sdk.withdrawals.wait(handle, { for: "l2" }); +await sdk.withdrawals.wait(handle, { for: 'l2' }); // 2) Wait until finalizable (no side effects) -await sdk.withdrawals.wait(handle, { for: "ready", pollMs: 6000 }); +await sdk.withdrawals.wait(handle, { for: 'ready', pollMs: 6000 }); // 3) Finalize on L1 (no-op if already finalized) const { status, receipt: l1Receipt } = await sdk.withdrawals.finalize(handle.l2TxHash); @@ -53,9 +53,9 @@ Withdrawals are two-phase: inclusion on **L2**, then **finalization on L1**. You ## Route selection (automatic) -* `eth-base` — Base token is **ETH** on L2 -* `eth-nonbase` — Base token is **not ETH** on L2 -* `erc20-nonbase` — Withdrawing an ERC-20 that is **not** the base token +- `eth-base` — Base token is **ETH** on L2 +- `eth-nonbase` — Base token is **not ETH** on L2 +- `erc20-nonbase` — Withdrawing an ERC-20 that is **not** the base token You **do not** pass a route; it’s derived from network metadata + `token`. @@ -65,7 +65,15 @@ You **do not** pass a route; it’s derived from network metadata + `token`. Estimate the operation (route, approvals, gas hints). Does **not** send txs. -L2 token (ETH handled by the SDK; ETH sentinel supported). Amount in wei. L1 recipient. + + L2 token (ETH handled by the SDK; ETH sentinel supported). + + + Amount in wei. + + + L1 recipient. + **Returns:** `WithdrawQuote` @@ -127,7 +135,8 @@ const handle = await sdk.withdrawals.create({ token, amount, to }); ``` -If any L2 step reverts, create throws a typed error. Prefer tryCreate for a result object. + If any L2 step reverts, create throws a typed error. Prefer tryCreate{' '} + for a result object. ### `tryCreate(p) → Promise<{ ok: true; value: WithdrawHandle } | { ok: false; error }>` @@ -140,11 +149,11 @@ Report current phase for a withdrawal. Accepts the `WithdrawHandle` from `create **Phases** -* `UNKNOWN` — no L2 hash provided -* `L2_PENDING` — L2 receipt missing -* `PENDING` — included on L2 but not yet finalizable -* `READY_TO_FINALIZE` — can be finalized on L1 now -* `FINALIZED` — already finalized on L1 +- `UNKNOWN` — no L2 hash provided +- `L2_PENDING` — L2 receipt missing +- `PENDING` — included on L2 but not yet finalizable +- `READY_TO_FINALIZE` — can be finalized on L1 now +- `FINALIZED` — already finalized on L1 ```ts const s = await sdk.withdrawals.status(handle); @@ -155,18 +164,18 @@ const s = await sdk.withdrawals.status(handle); Block until a target is reached. -* `{ for: 'l2' }` → resolves **L2 receipt** (`TransactionReceiptZKsyncOS`) or `null` -* `{ for: 'ready' }` → resolves `null` when finalizable -* `{ for: 'finalized' }` → resolves **L1 receipt** (if found) or `null` +- `{ for: 'l2' }` → resolves **L2 receipt** (`TransactionReceiptZKsyncOS`) or `null` +- `{ for: 'ready' }` → resolves `null` when finalizable +- `{ for: 'finalized' }` → resolves **L1 receipt** (if found) or `null` ```ts -const l2Rcpt = await sdk.withdrawals.wait(handle, { for: "l2" }); -await sdk.withdrawals.wait(handle, { for: "ready", pollMs: 6000, timeoutMs: 15 * 60_000 }); -const l1Rcpt = await sdk.withdrawals.wait(handle, { for: "finalized", pollMs: 7000 }); +const l2Rcpt = await sdk.withdrawals.wait(handle, { for: 'l2' }); +await sdk.withdrawals.wait(handle, { for: 'ready', pollMs: 6000, timeoutMs: 15 * 60_000 }); +const l1Rcpt = await sdk.withdrawals.wait(handle, { for: 'finalized', pollMs: 7000 }); ``` -Default polling is 5500 ms (min 1000 ms). Use timeoutMs for long windows. + Default polling is 5500 ms (min 1000 ms). Use timeoutMs for long windows. ### `tryWait(handleOrHash, opts) → Result` @@ -179,8 +188,8 @@ Sends the **L1 finalize** transaction **if** ready. If already finalized, return ```ts const { status, receipt } = await sdk.withdrawals.finalize(handle.l2TxHash); -if (status.phase === "FINALIZED") { - console.log("L1 tx:", receipt?.transactionHash); +if (status.phase === 'FINALIZED') { + console.log('L1 tx:', receipt?.transactionHash); } ``` @@ -200,13 +209,13 @@ Result-style `finalize`. const handle = await sdk.withdrawals.create({ token, amount, to }); // L2 inclusion -await sdk.withdrawals.wait(handle, { for: "l2" }); +await sdk.withdrawals.wait(handle, { for: 'l2' }); // Option A: finalize immediately (will throw if not ready) await sdk.withdrawals.finalize(handle.l2TxHash); // Option B: wait for readiness, then finalize -await sdk.withdrawals.wait(handle, { for: "ready" }); +await sdk.withdrawals.wait(handle, { for: 'ready' }); await sdk.withdrawals.finalize(handle.l2TxHash); ``` @@ -214,44 +223,43 @@ await sdk.withdrawals.finalize(handle.l2TxHash); ```ts type WithdrawParams = { - token: Address; // L2 token (ETH sentinel supported) - amount: bigint; // wei - to: Address; // L1 recipient + token: Address; // L2 token (ETH sentinel supported) + amount: bigint; // wei + to: Address; // L1 recipient }; type WithdrawQuote = { - route: "eth-base" | "eth-nonbase" | "erc20-nonbase"; + route: 'eth-base' | 'eth-nonbase' | 'erc20-nonbase'; approvalsNeeded: Array<{ token: Address; spender: Address; amount: bigint }>; suggestedL2GasLimit?: bigint; }; type WithdrawPlan = { - route: WithdrawQuote["route"]; + route: WithdrawQuote['route']; summary: WithdrawQuote; steps: Array<{ key: string; kind: string; tx: TTx }>; }; type WithdrawHandle = { - kind: "withdrawal"; + kind: 'withdrawal'; l2TxHash: Hex; stepHashes: Record; plan: WithdrawPlan; }; type WithdrawalStatus = - | { phase: "UNKNOWN"; l2TxHash: Hex } - | { phase: "L2_PENDING"; l2TxHash: Hex } - | { phase: "PENDING"; l2TxHash: Hex; key?: unknown } - | { phase: "READY_TO_FINALIZE"; l2TxHash: Hex; key: unknown } - | { phase: "FINALIZED"; l2TxHash: Hex; key: unknown }; + | { phase: 'UNKNOWN'; l2TxHash: Hex } + | { phase: 'L2_PENDING'; l2TxHash: Hex } + | { phase: 'PENDING'; l2TxHash: Hex; key?: unknown } + | { phase: 'READY_TO_FINALIZE'; l2TxHash: Hex; key: unknown } + | { phase: 'FINALIZED'; l2TxHash: Hex; key: unknown }; // L2 receipt augmentation returned by wait({ for: 'l2' }) -type TransactionReceiptZKsyncOS = - TransactionReceipt & { l2ToL1Logs?: Array }; +type TransactionReceiptZKsyncOS = TransactionReceipt & { l2ToL1Logs?: Array }; ``` ## Notes & pitfalls -* **Two chains, two receipts:** inclusion on **L2** and finalization on **L1** are independent events. -* **Polling strategy:** for production UIs, prefer `wait({ for: 'ready' })` then finalize; it avoids premature finalize calls. -* **Approvals:** if withdrawing ERC-20 requires approvals, `create` will include those steps automatically. +- **Two chains, two receipts:** inclusion on **L2** and finalization on **L1** are independent events. +- **Polling strategy:** for production UIs, prefer `wait({ for: 'ready' })` then finalize; it avoids premature finalize calls. +- **Approvals:** if withdrawing ERC-20 requires approvals, `create` will include those steps automatically. diff --git a/docs/api-reference/introduction.mdx b/docs/api-reference/introduction.mdx index 39b62d1..55495ab 100644 --- a/docs/api-reference/introduction.mdx +++ b/docs/api-reference/introduction.mdx @@ -8,10 +8,10 @@ group: API Reference / Overview The **ZKsyncOS SDK** provides lightweight adapters for **ethers** and **viem** to build L1 ↔ L2 flows—**deposits** and **withdrawals**—with a small, focused API. You’ll work with: -* Adapter-level **Clients** (providers/wallets, resolved addresses, convenience contracts) -* High-level **SDKs** (resources for deposits & withdrawals + helpers) -* ZKsync-specific **RPC** helpers (`client.zks.*`) -* A consistent, typed **Error model** (`ZKsyncError`, `try*` results) +- Adapter-level **Clients** (providers/wallets, resolved addresses, convenience contracts) +- High-level **SDKs** (resources for deposits & withdrawals + helpers) +- ZKsync-specific **RPC** helpers (`client.zks.*`) +- A consistent, typed **Error model** (`ZKsyncError`, `try*` results) ## Quick start @@ -47,7 +47,13 @@ const bridgehub = await client.zks.getBridgehubAddress(); ```ts -import { createPublicClient, http, createWalletClient, privateKeyToAccount, parseEther } from 'viem'; +import { + createPublicClient, + http, + createWalletClient, + privateKeyToAccount, + parseEther, +} from 'viem'; import { createViemClient, createViemSdk, ETH_ADDRESS } from '@dutterbutter/zksync-sdk/viem'; const account = privateKeyToAccount(process.env.PRIVATE_KEY! as `0x${string}`); @@ -64,7 +70,7 @@ const handle = await sdk.withdrawals.create({ to: account.address, // L1 recipient }); -await sdk.withdrawals.wait(handle, { for: 'l2' }); // inclusion on L2 +await sdk.withdrawals.wait(handle, { for: 'l2' }); // inclusion on L2 const { status } = await sdk.withdrawals.finalize(handle.l2TxHash); // finalize on L1 const bridgehub = await client.zks.getBridgehubAddress(); @@ -89,18 +95,18 @@ const bridgehub = await client.zks.getBridgehubAddress(); L2 → L1 flow with quote, prepare, create, status, wait, and finalize. - - PublicClient/WalletClient integration, resolved addresses, contracts, ZK RPC access. - - - Same high-level surface as ethers, typed to viem contracts. - - - L1 → L2 flow with quote, prepare, create, status, and wait. - - - L2 → L1 flow with quote, prepare, create, status, wait, and finalize. - + + PublicClient/WalletClient integration, resolved addresses, contracts, ZK RPC access. + + + Same high-level surface as ethers, typed to viem contracts. + + + L1 → L2 flow with quote, prepare, create, status, and wait. + + + L2 → L1 flow with quote, prepare, create, status, wait, and finalize. + ZKsync-specific RPC: getBridgehubAddress, getL2ToL1LogProof, enhanced receipts. @@ -112,10 +118,10 @@ const bridgehub = await client.zks.getBridgehubAddress(); ## Notes & conventions -- **Standard eth_* RPC** should be performed through your chosen base library (**ethers** / **viem**). -The SDK only adds ZKsync-specific RPC via client.zks.* (e.g., getBridgehubAddress, getL2ToL1LogProof, enhanced receipts). +- **Standard eth\_\* RPC** should be performed through your chosen base library (**ethers** / **viem**). + The SDK only adds ZKsync-specific RPC via client.zks.\* (e.g., getBridgehubAddress, getL2ToL1LogProof, enhanced receipts). -- Every resource method has a try* variant (e.g., tryCreate) that returns a result object instead of throwing. -When errors occur, the SDK throws ZKsyncError with a stable envelope (see Error model). +- Every resource method has a try\* variant (e.g., tryCreate) that returns a result object instead of throwing. + When errors occur, the SDK throws ZKsyncError with a stable envelope (see Error model). - Address resolution comes from on-chain lookups and well-known constants. You can override addresses in the client constructor for forks/tests. diff --git a/docs/api-reference/viem/client.mdx b/docs/api-reference/viem/client.mdx index ef6d220..8b809ba 100644 --- a/docs/api-reference/viem/client.mdx +++ b/docs/api-reference/viem/client.mdx @@ -13,7 +13,7 @@ group: SDK Reference / Viem ## Import ```ts -import { createViemClient } from "@dutterbutter/zksync-sdk/viem"; +import { createViemClient } from '@dutterbutter/zksync-sdk/viem'; ``` ## Quick start @@ -47,18 +47,53 @@ const { bridgehub, l1AssetRouter } = await client.contracts(); ``` -l1Wallet.account is required. If you omit l2Wallet, use client.getL2Wallet(); it lazily reuses the L1 account over the L2 transport. + l1Wallet.account is required. If you omit l2Wallet, use{' '} + client.getL2Wallet(); it lazily reuses the L1 account over the L2 transport. ## `createViemClient(args) → ViemClient` -L1 client for reads and chain metadata. L2 (ZKsync) client for reads and ZK RPC. L1 wallet (must include account) used for L1 sends. Optional L2 wallet for L2 sends; otherwise derived via getL2Wallet(). Optional contract-address overrides (forks/tests). + + L1 client for reads and chain metadata. + + + L2 (ZKsync) client for reads and ZK RPC. + + + L1 wallet (must include account) used for L1 sends. + + + Optional L2 wallet for L2 sends; otherwise derived via getL2Wallet(). + + + Optional contract-address overrides (forks/tests). + **Returns:** `ViemClient` ## ViemClient interface -Adapter discriminator. Public L1 client. Public L2 (ZKsync) client. Wallet bound to L1 (carries default account). Optional pre-supplied L2 wallet. Default account (from l1Wallet). ZKsync-specific RPC bound to l2. + + Adapter discriminator. + + + Public L1 client. + + + Public L2 (ZKsync) client. + + + Wallet bound to L1 (carries default account). + + + Optional pre-supplied L2 wallet. + + + Default account (from l1Wallet). + + + ZKsync-specific RPC bound to l2. + ## Methods @@ -128,7 +163,7 @@ type ResolvedAddresses = { ## Notes & pitfalls -* **Wallet placement:** Deposits sign on **L1**; withdrawals sign on **L2**; finalization signs on **L1** (via SDK). -* **Caching:** `ensureAddresses()` and `contracts()` are cached. Use `refresh()` after network/override changes. -* **Overrides:** For forks or custom deployments, pass `overrides` at construction; they’ll be merged with on-chain lookups. -* **Error surface:** Methods may throw typed errors; use the SDK’s `try*` variants (on resources) if you prefer result objects. +- **Wallet placement:** Deposits sign on **L1**; withdrawals sign on **L2**; finalization signs on **L1** (via SDK). +- **Caching:** `ensureAddresses()` and `contracts()` are cached. Use `refresh()` after network/override changes. +- **Overrides:** For forks or custom deployments, pass `overrides` at construction; they’ll be merged with on-chain lookups. +- **Error surface:** Methods may throw typed errors; use the SDK’s `try*` variants (on resources) if you prefer result objects. diff --git a/docs/api-reference/viem/deposits.mdx b/docs/api-reference/viem/deposits.mdx index 3e0a2b0..65b0897 100644 --- a/docs/api-reference/viem/deposits.mdx +++ b/docs/api-reference/viem/deposits.mdx @@ -47,24 +47,24 @@ Deposit **0.1 ETH** from L1 → L2 and wait for **L2 execution**: ```ts const handle = await sdk.deposits.create({ - token: ETH_ADDRESS, // 0x…00 for ETH - amount: parseEther("0.1"), + token: ETH_ADDRESS, // 0x…00 for ETH + amount: parseEther('0.1'), to: await signer.getAddress(), }); -const l2Receipt = await sdk.deposits.wait(handle, { for: "l2" }); // null only if no L1 hash +const l2Receipt = await sdk.deposits.wait(handle, { for: 'l2' }); // null only if no L1 hash ``` -For UX that never throws, use the try* variants and branch on ok. + For UX that never throws, use the try* variants and branch on ok. ## Route selection (automatic) -* `eth-base` — ETH when L2 base token **is ETH** -* `eth-nonbase` — ETH when L2 base token **≠ ETH** -* `erc20-base` — ERC-20 that **is** the L2 base token -* `erc20-nonbase` — ERC-20 that **is not** the L2 base token +- `eth-base` — ETH when L2 base token **is ETH** +- `eth-nonbase` — ETH when L2 base token **≠ ETH** +- `erc20-base` — ERC-20 that **is** the L2 base token +- `erc20-nonbase` — ERC-20 that **is not** the L2 base token You **do not** pass a route; it’s derived from network metadata + `token`. @@ -74,14 +74,22 @@ You **do not** pass a route; it’s derived from network metadata + `token`. Estimate the operation (route, approvals, gas hints). Does **not** send txs. -L1 token (use 0x…00 for ETH). Amount in wei. L2 recipient. + + L1 token (use 0x…00 for ETH). + + + Amount in wei. + + + L2 recipient. + **Returns:** `DepositQuote` ```ts const q = await sdk.deposits.quote({ token: ETH_L1, - amount: parseEther("0.25"), + amount: parseEther('0.25'), to: await signer.getAddress(), }); /* @@ -97,7 +105,8 @@ const q = await sdk.deposits.quote({ ``` -If approvalsNeeded is non-empty (ERC-20), create will include those steps automatically. + If approvalsNeeded is non-empty (ERC-20), create will include those + steps automatically. ### `tryQuote(p) → Promise<{ ok: true; value: DepositQuote } | { ok: false; error }>` @@ -111,7 +120,7 @@ Builds the plan (ordered steps + unsigned txs) without sending. **Returns:** `DepositPlan` ```ts -const plan = await sdk.deposits.prepare({ token: ETH_L1, amount: parseEther("0.05"), to }); +const plan = await sdk.deposits.prepare({ token: ETH_L1, amount: parseEther('0.05'), to }); /* { route, @@ -147,7 +156,8 @@ const handle = await sdk.deposits.create({ token, amount, to }); ``` -If any step reverts, create throws a typed error. Prefer tryCreate to avoid exceptions. + If any step reverts, create throws a typed error. Prefer tryCreate to + avoid exceptions. ### `tryCreate(p) → Promise<{ ok: true; value: DepositHandle } | { ok: false; error }>` @@ -160,12 +170,12 @@ Resolve current phase for a deposit. Accepts the `DepositHandle` from `create` * **Phases** -* `UNKNOWN` — no L1 hash provided -* `L1_PENDING` — L1 receipt not yet found -* `L1_INCLUDED` — included on L1; L2 hash not derivable yet -* `L2_PENDING` — L2 hash known; waiting for L2 receipt -* `L2_EXECUTED` — L2 receipt found with `status === 1` -* `L2_FAILED` — L2 receipt found with `status !== 1` +- `UNKNOWN` — no L1 hash provided +- `L1_PENDING` — L1 receipt not yet found +- `L1_INCLUDED` — included on L1; L2 hash not derivable yet +- `L2_PENDING` — L2 hash known; waiting for L2 receipt +- `L2_EXECUTED` — L2 receipt found with `status === 1` +- `L2_FAILED` — L2 receipt found with `status !== 1` ```ts const s = await sdk.deposits.status(handle); @@ -176,12 +186,12 @@ const s = await sdk.deposits.status(handle); Block until the chosen checkpoint. -* `{ for: 'l1' }` → L1 receipt (or `null` if no L1 hash available) -* `{ for: 'l2' }` → L2 receipt after canonical execution (or `null` if no L1 hash) +- `{ for: 'l1' }` → L1 receipt (or `null` if no L1 hash available) +- `{ for: 'l2' }` → L2 receipt after canonical execution (or `null` if no L1 hash) ```ts -const l1Receipt = await sdk.deposits.wait(handle, { for: "l1" }); -const l2Receipt = await sdk.deposits.wait(handle, { for: "l2" }); +const l1Receipt = await sdk.deposits.wait(handle, { for: 'l1' }); +const l2Receipt = await sdk.deposits.wait(handle, { for: 'l2' }); ``` ### `tryWait(handleOrHash, opts) → Result` @@ -195,36 +205,36 @@ Result-style `wait`. ```ts const handle = await sdk.deposits.create({ token: ETH_ADDRESS, - amount: parseEther("0.1"), + amount: parseEther('0.1'), to: await signer.getAddress(), }); -await sdk.deposits.wait(handle, { for: "l2" }); +await sdk.deposits.wait(handle, { for: 'l2' }); ``` ### ERC-20 deposit (with automatic approvals) ```ts const handle = await sdk.deposits.create({ - token: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // example: USDC - amount: 1_000_000n, // 1.0 USDC (6 dp) + token: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // example: USDC + amount: 1_000_000n, // 1.0 USDC (6 dp) to: await signer.getAddress(), }); -const l1Receipt = await sdk.deposits.wait(handle, { for: "l1" }); +const l1Receipt = await sdk.deposits.wait(handle, { for: 'l1' }); ``` ## Types (overview) ```ts type DepositParams = { - token: Address; // 0x…00 for ETH - amount: bigint; // wei - to: Address; // L2 recipient + token: Address; // 0x…00 for ETH + amount: bigint; // wei + to: Address; // L2 recipient }; type DepositQuote = { - route: "eth-base" | "eth-nonbase" | "erc20-base" | "erc20-nonbase"; + route: 'eth-base' | 'eth-nonbase' | 'erc20-base' | 'erc20-nonbase'; approvalsNeeded: Array<{ token: Address; spender: Address; amount: bigint }>; baseCost?: bigint; mintValue?: bigint; @@ -233,33 +243,34 @@ type DepositQuote = { }; type DepositPlan = { - route: DepositQuote["route"]; + route: DepositQuote['route']; summary: DepositQuote; steps: Array<{ key: string; kind: string; tx: TTx }>; }; type DepositHandle = { - kind: "deposit"; + kind: 'deposit'; l1TxHash: Hex; stepHashes: Record; plan: DepositPlan; }; type DepositStatus = - | { phase: "UNKNOWN"; l1TxHash: Hex } - | { phase: "L1_PENDING"; l1TxHash: Hex } - | { phase: "L1_INCLUDED"; l1TxHash: Hex } - | { phase: "L2_PENDING"; l1TxHash: Hex; l2TxHash: Hex } - | { phase: "L2_EXECUTED"; l1TxHash: Hex; l2TxHash: Hex } - | { phase: "L2_FAILED"; l1TxHash: Hex; l2TxHash: Hex }; + | { phase: 'UNKNOWN'; l1TxHash: Hex } + | { phase: 'L1_PENDING'; l1TxHash: Hex } + | { phase: 'L1_INCLUDED'; l1TxHash: Hex } + | { phase: 'L2_PENDING'; l1TxHash: Hex; l2TxHash: Hex } + | { phase: 'L2_EXECUTED'; l1TxHash: Hex; l2TxHash: Hex } + | { phase: 'L2_FAILED'; l1TxHash: Hex; l2TxHash: Hex }; ``` -Prefer the try* variants if you want to avoid exceptions and work with result objects. + Prefer the try* variants if you want to avoid exceptions and work with result + objects. ## Notes & pitfalls -* **ETH sentinel:** use the canonical `0x…00` address when passing ETH as `token`. -* **Receipts timing:** `wait({ for: 'l2' })` resolves on canonical L2 execution; it can take longer than L1 inclusion. -* **Gas hints:** `suggestedL2GasLimit` and `gasPerPubdata` are hints; advanced users may override via low-level calls from the plan. +- **ETH sentinel:** use the canonical `0x…00` address when passing ETH as `token`. +- **Receipts timing:** `wait({ for: 'l2' })` resolves on canonical L2 execution; it can take longer than L1 inclusion. +- **Gas hints:** `suggestedL2GasLimit` and `gasPerPubdata` are hints; advanced users may override via low-level calls from the plan. diff --git a/docs/api-reference/viem/sdk.mdx b/docs/api-reference/viem/sdk.mdx index a167792..c4786a9 100644 --- a/docs/api-reference/viem/sdk.mdx +++ b/docs/api-reference/viem/sdk.mdx @@ -17,10 +17,7 @@ group: SDK Reference / Viem ## Import ```ts -import { - createViemClient, - createViemSdk, -} from "@dutterbutter/zksync-sdk/viem"; +import { createViemClient, createViemSdk } from '@dutterbutter/zksync-sdk/viem'; ``` ## Quick start @@ -61,7 +58,8 @@ const l2Crown = await sdk.helpers.l2TokenAddress(CROWN_ERC20_ADDRESS); ``` -You can construct the client with only the wallets you need for a given flow (e.g., just l2Wallet to create withdrawals; add l1Wallet when you plan to finalize). + You can construct the client with only the wallets you need for a given flow (e.g., just{' '} + l2Wallet to create withdrawals; add l1Wallet when you plan to finalize). ## `createViemSdk(client) → ViemSdk` @@ -73,7 +71,8 @@ Instance returned by `createViemClient({ l1, l2, l1Wallet?, l2Wallet? })`< **Returns:** `ViemSdk` -The SDK composes the client with resources: deposits, withdrawals, and convenience helpers. + The SDK composes the client with resources: deposits, withdrawals, and + convenience helpers. ## ViemSdk interface @@ -129,9 +128,9 @@ const base = await sdk.helpers.baseToken(); // infers from the L2 client L2 token address for an L1 token. -* Handles ETH special case (L2 ETH placeholder). -* If the token is the chain’s base token, returns the L2 base-token system address. -* Otherwise queries `IL2NativeTokenVault.l2TokenAddress`. +- Handles ETH special case (L2 ETH placeholder). +- If the token is the chain’s base token, returns the L2 base-token system address. +- Otherwise queries `IL2NativeTokenVault.l2TokenAddress`. ```ts const l2Crown = await sdk.helpers.l2TokenAddress(CROWN_ERC20_ADDRESS); @@ -155,6 +154,6 @@ const id = await sdk.helpers.assetId(CROWN_ERC20_ADDRESS); ## Notes & pitfalls -* **Wallet placement matters:** deposits sign on **L1**; withdrawals sign on **L2**; finalization signs on **L1**. -* **Chain-derived behavior:** helpers read from on-chain sources; results depend on connected networks. -* **Error model:** resource methods throw typed errors; prefer try* variants on resources for result objects. +- **Wallet placement matters:** deposits sign on **L1**; withdrawals sign on **L2**; finalization signs on **L1**. +- **Chain-derived behavior:** helpers read from on-chain sources; results depend on connected networks. +- **Error model:** resource methods throw typed errors; prefer try\* variants on resources for result objects. diff --git a/docs/api-reference/viem/withdrawals.mdx b/docs/api-reference/viem/withdrawals.mdx index 51823ff..74cad4b 100644 --- a/docs/api-reference/viem/withdrawals.mdx +++ b/docs/api-reference/viem/withdrawals.mdx @@ -47,16 +47,16 @@ Withdraw **0.1 ETH** from L2 → L1 and finalize on L1: ```ts const handle = await sdk.withdrawals.create({ - token: ETH_ADDRESS, // ETH sentinel supported - amount: parseEther("0.1"), - to: await signer.getAddress(), // L1 recipient + token: ETH_ADDRESS, // ETH sentinel supported + amount: parseEther('0.1'), + to: await signer.getAddress(), // L1 recipient }); // 1) L2 inclusion (adds l2ToL1Logs if available) -await sdk.withdrawals.wait(handle, { for: "l2" }); +await sdk.withdrawals.wait(handle, { for: 'l2' }); // 2) Wait until finalizable (no side effects) -await sdk.withdrawals.wait(handle, { for: "ready", pollMs: 6000 }); +await sdk.withdrawals.wait(handle, { for: 'ready', pollMs: 6000 }); // 3) Finalize on L1 (no-op if already finalized) const { status, receipt: l1Receipt } = await sdk.withdrawals.finalize(handle.l2TxHash); @@ -68,9 +68,9 @@ Withdrawals are two-phase: inclusion on **L2**, then **finalization on L1**. You ## Route selection (automatic) -* `eth-base` — Base token is **ETH** on L2 -* `eth-nonbase` — Base token is **not ETH** on L2 -* `erc20-nonbase` — Withdrawing an ERC-20 that is **not** the base token +- `eth-base` — Base token is **ETH** on L2 +- `eth-nonbase` — Base token is **not ETH** on L2 +- `erc20-nonbase` — Withdrawing an ERC-20 that is **not** the base token You **do not** pass a route; it’s derived from network metadata + `token`. @@ -80,7 +80,15 @@ You **do not** pass a route; it’s derived from network metadata + `token`. Estimate the operation (route, approvals, gas hints). Does **not** send txs. -L2 token (ETH handled by the SDK; ETH sentinel supported). Amount in wei. L1 recipient. + + L2 token (ETH handled by the SDK; ETH sentinel supported). + + + Amount in wei. + + + L1 recipient. + **Returns:** `WithdrawQuote` @@ -142,7 +150,8 @@ const handle = await sdk.withdrawals.create({ token, amount, to }); ``` -If any L2 step reverts, create throws a typed error. Prefer tryCreate for a result object. + If any L2 step reverts, create throws a typed error. Prefer tryCreate{' '} + for a result object. ### `tryCreate(p) → Promise<{ ok: true; value: WithdrawHandle } | { ok: false; error }>` @@ -155,11 +164,11 @@ Report current phase for a withdrawal. Accepts the `WithdrawHandle` from `create **Phases** -* `UNKNOWN` — no L2 hash provided -* `L2_PENDING` — L2 receipt missing -* `PENDING` — included on L2 but not yet finalizable -* `READY_TO_FINALIZE` — can be finalized on L1 now -* `FINALIZED` — already finalized on L1 +- `UNKNOWN` — no L2 hash provided +- `L2_PENDING` — L2 receipt missing +- `PENDING` — included on L2 but not yet finalizable +- `READY_TO_FINALIZE` — can be finalized on L1 now +- `FINALIZED` — already finalized on L1 ```ts const s = await sdk.withdrawals.status(handle); @@ -170,18 +179,18 @@ const s = await sdk.withdrawals.status(handle); Block until a target is reached. -* `{ for: 'l2' }` → resolves **L2 receipt** (`TransactionReceiptZKsyncOS`) or `null` -* `{ for: 'ready' }` → resolves `null` when finalizable -* `{ for: 'finalized' }` → resolves **L1 receipt** (if found) or `null` +- `{ for: 'l2' }` → resolves **L2 receipt** (`TransactionReceiptZKsyncOS`) or `null` +- `{ for: 'ready' }` → resolves `null` when finalizable +- `{ for: 'finalized' }` → resolves **L1 receipt** (if found) or `null` ```ts -const l2Rcpt = await sdk.withdrawals.wait(handle, { for: "l2" }); -await sdk.withdrawals.wait(handle, { for: "ready", pollMs: 6000, timeoutMs: 15 * 60_000 }); -const l1Rcpt = await sdk.withdrawals.wait(handle, { for: "finalized", pollMs: 7000 }); +const l2Rcpt = await sdk.withdrawals.wait(handle, { for: 'l2' }); +await sdk.withdrawals.wait(handle, { for: 'ready', pollMs: 6000, timeoutMs: 15 * 60_000 }); +const l1Rcpt = await sdk.withdrawals.wait(handle, { for: 'finalized', pollMs: 7000 }); ``` -Default polling is 5500 ms (min 1000 ms). Use timeoutMs for long windows. + Default polling is 5500 ms (min 1000 ms). Use timeoutMs for long windows. ### `tryWait(handleOrHash, opts) → Result` @@ -194,8 +203,8 @@ Sends the **L1 finalize** transaction **if** ready. If already finalized, return ```ts const { status, receipt } = await sdk.withdrawals.finalize(handle.l2TxHash); -if (status.phase === "FINALIZED") { - console.log("L1 tx:", receipt?.transactionHash); +if (status.phase === 'FINALIZED') { + console.log('L1 tx:', receipt?.transactionHash); } ``` @@ -215,13 +224,13 @@ Result-style `finalize`. const handle = await sdk.withdrawals.create({ token, amount, to }); // L2 inclusion -await sdk.withdrawals.wait(handle, { for: "l2" }); +await sdk.withdrawals.wait(handle, { for: 'l2' }); // Option A: finalize immediately (will throw if not ready) await sdk.withdrawals.finalize(handle.l2TxHash); // Option B: wait for readiness, then finalize -await sdk.withdrawals.wait(handle, { for: "ready" }); +await sdk.withdrawals.wait(handle, { for: 'ready' }); await sdk.withdrawals.finalize(handle.l2TxHash); ``` @@ -229,44 +238,43 @@ await sdk.withdrawals.finalize(handle.l2TxHash); ```ts type WithdrawParams = { - token: Address; // L2 token (ETH sentinel supported) - amount: bigint; // wei - to: Address; // L1 recipient + token: Address; // L2 token (ETH sentinel supported) + amount: bigint; // wei + to: Address; // L1 recipient }; type WithdrawQuote = { - route: "eth-base" | "eth-nonbase" | "erc20-nonbase"; + route: 'eth-base' | 'eth-nonbase' | 'erc20-nonbase'; approvalsNeeded: Array<{ token: Address; spender: Address; amount: bigint }>; suggestedL2GasLimit?: bigint; }; type WithdrawPlan = { - route: WithdrawQuote["route"]; + route: WithdrawQuote['route']; summary: WithdrawQuote; steps: Array<{ key: string; kind: string; tx: TTx }>; }; type WithdrawHandle = { - kind: "withdrawal"; + kind: 'withdrawal'; l2TxHash: Hex; stepHashes: Record; plan: WithdrawPlan; }; type WithdrawalStatus = - | { phase: "UNKNOWN"; l2TxHash: Hex } - | { phase: "L2_PENDING"; l2TxHash: Hex } - | { phase: "PENDING"; l2TxHash: Hex; key?: unknown } - | { phase: "READY_TO_FINALIZE"; l2TxHash: Hex; key: unknown } - | { phase: "FINALIZED"; l2TxHash: Hex; key: unknown }; + | { phase: 'UNKNOWN'; l2TxHash: Hex } + | { phase: 'L2_PENDING'; l2TxHash: Hex } + | { phase: 'PENDING'; l2TxHash: Hex; key?: unknown } + | { phase: 'READY_TO_FINALIZE'; l2TxHash: Hex; key: unknown } + | { phase: 'FINALIZED'; l2TxHash: Hex; key: unknown }; // L2 receipt augmentation returned by wait({ for: 'l2' }) -type TransactionReceiptZKsyncOS = - TransactionReceipt & { l2ToL1Logs?: Array }; +type TransactionReceiptZKsyncOS = TransactionReceipt & { l2ToL1Logs?: Array }; ``` ## Notes & pitfalls -* **Two chains, two receipts:** inclusion on **L2** and finalization on **L1** are independent events. -* **Polling strategy:** for production UIs, prefer `wait({ for: 'ready' })` then finalize; it avoids premature finalize calls. -* **Approvals:** if withdrawing ERC-20 requires approvals, `create` will include those steps automatically. +- **Two chains, two receipts:** inclusion on **L2** and finalization on **L1** are independent events. +- **Polling strategy:** for production UIs, prefer `wait({ for: 'ready' })` then finalize; it avoids premature finalize calls. +- **Approvals:** if withdrawing ERC-20 requires approvals, `create` will include those steps automatically. diff --git a/docs/changelog.mdx b/docs/changelog.mdx index f4156cd..a5975f3 100644 --- a/docs/changelog.mdx +++ b/docs/changelog.mdx @@ -4,42 +4,62 @@ description: New releases and improvements for the ZKsyncOS SDK. rss: true --- - - ### Features - - Add **custom base token** support ([#39](https://github.com/dutterbutter/zksync-sdk/issues/39)) ([a1bab03](https://github.com/dutterbutter/zksync-sdk/commit/a1bab034e6d133c74c43422533d5780165608e3f)) - Compare diff + + ### Features - Add **custom base token** support + ([#39](https://github.com/dutterbutter/zksync-sdk/issues/39)) + ([a1bab03](https://github.com/dutterbutter/zksync-sdk/commit/a1bab034e6d133c74c43422533d5780165608e3f)) + + + Compare diff + + ### Features - E2E tests for **ERC-20** across **ethers** and **viem** adapters ([#38](https://github.com/dutterbutter/zksync-sdk/issues/38)) ([763587a](https://github.com/dutterbutter/zksync-sdk/commit/763587a3035da61d7764864efe1048e8f4144062)) - ### Bug Fixes - - Reported **code coverage** ([#32](https://github.com/dutterbutter/zksync-sdk/issues/32)) ([98834dc](https://github.com/dutterbutter/zksync-sdk/commit/98834dc722559e38da270395591145f4d91ea2e4)) - - Docs tweak ([#28](https://github.com/dutterbutter/zksync-sdk/issues/28)) ([533eb70](https://github.com/dutterbutter/zksync-sdk/commit/533eb70a61c33718a3f56850ba8db65a7f3204af)) - - CI env for E2E tests ([#31](https://github.com/dutterbutter/zksync-sdk/issues/31)) ([5d4df64](https://github.com/dutterbutter/zksync-sdk/commit/5d4df64c7a3307ec02ff9d6158f6b535af4f98b5)) - - Published build/types fixes ([#35](https://github.com/dutterbutter/zksync-sdk/issues/35)) ([901a0ea](https://github.com/dutterbutter/zksync-sdk/commit/901a0ea717e16076323f5c37b6e98ca5b2540578)) - - Ethers ERC-20 withdrawal overload fix ([#37](https://github.com/dutterbutter/zksync-sdk/issues/37)) ([2403a9c](https://github.com/dutterbutter/zksync-sdk/commit/2403a9c122e7a6e8c1f24cd407eef57abf3b076a)) +### Bug Fixes + +- Reported **code coverage** ([#32](https://github.com/dutterbutter/zksync-sdk/issues/32)) ([98834dc](https://github.com/dutterbutter/zksync-sdk/commit/98834dc722559e38da270395591145f4d91ea2e4)) +- Docs tweak ([#28](https://github.com/dutterbutter/zksync-sdk/issues/28)) ([533eb70](https://github.com/dutterbutter/zksync-sdk/commit/533eb70a61c33718a3f56850ba8db65a7f3204af)) +- CI env for E2E tests ([#31](https://github.com/dutterbutter/zksync-sdk/issues/31)) ([5d4df64](https://github.com/dutterbutter/zksync-sdk/commit/5d4df64c7a3307ec02ff9d6158f6b535af4f98b5)) +- Published build/types fixes ([#35](https://github.com/dutterbutter/zksync-sdk/issues/35)) ([901a0ea](https://github.com/dutterbutter/zksync-sdk/commit/901a0ea717e16076323f5c37b6e98ca5b2540578)) +- Ethers ERC-20 withdrawal overload fix ([#37](https://github.com/dutterbutter/zksync-sdk/issues/37)) ([2403a9c](https://github.com/dutterbutter/zksync-sdk/commit/2403a9c122e7a6e8c1f24cd407eef57abf3b076a)) Compare diff - - ### Bug Fixes - - Adjust READMEs ([#25](https://github.com/dutterbutter/zksync-sdk/issues/25)) ([eacd5ae](https://github.com/dutterbutter/zksync-sdk/commit/eacd5ae6f27332ad8c756d67276e24fbdd3187df)) - Compare diff + + ### Bug Fixes - Adjust READMEs ([#25](https://github.com/dutterbutter/zksync-sdk/issues/25)) + ([eacd5ae](https://github.com/dutterbutter/zksync-sdk/commit/eacd5ae6f27332ad8c756d67276e24fbdd3187df)) + + + Compare diff + + - - ### Bug Fixes - - Remove JSON in favor of TS ([#23](https://github.com/dutterbutter/zksync-sdk/issues/23)) ([dca83b6](https://github.com/dutterbutter/zksync-sdk/commit/dca83b6e34c7dbf0d866e27dc9c7fa4f58bc5656)) - Compare diff + + ### Bug Fixes - Remove JSON in favor of TS + ([#23](https://github.com/dutterbutter/zksync-sdk/issues/23)) + ([dca83b6](https://github.com/dutterbutter/zksync-sdk/commit/dca83b6e34c7dbf0d866e27dc9c7fa4f58bc5656)) + + + Compare diff + + - - ### Bug Fixes - - Additional build fixes ([#21](https://github.com/dutterbutter/zksync-sdk/issues/21)) ([65475b2](https://github.com/dutterbutter/zksync-sdk/commit/65475b23b0acf8bbf8454e1ff39f59a09fd68aa9)) - Compare diff + + ### Bug Fixes - Additional build fixes + ([#21](https://github.com/dutterbutter/zksync-sdk/issues/21)) + ([65475b2](https://github.com/dutterbutter/zksync-sdk/commit/65475b23b0acf8bbf8454e1ff39f59a09fd68aa9)) + + + Compare diff + + @@ -58,10 +78,11 @@ rss: true - Prep for alpha.1 ([c6c15e1](https://github.com/dutterbutter/zksync-sdk/commit/c6c15e12fba16a355171e30db42995600fad106b)) - E2E green ✅ ([c65c5b1](https://github.com/dutterbutter/zksync-sdk/commit/c65c5b1976a940ac8f8ff4f82cb7b74cd8d37f5b)) - ### Bug Fixes - - Export fixes in build ([#18](https://github.com/dutterbutter/zksync-sdk/issues/18)) ([5afbcbd](https://github.com/dutterbutter/zksync-sdk/commit/5afbcbdf13a3e15da94c8b66bc38e643097f917a)) - - Build stability improvements ([1a24cf7](https://github.com/dutterbutter/zksync-sdk/commit/1a24cf76d61ee9c172fb0428c5b2386f4553f736)) - +### Bug Fixes + +- Export fixes in build ([#18](https://github.com/dutterbutter/zksync-sdk/issues/18)) ([5afbcbd](https://github.com/dutterbutter/zksync-sdk/commit/5afbcbdf13a3e15da94c8b66bc38e643097f917a)) +- Build stability improvements ([1a24cf7](https://github.com/dutterbutter/zksync-sdk/commit/1a24cf76d61ee9c172fb0428c5b2386f4553f736)) + Compare diff diff --git a/docs/docs.json b/docs/docs.json index 019a016..ae6234d 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -4,21 +4,21 @@ "name": "ZKsync SDK", "colors": { "primary": "#1755F4", - "light": "#BFF351", + "light": "#BFF351", "dark": "#0C18EC" }, "favicon": "/favicon.svg", "appearance": { "default": "dark" }, - "styling": { + "styling": { "eyebrows": "breadcrumbs", "codeblocks": { "theme": { - "light": "vitesse-light", - "dark": "tokyo-night" + "light": "vitesse-light", + "dark": "tokyo-night" + } } - } }, "navigation": { "tabs": [ @@ -28,9 +28,7 @@ "groups": [ { "group": "Overview", - "pages": [ - "index" - ] + "pages": ["index"] } ] }, @@ -38,32 +36,25 @@ "tab": "Getting Started", "icon": "play", "groups": [ - { - "group": "Overview", - "pages": [ - "overview/index", - "overview/mental-model", - "overview/adapters", - "overview/status-vs-wait", - "overview/finalization" - ] - }, - { - "group": "Quickstart", - "pages": [ - "quickstart/index", - "quickstart/deposits", - "quickstart/withdrawals" - ] - }, - { - "group": "Guides", - "pages": [ - "guides/deposits", - "guides/withdrawals" + { + "group": "Overview", + "pages": [ + "overview/index", + "overview/mental-model", + "overview/adapters", + "overview/status-vs-wait", + "overview/finalization" + ] + }, + { + "group": "Quickstart", + "pages": ["quickstart/index", "quickstart/deposits", "quickstart/withdrawals"] + }, + { + "group": "Guides", + "pages": ["guides/deposits", "guides/withdrawals"] + } ] - } - ] }, { "tab": "SDK Reference", @@ -71,9 +62,7 @@ "groups": [ { "group": "Overview", - "pages": [ - "api-reference/introduction" - ] + "pages": ["api-reference/introduction"] }, { "group": "Ethers", @@ -81,7 +70,7 @@ "api-reference/ethers/client", "api-reference/ethers/sdk", "api-reference/ethers/deposits", - "api-reference/ethers/withdrawals" + "api-reference/ethers/withdrawals" ] }, { @@ -95,10 +84,7 @@ }, { "group": "Core", - "pages": [ - "api-reference/core/rpc", - "api-reference/core/errors" - ] + "pages": ["api-reference/core/rpc", "api-reference/core/errors"] } ] }, @@ -108,9 +94,7 @@ "groups": [ { "group": "Releases", - "pages": [ - "changelog" - ] + "pages": ["changelog"] } ] } @@ -121,8 +105,8 @@ "dark": "/logo/zksync-light.svg", "href": "https://zksync.io" }, - "search": { - "prompt": "Search ZKsync SDK..." + "search": { + "prompt": "Search ZKsync SDK..." }, "navbar": { "links": [ @@ -139,16 +123,7 @@ ] }, "contextual": { - "options": [ - "copy", - "view", - "chatgpt", - "claude", - "perplexity", - "mcp", - "cursor", - "vscode" - ] + "options": ["copy", "view", "chatgpt", "claude", "perplexity", "mcp", "cursor", "vscode"] }, "footer": { "socials": { diff --git a/docs/guides/deposits.mdx b/docs/guides/deposits.mdx index ae413ff..5e46bc1 100644 --- a/docs/guides/deposits.mdx +++ b/docs/guides/deposits.mdx @@ -1,6 +1,6 @@ --- -title: "Deposits (L1 → L2)" -description: "Fast, developer-focused deposits with validation, observability, and battle-tested patterns." +title: 'Deposits (L1 → L2)' +description: 'Fast, developer-focused deposits with validation, observability, and battle-tested patterns.' --- # Guide: Depositing funds L1 to L2 @@ -22,12 +22,8 @@ Before you begin, ensure you have the following: 4. A project set up with `viem` or `ethers` and `@dutterbutter/zksync-sdk` installed. - ```bash title="viem" - npm install viem @dutterbutter/zksync-sdk dotenv - ``` - ```bash title="ethers" - npm install ethers @dutterbutter/zksync-sdk dotenv - ``` + ```bash title="viem" npm install viem @dutterbutter/zksync-sdk dotenv ``` ```bash + title="ethers" npm install ethers @dutterbutter/zksync-sdk dotenv ``` 5. An `.env` file in your project's root directory with the following variables: @@ -74,8 +70,8 @@ const account = privateKeyToAccount(PRIVATE_KEY as `0x${string}`); const l1 = createPublicClient({ transport: http(L1_RPC) }); const l2 = createPublicClient({ transport: http(L2_RPC) }); const l1Wallet: WalletClient = createWalletClient({ - account, - transport: http(L1_RPC), +account, +transport: http(L1_RPC), }); // --- 2. Initialize the SDK --- @@ -83,7 +79,8 @@ const client = createViemClient({ l1, l2, l1Wallet }); const sdk = createViemSdk(client); console.log(`Using account: ${account.address}`); -``` + +```` ```typescript title="ethers" import 'dotenv/config'; import { JsonRpcProvider, Wallet, parseEther } from 'ethers'; @@ -105,7 +102,8 @@ const client = await createEthersClient({ l1: l1Provider, l2: l2Provider, signer const sdk = createEthersSdk(client); console.log(`Using account: ${signer.address}`); -``` +```` + #### Step 1: Define Deposit Parameters @@ -117,11 +115,12 @@ Next, define the parameters for your deposit in an object. You’ll specify the const me = signer.address as Address; const depositParams = { - amount: parseEther('0.01'), // The amount of ETH to deposit (e.g., 0.01 ETH) - token: ETH_ADDRESS, // The address for native ETH - to: me, // The recipient address on L2 (in this case, our own address) +amount: parseEther('0.01'), // The amount of ETH to deposit (e.g., 0.01 ETH) +token: ETH_ADDRESS, // The address for native ETH +to: me, // The recipient address on L2 (in this case, our own address) } as const; -``` + +```` ```typescript title="ERC20 Token Deposit" const me = signer.address as Address; @@ -130,26 +129,28 @@ const depositParams = { token: ERC20_TOKEN_ADDRESS, // The address for the ERC20 token to: me, // The recipient address on L2 (in this case, our own address) } as const; -``` +```` + ```typescript title="Base Token Deposit" const me = signer.address as Address; const depositParams = { amount: parseEther('0.01'), // The amount of SOPH to deposit (e.g., 0.01 SOPH) - token: L1_SOPH_TOKEN_ADDRESS, // The address for SOPH (or your chain's base token on L1) - to: me, // The recipient address on L2 (in this case, our own address) + token: L1_SOPH_TOKEN_ADDRESS, // The address for SOPH (or your chain's base token on L1) + to: me, // The recipient address on L2 (in this case, our own address) } as const; ``` + You can also specify advanced options for finer control over the transaction: - * `l2GasLimit`: The gas limit for the L2 part of the transaction. - * `gasPerPubdata`: The gas price per byte of public data. - * `operatorTip`: A tip for the L2 operator. - * `refundRecipient`: An address to receive any L1 gas refunds. +- `l2GasLimit`: The gas limit for the L2 part of the transaction. +- `gasPerPubdata`: The gas price per byte of public data. +- `operatorTip`: A tip for the L2 operator. +- `refundRecipient`: An address to receive any L1 gas refunds. @@ -158,7 +159,7 @@ You can also specify advanced options for finer control over the transaction: Before sending, it's best practice to get a cost estimate using `sdk.deposits.quote`. This returns information about fees and the expected gas required. -Users can skip this step and go directly to `create`, but quoting helps avoid surprises. + Users can skip this step and go directly to `create`, but quoting helps avoid surprises. ```typescript @@ -194,8 +195,8 @@ console.log('TRANSACTION CREATED →', handle); A deposit is a two-stage process: inclusion on L1 and then execution on L2. The SDK provides tools to track both stages. - * **`sdk.deposits.status(handle)`:** Check the current status of the deposit at any time. - * **`sdk.deposits.wait(handle, options)`:** Pause execution until the deposit reaches a specific stage. +- **`sdk.deposits.status(handle)`:** Check the current status of the deposit at any time. +- **`sdk.deposits.wait(handle, options)`:** Pause execution until the deposit reaches a specific stage. ```typescript // --- STEP 5: TRACK --- @@ -325,6 +326,7 @@ main().catch((err) => { process.exit(1); }); ``` + ```typescript title="ethers" /** * Example: Deposit ETH from L1 into a ZKsync L2 @@ -391,6 +393,7 @@ main().catch((err) => { process.exit(1); }); ``` + @@ -398,8 +401,8 @@ main().catch((err) => { For more detailed information on the methods used in this guide, see the official API reference: - * [`sdk.deposits.quote()`](https://zksync-sdk.mintlify.app/api-reference/ethers/deposits#quote-p%3A-depositparams-%E2%86%92-promise%3Cdepositquote%3E) - * [`sdk.deposits.prepare()`](https://zksync-sdk.mintlify.app/api-reference/ethers/deposits#prepare-p%3A-depositparams-%E2%86%92-promise%3Cdepositplan%3Ctransactionrequest%3E%3E) - * [`sdk.deposits.create()`](https://zksync-sdk.mintlify.app/api-reference/ethers/deposits#create-p%3A-depositparams-%E2%86%92-promise%3Cdeposithandle%3Ctransactionrequest%3E%3E) - * [`sdk.deposits.status()`](https://zksync-sdk.mintlify.app/api-reference/ethers/deposits#status-handleorhash-%E2%86%92-promise%3Cdepositstatus%3E) - * [`sdk.deposits.wait()`](https://zksync-sdk.mintlify.app/api-reference/ethers/deposits#wait-handleorhash%2C-%7B-for%3A-l1-%7C-l2-%7D-%E2%86%92-promise%3Ctransactionreceipt-%7C-null%3E) +- [`sdk.deposits.quote()`](https://zksync-sdk.mintlify.app/api-reference/ethers/deposits#quote-p%3A-depositparams-%E2%86%92-promise%3Cdepositquote%3E) +- [`sdk.deposits.prepare()`](https://zksync-sdk.mintlify.app/api-reference/ethers/deposits#prepare-p%3A-depositparams-%E2%86%92-promise%3Cdepositplan%3Ctransactionrequest%3E%3E) +- [`sdk.deposits.create()`](https://zksync-sdk.mintlify.app/api-reference/ethers/deposits#create-p%3A-depositparams-%E2%86%92-promise%3Cdeposithandle%3Ctransactionrequest%3E%3E) +- [`sdk.deposits.status()`](https://zksync-sdk.mintlify.app/api-reference/ethers/deposits#status-handleorhash-%E2%86%92-promise%3Cdepositstatus%3E) +- [`sdk.deposits.wait()`](https://zksync-sdk.mintlify.app/api-reference/ethers/deposits#wait-handleorhash%2C-%7B-for%3A-l1-%7C-l2-%7D-%E2%86%92-promise%3Ctransactionreceipt-%7C-null%3E) diff --git a/docs/guides/withdrawals.mdx b/docs/guides/withdrawals.mdx index 69868f9..676482e 100644 --- a/docs/guides/withdrawals.mdx +++ b/docs/guides/withdrawals.mdx @@ -1,6 +1,6 @@ --- -title: "Withdrawals (L2 → L1)" -description: "Fast, developer-focused withdrawals with validation, observability, and battle-tested patterns." +title: 'Withdrawals (L2 → L1)' +description: 'Fast, developer-focused withdrawals with validation, observability, and battle-tested patterns.' --- # Guide: Withdrawing funds L2 to L1 @@ -22,12 +22,8 @@ Before you begin, ensure you have the following: 4. A project set up with `viem` or `ethers` and `@dutterbutter/zksync-sdk` installed. - ```bash title="viem" - npm install viem @dutterbutter/zksync-sdk dotenv - ``` - ```bash title="ethers" - npm install ethers @dutterbutter/zksync-sdk dotenv - ``` + ```bash title="viem" npm install viem @dutterbutter/zksync-sdk dotenv ``` ```bash + title="ethers" npm install ethers @dutterbutter/zksync-sdk dotenv ``` 5. An `.env` file in your project's root directory with the following variables: @@ -43,8 +39,8 @@ Before you begin, ensure you have the following: Withdrawals generally follow **two phases**: -* An **L2 transaction** that burns/transfers the token and emits the L2→L1 message. -* A **finalization on L1** (after the message is ready) to release funds on L1. +- An **L2 transaction** that burns/transfers the token and emits the L2→L1 message. +- A **finalization on L1** (after the message is ready) to release funds on L1. The SDK exposes `wait(..., { for: 'ready' })`, `tryFinalize(...)`, and `wait(..., { for: 'finalized' })`. #### Step 0: Setup and SDK Initialization @@ -77,13 +73,13 @@ const account = privateKeyToAccount(PRIVATE_KEY as `0x${string}`); const l1 = createPublicClient({ transport: http(L1_RPC) }); const l2 = createPublicClient({ transport: http(L2_RPC) }); const l1Wallet: WalletClient = createWalletClient({ - account, - transport: http(L1_RPC), +account, +transport: http(L1_RPC), }); // Need to provide an L2 wallet client for sending L2 withdraw tx const l2Wallet = createWalletClient({ - account, - transport: http(L2_RPC), +account, +transport: http(L2_RPC), }); // --- 2. Initialize the SDK --- @@ -91,7 +87,8 @@ const client = createViemClient({ l1, l2, l2Wallet }); const sdk = createViemSdk(client); console.log(`Using account: ${account.address}`); -``` + +```` ```typescript title="ethers" import 'dotenv/config'; import { JsonRpcProvider, Wallet, parseEther } from 'ethers'; @@ -113,7 +110,7 @@ const client = await createEthersClient({ l1: l1Provider, l2: l2Provider, signer const sdk = createEthersSdk(client); console.log(`Using account: ${await signer.getAddress()}`); -``` +```` @@ -127,11 +124,12 @@ import { ETH_ADDRESS } from '@dutterbutter/zksync-sdk/core'; import type { Address } from '@dutterbutter/zksync-sdk/core'; const withdrawalParams = { - amount: parseEther('0.02'), - token: ETH_ADDRESS, // 👈 For ETH-based L2s, use the ETH sentinel - to: await signer.getAddress(), // L1 recipient (can be different from the L2 sender) +amount: parseEther('0.02'), +token: ETH_ADDRESS, // 👈 For ETH-based L2s, use the ETH sentinel +to: await signer.getAddress(), // L1 recipient (can be different from the L2 sender) } as const; -``` + +```` ```typescript title="ETH — Non-Base L2" import type { Address } from '@dutterbutter/zksync-sdk/core'; @@ -145,7 +143,7 @@ const withdrawalParams = { token: L2_ETH_TOKEN, // 👈 L2 representation of ETH on non-ETH-base chains to: await signer.getAddress(), } as const; -``` +```` ```typescript title="ERC-20" import type { Address } from '@dutterbutter/zksync-sdk/core'; @@ -157,7 +155,7 @@ const L2_ERC20_TOKEN = process.env.L2_ERC20_TOKEN as Address; const withdrawalParams = { amount: parseEther('10'), // or use parseUnits('amount', decimals) if not 18 - token: L2_ERC20_TOKEN, // 👈 L2 token address for the ERC-20 + token: L2_ERC20_TOKEN, // 👈 L2 token address for the ERC-20 to: await signer.getAddress(), } as const; ``` @@ -167,7 +165,7 @@ import { L2_BASE_TOKEN_ADDRESS } from '@dutterbutter/zksync-sdk/core'; import type { Address } from '@dutterbutter/zksync-sdk/core'; const withdrawalParams = { - amount: parseEther('5'), // adjust to your base token decimals if not 18 + amount: parseEther('5'), // adjust to your base token decimals if not 18 token: L2_BASE_TOKEN_ADDRESS, // 👈 L2 address of the chain’s Base Token (ERC-20) to: await signer.getAddress(), } as const; @@ -179,9 +177,9 @@ const withdrawalParams = { You can also specify advanced options for finer control over the transaction: -* `l2GasLimit`: The gas limit for the L2 withdrawal transaction. -* `operatorTip`: A tip for the L2 operator (if supported). -* `refundRecipient`: An L1 address to receive any L1 finalize-phase refunds (chain-specific). +- `l2GasLimit`: The gas limit for the L2 withdrawal transaction. +- `operatorTip`: A tip for the L2 operator (if supported). +- `refundRecipient`: An L1 address to receive any L1 finalize-phase refunds (chain-specific). @@ -189,9 +187,7 @@ You can also specify advanced options for finer control over the transaction: Before sending, get an estimate with `sdk.withdrawals.quote`. This returns expected fees and gas for the L2 step and any finalize phase hints. - -You can skip straight to `create`, but quoting helps avoid surprises. - +You can skip straight to `create`, but quoting helps avoid surprises. ```typescript // --- STEP 2: QUOTE --- @@ -223,10 +219,10 @@ console.log('TRANSACTION CREATED →', handle); Use `status` and `wait` to track all phases: -* `wait(handle, { for: 'l2' })` → L2 inclusion -* `wait(handle, { for: 'ready' })` → message proven/ready on L1 -* `tryFinalize(l2TxHash)` → submit finalize on L1 (no-op if already finalized) -* `wait(l2TxHash, { for: 'finalized' })` → finalized on L1 +- `wait(handle, { for: 'l2' })` → L2 inclusion +- `wait(handle, { for: 'ready' })` → message proven/ready on L1 +- `tryFinalize(l2TxHash)` → submit finalize on L1 (no-op if already finalized) +- `wait(l2TxHash, { for: 'finalized' })` → finalized on L1 ```typescript // --- STEP 5: TRACK --- @@ -308,10 +304,10 @@ async function main() { to: meL1, } as const; - const quote = await sdk.withdrawals.quote(params); + const quote = await sdk.withdrawals.quote(params); console.log('QUOTE →', quote); - const plan = await sdk.withdrawals.prepare(params); + const plan = await sdk.withdrawals.prepare(params); console.log('PREPARE →', plan); const handle = await sdk.withdrawals.create(params); @@ -369,10 +365,10 @@ async function main() { to: meL1, } as const; - const quote = await sdk.withdrawals.quote(params); + const quote = await sdk.withdrawals.quote(params); console.log('QUOTE →', quote); - const plan = await sdk.withdrawals.prepare(params); + const plan = await sdk.withdrawals.prepare(params); console.log('PREPARE →', plan); const handle = await sdk.withdrawals.create(params); @@ -404,9 +400,9 @@ main().catch((err) => { For more detailed information on the methods used in this guide, see the official API reference: -* [`sdk.withdrawals.quote()`](/api-reference/ethers/withdrawals#quote) -* [`sdk.withdrawals.prepare()`](/api-reference/ethers/withdrawals#prepare) -* [`sdk.withdrawals.create()`](/api-reference/ethers/withdrawals#create) -* [`sdk.withdrawals.status()`](/api-reference/ethers/withdrawals#status) -* [`sdk.withdrawals.wait()`](/api-reference/ethers/withdrawals#wait) -* [`sdk.withdrawals.tryFinalize()`](/api-reference/ethers/withdrawals#tryfinalize) +- [`sdk.withdrawals.quote()`](/api-reference/ethers/withdrawals#quote-p%3A-withdrawparams-→-promise) +- [`sdk.withdrawals.prepare()`](/api-reference/ethers/withdrawals#prepare-p%3A-withdrawparams-→-promise>) +- [`sdk.withdrawals.create()`](/api-reference/ethers/withdrawals#create-p%3A-withdrawparams-→-promise>) +- [`sdk.withdrawals.status()`](/api-reference/ethers/withdrawals#status-handleorhash-→-promise) +- [`sdk.withdrawals.wait()`](/api-reference/ethers/withdrawals#wait-handleorhash%2C-%7B-for%3A-l2-%7C-ready-%7C-finalized-%2C-pollms%3F%2C-timeoutms%3F-%7D) +- [`sdk.withdrawals.tryFinalize()`](/api-reference/ethers/withdrawals#tryfinalize-l2txhash-→-promise<%7B-ok%3A-true%3B-value%3A-%7B-status%3A-withdrawalstatus%3B-receipt%3F%3A-transactionreceipt-%7D-%7D-%7C-%7B-ok%3A-false%3B-error-%7D>) diff --git a/docs/index.mdx b/docs/index.mdx index 48fbde5..8abeb8a 100644 --- a/docs/index.mdx +++ b/docs/index.mdx @@ -1,7 +1,7 @@ --- title: ZKsyncOS SDK description: Lightweight adapters for viem and ethers to build ZKsync L1↔L2 flows fast. -mode: "custom" +mode: 'custom' ---

@@ -45,29 +45,30 @@ mode: "custom"
+

Quickstart guides

+ + Install the viem or ethers adapter, connect clients, and run your first deposit. + Send ETH or ERC-20 from Ethereum to ZKsync, then track L1 inclusion and L2 execution. Create the withdrawal on ZKsync, monitor execution, and finalize back on Ethereum. - - Install the viem adapter, connect clients, and run your first deposit. - - - Use an ethers v6 signer to perform a deposit and wait for finality. - Understand statuses vs waits and how to poll each phase of a flow. - - Utilities like getBridgehubAddress, getL2ToL1LogProof, and enhanced receipts. + + Understand the finalization process for withdrawals and how to ensure they are completed. + + + Utilities like getBridgehubAddress, getL2ToL1LogProof.
@@ -75,13 +76,17 @@ mode: "custom"

Resources

- + Fully typed clients, methods, and errors for core and adapters. See what’s new, fixed, and changed across releases. - + Questions or issues? Reach out and we’ll help you. diff --git a/docs/overview/adapters.mdx b/docs/overview/adapters.mdx index 7f86f07..b808ef1 100644 --- a/docs/overview/adapters.mdx +++ b/docs/overview/adapters.mdx @@ -9,15 +9,15 @@ The SDK is designed to work _with_ the tools you already know and love. It’s not a standalone library — it’s an **extension** that plugs directly into your existing [`viem`](https://viem.sh) or [`ethers.js`](https://docs.ethers.io/) setup. -This design means you can keep your existing provider, signer, and connection logic. -The SDK simply layers ZKsync-specific actions on top. + This design means you can keep your existing provider, signer, and connection logic. The SDK + simply layers ZKsync-specific actions on top. ## Why an Adapter Model? -- **Bring Your Own Stack:** Integrates directly with `viem` (`PublicClient`, `WalletClient`) or `ethers` providers and signers. -- **Familiar Developer Experience:** Keep your existing connection and signing flow unchanged. -- **Lightweight & Focused:** Only adds ZKsync-specific functionality like deposits, withdrawals, and soon interop — nothing more. +- **Bring Your Own Stack:** Integrates directly with `viem` (`PublicClient`, `WalletClient`) or `ethers` providers and signers. +- **Familiar Developer Experience:** Keep your existing connection and signing flow unchanged. +- **Lightweight & Focused:** Only adds ZKsync-specific functionality like deposits, withdrawals, and soon interop — nothing more. ## Installation @@ -27,11 +27,9 @@ npm install @dutterbutter/zksync-sdk viem # For ethers.js users npm install @dutterbutter/zksync-sdk ethers -```` +``` - -You install the **core SDK** plus the adapter matching your stack. - +You install the **core SDK** plus the adapter matching your stack. ## How to Use @@ -47,23 +45,23 @@ const l1 = createPublicClient({ transport: http(L1_RPC) }); const l2 = createPublicClient({ transport: http(L2_RPC) }); const l1Wallet: WalletClient = createWalletClient({ - account, - transport: http(L1_RPC), - }); +account, +transport: http(L1_RPC), +}); const client = createViemClient({ l1, l2, l1Wallet }); const sdk = createViemSdk(client); const me = account.address as Address; const params = { - amount: parseEther('0.01'), - token: ETH_ADDRESS, - to: me, - // optional: - // l2GasLimit: 300_000n, - // gasPerPubdata: 800n, - // operatorTip: 0n, - // refundRecipient: me, +amount: parseEther('0.01'), +token: ETH_ADDRESS, +to: me, +// optional: +// l2GasLimit: 300_000n, +// gasPerPubdata: 800n, +// operatorTip: 0n, +// refundRecipient: me, } as const; const handle = await sdk.deposits.create({ params }); @@ -71,7 +69,8 @@ await sdk.deposits.wait(handle, { for: 'l1' }); // L1 included await sdk.deposits.wait(handle, { for: 'l2' }); // L2 executed console.log('Deposit complete ✅'); -``` + +```` ```ts ethers.ts import { JsonRpcProvider, Wallet, parseEther } from 'ethers'; @@ -101,16 +100,17 @@ await sdk.deposits.wait(handle, { for: 'l1' }); // L1 included await sdk.deposits.wait(handle, { for: 'l2' }); // L2 executed console.log('Deposit complete ✅'); -``` +```` + ## Key Principles -* **No Key Management:** The SDK never asks for or stores private keys — signing stays with your `WalletClient` or `Signer`. -* **API Parity:** Both adapters expose the same API. Calling `sdk.deposits.quote()` works identically with `viem` or `ethers`. -* **Easy Migration:** Switch between `ethers` and `viem` by only changing the initialization code. +- **No Key Management:** The SDK never asks for or stores private keys — signing stays with your `WalletClient` or `Signer`. +- **API Parity:** Both adapters expose the same API. Calling `sdk.deposits.quote()` works identically with `viem` or `ethers`. +- **Easy Migration:** Switch between `ethers` and `viem` by only changing the initialization code. diff --git a/docs/overview/finalization.mdx b/docs/overview/finalization.mdx index 57e94b2..35136be 100644 --- a/docs/overview/finalization.mdx +++ b/docs/overview/finalization.mdx @@ -13,8 +13,8 @@ Withdrawals are a **two-step process**: This submits an L1 tx; only then does your ETH or token balance increase on Ethereum. - If you **never finalize**, your funds remain locked: visible as “ready to withdraw,” but unavailable on L1. - Anyone can finalize on your behalf, but you typically do it. + If you **never finalize**, your funds remain locked: visible as “ready to withdraw,” but + unavailable on L1. Anyone can finalize on your behalf, but you typically do it. ## Why finalization matters @@ -25,25 +25,26 @@ Withdrawals are a **two-step process**: ## Finalization methods -| Method | Purpose | Returns | -| --- | --- | --- | -| `withdrawals.status(h \| l2TxHash)` | Snapshot phase (`UNKNOWN` → `FINALIZED`) | `WithdrawalStatus` | -| `withdrawals.wait(h \| l2TxHash, { for })` | Block until a checkpoint (`'l2' \| 'ready' \| 'finalized'`) | Receipt or `null` | -| `withdrawals.finalize(l2TxHash)` | **Send** the L1 finalize tx | `{ status, receipt }` | +| Method | Purpose | Returns | +| ------------------------------------------ | ----------------------------------------------------------- | --------------------- | +| `withdrawals.status(h \| l2TxHash)` | Snapshot phase (`UNKNOWN` → `FINALIZED`) | `WithdrawalStatus` | +| `withdrawals.wait(h \| l2TxHash, { for })` | Block until a checkpoint (`'l2' \| 'ready' \| 'finalized'`) | Receipt or `null` | +| `withdrawals.finalize(l2TxHash)` | **Send** the L1 finalize tx | `{ status, receipt }` | - All methods accept either a **handle** (from `create`) or a **raw L2 tx hash**. If you only have the hash, you can still finalize. + All methods accept either a **handle** (from `create`) or a **raw L2 tx hash**. If you only have + the hash, you can still finalize. ## Phases -| Phase | Meaning | -| --- | --- | -| `UNKNOWN` | Handle doesn’t contain an L2 hash yet. | -| `L2_PENDING` | L2 tx not yet included. | -| `PENDING` | L2 included, but not yet ready to finalize on L1. | -| `READY_TO_FINALIZE` | Finalization on L1 would succeed now. | -| `FINALIZED` | Finalized on L1; funds released. | +| Phase | Meaning | +| ------------------- | ------------------------------------------------- | +| `UNKNOWN` | Handle doesn’t contain an L2 hash yet. | +| `L2_PENDING` | L2 tx not yet included. | +| `PENDING` | L2 included, but not yet ready to finalize on L1. | +| `READY_TO_FINALIZE` | Finalization on L1 would succeed now. | +| `FINALIZED` | Finalized on L1; funds released. | ## Examples @@ -62,9 +63,10 @@ await sdk.withdrawals.wait(withdrawal, { for: 'ready', pollMs: 5500 }); // 3) Finalize on L1 const { status, receipt } = await sdk.withdrawals.finalize(withdrawal.l2TxHash); -console.log(status.phase); // "FINALIZED" -console.log(receipt?.transactionHash); // L1 finalize tx hash -``` +console.log(status.phase); // "FINALIZED" +console.log(receipt?.transactionHash); // L1 finalize tx hash + +```` ```ts finalize-by-hash.ts theme={null} // If you only have the L2 tx hash: @@ -78,13 +80,12 @@ if (s.phase !== 'READY_TO_FINALIZE') { // Then finalize const { status, receipt } = await sdk.withdrawals.finalize(l2TxHash); -``` +```` Prefer the **no-throw** variants in UIs/services that want explicit flow control: - ```ts try-finalize.ts theme={null} const r = await sdk.withdrawals.tryFinalize(l2TxHash); if (!r.ok) { @@ -97,18 +98,17 @@ if (!r.ok) { ## Operational tips -* **Gate UX with phases:** Display a **Finalize** button only when `status.phase === 'READY_TO_FINALIZE'`. -* **Polling cadence:** `wait(..., { for: 'ready' })` defaults to ~**5500 ms**. Adjust with `pollMs` if needed. -* **Timeouts:** Use `timeoutMs` for long windows and fall back to `status(...)` to keep the UI responsive. -* **Receipts can be `null`:** `wait(..., { for: 'finalized' })` can resolve `null` if finalized but receipt isn’t retrievable; consider showing a link to the L1 explorer based on the tx hash you submitted. +- **Gate UX with phases:** Display a **Finalize** button only when `status.phase === 'READY_TO_FINALIZE'`. +- **Polling cadence:** `wait(..., { for: 'ready' })` defaults to ~**5500 ms**. Adjust with `pollMs` if needed. +- **Timeouts:** Use `timeoutMs` for long windows and fall back to `status(...)` to keep the UI responsive. +- **Receipts can be `null`:** `wait(..., { for: 'finalized' })` can resolve `null` if finalized but receipt isn’t retrievable; consider showing a link to the L1 explorer based on the tx hash you submitted. ## Common errors -* **RPC/network hiccups:** thrown `ZKsyncError` with kind **`RPC`**. Retry with backoff. -* **Internal decode issues:** thrown `ZKsyncError` with kind **`INTERNAL`**. Capture logs and report. +- **RPC/network hiccups:** thrown `ZKsyncError` with kind **`RPC`**. Retry with backoff. +- **Internal decode issues:** thrown `ZKsyncError` with kind **`INTERNAL`**. Capture logs and report. ## See also -* [Status vs Wait](/concepts/status-vs-wait) -* [Withdrawals guide](/guides/withdrawals) - +- [Status vs Wait](/overview/status-vs-wait) +- [Withdrawals guide](/guides/withdrawals) diff --git a/docs/overview/index.mdx b/docs/overview/index.mdx index 1c8015c..6304f00 100644 --- a/docs/overview/index.mdx +++ b/docs/overview/index.mdx @@ -11,42 +11,40 @@ Instead of re-implementing accounts or low-level RPC logic, this SDK focuses onl - Deposits (L1 → L2) - Withdrawals (L2 → L1, including finalization) -- Try variants for functional error handling (e.g. ) +- Try variants for functional error handling (e.g. `tryCreate`) - Status & wait helpers - ZKsync-specific JSON-RPC methods -The SDK doesn’t replace your existing Ethereum libraries — it **extends** them with ZKsync-only capabilities while keeping your current tooling intact. + The SDK doesn’t replace your existing Ethereum libraries — it **extends** them with ZKsync-only + capabilities while keeping your current tooling intact. ### Key Supported Features -- **Deposits (L1 → L2)** — ETH, Custom Base Token and ERC-20 - - **Initiate on L1:** build and send the deposit transaction from Ethereum. - - **Track progress:** query intermediate states (queued, included, executed). +- **Deposits (L1 → L2)** — ETH, Custom Base Token and ERC-20 + - **Initiate on L1:** build and send the deposit transaction from Ethereum. + - **Track progress:** query intermediate states (queued, included, executed). - **Verify completion on L2:** confirm funds credited/available on ZKsync. -- **Withdrawals (L2 → L1)** — ETH, Custom Base Token and ERC-20 - - **Initiate on L2:** create the withdrawal transaction on ZKsync. - - **Track progress:** monitor execution and finalization availability. +- **Withdrawals (L2 → L1)** — ETH, Custom Base Token and ERC-20 + - **Initiate on L2:** create the withdrawal transaction on ZKsync. + - **Track progress:** monitor execution and finalization availability. - **Finalize on L1:** finalize withdrawal to release funds back to Ethereum. -- **ZKsync RPC** - - **`getBridgehubAddress`** (`zks_getBridgehubContract`) – resolve the canonical Bridgehub contract address. - - **`getL2ToL1LogProof`** (`zks_getL2ToL1LogProof`) – retrieve the log proof for an L2 → L1 transaction. - - **`getReceiptWithL2ToL1`** *(receipt extension)* – returns a standard Ethereum `TransactionReceipt` **augmented** with `l2ToL1Logs`. +- **ZKsync RPC** + - **`getBridgehubAddress`** (`zks_getBridgehubContract`) – resolve the canonical Bridgehub contract address. + - **`getL2ToL1LogProof`** (`zks_getL2ToL1LogProof`) – retrieve the log proof for an L2 → L1 transaction. + - **`getReceiptWithL2ToL1`** _(receipt extension)_ – returns a standard Ethereum `TransactionReceipt` **augmented** with `l2ToL1Logs`. ## What you’ll find here -- [**What this SDK does**](./what-it-does) — the purpose, scope, and non-goals. -- [**Mental model**](./mental-model) — how to think about the core methods (`quote → prepare → create → status → wait → finalize`). -- [**Adapters (viem & ethers)**](./adapters) — how the SDK integrates with your existing stack. +- [**Mental model**](./overview/mental-model) — how to think about the core methods (`quote → prepare → create → status → wait → finalize`). +- [**Adapters (viem & ethers)**](./overview/adapters) — how the SDK integrates with your existing stack. +- [**Withdrawal Finalization**](./overview/finalization) — understand the finalization process for withdrawals and how to ensure they are completed. ## Next steps 👉 Ready to build? Jump to the [Quickstart](../quickstart/index). - + diff --git a/docs/overview/mental-model.mdx b/docs/overview/mental-model.mdx index ae9d669..46d0fef 100644 --- a/docs/overview/mental-model.mdx +++ b/docs/overview/mental-model.mdx @@ -11,13 +11,13 @@ Understanding this lifecycle is key to using the SDK effectively. ```bash quote → prepare → create → status → wait → (finalize*) -```` +``` -* The first five steps are common to both **Deposits** and **Withdrawals**. -* Withdrawals require an additional **`finalize`** step to prove and claim funds on L1. +- The first five steps are common to both **Deposits** and **Withdrawals**. +- Withdrawals require an additional **`finalize`** step to prove and claim funds on L1. -You can enter this lifecycle at **different stages** depending on how much control you need. + You can enter this lifecycle at **different stages** depending on how much control you need. ## The Core API: A Layered Approach @@ -27,82 +27,83 @@ Start by just gathering info (`quote`), move to building transactions yourself ( ### `quote(params)` -> *"What will this operation involve and cost?"* +> _"What will this operation involve and cost?"_ -* **Read-only dry run**: performs no transactions and has no side effects. -* Returns a `Quote` object with estimated fees, gas costs, and the planned steps. +- **Read-only dry run**: performs no transactions and has no side effects. +- Returns a `Quote` object with estimated fees, gas costs, and the planned steps. -Best for **displaying a confirmation screen** or cost estimate to a user before committing. + Best for **displaying a confirmation screen** or cost estimate to a user before committing. ### `prepare(params)` -> *"Build the transactions for me, but let me send them."* +> _"Build the transactions for me, but let me send them."_ -* Constructs all necessary transactions as an array of `TransactionRequest` objects inside a `Plan`. -* Does **not** sign or send them. +- Constructs all necessary transactions as an array of `TransactionRequest` objects inside a `Plan`. +- Does **not** sign or send them. -Best for **custom workflows** (e.g., multisigs or when you want to review the raw tx data before signing). + Best for **custom workflows** (e.g., multisigs or when you want to review the raw tx data before + signing). ### `create(params)` -> *"Prepare, sign, and send in one go."* +> _"Prepare, sign, and send in one go."_ -* Calls `prepare` internally, then signs & dispatches the txs using your configured signer. -* Returns a `Handle` — a lightweight tracker for later `status` or `wait`. +- Calls `prepare` internally, then signs & dispatches the txs using your configured signer. +- Returns a `Handle` — a lightweight tracker for later `status` or `wait`. -Best for **standard use cases** where you just want to kick off a deposit or withdrawal. + Best for **standard use cases** where you just want to kick off a deposit or withdrawal. ### `status(handle | txHash)` -> *"Where is my transaction right now?"* +> _"Where is my transaction right now?"_ -* Non-blocking: returns the **current state** of an operation. -* Works with a `Handle` or raw transaction hash. +- Non-blocking: returns the **current state** of an operation. +- Works with a `Handle` or raw transaction hash. Example return values: ```ts // Deposits -{ phase: 'L1_PENDING' | 'L2_EXECUTED' } +{ + phase: 'L1_PENDING' | 'L2_EXECUTED'; +} // Withdrawals -{ phase: 'L1_INCLUDED' | 'L2_PENDING' | 'READY_TO_FINALIZE' | 'FINALIZED' } +{ + phase: 'L1_INCLUDED' | 'L2_PENDING' | 'READY_TO_FINALIZE' | 'FINALIZED'; +} ``` - -Best for **polling in a UI** to show live progress without blocking. - +Best for **polling in a UI** to show live progress without blocking. ### `wait(handle, { for })` -> *"Pause until a specific checkpoint is reached."* +> _"Pause until a specific checkpoint is reached."_ -* Blocking async method: polls until the desired checkpoint, then resolves with the tx receipt. +- Blocking async method: polls until the desired checkpoint, then resolves with the tx receipt. Common checkpoints: -* **Deposits:** `'l1'` (included on L1) or `'l2'` (executed on L2). -* **Withdrawals:** `'l2'` (included), `'ready'` (ready to finalize), `'finalized'` (L1 finalization done). +- **Deposits:** `'l1'` (included on L1) or `'l2'` (executed on L2). +- **Withdrawals:** `'l2'` (included), `'ready'` (ready to finalize), `'finalized'` (L1 finalization done). -Best for **scripts or backends** that need to ensure one step is complete before the next. + Best for **scripts or backends** that need to ensure one step is complete before the next. -### `finalize(l2TxHash)` *(Withdrawals Only)* +### `finalize(l2TxHash)` _(Withdrawals Only)_ -> *"My funds are ready on L1. Finalize and release them."* +> _"My funds are ready on L1. Finalize and release them."_ -* Executes the **final step** of a withdrawal after `status` reports `READY_TO_FINALIZE`. +- Executes the **final step** of a withdrawal after `status` reports `READY_TO_FINALIZE`. - -Best for **claiming funds back to Ethereum** once the withdrawal is ready. - +Best for **claiming funds back to Ethereum** once the withdrawal is ready. ## Error Handling: The `try*` Philosophy @@ -128,7 +129,8 @@ if (result.ok) { ``` -Best for **applications that want explicit, predictable error handling** and to avoid uncaught exceptions. + Best for **applications that want explicit, predictable error handling** and to avoid uncaught + exceptions. ## Putting It All Together @@ -148,6 +150,6 @@ console.log('Deposit complete!'); ``` diff --git a/docs/overview/status-vs-wait.mdx b/docs/overview/status-vs-wait.mdx index 0ee0a9a..6eaf638 100644 --- a/docs/overview/status-vs-wait.mdx +++ b/docs/overview/status-vs-wait.mdx @@ -19,18 +19,20 @@ Both apply to **deposits** and **withdrawals**. Use `status(...)` for UI refresh ### `withdrawals.status(h | l2TxHash): Promise` **Input** + - `h`: a `WithdrawalWaitable` (e.g., from `create`) **or** the L2 tx hash `Hex`. **Phases** -| Phase | Meaning | +| Phase | Meaning | | -------------------- | ----------------------------------------------------------- | -| `UNKNOWN` | Handle doesn’t contain an L2 hash yet. | -| `L2_PENDING` | L2 tx not yet included. | -| `PENDING` | L2 included, **not** yet ready to finalize on L1. | -| `READY_TO_FINALIZE` | Finalization on L1 would succeed now. | -| `FINALIZED` | Finalized on L1; funds released. | +| `UNKNOWN` | Handle doesn’t contain an L2 hash yet. | +| `L2_PENDING` | L2 tx not yet included. | +| `PENDING` | L2 included, **not** yet ready to finalize on L1. | +| `READY_TO_FINALIZE` | Finalization on L1 would succeed now. | +| `FINALIZED` | Finalized on L1; funds released. | **Notes** + - No L2 receipt ⇒ `L2_PENDING`. - Finalization key derivable but not ready ⇒ `PENDING`. - Already finalized ⇒ `FINALIZED`. @@ -38,7 +40,7 @@ Both apply to **deposits** and **withdrawals**. Use `status(...)` for UI refresh ```ts withdrawals-status.ts theme={null} const s = await sdk.withdrawals.status(handleOrHash); // s.phase ∈ 'UNKNOWN' | 'L2_PENDING' | 'PENDING' | 'READY_TO_FINALIZE' | 'FINALIZED' -```` +``` ### `withdrawals.wait(h | l2TxHash, { for, pollMs?, timeoutMs? })` @@ -52,9 +54,9 @@ const s = await sdk.withdrawals.status(handleOrHash); **Behavior** -* If the handle has **no L2 hash**, returns `null` immediately. -* Default polling: **5500 ms** (override via `pollMs`). -* `timeoutMs` returns `null` on deadline. +- If the handle has **no L2 hash**, returns `null` immediately. +- Default polling: **5500 ms** (override via `pollMs`). +- `timeoutMs` returns `null` on deadline. ```ts withdrawals-wait.ts theme={null} // Wait for L2 inclusion → get L2 receipt (augmented with l2ToL1Logs if available) @@ -68,7 +70,8 @@ const l1Rcpt = await sdk.withdrawals.wait(handle, { for: 'finalized', timeoutMs: ``` - Building a UI? Use `status(...)` to paint current phase and enable/disable the **Finalize** button when phase is `READY_TO_FINALIZE`. + Building a UI? Use `status(...)` to paint current phase and enable/disable the **Finalize** button + when phase is `READY_TO_FINALIZE`. ## Deposits @@ -77,7 +80,7 @@ const l1Rcpt = await sdk.withdrawals.wait(handle, { for: 'finalized', timeoutMs: **Input** -* `h`: `DepositWaitable` (from `create`) **or** L1 tx hash `Hex`. +- `h`: `DepositWaitable` (from `create`) **or** L1 tx hash `Hex`. **Phases** @@ -117,15 +120,15 @@ const l2Rcpt = await sdk.deposits.wait(handle, { for: 'l2' }); ### Pick the right tool -* **Use `status(...)`** for **poll-less UI refreshes** (e.g., on page focus or interval timers you control). -* **Use `wait(...)`** for **workflow gating** (scripts, jobs, “continue when X happens”). +- **Use `status(...)`** for **poll-less UI refreshes** (e.g., on page focus or interval timers you control). +- **Use `wait(...)`** for **workflow gating** (scripts, jobs, “continue when X happens”). ### Timeouts & polling ```ts polling.ts theme={null} const ready = await sdk.withdrawals.wait(handle, { for: 'ready', - pollMs: 5500, // minimum enforced internally + pollMs: 5500, // minimum enforced internally timeoutMs: 30 * 60_000, // 30 minutes; returns null on deadline }); if (ready === null) { @@ -135,8 +138,8 @@ if (ready === null) { ### Error handling -* Network hiccup while fetching receipts ⇒ throws `ZKsyncError` of kind **`RPC`**. -* Internal decode issue ⇒ throws `ZKsyncError` of kind **`INTERNAL`**. +- Network hiccup while fetching receipts ⇒ throws `ZKsyncError` of kind **`RPC`**. +- Internal decode issue ⇒ throws `ZKsyncError` of kind **`INTERNAL`**. Prefer no-throw variants if you want explicit flow control: @@ -151,6 +154,6 @@ if (!r.ok) { ## Tips & edge cases -* **Handles vs hashes:** Passing a handle without the relevant hash yields `UNKNOWN`/`null`. If you already have a hash, pass the hash directly. -* **Finalization windows:** For withdrawals, `READY_TO_FINALIZE` can take a while. Use `status(...)` to keep the UI responsive and `wait(..., { for: 'finalized' })` only where blocking makes sense. -* **Retries:** If a wait returns `null` due to `timeoutMs`, you can safely call `status(...)` to decide whether to keep waiting or surface guidance to the user. +- **Handles vs hashes:** Passing a handle without the relevant hash yields `UNKNOWN`/`null`. If you already have a hash, pass the hash directly. +- **Finalization windows:** For withdrawals, `READY_TO_FINALIZE` can take a while. Use `status(...)` to keep the UI responsive and `wait(..., { for: 'finalized' })` only where blocking makes sense. +- **Retries:** If a wait returns `null` due to `timeoutMs`, you can safely call `status(...)` to decide whether to keep waiting or surface guidance to the user. diff --git a/docs/quickstart/deposits.mdx b/docs/quickstart/deposits.mdx index b506eb9..966fa22 100644 --- a/docs/quickstart/deposits.mdx +++ b/docs/quickstart/deposits.mdx @@ -8,9 +8,7 @@ description: Get your first ETH deposit from Ethereum (L1) to ZKsync (L2). - You have [Bun](https://bun.sh/) installed. - A funded **L1 wallet** with ETH for both the deposit amount and L1 gas fees - -Use a test network like **Sepolia** for experimentation. - +Use a test network like **Sepolia** for experimentation. ## 2. Installation @@ -24,6 +22,7 @@ Choose your adapter and install the SDK + adapter package: ```bash title="ethers" bun install @dutterbutter/zksync-sdk ethers dotenv ``` + Create a `.env` file in your project root: @@ -37,9 +36,7 @@ L1_RPC_URL=https://sepolia.infura.io/v3/YOUR_INFURA_ID L2_RPC_URL=ZKSYNC-OS-TESTNET-RPC ``` - -Never commit your `.env` file to source control. - +Never commit your `.env` file to source control. ## 3. Write the deposit script @@ -177,6 +174,7 @@ Never commit your `.env` file to source control. process.exit(1); }); ``` + ## 4. Run it @@ -191,6 +189,7 @@ Execute the script using `bun`. ```bash title="ethers" bun run deposit/ethers.ts ``` + You’ll see logs for the L1 transaction, then L2 execution, followed by updated balances. diff --git a/docs/quickstart/index.mdx b/docs/quickstart/index.mdx index bacef37..4de65db 100644 --- a/docs/quickstart/index.mdx +++ b/docs/quickstart/index.mdx @@ -34,14 +34,9 @@ You can't make a wrong choice. Both adapters are fully supported and provide the ## What you’ll do -Each Quickstart walks you through: +Each Quickstart walks you through how to: 1. **Install** the adapter package. 2. **Configure** a client or signer. 3. **Run** a deposit (L1 → L2) or withdrawal (L2 → L1) as a working example. 4. **Track** the status until it’s complete. - - -Once you’re set up, continue to the -[How-to Guides](../guides/index.md) for deeper usage patterns and advanced flows. - diff --git a/docs/quickstart/withdrawals.mdx b/docs/quickstart/withdrawals.mdx index aa136ac..fd1dd2c 100644 --- a/docs/quickstart/withdrawals.mdx +++ b/docs/quickstart/withdrawals.mdx @@ -8,9 +8,7 @@ description: Get your first ETH withdrawal from ZKsync (L2) to Ethereum (L1). - You have [Bun](https://bun.sh/) installed. - A funded **L1 wallet** with ETH for both the withdrawal amount and L1 gas fees - -Use a test network like **Sepolia** for experimentation. - +Use a test network like **Sepolia** for experimentation. ## 2. Installation @@ -24,6 +22,7 @@ Choose your adapter and install the SDK + adapter package: ```bash title="ethers" bun install @dutterbutter/zksync-sdk ethers dotenv ``` + Create a `.env` file in your project root: @@ -37,9 +36,7 @@ L1_RPC_URL=https://sepolia.infura.io/v3/YOUR_INFURA_ID L2_RPC_URL=ZKSYNC-OS-TESTNET-RPC ``` - -Never commit your `.env` file to source control. - +Never commit your `.env` file to source control. ## 3. Write the withdrawal script @@ -185,17 +182,14 @@ Never commit your `.env` file to source control. process.exit(1); }); ``` + ## 4. Run it - ``` bash title="viem" - bun run withdrawals/viem.ts - ``` - ```bash title="ethers" - bun run withdrawals/ethers.ts - ``` + ``` bash title="viem" bun run withdrawals/viem.ts ``` ```bash title="ethers" bun run + withdrawals/ethers.ts ``` You’ll see logs for the L2 transaction, then L1 finalization readiness, L1 finalization execution, followed by updated balances. @@ -205,4 +199,3 @@ You’ll see logs for the L2 transaction, then L1 finalization readiness, L1 fin - **Insufficient funds on L2:** Ensure enough ETH for the withdrawal **and** L1 gas. - **Invalid PRIVATE_KEY:** Must be 0x + 64 hex chars. - **Stuck at wait(..., `{ for: 'l1' }`):** Verify L2_RPC_URL and network health; check sdk.deposits.status(handle) to see the current phase. - diff --git a/docs/style.css b/docs/style.css index 2ba8e1b..dd32e77 100644 --- a/docs/style.css +++ b/docs/style.css @@ -1,241 +1,377 @@ /* ========================= Base / Tokens / Resets ========================= */ -html, body { overflow-x: hidden; } +html, +body { + overflow-x: hidden; +} -:root{ +:root { /* Brand */ - --zk-blue:#1755F4; --zk-royal:#0C18EC; --zk-teal:#13D5D3; --zk-lime:#BFF351; + --zk-blue: #1755f4; + --zk-royal: #0c18ec; + --zk-teal: #13d5d3; + --zk-lime: #bff351; /* UI neutrals */ - --white:#FFFFFF; --surface:#FFFFFF; - --ink-0:#05060A; /* dark bg */ - --ink-1:#0b1226; /* heading */ - --ink-2:#334155; /* body */ - --line:rgba(2,6,23,.10); + --white: #ffffff; + --surface: #ffffff; + --ink-0: #05060a; /* dark bg */ + --ink-1: #0b1226; /* heading */ + --ink-2: #334155; /* body */ + --line: rgba(2, 6, 23, 0.1); /* CTA teal */ - --teal-700:#0BA3A1; --teal-600:#0FBEBB; + --teal-700: #0ba3a1; + --teal-600: #0fbebb; } /* ========================= Hero ========================= */ -.hero { position: relative; padding: 96px 16px; } +.hero { + position: relative; + padding: 96px 16px; +} /* background grid + radial glow */ -.hero--ai{ +.hero--ai { width: 100vw; margin-left: calc(50% - 50vw); margin-right: calc(50% - 50vw); border-bottom: 1px solid var(--line); background: - radial-gradient(rgba(23,85,244,.06) 1px, transparent 1.2px) 0 0 / 18px 18px, - radial-gradient(1200px 700px at 85% -10%, rgba(12,24,236,.26), transparent 60%), - radial-gradient(1100px 600px at 10% 80%, rgba(19,213,211,.24), transparent 60%), - radial-gradient(900px 580px at 30% 20%, rgba(239,109,242,.20), transparent 60%), - radial-gradient(900px 520px at 70% 70%, rgba(253,64,44,.16), transparent 60%), - radial-gradient(1200px 520px at -10% -20%, rgba(191,243,81,.18), transparent 60%), + radial-gradient(rgba(23, 85, 244, 0.06) 1px, transparent 1.2px) 0 0 / 18px 18px, + radial-gradient(1200px 700px at 85% -10%, rgba(12, 24, 236, 0.26), transparent 60%), + radial-gradient(1100px 600px at 10% 80%, rgba(19, 213, 211, 0.24), transparent 60%), + radial-gradient(900px 580px at 30% 20%, rgba(239, 109, 242, 0.2), transparent 60%), + radial-gradient(900px 520px at 70% 70%, rgba(253, 64, 44, 0.16), transparent 60%), + radial-gradient(1200px 520px at -10% -20%, rgba(191, 243, 81, 0.18), transparent 60%), var(--surface); } -:root.dark .hero--ai{ - border-bottom-color: rgba(23,85,244,.28); +:root.dark .hero--ai { + border-bottom-color: rgba(23, 85, 244, 0.28); background: - radial-gradient(rgba(23,85,244,.13) 1px, transparent 1.2px) 0 0 / 18px 18px, - radial-gradient(1250px 720px at 62% -10%, rgba(12,24,236,.60), transparent 62%), - radial-gradient(1100px 650px at 10% 86%, rgba(19,213,211,.25), transparent 62%), - radial-gradient(900px 600px at 26% 28%, rgba(239,109,242,.25), transparent 62%), - radial-gradient(900px 560px at 76% 72%, rgba(253,64,44,.18), transparent 62%), - radial-gradient(1100px 540px at -10% -20%, rgba(191,243,81,.16), transparent 62%), + radial-gradient(rgba(23, 85, 244, 0.13) 1px, transparent 1.2px) 0 0 / 18px 18px, + radial-gradient(1250px 720px at 62% -10%, rgba(12, 24, 236, 0.6), transparent 62%), + radial-gradient(1100px 650px at 10% 86%, rgba(19, 213, 211, 0.25), transparent 62%), + radial-gradient(900px 600px at 26% 28%, rgba(239, 109, 242, 0.25), transparent 62%), + radial-gradient(900px 560px at 76% 72%, rgba(253, 64, 44, 0.18), transparent 62%), + radial-gradient(1100px 540px at -10% -20%, rgba(191, 243, 81, 0.16), transparent 62%), var(--ink-0); } /* grid split */ -.hero--split .hero-inner{ - max-width: 1200px; margin: 0 auto; display: grid; - grid-template-columns: 1.05fr 0.95fr; gap: 40px; align-items: center; padding: 0 24px; +.hero--split .hero-inner { + max-width: 1200px; + margin: 0 auto; + display: grid; + grid-template-columns: 1.05fr 0.95fr; + gap: 40px; + align-items: center; + padding: 0 24px; +} +.promo-left { + display: flex; + flex-direction: column; + gap: 18px; + align-items: flex-start; +} +.promo-right { + display: flex; + justify-content: flex-end; } -.promo-left { display: flex; flex-direction: column; gap: 18px; align-items: flex-start; } -.promo-right{ display: flex; justify-content: flex-end; } /* ========================= Pill ========================= */ -.pill-tag{ - align-self:flex-start; position:relative; display:inline-flex; align-items:center; gap:8px; - padding:8px 14px; border-radius:999px; font-size:.95rem; font-weight:600; color: var(--ink-1); - border:1px solid rgba(191,243,81,.45); +.pill-tag { + align-self: flex-start; + position: relative; + display: inline-flex; + align-items: center; + gap: 8px; + padding: 8px 14px; + border-radius: 999px; + font-size: 0.95rem; + font-weight: 600; + color: var(--ink-1); + border: 1px solid rgba(191, 243, 81, 0.45); background: color-mix(in srgb, var(--zk-blue) 8%, #fff); } -.pill-tag--ring{ - border:1px solid transparent; +.pill-tag--ring { + border: 1px solid transparent; background: - linear-gradient(#fff,#fff) padding-box, - conic-gradient(#BFF351, #1755F4, #EF6DF2, #FD402C, #13D5D3, #BFF351) border-box; + linear-gradient(#fff, #fff) padding-box, + conic-gradient(#bff351, #1755f4, #ef6df2, #fd402c, #13d5d3, #bff351) border-box; } -:root.dark .pill-tag{ - color:#F1F5FF; - background: linear-gradient(180deg, rgba(12,24,236,.32), rgba(12,24,236,.16)); - border-color: rgba(191,243,81,.60); +:root.dark .pill-tag { + color: #f1f5ff; + background: linear-gradient(180deg, rgba(12, 24, 236, 0.32), rgba(12, 24, 236, 0.16)); + border-color: rgba(191, 243, 81, 0.6); } -:root.dark .pill-tag--ring{ +:root.dark .pill-tag--ring { background: - linear-gradient(#0C1322, #0C1322) padding-box, - conic-gradient(#BFF351, #1755F4, #EF6DF2, #FD402C, #13D5D3, #BFF351) border-box; + linear-gradient(#0c1322, #0c1322) padding-box, + conic-gradient(#bff351, #1755f4, #ef6df2, #fd402c, #13d5d3, #bff351) border-box; border: 1px solid transparent; } /* ========================= Headline & Subtitle ========================= */ -.promo-title{ +.promo-title { font-size: clamp(2.6rem, 6vw, 4.4rem); - line-height: .95; letter-spacing: -0.02em; font-weight: 800; margin: 0; max-width: 12ch; + line-height: 0.95; + letter-spacing: -0.02em; + font-weight: 800; + margin: 0; + max-width: 12ch; color: var(--ink-1); } -.promo-title .zk-strong{ color: var(--zk-blue); } -:root.dark .promo-title{ color: var(--zk-blue); } -:root.dark .promo-title .zk-strong{ color: var(--white); } +.promo-title .zk-strong { + color: var(--zk-blue); +} +:root.dark .promo-title { + color: var(--zk-blue); +} +:root.dark .promo-title .zk-strong { + color: var(--white); +} -.hero-subtitle{ - max-width: 680px; font-size: clamp(1.05rem, 2vw, 1.25rem); line-height: 1.65; - margin: 6px 0 4px; color: var(--ink-2); +.hero-subtitle { + max-width: 680px; + font-size: clamp(1.05rem, 2vw, 1.25rem); + line-height: 1.65; + margin: 6px 0 4px; + color: var(--ink-2); +} +:root.dark .hero-subtitle { + color: #a7b1d6; } -:root.dark .hero-subtitle{ color:#A7B1D6; } /* ========================= CTAs ========================= */ -.hero-actions{ display:flex; gap:12px; flex-wrap:wrap; margin-top:6px; } +.hero-actions { + display: flex; + gap: 12px; + flex-wrap: wrap; + margin-top: 6px; +} -.hero-cta{ - display:inline-flex; align-items:center; justify-content:center; gap:8px; - padding:14px 22px; border-radius:12px; font-weight:600; text-decoration:none; - color:#fff; background: var(--zk-blue); - box-shadow: 0 6px 16px rgba(0,0,0,0.08); - transition: transform .06s ease, box-shadow .2s ease, background-color .2s ease, border-color .2s ease; +.hero-cta { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 8px; + padding: 14px 22px; + border-radius: 12px; + font-weight: 600; + text-decoration: none; + color: #fff; + background: var(--zk-blue); + box-shadow: 0 6px 16px rgba(0, 0, 0, 0.08); + transition: + transform 0.06s ease, + box-shadow 0.2s ease, + background-color 0.2s ease, + border-color 0.2s ease; +} +.hero-cta:hover { + transform: translateY(-1px); + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.12); } -.hero-cta:hover{ transform: translateY(-1px); box-shadow: 0 10px 20px rgba(0,0,0,0.12); } -.hero-cta.ghost{ background:#fff; color:var(--ink-1); border:1px solid var(--line); box-shadow:none; } -.hero-cta.ghost:hover{ background:#f8fafc; border-color: rgba(2,6,23,.14); } +.hero-cta.ghost { + background: #fff; + color: var(--ink-1); + border: 1px solid var(--line); + box-shadow: none; +} +.hero-cta.ghost:hover { + background: #f8fafc; + border-color: rgba(2, 6, 23, 0.14); +} -.hero-cta.teal{ +.hero-cta.teal { background: linear-gradient(90deg, var(--teal-700), var(--teal-600)); - color:#fff; border:1px solid rgba(19,213,211,.35); + color: #fff; + border: 1px solid rgba(19, 213, 211, 0.35); } /* dark */ -:root.dark .hero-cta{ - background: linear-gradient(90deg, #1755F4, #0C18EC); - color:#fff; box-shadow: 0 8px 24px rgba(23,85,244,.35); +:root.dark .hero-cta { + background: linear-gradient(90deg, #1755f4, #0c18ec); + color: #fff; + box-shadow: 0 8px 24px rgba(23, 85, 244, 0.35); } -:root.dark .hero-cta.teal{ +:root.dark .hero-cta.teal { background: linear-gradient(90deg, var(--teal-700), var(--teal-600)); - border:1px solid rgba(19,213,211,.45); - box-shadow: 0 10px 28px rgba(19,213,211,.32); + border: 1px solid rgba(19, 213, 211, 0.45); + box-shadow: 0 10px 28px rgba(19, 213, 211, 0.32); } -:root.dark .hero-cta.ghost{ - background:#fff; color:#0b1226; border:1px solid rgba(2,6,23,.28); +:root.dark .hero-cta.ghost { + background: #fff; + color: #0b1226; + border: 1px solid rgba(2, 6, 23, 0.28); } -:root.dark .hero-cta.ghost:hover{ - background:#f8fafc; border-color: rgba(2,6,23,.40); +:root.dark .hero-cta.ghost:hover { + background: #f8fafc; + border-color: rgba(2, 6, 23, 0.4); } /* ========================= Installer card ========================= */ -.dev-card{ - width:100%; max-width:520px; border-radius:16px; padding:16px; - border:1px solid var(--line); background:#fff; - box-shadow: 0 8px 26px rgba(2,6,23,.06); +.dev-card { + width: 100%; + max-width: 520px; + border-radius: 16px; + padding: 16px; + border: 1px solid var(--line); + background: #fff; + box-shadow: 0 8px 26px rgba(2, 6, 23, 0.06); +} +.dev-label { + font-size: 0.9rem; + font-weight: 600; + color: #64748b; + margin-bottom: 8px; +} +.dev-footnote { + margin-top: 10px; + font-size: 0.85rem; + color: #94a3b8; } -.dev-label{ font-size:.9rem; font-weight:600; color:#64748b; margin-bottom:8px; } -.dev-footnote{ margin-top:10px; font-size:.85rem; color:#94a3b8; } /* single-border look for code block */ .dev-card pre, -.dev-card pre[class*="language-"], +.dev-card pre[class*='language-'], .dev-card .shiki, .dev-card .code-block, -.dev-card pre code{ - background:transparent !important; border:0 !important; box-shadow:none !important; +.dev-card pre code { + background: transparent !important; + border: 0 !important; + box-shadow: none !important; +} +.dev-card pre { + margin: 0 !important; + padding: 14px 16px !important; + border-radius: 10px !important; } -.dev-card pre{ margin:0 !important; padding:14px 16px !important; border-radius:10px !important; } /* gradient ring variant */ -.dev-card--gradient{ - position:relative; border:1px solid transparent; border-radius:16px; +.dev-card--gradient { + position: relative; + border: 1px solid transparent; + border-radius: 16px; background: - linear-gradient(#fff,#fff) padding-box, - linear-gradient(135deg, #1755F4, #EF6DF2, #FD402C, #13D5D3) border-box; - box-shadow: 0 12px 32px rgba(2,6,23,.10); + linear-gradient(#fff, #fff) padding-box, + linear-gradient(135deg, #1755f4, #ef6df2, #fd402c, #13d5d3) border-box; + box-shadow: 0 12px 32px rgba(2, 6, 23, 0.1); } /* dark */ -:root.dark .dev-card{ - background: linear-gradient(180deg, rgba(12,24,236,.18), rgba(12,16,28,.30)); - border-color: rgba(232,237,255,.16); - box-shadow: 0 14px 40px rgba(0,0,0,.55), 0 0 0 1px rgba(5,12,255,.06) inset; +:root.dark .dev-card { + background: linear-gradient(180deg, rgba(12, 24, 236, 0.18), rgba(12, 16, 28, 0.3)); + border-color: rgba(232, 237, 255, 0.16); + box-shadow: + 0 14px 40px rgba(0, 0, 0, 0.55), + 0 0 0 1px rgba(5, 12, 255, 0.06) inset; } -:root.dark .dev-card--gradient{ +:root.dark .dev-card--gradient { background: - linear-gradient(#0C1322, #0C1322) padding-box, - linear-gradient(135deg, #1755F4, #EF6DF2, #FD402C, #13D5D3) border-box; + linear-gradient(#0c1322, #0c1322) padding-box, + linear-gradient(135deg, #1755f4, #ef6df2, #fd402c, #13d5d3) border-box; border: 1px solid transparent; } -:root.dark .dev-card pre code{ color:#F3FAFF; } +:root.dark .dev-card pre code { + color: #f3faff; +} /* ========================= Sections & responsive ========================= */ -.lp-container{ max-width:1200px; margin:0 auto; padding:40px 24px 56px; } -.lp-container > h2{ font-size:clamp(1.25rem, 2vw, 1.5rem); font-weight:600; margin:0 0 16px; } +.lp-container { + max-width: 1200px; + margin: 0 auto; + padding: 40px 24px 56px; +} +.lp-container > h2 { + font-size: clamp(1.25rem, 2vw, 1.5rem); + font-weight: 600; + margin: 0 0 16px; +} -@media (max-width: 960px){ - .hero--split .hero-inner{ grid-template-columns:1fr; gap:28px; } - .promo-right{ justify-content:flex-start; } +@media (max-width: 960px) { + .hero--split .hero-inner { + grid-template-columns: 1fr; + gap: 28px; + } + .promo-right { + justify-content: flex-start; + } } -@media (min-width: 1280px){ - .hero--split .hero-inner{ gap:44px; } - .promo-right{ transform: translateY(6px); } +@media (min-width: 1280px) { + .hero--split .hero-inner { + gap: 44px; + } + .promo-right { + transform: translateY(6px); + } } /* ========================= Top bleed for non-hero pages ========================= */ -:root { --zk-bleed-height: min(38vh, 560px); } +:root { + --zk-bleed-height: min(38vh, 560px); +} -body { position: relative; background: var(--surface); } -:root.dark body { background: var(--ink-0); } +body { + position: relative; + background: var(--surface); +} +:root.dark body { + background: var(--ink-0); +} /* only on pages WITHOUT the hero */ body:not(.has-hero)::before { - content: ""; position: absolute; top: 0; left: 0; right: 0; - height: var(--zk-bleed-height); pointer-events: none; z-index: 0; + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: var(--zk-bleed-height); + pointer-events: none; + z-index: 0; background: - radial-gradient(rgba(23,85,244,.06) 1px, transparent 1.2px) 0 0 / 18px 18px, - radial-gradient(1200px 700px at 85% -10%, rgba(12,24,236,.26), transparent 60%), - radial-gradient(1100px 600px at 10% 80%, rgba(19,213,211,.24), transparent 60%), - radial-gradient(900px 580px at 30% 20%, rgba(239,109,242,.20), transparent 60%), - radial-gradient(900px 520px at 70% 70%, rgba(253,64,44,.16), transparent 60%), - radial-gradient(1200px 520px at -10% -20%, rgba(191,243,81,.18), transparent 60%), + radial-gradient(rgba(23, 85, 244, 0.06) 1px, transparent 1.2px) 0 0 / 18px 18px, + radial-gradient(1200px 700px at 85% -10%, rgba(12, 24, 236, 0.26), transparent 60%), + radial-gradient(1100px 600px at 10% 80%, rgba(19, 213, 211, 0.24), transparent 60%), + radial-gradient(900px 580px at 30% 20%, rgba(239, 109, 242, 0.2), transparent 60%), + radial-gradient(900px 520px at 70% 70%, rgba(253, 64, 44, 0.16), transparent 60%), + radial-gradient(1200px 520px at -10% -20%, rgba(191, 243, 81, 0.18), transparent 60%), transparent; - mask-image: linear-gradient(to bottom, rgba(0,0,0,.95) 58%, rgba(0,0,0,0)); - -webkit-mask-image: linear-gradient(to bottom, rgba(0,0,0,.95) 58%, rgba(0,0,0,0)); + mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.95) 58%, rgba(0, 0, 0, 0)); + -webkit-mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.95) 58%, rgba(0, 0, 0, 0)); box-shadow: inset 0 -1px 0 var(--line); } :root.dark body:not(.has-hero)::before { background: - radial-gradient(rgba(23,85,244,.13) 1px, transparent 1.2px) 0 0 / 18px 18px, - radial-gradient(1250px 720px at 62% -10%, rgba(12,24,236,.60), transparent 62%), - radial-gradient(1100px 650px at 10% 86%, rgba(19,213,211,.25), transparent 62%), - radial-gradient(900px 600px at 26% 28%, rgba(239,109,242,.25), transparent 62%), - radial-gradient(900px 560px at 76% 72%, rgba(253,64,44,.18), transparent 62%), - radial-gradient(1100px 540px at -10% -20%, rgba(191,243,81,.16), transparent 62%), + radial-gradient(rgba(23, 85, 244, 0.13) 1px, transparent 1.2px) 0 0 / 18px 18px, + radial-gradient(1250px 720px at 62% -10%, rgba(12, 24, 236, 0.6), transparent 62%), + radial-gradient(1100px 650px at 10% 86%, rgba(19, 213, 211, 0.25), transparent 62%), + radial-gradient(900px 600px at 26% 28%, rgba(239, 109, 242, 0.25), transparent 62%), + radial-gradient(900px 560px at 76% 72%, rgba(253, 64, 44, 0.18), transparent 62%), + radial-gradient(1100px 540px at -10% -20%, rgba(191, 243, 81, 0.16), transparent 62%), transparent; } /* ensure content sits above the pseudo */ -body > * { position: relative; } +body > * { + position: relative; +} From d18252f82f2ff0e187a195276c92848cfba9c865 Mon Sep 17 00:00:00 2001 From: Dustin Brickwood Date: Mon, 20 Oct 2025 10:11:44 -0500 Subject: [PATCH 18/18] chore: clean up links --- docs/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.mdx b/docs/index.mdx index 8abeb8a..2de743e 100644 --- a/docs/index.mdx +++ b/docs/index.mdx @@ -53,7 +53,7 @@ mode: 'custom'

Quickstart guides

- Install the viem or ethers adapter, connect clients, and run your first deposit. + Install the `viem` or `ethers` adapter, connect clients, and run your first deposit. Send ETH or ERC-20 from Ethereum to ZKsync, then track L1 inclusion and L2 execution.