Skip to content

feat(sdk-agnostic-lib): refactor tutorials for new SDK monorepo with provider adapters#45

Closed
jeffersonBastos wants to merge 20 commits into
cowprotocol:mainfrom
bleu:BLEU-SDK-AGNOSTIC-LIB
Closed

feat(sdk-agnostic-lib): refactor tutorials for new SDK monorepo with provider adapters#45
jeffersonBastos wants to merge 20 commits into
cowprotocol:mainfrom
bleu:BLEU-SDK-AGNOSTIC-LIB

Conversation

@jeffersonBastos
Copy link
Copy Markdown
Contributor

@jeffersonBastos jeffersonBastos commented Aug 8, 2025

Description

This PR updates the CoW Protocol Learn tutorials to align with the new SDK monorepo architecture that introduces provider adapters.
It also adds new tutorial sections to demonstrate different SDK usage patterns.

Changes

Existing tutorial updates:

  • Updated SDK classes to use provider adapters where required
  • Replaced deprecated APIs: appDataToCid()getAppDataInfo()
  • Added adapter setup for tutorials using MetadataApi, OrderSigningUtils, etc.
  • Updated imports to use the umbrella package (@cowprotocol/cow-sdk) with specific adapter packages
  • Fixed method calls and parameters for compatibility with the new SDK version

New tutorial sections:

  • 00-setup/01-provider-adapters
  • 03-umbrella-sdk/ — complete new section comparing different SDK usage approaches

Summary by CodeRabbit

  • New Features

    • Added many new tutorial guides and hands-on examples covering SDK setup, unified SDK workflows, individual package usage, and end-to-end trading demos.
  • Improvements

    • Introduced a global adapter pattern across tutorials and clarified provider-adapter documentation.
    • Standardized app-data handling to surface content identifiers and updated example flows (quoting, signing, cancellations).
    • Improved formatting and consistent return values in examples.
  • Chores

    • Added tutorial metadata and TypeScript configs; updated dependencies to new SDK and adapter packages.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Aug 8, 2025

Walkthrough

Added and updated many tutorial files: new umbrella SDK and adapter documentation, metadata and tsconfig files, example code switching to a global EthersV5Adapter and new @cowprotocol/cow-sdk APIs (including CowSdk), adjusted app-data APIs to getAppDataInfo, and updated routing redirects to the new tutorial paths.

Changes

