From 19399a7d30eb92dfb14b6f50cc9ced559f6a388b Mon Sep 17 00:00:00 2001 From: BrettCleary <27568879+BrettCleary@users.noreply.github.com> Date: Wed, 18 Feb 2026 08:17:04 -0300 Subject: [PATCH 1/6] add cd --- .github/workflows/publish-coinfello-skill.yml | 45 +++++ .github/workflows/publish.yml | 56 ++++++ coinfello/SKILL.md | 167 ++++++++++++++++++ coinfello/references/REFERENCE.md | 142 +++++++++++++++ coinfello/scripts/setup-and-send.sh | 41 +++++ package.json | 10 +- 6 files changed, 459 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/publish-coinfello-skill.yml create mode 100644 .github/workflows/publish.yml create mode 100644 coinfello/SKILL.md create mode 100644 coinfello/references/REFERENCE.md create mode 100644 coinfello/scripts/setup-and-send.sh diff --git a/.github/workflows/publish-coinfello-skill.yml b/.github/workflows/publish-coinfello-skill.yml new file mode 100644 index 0000000..eb9063a --- /dev/null +++ b/.github/workflows/publish-coinfello-skill.yml @@ -0,0 +1,45 @@ +name: Publish Coinfello Skill + +on: + push: + branches: [main] + paths: + - 'coinfello/**' + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install clawhub CLI + run: npm i -g clawhub + + - name: Extract version + run: echo "VERSION=$(node -p "require('./package.json').version")" >> $GITHUB_ENV + + - name: Generate changelog + run: | + PREV_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") + if [ -n "$PREV_TAG" ]; then + CHANGELOG=$(git log "${PREV_TAG}..HEAD" --oneline --no-merges | head -20 | tr '\n' '; ') + else + CHANGELOG="Release v${VERSION}" + fi + echo "CHANGELOG=${CHANGELOG}" >> $GITHUB_ENV + + - name: Publish coinfello skill to ClawHub + env: + CLAWHUB_TOKEN: ${{ secrets.CLAWHUB_TOKEN }} + run: | + clawhub publish ./coinfello \ + --slug coinfello \ + --name "CoinFello" \ + --version "$VERSION" \ + --changelog "$CHANGELOG" diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..f3f78ff --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,56 @@ +name: Publish @coinfello/agent-cli + +on: + push: + branches: [main] + +jobs: + publish: + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write # enables npm provenance + + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + with: + version: 10.24.0 + + - uses: actions/setup-node@v4 + with: + node-version: '20' + registry-url: 'https://registry.npmjs.org' + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Typecheck + run: pnpm codecheck + + - name: Build + run: pnpm build + + - name: Check if version is already published + id: version_check + run: | + PKG_VERSION=$(node -p "require('./package.json').version") + PKG_NAME=$(node -p "require('./package.json').name") + echo "version=${PKG_VERSION}" >> $GITHUB_OUTPUT + if npm view "${PKG_NAME}@${PKG_VERSION}" version 2>/dev/null | grep -q "${PKG_VERSION}"; then + echo "already_published=true" >> $GITHUB_OUTPUT + else + echo "already_published=false" >> $GITHUB_OUTPUT + fi + + - name: Publish to npm + if: steps.version_check.outputs.already_published == 'false' + run: pnpm publish --no-git-checks + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Skip publish (version already exists) + if: steps.version_check.outputs.already_published == 'true' + run: echo "Version ${{ steps.version_check.outputs.version }} already published. Skipping." diff --git a/coinfello/SKILL.md b/coinfello/SKILL.md new file mode 100644 index 0000000..5b44ca4 --- /dev/null +++ b/coinfello/SKILL.md @@ -0,0 +1,167 @@ +--- +name: coinfello +description: >- + Interact with CoinFello using the openclaw CLI to create MetaMask smart accounts, + manage delegations, send prompts with ERC-20 token subdelegations, and check + transaction status. Use when the user wants to send crypto transactions via + natural language prompts, manage smart account delegations, or check CoinFello + transaction results. +compatibility: Requires Node.js 20+ and pnpm. +metadata: { + "openclaw": + { + "emoji": "👋", + "homepage":"https://coinfello.com", + "requires": + { "bins": ["curl", "jq"] } + } +} +--- + +# CoinFello CLI Skill + +Use the `openclaw` CLI to interact with CoinFello through MetaMask Smart Accounts. The CLI handles smart account creation, delegation management, prompt-based ERC-20 token transactions, and transaction status checks. + +## Prerequisites + +- Node.js 20 or later +- pnpm package manager +- Build the CLI before first use: `pnpm build` + +The CLI binary is available at `./dist/index.js` after building, or as `openclaw` if installed globally. + +## Quick Start + +```bash +# 1. Create a smart account on a chain (generates a new private key automatically) +openclaw create_account sepolia + +# 2. Send a prompt with token subdelegation +openclaw send_prompt "swap 5 USDC for ETH" \ + --token-address 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 \ + --amount 5 \ + --decimals 6 + +# 3. Check transaction status +openclaw get_transaction_status +``` + +## Commands + +### create_account + +Creates a MetaMask Hybrid smart account with an auto-generated private key and saves it to local config. + +```bash +openclaw create_account +``` + +- `` — A viem chain name: `sepolia`, `mainnet`, `polygon`, `arbitrum`, `optimism`, `base`, etc. +- Generates a new private key automatically +- Saves `private_key`, `smart_account_address`, and `chain` to `~/.clawdbot/skills/coinfello/config.json` +- Must be run before `send_prompt` + +### get_account + +Displays the current smart account address from local config. + +```bash +openclaw get_account +``` + +- Prints the stored `smart_account_address` +- Exits with an error if no account has been created yet + +### set_delegation + +Stores a signed parent delegation (JSON) in local config for use with redelegation flows. + +```bash +openclaw set_delegation '' +``` + +- `` — A JSON string representing a `Delegation` object from MetaMask Smart Accounts Kit +- Only needed if you plan to use `--use-redelegation` with `send_prompt` + +### send_prompt + +Sends a natural language prompt to CoinFello with a locally-created and signed ERC-20 token subdelegation. + +```bash +openclaw send_prompt "" \ + --token-address \ + --amount \ + [--decimals ] \ + [--use-redelegation] +``` + +**Required options:** +- `--token-address
` — ERC-20 token contract address for the subdelegation scope +- `--amount ` — Maximum token amount in human-readable form (e.g. `5`, `100.5`) + +**Optional:** +- `--decimals ` — Token decimals for parsing `--amount` (default: `18`) +- `--use-redelegation` — Create a redelegation from a stored parent delegation (requires `set_delegation` first) + +**What happens internally:** +1. Fetches CoinFello's delegate address from the API +2. Rebuilds the smart account from the stored private key and chain in config +3. Creates a subdelegation scoped to `erc20TransferAmount` with the specified token and max amount +4. Signs the subdelegation with the smart account +5. Sends the prompt + signed subdelegation to CoinFello's conversation endpoint +6. Returns a `txn_id` for tracking + +### get_transaction_status + +Checks the status of a previously submitted transaction. + +```bash +openclaw get_transaction_status +``` + +- Returns a JSON object with the current transaction status + +## Common Workflows + +### Basic: Send a Token Transfer Prompt + +```bash +# Create account if not already done +openclaw create_account sepolia + +# Send prompt to transfer up to 10 USDC +openclaw send_prompt "send 5 USDC to 0xRecipient..." \ + --token-address 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 \ + --amount 10 \ + --decimals 6 + +# Check the result +openclaw get_transaction_status +``` + +### With Redelegation + +Use this when you have a parent delegation from another delegator and want to create a subdelegation chain. + +```bash +# Store the parent delegation +openclaw set_delegation '{"delegate":"0x...","delegator":"0x...","authority":"0x...","caveats":[],"salt":"0x...","signature":"0x..."}' + +# Send with redelegation +openclaw send_prompt "swap tokens" \ + --token-address 0xTokenAddress \ + --amount 100 \ + --use-redelegation +``` + +## Edge Cases + +- **No smart account**: Run `create_account` before `send_prompt`. The CLI checks for a saved private key and address in config. +- **Invalid chain name**: The CLI throws an error listing valid viem chain names. +- **Missing parent delegation with --use-redelegation**: The CLI exits with an error. Run `set_delegation` first. + +## Reference + +See [references/REFERENCE.md](references/REFERENCE.md) for the full config schema, supported chains, API details, and troubleshooting. + +See [scripts/setup-and-send.sh](scripts/setup-and-send.sh) for an end-to-end automation script. diff --git a/coinfello/references/REFERENCE.md b/coinfello/references/REFERENCE.md new file mode 100644 index 0000000..1062b22 --- /dev/null +++ b/coinfello/references/REFERENCE.md @@ -0,0 +1,142 @@ +# CoinFello CLI Reference + +## Config File + +Location: `~/.clawdbot/skills/coinfello/config.json` + +Created automatically by `create_account`. Schema: + +```json +{ + "private_key": "0xabc123...def", + "smart_account_address": "0x1234...abcd", + "chain": "sepolia", + "delegation": { + "delegate": "0x...", + "delegator": "0x...", + "authority": "0x...", + "caveats": [], + "salt": "0x...", + "signature": "0x..." + } +} +``` + +| Field | Type | Set by | Description | +| ------------------------ | ---------- | ---------------- | ------------------------------------------ | +| `private_key` | `string` | `create_account` | Auto-generated hex private key | +| `smart_account_address` | `string` | `create_account` | Counterfactual address of the smart account | +| `chain` | `string` | `create_account` | viem chain name used for account creation | +| `delegation` | `object` | `set_delegation` | Optional parent delegation for redelegation | + +## Command Reference + +### openclaw create_account + +``` +openclaw create_account +``` + +| Parameter | Type | Required | Description | +| --------- | -------- | -------- | ---------------------------------- | +| `chain` | `string` | Yes | viem chain name (see below) | + +Generates a new private key automatically and saves it along with the smart account address and chain to config. + +### openclaw get_account + +``` +openclaw get_account +``` + +No parameters. Prints the stored smart account address from config. Exits with an error if no account has been created. + +### openclaw set_delegation + +``` +openclaw set_delegation +``` + +| Parameter | Type | Required | Description | +| ------------ | -------- | -------- | ----------------------------------------- | +| `delegation` | `string` | Yes | JSON-encoded Delegation object from MetaMask Smart Accounts Kit | + +### openclaw send_prompt + +``` +openclaw send_prompt --token-address --amount [--decimals ] [--use-redelegation] +``` + +| Parameter | Type | Required | Default | Description | +| ------------------- | --------- | -------- | ------- | ------------------------------------------------ | +| `prompt` | `string` | Yes | — | Natural language prompt to send to CoinFello | +| `--token-address` | `string` | Yes | — | ERC-20 token contract address | +| `--amount` | `string` | Yes | — | Max token amount (human-readable, e.g. `"5"`) | +| `--decimals` | `string` | No | `"18"` | Token decimals for parsing amount | +| `--use-redelegation`| `boolean` | No | `false` | Use stored parent delegation for redelegation | + +Uses the private key and chain stored in config (from `create_account`). + +### openclaw get_transaction_status + +``` +openclaw get_transaction_status +``` + +| Parameter | Type | Required | Description | +| --------- | -------- | -------- | ---------------------------- | +| `txn_id` | `string` | Yes | Transaction ID from send_prompt | + +## Supported Chains + +Any chain exported by `viem/chains`. Common examples: + +| Chain Name | Chain ID | Network | +| ------------ | -------- | ---------------------- | +| `mainnet` | 1 | Ethereum mainnet | +| `sepolia` | 11155111 | Ethereum Sepolia testnet | +| `polygon` | 137 | Polygon PoS | +| `arbitrum` | 42161 | Arbitrum One | +| `optimism` | 10 | OP Mainnet | +| `base` | 8453 | Base | +| `avalanche` | 43114 | Avalanche C-Chain | +| `bsc` | 56 | BNB Smart Chain | + +## API Endpoints + +Base URL: `https://app.coinfello.com/api/v1` + +| Endpoint | Method | Description | +| --------------------------------- | ------ | -------------------------------- | +| `/coinfello-address` | GET | Returns CoinFello's delegate address | +| `/conversation` | POST | Submits prompt + signed subdelegation | +| `/transaction_status?txn_id=` | GET | Returns transaction status | + +### POST /conversation body + +```json +{ + "prompt": "swap 5 USDC for ETH", + "signed_subdelegation": { "...delegation object with signature..." }, + "smart_account_address": "0x..." +} +``` + +## Common Token Decimals + +| Token | Decimals | Note | +| ----- | -------- | ----------------------------- | +| USDC | 6 | Use `--decimals 6` | +| USDT | 6 | Use `--decimals 6` | +| DAI | 18 | Default, no `--decimals` needed | +| WETH | 18 | Default, no `--decimals` needed | + +## Error Messages + +| Error | Cause | Fix | +| ---------------------------------------------------------------------- | ---------------------------------- | ---------------------------------------- | +| `Unknown chain ""` | Invalid chain name | Use a valid viem chain name | +| `No private key found in config. Run 'create_account' first.` | Missing private key in config | Run `openclaw create_account ` | +| `No smart account found. Run 'create_account' first.` | Missing smart account in config | Run `openclaw create_account ` | +| `No chain found in config. Run 'create_account' first.` | Missing chain in config | Run `openclaw create_account ` | +| `--use-redelegation requires a parent delegation. Run 'set_delegation' first.` | No stored delegation | Run `openclaw set_delegation ''` | diff --git a/coinfello/scripts/setup-and-send.sh b/coinfello/scripts/setup-and-send.sh new file mode 100644 index 0000000..990d378 --- /dev/null +++ b/coinfello/scripts/setup-and-send.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# setup-and-send.sh — End-to-end CoinFello workflow +# +# Usage: +# ./setup-and-send.sh [decimals] +# +# Example: +# ./setup-and-send.sh sepolia \ +# 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 \ +# 5 \ +# "send 3 USDC to 0xRecipient" \ +# 6 + +set -euo pipefail + +CHAIN="${1:?Usage: $0 [decimals]}" +TOKEN_ADDRESS="${2:?Missing token-address}" +AMOUNT="${3:?Missing amount}" +PROMPT="${4:?Missing prompt}" +DECIMALS="${5:-18}" + +echo "==> Creating smart account on ${CHAIN}..." +openclaw create_account "$CHAIN" + +echo "" +echo "==> Sending prompt..." +OUTPUT=$(openclaw send_prompt "$PROMPT" \ + --token-address "$TOKEN_ADDRESS" \ + --amount "$AMOUNT" \ + --decimals "$DECIMALS") + +echo "$OUTPUT" + +# Extract txn_id from output +TXN_ID=$(echo "$OUTPUT" | grep -oP 'Transaction ID: \K.*') + +if [ -n "$TXN_ID" ]; then + echo "" + echo "==> Checking transaction status..." + openclaw get_transaction_status "$TXN_ID" +fi diff --git a/package.json b/package.json index 848a6f5..1a3e44a 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,21 @@ { "name": "@coinfello/agent-cli", - "version": "1.0.0", + "version": "0.0.0", "description": "", "type": "module", "main": "dist/index.js", "bin": { "openclaw": "./dist/index.js" }, + "files": [ + "dist" + ], + "publishConfig": { + "access": "public" + }, "scripts": { "build": "vite build", - "typecheck": "tsc --noEmit", + "codecheck": "tsc --noEmit", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], From 276b5b5fbaa5e4dc41eded09320754f9236b80df Mon Sep 17 00:00:00 2001 From: BrettCleary <27568879+BrettCleary@users.noreply.github.com> Date: Wed, 18 Feb 2026 08:18:44 -0300 Subject: [PATCH 2/6] update requires --- coinfello/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coinfello/SKILL.md b/coinfello/SKILL.md index 5b44ca4..bfa8fed 100644 --- a/coinfello/SKILL.md +++ b/coinfello/SKILL.md @@ -13,7 +13,7 @@ metadata: { "emoji": "👋", "homepage":"https://coinfello.com", "requires": - { "bins": ["curl", "jq"] } + { "bins": ["node"] } } } --- From a033c0b707d406dfe2ca6d0a17ebe46d08953cc3 Mon Sep 17 00:00:00 2001 From: BrettCleary <27568879+BrettCleary@users.noreply.github.com> Date: Wed, 18 Feb 2026 08:30:49 -0300 Subject: [PATCH 3/6] add CI --- .github/workflows/ci.yml | 34 ++ .prettierrc | 7 + .vscode/settings.json | 12 + eslint.config.js | 12 + package.json | 7 + pnpm-lock.yaml | 737 +++++++++++++++++++++++++++++++++++++++ src/account.ts | 52 +-- src/api.ts | 44 ++- src/config.ts | 36 +- src/index.ts | 265 +++++++------- src/siwe.ts | 144 +++----- 11 files changed, 1032 insertions(+), 318 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .prettierrc create mode 100644 .vscode/settings.json create mode 100644 eslint.config.js diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..e2a4940 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,34 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + +jobs: + check: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + with: + version: 10.24.0 + + - uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Typecheck + run: pnpm codecheck + + - name: Prettier + run: pnpm prettier + + - name: Lint + run: pnpm lint diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..238d4d9 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,7 @@ +{ + "semi": false, + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "es5", + "printWidth": 100 +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..aab8cce --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,12 @@ +{ + "editor.bracketPairColorization.enabled": true, + "prettier.configPath": "${fileDirname}/../.prettierrc.json", + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "[javascript]": { + "editor.formatOnSave": true + }, + "[typescript]": { + "editor.formatOnSave": true + } +} diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..d973465 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,12 @@ +import tseslint from 'typescript-eslint' +import prettierConfig from 'eslint-config-prettier' + +export default tseslint.config( + tseslint.configs.recommended, + prettierConfig, + { + rules: { + '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], + }, + } +) diff --git a/package.json b/package.json index 1a3e44a..54b3ec9 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,9 @@ "scripts": { "build": "vite build", "codecheck": "tsc --noEmit", + "lint": "eslint src", + "prettier-fix": "prettier --write src", + "prettier": "prettier --check src", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], @@ -29,7 +32,11 @@ }, "devDependencies": { "@types/node": "^25.2.1", + "eslint": "^10.0.0", + "eslint-config-prettier": "^10.1.8", + "prettier": "^3.8.1", "typescript": "^5.9.3", + "typescript-eslint": "^8.56.0", "vite": "^7.3.1" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5f7b17b..8ece4f0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -21,9 +21,21 @@ importers: '@types/node': specifier: ^25.2.1 version: 25.2.1 + eslint: + specifier: ^10.0.0 + version: 10.0.0 + eslint-config-prettier: + specifier: ^10.1.8 + version: 10.1.8(eslint@10.0.0) + prettier: + specifier: ^3.8.1 + version: 3.8.1 typescript: specifier: ^5.9.3 version: 5.9.3 + typescript-eslint: + specifier: ^8.56.0 + version: 8.56.0(eslint@10.0.0)(typescript@5.9.3) vite: specifier: ^7.3.1 version: 7.3.1(@types/node@25.2.1) @@ -189,6 +201,36 @@ packages: cpu: [x64] os: [win32] + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.23.1': + resolution: {integrity: sha512-uVSdg/V4dfQmTjJzR0szNczjOH/J+FyUMMjYtr07xFRXR7EDf9i1qdxrD0VusZH9knj1/ecxzCQQxyic5NzAiA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/config-helpers@0.5.2': + resolution: {integrity: sha512-a5MxrdDXEvqnIq+LisyCX6tQMPF/dSJpCfBgBauY+pNZ28yCtSsTvyTYrMhaI+LK26bVyCJfJkT0u8KIj2i1dQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/core@1.1.0': + resolution: {integrity: sha512-/nr9K9wkr3P1EzFTdFdMoLuo1PmIxjmwvPozwoSodjNBdefGujXQUF93u1DDZpEaTuDvMsIQddsd35BwtrW9Xw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/object-schema@3.0.1': + resolution: {integrity: sha512-P9cq2dpr+LU8j3qbLygLcSZrl2/ds/pUpfnHNNuk5HW7mnngHs+6WSq5C9mO3rqRX8A1poxqLTC9cu0KOyJlBg==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + '@eslint/plugin-kit@0.6.0': + resolution: {integrity: sha512-bIZEUzOI1jkhviX2cp5vNyXQc6olzb2ohewQubuYlMXZ2Q/XjBO0x0XhGPvc9fjSIiUN0vw+0hq53BJ4eQSJKQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + '@ethereumjs/common@3.2.0': resolution: {integrity: sha512-pksvzI0VyLgmuEF2FA/JR/4/y6hcPq8OUail3/AvycBaW1d5VSauOZzqGvJ3RTmR4MU35lWE8KseKOsEhrFRBA==} @@ -205,6 +247,22 @@ packages: resolution: {integrity: sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==} engines: {node: '>=14'} + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.7': + resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + '@metamask/7715-permission-types@0.5.0': resolution: {integrity: sha512-UTlAXhfVM83/dCtghIqZiPqJmeGa4KI2HhkKYjmeP0oFtwzsgDwFfNakdICC4VX82338AiyVVtbEFyx6t7SE1w==} engines: {node: ^18.18 || >=20} @@ -408,9 +466,15 @@ packages: '@types/debug@4.1.12': resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + '@types/esrecurse@4.3.1': + resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} + '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/lodash@4.17.23': resolution: {integrity: sha512-RDvF6wTulMPjrNdCoYRC8gNR880JNGT8uB+REUpC2Ns4pRqQJhGz90wh7rgdXDPpCczF3VGktDuFGVnz8zP7HA==} @@ -420,6 +484,65 @@ packages: '@types/node@25.2.1': resolution: {integrity: sha512-CPrnr8voK8vC6eEtyRzvMpgp3VyVRhgclonE7qYi6P9sXwYb59ucfrnmFBTaP0yUi8Gk4yZg/LlTJULGxvTNsg==} + '@typescript-eslint/eslint-plugin@8.56.0': + resolution: {integrity: sha512-lRyPDLzNCuae71A3t9NEINBiTn7swyOhvUj3MyUOxb8x6g6vPEFoOU+ZRmGMusNC3X3YMhqMIX7i8ShqhT74Pw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.56.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/parser@8.56.0': + resolution: {integrity: sha512-IgSWvLobTDOjnaxAfDTIHaECbkNlAlKv2j5SjpB2v7QHKv1FIfjwMy8FsDbVfDX/KjmCmYICcw7uGaXLhtsLNg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/project-service@8.56.0': + resolution: {integrity: sha512-M3rnyL1vIQOMeWxTWIW096/TtVP+8W3p/XnaFflhmcFp+U4zlxUxWj4XwNs6HbDeTtN4yun0GNTTDBw/SvufKg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/scope-manager@8.56.0': + resolution: {integrity: sha512-7UiO/XwMHquH+ZzfVCfUNkIXlp/yQjjnlYUyYz7pfvlK3/EyyN6BK+emDmGNyQLBtLGaYrTAI6KOw8tFucWL2w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.56.0': + resolution: {integrity: sha512-bSJoIIt4o3lKXD3xmDh9chZcjCz5Lk8xS7Rxn+6l5/pKrDpkCwtQNQQwZ2qRPk7TkUYhrq3WPIHXOXlbXP0itg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/type-utils@8.56.0': + resolution: {integrity: sha512-qX2L3HWOU2nuDs6GzglBeuFXviDODreS58tLY/BALPC7iu3Fa+J7EOTwnX9PdNBxUI7Uh0ntP0YWGnxCkXzmfA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/types@8.56.0': + resolution: {integrity: sha512-DBsLPs3GsWhX5HylbP9HNG15U0bnwut55Lx12bHB9MpXxQ+R5GC8MwQe+N1UFXxAeQDvEsEDY6ZYwX03K7Z6HQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.56.0': + resolution: {integrity: sha512-ex1nTUMWrseMltXUHmR2GAQ4d+WjkZCT4f+4bVsps8QEdh0vlBsaCokKTPlnqBFqqGaxilDNJG7b8dolW2m43Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/utils@8.56.0': + resolution: {integrity: sha512-RZ3Qsmi2nFGsS+n+kjLAYDPVlrzf7UhTffrDIKr+h2yzAlYP/y5ZulU0yeDEPItos2Ph46JAL5P/On3pe7kDIQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/visitor-keys@8.56.0': + resolution: {integrity: sha512-q+SL+b+05Ud6LbEE35qe4A99P+htKTKVbyiNEe45eCbJFyh/HVK9QXwlrbz+Q4L8SOW4roxSVwXYj4DMBT7Ieg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + abitype@1.2.3: resolution: {integrity: sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg==} peerDependencies: @@ -431,9 +554,36 @@ packages: zod: optional: true + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + balanced-match@4.0.3: + resolution: {integrity: sha512-1pHv8LX9CpKut1Zp4EXey7Z8OfH11ONNH6Dhi2WDUt31VVZFXZzKwXcysBgqSumFCmR+0dqjMK5v5JiFHzi0+g==} + engines: {node: 20 || >=22} + base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + brace-expansion@5.0.2: + resolution: {integrity: sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==} + engines: {node: 20 || >=22} + buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} @@ -446,6 +596,10 @@ packages: engines: {node: '>=0.8'} hasBin: true + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -455,17 +609,81 @@ packages: supports-color: optional: true + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + esbuild@0.27.2: resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} engines: {node: '>=18'} hasBin: true + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-config-prettier@10.1.8: + resolution: {integrity: sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + + eslint-scope@9.1.0: + resolution: {integrity: sha512-CkWE42hOJsNj9FJRaoMX9waUFYhqY4jmyLFdAdzZr6VaCg3ynLYx4WnOdkaIifGfH4gsUcBTn4OZbHXkpLD0FQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@5.0.0: + resolution: {integrity: sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint@10.0.0: + resolution: {integrity: sha512-O0piBKY36YSJhlFSG8p9VUdPV/SxxS4FYDWVpr/9GJuMaepzwlf4J8I4ov1b+ySQfDTPhc3DtLaxcT1fN0yqCg==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@11.1.0: + resolution: {integrity: sha512-WFWYhO1fV4iYkqOOvq8FbqIhr2pYfoDY0kCotMkDeNtGpiGGkZ1iov2u8ydjtgM8yF8rzK7oaTbw2NAzbAbehw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + ethereum-cryptography@2.2.1: resolution: {integrity: sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==} eventemitter3@5.0.1: resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -475,25 +693,95 @@ packages: picomatch: optional: true + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.3.3: + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + isows@1.0.7: resolution: {integrity: sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==} peerDependencies: ws: '*' + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + lodash@4.17.23: resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==} micro-ftch@0.3.1: resolution: {integrity: sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==} + minimatch@10.2.1: + resolution: {integrity: sha512-MClCe8IL5nRRmawL6ib/eT4oLyeKMGCghibcDWK+J0hh0Q8kqSdia6BvbRMVk6mPa6WqUa5uR2oxt6C5jd533A==} + engines: {node: 20 || >=22} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -502,6 +790,13 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + ox@0.11.3: resolution: {integrity: sha512-1bWYGk/xZel3xro3l8WGg6eq4YEKlaqvyMtVhfMFpbJzK2F6rj4EDRtqDCWVEJMkzcmEi9uW2QxsqELokOlarw==} peerDependencies: @@ -510,6 +805,22 @@ packages: typescript: optional: true + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -525,6 +836,19 @@ packages: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier@3.8.1: + resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} + engines: {node: '>=14'} + hasBin: true + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + rollup@4.57.1: resolution: {integrity: sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -535,6 +859,14 @@ packages: engines: {node: '>=10'} hasBin: true + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -543,6 +875,23 @@ packages: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} + ts-api-utils@2.4.0: + resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + typescript-eslint@8.56.0: + resolution: {integrity: sha512-c7toRLrotJ9oixgdW7liukZpsnq5CZ7PuKztubGYlNppuTqhIoWfhgHo/7EU0v06gS2l/x0i2NEFK1qMIf0rIg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.0.0' + typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} @@ -551,6 +900,9 @@ packages: undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + uuid@9.0.1: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true @@ -606,6 +958,15 @@ packages: webauthn-p256@0.0.10: resolution: {integrity: sha512-EeYD+gmIT80YkSIDb2iWq0lq2zbHo1CxHlQTeJ+KkCILWpVy3zASH3ByD4bopzfk0uCwXxLqKGLqp2W4O28VFA==} + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + ws@8.18.3: resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} engines: {node: '>=10.0.0'} @@ -618,6 +979,10 @@ packages: utf-8-validate: optional: true + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + snapshots: '@adraffy/ens-normalize@1.11.1': {} @@ -700,6 +1065,36 @@ snapshots: '@esbuild/win32-x64@0.27.2': optional: true + '@eslint-community/eslint-utils@4.9.1(eslint@10.0.0)': + dependencies: + eslint: 10.0.0 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.23.1': + dependencies: + '@eslint/object-schema': 3.0.1 + debug: 4.4.3 + minimatch: 10.2.1 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.5.2': + dependencies: + '@eslint/core': 1.1.0 + + '@eslint/core@1.1.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/object-schema@3.0.1': {} + + '@eslint/plugin-kit@0.6.0': + dependencies: + '@eslint/core': 1.1.0 + levn: 0.4.1 + '@ethereumjs/common@3.2.0': dependencies: '@ethereumjs/util': 8.1.0 @@ -720,6 +1115,17 @@ snapshots: ethereum-cryptography: 2.2.1 micro-ftch: 0.3.1 + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.7': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.4.3 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + '@metamask/7715-permission-types@0.5.0': {} '@metamask/abi-utils@3.0.0': @@ -894,8 +1300,12 @@ snapshots: dependencies: '@types/ms': 2.1.0 + '@types/esrecurse@4.3.1': {} + '@types/estree@1.0.8': {} + '@types/json-schema@7.0.15': {} + '@types/lodash@4.17.23': {} '@types/ms@2.1.0': {} @@ -904,12 +1314,128 @@ snapshots: dependencies: undici-types: 7.16.0 + '@typescript-eslint/eslint-plugin@8.56.0(@typescript-eslint/parser@8.56.0(eslint@10.0.0)(typescript@5.9.3))(eslint@10.0.0)(typescript@5.9.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.56.0(eslint@10.0.0)(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.56.0 + '@typescript-eslint/type-utils': 8.56.0(eslint@10.0.0)(typescript@5.9.3) + '@typescript-eslint/utils': 8.56.0(eslint@10.0.0)(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.56.0 + eslint: 10.0.0 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.4.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.56.0(eslint@10.0.0)(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.56.0 + '@typescript-eslint/types': 8.56.0 + '@typescript-eslint/typescript-estree': 8.56.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.56.0 + debug: 4.4.3 + eslint: 10.0.0 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.56.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.56.0(typescript@5.9.3) + '@typescript-eslint/types': 8.56.0 + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.56.0': + dependencies: + '@typescript-eslint/types': 8.56.0 + '@typescript-eslint/visitor-keys': 8.56.0 + + '@typescript-eslint/tsconfig-utils@8.56.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@typescript-eslint/type-utils@8.56.0(eslint@10.0.0)(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 8.56.0 + '@typescript-eslint/typescript-estree': 8.56.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.56.0(eslint@10.0.0)(typescript@5.9.3) + debug: 4.4.3 + eslint: 10.0.0 + ts-api-utils: 2.4.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.56.0': {} + + '@typescript-eslint/typescript-estree@8.56.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/project-service': 8.56.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.56.0(typescript@5.9.3) + '@typescript-eslint/types': 8.56.0 + '@typescript-eslint/visitor-keys': 8.56.0 + debug: 4.4.3 + minimatch: 9.0.5 + semver: 7.7.4 + tinyglobby: 0.2.15 + ts-api-utils: 2.4.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.56.0(eslint@10.0.0)(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.0) + '@typescript-eslint/scope-manager': 8.56.0 + '@typescript-eslint/types': 8.56.0 + '@typescript-eslint/typescript-estree': 8.56.0(typescript@5.9.3) + eslint: 10.0.0 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.56.0': + dependencies: + '@typescript-eslint/types': 8.56.0 + eslint-visitor-keys: 5.0.0 + abitype@1.2.3(typescript@5.9.3): optionalDependencies: typescript: 5.9.3 + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn@8.15.0: {} + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + balanced-match@1.0.2: {} + + balanced-match@4.0.3: {} + base64-js@1.5.1: {} + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + brace-expansion@5.0.2: + dependencies: + balanced-match: 4.0.3 + buffer@6.0.3: dependencies: base64-js: 1.5.1 @@ -919,10 +1445,18 @@ snapshots: crc-32@1.2.2: {} + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + debug@4.4.3: dependencies: ms: 2.1.3 + deep-is@0.1.4: {} + esbuild@0.27.2: optionalDependencies: '@esbuild/aix-ppc64': 0.27.2 @@ -952,6 +1486,76 @@ snapshots: '@esbuild/win32-ia32': 0.27.2 '@esbuild/win32-x64': 0.27.2 + escape-string-regexp@4.0.0: {} + + eslint-config-prettier@10.1.8(eslint@10.0.0): + dependencies: + eslint: 10.0.0 + + eslint-scope@9.1.0: + dependencies: + '@types/esrecurse': 4.3.1 + '@types/estree': 1.0.8 + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@5.0.0: {} + + eslint@10.0.0: + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.0) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.23.1 + '@eslint/config-helpers': 0.5.2 + '@eslint/core': 1.1.0 + '@eslint/plugin-kit': 0.6.0 + '@humanfs/node': 0.16.7 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + ajv: 6.12.6 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 9.1.0 + eslint-visitor-keys: 5.0.0 + espree: 11.1.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + minimatch: 10.2.1 + natural-compare: 1.4.0 + optionator: 0.9.4 + transitivePeerDependencies: + - supports-color + + espree@11.1.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 5.0.0 + + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + esutils@2.0.3: {} + ethereum-cryptography@2.2.1: dependencies: '@noble/curves': 1.4.2 @@ -961,27 +1565,105 @@ snapshots: eventemitter3@5.0.1: {} + fast-deep-equal@3.1.3: {} + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + fdir@6.5.0(picomatch@4.0.3): optionalDependencies: picomatch: 4.0.3 + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + + flatted@3.3.3: {} + fsevents@2.3.3: optional: true + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + ieee754@1.2.1: {} + ignore@5.3.2: {} + + ignore@7.0.5: {} + + imurmurhash@0.1.4: {} + + is-extglob@2.1.1: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + isexe@2.0.0: {} + isows@1.0.7(ws@8.18.3): dependencies: ws: 8.18.3 + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + lodash@4.17.23: {} micro-ftch@0.3.1: {} + minimatch@10.2.1: + dependencies: + brace-expansion: 5.0.2 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.2 + ms@2.1.3: {} nanoid@3.3.11: {} + natural-compare@1.4.0: {} + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + ox@0.11.3(typescript@5.9.3): dependencies: '@adraffy/ens-normalize': 1.11.1 @@ -997,6 +1679,18 @@ snapshots: transitivePeerDependencies: - zod + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + picocolors@1.1.1: {} picomatch@4.0.3: {} @@ -1009,6 +1703,12 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + prelude-ls@1.2.1: {} + + prettier@3.8.1: {} + + punycode@2.3.1: {} + rollup@4.57.1: dependencies: '@types/estree': 1.0.8 @@ -1042,6 +1742,12 @@ snapshots: semver@7.7.4: {} + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + source-map-js@1.2.1: {} tinyglobby@0.2.15: @@ -1049,10 +1755,33 @@ snapshots: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 + ts-api-utils@2.4.0(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + typescript-eslint@8.56.0(eslint@10.0.0)(typescript@5.9.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.56.0(@typescript-eslint/parser@8.56.0(eslint@10.0.0)(typescript@5.9.3))(eslint@10.0.0)(typescript@5.9.3) + '@typescript-eslint/parser': 8.56.0(eslint@10.0.0)(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.56.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.56.0(eslint@10.0.0)(typescript@5.9.3) + eslint: 10.0.0 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + typescript@5.9.3: {} undici-types@7.16.0: {} + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + uuid@9.0.1: {} viem@2.45.1(typescript@5.9.3): @@ -1089,4 +1818,12 @@ snapshots: '@noble/curves': 1.9.7 '@noble/hashes': 1.8.0 + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + ws@8.18.3: {} + + yocto-queue@0.1.0: {} diff --git a/src/account.ts b/src/account.ts index cf294fc..f3d0db5 100644 --- a/src/account.ts +++ b/src/account.ts @@ -4,54 +4,54 @@ import { createDelegation, type ToMetaMaskSmartAccountReturnType, type Delegation, -} from "@metamask/smart-accounts-kit"; -import { privateKeyToAccount } from "viem/accounts"; -import { createPublicClient, http, type Hex, type Chain } from "viem"; -import * as chains from "viem/chains"; +} from '@metamask/smart-accounts-kit' +import { PrivateKeyAccount, privateKeyToAccount } from 'viem/accounts' +import { createPublicClient, http, type Hex, type Chain } from 'viem' +import * as chains from 'viem/chains' -export type HybridSmartAccount = ToMetaMaskSmartAccountReturnType; +export type HybridSmartAccount = ToMetaMaskSmartAccountReturnType export function resolveChain(chainName: string): Chain { - const chain = (chains as Record)[chainName]; + const chain = (chains as Record)[chainName] if (!chain) { throw new Error( `Unknown chain "${chainName}". Use a viem chain name (e.g. sepolia, mainnet, polygon, arbitrum).` - ); + ) } - return chain; + return chain } export async function createSmartAccount( privateKey: Hex, chainName: string -): Promise<{ smartAccount: HybridSmartAccount; address: string; owner: any }> { - const chain = resolveChain(chainName); +): Promise<{ smartAccount: HybridSmartAccount; address: string; owner: PrivateKeyAccount }> { + const chain = resolveChain(chainName) const publicClient = createPublicClient({ chain, transport: http(), - }); + }) - const owner = privateKeyToAccount(privateKey); + const owner = privateKeyToAccount(privateKey) const smartAccount = await toMetaMaskSmartAccount({ client: publicClient, implementation: Implementation.Hybrid, deployParams: [owner.address, [], [], []], - deploySalt: "0x", - signer: { account: owner } - }); + deploySalt: '0x', + signer: { account: owner }, + }) - const address = await smartAccount.getAddress(); - return { smartAccount, address, owner }; + const address = await smartAccount.getAddress() + return { smartAccount, address, owner } } export async function getSmartAccount( privateKey: Hex, chainName: string ): Promise { - const { smartAccount } = await createSmartAccount(privateKey, chainName); - return smartAccount; + const { smartAccount } = await createSmartAccount(privateKey, chainName) + return smartAccount } export function createSubdelegation({ @@ -61,15 +61,15 @@ export function createSubdelegation({ tokenAddress, maxAmount, }: { - smartAccount: HybridSmartAccount; - delegateAddress: Hex; - parentDelegation?: Delegation; - tokenAddress: Hex; - maxAmount: bigint; + smartAccount: HybridSmartAccount + delegateAddress: Hex + parentDelegation?: Delegation + tokenAddress: Hex + maxAmount: bigint }): Delegation { return createDelegation({ scope: { - type: "erc20TransferAmount", + type: 'erc20TransferAmount', tokenAddress, maxAmount, }, @@ -77,5 +77,5 @@ export function createSubdelegation({ from: smartAccount.address, parentDelegation, environment: smartAccount.environment, - }); + }) } diff --git a/src/api.ts b/src/api.ts index 66c3820..9e9eee0 100644 --- a/src/api.ts +++ b/src/api.ts @@ -1,21 +1,21 @@ -const BASE_URL = "https://app.coinfello.com/api/v1"; +const BASE_URL = 'https://app.coinfello.com/api/v1' export async function getCoinFelloAddress(): Promise { - const response = await fetch(`${BASE_URL}/coinfello-address`); + const response = await fetch(`${BASE_URL}/coinfello-address`) if (!response.ok) { - const text = await response.text(); - throw new Error(`Failed to get CoinFello address (${response.status}): ${text}`); + const text = await response.text() + throw new Error(`Failed to get CoinFello address (${response.status}): ${text}`) } - const data = (await response.json()) as { address: string }; - return data.address; + const data = (await response.json()) as { address: string } + return data.address } export interface SendConversationParams { - prompt: string; - signedSubdelegation: unknown; - smartAccountAddress: string; + prompt: string + signedSubdelegation: unknown + smartAccountAddress: string } export async function sendConversation({ @@ -24,34 +24,30 @@ export async function sendConversation({ smartAccountAddress, }: SendConversationParams): Promise<{ txn_id: string }> { const response = await fetch(`${BASE_URL}/conversation`, { - method: "POST", - headers: { "Content-Type": "application/json" }, + method: 'POST', + headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ prompt, signed_subdelegation: signedSubdelegation, smart_account_address: smartAccountAddress, }), - }); + }) if (!response.ok) { - const text = await response.text(); - throw new Error(`Conversation request failed (${response.status}): ${text}`); + const text = await response.text() + throw new Error(`Conversation request failed (${response.status}): ${text}`) } - return response.json() as Promise<{ txn_id: string }>; + return response.json() as Promise<{ txn_id: string }> } -export async function getTransactionStatus( - txnId: string -): Promise> { - const response = await fetch( - `${BASE_URL}/transaction_status?txn_id=${encodeURIComponent(txnId)}` - ); +export async function getTransactionStatus(txnId: string): Promise> { + const response = await fetch(`${BASE_URL}/transaction_status?txn_id=${encodeURIComponent(txnId)}`) if (!response.ok) { - const text = await response.text(); - throw new Error(`Transaction status request failed (${response.status}): ${text}`); + const text = await response.text() + throw new Error(`Transaction status request failed (${response.status}): ${text}`) } - return response.json() as Promise>; + return response.json() as Promise> } diff --git a/src/config.ts b/src/config.ts index 91b79af..12d285b 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,32 +1,32 @@ -import { readFile, writeFile, mkdir } from "node:fs/promises"; -import { homedir } from "node:os"; -import { join } from "node:path"; -import type { Delegation } from "@metamask/smart-accounts-kit"; +import { readFile, writeFile, mkdir } from 'node:fs/promises' +import { homedir } from 'node:os' +import { join } from 'node:path' +import type { Delegation } from '@metamask/smart-accounts-kit' export interface Config { - private_key?: string; - smart_account_address?: string; - chain?: string; - delegation?: Delegation; - session_token?: string; + private_key?: string + smart_account_address?: string + chain?: string + delegation?: Delegation + session_token?: string } -const CONFIG_DIR = join(homedir(), ".clawdbot", "skills", "coinfello"); -export const CONFIG_PATH = join(CONFIG_DIR, "config.json"); +const CONFIG_DIR = join(homedir(), '.clawdbot', 'skills', 'coinfello') +export const CONFIG_PATH = join(CONFIG_DIR, 'config.json') export async function loadConfig(): Promise { try { - const raw = await readFile(CONFIG_PATH, "utf-8"); - return JSON.parse(raw) as Config; + const raw = await readFile(CONFIG_PATH, 'utf-8') + return JSON.parse(raw) as Config } catch (err: unknown) { - if ((err as NodeJS.ErrnoException).code === "ENOENT") { - return {}; + if ((err as NodeJS.ErrnoException).code === 'ENOENT') { + return {} } - throw err; + throw err } } export async function saveConfig(config: Config): Promise { - await mkdir(CONFIG_DIR, { recursive: true }); - await writeFile(CONFIG_PATH, JSON.stringify(config, null, 2), "utf-8"); + await mkdir(CONFIG_DIR, { recursive: true }) + await writeFile(CONFIG_PATH, JSON.stringify(config, null, 2), 'utf-8') } diff --git a/src/index.ts b/src/index.ts index 672e21d..75a34c1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,237 +1,208 @@ -import { Command } from "commander"; -import { - createSmartAccount, - getSmartAccount, - createSubdelegation, -} from "./account.js"; -import { loadConfig, saveConfig, CONFIG_PATH } from "./config.js"; -import { - getCoinFelloAddress, - sendConversation, - getTransactionStatus, -} from "./api.js"; -import { signInWithAgent } from "./siwe.js"; -import { type Hex, parseUnits } from "viem"; -import { generatePrivateKey } from "viem/accounts"; -import type { Delegation } from "@metamask/smart-accounts-kit"; - -const program = new Command(); +import { Command } from 'commander' +import { createSmartAccount, getSmartAccount, createSubdelegation } from './account.js' +import { loadConfig, saveConfig, CONFIG_PATH } from './config.js' +import { getCoinFelloAddress, sendConversation, getTransactionStatus } from './api.js' +import { signInWithAgent } from './siwe.js' +import { type Hex, parseUnits } from 'viem' +import { generatePrivateKey } from 'viem/accounts' +import type { Delegation } from '@metamask/smart-accounts-kit' + +const program = new Command() program - .name("openclaw") - .description("CoinFello CLI - MetaMask Smart Account interactions") - .version("1.0.0"); + .name('openclaw') + .description('CoinFello CLI - MetaMask Smart Account interactions') + .version('1.0.0') // ── create_account ────────────────────────────────────────────── program - .command("create_account") - .description("Create a MetaMask smart account and save its address to local config") - .argument("", "Chain name (e.g. sepolia, mainnet, polygon, arbitrum)") + .command('create_account') + .description('Create a MetaMask smart account and save its address to local config') + .argument('', 'Chain name (e.g. sepolia, mainnet, polygon, arbitrum)') .action(async (chain: string) => { try { - console.log(`Creating smart account on ${chain}...`); - const privateKey = generatePrivateKey(); - const { address } = await createSmartAccount(privateKey, chain); - - const config = await loadConfig(); - config.private_key = privateKey; - config.smart_account_address = address; - config.chain = chain; - await saveConfig(config); - - console.log("Smart account created successfully."); - console.log(`Address: ${address}`); - console.log(`Config saved to: ${CONFIG_PATH}`); + console.log(`Creating smart account on ${chain}...`) + const privateKey = generatePrivateKey() + const { address } = await createSmartAccount(privateKey, chain) + + const config = await loadConfig() + config.private_key = privateKey + config.smart_account_address = address + config.chain = chain + await saveConfig(config) + + console.log('Smart account created successfully.') + console.log(`Address: ${address}`) + console.log(`Config saved to: ${CONFIG_PATH}`) } catch (err) { - console.error(`Failed to create account: ${(err as Error).message}`); - process.exit(1); + console.error(`Failed to create account: ${(err as Error).message}`) + process.exit(1) } - }); + }) // ── get_account ───────────────────────────────────────────────── program - .command("get_account") - .description("Display the current smart account address from local config") + .command('get_account') + .description('Display the current smart account address from local config') .action(async () => { try { - const config = await loadConfig(); + const config = await loadConfig() if (!config.smart_account_address) { - console.error( - "Error: No smart account found. Run 'create_account' first." - ); - process.exit(1); + console.error("Error: No smart account found. Run 'create_account' first.") + process.exit(1) } - console.log(config.smart_account_address); + console.log(config.smart_account_address) } catch (err) { - console.error(`Failed to get account: ${(err as Error).message}`); - process.exit(1); + console.error(`Failed to get account: ${(err as Error).message}`) + process.exit(1) } - }); + }) // ── sign_in ───────────────────────────────────────────────────── program - .command("sign_in") - .description("Sign in to a server using SIWE with your smart account") - .option("--base-url ", "The server base URL override (e.g. https://api.example.com)", "https://app.coinfello.com/api/auth") - .action(async (opts: {baseUrl: string}) => { + .command('sign_in') + .description('Sign in to a server using SIWE with your smart account') + .option( + '--base-url ', + 'The server base URL override (e.g. https://api.example.com)', + 'https://app.coinfello.com/api/auth' + ) + .action(async (opts: { baseUrl: string }) => { try { - console.log("Signing in with smart account..."); - const config = await loadConfig(); - const result = await signInWithAgent(opts.baseUrl, config); - console.log("Sign-in successful."); - console.log(`User ID: ${result.user.id}`); - console.log(`Session token saved to config.`); + console.log('Signing in with smart account...') + const config = await loadConfig() + const result = await signInWithAgent(opts.baseUrl, config) + console.log('Sign-in successful.') + console.log(`User ID: ${result.user.id}`) + console.log(`Session token saved to config.`) } catch (err) { - console.error(`Failed to sign in: ${(err as Error).message}`); - process.exit(1); + console.error(`Failed to sign in: ${(err as Error).message}`) + process.exit(1) } - }); + }) // ── set_delegation ────────────────────────────────────────────── program - .command("set_delegation") - .description("Store a signed delegation (JSON) in local config") - .argument("", "The signed delegation as a JSON string") + .command('set_delegation') + .description('Store a signed delegation (JSON) in local config') + .argument('', 'The signed delegation as a JSON string') .action(async (delegationJson: string) => { try { - const delegation = JSON.parse(delegationJson) as Delegation; + const delegation = JSON.parse(delegationJson) as Delegation - const config = await loadConfig(); - config.delegation = delegation; - await saveConfig(config); + const config = await loadConfig() + config.delegation = delegation + await saveConfig(config) - console.log("Delegation saved successfully."); - console.log(`Config saved to: ${CONFIG_PATH}`); + console.log('Delegation saved successfully.') + console.log(`Config saved to: ${CONFIG_PATH}`) } catch (err) { - console.error(`Failed to set delegation: ${(err as Error).message}`); - process.exit(1); + console.error(`Failed to set delegation: ${(err as Error).message}`) + process.exit(1) } - }); + }) // ── send_prompt ───────────────────────────────────────────────── program - .command("send_prompt") - .description( - "Send a prompt to CoinFello, creating and signing a subdelegation locally" - ) - .argument("", "The prompt to send") + .command('send_prompt') + .description('Send a prompt to CoinFello, creating and signing a subdelegation locally') + .argument('', 'The prompt to send') .requiredOption( - "--token-address
", - "ERC-20 token contract address for the subdelegation scope" - ) - .requiredOption( - "--amount ", - "Maximum token amount (human-readable, e.g. '5')" - ) - .option( - "--decimals ", - "Token decimals for parsing max-amount", - "18" - ) - .option( - "--use-redelegation", - "Create a redelegation from a stored parent delegation" + '--token-address
', + 'ERC-20 token contract address for the subdelegation scope' ) + .requiredOption('--amount ', "Maximum token amount (human-readable, e.g. '5')") + .option('--decimals ', 'Token decimals for parsing max-amount', '18') + .option('--use-redelegation', 'Create a redelegation from a stored parent delegation') .action( async ( prompt: string, opts: { - tokenAddress: string; - amount: string; - decimals: string; - useRedelegation?: boolean; + tokenAddress: string + amount: string + decimals: string + useRedelegation?: boolean } ) => { try { - const config = await loadConfig(); + const config = await loadConfig() if (!config.private_key) { - console.error( - "Error: No private key found in config. Run 'create_account' first." - ); - process.exit(1); + console.error("Error: No private key found in config. Run 'create_account' first.") + process.exit(1) } if (!config.smart_account_address) { - console.error( - "Error: No smart account found. Run 'create_account' first." - ); - process.exit(1); + console.error("Error: No smart account found. Run 'create_account' first.") + process.exit(1) } if (!config.chain) { - console.error( - "Error: No chain found in config. Run 'create_account' first." - ); - process.exit(1); + console.error("Error: No chain found in config. Run 'create_account' first.") + process.exit(1) } if (opts.useRedelegation && !config.delegation) { console.error( "Error: --use-redelegation requires a parent delegation. Run 'set_delegation' first." - ); - process.exit(1); + ) + process.exit(1) } // 1. Get CoinFello delegate address - console.log("Fetching CoinFello delegate address..."); - const delegateAddress = await getCoinFelloAddress(); + console.log('Fetching CoinFello delegate address...') + const delegateAddress = await getCoinFelloAddress() // 2. Rebuild smart account - console.log("Loading smart account..."); - const smartAccount = await getSmartAccount( - config.private_key as Hex, - config.chain - ); + console.log('Loading smart account...') + const smartAccount = await getSmartAccount(config.private_key as Hex, config.chain) // 3. Create subdelegation locally - console.log("Parsing amount..."); - const maxAmount = parseUnits(opts.amount, Number(opts.decimals)); - console.log("Creating subdelegation..."); + console.log('Parsing amount...') + const maxAmount = parseUnits(opts.amount, Number(opts.decimals)) + console.log('Creating subdelegation...') const subdelegation = createSubdelegation({ smartAccount, delegateAddress: delegateAddress as Hex, parentDelegation: opts.useRedelegation ? config.delegation : undefined, tokenAddress: opts.tokenAddress as Hex, maxAmount, - }); + }) // 4. Sign the subdelegation - console.log("Signing subdelegation..."); + console.log('Signing subdelegation...') const signature = await smartAccount.signDelegation({ delegation: subdelegation, - }); - const signedSubdelegation = { ...subdelegation, signature }; + }) + const signedSubdelegation = { ...subdelegation, signature } // 5. Send to conversation endpoint - console.log("Sending to conversation endpoint..."); + console.log('Sending to conversation endpoint...') const result = await sendConversation({ prompt, signedSubdelegation, smartAccountAddress: config.smart_account_address, - }); + }) - console.log("Transaction submitted successfully."); - console.log(`Transaction ID: ${result.txn_id}`); + console.log('Transaction submitted successfully.') + console.log(`Transaction ID: ${result.txn_id}`) } catch (err) { - console.error(`Failed to send prompt: ${(err as Error).message}`); - process.exit(1); + console.error(`Failed to send prompt: ${(err as Error).message}`) + process.exit(1) } } - ); + ) // ── get_transaction_status ────────────────────────────────────── program - .command("get_transaction_status") - .description("Check the status of a submitted transaction") - .argument("", "The transaction ID to check") + .command('get_transaction_status') + .description('Check the status of a submitted transaction') + .argument('', 'The transaction ID to check') .action(async (txnId: string) => { try { - const result = await getTransactionStatus(txnId); - console.log(JSON.stringify(result, null, 2)); + const result = await getTransactionStatus(txnId) + console.log(JSON.stringify(result, null, 2)) } catch (err) { - console.error( - `Failed to get transaction status: ${(err as Error).message}` - ); - process.exit(1); + console.error(`Failed to get transaction status: ${(err as Error).message}`) + process.exit(1) } - }); + }) -program.parse(); +program.parse() diff --git a/src/siwe.ts b/src/siwe.ts index da882c7..f6d8274 100644 --- a/src/siwe.ts +++ b/src/siwe.ts @@ -1,112 +1,53 @@ -import { createSiweMessage } from "viem/siwe"; -import { type Hex, type Address, keccak256, toHex, hashMessage, encodeFunctionData, pad, verifyHash, createPublicClient, http, parseErc6492Signature } from "viem"; -import { Config, loadConfig, saveConfig } from "./config.js"; -import { createSmartAccount, getSmartAccount, resolveChain } from "./account.js"; -import { signMessage } from "viem/experimental/erc7739"; -import { hardhat } from "viem/chains"; +import { createSiweMessage } from 'viem/siwe' +import { type Hex, type Address } from 'viem' +import { Config, saveConfig } from './config.js' +import { createSmartAccount, resolveChain } from './account.js' export interface SignInResult { - token: string; - success: boolean; + token: string + success: boolean user: { - id: string; - walletAddress: string; - chainId: number; - }; -} - -const factoryAbi = [ - { inputs: [], name: 'Create2EmptyBytecode', type: 'error' }, - { inputs: [], name: 'Create2FailedDeployment', type: 'error' }, - { - inputs: [ - { internalType: 'uint256', name: 'balance', type: 'uint256' }, - { internalType: 'uint256', name: 'needed', type: 'uint256' } - ], - name: 'Create2InsufficientBalance', - type: 'error' - }, - { - inputs: [{ internalType: 'address', name: 'deployed', type: 'address' }], - name: 'SimpleFactoryEmptyContract', - type: 'error' - }, - { - anonymous: false, - inputs: [ - { indexed: true, internalType: 'address', name: 'addr', type: 'address' } - ], - name: 'Deployed', - type: 'event' - }, - { - inputs: [ - { internalType: 'bytes32', name: '_bytecodeHash', type: 'bytes32' }, - { internalType: 'bytes32', name: '_salt', type: 'bytes32' } - ], - name: 'computeAddress', - outputs: [{ internalType: 'address', name: 'addr_', type: 'address' }], - stateMutability: 'view', - type: 'function' - }, - { - inputs: [ - { internalType: 'bytes', name: '_bytecode', type: 'bytes' }, - { internalType: 'bytes32', name: '_salt', type: 'bytes32' } - ], - name: 'deploy', - outputs: [{ internalType: 'address', name: 'addr_', type: 'address' }], - stateMutability: 'nonpayable', - type: 'function' + id: string + walletAddress: string + chainId: number } -] +} export async function signInWithAgent(baseUrl: string, config: Config): Promise { if (!config.private_key) { - throw new Error( - "No private key found in config. Run 'create_account' first." - ); + throw new Error("No private key found in config. Run 'create_account' first.") } if (!config.smart_account_address) { - throw new Error( - "No smart account address found in config. Run 'create_account' first." - ); + throw new Error("No smart account address found in config. Run 'create_account' first.") } if (!config.chain) { - throw new Error( - "No chain found in config. Run 'create_account' first." - ); + throw new Error("No chain found in config. Run 'create_account' first.") } - const chain = resolveChain(config.chain); - const chainId = chain.id; - const walletAddress = config.smart_account_address; + const chain = resolveChain(config.chain) + const chainId = chain.id + const walletAddress = config.smart_account_address - const {smartAccount, owner} = await createSmartAccount( - config.private_key as Hex, - config.chain - ); + const { smartAccount } = await createSmartAccount(config.private_key as Hex, config.chain) // Extract domain info from baseUrl - const url = new URL(baseUrl); - const domain = url.host; + const url = new URL(baseUrl) + const domain = url.host // Fetch nonce from server console.log('fetching nonce...') const nonceResponse = await fetch(`${baseUrl}/siwe/nonce`, { - method: "POST", - headers: { "Content-Type": "application/json" }, + method: 'POST', + headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ walletAddress, chainId }), - }); + }) if (!nonceResponse.ok) { - const text = await nonceResponse.text(); - throw new Error( - `Failed to fetch SIWE nonce (${nonceResponse.status}): ${text}` - ); + const text = await nonceResponse.text() + throw new Error(`Failed to fetch SIWE nonce (${nonceResponse.status}): ${text}`) } - const { nonce } = (await nonceResponse.json()) as { nonce: string }; + const { nonce } = (await nonceResponse.json()) as { nonce: string } // Construct SIWE message console.log('creating siwe message...') @@ -116,43 +57,40 @@ export async function signInWithAgent(baseUrl: string, config: Config): Promise< domain, nonce, uri: url.origin, - version: "1", - scheme: url.protocol.replace(":", ""), + version: '1', + scheme: url.protocol.replace(':', ''), issuedAt: new Date(), - }); + }) - // Sign with smart account + // Sign with smart account if (!smartAccount.signMessage) { - throw new Error("Smart account does not support signMessage()"); + throw new Error('Smart account does not support signMessage()') } - const signature = await smartAccount.signMessage({ message: message }); - + const signature = await smartAccount.signMessage({ message: message }) // Verify signature with server console.log('signing in with siwe message...') const verifyResponse = await fetch(`${baseUrl}/siwe/verify`, { - method: "POST", - headers: { "Content-Type": "application/json" }, + method: 'POST', + headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message, signature, walletAddress, chainId }), - }); + }) if (!verifyResponse.ok) { - const text = await verifyResponse.text(); - throw new Error( - `SIWE verification failed (${verifyResponse.status}): ${text}` - ); + const text = await verifyResponse.text() + throw new Error(`SIWE verification failed (${verifyResponse.status}): ${text}`) } - const result = (await verifyResponse.json()) as SignInResult; + const result = (await verifyResponse.json()) as SignInResult if (!result.success) { - throw new Error("SIWE verification returned success: false"); + throw new Error('SIWE verification returned success: false') } // Persist session token console.log('saving token...') - config.session_token = result.token; - await saveConfig(config); + config.session_token = result.token + await saveConfig(config) - return result; + return result } From 51c27f22acc16aa1939f1775c2c73ac5fb26ef89 Mon Sep 17 00:00:00 2001 From: BrettCleary <27568879+BrettCleary@users.noreply.github.com> Date: Wed, 18 Feb 2026 08:47:20 -0300 Subject: [PATCH 4/6] prettier coinfello skill too --- coinfello/SKILL.md | 21 +++----- coinfello/references/REFERENCE.md | 90 +++++++++++++++---------------- package.json | 4 +- 3 files changed, 53 insertions(+), 62 deletions(-) diff --git a/coinfello/SKILL.md b/coinfello/SKILL.md index bfa8fed..5bdf72f 100644 --- a/coinfello/SKILL.md +++ b/coinfello/SKILL.md @@ -1,21 +1,9 @@ --- name: coinfello -description: >- - Interact with CoinFello using the openclaw CLI to create MetaMask smart accounts, - manage delegations, send prompts with ERC-20 token subdelegations, and check - transaction status. Use when the user wants to send crypto transactions via - natural language prompts, manage smart account delegations, or check CoinFello - transaction results. +description: 'Interact with CoinFello using the openclaw CLI to create MetaMask smart accounts, manage delegations, send prompts with ERC-20 token subdelegations, and check transaction status. Use when the user wants to send crypto transactions via natural language prompts, manage smart account delegations, or check CoinFello transaction results.' compatibility: Requires Node.js 20+ and pnpm. -metadata: { - "openclaw": - { - "emoji": "👋", - "homepage":"https://coinfello.com", - "requires": - { "bins": ["node"] } - } -} +metadata: + {'clawdbot':{ 'emoji': '👋', 'homepage': 'https://coinfello.com', 'requires': { 'bins': ['node'] } },} --- # CoinFello CLI Skill @@ -96,14 +84,17 @@ openclaw send_prompt "" \ ``` **Required options:** + - `--token-address
` — ERC-20 token contract address for the subdelegation scope - `--amount ` — Maximum token amount in human-readable form (e.g. `5`, `100.5`) **Optional:** + - `--decimals ` — Token decimals for parsing `--amount` (default: `18`) - `--use-redelegation` — Create a redelegation from a stored parent delegation (requires `set_delegation` first) **What happens internally:** + 1. Fetches CoinFello's delegate address from the API 2. Rebuilds the smart account from the stored private key and chain in config 3. Creates a subdelegation scoped to `erc20TransferAmount` with the specified token and max amount diff --git a/coinfello/references/REFERENCE.md b/coinfello/references/REFERENCE.md index 1062b22..aabbede 100644 --- a/coinfello/references/REFERENCE.md +++ b/coinfello/references/REFERENCE.md @@ -22,12 +22,12 @@ Created automatically by `create_account`. Schema: } ``` -| Field | Type | Set by | Description | -| ------------------------ | ---------- | ---------------- | ------------------------------------------ | -| `private_key` | `string` | `create_account` | Auto-generated hex private key | -| `smart_account_address` | `string` | `create_account` | Counterfactual address of the smart account | -| `chain` | `string` | `create_account` | viem chain name used for account creation | -| `delegation` | `object` | `set_delegation` | Optional parent delegation for redelegation | +| Field | Type | Set by | Description | +| ----------------------- | -------- | ---------------- | ------------------------------------------- | +| `private_key` | `string` | `create_account` | Auto-generated hex private key | +| `smart_account_address` | `string` | `create_account` | Counterfactual address of the smart account | +| `chain` | `string` | `create_account` | viem chain name used for account creation | +| `delegation` | `object` | `set_delegation` | Optional parent delegation for redelegation | ## Command Reference @@ -37,9 +37,9 @@ Created automatically by `create_account`. Schema: openclaw create_account ``` -| Parameter | Type | Required | Description | -| --------- | -------- | -------- | ---------------------------------- | -| `chain` | `string` | Yes | viem chain name (see below) | +| Parameter | Type | Required | Description | +| --------- | -------- | -------- | --------------------------- | +| `chain` | `string` | Yes | viem chain name (see below) | Generates a new private key automatically and saves it along with the smart account address and chain to config. @@ -57,8 +57,8 @@ No parameters. Prints the stored smart account address from config. Exits with a openclaw set_delegation ``` -| Parameter | Type | Required | Description | -| ------------ | -------- | -------- | ----------------------------------------- | +| Parameter | Type | Required | Description | +| ------------ | -------- | -------- | --------------------------------------------------------------- | | `delegation` | `string` | Yes | JSON-encoded Delegation object from MetaMask Smart Accounts Kit | ### openclaw send_prompt @@ -67,13 +67,13 @@ openclaw set_delegation openclaw send_prompt --token-address --amount [--decimals ] [--use-redelegation] ``` -| Parameter | Type | Required | Default | Description | -| ------------------- | --------- | -------- | ------- | ------------------------------------------------ | -| `prompt` | `string` | Yes | — | Natural language prompt to send to CoinFello | -| `--token-address` | `string` | Yes | — | ERC-20 token contract address | -| `--amount` | `string` | Yes | — | Max token amount (human-readable, e.g. `"5"`) | -| `--decimals` | `string` | No | `"18"` | Token decimals for parsing amount | -| `--use-redelegation`| `boolean` | No | `false` | Use stored parent delegation for redelegation | +| Parameter | Type | Required | Default | Description | +| -------------------- | --------- | -------- | ------- | --------------------------------------------- | +| `prompt` | `string` | Yes | — | Natural language prompt to send to CoinFello | +| `--token-address` | `string` | Yes | — | ERC-20 token contract address | +| `--amount` | `string` | Yes | — | Max token amount (human-readable, e.g. `"5"`) | +| `--decimals` | `string` | No | `"18"` | Token decimals for parsing amount | +| `--use-redelegation` | `boolean` | No | `false` | Use stored parent delegation for redelegation | Uses the private key and chain stored in config (from `create_account`). @@ -83,34 +83,34 @@ Uses the private key and chain stored in config (from `create_account`). openclaw get_transaction_status ``` -| Parameter | Type | Required | Description | -| --------- | -------- | -------- | ---------------------------- | +| Parameter | Type | Required | Description | +| --------- | -------- | -------- | ------------------------------- | | `txn_id` | `string` | Yes | Transaction ID from send_prompt | ## Supported Chains Any chain exported by `viem/chains`. Common examples: -| Chain Name | Chain ID | Network | -| ------------ | -------- | ---------------------- | -| `mainnet` | 1 | Ethereum mainnet | -| `sepolia` | 11155111 | Ethereum Sepolia testnet | -| `polygon` | 137 | Polygon PoS | -| `arbitrum` | 42161 | Arbitrum One | -| `optimism` | 10 | OP Mainnet | -| `base` | 8453 | Base | -| `avalanche` | 43114 | Avalanche C-Chain | -| `bsc` | 56 | BNB Smart Chain | +| Chain Name | Chain ID | Network | +| ----------- | -------- | ------------------------ | +| `mainnet` | 1 | Ethereum mainnet | +| `sepolia` | 11155111 | Ethereum Sepolia testnet | +| `polygon` | 137 | Polygon PoS | +| `arbitrum` | 42161 | Arbitrum One | +| `optimism` | 10 | OP Mainnet | +| `base` | 8453 | Base | +| `avalanche` | 43114 | Avalanche C-Chain | +| `bsc` | 56 | BNB Smart Chain | ## API Endpoints Base URL: `https://app.coinfello.com/api/v1` -| Endpoint | Method | Description | -| --------------------------------- | ------ | -------------------------------- | -| `/coinfello-address` | GET | Returns CoinFello's delegate address | +| Endpoint | Method | Description | +| --------------------------------- | ------ | ------------------------------------- | +| `/coinfello-address` | GET | Returns CoinFello's delegate address | | `/conversation` | POST | Submits prompt + signed subdelegation | -| `/transaction_status?txn_id=` | GET | Returns transaction status | +| `/transaction_status?txn_id=` | GET | Returns transaction status | ### POST /conversation body @@ -124,19 +124,19 @@ Base URL: `https://app.coinfello.com/api/v1` ## Common Token Decimals -| Token | Decimals | Note | -| ----- | -------- | ----------------------------- | -| USDC | 6 | Use `--decimals 6` | -| USDT | 6 | Use `--decimals 6` | +| Token | Decimals | Note | +| ----- | -------- | ------------------------------- | +| USDC | 6 | Use `--decimals 6` | +| USDT | 6 | Use `--decimals 6` | | DAI | 18 | Default, no `--decimals` needed | | WETH | 18 | Default, no `--decimals` needed | ## Error Messages -| Error | Cause | Fix | -| ---------------------------------------------------------------------- | ---------------------------------- | ---------------------------------------- | -| `Unknown chain ""` | Invalid chain name | Use a valid viem chain name | -| `No private key found in config. Run 'create_account' first.` | Missing private key in config | Run `openclaw create_account ` | -| `No smart account found. Run 'create_account' first.` | Missing smart account in config | Run `openclaw create_account ` | -| `No chain found in config. Run 'create_account' first.` | Missing chain in config | Run `openclaw create_account ` | -| `--use-redelegation requires a parent delegation. Run 'set_delegation' first.` | No stored delegation | Run `openclaw set_delegation ''` | +| Error | Cause | Fix | +| ------------------------------------------------------------------------------ | ------------------------------- | -------------------------------------- | +| `Unknown chain ""` | Invalid chain name | Use a valid viem chain name | +| `No private key found in config. Run 'create_account' first.` | Missing private key in config | Run `openclaw create_account ` | +| `No smart account found. Run 'create_account' first.` | Missing smart account in config | Run `openclaw create_account ` | +| `No chain found in config. Run 'create_account' first.` | Missing chain in config | Run `openclaw create_account ` | +| `--use-redelegation requires a parent delegation. Run 'set_delegation' first.` | No stored delegation | Run `openclaw set_delegation ''` | diff --git a/package.json b/package.json index 54b3ec9..a5d8ae0 100644 --- a/package.json +++ b/package.json @@ -17,8 +17,8 @@ "build": "vite build", "codecheck": "tsc --noEmit", "lint": "eslint src", - "prettier-fix": "prettier --write src", - "prettier": "prettier --check src", + "prettier-fix": "prettier --write src coinfello", + "prettier": "prettier --check src coinfello", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], From 61606911c3b42a599599bbee7250c61e91b330c3 Mon Sep 17 00:00:00 2001 From: BrettCleary <27568879+BrettCleary@users.noreply.github.com> Date: Wed, 18 Feb 2026 08:49:07 -0300 Subject: [PATCH 5/6] add license --- LICENSE.md | 1 + package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 LICENSE.md diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..06d1047 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1 @@ +© 2026 HyperPlay Labs, Inc. - All Rights Reserved. \ No newline at end of file diff --git a/package.json b/package.json index a5d8ae0..2708216 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ }, "keywords": [], "author": "", - "license": "ISC", + "license": "UNLICENSED", "packageManager": "pnpm@10.24.0", "dependencies": { "@metamask/smart-accounts-kit": "0.4.0-beta.1", From 237a00979bc36a55893252213179c2d059a9e6cf Mon Sep 17 00:00:00 2001 From: BrettCleary <27568879+BrettCleary@users.noreply.github.com> Date: Wed, 18 Feb 2026 08:51:47 -0300 Subject: [PATCH 6/6] prettier --- coinfello/SKILL.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/coinfello/SKILL.md b/coinfello/SKILL.md index 5bdf72f..f2f2346 100644 --- a/coinfello/SKILL.md +++ b/coinfello/SKILL.md @@ -3,7 +3,10 @@ name: coinfello description: 'Interact with CoinFello using the openclaw CLI to create MetaMask smart accounts, manage delegations, send prompts with ERC-20 token subdelegations, and check transaction status. Use when the user wants to send crypto transactions via natural language prompts, manage smart account delegations, or check CoinFello transaction results.' compatibility: Requires Node.js 20+ and pnpm. metadata: - {'clawdbot':{ 'emoji': '👋', 'homepage': 'https://coinfello.com', 'requires': { 'bins': ['node'] } },} + { + 'clawdbot': + { 'emoji': '👋', 'homepage': 'https://coinfello.com', 'requires': { 'bins': ['node'] } }, + } --- # CoinFello CLI Skill