diff --git a/chain138-snap/.github/workflows/build-lint-test.yml b/chain138-snap/.github/workflows/build-lint-test.yml index 53172c1..8922581 100644 --- a/chain138-snap/.github/workflows/build-lint-test.yml +++ b/chain138-snap/.github/workflows/build-lint-test.yml @@ -93,7 +93,7 @@ jobs: - name: Install dependencies run: pnpm install --frozen-lockfile - name: Run Snap unit tests - run: pnpm --filter snap run test + run: pnpm --filter chain138-snap run test - name: Install Playwright browsers run: npx playwright install chromium --with-deps - name: Run Playwright E2E (companion site) diff --git a/chain138-snap/ALLOWLIST_FORM_FIELDS.md b/chain138-snap/ALLOWLIST_FORM_FIELDS.md new file mode 100644 index 0000000..a78b6d6 --- /dev/null +++ b/chain138-snap/ALLOWLIST_FORM_FIELDS.md @@ -0,0 +1,48 @@ +# MetaMask Snaps Directory — Allowlist form fields + +Use this when submitting the Chain 138 Snap via the [MetaMask Snaps Directory Information form](https://docs.metamask.io/snaps/how-to/get-allowlisted/#1-submit-your-snap). + +## Pre-filled values + +| Field | Value | +|-------|--------| +| **Snap name** | Chain 138 *(must match `proposedName` in snap.manifest.json)* | +| **Snap builder name and URL** | BIS Innovations — https://github.com/bis-innovations | +| **Snap website URL** | https://github.com/bis-innovations/chain138-snap#readme *(or your deployed companion site, e.g. https://explorer.d-bis.org/snap/)* | +| **GitHub repository** | https://github.com/bis-innovations/chain138-snap | +| **npm package** | https://www.npmjs.com/package/chain138-snap | +| **Snap version to allowlist** | 0.1.0 *(must match package.json and snap.manifest.json)* | +| **Snap auditor / audit report** | Leave blank *(no key-management APIs; audit not required)* | + +## Short description (1–2 sentences) + +Chain 138 adds DeFi Oracle Meta Mainnet (and ALL Mainnet) support in MetaMask: network params, token list, market data, swap quotes, and CCIP bridge routes. Use with the token-aggregation API for full features. + +## Long description + +Use line breaks and lists; no HTML. Example: + +- **Networks:** Chain 138 (DeFi Oracle Meta Mainnet) and ALL Mainnet (651940); full EIP-3085 params from API. +- **Token list & market data:** Tokens and USD prices via token-aggregation (or optional JSON URLs). +- **Swap quotes:** In-Snap quotes for Chain 138 when quote API is configured. +- **Bridge routes:** CCIP WETH9/WETH10 routes to Ethereum Mainnet when bridge API is available. + +After installing, dApps must pass `apiBaseUrl` (your token-aggregation base URL) when invoking the Snap for market data, swap quote, and bridge routes. See the repo README and INTEGRATORS.md. + +## Customer support + +- **Escalation contact:** *(confidential; provide email or contact form)* +- **Public support:** GitHub Issues — https://github.com/bis-innovations/chain138-snap/issues + *(Add at least one other channel, e.g. docs link or support URL.)* + +## Images + +Screenshots or promotional images of the Snap (companion site, dialogs, or in-wallet UI). Upload as required by the form. + +## Demo video (optional) + +Video walkthrough of installing and using the Snap. Helps review and may be used by MetaMask marketing. + +--- + +After submission, the Snap will be reviewed (at least two approvals). Once allowlisted, it will appear in the MetaMask Snaps Directory and users can install it on standard MetaMask (non-Flask). diff --git a/chain138-snap/ALLOWLIST_SOURCE_AND_COMPLIANCE_CHECKLIST.md b/chain138-snap/ALLOWLIST_SOURCE_AND_COMPLIANCE_CHECKLIST.md new file mode 100644 index 0000000..d64bbc8 --- /dev/null +++ b/chain138-snap/ALLOWLIST_SOURCE_AND_COMPLIANCE_CHECKLIST.md @@ -0,0 +1,21 @@ +# Allowlist: source and compliance checklist + +Before submitting the Chain 138 Snap for MetaMask allowlisting, confirm: + +## Source code + +- [ ] Snap source code is **publicly available** (e.g. public Git repo). Repo: **https://github.com/bis-innovations/chain138-snap** + +## Compliance + +- [ ] The Snap does **not** impair MetaMask’s compliance with laws or regulations (no illicit use of data, keys, or network access). +- [ ] No key-management APIs are used (this Snap does not use `snap_getBip32Entropy`, `snap_getBip44Entropy`, `snap_manageAccounts`, etc.), so **no third-party audit** is required. + +## Already done in this repo + +- [x] Package name set to `chain138-snap` (no conflict with existing npm `snap`). +- [x] Repository/homepage/bugs set to **https://github.com/bis-innovations/chain138-snap**. +- [x] No `console` logs, to-do comments, or unused permissions in Snap code. +- [x] Security: CI runs MetaMask Security Code Scanner (`.github/workflows/security-code-scanner.yml`). Optionally run [Snapper](https://docs.metamask.io/snaps/how-to/get-allowlisted/) locally before submission. + +After publishing to npm, submit via the [MetaMask Snaps Directory Information form](https://docs.metamask.io/snaps/how-to/get-allowlisted/#1-submit-your-snap). diff --git a/chain138-snap/INTEGRATORS.md b/chain138-snap/INTEGRATORS.md new file mode 100644 index 0000000..ab401b6 --- /dev/null +++ b/chain138-snap/INTEGRATORS.md @@ -0,0 +1,53 @@ +# Chain 138 Snap — Integrator guide + +Use this Snap from your dApp to provide Chain 138 (and ALL Mainnet) network params, token list, market data, swap quotes, and bridge routes inside MetaMask. + +## Production Snap ID + +After the Snap is published to npm, use: + +**`npm:chain138-snap`** + +Example (wallet_invokeSnap): + +```js +await ethereum.request({ + method: 'wallet_invokeSnap', + params: { + snapId: 'npm:chain138-snap', + request: { method: 'hello' }, + }, +}); +``` + +## Required: apiBaseUrl + +For **market data**, **swap quotes**, and **bridge routes**, the dApp must pass `apiBaseUrl` (your token-aggregation service base URL) in the request params: + +```js +params: { + apiBaseUrl: 'https://your-token-aggregation-api.com', + // optional: chainId (default 138), tokenIn, tokenOut, amountIn for swap, etc. +} +``` + +## Optional URL params + +You can pass these instead of or in addition to `apiBaseUrl` for specific data: + +| Param | Purpose | Used by RPCs | +|----------------|----------------------|--------------------------------------| +| `networksUrl` | JSON URL for networks| `get_networks`, `get_chain138_config` | +| `tokenListUrl` | JSON URL for tokens | `get_token_list`, `get_token_list_url`| +| `bridgeListUrl`| JSON URL for bridge | `get_bridge_routes`, `show_bridge_routes` | + +## Companion site env + +For the companion site (this repo’s `packages/site`): + +- **Development:** Uses local Snap; no `SNAP_ORIGIN` needed (defaults to local). +- **Production:** Set `SNAP_ORIGIN=npm:chain138-snap` and `GATSBY_SNAP_API_BASE_URL` to your token-aggregation base URL so the site uses the published Snap and passes `apiBaseUrl` to it. + +## RPC methods + +See [TESTING_INSTRUCTIONS.md](TESTING_INSTRUCTIONS.md) for the full list: `hello`, `get_networks`, `get_chain138_config`, `get_chain138_market_chains`, `get_token_list`, `get_token_list_url`, `get_oracles`, `show_dynamic_info`, `get_market_summary`, `show_market_data`, `get_bridge_routes`, `show_bridge_routes`, `get_swap_quote`, `show_swap_quote`. diff --git a/chain138-snap/MANUAL_E2E_CHECKLIST.md b/chain138-snap/MANUAL_E2E_CHECKLIST.md new file mode 100644 index 0000000..de41dd8 --- /dev/null +++ b/chain138-snap/MANUAL_E2E_CHECKLIST.md @@ -0,0 +1,44 @@ +# Manual E2E checklist (MetaMask Flask + companion site) + +Use this checklist to complete **manual** E2E verification. Covers Snap install, all RPC methods, and companion site cards. + +## Prerequisites + +- [ ] MetaMask Flask installed: https://metamask.io/flask/ +- [ ] Snap dev server: `pnpm run start` in `chain138-snap` (or `pnpm start` from repo root) +- [ ] For API-dependent features: token-aggregation service running; set `GATSBY_SNAP_API_BASE_URL` in `packages/site/.env` (copy from `.env.production.dist`) + +--- + +## 1. Install Snap + +- [ ] Open http://localhost:8000 in the browser +- [ ] Click **Connect** and approve Snap installation in MetaMask Flask + +--- + +## 2. RPC methods (pass `apiBaseUrl` or optional URLs where required) + +- [ ] `hello` +- [ ] `get_networks` (apiBaseUrl or networksUrl) +- [ ] `get_chain138_config` (apiBaseUrl or networksUrl) +- [ ] `get_chain138_market_chains` (apiBaseUrl) +- [ ] `get_token_list`, `get_token_list_url` (apiBaseUrl or tokenListUrl; optional chainId) +- [ ] `get_oracles` (apiBaseUrl), `show_dynamic_info` (apiBaseUrl or networksUrl/tokenListUrl) +- [ ] `get_market_summary`, `show_market_data` (apiBaseUrl; optional chainId) +- [ ] `get_bridge_routes`, `show_bridge_routes` (apiBaseUrl or bridgeListUrl) +- [ ] `get_swap_quote`, `show_swap_quote` (apiBaseUrl, tokenIn, tokenOut, amountIn; optional chainId) + +*(Use browser console and `wallet_invokeSnap` as in TESTING_INSTRUCTIONS.md.)* + +--- + +## 3. Companion site cards + +- [ ] **Market data:** "Show market data" opens Snap dialog; "Fetch market summary" shows tokens/prices +- [ ] **Bridge:** "Show bridge routes" opens Snap dialog with CCIP routes +- [ ] **Swap quote:** Enter token In/Out addresses and amount (raw); "Get quote" shows amountOut; "Show quote in Snap" opens dialog + +--- + +When all items are checked, manual E2E (snap-9 and snap-10) is complete. diff --git a/chain138-snap/PACKAGE_MANAGER.md b/chain138-snap/PACKAGE_MANAGER.md index 2bfcf4d..395a3e3 100644 --- a/chain138-snap/PACKAGE_MANAGER.md +++ b/chain138-snap/PACKAGE_MANAGER.md @@ -20,7 +20,7 @@ ## CI -GitHub Actions use **pnpm** by default: `corepack prepare pnpm@9.15.0 --activate` then `pnpm install --frozen-lockfile` and `pnpm run build` / `pnpm run lint` / `pnpm --filter snap run test`. **Before the first CI run** (or after adding dependencies), run `pnpm install` locally and commit `pnpm-lock.yaml` so CI has a lockfile. +GitHub Actions use **pnpm** by default: `corepack prepare pnpm@9.15.0 --activate` then `pnpm install --frozen-lockfile` and `pnpm run build` / `pnpm run lint` / `pnpm --filter chain138-snap run test`. **Before the first CI run** (or after adding dependencies), run `pnpm install` locally and commit `pnpm-lock.yaml` so CI has a lockfile. ## Recommendations diff --git a/chain138-snap/PUSH_AND_PUBLISH.md b/chain138-snap/PUSH_AND_PUBLISH.md new file mode 100644 index 0000000..ce828e4 --- /dev/null +++ b/chain138-snap/PUSH_AND_PUBLISH.md @@ -0,0 +1,43 @@ +# Push to GitHub and publish to npm + +Use this when the Snap lives in **https://github.com/bis-innovations/chain138-snap** and you are ready to push and publish. + +## 1. Push to GitHub (first-time setup) + +From the **chain138-snap** directory (or the repo root if this monorepo is the whole repo): + +```bash +# If this folder is the repo to push (you cloned/copied it as chain138-snap): +git remote add origin https://github.com/bis-innovations/chain138-snap.git +git branch -M main +git push -u origin main +``` + +If this directory is part of a larger repo (e.g. `proxmox`), you can either push only the Snap subtree to **chain138-snap** (e.g. `git subtree push` or a new clone containing just the Snap), or push the whole repo and then point the Snap’s `repository` to a dedicated Snap repo. For a **standalone** Snap repo: create **bis-innovations/chain138-snap** on GitHub, then from a clone that contains only this Snap monorepo (e.g. copy `metamask-integration/chain138-snap` contents into a new repo): run the `git remote add origin` / `git push` commands above. + +## 2. Publish Snap package to npm + +From the **chain138-snap** monorepo root: + +```bash +# Build (updates manifest shasum) +pnpm run build + +# Publish the Snap package (requires npm login) +cd packages/snap && npm publish --access public +# Or: pnpm publish --no-git-checks --access public +``` + +Production Snap ID will be **`npm:chain138-snap`**. + +## 3. Submit for allowlist + +After npm publish, fill the [MetaMask Snaps Directory Information form](https://docs.metamask.io/snaps/how-to/get-allowlisted/#1-submit-your-snap) with: + +- **Snap name:** Chain 138 (must match `proposedName` in `snap.manifest.json`) +- **GitHub repository:** https://github.com/bis-innovations/chain138-snap +- **npm package:** https://www.npmjs.com/package/chain138-snap +- **Version:** from `packages/snap/package.json` (e.g. 0.1.0) +- Descriptions, support details, images, optional demo video as required. + +See **ALLOWLIST_SOURCE_AND_COMPLIANCE_CHECKLIST.md** for prerequisites. diff --git a/chain138-snap/README.md b/chain138-snap/README.md index b6899d8..e5652b4 100644 --- a/chain138-snap/README.md +++ b/chain138-snap/README.md @@ -2,9 +2,11 @@ This Snap provides **Chain 138** (DeFi Oracle Meta Mainnet) and **ALL Mainnet** (651940) support in MetaMask: network params, token list, market data (prices), swap quotes, and CCIP bridge routes. It reads configuration from a **token-aggregation** (or compatible) API. +**Why we built it:** MetaMask already supports Chain 138 as a custom EVM network (add via RPC), but native **Swaps**, **Portfolio Bridge**, and **USD pricing** do not include Chain 138 (Consensys-controlled). No public Snap existed for swap/bridge/pricing on 138. This Snap gives in-wallet swap quotes, bridge routes, and market data by calling our APIs, so users get feature parity without waiting for Consensys. See [docs/04-configuration/CHAIN138_WALLET_ECOSYSTEM_AND_RATIONALE.md](../../docs/04-configuration/CHAIN138_WALLET_ECOSYSTEM_AND_RATIONALE.md#2-why-we-created-the-metamask-snap) for full rationale. + For detailed development and testing, see [TESTING_INSTRUCTIONS.md](TESTING_INSTRUCTIONS.md). For implementation phases and backend APIs, see [docs/04-configuration/metamask/SNAP_IMPLEMENTATION_ROADMAP.md](../../docs/04-configuration/metamask/SNAP_IMPLEMENTATION_ROADMAP.md) in the repo root. -**Integrators:** Market data, swap quote, and bridge route features require the dApp to pass `apiBaseUrl` (the token-aggregation service base URL) when invoking the Snap. Set `GATSBY_SNAP_API_BASE_URL` on the companion site so the demo page works. +**Integrators:** Production Snap ID: **`npm:chain138-snap`**. Market data, swap quote, and bridge route features require the dApp to pass `apiBaseUrl` (the token-aggregation service base URL) when invoking the Snap. You may also pass optional URLs: `networksUrl`, `tokenListUrl`, `bridgeListUrl`. Set `GATSBY_SNAP_API_BASE_URL` on the companion site so the demo page works. For production, set `SNAP_ORIGIN=npm:chain138-snap` in the site env so the companion uses the published Snap. This Snap targets the **latest stable MetaMask Snap SDK** (`@metamask/snaps-sdk`). diff --git a/chain138-snap/TESTING_INSTRUCTIONS.md b/chain138-snap/TESTING_INSTRUCTIONS.md index 2f2b0a7..8a2eda0 100644 --- a/chain138-snap/TESTING_INSTRUCTIONS.md +++ b/chain138-snap/TESTING_INSTRUCTIONS.md @@ -365,7 +365,7 @@ Use this checklist for full manual E2E testing: 2. **Publish package:** Publish the Snap package to npm (e.g. from `packages/snap`) so `source.location.npm` in `snap.manifest.json` is valid. 3. **Snap directory:** Follow the [MetaMask Snap publishing guide](https://docs.metamask.io/snaps/how-to/publish-a-snap/) to register the Snap (package name or bundle URL, description, category, permissions). -**Production use:** After the Snap is published, the production Snap ID will be the npm package name (e.g. `npm:snap` or `npm:@your-org/chain138-snap`). For market data, swap quote, and bridge routes to work, dApps (and the companion site) must pass `apiBaseUrl` (your token-aggregation service URL) or the optional URLs when invoking the Snap. Document this for integrators; see "API calls failing" in Troubleshooting. +**Production use:** After the Snap is published, the production Snap ID is **`npm:chain138-snap`**. For market data, swap quote, and bridge routes to work, dApps (and the companion site) must pass `apiBaseUrl` (your token-aggregation service URL) or the optional URLs (`networksUrl`, `tokenListUrl`, `bridgeListUrl`) when invoking the Snap. See "Integrators" in the repo README and "API calls failing" in Troubleshooting. --- diff --git a/chain138-snap/e2e/site.spec.ts b/chain138-snap/e2e/site.spec.ts index 33e174f..450f0d6 100644 --- a/chain138-snap/e2e/site.spec.ts +++ b/chain138-snap/e2e/site.spec.ts @@ -12,6 +12,6 @@ test.describe('Chain 138 Snap companion site', () => { test('page has Snap-related content', async ({ page }) => { await page.goto('/', { waitUntil: 'domcontentloaded' }); const body = page.locator('body'); - await expect(body).toContainText(/Connect|template-snap|Get started|Snap|Install|Reconnect/i, { timeout: 30_000 }); + await expect(body).toContainText(/Connect|Chain 138|Get started|Snap|Install|Reconnect/i, { timeout: 30_000 }); }); }); diff --git a/chain138-snap/package.json b/chain138-snap/package.json index 867945c..35bb0f9 100644 --- a/chain138-snap/package.json +++ b/chain138-snap/package.json @@ -3,13 +3,13 @@ "version": "0.1.0", "private": true, "description": "", - "homepage": "https://github.com/MetaMask/template-snap-monorepo#readme", + "homepage": "https://github.com/bis-innovations/chain138-snap#readme", "bugs": { - "url": "https://github.com/MetaMask/template-snap-monorepo/issues" + "url": "https://github.com/bis-innovations/chain138-snap/issues" }, "repository": { "type": "git", - "url": "git+https://github.com/MetaMask/template-snap-monorepo.git" + "url": "git+https://github.com/bis-innovations/chain138-snap.git" }, "license": "(MIT-0 OR Apache-2.0)", "author": "", @@ -24,7 +24,7 @@ "lint:fix": "pnpm run lint:eslint --fix && pnpm run lint:misc --write", "lint:misc": "prettier '**/*.json' '**/*.md' '**/*.yml' '!.yarnrc.yml' --ignore-path .gitignore --no-error-on-unmatched-pattern", "start": "pnpm -r --parallel run start", - "test": "pnpm --filter snap run build && pnpm --filter snap run test", + "test": "pnpm --filter chain138-snap run build && pnpm --filter chain138-snap run test", "test:e2e": "playwright test", "test:e2e:ui": "playwright test --ui" }, diff --git a/chain138-snap/packages/site/static/version.json b/chain138-snap/packages/site/static/version.json new file mode 100644 index 0000000..73bd44c --- /dev/null +++ b/chain138-snap/packages/site/static/version.json @@ -0,0 +1 @@ +{"version":"dev","buildTime":"2026-02-16T03:22:42.028Z"} \ No newline at end of file diff --git a/chain138-snap/packages/snap/package.json b/chain138-snap/packages/snap/package.json index 2b17f34..a34f929 100644 --- a/chain138-snap/packages/snap/package.json +++ b/chain138-snap/packages/snap/package.json @@ -1,10 +1,14 @@ { - "name": "snap", + "name": "chain138-snap", "version": "0.1.0", "description": "Chain 138 (DeFi Oracle Meta Mainnet) and ALL Mainnet Snap: networks, token list, market data, swap quotes, CCIP bridge routes for MetaMask.", "repository": { "type": "git", - "url": "https://github.com/MetaMask/template-snap-monorepo.git" + "url": "https://github.com/bis-innovations/chain138-snap.git" + }, + "homepage": "https://github.com/bis-innovations/chain138-snap#readme", + "bugs": { + "url": "https://github.com/bis-innovations/chain138-snap/issues" }, "license": "(MIT-0 OR Apache-2.0)", "main": "./dist/bundle.js", diff --git a/chain138-snap/packages/snap/snap.manifest.json b/chain138-snap/packages/snap/snap.manifest.json index 09562da..9bf2c86 100644 --- a/chain138-snap/packages/snap/snap.manifest.json +++ b/chain138-snap/packages/snap/snap.manifest.json @@ -4,15 +4,15 @@ "proposedName": "Chain 138", "repository": { "type": "git", - "url": "https://github.com/MetaMask/template-snap-monorepo.git" + "url": "https://github.com/bis-innovations/chain138-snap.git" }, "source": { - "shasum": "gLlFZx1q+vaYM4tYKOg0hHlIDB9p6GdoZ4jw3ZU7jYg=", + "shasum": "BP9yQblP1R+fSCxYQjdV965YIDdal9Xx3ZiSTbmJYik=", "location": { "npm": { "filePath": "dist/bundle.js", "iconPath": "images/icon.svg", - "packageName": "snap", + "packageName": "chain138-snap", "registry": "https://registry.npmjs.org/" } }