Cohort / File(s) Change Summary
Tutorial metadata & configs
content/tutorial/00-setup/meta.json, content/tutorial/00-setup/tsconfig.json, content/tutorial/03-umbrella-sdk/meta.json, content/tutorial/03-umbrella-sdk/tsconfig.json, content/tutorial/03-umbrella-sdk/01-unified-approach/meta.json, content/tutorial/03-umbrella-sdk/02-individual-packages/meta.json, content/tutorial/00-setup/00-getting-started/01-provider-adapters/meta.json
Added new tutorial meta.json files and per-section tsconfig.json files to define scopes, focus files, and TypeScript path mappings.
Common package changes
content/tutorial/common/package.json
Replaced @cowprotocol/app-data, upgraded @cowprotocol/cow-sdk to a monorepo version, and added @cowprotocol/sdk-ethers-v5-adapter.
Global adapter + provider adapters docs
content/tutorial/00-setup/00-getting-started/01-provider-adapters/README.md, .../app-a/src/lib/run.ts, .../app-b/src/lib/run.ts, .../00-getting-started/app-a/src/lib/run.ts
New documentation and examples introducing provider adapters and the global adapter pattern; example runs showing EthersV5Adapter setup and global adapter inspection.
Simple Orders: order flow & signer setup
content/tutorial/01-simple-orders/01-order/... 01-approve-sell-token-order/app-a/src/lib/run.ts, 02-quote-order/.../app-a/src/lib/run.ts, 03-sign-order/README.md, 03-sign-order/app-a/src/lib/run.ts, 03-sign-order/app-b/src/lib/run.ts, 04-submit-order/README.md, 04-submit-order/app-a/src/lib/run.ts, 04-submit-order/app-b/src/lib/run.ts, 06-cancel-off-chain-order/README.md, 06-cancel-off-chain-order/app-a/src/lib/run.ts, 06-cancel-off-chain-order/app-b/src/lib/run.ts
Introduced setupAdapter helper and added setGlobalAdapter + EthersV5Adapter usage across examples; README updates describing adapter setup; minor formatting and some functions now return {}.
App Data: API changes & examples
content/tutorial/01-simple-orders/02-app-data/... (README and app-a/app-b variants across 01-04 and 02-03)
Switched to getAppDataInfo() (returns cid, appDataHex, appDataContent), changed slippageBips to numeric 50, integrated global adapter pattern, updated examples and READMEs.
Advanced Orders: ETH Flow & pre-signed flows
content/tutorial/02-advanced-orders/... (eth-flow, pre-signed orders, cancel flows; app-a/app-b variants and READMEs)
Added setupAdapter helper, migrated to global adapter usage, updated metadata handling to getAppDataInfo, adjusted formatting and some small logic (e.g., buyAmount slippage calc); Safe-related examples updated to use adapter signer.
Umbrella SDK tutorials
content/tutorial/03-umbrella-sdk/01-unified-approach/*, content/tutorial/03-umbrella-sdk/02-individual-packages/* (READMEs and app-a/app-b run.ts)
New unified-SDK (CowSdk) tutorials and individual-package tutorials with example run functions demonstrating CowSdk usage and separate package usage; added README guidance and example flows.
New example run implementations / placeholders
Many app-a/src/lib/run.ts and app-b/src/lib/run.ts files across tutorials
Added new run functions, introduced adapter setup helper in many examples, and in several places added explicit return {} placeholders or expanded example returns.
Routing updates
src/routes/+page.server.js, src/routes/tutorial/+page.js, src/routes/tutorial/[slug]/+page.server.js
Redirect targets changed from /tutorial/getting-started-order to /tutorial/getting-started; adjusted import to use base path in one file.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant UserApp
    participant Web3Provider
    participant Adapter as EthersV5Adapter
    participant Global as GlobalAdapterRegistry
    participant CowSdk
    participant OrderBook
    participant Metadata

    UserApp->>Web3Provider: request signer & chainId
    Web3Provider-->>UserApp: signer, chainId
    UserApp->>Adapter: new Adapter(provider, signer)
    Adapter-->>UserApp: adapterInstance
    UserApp->>Global: setGlobalAdapter(adapterInstance)
    Global-->>UserApp: adapter registered
    UserApp->>CowSdk: init(adapter, chainId, env)
    CowSdk-->>OrderBook: expose orderBook module
    CowSdk-->>Metadata: expose metadataApi module
    UserApp->>Metadata: generate app data -> getAppDataInfo()
    Metadata-->>UserApp: { cid, appDataHex, appDataContent }
    UserApp->>OrderBook: getQuote(appData, appDataHash)
    OrderBook-->>UserApp: quote
    UserApp->>CowSdk: orderSigning.signOrder(quote, signer)
    CowSdk-->>UserApp: signature
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20-30 minutes

🐇
I hopped through docs, code, and guide,
Set adapters global, far and wide—
CowSdk stitched the scattered seams,
App data flows and new README dreams.
Packaged, signed, the tutorials gleam.

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@vercel
Copy link
Copy Markdown

vercel Bot commented Aug 8, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Updated (UTC)
learn Ready Ready Preview Aug 22, 2025 9:28pm

@socket-security
Copy link
Copy Markdown

socket-security Bot commented Aug 8, 2025

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 23

🔭 Outside diff range comments (5)
content/tutorial/02-advanced-orders/01-eth-flow/03-cancel-eth-flow/app-a/src/lib/run.ts (1)

14-15: Use hex chainId with wallet_switchEthereumChain and handle chain-not-added (4902).

EIP-3326 expects chainId as a hex string (e.g., '0x64' for Gnosis). Passing 100 can fail on many wallets. Add a fallback to wallet_addEthereumChain for error 4902.

-        await provider.send('wallet_switchEthereumChain', [{ chainId: 100 }]);
+        const gnosisChainIdHex = '0x' + SupportedChainId.GNOSIS_CHAIN.toString(16); // 0x64
+        try {
+            await provider.send('wallet_switchEthereumChain', [{ chainId: gnosisChainIdHex }]);
+        } catch (err: any) {
+            const code = err?.code ?? err?.data?.originalError?.code;
+            if (code === 4902) {
+                await provider.send('wallet_addEthereumChain', [{
+                    chainId: gnosisChainIdHex,
+                    chainName: 'Gnosis',
+                    nativeCurrency: { name: 'xDAI', symbol: 'xDAI', decimals: 18 },
+                    rpcUrls: ['https://rpc.gnosischain.com/'],
+                    blockExplorerUrls: ['https://gnosisscan.io']
+                }]);
+            } else {
+                throw err;
+            }
+        }
content/tutorial/01-simple-orders/01-order/06-cancel-off-chain-order/README.md (1)

49-53: Fix parameters for signOrderCancellations.

The object literal { [orderUid], chainId, signer } is invalid. The API expects orderUids to be an array.

Use:

-    const orderCancellationsSigningResult = await OrderSigningUtils.signOrderCancellations({
-        [orderUid],
-        chainId,
-        signer
-    });
+    const orderCancellationsSigningResult = await OrderSigningUtils.signOrderCancellations({
+        orderUids: [orderUid],
+        chainId,
+        signer,
+    });
content/tutorial/02-advanced-orders/03-pre-signed-orders/01-create-pre-signed-order/app-b/src/lib/run.ts (2)

31-36: chainId becomes stale after wallet_switchEthereumChain – leads to wrong addresses

After requesting the chain switch you still use the old chainId when:

  • instantiating OrderBookApi
  • indexing COW_PROTOCOL_SETTLEMENT_CONTRACT_ADDRESS
  • selecting the Safe TX service URL.

Re-read the chainId or hard-set it after the switch.

-  if (chainId !== SupportedChainId.GNOSIS_CHAIN) {
-      await provider.send('wallet_switchEthereumChain', [{ chainId: SupportedChainId.GNOSIS_CHAIN }]);
-  }
+  if (chainId !== SupportedChainId.GNOSIS_CHAIN) {
+      await provider.send('wallet_switchEthereumChain', [{ chainId: SupportedChainId.GNOSIS_CHAIN }]);
+      chainId = SupportedChainId.GNOSIS_CHAIN;
+  }

107-110: new Contract(address, abi) needs a provider or signer

Without passing provider/signer, the contract instance can’t perform calls. Use the signer from setupAdapter or the provider:

-  const settlementContract = new Contract(COW_PROTOCOL_SETTLEMENT_CONTRACT_ADDRESS[chainId], abi)
+  const settlementContract = new Contract(
+    COW_PROTOCOL_SETTLEMENT_CONTRACT_ADDRESS[chainId],
+    abi,
+    provider   // or signer
+  )
content/tutorial/02-advanced-orders/03-pre-signed-orders/03-cancel-pre-signed-order/app-a/src/lib/run.ts (1)

104-104: Pass a signer or provider to Contract

Without the third argument ethers.Contract can’t send transactions.

- const settlementContract = new Contract(COW_PROTOCOL_SETTLEMENT_CONTRACT_ADDRESS[chainId], abi)
+ const settlementContract = new Contract(
+   COW_PROTOCOL_SETTLEMENT_CONTRACT_ADDRESS[chainId],
+   abi,
+   signer
+ )
🧹 Nitpick comments (56)
content/tutorial/03-umbrella-sdk/02-individual-packages/meta.json (1)

3-6: Align scope prefix/name for clarity

prefix targets /src/lib/ while name is src. To avoid confusion in the UI, broaden the prefix to cover the entire src tree.

Apply:

   "scope": {
-    "prefix": "/src/lib/",
-    "name": "src"
+    "prefix": "/src/",
+    "name": "src"
   },
content/tutorial/00-setup/tsconfig.json (1)

4-9: Wildcard path mapping may mask local modules.

Redirecting every import to ../common/node_modules/* can inadvertently hide typos or local module resolutions. Consider narrowing the pattern or adding "paths" only for the specific shared packages you intend to hoist.

content/tutorial/00-setup/00-getting-started/app-a/src/lib/run.ts (1)

3-6: Implement or clarify placeholder run logic.

run now returns {} typed as unknown, which provides no instructional value and can hide type-checking errors. Either:

  1. Change the return type to void until real logic is added, or
  2. Flesh out a minimal example (e.g., echo provider network) so readers see a working snippet.
content/tutorial/01-simple-orders/01-order/01-approve-sell-token-order/app-a/src/lib/run.ts (1)

3-6: Make the run() return type explicit (avoid Promise).

Returning an empty object is fine as a placeholder, but the unknown return type is ambiguous. Prefer a concrete type alias or void for clarity and consistency.

Apply one of the following:

Option A: Keep the empty object but type it:

 export async function run(provider: Web3Provider): Promise<unknown> {
   // TODO: Implement
-  return {}
+  type RunResult = Record<string, never>
+  return {} as RunResult
 }

Option B: Return nothing (void):

-export async function run(provider: Web3Provider): Promise<unknown> {
+export async function run(provider: Web3Provider): Promise<void> {
   // TODO: Implement
-  return {}
+  return
 }
content/tutorial/02-advanced-orders/01-eth-flow/03-cancel-eth-flow/app-a/src/lib/run.ts (1)

29-31: Prefer a concrete result type or Promise over returning {}.

For tutorial consistency, either:

  • Keep Promise<void> and return nothing, or
  • Define a RunResult type with the fields you intend to surface later.
-export async function run(provider: Web3Provider): Promise<unknown> {
+export async function run(provider: Web3Provider): Promise<void> {
 ...
-    return {}
+    return
 }
content/tutorial/01-simple-orders/01-order/02-quote-order/app-a/src/lib/run.ts (2)

4-4: Clarify next step in TODO (quote order).

Consider specifying the intended implementation here (e.g., instantiate OrderBookApi and call quote endpoint) to guide readers. I can draft it when you’re ready.


5-5: Narrow the return type for consistency.

Returning {} is fine as a placeholder, but defining an explicit result type improves tutorial clarity and future refactors.

Apply this small refactor:

-import type { Web3Provider } from '@ethersproject/providers'
+import type { Web3Provider } from '@ethersproject/providers'
+
+type RunResult = Record<string, never>;
 
-export async function run(provider: Web3Provider): Promise<unknown> {
+export async function run(provider: Web3Provider): Promise<RunResult> {
   // TODO: Implement
   return {}
 }
content/tutorial/01-simple-orders/01-order/06-cancel-off-chain-order/README.md (2)

44-44: Remove stray diff markers from code snippet.

The +++ ... +++ around the import will confuse readers and break copy/paste.

Use this corrected line in the snippet:

-+++import { SupportedChainId, OrderBookApi, OrderSigningUtils } from '@cowprotocol/cow-sdk';+++
+import { SupportedChainId, OrderBookApi, OrderSigningUtils } from '@cowprotocol/cow-sdk';

13-16: Add adapter setup to match the new SDK pattern.

You mention configuring the signer, but with provider adapters now standard, show setting the global adapter for coherence with the rest of the tutorials.

Consider adding a short snippet prior to usage:

import { setGlobalAdapter } from '@cowprotocol/cow-sdk';
import { EthersV5Adapter } from '@cowprotocol/sdk-ethers-v5-adapter';

// ...
const signer = provider.getSigner();
const adapter = new EthersV5Adapter({ provider, signer });
setGlobalAdapter(adapter);
content/tutorial/02-advanced-orders/01-eth-flow/02-view-eth-flow/app-b/src/lib/run.ts (1)

29-37: Make log parsing resilient to unrelated events.

iface.parseLog(log) throws if the log’s topics don’t match any ABI event. Wrap in try/catch to skip safely.

-  const ethFlowOrderUids: string[] = receipt.logs.reduce((orderIds, log) => {
+  const ethFlowOrderUids: string[] = receipt.logs.reduce((orderIds, log) => {
     if (log.address !== ethFlowAddress) {
       return orderIds;
     }
 
-    const parsedLog = iface.parseLog(log);
-    if (parsedLog.name === 'OrderPlacement') {
-      const [, order, ,] = parsedLog.args;
-
-      orderIds.push(ethFlowOrderUid(order));
-    }
+    try {
+      const parsedLog = iface.parseLog(log);
+      if (parsedLog.name === 'OrderPlacement') {
+        const [, order] = parsedLog.args;
+        orderIds.push(ethFlowOrderUid(order));
+      }
+    } catch {
+      // Skip logs not in the ABI
+    }
 
     return orderIds;
   }, []);
content/tutorial/01-simple-orders/02-app-data/04-view-app-data/app-b/src/lib/run.ts (1)

4-4: Provider param is unused.

Either remove the provider argument from run() or use it (e.g., derive chainId dynamically for consistency with other steps).

content/tutorial/02-advanced-orders/01-eth-flow/02-view-eth-flow/app-a/src/lib/run.ts (1)

12-13: Remove or defer unused variables until implementation.

iface and ethFlowAddress are currently unused. Trim to reduce noise until the TODO is implemented.

-  const ethFlowAddress = '0x40A50cf069e992AA4536211B23F286eF88752187';
-  const iface = new utils.Interface(abi);
+  // const ethFlowAddress = '0x40A50cf069e992AA4536211B23F286eF88752187';
+  // const iface = new utils.Interface(abi);
content/tutorial/00-setup/01-provider-adapters/app-b/src/lib/run.ts (1)

2-2: Fix import spacing for consistency.

Minor style nit to align with the rest of the repo.

-import { setGlobalAdapter , getGlobalAdapter} from '@cowprotocol/cow-sdk'
+import { setGlobalAdapter, getGlobalAdapter } from '@cowprotocol/cow-sdk'
content/tutorial/03-umbrella-sdk/02-individual-packages/02-advanced-usage/app-a/src/lib/run.ts (3)

12-15: Prefer explicit hex-to-int parsing for chainId instead of unary plus

Using unary plus on the result of eth_chainId relies on implicit coercion. Be explicit and robust to both hex string and numeric responses.

- const chainId = +(await provider.send('eth_chainId', []));
+ const chainIdHex = await provider.send('eth_chainId', []);
+ const chainId = typeof chainIdHex === 'string' ? parseInt(chainIdHex, 16) : chainIdHex;

2-9: If you plan to use OrderSigningUtils (or any global adapter consumer), set the global adapter

Several tutorials in this PR set a global adapter for utilities that read it implicitly. If that’s the intended pattern here, add setGlobalAdapter(adapter) after constructing the adapter.

 import {
 	OrderBookApi,
 	MetadataApi,
 	OrderSigningUtils,
 	SupportedChainId,
-	OrderQuoteSideKindSell
+	OrderQuoteSideKindSell,
+	setGlobalAdapter
 } from '@cowprotocol/cow-sdk';
@@
 const signer = provider.getSigner();
 const adapter = new EthersV5Adapter({ provider, signer });
+setGlobalAdapter(adapter);

If instead you’ll instantiate utilities with the adapter directly (no global state), feel free to ignore this.

Also applies to: 17-23


24-29: Complete the workflow or reference the implemented example

This file is a scaffold. Consider either:

  • Implementing the steps (get app data via MetadataApi, request quote via OrderBookApi, sign with OrderSigningUtils), or
  • Linking to the completed “app-b” variant so readers know where to see the full flow.

I can mirror the “app-b” flow here once you confirm whether to use global or per-instance utilities.

content/tutorial/03-umbrella-sdk/02-individual-packages/01-basic-usage/app-a/src/lib/run.ts (2)

5-8: Parse chainId explicitly from hex

Be explicit when converting eth_chainId to a number to avoid implicit coercion pitfalls.

- const chainId = +(await provider.send('eth_chainId', []));
+ const chainIdHex = await provider.send('eth_chainId', []);
+ const chainId = typeof chainIdHex === 'string' ? parseInt(chainIdHex, 16) : chainIdHex;

10-13: Initialize OrderBookApi so the example actually demonstrates basic usage

Instantiate the API now; you can keep the method calls as follow-ups if you prefer.

- // TODO: Initialize OrderBookApi individually
- // TODO: Test basic functionality
+ // Initialize OrderBookApi individually
+ const orderBookApi = new OrderBookApi({ chainId });
+ // TODO: Use orderBookApi (e.g., fetch an order by UID) and return a meaningful result

If you want, I can add a minimal call (e.g., get an order by UID) consistent with other examples in this tutorial section.

content/tutorial/03-umbrella-sdk/01-unified-approach/01-simple-setup/app-b/src/lib/run.ts (2)

6-9: Use explicit hex-to-int parsing for chainId

Same note as other files—be explicit when converting eth_chainId.

- const chainId = +(await provider.send('eth_chainId', []));
+ const chainIdHex = await provider.send('eth_chainId', []);
+ const chainId = typeof chainIdHex === 'string' ? parseInt(chainIdHex, 16) : chainIdHex;

29-31: Optionally guard the order fetch for a better tutorial UX

Wrap the fetch with try/catch to avoid unhandled rejections in the UI if the UID is invalid or the network is down.

- const order = await cowSdk.orderBook.getOrder(testOrderUid);
- return { order };
+ try {
+   const order = await cowSdk.orderBook.getOrder(testOrderUid);
+   return { order };
+ } catch (e) {
+   return { error: `Failed to fetch order: ${(e as Error).message}` };
+ }
content/tutorial/02-advanced-orders/01-eth-flow/02-view-eth-flow/README.md (2)

73-75: Handle the case where getTransactionReceipt returns null

On ethers v5, getTransactionReceipt can return null if the tx is not yet mined or unknown. Add a guard to make the tutorial more robust.

- const receipt = await provider.getTransactionReceipt(txHash);
+ const receipt = await provider.getTransactionReceipt(txHash);
+ if (!receipt) {
+   throw new Error('Transaction receipt not found. Ensure the txHash is valid on the connected chain and the tx is mined.');
+ }

89-96: Make log filtering and arg access more robust

  • Compare addresses using checksum-normalized values to avoid case mismatches.
  • Prefer named args when available to avoid brittle positional destructuring.
- if (log.address !== ethFlowAddress) {
+ if (utils.getAddress(log.address) !== utils.getAddress(ethFlowAddress)) {
   return orderIds;
 }
 
 const parsedLog = iface.parseLog(log);
 if (parsedLog.name === 'OrderPlacement') {
-  const [, order, ,] = parsedLog.args;
+  const order = (parsedLog.args.order ?? parsedLog.args[1]) as any;
 
   orderIds.push(ethFlowOrderUid(order));
 }
 
 return orderIds;

Also applies to: 98-102

content/tutorial/03-umbrella-sdk/01-unified-approach/02-complete-workflow/app-a/src/lib/run.ts (1)

6-9: Clarify chainId conversion

provider.send('eth_chainId', []) returns a hex string (e.g. "0x64").
Unary + works but relies on implicit radix detection; parseInt(hex, 16) is clearer and immune to edge-case surprises in strict lint setups.

-const chainId = +(await provider.send('eth_chainId', []));
+const chainIdHex = await provider.send('eth_chainId', []);
+const chainId = parseInt(chainIdHex, 16);
content/tutorial/01-simple-orders/01-order/03-sign-order/app-b/src/lib/run.ts (1)

14-19: Return value of setupAdapter

adapter is returned but never used by the caller; if future examples won’t need it, drop it from the return signature to keep the helper minimal.

-return { signer, adapter };
+return { signer };

(or use the adapter downstream)

content/tutorial/01-simple-orders/01-order/03-sign-order/app-a/src/lib/run.ts (1)

30-33: Optional: keep constants in one place

The same hard-coded token addresses/sell amount appear across many tutorial files.
Extracting them into a shared constants module reduces duplication and risk of inconsistent edits later.

content/tutorial/03-umbrella-sdk/02-individual-packages/02-advanced-usage/README.md (1)

30-37: Missing import for EthersV5Adapter

The snippet uses new EthersV5Adapter but the import statement is absent. Add for copy-paste completeness:

import { EthersV5Adapter } from '@cowprotocol/sdk-ethers-v5-adapter';
content/tutorial/03-umbrella-sdk/01-unified-approach/02-complete-workflow/README.md (1)

63-69: Order of operations in example

chainId constant is set after it’s needed to construct CowSdk (which also takes chainId). Move const chainId = SupportedChainId.GNOSIS_CHAIN; above the adapter creation for clearer flow.

content/tutorial/01-simple-orders/01-order/04-submit-order/app-a/src/lib/run.ts (1)

21-61: Return the concrete signed-order type instead of unknown

OrderSigningUtils.signOrder() returns a SignedOrder (or similar) – exposing that type here improves downstream type-safety and IDE support.

-export async function run(provider: Web3Provider): Promise<unknown> {
+export async function run(provider: Web3Provider): Promise<SignedOrder> {
content/tutorial/01-simple-orders/02-app-data/03-orderbook-upload-app-data/app-b/src/lib/run.ts (1)

47-52: You compute cid but never use it

getAppDataInfo() now returns { cid, … } yet cid is discarded. If the CID is meant to be surfaced to the UI or logged, please return or log it; otherwise remove it from the destructuring.

content/tutorial/02-advanced-orders/03-pre-signed-orders/01-create-pre-signed-order/app-b/src/lib/run.ts (1)

54-57: Reuse the signer returned by setupAdapter

You already obtain a signer via setupAdapter. Calling provider.getSigner() again is redundant and risks diverging signers if a different account is selected later.

content/tutorial/01-simple-orders/01-order/06-cancel-off-chain-order/app-a/src/lib/run.ts (2)

19-23: Initialise the adapter before creating OrderBookApi for consistency

As in other examples, move setupAdapter above the API construction; this guarantees the global adapter is always in place.

-	const orderBookApi = new OrderBookApi({ chainId: SupportedChainId.GNOSIS_CHAIN });
-	const { signer } = setupAdapter(provider);
+	const { signer } = setupAdapter(provider);
+	const orderBookApi = new OrderBookApi({ chainId: SupportedChainId.GNOSIS_CHAIN });

21-24: Function currently does nothing – consider implementing or marking TODO

run() returns an empty object. If cancellation logic is planned add a TODO; otherwise the tutorial step might confuse readers.

content/tutorial/01-simple-orders/02-app-data/01-simple-app-data/app-a/src/lib/run.ts (2)

19-21: Unimplemented code path

A TODO comment is present and the function returns {}. Either implement the sample or link to the next tutorial section to avoid dead-end code.


13-15: Expose explicit return type instead of unknown

Even if the body is TBD, declaring a concrete return type sets expectations for implementers.

content/tutorial/01-simple-orders/01-order/06-cancel-off-chain-order/app-b/src/lib/run.ts (2)

10-16: Avoid resetting the global adapter on every run() call

setupAdapter() calls setGlobalAdapter() each time the tutorial is executed. If the playground re-invokes run() (e.g. hot-reload, multiple components), the global singleton keeps being replaced, which may break stateful caches inside other SDK classes.

-export function setupAdapter(provider: Web3Provider) {
+let cachedAdapter: EthersV5Adapter | undefined;
+export function setupAdapter(provider: Web3Provider) {
   const signer = provider.getSigner();
-  const adapter = new EthersV5Adapter({ provider, signer });
-  setGlobalAdapter(adapter);
-  return { signer, adapter };
+  if (!cachedAdapter) {
+    cachedAdapter = new EthersV5Adapter({ provider, signer });
+    setGlobalAdapter(cachedAdapter);
+  }
+  return { signer, adapter: cachedAdapter };
}

18-26: Narrow the return type

The function returns either { cancellationsResult } or the error object. Prefer a discriminated union so callers can handle both cases safely.

export async function run(provider: Web3Provider): Promise<
  | { kind: 'ok'; cancellationsResult: unknown }
  | { kind: 'error'; error: unknown }
> {  }
content/tutorial/03-umbrella-sdk/02-individual-packages/01-basic-usage/README.md (2)

33-50: Code snippet is missing chainId definition

new OrderBookApi({ chainId }) will not compile as chainId is undefined in the snippet.

-import type { Web3Provider } from '@ethersproject/providers';
+import type { Web3Provider } from '@ethersproject/providers';
+
+const chainId = SupportedChainId.GNOSIS_CHAIN; // or derive from the provider

47-66: Adapter not made globally available

Later tutorials rely on MetadataApi picking up the global adapter. Either call setGlobalAdapter(adapter) here or mention that some packages (e.g. OrderSigningUtils) will require it.

content/tutorial/03-umbrella-sdk/02-individual-packages/01-basic-usage/app-b/src/lib/run.ts (2)

11-17: Consider registering the adapter globally

If another SDK helper (e.g. OrderSigningUtils) gets added later, it will look for getGlobalAdapter(). A one-liner keeps future snippets consistent:

import { setGlobalAdapter } from '@cowprotocol/cow-sdk';

setGlobalAdapter(adapter);

43-47: Return the actual error for easier debugging

Swallowing the exception hides valuable info.

-  } catch (error) {
-    return {
-      error: 'Test order not found, but packages initialized correctly'
-    };
+  } catch (error) {
+    return { error };
   }
content/tutorial/01-simple-orders/02-app-data/02-create-order-app-data/README.md (1)

47-48: Strip +++ diff markers from code blocks

The +++ prefixes are rendered literally and will cause copy-pasted code to fail.

-        +++appData: appDataContent,+++
-        +++appDataHash: appDataHex,+++
+        appData: appDataContent,
+        appDataHash: appDataHex,-        +++appData: appDataHex,+++
+        appData: appDataHex,

Also applies to: 67-68

content/tutorial/01-simple-orders/02-app-data/03-orderbook-upload-app-data/app-a/src/lib/run.ts (2)

11-17: Return type is implicit – please make it explicit

Explicitly annotate the return type of setupAdapter() (e.g. { signer: JsonRpcSigner; adapter: EthersV5Adapter }) to help IDEs and future readers.


30-31: TODO left in production tutorial code

// TODO: Generate app data document and upload to API plus returning an empty object leaves the example non-functional. Either implement the missing logic or add a short note explaining that the snippet is intentionally partial.

content/tutorial/01-simple-orders/01-order/03-sign-order/README.md (1)

39-50: sellAmount used but never defined in snippet

The code builds an UnsignedOrder with sellAmount, yet the snippet never assigns that variable (only a comment above mentions it). Add the definition to avoid copy-paste confusion.

content/tutorial/01-simple-orders/02-app-data/04-view-app-data/README.md (2)

16-20: provider parameter is unused

The run(provider: Web3Provider) signature suggests the function needs a provider, but the body doesn’t reference it. Either use the provider (e.g. for chain-ID validation) or drop the parameter to keep the example minimal.


77-90: Hard tabs trigger markdown-lint MD010

Replace the leading tab characters in the JSON block with spaces to satisfy Markdown linters and keep formatting consistent.

content/tutorial/00-setup/01-provider-adapters/README.md (1)

1-160: Replace hard tabs with spaces across the file

markdownlint reports multiple MD010 violations. Converting indentation to spaces prevents lint noise and keeps style consistent with the rest of the docs.

content/tutorial/01-simple-orders/02-app-data/02-create-order-app-data/app-b/src/lib/run.ts (1)

52-54: Unused variable cid

cid returned from getAppDataInfo() is never referenced. If it’s intentionally ignored, prefix with _ or remove it to avoid dead-code warnings.

content/tutorial/03-umbrella-sdk/01-unified-approach/02-complete-workflow/app-b/src/lib/run.ts (1)

1-8: latest import is unused

If noUnusedLocals is enabled the build will fail.

-import { … , latest, UnsignedOrder } from '@cowprotocol/cow-sdk';
+import { … , UnsignedOrder } from '@cowprotocol/cow-sdk';
content/tutorial/02-advanced-orders/03-pre-signed-orders/03-cancel-pre-signed-order/app-a/src/lib/run.ts (1)

30-31: Hex string required for wallet_switchEthereumChain

Same fix as suggested in the ETH-flow tutorial.

content/tutorial/02-advanced-orders/03-pre-signed-orders/01-create-pre-signed-order/app-a/src/lib/run.ts (1)

21-22: Switch network with hex id

- await provider.send('wallet_switchEthereumChain', [{ chainId: SupportedChainId.GNOSIS_CHAIN }]);
+ await provider.send('wallet_switchEthereumChain', [{ chainId: '0x64' }]);
content/tutorial/03-umbrella-sdk/02-individual-packages/02-advanced-usage/app-b/src/lib/run.ts (2)

13-16: Chain ID conversion works; consider ethers-native alternative

+await provider.send('eth_chainId') works with hex strings. Optionally prefer const { chainId } = await provider.getNetwork() for v5 providers to avoid raw RPC calls.


75-77: Harden error handling for unknown error types

In some TS configs, catch (error) is unknown. Safely serialize the error to avoid error.message access issues.

-  } catch (error) {
-    return { error: error.message };
-  }
+  } catch (err) {
+    const message =
+      err instanceof Error
+        ? err.message
+        : typeof err === 'string'
+        ? err
+        : JSON.stringify(err);
+    return { error: message };
+  }
content/tutorial/01-simple-orders/02-app-data/03-orderbook-upload-app-data/README.md (1)

86-86: Replace hard tab in JSON example (MD010)

Remove the hard tab in the JSON snippet to satisfy markdownlint.

content/tutorial/02-advanced-orders/01-eth-flow/01-create-eth-flow/README.md (1)

79-79: Fix formatting: Replace hard tabs with spaces.

The markdown content uses hard tabs instead of spaces for indentation, which violates markdown formatting standards.

Apply consistent spacing instead of hard tabs for proper markdown formatting.

Also applies to: 106-109, 168-184

content/tutorial/02-advanced-orders/03-pre-signed-orders/01-create-pre-signed-order/README.md (1)

21-21: Fix formatting: Replace hard tabs with spaces.

Similar to the previous file, hard tabs should be replaced with spaces for proper markdown formatting.

Apply consistent spacing throughout the markdown content.

Also applies to: 49-53

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5414e59 and a59318a.

⛔ Files ignored due to path filters (1)
  • content/tutorial/common/yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (59)
  • content/tutorial/00-setup/00-getting-started/app-a/src/lib/run.ts (1 hunks)
  • content/tutorial/00-setup/01-provider-adapters/README.md (1 hunks)
  • content/tutorial/00-setup/01-provider-adapters/app-a/src/lib/run.ts (1 hunks)
  • content/tutorial/00-setup/01-provider-adapters/app-b/src/lib/run.ts (1 hunks)
  • content/tutorial/00-setup/01-provider-adapters/meta.json (1 hunks)
  • content/tutorial/00-setup/meta.json (1 hunks)
  • content/tutorial/00-setup/tsconfig.json (1 hunks)
  • content/tutorial/01-simple-orders/01-order/01-approve-sell-token-order/app-a/src/lib/run.ts (1 hunks)
  • content/tutorial/01-simple-orders/01-order/02-quote-order/app-a/src/lib/run.ts (1 hunks)
  • content/tutorial/01-simple-orders/01-order/03-sign-order/README.md (4 hunks)
  • content/tutorial/01-simple-orders/01-order/03-sign-order/app-a/src/lib/run.ts (1 hunks)
  • content/tutorial/01-simple-orders/01-order/03-sign-order/app-b/src/lib/run.ts (1 hunks)
  • content/tutorial/01-simple-orders/01-order/04-submit-order/README.md (2 hunks)
  • content/tutorial/01-simple-orders/01-order/04-submit-order/app-a/src/lib/run.ts (1 hunks)
  • content/tutorial/01-simple-orders/01-order/04-submit-order/app-b/src/lib/run.ts (1 hunks)
  • content/tutorial/01-simple-orders/01-order/06-cancel-off-chain-order/README.md (3 hunks)
  • content/tutorial/01-simple-orders/01-order/06-cancel-off-chain-order/app-a/src/lib/run.ts (1 hunks)
  • content/tutorial/01-simple-orders/01-order/06-cancel-off-chain-order/app-b/src/lib/run.ts (1 hunks)
  • content/tutorial/01-simple-orders/02-app-data/01-simple-app-data/README.md (4 hunks)
  • content/tutorial/01-simple-orders/02-app-data/01-simple-app-data/app-a/src/lib/run.ts (1 hunks)
  • content/tutorial/01-simple-orders/02-app-data/01-simple-app-data/app-b/src/lib/run.ts (1 hunks)
  • content/tutorial/01-simple-orders/02-app-data/02-create-order-app-data/README.md (2 hunks)
  • content/tutorial/01-simple-orders/02-app-data/02-create-order-app-data/app-a/src/lib/run.ts (1 hunks)
  • content/tutorial/01-simple-orders/02-app-data/02-create-order-app-data/app-b/src/lib/run.ts (1 hunks)
  • content/tutorial/01-simple-orders/02-app-data/03-orderbook-upload-app-data/README.md (2 hunks)
  • content/tutorial/01-simple-orders/02-app-data/03-orderbook-upload-app-data/app-a/src/lib/run.ts (1 hunks)
  • content/tutorial/01-simple-orders/02-app-data/03-orderbook-upload-app-data/app-b/src/lib/run.ts (1 hunks)
  • content/tutorial/01-simple-orders/02-app-data/04-view-app-data/README.md (2 hunks)
  • content/tutorial/01-simple-orders/02-app-data/04-view-app-data/app-a/src/lib/run.ts (1 hunks)
  • content/tutorial/01-simple-orders/02-app-data/04-view-app-data/app-b/src/lib/run.ts (1 hunks)
  • content/tutorial/02-advanced-orders/01-eth-flow/01-create-eth-flow/README.md (5 hunks)
  • content/tutorial/02-advanced-orders/01-eth-flow/01-create-eth-flow/app-a/src/lib/run.ts (1 hunks)
  • content/tutorial/02-advanced-orders/01-eth-flow/01-create-eth-flow/app-b/src/lib/run.ts (1 hunks)
  • content/tutorial/02-advanced-orders/01-eth-flow/02-view-eth-flow/README.md (2 hunks)
  • content/tutorial/02-advanced-orders/01-eth-flow/02-view-eth-flow/app-a/src/lib/run.ts (1 hunks)
  • content/tutorial/02-advanced-orders/01-eth-flow/02-view-eth-flow/app-b/src/lib/run.ts (1 hunks)
  • content/tutorial/02-advanced-orders/01-eth-flow/03-cancel-eth-flow/app-a/src/lib/run.ts (1 hunks)
  • content/tutorial/02-advanced-orders/01-eth-flow/03-cancel-eth-flow/app-b/src/lib/run.ts (1 hunks)
  • content/tutorial/02-advanced-orders/03-pre-signed-orders/01-create-pre-signed-order/README.md (13 hunks)
  • content/tutorial/02-advanced-orders/03-pre-signed-orders/01-create-pre-signed-order/app-a/src/lib/run.ts (2 hunks)
  • content/tutorial/02-advanced-orders/03-pre-signed-orders/01-create-pre-signed-order/app-b/src/lib/run.ts (5 hunks)
  • content/tutorial/02-advanced-orders/03-pre-signed-orders/03-cancel-pre-signed-order/app-a/src/lib/run.ts (5 hunks)
  • content/tutorial/03-umbrella-sdk/01-unified-approach/01-simple-setup/README.md (1 hunks)
  • content/tutorial/03-umbrella-sdk/01-unified-approach/01-simple-setup/app-a/src/lib/run.ts (1 hunks)
  • content/tutorial/03-umbrella-sdk/01-unified-approach/01-simple-setup/app-b/src/lib/run.ts (1 hunks)
  • content/tutorial/03-umbrella-sdk/01-unified-approach/02-complete-workflow/README.md (1 hunks)
  • content/tutorial/03-umbrella-sdk/01-unified-approach/02-complete-workflow/app-a/src/lib/run.ts (1 hunks)
  • content/tutorial/03-umbrella-sdk/01-unified-approach/02-complete-workflow/app-b/src/lib/run.ts (1 hunks)
  • content/tutorial/03-umbrella-sdk/01-unified-approach/meta.json (1 hunks)
  • content/tutorial/03-umbrella-sdk/02-individual-packages/01-basic-usage/README.md (1 hunks)
  • content/tutorial/03-umbrella-sdk/02-individual-packages/01-basic-usage/app-a/src/lib/run.ts (1 hunks)
  • content/tutorial/03-umbrella-sdk/02-individual-packages/01-basic-usage/app-b/src/lib/run.ts (1 hunks)
  • content/tutorial/03-umbrella-sdk/02-individual-packages/02-advanced-usage/README.md (1 hunks)
  • content/tutorial/03-umbrella-sdk/02-individual-packages/02-advanced-usage/app-a/src/lib/run.ts (1 hunks)
  • content/tutorial/03-umbrella-sdk/02-individual-packages/02-advanced-usage/app-b/src/lib/run.ts (1 hunks)
  • content/tutorial/03-umbrella-sdk/02-individual-packages/meta.json (1 hunks)
  • content/tutorial/03-umbrella-sdk/meta.json (1 hunks)
  • content/tutorial/03-umbrella-sdk/tsconfig.json (1 hunks)
  • content/tutorial/common/package.json (1 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
content/tutorial/01-simple-orders/01-order/06-cancel-off-chain-order/README.md

79-79: Hard tabs
Column: 1

(MD010, no-hard-tabs)


80-80: Hard tabs
Column: 1

(MD010, no-hard-tabs)


82-82: Hard tabs
Column: 1

(MD010, no-hard-tabs)

content/tutorial/01-simple-orders/02-app-data/03-orderbook-upload-app-data/README.md

86-86: Hard tabs
Column: 1

(MD010, no-hard-tabs)

content/tutorial/03-umbrella-sdk/01-unified-approach/01-simple-setup/README.md

16-16: Hard tabs
Column: 1

(MD010, no-hard-tabs)


17-17: Hard tabs
Column: 1

(MD010, no-hard-tabs)


18-18: Hard tabs
Column: 1

(MD010, no-hard-tabs)


19-19: Hard tabs
Column: 1

(MD010, no-hard-tabs)


20-20: Hard tabs
Column: 1

(MD010, no-hard-tabs)


21-21: Hard tabs
Column: 1

(MD010, no-hard-tabs)


22-22: Hard tabs
Column: 1

(MD010, no-hard-tabs)


33-33: Hard tabs
Column: 1

(MD010, no-hard-tabs)


34-34: Hard tabs
Column: 1

(MD010, no-hard-tabs)


35-35: Hard tabs
Column: 1

(MD010, no-hard-tabs)


36-36: Hard tabs
Column: 1

(MD010, no-hard-tabs)


37-37: Hard tabs
Column: 1

(MD010, no-hard-tabs)


38-38: Hard tabs
Column: 1

(MD010, no-hard-tabs)


39-39: Hard tabs
Column: 1

(MD010, no-hard-tabs)


40-40: Hard tabs
Column: 1

(MD010, no-hard-tabs)


49-49: Hard tabs
Column: 1

(MD010, no-hard-tabs)


50-50: Hard tabs
Column: 1

(MD010, no-hard-tabs)


51-51: Hard tabs
Column: 1

(MD010, no-hard-tabs)


52-52: Hard tabs
Column: 1

(MD010, no-hard-tabs)


53-53: Hard tabs
Column: 1

(MD010, no-hard-tabs)

content/tutorial/01-simple-orders/02-app-data/04-view-app-data/README.md

79-79: Hard tabs
Column: 1

(MD010, no-hard-tabs)


80-80: Hard tabs
Column: 1

(MD010, no-hard-tabs)


81-81: Hard tabs
Column: 1

(MD010, no-hard-tabs)


82-82: Hard tabs
Column: 1

(MD010, no-hard-tabs)


83-83: Hard tabs
Column: 1

(MD010, no-hard-tabs)


84-84: Hard tabs
Column: 1

(MD010, no-hard-tabs)


85-85: Hard tabs
Column: 1

(MD010, no-hard-tabs)


86-86: Hard tabs
Column: 1

(MD010, no-hard-tabs)


87-87: Hard tabs
Column: 1

(MD010, no-hard-tabs)


88-88: Hard tabs
Column: 1

(MD010, no-hard-tabs)


89-89: Hard tabs
Column: 1

(MD010, no-hard-tabs)

content/tutorial/01-simple-orders/02-app-data/01-simple-app-data/README.md

71-71: Hard tabs
Column: 1

(MD010, no-hard-tabs)


73-73: Hard tabs
Column: 1

(MD010, no-hard-tabs)


74-74: Hard tabs
Column: 1

(MD010, no-hard-tabs)


87-87: Hard tabs
Column: 1

(MD010, no-hard-tabs)


89-89: Hard tabs
Column: 1

(MD010, no-hard-tabs)


102-102: Hard tabs
Column: 1

(MD010, no-hard-tabs)

content/tutorial/02-advanced-orders/03-pre-signed-orders/01-create-pre-signed-order/README.md

21-21: Hard tabs
Column: 1

(MD010, no-hard-tabs)


49-49: Hard tabs
Column: 1

(MD010, no-hard-tabs)


50-50: Hard tabs
Column: 1

(MD010, no-hard-tabs)


51-51: Hard tabs
Column: 1

(MD010, no-hard-tabs)


52-52: Hard tabs
Column: 1

(MD010, no-hard-tabs)


53-53: Hard tabs
Column: 1

(MD010, no-hard-tabs)

content/tutorial/02-advanced-orders/01-eth-flow/01-create-eth-flow/README.md

79-79: Hard tabs
Column: 1

(MD010, no-hard-tabs)


106-106: Hard tabs
Column: 1

(MD010, no-hard-tabs)


107-107: Hard tabs
Column: 1

(MD010, no-hard-tabs)


109-109: Hard tabs
Column: 1

(MD010, no-hard-tabs)


168-168: Hard tabs
Column: 1

(MD010, no-hard-tabs)


169-169: Hard tabs
Column: 1

(MD010, no-hard-tabs)


170-170: Hard tabs
Column: 1

(MD010, no-hard-tabs)


171-171: Hard tabs
Column: 1

(MD010, no-hard-tabs)


172-172: Hard tabs
Column: 1

(MD010, no-hard-tabs)


173-173: Hard tabs
Column: 1

(MD010, no-hard-tabs)


174-174: Hard tabs
Column: 1

(MD010, no-hard-tabs)


175-175: Hard tabs
Column: 1

(MD010, no-hard-tabs)


176-176: Hard tabs
Column: 1

(MD010, no-hard-tabs)


177-177: Hard tabs
Column: 1

(MD010, no-hard-tabs)


178-178: Hard tabs
Column: 1

(MD010, no-hard-tabs)


179-179: Hard tabs
Column: 1

(MD010, no-hard-tabs)


180-180: Hard tabs
Column: 1

(MD010, no-hard-tabs)


181-181: Hard tabs
Column: 1

(MD010, no-hard-tabs)


182-182: Hard tabs
Column: 1

(MD010, no-hard-tabs)


183-183: Hard tabs
Column: 1

(MD010, no-hard-tabs)


184-184: Hard tabs
Column: 1

(MD010, no-hard-tabs)

🪛 Gitleaks (8.27.2)
content/tutorial/01-simple-orders/01-order/03-sign-order/app-b/src/lib/run.ts

32-32: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


33-33: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

content/tutorial/01-simple-orders/01-order/03-sign-order/app-a/src/lib/run.ts

30-30: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


31-31: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

content/tutorial/01-simple-orders/02-app-data/02-create-order-app-data/app-a/src/lib/run.ts

56-56: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


57-57: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

content/tutorial/03-umbrella-sdk/01-unified-approach/02-complete-workflow/app-a/src/lib/run.ts

30-30: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


31-31: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

content/tutorial/03-umbrella-sdk/02-individual-packages/02-advanced-usage/app-b/src/lib/run.ts

41-41: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


42-42: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

content/tutorial/01-simple-orders/02-app-data/02-create-order-app-data/app-b/src/lib/run.ts

56-56: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


57-57: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

content/tutorial/03-umbrella-sdk/01-unified-approach/02-complete-workflow/app-b/src/lib/run.ts

30-30: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


31-31: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🪛 LanguageTool
content/tutorial/03-umbrella-sdk/02-individual-packages/01-basic-usage/README.md

[grammar] ~17-~17: Ensure spelling is correct
Context: ...ustom rate limits, URLs, etc. ### 📋 MetadataApi Generates and processes app data: - *...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🔇 Additional comments (38)
content/tutorial/00-setup/01-provider-adapters/meta.json (1)

1-8: Looks good – no issues found.

content/tutorial/00-setup/meta.json (1)

1-8: Metadata OK.

content/tutorial/02-advanced-orders/01-eth-flow/03-cancel-eth-flow/app-b/src/lib/run.ts (1)

54-55: Nit: whitespace fix acknowledged.

content/tutorial/03-umbrella-sdk/meta.json (1)

1-8: LGTM: metadata structure is consistent.

Title, scope, and focus keys look aligned with other tutorial entries.

content/tutorial/03-umbrella-sdk/01-unified-approach/meta.json (1)

1-8: LGTM: metadata structure is consistent.

Matches the umbrella SDK conventions for scope and focus.

content/tutorial/01-simple-orders/01-order/03-sign-order/app-b/src/lib/run.ts (1)

32-35: False-positive “API key” warnings

The static-analysis hit is only an Ethereum token address, not a credential. Safe to ignore.

content/tutorial/01-simple-orders/02-app-data/03-orderbook-upload-app-data/app-b/src/lib/run.ts (1)

34-37: slippageBips API expects a string – confirm the numeric literal compiles

Historically latest.Quote.slippageBips is typed as string. Switching from '50' to 50 will break the build if the type definition hasn’t changed in the new SDK. Please re-check the type or convert with String(50).

content/tutorial/03-umbrella-sdk/02-individual-packages/01-basic-usage/README.md (1)

24-28: Minor wording

“eye-ed” → “eyed”.

content/tutorial/01-simple-orders/02-app-data/02-create-order-app-data/app-a/src/lib/run.ts (1)

56-58: False positive from gitleaks

The flagged strings are plain ERC-20 token addresses, not secrets. Safe to keep.

content/tutorial/01-simple-orders/02-app-data/02-create-order-app-data/app-b/src/lib/run.ts (1)

56-57: Gitleaks false positive – addresses, not secrets

The detector flagged the token addresses as “Generic API Key”. They’re public ERC-20 addresses, safe to commit. No action needed.

content/tutorial/03-umbrella-sdk/01-unified-approach/02-complete-workflow/app-b/src/lib/run.ts (1)

29-33: Gitleaks warning is a false positive

The hard-coded token addresses are public ERC-20 contracts, not credentials. Safe to ignore the “generic-api-key” alert.

content/tutorial/02-advanced-orders/03-pre-signed-orders/01-create-pre-signed-order/app-a/src/lib/run.ts (1)

49-51: run currently returns an empty object

Add a TODO or implement the remainder of the workflow; exporting an empty result is confusing for learners following the tutorial.

content/tutorial/03-umbrella-sdk/02-individual-packages/02-advanced-usage/app-b/src/lib/run.ts (2)

37-49: Quote payload looks aligned with new appData API; sanity-check token addresses

Passing appData: appDataContent and appDataHash: appDataHex matches the updated flow. Please verify the wxDAI and COW addresses for Gnosis are correct, and consider centralizing them as constants.

Also, gitleaks flagged these lines as "Generic API Key" due to 0x-prefixed strings. If these are known token addresses, mark as false positives or add an allowlist rule in your gitleaks config to ignore 40-byte hex addresses that are not secrets.


60-61: Signing flow LGTM

Using OrderSigningUtils.signOrder(order, chainId, signer) with the constructed UnsignedOrder is correct in this context.

content/tutorial/03-umbrella-sdk/01-unified-approach/01-simple-setup/README.md (2)

28-33: Unified SDK init example looks correct

CowSdk initialized with EthersV5Adapter, SupportedChainId.GNOSIS_CHAIN, and env: 'prod' matches the new umbrella SDK approach.


16-37: No hard tabs detected – no action required

A search for literal \t in content/tutorial/03-umbrella-sdk/01-unified-approach/01-simple-setup/README.md returned no matches. The file already uses spaces exclusively, so the MD010 recommendation can be ignored.

Likely an incorrect or invalid review comment.

content/tutorial/01-simple-orders/02-app-data/03-orderbook-upload-app-data/README.md (2)

16-36: Ensure “+++” inline markers are intended; otherwise they break TypeScript snippets

The code block uses +++ prefixes within a typescript fence. If the site renderer doesn’t support this highlighting syntax, readers will copy invalid TS. Prefer a diff code block for highlighting or remove the markers.

Example using diff:

```diff
- import { OrderBookApi } from '@cowprotocol/...'
+ import { OrderBookApi, MetadataApi, latest, SupportedChainId, setGlobalAdapter } from '@cowprotocol/cow-sdk';
+ import { EthersV5Adapter } from '@cowprotocol/sdk-ethers-v5-adapter';

---

`40-49`: **New app data flow reads well and matches updated API**

- Using `getAppDataInfo()` to obtain `{ cid, appDataHex, appDataContent }` is correct.
- `uploadAppData(appDataHex, appDataContent)` returning the confirmed appData hash (`fullAppData`) is consistent with the new semantics.




Also applies to: 63-67, 72-72

</details>
<details>
<summary>content/tutorial/01-simple-orders/02-app-data/01-simple-app-data/app-b/src/lib/run.ts (2)</summary>

`5-11`: **Global adapter setup is consistent and clear**

`setupAdapter` with `EthersV5Adapter` and `setGlobalAdapter`, then `new MetadataApi()` without params aligns with the new global adapter pattern.




Also applies to: 14-19

---

`24-26`: **Updated types and app data processing look correct**

- `latest.Quote` with numeric `slippageBips: 50` and `latest.OrderClass` are consistent.
- `getAppDataInfo` returning `{ cid, appDataHex, appDataContent }` matches the new API.




Also applies to: 37-44

</details>
<details>
<summary>content/tutorial/01-simple-orders/02-app-data/01-simple-app-data/README.md (3)</summary>

`35-56`: **Good exposition of the global adapter pattern and updated MetadataApi usage**

Examples clearly show:
- Using umbrella package imports
- Global adapter setup
- Environment string as `'production'`
- Transition to `getAppDataInfo` returning CID, hash, and content




Also applies to: 72-91, 99-123, 133-154

---

`38-47`: **Confirm whether “+++” markers are needed in TS code fences**

If not processed by your doc tooling, they will invalidate the snippet when copied. Prefer `diff` fences for highlighting or remove the markers.




Also applies to: 75-77, 102-104, 136-138

---

`71-74`: **No hard tabs detected in README.md; markdownlint MD010 fix not required**

I searched the entire `content/tutorial/01-simple-orders/02-app-data/01-simple-app-data/README.md` and found zero tab characters—there’s nothing to replace. You can ignore this suggestion. 

> Likely an incorrect or invalid review comment.

</details>
<details>
<summary>content/tutorial/02-advanced-orders/01-eth-flow/01-create-eth-flow/README.md (4)</summary>

`29-38`: **LGTM: Consistent adapter setup pattern.**

The `setupAdapter` helper function correctly initializes the EthersV5Adapter and sets it globally. This follows the established pattern across the SDK refactor.

---

`100-109`: **LGTM: Comprehensive imports for EthFlow functionality.**

The expanded imports include all necessary types and APIs for EthFlow order creation, properly using the consolidated `@cowprotocol/cow-sdk` package.

---

`162-183`: **LGTM: Updated app data processing with new API.**

The migration from `appDataToCid()` to `getAppDataInfo()` is correct and provides richer information including the CID alongside hex and content.

---

`196-196`: **LGTM: Proper slippage calculation.**

The slippage calculation using BigNumber arithmetic (0.5% = 9950/10000) is mathematically correct and safe for large numbers.

</details>
<details>
<summary>content/tutorial/02-advanced-orders/03-pre-signed-orders/01-create-pre-signed-order/README.md (3)</summary>

`55-61`: **LGTM: Consistent adapter setup implementation.**

The adapter setup helper function matches the pattern used across other tutorials and correctly initializes the global adapter for MetadataApi usage.

---

`268-289`: **LGTM: Proper app data processing update.**

The migration to `getAppDataInfo()` is implemented correctly, providing the CID along with hex and content data for comprehensive app data handling.

---

`362-364`: **LGTM: Correct PRESIGN order configuration.**

The order fields are properly set for pre-signed orders:
- `from` set to Safe address
- `signature` set to empty bytes (`0x`)
- `signingScheme` set to `SigningScheme.PRESIGN`

</details>
<details>
<summary>content/tutorial/02-advanced-orders/01-eth-flow/01-create-eth-flow/app-b/src/lib/run.ts (8)</summary>

`17-23`: **LGTM: Well-structured adapter setup.**

The helper function properly encapsulates adapter initialization and global setup, returning both signer and adapter for flexibility.

---

`25-30`: **LGTM: Proper EthFlowOrder type definition.**

The type correctly omits fields not required for EthFlow orders and adds the `quoteId` field. The type definition accurately reflects the EthFlow contract requirements.

---

`35-38`: **LGTM: Proper chain handling for Gnosis Chain.**

The chain ID verification and automatic switching to Gnosis Chain ensures the tutorial runs on the correct network where the EthFlow contract is deployed.

---

`58-58`: **LGTM: Updated app data API usage.**

The migration to `getAppDataInfo()` with destructuring assignment is clean and provides the required `cid`, `appDataHex`, and `appDataContent` properties.

---

`75-79`: **LGTM: Proper EthFlow quote configuration.**

The additional fields (`from`, `signingScheme: EIP1271`, `onchainOrder: true`) are correctly set for EthFlow orders that require on-chain signing.

---

`86-86`: **LGTM: Correct slippage calculation.**

The 0.5% slippage calculation using BigNumber arithmetic (mul(9950).div(10000)) is mathematically sound and prevents precision loss.

---

`92-92`: **LGTM: Proper ETH value transfer.**

The contract call correctly includes `{ value: sellAmount }` to send ETH with the transaction, which is required for EthFlow orders.

---

`45-45`: **LGTM: Standardized parameter type.**

The change from `slippageBips: '50'` to `slippageBips: 50` (string to number) standardizes the parameter type across the SDK.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment thread content/tutorial/00-setup/01-provider-adapters/app-a/src/lib/run.ts
Comment thread content/tutorial/00-setup/01-provider-adapters/app-b/src/lib/run.ts
Comment thread content/tutorial/00-setup/01-provider-adapters/app-b/src/lib/run.ts
Comment thread content/tutorial/03-umbrella-sdk/02-individual-packages/meta.json
Comment thread content/tutorial/03-umbrella-sdk/tsconfig.json
Comment thread content/tutorial/common/package.json
@alfetopito
Copy link
Copy Markdown
Contributor

@jeffersonBastos the build failed. Can you take a look?

image

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (8)
content/tutorial/03-umbrella-sdk/01-unified-approach/02-complete-workflow/README.md (3)

32-41: Quote params: ensure appData/appDataHash alignment and type imports

  • After fixing Step 1, appDataContent will be defined; otherwise this snippet fails.
  • Confirm the quote API expects both appData (content) and appDataHash (hex). If only one is required, remove the other to avoid confusion.
  • You reference OrderQuoteSideKindSell.SELL but no import is shown. Add the import or inline the string literal.
-  kind: OrderQuoteSideKindSell.SELL,
+  // import { OrderQuoteSideKindSell } from '@cowprotocol/cow-sdk' (if needed)
+  kind: OrderQuoteSideKindSell.SELL,

Or:

-  kind: OrderQuoteSideKindSell.SELL,
+  kind: 'sell',

82-87: Naming consistency: appDataHex vs appDataHash in output

You return { appDataHash: appDataHex }. Prefer consistent naming to avoid confusion.

-return {
-  appDataHash: appDataHex,
+return {
+  appDataHex,
   expectedBuyAmount: quote.buyAmount,
   signature: signature.signature.substring(0, 20) + '...',
   signingScheme: signature.signingScheme
};

Or rename the variable earlier to appDataHash.


88-90: Type-safe error handling in TS

error can be unknown. Narrow before reading .message.

-} catch (error) {
-  return { error: error.message };
+} catch (error) {
+  const message = error instanceof Error ? error.message : String(error);
+  return { error: message };
}
content/tutorial/03-umbrella-sdk/01-unified-approach/01-simple-setup/README.md (1)

69-77: Signing example clarity

signOrder(order, chainId, signer) assumes order is an unsigned order. The preceding snippet shows getOrder(orderUid) which returns an existing on-chain order, not an unsigned payload. Consider clarifying that the signed object must be an UnsignedOrder constructed from a quote.

Example:

// After obtaining a quote:
// const order: UnsignedOrder = { ...quote, appData: appDataHex, ... }
const signature = await cowSdk.orderSigning.signOrder(order, chainId, signer);
content/tutorial/00-setup/00-getting-started/01-provider-adapters/app-b/src/lib/run.ts (4)

5-5: Return a strongly-typed result instead of Promise.

Make the return type explicit to improve readability and caller ergonomics.

Update the signature only within the selected range:

-export async function run(provider: Web3Provider): Promise<unknown> {
+export async function run(provider: Web3Provider): Promise<RunResult> {

Add this type alias outside the selected range (e.g., below the imports):

type RunResult = {
  globalAdapter: EthersV5Adapter
  chainId: number
  address: string
}

Also applies to: 19-24


14-15: Fetch chainId and address concurrently.

Minor optimization and slightly cleaner code.

-  const chainId = await adapter.getChainId()
-  const address = await adapter.signer.getAddress()
+  const [chainId, address] = await Promise.all([
+    adapter.getChainId(),
+    adapter.signer.getAddress(),
+  ])

13-16: Guard against locked wallets by requesting accounts before getAddress.

Depending on the environment, getAddress may throw if the wallet isn’t connected. Proactively requesting accounts improves tutorial UX.

Insert before reading the address:

await provider.send('eth_requestAccounts', []).catch(() => {
  throw new Error('Please connect your wallet to continue')
})

If your tutorial flow guarantees a connected wallet earlier, you can skip this. Otherwise, adding it avoids common pitfalls during first run.


17-23: Avoid redundant getGlobalAdapter call (optional).

You already hold adapter; unless you’re explicitly demonstrating getGlobalAdapter, you can return the local instance.

-  const globalAdapter = getGlobalAdapter()
-
-  return {
-    globalAdapter,
+  return {
+    globalAdapter: adapter,
     chainId,
     address,
   }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a59318a and abde82f.

📒 Files selected for processing (9)
  • content/tutorial/00-setup/00-getting-started/00-getting-started/app-a/src/lib/run.ts (1 hunks)
  • content/tutorial/00-setup/00-getting-started/01-provider-adapters/README.md (1 hunks)
  • content/tutorial/00-setup/00-getting-started/01-provider-adapters/app-a/src/lib/run.ts (1 hunks)
  • content/tutorial/00-setup/00-getting-started/01-provider-adapters/app-b/src/lib/run.ts (1 hunks)
  • content/tutorial/00-setup/00-getting-started/01-provider-adapters/meta.json (1 hunks)
  • content/tutorial/03-umbrella-sdk/01-unified-approach/01-simple-setup/README.md (1 hunks)
  • content/tutorial/03-umbrella-sdk/01-unified-approach/02-complete-workflow/README.md (1 hunks)
  • content/tutorial/03-umbrella-sdk/02-individual-packages/01-basic-usage/README.md (1 hunks)
  • content/tutorial/03-umbrella-sdk/02-individual-packages/02-advanced-usage/README.md (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • content/tutorial/00-setup/00-getting-started/01-provider-adapters/meta.json
  • content/tutorial/00-setup/00-getting-started/00-getting-started/app-a/src/lib/run.ts
  • content/tutorial/00-setup/00-getting-started/01-provider-adapters/README.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • content/tutorial/03-umbrella-sdk/02-individual-packages/02-advanced-usage/README.md
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
content/tutorial/03-umbrella-sdk/01-unified-approach/01-simple-setup/README.md

24-24: Hard tabs
Column: 1

(MD010, no-hard-tabs)


25-25: Hard tabs
Column: 1

(MD010, no-hard-tabs)


27-27: Hard tabs
Column: 1

(MD010, no-hard-tabs)


28-28: Hard tabs
Column: 1

(MD010, no-hard-tabs)


29-29: Hard tabs
Column: 1

(MD010, no-hard-tabs)


30-30: Hard tabs
Column: 1

(MD010, no-hard-tabs)


31-31: Hard tabs
Column: 1

(MD010, no-hard-tabs)


32-32: Hard tabs
Column: 1

(MD010, no-hard-tabs)


34-34: Hard tabs
Column: 1

(MD010, no-hard-tabs)


35-35: Hard tabs
Column: 1

(MD010, no-hard-tabs)


90-90: Hard tabs
Column: 1

(MD010, no-hard-tabs)


91-91: Hard tabs
Column: 1

(MD010, no-hard-tabs)


92-92: Hard tabs
Column: 1

(MD010, no-hard-tabs)


93-93: Hard tabs
Column: 1

(MD010, no-hard-tabs)


94-94: Hard tabs
Column: 1

(MD010, no-hard-tabs)


95-95: Hard tabs
Column: 1

(MD010, no-hard-tabs)


96-96: Hard tabs
Column: 1

(MD010, no-hard-tabs)

content/tutorial/03-umbrella-sdk/01-unified-approach/02-complete-workflow/README.md

16-16: Hard tabs
Column: 1

(MD010, no-hard-tabs)


17-17: Hard tabs
Column: 1

(MD010, no-hard-tabs)


18-18: Hard tabs
Column: 1

(MD010, no-hard-tabs)


19-19: Hard tabs
Column: 1

(MD010, no-hard-tabs)


20-20: Hard tabs
Column: 1

(MD010, no-hard-tabs)


21-21: Hard tabs
Column: 1

(MD010, no-hard-tabs)


22-22: Hard tabs
Column: 1

(MD010, no-hard-tabs)


33-33: Hard tabs
Column: 1

(MD010, no-hard-tabs)


34-34: Hard tabs
Column: 1

(MD010, no-hard-tabs)


35-35: Hard tabs
Column: 1

(MD010, no-hard-tabs)


36-36: Hard tabs
Column: 1

(MD010, no-hard-tabs)


37-37: Hard tabs
Column: 1

(MD010, no-hard-tabs)


38-38: Hard tabs
Column: 1

(MD010, no-hard-tabs)


39-39: Hard tabs
Column: 1

(MD010, no-hard-tabs)


40-40: Hard tabs
Column: 1

(MD010, no-hard-tabs)


49-49: Hard tabs
Column: 1

(MD010, no-hard-tabs)


50-50: Hard tabs
Column: 1

(MD010, no-hard-tabs)


51-51: Hard tabs
Column: 1

(MD010, no-hard-tabs)


52-52: Hard tabs
Column: 1

(MD010, no-hard-tabs)


53-53: Hard tabs
Column: 1

(MD010, no-hard-tabs)


107-107: Hard tabs
Column: 1

(MD010, no-hard-tabs)


108-108: Hard tabs
Column: 1

(MD010, no-hard-tabs)


109-109: Hard tabs
Column: 1

(MD010, no-hard-tabs)


110-110: Hard tabs
Column: 1

(MD010, no-hard-tabs)

🪛 LanguageTool
content/tutorial/03-umbrella-sdk/02-individual-packages/01-basic-usage/README.md

[grammar] ~17-~17: Ensure spelling is correct
Context: ...ustom rate limits, URLs, etc. ### 📋 MetadataApi Generates and processes app data: - *...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🔇 Additional comments (4)
content/tutorial/03-umbrella-sdk/01-unified-approach/01-simple-setup/README.md (1)

21-22: Confirm adapter package and version alignment

Ensure @cowprotocol/sdk-ethers-v5-adapter version matches the umbrella @cowprotocol/cow-sdk version expected by this tutorial to avoid peer-dependency mismatches in examples.

content/tutorial/03-umbrella-sdk/02-individual-packages/01-basic-usage/README.md (3)

84-90: Adapters example looks good

Demonstrates read-only vs signing adapters clearly and matches the individual-package approach.


98-110: Ensure the sample output matches the returned object shape

Your code originally returned { order, appDataDoc } while the sample output shows { orderBook, metadata: { appDataHex } }. With the suggested changes above, the code will match the sample. If you prefer a different shape, update either the code or this example to stay consistent.


75-82: Env and GNOSIS baseUrl are correct; please verify backoffOpts keys

We’ve confirmed from the official docs that:

  • env accepts only 'prod' (production) or 'staging'.
  • The GNOSIS_CHAIN production base URL remains https://api.cow.fi/xdai (full endpoint at /xdai/api).

Please double-check in the SDK’s type definitions that your backoffOpts properties—namely maxDelay and numOfAttempts—match the library’s configuration interface exactly.

Comment thread content/tutorial/03-umbrella-sdk/01-unified-approach/01-simple-setup/README.md Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
content/tutorial/03-umbrella-sdk/02-individual-packages/01-basic-usage/README.md (2)

43-53: Missing variables: define chainId and orderUid before usage

chainId and orderUid are referenced but not defined, making the snippet non-runnable. Define them right after creating the adapter.

Apply this diff:

 export async function run(provider: Web3Provider): Promise<unknown> {
   const signer = provider.getSigner();
   const adapter = new EthersV5Adapter({ provider, signer });
 
+  // Resolve chainId from the connected network
+  const { chainId } = await provider.getNetwork();
+  // Example: use env var or fallback placeholder for docs
+  const orderUid =
+    (process?.env?.ORDER_UID as string | undefined) ??
+    '0x8464af00000000000000000000000000000000000000000000000000000000';
+
   // Initialize packages individually
   const orderBookApi = new OrderBookApi({ chainId });
   const metadataApi = new MetadataApi(adapter);
 
   // Test OrderBookApi
   const order = await orderBookApi.getOrder(orderUid);

55-66: Align with new API and example output: add getAppDataInfo and return expected keys

Call getAppDataInfo() and return keys to match the “Example output” (orderBook, metadata.appDataHex).

Apply this diff:

   // Test MetadataApi
   const appDataDoc = await metadataApi.generateAppDataDoc({
     appCode: 'Individual Basic Usage',
     environment: 'production',
     metadata: {
       quote: { slippageBips: 50 },
       orderClass: { orderClass: 'market' }
     }
   });
 
-  return { order, appDataDoc };
+  // Convert doc into on-chain usable fields (hex, cid, etc.)
+  const appDataInfo = await metadataApi.getAppDataInfo(appDataDoc);
+
+  // Return shape aligned with the "Example output" section
+  return {
+    orderBook: order,
+    metadata: { appDataHex: appDataInfo.appDataHex }
+  };
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between abde82f and b65519d.

📒 Files selected for processing (12)
  • content/tutorial/00-setup/00-getting-started/00-getting-started/app-a/src/lib/run.ts (1 hunks)
  • content/tutorial/00-setup/00-getting-started/01-provider-adapters/README.md (1 hunks)
  • content/tutorial/00-setup/00-getting-started/01-provider-adapters/app-a/src/lib/run.ts (1 hunks)
  • content/tutorial/00-setup/00-getting-started/01-provider-adapters/app-b/src/lib/run.ts (1 hunks)
  • content/tutorial/00-setup/00-getting-started/01-provider-adapters/meta.json (1 hunks)
  • content/tutorial/03-umbrella-sdk/01-unified-approach/01-simple-setup/README.md (1 hunks)
  • content/tutorial/03-umbrella-sdk/01-unified-approach/02-complete-workflow/README.md (1 hunks)
  • content/tutorial/03-umbrella-sdk/02-individual-packages/01-basic-usage/README.md (1 hunks)
  • content/tutorial/03-umbrella-sdk/02-individual-packages/02-advanced-usage/README.md (1 hunks)
  • src/routes/+page.server.js (1 hunks)
  • src/routes/tutorial/+page.js (1 hunks)
  • src/routes/tutorial/[slug]/+page.server.js (1 hunks)
✅ Files skipped from review due to trivial changes (4)
  • src/routes/tutorial/[slug]/+page.server.js
  • src/routes/tutorial/+page.js
  • content/tutorial/00-setup/00-getting-started/01-provider-adapters/README.md
  • content/tutorial/03-umbrella-sdk/02-individual-packages/02-advanced-usage/README.md
🚧 Files skipped from review as they are similar to previous changes (6)
  • content/tutorial/00-setup/00-getting-started/00-getting-started/app-a/src/lib/run.ts
  • content/tutorial/00-setup/00-getting-started/01-provider-adapters/app-b/src/lib/run.ts
  • content/tutorial/00-setup/00-getting-started/01-provider-adapters/app-a/src/lib/run.ts
  • content/tutorial/03-umbrella-sdk/01-unified-approach/02-complete-workflow/README.md
  • content/tutorial/00-setup/00-getting-started/01-provider-adapters/meta.json
  • content/tutorial/03-umbrella-sdk/01-unified-approach/01-simple-setup/README.md
🧰 Additional context used
🪛 LanguageTool
content/tutorial/03-umbrella-sdk/02-individual-packages/01-basic-usage/README.md

[grammar] ~17-~17: Ensure spelling is correct
Context: ...ustom rate limits, URLs, etc. ### 📋 MetadataApi Generates and processes app data: - *...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🔇 Additional comments (1)
content/tutorial/03-umbrella-sdk/02-individual-packages/01-basic-usage/README.md (1)

73-82: Verify OrderBookApi option names and values

Ensure that the config keys you’re passing to new OrderBookApi({ … }) match your installed SDK’s types exactly:

  • env
    – Confirm that 'prod' is an accepted literal (or whether the enum expects something like Env.PROD or 'production').
  • backoffOpts
    – Validate that maxDelay and numOfAttempts align with the defined BackoffOpts interface.
  • baseUrls
    – Make sure the keys (e.g. SupportedChainId.GNOSIS_CHAIN) and their URL values conform to the SDK’s type definitions.

You can inspect your local SDK package’s type declarations (usually under node_modules/<your-cow-sdk-package>/dist/*.d.ts) to verify exactly which names and string literals are allowed. For example:

grep -R "interface .*OrderBook.*Options" -n node_modules
grep -R "class OrderBookApi" -n node_modules

Comment thread src/routes/+page.server.js Outdated
@jeffersonBastos
Copy link
Copy Markdown
Contributor Author

@jeffersonBastos the build failed. Can you take a look?

image

My branch wasn’t up to date with the fix made on main… I’ve updated it and it’s working now.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
content/tutorial/01-simple-orders/01-order/06-cancel-off-chain-order/README.md (1)

49-53: Bug: invalid object literal for signOrderCancellations (computed key used incorrectly).

{ [orderUid] } is not a valid way to pass the order IDs. The API expects an array under a named key (typically orderUids). This is a syntax/functional error.

-    const orderCancellationsSigningResult = await OrderSigningUtils.signOrderCancellations({
-        [orderUid],
-        chainId,
-        signer
-    });
+    const orderCancellationsSigningResult = await OrderSigningUtils.signOrderCancellations({
+        orderUids: [orderUid],
+        chainId,
+        signer,
+    });
♻️ Duplicate comments (5)
content/tutorial/03-umbrella-sdk/02-individual-packages/01-basic-usage/README.md (2)

47-49: Make the snippet runnable: resolve chainId from provider and provide a usable orderUid

Using a fixed chain constant may mismatch the connected wallet’s network, and an empty orderUid will make getOrder fail immediately. Resolve chainId from the provider (still fine to keep a constant if you want) and provide a realistic UID via env or a placeholder.

Apply this diff:

-  const chainId = SupportedChainId.GNOSIS_CHAIN;
-  const orderUid = '';
+  // Resolve chain ID from the connected wallet to avoid network mismatches
+  const { chainId } = await provider.getNetwork();
+  // Provide an order UID from env or a safe placeholder for docs
+  const orderUid =
+    (process?.env?.ORDER_UID as string | undefined) ??
+    '0x8464af00000000000000000000000000000000000000000000000000000000';

57-68: Align code with new API and the “Example output”: add getAppDataInfo and return matching keys

The text and PR objectives mention replacing deprecated appDataToCid with getAppDataInfo, and your “Example output” shows metadata.appDataHex. The current snippet returns { order, appDataDoc }, which doesn’t match.

Apply this diff:

   const appDataDoc = await metadataApi.generateAppDataDoc({
     appCode: 'Individual Basic Usage',
     environment: 'production',
     metadata: {
       quote: { slippageBips: 50 },
       orderClass: { orderClass: 'market' }
     }
   });
 
-  return { order, appDataDoc };
+  // Convert the document into on-chain usable fields (hex, cid, etc.)
+  const appDataInfo = await metadataApi.getAppDataInfo(appDataDoc);
+
+  // Return shape aligned with the "Example output" section below
+  return {
+    orderBook: order,
+    metadata: { appDataHex: appDataInfo.appDataHex }
+  };
content/tutorial/01-simple-orders/01-order/06-cancel-off-chain-order/README.md (1)

29-29: Replace hard tabs with spaces to satisfy markdownlint (MD010).

This mirrors a prior comment and still applies here. Convert all \t characters to spaces in these regions to keep CI green.

You can verify/fix with:

#!/bin/bash
# Show remaining hard tabs
rg -nP "\t" content/tutorial/01-simple-orders/01-order/06-cancel-off-chain-order/README.md

# Replace tabs with 2 spaces (adjust to your convention)
sed -i'' $'s/\t/  /g' content/tutorial/01-simple-orders/01-order/06-cancel-off-chain-order/README.md

Also applies to: 31-31, 33-33, 71-82, 103-103

content/tutorial/03-umbrella-sdk/01-unified-approach/01-simple-setup/README.md (1)

24-26: Fix markdownlint MD010 (hard tabs) to unblock the build

Replace hard tabs with spaces in the indicated ranges. This was flagged previously and still applies to this file.

Example diff for one block (apply same replacement pattern elsewhere):

-	export async function run(provider: Web3Provider): Promise<unknown> {
-		const signer = provider.getSigner();
-		const adapter = new EthersV5Adapter({ provider, signer });
+  export async function run(provider: Web3Provider): Promise<unknown> {
+    const signer = provider.getSigner();
+    const adapter = new EthersV5Adapter({ provider, signer });

Also applies to: 34-35, 90-96

content/tutorial/03-umbrella-sdk/02-individual-packages/02-advanced-usage/app-b/src/lib/run.ts (1)

51-53: Good: feeAmount is no longer overridden (previous feedback addressed)

You kept the quoted fee intact, which preserves quote validity and prevents API rejections.

🧹 Nitpick comments (13)
content/tutorial/03-umbrella-sdk/02-individual-packages/01-basic-usage/README.md (2)

75-86: Config naming consistency: env vs environment

You use environment: 'production' above (MetadataApi) and env: 'prod' here (OrderBookApi). If both are the intended option names for their respective packages, add a short note to prevent confusion. If the SDK now prefers a single naming convention, align them.


54-56: Optional: guard or handle missing/invalid orderUid for a smoother tutorial run

If ORDER_UID isn’t provided, getOrder(orderUid) will throw. Consider a small guard or try/catch to keep the example flow friendly.

Example adjustment:

-  const order = await orderBookApi.getOrder(orderUid);
+  let order: unknown = null;
+  if (orderUid && /^0x[0-9a-fA-F]+$/.test(orderUid)) {
+    order = await orderBookApi.getOrder(orderUid);
+  } else {
+    console.warn('Tip: set ORDER_UID env var to fetch a real order.');
+  }
content/tutorial/01-simple-orders/01-order/06-cancel-off-chain-order/README.md (4)

31-31: Use a plain string literal for orderUid (template literal unnecessary).

Keeps the sample minimal and avoids implying interpolation.

-    const orderUid = `0x8464affce2df48b60f6976e51414dbc079e9c30ef64f4c1f78c7abe2c7f96a0c29104bb91ada737a89393c78335e48ff4708727e659523a1`;
+    const orderUid = '0x8464affce2df48b60f6976e51414dbc079e9c30ef64f4c1f78c7abe2c7f96a0c29104bb91ada737a89393c78335e48ff4708727e659523a1';

44-44: Import looks good; ensure chainId is actually defined or remove SupportedChainId.

Either show a concrete chainId assignment (helps copy/paste-ability) or drop the unused import if chainId is defined elsewhere in the snippet.

For example:

 import type { Web3Provider } from '@ethersproject/providers';
-import { SupportedChainId, OrderBookApi, OrderSigningUtils } from '@cowprotocol/cow-sdk';
+import { SupportedChainId, OrderBookApi, OrderSigningUtils } from '@cowprotocol/cow-sdk';
 
 export async function run(provider: Web3Provider): Promise<unknown> {
     // ...
+    const chainId = SupportedChainId.SEPOLIA; // or derive from provider/network

79-79: Consider returning the orderUid alongside the result for traceability.

Helps readers correlate the response with the attempted cancellation when running multiple examples.

-        return { cancellationsResult };
+        return { orderUid, cancellationsResult };

81-81: Avoid returning raw errors; return a structured error or rethrow.

Returning the raw error object can leak internals and varies by runtime. Prefer a stable shape.

-    } catch (e) {
-        return e;
+    } catch (e) {
+        return { error: e instanceof Error ? e.message : String(e) };
     }
content/tutorial/03-umbrella-sdk/01-unified-approach/01-simple-setup/README.md (5)

87-98: Make JSON example valid (use jsonc or remove the comment line)

The code fence is tagged as JSON, but the first line inside is a comment. Either switch the fence to jsonc or remove the comment line so users can copy-paste valid JSON.

-```json
-/// file: output.json
+```jsonc
 {
     "cowSdkInitialized": true,
     "availableModules": {
         "orderBook": true,
         "metadataApi": true,
         "orderSigning": true,
         "subgraph": true
     }
 }

---

`5-13`: **Tighten naming consistency: “CowSdk” vs “CowSdk class”; brand casing “CoW”**

- Prefer “CowSdk” (or “CoW SDK” for prose) consistently; avoid switching between “CowSdk class” and “CowSdk Class”.
- Example: change the heading to “Why use CowSdk?” and the first sentence to “CowSdk provides a unified interface…”.


```diff
-The **CowSdk class** provides a unified interface to access all CoW Protocol functionality through a single SDK instance.
+CowSdk provides a unified interface to access all CoW Protocol functionality through a single SDK instance.
 
-## Why Use CowSdk Class?
+## Why use CowSdk?

17-37: Optional: clarify signer availability and adapter expectations

Readers may copy-paste this. Consider a brief note that provider.getSigner() requires a connected wallet context; otherwise, some modules (like signing) won’t work. You can show a guard or mention read-only mode.

 export async function run(provider: Web3Provider): Promise<unknown> {
-    const signer = provider.getSigner();
+    // Requires a connected wallet; in read-only contexts, omit the signer.
+    const signer = provider.getSigner();
     const adapter = new EthersV5Adapter({ provider, signer });

49-61: Avoid ellipses in TypeScript blocks; prefer comments so copy-paste compiles

Using ... inside a TS code fence breaks copy-paste. Replace with comments and include a trailing comma fix.

-const cowSdk = new CowSdk({
-  adapter,                    // Required: Your provider adapter
-  chainId,                   // Required: Target blockchain
-  env: 'prod',              // Optional: 'prod' or 'staging' (default: 'prod')
-  orderBookOptions: {        // Optional: Advanced order book configuration
-    backoffOpts: {...},
-    baseUrls: {...}
-  }
-  ...
-})
+const cowSdk = new CowSdk({
+  adapter,                  // Required: your provider adapter
+  chainId,                  // Required: target blockchain
+  env: 'prod',              // Optional: 'prod' or 'staging' (default: 'prod')
+  // Optional: advanced order book configuration
+  // orderBookOptions: {
+  //   backoffOpts: { /* retry/backoff options */ },
+  //   baseUrls: { /* override base URLs if needed */ },
+  // },
+});

