diff --git a/.changeset/README.md b/.changeset/README.md
new file mode 100644
index 000000000..e5b6d8d6a
--- /dev/null
+++ b/.changeset/README.md
@@ -0,0 +1,8 @@
+# Changesets
+
+Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
+with multi-package repos, or single-package repos to help you version and publish your code. You can
+find the full documentation for it [in our repository](https://github.com/changesets/changesets)
+
+We have a quick list of common questions to get you started engaging with this project in
+[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
diff --git a/.changeset/config.json b/.changeset/config.json
new file mode 100644
index 000000000..765c9d223
--- /dev/null
+++ b/.changeset/config.json
@@ -0,0 +1,14 @@
+{
+ "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
+ "changelog": "@changesets/cli/changelog",
+ "commit": false,
+ "fixed": [],
+ "linked": [],
+ "access": "public",
+ "baseBranch": "main",
+ "updateInternalDependencies": "patch",
+ "___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
+ "onlyUpdatePeerDependentsWhenOutOfRange": true
+ },
+ "ignore": []
+}
diff --git a/.env.example b/.env.example
index fdf442b9d..764c9ab79 100644
--- a/.env.example
+++ b/.env.example
@@ -1,7 +1,7 @@
E2E_PRIVATE_KEY_ONE=
E2E_PRIVATE_KEY_TWO=
-E2E_BICO_PAYMASTER_KEY_MUMBAI=
+BUNDLER_URL=https://bundler.biconomy.io/api/v2/80002/cJPK7B3ru.dd7f7861-190d-45ic-af80-6877f74b8f44
+E2E_BICO_PAYMASTER_KEY_AMOY=
E2E_BICO_PAYMASTER_KEY_BASE=
-E2E_BICO_PAYMASTER_KEY_OP=
-BICONOMY_SDK_DEBUG=true
-WITH_MAINNET_TESTS=false
\ No newline at end of file
+CHAIN_ID=80002
+CODECOV_TOKEN=
\ No newline at end of file
diff --git a/.eslintignore b/.eslintignore
deleted file mode 100644
index bc013db12..000000000
--- a/.eslintignore
+++ /dev/null
@@ -1,14 +0,0 @@
-# Ignore node_modules in the root and in all packages
-**/node_modules/
-
-# Ignore build or dist directories
-**/dist/
-**/build/
-**/coverage/
-
-# Ignore any auto-generated files
-**/typechain/
-
-# Ignore any config files
-*.config.js
-*.config.ts
\ No newline at end of file
diff --git a/.eslintrc.js b/.eslintrc.js
deleted file mode 100644
index ce0d3c84a..000000000
--- a/.eslintrc.js
+++ /dev/null
@@ -1,49 +0,0 @@
-module.exports = {
- parser: "@typescript-eslint/parser",
- extends: [
- "eslint:recommended",
- "plugin:@typescript-eslint/recommended",
- "airbnb-typescript/base",
- "plugin:import/typescript",
- "plugin:@typescript-eslint/eslint-recommended",
- "plugin:prettier/recommended",
- ],
- parserOptions: {
- ecmaVersion: 2020,
- sourceType: "module",
- project: "./tsconfig.eslint.json",
- },
- env: {
- node: true,
- es6: true,
- },
- plugins: ["@typescript-eslint", "prettier", "security", "import"],
- rules: {
- "prettier/prettier": "error",
- "no-var": "error",
- "prefer-const": "error",
- "no-unused-vars": ["warn", { argsIgnorePattern: "^_" }], // needs to be set to "error" later
- "no-console": "warn",
- "@typescript-eslint/naming-convention": "off", // needs to be removed later
- "@typescript-eslint/no-explicit-any": "off",
- "@typescript-eslint/explicit-module-boundary-types": "off",
- "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }],
- "security/detect-object-injection": "warn",
- "security/detect-unsafe-regex": "error",
- "security/detect-object-injection": "off", // turning off Injection Sink rule
- "@typescript-eslint/no-throw-literal": "off", // temp deactivated needs to be removed once fixed
- "@typescript-eslint/ban-ts-ignore": "off",
- "@typescript-eslint/ban-ts-comment": "off",
- "import/extensions": ["error", "ignorePackages"],
- "import/no-unresolved": "off",
- },
- settings: {},
- overrides: [
- {
- files: ["*.ts", "*.tsx"],
- rules: {
- "@typescript-eslint/explicit-function-return-type": ["warn", { allowExpressions: true }],
- },
- },
- ],
-};
diff --git a/.github/ISSUE_TEMPLATE/1_general_issue.yml b/.github/ISSUE_TEMPLATE/1_general_issue.yml
new file mode 100644
index 000000000..1e2fac688
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/1_general_issue.yml
@@ -0,0 +1,26 @@
+name: 💡 General Inquiry & Suggestions
+description: Share general questions or suggestions that don't fit other categories
+title: "[GENERAL] "
+labels: ["question", "enhancement"]
+body:
+ - type: markdown
+ attributes:
+ value: "Got a question or suggestion? We're all ears!"
+ - type: textarea
+ attributes:
+ label: Inquiry or Suggestion
+ description: What would you like to share with us?
+ placeholder: "I'm wondering about..."
+ validations:
+ required: false
+ - type: input
+ attributes:
+ label: Relevant Links or References
+ description: Optionally, add any relevant links or references.
+ placeholder: "e.g., https://github.com/example"
+ - type: checkboxes
+ attributes:
+ label: Code of Conduct
+ options:
+ - label: I agree to follow this project's Code of Conduct.
+ required: true
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/2_bug_report.yml
similarity index 94%
rename from .github/ISSUE_TEMPLATE/bug_report.yml
rename to .github/ISSUE_TEMPLATE/2_bug_report.yml
index 45f4d6bf0..038107e78 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/2_bug_report.yml
@@ -1,6 +1,7 @@
-name: Bug Report
-description: File a bug/issue
-title: "bug:
"
+name: 🐛 Bug Report & Test Failures
+description: Report unexpected behaviors or failing tests
+title: "[BUG] "
+labels: ["bug", "help wanted"]
body:
- type: markdown
attributes:
diff --git a/.github/ISSUE_TEMPLATE/3_feature_request.yml b/.github/ISSUE_TEMPLATE/3_feature_request.yml
new file mode 100644
index 000000000..9d1cc0b6e
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/3_feature_request.yml
@@ -0,0 +1,31 @@
+name: ✨ Feature Requests & Performance Improvements
+description: Suggest a new feature or performance enhancement
+title: "[FEATURE] "
+labels: ["enhancement", "good first issue"]
+body:
+ - type: markdown
+ attributes:
+ value: "Your suggestions inspire us to improve. Share your ideas below!"
+ - type: input
+ attributes:
+ label: Feature or Improvement Description
+ description: Describe the feature or improvement you're suggesting.
+ placeholder: "e.g., Add support for platform Z."
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: Benefits & Outcomes
+ description: Explain the benefits of your suggestion and the expected outcomes.
+ placeholder: "This improvement will improve performance by 30%..."
+ - type: input
+ attributes:
+ label: Any References?
+ description: Provide links or references to similar features or standards.
+ placeholder: "EIP-1234, https://github.com/example"
+ - type: checkboxes
+ attributes:
+ label: Code of Conduct
+ options:
+ - label: I agree to follow this project's Code of Conduct.
+ required: true
diff --git a/.github/ISSUE_TEMPLATE/4_security_report.yml b/.github/ISSUE_TEMPLATE/4_security_report.yml
new file mode 100644
index 000000000..6fc0ef4fa
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/4_security_report.yml
@@ -0,0 +1,31 @@
+name: 🔒 Security Pre-Screening
+description: Pre-screening for security-related reports
+title: "[SECURITY PRE-SCREEN] "
+labels: ["security", "triage needed"]
+body:
+ - type: markdown
+ attributes:
+ value: "Security is our top priority. If you've discovered a potential security issue please proceed."
+ - type: checkboxes
+ attributes:
+ label: Security Level Acknowledgement
+ options:
+ - label: "I understand this issue will be public. It is NOT critical or high risk and does not endanger deployed contracts. If it is please email: security@biconomy.io"
+ required: true
+ - type: input
+ attributes:
+ label: Overview
+ description: Provide a summary of the non-critical security concern or question.
+ placeholder: "e.g., Questions about the audit process."
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: Additional Details
+ description: Offer more detail on your concern or question.
+ placeholder: "Provide any additional context..."
+ - type: input
+ attributes:
+ label: Suggestions for Mitigation
+ description: (Optional) Suggest ways to address the concern.
+ placeholder: "Potential mitigation steps include..."
diff --git a/.github/ISSUE_TEMPLATE/5_document_improvement.yml b/.github/ISSUE_TEMPLATE/5_document_improvement.yml
new file mode 100644
index 000000000..a4b0b5257
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/5_document_improvement.yml
@@ -0,0 +1,33 @@
+name: 📚 Documentation Improvement
+description: Propose improvements or report issues with documentation
+title: "[DOCS] "
+labels: ["documentation"]
+body:
+ - type: markdown
+ attributes:
+ value: "Help us enhance our documentation for everyone."
+ - type: input
+ attributes:
+ label: Documentation Page/Section
+ description: Which page or section are you referring to?
+ placeholder: "e.g., README.md, TSDoc guidelines."
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: Suggested Improvements
+ description: Detail the improvements or corrections needed.
+ placeholder: "The section on XYZ could clarify..."
+ validations:
+ required: true
+ - type: input
+ attributes:
+ label: Additional Comments
+ description: Any other comments or suggestions?
+ placeholder: "Consider adding examples for..."
+ - type: checkboxes
+ attributes:
+ label: Code of Conduct
+ options:
+ - label: I agree to follow this project's Code of Conduct.
+ required: true
diff --git a/.github/ISSUE_TEMPLATE/6_build_deployment_issue.yml b/.github/ISSUE_TEMPLATE/6_build_deployment_issue.yml
new file mode 100644
index 000000000..e0034b17e
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/6_build_deployment_issue.yml
@@ -0,0 +1,33 @@
+name: 🛠 Build & Deployment Issues
+description: Report issues
+title: "[BUILD/DEPLOY] "
+labels: ["bug", "help wanted"]
+body:
+ - type: markdown
+ attributes:
+ value: "Help us identify build or deployment problems to improve our processes."
+ - type: input
+ attributes:
+ label: Issue Summary
+ description: Briefly describe the issue encountered.
+ placeholder: "e.g., Failed to deploy contract due to..."
+ validations:
+ required: true
+ - type: textarea
+ attributes:
+ label: Error Logs & Messages
+ description: Provide any error logs or messages seen.
+ placeholder: "Error: Failed to..."
+ validations:
+ required: true
+ - type: input
+ attributes:
+ label: Environment & Tools
+ description: Mention the tools and environment where the issue occurred.
+ placeholder: "e.g., Truffle v5.3, Rinkeby testnet"
+ - type: checkboxes
+ attributes:
+ label: Code of Conduct
+ options:
+ - label: I agree to follow this project's Code of Conduct.
+ required: true
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
deleted file mode 100644
index 5b7de7d5d..000000000
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-blank_issues_enabled: false
-contact_links:
- - name: Ask Question
- url: https://github.com/bcnmy/biconomy-client-sdk/discussions
- about: Ask questions and discuss with other community members
- - name: Request Feature
- url: https://github.com/bcnmy/biconomy-client-sdk/discussions
- about: Requests features or brainstorm ideas for new functionality
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
deleted file mode 100644
index 3e93355fb..000000000
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-name: Feature Request
-about: Propose an enhancement or new feature to improve the project
-title: "Feature: "
-labels: feature-request, needs-review
-assignees: ""
----
-
-**Problem You're Facing**
-
-
-
-**Proposed Solution**
-
-
-
-**Alternatives Considered**
-
-
-
-## Use Cases
-
-
-
-**Additional Info**
-
-
diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md
new file mode 100644
index 000000000..35e920656
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md
@@ -0,0 +1,22 @@
+## Pull Request for SDK Improvement
+
+**Describe your changes:**
+
+
+
+**Link any related issues:**
+
+
+
+**Testing:**
+
+
+
+**Note:** Please ensure all tests and lint checks pass before requesting a review. If there are any errors, fix them prior to submission.
+
+**Checklist:**
+
+- [ ] I have performed a self-review of my own code.
+- [ ] I have added tests that prove my fix is effective or that my feature works.
+- [ ] I have made corresponding changes to the documentation, if applicable.
+- [ ] My changes generate no new warnings or errors.
diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml
new file mode 100644
index 000000000..1cd962cb5
--- /dev/null
+++ b/.github/actions/build/action.yml
@@ -0,0 +1,16 @@
+name: "Build"
+description: "Prepare repository, all dependencies and build"
+
+runs:
+ using: "composite"
+ steps:
+ - name: Set up Bun
+ uses: oven-sh/setup-bun@v1
+
+ - name: Install dependencies
+ shell: bash
+ run: bun install --frozen-lockfile
+
+ - name: Build
+ shell: bash
+ run: bun run build
diff --git a/.github/actions/install-dependencies/action.yml b/.github/actions/install-dependencies/action.yml
new file mode 100644
index 000000000..3dbb2bd0b
--- /dev/null
+++ b/.github/actions/install-dependencies/action.yml
@@ -0,0 +1,13 @@
+name: "Install dependencies"
+description: "Prepare repository and all dependencies"
+
+runs:
+ using: "composite"
+ steps:
+ - name: Set up Bun
+ uses: oven-sh/setup-bun@v1
+
+ - name: Install dependencies
+ shell: bash
+ run: |
+ bun install --frozen-lockfile
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
deleted file mode 100644
index 9b66596c9..000000000
--- a/.github/pull_request_template.md
+++ /dev/null
@@ -1,35 +0,0 @@
-# Summary
-
-
-
-Related Issue: # (issue number)
-
-## Change Type
-
-- [ ] Bug Fix
-- [ ] Refactor
-- [ ] New Feature
-- [ ] Breaking Change
-- [ ] Documentation Update
-- [ ] Performance Improvement
-- [ ] Other
-
-# Checklist
-
-- [ ] My code follows this project's style guidelines
-- [ ] I've reviewed my own code
-- [ ] I've added comments for any hard-to-understand areas
-- [ ] I've updated the documentation if necessary
-- [ ] My changes generate no new warnings
-- [ ] I've added tests that prove my fix is effective or my feature works
-- [ ] All unit tests pass locally with my changes
-- [ ] Any dependent changes have been merged and published
-
-# Additional Information
-
-
-
-# Branch Naming
-
-
-
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 000000000..08c18cd34
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,14 @@
+name: build
+on:
+ workflow_dispatch:
+ pull_request:
+ types: [opened, reopened, synchronize, ready_for_review]
+jobs:
+ build:
+ name: build
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Build
+ uses: ./.github/actions/build
diff --git a/.github/workflows/check_branch_name.yml b/.github/workflows/check_branch_name.yml
deleted file mode 100644
index 39422432d..000000000
--- a/.github/workflows/check_branch_name.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-name: Check Branch Name
-
-on:
- create:
- types: [branch]
-
-jobs:
- check-branch-name:
- runs-on: ubuntu-latest
- if: github.event.ref_type == 'branch'
- steps:
- - name: Ensure branch name follows GitFlow conventions
- run: |
- BRANCH_NAME="${{ github.ref#refs/heads/ }}"
- echo "Created branch: $BRANCH_NAME"
-
- # Checking against GitFlow naming conventions for branches
- if [[ ! $BRANCH_NAME =~ ^(features/|fixes/|releases/) ]]; then
- echo "error: Branch names should follow GitFlow naming convention (features/, fixes/, releases/)."
- exit 1
- fi
diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml
new file mode 100644
index 000000000..653e7b1e3
--- /dev/null
+++ b/.github/workflows/coverage.yml
@@ -0,0 +1,44 @@
+name: coverage
+on:
+ workflow_dispatch:
+ push:
+ branches:
+ - main
+jobs:
+ coverage:
+ name: coverage
+ permissions: write-all
+ runs-on: ubuntu-latest
+ concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Install dependencies
+ uses: ./.github/actions/install-dependencies
+
+ - name: Run the tests
+ run: bun run test:coverage
+ env:
+ E2E_PRIVATE_KEY_ONE: ${{ secrets.E2E_PRIVATE_KEY_ONE }}
+ E2E_PRIVATE_KEY_TWO: ${{ secrets.E2E_PRIVATE_KEY_TWO }}
+ BUNDLER_URL: https://bundler.biconomy.io/api/v2/80002/cJPK7B3ru.dd7f7861-190d-45ic-af80-6877f74b8f44
+ E2E_BICO_PAYMASTER_KEY_BASE: ${{ secrets.E2E_BICO_PAYMASTER_KEY_BASE }}
+ E2E_BICO_PAYMASTER_KEY_AMOY: ${{ secrets.E2E_BICO_PAYMASTER_KEY_AMOY }}
+ CHAIN_ID: 80002
+
+ - name: report coverage
+ uses: davelosert/vitest-coverage-report-action@v2
+ with:
+ json-summary-path: ./coverage/coverage-summary.json
+ json-final-path: "./coverage/coverage-final.json"
+ vite-config-path: ./tests/vitest.config.ts
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Upload coverage reports to Codecov
+ uses: codecov/codecov-action@v4.0.1
+ with:
+ token: ${{ secrets.CODECOV_TOKEN }}
+ verbose: true
+ slug: bcnmy/biconomy-client-sdk
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 188b963b1..078b083ba 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -1,26 +1,30 @@
-name: Build and Deploy Documentation
+name: deploy docs
on:
workflow_dispatch:
push:
branches:
- - docs
+ - main
permissions:
contents: write
jobs:
- build-docs-and-deploy:
+ deploy-docs:
runs-on: ubuntu-latest
steps:
- - name: Checkout 🛎️
- uses: actions/checkout@v3
+ - uses: actions/checkout@v3
+ - run: git config --global user.email "gh@runner.com"
+ - run: git config --global user.name "gh-runner"
- - name: Install and Build
- run: |
- yarn
- yarn build
- yarn --cwd ./packages/account docs
+ - name: Install dependencies
+ uses: ./.github/actions/install-dependencies
+
+ - name: Set remote url
+ run: git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/bcnmy/biconomy-client-sdk.git
+
+ - name: Run the tests
+ run: bun run docs:deploy
- name: Deploy 🚀
uses: JamesIves/github-pages-deploy-action@v4
with:
- folder: ./packages/account/docs
+ folder: ./docs
diff --git a/.github/workflows/mainnet_tests.yml b/.github/workflows/mainnet_tests.yml
deleted file mode 100644
index 3118a1e94..000000000
--- a/.github/workflows/mainnet_tests.yml
+++ /dev/null
@@ -1,32 +0,0 @@
-name: E2E Test workflow - with mainnet tests
-on:
- workflow_dispatch:
-jobs:
- e2e_test:
- name: E2E tests - with mainnet tests
- runs-on: ubuntu-latest
- strategy:
- matrix:
- node-version: [18.x]
-
- steps:
- - name: Checkout
- uses: "actions/checkout@main"
-
- - name: Set Node.js
- uses: actions/setup-node@v1
- with:
- node-version: ${{ matrix.node-version }}
-
- - name: Install dependencies
- run: yarn install --frozen-lockfile && yarn build
-
- - name: Run tests
- env:
- E2E_PRIVATE_KEY_ONE: ${{ secrets.E2E_PRIVATE_KEY_ONE }}
- E2E_PRIVATE_KEY_TWO: ${{ secrets.E2E_PRIVATE_KEY_TWO }}
- E2E_BICO_PAYMASTER_KEY_MUMBAI: ${{ secrets.E2E_BICO_PAYMASTER_KEY_MUMBAI }}
- E2E_BICO_PAYMASTER_KEY_BASE: ${{ secrets.E2E_BICO_PAYMASTER_KEY_BASE }}
- E2E_BICO_PAYMASTER_KEY_OP: ${{ secrets.E2E_BICO_PAYMASTER_KEY_OP }}
- WITH_MAINNET_TESTS: true
- run: yarn test:e2e
diff --git a/.github/workflows/mark_stale.yml b/.github/workflows/mark_stale.yml
deleted file mode 100644
index 1864296c5..000000000
--- a/.github/workflows/mark_stale.yml
+++ /dev/null
@@ -1,22 +0,0 @@
-name: Mark Inactive Issues and PRs
-
-on:
- schedule:
- - cron: "0 0 * * *"
-
-jobs:
- stale:
- runs-on: ubuntu-latest
- permissions:
- issues: write
- pull-requests: write
-
- steps:
- - uses: actions/stale@v5
- with:
- repo-token: ${{ secrets.GITHUB_TOKEN }}
- stale-issue-message: "This issue has been inactive for 30 days. It will be closed due to inactivity. If this issue is still relevant, please comment to keep it open. Alternatively, you can create a new issue with updated information."
- stale-pr-message: "This PR has been inactive for 30 days. If it's waiting for a review, please reach out to the team. Otherwise, please update the PR or it will be closed due to inactivity."
- stale-issue-label: "inactive-issue"
- stale-pr-label: "inactive-pr"
- days-before-stale: 30
diff --git a/.github/workflows/pr-lint.yml b/.github/workflows/pr-lint.yml
new file mode 100644
index 000000000..3e77f7837
--- /dev/null
+++ b/.github/workflows/pr-lint.yml
@@ -0,0 +1,17 @@
+name: pr lint
+on:
+ workflow_dispatch:
+ pull_request:
+ types: [opened, reopened, synchronize, ready_for_review, edited]
+jobs:
+ enforce_title:
+ name: pr lint
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Install dependencies
+ uses: ./.github/actions/install-dependencies
+
+ - name: Use commitlint to check PR title
+ run: echo "${{ github.event.pull_request.title }}" | bun commitlint
diff --git a/.github/workflows/pull_request_approved.yml b/.github/workflows/pull_request_approved.yml
deleted file mode 100644
index 84688b90b..000000000
--- a/.github/workflows/pull_request_approved.yml
+++ /dev/null
@@ -1,34 +0,0 @@
-name: E2E Test workflow
-on:
- pull_request_review:
- types: [submitted]
- workflow_dispatch:
-jobs:
- e2e_test:
- if: github.event.review.state == 'approved'
- name: E2E tests
- runs-on: ubuntu-latest
- strategy:
- matrix:
- node-version: [18.x]
-
- steps:
- - name: Checkout
- uses: "actions/checkout@main"
-
- - name: Set Node.js
- uses: actions/setup-node@v1
- with:
- node-version: ${{ matrix.node-version }}
-
- - name: Install dependencies
- run: yarn install --frozen-lockfile && yarn build
-
- - name: Run tests
- env:
- E2E_PRIVATE_KEY_ONE: ${{ secrets.E2E_PRIVATE_KEY_ONE }}
- E2E_PRIVATE_KEY_TWO: ${{ secrets.E2E_PRIVATE_KEY_TWO }}
- E2E_BICO_PAYMASTER_KEY_MUMBAI: ${{ secrets.E2E_BICO_PAYMASTER_KEY_MUMBAI }}
- E2E_BICO_PAYMASTER_KEY_BASE: ${{ secrets.E2E_BICO_PAYMASTER_KEY_BASE }}
- E2E_BICO_PAYMASTER_KEY_OP: ${{ secrets.E2E_BICO_PAYMASTER_KEY_OP }}
- run: yarn test:e2e
diff --git a/.github/workflows/push_check.yml b/.github/workflows/push_check.yml
deleted file mode 100644
index 35705a430..000000000
--- a/.github/workflows/push_check.yml
+++ /dev/null
@@ -1,44 +0,0 @@
-name: Test workflow
-on: [push, workflow_dispatch]
-
-jobs:
- lint:
- name: Lint sources
- runs-on: ubuntu-latest
- strategy:
- matrix:
- node-version: [18.x]
-
- steps:
- - name: Checkout
- uses: "actions/checkout@main"
-
- - name: Set Node.js
- uses: actions/setup-node@v1
- with:
- node-version: ${{ matrix.node-version }}
- - name: Install dependencies
- run: yarn install --frozen-lockfile
- - name: Lint sources
- run: yarn run lint
-
- unit_test:
- name: Unit tests
- runs-on: ubuntu-latest
- strategy:
- matrix:
- node-version: [18.x]
-
- steps:
- - name: Checkout
- uses: "actions/checkout@main"
-
- - name: Set Node.js
- uses: actions/setup-node@v1
- with:
- node-version: ${{ matrix.node-version }}
-
- - name: Install dependencies
- run: yarn install --frozen-lockfile && yarn build
- - name: Run tests
- run: yarn test
diff --git a/.github/workflows/size-report.yml b/.github/workflows/size-report.yml
new file mode 100644
index 000000000..0cbdac716
--- /dev/null
+++ b/.github/workflows/size-report.yml
@@ -0,0 +1,34 @@
+name: size report
+on:
+ workflow_dispatch:
+ pull_request:
+ types: [opened, reopened, synchronize, ready_for_review]
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
+ cancel-in-progress: true
+
+jobs:
+ size-report:
+ name: size report
+ runs-on: ubuntu-latest
+ timeout-minutes: 5
+ permissions: write-all
+
+ steps:
+ - name: Clone repository
+ uses: actions/checkout@v3
+
+ - name: Set up Bun
+ uses: oven-sh/setup-bun@v1
+
+ - name: Install dependencies
+ shell: bash
+ run: |
+ bun install --frozen-lockfile
+
+ - name: Report bundle size
+ uses: andresz1/size-limit-action@master
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ package_manager: bun
diff --git a/.github/workflows/test-read.yml b/.github/workflows/test-read.yml
new file mode 100644
index 000000000..4a36c8c45
--- /dev/null
+++ b/.github/workflows/test-read.yml
@@ -0,0 +1,28 @@
+name: test-read
+on:
+ workflow_dispatch:
+ pull_request:
+ types: [opened, reopened, synchronize, ready_for_review]
+jobs:
+ test-read:
+ name: test-read
+ permissions: write-all
+ runs-on: ubuntu-latest
+ concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Install dependencies
+ uses: ./.github/actions/install-dependencies
+
+ - name: Run the tests
+ run: bun run test:ci -t=Read
+ env:
+ E2E_PRIVATE_KEY_ONE: ${{ secrets.E2E_PRIVATE_KEY_ONE }}
+ E2E_PRIVATE_KEY_TWO: ${{ secrets.E2E_PRIVATE_KEY_TWO }}
+ BUNDLER_URL: https://bundler.biconomy.io/api/v2/80002/cJPK7B3ru.dd7f7861-190d-45ic-af80-6877f74b8f44
+ E2E_BICO_PAYMASTER_KEY_BASE: ${{ secrets.E2E_BICO_PAYMASTER_KEY_BASE }}
+ E2E_BICO_PAYMASTER_KEY_AMOY: ${{ secrets.E2E_BICO_PAYMASTER_KEY_AMOY }}
+ CHAIN_ID: 80002
diff --git a/.github/workflows/test-write.yml b/.github/workflows/test-write.yml
new file mode 100644
index 000000000..ee749bdbe
--- /dev/null
+++ b/.github/workflows/test-write.yml
@@ -0,0 +1,60 @@
+name: test-write
+on:
+ workflow_dispatch:
+ pull_request_review:
+ types: [submitted]
+ pull_request:
+ types: [opened]
+jobs:
+ test-write:
+ name: test-write
+ permissions: write-all
+ runs-on: ubuntu-latest
+ concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}-test-write
+ cancel-in-progress: true
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Install dependencies
+ uses: ./.github/actions/install-dependencies
+
+ - name: Run the account tests
+ run: bun run test:ci -t=Account:Write
+ env:
+ E2E_PRIVATE_KEY_ONE: ${{ secrets.E2E_PRIVATE_KEY_ONE }}
+ E2E_PRIVATE_KEY_TWO: ${{ secrets.E2E_PRIVATE_KEY_TWO }}
+ BUNDLER_URL: https://bundler.biconomy.io/api/v2/80002/cJPK7B3ru.dd7f7861-190d-45ic-af80-6877f74b8f44
+ E2E_BICO_PAYMASTER_KEY_BASE: ${{ secrets.E2E_BICO_PAYMASTER_KEY_BASE }}
+ E2E_BICO_PAYMASTER_KEY_AMOY: ${{ secrets.E2E_BICO_PAYMASTER_KEY_AMOY }}
+ CHAIN_ID: 80002
+
+ - name: Run the bundler tests
+ run: bun run test:ci -t=Bundler:Write
+ env:
+ E2E_PRIVATE_KEY_ONE: ${{ secrets.E2E_PRIVATE_KEY_ONE }}
+ E2E_PRIVATE_KEY_TWO: ${{ secrets.E2E_PRIVATE_KEY_TWO }}
+ BUNDLER_URL: https://bundler.biconomy.io/api/v2/80002/cJPK7B3ru.dd7f7861-190d-45ic-af80-6877f74b8f44
+ E2E_BICO_PAYMASTER_KEY_BASE: ${{ secrets.E2E_BICO_PAYMASTER_KEY_BASE }}
+ E2E_BICO_PAYMASTER_KEY_AMOY: ${{ secrets.E2E_BICO_PAYMASTER_KEY_AMOY }}
+ CHAIN_ID: 80002
+
+ - name: Run the paymaster tests
+ run: bun run test:ci -t=Paymaster:Write
+ env:
+ E2E_PRIVATE_KEY_ONE: ${{ secrets.E2E_PRIVATE_KEY_ONE }}
+ E2E_PRIVATE_KEY_TWO: ${{ secrets.E2E_PRIVATE_KEY_TWO }}
+ BUNDLER_URL: https://bundler.biconomy.io/api/v2/80002/cJPK7B3ru.dd7f7861-190d-45ic-af80-6877f74b8f44
+ E2E_BICO_PAYMASTER_KEY_BASE: ${{ secrets.E2E_BICO_PAYMASTER_KEY_BASE }}
+ E2E_BICO_PAYMASTER_KEY_AMOY: ${{ secrets.E2E_BICO_PAYMASTER_KEY_AMOY }}
+ CHAIN_ID: 80002
+
+ - name: Run the modules tests
+ run: bun run test:ci -t=Modules:Write
+ env:
+ E2E_PRIVATE_KEY_ONE: ${{ secrets.E2E_PRIVATE_KEY_ONE }}
+ E2E_PRIVATE_KEY_TWO: ${{ secrets.E2E_PRIVATE_KEY_TWO }}
+ BUNDLER_URL: https://bundler.biconomy.io/api/v2/80002/cJPK7B3ru.dd7f7861-190d-45ic-af80-6877f74b8f44
+ E2E_BICO_PAYMASTER_KEY_BASE: ${{ secrets.E2E_BICO_PAYMASTER_KEY_BASE }}
+ E2E_BICO_PAYMASTER_KEY_AMOY: ${{ secrets.E2E_BICO_PAYMASTER_KEY_AMOY }}
+ CHAIN_ID: 80002
diff --git a/.gitignore b/.gitignore
index ac3583499..41980e0af 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,75 +1,180 @@
+_cjs
+_esm
+_types
+
# Logs
+
logs
-*.log
+_.log
+npm-debug.log_
yarn-debug.log*
yarn-error.log*
-lockfiles
+lerna-debug.log*
+.pnpm-debug.log*
+
+# Caches
+
+.cache
# Diagnostic reports (https://nodejs.org/api/report.html)
-report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
-# Coverage directory used by tools like istanbul
+report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
+
+# Runtime data
+
+pids
+_.pid
+_.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
coverage
+lib-cov
+
+# Coverage directory used by tools like istanbul
*.lcov
# nyc test coverage
+
.nyc_output
-# Compiled binary addons
-build/
-dist/
+# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
+
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+
+bower_components
+
+# node-waf configuration
+
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+
+build/Release
# Dependency directories
+
node_modules/
+jspm_packages/
+
+# Snowpack dependency directory (https://snowpack.dev/)
+
+web_modules/
+
+# TypeScript cache
+
+*.tsbuildinfo
# Optional npm cache directory
+
.npm
# Optional eslint cache
+
.eslintcache
+# Optional stylelint cache
+
+.stylelintcache
+
+# Microbundle cache
+
+.rpt2_cache/
+.rts2_cache_cjs/
+.rts2_cache_es/
+.rts2_cache_umd/
+
+# Optional REPL history
+
+.node_repl_history
+
+# Output of 'npm pack'
+
+*.tgz
+
# Yarn Integrity file
+
.yarn-integrity
-# dotenv environment variables file
+# dotenv environment variable files
+
.env
-.env.test
+.env.development.local
+.env.test.local
+.env.production.local
.env.local
+# parcel-bundler cache (https://parceljs.org/)
+
+.parcel-cache
+
+# Next.js build output
+
+.next
+out
+
+# Nuxt.js build / generate output
+
+.nuxt
+dist
+
+# Gatsby files
+
+# Comment in the public line in if your project uses Gatsby and not Next.js
+
+# https://nextjs.org/blog/next-9-1#public-directory-support
+
+# public
+
+# vuepress build output
+
+.vuepress/dist
+
+# vuepress v2.x temp and cache directory
+
+.temp
+
+# Docusaurus cache and generated files
+
+.docusaurus
+
+# Serverless directories
+
+.serverless/
+
+# FuseBox cache
+
+.fusebox/
+
+# DynamoDB Local files
+
+.dynamodb/
+
+# TernJS port file
+
+.tern-port
+
# Stores VSCode versions used for testing VSCode extensions
+
.vscode
.vscode-test
# yarn v2
+
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
-# macOS
+# IntelliJ based IDEs
+.idea
+
+# Finder (MacOS) folder config
.DS_Store
-# Hardhat files
-cache
-artifacts
-deployments
-
-# lockfiles
-packages/account/package-lock.json
-packages/modules/package-lock.json
-packages/bundler/package-lock.json
-packages/paymaster/package-lock.json
-packages/particle-auth/package-lock.json
-packages/transak/package-lock.json
-package-lock.json
-
-#ignore sessionStorageData files
-packages/modules/tests/utils/sessionStorageData/*
-#except sessionStorageData folder
-!packages/modules/tests/utils/sessionStorageData/.gitkeep
-
-openapi/
-
-# docs
-packages/account/docs/*
\ No newline at end of file
+docs
+
+tests/sessionStorageData
\ No newline at end of file
diff --git a/.nvmrc b/.nvmrc
deleted file mode 100644
index b1215e876..000000000
--- a/.nvmrc
+++ /dev/null
@@ -1 +0,0 @@
-v18.16.0
\ No newline at end of file
diff --git a/.nycrc.json b/.nycrc.json
deleted file mode 100644
index 5d9f97afe..000000000
--- a/.nycrc.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "include": ["src/**/*.ts"]
-}
diff --git a/.prettierignore b/.prettierignore
deleted file mode 100644
index bc013db12..000000000
--- a/.prettierignore
+++ /dev/null
@@ -1,14 +0,0 @@
-# Ignore node_modules in the root and in all packages
-**/node_modules/
-
-# Ignore build or dist directories
-**/dist/
-**/build/
-**/coverage/
-
-# Ignore any auto-generated files
-**/typechain/
-
-# Ignore any config files
-*.config.js
-*.config.ts
\ No newline at end of file
diff --git a/.prettierrc.json b/.prettierrc.json
deleted file mode 100644
index 6b3f54736..000000000
--- a/.prettierrc.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "printWidth": 150,
- "semi": true,
- "singleQuote": false,
- "trailingComma": "all",
- "tabWidth": 2
-}
diff --git a/.size-limit.json b/.size-limit.json
new file mode 100644
index 000000000..a2bdf369c
--- /dev/null
+++ b/.size-limit.json
@@ -0,0 +1,37 @@
+[
+ {
+ "name": "core (esm)",
+ "path": "./dist/_esm/index.js",
+ "limit": "60 kB",
+ "import": "*"
+ },
+ {
+ "name": "core (cjs)",
+ "path": "./dist/_cjs/index.js",
+ "limit": "60 kB"
+ },
+ {
+ "name": "account (tree-shaking)",
+ "path": "./dist/_esm/index.js",
+ "limit": "60 kB",
+ "import": "{ createSmartAccountClient }"
+ },
+ {
+ "name": "bundler (tree-shaking)",
+ "path": "./dist/_esm/bundler/index.js",
+ "limit": "5 kB",
+ "import": "{ createBundler }"
+ },
+ {
+ "name": "paymaster (tree-shaking)",
+ "path": "./dist/_esm/paymaster/index.js",
+ "limit": "5 kB",
+ "import": "{ createPaymaster }"
+ },
+ {
+ "name": "modules (tree-shaking)",
+ "path": "./dist/_esm/modules/index.js",
+ "limit": "60 kB",
+ "import": "{ createSessionKeyManagerModule }"
+ }
+]
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b950ebfb7..96cc7c818 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,25 +1,202 @@
-# Change Log
+# @biconomy/account
-All notable changes to this project will be documented in this file.
-See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+## 4.2.0
+
+### Minor Changes
+
+- Features:
+
+ - Improved getBalances utility helper ([da340f](https://github.com/bcnmy/biconomy-client-sdk/pull/479/commits/da340fbcc20778c9810dd8980061a6bb7b4cf097))
+ - Added 1271 Signature support ([fd832fe](https://github.com/bcnmy/biconomy-client-sdk/pull/479/commits/fd832fe2e286a5d3e57d3292cfa395e388b07b96))
+ - Added withdrawal utility helper ([7a93d87](https://github.com/bcnmy/biconomy-client-sdk/pull/479/commits/7a93d871ecefbce8ed5ef63349c055072877189e))
+ - Reduce bundle size ([7c594fa](https://github.com/bcnmy/biconomy-client-sdk/pull/479/commits/7c594fa74e81650b4cb5043afb4cd1153e638a19))
+ - Integrate [AAErrors](https://github.com/bcnmy/aa-errors) ([7c594fa](https://github.com/bcnmy/biconomy-client-sdk/pull/479/commits/7c594fa74e81650b4cb5043afb4cd1153e638a19))
+ - Added 6492 Signature support ([fd832fe](https://github.com/bcnmy/biconomy-client-sdk/pull/479/commits/fd832fe2e286a5d3e57d3292cfa395e388b07b96))
+ - Added Token Balances to getSupportedTokens payload ([869436](https://github.com/bcnmy/biconomy-client-sdk/pull/479/commits/8694366165208cac6bbf7e560fe2abefce0eaa3a))
+ - Added gas estimates utility helper ([950a521](https://github.com/bcnmy/biconomy-client-sdk/pull/479/commits/950a521af63d7a719edcbae4df57259d3fe110e7))
+ - Added dummy pnd override ([8d34d14](https://github.com/bcnmy/biconomy-client-sdk/pull/479/commits/8d34d148862510fdb76c58852c55a48bc7c20b4c))
+
+ Chores:
+
+ - Modernise tooling ([7c594fa](https://github.com/bcnmy/biconomy-client-sdk/pull/479/commits/7c594fa74e81650b4cb5043afb4cd1153e638a19))
+ - Add changesets
+ - Migrate tests to Amoy
+ - Add pr lint
+ - Add size report
+ - Add tree shaking
+ - Add code of conduct
+ - Update README (table of contents)
+ - Add SECURITY.md
+ - Replace prettier with biome
+ - Replace yarn with bun
+ - Remove deprecated Base class
+ - Added "NEXT_PUBLIC_BICONOMY_SDK_DEBUG" to support NextJS debugging information
+ - Replace jest with vitest
+ - Added size threshold checks to PRs
+ - Added test coverage checks to PRs
+ - Added tsdoc auto-deploy
+
+ Fixes:
+
+ - Fix wrong falsy check for user op nonce ([f2567](https://github.com/bcnmy/biconomy-client-sdk/pull/479/commits/f256712bbf7dc0de40b82c70ad183c59bf5f39f9))
+
+## 4.1.1 (2023-07-03)
+
+- Added missing extensions ([fdbec6](https://github.com/bcnmy/biconomy-client-sdk/pull/451/commits/fdbec68625f4d7f436dc39d4c1779cdbb7c53e6d))
+- Fixed issue reporting format ([815e9440](https://github.com/bcnmy/biconomy-client-sdk/pull/450/commits/815e9440db03ebae98bb24edfcb3bbcabf9b2a61))
+
+## 4.1.0 (2023-04-03)
+
+Features:
+
+- Added Speed optimisation, removing redundant gasEstimate call to bundler ([2371b2](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/2371b230cd5806ec4c7c95ba604d6f924b4be768))
+- Added smartAccount.getBalances() method ([4b8bae](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/4b8bae412577b846e700b168976cefa6b0803ff6))
+- Added smartAccount.getSupportedTokens() method ([6d2fb27](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/6d2fb27d6f9b424e440e45990ea06820a9d16d4b))
+- Added smartAccount.deploy() method ([be9dc4](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/be9dc4d74a3e5a22e69416983436997cf2ea417c))
+- Increased checking of the chainId from the bundler, paymaster and the provider ([5d2f3](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/5d2f34d8f0fb4f9ff7c7ddc00336471e57efdcfd))
+- Added entity name to Logger calls ([9278ec](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/9278ecc21e060ef75ab29a0d054d95d69cd4ae27))
+- Export a 'getChain' by id helper, which returns a viem chain ([ab2ba](https://github.com/bcnmy/biconomy-client-sdk/pull/449/commits/ab2ba2c518ce867c52bf90b9018dfc1b4ec3b4d4))
+- Add "stateOverride" optional param ([20fd54](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/20fd54c817d2dcbc6b7d9a247d890d91b19a9c2f))
+
+Fixes:
+
+- Fix for encodeAbiParameters inside batched session module ([b27061](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/b27061e2eec7bafb0620e88e6d94e56e9a13cb76))
+- added flag to skip calldata approval patch ([75698](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/75698c827015533e32acb1f535bdf6b738876217))
+- Fixed the particle auth build
+
+Chores:
+
+- Added tests for ecdsa module ([1a8f29](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/1a8f296c26c9fedd57023f8f6423d7662a3adfee))
+- Increased test coverage ([329003](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/329003cebb6b4034496e41651985804cdec0d311))
+- Improved issue reporting guidelines ([8b9fb5d](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/8b9fb5de9556870611307c12e57df333619d9252))
+- Added e2e tests for optimism, ran from GH actions ([5051ba](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/5051ba5ff14220ad616f1ec3bc93a3f42d6f8887))
+- Added ABI SVM test ([49c96](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/49c968220e2db0aeee5cc6419f45df2b98f9792c))
+- Added tests for batched session router testing ([2eb9765](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/2eb9765d066fcb7b35d08223257aeb9b38c7a78b))
+
+## 4.0.3 (2023-28-02)
+
+VERSION Bump Only.
+
+## 4.0.2 (2023-26-02)
### Bug Fixes
-- init param ([6bbccfb](https://github.com/bcnmy/biconomy-client-sdk/commit/6bbccfbff8834fa96160685f80bab7d64ec0f135))
+Particle Auth Fix
+
+## 4.0.1 (2023-02-22)
+
+### Bug Fixes
+
+- Fix for RPC endpoints (Quiknode, Blast Sepolia etc) failing to respond because of custom headers being set
+
+## 4.0.0 (2023-02-06)
+
+### Features
+
+- Export bundler / paymaster instances + helpers from master package ([1d1f9d](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/1d1f9dafddf11bde0e1a75383bc935b22448bedd))
+- Export modules aliases from master package ([d6205c](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/d6205c4d76ab846ecdc10843c65e0277f3ceab00))
+- Added sendTransaction abstraction for buildUserOp + sendUserOp ([335c6e](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/335c6e7bfc5ca1ad240e7cbfd678d905c7f16812))
+- Reduced bundle size ([765a3e3](https://github.com/bcnmy/biconomy-client-sdk/commit/765a3e337fb9ad8f1f8dc92b5edcb1ed0940f94d))
+- Added bundler abstraction during SmartAccount init ([591bbb4](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/591bbb4e37774b16cbe801d583d31b3a14608bc1))
+- Added e2e tests that speak with prod bundler / paymasters ([4b4a53a](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/4b4a53aabdf9e22485599872332b3d63e8ddd87a))
+- Added support for simultaneous ethers + viem signers ([8e4b2c8](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/8e4b2c86b871130befbf3b733cf503d24f7226a5))
+- E2E tests for multichain modules ([ecc86e2](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/ecc86e2c7146046a981c3b6fd4bb29e4828b278b))
+- E2E tests for session validation modules ([4ad7ea7](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/4ad7ea7f8eb6a28854dcce83834b2b7ff9ad3287))
+- Added [TSDoc](https://bcnmy.github.io/biconomy-client-sdk) ([638dae](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/638daee0ed6924f67c5151a2d0e5a02d32e4bf23))
+- Make txs more typesafe and default with valueOrData ([b1e5b5e](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/b1e5b5e02ab3a7fb99faa1d45b55e3cbe8d6bc93))
+- Added createSmartAccountClient alias ([232472](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/232472c788bed0619cf6295ade076b6ec3a9e0f8))
+- Improve dx of using paymster to build userOps ([bb54888](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/bb548884e76a94a20329e49b18994503de9e3888))
+- Add ethers v6 signer support ([9727fd](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/9727fd51e47d62904399d17d48f5c9d6b9e591e5))
+- Improved dx of using gas payments with erc20 ([741806](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/741806da68457eba262e1a49be77fcc24360ba36))
+
+### Chores
+
+- Removed SmartAccount Base class in favour of Alchemy's ([be82732](https://github.com/bcnmy/biconomy-client-sdk/commit/be827327fafa858b1551ade0c8389293034cacbb))
+- Migrate to viem v2 ([8ce04a](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/8ce04a56f6dcdfd1f44d9534f43e3c6eb8b3885d))
+- Remove common + core-types dependencies ([673514](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/6735141fbd21a855aadf69011bc06c69e20f811b))
+- Reincluded simulation flags ([25d2be](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/25d2bee339afd9d8c143fe6dad1898e28034be17))
+
+### Bug Fixes
+
+- Make silently failing paymaster calls throw an error instead ([693bf0](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/693bf08591427c03e317d64d0491e23b1c96ea30))
+- Added string as a supported Transaction value type ([b905dc](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/b905dcf3f7849396573fc8b51f808cc68061ee11))
+- Removed skipBundlerGasEstimation option ([b905dc](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/b905dcf3f7849396573fc8b51f808cc68061ee11))
+- Ingest rpcUrl from SupportedSigners (ethers + viem) ([f56b4d](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/f56b4da08f47af577c01a641b81a3ef9e354cf97))
+
+## 3.1.3 (2023-12-28)
+
+VERSION Bump Only.
+
+## 3.1.2 (2023-12-28)
+
+### Features
+
+- Make entryPointAddress optional in config([cf35c4a](https://github.com/bcnmy/biconomy-client-sdk/pull/336/commits/cf35c4a8266d27648035d8c9d63f1b9157553128))
+
+### Bug Fixes
+
+- use undefined in place of ! + check on limits returned by paymaster and throw ([0376901](https://github.com/bcnmy/biconomy-client-sdk/commit/0376901b7aec8c268a6a3c654d147335974d78f3))
+- change receipt status type from boolean to string to be compatible with bundler response. ([317f986](https://github.com/bcnmy/biconomy-client-sdk/pull/342/commits/317f986b7e8f08d3ccf1e68f12a0696f1116de6b))
+
+## 3.1.1 (2023-11-09)
+
+### Bug Fixes
+
+- optimistic implementation for getNonce() and cache for isAccountDeployed ([5b1d4bf](https://github.com/bcnmy/biconomy-client-sdk/commit/5b1d4bfd7b5062d05bbb97286b833d879cd972b0))
+
+### Reverts
+
+- update paymaster check in estimateUserOpGas ([2eb0237](https://github.com/bcnmy/biconomy-client-sdk/commit/2eb0237b37425da3558801bbe9d0ce5d6fd696c9))
+
+## 3.1.0 (2023-09-20)
+
+Modular Account Abstraction is here. Contains BiconomySmartAccountV2 - an API for modular smart account.
+
+### Bug Fixes
+
+- add 10sec timeout limit for a test ([5d12fe7](https://github.com/bcnmy/biconomy-client-sdk/commit/5d12fe7d4b32e5c4628b971d22f6fc9cfcc6b414))
+- avoid sending populated values of gas prices when estimating from bundler ([c58c9fc](https://github.com/bcnmy/biconomy-client-sdk/commit/c58c9fc29ee83978e1a90305e839002431db2b7b))
+- BiconomySmartAccountV2 API Specs ([69a580e](https://github.com/bcnmy/biconomy-client-sdk/commit/69a580ea9e309141b500274aa95e20e24365b522))
+- build errors ([9fb0475](https://github.com/bcnmy/biconomy-client-sdk/commit/9fb047534935b0600bd08a4de7e68fd91a8a089a))
+- comments [#296](https://github.com/bcnmy/biconomy-client-sdk/issues/296) ([55b7376](https://github.com/bcnmy/biconomy-client-sdk/commit/55b7376336886226967b5bec5f11ba3ab750c5b6))
+- estimation without bundler ([5e49473](https://github.com/bcnmy/biconomy-client-sdk/commit/5e49473e7745c2e87e241731ef8ca1f65ee90388))
+- gitInitCode cache issue ([4df3502](https://github.com/bcnmy/biconomy-client-sdk/commit/4df3502204e3c6c0c6faa90ba2c8aa0d6e826e48))
+- lint warning and errors ([2135498](https://github.com/bcnmy/biconomy-client-sdk/commit/2135498896beb54d25add820c1521ffa22d5db7c))
+- unshift error for batch ([4d090e8](https://github.com/bcnmy/biconomy-client-sdk/commit/4d090e8fbc7e7bcc03805d8dd28c738d5c95dae7))
+
+### Features
+
+- get fee quote or data method in biconomy paymaster ([47748a6](https://github.com/bcnmy/biconomy-client-sdk/commit/47748a6384c2b74e1d9be4d570554098e1ac02e7))
+- update responses to support calculateGasLimits flag + update interfaces ([55bbd38](https://github.com/bcnmy/biconomy-client-sdk/commit/55bbd38b4ef8acaf8da1d52e36846557b134aba4))
+- using hybrid paymaster interface ([5fc56a7](https://github.com/bcnmy/biconomy-client-sdk/commit/5fc56a7db2de4a3f4bb87cd4d75584e79010b206))
+
+## 3.0.0 (2023-08-28)
+
+VERSION Bump Only.
+
+Modular SDK - consists stable version of below updates done in Alphas.
+
+## 3.1.1-alpha.0 (2023-08-02)
+
+### Bug Fixes
+
+VERSION Bump Only.
+
+# 3.1.0-alpha.0 (2023-07-24)
+
+### Bug Fixes
+
+- avoid sending populated values of gas prices when estimating from bundler ([c58c9fc](https://github.com/bcnmy/biconomy-client-sdk/commit/c58c9fc29ee83978e1a90305e839002431db2b7b))
+
+## 3.0.0-alpha.0 (2023-07-12)
### Bug Fixes
-- build ([6fb012a](https://github.com/bcnmy/biconomy-client-sdk/commit/6fb012a7d2004d5a5bad616a0ed025f1ee0a93b8))
-- optional sign flag ([0d689d2](https://github.com/bcnmy/biconomy-client-sdk/commit/0d689d214fc7abf32f4f2deabcce61041b73d642))
-- smart account response type ([f457f79](https://github.com/bcnmy/biconomy-client-sdk/commit/f457f794e27999ccc069c4afb7eb7644e224b61e))
-- ui bugs ([f7a4f47](https://github.com/bcnmy/biconomy-client-sdk/commit/f7a4f47c6076fd78515131ec59b128f312687a06))
+- estimation without bundler ([5e49473](https://github.com/bcnmy/biconomy-client-sdk/commit/5e49473e7745c2e87e241731ef8ca1f65ee90388))
+- unshift error for batch ([4d090e8](https://github.com/bcnmy/biconomy-client-sdk/commit/4d090e8fbc7e7bcc03805d8dd28c738d5c95dae7))
### Features
-- added email input and light mode ([741301a](https://github.com/bcnmy/biconomy-client-sdk/commit/741301a526774ed45805e477fac461b1d6afd8ac))
-- increased bg opacity ([aabbb2f](https://github.com/bcnmy/biconomy-client-sdk/commit/aabbb2fc7bab637de7a6c29fead0636979e6f6d0))
-- smart account signer ([9fcb5b1](https://github.com/bcnmy/biconomy-client-sdk/commit/9fcb5b106519b1d8fe658ab0924d722b0d102351))
-- social login ui added ([4772065](https://github.com/bcnmy/biconomy-client-sdk/commit/477206546e0518af5a1d835f7370d70d586420c0))
-- transak wrapper module ([102e6eb](https://github.com/bcnmy/biconomy-client-sdk/commit/102e6eb5f179e4aff77d1e91973e0b32fa7b8f9a))
-- web3auth modal UI ([7b7e510](https://github.com/bcnmy/biconomy-client-sdk/commit/7b7e5104ad5b1828e083f70a185328b566e9d456))
-- whitelist logic added ([53c2140](https://github.com/bcnmy/biconomy-client-sdk/commit/53c2140ef9b9d79d9d9c0e0c2c80e82b1df7f8b9))
+- get fee quote or data method in biconomy paymaster ([47748a6](https://github.com/bcnmy/biconomy-client-sdk/commit/47748a6384c2b74e1d9be4d570554098e1ac02e7))
+- update responses to support calculateGasLimits flag + update interfaces ([55bbd38](https://github.com/bcnmy/biconomy-client-sdk/commit/55bbd38b4ef8acaf8da1d52e36846557b134aba4))
+- using hybrid paymaster interface ([5fc56a7](https://github.com/bcnmy/biconomy-client-sdk/commit/5fc56a7db2de4a3f4bb87cd4d75584e79010b206))
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 000000000..6d58094ee
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,46 @@
+# Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment include:
+
+- Using welcoming and inclusive language
+- Being respectful of differing viewpoints and experiences
+- Gracefully accepting constructive criticism
+- Focusing on what is best for the community
+- Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+- The use of sexualized language or imagery and unwelcome sexual attention or advances
+- Trolling, insulting/derogatory comments, and personal or political attacks
+- Public or private harassment
+- Publishing others' private information, such as a physical or electronic address, without explicit permission
+- Other conduct which could reasonably be considered inappropriate in a professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at graeme.barnes@biconomy.io or joe.pegler@biconomy.io. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other project leadership members.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [https://contributor-covenant.org/version/1/4][version]
+
+[homepage]: https://contributor-covenant.org
+[version]: https://contributor-covenant.org/version/1/4/
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
deleted file mode 100644
index a0c7d7050..000000000
--- a/CONTRIBUTING.md
+++ /dev/null
@@ -1,64 +0,0 @@
-# Contributing to Biconomy Projects 🚀
-
-First off, thank you for considering contributing to Biconomy! We truly appreciate your effort and contributions from the community are what make Biconomy awesome. 🙌
-
-Your contributions are valued and will help in driving the decentralized web forward.
-
-> If you're passionate about our mission but can't contribute directly, there are other ways to support:
-> - ⭐ Star our projects on GitHub
-> - 🐦 [Tweet about Biconomy](https://twitter.com/biconomy/)
-> - 📌 Reference Biconomy in your project's readme
-> - 🗣️ Share about Biconomy at meetups or with peers
-
-## Table of Contents
-
-- [Contributing to Biconomy Projects 🚀](#contributing-to-biconomy-projects-)
- - [Table of Contents](#table-of-contents)
- - [Have a Question?](#have-a-question)
- - [Ready to Contribute?](#ready-to-contribute)
- - [Legal Notice 📜](#legal-notice-)
- - [Reporting Bugs 🐛](#reporting-bugs-)
- - [Suggesting Enhancements 💡](#suggesting-enhancements-)
- - [First Time Contributing? 🌱](#first-time-contributing-)
- - [Improving Documentation 📚](#improving-documentation-)
- - [Commit Messages 📝](#commit-messages-)
- - [Join Biconomy's Team! 🚀](#join-biconomys-team-)
-
-## Have a Question?
-
-Before reaching out, please ensure you've gone through our [Documentation](https://docs.biconomy.io/). If you still have questions:
-
-1. Search for existing [Issues](https://github.com/bcnmy/scw-contracts/issues) that might answer your question.
-2. Check out our [Forum](https://forum.biconomy.io/).
-3. Join our [Discord](https://discord.com/invite/biconomy) or [Telegram](https://t.me/biconomy) communities.
-
-If you still need assistance, feel free to open an [Issue](https://github.com/bcnmy/scw-contracts/issues/new) with your question.
-
-## Ready to Contribute?
-
-### Legal Notice 📜
-By contributing, you agree that you've authored your contribution and that it can be provided under the project's license.
-
-### Reporting Bugs 🐛
-
-Before submitting a bug report, ensure you're using the latest version and that you've read our [documentation](https://docs.biconomy.io/). If you've identified a bug that hasn't been reported, open a new [Issue](https://github.com/bcnmy/scw-contracts/issues/new) detailing the bug.
-
-### Suggesting Enhancements 💡
-
-Have a feature in mind? First, ensure it aligns with Biconomy's mission and hasn't been suggested before. Then, open an [Issue](https://github.com/bcnmy/scw-contracts/issues/new) to discuss your enhancement.
-
-### First Time Contributing? 🌱
-
-Welcome! We're thrilled to have you. If you're unsure where to start, look for issues labeled `good first issue`.
-
-### Improving Documentation 📚
-
-Good documentation is key! If you spot areas for improvement or errors in our documentation, we'd love your input. If you wish to suggest changes, feel free to raise a PR on our [documentation repository](https://github.com/bcnmy/docs).
-
-### Commit Messages 📝
-
-Ensure your commit messages are clear and descriptive.
-
-## Join Biconomy's Team! 🚀
-
-Interested in joining our mission full-time? Check out our [current job openings](https://jobs.lever.co/biconomy).
\ No newline at end of file
diff --git a/LICENSE.md b/LICENSE
similarity index 97%
rename from LICENSE.md
rename to LICENSE
index cf907e971..84dbcc863 100644
--- a/LICENSE.md
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2023 Biconomy
+Copyright (c) 2024 Biconomy
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index b58116402..8d8bd5bca 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,47 @@
-# Biconomy SDK
+[![Biconomy](https://img.shields.io/badge/Made_with_%F0%9F%8D%8A_by-Biconomy-ff4e17?style=flat)](https://biconomy.io) [![License MIT](https://img.shields.io/badge/License-MIT-blue?&style=flat)](./LICENSE) [![codecov](https://codecov.io/gh/bcnmy/biconomy-client-sdk/graph/badge.svg?token=DTdIR5aBDA)](https://codecov.io/gh/bcnmy/biconomy-client-sdk)
-![Biconomy SDK](https://img.shields.io/badge/Biconomy-SDK-blue.svg)
-![TypeScript](https://img.shields.io/badge/-TypeScript-blue)
-![Test Coverage](https://img.shields.io/badge/Coverage-79.82%25-green.svg)
+# SDK 🚀
-## 👋 Introduction
+[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/bcnmy/biconomy-client-sdk)
The Biconomy SDK is your all-in-one toolkit for building decentralized applications (dApps) with **ERC4337 Account Abstraction** and **Smart Accounts**. It is designed for seamless user experiences and offers non-custodial solutions for user onboarding, sending transactions (userOps), gas sponsorship and much more.
+## 📚 Table of Contents
+
+- [SDK 🚀](#sdk-)
+
+ - [📚 Table of Contents](#-table-of-contents)
+ - [🛠️ Quickstart](#-quickstart)
+
+ - [Prerequisites](#prerequisites)
+ - [Installation](#installation)
+
+ - [📄 Documentation and Resources](#-documentation-and-resources)
+ - [💼 Examples](#-examples)
+
+ - [🛠️ Initialise a smartAccount](#-initialise-a-smartAccount)
+ - [📨 send some eth with sponsorship](#-send-some-eth-with-sponsorship)
+ - [🔢 send a multi tx and pay gas with a token](#️-send-a-multi-tx-and-pay-gas-with-a-token)
+
+ - [License](#license)
+ - [Connect with Biconomy 🍊](#connect-with-biconomy-🍊)
+
## 🛠️ Quickstart
+### Installation
+
+1. **Add the package and install dependencies:**
+
+```bash
+bun add @biconomy/account viem
+```
+
+2. **Install dependencies:**
+
+```bash
+bun i
+```
+
```typescript
import { createSmartAccountClient } from "@biconomy/account";
@@ -23,39 +55,30 @@ const { wait } = await smartAccount.sendTransaction({ to: "0x...", value: 1 });
const {
receipt: { transactionHash },
- userOpHash,
+ success,
} = await wait();
```
-## 🌟 Features
+## Documentation and Resources
-- **ERC4337 Account Abstraction**: Simplify user operations and gas payments.
-- **Smart Accounts**: Enhance user experience with modular smart accounts.
-- **Paymaster Service**: Enable third-party gas sponsorship.
-- **Bundler Infrastructure**: Ensure efficient and reliable transaction bundling.
+For a comprehensive understanding of our project and to contribute effectively, please refer to the following resources:
-For a step-by-step guide on integrating **ERC4337 Account Abstraction** and **Smart Accounts** into your dApp using the Biconomy SDK, refer to the [official documentation](https://docs.biconomy.io). You can also start with Quick start [here](https://docs.biconomy.io/quickstart).
+- [**Biconomy Documentation**](https://docs.biconomy.io)
+- [**Biconomy Dashboard**](https://dashboard.biconomy.io)
+- [**API Documentation**](https://bcnmy.github.io/biconomy-client-sdk)
+- [**Contributing Guidelines**](./CONTRIBUTING.md): Learn how to contribute to our project, from code contributions to documentation improvements.
+- [**Code of Conduct**](./CODE_OF_CONDUCT.md): Our commitment to fostering an open and welcoming environment.
+- [**Security Policy**](./SECURITY.md): Guidelines for reporting security vulnerabilities.
+- [**Changelog**](./CHANGELOG.md): Stay updated with the changes and versions
-## 📚 Resources
+## 💼 Examples
-- [Biconomy Documentation](https://docs.biconomy.io/)
-- [Biconomy Dashboard](https://dashboard.biconomy.io)
-- [TSDoc](https://bcnmy.github.io/biconomy-client-sdk)
-
-## ⚙️ installation
-
-```bash
-npm i @biconomy/account
-```
-
-## 💼 Example Usages
-
-### [Initialise the smartAccount](https://bcnmy.github.io/biconomy-client-sdk/functions/createSmartAccountClient.html)
+### [Initialise a smartAccount](https://bcnmy.github.io/biconomy-client-sdk/functions/createSmartAccountClient.html)
| Key | Description |
| -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| [signer](https://bcnmy.github.io/biconomy-client-sdk/packages/account/docs/interfaces/SmartAccountSigner.html) | This signer will be used for signing userOps for any transactions you build. Will accept ethers.JsonRpcSigner as well as a viemWallet |
-| [paymasterUrl](https://dashboard.biconomy.io) | You can pass in a paymasterUrl necessary for sponsoring transactions (retrieved from the biconomy dashboard) |
+| [paymasterUrl](https://dashboard.biconomy.io) | You can pass in a paymasterUrl necessary for sponsoring transactions (retrieved from the biconomy dashboard) |
| [bundlerUrl](https://dashboard.biconomy.io) | You can pass in a bundlerUrl (retrieved from the biconomy dashboard) for sending transactions |
```typescript
@@ -74,7 +97,7 @@ const smartAccount = await createSmartAccountClient({
});
```
-### [Send some ETH, have gas sponsored](https://bcnmy.github.io/biconomy-client-sdk/classes/BiconomySmartAccountV2.html#sendTransaction)
+### [Send some eth with sponsorship](https://bcnmy.github.io/biconomy-client-sdk/classes/BiconomySmartAccountV2.html#sendTransaction)
| Key | Description |
| --------------------------------------------------------------------------------- | -------------------------------------------------------------- |
@@ -85,16 +108,19 @@ const smartAccount = await createSmartAccountClient({
const oneOrManyTx = { to: "0x...", value: 1 };
const { wait } = await smartAccount.sendTransaction(oneOrManyTx, {
- mode: PaymasterMode.SPONSORED,
+ paymasterServiceData: {
+ mode: PaymasterMode.SPONSORED,
+ },
});
const {
receipt: { transactionHash },
userOpHash,
+ success,
} = await wait();
```
-### [Mint two NFTs, pay gas with token](https://bcnmy.github.io/biconomy-client-sdk/classes/BiconomySmartAccountV2.html#getTokenFees)
+### [Send a multi tx and pay gas with a token](https://bcnmy.github.io/biconomy-client-sdk/classes/BiconomySmartAccountV2.html#getTokenFees)
| Key | Description |
| -------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
@@ -103,36 +129,40 @@ const {
```typescript
import { encodeFunctionData, parseAbi } from "viem";
-
-const encodedCall = encodeFunctionData({
- abi: parseAbi(["function safeMint(address to) public"]),
- functionName: "safeMint",
- args: ["0x..."],
-});
+const preferredToken = "0x747A4168DB14F57871fa8cda8B5455D8C2a8e90a"; // USDC
const tx = {
to: nftAddress,
- data: encodedCall,
+ data: encodeFunctionData({
+ abi: parseAbi(["function safeMint(address to) public"]),
+ functionName: "safeMint",
+ args: ["0x..."],
+ }),
};
-const oneOrManyTx = [tx, tx]; // Mint twice
-const paymasterServiceData = {
- mode: PaymasterMode.ERC20,
- preferredToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
+
+const buildUseropDto = {
+ paymasterServiceData: {
+ mode: PaymasterMode.ERC20,
+ preferredToken,
+ },
};
-const buildUseropDto = { paymasterServiceData };
-const { wait } = await smartAccount.sendTransaction(oneOrManyTx, buildUseropDto);
+const { wait } = await smartAccount.sendTransaction(
+ [tx, tx] /* Mint twice */,
+ buildUseropDto
+);
const {
receipt: { transactionHash },
userOpHash,
+ success,
} = await wait();
```
-## 🤝 Contributing
+## License
-Community contributions are welcome! For guidelines on contributing, please read our [contribution guidelines](./CONTRIBUTING.md).
+This project is licensed under the MIT License. See the [LICENSE](./LICENSE) file for details
-## 📜 License
+## Connect with Biconomy 🍊
-This project is licensed under the MIT License. See the [LICENSE.md](./LICENSE.md) file for details.
+[![Website](https://img.shields.io/badge/🍊-Website-ff4e17?style=for-the-badge&logoColor=white)](https://biconomy.io) [![Telegram](https://img.shields.io/badge/Telegram-2CA5E0?style=for-the-badge&logo=telegram&logoColor=white)](https://t.me/biconomy) [![Twitter](https://img.shields.io/badge/Twitter-1DA1F2?style=for-the-badge&logo=twitter&logoColor=white)](https://twitter.com/biconomy) [![LinkedIn](https://img.shields.io/badge/LinkedIn-0077B5?style=for-the-badge&logo=linkedin&logoColor=white)](https://www.linkedin.com/company/biconomy) [![Discord](https://img.shields.io/badge/Discord-7289DA?style=for-the-badge&logo=discord&logoColor=white)](https://discord.gg/biconomy) [![YouTube](https://img.shields.io/badge/YouTube-FF0000?style=for-the-badge&logo=youtube&logoColor=white)](https://www.youtube.com/channel/UC0CtA-Dw9yg-ENgav_VYjRw) [![GitHub](https://img.shields.io/badge/GitHub-181717?style=for-the-badge&logo=github&logoColor=white)](https://github.com/bcnmy/)
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 000000000..74aa0598b
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,57 @@
+# Security Policy
+
+## Reporting a Vulnerability
+
+The safety and security of our sdk is our top priority. If you have discovered a security vulnerability, we appreciate your help in disclosing it to us responsibly.
+
+### Contact Us Directly for Critical or High-Risk Findings
+
+For critical or high-impact vulnerabilities that could affect our users, **please contact us directly** at:
+
+- Email: security@biconomy.io
+
+We'll work with you to assess and understand the scope of the issue.
+
+### For Other Issues
+
+For vulnerabilities that are less critical and do not immediately affect our users:
+
+1. Open an issue in our GitHub repository (`https://github.com/bcnmy/biconomy-client-sdk/issues`).
+
+2. Provide detailed information about the issue and steps to reproduce.
+
+If your findings are eligible for a bounty, we will follow up with you on the payment process.
+
+### Scope
+
+The bounty program covers code in the `main` branch of our repository. The vulnerability must not have already been addressed or fixed in the `develop` branch.
+
+### Eligibility
+
+To be eligible for a bounty, researchers must:
+
+- Report a security bug that has not been previously reported.
+
+- Not violate our testing policies (detailed below).
+
+- Follow responsible disclosure guidelines.
+
+### Testing Policies
+
+- Do not conduct testing on the mainnet or public testnets. Local forks should be used for testing.
+
+- Avoid testing that generates significant traffic or could lead to denial of service.
+
+- Do not disclose the vulnerability publicly until we have had the chance to address it.
+
+### Out of Scope
+
+- Known issues listed in the issue tracker or already fixed in the `develop` branch.
+
+- Issues in third-party components.
+
+## Legal Notice
+
+By submitting a vulnerability report, you agree to comply with our responsible disclosure process. Public disclosure of the vulnerability without consent from us will render the vulnerability ineligible for a bounty.
+
+Thank you for helping to keep Biconomy 🍊 and the blockchain community safe!
diff --git a/assets/readme/biconomy-client-sdk.png b/assets/readme/biconomy-client-sdk.png
deleted file mode 100644
index ffe67d367..000000000
Binary files a/assets/readme/biconomy-client-sdk.png and /dev/null differ
diff --git a/assets/readme/biconomy-sdk.png b/assets/readme/biconomy-sdk.png
deleted file mode 100644
index 6c1fe2bcf..000000000
Binary files a/assets/readme/biconomy-sdk.png and /dev/null differ
diff --git a/biome.json b/biome.json
new file mode 100644
index 000000000..dfd9300dc
--- /dev/null
+++ b/biome.json
@@ -0,0 +1,47 @@
+{
+ "$schema": "https://biomejs.dev/schemas/1.5.3/schema.json",
+ "files": {
+ "ignore": [
+ "node_modules",
+ "**/node_modules",
+ "cache",
+ "coverage",
+ "tsconfig.json",
+ "tsconfig.*.json",
+ "_cjs",
+ "_esm",
+ "_types",
+ "bun.lockb",
+ "docs",
+ "dist"
+ ]
+ },
+ "organizeImports": {
+ "enabled": true
+ },
+ "linter": {
+ "enabled": true,
+ "rules": {
+ "recommended": true,
+ "suspicious": {
+ "noExplicitAny": "warn"
+ },
+ "style": {
+ "noUnusedTemplateLiteral": "warn"
+ }
+ }
+ },
+ "formatter": {
+ "enabled": true,
+ "formatWithErrors": true,
+ "lineWidth": 80,
+ "indentWidth": 2,
+ "indentStyle": "space"
+ },
+ "javascript": {
+ "formatter": {
+ "semicolons": "asNeeded",
+ "trailingComma": "none"
+ }
+ }
+}
diff --git a/bun.lockb b/bun.lockb
new file mode 100755
index 000000000..1784ac93e
Binary files /dev/null and b/bun.lockb differ
diff --git a/jest.config.e2e.ts b/jest.config.e2e.ts
deleted file mode 100644
index 2fff1ca6d..000000000
--- a/jest.config.e2e.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import config from "./jest.config";
-const e2eConfig = { ...config };
-e2eConfig.testMatch = ["**/*.e2e.spec.ts"];
-e2eConfig.setupFilesAfterEnv = ["/tests/setup-e2e-tests.ts"];
-
-export default e2eConfig;
diff --git a/jest.config.ts b/jest.config.ts
deleted file mode 100644
index 844398aba..000000000
--- a/jest.config.ts
+++ /dev/null
@@ -1,198 +0,0 @@
-/**
- * For a detailed explanation regarding each configuration property, visit:
- * https://jestjs.io/docs/configuration
- */
-
-import type { Config } from "jest";
-
-const config: Config = {
- // All imported modules in your tests should be mocked automatically
- // automock: false,
-
- // Stop running tests after `n` failures
- // bail: 0,
-
- // The directory where Jest should store its cached dependency information
- // cacheDirectory: "/private/var/folders/_y/33lkcttj3w3fd6v6xvg7f33m0000gn/T/jest_dx",
-
- // Automatically clear mock calls, instances, contexts and results before every test
- clearMocks: true,
-
- // Indicates whether the coverage information should be collected while executing the test
- collectCoverage: false,
-
- // An array of glob patterns indicating a set of files for which coverage information should be collected
- collectCoverageFrom: ["packages/**/*.{js,ts}", "!packages/**/node_modules/**", "!packages/**/dist/**"],
-
- // The directory where Jest should output its coverage files
- coverageDirectory: "coverage",
-
- // An array of regexp pattern strings used to skip coverage collection
- // coveragePathIgnorePatterns: [
- // "/node_modules/"
- // ],
-
- // Indicates which provider should be used to instrument code for coverage
- coverageProvider: "v8",
-
- // A list of reporter names that Jest uses when writing coverage reports
- // coverageReporters: [
- // "json",
- // "text",
- // "lcov",
- // "clover"
- // ],
-
- // An object that configures minimum threshold enforcement for coverage results
- // coverageThreshold: undefined,
-
- // A path to a custom dependency extractor
- // dependencyExtractor: undefined,
-
- // Make calling deprecated APIs throw helpful error messages
- // errorOnDeprecated: false,
-
- // The default configuration for fake timers
- // fakeTimers: {
- // "enableGlobally": false
- // },
-
- // Force coverage collection from ignored files using an array of glob patterns
- // forceCoverageMatch: [],
-
- // A path to a module which exports an async function that is triggered once before all test suites
- // globalSetup: undefined,
-
- // A path to a module which exports an async function that is triggered once after all test suites
- // globalTeardown: undefined,
-
- // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers.
- // maxWorkers: "50%",
-
- // An array of directory names to be searched recursively up from the requiring module's location
- // moduleDirectories: [
- // "node_modules"
- // ],
-
- workerThreads: true,
- // This is experimental feature. Keep in mind that the worker threads use structured clone instead of JSON.stringify() to serialize messages.
- // This means that built-in JavaScript objects as BigInt, Map or Set will get serialized properly.
- // However extra properties set on Error, Map or Set will not be passed on through the serialization step.
- // For more details see the article on structured clone.
-
- // An array of file extensions your modules use
- moduleFileExtensions: ["js", "mjs", "cjs", "jsx", "ts", "tsx", "json", "node"],
-
- // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
- moduleNameMapper: {
- '^(?!bn\.js$|hash\.js$)(.+)\\.js$': '$1'
- },
-
- extensionsToTreatAsEsm: ['.ts'],
-
- // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
- // modulePathIgnorePatterns: [],
-
- // Activates notifications for test results
- // notify: false,
-
- // An enum that specifies notification mode. Requires { notify: true }
- // notifyMode: "failure-change",
-
- // A preset that is used as a base for Jest's configuration
- preset: "ts-jest",
-
- // Run tests from one or more projects
- // projects: undefined,
-
- // Use this configuration option to add custom reporters to Jest
- // reporters: undefined,
-
- // Automatically reset mock state before every test
- // resetMocks: false,
-
- // Reset the module registry before running each individual test
- // resetModules: false,
-
- // A path to a custom resolver
- // resolver: undefined,
-
- // Automatically restore mock state and implementation before every test
- // restoreMocks: false,
-
- // The root directory that Jest should scan for tests and modules within
- // rootDir: undefined,
-
- // A list of paths to directories that Jest should use to search for files in
- roots: ["/packages/"],
-
- // Allows you to use a custom runner instead of Jest's default test runner
- // runner: "jest-runner",
-
- // The paths to modules that run some code to configure or set up the testing environment before each test
- // setupFiles: [],
-
- // A list of paths to modules that run some code to configure or set up the testing framework before each test
- setupFilesAfterEnv: ["/tests/setup-unit-tests.ts"],
-
- // The number of seconds after which a test is considered as slow and reported as such in the results.
- // slowTestThreshold: 5,
-
- // A list of paths to snapshot serializer modules Jest should use for snapshot testing
- // snapshotSerializers: [],
-
- // The test environment that will be used for testing
- testEnvironment: "node",
-
- // Options that will be passed to the testEnvironment
- // testEnvironmentOptions: {},
-
- // Adds a location field to test results
- // testLocationInResults: false,
-
- // The glob patterns Jest uses to detect test files
- testMatch: ["**/*.spec.ts", "!**/*.e2e.spec.ts"],
-
- // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
- // testPathIgnorePatterns: [
- // "/node_modules/"
- // ],
-
- // The regexp pattern or array of patterns that Jest uses to detect test files
- // testRegex: [],
-
- // This option allows the use of a custom results processor
- // testResultsProcessor: undefined,
-
- // This option allows use of a custom test runner
- // testRunner: "jest-circus/runner",
-
- // A map from regular expressions to paths to transformers
- transform: {
- "^.+\\.tsx?$": ["ts-jest", { useESM: true }],
- },
-
- // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
- // transformIgnorePatterns: [
- // "/node_modules/",
- // "\\.pnp\\.[^\\/]+$"
- // ],
-
- // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
- // unmockedModulePathPatterns: undefined,
-
- // Indicates whether each individual test should be reported during the run
- verbose: true,
-
- // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
- // watchPathIgnorePatterns: [],
-
- // Whether to use watchman for file crawling
- // watchman: true,
-
- globals: {
- testDataPerChain: [],
- }
-};
-
-export default config;
\ No newline at end of file
diff --git a/lerna.json b/lerna.json
deleted file mode 100644
index be069a470..000000000
--- a/lerna.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "packages": ["packages/*"],
- "npmClient": "yarn",
- "version": "independent",
- "command": {
- "publish": {
- "conventionalCommits": true
- }
- },
- "ignoreChanges": ["**/CHANGELOG.md", "**/node_modules/**", "**/*.md", "**/perf/**"]
-}
diff --git a/link.sh b/link.sh
deleted file mode 100755
index beaca34a1..000000000
--- a/link.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-!/bin/sh
-npm run unbuild
-npm run build
-npm link
-
diff --git a/linkAll.sh b/linkAll.sh
deleted file mode 100755
index 3597ec1c0..000000000
--- a/linkAll.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-!/bin/sh
-for dir in ./packages/*; do (cd "$dir" && yarn link); done
-cd ./packages/account && yarn link '@biconomy/bundler' '@biconomy/modules' '@biconomy/paymaster' '@biconomy/common'
\ No newline at end of file
diff --git a/package.json b/package.json
index 72746e0a2..361af2fe7 100644
--- a/package.json
+++ b/package.json
@@ -1,86 +1,119 @@
{
- "name": "biconomy-sdk",
- "version": "1.0.0",
+ "type": "module",
+ "main": "./dist/_cjs/index.js",
+ "module": "./dist/_esm/index.js",
+ "types": "./dist/_types/index.d.ts",
+ "typings": "./dist/_types/index.d.ts",
+ "homepage": "https://biconomy.io",
+ "sideEffects": false,
+ "name": "@biconomy/account",
+ "author": "Biconomy",
+ "version": "4.2.0",
"description": "SDK for Biconomy integration with support for account abstraction, smart accounts, ERC-4337.",
"keywords": [
- "biconomy",
- "sdk",
- "blockchain",
- "integration",
+ "erc-7579",
+ "modular smart account",
"account abstraction",
- "smart accounts",
- "erc-4337",
- "crosschain",
- "cross-chain",
- "metatransactions"
+ "biconomy",
+ "sdk"
],
"license": "MIT",
- "homepage": "https://biconomy.io/docs",
- "bugs": {
- "url": "https://github.com/bcnmy/biconomy-client-sdk/issues"
- },
- "repository": {
- "type": "git",
- "url": "https://github.com/bcnmy/biconomy-client-sdk"
+ "repository": "github:bcnmy/biconomy-client-sdk",
+ "exports": {
+ ".": {
+ "types": "./dist/_types/index.d.ts",
+ "import": "./dist/_esm/index.js",
+ "default": "./dist/_cjs/index.js"
+ },
+ "./account": {
+ "types": "./_types/account/index.d.ts",
+ "import": "./_esm/account/index.js",
+ "default": "./_cjs/account/index.js"
+ },
+ "./bundler": {
+ "types": "./_types/bundler/index.d.ts",
+ "import": "./_esm/bundler/index.js",
+ "default": "./_cjs/bundler/index.js"
+ },
+ "./paymaster": {
+ "types": "./_types/paymaster/index.d.ts",
+ "import": "./_esm/paymaster/index.js",
+ "default": "./_cjs/paymaster/index.js"
+ },
+ "./modules": {
+ "types": "./_types/modules/index.d.ts",
+ "import": "./_esm/modules/index.js",
+ "default": "./_cjs/modules/index.js"
+ }
},
- "author": "Biconomy (https://biconomy.io)",
- "private": true,
+ "files": [
+ "dist/*",
+ "README.md"
+ ],
"scripts": {
- "dev": "yarn rebuild && yarn install && lerna run build && yarn link:all",
- "rebuild": "./rebuild.sh",
- "link:all": "./linkAll.sh",
- "build": "yarn rebuild && yarn install && lerna run build",
- "clean": "lerna clean && lerna run unbuild",
- "format": "lerna run format --npm-client=yarn",
- "prettier": "npx prettier --write .",
- "lint": "eslint -c .eslintrc.js 'packages/*/src/**/*.{ts,tsx}'",
- "lint:fix": "eslint -c .eslintrc.js 'packages/*/src/**/*.{ts,tsx}' --fix",
- "test:run": "yarn jest --runInBand",
- "test": "concurrently -k --success first 'yarn start:ganache' 'yarn test:run' && exit 0",
- "start:ganache": "ganache -m 'direct buyer cliff train rice spirit census refuse glare expire innocent quote'",
- "test:ci": "FORCE_COLOR=1 lerna run test:ci --stream --npm-client=yarn",
- "test:coverage": "concurrently -k --success first 'yarn start:ganache' 'yarn jest --runInBand --coverage'",
- "test:e2e": "yarn test:run --config=jest.config.e2e.ts",
- "diff": "lerna diff",
- "release": "lerna version patch --no-git-tag-version --no-push --conventional-commits --yes"
+ "format": "biome format . --write",
+ "lint": "biome check .",
+ "lint:fix": "bun run lint --apply",
+ "dev": "concurrently \"bun run esm:watch\" \"bun run cjs:watch\" \"bun run esm:watch:aliases\" \"bun run cjs:watch:aliases\"",
+ "build": "bun run clean && bun run build:cjs && bun run build:esm && bun run build:types",
+ "clean": "rimraf ./dist/_esm ./dist/_cjs ./dist/_types ./dist/tsconfig",
+ "test": "vitest dev -c ./tests/vitest.config.ts",
+ "test:readOnly": "bun run test read",
+ "test:watch": "bun run test --watch",
+ "test:watch:readOnly": "bun run test:readOnly --watch",
+ "test:coverage": "CI=true vitest -c ./tests/vitest.config.ts --coverage",
+ "test:ci": "CI=true vitest -c ./tests/vitest.config.ts",
+ "size": "size-limit",
+ "docs": "typedoc --tsconfig ./tsconfig/tsconfig.esm.json",
+ "docs:deploy": "bun run docs && gh-pages -d docs",
+ "changeset": "changeset",
+ "changeset:release": "bun run build && changeset publish",
+ "changeset:version": "changeset version && bun install --lockfile-only",
+ "esm:watch": "tsc --project ./tsconfig/tsconfig.esm.json --watch",
+ "cjs:watch": "tsc --project ./tsconfig/tsconfig.cjs.json --watch",
+ "esm:watch:aliases": "tsc-alias -p ./tsconfig/tsconfig.esm.json --watch",
+ "cjs:watch:aliases": "tsc-alias -p ./tsconfig/tsconfig.cjs.json --watch",
+ "build:cjs": "tsc --project ./tsconfig/tsconfig.cjs.json && tsc-alias -p ./tsconfig/tsconfig.cjs.json && echo > ./dist/_cjs/package.json '{\"type\":\"commonjs\"}'",
+ "build:esm": "tsc --project ./tsconfig/tsconfig.esm.json && tsc-alias -p ./tsconfig/tsconfig.esm.json && echo > ./dist/_esm/package.json '{\"type\": \"module\",\"sideEffects\":false}'",
+ "build:types": "tsc --project ./tsconfig/tsconfig.types.json && tsc-alias -p ./tsconfig/tsconfig.types.json"
},
- "changelog": {
- "labels": {
- "feature": "New Feature",
- "bug": "Bug Fix"
- }
+ "devDependencies": {
+ "@biomejs/biome": "1.6.0",
+ "@changesets/cli": "^2.27.1",
+ "@commitlint/cli": "^19.0.3",
+ "@commitlint/config-conventional": "^19.0.3",
+ "@ethersproject/abi": "^5.7.0",
+ "@ethersproject/providers": "^5.7.2",
+ "@ethersproject/wallet": "^5.7.0",
+ "@size-limit/esbuild-why": "^11",
+ "@size-limit/preset-small-lib": "^11",
+ "@types/bun": "latest",
+ "@vitest/coverage-v8": "^1.3.1",
+ "concurrently": "^8.2.2",
+ "gh-pages": "^6.1.1",
+ "rimraf": "^5.0.5",
+ "simple-git-hooks": "^2.9.0",
+ "size-limit": "^11",
+ "tsc-alias": "^1.8.8",
+ "tslib": "^2.6.2",
+ "typedoc": "^0.25.9",
+ "vitest": "^1.3.1",
+ "buffer": "^6.0.3"
+ },
+ "peerDependencies": {
+ "typescript": "^5",
+ "viem": "^2"
},
- "workspaces": {
- "packages": [
- "packages/*"
+ "commitlint": {
+ "extends": [
+ "@commitlint/config-conventional"
]
},
- "dependencies": {
- "node-gyp": "^9.4.0",
- "typescript": "^5.3.3"
+ "simple-git-hooks": {
+ "pre-commit": "bun run format && bun run lint:fix",
+ "commit-msg": "npx --no -- commitlint --edit ${1}"
},
- "devDependencies": {
- "@types/debug": "^4.1.9",
- "@types/jest": "^29.5.4",
- "@typescript-eslint/eslint-plugin": "^6.7.0",
- "@typescript-eslint/parser": "^6.6.0",
- "concurrently": "^8.2.2",
- "eslint": "^8.48.0",
- "eslint-config-airbnb-base": "15.0.0",
- "eslint-config-airbnb-typescript": "17.1.0",
- "eslint-config-prettier": "^9.0.0",
- "eslint-plugin-import": "^2.28.1",
- "eslint-plugin-prettier": "^5.0.0",
- "eslint-plugin-security": "^1.7.1",
- "ganache": "^7.9.2",
- "hardhat": "^2.17.3",
- "jest": "^29.7.0",
- "lerna": "^7.2.0",
- "lerna-changelog": "^2.2.0",
- "nx": "^16.8.1",
- "prettier": "^3.0.3",
- "rimraf": "^5.0.1",
- "ts-jest": "^29.1.1",
- "ts-node": "^10.9.1"
+ "dependencies": {
+ "merkletreejs": "^0.3.11"
}
}
diff --git a/packages/account/.esbuild.js b/packages/account/.esbuild.js
deleted file mode 100644
index ca355e346..000000000
--- a/packages/account/.esbuild.js
+++ /dev/null
@@ -1,58 +0,0 @@
-const esbuildPluginTsc = require("esbuild-plugin-tsc");
-const esbuild = require("esbuild");
-const { dependencies, peerDependencies = {} } = require("./package.json");
-const { Generator } = require("npm-dts");
-
-const COMMON_SETTINGS = {
- entryPoints: ["src/index.ts"],
- minify: true,
- bundle: true,
- plugins: [esbuildPluginTsc({ force: true })],
-};
-
-const ESM_SETTINGS = {
- ...COMMON_SETTINGS,
- sourcemap: true,
- outfile: "dist/esm/index.js",
- platform: "browser",
- target: "esnext",
- format: "esm",
- mainFields: ["browser", "module", "main"],
-};
-const buildForESM = async () => await esbuild.build(ESM_SETTINGS);
-
-const CJS_SETTINGS = {
- ...COMMON_SETTINGS,
- format: "cjs",
- sourcemap: false,
- outfile: "dist/cjs/index.js",
- platform: "node",
-};
-
-const watchForCJS = async () => {
- let ctx = await esbuild.context(CJS_SETTINGS);
- await ctx.watch();
- await ctx.serve({ servedir: "dist/src" });
- console.log("watching...");
-};
-
-const buildForCJS = async () => await esbuild.build(CJS_SETTINGS);
-const buildForTYP = async () => await new Generator({ entry: "src/index.ts", output: "dist/types/index.d.ts" }).generate();
-
-(async () => {
- const buildType = process.argv.slice(2)[0];
- const shouldWatch = process.argv.slice(3)[0] === "--watch";
- if (!buildType) {
- console.log("No build type provided");
- process.exit(1);
- }
- console.log(`Building for ${buildType}`);
- if (buildType === "ESM") {
- await buildForESM();
- } else if (buildType === "CJS") {
- console.log("watching? " + shouldWatch);
- await (shouldWatch ? watchForCJS : buildForCJS)();
- } else if (buildType === "TYP") {
- await buildForTYP();
- }
-})();
diff --git a/packages/account/CHANGELOG.md b/packages/account/CHANGELOG.md
deleted file mode 100644
index 59678fcca..000000000
--- a/packages/account/CHANGELOG.md
+++ /dev/null
@@ -1,166 +0,0 @@
-# Change Log
-
-All notable changes to this project will be documented in this file.
-See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
-
-## 4.1.1 (2023-07-03)
-
-- Added missing extensions ([fdbec6](https://github.com/bcnmy/biconomy-client-sdk/pull/451/commits/fdbec68625f4d7f436dc39d4c1779cdbb7c53e6d))
-- Fixed issue reporting format ([815e9440](https://github.com/bcnmy/biconomy-client-sdk/pull/450/commits/815e9440db03ebae98bb24edfcb3bbcabf9b2a61))
-
-
-## 4.1.0 (2023-04-03)
-
-Features:
-
-- Added Speed optimisation, removing redundant gasEstimate call to bundler ([2371b2](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/2371b230cd5806ec4c7c95ba604d6f924b4be768))
-- Added smartAccount.getBalances() method ([4b8bae](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/4b8bae412577b846e700b168976cefa6b0803ff6))
-- Added smartAccount.getSupportedTokens() method ([6d2fb27](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/6d2fb27d6f9b424e440e45990ea06820a9d16d4b))
-- Added smartAccount.deploy() method ([be9dc4](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/be9dc4d74a3e5a22e69416983436997cf2ea417c))
-- Increased checking of the chainId from the bundler, paymaster and the provider ([5d2f3](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/5d2f34d8f0fb4f9ff7c7ddc00336471e57efdcfd))
-- Added entity name to Logger calls ([9278ec](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/9278ecc21e060ef75ab29a0d054d95d69cd4ae27))
-- Export a 'getChain' by id helper, which returns a viem chain ([ab2ba](https://github.com/bcnmy/biconomy-client-sdk/pull/449/commits/ab2ba2c518ce867c52bf90b9018dfc1b4ec3b4d4))
-- Add "stateOverride" optional param ([20fd54](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/20fd54c817d2dcbc6b7d9a247d890d91b19a9c2f))
-
-Fixes:
-
-- Fix for encodeAbiParameters inside batched session module ([b27061](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/b27061e2eec7bafb0620e88e6d94e56e9a13cb76))
-- added flag to skip calldata approval patch ([75698](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/75698c827015533e32acb1f535bdf6b738876217))
-- Fixed the particle auth build
-
-Chores:
-
-- Added tests for ecdsa module ([1a8f29](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/1a8f296c26c9fedd57023f8f6423d7662a3adfee))
-- Increased test coverage ([329003](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/329003cebb6b4034496e41651985804cdec0d311))
-- Improved issue reporting guidelines ([8b9fb5d](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/8b9fb5de9556870611307c12e57df333619d9252))
-- Added e2e tests for optimism, ran from GH actions ([5051ba](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/5051ba5ff14220ad616f1ec3bc93a3f42d6f8887))
-- Added ABI SVM test ([49c96](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/49c968220e2db0aeee5cc6419f45df2b98f9792c))
-- Added tests for batched session router testing ([2eb9765](https://github.com/bcnmy/biconomy-client-sdk/pull/447/commits/2eb9765d066fcb7b35d08223257aeb9b38c7a78b))
-
-## 4.0.3 (2023-28-02)
-
-VERSION Bump Only.
-
-## 4.0.2 (2023-26-02)
-
-### Bug Fixes
-
-Particle Auth Fix
-
-## 4.0.1 (2023-02-22)
-
-### Bug Fixes
-
-- Fix for RPC endpoints (Quiknode, Blast Sepolia etc) failing to respond because of custom headers being set
-
-## 4.0.0 (2023-02-06)
-
-### Features
-
-- Export bundler / paymaster instances + helpers from master package ([1d1f9d](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/1d1f9dafddf11bde0e1a75383bc935b22448bedd))
-- Export modules aliases from master package ([d6205c](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/d6205c4d76ab846ecdc10843c65e0277f3ceab00))
-- Added sendTransaction abstraction for buildUserOp + sendUserOp ([335c6e](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/335c6e7bfc5ca1ad240e7cbfd678d905c7f16812))
-- Reduced bundle size ([765a3e3](https://github.com/bcnmy/biconomy-client-sdk/commit/765a3e337fb9ad8f1f8dc92b5edcb1ed0940f94d))
-- Added bundler abstraction during SmartAccount init ([591bbb4](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/591bbb4e37774b16cbe801d583d31b3a14608bc1))
-- Added e2e tests that speak with prod bundler / paymasters ([4b4a53a](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/4b4a53aabdf9e22485599872332b3d63e8ddd87a))
-- Added support for simultaneous ethers + viem signers ([8e4b2c8](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/8e4b2c86b871130befbf3b733cf503d24f7226a5))
-- E2E tests for multichain modules ([ecc86e2](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/ecc86e2c7146046a981c3b6fd4bb29e4828b278b))
-- E2E tests for session validation modules ([4ad7ea7](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/4ad7ea7f8eb6a28854dcce83834b2b7ff9ad3287))
-- Added [TSDoc](https://bcnmy.github.io/biconomy-client-sdk) ([638dae](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/638daee0ed6924f67c5151a2d0e5a02d32e4bf23))
-- Make txs more typesafe and default with valueOrData ([b1e5b5e](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/b1e5b5e02ab3a7fb99faa1d45b55e3cbe8d6bc93))
-- Added createSmartAccountClient alias ([232472](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/232472c788bed0619cf6295ade076b6ec3a9e0f8))
-- Improve dx of using paymster to build userOps ([bb54888](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/bb548884e76a94a20329e49b18994503de9e3888))
-- Add ethers v6 signer support ([9727fd](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/9727fd51e47d62904399d17d48f5c9d6b9e591e5))
-- Improved dx of using gas payments with erc20 ([741806](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/741806da68457eba262e1a49be77fcc24360ba36))
-
-### Chores
-
-- Removed SmartAccount Base class in favour of Alchemy's ([be82732](https://github.com/bcnmy/biconomy-client-sdk/commit/be827327fafa858b1551ade0c8389293034cacbb))
-- Migrate to viem v2 ([8ce04a](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/8ce04a56f6dcdfd1f44d9534f43e3c6eb8b3885d))
-- Remove common + core-types dependencies ([673514](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/6735141fbd21a855aadf69011bc06c69e20f811b))
-- Reincluded simulation flags ([25d2be](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/25d2bee339afd9d8c143fe6dad1898e28034be17))
-
-### Bug Fixes
-
-- Make silently failing paymaster calls throw an error instead ([693bf0](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/693bf08591427c03e317d64d0491e23b1c96ea30))
-- Added string as a supported Transaction value type ([b905dc](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/b905dcf3f7849396573fc8b51f808cc68061ee11))
-- Removed skipBundlerGasEstimation option ([b905dc](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/b905dcf3f7849396573fc8b51f808cc68061ee11))
-- Ingest rpcUrl from SupportedSigners (ethers + viem) ([f56b4d](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/f56b4da08f47af577c01a641b81a3ef9e354cf97))
-
-## 3.1.3 (2023-12-28)
-
-VERSION Bump Only.
-
-## 3.1.2 (2023-12-28)
-
-### Features
-
-- Make entryPointAddress optional in config([cf35c4a](https://github.com/bcnmy/biconomy-client-sdk/pull/336/commits/cf35c4a8266d27648035d8c9d63f1b9157553128))
-
-### Bug Fixes
-
-- use undefined in place of ! + check on limits returned by paymaster and throw ([0376901](https://github.com/bcnmy/biconomy-client-sdk/commit/0376901b7aec8c268a6a3c654d147335974d78f3))
-- change receipt status type from boolean to string to be compatible with bundler response. ([317f986](https://github.com/bcnmy/biconomy-client-sdk/pull/342/commits/317f986b7e8f08d3ccf1e68f12a0696f1116de6b))
-
-## 3.1.1 (2023-11-09)
-
-### Bug Fixes
-
-- optimistic implementation for getNonce() and cache for isAccountDeployed ([5b1d4bf](https://github.com/bcnmy/biconomy-client-sdk/commit/5b1d4bfd7b5062d05bbb97286b833d879cd972b0))
-
-### Reverts
-
-- update paymaster check in estimateUserOpGas ([2eb0237](https://github.com/bcnmy/biconomy-client-sdk/commit/2eb0237b37425da3558801bbe9d0ce5d6fd696c9))
-
-## 3.1.0 (2023-09-20)
-
-Modular Account Abstraction is here. Contains BiconomySmartAccountV2 - an API for modular smart account.
-
-### Bug Fixes
-
-- add 10sec timeout limit for a test ([5d12fe7](https://github.com/bcnmy/biconomy-client-sdk/commit/5d12fe7d4b32e5c4628b971d22f6fc9cfcc6b414))
-- avoid sending populated values of gas prices when estimating from bundler ([c58c9fc](https://github.com/bcnmy/biconomy-client-sdk/commit/c58c9fc29ee83978e1a90305e839002431db2b7b))
-- BiconomySmartAccountV2 API Specs ([69a580e](https://github.com/bcnmy/biconomy-client-sdk/commit/69a580ea9e309141b500274aa95e20e24365b522))
-- build errors ([9fb0475](https://github.com/bcnmy/biconomy-client-sdk/commit/9fb047534935b0600bd08a4de7e68fd91a8a089a))
-- comments [#296](https://github.com/bcnmy/biconomy-client-sdk/issues/296) ([55b7376](https://github.com/bcnmy/biconomy-client-sdk/commit/55b7376336886226967b5bec5f11ba3ab750c5b6))
-- estimation without bundler ([5e49473](https://github.com/bcnmy/biconomy-client-sdk/commit/5e49473e7745c2e87e241731ef8ca1f65ee90388))
-- gitInitCode cache issue ([4df3502](https://github.com/bcnmy/biconomy-client-sdk/commit/4df3502204e3c6c0c6faa90ba2c8aa0d6e826e48))
-- lint warning and errors ([2135498](https://github.com/bcnmy/biconomy-client-sdk/commit/2135498896beb54d25add820c1521ffa22d5db7c))
-- unshift error for batch ([4d090e8](https://github.com/bcnmy/biconomy-client-sdk/commit/4d090e8fbc7e7bcc03805d8dd28c738d5c95dae7))
-
-### Features
-
-- get fee quote or data method in biconomy paymaster ([47748a6](https://github.com/bcnmy/biconomy-client-sdk/commit/47748a6384c2b74e1d9be4d570554098e1ac02e7))
-- update responses to support calculateGasLimits flag + update interfaces ([55bbd38](https://github.com/bcnmy/biconomy-client-sdk/commit/55bbd38b4ef8acaf8da1d52e36846557b134aba4))
-- using hybrid paymaster interface ([5fc56a7](https://github.com/bcnmy/biconomy-client-sdk/commit/5fc56a7db2de4a3f4bb87cd4d75584e79010b206))
-
-## 3.0.0 (2023-08-28)
-
-VERSION Bump Only.
-
-Modular SDK - consists stable version of below updates done in Alphas.
-
-## 3.1.1-alpha.0 (2023-08-02)
-
-### Bug Fixes
-
-VERSION Bump Only.
-
-# 3.1.0-alpha.0 (2023-07-24)
-
-### Bug Fixes
-
-- avoid sending populated values of gas prices when estimating from bundler ([c58c9fc](https://github.com/bcnmy/biconomy-client-sdk/commit/c58c9fc29ee83978e1a90305e839002431db2b7b))
-
-## 3.0.0-alpha.0 (2023-07-12)
-
-### Bug Fixes
-
-- estimation without bundler ([5e49473](https://github.com/bcnmy/biconomy-client-sdk/commit/5e49473e7745c2e87e241731ef8ca1f65ee90388))
-- unshift error for batch ([4d090e8](https://github.com/bcnmy/biconomy-client-sdk/commit/4d090e8fbc7e7bcc03805d8dd28c738d5c95dae7))
-
-### Features
-
-- get fee quote or data method in biconomy paymaster ([47748a6](https://github.com/bcnmy/biconomy-client-sdk/commit/47748a6384c2b74e1d9be4d570554098e1ac02e7))
-- update responses to support calculateGasLimits flag + update interfaces ([55bbd38](https://github.com/bcnmy/biconomy-client-sdk/commit/55bbd38b4ef8acaf8da1d52e36846557b134aba4))
-- using hybrid paymaster interface ([5fc56a7](https://github.com/bcnmy/biconomy-client-sdk/commit/5fc56a7db2de4a3f4bb87cd4d75584e79010b206))
diff --git a/packages/account/Readme.md b/packages/account/Readme.md
deleted file mode 100644
index dedd3e2e6..000000000
--- a/packages/account/Readme.md
+++ /dev/null
@@ -1,138 +0,0 @@
-# Biconomy SDK
-
-![Biconomy SDK](https://img.shields.io/badge/Biconomy-SDK-blue.svg)
-![TypeScript](https://img.shields.io/badge/-TypeScript-blue)
-![Test Coverage](https://img.shields.io/badge/Coverage-79.82%25-green.svg)
-
-## 👋 Introduction
-
-The Biconomy SDK is your all-in-one toolkit for building decentralized applications (dApps) with **ERC4337 Account Abstraction** and **Smart Accounts**. It is designed for seamless user experiences and offers non-custodial solutions for user onboarding, sending transactions (userOps), gas sponsorship and much more.
-
-## ⚙️ installation
-
-```bash
-npm i @biconomy/account
-```
-
-## 🛠️ Quickstart
-
-```typescript
-import { createSmartAccountClient } from "@biconomy/account";
-
-const smartAccount = await createSmartAccountClient({
- signer: viemWalletOrEthersSigner,
- bundlerUrl: "", // From dashboard.biconomy.io
- paymasterUrl: "", // From dashboard.biconomy.io
-});
-
-const { wait } = await smartAccount.sendTransaction({ to: "0x...", value: 1 });
-
-const {
- receipt: { transactionHash },
- userOpHash,
-} = await wait();
-```
-
-## 🌟 Features
-
-- **ERC4337 Account Abstraction**: Simplify user operations and gas payments.
-- **Smart Accounts**: Enhance user experience with modular smart accounts.
-- **Paymaster Service**: Enable third-party gas sponsorship.
-- **Bundler Infrastructure**: Ensure efficient and reliable transaction bundling.
-
-For a step-by-step guide on integrating **ERC4337 Account Abstraction** and **Smart Accounts** into your dApp using the Biconomy SDK, refer to the [official documentation](https://docs.biconomy.io/docs/overview). You can also start with Quick start [here](https://docs.biconomy.io/quickstart).
-
-## 📚 Resources
-
-- [Biconomy Documentation](https://docs.biconomy.io/)
-- [Biconomy Dashboard](https://dashboard.biconomy.io)
-- [TSDoc](https://bcnmy.github.io/biconomy-client-sdk)
-
-## 💼 Example Usages
-
-### [Initialise the smartAccount](https://bcnmy.github.io/biconomy-client-sdk/functions/createSmartAccountClient.html)
-
-| Key | Description |
-| -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
-| [signer](https://bcnmy.github.io/biconomy-client-sdk/packages/account/docs/interfaces/SmartAccountSigner.html) | This signer will be used for signing userOps for any transactions you build. Will accept ethers.JsonRpcSigner as well as a viemWallet |
-| [paymasterUrl](https://dashboard.biconomy.io) | You can pass in a paymasterUrl necessary for sponsoring transactions (retrieved from the biconomy dashboard) |
-| [bundlerUrl](https://dashboard.biconomy.io) | You can pass in a bundlerUrl (retrieved from the biconomy dashboard) for sending transactions |
-
-```typescript
-import { createSmartAccountClient } from "@biconomy/account";
-import { createWalletClient, http, createPublicClient } from "viem";
-import { privateKeyToAccount, generatePrivateKey } from "viem/accounts";
-import { mainnet as chain } from "viem/chains";
-
-const account = privateKeyToAccount(generatePrivateKey());
-const signer = createWalletClient({ account, chain, transport: http() });
-
-const smartAccount = await createSmartAccountClient({
- signer,
- bundlerUrl,
- paymasterUrl,
-});
-```
-
-### [Send some ETH, have gas sponsored](https://bcnmy.github.io/biconomy-client-sdk/classes/BiconomySmartAccountV2.html#sendTransaction)
-
-| Key | Description |
-| --------------------------------------------------------------------------------- | -------------------------------------------------------------- |
-| [oneOrManyTx](https://bcnmy.github.io/biconomy-client-sdk/types/Transaction.html) | Submit multiple or one transactions |
-| [userOpReceipt](https://bcnmy.github.io/biconomy-client-sdk/types/UserOpReceipt) | Returned information about your tx, receipts, userOpHashes etc |
-
-```typescript
-const oneOrManyTx = { to: "0x...", value: 1 };
-
-const { wait } = await smartAccount.sendTransaction(oneOrManyTx, {
- mode: PaymasterMode.SPONSORED,
-});
-
-const {
- receipt: { transactionHash },
- userOpHash,
-} = await wait();
-```
-
-### [Mint two NFTs, pay gas with token](https://bcnmy.github.io/biconomy-client-sdk/classes/BiconomySmartAccountV2.html#getTokenFees)
-
-| Key | Description |
-| -------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
-| [buildUseropDto](https://bcnmy.github.io/biconomy-client-sdk/types/BuildUserOpOptions.html) | Options for building a userOp |
-| [paymasterServiceData](https://bcnmy.github.io/biconomy-client-sdk/types/PaymasterUserOperationDto.html) | PaymasterOptions set in the buildUseropDto |
-
-```typescript
-import { encodeFunctionData, parseAbi } from "viem";
-
-const encodedCall = encodeFunctionData({
- abi: parseAbi(["function safeMint(address to) public"]),
- functionName: "safeMint",
- args: ["0x..."],
-});
-
-const tx = {
- to: nftAddress,
- data: encodedCall,
-};
-const oneOrManyTx = [tx, tx]; // Mint twice
-const paymasterServiceData = {
- mode: PaymasterMode.ERC20,
- preferredToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
-};
-const buildUseropDto = { paymasterServiceData };
-
-const { wait } = await smartAccount.sendTransaction(oneOrManyTx, buildUseropDto);
-
-const {
- receipt: { transactionHash },
- userOpHash,
-} = await wait();
-```
-
-## 🤝 Contributing
-
-Community contributions are welcome! For guidelines on contributing, please read our [contribution guidelines](./CONTRIBUTING.md).
-
-## 📜 License
-
-This project is licensed under the MIT License. See the [LICENSE.md](./LICENSE.md) file for details.
diff --git a/packages/account/package.json b/packages/account/package.json
deleted file mode 100644
index 408ff4cef..000000000
--- a/packages/account/package.json
+++ /dev/null
@@ -1,77 +0,0 @@
-{
- "name": "@biconomy/account",
- "version": "4.1.1",
- "description": "This package provides apis for ERC-4337 based smart account implementations",
- "main": "./dist/cjs/index.js",
- "module": "./dist/esm/index.js",
- "types": "./dist/types/index.d.ts",
- "typings": "./dist/types/index.d.ts",
- "exports": {
- ".": {
- "import": "./dist/esm/index.js",
- "types": "./dist/types/index.d.ts",
- "default": "./dist/cjs/index.js"
- },
- "./package.json": "./package.json"
- },
- "keywords": [
- "Ethereum",
- "Smart Account",
- "ERC-4337",
- "Account Abstraction",
- "Smart Contract Wallets",
- "Biconomy",
- "SDK"
- ],
- "scripts": {
- "docs": "typedoc",
- "unbuild": "rimraf dist *.tsbuildinfo",
- "build:watch": "yarn build:tsc --watch",
- "dist:minify": "esbuild ./dist/esm/**/*.js ./dist/esm/*.js --minify --outdir=./dist/esm --bundle=false --allow-overwrite",
- "build": "yarn unbuild && yarn build:tsc",
- "build:esbuild": "yarn build:esbuild:cjs && yarn build:esbuild:esm && yarn build:typ",
- "build:tsc:cjs": "tsc --project tsconfig.build.json --module commonjs --outDir ./dist/cjs --removeComments --verbatimModuleSyntax false && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'",
- "build:tsc:esm": "tsc --project tsconfig.build.json --module esnext --outDir ./dist/esm --removeComments && echo > ./dist/esm/package.json '{\"type\":\"module\"}'",
- "build:esbuild:cjs": "node .esbuild.js CJS && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'",
- "build:esbuild:esm": "node .esbuild.js ESM && echo > ./dist/esm/package.json '{\"type\":\"module\"}'",
- "build:typ": "tsc --project tsconfig.build.json --module esnext --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap",
- "build:tsc": "yarn build:tsc:cjs && yarn build:tsc:esm && yarn build:typ && yarn dist:minify",
- "test:concurrently": "concurrently -k --success first 'yarn start:ganache' 'yarn test'",
- "test:cov": "jest --coverage",
- "test": "jest tests/**/*.spec.ts --runInBand",
- "test:run": "yarn test:concurrently",
- "start:ganache": "ganache -m 'direct buyer cliff train rice spirit census refuse glare expire innocent quote'",
- "format": "prettier --write \"{src,tests}/**/*.ts\"",
- "lint": "tslint -p tsconfig.json",
- "docs:deploy": "yarn docs && gh-pages -d docs"
- },
- "author": "Biconomy",
- "license": "MIT",
- "files": [
- "dist/*",
- "README.md"
- ],
- "publishConfig": {
- "access": "public"
- },
- "devDependencies": {
- "@ethersproject/providers": "^5.7.2",
- "@ethersproject/wallet": "^5.7.0",
- "@types/node": "^20.11.10",
- "esbuild": "^0.19.11",
- "esbuild-plugin-tsc": "^0.4.0",
- "gh-pages": "^6.1.1",
- "lru-cache": "^10.0.1",
- "nock": "^13.2.9",
- "npm-dts": "^1.3.12",
- "typedoc": "^0.25.7"
- },
- "dependencies": {
- "@alchemy/aa-core": "^3.1.1",
- "@biconomy/bundler": "^4.1.1",
- "@biconomy/common": "^4.1.1",
- "@biconomy/modules": "^4.1.1",
- "@biconomy/paymaster": "^4.1.1",
- "viem": "^2.7.12"
- }
-}
diff --git a/packages/account/src/BiconomySmartAccountV2.ts b/packages/account/src/BiconomySmartAccountV2.ts
deleted file mode 100644
index 3aa81a4e2..000000000
--- a/packages/account/src/BiconomySmartAccountV2.ts
+++ /dev/null
@@ -1,1356 +0,0 @@
-import {
- Hex,
- keccak256,
- encodePacked,
- getCreate2Address,
- encodeAbiParameters,
- parseAbiParameters,
- toHex,
- toBytes,
- encodeFunctionData,
- PublicClient,
- createPublicClient,
- http,
- concatHex,
- GetContractReturnType,
- getContract,
- decodeFunctionData,
- parseAbi,
- formatUnits,
-} from "viem";
-import {
- BaseSmartContractAccount,
- getChain,
- type BigNumberish,
- type UserOperationStruct,
- BatchUserOperationCallData,
- SmartAccountSigner,
-} from "@alchemy/aa-core";
-import { compareChainIds, isNullOrUndefined, packUserOp, isValidRpcUrl } from "./utils/Utils.js";
-import { BaseValidationModule, ModuleInfo, SendUserOpParams, createECDSAOwnershipValidationModule } from "@biconomy/modules";
-import {
- IHybridPaymaster,
- IPaymaster,
- Paymaster,
- PaymasterMode,
- SponsorUserOperationDto,
- Bundler,
- IBundler,
- UserOpResponse,
- extractChainIdFromBundlerUrl,
- convertSigner,
- NATIVE_TOKEN_ALIAS,
-} from "./index.js";
-import {
- BiconomyTokenPaymasterRequest,
- BiconomySmartAccountV2Config,
- CounterFactualAddressParam,
- BuildUserOpOptions,
- NonceOptions,
- Transaction,
- QueryParamsForAddressResolver,
- BiconomySmartAccountV2ConfigConstructorProps,
- PaymasterUserOperationDto,
- SimulationType,
- BalancePayload,
- SupportedToken,
-} from "./utils/Types.js";
-import {
- ADDRESS_RESOLVER_ADDRESS,
- BICONOMY_IMPLEMENTATION_ADDRESSES_BY_VERSION,
- DEFAULT_BICONOMY_FACTORY_ADDRESS,
- DEFAULT_FALLBACK_HANDLER_ADDRESS,
- PROXY_CREATION_CODE,
- ADDRESS_ZERO,
- DEFAULT_ENTRYPOINT_ADDRESS,
- ERROR_MESSAGES,
- ERC20_ABI,
-} from "./utils/Constants.js";
-import { BiconomyFactoryAbi } from "./abi/Factory.js";
-import { BiconomyAccountAbi } from "./abi/SmartAccount.js";
-import { AccountResolverAbi } from "./abi/AccountResolver.js";
-import { Logger, StateOverrideSet } from "@biconomy/common";
-import { BiconomyPaymaster, FeeQuotesOrDataDto, FeeQuotesOrDataResponse } from "@biconomy/paymaster";
-
-type UserOperationKey = keyof UserOperationStruct;
-
-export class BiconomySmartAccountV2 extends BaseSmartContractAccount {
- private SENTINEL_MODULE = "0x0000000000000000000000000000000000000001";
-
- private index: number;
-
- private chainId: number;
-
- private provider: PublicClient;
-
- paymaster?: IPaymaster;
-
- bundler?: IBundler;
-
- private accountContract?: GetContractReturnType;
-
- private defaultFallbackHandlerAddress: Hex;
-
- private implementationAddress: Hex;
-
- private scanForUpgradedAccountsFromV1!: boolean;
-
- private maxIndexForScan!: number;
-
- // Validation module responsible for account deployment initCode. This acts as a default authorization module.
- defaultValidationModule!: BaseValidationModule;
-
- // Deployed Smart Account can have more than one module enabled. When sending a transaction activeValidationModule is used to prepare and validate userOp signature.
- activeValidationModule!: BaseValidationModule;
-
- private constructor(readonly biconomySmartAccountConfig: BiconomySmartAccountV2ConfigConstructorProps) {
- super({
- ...biconomySmartAccountConfig,
- chain: biconomySmartAccountConfig.viemChain ?? getChain(biconomySmartAccountConfig.chainId),
- rpcClient: biconomySmartAccountConfig.rpcUrl || getChain(biconomySmartAccountConfig.chainId).rpcUrls.default.http[0],
- entryPointAddress: (biconomySmartAccountConfig.entryPointAddress as Hex) ?? DEFAULT_ENTRYPOINT_ADDRESS,
- accountAddress: (biconomySmartAccountConfig.accountAddress as Hex) ?? undefined,
- factoryAddress: biconomySmartAccountConfig.factoryAddress ?? DEFAULT_BICONOMY_FACTORY_ADDRESS,
- });
-
- this.defaultValidationModule = biconomySmartAccountConfig.defaultValidationModule;
- this.activeValidationModule = biconomySmartAccountConfig.activeValidationModule;
-
- this.index = biconomySmartAccountConfig.index ?? 0;
- this.chainId = biconomySmartAccountConfig.chainId;
- this.bundler = biconomySmartAccountConfig.bundler;
- this.implementationAddress = biconomySmartAccountConfig.implementationAddress ?? (BICONOMY_IMPLEMENTATION_ADDRESSES_BY_VERSION.V2_0_0 as Hex);
-
- if (biconomySmartAccountConfig.paymasterUrl) {
- this.paymaster = new Paymaster({
- paymasterUrl: biconomySmartAccountConfig.paymasterUrl,
- });
- } else if (biconomySmartAccountConfig.biconomyPaymasterApiKey) {
- this.paymaster = new Paymaster({
- paymasterUrl: `https://paymaster.biconomy.io/api/v1/${biconomySmartAccountConfig.chainId}/${biconomySmartAccountConfig.biconomyPaymasterApiKey}`,
- });
- } else {
- this.paymaster = biconomySmartAccountConfig.paymaster;
- }
-
- this.bundler = biconomySmartAccountConfig.bundler;
-
- const defaultFallbackHandlerAddress =
- this.factoryAddress === DEFAULT_BICONOMY_FACTORY_ADDRESS ? DEFAULT_FALLBACK_HANDLER_ADDRESS : biconomySmartAccountConfig.defaultFallbackHandler;
- if (!defaultFallbackHandlerAddress) {
- throw new Error("Default Fallback Handler address is not provided");
- }
- this.defaultFallbackHandlerAddress = defaultFallbackHandlerAddress;
-
- // Added bang operator to avoid null check as the constructor have these params as optional
- this.defaultValidationModule = biconomySmartAccountConfig.defaultValidationModule!;
- this.activeValidationModule = biconomySmartAccountConfig.activeValidationModule!;
-
- this.provider = createPublicClient({
- chain: biconomySmartAccountConfig.viemChain ?? getChain(biconomySmartAccountConfig.chainId),
- transport: http(biconomySmartAccountConfig.rpcUrl || getChain(biconomySmartAccountConfig.chainId).rpcUrls.default.http[0]),
- });
-
- this.scanForUpgradedAccountsFromV1 = biconomySmartAccountConfig.scanForUpgradedAccountsFromV1 ?? false;
- this.maxIndexForScan = biconomySmartAccountConfig.maxIndexForScan ?? 10;
- }
-
- /**
- * Creates a new instance of BiconomySmartAccountV2
- *
- * This method will create a BiconomySmartAccountV2 instance but will not deploy the Smart Account
- * Deployment of the Smart Account will be donewith the first user operation.
- *
- * - Docs: https://docs.biconomy.io/Account/integration#integration-1
- *
- * @param biconomySmartAccountConfig - Configuration for initializing the BiconomySmartAccountV2 instance.
- * @returns A promise that resolves to a new instance of BiconomySmartAccountV2.
- * @throws An error if something is wrong with the smart account instance creation.
- *
- * @example
- * import { createClient } from "viem"
- * import { createSmartAccountClient, BiconomySmartAccountV2 } from "@biconomy/account"
- * import { createWalletClient, http } from "viem";
- * import { polygonMumbai } from "viem/chains";
- *
- * const signer = createWalletClient({
- * account,
- * chain: polygonMumbai,
- * transport: http(),
- * });
- *
- * const bundlerUrl = "" // Retrieve bundler url from dasboard
- *
- * const smartAccountFromStaticCreate = await BiconomySmartAccountV2.create({ signer, bundlerUrl });
- *
- * // Is the same as...
- *
- * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl });
- *
- */
- public static async create(biconomySmartAccountConfig: BiconomySmartAccountV2Config): Promise {
- let chainId = biconomySmartAccountConfig.chainId;
- let rpcUrl = biconomySmartAccountConfig.rpcUrl;
- let resolvedSmartAccountSigner!: SmartAccountSigner;
-
- // Signer needs to be initialised here before defaultValidationModule is set
- if (biconomySmartAccountConfig.signer) {
- const signerResult = await convertSigner(biconomySmartAccountConfig.signer, !!chainId);
- if (!chainId && !!signerResult.chainId) {
- chainId = signerResult.chainId;
- }
- if (!rpcUrl && !!signerResult.rpcUrl) {
- if (isValidRpcUrl(signerResult.rpcUrl)) {
- rpcUrl = signerResult.rpcUrl;
- }
- }
- resolvedSmartAccountSigner = signerResult.signer;
- }
- if (!chainId) {
- // Get it from bundler
- if (biconomySmartAccountConfig.bundlerUrl) {
- chainId = extractChainIdFromBundlerUrl(biconomySmartAccountConfig.bundlerUrl);
- } else if (biconomySmartAccountConfig.bundler) {
- const bundlerUrlFromBundler = biconomySmartAccountConfig.bundler.getBundlerUrl();
- chainId = extractChainIdFromBundlerUrl(bundlerUrlFromBundler);
- }
- }
- if (!chainId) {
- throw new Error("chainId required");
- }
- const bundler: IBundler = biconomySmartAccountConfig.bundler ?? new Bundler({ bundlerUrl: biconomySmartAccountConfig.bundlerUrl!, chainId });
- let defaultValidationModule = biconomySmartAccountConfig.defaultValidationModule;
-
- // Note: If no module is provided, we will use ECDSA_OWNERSHIP as default
- if (!defaultValidationModule) {
- const newModule = await createECDSAOwnershipValidationModule({ signer: resolvedSmartAccountSigner! });
- defaultValidationModule = newModule;
- }
- const activeValidationModule = biconomySmartAccountConfig?.activeValidationModule ?? defaultValidationModule;
- if (!resolvedSmartAccountSigner) {
- resolvedSmartAccountSigner = await activeValidationModule.getSigner();
- }
- if (!resolvedSmartAccountSigner) {
- throw new Error("signer required");
- }
- const config: BiconomySmartAccountV2ConfigConstructorProps = {
- ...biconomySmartAccountConfig,
- defaultValidationModule,
- activeValidationModule,
- chainId,
- bundler,
- signer: resolvedSmartAccountSigner,
- rpcUrl,
- };
-
- // We check if chain ids match (skip this if chainId is passed by in the config)
- // This check is at the end of the function for cases when the signer is not passed in the config but a validation modules is and we get the signer from the validation module in this case
- if (!biconomySmartAccountConfig.chainId) {
- await compareChainIds(biconomySmartAccountConfig.signer || resolvedSmartAccountSigner, config, false);
- }
-
- return new BiconomySmartAccountV2(config);
- }
-
- // Calls the getCounterFactualAddress
- async getAddress(params?: CounterFactualAddressParam): Promise {
- if (this.accountAddress == null) {
- // means it needs deployment
- this.accountAddress = await this.getCounterFactualAddress(params);
- }
- return this.accountAddress;
- }
-
- // Calls the getCounterFactualAddress
- async getAccountAddress(params?: CounterFactualAddressParam): Promise<`0x${string}`> {
- if (this.accountAddress == null || this.accountAddress == undefined) {
- // means it needs deployment
- this.accountAddress = await this.getCounterFactualAddress(params);
- }
- return this.accountAddress;
- }
-
- /**
- * Returns token balances (and native token balance) of the smartAccount instance.
- *
- * This method will fetch the token balances of the smartAccount instance.
- * The balance of the native token will always be returned as the last element in the reponse array, with the address set to 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE.
- *
- * @param addresses - Optional. Array of asset addresses to fetch the balances of. If not provided, the method will return only the balance of the native token.
- * @returns Promise> - An array of token balances (plus the native token balance) of the smartAccount instance.
- *
- * @example
- * import { createClient } from "viem"
- * import { createSmartAccountClient } from "@biconomy/account"
- * import { createWalletClient, http } from "viem";
- * import { polygonMumbai } from "viem/chains";
- *
- * const signer = createWalletClient({
- * account,
- * chain: polygonMumbai,
- * transport: http(),
- * });
- *
- * const usdt = "0xda5289fcaaf71d52a80a254da614a192b693e977";
- * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl });
- * const [usdtBalanceFromSmartAccount, nativeTokenBalanceFromSmartAccount] = await smartAccount.getBalances([usdt]);
- *
- * console.log(usdtBalanceFromSmartAccount);
- * // {
- * // amount: 1000000000000000n,
- * // decimals: 6,
- * // address: "0xda5289fcaaf71d52a80a254da614a192b693e977",
- * // formattedAmount: "1000000",
- * // chainId: 80001
- * // }
- *
- * // or to get the nativeToken balance
- *
- * const [nativeTokenBalanceFromSmartAccount] = await smartAccount.getBalances();
- *
- * console.log(nativeTokenBalanceFromSmartAccount);
- * // {
- * // amount: 1000000000000000n,
- * // decimals: 18,
- * // address: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
- * // formattedAmount: "1",
- * // chainId: 80001
- * // }
- *
- */
- public async getBalances(addresses?: Array): Promise> {
- const accountAddress = await this.getAccountAddress();
- const result: BalancePayload[] = [];
-
- if (addresses) {
- const tokenContracts = addresses.map((address) =>
- getContract({
- address,
- abi: parseAbi(ERC20_ABI),
- client: this.provider,
- }),
- );
-
- const balancePromises = tokenContracts.map((tokenContract) => tokenContract.read.balanceOf([accountAddress])) as Promise[];
- const decimalsPromises = tokenContracts.map((tokenContract) => tokenContract.read.decimals()) as Promise[];
- const [balances, decimalsPerToken] = await Promise.all([Promise.all(balancePromises), Promise.all(decimalsPromises)]);
-
- balances.forEach((amount, index) =>
- result.push({
- amount,
- decimals: decimalsPerToken[index],
- address: addresses[index],
- formattedAmount: formatUnits(amount, decimalsPerToken[index]),
- chainId: this.chainId,
- }),
- );
- }
-
- const balance = await this.provider.getBalance({ address: accountAddress });
-
- result.push({
- amount: balance,
- decimals: 18,
- address: NATIVE_TOKEN_ALIAS,
- formattedAmount: formatUnits(balance, 18),
- chainId: this.chainId,
- });
-
- return result;
- }
-
- /**
- * Return the account's address. This value is valid even before deploying the contract.
- */
- async getCounterFactualAddress(params?: CounterFactualAddressParam): Promise {
- const validationModule = params?.validationModule ?? this.defaultValidationModule;
- const index = params?.index ?? this.index;
-
- const maxIndexForScan = params?.maxIndexForScan ?? this.maxIndexForScan;
- // Review: default behavior
- const scanForUpgradedAccountsFromV1 = params?.scanForUpgradedAccountsFromV1 ?? this.scanForUpgradedAccountsFromV1;
-
- // if it's intended to detect V1 upgraded accounts
- if (scanForUpgradedAccountsFromV1) {
- const eoaSigner = await validationModule.getSigner();
- const eoaAddress = (await eoaSigner.getAddress()) as Hex;
- const moduleAddress = validationModule.getAddress() as Hex;
- const moduleSetupData = (await validationModule.getInitData()) as Hex;
- const queryParams = {
- eoaAddress,
- index,
- moduleAddress,
- moduleSetupData,
- maxIndexForScan,
- };
- const accountAddress = await this.getV1AccountsUpgradedToV2(queryParams);
- if (accountAddress !== ADDRESS_ZERO) {
- return accountAddress;
- }
- }
-
- const counterFactualAddressV2 = await this.getCounterFactualAddressV2({ validationModule, index });
- return counterFactualAddressV2;
- }
-
- private async getCounterFactualAddressV2(params?: CounterFactualAddressParam): Promise {
- const validationModule = params?.validationModule ?? this.defaultValidationModule;
- const index = params?.index ?? this.index;
-
- try {
- const initCalldata = encodeFunctionData({
- abi: BiconomyAccountAbi,
- functionName: "init",
- args: [this.defaultFallbackHandlerAddress, validationModule.getAddress() as Hex, (await validationModule.getInitData()) as Hex],
- });
-
- const proxyCreationCodeHash = keccak256(encodePacked(["bytes", "uint256"], [PROXY_CREATION_CODE, BigInt(this.implementationAddress)]));
-
- const salt = keccak256(encodePacked(["bytes32", "uint256"], [keccak256(initCalldata), BigInt(index)]));
-
- const counterFactualAddress = getCreate2Address({
- from: this.factoryAddress,
- salt: salt,
- bytecodeHash: proxyCreationCodeHash,
- });
-
- return counterFactualAddress;
- } catch (e) {
- throw new Error(`Failed to get counterfactual address, ${e}`);
- }
- }
-
- async _getAccountContract(): Promise> {
- if (this.accountContract == null) {
- this.accountContract = getContract({
- address: await this.getAddress(),
- abi: BiconomyAccountAbi,
- client: this.provider as PublicClient,
- });
- }
- return this.accountContract;
- }
-
- isActiveValidationModuleDefined(): boolean {
- if (!this.activeValidationModule) throw new Error("Must provide an instance of active validation module.");
- return true;
- }
-
- isDefaultValidationModuleDefined(): boolean {
- if (!this.defaultValidationModule) throw new Error("Must provide an instance of default validation module.");
- return true;
- }
-
- setActiveValidationModule(validationModule: BaseValidationModule): BiconomySmartAccountV2 {
- if (validationModule instanceof BaseValidationModule) {
- this.activeValidationModule = validationModule;
- }
- return this;
- }
-
- setDefaultValidationModule(validationModule: BaseValidationModule): BiconomySmartAccountV2 {
- if (validationModule instanceof BaseValidationModule) {
- this.defaultValidationModule = validationModule;
- }
- return this;
- }
-
- async getV1AccountsUpgradedToV2(params: QueryParamsForAddressResolver): Promise {
- const maxIndexForScan = params.maxIndexForScan ?? this.maxIndexForScan;
-
- const addressResolver = getContract({
- address: ADDRESS_RESOLVER_ADDRESS,
- abi: AccountResolverAbi,
- client: {
- public: this.provider as PublicClient,
- },
- });
- // Note: depending on moduleAddress and moduleSetupData passed call this. otherwise could call resolveAddresses()
-
- if (params.moduleAddress && params.moduleSetupData) {
- const result = await addressResolver.read.resolveAddressesFlexibleForV2([
- params.eoaAddress,
- maxIndexForScan,
- params.moduleAddress,
- params.moduleSetupData,
- ]);
-
- const desiredV1Account = result.find(
- (smartAccountInfo: { factoryVersion: string; currentVersion: string; deploymentIndex: { toString: () => any } }) =>
- smartAccountInfo.factoryVersion === "v1" &&
- smartAccountInfo.currentVersion === "2.0.0" &&
- Number(smartAccountInfo.deploymentIndex.toString()) === params.index,
- );
-
- if (desiredV1Account) {
- const smartAccountAddress = desiredV1Account.accountAddress;
- return smartAccountAddress;
- } else {
- return ADDRESS_ZERO;
- }
- } else {
- return ADDRESS_ZERO;
- }
- }
-
- /**
- * Return the value to put into the "initCode" field, if the account is not yet deployed.
- * This value holds the "factory" address, followed by this account's information
- */
- async getAccountInitCode(): Promise {
- this.isDefaultValidationModuleDefined();
-
- return concatHex([
- this.factoryAddress as Hex,
- encodeFunctionData({
- abi: BiconomyFactoryAbi,
- functionName: "deployCounterFactualAccount",
- args: [this.defaultValidationModule.getAddress() as Hex, (await this.defaultValidationModule.getInitData()) as Hex, BigInt(this.index)],
- }),
- ]);
- }
-
- /**
- *
- * @param to { target } address of transaction
- * @param value represents amount of native tokens
- * @param data represent data associated with transaction
- * @returns encoded data for execute function
- */
- async encodeExecute(to: Hex, value: bigint, data: Hex): Promise {
- // return accountContract.interface.encodeFunctionData("execute_ncC", [to, value, data]) as Hex;
- return encodeFunctionData({
- abi: BiconomyAccountAbi,
- functionName: "execute_ncC",
- args: [to, value, data],
- });
- }
-
- /**
- *
- * @param to { target } array of addresses in transaction
- * @param value represents array of amount of native tokens associated with each transaction
- * @param data represent array of data associated with each transaction
- * @returns encoded data for executeBatch function
- */
- async encodeExecuteBatch(to: Array, value: Array, data: Array): Promise {
- return encodeFunctionData({
- abi: BiconomyAccountAbi,
- functionName: "executeBatch_y6U",
- args: [to, value, data],
- });
- }
-
- override async encodeBatchExecute(txs: BatchUserOperationCallData): Promise {
- const [targets, datas, value] = txs.reduce(
- (accum, curr) => {
- accum[0].push(curr.target);
- accum[1].push(curr.data);
- accum[2].push(curr.value || BigInt(0));
-
- return accum;
- },
- [[], [], []] as [Hex[], Hex[], bigint[]],
- );
-
- return this.encodeExecuteBatch(targets, value, datas);
- }
-
- // dummy signature depends on the validation module supplied.
- async getDummySignatures(params?: ModuleInfo): Promise {
- this.isActiveValidationModuleDefined();
- return (await this.activeValidationModule.getDummySignature(params)) as Hex;
- }
-
- // TODO: review this
- getDummySignature(): Hex {
- throw new Error("Method not implemented! Call getDummySignatures instead.");
- }
-
- // Might use provided paymaster instance to get dummy data (from pm service)
- getDummyPaymasterData(): string {
- return "0x";
- }
-
- validateUserOp(userOp: Partial, requiredFields: UserOperationKey[]): boolean {
- for (const field of requiredFields) {
- if (!userOp[field]) {
- throw new Error(`${String(field)} is missing in the UserOp`);
- }
- }
- return true;
- }
-
- async signUserOp(userOp: Partial, params?: SendUserOpParams): Promise {
- this.isActiveValidationModuleDefined();
- const requiredFields: UserOperationKey[] = [
- "sender",
- "nonce",
- "initCode",
- "callData",
- "callGasLimit",
- "verificationGasLimit",
- "preVerificationGas",
- "maxFeePerGas",
- "maxPriorityFeePerGas",
- "paymasterAndData",
- ];
- this.validateUserOp(userOp, requiredFields);
- const userOpHash = await this.getUserOpHash(userOp);
-
- const moduleSig = (await this.activeValidationModule.signUserOpHash(userOpHash, params)) as Hex;
-
- const signatureWithModuleAddress = this.getSignatureWithModuleAddress(moduleSig, this.activeValidationModule.getAddress() as Hex);
-
- userOp.signature = signatureWithModuleAddress;
- return userOp as UserOperationStruct;
- }
-
- getSignatureWithModuleAddress(moduleSignature: Hex, moduleAddress?: Hex): Hex {
- const moduleAddressToUse = moduleAddress ?? (this.activeValidationModule.getAddress() as Hex);
- return encodeAbiParameters(parseAbiParameters("bytes, address"), [moduleSignature, moduleAddressToUse]);
- }
-
- public async getPaymasterUserOp(
- userOp: Partial,
- paymasterServiceData: PaymasterUserOperationDto,
- ): Promise> {
- if (paymasterServiceData.mode === PaymasterMode.SPONSORED) {
- return this.getPaymasterAndData(userOp, paymasterServiceData);
- } else if (paymasterServiceData.mode === PaymasterMode.ERC20) {
- if (paymasterServiceData?.feeQuote) {
- const { feeQuote, spender, maxApproval = false } = paymasterServiceData;
- Logger.log("there is a feeQuote: ", feeQuote);
- if (!spender) throw new Error(ERROR_MESSAGES.SPENDER_REQUIRED);
- if (!feeQuote) throw new Error(ERROR_MESSAGES.FAILED_FEE_QUOTE_FETCH);
- if (paymasterServiceData.skipPatchCallData && paymasterServiceData.skipPatchCallData === true) {
- return this.getPaymasterAndData(userOp, {
- ...paymasterServiceData,
- feeTokenAddress: feeQuote.tokenAddress,
- });
- }
- const partialUserOp = await this.buildTokenPaymasterUserOp(userOp, {
- ...paymasterServiceData,
- spender,
- maxApproval,
- feeQuote,
- });
- return this.getPaymasterAndData(partialUserOp, {
- ...paymasterServiceData,
- feeTokenAddress: feeQuote.tokenAddress,
- calculateGasLimits: true, // Always recommended and especially when using token paymaster
- });
- } else if (paymasterServiceData?.preferredToken) {
- const { preferredToken } = paymasterServiceData;
- Logger.log("there is a preferred token: ", preferredToken);
- const feeQuotesResponse = await this.getPaymasterFeeQuotesOrData(userOp, paymasterServiceData);
- const spender = feeQuotesResponse.tokenPaymasterAddress;
- const feeQuote = feeQuotesResponse.feeQuotes?.[0];
- if (!spender) throw new Error(ERROR_MESSAGES.SPENDER_REQUIRED);
- if (!feeQuote) throw new Error(ERROR_MESSAGES.FAILED_FEE_QUOTE_FETCH);
- return this.getPaymasterUserOp(userOp, { ...paymasterServiceData, feeQuote, spender }); // Recursively call getPaymasterUserOp with the feeQuote
- } else {
- Logger.log("ERC20 mode without feeQuote or preferredToken provided. Passing through unchanged.");
- return userOp;
- }
- }
- throw new Error("Invalid paymaster mode");
- }
-
- private async getPaymasterAndData(
- userOp: Partial,
- paymasterServiceData: PaymasterUserOperationDto,
- ): Promise> {
- const paymaster = this.paymaster as IHybridPaymaster;
- const paymasterData = await paymaster.getPaymasterAndData(userOp, paymasterServiceData);
- return { ...userOp, ...paymasterData };
- }
-
- private async getPaymasterFeeQuotesOrData(
- userOp: Partial,
- feeQuotesOrData: FeeQuotesOrDataDto,
- ): Promise {
- const paymaster = this.paymaster as IHybridPaymaster;
- const tokenList = feeQuotesOrData?.preferredToken
- ? [feeQuotesOrData?.preferredToken]
- : feeQuotesOrData?.tokenList?.length
- ? feeQuotesOrData?.tokenList
- : [];
- return paymaster.getPaymasterFeeQuotesOrData(userOp, { ...feeQuotesOrData, tokenList });
- }
-
- /**
- *
- * @description This function will retrieve fees from the paymaster in erc20 mode
- *
- * @param manyOrOneTransactions Array of {@link Transaction} to be batched and sent. Can also be a single {@link Transaction}.
- * @param buildUseropDto {@link BuildUserOpOptions}.
- * @returns Promise
- *
- * @example
- * import { createClient } from "viem"
- * import { createSmartAccountClient } from "@biconomy/account"
- * import { createWalletClient, http } from "viem";
- * import { polygonMumbai } from "viem/chains";
- *
- * const signer = createWalletClient({
- * account,
- * chain: polygonMumbai,
- * transport: http(),
- * });
- *
- * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl }); // Retrieve bundler url from dasboard
- * const encodedCall = encodeFunctionData({
- * abi: parseAbi(["function safeMint(address to) public"]),
- * functionName: "safeMint",
- * args: ["0x..."],
- * });
- *
- * const transaction = {
- * to: nftAddress,
- * data: encodedCall
- * }
- *
- * const feeQuotesResponse: FeeQuotesOrDataResponse = await smartAccount.getTokenFees(transaction, { paymasterServiceData: { mode: PaymasterMode.ERC20 } });
- *
- * const userSeletedFeeQuote = feeQuotesResponse.feeQuotes?.[0];
- *
- * const { wait } = await smartAccount.sendTransaction(transaction, {
- * paymasterServiceData: {
- * mode: PaymasterMode.ERC20,
- * feeQuote: userSeletedFeeQuote,
- * spender: feeQuotesResponse.tokenPaymasterAddress,
- * },
- * });
- *
- * const { success, receipt } = await wait();
- *
- */
- public async getTokenFees(
- manyOrOneTransactions: Transaction | Transaction[],
- buildUseropDto: BuildUserOpOptions,
- ): Promise {
- const txs = Array.isArray(manyOrOneTransactions) ? manyOrOneTransactions : [manyOrOneTransactions];
- const userOp = await this.buildUserOp(txs, buildUseropDto);
- if (!buildUseropDto.paymasterServiceData) throw new Error("paymasterServiceData was not provided");
- return this.getPaymasterFeeQuotesOrData(userOp, buildUseropDto.paymasterServiceData);
- }
-
- /**
- *
- * @description This function will return an array of supported tokens from the erc20 paymaster associated with the Smart Account
- * @returns Promise<{@link SupportedToken}>
- *
- * @example
- * import { createClient } from "viem"
- * import { createSmartAccountClient } from "@biconomy/account"
- * import { createWalletClient, http } from "viem";
- * import { polygonMumbai } from "viem/chains";
- *
- * const signer = createWalletClient({
- * account,
- * chain: polygonMumbai,
- * transport: http(),
- * });
- *
- * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl, biconomyPaymasterApiKey }); // Retrieve bundler url from dasboard
- * const tokens = await smartAccount.getSupportedTokens();
- *
- * // [
- * // {
- * // symbol: "USDC",
- * // tokenAddress: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
- * // decimal: 6,
- * // logoUrl: "https://assets.coingecko.com/coins/images/279/large/usd-coin.png?1595353707",
- * // premiumPercentage: 0.1,
- * // }
- * // ]
- *
- */
- public async getSupportedTokens(): Promise {
- const feeQuotesResponse = await this.getTokenFees(
- {
- data: "0x",
- value: BigInt(0),
- to: await this.getAccountAddress(),
- },
- {
- paymasterServiceData: { mode: PaymasterMode.ERC20 },
- },
- );
- return (feeQuotesResponse?.feeQuotes ?? []).map(({ maxGasFee: _, maxGasFeeUSD: __, validUntil: ___, usdPayment: ____, ...rest }) => rest);
- }
-
- /**
- *
- * @param userOp
- * @param params
- * @description This function will take a user op as an input, sign it with the owner key, and send it to the bundler.
- * @returns Promise
- * Sends a user operation
- *
- * - Docs: https://docs.biconomy.io/Account/transactions/userpaid#send-useroperation
- *
- * @param userOp Partial<{@link UserOperationStruct}> the userOp params to be sent.
- * @param params {@link SendUserOpParams}.
- * @returns Promise<{@link UserOpResponse}> that you can use to track the user operation.
- *
- * @example
- * import { createClient } from "viem"
- * import { createSmartAccountClient } from "@biconomy/account"
- * import { createWalletClient, http } from "viem";
- * import { polygonMumbai } from "viem/chains";
- *
- * const signer = createWalletClient({
- * account,
- * chain: polygonMumbai,
- * transport: http(),
- * });
- *
- * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl }); // Retrieve bundler url from dasboard
- * const encodedCall = encodeFunctionData({
- * abi: parseAbi(["function safeMint(address to) public"]),
- * functionName: "safeMint",
- * args: ["0x..."],
- * });
- *
- * const transaction = {
- * to: nftAddress,
- * data: encodedCall
- * }
- *
- * const userOp = await smartAccount.buildUserOp([transaction]);
- *
- * const { wait } = await smartAccount.sendUserOp(userOp);
- * const { success, receipt } = await wait();
- *
- */
- async sendUserOp(userOp: Partial, params?: SendUserOpParams): Promise {
- delete userOp.signature;
- const userOperation = await this.signUserOp(userOp, params);
- const bundlerResponse = await this.sendSignedUserOp(userOperation, params?.simulationType);
- return bundlerResponse;
- }
-
- /**
- *
- * @param userOp - The signed user operation to send
- * @param simulationType - The type of simulation to perform ("validation" | "validation_and_execution")
- * @description This function call will take 'signedUserOp' as input and send it to the bundler
- * @returns
- */
- async sendSignedUserOp(userOp: UserOperationStruct, simulationType?: SimulationType): Promise {
- const requiredFields: UserOperationKey[] = [
- "sender",
- "nonce",
- "initCode",
- "callData",
- "callGasLimit",
- "verificationGasLimit",
- "preVerificationGas",
- "maxFeePerGas",
- "maxPriorityFeePerGas",
- "paymasterAndData",
- "signature",
- ];
- this.validateUserOp(userOp, requiredFields);
- if (!this.bundler) throw new Error("Bundler is not provided");
- Logger.warn("userOp being sent to the bundler", userOp);
- const bundlerResponse = await this.bundler.sendUserOp(userOp, simulationType);
- return bundlerResponse;
- }
-
- async getUserOpHash(userOp: Partial): Promise {
- const userOpHash = keccak256(packUserOp(userOp, true) as Hex);
- const enc = encodeAbiParameters(parseAbiParameters("bytes32, address, uint256"), [userOpHash, this.entryPoint.address, BigInt(this.chainId)]);
- return keccak256(enc);
- }
-
- async estimateUserOpGas(userOp: Partial, stateOverrideSet?: StateOverrideSet): Promise> {
- if (!this.bundler) throw new Error("Bundler is not provided");
- const requiredFields: UserOperationKey[] = ["sender", "nonce", "initCode", "callData"];
- this.validateUserOp(userOp, requiredFields);
-
- const finalUserOp = userOp;
-
- // Making call to bundler to get gas estimations for userOp
- const { callGasLimit, verificationGasLimit, preVerificationGas, maxFeePerGas, maxPriorityFeePerGas } = await this.bundler.estimateUserOpGas(
- userOp,
- stateOverrideSet,
- );
- // if neither user sent gas fee nor the bundler, estimate gas from provider
- if (!userOp.maxFeePerGas && !userOp.maxPriorityFeePerGas && (!maxFeePerGas || !maxPriorityFeePerGas)) {
- const feeData = await this.provider.estimateFeesPerGas();
- if (feeData.maxFeePerGas?.toString()) {
- finalUserOp.maxFeePerGas = ("0x" + feeData.maxFeePerGas.toString(16)) as Hex;
- } else if (feeData.gasPrice?.toString()) {
- finalUserOp.maxFeePerGas = ("0x" + feeData.gasPrice.toString(16)) as Hex;
- } else {
- finalUserOp.maxFeePerGas = ("0x" + (await this.provider.getGasPrice()).toString(16)) as Hex;
- }
-
- if (feeData.maxPriorityFeePerGas?.toString()) {
- finalUserOp.maxPriorityFeePerGas = ("0x" + feeData.maxPriorityFeePerGas?.toString()) as Hex;
- } else if (feeData.gasPrice?.toString()) {
- finalUserOp.maxPriorityFeePerGas = toHex(Number(feeData.gasPrice?.toString()));
- } else {
- finalUserOp.maxPriorityFeePerGas = ("0x" + (await this.provider.getGasPrice()).toString(16)) as Hex;
- }
- } else {
- finalUserOp.maxFeePerGas = toHex(Number(maxFeePerGas)) ?? userOp.maxFeePerGas;
- finalUserOp.maxPriorityFeePerGas = toHex(Number(maxPriorityFeePerGas)) ?? userOp.maxPriorityFeePerGas;
- }
- finalUserOp.verificationGasLimit = toHex(Number(verificationGasLimit)) ?? userOp.verificationGasLimit;
- finalUserOp.callGasLimit = toHex(Number(callGasLimit)) ?? userOp.callGasLimit;
- finalUserOp.preVerificationGas = toHex(Number(preVerificationGas)) ?? userOp.preVerificationGas;
- if (!finalUserOp.paymasterAndData) {
- finalUserOp.paymasterAndData = "0x";
- }
-
- return finalUserOp;
- }
-
- // Could call it nonce space
- async getNonce(nonceKey?: number): Promise {
- const nonceSpace = nonceKey ?? 0;
- try {
- const address = await this.getAddress();
- return await this.entryPoint.read.getNonce([address, BigInt(nonceSpace)]);
- } catch (e) {
- return BigInt(0);
- }
- }
-
- private async getBuildUserOpNonce(nonceOptions: NonceOptions | undefined): Promise {
- let nonce = BigInt(0);
- try {
- if (nonceOptions?.nonceOverride) {
- nonce = BigInt(nonceOptions?.nonceOverride);
- } else {
- const _nonceSpace = nonceOptions?.nonceKey ?? 0;
- nonce = await this.getNonce(_nonceSpace);
- }
- } catch (error) {
- // Not throwing this error as nonce would be 0 if this.getNonce() throw exception, which is expected flow for undeployed account
- Logger.warn("Error while getting nonce for the account. This is expected for undeployed accounts set nonce to 0");
- }
- return nonce;
- }
-
- /**
- * Sends a transaction (builds and sends a user op in sequence)
- *
- * - Docs: https://docs.biconomy.io/Account/transactions/userpaid#send-transaction
- *
- * @param manyOrOneTransactions Array of {@link Transaction} to be batched and sent. Can also be a single {@link Transaction}.
- * @param buildUseropDto {@link BuildUserOpOptions}.
- * @returns Promise<{@link UserOpResponse}> that you can use to track the user operation.
- *
- * @example
- * import { createClient } from "viem"
- * import { createSmartAccountClient } from "@biconomy/account"
- * import { createWalletClient, http } from "viem";
- * import { polygonMumbai } from "viem/chains";
- *
- * const signer = createWalletClient({
- * account,
- * chain: polygonMumbai,
- * transport: http(),
- * });
- *
- * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl }); // Retrieve bundler url from dasboard
- * const encodedCall = encodeFunctionData({
- * abi: parseAbi(["function safeMint(address to) public"]),
- * functionName: "safeMint",
- * args: ["0x..."],
- * });
- *
- * const transaction = {
- * to: nftAddress,
- * data: encodedCall
- * }
- *
- * const { waitForTxHash } = await smartAccount.sendTransaction(transaction);
- * const { transactionHash, userOperationReceipt } = await wait();
- *
- */
- async sendTransaction(manyOrOneTransactions: Transaction | Transaction[], buildUseropDto?: BuildUserOpOptions): Promise {
- const userOp = await this.buildUserOp(Array.isArray(manyOrOneTransactions) ? manyOrOneTransactions : [manyOrOneTransactions], buildUseropDto);
- return this.sendUserOp(userOp, { simulationType: buildUseropDto?.simulationType, ...buildUseropDto?.params });
- }
-
- /**
- * Builds a user operation
- *
- * - Docs: https://docs.biconomy.io/Account/transactions/userpaid#build-useroperation
- *
- * @param transactions Array of {@link Transaction} to be sent.
- * @param buildUseropDto {@link BuildUserOpOptions}.
- * @returns Promise> the built user operation to be sent.
- *
- * @example
- * import { createClient } from "viem"
- * import { createSmartAccountClient } from "@biconomy/account"
- * import { createWalletClient, http } from "viem";
- * import { polygonMumbai } from "viem/chains";
- *
- * const signer = createWalletClient({
- * account,
- * chain: polygonMumbai,
- * transport: http(),
- * });
- *
- * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl }); // Retrieve bundler url from dasboard
- * const encodedCall = encodeFunctionData({
- * abi: parseAbi(["function safeMint(address to) public"]),
- * functionName: "safeMint",
- * args: ["0x..."],
- * });
- *
- * const transaction = {
- * to: nftAddress,
- * data: encodedCall
- * }
- *
- * const userOp = await smartAccount.buildUserOp([{ to: "0x...", data: encodedCall }]);
- *
- */
- async buildUserOp(transactions: Transaction[], buildUseropDto?: BuildUserOpOptions): Promise> {
- const to = transactions.map((element: Transaction) => element.to as Hex);
- const data = transactions.map((element: Transaction) => (element.data as Hex) ?? "0x");
- const value = transactions.map((element: Transaction) => (element.value as bigint) ?? BigInt(0));
-
- const initCodeFetchPromise = this.getInitCode();
- const dummySignatureFetchPromise = this.getDummySignatures(buildUseropDto?.params);
-
- const [nonceFromFetch, initCode, signature] = await Promise.all([
- this.getBuildUserOpNonce(buildUseropDto?.nonceOptions),
- initCodeFetchPromise,
- dummySignatureFetchPromise,
- ]);
-
- if (transactions.length === 0) {
- throw new Error("Transactions array cannot be empty");
- }
- let callData: Hex = "0x";
- if (!buildUseropDto?.useEmptyDeployCallData) {
- if (transactions.length > 1 || buildUseropDto?.forceEncodeForBatch) {
- callData = await this.encodeExecuteBatch(to, value, data);
- } else {
- // transactions.length must be 1
- callData = await this.encodeExecute(to[0], value[0], data[0]);
- }
- }
-
- let userOp: Partial = {
- sender: (await this.getAccountAddress()) as Hex,
- nonce: toHex(nonceFromFetch),
- initCode,
- callData,
- };
-
- // for this Smart Account current validation module dummy signature will be used to estimate gas
- userOp.signature = signature;
-
- if (
- buildUseropDto?.paymasterServiceData &&
- buildUseropDto?.paymasterServiceData.mode === PaymasterMode.SPONSORED &&
- this.paymaster instanceof BiconomyPaymaster
- ) {
- const gasFeeValues = await this.bundler?.getGasFeeValues();
-
- // populate gasfee values and make a call to paymaster
- userOp.maxFeePerGas = gasFeeValues?.maxFeePerGas as Hex;
- userOp.maxPriorityFeePerGas = gasFeeValues?.maxPriorityFeePerGas as Hex;
-
- userOp = await this.getPaymasterUserOp(userOp, buildUseropDto.paymasterServiceData);
- return userOp;
- } else {
- userOp = await this.estimateUserOpGas(userOp);
-
- if (buildUseropDto?.paymasterServiceData) {
- userOp = await this.getPaymasterUserOp(userOp, buildUseropDto.paymasterServiceData);
- }
- return userOp;
- }
- }
-
- private validateUserOpAndPaymasterRequest(userOp: Partial, tokenPaymasterRequest: BiconomyTokenPaymasterRequest): void {
- if (isNullOrUndefined(userOp.callData)) {
- throw new Error("UserOp callData cannot be undefined");
- }
-
- const feeTokenAddress = tokenPaymasterRequest?.feeQuote?.tokenAddress;
- Logger.warn("Requested fee token is ", feeTokenAddress);
-
- if (!feeTokenAddress || feeTokenAddress === ADDRESS_ZERO) {
- throw new Error("Invalid or missing token address. Token address must be part of the feeQuote in tokenPaymasterRequest");
- }
-
- const spender = tokenPaymasterRequest?.spender;
- Logger.warn("Spender address is ", spender);
-
- if (!spender || spender === ADDRESS_ZERO) {
- throw new Error("Invalid or missing spender address. Sepnder address must be part of tokenPaymasterRequest");
- }
- }
-
- /**
- *
- * @param userOp partial user operation without signature and paymasterAndData
- * @param tokenPaymasterRequest This dto provides information about fee quote. Fee quote is received from earlier request getFeeQuotesOrData() to the Biconomy paymaster.
- * maxFee and token decimals from the quote, along with the spender is required to append approval transaction.
- * @notice This method should be called when gas is paid in ERC20 token using TokenPaymaster
- * @description Optional method to update the userOp.calldata with batched transaction which approves the paymaster spender with necessary amount(if required)
- * @returns updated userOp with new callData, callGasLimit
- */
- async buildTokenPaymasterUserOp(
- userOp: Partial,
- tokenPaymasterRequest: BiconomyTokenPaymasterRequest,
- ): Promise> {
- this.validateUserOpAndPaymasterRequest(userOp, tokenPaymasterRequest);
- try {
- let batchTo: Array = [];
- let batchValue: Array = [];
- let batchData: Array = [];
-
- let newCallData = userOp.callData;
- Logger.warn("Received information about fee token address and quote ", tokenPaymasterRequest);
-
- if (this.paymaster && this.paymaster instanceof Paymaster) {
- // Make a call to paymaster.buildTokenApprovalTransaction() with necessary details
-
- // Review: might request this form of an array of Transaction
- const approvalRequest: Transaction = await (this.paymaster as IHybridPaymaster).buildTokenApprovalTransaction(
- tokenPaymasterRequest,
- );
- Logger.warn("ApprovalRequest is for erc20 token ", approvalRequest.to);
-
- if (approvalRequest.data === "0x" || approvalRequest.to === ADDRESS_ZERO) {
- return userOp;
- }
-
- if (isNullOrUndefined(userOp.callData)) {
- throw new Error("UserOp callData cannot be undefined");
- }
-
- const decodedSmartAccountData = decodeFunctionData({
- abi: BiconomyAccountAbi,
- data: userOp.callData as Hex,
- });
-
- if (!decodedSmartAccountData) {
- throw new Error("Could not parse userOp call data for this smart account");
- }
-
- const smartAccountExecFunctionName = decodedSmartAccountData.functionName;
-
- Logger.warn(`Originally an ${smartAccountExecFunctionName} method call for Biconomy Account V2`);
- if (smartAccountExecFunctionName === "execute" || smartAccountExecFunctionName === "execute_ncC") {
- const methodArgsSmartWalletExecuteCall = decodedSmartAccountData.args;
- const toOriginal = methodArgsSmartWalletExecuteCall[0];
- const valueOriginal = methodArgsSmartWalletExecuteCall[1];
- const dataOriginal = methodArgsSmartWalletExecuteCall[2];
-
- batchTo.push(toOriginal);
- batchValue.push(valueOriginal);
- batchData.push(dataOriginal);
- } else if (smartAccountExecFunctionName === "executeBatch" || smartAccountExecFunctionName === "executeBatch_y6U") {
- const methodArgsSmartWalletExecuteCall = decodedSmartAccountData.args;
- batchTo = [...methodArgsSmartWalletExecuteCall[0]];
- batchValue = [...methodArgsSmartWalletExecuteCall[1]];
- batchData = [...methodArgsSmartWalletExecuteCall[2]];
- }
-
- if (approvalRequest.to && approvalRequest.data && approvalRequest.value) {
- batchTo = [approvalRequest.to as Hex, ...batchTo];
- batchValue = [BigInt(Number(approvalRequest.value.toString())), ...batchValue];
- batchData = [approvalRequest.data as Hex, ...batchData];
-
- newCallData = await this.encodeExecuteBatch(batchTo, batchValue, batchData);
- }
- const finalUserOp: Partial = {
- ...userOp,
- callData: newCallData,
- };
-
- // Optionally Requesting to update gas limits again (especially callGasLimit needs to be re-calculated)
-
- return finalUserOp;
- }
- } catch (error) {
- Logger.log("Failed to update userOp. Sending back original op");
- Logger.error("Failed to update callData with error", error);
- return userOp;
- }
- return userOp;
- }
-
- async signUserOpHash(userOpHash: string, params?: ModuleInfo): Promise {
- this.isActiveValidationModuleDefined();
- const moduleSig = (await this.activeValidationModule.signUserOpHash(userOpHash, params)) as Hex;
-
- const signatureWithModuleAddress = encodeAbiParameters(parseAbiParameters("bytes, address"), [
- moduleSig,
- this.activeValidationModule.getAddress() as Hex,
- ]);
-
- return signatureWithModuleAddress;
- }
-
- /**
- * Deploys the smart contract
- *
- * This method will deploy a Smart Account contract. It is useful for deploying in a moment when you know that gas prices are low,
- * and you want to deploy the account before sending the first user operation. This step can otherwise be skipped,
- * as the deployment will alternatively be bundled with the first user operation.
- *
- * @param buildUseropDto {@link BuildUserOpOptions}.
- * @returns Promise<{@link UserOpResponse}> that you can use to track the user operation.
- * @error Throws an error if the account has already been deployed.
- * @error Throws an error if the account has not enough native token balance to deploy, if not using a paymaster.
- *
- * @example
- * import { createClient } from "viem"
- * import { createSmartAccountClient } from "@biconomy/account"
- * import { createWalletClient, http } from "viem";
- * import { polygonMumbai } from "viem/chains";
- *
- * const signer = createWalletClient({
- * account,
- * chain: polygonMumbai,
- * transport: http(),
- * });
- *
- * const smartAccount = await createSmartAccountClient({
- * signer,
- * biconomyPaymasterApiKey,
- * bundlerUrl
- * });
- *
- * // If you want to use a paymaster...
- * const { wait } = await smartAccount.deploy({
- * paymasterServiceData: { mode: PaymasterMode.SPONSORED },
- * });
- *
- * // Or if you can't use a paymaster send native token to this address:
- * const counterfactualAddress = await smartAccount.getAccountAddress();
- *
- * // Then deploy the account
- * const { wait } = await smartAccount.deploy();
- *
- * const { success, receipt } = await wait();
- *
- */
- public async deploy(buildUseropDto?: BuildUserOpOptions): Promise {
- const accountAddress = this.accountAddress ?? (await this.getAccountAddress());
-
- // Check that the account has not already been deployed
- const byteCode = await this.provider?.getBytecode({ address: accountAddress as Hex });
- if (byteCode !== undefined) {
- throw new Error(ERROR_MESSAGES.ACCOUNT_ALREADY_DEPLOYED);
- }
-
- // Check that the account has enough native token balance to deploy, if not using a paymaster
- if (!buildUseropDto?.paymasterServiceData?.mode) {
- const nativeTokenBalance = await this.provider?.getBalance({ address: accountAddress });
- if (nativeTokenBalance === BigInt(0)) {
- throw new Error(ERROR_MESSAGES.NO_NATIVE_TOKEN_BALANCE_DURING_DEPLOY);
- }
- }
-
- const useEmptyDeployCallData = true;
-
- return this.sendTransaction(
- {
- to: accountAddress,
- data: "0x",
- },
- { ...buildUseropDto, useEmptyDeployCallData },
- );
- }
-
- async signMessage(message: string | Uint8Array): Promise {
- this.isActiveValidationModuleDefined();
- const dataHash = typeof message === "string" ? toBytes(message) : message;
- let signature = await this.activeValidationModule.signMessage(dataHash);
-
- const potentiallyIncorrectV = parseInt(signature.slice(-2), 16);
- if (![27, 28].includes(potentiallyIncorrectV)) {
- const correctV = potentiallyIncorrectV + 27;
- signature = signature.slice(0, -2) + correctV.toString(16);
- }
- if (signature.slice(0, 2) !== "0x") {
- signature = "0x" + signature;
- }
- return signature as Hex;
- }
-
- async enableModule(moduleAddress: Hex): Promise {
- const tx: Transaction = await this.getEnableModuleData(moduleAddress);
- const partialUserOp = await this.buildUserOp([tx]);
- return this.sendUserOp(partialUserOp);
- }
-
- async getEnableModuleData(moduleAddress: Hex): Promise {
- const callData = encodeFunctionData({
- abi: BiconomyAccountAbi,
- functionName: "enableModule",
- args: [moduleAddress],
- });
- const tx: Transaction = {
- to: await this.getAddress(),
- value: "0x00",
- data: callData,
- };
- return tx;
- }
-
- async getSetupAndEnableModuleData(moduleAddress: Hex, moduleSetupData: Hex): Promise {
- const callData = encodeFunctionData({
- abi: BiconomyAccountAbi,
- functionName: "setupAndEnableModule",
- args: [moduleAddress, moduleSetupData],
- });
- const tx: Transaction = {
- to: await this.getAddress(),
- value: "0x00",
- data: callData,
- };
- return tx;
- }
-
- async disableModule(prevModule: Hex, moduleAddress: Hex): Promise {
- const tx: Transaction = await this.getDisableModuleData(prevModule, moduleAddress);
- const partialUserOp = await this.buildUserOp([tx]);
- return this.sendUserOp(partialUserOp);
- }
-
- async getDisableModuleData(prevModule: Hex, moduleAddress: Hex): Promise {
- const callData = encodeFunctionData({
- abi: BiconomyAccountAbi,
- functionName: "disableModule",
- args: [prevModule, moduleAddress],
- });
- const tx: Transaction = {
- to: await this.getAddress(),
- value: "0x00",
- data: callData,
- };
- return tx;
- }
-
- async isModuleEnabled(moduleAddress: Hex): Promise {
- const accountContract = await this._getAccountContract();
- return accountContract.read.isModuleEnabled([moduleAddress]);
- }
-
- // Review
- async getAllModules(pageSize?: number): Promise> {
- pageSize = pageSize ?? 100;
- const accountContract = await this._getAccountContract();
- const result = await accountContract.read.getModulesPaginated([this.SENTINEL_MODULE as Hex, BigInt(pageSize)]);
- const modules: Array = result[0] as Array;
- return modules;
- }
-}
diff --git a/packages/account/src/abi/SmartAccount.ts b/packages/account/src/abi/SmartAccount.ts
deleted file mode 100644
index 3542c17d1..000000000
--- a/packages/account/src/abi/SmartAccount.ts
+++ /dev/null
@@ -1,944 +0,0 @@
-export const BiconomyAccountAbi = [
- {
- inputs: [],
- name: "AlreadyInitialized",
- type: "error",
- },
- {
- inputs: [],
- name: "BaseImplementationCannotBeZero",
- type: "error",
- },
- {
- inputs: [
- {
- internalType: "address",
- name: "caller",
- type: "address",
- },
- ],
- name: "CallerIsNotAnEntryPoint",
- type: "error",
- },
- {
- inputs: [
- {
- internalType: "address",
- name: "caller",
- type: "address",
- },
- ],
- name: "CallerIsNotEntryPoint",
- type: "error",
- },
- {
- inputs: [
- {
- internalType: "address",
- name: "caller",
- type: "address",
- },
- ],
- name: "CallerIsNotEntryPointOrOwner",
- type: "error",
- },
- {
- inputs: [
- {
- internalType: "address",
- name: "caller",
- type: "address",
- },
- ],
- name: "CallerIsNotEntryPointOrSelf",
- type: "error",
- },
- {
- inputs: [
- {
- internalType: "address",
- name: "caller",
- type: "address",
- },
- ],
- name: "CallerIsNotOwner",
- type: "error",
- },
- {
- inputs: [],
- name: "DelegateCallsOnly",
- type: "error",
- },
- {
- inputs: [],
- name: "EntryPointCannotBeZero",
- type: "error",
- },
- {
- inputs: [
- {
- internalType: "address",
- name: "implementationAddress",
- type: "address",
- },
- ],
- name: "InvalidImplementation",
- type: "error",
- },
- {
- inputs: [
- {
- internalType: "address",
- name: "caller",
- type: "address",
- },
- ],
- name: "MixedAuthFail",
- type: "error",
- },
- {
- inputs: [
- {
- internalType: "address",
- name: "module",
- type: "address",
- },
- ],
- name: "ModuleAlreadyEnabled",
- type: "error",
- },
- {
- inputs: [
- {
- internalType: "address",
- name: "expectedModule",
- type: "address",
- },
- {
- internalType: "address",
- name: "returnedModule",
- type: "address",
- },
- {
- internalType: "address",
- name: "prevModule",
- type: "address",
- },
- ],
- name: "ModuleAndPrevModuleMismatch",
- type: "error",
- },
- {
- inputs: [
- {
- internalType: "address",
- name: "module",
- type: "address",
- },
- ],
- name: "ModuleCannotBeZeroOrSentinel",
- type: "error",
- },
- {
- inputs: [
- {
- internalType: "address",
- name: "module",
- type: "address",
- },
- ],
- name: "ModuleNotEnabled",
- type: "error",
- },
- {
- inputs: [],
- name: "ModulesAlreadyInitialized",
- type: "error",
- },
- {
- inputs: [],
- name: "ModulesSetupExecutionFailed",
- type: "error",
- },
- {
- inputs: [],
- name: "OwnerCanNotBeSelf",
- type: "error",
- },
- {
- inputs: [],
- name: "OwnerCannotBeZero",
- type: "error",
- },
- {
- inputs: [],
- name: "OwnerProvidedIsSame",
- type: "error",
- },
- {
- inputs: [],
- name: "TransferToZeroAddressAttempt",
- type: "error",
- },
- {
- inputs: [
- {
- internalType: "uint256",
- name: "destLength",
- type: "uint256",
- },
- {
- internalType: "uint256",
- name: "valueLength",
- type: "uint256",
- },
- {
- internalType: "uint256",
- name: "funcLength",
- type: "uint256",
- },
- {
- internalType: "uint256",
- name: "operationLength",
- type: "uint256",
- },
- ],
- name: "WrongBatchProvided",
- type: "error",
- },
- {
- inputs: [
- {
- internalType: "bytes",
- name: "contractSignature",
- type: "bytes",
- },
- ],
- name: "WrongContractSignature",
- type: "error",
- },
- {
- inputs: [
- {
- internalType: "uint256",
- name: "uintS",
- type: "uint256",
- },
- {
- internalType: "uint256",
- name: "contractSignatureLength",
- type: "uint256",
- },
- {
- internalType: "uint256",
- name: "signatureLength",
- type: "uint256",
- },
- ],
- name: "WrongContractSignatureFormat",
- type: "error",
- },
- {
- inputs: [
- {
- internalType: "address",
- name: "moduleAddressProvided",
- type: "address",
- },
- ],
- name: "WrongValidationModule",
- type: "error",
- },
- {
- anonymous: false,
- inputs: [
- {
- indexed: false,
- internalType: "address",
- name: "module",
- type: "address",
- },
- ],
- name: "DisabledModule",
- type: "event",
- },
- {
- anonymous: false,
- inputs: [
- {
- indexed: false,
- internalType: "address",
- name: "module",
- type: "address",
- },
- ],
- name: "EnabledModule",
- type: "event",
- },
- {
- anonymous: false,
- inputs: [
- {
- indexed: true,
- internalType: "address",
- name: "module",
- type: "address",
- },
- ],
- name: "ExecutionFromModuleFailure",
- type: "event",
- },
- {
- anonymous: false,
- inputs: [
- {
- indexed: true,
- internalType: "address",
- name: "module",
- type: "address",
- },
- ],
- name: "ExecutionFromModuleSuccess",
- type: "event",
- },
- {
- anonymous: false,
- inputs: [
- {
- indexed: true,
- internalType: "address",
- name: "oldImplementation",
- type: "address",
- },
- {
- indexed: true,
- internalType: "address",
- name: "newImplementation",
- type: "address",
- },
- ],
- name: "ImplementationUpdated",
- type: "event",
- },
- {
- anonymous: false,
- inputs: [
- {
- indexed: false,
- internalType: "address",
- name: "module",
- type: "address",
- },
- {
- indexed: false,
- internalType: "address",
- name: "to",
- type: "address",
- },
- {
- indexed: false,
- internalType: "uint256",
- name: "value",
- type: "uint256",
- },
- {
- indexed: false,
- internalType: "bytes",
- name: "data",
- type: "bytes",
- },
- {
- indexed: false,
- internalType: "enum Enum.Operation",
- name: "operation",
- type: "uint8",
- },
- ],
- name: "ModuleTransaction",
- type: "event",
- },
- {
- anonymous: false,
- inputs: [
- {
- indexed: true,
- internalType: "address",
- name: "sender",
- type: "address",
- },
- {
- indexed: true,
- internalType: "uint256",
- name: "value",
- type: "uint256",
- },
- ],
- name: "SmartAccountReceivedNativeToken",
- type: "event",
- },
- {
- inputs: [],
- name: "VERSION",
- outputs: [
- {
- internalType: "string",
- name: "",
- type: "string",
- },
- ],
- stateMutability: "pure",
- type: "function",
- },
- {
- inputs: [],
- name: "addDeposit",
- outputs: [],
- stateMutability: "payable",
- type: "function",
- },
- {
- inputs: [
- {
- internalType: "address",
- name: "prevModule",
- type: "address",
- },
- {
- internalType: "address",
- name: "module",
- type: "address",
- },
- ],
- name: "disableModule",
- outputs: [],
- stateMutability: "nonpayable",
- type: "function",
- },
- {
- inputs: [
- {
- internalType: "address",
- name: "module",
- type: "address",
- },
- ],
- name: "enableModule",
- outputs: [],
- stateMutability: "nonpayable",
- type: "function",
- },
- {
- inputs: [],
- name: "entryPoint",
- outputs: [
- {
- internalType: "contract IEntryPoint",
- name: "",
- type: "address",
- },
- ],
- stateMutability: "view",
- type: "function",
- },
- {
- inputs: [
- {
- internalType: "address[]",
- name: "to",
- type: "address[]",
- },
- {
- internalType: "uint256[]",
- name: "value",
- type: "uint256[]",
- },
- {
- internalType: "bytes[]",
- name: "data",
- type: "bytes[]",
- },
- {
- internalType: "enum Enum.Operation[]",
- name: "operations",
- type: "uint8[]",
- },
- ],
- name: "execBatchTransactionFromModule",
- outputs: [
- {
- internalType: "bool",
- name: "success",
- type: "bool",
- },
- ],
- stateMutability: "nonpayable",
- type: "function",
- },
- {
- inputs: [
- {
- internalType: "address",
- name: "to",
- type: "address",
- },
- {
- internalType: "uint256",
- name: "value",
- type: "uint256",
- },
- {
- internalType: "bytes",
- name: "data",
- type: "bytes",
- },
- {
- internalType: "enum Enum.Operation",
- name: "operation",
- type: "uint8",
- },
- {
- internalType: "uint256",
- name: "txGas",
- type: "uint256",
- },
- ],
- name: "execTransactionFromModule",
- outputs: [
- {
- internalType: "bool",
- name: "success",
- type: "bool",
- },
- ],
- stateMutability: "nonpayable",
- type: "function",
- },
- {
- inputs: [
- {
- internalType: "address",
- name: "to",
- type: "address",
- },
- {
- internalType: "uint256",
- name: "value",
- type: "uint256",
- },
- {
- internalType: "bytes",
- name: "data",
- type: "bytes",
- },
- {
- internalType: "enum Enum.Operation",
- name: "operation",
- type: "uint8",
- },
- ],
- name: "execTransactionFromModule",
- outputs: [
- {
- internalType: "bool",
- name: "",
- type: "bool",
- },
- ],
- stateMutability: "nonpayable",
- type: "function",
- },
- {
- inputs: [
- {
- internalType: "address",
- name: "to",
- type: "address",
- },
- {
- internalType: "uint256",
- name: "value",
- type: "uint256",
- },
- {
- internalType: "bytes",
- name: "data",
- type: "bytes",
- },
- {
- internalType: "enum Enum.Operation",
- name: "operation",
- type: "uint8",
- },
- ],
- name: "execTransactionFromModuleReturnData",
- outputs: [
- {
- internalType: "bool",
- name: "success",
- type: "bool",
- },
- {
- internalType: "bytes",
- name: "returnData",
- type: "bytes",
- },
- ],
- stateMutability: "nonpayable",
- type: "function",
- },
- {
- inputs: [
- {
- internalType: "address",
- name: "dest",
- type: "address",
- },
- {
- internalType: "uint256",
- name: "value",
- type: "uint256",
- },
- {
- internalType: "bytes",
- name: "func",
- type: "bytes",
- },
- ],
- name: "execute",
- outputs: [],
- stateMutability: "nonpayable",
- type: "function",
- },
- {
- inputs: [
- {
- internalType: "address[]",
- name: "dest",
- type: "address[]",
- },
- {
- internalType: "uint256[]",
- name: "value",
- type: "uint256[]",
- },
- {
- internalType: "bytes[]",
- name: "func",
- type: "bytes[]",
- },
- ],
- name: "executeBatch",
- outputs: [],
- stateMutability: "nonpayable",
- type: "function",
- },
- {
- inputs: [
- {
- internalType: "address[]",
- name: "dest",
- type: "address[]",
- },
- {
- internalType: "uint256[]",
- name: "value",
- type: "uint256[]",
- },
- {
- internalType: "bytes[]",
- name: "func",
- type: "bytes[]",
- },
- ],
- name: "executeBatch_y6U",
- outputs: [],
- stateMutability: "nonpayable",
- type: "function",
- },
- {
- inputs: [
- {
- internalType: "address",
- name: "dest",
- type: "address",
- },
- {
- internalType: "uint256",
- name: "value",
- type: "uint256",
- },
- {
- internalType: "bytes",
- name: "func",
- type: "bytes",
- },
- ],
- name: "execute_ncC",
- outputs: [],
- stateMutability: "nonpayable",
- type: "function",
- },
- {
- inputs: [],
- name: "getDeposit",
- outputs: [
- {
- internalType: "uint256",
- name: "",
- type: "uint256",
- },
- ],
- stateMutability: "view",
- type: "function",
- },
- {
- inputs: [],
- name: "getImplementation",
- outputs: [
- {
- internalType: "address",
- name: "_implementation",
- type: "address",
- },
- ],
- stateMutability: "view",
- type: "function",
- },
- {
- inputs: [
- {
- internalType: "address",
- name: "start",
- type: "address",
- },
- {
- internalType: "uint256",
- name: "pageSize",
- type: "uint256",
- },
- ],
- name: "getModulesPaginated",
- outputs: [
- {
- internalType: "address[]",
- name: "array",
- type: "address[]",
- },
- {
- internalType: "address",
- name: "next",
- type: "address",
- },
- ],
- stateMutability: "view",
- type: "function",
- },
- {
- inputs: [
- {
- internalType: "address",
- name: "handler",
- type: "address",
- },
- {
- internalType: "address",
- name: "moduleSetupContract",
- type: "address",
- },
- {
- internalType: "bytes",
- name: "moduleSetupData",
- type: "bytes",
- },
- ],
- name: "init",
- outputs: [
- {
- internalType: "address",
- name: "",
- type: "address",
- },
- ],
- stateMutability: "nonpayable",
- type: "function",
- },
- {
- inputs: [
- {
- internalType: "address",
- name: "module",
- type: "address",
- },
- ],
- name: "isModuleEnabled",
- outputs: [
- {
- internalType: "bool",
- name: "",
- type: "bool",
- },
- ],
- stateMutability: "view",
- type: "function",
- },
- {
- inputs: [
- {
- internalType: "uint192",
- name: "_key",
- type: "uint192",
- },
- ],
- name: "nonce",
- outputs: [
- {
- internalType: "uint256",
- name: "",
- type: "uint256",
- },
- ],
- stateMutability: "view",
- type: "function",
- },
- {
- inputs: [
- {
- internalType: "address",
- name: "setupContract",
- type: "address",
- },
- {
- internalType: "bytes",
- name: "setupData",
- type: "bytes",
- },
- ],
- name: "setupAndEnableModule",
- outputs: [
- {
- internalType: "address",
- name: "",
- type: "address",
- },
- ],
- stateMutability: "nonpayable",
- type: "function",
- },
- {
- inputs: [
- {
- internalType: "address",
- name: "_implementation",
- type: "address",
- },
- ],
- name: "updateImplementation",
- outputs: [],
- stateMutability: "nonpayable",
- type: "function",
- },
- {
- inputs: [
- {
- components: [
- {
- internalType: "address",
- name: "sender",
- type: "address",
- },
- {
- internalType: "uint256",
- name: "nonce",
- type: "uint256",
- },
- {
- internalType: "bytes",
- name: "initCode",
- type: "bytes",
- },
- {
- internalType: "bytes",
- name: "callData",
- type: "bytes",
- },
- {
- internalType: "uint256",
- name: "callGasLimit",
- type: "uint256",
- },
- {
- internalType: "uint256",
- name: "verificationGasLimit",
- type: "uint256",
- },
- {
- internalType: "uint256",
- name: "preVerificationGas",
- type: "uint256",
- },
- {
- internalType: "uint256",
- name: "maxFeePerGas",
- type: "uint256",
- },
- {
- internalType: "uint256",
- name: "maxPriorityFeePerGas",
- type: "uint256",
- },
- {
- internalType: "bytes",
- name: "paymasterAndData",
- type: "bytes",
- },
- {
- internalType: "bytes",
- name: "signature",
- type: "bytes",
- },
- ],
- internalType: "struct UserOperation",
- name: "userOp",
- type: "tuple",
- },
- {
- internalType: "bytes32",
- name: "userOpHash",
- type: "bytes32",
- },
- {
- internalType: "uint256",
- name: "missingAccountFunds",
- type: "uint256",
- },
- ],
- name: "validateUserOp",
- outputs: [
- {
- internalType: "uint256",
- name: "",
- type: "uint256",
- },
- ],
- stateMutability: "nonpayable",
- type: "function",
- },
- {
- inputs: [
- {
- internalType: "address payable",
- name: "withdrawAddress",
- type: "address",
- },
- {
- internalType: "uint256",
- name: "amount",
- type: "uint256",
- },
- ],
- name: "withdrawDepositTo",
- outputs: [],
- stateMutability: "payable",
- type: "function",
- },
-] as const;
diff --git a/packages/account/src/index.ts b/packages/account/src/index.ts
deleted file mode 100644
index f46953a67..000000000
--- a/packages/account/src/index.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-import { BiconomySmartAccountV2 } from "./BiconomySmartAccountV2.js";
-import { type BiconomySmartAccountV2Config } from "./utils/Types.js";
-
-export * from "./utils/Types.js";
-export * from "./utils/Constants.js";
-export * from "./utils/Utils.js";
-export * from "./BiconomySmartAccountV2.js";
-
-export { WalletClientSigner, LocalAccountSigner, type SmartAccountSigner } from "@alchemy/aa-core";
-export {
- BiconomyPaymaster as Paymaster,
- type IPaymaster,
- PaymasterMode,
- type IHybridPaymaster,
- type PaymasterFeeQuote,
- type SponsorUserOperationDto,
- type FeeQuotesOrDataResponse,
- createPaymaster,
-} from "@biconomy/paymaster";
-export { EthersSigner, convertSigner, type LightSigner, type SupportedSigner } from "@biconomy/common";
-export {
- Bundler,
- type IBundler,
- extractChainIdFromBundlerUrl,
- type UserOpResponse,
- type UserOpStatus,
- type UserOpReceipt,
- createBundler,
-} from "@biconomy/bundler";
-export {
- createECDSAOwnershipValidationModule,
- createERC20SessionValidationModule,
- createBatchedSessionRouterModule,
- createSessionKeyManagerModule,
- createMultiChainValidationModule,
- DEFAULT_ECDSA_OWNERSHIP_MODULE,
- DEFAULT_SESSION_KEY_MANAGER_MODULE,
- DEFAULT_MULTICHAIN_MODULE,
- DEFAULT_BATCHED_SESSION_ROUTER_MODULE,
- type ECDSAOwnershipValidationModuleConfig,
- type BatchedSessionRouterModuleConfig,
- type SessionKeyManagerModuleConfig,
- type MultiChainValidationModuleConfig,
- type SessionValidationModuleConfig,
-} from "@biconomy/modules";
-
-export const createSmartAccountClient = BiconomySmartAccountV2.create;
-
-export type SmartWalletConfig = BiconomySmartAccountV2Config;
diff --git a/packages/account/src/utils/Types.ts b/packages/account/src/utils/Types.ts
deleted file mode 100644
index f653796c1..000000000
--- a/packages/account/src/utils/Types.ts
+++ /dev/null
@@ -1,304 +0,0 @@
-import { BigNumberish, SmartAccountSigner, UserOperationStruct } from "@alchemy/aa-core";
-import { IBundler } from "@biconomy/bundler";
-import {
- type FeeQuotesOrDataDto,
- type IPaymaster,
- type PaymasterFeeQuote,
- PaymasterMode,
- type SmartAccountData,
- type SponsorUserOperationDto,
-} from "@biconomy/paymaster";
-import { BaseValidationModule, ModuleInfo } from "@biconomy/modules";
-import { Chain, Hex, WalletClient } from "viem";
-import { SupportedSigner, StateOverrideSet } from "@biconomy/common";
-
-export type EntryPointAddresses = Record;
-export type BiconomyFactories = Record;
-export type BiconomyImplementations = Record;
-export type EntryPointAddressesByVersion = Record;
-export type BiconomyFactoriesByVersion = Record;
-export type BiconomyImplementationsByVersion = Record;
-
-export type SmartAccountConfig = {
- /** entryPointAddress: address of the entry point */
- entryPointAddress: string;
- /** factoryAddress: address of the smart account factory */
- bundler?: IBundler;
-};
-
-export interface BalancePayload {
- /** address: The address of the account */
- address: string;
- /** chainId: The chainId of the network */
- chainId: number;
- /** amount: The amount of the balance */
- amount: bigint;
- /** decimals: The number of decimals */
- decimals: number;
- /** formattedAmount: The amount of the balance formatted */
- formattedAmount: string;
-}
-
-export interface GasOverheads {
- /** fixed: fixed gas overhead */
- fixed: number;
- /** perUserOp: per user operation gas overhead */
- perUserOp: number;
- /** perUserOpWord: per user operation word gas overhead */
- perUserOpWord: number;
- /** zeroByte: per byte gas overhead */
- zeroByte: number;
- /** nonZeroByte: per non zero byte gas overhead */
- nonZeroByte: number;
- /** bundleSize: per signature bundleSize */
- bundleSize: number;
- /** sigSize: sigSize gas overhead */
- sigSize: number;
-}
-
-export type BaseSmartAccountConfig = {
- /** index: helps to not conflict with other smart account instances */
- index?: number;
- /** provider: WalletClientSigner from viem */
- provider?: WalletClient;
- /** entryPointAddress: address of the smart account entry point */
- entryPointAddress?: string;
- /** accountAddress: address of the smart account, potentially counterfactual */
- accountAddress?: string;
- /** overheads: {@link GasOverheads} */
- overheads?: Partial;
- /** paymaster: {@link IPaymaster} interface */
- paymaster?: IPaymaster;
- /** chainId: chainId of the network */
- chainId?: number;
-};
-
-export type BiconomyTokenPaymasterRequest = {
- /** feeQuote: {@link PaymasterFeeQuote} */
- feeQuote: PaymasterFeeQuote;
- /** spender: The address of the spender who is paying for the transaction, this can usually be set to feeQuotesResponse.tokenPaymasterAddress */
- spender: Hex;
- /** maxApproval: If set to true, the paymaster will approve the maximum amount of tokens required for the transaction. Not recommended */
- maxApproval?: boolean;
- /* skip option to patch callData if approval is already given to the paymaster */
- skipPatchCallData?: boolean;
-};
-
-export type RequireAtLeastOne = Pick> &
- {
- [K in Keys]-?: Required> & Partial>>;
- }[Keys];
-
-export type ConditionalBundlerProps = RequireAtLeastOne<
- {
- bundler: IBundler;
- bundlerUrl: string;
- },
- "bundler" | "bundlerUrl"
->;
-export type ResolvedBundlerProps = {
- bundler: IBundler;
-};
-export type ConditionalValidationProps = RequireAtLeastOne<
- {
- defaultValidationModule: BaseValidationModule;
- signer: SupportedSigner;
- },
- "defaultValidationModule" | "signer"
->;
-
-export type ResolvedValidationProps = {
- /** defaultValidationModule: {@link BaseValidationModule} */
- defaultValidationModule: BaseValidationModule;
- /** activeValidationModule: {@link BaseValidationModule}. The active validation module. Will default to the defaultValidationModule */
- activeValidationModule: BaseValidationModule;
- /** signer: ethers Wallet, viemWallet or alchemys SmartAccountSigner */
- signer: SmartAccountSigner;
- /** chainId: chainId of the network */
- chainId: number;
-};
-
-export type BiconomySmartAccountV2ConfigBaseProps = {
- /** Factory address of biconomy factory contract or some other contract you have deployed on chain */
- factoryAddress?: Hex;
- /** Sender address: If you want to override the Signer address with some other address and get counterfactual address can use this to pass the EOA and get SA address */
- senderAddress?: Hex;
- /** implementation of smart contract address or some other contract you have deployed and want to override */
- implementationAddress?: Hex;
- /** defaultFallbackHandler: override the default fallback contract address */
- defaultFallbackHandler?: Hex;
- /** rpcUrl: Rpc url, optional, we set default rpc url if not passed. */
- rpcUrl?: string; // as good as Provider
- /** paymasterUrl: The Paymaster URL retrieved from the Biconomy dashboard */
- paymasterUrl?: string;
- /** biconomyPaymasterApiKey: The API key retrieved from the Biconomy dashboard */
- biconomyPaymasterApiKey?: string;
- /** activeValidationModule: The active validation module. Will default to the defaultValidationModule */
- activeValidationModule?: BaseValidationModule;
- /** scanForUpgradedAccountsFromV1: set to true if you you want the userwho was using biconomy SA v1 to upgrade to biconomy SA v2 */
- scanForUpgradedAccountsFromV1?: boolean;
- /** the index of SA the EOA have generated and till which indexes the upgraded SA should scan */
- maxIndexForScan?: number;
- /** Can be used to optionally override the chain with a custom chain if it doesn't already exist in viems list of supported chains */
- viemChain?: Chain;
-};
-export type BiconomySmartAccountV2Config = BiconomySmartAccountV2ConfigBaseProps &
- BaseSmartAccountConfig &
- ConditionalBundlerProps &
- ConditionalValidationProps;
-
-export type BiconomySmartAccountV2ConfigConstructorProps = BiconomySmartAccountV2ConfigBaseProps &
- BaseSmartAccountConfig &
- ResolvedBundlerProps &
- ResolvedValidationProps;
-
-export type BuildUserOpOptions = {
- /** overrides: Explicitly set gas values */
- // overrides?: Overrides;
- /** Not currently in use */
- // skipBundlerGasEstimation?: boolean;
- /** params relevant to the module, mostly relevant to sessions */
- params?: ModuleInfo;
- /** nonceOptions: For overriding the nonce */
- nonceOptions?: NonceOptions;
- /** forceEncodeForBatch: For encoding the user operation for batch */
- forceEncodeForBatch?: boolean;
- /** paymasterServiceData: Options specific to transactions that involve a paymaster */
- paymasterServiceData?: PaymasterUserOperationDto;
- /** simulationType: Determine which parts of the tx a bundler will simulate: "validation" | "validation_and_execution". */
- simulationType?: SimulationType;
- /** stateOverrideSet: For overriding the state */
- stateOverrideSet?: StateOverrideSet;
- /** set to true if the tx is being used *only* to deploy the smartContract, so "0x" is set as the userOp.callData */
- useEmptyDeployCallData?: boolean;
-};
-
-export type NonceOptions = {
- /** nonceKey: The key to use for nonce */
- nonceKey?: number;
- /** nonceOverride: The nonce to use for the transaction */
- nonceOverride?: number;
-};
-
-export type SimulationType = "validation" | "validation_and_execution";
-
-export type Overrides = {
- /* Value used by inner account execution */
- callGasLimit?: Hex;
- /* Actual gas used by the validation of this UserOperation */
- verificationGasLimit?: Hex;
- /* Gas overhead of this UserOperation */
- preVerificationGas?: Hex;
- /* Maximum fee per gas (similar to EIP-1559 max_fee_per_gas) */
- maxFeePerGas?: Hex;
- /* Maximum priority fee per gas (similar to EIP-1559 max_priority_fee_per_gas) */
- maxPriorityFeePerGas?: Hex;
- /* Address of paymaster sponsoring the transaction, followed by extra data to send to the paymaster ("0x" for self-sponsored transaction) */
- paymasterData?: Hex;
- /* Data passed into the account along with the nonce during the verification step */
- signature?: Hex;
-};
-
-export type InitilizationData = {
- accountIndex?: number;
- signerAddress?: string;
-};
-
-export type PaymasterUserOperationDto = SponsorUserOperationDto &
- FeeQuotesOrDataDto & {
- /** mode: sponsored or erc20 */
- mode: PaymasterMode;
- /** Always recommended, especially when using token paymaster */
- calculateGasLimits?: boolean;
- /** Expiry duration in seconds */
- expiryDuration?: number;
- /** Webhooks to be fired after user op is sent */
- webhookData?: Record;
- /** Smart account meta data */
- smartAccountInfo?: SmartAccountData;
- /** the fee-paying token address */
- feeTokenAddress?: string;
- /** The fee quote */
- feeQuote?: PaymasterFeeQuote;
- /** The address of the spender. This is usually set to FeeQuotesOrDataResponse.tokenPaymasterAddress */
- spender?: Hex;
- /** Not recommended */
- maxApproval?: boolean;
- /* skip option to patch callData if approval is already given to the paymaster */
- skipPatchCallData?: boolean;
- };
-
-export type InitializeV2Data = {
- accountIndex?: number;
-};
-
-export type EstimateUserOpGasParams = {
- userOp: Partial;
- // overrides?: Overrides;
- /** Currrently has no effect */
- // skipBundlerGasEstimation?: boolean;
- /** paymasterServiceData: Options specific to transactions that involve a paymaster */
- paymasterServiceData?: SponsorUserOperationDto;
-};
-
-export interface TransactionDetailsForUserOp {
- /** target: The address of the contract to call */
- target: string;
- /** data: The data to send to the contract */
- data: string;
- /** value: The value to send to the contract */
- value?: BigNumberish;
- /** gasLimit: The gas limit to use for the transaction */
- gasLimit?: BigNumberish;
- /** maxFeePerGas: The maximum fee per gas to use for the transaction */
- maxFeePerGas?: BigNumberish;
- /** maxPriorityFeePerGas: The maximum priority fee per gas to use for the transaction */
- maxPriorityFeePerGas?: BigNumberish;
- /** nonce: The nonce to use for the transaction */
- nonce?: BigNumberish;
-}
-
-export type CounterFactualAddressParam = {
- index?: number;
- validationModule?: BaseValidationModule;
- /** scanForUpgradedAccountsFromV1: set to true if you you want the userwho was using biconomy SA v1 to upgrade to biconomy SA v2 */
- scanForUpgradedAccountsFromV1?: boolean;
- /** the index of SA the EOA have generated and till which indexes the upgraded SA should scan */
- maxIndexForScan?: number;
-};
-
-export type QueryParamsForAddressResolver = {
- eoaAddress: Hex;
- index: number;
- moduleAddress: Hex;
- moduleSetupData: Hex;
- maxIndexForScan?: number;
-};
-
-export type SmartAccountInfo = {
- /** accountAddress: The address of the smart account */
- accountAddress: Hex;
- /** factoryAddress: The address of the smart account factory */
- factoryAddress: Hex;
- /** currentImplementation: The address of the current implementation */
- currentImplementation: string;
- /** currentVersion: The version of the smart account */
- currentVersion: string;
- /** factoryVersion: The version of the factory */
- factoryVersion: string;
- /** deploymentIndex: The index of the deployment */
- deploymentIndex: BigNumberish;
-};
-
-export type ValueOrData = RequireAtLeastOne<
- {
- value: BigNumberish | string;
- data: string;
- },
- "value" | "data"
->;
-export type Transaction = {
- to: string;
-} & ValueOrData;
-
-export type SupportedToken = Omit;
diff --git a/packages/account/src/utils/Utils.ts b/packages/account/src/utils/Utils.ts
deleted file mode 100644
index 7d18918b1..000000000
--- a/packages/account/src/utils/Utils.ts
+++ /dev/null
@@ -1,105 +0,0 @@
-import { encodeAbiParameters, parseAbiParameters, keccak256, Hex, Chain } from "viem";
-import type { UserOperationStruct } from "@alchemy/aa-core";
-import { SupportedSigner, convertSigner } from "@biconomy/common";
-import { extractChainIdFromBundlerUrl } from "@biconomy/bundler";
-import { BiconomySmartAccountV2Config } from "./Types.js";
-import { extractChainIdFromPaymasterUrl } from "@biconomy/bundler";
-import * as chains from "viem/chains";
-import { ERROR_MESSAGES } from "./Constants.js";
-
-/**
- * pack the userOperation
- * @param op
- * @param forSignature "true" if the hash is needed to calculate the getUserOpHash()
- * "false" to pack entire UserOp, for calculating the calldata cost of putting it on-chain.
- */
-export function packUserOp(op: Partial, forSignature = true): string {
- if (!op.initCode || !op.callData || !op.paymasterAndData) throw new Error("Missing userOp properties");
- if (forSignature) {
- return encodeAbiParameters(parseAbiParameters("address, uint256, bytes32, bytes32, uint256, uint256, uint256, uint256, uint256, bytes32"), [
- op.sender as Hex,
- BigInt(op.nonce as Hex),
- keccak256(op.initCode as Hex),
- keccak256(op.callData as Hex),
- BigInt(op.callGasLimit as Hex),
- BigInt(op.verificationGasLimit as Hex),
- BigInt(op.preVerificationGas as Hex),
- BigInt(op.maxFeePerGas as Hex),
- BigInt(op.maxPriorityFeePerGas as Hex),
- keccak256(op.paymasterAndData as Hex),
- ]);
- } else {
- // for the purpose of calculating gas cost encode also signature (and no keccak of bytes)
- return encodeAbiParameters(parseAbiParameters("address, uint256, bytes, bytes, uint256, uint256, uint256, uint256, uint256, bytes, bytes"), [
- op.sender as Hex,
- BigInt(op.nonce as Hex),
- op.initCode as Hex,
- op.callData as Hex,
- BigInt(op.callGasLimit as Hex),
- BigInt(op.verificationGasLimit as Hex),
- BigInt(op.preVerificationGas as Hex),
- BigInt(op.maxFeePerGas as Hex),
- BigInt(op.maxPriorityFeePerGas as Hex),
- op.paymasterAndData as Hex,
- op.signature as Hex,
- ]);
- }
-}
-
-export const isNullOrUndefined = (value: any): value is undefined => {
- return value === null || value === undefined;
-};
-
-export const compareChainIds = async (
- signer: SupportedSigner,
- biconomySmartAccountConfig: BiconomySmartAccountV2Config,
- skipChainIdCalls: boolean,
-): Promise => {
- const signerResult = await convertSigner(signer, skipChainIdCalls);
-
- const chainIdFromBundler = biconomySmartAccountConfig.bundlerUrl
- ? extractChainIdFromBundlerUrl(biconomySmartAccountConfig.bundlerUrl)
- : biconomySmartAccountConfig.bundler
- ? extractChainIdFromBundlerUrl(biconomySmartAccountConfig.bundler.getBundlerUrl())
- : undefined;
-
- const chainIdFromPaymasterUrl = biconomySmartAccountConfig.paymasterUrl
- ? extractChainIdFromPaymasterUrl(biconomySmartAccountConfig.paymasterUrl)
- : undefined;
-
- if (!isNullOrUndefined(signerResult.chainId)) {
- if (chainIdFromBundler !== undefined && signerResult.chainId !== chainIdFromBundler) {
- throw new Error(`Chain IDs from signer (${signerResult.chainId}) and bundler (${chainIdFromBundler}) do not match.`);
- }
- if (chainIdFromPaymasterUrl !== undefined && signerResult.chainId !== chainIdFromPaymasterUrl) {
- throw new Error(`Chain IDs from signer (${signerResult.chainId}) and paymaster (${chainIdFromPaymasterUrl}) do not match.`);
- }
- } else {
- if (chainIdFromBundler !== undefined && chainIdFromPaymasterUrl !== undefined && chainIdFromBundler !== chainIdFromPaymasterUrl) {
- throw new Error(`Chain IDs from bundler (${chainIdFromBundler}) and paymaster (${chainIdFromPaymasterUrl}) do not match.`);
- }
- }
-};
-
-export const isValidRpcUrl = (url: string): boolean => {
- const regex = /^(https:\/\/|wss:\/\/).*/;
- return regex.test(url);
-};
-
-export const addressEquals = (a?: string, b?: string): boolean => !!a && !!b && a?.toLowerCase() === b.toLowerCase();
-
-/**
- * Utility method for converting a chainId to a {@link Chain} object
- *
- * @param chainId
- * @returns a {@link Chain} object for the given chainId
- * @throws if the chainId is not found
- */
-export const getChain = (chainId: number): Chain => {
- for (const chain of Object.values(chains)) {
- if (chain.id === chainId) {
- return chain;
- }
- }
- throw new Error(ERROR_MESSAGES.CHAIN_NOT_FOUND);
-};
diff --git a/packages/account/src/utils/index.ts b/packages/account/src/utils/index.ts
deleted file mode 100644
index bc65ec9be..000000000
--- a/packages/account/src/utils/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export * from "./Types.js";
-export * from "./Utils.js";
-export * from "./Constants.js";
diff --git a/packages/account/tests/account.e2e.spec.ts b/packages/account/tests/account.e2e.spec.ts
deleted file mode 100644
index 82f9649f1..000000000
--- a/packages/account/tests/account.e2e.spec.ts
+++ /dev/null
@@ -1,671 +0,0 @@
-import { TestData } from "../../../tests";
-import { createSmartAccountClient, ERROR_MESSAGES, FeeQuotesOrDataResponse, NATIVE_TOKEN_ALIAS, PaymasterMode } from "../src/index";
-import { Hex, createWalletClient, encodeFunctionData, getContract, http, parseAbi } from "viem";
-import { UserOperationStruct } from "@alchemy/aa-core";
-import { checkBalance, entryPointABI } from "../../../tests/utils";
-import { ERC20_ABI } from "@biconomy/modules";
-import { privateKeyToAccount, generatePrivateKey } from "viem/accounts";
-
-describe("Account Tests", () => {
- let mumbai: TestData;
- let baseSepolia: TestData;
- let optimism: TestData;
-
- beforeEach(() => {
- // @ts-ignore: Comes from setup-e2e-tests
- [mumbai, baseSepolia, optimism] = testDataPerChain;
- });
-
- it("should have addresses", async () => {
- const {
- whale: { viemWallet: signer, publicAddress: sender },
- minnow: { viemWallet: recipientSigner, publicAddress: recipient },
- bundlerUrl,
- } = mumbai;
-
- const {
- whale: { viemWallet: signerBase, publicAddress: senderBase },
- minnow: { viemWallet: recipientSignerBase, publicAddress: recipientBase },
- bundlerUrl: bundlerUrlBase,
- } = baseSepolia;
-
- const {
- whale: { viemWallet: signerOp, publicAddress: senderOp },
- minnow: { viemWallet: recipientSignerOp, publicAddress: recipientOp },
- bundlerUrl: bundlerUrlOp,
- } = optimism;
-
- const smartAccount = await createSmartAccountClient({
- signer,
- bundlerUrl,
- });
-
- const reciepientSmartAccount = await createSmartAccountClient({
- signer: recipientSigner,
- bundlerUrl,
- });
-
- const smartAccountBase = await createSmartAccountClient({
- signer: signerBase,
- bundlerUrl: bundlerUrlBase,
- });
-
- const reciepientSmartAccountBase = await createSmartAccountClient({
- signer: recipientSignerBase,
- bundlerUrl: bundlerUrlBase,
- });
-
- const smartAccountOp = await createSmartAccountClient({
- signer: signerOp,
- bundlerUrl: bundlerUrlOp,
- });
-
- const reciepientSmartAccountOp = await createSmartAccountClient({
- signer: recipientSignerOp,
- bundlerUrl: bundlerUrlOp,
- });
-
- const addresses = await Promise.all([
- sender,
- smartAccount.getAddress(),
- recipient,
- reciepientSmartAccount.getAddress(),
- senderBase,
- smartAccountBase.getAddress(),
- recipientBase,
- reciepientSmartAccountBase.getAddress(),
- senderOp,
- smartAccountOp.getAddress(),
- recipientOp,
- reciepientSmartAccountOp.getAddress(),
- ]);
- expect(addresses.every(Boolean)).toBeTruthy();
- });
-
- it("should send some native token to a recipient", async () => {
- const {
- whale: { viemWallet: signer },
- minnow: { publicAddress: recipient },
- bundlerUrl,
- publicClient,
- } = mumbai;
-
- const smartAccount = await createSmartAccountClient({
- signer,
- bundlerUrl,
- });
-
- const balance = (await checkBalance(publicClient, recipient)) as bigint;
- const { wait } = await smartAccount.sendTransaction(
- {
- to: recipient,
- value: 1,
- },
- {
- simulationType: "validation_and_execution",
- },
- );
-
- const result = await wait();
- const newBalance = (await checkBalance(publicClient, recipient)) as bigint;
-
- expect(result?.receipt?.transactionHash).toBeTruthy();
- expect(newBalance - balance).toBe(1n);
- }, 50000);
-
- it("Create a smart account with paymaster with an api key", async () => {
- const {
- whale: { viemWallet: signer },
- bundlerUrl,
- paymasterUrl,
- } = mumbai;
-
- const smartAccount = await createSmartAccountClient({
- signer,
- paymasterUrl,
- bundlerUrl,
- });
-
- const paymaster = smartAccount.paymaster;
- expect(paymaster).not.toBeNull();
- expect(paymaster).not.toBeUndefined();
- });
-
- it("Should gaslessly mint an NFT on Mumbai", async () => {
- const {
- whale: { viemWallet: signer, publicAddress: recipient },
- bundlerUrl,
- paymasterUrl,
- publicClient,
- nftAddress,
- } = mumbai;
-
- const smartAccount = await createSmartAccountClient({
- signer,
- bundlerUrl,
- paymasterUrl,
- });
-
- const encodedCall = encodeFunctionData({
- abi: parseAbi(["function safeMint(address to) public"]),
- functionName: "safeMint",
- args: [recipient],
- });
-
- const transaction = {
- to: nftAddress, // NFT address
- data: encodedCall,
- };
-
- const balance = (await checkBalance(publicClient, recipient, nftAddress)) as bigint;
-
- const maticBalanceBefore = await checkBalance(publicClient, await smartAccount.getAddress());
-
- const response = await smartAccount.sendTransaction(transaction, {
- paymasterServiceData: { mode: PaymasterMode.SPONSORED },
- simulationType: "validation",
- });
-
- const userOpReceipt = await response.wait(3);
- expect(userOpReceipt.userOpHash).toBeTruthy();
- expect(userOpReceipt.success).toBe("true");
-
- const maticBalanceAfter = await checkBalance(publicClient, await smartAccount.getAddress());
-
- expect(maticBalanceAfter).toEqual(maticBalanceBefore);
-
- const newBalance = (await checkBalance(publicClient, recipient, nftAddress)) as bigint;
-
- expect(newBalance - balance).toBe(1n);
- }, 60000);
-
- // TODO(Remove when Yash fixes approvals issue)
- it.skip("Should mint an NFT on Mumbai and pay with ERC20 - with preferredToken", async () => {
- const {
- whale: { viemWallet: signer, publicAddress: recipient },
- bundlerUrl,
- nftAddress,
- publicClient
- } = mumbai;
-
- const smartAccount = await createSmartAccountClient({
- signer,
- bundlerUrl,
- biconomyPaymasterApiKey: "7K_k68BFN.ed274da8-69a1-496d-a897-508fc2653666",
- });
-
- const accountAddress = await smartAccount.getAddress();
-
- const encodedCall = encodeFunctionData({
- abi: parseAbi(["function safeMint(address _to)"]),
- functionName: "safeMint",
- args: [recipient],
- });
-
- const transaction = {
- to: nftAddress, // NFT address
- data: encodedCall,
- };
-
- const balance = (await checkBalance(publicClient, recipient, nftAddress)) as bigint;
- const maticBalanceBefore = await checkBalance(publicClient, accountAddress);
- const usdcBalanceBefore = await checkBalance(publicClient, accountAddress, "0xda5289fcaaf71d52a80a254da614a192b693e977");
-
- const { wait } = await smartAccount.sendTransaction([transaction], {
- paymasterServiceData: {
- mode: PaymasterMode.ERC20,
- preferredToken: "0xda5289fcaaf71d52a80a254da614a192b693e977",
- },
- });
-
- const {
- receipt: { transactionHash },
- userOpHash,
- success,
- } = await wait();
-
- expect(transactionHash).toBeTruthy();
- expect(userOpHash).toBeTruthy();
- expect(success).toBe("true");
-
- const maticBalanceAfter = await checkBalance(publicClient, await smartAccount.getAddress());
- expect(maticBalanceAfter).toEqual(maticBalanceBefore);
-
- const usdcBalanceAfter = await checkBalance(publicClient, await smartAccount.getAddress(), "0xda5289fcaaf71d52a80a254da614a192b693e977");
- expect(usdcBalanceAfter).toBeLessThan(usdcBalanceBefore);
-
- const newBalance = (await checkBalance(publicClient, recipient, nftAddress)) as bigint;
- expect(newBalance - balance).toBe(1n);
- }, 60000);
-
- it("Should expect several feeQuotes in resonse to empty tokenInfo fields", async () => {
- const {
- whale: { viemWallet: signer, publicAddress: recipient },
- bundlerUrl,
- biconomyPaymasterApiKey,
- nftAddress,
- } = mumbai;
-
- const smartAccount = await createSmartAccountClient({
- signer,
- bundlerUrl,
- biconomyPaymasterApiKey,
- });
-
- const encodedCall = encodeFunctionData({
- abi: parseAbi(["function safeMint(address _to)"]),
- functionName: "safeMint",
- args: [recipient],
- });
-
- const transaction = {
- to: nftAddress, // NFT address
- data: encodedCall,
- };
-
- const feeQuotesResponse = await smartAccount.getTokenFees(transaction, { paymasterServiceData: { mode: PaymasterMode.ERC20 } });
- expect(feeQuotesResponse.feeQuotes?.length).toBeGreaterThan(1);
- });
-
- // TODO(Remove when Yash fixes approvals issue)
- it.skip("Should mint an NFT on Mumbai and pay with ERC20 - with token selection and no maxApproval", async () => {
- const preferredToken: Hex = "0xda5289fcaaf71d52a80a254da614a192b693e977";
- const {
- whale: { viemWallet: signer, publicAddress: recipient },
- bundlerUrl,
- paymasterUrl,
- publicClient,
- nftAddress,
- } = mumbai;
-
- const smartAccount = await createSmartAccountClient({
- signer,
- bundlerUrl,
- paymasterUrl,
- });
-
- const smartAccountAddress = await smartAccount.getAddress();
-
- const encodedCall = encodeFunctionData({
- abi: parseAbi(["function safeMint(address _to)"]),
- functionName: "safeMint",
- args: [recipient],
- });
-
- const transaction = {
- to: nftAddress, // NFT address
- data: encodedCall,
- };
-
- const feeQuotesResponse = await smartAccount.getTokenFees(transaction, {
- paymasterServiceData: {
- mode: PaymasterMode.ERC20,
- preferredToken,
- },
- });
-
- const selectedFeeQuote = feeQuotesResponse.feeQuotes?.[0];
- const spender = feeQuotesResponse.tokenPaymasterAddress!;
-
- const contract = getContract({
- address: preferredToken,
- abi: parseAbi(ERC20_ABI),
- client: publicClient,
- });
-
- const allowanceBefore = (await contract.read.allowance([smartAccountAddress, spender])) as bigint;
-
- if (allowanceBefore > 0) {
- const decreaseAllowanceData = encodeFunctionData({
- abi: parseAbi(["function decreaseAllowance(address spender, uint256 subtractedValue)"]),
- functionName: "decreaseAllowance",
- args: [spender, allowanceBefore],
- });
-
- const decreaseAllowanceTx = {
- to: "0xda5289fcaaf71d52a80a254da614a192b693e977",
- data: decreaseAllowanceData,
- };
-
- const { wait } = await smartAccount.sendTransaction(decreaseAllowanceTx, { paymasterServiceData: { mode: PaymasterMode.SPONSORED } });
- const { success } = await wait();
-
- expect(success).toBe("true");
- const allowanceAfter = (await contract.read.allowance([smartAccountAddress, spender])) as bigint;
- expect(allowanceAfter).toBe(0n);
- }
-
- const balance = (await checkBalance(publicClient, recipient, nftAddress)) as bigint;
- const maticBalanceBefore = await checkBalance(publicClient, smartAccountAddress);
- const usdcBalanceBefore = await checkBalance(publicClient, smartAccountAddress, preferredToken);
-
- const { wait } = await smartAccount.sendTransaction(transaction, {
- paymasterServiceData: {
- mode: PaymasterMode.ERC20,
- feeQuote: selectedFeeQuote,
- spender: feeQuotesResponse.tokenPaymasterAddress,
- },
- });
-
- const {
- receipt: { transactionHash },
- userOpHash,
- success,
- } = await wait();
-
- expect(userOpHash).toBeTruthy();
- expect(success).toBe("true");
- expect(transactionHash).toBeTruthy();
-
- const maticBalanceAfter = await checkBalance(publicClient, smartAccountAddress);
- expect(maticBalanceAfter).toEqual(maticBalanceBefore);
-
- const usdcBalanceAfter = await checkBalance(publicClient, smartAccountAddress, preferredToken);
- expect(usdcBalanceAfter).toBeLessThan(usdcBalanceBefore);
-
- const newBalance = (await checkBalance(publicClient, recipient, nftAddress)) as bigint;
- expect(newBalance - balance).toBe(1n);
- }, 60000);
-
- it("Should throw and error if missing field for ERC20 Paymaster user op", async () => {
- const {
- whale: { viemWallet: signer, publicAddress: recipient },
- bundlerUrl,
- biconomyPaymasterApiKey,
- nftAddress,
- } = mumbai;
-
- const smartAccount = await createSmartAccountClient({
- signer,
- bundlerUrl,
- biconomyPaymasterApiKey,
- });
-
- const encodedCall = encodeFunctionData({
- abi: parseAbi(["function safeMint(address _to)"]),
- functionName: "safeMint",
- args: [recipient],
- });
-
- const transaction = {
- to: nftAddress, // NFT address
- data: encodedCall,
- };
-
- const feeQuotesResponse: FeeQuotesOrDataResponse = await smartAccount.getTokenFees(transaction, {
- paymasterServiceData: {
- mode: PaymasterMode.ERC20,
- preferredToken: "0xda5289fcaaf71d52a80a254da614a192b693e977",
- },
- });
-
- expect(async () =>
- smartAccount.sendTransaction(transaction, {
- paymasterServiceData: {
- mode: PaymasterMode.ERC20,
- feeQuote: feeQuotesResponse.feeQuotes?.[0],
- },
- simulationType: "validation",
- }),
- ).rejects.toThrow(ERROR_MESSAGES.SPENDER_REQUIRED);
- }, 60000);
-
- it("#getUserOpHash should match entryPoint.getUserOpHash", async () => {
- const {
- whale: { viemWallet: signer },
- bundlerUrl,
- entryPointAddress,
- publicClient,
- paymasterUrl,
- } = mumbai;
-
- const smartAccount = await createSmartAccountClient({
- signer,
- paymasterUrl,
- bundlerUrl,
- });
-
- const userOp: UserOperationStruct = {
- sender: "0x".padEnd(42, "1") as string,
- nonce: 2,
- initCode: "0x3333",
- callData: "0x4444",
- callGasLimit: 5,
- verificationGasLimit: 6,
- preVerificationGas: 7,
- maxFeePerGas: 8,
- maxPriorityFeePerGas: 9,
- paymasterAndData: "0xaaaaaa",
- signature: "0xbbbb",
- };
-
- const epHash = await publicClient.readContract({
- address: entryPointAddress as Hex,
- abi: entryPointABI,
- functionName: "getUserOpHash",
- // @ts-ignore
- args: [userOp],
- });
-
- const hash = await smartAccount.getUserOpHash(userOp);
- expect(hash).toBe(epHash);
- }, 30000);
-
- it("should be deployed to counterfactual address", async () => {
- const {
- whale: { viemWallet: signer },
- bundlerUrl,
- publicClient,
- paymasterUrl,
- } = mumbai;
-
- const smartAccount = await createSmartAccountClient({
- signer,
- paymasterUrl,
- bundlerUrl,
- });
-
- const accountAddress = await smartAccount.getAccountAddress();
- const byteCode = await publicClient.getBytecode({ address: accountAddress as Hex });
-
- expect(byteCode?.length).toBeGreaterThan(2);
- }, 10000); // on github runner it takes more time than 5000ms
-
- it("should check if ecdsaOwnershipModule is enabled", async () => {
- const ecdsaOwnershipModule = "0x0000001c5b32F37F5beA87BDD5374eB2aC54eA8e";
-
- const {
- whale: { viemWallet: signer },
- bundlerUrl,
- viemChain,
- } = mumbai;
-
- const smartAccount = await createSmartAccountClient({
- signer,
- bundlerUrl,
- rpcUrl: viemChain.rpcUrls.default.http[0],
- });
-
- expect(ecdsaOwnershipModule).toBe(smartAccount.activeValidationModule.getAddress());
- });
-
- it("Should throw, chain id from signer and bundlerUrl do not match", async () => {
- const {
- whale: { viemWallet: signer },
- } = mumbai;
-
- const createAccount = createSmartAccountClient({
- signer,
- bundlerUrl: "https://bundler.biconomy.io/api/v2/1/nJPK7B3ru.dd7f7861-190d-41bd-af80-6877f74b8f44", // mock
- });
-
- await expect(createAccount).rejects.toThrow();
- });
-
- it("Should throw, chain id from paymasterUrl and bundlerUrl do not match", async () => {
- const {
- whale: { viemWallet: signer },
- } = mumbai;
-
- const createAccount = createSmartAccountClient({
- signer,
- paymasterUrl: "https://paymaster.biconomy.io/api/v1/1/-RObQRX9ei.fc6918eb-c582-4417-9d5a-0507b17cfe71",
- bundlerUrl: "https://bundler.biconomy.io/api/v2/80001/nJPK7B3ru.dd7f7861-190d-41bd-af80-6877f74b8f44", // mock
- });
-
- await expect(createAccount).rejects.toThrow();
- });
- it("should deploy a smart account with native token balance", async () => {
- const {
- bundlerUrl,
- biconomyPaymasterApiKey,
- viemChain,
- publicClient,
- whale: { viemWallet: signer, publicAddress, account },
- deploymentCost,
- } = mumbai;
-
- const newPrivateKey = generatePrivateKey();
- const newAccount = privateKeyToAccount(newPrivateKey);
-
- const newViemWallet = createWalletClient({
- account: newAccount,
- chain: viemChain,
- transport: http(viemChain.rpcUrls.default.http[0]),
- });
-
- const smartAccount = await createSmartAccountClient({
- signer: newViemWallet,
- biconomyPaymasterApiKey,
- bundlerUrl,
- });
-
- const smartAccountAddress = await smartAccount.getAccountAddress();
-
- // Setup:
- const hash = await signer.sendTransaction({ to: smartAccountAddress, value: BigInt(deploymentCost), account, chain: viemChain }); // Send enough native token to counterfactual address to deploy the smart account
- const transaction = await publicClient.waitForTransactionReceipt({ hash });
- expect(transaction).toBeTruthy();
-
- // Test:
- const { wait } = await smartAccount.deploy();
- const { success } = await wait();
-
- const byteCode = await publicClient.getBytecode({ address: smartAccountAddress });
- expect(success).toBe("true");
- expect(byteCode).toBeTruthy();
- }, 60000);
-
- it("should deploy a smart account with sponsorship", async () => {
- const { bundlerUrl, biconomyPaymasterApiKey, viemChain, publicClient } = mumbai;
-
- const newPrivateKey = generatePrivateKey();
- const newAccount = privateKeyToAccount(newPrivateKey);
-
- const newViemWallet = createWalletClient({
- account: newAccount,
- chain: viemChain,
- transport: http(viemChain.rpcUrls.default.http[0]),
- });
-
- const smartAccount = await createSmartAccountClient({
- signer: newViemWallet,
- biconomyPaymasterApiKey,
- bundlerUrl,
- });
-
- const smartAccountAddress = await smartAccount.getAccountAddress();
- const balance = await publicClient.getBalance({ address: smartAccountAddress });
- expect(balance).toBe(0n);
-
- const { wait } = await smartAccount.deploy({
- paymasterServiceData: { mode: PaymasterMode.SPONSORED },
- });
- const { success } = await wait();
-
- const byteCode = await publicClient.getBytecode({ address: smartAccountAddress });
- expect(success).toBe("true");
- expect(byteCode).toBeTruthy();
- }, 60000);
-
- it("should fail to deploy a smart account if no native token balance or paymaster", async () => {
- const { bundlerUrl, biconomyPaymasterApiKey, viemChain } = mumbai;
-
- const newPrivateKey = generatePrivateKey();
- const newAccount = privateKeyToAccount(newPrivateKey);
-
- const newViemWallet = createWalletClient({
- account: newAccount,
- chain: viemChain,
- transport: http(viemChain.rpcUrls.default.http[0]),
- });
-
- const smartAccount = await createSmartAccountClient({
- signer: newViemWallet,
- biconomyPaymasterApiKey,
- bundlerUrl,
- });
-
- expect(async () => smartAccount.deploy()).rejects.toThrow(ERROR_MESSAGES.NO_NATIVE_TOKEN_BALANCE_DURING_DEPLOY);
- });
-
- it("should get supported tokens from the paymaster", async () => {
- const {
- whale: { viemWallet: signer },
- bundlerUrl,
- biconomyPaymasterApiKey,
- } = mumbai;
-
- const smartAccount = await createSmartAccountClient({
- signer,
- biconomyPaymasterApiKey,
- bundlerUrl,
- });
-
- const tokens = await smartAccount.getSupportedTokens();
-
- expect(tokens.length).toBeGreaterThan(0);
- expect(tokens[0]).toHaveProperty("tokenAddress");
- expect(tokens[0]).toHaveProperty("symbol");
- expect(tokens[0]).toHaveProperty("decimal");
- expect(tokens[0]).toHaveProperty("premiumPercentage");
- expect(tokens[0]).toHaveProperty("logoUrl");
- }, 60000);
-
- it("should fail to deploy a smart account if already deployed", async () => {
- const {
- whale: { viemWallet: signer },
- bundlerUrl,
- biconomyPaymasterApiKey,
- } = mumbai;
-
- const smartAccount = await createSmartAccountClient({
- signer,
- biconomyPaymasterApiKey,
- bundlerUrl,
- });
-
- expect(async () => smartAccount.deploy()).rejects.toThrow(ERROR_MESSAGES.ACCOUNT_ALREADY_DEPLOYED);
- }, 60000);
-
- it("should fetch balances for smartAccount", async () => {
- const usdt = "0xda5289fcaaf71d52a80a254da614a192b693e977";
- const {
- whale: { viemWallet: signer },
- bundlerUrl,
- publicClient,
- biconomyPaymasterApiKey,
- } = mumbai;
-
- const smartAccount = await createSmartAccountClient({
- signer,
- biconomyPaymasterApiKey,
- bundlerUrl,
- });
-
- const usdcBalanceBefore = await checkBalance(publicClient, await smartAccount.getAddress(), usdt);
- const [usdtBalanceFromSmartAccount] = await smartAccount.getBalances([usdt]);
-
- expect(usdcBalanceBefore).toBe(usdtBalanceFromSmartAccount.amount);
- });
-});
diff --git a/packages/account/tests/account.optimism.e2e.spec.ts b/packages/account/tests/account.optimism.e2e.spec.ts
deleted file mode 100644
index d558ba4ed..000000000
--- a/packages/account/tests/account.optimism.e2e.spec.ts
+++ /dev/null
@@ -1,118 +0,0 @@
-import { TestData } from "../../../tests";
-import { createSmartAccountClient, PaymasterMode } from "../src/index";
-import { encodeFunctionData, parseAbi } from "viem";
-import { checkBalance } from "../../../tests/utils";
-
-const maybe = process.env.WITH_MAINNET_TESTS === "true" ? describe : describe.skip;
-
-maybe("Account Tests", () => {
- let optimism: TestData;
- let _: TestData;
- let __: TestData;
-
- beforeEach(() => {
- // @ts-ignore: Comes from setup-e2e-tests
- [_, __, optimism] = testDataPerChain;
- });
-
- it("should send some native token to a recipient on optimism", async () => {
- const {
- whale: { viemWallet: signer, publicAddress: sender },
- minnow: { publicAddress: recipient },
- bundlerUrl,
- publicClient,
- } = optimism;
-
- const smartAccount = await createSmartAccountClient({
- signer,
- bundlerUrl,
- });
-
- const accountAddress = await smartAccount.getAddress();
-
- const balanceOfRecipient = (await checkBalance(publicClient, recipient)) as bigint;
- const smartAccountBalance = (await checkBalance(publicClient, accountAddress)) as bigint;
- const { wait } = await smartAccount.sendTransaction(
- {
- to: recipient,
- value: BigInt(1),
- },
- {
- simulationType: "validation_and_execution",
- },
- );
-
- const result = await wait();
- const newBalanceOfRecipient = (await checkBalance(publicClient, recipient)) as bigint;
-
- expect(result?.receipt?.transactionHash).toBeTruthy();
- expect(result.success).toBe("true");
- expect(newBalanceOfRecipient).toBeGreaterThan(balanceOfRecipient);
- }, 50000);
-
- it("Create a smart account with paymaster with an api key on optimism", async () => {
- const {
- whale: { viemWallet: signer },
- bundlerUrl,
- biconomyPaymasterApiKey,
- } = optimism;
-
- const smartAccount = await createSmartAccountClient({
- signer,
- biconomyPaymasterApiKey,
- bundlerUrl,
- });
-
- const paymaster = smartAccount.paymaster;
- expect(paymaster).not.toBeNull();
- expect(paymaster).not.toBeUndefined();
- });
-
- it("Should gaslessly mint an NFT on optimism", async () => {
- const {
- whale: { viemWallet: signer, publicAddress: recipient },
- bundlerUrl,
- biconomyPaymasterApiKey,
- publicClient,
- nftAddress,
- } = optimism;
-
- const smartAccount = await createSmartAccountClient({
- signer,
- bundlerUrl,
- biconomyPaymasterApiKey,
- });
-
- const encodedCall = encodeFunctionData({
- abi: parseAbi(["function safeMint(address to) public"]),
- functionName: "safeMint",
- args: [recipient],
- });
-
- const transaction = {
- to: nftAddress, // NFT address
- data: encodedCall,
- };
-
- const balance = (await checkBalance(publicClient, recipient, nftAddress)) as bigint;
-
- const maticBalanceBefore = await checkBalance(publicClient, await smartAccount.getAddress());
-
- const response = await smartAccount.sendTransaction(transaction, {
- paymasterServiceData: { mode: PaymasterMode.SPONSORED },
- simulationType: "validation_and_execution",
- });
-
- const userOpReceipt = await response.wait(3);
- expect(userOpReceipt.userOpHash).toBeTruthy();
- expect(userOpReceipt.success).toBe("true");
-
- const maticBalanceAfter = await checkBalance(publicClient, await smartAccount.getAddress());
-
- expect(maticBalanceAfter).toEqual(maticBalanceBefore);
-
- const newBalance = (await checkBalance(publicClient, recipient, nftAddress)) as bigint;
-
- expect(newBalance - balance).toBe(1n);
- }, 50000);
-});
diff --git a/packages/account/tests/account.read.e2e.spec.ts b/packages/account/tests/account.read.e2e.spec.ts
deleted file mode 100644
index 80abf9d21..000000000
--- a/packages/account/tests/account.read.e2e.spec.ts
+++ /dev/null
@@ -1,108 +0,0 @@
-import { TestData } from "../../../tests";
-import { createSmartAccountClient } from "../src/index";
-import { DEFAULT_ECDSA_OWNERSHIP_MODULE, DEFAULT_SESSION_KEY_MANAGER_MODULE, createECDSAOwnershipValidationModule } from "@biconomy/modules";
-
-describe("Account Tests", () => {
- let mumbai: TestData;
-
- beforeEach(() => {
- // @ts-ignore: Comes from setup-e2e-tests
- [mumbai] = testDataPerChain;
- });
-
- it("should check if module is enabled on the smart account", async () => {
- const {
- whale: { viemWallet: signer },
- bundlerUrl,
- } = mumbai;
-
- const smartWallet = await createSmartAccountClient({
- signer,
- bundlerUrl,
- });
-
- const isEnabled = await smartWallet.isModuleEnabled(DEFAULT_ECDSA_OWNERSHIP_MODULE);
- expect(isEnabled).toBeTruthy();
- }, 30000);
-
- it("should get all modules", async () => {
- const {
- whale: {
- viemWallet: signer,
- account: { address: accountAddress },
- },
- bundlerUrl,
- biconomyPaymasterApiKey,
- } = mumbai;
-
- const smartAccount = await createSmartAccountClient({
- signer,
- bundlerUrl,
- biconomyPaymasterApiKey,
- });
-
- const modules = await smartAccount.getAllModules();
-
- expect(modules).toContain(DEFAULT_SESSION_KEY_MANAGER_MODULE); // session manager module
- expect(modules).toContain(DEFAULT_ECDSA_OWNERSHIP_MODULE); // ecdsa ownership module
- }, 30000);
-
- it("should get disabled module data", async () => {
- const {
- whale: { viemWallet: signer },
- bundlerUrl,
- } = mumbai;
-
- const smartWallet = await createSmartAccountClient({
- signer,
- bundlerUrl,
- });
-
- const disableModuleData = await smartWallet.getDisableModuleData(DEFAULT_ECDSA_OWNERSHIP_MODULE, DEFAULT_ECDSA_OWNERSHIP_MODULE);
- expect(disableModuleData).toBeTruthy();
- }, 30000);
-
- it("should get setup and enable module data", async () => {
- const {
- whale: { viemWallet: signer },
- bundlerUrl,
- } = mumbai;
-
- const smartWallet = await createSmartAccountClient({
- signer,
- bundlerUrl,
- });
-
- const module = await createECDSAOwnershipValidationModule({ signer });
- const initData = await module.getInitData();
- const setupAndEnableModuleData = await smartWallet.getSetupAndEnableModuleData(DEFAULT_ECDSA_OWNERSHIP_MODULE, initData);
- expect(setupAndEnableModuleData).toBeTruthy();
- }, 30000);
-
- it("should read estimated user op gas values", async () => {
- const {
- whale: { viemWallet: signer },
- bundlerUrl,
- } = mumbai;
-
- const smartWallet = await createSmartAccountClient({
- signer,
- bundlerUrl,
- });
-
- const tx = {
- to: "0x000000D50C68705bd6897B2d17c7de32FB519fDA",
- data: "0x",
- };
-
- const userOp = await smartWallet.buildUserOp([tx]);
-
- const estimatedGas = await smartWallet.estimateUserOpGas(userOp);
- expect(estimatedGas.maxFeePerGas).toBeTruthy();
- expect(estimatedGas.maxPriorityFeePerGas).toBeTruthy();
- expect(estimatedGas.verificationGasLimit).toBeTruthy();
- expect(estimatedGas.callGasLimit).toBeTruthy();
- expect(estimatedGas.preVerificationGas).toBeTruthy();
- expect(estimatedGas).toHaveProperty("paymasterAndData", "0x");
- }, 35000);
-});
diff --git a/packages/account/tests/account.spec.ts b/packages/account/tests/account.spec.ts
deleted file mode 100644
index 42cc90355..000000000
--- a/packages/account/tests/account.spec.ts
+++ /dev/null
@@ -1,284 +0,0 @@
-import { Bundler, Paymaster, createBundler, createSmartAccountClient } from "../src";
-import { Chain, createWalletClient, http } from "viem";
-import { localhost } from "viem/chains";
-import { privateKeyToAccount, generatePrivateKey } from "viem/accounts";
-import { TestData } from "../../../tests";
-import { JsonRpcProvider } from "@ethersproject/providers";
-import { Wallet } from "@ethersproject/wallet";
-import { getMockBundlerUrl } from "../../../tests/utils";
-
-describe("Account Tests", () => {
- let ganache: TestData;
- const mockBundlerUrl = "https://bundler.biconomy.io/api/v2/1337/nJPK7B3ru.dd7f7861-190d-41bd-af80-6877f74b8f14";
-
- beforeEach(() => {
- // @ts-ignore: Comes from setup-unit-tests
- [ganache] = testDataPerChain;
- });
-
- it("should create a smartAccountClient from an ethers signer", async () => {
- const {
- minnow: { ethersSigner: signer },
- } = ganache;
-
- const smartAccount = await createSmartAccountClient({
- signer,
- bundlerUrl: mockBundlerUrl,
- rpcUrl: localhost.rpcUrls.default.http[0],
- });
- const address = await smartAccount.getAccountAddress();
- expect(address).toBeTruthy();
- });
-
- it("should create a whale smartAccountClient from an ethers signer", async () => {
- const {
- bundlerUrl,
- whale: { ethersSigner: signer },
- } = ganache;
-
- const smartAccount = await createSmartAccountClient({
- signer,
- bundlerUrl: mockBundlerUrl,
- rpcUrl: localhost.rpcUrls.default.http[0],
- });
- const address = await smartAccount.getAccountAddress();
- expect(address).toBeTruthy();
- });
-
- it("should create a smartAccountClient from a walletClient", async () => {
- const {
- whale: { viemWallet: signer },
- } = ganache;
-
- const smartAccount = await createSmartAccountClient({
- signer,
- bundlerUrl: mockBundlerUrl,
- rpcUrl: localhost.rpcUrls.default.http[0],
- });
- const address = await smartAccount.getAccountAddress();
- expect(address).toBeTruthy();
- });
-
- it("should pickup the rpcUrl when a custom chain is used", async () => {
- const customBlastChain = {
- id: 81_457,
- name: "Blast",
- // network: "blast",
- nativeCurrency: {
- decimals: 18,
- name: "Ethereum",
- symbol: "ETH",
- },
- rpcUrls: {
- public: { http: ["https://rpc.blast.io"] },
- default: { http: ["https://rpc.blast.io"] },
- },
- blockExplorers: {
- etherscan: { name: "Blastscan", url: "https://blastscan.io/" },
- default: { name: "Blastscan", url: "https://blastscan.io/" },
- },
- contracts: {
- multicall3: {
- address: "0xca11bde05977b3631167028862be2a173976ca11",
- blockCreated: 88_189,
- },
- },
- } as const satisfies Chain;
-
- const {
- whale: { privateKey },
- } = ganache;
-
- const accountOne = privateKeyToAccount(privateKey);
-
- const walletClientWithCustomChain = createWalletClient({
- account: accountOne,
- chain: customBlastChain,
- transport: http(customBlastChain.rpcUrls.default.http[0]),
- });
-
- const blastBundler = await createBundler({
- bundlerUrl: getMockBundlerUrl(customBlastChain.id),
- viemChain: customBlastChain,
- });
- const smartAccountFromViemWithCustomChain = await createSmartAccountClient({
- viemChain: customBlastChain,
- signer: walletClientWithCustomChain,
- bundler: blastBundler,
- rpcUrl: customBlastChain.rpcUrls.default.http[0],
- });
-
- expect(smartAccountFromViemWithCustomChain.rpcProvider.transport.url).toBe("https://rpc.blast.io");
- expect(blastBundler.getBundlerUrl()).toBe(getMockBundlerUrl(customBlastChain.id));
- });
-
- it("should pickup the rpcUrl from viem wallet and ethers", async () => {
- const {
- chainId,
- viemChain,
- whale: { privateKey, viemWallet: originalViemSigner, ethersSigner: originalEthersSigner },
- } = ganache;
-
- const newRpcUrl = "http://localhost:8545";
- const defaultRpcUrl = viemChain.rpcUrls.default.http[0]; //http://127.0.0.1:8545"
-
- const ethersProvider = new JsonRpcProvider(newRpcUrl);
- const ethersSignerWithNewRpcUrl = new Wallet(privateKey, ethersProvider);
-
- const accountOne = privateKeyToAccount(privateKey);
- const walletClientWithNewRpcUrl = createWalletClient({
- account: accountOne,
- chain: viemChain,
- transport: http(newRpcUrl),
- });
-
- const [smartAccountFromEthersWithNewRpc, smartAccountFromViemWithNewRpc, smartAccountFromEthersWithOldRpc, smartAccountFromViemWithOldRpc] =
- await Promise.all([
- createSmartAccountClient({
- chainId,
- signer: ethersSignerWithNewRpcUrl,
- bundlerUrl: mockBundlerUrl,
- rpcUrl: newRpcUrl,
- }),
- createSmartAccountClient({
- chainId,
- signer: walletClientWithNewRpcUrl,
- bundlerUrl: mockBundlerUrl,
- rpcUrl: newRpcUrl,
- }),
- createSmartAccountClient({
- chainId,
- signer: originalEthersSigner,
- bundlerUrl: mockBundlerUrl,
- rpcUrl: viemChain.rpcUrls.default.http[0],
- }),
- createSmartAccountClient({
- chainId,
- signer: originalViemSigner,
- bundlerUrl: mockBundlerUrl,
- rpcUrl: viemChain.rpcUrls.default.http[0],
- }),
- ]);
-
- const [
- smartAccountFromEthersWithNewRpcAddress,
- smartAccountFromViemWithNewRpcAddress,
- smartAccountFromEthersWithOldRpcAddress,
- smartAccountFromViemWithOldRpcAddress,
- ] = await Promise.all([
- smartAccountFromEthersWithNewRpc.getAccountAddress(),
- smartAccountFromViemWithNewRpc.getAccountAddress(),
- smartAccountFromEthersWithOldRpc.getAccountAddress(),
- smartAccountFromViemWithOldRpc.getAccountAddress(),
- ]);
-
- expect(
- [
- smartAccountFromEthersWithNewRpcAddress,
- smartAccountFromViemWithNewRpcAddress,
- smartAccountFromEthersWithOldRpcAddress,
- smartAccountFromViemWithOldRpcAddress,
- ].every(Boolean),
- ).toBeTruthy();
-
- expect(smartAccountFromEthersWithNewRpc.rpcProvider.transport.url).toBe(newRpcUrl);
- expect(smartAccountFromViemWithNewRpc.rpcProvider.transport.url).toBe(newRpcUrl);
- expect(smartAccountFromEthersWithOldRpc.rpcProvider.transport.url).toBe(defaultRpcUrl);
- expect(smartAccountFromViemWithOldRpc.rpcProvider.transport.url).toBe(defaultRpcUrl);
- });
-
- it("should create a smartAccountClient from a signer and chainId", async () => {
- const {
- chainId,
- whale: { alchemyWalletClientSigner: signer },
- } = ganache;
-
- const smartAccount = await createSmartAccountClient({
- chainId,
- signer,
- bundlerUrl: mockBundlerUrl,
- rpcUrl: localhost.rpcUrls.default.http[0],
- });
- const address = await smartAccount.getAccountAddress();
- expect(address).toBeTruthy();
- });
-
- it("should provide an account address", async () => {
- const {
- whale: { viemWallet: signer },
- } = ganache;
-
- const smartAccount = await createSmartAccountClient({
- signer,
- bundlerUrl: mockBundlerUrl,
- rpcUrl: localhost.rpcUrls.default.http[0],
- });
- const address = await smartAccount.getAccountAddress();
- expect(address).toBeTruthy();
- });
-
- it("should have an active validation module", async () => {
- const {
- whale: { viemWallet: signer },
- } = ganache;
-
- const smartAccount = await createSmartAccountClient({
- signer,
- bundlerUrl: mockBundlerUrl,
- rpcUrl: localhost.rpcUrls.default.http[0],
- });
-
- const module = smartAccount.activeValidationModule;
- expect(module).toBeTruthy();
- });
-
- it("Create a smart account with paymaster by creating instance", async () => {
- const {
- whale: { viemWallet: signer },
- paymasterUrl,
- } = ganache;
-
- const paymaster = new Paymaster({ paymasterUrl });
-
- const smartAccount = await createSmartAccountClient({
- signer,
- bundlerUrl: mockBundlerUrl,
- paymaster,
- rpcUrl: localhost.rpcUrls.default.http[0],
- });
- expect(smartAccount.paymaster).not.toBeNull();
- expect(smartAccount.paymaster).not.toBeUndefined();
- }, 10000);
-
- it("should fail to create a smartAccountClient from a walletClient without a chainId", async () => {
- const account = privateKeyToAccount(generatePrivateKey());
- const viemWalletClientNoChainId = createWalletClient({
- account,
- transport: http(localhost.rpcUrls.default.http[0]),
- });
-
- expect(
- await expect(
- createSmartAccountClient({
- signer: viemWalletClientNoChainId,
- bundlerUrl: mockBundlerUrl,
- rpcUrl: localhost.rpcUrls.default.http[0],
- }),
- ).rejects.toThrow("Cannot consume a viem wallet without a chainId"),
- );
- });
-
- it("should fail to create a smartAccountClient from a walletClient without an account", async () => {
- const viemWalletNoAccount = createWalletClient({
- transport: http(localhost.rpcUrls.default.http[0]),
- });
-
- expect(async () =>
- createSmartAccountClient({
- signer: viemWalletNoAccount,
- bundlerUrl: mockBundlerUrl,
- rpcUrl: localhost.rpcUrls.default.http[0],
- }),
- ).rejects.toThrow("Cannot consume a viem wallet without an account");
- });
-});
diff --git a/packages/account/tests/utils.spec.ts b/packages/account/tests/utils.spec.ts
deleted file mode 100644
index d8dfc2a79..000000000
--- a/packages/account/tests/utils.spec.ts
+++ /dev/null
@@ -1,130 +0,0 @@
-import { BiconomySmartAccountV2Config, ERROR_MESSAGES, createECDSAOwnershipValidationModule } from "../src";
-import { TestData } from "../../../tests";
-import { compareChainIds, getChain } from "../src/utils";
-import { createWalletClient, http } from "viem";
-import { bsc } from "viem/chains";
-
-describe("Utils tests", () => {
- let ganache: TestData;
-
- beforeEach(() => {
- // @ts-ignore: Comes from setup-unit-tests
- [ganache] = testDataPerChain;
- });
-
- it("Should not throw and error, chain ids match", async () => {
- const {
- minnow: { viemWallet: walletClient },
- } = ganache;
-
- const mockBundlerUrl = "https://bundler.biconomy.io/api/v2/1337/nJPK7B3ru.dd7f7861-190d-41bd-af80-6877f74b8f44";
- const mockPaymasterUrl = "https://paymaster.biconomy.io/api/v1/1337/-RObQRX9ei.fc6918eb-c582-4417-9d5a-0507b17cfe71";
-
- const config: BiconomySmartAccountV2Config = {
- signer: walletClient,
- bundlerUrl: mockBundlerUrl,
- paymasterUrl: mockPaymasterUrl,
- };
-
- await expect(compareChainIds(walletClient, config, false)).resolves.not.toThrow();
- });
-
- it("Should throw and error, bundlerUrl chain id and signer chain id does not match", async () => {
- const {
- minnow: { viemWallet: walletClient },
- paymasterUrl,
- } = ganache;
-
- const mockBundlerUrl = "https://bundler.biconomy.io/api/v2/1/nJPK7B3ru.dd7f7861-190d-41bd-af80-6877f74b8f44";
-
- const config: BiconomySmartAccountV2Config = {
- signer: walletClient,
- bundlerUrl: mockBundlerUrl,
- paymasterUrl,
- };
-
- await expect(compareChainIds(walletClient, config, false)).rejects.toThrow();
- });
-
- it("Should throw and error, bundlerUrl chain id and paymaster url chain id does not match", async () => {
- const {
- bundlerUrl,
- minnow: { viemWallet: walletClient },
- } = ganache;
-
- const mockPaymasterUrl = "https://paymaster.biconomy.io/api/v1/80001/-RObQRX9ei.fc6918eb-c582-4417-9d5a-0507b17cfe71";
-
- const config: BiconomySmartAccountV2Config = {
- signer: walletClient,
- bundlerUrl,
- paymasterUrl: mockPaymasterUrl,
- };
-
- await expect(compareChainIds(walletClient, config, false)).rejects.toThrow();
- });
-
- it("Should throw and error, bundlerUrl chain id and paymaster url chain id does not match", async () => {
- const {
- bundlerUrl,
- minnow: { viemWallet: walletClient },
- } = ganache;
-
- const mockPaymasterUrl = "https://paymaster.biconomy.io/api/v1/80001/-RObQRX9ei.fc6918eb-c582-4417-9d5a-0507b17cfe71";
-
- const ecdsaModule = await createECDSAOwnershipValidationModule({
- signer: walletClient,
- });
-
- const config: BiconomySmartAccountV2Config = {
- defaultValidationModule: ecdsaModule,
- activeValidationModule: ecdsaModule,
- bundlerUrl,
- paymasterUrl: mockPaymasterUrl,
- };
-
- await expect(compareChainIds(walletClient, config, false)).rejects.toThrow();
- });
-
- it("Should throw and error, signer has chain id (56) and paymasterUrl has chain id (80001)", async () => {
- const { bundlerUrl, whale } = ganache;
-
- const mockPaymasterUrl = "https://paymaster.biconomy.io/api/v1/80001/-RObQRX9ei.fc6918eb-c582-4417-9d5a-0507b17cfe71";
-
- const walletClient = createWalletClient({
- account: whale.viemWallet.account,
- chain: bsc,
- transport: http(bsc.rpcUrls.default.http[0]),
- });
-
- const config: BiconomySmartAccountV2Config = {
- signer: walletClient,
- bundlerUrl,
- paymasterUrl: mockPaymasterUrl,
- };
-
- await expect(compareChainIds(walletClient, config, false)).rejects.toThrow();
- });
-
- // test chains
- it("Should return chain object for chain id 1", () => {
- const chainId = 1;
- const chain = getChain(chainId);
- expect(chain.id).toBe(chainId);
- });
-
- // should have correct fields
- it("Should have correct fields", () => {
- const chainId = 1;
- const chain = getChain(chainId);
-
- ["blockExplorers", "contracts", "fees", "formatters", "id", "name", "nativeCurrency", "rpcUrls", "serializers"].every((field) => {
- expect(chain).toHaveProperty(field);
- });
- });
-
- // Should throw an error, chain id not found
- it("Should throw an error, chain id not found", () => {
- const chainId = 0;
- expect(() => getChain(chainId)).toThrow(ERROR_MESSAGES.CHAIN_NOT_FOUND);
- });
-});
diff --git a/packages/account/tsconfig.build.json b/packages/account/tsconfig.build.json
deleted file mode 100644
index 42d88a236..000000000
--- a/packages/account/tsconfig.build.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "$schema": "https://json.schemastore.org/tsconfig",
- "display": "Build",
- "compilerOptions": {
- "lib": ["es2022", "dom"],
- "target": "es2021",
- "types": ["node"],
- "allowJs": false,
- "skipLibCheck": true,
- "esModuleInterop": true,
- "allowSyntheticDefaultImports": true,
- "strict": true,
- "forceConsistentCasingInFileNames": true,
- "module": "esnext",
- "moduleResolution": "node",
- "resolveJsonModule": true,
- "isolatedModules": true,
- "verbatimModuleSyntax": false,
- "useDefineForClassFields": true,
- "noFallthroughCasesInSwitch": true,
- "noImplicitReturns": true,
- "useUnknownInCatchVariables": true,
- "noUnusedLocals": true,
- "noUnusedParameters": true,
- "declaration": true,
- "inlineSources": true,
- "noEmit": false,
- "sourceMap": true
- },
- "exclude": ["**/*/node_modules", "**/*/tests", "tests", "tests/**/*"],
- "include": ["src"]
-}
\ No newline at end of file
diff --git a/packages/account/tsconfig.json b/packages/account/tsconfig.json
deleted file mode 100644
index 53677da37..000000000
--- a/packages/account/tsconfig.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "extends": "../../tsconfig.settings.json",
- "compilerOptions": {
- "composite": true,
- "outDir": "dist",
- "baseUrl": "src",
- "resolveJsonModule": true,
- "esModuleInterop": true,
- "lib": ["es2020"],
- "types": ["node"]
- },
- "include": ["src", "src/**/*.json"],
-}
diff --git a/packages/bundler/.esbuild.js b/packages/bundler/.esbuild.js
deleted file mode 100644
index ca355e346..000000000
--- a/packages/bundler/.esbuild.js
+++ /dev/null
@@ -1,58 +0,0 @@
-const esbuildPluginTsc = require("esbuild-plugin-tsc");
-const esbuild = require("esbuild");
-const { dependencies, peerDependencies = {} } = require("./package.json");
-const { Generator } = require("npm-dts");
-
-const COMMON_SETTINGS = {
- entryPoints: ["src/index.ts"],
- minify: true,
- bundle: true,
- plugins: [esbuildPluginTsc({ force: true })],
-};
-
-const ESM_SETTINGS = {
- ...COMMON_SETTINGS,
- sourcemap: true,
- outfile: "dist/esm/index.js",
- platform: "browser",
- target: "esnext",
- format: "esm",
- mainFields: ["browser", "module", "main"],
-};
-const buildForESM = async () => await esbuild.build(ESM_SETTINGS);
-
-const CJS_SETTINGS = {
- ...COMMON_SETTINGS,
- format: "cjs",
- sourcemap: false,
- outfile: "dist/cjs/index.js",
- platform: "node",
-};
-
-const watchForCJS = async () => {
- let ctx = await esbuild.context(CJS_SETTINGS);
- await ctx.watch();
- await ctx.serve({ servedir: "dist/src" });
- console.log("watching...");
-};
-
-const buildForCJS = async () => await esbuild.build(CJS_SETTINGS);
-const buildForTYP = async () => await new Generator({ entry: "src/index.ts", output: "dist/types/index.d.ts" }).generate();
-
-(async () => {
- const buildType = process.argv.slice(2)[0];
- const shouldWatch = process.argv.slice(3)[0] === "--watch";
- if (!buildType) {
- console.log("No build type provided");
- process.exit(1);
- }
- console.log(`Building for ${buildType}`);
- if (buildType === "ESM") {
- await buildForESM();
- } else if (buildType === "CJS") {
- console.log("watching? " + shouldWatch);
- await (shouldWatch ? watchForCJS : buildForCJS)();
- } else if (buildType === "TYP") {
- await buildForTYP();
- }
-})();
diff --git a/packages/bundler/CHANGELOG.md b/packages/bundler/CHANGELOG.md
deleted file mode 100644
index 7730bad6b..000000000
--- a/packages/bundler/CHANGELOG.md
+++ /dev/null
@@ -1,94 +0,0 @@
-# Change Log
-
-All notable changes to this project will be documented in this file.
-See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
-
-## 4.1.1 (2023-07-03)
-
-VERSION Bump Only.
-
-## 4.1.0 (2023-04-03)
-
-VERSION Bump Only.
-
-## 4.0.3 (2023-28-02)
-
-VERSION Bump Only.
-
-## 4.0.2 (2023-26-02)
-
-VERSION Bump Only.
-
-## 4.0.1 (2023-02-22)
-
-VERSION Bump Only.
-
-## 4.0.0 (2023-07-02)
-
-Export createBundler alias for static Bundler.create call
-
-## 3.1.3 (2023-12-28)
-
-VERSION Bump Only.
-
-## 3.1.2 (2023-12-28)
-
-### Features
-
-- Make entrypoint address optional in bundler config ([547724a](https://github.com/bcnmy/biconomy-client-sdk/pull/337/commits/547724a15366ee1e63aee80fdee0edc128a84c41))
-
-### Bug Fixes
-
-- use undefined in place of ! + check on limits returned by paymaster and throw ([0376901](https://github.com/bcnmy/biconomy-client-sdk/commit/0376901b7aec8c268a6a3c654d147335974d78f3))
-
-## 3.1.1 (2023-11-09)
-
-### Bug Fixes
-
-- resolve comments ([34fd6a3](https://github.com/bcnmy/biconomy-client-sdk/commit/34fd6a308805061d9faf408f1ce6da9cac0ee819))
-
-### Features
-
-- add linea mainnet ([c3d1283](https://github.com/bcnmy/biconomy-client-sdk/commit/c3d12832002c18e187f910b5f7dac5ef5b797abf))
-- chain integration ([ddc5d91](https://github.com/bcnmy/biconomy-client-sdk/commit/ddc5d91d5df10a10266f4500644d24e0bc1ea684))
-- chain integration ([738556e](https://github.com/bcnmy/biconomy-client-sdk/commit/738556efcfda70fedc652befc0b35f8835c5e360))
-
-## 3.1.0 (2023-09-20)
-
-Modular Account Abstraction is here.
-
-### Bug Fixes
-
-- lint warning and errors ([2135498](https://github.com/bcnmy/biconomy-client-sdk/commit/2135498896beb54d25add820c1521ffa22d5db7c))
-- linting ([563befe](https://github.com/bcnmy/biconomy-client-sdk/commit/563befedcc37aee4c531e01809b47e559a33f526))
-- more lint issues ([10df908](https://github.com/bcnmy/biconomy-client-sdk/commit/10df90821b473fd668907cf3e447dfe3825317fc))
-
-### Features
-
-- base mainnet integration ([c17f5d6](https://github.com/bcnmy/biconomy-client-sdk/commit/c17f5d6c2fe34b106e6d9755f54fab2493db6fbe))
-- chain integration ([ddc5d91](https://github.com/bcnmy/biconomy-client-sdk/commit/ddc5d91d5df10a10266f4500644d24e0bc1ea684))
-- chain integration ([738556e](https://github.com/bcnmy/biconomy-client-sdk/commit/738556efcfda70fedc652befc0b35f8835c5e360))
-
-## 3.0.0 (2023-08-28)
-
-Modular SDK - consists stable version of below updates done in Alphas.
-
-### Features
-
-- base mainnet integration ([c17f5d6](https://github.com/bcnmy/biconomy-client-sdk/commit/c17f5d6c2fe34b106e6d9755f54fab2493db6fbe))
-
-## 3.0.0-alpha.0 (2023-08-02)
-
-VERSION Bump Only.
-
-# 3.1.0-alpha.0 (2023-07-24)
-
-### Features
-
-- chain integration ([738556e](https://github.com/bcnmy/biconomy-client-sdk/commit/738556efcfda70fedc652befc0b35f8835c5e360))
-
-## 3.0.0-alpha.0 (2023-07-12)
-
-### Bug Fixes
-
-- linting ([563befe](https://github.com/bcnmy/biconomy-client-sdk/commit/563befedcc37aee4c531e01809b47e559a33f526))
diff --git a/packages/bundler/Readme.md b/packages/bundler/Readme.md
deleted file mode 100644
index 06e0c4af6..000000000
--- a/packages/bundler/Readme.md
+++ /dev/null
@@ -1,99 +0,0 @@
-### Bundler
-
-In the context of (ERC4337), A bundler plays a main role in the infrastructure. This concept is integral to the operation of account abstraction across any network that utilizes the Ethereum Virtual Machine (EVM).
-
-## Installation
-
-Using `npm` package manager
-
-```bash
-npm i @biconomy/bundler
-```
-
-OR
-
-Using `yarn` package manager
-
-```bash
-yarn add @biconomy/bundler
-```
-
-## configuration
-
-| Key | Description |
-| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
-| bundlerUrl | Represent ERC4337 spec implemented bundler url. you can get one from biconomy dashboard. Alternatively you can supply any of your preferred |
-| chainId | This represents the network your smart wallet transactions will be conducted on. Take a look following Link for supported chain id's |
-| entryPointAddress | Since entrypoint can have different addresses you can call getSupportedEntryPoints() on bundler instance for supported addresses list |
-
-```typescript
-// This is how you create bundler instance in your dapp's
-import { IBundler, createBundler } from "@biconomy/bundler";
-
-// Make use of core-types package
-import { ChainId } from "@biconomy/core-types";
-
-const bundler: IBundler = await createBundler({ bundlerUrl: "" }); // you can get this value from biconomy dashboard. https://dashboard.biconomy.io
-```
-
-Following are the methods that can be call on bundler instance
-
-```typescript
-export interface IBundler {
- estimateUserOpGas(userOp: Partial): Promise;
- sendUserOp(userOp: UserOperation): Promise;
- getUserOpReceipt(userOpHash: string): Promise;
- getUserOpByHash(userOpHash: string): Promise;
-}
-```
-
-**[estimateUserOpGas](https://bcnmy.github.io/biconomy-client-sdk/classes/Bundler.html#estimateUserOpGas)**
-Estimate the gas values for a UserOperation. Given UserOperation optionally without gas limits and gas prices, return the needed gas limits. The signature field is ignored by the wallet, so that the operation will not require user's approval. Still, it might require putting a "semi-valid" signature (e.g. a signature in the right length)
-
-**Return Values**
-
-**preVerificationGas** gas overhead of this UserOperation
-**verificationGasLimit** actual gas used by the validation of this UserOperation
-**callGasLimit** limit used to execute userop.callData called from EntryPoint to the Smart Account
-
- --------------------------------
-
-**[sendUserOp](https://bcnmy.github.io/biconomy-client-sdk/classes/Bundler.html#sendUserOp)**
-it submits a User Operation object to the User Operation pool of the client. The client MUST validate the UserOperation, and return a result accordingly.
-
-The result SHOULD be set to the userOpHash if and only if the request passed simulation and was accepted in the client's User Operation pool. If the validation, simulation, or User Operation pool inclusion fails, result SHOULD NOT be returned. Rather, the client SHOULD return the failure reason.
-
-**Return Values**
-If the UserOperation is valid, the client MUST return the calculated userOpHash for it
-
- --------------------------------
-
-**[getUserOpByHash](https://bcnmy.github.io/biconomy-client-sdk/classes/Bundler.html#getUserOpByHash)**
-Return a UserOperation based on a hash (userOpHash) returned by sendUserOp (eth_sendUserOperation)
-
-**Return Values**
-
-null in case the UserOperation is not yet included in a block, or a full UserOperation, with the addition of entryPoint, blockNumber, blockHash and transactionHash
-
- --------------------------------
-
-**[getUserOpReceipt](https://bcnmy.github.io/biconomy-client-sdk/classes/Bundler.html#getUserOpReceipt)**
-
-Return a UserOperation receipt based on a hash (userOpHash) returned by eth_sendUserOperation
-
-**Return Values**
-null in case the UserOperation is not yet included in a block, or:
-
-**userOpHash** the request hash
-**entryPoint**
-**sender**
-**nonce**
-**paymaster** the paymaster used for this userOp (or empty)
-**actualGasCost** - actual amount paid (by account or paymaster) for this UserOperation
-**actualGasUsed** - total gas used by this UserOperation (including preVerification, creation, validation and execution)
-**success** boolean - did this execution completed without revert
-**reason** in case of revert, this is the revert reason
-**logs** the logs generated by this UserOperation (not including logs of other UserOperations in the same bundle)
-**receipt** the TransactionReceipt object. Note that the returned TransactionReceipt is for the entire bundle, not only for this UserOperation.
-
- --------------------------------
diff --git a/packages/bundler/package.json b/packages/bundler/package.json
deleted file mode 100644
index a41dde75f..000000000
--- a/packages/bundler/package.json
+++ /dev/null
@@ -1,69 +0,0 @@
-{
- "name": "@biconomy/bundler",
- "version": "4.1.1",
- "description": "Biconomy Bundler package to interact with any bundler node as per ERC4337 standard",
- "main": "./dist/cjs/index.js",
- "module": "./dist/esm/index.js",
- "types": "./dist/types/index.d.ts",
- "typings": "./dist/types/index.d.ts",
- "exports": {
- ".": {
- "import": "./dist/esm/index.js",
- "types": "./dist/types/index.d.ts",
- "default": "./dist/cjs/index.js"
- },
- "./package.json": "./package.json"
- },
- "keywords": [
- "Ethereum",
- "Bundler",
- "Relayer",
- "ERC4337",
- "Gasless Transaction",
- "Biconomy",
- "SDK"
- ],
- "scripts": {
- "unbuild": "rimraf dist *.tsbuildinfo",
- "build:watch": "yarn build:tsc --watch",
- "dist:minify": "esbuild ./dist/esm/**/*.js ./dist/esm/*.js --minify --outdir=./dist/esm --bundle=false --allow-overwrite",
- "build": "yarn unbuild && yarn build:tsc",
- "build:esbuild": "yarn build:esbuild:cjs && yarn build:esbuild:esm && yarn build:typ",
- "build:tsc:cjs": "tsc --project tsconfig.build.json --module commonjs --outDir ./dist/cjs --removeComments --verbatimModuleSyntax false && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'",
- "build:tsc:esm": "tsc --project tsconfig.build.json --module esnext --outDir ./dist/esm --removeComments && echo > ./dist/esm/package.json '{\"type\":\"module\"}'",
- "build:esbuild:cjs": "node .esbuild.js CJS && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'",
- "build:esbuild:esm": "node .esbuild.js ESM && echo > ./dist/esm/package.json '{\"type\":\"module\"}'",
- "build:typ": "tsc --project tsconfig.build.json --module esnext --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap",
- "build:tsc": "yarn build:tsc:cjs && yarn build:tsc:esm && yarn build:typ && yarn dist:minify",
- "test:file": "jest --config=../../jest.config.js --runInBand",
- "test:concurrently": "concurrently -k --success first 'yarn start:ganache > /dev/null'",
- "test:run": "jest tests/**/*.spec.ts --runInBand",
- "start:ganache": "ganache -m 'direct buyer cliff train rice spirit census refuse glare expire innocent quote'",
- "format": "prettier --write \"{src,tests}/**/*.ts\"",
- "lint": "tslint -p tsconfig.json"
- },
- "author": "Biconomy",
- "repository": {
- "type": "git",
- "url": "git+https://github.com/bcnmy/biconomy-client-sdk.git"
- },
- "license": "MIT",
- "files": [
- "dist/*",
- "README.md"
- ],
- "publishConfig": {
- "access": "public"
- },
- "dependencies": {
- "@alchemy/aa-core": "^3.1.1",
- "@biconomy/common": "^4.1.1",
- "viem": "^2.7.12"
- },
- "devDependencies": {
- "@types/node": "^20.11.10",
- "esbuild": "^0.19.11",
- "esbuild-plugin-tsc": "^0.4.0",
- "npm-dts": "^1.3.12"
- }
-}
diff --git a/packages/bundler/src/index.ts b/packages/bundler/src/index.ts
deleted file mode 100644
index 7a779f5d5..000000000
--- a/packages/bundler/src/index.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { Bundler } from "./Bundler.js";
-
-export * from "./interfaces/IBundler.js";
-export * from "./Bundler.js";
-export * from "./utils/Types.js";
-export * from "./utils/Utils.js";
-
-export const createBundler = Bundler.create;
diff --git a/packages/bundler/src/interfaces/IBundler.ts b/packages/bundler/src/interfaces/IBundler.ts
deleted file mode 100644
index 75077e141..000000000
--- a/packages/bundler/src/interfaces/IBundler.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import { StateOverrideSet } from "@biconomy/common";
-import {
- UserOpResponse,
- UserOpGasResponse,
- UserOpReceipt,
- UserOpByHashResponse,
- UserOpStatus,
- SimulationType,
- GasFeeValues,
-} from "../utils/Types.js";
-import { UserOperationStruct } from "@alchemy/aa-core";
-
-export interface IBundler {
- estimateUserOpGas(_userOp: Partial, stateOverrideSet?: StateOverrideSet): Promise;
- sendUserOp(_userOp: UserOperationStruct, _simulationType?: SimulationType): Promise;
- getUserOpReceipt(_userOpHash: string): Promise;
- getUserOpByHash(_userOpHash: string): Promise;
- getGasFeeValues(): Promise;
- getUserOpStatus(_userOpHash: string): Promise;
- getBundlerUrl(): string;
-}
diff --git a/packages/bundler/src/utils/Utils.ts b/packages/bundler/src/utils/Utils.ts
deleted file mode 100644
index 692cf1bdd..000000000
--- a/packages/bundler/src/utils/Utils.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-export const extractChainIdFromBundlerUrl = (url: string): number => {
- try {
- const regex = /\/api\/v2\/(\d+)\/[a-zA-Z0-9.-]+$/;
- const match = regex.exec(url)!;
- return parseInt(match[1]);
- } catch (error) {
- throw new Error("Invalid chain id");
- }
-};
-
-export const extractChainIdFromPaymasterUrl = (url: string): number => {
- try {
- const regex = /\/api\/v\d+\/(\d+)\//;
- const match = regex.exec(url);
- if (!match) {
- throw new Error("Invalid URL format");
- }
- return parseInt(match[1]);
- } catch (error) {
- throw new Error("Invalid chain id");
- }
-};
diff --git a/packages/bundler/tests/bundler.e2e.spec.ts b/packages/bundler/tests/bundler.e2e.spec.ts
deleted file mode 100644
index 7b9211dd0..000000000
--- a/packages/bundler/tests/bundler.e2e.spec.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import { TestData } from "../../../tests";
-
-describe("Bundler Unit Tests", () => {
- let mumbai: TestData;
- let baseSepolia: TestData;
-
- beforeEach(() => {
- // @ts-ignore: Comes from setup-e2e-tests
- [mumbai, baseSepolia] = testDataPerChain;
- });
-
- it("should have chain data for mumbai", () => {
- expect(mumbai).toHaveProperty("chainId");
- });
-
- it("should also have chain data for base", () => {
- expect(baseSepolia).toHaveProperty("chainId");
- });
-});
diff --git a/packages/bundler/tests/bundler.spec.ts b/packages/bundler/tests/bundler.spec.ts
deleted file mode 100644
index e663dafb4..000000000
--- a/packages/bundler/tests/bundler.spec.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import { TestData } from "../../../tests";
-
-describe("Bundler Unit Tests", () => {
- let ganache: TestData;
-
- beforeEach(() => {
- // @ts-ignore: Comes from setup-unit-tests
- [ganache] = testDataPerChain;
- });
-
- it("should have chain data for ganache", () => {
- expect(ganache).toHaveProperty("chainId");
- });
-});
diff --git a/packages/bundler/tsconfig.build.json b/packages/bundler/tsconfig.build.json
deleted file mode 100644
index 4ac8b8026..000000000
--- a/packages/bundler/tsconfig.build.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "$schema": "https://json.schemastore.org/tsconfig",
- "display": "Build",
- "compilerOptions": {
- "lib": ["es2022", "dom"],
- "target": "es2021",
- "types": ["node"],
- "allowJs": false,
- "skipLibCheck": true,
- "esModuleInterop": true,
- "allowSyntheticDefaultImports": true,
- "strict": true,
- "forceConsistentCasingInFileNames": true,
- "module": "esnext",
- "moduleResolution": "node",
- "resolveJsonModule": true,
- "isolatedModules": true,
- "verbatimModuleSyntax": false,
- "useDefineForClassFields": true,
- "noFallthroughCasesInSwitch": true,
- "noImplicitReturns": true,
- "useUnknownInCatchVariables": true,
- "noUnusedLocals": true,
- "noUnusedParameters": true,
- "declaration": true,
- "inlineSources": true,
- "noEmit": false,
- "sourceMap": true
- },
- "exclude": ["**/*/node_modules", "**/*/tests", "tests"],
- "include": ["src"]
-}
\ No newline at end of file
diff --git a/packages/bundler/tsconfig.json b/packages/bundler/tsconfig.json
deleted file mode 100644
index d9b305a9a..000000000
--- a/packages/bundler/tsconfig.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "extends": "../../tsconfig.settings.json",
- "compilerOptions": {
- "composite": true,
- "outDir": "dist",
- "baseUrl": "src",
- "resolveJsonModule": true,
- "esModuleInterop": true,
- "lib": ["es2020"],
- "types": ["node"]
- },
- "include": ["src", "src/**/*.json"]
-}
diff --git a/packages/common/.esbuild.js b/packages/common/.esbuild.js
deleted file mode 100644
index ca355e346..000000000
--- a/packages/common/.esbuild.js
+++ /dev/null
@@ -1,58 +0,0 @@
-const esbuildPluginTsc = require("esbuild-plugin-tsc");
-const esbuild = require("esbuild");
-const { dependencies, peerDependencies = {} } = require("./package.json");
-const { Generator } = require("npm-dts");
-
-const COMMON_SETTINGS = {
- entryPoints: ["src/index.ts"],
- minify: true,
- bundle: true,
- plugins: [esbuildPluginTsc({ force: true })],
-};
-
-const ESM_SETTINGS = {
- ...COMMON_SETTINGS,
- sourcemap: true,
- outfile: "dist/esm/index.js",
- platform: "browser",
- target: "esnext",
- format: "esm",
- mainFields: ["browser", "module", "main"],
-};
-const buildForESM = async () => await esbuild.build(ESM_SETTINGS);
-
-const CJS_SETTINGS = {
- ...COMMON_SETTINGS,
- format: "cjs",
- sourcemap: false,
- outfile: "dist/cjs/index.js",
- platform: "node",
-};
-
-const watchForCJS = async () => {
- let ctx = await esbuild.context(CJS_SETTINGS);
- await ctx.watch();
- await ctx.serve({ servedir: "dist/src" });
- console.log("watching...");
-};
-
-const buildForCJS = async () => await esbuild.build(CJS_SETTINGS);
-const buildForTYP = async () => await new Generator({ entry: "src/index.ts", output: "dist/types/index.d.ts" }).generate();
-
-(async () => {
- const buildType = process.argv.slice(2)[0];
- const shouldWatch = process.argv.slice(3)[0] === "--watch";
- if (!buildType) {
- console.log("No build type provided");
- process.exit(1);
- }
- console.log(`Building for ${buildType}`);
- if (buildType === "ESM") {
- await buildForESM();
- } else if (buildType === "CJS") {
- console.log("watching? " + shouldWatch);
- await (shouldWatch ? watchForCJS : buildForCJS)();
- } else if (buildType === "TYP") {
- await buildForTYP();
- }
-})();
diff --git a/packages/common/README.md b/packages/common/README.md
deleted file mode 100644
index db4c4a8c7..000000000
--- a/packages/common/README.md
+++ /dev/null
@@ -1,11 +0,0 @@
-# `@biconomy/common`
-
-common utils
-
-common methods for other biconomy packages
-
-## Usage
-
-```
-no direct usage of this package
-```
diff --git a/packages/common/package.json b/packages/common/package.json
deleted file mode 100644
index 22010587c..000000000
--- a/packages/common/package.json
+++ /dev/null
@@ -1,67 +0,0 @@
-{
- "name": "@biconomy/common",
- "version": "4.1.1",
- "description": "common utils to be used for aa transactions",
- "keywords": [
- "utils"
- ],
- "author": "livingrockrises ",
- "homepage": "https://github.com/bcnmy/biconomy-client-sdk#readme",
- "license": "MIT",
- "main": "./dist/cjs/index.js",
- "module": "./dist/esm/index.js",
- "types": "./dist/types/index.d.ts",
- "typings": "./dist/types/index.d.ts",
- "exports": {
- ".": {
- "import": "./dist/esm/index.js",
- "types": "./dist/types/index.d.ts",
- "default": "./dist/cjs/index.js"
- },
- "./package.json": "./package.json"
- },
- "files": [
- "dist/*",
- "README.md"
- ],
- "publishConfig": {
- "access": "public"
- },
- "repository": {
- "type": "git",
- "url": "git+https://github.com/bcnmy/biconomy-client-sdk.git"
- },
- "scripts": {
- "unbuild": "rimraf dist *.tsbuildinfo",
- "build:watch": "yarn build:tsc --watch",
- "dist:minify": "esbuild ./dist/esm/**/*.js ./dist/esm/*.js --minify --outdir=./dist/esm --bundle=false --allow-overwrite",
- "build": "yarn unbuild && yarn build:tsc",
- "build:esbuild": "yarn build:esbuild:cjs && yarn build:esbuild:esm && yarn build:typ",
- "build:tsc:cjs": "tsc --project tsconfig.build.json --module commonjs --outDir ./dist/cjs --removeComments --verbatimModuleSyntax false && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'",
- "build:tsc:esm": "tsc --project tsconfig.build.json --module esnext --outDir ./dist/esm --removeComments && echo > ./dist/esm/package.json '{\"type\":\"module\"}'",
- "build:esbuild:cjs": "node .esbuild.js CJS && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'",
- "build:esbuild:esm": "node .esbuild.js ESM && echo > ./dist/esm/package.json '{\"type\":\"module\"}'",
- "build:typ": "tsc --project tsconfig.build.json --module esnext --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap",
- "build:tsc": "yarn build:tsc:cjs && yarn build:tsc:esm && yarn build:typ && yarn dist:minify",
- "test:file": "jest --config=../../jest.config.js --runInBand",
- "test:concurrently": "concurrently -k --success first 'yarn start:ganache > /dev/null'",
- "test:run": "jest tests/**/*.spec.ts --runInBand",
- "start:ganache": "ganache -m 'direct buyer cliff train rice spirit census refuse glare expire innocent quote'",
- "format": "prettier --write \"{src,tests}/**/*.ts\"",
- "lint": "tslint -p tsconfig.json"
- },
- "bugs": {
- "url": "https://github.com/bcnmy/biconomy-client-sdk/issues"
- },
- "dependencies": {
- "@alchemy/aa-core": "^3.1.1",
- "@ethersproject/abstract-signer": "^5.7.0",
- "viem": "^2.7.12"
- },
- "devDependencies": {
- "@types/node": "^20.11.10",
- "esbuild": "^0.19.11",
- "esbuild-plugin-tsc": "^0.4.0",
- "npm-dts": "^1.3.12"
- }
-}
diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts
deleted file mode 100644
index cca231168..000000000
--- a/packages/common/src/index.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-export * from "./utils/Helpers/convertSigner.js";
-export * from "./utils/Types.js";
-export * from "./utils/Constants.js";
-export * from "./utils/Logger.js";
-export * from "./utils/HttpRequests.js";
-export { EthersSigner } from "./utils/EthersSigner.js";
diff --git a/packages/common/src/utils/Constants.ts b/packages/common/src/utils/Constants.ts
deleted file mode 100644
index 4e3292cb5..000000000
--- a/packages/common/src/utils/Constants.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { SupportedSignerName } from "./Types.js";
-
-export const UNIQUE_PROPERTIES_PER_SIGNER: Record = {
- alchemy: "signerType",
- ethers: "provider",
- viem: "transport",
-};
diff --git a/packages/common/src/utils/EthersSigner.ts b/packages/common/src/utils/EthersSigner.ts
deleted file mode 100644
index d77e0eab1..000000000
--- a/packages/common/src/utils/EthersSigner.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import { SmartAccountSigner } from "@alchemy/aa-core";
-import { Hex, SignableMessage } from "viem";
-import { Signer } from "@ethersproject/abstract-signer";
-
-export class EthersSigner implements SmartAccountSigner {
- signerType: string = "ethers";
-
- inner: T;
-
- constructor(inner: T, signerType: string) {
- this.inner = inner;
- this.signerType = signerType;
- }
-
- async getAddress() {
- return (await this.inner.getAddress()) as Hex;
- }
-
- async signMessage(_message: SignableMessage): Promise {
- const message = typeof _message === "string" ? _message : _message.raw;
- const signature = await this.inner?.signMessage(message);
- return this.#correctSignature(signature as Hex);
- }
-
- async signTypedData(_notUsed: any): Promise {
- throw new Error("signTypedData is not supported for Ethers Signer");
- }
-
- #correctSignature = (signature: Hex): Hex => {
- const potentiallyIncorrectV = parseInt(signature.slice(-2), 16);
- if (![27, 28].includes(potentiallyIncorrectV)) {
- const correctV = potentiallyIncorrectV + 27;
- signature = signature.slice(0, -2) + correctV.toString(16);
- }
- return signature;
- };
-}
-
-export default EthersSigner;
diff --git a/packages/common/src/utils/Helpers/convertSigner.ts b/packages/common/src/utils/Helpers/convertSigner.ts
deleted file mode 100644
index 5aadb0803..000000000
--- a/packages/common/src/utils/Helpers/convertSigner.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-import { EthersSigner } from "../EthersSigner.js";
-import { SupportedSigner } from "../Types.js";
-import { WalletClient } from "viem";
-import { WalletClientSigner, SmartAccountSigner } from "@alchemy/aa-core";
-import { UNIQUE_PROPERTIES_PER_SIGNER } from "../Constants.js";
-import { Signer } from "@ethersproject/abstract-signer";
-
-interface SmartAccountResult {
- signer: SmartAccountSigner;
- chainId: number | null;
- rpcUrl: string | null;
-}
-
-export const convertSigner = async (signer: SupportedSigner, skipChainIdCalls: boolean = false): Promise => {
- let resolvedSmartAccountSigner: SmartAccountSigner;
- let rpcUrl: string | null = null;
- let chainId: number | null = null;
- const isAnAlchemySigner = UNIQUE_PROPERTIES_PER_SIGNER.alchemy in signer;
- const isAnEthersSigner = UNIQUE_PROPERTIES_PER_SIGNER.ethers in signer;
- const isAViemSigner = UNIQUE_PROPERTIES_PER_SIGNER.viem in signer;
-
- if (!isAnAlchemySigner) {
- if (isAnEthersSigner) {
- const ethersSigner = signer as Signer;
- if (!skipChainIdCalls) {
- // If chainId not provided, get it from walletClient
- if (!ethersSigner.provider) {
- throw new Error("Cannot consume an ethers Wallet without a provider");
- }
- const chainIdFromProvider = await ethersSigner.provider.getNetwork();
- if (!chainIdFromProvider?.chainId) {
- throw new Error("Cannot consume an ethers Wallet without a chainId");
- }
- chainId = Number(chainIdFromProvider.chainId);
- }
- // convert ethers Wallet to alchemy's SmartAccountSigner under the hood
- resolvedSmartAccountSigner = new EthersSigner(ethersSigner, "ethers");
- // @ts-ignore
- rpcUrl = ethersSigner.provider?.connection?.url ?? null;
- } else if (isAViemSigner) {
- const walletClient = signer as WalletClient;
- if (!walletClient.account) {
- throw new Error("Cannot consume a viem wallet without an account");
- }
- if (!skipChainIdCalls) {
- // If chainId not provided, get it from walletClient
- if (!walletClient.chain) {
- throw new Error("Cannot consume a viem wallet without a chainId");
- }
- chainId = walletClient.chain.id;
- }
- // convert viems walletClient to alchemy's SmartAccountSigner under the hood
- resolvedSmartAccountSigner = new WalletClientSigner(walletClient, "viem");
- rpcUrl = walletClient?.transport?.url ?? null;
- } else {
- throw new Error("Unsupported signer");
- }
- } else {
- resolvedSmartAccountSigner = signer as SmartAccountSigner;
- }
- return { signer: resolvedSmartAccountSigner, rpcUrl, chainId };
-};
diff --git a/packages/common/src/utils/Helpers/index.ts b/packages/common/src/utils/Helpers/index.ts
deleted file mode 100644
index 235336dc3..000000000
--- a/packages/common/src/utils/Helpers/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from "./convertSigner.js";
diff --git a/packages/common/src/utils/HttpRequests.ts b/packages/common/src/utils/HttpRequests.ts
deleted file mode 100644
index 192a33e4e..000000000
--- a/packages/common/src/utils/HttpRequests.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-import { Logger } from "./Logger.js";
-import { Service } from "./Types.js";
-
-export enum HttpMethod {
- Get = "get",
- Post = "post",
- Delete = "delete",
-}
-
-/* eslint-disable @typescript-eslint/no-explicit-any */
-export interface HttpRequest {
- url: string;
- method: HttpMethod;
- body?: Record;
-}
-
-export async function sendRequest({ url, method, body }: HttpRequest, service: Service): Promise {
- const response = await fetch(url, {
- method,
- headers: {
- Accept: "application/json",
- "Content-Type": "application/json",
- },
- body: JSON.stringify(body),
- });
-
- let jsonResponse;
- try {
- jsonResponse = await response.json();
- Logger.log(`${service} RPC Response`, jsonResponse);
- } catch (error) {
- if (!response.ok) {
- throw new Error(response.statusText);
- }
- }
-
- if (response.ok) {
- return jsonResponse as T;
- }
- if (jsonResponse.error) {
- throw new Error(`Error coming from ${service}: ${jsonResponse.error.message}`);
- }
- if (jsonResponse.message) {
- throw new Error(jsonResponse.message);
- }
- if (jsonResponse.msg) {
- throw new Error(jsonResponse.msg);
- }
- if (jsonResponse.data) {
- throw new Error(jsonResponse.data);
- }
- if (jsonResponse.detail) {
- throw new Error(jsonResponse.detail);
- }
- if (jsonResponse.message) {
- throw new Error(jsonResponse.message);
- }
- if (jsonResponse.nonFieldErrors) {
- throw new Error(jsonResponse.nonFieldErrors);
- }
- if (jsonResponse.delegate) {
- throw new Error(jsonResponse.delegate);
- }
- throw new Error(response.statusText);
-}
diff --git a/packages/common/src/utils/Types.ts b/packages/common/src/utils/Types.ts
deleted file mode 100644
index 52eac0216..000000000
--- a/packages/common/src/utils/Types.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { WalletClient } from "viem";
-import { Signer } from "@ethersproject/abstract-signer";
-import { SmartAccountSigner } from "@alchemy/aa-core";
-
-export type SupportedSignerName = "alchemy" | "ethers" | "viem";
-export type SupportedSigner = SmartAccountSigner | WalletClient | Signer | LightSigner;
-
-export type Service = "Bundler" | "Paymaster";
-
-export interface LightSigner {
- getAddress(): Promise;
- signMessage(message: string | Uint8Array): Promise;
-}
-
-export type StateOverrideSet = {
- [key: string]: {
- balance?: string;
- nonce?: string;
- code?: string;
- state?: object;
- stateDiff?: object;
- };
-};
diff --git a/packages/common/tsconfig.build.json b/packages/common/tsconfig.build.json
deleted file mode 100644
index 4ac8b8026..000000000
--- a/packages/common/tsconfig.build.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "$schema": "https://json.schemastore.org/tsconfig",
- "display": "Build",
- "compilerOptions": {
- "lib": ["es2022", "dom"],
- "target": "es2021",
- "types": ["node"],
- "allowJs": false,
- "skipLibCheck": true,
- "esModuleInterop": true,
- "allowSyntheticDefaultImports": true,
- "strict": true,
- "forceConsistentCasingInFileNames": true,
- "module": "esnext",
- "moduleResolution": "node",
- "resolveJsonModule": true,
- "isolatedModules": true,
- "verbatimModuleSyntax": false,
- "useDefineForClassFields": true,
- "noFallthroughCasesInSwitch": true,
- "noImplicitReturns": true,
- "useUnknownInCatchVariables": true,
- "noUnusedLocals": true,
- "noUnusedParameters": true,
- "declaration": true,
- "inlineSources": true,
- "noEmit": false,
- "sourceMap": true
- },
- "exclude": ["**/*/node_modules", "**/*/tests", "tests"],
- "include": ["src"]
-}
\ No newline at end of file
diff --git a/packages/common/tsconfig.json b/packages/common/tsconfig.json
deleted file mode 100644
index d9b305a9a..000000000
--- a/packages/common/tsconfig.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "extends": "../../tsconfig.settings.json",
- "compilerOptions": {
- "composite": true,
- "outDir": "dist",
- "baseUrl": "src",
- "resolveJsonModule": true,
- "esModuleInterop": true,
- "lib": ["es2020"],
- "types": ["node"]
- },
- "include": ["src", "src/**/*.json"]
-}
diff --git a/packages/modules/.esbuild.js b/packages/modules/.esbuild.js
deleted file mode 100644
index ca355e346..000000000
--- a/packages/modules/.esbuild.js
+++ /dev/null
@@ -1,58 +0,0 @@
-const esbuildPluginTsc = require("esbuild-plugin-tsc");
-const esbuild = require("esbuild");
-const { dependencies, peerDependencies = {} } = require("./package.json");
-const { Generator } = require("npm-dts");
-
-const COMMON_SETTINGS = {
- entryPoints: ["src/index.ts"],
- minify: true,
- bundle: true,
- plugins: [esbuildPluginTsc({ force: true })],
-};
-
-const ESM_SETTINGS = {
- ...COMMON_SETTINGS,
- sourcemap: true,
- outfile: "dist/esm/index.js",
- platform: "browser",
- target: "esnext",
- format: "esm",
- mainFields: ["browser", "module", "main"],
-};
-const buildForESM = async () => await esbuild.build(ESM_SETTINGS);
-
-const CJS_SETTINGS = {
- ...COMMON_SETTINGS,
- format: "cjs",
- sourcemap: false,
- outfile: "dist/cjs/index.js",
- platform: "node",
-};
-
-const watchForCJS = async () => {
- let ctx = await esbuild.context(CJS_SETTINGS);
- await ctx.watch();
- await ctx.serve({ servedir: "dist/src" });
- console.log("watching...");
-};
-
-const buildForCJS = async () => await esbuild.build(CJS_SETTINGS);
-const buildForTYP = async () => await new Generator({ entry: "src/index.ts", output: "dist/types/index.d.ts" }).generate();
-
-(async () => {
- const buildType = process.argv.slice(2)[0];
- const shouldWatch = process.argv.slice(3)[0] === "--watch";
- if (!buildType) {
- console.log("No build type provided");
- process.exit(1);
- }
- console.log(`Building for ${buildType}`);
- if (buildType === "ESM") {
- await buildForESM();
- } else if (buildType === "CJS") {
- console.log("watching? " + shouldWatch);
- await (shouldWatch ? watchForCJS : buildForCJS)();
- } else if (buildType === "TYP") {
- await buildForTYP();
- }
-})();
diff --git a/packages/modules/CHANGELOG.md b/packages/modules/CHANGELOG.md
deleted file mode 100644
index 7c3d40af8..000000000
--- a/packages/modules/CHANGELOG.md
+++ /dev/null
@@ -1,64 +0,0 @@
-# Change Log
-
-All notable changes to this project will be documented in this file.
-See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
-
-## 4.1.1 (2023-07-03)
-
-VERSION Bump Only.
-
-## 4.1.0 (2023-04-03)
-
-VERSION Bump Only.
-
-## 4.0.3 (2023-28-02)
-
-VERSION Bump Only.
-
-## 4.0.2 (2023-26-02)
-
-VERSION Bump Only.
-
-## 4.0.1 (2023-02-22)
-
-VERSION Bump Only.
-
-## 4.0.0 (2024-02-12)
-
-### Features
-
-- Export module create aliases from modules package ([d6205c](https://github.com/bcnmy/biconomy-client-sdk/pull/401/commits/d6205c4d76ab846ecdc10843c65e0277f3ceab00))
-
-## 3.1.3 (2023-12-28)
-
-VERSION Bump Only.
-
-## 3.1.2 (2023-12-28)
-
-### Bug Fixes
-
-- Update import paths for consistency and fixing build issues ([ec5c3a3](https://github.com/bcnmy/biconomy-client-sdk/pull/332/commits/ec5c3a352e8caab6e94234264f4cd5cb32e5af3f))
-
-## 3.1.1 (2023-11-09)
-
-### Bug Fixes
-
-- Fix update batched session router address and signing logic ([107b881](https://github.com/bcnmy/biconomy-client-sdk/commit/107b881da4b1a6da1f9db22ac54eda62f8c05b59))
-
-## 3.1.0 (2023-09-20)
-
-Modular Account Abstraction is here.
-
-### Bug Fixes
-
-- incorrect data merkleRoot length ([2e9d2dd](https://github.com/bcnmy/biconomy-client-sdk/commit/2e9d2dd5876a4de61af390d6595e1ab2cf8c137c))
-- lint warning and errors ([2135498](https://github.com/bcnmy/biconomy-client-sdk/commit/2135498896beb54d25add820c1521ffa22d5db7c))
-- more lint issues ([10df908](https://github.com/bcnmy/biconomy-client-sdk/commit/10df90821b473fd668907cf3e447dfe3825317fc))
-- signing issue ([f67e339](https://github.com/bcnmy/biconomy-client-sdk/commit/f67e339bcff8d9712df8406b4d123affcd4d4aa4))
-- sorting leaves always ([1fb908c](https://github.com/bcnmy/biconomy-client-sdk/commit/1fb908cb3b90abe4588c3a162ecf45c8afc80d81))
-- use hexZeroPad in leaf ([b3da05f](https://github.com/bcnmy/biconomy-client-sdk/commit/b3da05f2e9c56973e96d0a7a3bc065aef23f9c18))
-- use proof instead of root ([3a40a9d](https://github.com/bcnmy/biconomy-client-sdk/commit/3a40a9d8b9fb1fba8f660e5eab1fae1369f9f289))
-
-### Features
-
-- add session key manager ([af41480](https://github.com/bcnmy/biconomy-client-sdk/commit/af41480ff1c88e2a4d0ee8605f2f01b3a958a1d9))
diff --git a/packages/modules/README.md b/packages/modules/README.md
deleted file mode 100644
index e69de29bb..000000000
diff --git a/packages/modules/package.json b/packages/modules/package.json
deleted file mode 100644
index 7d73de383..000000000
--- a/packages/modules/package.json
+++ /dev/null
@@ -1,70 +0,0 @@
-{
- "name": "@biconomy/modules",
- "version": "4.1.1",
- "description": "This package provides different validation modules/plugins for ERC4337 compatible modular account",
- "main": "./dist/cjs/index.js",
- "module": "./dist/esm/index.js",
- "types": "./dist/types/index.d.ts",
- "typings": "./dist/types/index.d.ts",
- "exports": {
- ".": {
- "import": "./dist/esm/index.js",
- "types": "./dist/types/index.d.ts",
- "default": "./dist/cjs/index.js"
- },
- "./package.json": "./package.json"
- },
- "keywords": [
- "Smart Account",
- "ERC-4337",
- "Account Abstraction",
- "Smart Contract Wallets",
- "Biconomy",
- "Modules",
- "Plugins"
- ],
- "scripts": {
- "unbuild": "rimraf dist *.tsbuildinfo",
- "build:watch": "yarn build:tsc --watch",
- "dist:minify": "esbuild ./dist/esm/**/*.js ./dist/esm/*.js --minify --outdir=./dist/esm --bundle=false --allow-overwrite",
- "build": "yarn unbuild && yarn build:tsc",
- "build:esbuild": "yarn build:esbuild:cjs && yarn build:esbuild:esm && yarn build:typ",
- "build:tsc:cjs": "tsc --project tsconfig.build.json --module commonjs --outDir ./dist/cjs --removeComments --verbatimModuleSyntax false && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'",
- "build:tsc:esm": "tsc --project tsconfig.build.json --module esnext --outDir ./dist/esm --removeComments && echo > ./dist/esm/package.json '{\"type\":\"module\"}'",
- "build:esbuild:cjs": "node .esbuild.js CJS && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'",
- "build:esbuild:esm": "node .esbuild.js ESM && echo > ./dist/esm/package.json '{\"type\":\"module\"}'",
- "build:typ": "tsc --project tsconfig.build.json --module esnext --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap",
- "build:tsc": "yarn build:tsc:cjs && yarn build:tsc:esm && yarn build:typ && yarn dist:minify",
- "test:file": "TS_NODE_PROJECT=../../tsconfig.json mocha -r ts-node/register --timeout 30000",
- "test:concurrently": "concurrently -k --success first 'yarn start:ganache > /dev/null'",
- "test:cov": "jest --coverage",
- "test:run": "yarn test:file tests/**/*.spec.ts",
- "start:ganache": "ganache -m 'direct buyer cliff train rice spirit census refuse glare expire innocent quote'",
- "format": "prettier --write \"{src,tests}/**/*.ts\"",
- "lint": "tslint -p tsconfig.json"
- },
- "author": "Biconomy",
- "license": "MIT",
- "files": [
- "dist/*",
- "README.md"
- ],
- "publishConfig": {
- "access": "public"
- },
- "dependencies": {
- "@alchemy/aa-core": "^3.1.1",
- "@biconomy/common": "^4.1.1",
- "@ethersproject/abi": "^5.7.0",
- "merkletreejs": "^0.3.11",
- "viem": "^2.7.12"
- },
- "devDependencies": {
- "@types/node": "^20.11.10",
- "esbuild": "^0.19.11",
- "esbuild-plugin-tsc": "^0.4.0",
- "npm-dts": "^1.3.12",
- "@biconomy/paymaster": "^4.1.1",
- "@biconomy/modules": "^4.1.1"
- }
-}
diff --git a/packages/modules/src/BaseValidationModule.ts b/packages/modules/src/BaseValidationModule.ts
deleted file mode 100644
index 4f739f782..000000000
--- a/packages/modules/src/BaseValidationModule.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-import { Hex } from "viem";
-import { SmartAccountSigner } from "@alchemy/aa-core";
-import { BaseValidationModuleConfig, ModuleInfo } from "./utils/Types.js";
-import { DEFAULT_ENTRYPOINT_ADDRESS } from "./utils/Constants.js";
-import { IValidationModule } from "./interfaces/IValidationModule.js";
-
-export abstract class BaseValidationModule implements IValidationModule {
- entryPointAddress: Hex;
-
- constructor(moduleConfig: BaseValidationModuleConfig) {
- const { entryPointAddress } = moduleConfig;
-
- this.entryPointAddress = entryPointAddress || DEFAULT_ENTRYPOINT_ADDRESS;
- }
-
- abstract getAddress(): Hex;
-
- setEntryPointAddress(entryPointAddress: Hex): void {
- this.entryPointAddress = entryPointAddress;
- }
-
- abstract getInitData(): Promise;
-
- // Anything required to get dummy signature can be passed as params
- abstract getDummySignature(_params?: ModuleInfo): Promise;
-
- abstract getSigner(): Promise;
-
- // Signer specific or any other additional information can be passed as params
- abstract signUserOpHash(_userOpHash: string, _params?: ModuleInfo): Promise;
-
- abstract signMessage(_message: Uint8Array | string): Promise;
-
- async signMessageSmartAccountSigner(_message: string | Uint8Array, signer: SmartAccountSigner): Promise {
- const message = typeof _message === "string" ? _message : { raw: _message };
- let signature: `0x${string}` = await signer.signMessage(message);
-
- const potentiallyIncorrectV = parseInt(signature.slice(-2), 16);
- if (![27, 28].includes(potentiallyIncorrectV)) {
- const correctV = potentiallyIncorrectV + 27;
- signature = `0x${signature.slice(0, -2) + correctV.toString(16)}`;
- }
-
- return signature;
- }
-}
diff --git a/packages/modules/src/BatchedSessionRouterModule.ts b/packages/modules/src/BatchedSessionRouterModule.ts
deleted file mode 100644
index cec1cddd4..000000000
--- a/packages/modules/src/BatchedSessionRouterModule.ts
+++ /dev/null
@@ -1,278 +0,0 @@
-import { ModuleVersion, CreateSessionDataParams, BatchedSessionRouterModuleConfig, ModuleInfo, CreateSessionDataResponse } from "./utils/Types.js";
-import {
- BATCHED_SESSION_ROUTER_MODULE_ADDRESSES_BY_VERSION,
- DEFAULT_SESSION_KEY_MANAGER_MODULE,
- DEFAULT_BATCHED_SESSION_ROUTER_MODULE,
-} from "./utils/Constants.js";
-import { BaseValidationModule } from "./BaseValidationModule.js";
-import { SessionKeyManagerModule } from "./SessionKeyManagerModule.js";
-import { SessionSearchParam, SessionStatus } from "./interfaces/ISessionStorage.js";
-import { Hex, concat, encodeAbiParameters, keccak256, pad, parseAbiParameters, toBytes, toHex } from "viem";
-import { SmartAccountSigner } from "@alchemy/aa-core";
-import { convertSigner } from "@biconomy/common";
-import { defaultAbiCoder } from "@ethersproject/abi";
-
-export class BatchedSessionRouterModule extends BaseValidationModule {
- version: ModuleVersion = "V1_0_0";
-
- moduleAddress!: Hex;
-
- sessionManagerModuleAddress!: Hex;
-
- sessionKeyManagerModule!: SessionKeyManagerModule;
-
- readonly mockEcdsaSessionKeySig: Hex =
- "0x73c3ac716c487ca34bb858247b5ccf1dc354fbaabdd089af3b2ac8e78ba85a4959a2d76250325bd67c11771c31fccda87c33ceec17cc0de912690521bb95ffcb1b";
-
- /**
- * This constructor is private. Use the static create method to instantiate SessionKeyManagerModule
- * @param moduleConfig The configuration for the module
- * @returns An instance of SessionKeyManagerModule
- */
- private constructor(moduleConfig: BatchedSessionRouterModuleConfig) {
- super(moduleConfig);
- }
-
- /**
- * Asynchronously creates and initializes an instance of SessionKeyManagerModule
- * @param moduleConfig The configuration for the module
- * @returns A Promise that resolves to an instance of SessionKeyManagerModule
- */
- public static async create(moduleConfig: BatchedSessionRouterModuleConfig): Promise {
- const instance = new BatchedSessionRouterModule(moduleConfig);
-
- if (moduleConfig.moduleAddress) {
- instance.moduleAddress = moduleConfig.moduleAddress;
- } else if (moduleConfig.version) {
- const moduleAddr = BATCHED_SESSION_ROUTER_MODULE_ADDRESSES_BY_VERSION[moduleConfig.version] as Hex;
- if (!moduleAddr) {
- throw new Error(`Invalid version ${moduleConfig.version}`);
- }
- instance.moduleAddress = moduleAddr;
- instance.version = moduleConfig.version as ModuleVersion;
- } else {
- instance.moduleAddress = DEFAULT_BATCHED_SESSION_ROUTER_MODULE;
- // Note: in this case Version remains the default one
- }
-
- instance.sessionManagerModuleAddress = moduleConfig.sessionManagerModuleAddress ?? DEFAULT_SESSION_KEY_MANAGER_MODULE;
-
- if (!moduleConfig.sessionKeyManagerModule) {
- // generate sessionModule
- const sessionModule = await SessionKeyManagerModule.create({
- moduleAddress: instance.sessionManagerModuleAddress,
- smartAccountAddress: moduleConfig.smartAccountAddress,
- storageType: moduleConfig.storageType,
- });
-
- instance.sessionKeyManagerModule = sessionModule;
- } else {
- instance.sessionKeyManagerModule = moduleConfig.sessionKeyManagerModule;
- instance.sessionManagerModuleAddress = moduleConfig.sessionKeyManagerModule.getAddress();
- }
-
- return instance;
- }
-
- /**
- * Method to create session data for any module. The session data is used to create a leaf in the merkle tree
- * @param leavesData The data of one or more leaves to be used to create session data
- * @returns The session data
- */
- createSessionData = async (leavesData: CreateSessionDataParams[]): Promise => {
- return this.sessionKeyManagerModule.createSessionData(leavesData);
- };
-
- /**
- * This method is used to sign the user operation using the session signer
- * @param userOp The user operation to be signed
- * @param sessionParams Information about all the sessions to be used to sign the user operation which has a batch execution
- * @returns The signature of the user operation
- */
- async signUserOpHash(userOpHash: string, params?: ModuleInfo): Promise {
- const sessionParams = params?.batchSessionParams;
- if (!sessionParams || sessionParams.length === 0) {
- throw new Error("Session parameters are not provided");
- }
-
- const sessionDataTupleArray = [];
-
- // signer must be the same for all the sessions
- const { signer: sessionSigner } = await convertSigner(sessionParams[0].sessionSigner, false);
-
- const signature = await sessionSigner.signMessage({ raw: toBytes(userOpHash) });
-
- for (const sessionParam of sessionParams) {
- if (!sessionParam.sessionSigner) {
- throw new Error("Session signer is not provided.");
- }
-
- const sessionDataTuple = [];
-
- let sessionSignerData;
-
- if (sessionParam.sessionID) {
- sessionSignerData = await this.sessionKeyManagerModule.sessionStorageClient.getSessionData({
- sessionID: sessionParam.sessionID,
- });
- } else if (sessionParam.sessionValidationModule) {
- sessionSignerData = await this.sessionKeyManagerModule.sessionStorageClient.getSessionData({
- sessionValidationModule: sessionParam.sessionValidationModule,
- sessionPublicKey: await sessionSigner.getAddress(),
- });
- } else {
- throw new Error("sessionID or sessionValidationModule should be provided.");
- }
-
- sessionDataTuple.push(sessionSignerData.validUntil);
- sessionDataTuple.push(sessionSignerData.validAfter);
- sessionDataTuple.push(sessionSignerData.sessionValidationModule);
- sessionDataTuple.push(sessionSignerData.sessionKeyData);
-
- const leafDataHex = concat([
- pad(toHex(sessionSignerData.validUntil), { size: 6 }),
- pad(toHex(sessionSignerData.validAfter), { size: 6 }),
- pad(sessionSignerData.sessionValidationModule, { size: 20 }),
- sessionSignerData.sessionKeyData,
- ]);
-
- const proof = this.sessionKeyManagerModule.merkleTree.getHexProof(keccak256(leafDataHex));
-
- sessionDataTuple.push(proof);
- sessionDataTuple.push(sessionParam.additionalSessionData ?? "0x");
-
- sessionDataTupleArray.push(sessionDataTuple);
- }
-
- // Generate the padded signature
-
- const paddedSignature = defaultAbiCoder.encode(
- ["address", "tuple(uint48,uint48,address,bytes,bytes32[],bytes)[]", "bytes"],
- [this.getSessionKeyManagerAddress(), sessionDataTupleArray, signature],
- );
-
- return paddedSignature as Hex;
- }
-
- /**
- * Update the session data pending state to active
- * @param param The search param to find the session data
- * @param status The status to be updated
- * @returns
- */
- async updateSessionStatus(param: SessionSearchParam, status: SessionStatus): Promise {
- this.sessionKeyManagerModule.sessionStorageClient.updateSessionStatus(param, status);
- }
-
- /**
- * @remarks This method is used to clear all the pending sessions
- * @returns
- */
- async clearPendingSessions(): Promise {
- this.sessionKeyManagerModule.sessionStorageClient.clearPendingSessions();
- }
-
- /**
- * @returns SessionKeyManagerModule address
- */
- getAddress(): Hex {
- return this.moduleAddress;
- }
-
- /**
- * @returns SessionKeyManagerModule address
- */
- getSessionKeyManagerAddress(): Hex {
- return this.sessionManagerModuleAddress;
- }
-
- /**
- * @remarks This is the version of the module contract
- */
- async getSigner(): Promise {
- throw new Error("Method not implemented.");
- }
-
- /**
- * @remarks This is the dummy signature for the module, used in buildUserOp for bundler estimation
- * @returns Dummy signature
- */
- async getDummySignature(params?: ModuleInfo): Promise {
- const sessionParams = params?.batchSessionParams;
- if (!sessionParams || sessionParams.length === 0) {
- throw new Error("Session parameters are not provided");
- }
-
- const sessionDataTupleArray = [];
-
- // if needed we could do mock signature over userOpHashAndModuleAddress
-
- // signer must be the same for all the sessions
- const { signer: sessionSigner } = await convertSigner(sessionParams[0].sessionSigner, false);
-
- for (const sessionParam of sessionParams) {
- if (!sessionParam.sessionSigner) {
- throw new Error("Session signer is not provided.");
- }
-
- const sessionDataTuple = [];
-
- let sessionSignerData;
-
- if (sessionParam.sessionID) {
- sessionSignerData = await this.sessionKeyManagerModule.sessionStorageClient.getSessionData({
- sessionID: sessionParam.sessionID,
- });
- } else if (sessionParam.sessionValidationModule) {
- sessionSignerData = await this.sessionKeyManagerModule.sessionStorageClient.getSessionData({
- sessionValidationModule: sessionParam.sessionValidationModule,
- sessionPublicKey: await sessionSigner.getAddress(),
- });
- } else {
- throw new Error("sessionID or sessionValidationModule should be provided.");
- }
-
- sessionDataTuple.push(BigInt(sessionSignerData.validUntil));
- sessionDataTuple.push(BigInt(sessionSignerData.validAfter));
- sessionDataTuple.push(sessionSignerData.sessionValidationModule);
- sessionDataTuple.push(sessionSignerData.sessionKeyData);
-
- const leafDataHex = concat([
- pad(toHex(sessionSignerData.validUntil), { size: 6 }),
- pad(toHex(sessionSignerData.validAfter), { size: 6 }),
- pad(sessionSignerData.sessionValidationModule, { size: 20 }),
- sessionSignerData.sessionKeyData,
- ]);
-
- const proof = this.sessionKeyManagerModule.merkleTree.getHexProof(keccak256(leafDataHex));
-
- sessionDataTuple.push(proof);
- sessionDataTuple.push(sessionParam.additionalSessionData ?? "0x");
-
- sessionDataTupleArray.push(sessionDataTuple);
- }
-
- // Generate the padded signature
- const paddedSignature = defaultAbiCoder.encode(
- ["address", "tuple(uint48,uint48,address,bytes,bytes32[],bytes)[]", "bytes"],
- [this.getSessionKeyManagerAddress(), sessionDataTupleArray, this.mockEcdsaSessionKeySig],
- );
-
- const dummySig = encodeAbiParameters(parseAbiParameters("bytes, address"), [paddedSignature as Hex, this.getAddress()]);
- return dummySig;
- }
-
- /**
- * @remarks Other modules may need additional attributes to build init data
- */
- async getInitData(): Promise {
- throw new Error("Method not implemented.");
- }
-
- /**
- * @remarks This Module dont have knowledge of signer. So, this method is not implemented
- */
- async signMessage(_message: Uint8Array | string): Promise {
- throw new Error("Method not implemented.");
- }
-}
diff --git a/packages/modules/src/MultichainValidationModule.ts b/packages/modules/src/MultichainValidationModule.ts
deleted file mode 100644
index 0846b0f83..000000000
--- a/packages/modules/src/MultichainValidationModule.ts
+++ /dev/null
@@ -1,163 +0,0 @@
-import { Hex, concat, encodeAbiParameters, encodeFunctionData, getAddress, keccak256, pad, parseAbi, parseAbiParameters, toBytes, toHex } from "viem";
-import { UserOperationStruct, SmartAccountSigner } from "@alchemy/aa-core";
-import { MerkleTree } from "merkletreejs";
-import { DEFAULT_MULTICHAIN_MODULE, MULTICHAIN_VALIDATION_MODULE_ADDRESSES_BY_VERSION } from "./utils/Constants.js";
-import {
- ModuleVersion,
- MultiChainUserOpDto,
- MultiChainValidationModuleConfig,
- MultiChainValidationModuleConfigConstructorProps,
-} from "./utils/Types.js";
-import { BaseValidationModule } from "./BaseValidationModule.js";
-import { getUserOpHash } from "./utils/Helper.js";
-import { convertSigner, Logger } from "@biconomy/common";
-
-export class MultiChainValidationModule extends BaseValidationModule {
- signer: SmartAccountSigner;
-
- moduleAddress!: Hex;
-
- version: ModuleVersion = "V1_0_0";
-
- private constructor(moduleConfig: MultiChainValidationModuleConfigConstructorProps) {
- super(moduleConfig);
- this.signer = moduleConfig.signer;
- }
-
- public static async create(moduleConfig: MultiChainValidationModuleConfig): Promise {
- // Signer needs to be initialised here before defaultValidationModule is set
- const { signer } = await convertSigner(moduleConfig.signer, false);
- const configForConstructor: MultiChainValidationModuleConfigConstructorProps = { ...moduleConfig, signer };
-
- // TODO: (Joe) stop doing things in a 'create' call after the instance has been created
- const instance = new MultiChainValidationModule(configForConstructor);
- if (moduleConfig.moduleAddress) {
- instance.moduleAddress = moduleConfig.moduleAddress;
- } else if (moduleConfig.version) {
- const moduleAddr = MULTICHAIN_VALIDATION_MODULE_ADDRESSES_BY_VERSION[moduleConfig.version] as Hex;
- if (!moduleAddr) {
- throw new Error(`Invalid version ${moduleConfig.version}`);
- }
- instance.moduleAddress = moduleAddr;
- instance.version = moduleConfig.version as ModuleVersion;
- } else {
- instance.moduleAddress = DEFAULT_MULTICHAIN_MODULE;
- // Note: in this case Version remains the default one
- }
- return instance;
- }
-
- getAddress(): Hex {
- return this.moduleAddress;
- }
-
- async getSigner(): Promise {
- return Promise.resolve(this.signer);
- }
-
- async getDummySignature(): Promise {
- const moduleAddress = getAddress(this.getAddress());
- const dynamicPart = moduleAddress.substring(2).padEnd(40, "0");
- return `0x0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000${dynamicPart}000000000000000000000000000000000000000000000000000000000000004181d4b4981670cb18f99f0b4a66446df1bf5b204d24cfcb659bf38ba27a4359b5711649ec2423c5e1247245eba2964679b6a1dbb85c992ae40b9b00c6935b02ff1b00000000000000000000000000000000000000000000000000000000000000`;
- }
-
- // Note: other modules may need additional attributes to build init data
- async getInitData(): Promise {
- const ecdsaOwnerAddress = await this.signer.getAddress();
- const moduleRegistryParsedAbi = parseAbi(["function initForSmartAccount(address owner)"]);
- const ecdsaOwnershipInitData = encodeFunctionData({
- abi: moduleRegistryParsedAbi,
- functionName: "initForSmartAccount",
- args: [ecdsaOwnerAddress],
- });
- return ecdsaOwnershipInitData;
- }
-
- async signUserOpHash(userOpHash: string): Promise {
- const sig = await this.signer.signMessage({ raw: toBytes(userOpHash) });
- return sig;
- }
-
- /**
- * Signs a message using the appropriate method based on the type of signer.
- *
- * @param {Uint8Array | string} message - The message to be signed.
- * @returns {Promise} A promise resolving to the signature or error message.
- * @throws {Error} If the signer type is invalid or unsupported.
- */
- async signMessage(_message: Uint8Array | string): Promise {
- const message = typeof _message === "string" ? _message : { raw: _message };
- let signature = await this.signer.signMessage(message);
-
- const potentiallyIncorrectV = parseInt(signature.slice(-2), 16);
- if (![27, 28].includes(potentiallyIncorrectV)) {
- const correctV = potentiallyIncorrectV + 27;
- signature = signature.slice(0, -2) + correctV.toString(16);
- }
- return signature;
- }
-
- async signUserOps(multiChainUserOps: MultiChainUserOpDto[]): Promise {
- try {
- const leaves: string[] = [];
-
- // Iterate over each userOp and process them
- for (const multiChainOp of multiChainUserOps) {
- const validUntil = multiChainOp.validUntil ?? 0;
- const validAfter = multiChainOp.validAfter ?? 0;
- const leaf = concat([
- pad(toHex(validUntil), { size: 6 }),
- pad(toHex(validAfter), { size: 6 }),
- pad(getUserOpHash(multiChainOp.userOp, this.entryPointAddress, multiChainOp.chainId), { size: 32 }),
- ]);
-
- leaves.push(keccak256(leaf));
- }
-
- // Create a new Merkle tree using the leaves array
- const merkleTree = new MerkleTree(leaves, keccak256, { sortPairs: true });
-
- let multichainSignature = await this.signer.signMessage({ raw: toBytes(merkleTree.getHexRoot()) });
-
- const potentiallyIncorrectV = parseInt(multichainSignature.slice(-2), 16);
- if (![27, 28].includes(potentiallyIncorrectV)) {
- const correctV = potentiallyIncorrectV + 27;
- multichainSignature = multichainSignature.slice(0, -2) + correctV.toString(16);
- }
-
- // Create an array to store updated userOps
- const updatedUserOps: UserOperationStruct[] = [];
-
- for (let i = 0; i < leaves.length; i++) {
- const merkleProof = merkleTree.getHexProof(leaves[i]);
-
- const validUntil = multiChainUserOps[i].validUntil ?? 0;
- const validAfter = multiChainUserOps[i].validAfter ?? 0;
-
- // Create the moduleSignature
- const moduleSignature = encodeAbiParameters(parseAbiParameters(["uint48, uint48, bytes32, bytes32[], bytes"]), [
- validUntil,
- validAfter,
- merkleTree.getHexRoot() as Hex,
- merkleProof as Hex[],
- multichainSignature as Hex,
- ]);
-
- // Note: Because accountV2 does not directly call this method. hence we need to add validation module address to the signature
- const signatureWithModuleAddress = encodeAbiParameters(parseAbiParameters(["bytes, address"]), [moduleSignature, this.getAddress()]);
-
- // Update userOp with the final signature
- const updatedUserOp: UserOperationStruct = {
- ...(multiChainUserOps[i].userOp as UserOperationStruct),
- signature: signatureWithModuleAddress as `0x${string}`,
- };
-
- updatedUserOps.push(updatedUserOp);
- }
- return updatedUserOps;
- } catch (error) {
- Logger.error("Error in signing multi chain userops");
- throw new Error(JSON.stringify(error));
- }
- }
-}
diff --git a/packages/modules/src/index.ts b/packages/modules/src/index.ts
deleted file mode 100644
index ca954778b..000000000
--- a/packages/modules/src/index.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-export * from "./utils/Types.js";
-export * from "./utils/Constants.js";
-export * from "./interfaces/IValidationModule.js";
-export * from "./interfaces/ISessionValidationModule.js";
-export * from "./BaseValidationModule.js";
-export * from "./ECDSAOwnershipValidationModule.js";
-export * from "./MultichainValidationModule.js";
-export * from "./SessionKeyManagerModule.js";
-export * from "./BatchedSessionRouterModule.js";
-export * from "./session-validation-modules/ERC20SessionValidationModule.js";
-
-import {
- BatchedSessionRouterModule,
- ECDSAOwnershipValidationModule,
- MultiChainValidationModule,
- SessionKeyManagerModule,
- ERC20SessionValidationModule,
-} from "./index.js";
-
-export const createBatchedSessionRouterModule = BatchedSessionRouterModule.create;
-export const createMultiChainValidationModule = MultiChainValidationModule.create;
-export const createECDSAOwnershipValidationModule = ECDSAOwnershipValidationModule.create;
-export const createSessionKeyManagerModule = SessionKeyManagerModule.create;
-export const createERC20SessionValidationModule = ERC20SessionValidationModule.create;
-
-// export * from './PasskeyValidationModule'
diff --git a/packages/modules/src/interfaces/IValidationModule.ts b/packages/modules/src/interfaces/IValidationModule.ts
deleted file mode 100644
index ee3da28a9..000000000
--- a/packages/modules/src/interfaces/IValidationModule.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { SmartAccountSigner } from "@alchemy/aa-core";
-import { Hex } from "viem";
-
-export interface IValidationModule {
- getAddress(): Hex;
- getInitData(): Promise;
- getSigner(): Promise;
- signUserOpHash(_userOpHash: string): Promise;
- signMessage(_message: string | Uint8Array): Promise;
- getDummySignature(): Promise;
-}
diff --git a/packages/modules/src/session-storage/SessionLocalStorage.ts b/packages/modules/src/session-storage/SessionLocalStorage.ts
deleted file mode 100644
index 97a1d6953..000000000
--- a/packages/modules/src/session-storage/SessionLocalStorage.ts
+++ /dev/null
@@ -1,179 +0,0 @@
-import { Hex, createWalletClient, http, toHex } from "viem";
-import { SmartAccountSigner, WalletClientSigner } from "@alchemy/aa-core";
-import { ISessionStorage, SessionLeafNode, SessionSearchParam, SessionStatus } from "../interfaces/ISessionStorage.js";
-import { mainnet } from "viem/chains";
-import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
-import { SignerData } from "../utils/Types.js";
-
-export class SessionLocalStorage implements ISessionStorage {
- private smartAccountAddress: string;
-
- constructor(smartAccountAddress: string) {
- this.smartAccountAddress = smartAccountAddress.toLowerCase();
- }
-
- private validateSearchParam(param: SessionSearchParam): void {
- if (param.sessionID) {
- return;
- } else if (!param.sessionID && param.sessionPublicKey && param.sessionValidationModule) {
- return;
- } else {
- throw new Error("Either pass sessionId or a combination of sessionPublicKey and sessionValidationModule address.");
- }
- }
-
- private getSessionStore(): any {
- // @ts-ignore: LocalStorage is not available in node
- const data = localStorage.getItem(this.getStorageKey("sessions"));
- return data ? JSON.parse(data) : { merkleRoot: "", leafNodes: [] };
- }
-
- private getSignerStore(): any {
- // @ts-ignore: LocalStorage is not available in node
- const data = localStorage.getItem(this.getStorageKey("signers"));
- return data ? JSON.parse(data) : {};
- }
-
- private getStorageKey(type: "sessions" | "signers"): string {
- return `${this.smartAccountAddress}_${type}`;
- }
-
- private toLowercaseAddress(address: string): string {
- return address.toLowerCase();
- }
-
- async addSessionData(leaf: SessionLeafNode): Promise {
- const data = this.getSessionStore();
- leaf.sessionValidationModule = this.toLowercaseAddress(leaf.sessionValidationModule) as Hex;
- leaf.sessionPublicKey = this.toLowercaseAddress(leaf.sessionPublicKey) as Hex;
- data.leafNodes.push(leaf);
- // @ts-ignore: LocalStorage is not available in node
- localStorage.setItem(this.getStorageKey("sessions"), JSON.stringify(data));
- }
-
- async getSessionData(param: SessionSearchParam): Promise {
- this.validateSearchParam(param);
-
- const sessions = this.getSessionStore().leafNodes;
- const session = sessions.find((s: SessionLeafNode) => {
- if (param.sessionID) {
- return s.sessionID === param.sessionID && (!param.status || s.status === param.status);
- } else if (param.sessionPublicKey && param.sessionValidationModule) {
- return (
- s.sessionPublicKey === this.toLowercaseAddress(param.sessionPublicKey) &&
- s.sessionValidationModule === this.toLowercaseAddress(param.sessionValidationModule) &&
- (!param.status || s.status === param.status)
- );
- } else {
- return undefined;
- }
- });
-
- if (!session) {
- throw new Error("Session not found.");
- }
- return session;
- }
-
- async updateSessionStatus(param: SessionSearchParam, status: SessionStatus): Promise {
- this.validateSearchParam(param);
-
- const data = this.getSessionStore();
- const session = data.leafNodes.find((s: SessionLeafNode) => {
- if (param.sessionID) {
- return s.sessionID === param.sessionID;
- } else if (param.sessionPublicKey && param.sessionValidationModule) {
- return (
- s.sessionPublicKey === this.toLowercaseAddress(param.sessionPublicKey) &&
- s.sessionValidationModule === this.toLowercaseAddress(param.sessionValidationModule)
- );
- } else {
- return undefined;
- }
- });
-
- if (!session) {
- throw new Error("Session not found.");
- }
-
- session.status = status;
- // @ts-ignore: LocalStorage is not available in node
- localStorage.setItem(this.getStorageKey("sessions"), JSON.stringify(data));
- }
-
- async clearPendingSessions(): Promise {
- const data = this.getSessionStore();
- data.leafNodes = data.leafNodes.filter((s: SessionLeafNode) => s.status !== "PENDING");
- // @ts-ignore: LocalStorage is not available in node
- localStorage.setItem(this.getStorageKey("sessions"), JSON.stringify(data));
- }
-
- async addSigner(signerData: SignerData): Promise {
- const signers = this.getSignerStore();
- let signer: SignerData;
- if (!signerData) {
- const pkey = generatePrivateKey();
- signer = {
- pvKey: pkey,
- pbKey: privateKeyToAccount(pkey).publicKey,
- };
- } else {
- signer = signerData;
- }
- const accountSigner = privateKeyToAccount(toHex(signer.pvKey));
- const client = createWalletClient({
- account: accountSigner,
- chain: signerData.chainId,
- transport: http(),
- });
- const walletClientSigner = new WalletClientSigner(
- client,
- "json-rpc", // signerType
- );
- signers[this.toLowercaseAddress(accountSigner.address)] = signerData;
- // @ts-ignore: LocalStorage is not available in node
- localStorage.setItem(this.getStorageKey("signers"), JSON.stringify(signers));
- return walletClientSigner;
- }
-
- async getSignerByKey(sessionPublicKey: string): Promise {
- const signers = this.getSignerStore();
- const signerData = signers[this.toLowercaseAddress(sessionPublicKey)];
- if (!signerData) {
- throw new Error("Signer not found.");
- }
- const account = privateKeyToAccount(signerData.privateKey);
- const client = createWalletClient({
- account,
- chain: mainnet,
- transport: http(),
- });
- const signer = new WalletClientSigner(client, "viem");
- return signer;
- }
-
- async getSignerBySession(param: SessionSearchParam): Promise {
- const session = await this.getSessionData(param);
- return this.getSignerByKey(session.sessionPublicKey);
- }
-
- async getAllSessionData(param?: SessionSearchParam): Promise {
- const sessions = this.getSessionStore().leafNodes;
- if (!param || !param.status) {
- return sessions;
- }
- return sessions.filter((s: SessionLeafNode) => s.status === param.status);
- }
-
- async getMerkleRoot(): Promise {
- return this.getSessionStore().merkleRoot;
- }
-
- setMerkleRoot(merkleRoot: string): Promise {
- const data = this.getSessionStore();
- data.merkleRoot = merkleRoot;
- // @ts-ignore: LocalStorage is not available in node
- localStorage.setItem(this.getStorageKey("sessions"), JSON.stringify(data));
- return Promise.resolve();
- }
-}
diff --git a/packages/modules/src/utils/Constants.ts b/packages/modules/src/utils/Constants.ts
deleted file mode 100644
index 7a2a308fa..000000000
--- a/packages/modules/src/utils/Constants.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-import { ModuleVersion } from "./Types.js";
-
-export const DEFAULT_MODULE_VERSION: ModuleVersion = "V1_0_0";
-
-export const DEFAULT_ENTRYPOINT_ADDRESS = "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789";
-export const ENTRYPOINT_ADDRESSES = {
- "0x27a4db290b89ae3373ce4313cbeae72112ae7da9": "V0_0_5",
- "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789": "V0_0_6",
-};
-
-export const ENTRYPOINT_ADDRESSES_BY_VERSION = {
- V0_0_5: "0x27a4db290b89ae3373ce4313cbeae72112ae7da9",
- V0_0_6: "0x5ff137d4b0fdcd49dca30c7cf57e578a026d2789",
-};
-
-// Note: we could append these defaults with ADDRESS suffix
-export const DEFAULT_ECDSA_OWNERSHIP_MODULE = "0x0000001c5b32F37F5beA87BDD5374eB2aC54eA8e";
-
-export const ECDSA_OWNERSHIP_MODULE_ADDRESSES_BY_VERSION = {
- V1_0_0: "0x0000001c5b32F37F5beA87BDD5374eB2aC54eA8e",
-};
-
-export const DEFAULT_SESSION_KEY_MANAGER_MODULE = "0x000002FbFfedd9B33F4E7156F2DE8D48945E7489";
-
-export const SESSION_MANAGER_MODULE_ADDRESSES_BY_VERSION = {
- V1_0_0: "0x000000456b395c4e107e0302553B90D1eF4a32e9",
- V1_0_1: "0x000002FbFfedd9B33F4E7156F2DE8D48945E7489",
-};
-
-export const DEFAULT_BATCHED_SESSION_ROUTER_MODULE = "0x00000D09967410f8C76752A104c9848b57ebba55";
-
-export const BATCHED_SESSION_ROUTER_MODULE_ADDRESSES_BY_VERSION = {
- V1_0_0: "0x00000D09967410f8C76752A104c9848b57ebba55",
-};
-
-export const DEFAULT_ERC20_MODULE = "0x000000D50C68705bd6897B2d17c7de32FB519fDA";
-
-export const DEFAULT_MULTICHAIN_MODULE = "0x000000824dc138db84FD9109fc154bdad332Aa8E";
-
-export const MULTICHAIN_VALIDATION_MODULE_ADDRESSES_BY_VERSION = {
- V1_0_0: "0x000000824dc138db84FD9109fc154bdad332Aa8E",
-};
-
-// similarly others here or in module / signer classes
-// Mapping / Reverse mapping of version -> module address can be kept here
-
-export const ERC20_ABI = [
- "function transfer(address to, uint256 value) external returns (bool)",
- "function transferFrom(address from, address to, uint256 value) external returns (bool)",
- "function approve(address spender, uint256 value) external returns (bool)",
- "function allowance(address owner, address spender) external view returns (uint256)",
- "function balanceOf(address owner) external view returns (uint256)",
-];
diff --git a/packages/modules/src/utils/Helper.ts b/packages/modules/src/utils/Helper.ts
deleted file mode 100644
index b0b6fc43d..000000000
--- a/packages/modules/src/utils/Helper.ts
+++ /dev/null
@@ -1,74 +0,0 @@
-import { UserOperationStruct } from "@alchemy/aa-core";
-import { Hex, encodeAbiParameters, keccak256, parseAbiParameters, concat, pad, toHex } from "viem";
-
-export interface Rule {
- offset: number;
- condition: number;
- referenceValue: `0x${string}`;
-}
-
-export interface Permission {
- destContract: `0x${string}`;
- functionSelector: `0x${string}`;
- valueLimit: bigint;
- rules: Rule[];
-}
-
-function packUserOp(op: Partial, forSignature = true): string {
- if (!op.initCode || !op.callData || !op.paymasterAndData) throw new Error("Missing userOp properties");
- if (forSignature) {
- return encodeAbiParameters(parseAbiParameters("address, uint256, bytes32, bytes32, uint256, uint256, uint256, uint256, uint256, bytes32"), [
- op.sender as Hex,
- BigInt(op.nonce as Hex),
- keccak256(op.initCode as Hex),
- keccak256(op.callData as Hex),
- BigInt(op.callGasLimit as Hex),
- BigInt(op.verificationGasLimit as Hex),
- BigInt(op.preVerificationGas as Hex),
- BigInt(op.maxFeePerGas as Hex),
- BigInt(op.maxPriorityFeePerGas as Hex),
- keccak256(op.paymasterAndData as Hex),
- ]);
- } else {
- // for the purpose of calculating gas cost encode also signature (and no keccak of bytes)
- return encodeAbiParameters(parseAbiParameters("address, uint256, bytes, bytes, uint256, uint256, uint256, uint256, uint256, bytes, bytes"), [
- op.sender as Hex,
- BigInt(op.nonce as Hex),
- op.initCode as Hex,
- op.callData as Hex,
- BigInt(op.callGasLimit as Hex),
- BigInt(op.verificationGasLimit as Hex),
- BigInt(op.preVerificationGas as Hex),
- BigInt(op.maxFeePerGas as Hex),
- BigInt(op.maxPriorityFeePerGas as Hex),
- op.paymasterAndData as Hex,
- op.signature as Hex,
- ]);
- }
-}
-
-export const getUserOpHash = (userOp: Partial, entryPointAddress: Hex, chainId: number): Hex => {
- const userOpHash = keccak256(packUserOp(userOp, true) as Hex);
- const enc = encodeAbiParameters(parseAbiParameters("bytes32, address, uint256"), [userOpHash, entryPointAddress, BigInt(chainId)]);
- return keccak256(enc);
-};
-
-export async function getABISVMSessionKeyData(sessionKey: `0x${string}` | Uint8Array, permission: Permission): Promise<`0x${string}` | Uint8Array> {
- let sessionKeyData = concat([
- sessionKey,
- permission.destContract,
- permission.functionSelector,
- pad(toHex(permission.valueLimit), { size: 16 }),
- pad(toHex(permission.rules.length), { size: 2 }), // this can't be more 2**11 (see below), so uint16 (2 bytes) is enough
- ]) as `0x${string}`;
-
- for (let i = 0; i < permission.rules.length; i++) {
- sessionKeyData = concat([
- sessionKeyData,
- pad(toHex(permission.rules[i].offset), { size: 2 }), // offset is uint16, so there can't be more than 2**16/32 args = 2**11
- pad(toHex(permission.rules[i].condition), { size: 1 }), // uint8
- permission.rules[i].referenceValue,
- ]);
- }
- return sessionKeyData;
-}
diff --git a/packages/modules/tests/batchedSessionValidationModule.e2e.spec.ts b/packages/modules/tests/batchedSessionValidationModule.e2e.spec.ts
deleted file mode 100644
index 47f542e54..000000000
--- a/packages/modules/tests/batchedSessionValidationModule.e2e.spec.ts
+++ /dev/null
@@ -1,214 +0,0 @@
-import {
- DEFAULT_BATCHED_SESSION_ROUTER_MODULE,
- DEFAULT_SESSION_KEY_MANAGER_MODULE,
- createBatchedSessionRouterModule,
- createSessionKeyManagerModule,
-} from "@biconomy/modules";
-import { SessionFileStorage } from "./utils/customSession";
-import { WalletClientSigner, createSmartAccountClient } from "../../account/src/index";
-import { encodeAbiParameters, encodeFunctionData, parseAbi, parseUnits } from "viem";
-import { TestData } from "../../../tests";
-import { checkBalance } from "../../../tests/utils";
-import { PaymasterMode } from "@biconomy/paymaster";
-import { Logger } from "@biconomy/common";
-
-describe("Batched Session Router Tests", () => {
- let mumbai: TestData;
-
- beforeEach(() => {
- // @ts-ignore: Comes from setup-e2e-tests
- [mumbai] = testDataPerChain;
- });
-
- // TODO(Gabi): Fix Batched Session Router Module tests
- it.skip("Should send a user op using Batched Session Validation Module", async () => {
- let sessionSigner: WalletClientSigner;
-
- const {
- whale: {
- account: { address: sessionKeyEOA },
- privateKey: pvKey,
- viemWallet,
- },
- minnow: { publicAddress: recipient },
- publicClient,
- bundlerUrl,
- biconomyPaymasterApiKey,
- chainId,
- viemChain,
- } = mumbai;
-
- // Create smart account
- let smartAccount = await createSmartAccountClient({
- signer: viemWallet,
- bundlerUrl,
- biconomyPaymasterApiKey,
- index: 3, // Increasing index to not conflict with other test cases and use a new smart account
- });
-
- const smartAccountAddress = await smartAccount.getAddress();
-
- const sessionFileStorage: SessionFileStorage = new SessionFileStorage(smartAccountAddress);
-
- try {
- sessionSigner = await sessionFileStorage.getSignerByKey(sessionKeyEOA);
- } catch (error) {
- sessionSigner = await sessionFileStorage.addSigner({ pbKey: sessionKeyEOA, pvKey, chainId: viemChain });
- }
-
- expect(sessionSigner).toBeTruthy();
-
- // First we need to check if smart account is deployed
- // if not deployed, send an empty transaction to deploy it
- const isDeployed = await smartAccount.isAccountDeployed();
-
- if (!isDeployed) {
- const { wait } = await smartAccount.deploy({ paymasterServiceData: { mode: PaymasterMode.SPONSORED } });
- const { success } = await wait();
- expect(success).toBe("true");
- }
-
- // Create session module
- const sessionModule = await createSessionKeyManagerModule({
- moduleAddress: DEFAULT_SESSION_KEY_MANAGER_MODULE,
- smartAccountAddress,
- sessionStorageClient: sessionFileStorage,
- });
-
- // Create batched session module
- const batchedSessionModule = await createBatchedSessionRouterModule({
- moduleAddress: DEFAULT_BATCHED_SESSION_ROUTER_MODULE,
- smartAccountAddress,
- sessionKeyManagerModule: sessionModule,
- });
-
- // Set enabled call on session, only allows calling USDC contract transfer with <= 10 USDC
- const sessionKeyData = encodeAbiParameters(
- [{ type: "address" }, { type: "address" }, { type: "address" }, { type: "uint256" }],
- [
- sessionKeyEOA,
- "0xdA5289fCAAF71d52a80A254da614a192b693e977", // erc20 token address
- recipient, // receiver address
- parseUnits("10", 6),
- ],
- );
-
- // only requires that the caller is the session key
- // can call anything using the mock session module
- const sessionKeyData2 = encodeAbiParameters([{ type: "address" }], [sessionKeyEOA]);
-
- const erc20ModuleAddr = "0x000000D50C68705bd6897B2d17c7de32FB519fDA";
- const mockSessionModuleAddr = "0x7Ba4a7338D7A90dfA465cF975Cc6691812C3772E";
-
- const sessionTxData = await batchedSessionModule.createSessionData([
- {
- validUntil: 0,
- validAfter: 0,
- sessionValidationModule: erc20ModuleAddr,
- sessionPublicKey: sessionKeyEOA,
- sessionKeyData: sessionKeyData,
- },
- {
- validUntil: 0,
- validAfter: 0,
- sessionValidationModule: mockSessionModuleAddr,
- sessionPublicKey: sessionKeyEOA,
- sessionKeyData: sessionKeyData2,
- },
- ]);
-
- const setSessionAllowedTrx = {
- to: DEFAULT_SESSION_KEY_MANAGER_MODULE,
- data: sessionTxData.data,
- };
-
- const txArray: any = [];
-
- // Check if session module is enabled
- const isEnabled = await smartAccount.isModuleEnabled(DEFAULT_SESSION_KEY_MANAGER_MODULE);
- if (!isEnabled) {
- const enableModuleTrx = await smartAccount.getEnableModuleData(DEFAULT_SESSION_KEY_MANAGER_MODULE);
- txArray.push(enableModuleTrx);
- }
-
- // Check if batched session module is enabled
- const isBRMenabled = await smartAccount.isModuleEnabled(DEFAULT_BATCHED_SESSION_ROUTER_MODULE);
- if (!isBRMenabled) {
- // -----> enableModule batched session router module
- const tx2 = await smartAccount.getEnableModuleData(DEFAULT_BATCHED_SESSION_ROUTER_MODULE);
- txArray.push(tx2);
- }
-
- txArray.push(setSessionAllowedTrx);
-
- const userOpResponse1 = await smartAccount.sendTransaction(txArray, { paymasterServiceData: { mode: PaymasterMode.SPONSORED } }); // this user op will enable the modules and setup session allowed calls
- const transactionDetails = await userOpResponse1.wait();
- expect(transactionDetails.success).toBe("true");
- Logger.log("Tx Hash: ", transactionDetails.receipt.transactionHash);
-
- const usdcBalance = await checkBalance(publicClient, smartAccountAddress, "0xdA5289fCAAF71d52a80A254da614a192b693e977");
- expect(usdcBalance).toBeGreaterThan(0);
-
- smartAccount = smartAccount.setActiveValidationModule(batchedSessionModule);
-
- // WARNING* If the smart account does not have enough USDC, user op execution will FAIL
- const encodedCall = encodeFunctionData({
- abi: parseAbi(["function transfer(address _to, uint256 _value)"]),
- functionName: "transfer",
- args: [recipient, parseUnits("0.001", 6)],
- });
-
- const encodedCall2 = encodeFunctionData({
- abi: parseAbi(["function transfer(address _to, uint256 _value)"]),
- functionName: "transfer",
- args: ["0xd3C85Fdd3695Aee3f0A12B3376aCD8DC54020549", parseUnits("0.001", 6)],
- });
-
- const transferTx = {
- to: "0xdA5289fCAAF71d52a80A254da614a192b693e977",
- data: encodedCall,
- };
-
- const transferTx2 = {
- to: "0xdA5289fCAAF71d52a80A254da614a192b693e977",
- data: encodedCall2,
- };
-
- const activeModule = smartAccount.activeValidationModule;
- expect(activeModule).toEqual(batchedSessionModule);
-
- const maticBalanceBefore = await checkBalance(publicClient, smartAccountAddress);
-
- // failing with dummyTx because of invalid sessionKeyData
- const userOpResponse2 = await smartAccount.sendTransaction([transferTx, transferTx2], {
- params: {
- batchSessionParams: [
- {
- sessionSigner: sessionSigner,
- sessionValidationModule: erc20ModuleAddr,
- },
- {
- sessionSigner: sessionSigner,
- sessionValidationModule: mockSessionModuleAddr,
- },
- ],
- },
- paymasterServiceData: {
- mode: PaymasterMode.SPONSORED,
- },
- });
-
- const receipt = await userOpResponse2.wait();
- console.log(receipt.userOpHash, "Batched user op hash");
- expect(receipt.success).toBe("true");
-
- expect(userOpResponse2.userOpHash).toBeTruthy();
- expect(userOpResponse2.userOpHash).not.toBeNull();
-
- const maticBalanceAfter = await checkBalance(publicClient, smartAccountAddress);
-
- expect(maticBalanceAfter).toEqual(maticBalanceBefore);
-
- Logger.log(`Tx at: https://jiffyscan.xyz/userOpHash/${userOpResponse2.userOpHash}?network=mumbai`);
- }, 60000);
-});
diff --git a/packages/modules/tests/ecdsaValidationModule.e2e.spec.ts b/packages/modules/tests/ecdsaValidationModule.e2e.spec.ts
deleted file mode 100644
index 84b3f627e..000000000
--- a/packages/modules/tests/ecdsaValidationModule.e2e.spec.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-import { PaymasterMode } from "@biconomy/paymaster";
-import { TestData } from "../../../tests";
-import { createSmartAccountClient } from "../../account/src/index";
-import { Hex, encodeFunctionData, parseAbi } from "viem";
-import { DEFAULT_MULTICHAIN_MODULE, createECDSAOwnershipValidationModule } from "@biconomy/modules";
-
-describe("Account with ECDSAOwnershipValidationModule Module Tests", () => {
- let mumbai: TestData;
- let baseSepolia: TestData;
-
- beforeEach(() => {
- // @ts-ignore: Comes from setup-e2e-tests
- [mumbai, baseSepolia] = testDataPerChain;
- });
-
- it("should create a ECDSAOwnershipValidationModule with signer", async () => {
- const {
- bundlerUrl,
- whale: { viemWallet: signer },
- } = mumbai;
-
- const defaultValidationModule = await createECDSAOwnershipValidationModule({ signer });
- // Should not require a signer or chainId
- const smartAccount = await createSmartAccountClient({
- bundlerUrl,
- defaultValidationModule,
- signer,
- });
- const address = await smartAccount.getAccountAddress();
- expect(address).toBeTruthy();
- expect(smartAccount.activeValidationModule).toEqual(defaultValidationModule);
- });
-
- it("should create a ECDSAOwnershipValidationModule without signer", async () => {
- const {
- bundlerUrl,
- whale: { viemWallet: signer },
- } = mumbai;
-
- const defaultValidationModule = await createECDSAOwnershipValidationModule({ signer });
- // Should not require a signer or chainId
- const smartAccount = await createSmartAccountClient({
- bundlerUrl,
- defaultValidationModule,
- });
- const address = await smartAccount.getAccountAddress();
- expect(address).toBeTruthy();
- expect(smartAccount.activeValidationModule).toEqual(defaultValidationModule);
- });
-
- it("should create a ECDSAOwnershipValidationModule by default, without explicitly setting it on the smart account", async () => {
- const {
- bundlerUrl,
- whale: { viemWallet: signer },
- } = mumbai;
- const defaultValidationModule = await createECDSAOwnershipValidationModule({ signer });
- const smartAccount = await createSmartAccountClient({ bundlerUrl, signer });
- const address = await smartAccount.getAccountAddress();
- expect(address).toBeTruthy();
- const smartAccountValidationModuleAddress = await smartAccount.activeValidationModule.getAddress();
- expect(smartAccountValidationModuleAddress).toEqual(defaultValidationModule.moduleAddress);
- });
-});
diff --git a/packages/modules/tests/modules.e2e.spec.ts b/packages/modules/tests/modules.e2e.spec.ts
deleted file mode 100644
index 9de6d50ee..000000000
--- a/packages/modules/tests/modules.e2e.spec.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-import { TestData } from "../../../tests";
-import { PaymasterMode, Transaction, createSmartAccountClient } from "@biconomy/account";
-import { DEFAULT_BATCHED_SESSION_ROUTER_MODULE, DEFAULT_ERC20_MODULE, DEFAULT_SESSION_KEY_MANAGER_MODULE } from "../src";
-
-describe("Account Tests", () => {
- let mumbai: TestData;
-
- beforeEach(() => {
- // @ts-ignore: Comes from setup-unit-tests
- [mumbai] = testDataPerChain;
- });
-
- it("should enable batched module", async () => {
- const {
- whale: { viemWallet: signer },
- bundlerUrl,
- biconomyPaymasterApiKey,
- } = mumbai;
-
- const smartAccount = await createSmartAccountClient({
- signer,
- bundlerUrl,
- biconomyPaymasterApiKey,
- });
-
- const isBRMenabled = await smartAccount.isModuleEnabled(DEFAULT_BATCHED_SESSION_ROUTER_MODULE);
-
- if (!isBRMenabled) {
- const tx = await smartAccount.getEnableModuleData(DEFAULT_BATCHED_SESSION_ROUTER_MODULE);
- const { wait } = await smartAccount.sendTransaction(tx, {
- paymasterServiceData: { mode: PaymasterMode.SPONSORED },
- });
- const { success } = await wait();
- expect(success).toBe("true");
- }
- }, 50000);
-
- it("should enable session module", async () => {
- const {
- whale: { viemWallet: signer },
- bundlerUrl,
- biconomyPaymasterApiKey,
- } = mumbai;
-
- const smartAccount = await createSmartAccountClient({
- signer,
- bundlerUrl,
- biconomyPaymasterApiKey,
- });
-
- const isSessionKeyEnabled = await smartAccount.isModuleEnabled(DEFAULT_SESSION_KEY_MANAGER_MODULE);
-
- if (!isSessionKeyEnabled) {
- const tx = await smartAccount.getEnableModuleData(DEFAULT_SESSION_KEY_MANAGER_MODULE);
- const { wait } = await smartAccount.sendTransaction(tx, {
- paymasterServiceData: { mode: PaymasterMode.SPONSORED },
- });
- const { success } = await wait();
- expect(success).toBe("true");
- }
- }, 50000);
-});
diff --git a/packages/modules/tests/modules.spec.ts b/packages/modules/tests/modules.spec.ts
deleted file mode 100644
index a799a6760..000000000
--- a/packages/modules/tests/modules.spec.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-import { TestData } from "../../../tests";
-import { createSmartAccountClient } from "@biconomy/account";
-import { createECDSAOwnershipValidationModule, createMultiChainValidationModule } from "../src";
-
-describe("Account Tests", () => {
- let ganache: TestData;
-
- beforeEach(() => {
- // @ts-ignore: Comes from setup-unit-tests
- [ganache] = testDataPerChain;
- });
-
- it("should create a MultiChainValidationModule from an ethers signer using convertSigner", async () => {
- const {
- bundlerUrl,
- whale: { ethersSigner: signer },
- viemChain,
- } = ganache;
-
- const defaultValidationModule = await createMultiChainValidationModule({ signer });
- // Should not require a signer or chainId
- const smartAccount = await createSmartAccountClient({ bundlerUrl, defaultValidationModule, rpcUrl: viemChain.rpcUrls.default.http[0], });
- const address = await smartAccount.getAccountAddress();
- expect(address).toBeTruthy();
- // expect the relevant module to be set
- expect(smartAccount.activeValidationModule).toEqual(defaultValidationModule);
- }, 50000);
-
- it("should create a ECDSAOwnershipValidationModule from a viem signer using convertSigner", async () => {
- const {
- bundlerUrl,
- whale: { viemWallet: signer },
- viemChain,
- } = ganache;
-
- const defaultValidationModule = await createECDSAOwnershipValidationModule({ signer });
- // Should not require a signer or chainId
- const smartAccount = await createSmartAccountClient({
- bundlerUrl,
- defaultValidationModule,
- rpcUrl: viemChain.rpcUrls.default.http[0],
- });
- const address = await smartAccount.getAccountAddress();
- expect(address).toBeTruthy();
- // expect the relevant module to be set
- expect(smartAccount.activeValidationModule).toEqual(defaultValidationModule);
- }, 50000);
-});
diff --git a/packages/modules/tests/multiChainValidationModule.e2e.spec.ts b/packages/modules/tests/multiChainValidationModule.e2e.spec.ts
deleted file mode 100644
index 996be004c..000000000
--- a/packages/modules/tests/multiChainValidationModule.e2e.spec.ts
+++ /dev/null
@@ -1,122 +0,0 @@
-import { PaymasterMode } from "@biconomy/paymaster";
-import { TestData } from "../../../tests";
-import { createSmartAccountClient } from "../../account/src/index";
-import { Hex, encodeFunctionData, parseAbi } from "viem";
-import { DEFAULT_MULTICHAIN_MODULE, MultiChainValidationModule } from "@biconomy/modules";
-import { Logger } from "@biconomy/common";
-
-describe("MultiChainValidation Module Tests", () => {
- let mumbai: TestData;
- let baseSepolia: TestData;
-
- beforeEach(() => {
- // @ts-ignore: Comes from setup-e2e-tests
- [mumbai, baseSepolia] = testDataPerChain;
- });
-
- it("Should mint an NFT gasless on baseSepolia and mumbai", async () => {
- const {
- whale: { alchemyWalletClientSigner: signerMumbai, publicAddress: recipientForBothChains },
- paymasterUrl: biconomyPaymasterApiKeyMumbai,
- bundlerUrl: bundlerUrlMumbai,
- chainId: chainIdMumbai,
- } = mumbai;
-
- const {
- whale: { alchemyWalletClientSigner: signerBase },
- paymasterUrl: biconomyPaymasterApiKeyBase,
- bundlerUrl: bundlerUrlBase,
- chainId: chainIdBase,
- } = baseSepolia;
-
- const nftAddress: Hex = "0x1758f42Af7026fBbB559Dc60EcE0De3ef81f665e";
-
- const multiChainModule = await MultiChainValidationModule.create({
- signer: signerMumbai,
- moduleAddress: DEFAULT_MULTICHAIN_MODULE,
- });
-
- const [polygonAccount, baseAccount] = await Promise.all([
- createSmartAccountClient({
- chainId: chainIdMumbai,
- signer: signerMumbai,
- bundlerUrl: bundlerUrlMumbai,
- defaultValidationModule: multiChainModule,
- activeValidationModule: multiChainModule,
- paymasterUrl: biconomyPaymasterApiKeyMumbai,
- }),
- createSmartAccountClient({
- chainId: chainIdBase,
- signer: signerBase,
- bundlerUrl: bundlerUrlBase,
- defaultValidationModule: multiChainModule,
- activeValidationModule: multiChainModule,
- paymasterUrl: biconomyPaymasterApiKeyBase,
- }),
- ]);
-
- // Check if the smart account has been deployed
- const [isPolygonDeployed, isBaseDeployed] = await Promise.all([polygonAccount.isAccountDeployed(), baseAccount.isAccountDeployed()]);
- if (!isPolygonDeployed) {
- const { wait } = await polygonAccount.deploy({ paymasterServiceData: { mode: PaymasterMode.SPONSORED } });
- const { success } = await wait();
- expect(success).toBe("true");
- }
- if (!isBaseDeployed) {
- const { wait } = await baseAccount.deploy({ paymasterServiceData: { mode: PaymasterMode.SPONSORED } });
- const { success } = await wait();
- expect(success).toBe("true");
- }
-
- const moduleEnabled1 = await polygonAccount.isModuleEnabled(DEFAULT_MULTICHAIN_MODULE);
- const moduleActive1 = polygonAccount.activeValidationModule;
- expect(moduleEnabled1).toBeTruthy();
- expect(moduleActive1.getAddress()).toBe(DEFAULT_MULTICHAIN_MODULE);
-
- const moduleEnabled2 = await baseAccount.isModuleEnabled(DEFAULT_MULTICHAIN_MODULE);
- const moduleActive2 = polygonAccount.activeValidationModule;
- expect(moduleEnabled2).toBeTruthy();
- expect(moduleActive2.getAddress()).toBe(DEFAULT_MULTICHAIN_MODULE);
-
- const encodedCall = encodeFunctionData({
- abi: parseAbi(["function safeMint(address owner) view returns (uint balance)"]),
- functionName: "safeMint",
- args: [recipientForBothChains],
- });
-
- const transaction = {
- to: nftAddress,
- data: encodedCall,
- };
-
- const [partialUserOp1, partialUserOp2] = await Promise.all([
- baseAccount.buildUserOp([transaction], { paymasterServiceData: { mode: PaymasterMode.SPONSORED } }),
- polygonAccount.buildUserOp([transaction], { paymasterServiceData: { mode: PaymasterMode.SPONSORED } }),
- ]);
-
- expect(partialUserOp1.paymasterAndData).not.toBe("0x");
- expect(partialUserOp2.paymasterAndData).not.toBe("0x");
-
- // Sign the user ops using multiChainModule
- const returnedOps = await multiChainModule.signUserOps([
- { userOp: partialUserOp1, chainId: chainIdBase },
- { userOp: partialUserOp2, chainId: chainIdMumbai },
- ]);
-
- // Send the signed user ops on both chains
- const userOpResponse1 = await baseAccount.sendSignedUserOp(returnedOps[0] as any);
- const userOpResponse2 = await polygonAccount.sendSignedUserOp(returnedOps[1] as any);
-
- Logger.log(userOpResponse1.userOpHash, "MULTICHAIN BASE USER OP HASH");
- Logger.log(userOpResponse2.userOpHash, "MULTICHAIN POLYGON USER OP HASH");
-
- expect(userOpResponse1.userOpHash).toBeTruthy();
- expect(userOpResponse2.userOpHash).toBeTruthy();
-
- const { success: success1 } = await userOpResponse1.wait();
- const { success: success2 } = await userOpResponse2.wait();
-
- expect(success1).toBe("true");
- expect(success2).toBe("true");
- }, 50000);
-});
diff --git a/packages/modules/tests/sessionValidationModule.e2e.spec.ts b/packages/modules/tests/sessionValidationModule.e2e.spec.ts
deleted file mode 100644
index 286cfb9a7..000000000
--- a/packages/modules/tests/sessionValidationModule.e2e.spec.ts
+++ /dev/null
@@ -1,166 +0,0 @@
-import { DEFAULT_SESSION_KEY_MANAGER_MODULE, createSessionKeyManagerModule } from "@biconomy/modules";
-import { SessionFileStorage } from "./utils/customSession";
-import { WalletClientSigner, createSmartAccountClient } from "../../account/src/index";
-import { Hex, encodeAbiParameters, encodeFunctionData, pad, parseAbi, parseEther, parseUnits, slice, toFunctionSelector } from "viem";
-import { TestData } from "../../../tests";
-import { checkBalance } from "../../../tests/utils";
-import { PaymasterMode } from "@biconomy/paymaster";
-import { Logger } from "@biconomy/common";
-import { getABISVMSessionKeyData } from "../src/utils/Helper";
-import { privateKeyToAccount, generatePrivateKey } from "viem/accounts";
-
-describe("Session Validation Module Tests", () => {
- let mumbai: TestData;
-
- beforeEach(() => {
- // @ts-ignore: Comes from setup-e2e-tests
- [mumbai] = testDataPerChain;
- });
-
- // TODO(Gabi): Fix Session Validation Module tests
- it.skip("Should send a user op using Session Validation Module", async () => {
- let sessionSigner: WalletClientSigner;
- const {
- whale: {
- account: { address: sessionKeyEOA },
- privateKey: pvKey,
- viemWallet,
- },
- viemChain,
- minnow: { publicAddress: recipient },
- publicClient,
- chainId,
- bundlerUrl,
- biconomyPaymasterApiKey,
- } = mumbai;
-
- // Create smart account
- let smartAccount = await createSmartAccountClient({
- chainId,
- signer: viemWallet,
- bundlerUrl,
- biconomyPaymasterApiKey,
- index: 1, // Increasing index to not conflict with other test cases and use a new smart account
- });
-
- const accountAddress = await smartAccount.getAccountAddress();
- const sessionFileStorage: SessionFileStorage = new SessionFileStorage(accountAddress);
-
- // First we need to check if smart account is deployed
- // if not deployed, send an empty transaction to deploy it
- const isDeployed = await smartAccount.isAccountDeployed();
-
- Logger.log("session", { isDeployed });
-
- if (!isDeployed) {
- const { wait } = await smartAccount.deploy({ paymasterServiceData: { mode: PaymasterMode.SPONSORED } });
- const { success } = await wait();
- expect(success).toBe("true");
- }
-
- try {
- sessionSigner = await sessionFileStorage.getSignerByKey(sessionKeyEOA);
- } catch (error) {
- sessionSigner = await sessionFileStorage.addSigner({ pbKey: sessionKeyEOA, pvKey, chainId: viemChain });
- }
- expect(sessionSigner).toBeTruthy();
-
- // Create session module
- const sessionModule = await createSessionKeyManagerModule({
- moduleAddress: DEFAULT_SESSION_KEY_MANAGER_MODULE,
- smartAccountAddress: await smartAccount.getAddress(),
- sessionStorageClient: sessionFileStorage,
- });
-
- const functionSelector = slice(toFunctionSelector("safeMint(address)"), 0, 4);
- // Set enabled call on session
- const sessionKeyData = await getABISVMSessionKeyData(sessionKeyEOA as Hex, {
- destContract: "0xdd526eba63ef200ed95f0f0fb8993fe3e20a23d0" as Hex, // nft address
- functionSelector: functionSelector,
- valueLimit: parseEther("0"),
- rules: [
- {
- offset: 0, // offset 0 means we are checking first parameter of safeMint (recipient address)
- condition: 0, // 0 = Condition.EQUAL
- referenceValue: pad("0xd3C85Fdd3695Aee3f0A12B3376aCD8DC54020549", { size: 32 }), // recipient address
- },
- ],
- });
-
- const abiSvmAddress = "0x000006bC2eCdAe38113929293d241Cf252D91861";
-
- const sessionTxData = await sessionModule.createSessionData([
- {
- validUntil: 0,
- validAfter: 0,
- sessionValidationModule: abiSvmAddress,
- sessionPublicKey: sessionKeyEOA as Hex,
- sessionKeyData: sessionKeyData as Hex,
- },
- ]);
-
- const setSessionAllowedTrx = {
- to: DEFAULT_SESSION_KEY_MANAGER_MODULE,
- data: sessionTxData.data,
- };
-
- const txArray: any = [];
-
- // Check if module is enabled
- const isEnabled = await smartAccount.isModuleEnabled(DEFAULT_SESSION_KEY_MANAGER_MODULE);
-
- if (!isEnabled) {
- const enableModuleTrx = await smartAccount.getEnableModuleData(DEFAULT_SESSION_KEY_MANAGER_MODULE);
- txArray.push(enableModuleTrx);
- txArray.push(setSessionAllowedTrx);
- } else {
- Logger.log("MODULE ALREADY ENABLED");
- txArray.push(setSessionAllowedTrx);
- }
-
- const userOp = await smartAccount.buildUserOp(txArray, {
- paymasterServiceData: {
- mode: PaymasterMode.SPONSORED,
- },
- });
-
- const userOpResponse1 = await smartAccount.sendUserOp(userOp);
- const transactionDetails = await userOpResponse1.wait();
- expect(transactionDetails.success).toBe("true");
- Logger.log("Tx Hash: ", transactionDetails.receipt.transactionHash);
-
- const encodedCall = encodeFunctionData({
- abi: parseAbi(["function safeMint(address _to)"]),
- functionName: "safeMint",
- args: ["0xd3C85Fdd3695Aee3f0A12B3376aCD8DC54020549"],
- });
-
- const nftMintTx = {
- to: "0xdd526eba63ef200ed95f0f0fb8993fe3e20a23d0",
- data: encodedCall,
- };
-
- smartAccount = smartAccount.setActiveValidationModule(sessionModule);
-
- const maticBalanceBefore = await checkBalance(publicClient, await smartAccount.getAccountAddress());
-
- const userOpResponse2 = await smartAccount.sendTransaction(nftMintTx, {
- params: {
- sessionSigner: sessionSigner,
- sessionValidationModule: abiSvmAddress,
- },
- paymasterServiceData: {
- mode: PaymasterMode.SPONSORED,
- },
- });
-
- expect(userOpResponse2.userOpHash).toBeTruthy();
- expect(userOpResponse2.userOpHash).not.toBeNull();
-
- const maticBalanceAfter = await checkBalance(publicClient, await smartAccount.getAccountAddress());
-
- expect(maticBalanceAfter).toEqual(maticBalanceBefore);
-
- Logger.log(`Tx at: https://jiffyscan.xyz/userOpHash/${userOpResponse2.userOpHash}?network=mumbai`);
- }, 60000);
-});
diff --git a/packages/modules/tests/utils/customSession.ts b/packages/modules/tests/utils/customSession.ts
deleted file mode 100644
index 1326c4871..000000000
--- a/packages/modules/tests/utils/customSession.ts
+++ /dev/null
@@ -1,230 +0,0 @@
-import * as fs from "fs";
-import { SmartAccountSigner, WalletClientSigner, getChain } from "@alchemy/aa-core";
-import { SignerData } from "@biconomy/modules/src";
-import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
-import { Hex, createWalletClient, http } from "viem";
-import { polygonMumbai } from "viem/chains";
-import { ISessionStorage, SessionLeafNode, SessionSearchParam, SessionStatus } from "@biconomy/modules/src/interfaces/ISessionStorage.js";
-import { Logger } from "@biconomy/common";
-
-export class SessionFileStorage implements ISessionStorage {
- private smartAccountAddress: string;
-
- constructor(smartAccountAddress: string) {
- this.smartAccountAddress = smartAccountAddress.toLowerCase();
- }
-
- // This method reads data from the file and returns it in the JSON format
- private async readDataFromFile(type: "sessions" | "signers"): Promise {
- return new Promise((resolve) => {
- fs.readFile(this.getStorageFilePath(type), "utf8", (err, data) => {
- if (err) {
- // Handle errors appropriately
- resolve(undefined);
- } else {
- if (!data) {
- resolve(null);
- } else {
- resolve(JSON.parse(data));
- }
- // resolve(JSON.parse(data));
- }
- });
- });
- }
-
- private getStorageFilePath(type: "sessions" | "signers"): string {
- return `./packages/modules/tests/utils/sessionStorageData/${this.smartAccountAddress}_${type}.json`;
- }
-
- private async writeDataToFile(data: any, type: "sessions" | "signers"): Promise {
- return new Promise((resolve, reject) => {
- const filePath = this.getStorageFilePath(type);
- fs.writeFile(filePath, JSON.stringify(data), "utf8", (err) => {
- if (err) {
- // Handle errors appropriately
- reject(err);
- } else {
- resolve();
- }
- });
- });
- }
-
- private validateSearchParam(param: SessionSearchParam): void {
- if (param.sessionID) {
- return;
- } else if (!param.sessionID && param.sessionPublicKey && param.sessionValidationModule) {
- return;
- } else {
- throw new Error("Either pass sessionId or a combination of sessionPublicKey and sessionValidationModule address.");
- }
- }
-
- // Session store is in the form of mekrleRoot and leafnodes, each object will have a root and an array of leafNodes.
- private async getSessionStore(): Promise {
- // eslint-disable-next-line no-useless-catch
- try {
- const data = await this.readDataFromFile("sessions");
- return data || { merkleRoot: "", leafNodes: [] };
- } catch (error) {
- // Handle errors appropriately
- throw error;
- }
- }
-
- private async getSignerStore(): Promise {
- // eslint-disable-next-line no-useless-catch
- try {
- const data = await this.readDataFromFile("signers");
- return data || {};
- } catch (error) {
- // Handle errors appropriately
- throw error;
- }
- }
-
- private getStorageKey(type: "sessions" | "signers"): string {
- return `${this.smartAccountAddress}_${type}`;
- }
-
- private toLowercaseAddress(address: string): Hex {
- return address.toLowerCase() as Hex;
- }
-
- async getSessionData(param: SessionSearchParam): Promise {
- const sessions = (await this.getSessionStore()).leafNodes;
- const session = sessions.find((s: SessionLeafNode) => {
- if (param.sessionID) {
- return s.sessionID === param.sessionID && (!param.status || s.status === param.status);
- } else if (param.sessionPublicKey && param.sessionValidationModule) {
- return (
- s.sessionPublicKey === this.toLowercaseAddress(param.sessionPublicKey) &&
- s.sessionValidationModule === this.toLowercaseAddress(param.sessionValidationModule) &&
- (!param.status || s.status === param.status)
- );
- } else {
- return undefined;
- }
- });
-
- if (!session) {
- throw new Error("Session not found.");
- }
- return session;
- }
-
- async addSessionData(leaf: SessionLeafNode): Promise {
- Logger.log("Add session Data", leaf);
- const data = await this.getSessionStore();
- leaf.sessionValidationModule = this.toLowercaseAddress(leaf.sessionValidationModule);
- leaf.sessionPublicKey = this.toLowercaseAddress(leaf.sessionPublicKey);
- data.leafNodes.push(leaf);
- await this.writeDataToFile(data, "sessions"); // Use 'sessions' as the type
- }
-
- async updateSessionStatus(param: SessionSearchParam, status: SessionStatus): Promise {
- this.validateSearchParam(param);
-
- const data = await this.getSessionStore();
- const session = data.leafNodes.find((s: SessionLeafNode) => {
- if (param.sessionID) {
- return s.sessionID === param.sessionID;
- } else if (param.sessionPublicKey && param.sessionValidationModule) {
- return (
- s.sessionPublicKey === this.toLowercaseAddress(param.sessionPublicKey) &&
- s.sessionValidationModule === this.toLowercaseAddress(param.sessionValidationModule)
- );
- } else {
- return undefined;
- }
- });
-
- if (!session) {
- throw new Error("Session not found.");
- }
-
- session.status = status;
- await this.writeDataToFile(data, "sessions"); // Use 'sessions' as the type
- }
-
- async clearPendingSessions(): Promise {
- const data = await this.getSessionStore();
- data.leafNodes = data.leafNodes.filter((s: SessionLeafNode) => s.status !== "PENDING");
- await this.writeDataToFile(data, "sessions"); // Use 'sessions' as the type
- }
-
- async addSigner(signerData: SignerData): Promise {
- const signers = await this.getSignerStore();
- let signer: SignerData;
- if (!signerData) {
- const pkey = generatePrivateKey();
- signer = {
- pvKey: pkey,
- pbKey: privateKeyToAccount(pkey).publicKey,
- };
- } else {
- signer = signerData;
- }
- const accountSigner = privateKeyToAccount(signer.pvKey);
- const viemChain = getChain(signerData?.chainId?.id || 1);
- const client = createWalletClient({
- account: accountSigner,
- chain: signerData.chainId,
- transport: http(viemChain.rpcUrls.default.http[0]),
- });
- const walletClientSigner: SmartAccountSigner = new WalletClientSigner(
- client,
- "json-rpc", // signerType
- );
- signers[this.toLowercaseAddress(accountSigner.address)] = {
- pvKey: signer.pvKey,
- pbKey: signer.pbKey,
- };
- await this.writeDataToFile(signers, "signers"); // Use 'signers' as the type
- return walletClientSigner;
- }
-
- async getSignerByKey(sessionPublicKey: string): Promise {
- const signers = await this.getSignerStore();
- Logger.log("Got signers", signers);
-
- const signerData: SignerData = signers[this.toLowercaseAddress(sessionPublicKey)];
- if (!signerData) {
- throw new Error("Signer not found.");
- }
- Logger.log(signerData.pvKey, "PVKEY");
-
- const signer = privateKeyToAccount(signerData.pvKey);
- const walletClient = createWalletClient({
- account: signer,
- transport: http(polygonMumbai.rpcUrls.default.http[0]),
- });
- return new WalletClientSigner(walletClient, "json-rpc");
- }
-
- async getSignerBySession(param: SessionSearchParam): Promise {
- const session = await this.getSessionData(param);
- Logger.log("got session", session);
- const walletClientSinger = await this.getSignerByKey(session.sessionPublicKey);
- return walletClientSinger;
- }
-
- async getAllSessionData(param?: SessionSearchParam): Promise {
- const sessions = (await this.getSessionStore()).leafNodes;
- if (!param || !param.status) {
- return sessions;
- }
- return sessions.filter((s: SessionLeafNode) => s.status === param.status);
- }
-
- async getMerkleRoot(): Promise {
- return (await this.getSessionStore()).merkleRoot;
- }
-
- async setMerkleRoot(merkleRoot: string): Promise {
- const data = await this.getSessionStore();
- data.merkleRoot = merkleRoot;
- await this.writeDataToFile(data, "sessions"); // Use 'sessions' as the type
- }
-}
diff --git a/packages/modules/tests/utils/sessionStorageData/.gitkeep b/packages/modules/tests/utils/sessionStorageData/.gitkeep
deleted file mode 100644
index e69de29bb..000000000
diff --git a/packages/modules/tsconfig.build.json b/packages/modules/tsconfig.build.json
deleted file mode 100644
index 4ac8b8026..000000000
--- a/packages/modules/tsconfig.build.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "$schema": "https://json.schemastore.org/tsconfig",
- "display": "Build",
- "compilerOptions": {
- "lib": ["es2022", "dom"],
- "target": "es2021",
- "types": ["node"],
- "allowJs": false,
- "skipLibCheck": true,
- "esModuleInterop": true,
- "allowSyntheticDefaultImports": true,
- "strict": true,
- "forceConsistentCasingInFileNames": true,
- "module": "esnext",
- "moduleResolution": "node",
- "resolveJsonModule": true,
- "isolatedModules": true,
- "verbatimModuleSyntax": false,
- "useDefineForClassFields": true,
- "noFallthroughCasesInSwitch": true,
- "noImplicitReturns": true,
- "useUnknownInCatchVariables": true,
- "noUnusedLocals": true,
- "noUnusedParameters": true,
- "declaration": true,
- "inlineSources": true,
- "noEmit": false,
- "sourceMap": true
- },
- "exclude": ["**/*/node_modules", "**/*/tests", "tests"],
- "include": ["src"]
-}
\ No newline at end of file
diff --git a/packages/modules/tsconfig.json b/packages/modules/tsconfig.json
deleted file mode 100644
index adc19ded0..000000000
--- a/packages/modules/tsconfig.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "extends": "../../tsconfig.settings.json",
- "compilerOptions": {
- "composite": true,
- "outDir": "dist",
- "baseUrl": "src",
- "resolveJsonModule": true,
- "esModuleInterop": true,
- "lib": ["es2020"],
- "types": ["node"],
- },
- "include": ["src", "src/**/*.json"]
-}
diff --git a/packages/particle-auth/.esbuild.js b/packages/particle-auth/.esbuild.js
deleted file mode 100644
index ca355e346..000000000
--- a/packages/particle-auth/.esbuild.js
+++ /dev/null
@@ -1,58 +0,0 @@
-const esbuildPluginTsc = require("esbuild-plugin-tsc");
-const esbuild = require("esbuild");
-const { dependencies, peerDependencies = {} } = require("./package.json");
-const { Generator } = require("npm-dts");
-
-const COMMON_SETTINGS = {
- entryPoints: ["src/index.ts"],
- minify: true,
- bundle: true,
- plugins: [esbuildPluginTsc({ force: true })],
-};
-
-const ESM_SETTINGS = {
- ...COMMON_SETTINGS,
- sourcemap: true,
- outfile: "dist/esm/index.js",
- platform: "browser",
- target: "esnext",
- format: "esm",
- mainFields: ["browser", "module", "main"],
-};
-const buildForESM = async () => await esbuild.build(ESM_SETTINGS);
-
-const CJS_SETTINGS = {
- ...COMMON_SETTINGS,
- format: "cjs",
- sourcemap: false,
- outfile: "dist/cjs/index.js",
- platform: "node",
-};
-
-const watchForCJS = async () => {
- let ctx = await esbuild.context(CJS_SETTINGS);
- await ctx.watch();
- await ctx.serve({ servedir: "dist/src" });
- console.log("watching...");
-};
-
-const buildForCJS = async () => await esbuild.build(CJS_SETTINGS);
-const buildForTYP = async () => await new Generator({ entry: "src/index.ts", output: "dist/types/index.d.ts" }).generate();
-
-(async () => {
- const buildType = process.argv.slice(2)[0];
- const shouldWatch = process.argv.slice(3)[0] === "--watch";
- if (!buildType) {
- console.log("No build type provided");
- process.exit(1);
- }
- console.log(`Building for ${buildType}`);
- if (buildType === "ESM") {
- await buildForESM();
- } else if (buildType === "CJS") {
- console.log("watching? " + shouldWatch);
- await (shouldWatch ? watchForCJS : buildForCJS)();
- } else if (buildType === "TYP") {
- await buildForTYP();
- }
-})();
diff --git a/packages/particle-auth/CHANGELOG.md b/packages/particle-auth/CHANGELOG.md
deleted file mode 100644
index 9ebd16ef1..000000000
--- a/packages/particle-auth/CHANGELOG.md
+++ /dev/null
@@ -1,66 +0,0 @@
-# Change Log
-
-All notable changes to this project will be documented in this file.
-See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
-
-## 4.1.1 (2023-07-03)
-
-VERSION Bump Only.
-
-## 4.1.0 (2023-04-03)
-
-VERSION Bump Only.
-
-## 4.0.3 (2023-28-02)
-
-Fix build
-
-## 4.0.2 (2023-12-28)
-
-Fix build
-
-## 4.0.1 (2023-02-22)
-
-VERSION Bump Only.
-
-## 4.0.0 (2023-12-28)
-
-VERSION Bump Only.
-
-## 3.1.3 (2023-12-28)
-
-VERSION Bump Only.
-
-## 3.1.2 (2023-12-28)
-
-VERSION Bump Only.
-
-## 3.1.1 (2023-11-09)
-
-### Features
-
-- Upgrade package version ([])(https://github.com/bcnmy/biconomy-client-sdk/commit/d467b85)
-
-## 3.1.0 (2023-09-20)
-
-Version Bump Only.
-
-# 3.0.0 (2023-08-28)
-
-### Features
-
-- particle auth integration ([7b8fb1d](https://github.com/bcnmy/biconomy-client-sdk/commit/7b8fb1d05e3cc0196bc15806fa48100701af181e))
-
-## 3.0.0-alpha.0 (2023-07-12)
-
-## 2.0.1 (2023-06-10)
-
-### Bug Fixes
-
-- typo ([0a63ff1](https://github.com/bcnmy/biconomy-client-sdk/commit/0a63ff17bb38b1bc2fd68669b74c2efd5a959d31))
-
-## 2.0.0 (2023-30-05)
-
-### Features
-
-- particle-auth ([7b8fb1d](https://github.com/bcnmy/biconomy-client-sdk/commit/7b8fb1d05e3cc0196bc15806fa48100701af181e))
diff --git a/packages/particle-auth/README.md b/packages/particle-auth/README.md
deleted file mode 100644
index 8d3a34187..000000000
--- a/packages/particle-auth/README.md
+++ /dev/null
@@ -1,41 +0,0 @@
-# `@biconomy/particle-auth`
-
-> A library to import the particle-auth for web directly from [Biconomy SDK](https://github.com/bcnmy/biconomy-client-sdk)
-
-## Usage
-
-```ts
-import { ParticleNetwork, WalletEntryPosition } from "@biconomy/particle-auth";
-import { ParticleProvider } from "@biconomy/particle-auth";
-import Web3 from "web3";
-
-const particle = new ParticleNetwork({
- projectId: "xx",
- clientKey: "xx",
- appId: "xx",
- chainName: "Ethereum", //optional: current chain name, default Ethereum.
- chainId: 1, //optional: current chain id, default 1.
- wallet: {
- //optional: by default, the wallet entry is displayed in the bottom right corner of the webpage.
- displayWalletEntry: true, //show wallet entry when connect particle.
- defaultWalletEntryPosition: WalletEntryPosition.BR, //wallet entry position
- uiMode: "dark", //optional: light or dark, if not set, the default is the same as web auth.
- supportChains: [
- { id: 1, name: "Ethereum" },
- { id: 5, name: "Ethereum" },
- ], // optional: web wallet support chains.
- customStyle: {}, //optional: custom wallet style
- },
-});
-
-const particleProvider = new ParticleProvider(particle.auth);
-
-//if you use web3.js
-window.web3 = new Web3(particleProvider);
-window.web3.currentProvider.isParticleNetwork; // => true
-
-//if you use ethers.js
-import { ethers } from "ethers";
-const ethersProvider = new ethers.providers.Web3Provider(particleProvider, "any");
-const ethersSigner = ethersProvider.getSigner();
-```
diff --git a/packages/particle-auth/package.json b/packages/particle-auth/package.json
deleted file mode 100644
index 87f407661..000000000
--- a/packages/particle-auth/package.json
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "name": "@biconomy/particle-auth",
- "version": "4.1.1",
- "description": "Particle auth for Biconomy SDK",
- "main": "./dist/cjs/index.js",
- "module": "./dist/esm/index.js",
- "types": "./dist/types/index.d.ts",
- "typings": "./dist/types/index.d.ts",
- "exports": {
- ".": {
- "import": "./dist/esm/index.js",
- "types": "./dist/types/index.d.ts",
- "default": "./dist/cjs/index.js"
- },
- "./package.json": "./package.json"
- },
- "keywords": [
- "legos",
- "batching",
- "one-click",
- "cross-chain",
- "particle",
- "particle-auth"
- ],
- "author": "Biconomy",
- "homepage": "https://github.com/bcnmy/biconomy-client-sdk#readme",
- "license": "MIT",
- "files": [
- "dist/*",
- "README.md"
- ],
- "repository": {
- "type": "git",
- "url": "git+https://github.com/bcnmy/biconomy-client-sdk.git"
- },
- "scripts": {
- "unbuild": "rimraf dist *.tsbuildinfo",
- "build:watch": "yarn build:tsc --watch",
- "dist:minify": "esbuild ./dist/esm/**/*.js ./dist/esm/*.js --minify --outdir=./dist/esm --bundle=false --allow-overwrite",
- "build": "yarn unbuild && yarn build:tsc",
- "build:esbuild": "yarn build:esbuild:cjs && yarn build:esbuild:esm && yarn build:typ",
- "build:tsc:cjs": "tsc --project tsconfig.build.json --module commonjs --outDir ./dist/cjs --removeComments --verbatimModuleSyntax false && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'",
- "build:tsc:esm": "tsc --project tsconfig.build.json --module esnext --outDir ./dist/esm --removeComments && echo > ./dist/esm/package.json '{\"type\":\"module\"}'",
- "build:esbuild:cjs": "node .esbuild.js CJS && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'",
- "build:esbuild:esm": "node .esbuild.js ESM && echo > ./dist/esm/package.json '{\"type\":\"module\"}'",
- "build:typ": "tsc --project tsconfig.build.json --module esnext --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap",
- "build:tsc": "yarn build:tsc:cjs && yarn build:tsc:esm && yarn build:typ && yarn dist:minify",
- "format": "prettier --write \"{src,tests}/**/*.ts\"",
- "lint": "tslint -p tsconfig.json"
- },
- "bugs": {
- "url": "https://github.com/bcnmy/biconomy-client-sdk/issues"
- },
- "publishConfig": {
- "access": "public"
- },
- "dependencies": {
- "@particle-network/auth": "^1.2.1",
- "@particle-network/biconomy": "^1.0.0",
- "@particle-network/provider": "^1.2.0"
- },
- "devDependencies": {
- "@types/node": "^20.11.10",
- "esbuild": "^0.19.11",
- "esbuild-plugin-tsc": "^0.4.0",
- "npm-dts": "^1.3.12"
- }
-}
diff --git a/packages/particle-auth/src/index.ts b/packages/particle-auth/src/index.ts
deleted file mode 100644
index 03966301b..000000000
--- a/packages/particle-auth/src/index.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-import * as ParticleAuth from "@particle-network/auth";
-import * as BiconomyAccount from "@particle-network/biconomy";
-export { ParticleProvider, ParticleDelegateProvider } from "@particle-network/provider";
-export { ParticleAuth as ParticleAuthModule, BiconomyAccount as BiconomyAccountModule };
diff --git a/packages/particle-auth/tests/particle-auth.spec.ts b/packages/particle-auth/tests/particle-auth.spec.ts
deleted file mode 100644
index 97866f6b6..000000000
--- a/packages/particle-auth/tests/particle-auth.spec.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-describe("Particle Auth Tests", () => {
- it("should have a basic test", () => {
- expect(true).toBe(true);
- });
-});
diff --git a/packages/particle-auth/tsconfig.build.json b/packages/particle-auth/tsconfig.build.json
deleted file mode 100644
index 4ac8b8026..000000000
--- a/packages/particle-auth/tsconfig.build.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "$schema": "https://json.schemastore.org/tsconfig",
- "display": "Build",
- "compilerOptions": {
- "lib": ["es2022", "dom"],
- "target": "es2021",
- "types": ["node"],
- "allowJs": false,
- "skipLibCheck": true,
- "esModuleInterop": true,
- "allowSyntheticDefaultImports": true,
- "strict": true,
- "forceConsistentCasingInFileNames": true,
- "module": "esnext",
- "moduleResolution": "node",
- "resolveJsonModule": true,
- "isolatedModules": true,
- "verbatimModuleSyntax": false,
- "useDefineForClassFields": true,
- "noFallthroughCasesInSwitch": true,
- "noImplicitReturns": true,
- "useUnknownInCatchVariables": true,
- "noUnusedLocals": true,
- "noUnusedParameters": true,
- "declaration": true,
- "inlineSources": true,
- "noEmit": false,
- "sourceMap": true
- },
- "exclude": ["**/*/node_modules", "**/*/tests", "tests"],
- "include": ["src"]
-}
\ No newline at end of file
diff --git a/packages/particle-auth/tsconfig.json b/packages/particle-auth/tsconfig.json
deleted file mode 100644
index cda17a184..000000000
--- a/packages/particle-auth/tsconfig.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "extends": "../../tsconfig.settings.json",
- "compilerOptions": {
- "composite": true,
- "outDir": "dist",
- "baseUrl": "src",
- "resolveJsonModule": true,
- "esModuleInterop": true,
- "lib": ["es2020"],
- },
- "include": ["src", "src/**/*.json"]
-}
diff --git a/packages/paymaster/.esbuild.js b/packages/paymaster/.esbuild.js
deleted file mode 100644
index ca355e346..000000000
--- a/packages/paymaster/.esbuild.js
+++ /dev/null
@@ -1,58 +0,0 @@
-const esbuildPluginTsc = require("esbuild-plugin-tsc");
-const esbuild = require("esbuild");
-const { dependencies, peerDependencies = {} } = require("./package.json");
-const { Generator } = require("npm-dts");
-
-const COMMON_SETTINGS = {
- entryPoints: ["src/index.ts"],
- minify: true,
- bundle: true,
- plugins: [esbuildPluginTsc({ force: true })],
-};
-
-const ESM_SETTINGS = {
- ...COMMON_SETTINGS,
- sourcemap: true,
- outfile: "dist/esm/index.js",
- platform: "browser",
- target: "esnext",
- format: "esm",
- mainFields: ["browser", "module", "main"],
-};
-const buildForESM = async () => await esbuild.build(ESM_SETTINGS);
-
-const CJS_SETTINGS = {
- ...COMMON_SETTINGS,
- format: "cjs",
- sourcemap: false,
- outfile: "dist/cjs/index.js",
- platform: "node",
-};
-
-const watchForCJS = async () => {
- let ctx = await esbuild.context(CJS_SETTINGS);
- await ctx.watch();
- await ctx.serve({ servedir: "dist/src" });
- console.log("watching...");
-};
-
-const buildForCJS = async () => await esbuild.build(CJS_SETTINGS);
-const buildForTYP = async () => await new Generator({ entry: "src/index.ts", output: "dist/types/index.d.ts" }).generate();
-
-(async () => {
- const buildType = process.argv.slice(2)[0];
- const shouldWatch = process.argv.slice(3)[0] === "--watch";
- if (!buildType) {
- console.log("No build type provided");
- process.exit(1);
- }
- console.log(`Building for ${buildType}`);
- if (buildType === "ESM") {
- await buildForESM();
- } else if (buildType === "CJS") {
- console.log("watching? " + shouldWatch);
- await (shouldWatch ? watchForCJS : buildForCJS)();
- } else if (buildType === "TYP") {
- await buildForTYP();
- }
-})();
diff --git a/packages/paymaster/CHANGELOG.md b/packages/paymaster/CHANGELOG.md
deleted file mode 100644
index f4db34b38..000000000
--- a/packages/paymaster/CHANGELOG.md
+++ /dev/null
@@ -1,78 +0,0 @@
-# Change Log
-
-All notable changes to this project will be documented in this file.
-See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
-
-## 4.1.1 (2023-07-03)
-
-VERSION Bump Only.
-
-## 4.1.0 (2023-04-03)
-
-VERSION Bump Only.
-
-## 4.0.3 (2023-28-02)
-
-VERSION Bump Only.
-
-## 4.0.2 (2023-26-02)
-
-VERSION Bump Only.
-
-## 4.0.1 (2023-02-22)
-
-VERSION Bump Only.
-
-## 4.0.0 (2023-07-02)
-
-Export createPaymaster alias for static Paymaster.create call
-
-## 3.1.3 (2023-12-28)
-
-VERSION Bump Only.
-
-## 3.1.2 (2023-12-28)
-
-VERSION Bump Only.
-
-## 3.1.1 (2023-11-09)
-
-### Bug Fixes
-
-- lint warning and errors ([2135498](https://github.com/bcnmy/biconomy-client-sdk/commit/2135498896beb54d25add820c1521ffa22d5db7c))
-
-## 3.1.0 (2023-09-20)
-
-Version Bump Only.
-
-## 3.0.0 (2023-08-28)
-
-Modular SDK - consists stable version of below updates done in Alphas.
-
-## 3.0.0-alpha.0 (2023-08-02)
-
-### Features
-
-- letting maxFee and maxPriority not be undefined([46b985c](https://github.com/bcnmy/biconomy-client-sdk/commit/46b985c75fd135f151c9ac4380a65438cccc6f39))
-- passing on paymasterAndData([ae267f1])(https://github.com/bcnmy/biconomy-client-sdk/commit/ae267f1a103f37856eb233a38db7063bfcc4cb45)
-- handle undefined values([e53d4a7])(https://github.com/bcnmy/biconomy-client-sdk/commit/e53d4a78aded8c8802786173daf12b27d445d4a0)
-- handling userOp null values([c89ac42])(https://github.com/bcnmy/biconomy-client-sdk/commit/c89ac42ae1d7fd985ef2396d925cc63ec5cf926b)
-- using signature provided by userop([0c40641])(https://github.com/bcnmy/biconomy-client-sdk/commit/0c40641e4cd6133f7348bb3e3022f8ab78fe299b)
-
-# 3.1.0-alpha.0 (2023-07-24)
-
-VERSION Bump Only.
-
-## 3.0.0-alpha.0 (2023-07-12)
-
-### Bug Fixes
-
-- linting ([563befe](https://github.com/bcnmy/biconomy-client-sdk/commit/563befedcc37aee4c531e01809b47e559a33f526))
-- linting ([d2f5f1a](https://github.com/bcnmy/biconomy-client-sdk/commit/d2f5f1afadc2a561c4ef01c0821a25b9d7fe776e))
-
-### Features
-
-- covert gas limits to numbers for making pm service call ([b1fe96f](https://github.com/bcnmy/biconomy-client-sdk/commit/b1fe96f7a312ceaf7aa689939b7c69718c710dd1))
-- get fee quote or data method in biconomy paymaster ([47748a6](https://github.com/bcnmy/biconomy-client-sdk/commit/47748a6384c2b74e1d9be4d570554098e1ac02e7))
-- update responses to support calculateGasLimits flag + update interfaces ([55bbd38](https://github.com/bcnmy/biconomy-client-sdk/commit/55bbd38b4ef8acaf8da1d52e36846557b134aba4))
-- using hybrid paymaster interface ([5fc56a7](https://github.com/bcnmy/biconomy-client-sdk/commit/5fc56a7db2de4a3f4bb87cd4d75584e79010b206))
diff --git a/packages/paymaster/Readme.md b/packages/paymaster/Readme.md
deleted file mode 100644
index 562a790f6..000000000
--- a/packages/paymaster/Readme.md
+++ /dev/null
@@ -1,74 +0,0 @@
-# **Paymaster**
-
-ERC4337, Account abstraction, introduces the concept of Paymasters. These specialised entities play a pivotal role in revolutionising the traditional gas payment system in EVM transactions. Paymasters, acting as third-party intermediaries, possess the capability to sponsor gas fees for an account, provided specific predefined conditions are satisfied.
-
-## Installation
-
-Using `npm` package manager
-
-```bash
-npm i @biconomy/paymaster
-```
-
-OR
-
-Using `yarn` package manager
-
-```bash
-yarn add @biconomy/paymaster
-```
-
-**Usage**
-
-```typescript
-// This is how you create paymaster instance in your dapp's
-import { IPaymaster, createPaymaster } from "@biconomy/paymaster";
-
-// Currently this package only exports Biconomy Paymaster which acts as a Hybrid paymaster for gas abstraction. You can sponsor user transactions but can also make users pay gas in supported ERC20 tokens.
-
-const paymaster = await createPaymaster({
- paymasterUrl: "", // you can get this value from biconomy dashboard. https://dashboard.biconomy.io
-});
-```
-
-**paymasterUrl** you can get this value from biconomy dashboard.
-
-Following are the methods that can be called on paymaster instance
-
-```typescript
-export interface IHybridPaymaster extends IPaymaster {
- getPaymasterAndData(userOp: Partial, paymasterServiceData?: T): Promise;
- buildTokenApprovalTransaction(tokenPaymasterRequest: BiconomyTokenPaymasterRequest): Promise;
- getPaymasterFeeQuotesOrData(userOp: Partial, paymasterServiceData: FeeQuotesOrDataDto): Promise;
-}
-```
-
-One can also build their own Paymaster API class and submit a PR or just provide instance of it in the account package / use standalone to generate paymasterAndData
-
-It should follow below Interface.
-
-```typescript
-export interface IPaymaster {
- // Implementing class may add extra parameter (for example paymasterServiceData with it's own type) in below function signature
- getPaymasterAndData(userOp: Partial): Promise;
- getDummyPaymasterAndData(userOp: Partial): Promise;
-}
-```
-
-### Below API methods can be used for Biconomy Hybrid paymaster
-
-**[getPaymasterAndData](https://bcnmy.github.io/biconomy-client-sdk/classes/Paymaster.html#getPaymasterAndData)**
-
-This function accepts a **`Partial`** object that includes all properties of **`userOp`** except for the **`signature`** and **`paymasterAndData`** field. It returns **`paymasterAndData`** as part of the **`PaymasterAndDataResponse`**
-
-**[buildTokenApprovalTransaction](https://bcnmy.github.io/biconomy-client-sdk/classes/Paymaster.html#buildTokenApprovalTransaction)**
-
-This function is specifically used for token paymaster sponsorship. The primary purpose of this function is to create an approve transaction for paymaster that gets batched with the rest of your transactions.
-
-Note: You don't need to call this function. It will automatically get called as part of the **`buildTokenPaymasterUserOp`** function call.
-
-**[getPaymasterFeeQuotesOrData](https://bcnmy.github.io/biconomy-client-sdk/classes/Paymaster.html#getPaymasterFeeQuotesOrData)**
-
-This function is used to fetch quote information or paymaster data based on provided userOperation and paymasterServiceData. If explicit mode is not provided it tries for sponsorship first and then falls back to serving fee quotes for supported/requested token/s
-
-Note: This function can return **paymasterAndData** as well in case all of the policies checks get passed.
diff --git a/packages/paymaster/package.json b/packages/paymaster/package.json
deleted file mode 100644
index 2b6008747..000000000
--- a/packages/paymaster/package.json
+++ /dev/null
@@ -1,66 +0,0 @@
-{
- "name": "@biconomy/paymaster",
- "version": "4.1.1",
- "description": "Biconomy Paymaster to interact with Paymaster Services that interacts with ( veriying and token ) paymasters",
- "main": "./dist/cjs/index.js",
- "module": "./dist/esm/index.js",
- "types": "./dist/types/index.d.ts",
- "typings": "./dist/types/index.d.ts",
- "exports": {
- ".": {
- "import": "./dist/esm/index.js",
- "types": "./dist/types/index.d.ts",
- "default": "./dist/cjs/index.js"
- },
- "./package.json": "./package.json"
- },
- "keywords": [
- "Ethereum",
- "Veriying Paymaster",
- "Token Paymaster",
- "ERC4337",
- "Gasless Transaction",
- "Biconomy",
- "SDK"
- ],
- "scripts": {
- "unbuild": "rimraf dist *.tsbuildinfo",
- "build:watch": "yarn build:tsc --watch",
- "dist:minify": "esbuild ./dist/esm/**/*.js ./dist/esm/*.js --minify --outdir=./dist/esm --bundle=false --allow-overwrite",
- "build": "yarn unbuild && yarn build:tsc",
- "build:esbuild": "yarn build:esbuild:cjs && yarn build:esbuild:esm && yarn build:typ",
- "build:tsc:cjs": "tsc --project tsconfig.build.json --module commonjs --outDir ./dist/cjs --removeComments --verbatimModuleSyntax false && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'",
- "build:tsc:esm": "tsc --project tsconfig.build.json --module esnext --outDir ./dist/esm --removeComments && echo > ./dist/esm/package.json '{\"type\":\"module\"}'",
- "build:esbuild:cjs": "node .esbuild.js CJS && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'",
- "build:esbuild:esm": "node .esbuild.js ESM && echo > ./dist/esm/package.json '{\"type\":\"module\"}'",
- "build:typ": "tsc --project tsconfig.build.json --module esnext --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap",
- "build:tsc": "yarn build:tsc:cjs && yarn build:tsc:esm && yarn build:typ && yarn dist:minify",
- "format": "prettier --write \"{src,tests}/**/*.ts\"",
- "lint": "tslint -p tsconfig.json",
- "test": "jest tests/**/*.spec.ts --runInBand"
- },
- "author": "Biconomy",
- "repository": {
- "type": "git",
- "url": "git+https://github.com/bcnmy/biconomy-client-sdk.git"
- },
- "license": "MIT",
- "files": [
- "dist/*",
- "README.md"
- ],
- "publishConfig": {
- "access": "public"
- },
- "dependencies": {
- "@alchemy/aa-core": "^3.1.1",
- "@biconomy/common": "^4.1.1",
- "viem": "^2.7.12"
- },
- "devDependencies": {
- "@types/node": "^20.11.10",
- "esbuild": "^0.19.11",
- "esbuild-plugin-tsc": "^0.4.0",
- "npm-dts": "^1.3.12"
- }
-}
diff --git a/packages/paymaster/src/index.ts b/packages/paymaster/src/index.ts
deleted file mode 100644
index 4d78b3a0a..000000000
--- a/packages/paymaster/src/index.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { BiconomyPaymaster } from "./BiconomyPaymaster.js";
-export * from "./interfaces/IPaymaster.js";
-export * from "./interfaces/IHybridPaymaster.js";
-export * from "./utils/Types.js";
-export * from "./BiconomyPaymaster.js";
-
-export const Paymaster = BiconomyPaymaster;
-export const createPaymaster = Paymaster.create;
diff --git a/packages/paymaster/src/interfaces/IHybridPaymaster.ts b/packages/paymaster/src/interfaces/IHybridPaymaster.ts
deleted file mode 100644
index 5b73bfd5e..000000000
--- a/packages/paymaster/src/interfaces/IHybridPaymaster.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { type UserOperationStruct } from "@alchemy/aa-core";
-import {
- FeeQuotesOrDataResponse,
- BiconomyTokenPaymasterRequest,
- FeeQuotesOrDataDto,
- PaymasterAndDataResponse,
- type Transaction,
-} from "../utils/Types.js";
-import { IPaymaster } from "./IPaymaster.js";
-
-export interface IHybridPaymaster extends IPaymaster {
- getPaymasterAndData(_userOp: Partial, _paymasterServiceData?: T): Promise;
- getDummyPaymasterAndData(_userOp: Partial, _paymasterServiceData?: T): Promise;
- buildTokenApprovalTransaction(_tokenPaymasterRequest: BiconomyTokenPaymasterRequest): Promise;
- getPaymasterFeeQuotesOrData(_userOp: Partial, _paymasterServiceData: FeeQuotesOrDataDto): Promise;
-}
diff --git a/packages/paymaster/src/interfaces/IPaymaster.ts b/packages/paymaster/src/interfaces/IPaymaster.ts
deleted file mode 100644
index b9938797d..000000000
--- a/packages/paymaster/src/interfaces/IPaymaster.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { type UserOperationStruct } from "@alchemy/aa-core";
-import { PaymasterAndDataResponse } from "../utils/Types.js";
-
-export interface IPaymaster {
- // Implementing class may add extra parameter (for example paymasterServiceData with it's own type) in below function signature
- getPaymasterAndData(_userOp: Partial): Promise;
- getDummyPaymasterAndData(_userOp: Partial): Promise;
-}
diff --git a/packages/paymaster/src/utils/Types.ts b/packages/paymaster/src/utils/Types.ts
deleted file mode 100644
index 9d5f849d4..000000000
--- a/packages/paymaster/src/utils/Types.ts
+++ /dev/null
@@ -1,176 +0,0 @@
-import { BigNumberish } from "@alchemy/aa-core";
-export type Hex = `0x${string}`;
-
-export type PaymasterServiceErrorResponse = {
- jsonrpc: string;
- id: number;
- error: JsonRpcError;
-};
-
-export type JsonRpcResponse = {
- jsonrpc: string;
- id: number;
- result?: any;
- error?: JsonRpcError;
-};
-
-export type JsonRpcError = {
- code: string;
- message: string;
- data: any;
-};
-
-export type PaymasterConfig = {
- paymasterUrl: string;
- strictMode?: boolean;
-};
-
-export type SponsorUserOperationDto = {
- /** mode: sponsored or erc20 */
- mode: PaymasterMode;
- /** Always recommended, especially when using token paymaster */
- calculateGasLimits?: boolean;
- /** Expiry duration in seconds */
- expiryDuration?: number;
- /** Webhooks to be fired after user op is sent */
- webhookData?: Record;
- /** Smart account meta data */
- smartAccountInfo?: SmartAccountData;
- /** the fee-paying token address */
- feeTokenAddress?: string;
-};
-
-export type FeeQuotesOrDataDto = {
- /** mode: sponsored or erc20 */
- mode?: PaymasterMode;
- /** Expiry duration in seconds */
- expiryDuration?: number;
- /** Always recommended, especially when using token paymaster */
- calculateGasLimits?: boolean;
- /** List of tokens to be used for fee quotes, if ommitted fees for all supported will be returned */
- tokenList?: string[];
- /** preferredToken: Can be ommitted to return all quotes */
- preferredToken?: string;
- /** Webhooks to be fired after user op is sent */
- webhookData?: Record;
- /** Smart account meta data */
- smartAccountInfo?: SmartAccountData;
-};
-
-export type FeeQuoteParams = {
- tokenList?: string[];
- preferredToken?: string;
-};
-
-export type FeeTokenInfo = {
- feeTokenAddress: string;
-};
-
-export type SponsorpshipInfo = {
- /** Webhooks to be fired after user op is sent */
- webhookData?: Record;
- /** Smart account meta data */
- smartAccountInfo: SmartAccountData;
-};
-
-export type SmartAccountData = {
- /** name: Name of the smart account */
- name: string;
- /** version: Version of the smart account */
- version: string;
-};
-
-export type PaymasterFeeQuote = {
- /** symbol: Token symbol */
- symbol: string;
- /** tokenAddress: Token address */
- tokenAddress: string;
- /** decimal: Token decimal */
- decimal: number;
- logoUrl?: string;
- /** maxGasFee: in wei */
- maxGasFee: number;
- /** maxGasFee: in dollars */
- maxGasFeeUSD?: number;
- usdPayment?: number;
- /** The premium paid on the token */
- premiumPercentage: number;
- /** validUntil: Unix timestamp */
- validUntil?: number;
-};
-
-export type BiconomyTokenPaymasterRequest = {
- /** The feeQuote to be used for the transaction */
- feeQuote: PaymasterFeeQuote;
- /** The address of the spender. This is usually set to {@link FeeQuotesOrDataResponse.tokenPaymasterAddress} */
- spender: Hex;
- /** Not recommended */
- maxApproval?: boolean;
- /* skip option to patch callData if approval is already given to the paymaster */
- skipPatchCallData?: boolean;
-};
-
-export type FeeQuotesOrDataResponse = {
- /** Array of results from the paymaster */
- feeQuotes?: PaymasterFeeQuote[];
- /** Normally set to the spender in the proceeding call to send the tx */
- tokenPaymasterAddress?: Hex;
- /** Relevant Data returned from the paymaster */
- paymasterAndData?: Uint8Array | Hex;
- /* Gas overhead of this UserOperation */
- preVerificationGas?: BigNumberish;
- /* Actual gas used by the validation of this UserOperation */
- verificationGasLimit?: BigNumberish;
- /* Value used by inner account execution */
- callGasLimit?: BigNumberish;
-};
-
-export type PaymasterAndDataResponse = {
- paymasterAndData: Hex;
- /* Gas overhead of this UserOperation */
- preVerificationGas: number;
- /* Actual gas used by the validation of this UserOperation */
- verificationGasLimit: number;
- /* Value used by inner account execution */
- callGasLimit: number;
-};
-
-export enum PaymasterMode {
- ERC20 = "ERC20",
- SPONSORED = "SPONSORED",
-}
-
-// Converted to JsonRpcResponse with strict type
-export type EstimateUserOpGasResponse = {
- jsonrpc: string;
- id: number;
- result: UserOpGasResponse;
- error?: JsonRpcError;
-};
-
-export type UserOpGasResponse = {
- paymasterAndData: string;
- /* Gas overhead of this UserOperation */
- preVerificationGas: string;
- maxPriorityFeePerGas: string;
- maxFeePerGas: string;
- /* Actual gas used by the validation of this UserOperation */
- verificationGasLimit: string;
- callGasLimit: string;
-};
-
-type RequireAtLeastOne = Pick> &
- {
- [K in Keys]-?: Required> & Partial>>;
- }[Keys];
-
-type ValueOrData = RequireAtLeastOne<
- {
- value: BigNumberish | string;
- data: string;
- },
- "value" | "data"
->;
-export type Transaction = {
- to: string;
-} & ValueOrData;
diff --git a/packages/paymaster/tests/paymaster.e2e.spec.ts b/packages/paymaster/tests/paymaster.e2e.spec.ts
deleted file mode 100644
index 3a634f491..000000000
--- a/packages/paymaster/tests/paymaster.e2e.spec.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import { TestData } from "../../../tests";
-
-describe("Paymaster Unit Tests", () => {
- let mumbai: TestData;
- let baseSepolia: TestData;
-
- beforeEach(() => {
- // @ts-ignore: Comes from setup-e2e-tests
- [mumbai, baseSepolia] = testDataPerChain;
- });
-
- it("should have chain data for mumbai", () => {
- expect(mumbai).toHaveProperty("chainId");
- });
-
- it("should also have chain data for base", () => {
- expect(baseSepolia).toHaveProperty("chainId");
- });
-});
diff --git a/packages/paymaster/tests/paymaster.spec.ts b/packages/paymaster/tests/paymaster.spec.ts
deleted file mode 100644
index 0b3508a6b..000000000
--- a/packages/paymaster/tests/paymaster.spec.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import { TestData } from "../../../tests";
-
-describe("Paymaster Unit Tests", () => {
- let ganache: TestData;
-
- beforeEach(() => {
- // @ts-ignore: Comes from setup-unit-tests
- [ganache] = testDataPerChain;
- });
-
- it("should have chain data for mumbai", () => {
- expect(ganache).toHaveProperty("chainId");
- });
-});
diff --git a/packages/paymaster/tsconfig.build.json b/packages/paymaster/tsconfig.build.json
deleted file mode 100644
index 4ac8b8026..000000000
--- a/packages/paymaster/tsconfig.build.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "$schema": "https://json.schemastore.org/tsconfig",
- "display": "Build",
- "compilerOptions": {
- "lib": ["es2022", "dom"],
- "target": "es2021",
- "types": ["node"],
- "allowJs": false,
- "skipLibCheck": true,
- "esModuleInterop": true,
- "allowSyntheticDefaultImports": true,
- "strict": true,
- "forceConsistentCasingInFileNames": true,
- "module": "esnext",
- "moduleResolution": "node",
- "resolveJsonModule": true,
- "isolatedModules": true,
- "verbatimModuleSyntax": false,
- "useDefineForClassFields": true,
- "noFallthroughCasesInSwitch": true,
- "noImplicitReturns": true,
- "useUnknownInCatchVariables": true,
- "noUnusedLocals": true,
- "noUnusedParameters": true,
- "declaration": true,
- "inlineSources": true,
- "noEmit": false,
- "sourceMap": true
- },
- "exclude": ["**/*/node_modules", "**/*/tests", "tests"],
- "include": ["src"]
-}
\ No newline at end of file
diff --git a/packages/paymaster/tsconfig.json b/packages/paymaster/tsconfig.json
deleted file mode 100644
index d6269c535..000000000
--- a/packages/paymaster/tsconfig.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "extends": "../../tsconfig.settings.json",
- "compilerOptions": {
- "composite": true,
- "outDir": "dist",
- "baseUrl": "src",
- "resolveJsonModule": true,
- "esModuleInterop": true,
- "types": ["node"]
- },
- "include": ["src", "src/**/*.json"]
-}
diff --git a/packages/transak/.esbuild.js b/packages/transak/.esbuild.js
deleted file mode 100644
index ca355e346..000000000
--- a/packages/transak/.esbuild.js
+++ /dev/null
@@ -1,58 +0,0 @@
-const esbuildPluginTsc = require("esbuild-plugin-tsc");
-const esbuild = require("esbuild");
-const { dependencies, peerDependencies = {} } = require("./package.json");
-const { Generator } = require("npm-dts");
-
-const COMMON_SETTINGS = {
- entryPoints: ["src/index.ts"],
- minify: true,
- bundle: true,
- plugins: [esbuildPluginTsc({ force: true })],
-};
-
-const ESM_SETTINGS = {
- ...COMMON_SETTINGS,
- sourcemap: true,
- outfile: "dist/esm/index.js",
- platform: "browser",
- target: "esnext",
- format: "esm",
- mainFields: ["browser", "module", "main"],
-};
-const buildForESM = async () => await esbuild.build(ESM_SETTINGS);
-
-const CJS_SETTINGS = {
- ...COMMON_SETTINGS,
- format: "cjs",
- sourcemap: false,
- outfile: "dist/cjs/index.js",
- platform: "node",
-};
-
-const watchForCJS = async () => {
- let ctx = await esbuild.context(CJS_SETTINGS);
- await ctx.watch();
- await ctx.serve({ servedir: "dist/src" });
- console.log("watching...");
-};
-
-const buildForCJS = async () => await esbuild.build(CJS_SETTINGS);
-const buildForTYP = async () => await new Generator({ entry: "src/index.ts", output: "dist/types/index.d.ts" }).generate();
-
-(async () => {
- const buildType = process.argv.slice(2)[0];
- const shouldWatch = process.argv.slice(3)[0] === "--watch";
- if (!buildType) {
- console.log("No build type provided");
- process.exit(1);
- }
- console.log(`Building for ${buildType}`);
- if (buildType === "ESM") {
- await buildForESM();
- } else if (buildType === "CJS") {
- console.log("watching? " + shouldWatch);
- await (shouldWatch ? watchForCJS : buildForCJS)();
- } else if (buildType === "TYP") {
- await buildForTYP();
- }
-})();
diff --git a/packages/transak/CHANGELOG.md b/packages/transak/CHANGELOG.md
deleted file mode 100644
index 4af2afc36..000000000
--- a/packages/transak/CHANGELOG.md
+++ /dev/null
@@ -1,62 +0,0 @@
-# Change Log
-
-All notable changes to this project will be documented in this file.
-See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
-
-## 4.1.1 (2023-07-03)
-
-VERSION Bump Only.
-
-## 4.1.0 (2023-04-03)
-
-VERSION Bump Only.
-
-## 4.0.3 (2023-28-02)
-
-VERSION Bump Only.
-
-## 4.0.2 (2023-26-02)
-
-VERSION Bump Only.
-
-## 4.0.1 (2023-26-02)
-
-VERSION Bump Only.
-
-## 4.0.0 (2023-12-28)
-
-VERSION Bump Only.
-
-## 3.1.3 (2023-12-28)
-
-VERSION Bump Only.
-
-## 3.1.2 (2023-12-28)
-
-VERSION Bump Only.
-
-## 3.1.1 (2023-11-09)
-
-VERSION Bump Only.
-
-## 3.1.0 (2023-09-20)
-
-### Bug Fixes
-
-- lint warning and errors ([2135498](https://github.com/bcnmy/biconomy-client-sdk/commit/2135498896beb54d25add820c1521ffa22d5db7c))
-
-# 3.0.0 (2023-08-28)
-
-VERSION Bump Only.
-
-## 2.0.0 (2023-04-07)
-
-### Features
-
-- transak wrapper module ([102e6eb](https://github.com/bcnmy/biconomy-client-sdk/commit/102e6eb5f179e4aff77d1e91973e0b32fa7b8f9a))
-
-## 1.0.0 (2023-01-03)
-
-### Features
-
-- transak wrapper module ([102e6eb](https://github.com/bcnmy/biconomy-client-sdk/commit/102e6eb5f179e4aff77d1e91973e0b32fa7b8f9a))
diff --git a/packages/transak/README.md b/packages/transak/README.md
deleted file mode 100644
index ea5b73266..000000000
--- a/packages/transak/README.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# `@biconomy/transak`
-
-> A library to import the transak for web directly from [Biconomy SDK](https://github.com/bcnmy/biconomy-client-sdk)
-
-## Usage
-
-No need to create api key from transak dashboard.
-
-```ts
-import Transak from "@biconomy/transak";
-const transak = new Transak("STAGING");
-transak.init();
-```
diff --git a/packages/transak/package.json b/packages/transak/package.json
deleted file mode 100644
index 4232ed243..000000000
--- a/packages/transak/package.json
+++ /dev/null
@@ -1,65 +0,0 @@
-{
- "name": "@biconomy/transak",
- "version": "4.1.1",
- "description": "transak for biconomy sdk",
- "main": "./dist/cjs/index.js",
- "module": "./dist/esm/index.js",
- "types": "./dist/types/index.d.ts",
- "typings": "./dist/types/index.d.ts",
- "exports": {
- ".": {
- "import": "./dist/esm/index.js",
- "types": "./dist/types/index.d.ts",
- "default": "./dist/cjs/index.js"
- },
- "./package.json": "./package.json"
- },
- "keywords": [
- "legos",
- "batching",
- "one-click",
- "cross-chain",
- "transak"
- ],
- "author": "Biconomy",
- "homepage": "https://github.com/bcnmy/biconomy-client-sdk#readme",
- "license": "MIT",
- "files": [
- "dist/*",
- "README.md"
- ],
- "repository": {
- "type": "git",
- "url": "git+https://github.com/bcnmy/biconomy-client-sdk.git"
- },
- "scripts": {
- "unbuild": "rimraf dist *.tsbuildinfo",
- "build:watch": "yarn build:tsc --watch",
- "dist:minify": "esbuild ./dist/esm/**/*.js ./dist/esm/*.js --minify --outdir=./dist/esm --bundle=false --allow-overwrite",
- "build": "yarn unbuild && yarn build:tsc",
- "build:esbuild": "yarn build:esbuild:cjs && yarn build:esbuild:esm && yarn build:typ",
- "build:tsc:cjs": "tsc --project tsconfig.build.json --module commonjs --outDir ./dist/cjs --removeComments --verbatimModuleSyntax false && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'",
- "build:tsc:esm": "tsc --project tsconfig.build.json --module esnext --outDir ./dist/esm --removeComments && echo > ./dist/esm/package.json '{\"type\":\"module\"}'",
- "build:esbuild:cjs": "node .esbuild.js CJS && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'",
- "build:esbuild:esm": "node .esbuild.js ESM && echo > ./dist/esm/package.json '{\"type\":\"module\"}'",
- "build:typ": "tsc --project tsconfig.build.json --module esnext --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap",
- "build:tsc": "yarn build:tsc:cjs && yarn build:tsc:esm && yarn build:typ && yarn dist:minify",
- "format": "prettier --write \"{src,tests}/**/*.ts\"",
- "lint": "tslint -p tsconfig.json"
- },
- "bugs": {
- "url": "https://github.com/bcnmy/biconomy-client-sdk/issues"
- },
- "publishConfig": {
- "access": "public"
- },
- "dependencies": {
- "@transak/transak-sdk": "^1.2.3"
- },
- "devDependencies": {
- "@types/node": "^20.11.10",
- "esbuild": "^0.19.11",
- "esbuild-plugin-tsc": "^0.4.0",
- "npm-dts": "^1.3.12"
- }
-}
diff --git a/packages/transak/src/index.ts b/packages/transak/src/index.ts
deleted file mode 100644
index 36f5dcfd9..000000000
--- a/packages/transak/src/index.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-/* eslint-disable @typescript-eslint/ban-ts-comment */
-// @ts-ignore
-import transakSDK from "@transak/transak-sdk";
-import { ITransakDto, environments } from "./interface.js";
-
-class TransakSDK {
- apiKey: string;
-
- /* eslint-disable @typescript-eslint/no-explicit-any */
- transak: any;
-
- constructor(environment: environments, transakData: ITransakDto = {}) {
- if (environment === "PRODUCTION") {
- this.apiKey = "f7d64c91-8f89-4018-9577-9098e42290af";
- } else {
- this.apiKey = "c71ecd4a-0819-46a7-8d63-c8b7148aaf63";
- }
- const transak = new transakSDK({
- apiKey: this.apiKey,
- widgetHeight: "625px",
- widgetWidth: "500px",
- environment: environment,
- ...transakData,
- });
- this.transak = transak;
- }
-
- init(): void {
- try {
- this.transak.init();
- /* eslint-disable @typescript-eslint/no-explicit-any */
- } catch (err: any) {
- throw new Error(`Error while init transakSDK ${err}`);
- }
- }
-
- getTransak(): any {
- return this.transak;
- }
-}
-
-export default TransakSDK;
diff --git a/packages/transak/src/interface.ts b/packages/transak/src/interface.ts
deleted file mode 100644
index fd1218340..000000000
--- a/packages/transak/src/interface.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-export type environments = "PRODUCTION" | "STAGING";
-
-export interface IConfigBasic {
- // apiKey: string
- // environment: environments
- redirectURL?: string;
- cryptoCurrencyCode?: string;
- fiatCurrencyCode?: string;
- themeColor?: string;
- defaultCryptoCurrency?: string;
- defaultFiatCurrency?: string;
- walletAddress?: string;
- fiatAmount?: number;
- defaultFiatAmount?: number;
- defaultCryptoAmount?: number;
- fiatCurrency?: string;
- countryCode?: string;
- paymentMethod?: string;
- defaultPaymentMethod?: string;
- isAutoFillUserData?: boolean;
- isFeeCalculationHidden?: boolean;
- email?: string;
- disablePaymentMethods?: string;
- partnerOrderId?: string;
- partnerCustomerId?: string;
- exchangeScreenTitle?: string;
- hideMenu?: boolean;
- accessToken?: string;
- hideExchangeScreen?: boolean;
- isDisableCrypto?: boolean;
- disableWalletAddressForm?: boolean;
- defaultNetwork?: string;
- network?: string;
- widgetWidth?: string | number;
- widgetHeight?: string | number;
-}
-
-export interface ITransakDto extends IConfigBasic {
- networks?: string;
- cryptoCurrencyList?: string;
- userData?: {
- firstName: string;
- lastName: string;
- email: string;
- mobileNumber: string;
- dob: string;
- address: {
- addressLine1: string;
- addressLine2: string;
- city: string;
- state: string;
- postCode: string;
- countryCode: string;
- };
- };
- walletAddressesData?: {
- networks?: {
- [key: string]: { address: string; addressAdditionalData?: string };
- };
- coins?: {
- [key: string]: { address: string; addressAdditionalData?: string };
- };
- };
-}
diff --git a/packages/transak/tests/transak.spec.ts b/packages/transak/tests/transak.spec.ts
deleted file mode 100644
index 4c5cad00c..000000000
--- a/packages/transak/tests/transak.spec.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-describe("Transak Tests", () => {
- it("should have a basic test", () => {
- expect(true).toBe(true);
- });
-});
diff --git a/packages/transak/tsconfig.build.json b/packages/transak/tsconfig.build.json
deleted file mode 100644
index 4ac8b8026..000000000
--- a/packages/transak/tsconfig.build.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "$schema": "https://json.schemastore.org/tsconfig",
- "display": "Build",
- "compilerOptions": {
- "lib": ["es2022", "dom"],
- "target": "es2021",
- "types": ["node"],
- "allowJs": false,
- "skipLibCheck": true,
- "esModuleInterop": true,
- "allowSyntheticDefaultImports": true,
- "strict": true,
- "forceConsistentCasingInFileNames": true,
- "module": "esnext",
- "moduleResolution": "node",
- "resolveJsonModule": true,
- "isolatedModules": true,
- "verbatimModuleSyntax": false,
- "useDefineForClassFields": true,
- "noFallthroughCasesInSwitch": true,
- "noImplicitReturns": true,
- "useUnknownInCatchVariables": true,
- "noUnusedLocals": true,
- "noUnusedParameters": true,
- "declaration": true,
- "inlineSources": true,
- "noEmit": false,
- "sourceMap": true
- },
- "exclude": ["**/*/node_modules", "**/*/tests", "tests"],
- "include": ["src"]
-}
\ No newline at end of file
diff --git a/packages/transak/tsconfig.json b/packages/transak/tsconfig.json
deleted file mode 100644
index d9b305a9a..000000000
--- a/packages/transak/tsconfig.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "extends": "../../tsconfig.settings.json",
- "compilerOptions": {
- "composite": true,
- "outDir": "dist",
- "baseUrl": "src",
- "resolveJsonModule": true,
- "esModuleInterop": true,
- "lib": ["es2020"],
- "types": ["node"]
- },
- "include": ["src", "src/**/*.json"]
-}
diff --git a/rebuild.sh b/rebuild.sh
deleted file mode 100755
index 39c4c1a94..000000000
--- a/rebuild.sh
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/bin/sh
-rm -rf package-lock.json
-rm -rf yarn.lock
-rm -rf node_modules
-
-rm -rf packages/account/node_modules
-rm -rf packages/account/yarn.lock
-rm -rf packages/account/package-lock.json
-rm -rf packages/account/dist
-
-rm -rf packages/bundler/node_modules
-rm -rf packages/bundler/yarn.lock
-rm -rf packages/bundler/package-lock.json
-rm -rf packages/bundler/dist
-
-rm -rf packages/common/node_modules
-rm -rf packages/common/yarn.lock
-rm -rf packages/common/package-lock.json
-rm -rf packages/common/dist
-
-rm -rf packages/paymaster/node_modules
-rm -rf packages/paymaster/yarn.lock
-rm -rf packages/paymaster/package-lock.json
-rm -rf packages/paymaster/dist
-
-rm -rf packages/modules/node_modules
-rm -rf packages/modules/yarn.lock
-rm -rf packages/modules/package-lock.json
-rm -rf packages/modules/dist
-
-rm -rf packages/transak/node_modules
-rm -rf packages/transak/yarn.lock
-rm -rf packages/transak/package-lock.json
-rm -rf packages/transak/dist
-
-rm -rf packages/particle-auth/node_modules
-rm -rf packages/particle-auth/yarn.lock
-rm -rf packages/particle-auth/package-lock.json
-rm -rf packages/particle-auth/dist
-
-#npx lerna bootstrap --force-local
-#npm run build
-#npm link
\ No newline at end of file
diff --git a/src/account/BaseSmartContractAccount.ts b/src/account/BaseSmartContractAccount.ts
new file mode 100644
index 000000000..c6b0568ff
--- /dev/null
+++ b/src/account/BaseSmartContractAccount.ts
@@ -0,0 +1,354 @@
+import {
+ http,
+ type Address,
+ type GetContractReturnType,
+ type Hash,
+ type Hex,
+ type PublicClient,
+ createPublicClient,
+ getContract,
+ trim
+} from "viem"
+import { EntryPointAbi } from "./abi/EntryPointAbi.js"
+import { Logger, type SmartAccountSigner, getChain } from "./index.js"
+import { DEFAULT_ENTRYPOINT_ADDRESS } from "./utils/Constants.js"
+import type {
+ BasSmartContractAccountProps,
+ BatchUserOperationCallData,
+ ISmartContractAccount,
+ SignTypedDataParams
+} from "./utils/Types.js"
+import { wrapSignatureWith6492 } from "./utils/Utils.js"
+
+export enum DeploymentState {
+ UNDEFINED = "0x0",
+ NOT_DEPLOYED = "0x1",
+ DEPLOYED = "0x2"
+}
+
+export abstract class BaseSmartContractAccount<
+ TSigner extends SmartAccountSigner = SmartAccountSigner
+> implements ISmartContractAccount
+{
+ protected factoryAddress: Address
+
+ protected deploymentState: DeploymentState = DeploymentState.UNDEFINED
+
+ protected accountAddress?: Address
+
+ protected accountInitCode?: Hex
+
+ protected signer: TSigner
+
+ protected entryPoint: GetContractReturnType<
+ typeof EntryPointAbi,
+ PublicClient
+ >
+
+ protected entryPointAddress: Address
+
+ readonly rpcProvider: PublicClient
+
+ constructor(params: BasSmartContractAccountProps) {
+ this.entryPointAddress =
+ params.entryPointAddress ?? DEFAULT_ENTRYPOINT_ADDRESS
+
+ this.rpcProvider = createPublicClient({
+ chain: params.viemChain ?? getChain(params.chainId),
+ transport: http(
+ params.rpcUrl || getChain(params.chainId).rpcUrls.default.http[0]
+ )
+ }) as PublicClient
+
+ this.accountAddress = params.accountAddress
+ this.factoryAddress = params.factoryAddress
+ this.signer = params.signer as TSigner
+ this.accountInitCode = params.initCode
+
+ this.entryPoint = getContract({
+ address: this.entryPointAddress,
+ abi: EntryPointAbi,
+ client: this.rpcProvider as PublicClient
+ })
+ }
+
+ //#region abstract-methods
+
+ /**
+ * This method should return a signature that will not `revert` during validation.
+ * It does not have to pass validation, just not cause the contract to revert.
+ * This is required for gas estimation so that the gas estimate are accurate.
+ *
+ */
+ abstract getDummySignature(): Hash
+
+ /**
+ * this method should return the abi encoded function data for a call to your contract's `execute` method
+ *
+ * @param target -- equivalent to `to` in a normal transaction
+ * @param value -- equivalent to `value` in a normal transaction
+ * @param data -- equivalent to `data` in a normal transaction
+ * @returns abi encoded function data for a call to your contract's `execute` method
+ */
+ abstract encodeExecute(
+ target: string,
+ value: bigint,
+ data: string
+ ): Promise
+
+ /**
+ * this should return an ERC-191 compliant message and is used to sign UO Hashes
+ *
+ * @param msg -- the message to sign
+ */
+ abstract signMessage(msg: string | Uint8Array): Promise
+
+ /**
+ * this should return the init code that will be used to create an account if one does not exist.
+ * This is the concatenation of the account's factory address and the abi encoded function data of the account factory's `createAccount` method.
+ * https://github.com/eth-infinitism/account-abstraction/blob/abff2aca61a8f0934e533d0d352978055fddbd96/contracts/core/SenderCreator.sol#L12
+ */
+ protected abstract getAccountInitCode(): Promise
+
+ //#endregion abstract-methods
+
+ //#region optional-methods
+
+ /**
+ * If your account handles 1271 signatures of personal_sign differently
+ * than it does UserOperations, you can implement two different approaches to signing
+ *
+ * @param uoHash -- The hash of the UserOperation to sign
+ * @returns the signature of the UserOperation
+ */
+ async signUserOperationHash(uoHash: Hash): Promise {
+ return this.signMessage(uoHash)
+ }
+
+ /**
+ * If your contract supports signing and verifying typed data,
+ * you should implement this method.
+ *
+ * @param _params -- Typed Data params to sign
+ */
+ async signTypedData(_params: SignTypedDataParams): Promise<`0x${string}`> {
+ throw new Error("signTypedData not supported")
+ }
+
+ /**
+ * This method should wrap the result of `signMessage` as per
+ * [EIP-6492](https://eips.ethereum.org/EIPS/eip-6492)
+ *
+ * @param msg -- the message to sign
+ */
+ async signMessageWith6492(msg: string | Uint8Array): Promise<`0x${string}`> {
+ const [isDeployed, signature] = await Promise.all([
+ this.isAccountDeployed(),
+ this.signMessage(msg)
+ ])
+
+ return this.create6492Signature(isDeployed, signature)
+ }
+
+ /**
+ * Similar to the signMessageWith6492 method above,
+ * this method should wrap the result of `signTypedData` as per
+ * [EIP-6492](https://eips.ethereum.org/EIPS/eip-6492)
+ *
+ * @param params -- Typed Data params to sign
+ */
+ async signTypedDataWith6492(
+ params: SignTypedDataParams
+ ): Promise<`0x${string}`> {
+ const [isDeployed, signature] = await Promise.all([
+ this.isAccountDeployed(),
+ this.signTypedData(params)
+ ])
+
+ return this.create6492Signature(isDeployed, signature)
+ }
+
+ /**
+ * Not all contracts support batch execution.
+ * If your contract does, this method should encode a list of
+ * transactions into the call data that will be passed to your
+ * contract's batch execution method.
+ *
+ * @param _txs -- the transactions to batch execute
+ */
+ async encodeBatchExecute(
+ _txs: BatchUserOperationCallData
+ ): Promise<`0x${string}`> {
+ throw new Error("Batch execution not supported")
+ }
+
+ /**
+ * If your contract supports UUPS, you can implement this method which can be
+ * used to upgrade the implementation of the account.
+ *
+ * @param upgradeToImplAddress -- the implementation address of the contract you want to upgrade to
+ * @param upgradeToInitData -- the initialization data required by that account
+ */
+ encodeUpgradeToAndCall = async (
+ _upgradeToImplAddress: Address,
+ _upgradeToInitData: Hex
+ ): Promise => {
+ throw new Error("Upgrade ToAndCall Not Supported")
+ }
+ //#endregion optional-methods
+
+ // Extra implementations
+ async getNonce(): Promise {
+ if (!(await this.isAccountDeployed())) {
+ return 0n
+ }
+ const address = await this.getAddress()
+ return this.entryPoint.read.getNonce([address, BigInt(0)])
+ }
+
+ async getInitCode(): Promise {
+ if (this.deploymentState === DeploymentState.DEPLOYED) {
+ return "0x"
+ }
+
+ const contractCode = await this.rpcProvider.getBytecode({
+ address: await this.getAddress()
+ })
+
+ if ((contractCode?.length ?? 0) > 2) {
+ this.deploymentState = DeploymentState.DEPLOYED
+ return "0x"
+ }
+
+ this.deploymentState = DeploymentState.NOT_DEPLOYED
+
+ return this._getAccountInitCode()
+ }
+
+ async getAddress(): Promise {
+ if (!this.accountAddress) {
+ const initCode = await this._getAccountInitCode()
+ Logger.log("[BaseSmartContractAccount](getAddress) initCode: ", initCode)
+ try {
+ await this.entryPoint.simulate.getSenderAddress([initCode])
+ } catch (err: any) {
+ Logger.log(
+ "[BaseSmartContractAccount](getAddress) getSenderAddress err: ",
+ err
+ )
+
+ if (err.cause?.data?.errorName === "SenderAddressResult") {
+ this.accountAddress = err.cause.data.args[0] as Address
+ Logger.log(
+ "[BaseSmartContractAccount](getAddress) entryPoint.getSenderAddress result:",
+ this.accountAddress
+ )
+ return this.accountAddress
+ }
+
+ if (err.details === "Invalid URL") {
+ throw new Error("Invalid URL")
+ }
+ }
+
+ throw new Error("Failed to get counterfactual account address")
+ }
+
+ return this.accountAddress
+ }
+
+ extend = (fn: (self: this) => R): this & R => {
+ const extended = fn(this) as any
+ // this should make it so extensions can't overwrite the base methods
+ for (const key in this) {
+ delete extended[key]
+ }
+ return Object.assign(this, extended)
+ }
+
+ getSigner(): TSigner {
+ return this.signer
+ }
+
+ getFactoryAddress(): Address {
+ return this.factoryAddress
+ }
+
+ getEntryPointAddress(): Address {
+ return this.entryPointAddress
+ }
+
+ async isAccountDeployed(): Promise {
+ return (await this.getDeploymentState()) === DeploymentState.DEPLOYED
+ }
+
+ async getDeploymentState(): Promise {
+ if (this.deploymentState === DeploymentState.UNDEFINED) {
+ const initCode = await this.getInitCode()
+ return initCode === "0x"
+ ? DeploymentState.DEPLOYED
+ : DeploymentState.NOT_DEPLOYED
+ }
+ return this.deploymentState
+ }
+
+ /**
+ * https://eips.ethereum.org/EIPS/eip-4337#first-time-account-creation
+ * The initCode field (if non-zero length) is parsed as a 20-byte address,
+ * followed by calldata to pass to this address.
+ * The factory address is the first 40 char after the 0x, and the callData is the rest.
+ */
+ protected async parseFactoryAddressFromAccountInitCode(): Promise<
+ [Address, Hex]
+ > {
+ const initCode = await this._getAccountInitCode()
+ const factoryAddress = `0x${initCode.substring(2, 42)}` as Address
+ const factoryCalldata = `0x${initCode.substring(42)}` as Hex
+ return [factoryAddress, factoryCalldata]
+ }
+
+ protected async getImplementationAddress(): Promise<"0x0" | Address> {
+ const accountAddress = await this.getAddress()
+
+ const storage = await this.rpcProvider.getStorageAt({
+ address: accountAddress,
+ // This is the default slot for the implementation address for Proxies
+ slot: "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc"
+ })
+
+ if (storage == null) {
+ throw new Error(
+ "Failed to get storage slot 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc"
+ )
+ }
+
+ return trim(storage)
+ }
+
+ private async _getAccountInitCode(): Promise {
+ return this.accountInitCode ?? this.getAccountInitCode()
+ }
+
+ private async create6492Signature(
+ isDeployed: boolean,
+ signature: Hash
+ ): Promise {
+ if (isDeployed) {
+ return signature
+ }
+
+ const [factoryAddress, factoryCalldata] =
+ await this.parseFactoryAddressFromAccountInitCode()
+
+ Logger.log(
+ `[BaseSmartContractAccount](create6492Signature)\
+ factoryAddress: ${factoryAddress}, factoryCalldata: ${factoryCalldata}`
+ )
+
+ return wrapSignatureWith6492({
+ factoryAddress,
+ factoryCalldata,
+ signature
+ })
+ }
+}
diff --git a/src/account/BiconomySmartAccountV2.ts b/src/account/BiconomySmartAccountV2.ts
new file mode 100644
index 000000000..b6899f1b7
--- /dev/null
+++ b/src/account/BiconomySmartAccountV2.ts
@@ -0,0 +1,1930 @@
+import {
+ http,
+ type GetContractReturnType,
+ type Hex,
+ type PublicClient,
+ concat,
+ concatHex,
+ createPublicClient,
+ decodeFunctionData,
+ encodeAbiParameters,
+ encodeFunctionData,
+ encodePacked,
+ formatUnits,
+ getContract,
+ getCreate2Address,
+ keccak256,
+ parseAbi,
+ parseAbiParameters,
+ toBytes,
+ toHex
+} from "viem"
+import type { IBundler } from "../bundler/IBundler.js"
+import {
+ Bundler,
+ type UserOpResponse,
+ extractChainIdFromBundlerUrl
+} from "../bundler/index.js"
+import {
+ BaseValidationModule,
+ type ModuleInfo,
+ type SendUserOpParams,
+ createECDSAOwnershipValidationModule
+} from "../modules"
+import {
+ BiconomyPaymaster,
+ type FeeQuotesOrDataDto,
+ type FeeQuotesOrDataResponse,
+ type IHybridPaymaster,
+ type IPaymaster,
+ Paymaster,
+ PaymasterMode,
+ type SponsorUserOperationDto
+} from "../paymaster"
+import {
+ type BigNumberish,
+ Logger,
+ type SmartAccountSigner,
+ type StateOverrideSet,
+ type UserOperationStruct,
+ convertSigner,
+ getChain
+} from "./"
+import { BaseSmartContractAccount } from "./BaseSmartContractAccount.js"
+import { AccountResolverAbi } from "./abi/AccountResolver.js"
+import { BiconomyFactoryAbi } from "./abi/Factory.js"
+import { BiconomyAccountAbi } from "./abi/SmartAccount.js"
+import {
+ ADDRESS_RESOLVER_ADDRESS,
+ ADDRESS_ZERO,
+ BICONOMY_IMPLEMENTATION_ADDRESSES_BY_VERSION,
+ DEFAULT_BICONOMY_FACTORY_ADDRESS,
+ DEFAULT_ENTRYPOINT_ADDRESS,
+ DEFAULT_FALLBACK_HANDLER_ADDRESS,
+ ERC20_ABI,
+ ERROR_MESSAGES,
+ MAGIC_BYTES,
+ NATIVE_TOKEN_ALIAS,
+ PROXY_CREATION_CODE
+} from "./utils/Constants.js"
+import type {
+ BalancePayload,
+ BatchUserOperationCallData,
+ BiconomySmartAccountV2Config,
+ BiconomySmartAccountV2ConfigConstructorProps,
+ BiconomyTokenPaymasterRequest,
+ BuildUserOpOptions,
+ CounterFactualAddressParam,
+ NonceOptions,
+ PaymasterUserOperationDto,
+ QueryParamsForAddressResolver,
+ SimulationType,
+ SupportedToken,
+ Transaction,
+ WithdrawalRequest
+} from "./utils/Types.js"
+import {
+ addressEquals,
+ compareChainIds,
+ isNullOrUndefined,
+ isValidRpcUrl,
+ packUserOp
+} from "./utils/Utils.js"
+
+type UserOperationKey = keyof UserOperationStruct
+
+export class BiconomySmartAccountV2 extends BaseSmartContractAccount {
+ private SENTINEL_MODULE = "0x0000000000000000000000000000000000000001"
+
+ private index: number
+
+ private chainId: number
+
+ private provider: PublicClient
+
+ paymaster?: IPaymaster
+
+ bundler?: IBundler
+
+ private accountContract?: GetContractReturnType<
+ typeof BiconomyAccountAbi,
+ PublicClient
+ >
+
+ private defaultFallbackHandlerAddress: Hex
+
+ private implementationAddress: Hex
+
+ private scanForUpgradedAccountsFromV1!: boolean
+
+ private maxIndexForScan!: number
+
+ // Validation module responsible for account deployment initCode. This acts as a default authorization module.
+ defaultValidationModule!: BaseValidationModule
+
+ // Deployed Smart Account can have more than one module enabled. When sending a transaction activeValidationModule is used to prepare and validate userOp signature.
+ activeValidationModule!: BaseValidationModule
+
+ private constructor(
+ readonly biconomySmartAccountConfig: BiconomySmartAccountV2ConfigConstructorProps
+ ) {
+ super({
+ ...biconomySmartAccountConfig,
+ chain:
+ biconomySmartAccountConfig.viemChain ??
+ getChain(biconomySmartAccountConfig.chainId),
+ rpcClient:
+ biconomySmartAccountConfig.rpcUrl ||
+ getChain(biconomySmartAccountConfig.chainId).rpcUrls.default.http[0],
+ entryPointAddress:
+ (biconomySmartAccountConfig.entryPointAddress as Hex) ??
+ DEFAULT_ENTRYPOINT_ADDRESS,
+ accountAddress:
+ (biconomySmartAccountConfig.accountAddress as Hex) ?? undefined,
+ factoryAddress:
+ biconomySmartAccountConfig.factoryAddress ??
+ DEFAULT_BICONOMY_FACTORY_ADDRESS
+ })
+
+ this.defaultValidationModule =
+ biconomySmartAccountConfig.defaultValidationModule
+ this.activeValidationModule =
+ biconomySmartAccountConfig.activeValidationModule
+
+ this.index = biconomySmartAccountConfig.index ?? 0
+ this.chainId = biconomySmartAccountConfig.chainId
+ this.bundler = biconomySmartAccountConfig.bundler
+ this.implementationAddress =
+ biconomySmartAccountConfig.implementationAddress ??
+ (BICONOMY_IMPLEMENTATION_ADDRESSES_BY_VERSION.V2_0_0 as Hex)
+
+ if (biconomySmartAccountConfig.paymasterUrl) {
+ this.paymaster = new Paymaster({
+ paymasterUrl: biconomySmartAccountConfig.paymasterUrl
+ })
+ } else if (biconomySmartAccountConfig.biconomyPaymasterApiKey) {
+ this.paymaster = new Paymaster({
+ paymasterUrl: `https://paymaster.biconomy.io/api/v1/${biconomySmartAccountConfig.chainId}/${biconomySmartAccountConfig.biconomyPaymasterApiKey}`
+ })
+ } else {
+ this.paymaster = biconomySmartAccountConfig.paymaster
+ }
+
+ this.bundler = biconomySmartAccountConfig.bundler
+
+ const defaultFallbackHandlerAddress =
+ this.factoryAddress === DEFAULT_BICONOMY_FACTORY_ADDRESS
+ ? DEFAULT_FALLBACK_HANDLER_ADDRESS
+ : biconomySmartAccountConfig.defaultFallbackHandler
+ if (!defaultFallbackHandlerAddress) {
+ throw new Error("Default Fallback Handler address is not provided")
+ }
+ this.defaultFallbackHandlerAddress = defaultFallbackHandlerAddress
+
+ // Added bang operator to avoid null check as the constructor have these params as optional
+ this.defaultValidationModule =
+ // biome-ignore lint/style/noNonNullAssertion:
+ biconomySmartAccountConfig.defaultValidationModule!
+ this.activeValidationModule =
+ // biome-ignore lint/style/noNonNullAssertion:
+ biconomySmartAccountConfig.activeValidationModule!
+
+ this.provider = createPublicClient({
+ chain:
+ biconomySmartAccountConfig.viemChain ??
+ getChain(biconomySmartAccountConfig.chainId),
+ transport: http(
+ biconomySmartAccountConfig.rpcUrl ||
+ getChain(biconomySmartAccountConfig.chainId).rpcUrls.default.http[0]
+ )
+ })
+
+ this.scanForUpgradedAccountsFromV1 =
+ biconomySmartAccountConfig.scanForUpgradedAccountsFromV1 ?? false
+ this.maxIndexForScan = biconomySmartAccountConfig.maxIndexForScan ?? 10
+ }
+
+ /**
+ * Creates a new instance of BiconomySmartAccountV2
+ *
+ * This method will create a BiconomySmartAccountV2 instance but will not deploy the Smart Account
+ * Deployment of the Smart Account will be donewith the first user operation.
+ *
+ * - Docs: https://docs.biconomy.io/Account/integration#integration-1
+ *
+ * @param biconomySmartAccountConfig - Configuration for initializing the BiconomySmartAccountV2 instance.
+ * @returns A promise that resolves to a new instance of BiconomySmartAccountV2.
+ * @throws An error if something is wrong with the smart account instance creation.
+ *
+ * @example
+ * import { createClient } from "viem"
+ * import { createSmartAccountClient, BiconomySmartAccountV2 } from "@biconomy/account"
+ * import { createWalletClient, http } from "viem";
+ * import { polygonAmoy } from "viem/chains";
+ *
+ * const signer = createWalletClient({
+ * account,
+ * chain: polygonAmoy,
+ * transport: http(),
+ * });
+ *
+ * const bundlerUrl = "" // Retrieve bundler url from dashboard
+ *
+ * const smartAccountFromStaticCreate = await BiconomySmartAccountV2.create({ signer, bundlerUrl });
+ *
+ * // Is the same as...
+ *
+ * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl });
+ *
+ */
+ public static async create(
+ biconomySmartAccountConfig: BiconomySmartAccountV2Config
+ ): Promise {
+ let chainId = biconomySmartAccountConfig.chainId
+ let rpcUrl = biconomySmartAccountConfig.rpcUrl
+ let resolvedSmartAccountSigner!: SmartAccountSigner
+
+ // Signer needs to be initialised here before defaultValidationModule is set
+ if (biconomySmartAccountConfig.signer) {
+ const signerResult = await convertSigner(
+ biconomySmartAccountConfig.signer,
+ !!chainId,
+ rpcUrl
+ )
+ if (!chainId && !!signerResult.chainId) {
+ chainId = signerResult.chainId
+ }
+ if (!rpcUrl && !!signerResult.rpcUrl) {
+ if (isValidRpcUrl(signerResult.rpcUrl)) {
+ rpcUrl = signerResult.rpcUrl
+ }
+ }
+ resolvedSmartAccountSigner = signerResult.signer
+ }
+ if (!chainId) {
+ // Get it from bundler
+ if (biconomySmartAccountConfig.bundlerUrl) {
+ chainId = extractChainIdFromBundlerUrl(
+ biconomySmartAccountConfig.bundlerUrl
+ )
+ } else if (biconomySmartAccountConfig.bundler) {
+ const bundlerUrlFromBundler =
+ biconomySmartAccountConfig.bundler.getBundlerUrl()
+ chainId = extractChainIdFromBundlerUrl(bundlerUrlFromBundler)
+ }
+ }
+ if (!chainId) {
+ throw new Error("chainId required")
+ }
+ const bundler: IBundler =
+ biconomySmartAccountConfig.bundler ??
+ new Bundler({
+ // biome-ignore lint/style/noNonNullAssertion:
+ bundlerUrl: biconomySmartAccountConfig.bundlerUrl!,
+ chainId
+ })
+ let defaultValidationModule =
+ biconomySmartAccountConfig.defaultValidationModule
+
+ // Note: If no module is provided, we will use ECDSA_OWNERSHIP as default
+ if (!defaultValidationModule) {
+ const newModule = await createECDSAOwnershipValidationModule({
+ // biome-ignore lint/style/noNonNullAssertion:
+ signer: resolvedSmartAccountSigner!
+ })
+ defaultValidationModule = newModule
+ }
+ const activeValidationModule =
+ biconomySmartAccountConfig?.activeValidationModule ??
+ defaultValidationModule
+ if (!resolvedSmartAccountSigner) {
+ resolvedSmartAccountSigner = await activeValidationModule.getSigner()
+ }
+ if (!resolvedSmartAccountSigner) {
+ throw new Error("signer required")
+ }
+ const config: BiconomySmartAccountV2ConfigConstructorProps = {
+ ...biconomySmartAccountConfig,
+ defaultValidationModule,
+ activeValidationModule,
+ chainId,
+ bundler,
+ signer: resolvedSmartAccountSigner,
+ rpcUrl
+ }
+
+ // We check if chain ids match (skip this if chainId is passed by in the config)
+ // This check is at the end of the function for cases when the signer is not passed in the config but a validation modules is and we get the signer from the validation module in this case
+ if (!biconomySmartAccountConfig.chainId) {
+ await compareChainIds(
+ biconomySmartAccountConfig.signer || resolvedSmartAccountSigner,
+ config,
+ false
+ )
+ }
+
+ return new BiconomySmartAccountV2(config)
+ }
+
+ // Calls the getCounterFactualAddress
+ override async getAddress(params?: CounterFactualAddressParam): Promise {
+ if (this.accountAddress == null) {
+ // means it needs deployment
+ this.accountAddress = await this.getCounterFactualAddress(params)
+ }
+ return this.accountAddress
+ }
+
+ // Calls the getCounterFactualAddress
+ async getAccountAddress(
+ params?: CounterFactualAddressParam
+ ): Promise<`0x${string}`> {
+ if (this.accountAddress == null || this.accountAddress === undefined) {
+ // means it needs deployment
+ this.accountAddress = await this.getCounterFactualAddress(params)
+ }
+ return this.accountAddress
+ }
+
+ /**
+ * Returns an upper estimate for the gas spent on a specific user operation
+ *
+ * This method will fetch an approximate gas estimate for the user operation, given the current state of the network.
+ * It is regularly an overestimate, and the actual gas spent will likely be lower.
+ * It is unlikely to be an underestimate unless the network conditions rapidly change.
+ *
+ * @param transactions Array of {@link Transaction} to be sent.
+ * @param buildUseropDto {@link BuildUserOpOptions}.
+ * @returns Promise - The estimated gas cost in wei.
+ *
+ * @example
+ * import { createClient } from "viem"
+ * import { createSmartAccountClient } from "@biconomy/account"
+ * import { createWalletClient, http } from "viem";
+ * import { polygonAmoy } from "viem/chains";
+ *
+ * const signer = createWalletClient({
+ * account,
+ * chain: polygonAmoy,
+ * transport: http(),
+ * });
+ *
+ * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl, paymasterUrl }); // Retrieve bundler/paymaster url from dashboard
+ * const encodedCall = encodeFunctionData({
+ * abi: parseAbi(["function safeMint(address to) public"]),
+ * functionName: "safeMint",
+ * args: ["0x..."],
+ * });
+ *
+ * const tx = {
+ * to: nftAddress,
+ * data: encodedCall
+ * }
+ *
+ * const amountInWei = await smartAccount.getGasEstimates([tx, tx], {
+ * paymasterServiceData: {
+ * mode: PaymasterMode.SPONSORED,
+ * },
+ * });
+ *
+ * console.log(amountInWei.toString());
+ *
+ */
+ public async getGasEstimate(
+ transactions: Transaction[],
+ buildUseropDto?: BuildUserOpOptions
+ ): Promise {
+ const {
+ callGasLimit,
+ preVerificationGas,
+ verificationGasLimit,
+ maxFeePerGas
+ } = await this.buildUserOp(transactions, buildUseropDto)
+
+ const _callGasLimit = BigInt(callGasLimit || 0)
+ const _preVerificationGas = BigInt(preVerificationGas || 0)
+ const _verificationGasLimit = BigInt(verificationGasLimit || 0)
+ const _maxFeePerGas = BigInt(maxFeePerGas || 0)
+
+ if (!buildUseropDto?.paymasterServiceData?.mode) {
+ return (
+ (_callGasLimit + _preVerificationGas + _verificationGasLimit) *
+ _maxFeePerGas
+ )
+ }
+ return (
+ (_callGasLimit +
+ BigInt(3) * _verificationGasLimit +
+ _preVerificationGas) *
+ _maxFeePerGas
+ )
+ }
+
+ /**
+ * Returns balances for the smartAccount instance.
+ *
+ * This method will fetch tokens info given an array of token addresses for the smartAccount instance.
+ * The balance of the native token will always be returned as the last element in the reponse array, with the address set to 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE.
+ *
+ * @param addresses - Optional. Array of asset addresses to fetch the balances of. If not provided, the method will return only the balance of the native token.
+ * @returns Promise> - An array of token balances (plus the native token balance) of the smartAccount instance.
+ *
+ * @example
+ * import { createClient } from "viem"
+ * import { createSmartAccountClient } from "@biconomy/account"
+ * import { createWalletClient, http } from "viem";
+ * import { polygonAmoy } from "viem/chains";
+ *
+ * const signer = createWalletClient({
+ * account,
+ * chain: polygonAmoy,
+ * transport: http(),
+ * });
+ *
+ * const token = "0x747A4168DB14F57871fa8cda8B5455D8C2a8e90a";
+ * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl });
+ * const [tokenBalanceFromSmartAccount, nativeTokenBalanceFromSmartAccount] = await smartAccount.getBalances([token]);
+ *
+ * console.log(tokenBalanceFromSmartAccount);
+ * // {
+ * // amount: 1000000000000000n,
+ * // decimals: 6,
+ * // address: "0x747A4168DB14F57871fa8cda8B5455D8C2a8e90a",
+ * // formattedAmount: "1000000",
+ * // chainId: 80002
+ * // }
+ *
+ * // or to get the nativeToken balance
+ *
+ * const [nativeTokenBalanceFromSmartAccount] = await smartAccount.getBalances();
+ *
+ * console.log(nativeTokenBalanceFromSmartAccount);
+ * // {
+ * // amount: 1000000000000000n,
+ * // decimals: 18,
+ * // address: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
+ * // formattedAmount: "1",
+ * // chainId: 80002
+ * // }
+ *
+ */
+ public async getBalances(
+ addresses?: Array
+ ): Promise> {
+ const accountAddress = await this.getAccountAddress()
+ const result: BalancePayload[] = []
+
+ if (addresses) {
+ const tokenContracts = addresses.map((address) =>
+ getContract({
+ address,
+ abi: parseAbi(ERC20_ABI),
+ client: this.provider
+ })
+ )
+
+ const balancePromises = tokenContracts.map((tokenContract) =>
+ tokenContract.read.balanceOf([accountAddress])
+ ) as Promise[]
+ const decimalsPromises = tokenContracts.map((tokenContract) =>
+ tokenContract.read.decimals()
+ ) as Promise[]
+ const [balances, decimalsPerToken] = await Promise.all([
+ Promise.all(balancePromises),
+ Promise.all(decimalsPromises)
+ ])
+
+ balances.forEach((amount, index) =>
+ result.push({
+ amount,
+ decimals: decimalsPerToken[index],
+ address: addresses[index],
+ formattedAmount: formatUnits(amount, decimalsPerToken[index]),
+ chainId: this.chainId
+ })
+ )
+ }
+
+ const balance = await this.provider.getBalance({ address: accountAddress })
+
+ result.push({
+ amount: balance,
+ decimals: 18,
+ address: NATIVE_TOKEN_ALIAS,
+ formattedAmount: formatUnits(balance, 18),
+ chainId: this.chainId
+ })
+
+ return result
+ }
+
+ /**
+ * Transfers funds from Smart Account to recipient (usually EOA)
+ * @param recipient - Address of the recipient
+ * @param withdrawalRequests - Array of withdrawal requests {@link WithdrawalRequest}. If withdrawal request is an empty array, it will transfer the balance of the native token. Using a paymaster will ensure no dust remains in the smart account.
+ * @param buildUseropDto - Optional. {@link BuildUserOpOptions}
+ *
+ * @returns Promise - An object containing the status of the transaction.
+ *
+ * @example
+ * import { createClient } from "viem"
+ * import { createSmartAccountClient, NATIVE_TOKEN_ALIAS } from "@biconomy/account"
+ * import { createWalletClient, http } from "viem";
+ * import { polygonMumbai } from "viem/chains";
+ *
+ * const token = "0x747A4168DB14F57871fa8cda8B5455D8C2a8e90a";
+ * const signer = createWalletClient({
+ * account,
+ * chain: polygonMumbai,
+ * transport: http(),
+ * });
+ *
+ * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl, biconomyPaymasterApiKey });
+ *
+ * const { wait } = await smartAccount.withdraw(
+ * [
+ * { address: token }, // omit the amount to withdraw the full balance
+ * { address: NATIVE_TOKEN_ALIAS, amount: BigInt(1) }
+ * ],
+ * account.address, // Default recipient used if no recipient is present in the withdrawal request
+ * {
+ * paymasterServiceData: { mode: PaymasterMode.SPONSORED },
+ * }
+ * );
+ *
+ * // OR to withdraw all of the native token, leaving no dust in the smart account
+ *
+ * const { wait } = await smartAccount.withdraw([], account.address, {
+ * paymasterServiceData: { mode: PaymasterMode.SPONSORED },
+ * });
+ *
+ * const { success } = await wait();
+ */
+ public async withdraw(
+ withdrawalRequests?: WithdrawalRequest[] | null,
+ defaultRecipient?: Hex | null,
+ buildUseropDto?: BuildUserOpOptions
+ ): Promise {
+ const accountAddress =
+ this.accountAddress ?? (await this.getAccountAddress())
+
+ if (
+ !defaultRecipient &&
+ withdrawalRequests?.some(({ recipient }) => !recipient)
+ ) {
+ throw new Error(ERROR_MESSAGES.NO_RECIPIENT)
+ }
+
+ // Remove the native token from the withdrawal requests
+ let tokenRequests =
+ withdrawalRequests?.filter(
+ ({ address }) => !addressEquals(address, NATIVE_TOKEN_ALIAS)
+ ) ?? []
+
+ // Check if the amount is not present in all withdrawal requests
+ const shouldFetchMaxBalances = tokenRequests.some(({ amount }) => !amount)
+
+ // Get the balances of the tokens if the amount is not present in the withdrawal requests
+ if (shouldFetchMaxBalances) {
+ const balances = await this.getBalances(
+ tokenRequests.map(({ address }) => address)
+ )
+ tokenRequests = tokenRequests.map(({ amount, address }, i) => ({
+ address,
+ amount: amount ?? balances[i].amount
+ }))
+ }
+
+ // Create the transactions
+ const txs: Transaction[] = tokenRequests.map(
+ ({ address, amount, recipient: recipientFromRequest }) => ({
+ to: address,
+ data: encodeFunctionData({
+ abi: parseAbi(ERC20_ABI),
+ functionName: "transfer",
+ args: [recipientFromRequest || defaultRecipient, amount]
+ })
+ })
+ )
+
+ // Check if eth alias is present in the original withdrawal requests
+ const nativeTokenRequest = withdrawalRequests?.find(({ address }) =>
+ addressEquals(address, NATIVE_TOKEN_ALIAS)
+ )
+ const hasNoRequests = !withdrawalRequests?.length
+ if (!!nativeTokenRequest || hasNoRequests) {
+ // Check that an amount is present in the withdrawal request, if no paymaster service data is present, as max amounts cannot be calculated without a paymaster.
+ if (
+ !nativeTokenRequest?.amount &&
+ !buildUseropDto?.paymasterServiceData?.mode
+ ) {
+ throw new Error(ERROR_MESSAGES.NATIVE_TOKEN_WITHDRAWAL_WITHOUT_AMOUNT)
+ }
+
+ // get eth balance if not present in withdrawal requests
+ const nativeTokenAmountToWithdraw =
+ nativeTokenRequest?.amount ??
+ (await this.provider.getBalance({ address: accountAddress }))
+
+ txs.push({
+ to: (nativeTokenRequest?.recipient ?? defaultRecipient) as Hex,
+ value: nativeTokenAmountToWithdraw
+ })
+ }
+
+ return this.sendTransaction(txs, buildUseropDto)
+ }
+
+ /**
+ * Return the account's address. This value is valid even before deploying the contract.
+ */
+ async getCounterFactualAddress(
+ params?: CounterFactualAddressParam
+ ): Promise {
+ const validationModule =
+ params?.validationModule ?? this.defaultValidationModule
+ const index = params?.index ?? this.index
+
+ const maxIndexForScan = params?.maxIndexForScan ?? this.maxIndexForScan
+ // Review: default behavior
+ const scanForUpgradedAccountsFromV1 =
+ params?.scanForUpgradedAccountsFromV1 ??
+ this.scanForUpgradedAccountsFromV1
+
+ // if it's intended to detect V1 upgraded accounts
+ if (scanForUpgradedAccountsFromV1) {
+ const eoaSigner = await validationModule.getSigner()
+ const eoaAddress = (await eoaSigner.getAddress()) as Hex
+ const moduleAddress = validationModule.getAddress() as Hex
+ const moduleSetupData = (await validationModule.getInitData()) as Hex
+ const queryParams = {
+ eoaAddress,
+ index,
+ moduleAddress,
+ moduleSetupData,
+ maxIndexForScan
+ }
+ const accountAddress = await this.getV1AccountsUpgradedToV2(queryParams)
+ if (accountAddress !== ADDRESS_ZERO) {
+ return accountAddress
+ }
+ }
+
+ const counterFactualAddressV2 = await this.getCounterFactualAddressV2({
+ validationModule,
+ index
+ })
+ return counterFactualAddressV2
+ }
+
+ private async getCounterFactualAddressV2(
+ params?: CounterFactualAddressParam
+ ): Promise {
+ const validationModule =
+ params?.validationModule ?? this.defaultValidationModule
+ const index = params?.index ?? this.index
+
+ try {
+ const initCalldata = encodeFunctionData({
+ abi: BiconomyAccountAbi,
+ functionName: "init",
+ args: [
+ this.defaultFallbackHandlerAddress,
+ validationModule.getAddress() as Hex,
+ (await validationModule.getInitData()) as Hex
+ ]
+ })
+
+ const proxyCreationCodeHash = keccak256(
+ encodePacked(
+ ["bytes", "uint256"],
+ [PROXY_CREATION_CODE, BigInt(this.implementationAddress)]
+ )
+ )
+
+ const salt = keccak256(
+ encodePacked(
+ ["bytes32", "uint256"],
+ [keccak256(initCalldata), BigInt(index)]
+ )
+ )
+
+ const counterFactualAddress = getCreate2Address({
+ from: this.factoryAddress,
+ salt: salt,
+ bytecodeHash: proxyCreationCodeHash
+ })
+
+ return counterFactualAddress
+ } catch (e) {
+ throw new Error(`Failed to get counterfactual address, ${e}`)
+ }
+ }
+
+ async _getAccountContract(): Promise<
+ GetContractReturnType
+ > {
+ if (this.accountContract == null) {
+ this.accountContract = getContract({
+ address: await this.getAddress(),
+ abi: BiconomyAccountAbi,
+ client: this.provider as PublicClient
+ })
+ }
+ return this.accountContract
+ }
+
+ isActiveValidationModuleDefined(): boolean {
+ if (!this.activeValidationModule)
+ throw new Error("Must provide an instance of active validation module.")
+ return true
+ }
+
+ isDefaultValidationModuleDefined(): boolean {
+ if (!this.defaultValidationModule)
+ throw new Error("Must provide an instance of default validation module.")
+ return true
+ }
+
+ setActiveValidationModule(
+ validationModule: BaseValidationModule
+ ): BiconomySmartAccountV2 {
+ if (validationModule instanceof BaseValidationModule) {
+ this.activeValidationModule = validationModule
+ }
+ return this
+ }
+
+ setDefaultValidationModule(
+ validationModule: BaseValidationModule
+ ): BiconomySmartAccountV2 {
+ if (validationModule instanceof BaseValidationModule) {
+ this.defaultValidationModule = validationModule
+ }
+ return this
+ }
+
+ async getV1AccountsUpgradedToV2(
+ params: QueryParamsForAddressResolver
+ ): Promise {
+ const maxIndexForScan = params.maxIndexForScan ?? this.maxIndexForScan
+
+ const addressResolver = getContract({
+ address: ADDRESS_RESOLVER_ADDRESS,
+ abi: AccountResolverAbi,
+ client: {
+ public: this.provider as PublicClient
+ }
+ })
+ // Note: depending on moduleAddress and moduleSetupData passed call this. otherwise could call resolveAddresses()
+
+ if (params.moduleAddress && params.moduleSetupData) {
+ const result = await addressResolver.read.resolveAddressesFlexibleForV2([
+ params.eoaAddress,
+ maxIndexForScan,
+ params.moduleAddress,
+ params.moduleSetupData
+ ])
+
+ const desiredV1Account = result.find(
+ (smartAccountInfo: {
+ factoryVersion: string
+ currentVersion: string
+ deploymentIndex: { toString: () => string }
+ }) =>
+ smartAccountInfo.factoryVersion === "v1" &&
+ smartAccountInfo.currentVersion === "2.0.0" &&
+ Number(smartAccountInfo.deploymentIndex.toString()) === params.index
+ )
+
+ if (desiredV1Account) {
+ const smartAccountAddress = desiredV1Account.accountAddress
+ return smartAccountAddress
+ }
+ return ADDRESS_ZERO
+ }
+ return ADDRESS_ZERO
+ }
+
+ /**
+ * Return the value to put into the "initCode" field, if the account is not yet deployed.
+ * This value holds the "factory" address, followed by this account's information
+ */
+ async getAccountInitCode(): Promise {
+ this.isDefaultValidationModuleDefined()
+
+ if (await this.isAccountDeployed()) return "0x"
+
+ return concatHex([
+ this.factoryAddress as Hex,
+ (await this.getFactoryData()) ?? "0x"
+ ])
+ }
+
+ /**
+ *
+ * @param to { target } address of transaction
+ * @param value represents amount of native tokens
+ * @param data represent data associated with transaction
+ * @returns encoded data for execute function
+ */
+ async encodeExecute(to: Hex, value: bigint, data: Hex): Promise {
+ // return accountContract.interface.encodeFunctionData("execute_ncC", [to, value, data]) as Hex;
+ return encodeFunctionData({
+ abi: BiconomyAccountAbi,
+ functionName: "execute_ncC",
+ args: [to, value, data]
+ })
+ }
+
+ /**
+ *
+ * @param to { target } array of addresses in transaction
+ * @param value represents array of amount of native tokens associated with each transaction
+ * @param data represent array of data associated with each transaction
+ * @returns encoded data for executeBatch function
+ */
+ async encodeExecuteBatch(
+ to: Array,
+ value: Array,
+ data: Array
+ ): Promise {
+ return encodeFunctionData({
+ abi: BiconomyAccountAbi,
+ functionName: "executeBatch_y6U",
+ args: [to, value, data]
+ })
+ }
+
+ override async encodeBatchExecute(
+ txs: BatchUserOperationCallData
+ ): Promise {
+ const [targets, datas, value] = txs.reduce(
+ (accum, curr) => {
+ accum[0].push(curr.target)
+ accum[1].push(curr.data)
+ accum[2].push(curr.value || BigInt(0))
+
+ return accum
+ },
+ [[], [], []] as [Hex[], Hex[], bigint[]]
+ )
+
+ return this.encodeExecuteBatch(targets, value, datas)
+ }
+
+ // dummy signature depends on the validation module supplied.
+ async getDummySignatures(params?: ModuleInfo): Promise {
+ this.isActiveValidationModuleDefined()
+ return (await this.activeValidationModule.getDummySignature(params)) as Hex
+ }
+
+ // TODO: review this
+ getDummySignature(): Hex {
+ throw new Error("Method not implemented! Call getDummySignatures instead.")
+ }
+
+ // Might use provided paymaster instance to get dummy data (from pm service)
+ getDummyPaymasterData(): string {
+ return "0x"
+ }
+
+ validateUserOp(
+ userOp: Partial,
+ requiredFields: UserOperationKey[]
+ ): boolean {
+ for (const field of requiredFields) {
+ if (isNullOrUndefined(userOp[field])) {
+ throw new Error(`${String(field)} is missing in the UserOp`)
+ }
+ }
+ return true
+ }
+
+ async signUserOp(
+ userOp: Partial,
+ params?: SendUserOpParams
+ ): Promise {
+ this.isActiveValidationModuleDefined()
+ const requiredFields: UserOperationKey[] = [
+ "sender",
+ "nonce",
+ "initCode",
+ "callData",
+ "callGasLimit",
+ "verificationGasLimit",
+ "preVerificationGas",
+ "maxFeePerGas",
+ "maxPriorityFeePerGas",
+ "paymasterAndData"
+ ]
+ this.validateUserOp(userOp, requiredFields)
+ const userOpHash = await this.getUserOpHash(userOp)
+
+ const moduleSig = (await this.activeValidationModule.signUserOpHash(
+ userOpHash,
+ params
+ )) as Hex
+
+ const signatureWithModuleAddress = this.getSignatureWithModuleAddress(
+ moduleSig,
+ this.activeValidationModule.getAddress() as Hex
+ )
+
+ userOp.signature = signatureWithModuleAddress
+ return userOp as UserOperationStruct
+ }
+
+ getSignatureWithModuleAddress(
+ moduleSignature: Hex,
+ moduleAddress?: Hex
+ ): Hex {
+ const moduleAddressToUse =
+ moduleAddress ?? (this.activeValidationModule.getAddress() as Hex)
+ return encodeAbiParameters(parseAbiParameters("bytes, address"), [
+ moduleSignature,
+ moduleAddressToUse
+ ])
+ }
+
+ public async getPaymasterUserOp(
+ userOp: Partial,
+ paymasterServiceData: PaymasterUserOperationDto
+ ): Promise> {
+ if (paymasterServiceData.mode === PaymasterMode.SPONSORED) {
+ return this.getPaymasterAndData(userOp, paymasterServiceData)
+ }
+ if (paymasterServiceData.mode === PaymasterMode.ERC20) {
+ if (paymasterServiceData?.feeQuote) {
+ const { feeQuote, spender, maxApproval = false } = paymasterServiceData
+ Logger.log("there is a feeQuote: ", JSON.stringify(feeQuote, null, 2))
+ if (!spender) throw new Error(ERROR_MESSAGES.SPENDER_REQUIRED)
+ if (!feeQuote) throw new Error(ERROR_MESSAGES.FAILED_FEE_QUOTE_FETCH)
+ if (
+ paymasterServiceData.skipPatchCallData &&
+ paymasterServiceData.skipPatchCallData === true
+ ) {
+ return this.getPaymasterAndData(userOp, {
+ ...paymasterServiceData,
+ feeTokenAddress: feeQuote.tokenAddress
+ })
+ }
+ const partialUserOp = await this.buildTokenPaymasterUserOp(userOp, {
+ ...paymasterServiceData,
+ spender,
+ maxApproval,
+ feeQuote
+ })
+ return this.getPaymasterAndData(partialUserOp, {
+ ...paymasterServiceData,
+ feeTokenAddress: feeQuote.tokenAddress,
+ calculateGasLimits: true // Always recommended and especially when using token paymaster
+ })
+ }
+ if (paymasterServiceData?.preferredToken) {
+ const { preferredToken } = paymasterServiceData
+ Logger.log("there is a preferred token: ", preferredToken)
+ const feeQuotesResponse = await this.getPaymasterFeeQuotesOrData(
+ userOp,
+ paymasterServiceData
+ )
+ const spender = feeQuotesResponse.tokenPaymasterAddress
+ const feeQuote = feeQuotesResponse.feeQuotes?.[0]
+ if (!spender) throw new Error(ERROR_MESSAGES.SPENDER_REQUIRED)
+ if (!feeQuote) throw new Error(ERROR_MESSAGES.FAILED_FEE_QUOTE_FETCH)
+ return this.getPaymasterUserOp(userOp, {
+ ...paymasterServiceData,
+ feeQuote,
+ spender
+ }) // Recursively call getPaymasterUserOp with the feeQuote
+ }
+ Logger.log(
+ "ERC20 mode without feeQuote or preferredToken provided. Passing through unchanged."
+ )
+ return userOp
+ }
+ throw new Error("Invalid paymaster mode")
+ }
+
+ private async getPaymasterAndData(
+ userOp: Partial,
+ paymasterServiceData: PaymasterUserOperationDto
+ ): Promise> {
+ const paymaster = this
+ .paymaster as IHybridPaymaster
+ const paymasterData = await paymaster.getPaymasterAndData(
+ userOp,
+ paymasterServiceData
+ )
+ return { ...userOp, ...paymasterData }
+ }
+
+ private async getPaymasterFeeQuotesOrData(
+ userOp: Partial,
+ feeQuotesOrData: FeeQuotesOrDataDto
+ ): Promise {
+ const paymaster = this
+ .paymaster as IHybridPaymaster
+ const tokenList = feeQuotesOrData?.preferredToken
+ ? [feeQuotesOrData?.preferredToken]
+ : feeQuotesOrData?.tokenList?.length
+ ? feeQuotesOrData?.tokenList
+ : []
+ return paymaster.getPaymasterFeeQuotesOrData(userOp, {
+ ...feeQuotesOrData,
+ tokenList
+ })
+ }
+
+ /**
+ *
+ * @description This function will retrieve fees from the paymaster in erc20 mode
+ *
+ * @param manyOrOneTransactions Array of {@link Transaction} to be batched and sent. Can also be a single {@link Transaction}.
+ * @param buildUseropDto {@link BuildUserOpOptions}.
+ * @returns Promise
+ *
+ * @example
+ * import { createClient } from "viem"
+ * import { createSmartAccountClient } from "@biconomy/account"
+ * import { createWalletClient, http } from "viem";
+ * import { polygonAmoy } from "viem/chains";
+ *
+ * const signer = createWalletClient({
+ * account,
+ * chain: polygonAmoy,
+ * transport: http(),
+ * });
+ *
+ * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl }); // Retrieve bundler url from dashboard
+ * const encodedCall = encodeFunctionData({
+ * abi: parseAbi(["function safeMint(address to) public"]),
+ * functionName: "safeMint",
+ * args: ["0x..."],
+ * });
+ *
+ * const transaction = {
+ * to: nftAddress,
+ * data: encodedCall
+ * }
+ *
+ * const feeQuotesResponse: FeeQuotesOrDataResponse = await smartAccount.getTokenFees(transaction, { paymasterServiceData: { mode: PaymasterMode.ERC20 } });
+ *
+ * const userSeletedFeeQuote = feeQuotesResponse.feeQuotes?.[0];
+ *
+ * const { wait } = await smartAccount.sendTransaction(transaction, {
+ * paymasterServiceData: {
+ * mode: PaymasterMode.ERC20,
+ * feeQuote: userSeletedFeeQuote,
+ * spender: feeQuotesResponse.tokenPaymasterAddress,
+ * },
+ * });
+ *
+ * const { success, receipt } = await wait();
+ *
+ */
+ public async getTokenFees(
+ manyOrOneTransactions: Transaction | Transaction[],
+ buildUseropDto: BuildUserOpOptions
+ ): Promise {
+ const txs = Array.isArray(manyOrOneTransactions)
+ ? manyOrOneTransactions
+ : [manyOrOneTransactions]
+ const userOp = await this.buildUserOp(txs, buildUseropDto)
+ if (!buildUseropDto.paymasterServiceData)
+ throw new Error("paymasterServiceData was not provided")
+ return this.getPaymasterFeeQuotesOrData(
+ userOp,
+ buildUseropDto.paymasterServiceData
+ )
+ }
+
+ /**
+ *
+ * @description This function will return an array of supported tokens from the erc20 paymaster associated with the Smart Account
+ * @returns Promise<{@link SupportedToken}>
+ *
+ * @example
+ * import { createClient } from "viem"
+ * import { createSmartAccountClient } from "@biconomy/account"
+ * import { createWalletClient, http } from "viem";
+ * import { polygonAmoy } from "viem/chains";
+ *
+ * const signer = createWalletClient({
+ * account,
+ * chain: polygonAmoy,
+ * transport: http(),
+ * });
+ *
+ * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl, biconomyPaymasterApiKey }); // Retrieve bundler url from dashboard
+ * const tokens = await smartAccount.getSupportedTokens();
+ *
+ * // [
+ * // {
+ * // symbol: "USDC",
+ * // tokenAddress: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
+ * // decimal: 6,
+ * // logoUrl: "https://assets.coingecko.com/coins/images/279/large/usd-coin.png?1595353707",
+ * // premiumPercentage: 0.1,
+ * // }
+ * // ]
+ *
+ */
+ public async getSupportedTokens(): Promise {
+ const feeQuotesResponse = await this.getTokenFees(
+ {
+ data: "0x",
+ value: BigInt(0),
+ to: await this.getAccountAddress()
+ },
+ {
+ paymasterServiceData: { mode: PaymasterMode.ERC20 }
+ }
+ )
+
+ return await Promise.all(
+ (feeQuotesResponse?.feeQuotes ?? []).map(async (quote) => {
+ const [tokenBalance] = await this.getBalances([
+ quote.tokenAddress as Hex
+ ])
+ return {
+ symbol: quote.symbol,
+ tokenAddress: quote.tokenAddress,
+ decimal: quote.decimal,
+ logoUrl: quote.logoUrl,
+ premiumPercentage: quote.premiumPercentage,
+ balance: tokenBalance
+ }
+ })
+ )
+ }
+
+ /**
+ *
+ * @param userOp
+ * @param params
+ * @description This function will take a user op as an input, sign it with the owner key, and send it to the bundler.
+ * @returns Promise
+ * Sends a user operation
+ *
+ * - Docs: https://docs.biconomy.io/Account/transactions/userpaid#send-useroperation
+ *
+ * @param userOp Partial<{@link UserOperationStruct}> the userOp params to be sent.
+ * @param params {@link SendUserOpParams}.
+ * @returns Promise<{@link UserOpResponse}> that you can use to track the user operation.
+ *
+ * @example
+ * import { createClient } from "viem"
+ * import { createSmartAccountClient } from "@biconomy/account"
+ * import { createWalletClient, http } from "viem";
+ * import { polygonAmoy } from "viem/chains";
+ *
+ * const signer = createWalletClient({
+ * account,
+ * chain: polygonAmoy,
+ * transport: http(),
+ * });
+ *
+ * const smartAccount = await createSmartAccountClient({ signer, bundlerUrl }); // Retrieve bundler url from dashboard
+ * const encodedCall = encodeFunctionData({
+ * abi: parseAbi(["function safeMint(address to) public"]),
+ * functionName: "safeMint",
+ * args: ["0x..."],
+ * });
+ *
+ * const transaction = {
+ * to: nftAddress,
+ * data: encodedCall
+ * }
+ *
+ * const userOp = await smartAccount.buildUserOp([transaction]);
+ *
+ * const { wait } = await smartAccount.sendUserOp(userOp);
+ * const { success, receipt } = await wait();
+ *
+ */
+ async sendUserOp(
+ userOp: Partial