69-77: Consider showing the inferred-signing variant (if supported) alongside the explicit one

If the unified SDK infers chainId and signer from the adapter, show both forms so users pick the recommended path.

 // Sign an order using the unified SDK
-const signature = await cowSdk.orderSigning.signOrder(order, chainId, signer)
+// Explicit:
+const signature = await cowSdk.orderSigning.signOrder(order, chainId, signer)
+// Or, if supported by the current SDK (preferred for simplicity):
+// const signature = await cowSdk.orderSigning.signOrder(order)
content/tutorial/03-umbrella-sdk/02-individual-packages/02-advanced-usage/app-b/src/lib/run.ts (2)

74-76: Narrow the error type to avoid “unknown” access in strict TS

In TS 4.4+, catch variable is unknown. Accessing error.message can fail under stricter configs. Narrow or stringify safely.

Apply this diff:

-  } catch (error) {
-    return { error: error.message };
-  }
+  } catch (error) {
+    const message = error instanceof Error ? error.message : String(error);
+    return { error: message };
+  }

41-45: Optional: centralize chain-specific token addresses

Since this tutorial set uses these addresses in multiple places, consider extracting them to a small constants module keyed by chainId to avoid duplication and reduce copy/paste errors.

Example:

// tokens.ts
export const GNOSIS_TOKENS = {
  WXDAI: '0xe91d153e0b41518a2ce8dd3d7944fa863463a97d',
  COW:   '0x177127622c4A00F3d409B75571e12cB3c8973d3c',
};

Then:

sellToken: GNOSIS_TOKENS.WXDAI,
buyToken: GNOSIS_TOKENS.COW,
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b65519d and 2aaaf8b.

📒 Files selected for processing (7)
  • content/tutorial/00-setup/00-getting-started/01-provider-adapters/app-b/src/lib/run.ts (1 hunks)
  • content/tutorial/01-simple-orders/01-order/06-cancel-off-chain-order/README.md (2 hunks)
  • content/tutorial/03-umbrella-sdk/01-unified-approach/01-simple-setup/README.md (1 hunks)
  • content/tutorial/03-umbrella-sdk/01-unified-approach/02-complete-workflow/README.md (1 hunks)
  • content/tutorial/03-umbrella-sdk/02-individual-packages/01-basic-usage/README.md (1 hunks)
  • content/tutorial/03-umbrella-sdk/02-individual-packages/02-advanced-usage/app-b/src/lib/run.ts (1 hunks)
  • src/routes/+page.server.js (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • content/tutorial/00-setup/00-getting-started/01-provider-adapters/app-b/src/lib/run.ts
  • src/routes/+page.server.js
  • content/tutorial/03-umbrella-sdk/01-unified-approach/02-complete-workflow/README.md
🧰 Additional context used
🧬 Code graph analysis (1)
content/tutorial/03-umbrella-sdk/02-individual-packages/02-advanced-usage/app-b/src/lib/run.ts (4)
content/tutorial/00-setup/00-getting-started/01-provider-adapters/app-b/src/lib/run.ts (1)
  • run (5-31)
content/tutorial/03-umbrella-sdk/02-individual-packages/01-basic-usage/app-a/src/lib/run.ts (1)
  • run (4-14)
content/tutorial/03-umbrella-sdk/02-individual-packages/01-basic-usage/app-b/src/lib/run.ts (1)
  • run (5-48)
content/tutorial/03-umbrella-sdk/02-individual-packages/02-advanced-usage/app-a/src/lib/run.ts (1)
  • run (11-30)
🪛 Gitleaks (8.27.2)
content/tutorial/03-umbrella-sdk/02-individual-packages/02-advanced-usage/app-b/src/lib/run.ts

33-33: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


34-34: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🪛 LanguageTool
content/tutorial/03-umbrella-sdk/01-unified-approach/01-simple-setup/README.md

[grammar] ~12-~12: There might be a mistake here.
Context: ...t**: One import, one initialization - 🔧 Consistent Configuration: Same settin...

(QB_NEW_EN)


[grammar] ~13-~13: There might be a mistake here.
Context: ...**: Same settings for all modules - 📦 Batteries Included: All functionality ...

(QB_NEW_EN)


[grammar] ~15-~15: There might be a mistake here.
Context: ...**: All functionality in one place ## Basic Initialization ```typescript /// fil...

(QB_NEW_EN)

content/tutorial/03-umbrella-sdk/02-individual-packages/01-basic-usage/README.md

[grammar] ~11-~11: There might be a mistake here.
Context: ...dual packages: ### 📊 OrderBookApi Handles order management and quotes: - **...

(QB_NEW_EN)


[grammar] ~14-~14: There might be a mistake here.
Context: ...Standalone* - no adapter required - Simple initialization - just needs chai...

(QB_NEW_EN)


[grammar] ~15-~15: There might be a mistake here.
Context: ...itialization** - just needs chainId - Independent configuration - custom rate...

(QB_NEW_EN)


[grammar] ~15-~15: There might be a mistake here.
Context: ...ation** - custom rate limits, URLs, etc. ### 📋 MetadataApi Generates and processes ...

(QB_NEW_EN)


[grammar] ~17-~17: There might be a mistake here.
Context: ...its, URLs, etc. ### 📋 MetadataApi Generates and processes app data: - **Req...

(QB_NEW_EN)


[grammar] ~19-~19: There might be a mistake here.
Context: ...* Generates and processes app data: - Requires adapter for blockchain operati...

(QB_NEW_EN)


[grammar] ~20-~20: There might be a mistake here.
Context: ...adapter** for blockchain operations - Flexible adapter - can use different ad...

(QB_NEW_EN)


[grammar] ~21-~21: There might be a mistake here.
Context: ...pter** - can use different adapters - Blockchain aware - can interact with on...

(QB_NEW_EN)


[grammar] ~21-~21: There might be a mistake here.
Context: ...ware** - can interact with on-chain data ### ✍️ OrderSigningUtils Static utility cla...

(QB_NEW_EN)


[grammar] ~23-~23: There might be a mistake here.
Context: ...n-chain data ### ✍️ OrderSigningUtils Static utility class for signing orders:...

(QB_NEW_EN)


[grammar] ~24-~24: There might be a mistake here.
Context: ...Static utility class for signing orders: - No initialization needed - **Static me...

(QB_NEW_EN)

🔇 Additional comments (7)
content/tutorial/03-umbrella-sdk/02-individual-packages/01-basic-usage/README.md (1)

87-93: Nice demonstration of per-usage adapters

Showing separate read-only and signing adapters for MetadataApi is clear and helps readers understand adapter granularity.

content/tutorial/01-simple-orders/01-order/06-cancel-off-chain-order/README.md (2)

76-77: Good: explicitly setting orderUids after spreading the signing result.

Placing orderUids: [orderUid] after ...orderCancellationsSigningResult ensures your explicit value wins if the spread contains the same key. Nice attention to ordering.


59-59: Add documentation links for the deprecated single-UID cancellation endpoint

Please add direct links to the official docs where we mark the single-UID /cancel endpoint as deprecated and show the plural-payload version, so readers can verify and explore further:

These links will give readers confidence that the deprecation note is accurate and point them to the exact TypeScript types and examples.

content/tutorial/03-umbrella-sdk/01-unified-approach/01-simple-setup/README.md (2)

1-3: Overall: clear, well-structured tutorial and aligns with the PR goals

The document effectively introduces the unified CowSdk, adapter setup, and module usage; headings, code fences, and flow are easy to follow. Once the small nits above are addressed, this is good to go.

Also applies to: 5-14, 39-47, 63-67, 79-86


28-33: Manual verification required: Confirm SDK API surface against the monorepo

This tutorial repository contains only usage examples; the actual CowSdk implementation lives externally. Before merging, please cross-check the following against the latest umbrella-sdk monorepo and update these code snippets as needed:

  • Config key
    • Should be env (not environment)
    • Allowed values: exactly 'prod' or 'staging'

  • SDK modules on CowSdk instance
    .orderBook
    .metadataApi
    .orderSigning
    .subgraph

  • Signing API signature
    • Examples currently use await cowSdk.orderSigning.signOrder(order, chainId, signer)
    • If the latest SDK infers any parameters (e.g. signer or chainId), adjust calls accordingly (e.g. signOrder(order))

Affected sections:

  • 01-simple-setup README.md (lines 28–33)
  • 02-complete-workflow README.md (lines 69–77, 91–96)
content/tutorial/03-umbrella-sdk/02-individual-packages/02-advanced-usage/app-b/src/lib/run.ts (2)

27-38: Solid switch to getAppDataInfo and correct pairing of appDataContent/hash

The generateAppDataDoc → getAppDataInfo flow looks correct, and passing appDataContent to quoting while keeping appDataHex for the order aligns with the new SDK APIs.


39-49: Quote request parameters look consistent for SELL-side flows

Using sellAmountBeforeFee with OrderQuoteSideKindSell.SELL and providing both appData (content) and appDataHash (hex) is coherent. Token addresses match Gnosis, and from/receiver are aligned.

@mfw78
Copy link
Copy Markdown
Contributor

mfw78 commented Oct 6, 2025

Looks cool, would be great if this could be merged or actioned! 🙏 @alfetopito 😉

@shoom3301
Copy link
Copy Markdown
Contributor

Continued in #46

@shoom3301 shoom3301 closed this Oct 7, 2025
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 7, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants