Full Code of coinbase/wallet-mobile-sdk for AI

main 87da8726e82e cached
273 files
467.0 KB
129.7k tokens
151 symbols
1 requests
Download .txt
Showing preview only (539K chars total). Download the full file or copy to clipboard to get everything.
Repository: coinbase/wallet-mobile-sdk
Branch: main
Commit: 87da8726e82e
Files: 273
Total size: 467.0 KB

Directory structure:
gitextract_l82khy5j/

├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.yml
│   │   ├── config.yml
│   │   └── feature_request.yml
│   ├── PULL_REQUEST_TEMPLATE.md
│   └── workflows/
│       ├── publish.yml
│       ├── run_tests.yml
│       └── version_update.yml
├── .gitignore
├── CODEOWNERS
├── CoinbaseWalletSDK.podspec
├── Gemfile
├── LICENSE
├── Package.swift
├── README.md
├── android/
│   ├── README.md
│   ├── build.gradle
│   ├── example/
│   │   ├── .editorconfig
│   │   ├── .gitignore
│   │   ├── build.gradle
│   │   ├── proguard-rules.pro
│   │   └── src/
│   │       └── main/
│   │           ├── AndroidManifest.xml
│   │           ├── java/
│   │           │   └── com/
│   │           │       └── coinbase/
│   │           │           └── android/
│   │           │               └── beta/
│   │           │                   ├── ActionsManager.kt
│   │           │                   ├── MainActivity.kt
│   │           │                   └── SecondActivity.java
│   │           └── res/
│   │               ├── drawable/
│   │               │   └── ic_launcher_background.xml
│   │               ├── drawable-v24/
│   │               │   └── ic_launcher_foreground.xml
│   │               ├── layout/
│   │               │   └── activity_main.xml
│   │               ├── mipmap-anydpi-v26/
│   │               │   ├── ic_launcher.xml
│   │               │   └── ic_launcher_round.xml
│   │               ├── values/
│   │               │   ├── colors.xml
│   │               │   ├── strings.xml
│   │               │   └── themes.xml
│   │               ├── values-night/
│   │               │   └── themes.xml
│   │               └── xml/
│   │                   ├── backup_rules.xml
│   │                   └── data_extraction_rules.xml
│   ├── gradle/
│   │   ├── libs.versions.toml
│   │   └── wrapper/
│   │       ├── gradle-wrapper.jar
│   │       └── gradle-wrapper.properties
│   ├── gradle.properties
│   ├── gradlew
│   ├── gradlew.bat
│   ├── scripts/
│   │   └── publish-root.gradle
│   ├── settings.gradle
│   └── walletsdk/
│       ├── .editorconfig
│       ├── .gitignore
│       ├── build.gradle
│       ├── consumer-rules.pro
│       ├── proguard-rules.pro
│       └── src/
│           ├── androidTest/
│           │   └── java/
│           │       └── com/
│           │           └── coinbase/
│           │               └── android/
│           │                   └── nativesdk/
│           │                       └── ExampleInstrumentedTest.kt
│           ├── main/
│           │   ├── AndroidManifest.xml
│           │   └── java/
│           │       └── com/
│           │           └── coinbase/
│           │               └── android/
│           │                   └── nativesdk/
│           │                       ├── CoinbaseWalletSDK.kt
│           │                       ├── CoinbaseWalletSDKError.kt
│           │                       ├── OpenIntentCallback.kt
│           │                       ├── key/
│           │                       │   ├── KeyManager.kt
│           │                       │   ├── KeyStore.kt
│           │                       │   └── PublicKeySerializer.kt
│           │                       ├── message/
│           │                       │   ├── Cipher.kt
│           │                       │   ├── DateSerializer.kt
│           │                       │   ├── JSON.kt
│           │                       │   ├── Message.kt
│           │                       │   ├── MessageConverter.kt
│           │                       │   ├── request/
│           │                       │   │   ├── Account.kt
│           │                       │   │   ├── Action.kt
│           │                       │   │   ├── EncryptedRequestMessage.kt
│           │                       │   │   ├── RequestConverter.kt
│           │                       │   │   ├── UnencryptedRequestMessage.kt
│           │                       │   │   └── Web3JsonRPC.kt
│           │                       │   └── response/
│           │                       │       ├── ActionResult.kt
│           │                       │       ├── EncryptedResponseMessage.kt
│           │                       │       ├── Response.kt
│           │                       │       ├── ResponseCallback.kt
│           │                       │       ├── ResponseConverter.kt
│           │                       │       └── UnencryptedResponseMessage.kt
│           │                       └── task/
│           │                           ├── Task.kt
│           │                           └── TaskManager.kt
│           └── test/
│               ├── java/
│               │   └── com/
│               │       └── coinbase/
│               │           └── android/
│               │               └── nativesdk/
│               │                   ├── ExampleUnitTest.kt
│               │                   ├── helper/
│               │                   │   └── InputStreamExtensions.kt
│               │                   └── message/
│               │                       └── request/
│               │                           └── Web3JsonRPCTest.kt
│               └── resources/
│                   ├── add_chain.json
│                   ├── personal_sign.json
│                   ├── send_transaction.json
│                   ├── sign_transaction.json
│                   ├── sign_typed_data_v3.json
│                   ├── sign_typed_data_v4.json
│                   └── watch_asset.json
├── docs/
│   ├── .gitignore
│   ├── babel.config.js
│   ├── docs/
│   │   ├── client-sdk/
│   │   │   ├── android-api-reference.md
│   │   │   ├── android-establishing-a-connection.md
│   │   │   ├── android-install.md
│   │   │   ├── android-making-requests.md
│   │   │   ├── android-setup.md
│   │   │   ├── ios-api-reference.md
│   │   │   ├── ios-establishing-a-connection.md
│   │   │   ├── ios-install.md
│   │   │   ├── ios-making-requests.md
│   │   │   ├── ios-setup.md
│   │   │   └── mobile-sdk-overview.md
│   │   ├── spec/
│   │   │   ├── batch.md
│   │   │   ├── encryption.md
│   │   │   ├── handshake.md
│   │   │   ├── messages-example.md
│   │   │   ├── messages-request.md
│   │   │   ├── messages-response.md
│   │   │   ├── messages.md
│   │   │   ├── multi-chain.md
│   │   │   ├── network.md
│   │   │   └── verification.md
│   │   └── spec-overview.md
│   ├── docusaurus.config.js
│   ├── package.json
│   ├── sidebars.js
│   ├── spec.md
│   ├── src/
│   │   ├── components/
│   │   │   └── HomepageFeatures/
│   │   │       ├── index.tsx
│   │   │       └── styles.module.css
│   │   ├── css/
│   │   │   └── custom.css
│   │   └── pages/
│   │       ├── index.module.css
│   │       └── index.tsx
│   ├── static/
│   │   └── .nojekyll
│   └── tsconfig.json
├── flutter/
│   ├── .gitignore
│   ├── .metadata
│   ├── .pubignore
│   ├── .vscode/
│   │   └── settings.json
│   ├── CHANGELOG.md
│   ├── README.md
│   ├── analysis_options.yaml
│   ├── android/
│   │   ├── .gitignore
│   │   ├── build.gradle
│   │   ├── gradle/
│   │   │   └── wrapper/
│   │   │       └── gradle-wrapper.properties
│   │   ├── settings.gradle
│   │   └── src/
│   │       └── main/
│   │           ├── AndroidManifest.xml
│   │           └── kotlin/
│   │               └── com/
│   │                   └── coinbase/
│   │                       └── flutter/
│   │                           └── wallet_sdk/
│   │                               └── CoinbaseWalletSdkFlutterPlugin.kt
│   ├── example/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── analysis_options.yaml
│   │   ├── android/
│   │   │   ├── .gitignore
│   │   │   ├── app/
│   │   │   │   ├── build.gradle
│   │   │   │   └── src/
│   │   │   │       ├── debug/
│   │   │   │       │   └── AndroidManifest.xml
│   │   │   │       ├── main/
│   │   │   │       │   ├── AndroidManifest.xml
│   │   │   │       │   ├── kotlin/
│   │   │   │       │   │   └── xyz/
│   │   │   │       │   │       └── tribes/
│   │   │   │       │   │           └── coinbase/
│   │   │   │       │   │               └── coinbase_wallet_sdk_flutter_example/
│   │   │   │       │   │                   └── MainActivity.kt
│   │   │   │       │   └── res/
│   │   │   │       │       ├── drawable/
│   │   │   │       │       │   └── launch_background.xml
│   │   │   │       │       ├── drawable-v21/
│   │   │   │       │       │   └── launch_background.xml
│   │   │   │       │       ├── values/
│   │   │   │       │       │   └── styles.xml
│   │   │   │       │       └── values-night/
│   │   │   │       │           └── styles.xml
│   │   │   │       └── profile/
│   │   │   │           └── AndroidManifest.xml
│   │   │   ├── build.gradle
│   │   │   ├── gradle/
│   │   │   │   └── wrapper/
│   │   │   │       └── gradle-wrapper.properties
│   │   │   ├── gradle.properties
│   │   │   └── settings.gradle
│   │   ├── ios/
│   │   │   ├── .gitignore
│   │   │   ├── Flutter/
│   │   │   │   ├── AppFrameworkInfo.plist
│   │   │   │   ├── Debug.xcconfig
│   │   │   │   └── Release.xcconfig
│   │   │   ├── Podfile
│   │   │   ├── Runner/
│   │   │   │   ├── AppDelegate.swift
│   │   │   │   ├── Assets.xcassets/
│   │   │   │   │   ├── AppIcon.appiconset/
│   │   │   │   │   │   └── Contents.json
│   │   │   │   │   └── LaunchImage.imageset/
│   │   │   │   │       ├── Contents.json
│   │   │   │   │       └── README.md
│   │   │   │   ├── Base.lproj/
│   │   │   │   │   ├── LaunchScreen.storyboard
│   │   │   │   │   └── Main.storyboard
│   │   │   │   ├── Info.plist
│   │   │   │   └── Runner-Bridging-Header.h
│   │   │   └── Runner.xcodeproj/
│   │   │       └── project.pbxproj
│   │   ├── lib/
│   │   │   └── main.dart
│   │   ├── pubspec.yaml
│   │   └── test/
│   │       └── widget_test.dart
│   ├── ios/
│   │   ├── .gitignore
│   │   ├── Assets/
│   │   │   └── .gitkeep
│   │   ├── Classes/
│   │   │   ├── CoinbaseWalletSdkFlutterPlugin.h
│   │   │   ├── CoinbaseWalletSdkFlutterPlugin.m
│   │   │   └── SwiftCoinbaseWalletSdkFlutterPlugin.swift
│   │   └── coinbase_wallet_sdk.podspec
│   ├── lib/
│   │   ├── account.dart
│   │   ├── action.dart
│   │   ├── coinbase_wallet_sdk.dart
│   │   ├── coinbase_wallet_sdk_method_channel.dart
│   │   ├── coinbase_wallet_sdk_platform_interface.dart
│   │   ├── configuration.dart
│   │   ├── eth_web3_rpc.dart
│   │   ├── request.dart
│   │   └── return_value.dart
│   ├── pubspec.yaml
│   └── test/
│       ├── coinbase_wallet_sdk_method_channel_test.dart
│       └── coinbase_wallet_sdk_test.dart
├── ios/
│   ├── CoinbaseWalletSDK/
│   │   ├── CoinbaseWalletSDK.swift
│   │   ├── Error.swift
│   │   ├── Host/
│   │   │   ├── CoinbaseWalletHostSDK.swift
│   │   │   └── ResponseMessage+init.swift
│   │   ├── Key/
│   │   │   ├── Key+RawRepresentable.swift
│   │   │   ├── KeyManager.swift
│   │   │   ├── KeyStorage.swift
│   │   │   └── KeyStorageItem.swift
│   │   ├── Message/
│   │   │   ├── Cipher.swift
│   │   │   ├── EncryptedMessage.swift
│   │   │   ├── JSONString.swift
│   │   │   ├── Message.swift
│   │   │   ├── MessageConverter.swift
│   │   │   ├── Request/
│   │   │   │   ├── Account.swift
│   │   │   │   ├── Action.swift
│   │   │   │   ├── EncryptedRequestContent.swift
│   │   │   │   ├── Request.swift
│   │   │   │   ├── RequestMessage.swift
│   │   │   │   └── Web3JSONRPC.swift
│   │   │   ├── Response/
│   │   │   │   ├── ActionResult.swift
│   │   │   │   ├── EncryptedResponseContent.swift
│   │   │   │   └── ResponseMessage.swift
│   │   │   └── URL+extension.swift
│   │   ├── Resources/
│   │   │   └── CoinbaseWalletSDK+version.swift
│   │   ├── Task/
│   │   │   ├── Task.swift
│   │   │   └── TaskManager.swift
│   │   └── Test/
│   │       └── ExampleTest.swift
│   ├── README.md
│   └── example/
│       ├── Podfile
│       ├── README.md
│       ├── SampleClient/
│       │   ├── AppDelegate.swift
│       │   ├── Base.lproj/
│       │   │   └── Main.storyboard
│       │   ├── Info.plist
│       │   └── ViewController.swift
│       ├── SampleClient.xcodeproj/
│       │   └── project.pbxproj
│       ├── SampleWallet/
│       │   ├── AppDelegate.swift
│       │   ├── Base.lproj/
│       │   │   └── Main.storyboard
│       │   └── Info.plist
│       └── SampleWallet.xcodeproj/
│           └── project.pbxproj
└── react-native/
    ├── .eslintrc.js
    ├── .npmignore
    ├── README.md
    ├── android/
    │   ├── build.gradle
    │   ├── proguard-rules.pro
    │   └── src/
    │       └── main/
    │           ├── AndroidManifest.xml
    │           └── java/
    │               └── expo/
    │                   └── modules/
    │                       └── coinbasewalletsdkexpo/
    │                           ├── ActivityLifecycleListener.kt
    │                           ├── CoinbaseWalletSDKModule.kt
    │                           ├── CoinbaseWalletSDKPackage.kt
    │                           └── records/
    │                               ├── AccountRecord.kt
    │                               ├── ActionRecord.kt
    │                               ├── ActionResultRecord.kt
    │                               ├── ConfigParamsRecord.kt
    │                               ├── HandshakeParamsRecord.kt
    │                               └── RequestParamsRecord.kt
    ├── example/
    │   ├── .buckconfig
    │   ├── .bundle/
    │   │   └── config
    │   ├── .eslintrc.js
    │   ├── .flowconfig
    │   ├── .gitignore
    │   ├── .prettierrc.js
    │   ├── .watchmanconfig
    │   ├── App.js
    │   ├── __tests__/
    │   │   └── App-test.js
    │   ├── _node-version
    │   ├── app.json
    │   ├── babel.config.js
    │   ├── index.js
    │   ├── metro.config.js
    │   └── package.json
    ├── expo-module.config.json
    ├── ios/
    │   ├── CoinbaseWalletSDKExpo.podspec
    │   ├── CoinbaseWalletSDKModule.swift
    │   └── Records/
    │       ├── AccountRecord.swift
    │       ├── ActionRecord.swift
    │       ├── ActionResultRecord.swift
    │       ├── ConfigParamsRecord.swift
    │       ├── HandshakeParamsRecord.swift
    │       └── RequestParamsRecord.swift
    ├── package.json
    ├── src/
    │   ├── CoinbaseWalletSDK.ts
    │   ├── CoinbaseWalletSDK.types.ts
    │   ├── CoinbaseWalletSDKModule.ts
    │   ├── WalletMobileSDKEVMProvider.ts
    │   └── types/
    │       ├── core/
    │       │   ├── type.ts
    │       │   └── util.ts
    │       └── provider/
    │           ├── JSONRPC.ts
    │           └── Web3Provider.ts
    └── tsconfig.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.yml
================================================
name: Bug report
description: Create a report to help us improve
title: "Bug: "
labels: ["type: bug"]

body:
  - type: input
    id: description
    attributes:
      label: Describe the bug
      description: A clear and concise description of what the bug is.
      placeholder: Tell us what you see!
    validations:
      required: true

  - type: textarea
    id: steps
    attributes:
      label: Steps
      description: Steps to reproduce the behavior.
      placeholder: |
        1. Go to '...'
        2. Click on '....'
        3. Scroll down to '....'
        4. See error
    validations:
      required: true

  - type: textarea
    id: expected
    attributes:
      label: Expected behavior
      description: A clear and concise description of what you expected to happen.
    validations:
      required: true

  - type: input
    id: version
    attributes:
      label: Version
      description: Which version of Coinbase Wallet SDK

  - type: textarea
    id: additional
    attributes:
      label: Additional info
      description: If applicable, include links to screenshots or error logs

  - type: textarea
    id: desktop
    attributes:
      label: Desktop
      description: Please fill in details for bugs reported on desktop
      placeholder: |
        - OS: [e.g. iOS]
        - Browser [e.g. chrome, safari]
        - Version [e.g. 22]

  - type: textarea
    id: smartphone
    attributes:
      label: Smartphone
      description: Please fill in details for bugs reported on smartphone devices
      placeholder: |
        - Device: [e.g. iPhone6]
        - OS: [e.g. iOS8.1]
        - Browser [e.g. stock browser, safari]
        - Version [e.g. 22]


================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
  - name: Coinbase Wallet Developer Docs
    url: https://docs.cloud.coinbase.com/wallet-sdk/docs
    about: Coinbase Wallet's developer documentation


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.yml
================================================
name: Feature request
description: Suggest an idea for this project
title: "Feature Request: "
labels: ["type: enhancement"]

body:
  - type: markdown
    attributes:
      value: |
        This issue form is for feature requests only!
        If you've found a bug, please use [bug_report](/new?template=bug_report.yml)
  - type: textarea
    id: problem
    attributes:
      label: Is your feature request related to a problem? Please describe.
      description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

  - type: textarea
    id: solution
    attributes:
      label: Describe the solution you'd like
      description: A clear and concise description of what you want to happen.
    validations:
      required: true

  - type: textarea
    id: alternatives
    attributes:
      label: Describe alternatives you've considered
      description: Describe any alternative solutions or features you've considered.

  - type: textarea
    id: other
    attributes:
      label: Additional context
      description: Add any other context or screenshots about the feature request here.


================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
### _Summary_

<!--
  What changed? Link to relevant issues.
-->

### _How did you test your changes?_

<!--
  Verify changes. Include relevant screenshots/videos
-->


================================================
FILE: .github/workflows/publish.yml
================================================
name: Tag & Publish [auto]

on:
  push:
    branches:
      - master

jobs:
  environment: release
  permissions:
    contents: write
    pull-requests: write
    id-token: write
  authorize:
    name: Authorize
    runs-on: ubuntu-latest
    steps:
      - name: ${{ github.actor }} permission check to update release version
        uses: "lannonbr/repo-permission-check-action@2.0.2"
        with:
          permission: "write"
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  autotag:
    name: Auto Tag
    needs: authorize
    runs-on: ubuntu-latest
    outputs:
      tagcreated: ${{ steps.autotag.outputs.tagcreated }}
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - id: autotag
        uses: ButlerLogic/action-autotag@1.1.1
        with:
          strategy: regex
          root: "CoinbaseWalletSDK.podspec"
          regex_pattern: "s.version\\s*=\\s*'(\\d+\\.\\d+\\.\\d+)'"
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  publish_ios:
    name: Publish iOS SDK
    needs: autotag
    if: ${{ needs.autotag.outputs.tagcreated == 'yes' }}
    runs-on: macOS-latest
    steps: 
      - name: Checkout
        uses: actions/checkout@v3

      - name: Setup ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: '2.7.5'
          bundler-cache: true
      
      - name: Publish to Cocoapods
        run: |
          set -eo pipefail
          pod trunk push CoinbaseWalletSDK.podspec --allow-warnings
        env:
          COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }}

  publish_android:
    name: Publish Android SDK
    needs: autotag
    if: ${{ needs.autotag.outputs.tagcreated == 'yes' }}
    runs-on: macOS-latest
    defaults:
      run:
        working-directory: android
    steps: 
      - name: Checkout
        uses: actions/checkout@v3

      - name: Setup java
        uses: actions/setup-java@v3
        with:
          distribution: temurin
          java-version: 11
      
      - name: Setup Gradle
        uses: gradle/gradle-build-action@v2
    
      - name: Execute Gradle build
        run: ./gradlew publishReleasePublicationToSonatypeRepository closeAndReleaseSonatypeStagingRepository
        env:
          SIGNING_KEY_ID: ${{ secrets.ANDROID_SIGNING_KEYID }}
          SIGNING_PASSWORD: ${{ secrets.ANDROID_SIGNING_PASSWORD }}
          SIGNING_KEY: ${{ secrets.ANDROID_SIGNING_KEY }}
          OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
          OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
          SONATYPE_STAGING_PROFILE_ID: ${{ secrets.SONATYPE_STAGING_PROFILE_ID }}

  publish_rn:
    name: Publish React Native SDK
    needs: [publish_ios, publish_android]
    runs-on: macOS-latest
    defaults:
      run:
        working-directory: react-native
    steps: 
      - name: Checkout
        uses: actions/checkout@v3

      - name: Setup node
        uses: actions/setup-node@v3
        with:
          node-version: '16.x'
          registry-url: 'https://registry.npmjs.org'

      - name: Publish to npm
        run: |
          npm install
          npm run prepare
          npm publish
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPMJS_ACCESS_TOKEN }}

  publish_flutter:
    name: Publish Flutter SDK
    needs: [publish_ios, publish_android]
    runs-on: macOS-latest
    defaults:
      run:
        working-directory: flutter
    steps: 
      - name: Checkout
        uses: actions/checkout@v3
        
      - name: Setup Dart
        uses: dart-lang/setup-dart@v1.3

      - name: Authenticate
        run: |
          mkdir -p $PUB_CACHE
          cd $PUB_CACHE
          echo "$PUBDEV_CREDENTIALSJSON" > credentials.json
        env:
          PUBDEV_CREDENTIALSJSON: ${{ secrets.PUBDEV_CREDENTIALSJSON }}

      - name: Publish to pub.dev
        run: dart pub publish --force # TODO: automatically update CHANGELOG to run this without --force
        
      - name: Clean up
        if: ${{ always() }} 
        run: rm -r $PUB_CACHE


================================================
FILE: .github/workflows/run_tests.yml
================================================
name: Run Tests

on:
  pull_request:
    branches:
      - master

jobs:
  android:
    name: Android
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      # config java sdk version
      - name: Setup java
        uses: actions/setup-java@v3
        with:
          distribution: temurin
          java-version: 11

      - name: Setup Gradle
        uses: gradle/gradle-build-action@v2

      # Run Android unit tests
      - name: Run unit testing
        run: |
          cd android
          ./gradlew :walletsdk:testDebugUnitTest

  ios:
    name: iOS
    runs-on: macOS-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Setup ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: '2.7.5'
          bundler-cache: true

      - name: Run unit test
        run: bundle exec pod lib lint --verbose


================================================
FILE: .github/workflows/version_update.yml
================================================
name: Version Update PR

on:
  workflow_dispatch:
    inputs:
      packageVersion:
        description: "The version to publish in MAJOR.MINOR.PATCH format"
        required: true
        default: ""

jobs:
  environment: release
  permissions:
    contents: write
    pull-requests: write
    id-token: write
  authorize:
    name: Authorize
    runs-on: ubuntu-latest
    steps:
      - name: ${{ github.actor }} permission check to update release version
        uses: "lannonbr/repo-permission-check-action@2.0.2"
        with:
          permission: "write"
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

  version:
    name: Update package version
    runs-on: macOS-latest
    needs: authorize
    env:
      V_REGEX: '[0-9]+\.[0-9]+\.[0-9]+'
      NEW_VERSION: ${{ github.event.inputs.packageVersion }}
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Update iOS version
        run: |
          sed -i '' -E "s/= '${{env.V_REGEX}}/= '${{env.NEW_VERSION}}/" CoinbaseWalletSDK.podspec
          sed -i '' -E 's/= "${{env.V_REGEX}}/= "${{env.NEW_VERSION}}/' ios/CoinbaseWalletSDK/Resources/CoinbaseWalletSDK+version.swift
      
      - name: Update Android version
        run: |
          sed -i '' -E 's/(sdk-version =) "${{env.V_REGEX}}/\1 "${{env.NEW_VERSION}}/' android/gradle/libs.versions.toml

      - name: Update React Native version
        run: |
          sed -i '' -E "s/(CoinbaseWalletSDK\/CrossPlatform',) '${{env.V_REGEX}}/\1 '${{env.NEW_VERSION}}/" react-native/ios/CoinbaseWalletSDKExpo.podspec
          sed -i '' -E 's/(com.coinbase:coinbase-wallet-sdk):${{env.V_REGEX}}/\1:${{env.NEW_VERSION}}/' react-native/android/build.gradle
          sed -i '' -E 's/(version":) "${{env.V_REGEX}}/\1 "${{env.NEW_VERSION}}/' react-native/package.json

      - name: Update Flutter version
        run: |
          sed -i '' -E "s/(CoinbaseWalletSDK\/CrossPlatform',) '${{env.V_REGEX}}/\1 '${{env.NEW_VERSION}}/" flutter/ios/coinbase_wallet_sdk.podspec
          sed -i '' -E 's/(com.coinbase:coinbase-wallet-sdk):${{env.V_REGEX}}/\1:${{env.NEW_VERSION}}/' flutter/android/build.gradle
          sed -i '' -E 's/(version:) ${{env.V_REGEX}}/\1 ${{env.NEW_VERSION}}/' flutter/pubspec.yaml

      - name: Setup ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: '2.7.5'
          bundler-cache: true

      - name: Update iOS example
        run: bundle exec pod install
        working-directory: ios/example

      # - name: Update React Native example
      #   run: bundle exec pod install
      #   working-directory: react-native/example/ios
        
      # - name: Update Flutter example
      #   run: bundle exec pod install
      #   working-directory: flutter/example/ios
      
      - name: Open pull request
        uses: peter-evans/create-pull-request@v4
        with:
          add-paths: |
            CoinbaseWalletSDK.podspec
            ios/CoinbaseWalletSDK/Resources/CoinbaseWalletSDK+version.swift
            ios/example/Podfile.lock
            android/gradle/libs.versions.toml
            react-native/ios/CoinbaseWalletSDKExpo.podspec
            react-native/android/build.gradle
            react-native/package.json
            flutter/ios/coinbase_wallet_sdk.podspec
            flutter/android/build.gradle
            flutter/pubspec.yaml
          title: "[Version update] v${{env.NEW_VERSION}}"
          body: "Automated workflow: version update"
          branch: version-update-v${{env.NEW_VERSION}}
          reviewers: |
            bangtoven
            vishnumad
            AMITGOELNY
          commit-message: "[Version update] v${{env.NEW_VERSION}}"
          labels: version-update
          delete-branch: true


================================================
FILE: .gitignore
================================================
# misc
.DS_Store

# Native mobile

## User settings
xcuserdata/

## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
*.xcscmblueprint
*.xccheckout

## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
build/
DerivedData/
*.moved-aside
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3

## Obj-C/Swift specific
*.hmap

## App packaging
*.ipa
*.dSYM.zip
*.dSYM

## Playgrounds
timeline.xctimeline
playground.xcworkspace

# Swift Package Manager
#
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
# Packages/
# Package.pins
# Package.resolved
# *.xcodeproj
#
# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
# hence it is not needed unless you have added a package configuration file to your project
# .swiftpm

.build/

# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
Pods/
#
# Add this line if you want to avoid checking in source code from the Xcode workspace
*.xcworkspace

# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts

Carthage/Build/

# Accio dependency management
Dependencies/
.accio/

# fastlane
#
# It is recommended to not store the screenshots in the git repo.
# Instead, use fastlane to re-generate the screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/#source-control

fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots/**/*.png
fastlane/test_output

# Code Injection
#
# After new code Injection tools there's a generated folder /iOSInjectionProject
# https://github.com/johnno1962/injectionforxcode

iOSInjectionProject/
.DS_Store
xcshareddata

# Gradle files
.gradle/
build/

# Local configuration file (sdk path, etc)
local.properties

# Log/OS Files
*.log

# Android Studio generated files and folders
captures/
.externalNativeBuild/
.cxx/
*.apk
output.json

# IntelliJ
*.iml
.idea/
misc.xml
deploymentTargetDropDown.xml
render.experimental.xml

# Keystore files
*.jks
*.keystore

# Google Services (e.g. APIs or Firebase)
google-services.json

# Android Profiling
*.hprof

node_modules/



================================================
FILE: CODEOWNERS
================================================
* @coinbase/wallet-mobile-sdk
.github/workflows/* @bangtoven


================================================
FILE: CoinbaseWalletSDK.podspec
================================================
Pod::Spec.new do |s|
  s.name                  = 'CoinbaseWalletSDK'
  s.version               = '1.1.2'
  s.summary               = 'Swift implementation of WalletSegue protocol to interact with Coinbase Wallet iOS app'
  s.source                = { :git => 'https://github.com/MobileWalletProtocol/wallet-mobile-sdk.git', :tag => s.version }
  s.author                = 'Coinbase Wallet'
  s.social_media_url      = 'https://twitter.com/CoinbaseWallet'
  s.homepage              = 'https://github.com/MobileWalletProtocol/wallet-mobile-sdk'
  s.license               = { :type => 'Apache', :file => 'LICENSE' }
  s.ios.deployment_target = '13.0'
  s.swift_version         = '5.0'
  
  SDK_PATH = 'ios/CoinbaseWalletSDK'
  
  s.subspec 'Client' do |ss|
    ss.source_files = "#{SDK_PATH}/**/*.swift"
    ss.exclude_files = [
      "#{SDK_PATH}/Host/**/*.swift",
      "#{SDK_PATH}/Test/**/*.swift"
    ]
  end
  
  s.subspec 'Host' do |ss|
    ss.dependency 'CoinbaseWalletSDK/Client'
    ss.source_files = "#{SDK_PATH}/Host/**/*.swift"
  end
  
  s.subspec 'CrossPlatform' do |ss|
    ss.dependency 'CoinbaseWalletSDK/Client'
    ss.pod_target_xcconfig = {
      'OTHER_SWIFT_FLAGS' => '-DCROSS_PLATFORM'
    }
  end
  
  s.test_spec 'Test' do |ts|
    ts.ios.deployment_target = '13.0'
    ts.source_files = "#{SDK_PATH}/Test/**/*.swift"
  end
  
  s.default_subspec = 'Client'
end


================================================
FILE: Gemfile
================================================
source 'https://rubygems.org'

gem 'cocoapods'


================================================
FILE: LICENSE
================================================
Copyright (c) 2022 Coinbase, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.


================================================
FILE: Package.swift
================================================
// swift-tools-version: 5.4

import PackageDescription

let package = Package(
    name: "CoinbaseWalletSDK",
    platforms: [.iOS(.v13)],
    products: [
        .library(
            name: "CoinbaseWalletSDK",
            targets: ["CoinbaseWalletSDK"]
        )
    ],
    targets: [
        .target(
            name: "CoinbaseWalletSDK",
            path: "ios/CoinbaseWalletSDK",
            exclude: ["Host", "Test"]
        ),
        .testTarget(
            name: "CoinbaseWalletSDKTests",
            dependencies: ["CoinbaseWalletSDK"],
            path: "ios/CoinbaseWalletSDK/Test"
        )
    ]
)


================================================
FILE: README.md
================================================
# Coinbase Wallet Mobile SDK

[![Cocoapods](https://img.shields.io/cocoapods/v/CoinbaseWalletSDK)](https://cocoapods.org/pods/CoinbaseWalletSDK)
[![Maven](https://img.shields.io/maven-central/v/com.coinbase/coinbase-wallet-sdk?label=maven)](https://mavenlibs.com/maven/dependency/com.coinbase/coinbase-wallet-sdk)
[![npm](https://img.shields.io/npm/v/@coinbase/wallet-mobile-sdk)](https://www.npmjs.com/package/@coinbase/wallet-mobile-sdk)
[![pub.dev](https://img.shields.io/pub/v/coinbase_wallet_sdk)](https://pub.dev/packages/coinbase_wallet_sdk)

Coinbase Wallet Mobile SDK is an open source SDK which allows you to connect your native mobile applications to millions of Coinbase Wallet users.

## Getting Started

The SDK is available for the following platforms:

- [iOS](https://github.com/coinbase/wallet-mobile-sdk/tree/master/ios)
- [Android](https://github.com/coinbase/wallet-mobile-sdk/tree/master/android)

Wrapper libraries and modules are also available for the following platforms:

- [React Native](https://github.com/coinbase/wallet-mobile-sdk/tree/master/react-native)
- [Flutter](https://github.com/coinbase/wallet-mobile-sdk/tree/master/flutter)

For **Install** and **Usage** instructions of each platform, visit the links above or our [developer documentation](https://docs.cloud.coinbase.com/wallet-sdk/docs/mobile-sdk-overview).

## References
- Mobile Wallet Protocol [Specification](https://mobilewalletprotocol.github.io/wallet-mobile-sdk/docs/spec)
- Coinbase Wallet [Developer Documentation](https://docs.cloud.coinbase.com/wallet-sdk/docs)
- Questions? Visit our [Developer Forums](https://forums.coinbasecloud.dev/).
- For bugs, please report an issue on Github.

## License

```
Copyright © 2022 Coinbase, Inc. <https://www.coinbase.com/>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
```


================================================
FILE: android/README.md
================================================
# Coinbase Wallet Mobile SDK

[![Maven](https://img.shields.io/maven-central/v/com.coinbase/coinbase-wallet-sdk?label=maven)](https://mavenlibs.com/maven/dependency/com.coinbase/coinbase-wallet-sdk)

Coinbase Wallet Mobile SDK is an open source SDK which allows you to connect your native mobile applications to millions of Coinbase Wallet users.

## Install

The Coinbase Wallet Mobile SDK is available on [Maven Central](https://search.maven.org/artifact/com.coinbase/coinbase-wallet-sdk/0.1.0/aar).

### Gradle

Add Coinbase Wallet SDK to your `build.gradle` file.

```groovy
repositories {
   mavenCentral()
}

dependencies {
   implementation "com.coinbase:coinbase-wallet-sdk:1.0.3"
}
```

### Maven

Add Coinbase Wallet SDK to your `pom.xml` file.

```xml
<dependency>
	<groupId>com.coinbase</groupId>
	<artifactId>coinbase-wallet-sdk</artifactId>
	<version>1.0.3</version>
</dependency>
```

## Usage

### Setup

In order for your app to interact with Coinbase Wallet, you must add a [queries element](https://developer.android.com/guide/topics/manifest/queries-element) to your `AndroidManifest.xml` file, specifying the package name for Coinbase Wallet, `org.toshi`.

```xml
    <queries>
        <package android:name="org.toshi" />
    </queries>
```

Before the SDK can be used, it needs to be configured with an App Link to your application. This callback URL will be used by the Coinbase Wallet application to navigate back to your application.

```kotlin
CoinbaseWalletSDK(
    appContext = applicationContext,
    domain = Uri.parse("https://www.myappxyz.com"),
    openIntent = { intent -> launcher.launch(intent) }
)
```

When your application receives a response from Coinbase Wallet via App Links, this URL needs to be handed off to the SDK via the handleResponse function.

```kotlin
launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
   val uri = result.data?.data ?: return@registerForActivityResult
   client.handleResponse(uri)
}
```

An example is provided in the sample [application](https://github.com/coinbase/wallet-mobile-sdk/blob/master/android/example/src/main/java/com/coinbase/android/beta/MainActivity.kt#L27).

### Establishing a connection

A connection to Coinbase Wallet can be initiated by calling the `initiateHandshake` function provided by the SDK. The function also takes in an optional `initialActions` parameter which apps can use to take certain actions along with the initial handshake request.

```kotlin
val requestAccount = Web3JsonRPC.RequestAccounts().action()
val handShakeActions = listOf(requestAccount)

client.initiateHandshake(
   initialActions = handShakeActions
) { result: Result<List<ActionResult>>, account: Account? ->
    result.onSuccess { actionResults: List<ActionResult> ->
        actionResults.handleSuccess("Handshake", handShakeActions, account)
    }
    result.onFailure { err ->
        err.handleError("HandShake")
    }
}
```

An example handshake request is provided in the sample [application](https://github.com/coinbase/wallet-mobile-sdk/blob/master/android/example/src/main/java/com/coinbase/android/beta/MainActivity.kt#L52).

### Making requests

Requests to Coinbase Wallet can be made by calling the `makeRequest` function provided by the SDK. This function also accepts a list of `actions` that can be taken in as a single batch request.

```kotlin
val signTypedDataV3 = Web3JsonRPC.SignTypedDataV3(
   "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", // address
   typedDataJson // typed data JSON
).action()
val requestActions = listOf(signTypedDataV3)

client.makeRequest(request = RequestContent.Request(actions = requestActions)) { result ->
   result.fold(
       onSuccess = { returnValues ->
           returnValues.handleSuccess("Request", requestActions)
       },
       onFailure = { err ->
           err.handleError("Request")
       }
   )
}
```

An example request is provided in the sample [application](https://github.com/coinbase/wallet-mobile-sdk/blob/master/android/example/src/main/java/com/coinbase/android/beta/MainActivity.kt#L68).

For more information on the types of requests you can make, visit our [developer documentation](https://docs.cloud.coinbase.com/wallet-sdk/docs/mobile-sdk-overview).

## References
- Coinbase Wallet [Developer Documentation](https://docs.cloud.coinbase.com/wallet-sdk/docs)
- Questions? Visit our [Developer Forums](https://forums.coinbasecloud.dev/).
- For bugs, please report an issue on Github.

## License

```
Copyright © 2022 Coinbase, Inc. <https://www.coinbase.com/>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
```


================================================
FILE: android/build.gradle
================================================
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
    alias libs.plugins.android.application apply false
    alias libs.plugins.android.library apply false
    alias libs.plugins.kotlin.android apply false
    alias libs.plugins.maven.publish
}

apply from: "${rootDir}/scripts/publish-root.gradle"

task clean(type: Delete) {
    delete rootProject.buildDir
}

================================================
FILE: android/example/.editorconfig
================================================
[{*.kt, *.kts}]
max_line_length = 120

================================================
FILE: android/example/.gitignore
================================================
/build

================================================
FILE: android/example/build.gradle
================================================
plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
}

android {
    compileSdk 33

    signingConfigs {
        development {
            storeFile file('debug.keystore')
            storePassword 'android'
            keyAlias 'androiddebugkey'
            keyPassword 'android'
        }
    }

    defaultConfig {
        applicationId "com.coinbase.android.beta"
        minSdk 23
        targetSdk 33
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.development
        }
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    kotlinOptions {
        jvmTarget = '1.8'
    }

    buildFeatures {
        viewBinding true
    }

    namespace 'com.coinbase.android.beta'
}

dependencies {
    implementation libs.android.ktx
    implementation libs.android.appcompat
    implementation libs.android.constraintlayout
    implementation libs.android.material

    testImplementation libs.junit4
    androidTestImplementation libs.androidx.junit4

    implementation project(':walletsdk')
}

================================================
FILE: android/example/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
#   public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

================================================
FILE: android/example/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.ClientApp"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

    <queries>
        <package android:name="org.toshi" />
        <package android:name="org.toshi.development" />
    </queries>
</manifest>

================================================
FILE: android/example/src/main/java/com/coinbase/android/beta/ActionsManager.kt
================================================
package com.coinbase.android.beta

import android.content.Context
import android.content.SharedPreferences
import com.coinbase.android.nativesdk.message.request.Web3JsonRPC

object ActionsManager {

    private val requestAccount = Web3JsonRPC.RequestAccounts().action()

    private val personalSign = Web3JsonRPC.PersonalSign("", "Hello world").action()

    private val switchEthereumChain = Web3JsonRPC.SwitchEthereumChain("137").action()

    val addEthereumChain = Web3JsonRPC.AddEthereumChain("172222").action()

    private fun getSignTransaction(fromAddress: String, toAddress: String) = Web3JsonRPC.SignTransaction(
        fromAddress = fromAddress,
        toAddress = toAddress,
        weiValue = "10000000000000",
        data = "0x",
        nonce = null,
        gasPriceInWei = null,
        maxFeePerGas = null,
        maxPriorityFeePerGas = null,
        gasLimit = "1000",
        chainId = "1",
    ).action()

    private fun getSendTransaction(fromAddress: String, toAddress: String) = Web3JsonRPC.SendTransaction(
        fromAddress = fromAddress,
        toAddress = toAddress,
        weiValue = "10000000000000",
        data = "0x",
        nonce = null,
        gasPriceInWei = null,
        maxFeePerGas = null,
        maxPriorityFeePerGas = null,
        gasLimit = "1000",
        chainId = "1",
    ).action()

    val signTypedDataV3 = Web3JsonRPC.SignTypedDataV3("0xabcdefabcdefabcdefabcdefabcdefabcdef", "").action()

    val handShakeActions = listOf(requestAccount, personalSign)

    fun getRequestActions(
        fromAddress: String = SharedPrefsManager.account,
        toAddress: String
    ) = listOf(
        requestAccount,
        personalSign,
        switchEthereumChain,
        getSendTransaction(fromAddress, toAddress)
    )
}

object SharedPrefsManager {
    lateinit var sharedPrefs: SharedPreferences

    var account: String
        get() = sharedPrefs.getString("eth_account", "") ?: ""
        set(value) {
            with(sharedPrefs.edit()) {
                putString("eth_account", value)
                apply()
            }
        }

    fun init(context: Context) {
        sharedPrefs = context.getSharedPreferences("DEMO_APP", Context.MODE_PRIVATE)
    }

    fun removeAccount() {
        with(sharedPrefs.edit()) {
            remove("eth_account")
            apply()
        }
    }
}


================================================
FILE: android/example/src/main/java/com/coinbase/android/beta/MainActivity.kt
================================================
package com.coinbase.android.beta

import android.content.Intent
import android.net.Uri
import android.os.Bundle
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.isVisible
import com.coinbase.android.beta.databinding.ActivityMainBinding
import com.coinbase.android.nativesdk.CoinbaseWalletSDK
import com.coinbase.android.nativesdk.message.request.Account
import com.coinbase.android.nativesdk.message.request.Action
import com.coinbase.android.nativesdk.message.request.RequestContent
import com.coinbase.android.nativesdk.message.response.ActionResult
import com.google.android.material.shape.CornerFamily
import com.google.android.material.shape.MaterialShapeDrawable
import com.google.android.material.shape.ShapeAppearanceModel

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    private lateinit var launcher: ActivityResultLauncher<Intent>

    private val client by lazy {
        CoinbaseWalletSDK(
            appContext = applicationContext,
            domain = Uri.parse("https://myappxyz.com"),
            openIntent = { intent -> launcher.launch(intent) }
        )
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        SharedPrefsManager.init(this)
        launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
            val uri = result.data?.data ?: return@registerForActivityResult
            client.handleResponse(uri)
        }
    }

    override fun onStart() = with(binding) {
        super.onStart()

        val mwpVersion = CoinbaseWalletSDK.getCoinbaseWalletMWPVersion(this@MainActivity)
        textArea.text = "Wallet MWP Version: $mwpVersion"

        setVisibility()
        connectWalletButton.setOnClickListener {
            val handShakeActions = ActionsManager.handShakeActions
            client.initiateHandshake(
                initialActions = handShakeActions
            ) { result: Result<List<ActionResult>>, account: Account? ->
                result.onSuccess { actionResults: List<ActionResult> ->
                    actionResults.handleSuccess("Handshake", handShakeActions, account)
                }
                result.onFailure { err ->
                    err.handleError("HandShake")
                }
            }
        }

        personalSign.setOnClickListener {
            val requestActions = ActionsManager.getRequestActions(
                toAddress = "0x571a6a108adb08f9ca54fe8605280f9ee0ed4af6"
            )
            client.makeRequest(request = RequestContent.Request(actions = requestActions)) { result ->
                result.fold(
                    onSuccess = { returnValues ->
                        returnValues.handleSuccess("Request", requestActions)
                    },
                    onFailure = { err ->
                        err.handleError("Request")
                    }
                )
            }
        }

        removeAccount.setOnClickListener {
            client.resetSession()
            SharedPrefsManager.removeAccount()
            textArea.setText(R.string.connection_removed)
            setVisibility()
        }
    }

    private fun List<ActionResult>.handleSuccess(
        requestType: String,
        actions: List<Action>,
        account: Account? = null
    ) = with(binding) {
        textArea.text = buildString {
            if (actions.isEmpty()) {
                append("Handshake successful")
            } else {
                this@handleSuccess.forEachIndexed { index, returnValue ->
                    append(
                        "${actions[index].method} Result: " +
                                "${if (returnValue is ActionResult.Result) "Success" else "Error"}\n"
                    )

                    if (account != null) {
                        SharedPrefsManager.account = account.address
                    }

                    val result = when (returnValue) {
                        is ActionResult.Result -> returnValue.value
                        is ActionResult.Error -> returnValue.message
                    }
                    append("${result}\n\n")
                }
            }
        }
        setVisibility()
    }

    private fun Throwable.handleError(requestType: String) = with(binding) {
        textArea.text = buildString {
            append("$requestType Error: \n\n")
            append(message)
        }
    }

    private fun setVisibility() = with(binding) {
        val isConnected = client.isConnected
        connectContainer.isVisible = !isConnected
        requestContainer.isVisible = isConnected


        with(connectedStatus) {
            val radius = 28f
            val shapeAppearanceModel = ShapeAppearanceModel()
                .toBuilder()
                .setAllCorners(CornerFamily.ROUNDED, radius)
                .build()

            val shapeDrawable = MaterialShapeDrawable(shapeAppearanceModel)
            ViewCompat.setBackground(connectedStatus, shapeDrawable)

            if (isConnected) {
                text = getString(
                    R.string.connected_state,
                    "${SharedPrefsManager.account.take(5)}...${SharedPrefsManager.account.takeLast(4)}"
                )
                setTextColor(getColor(R.color.teal_200))
                shapeDrawable.setStroke(2.0f, getColor(R.color.teal_200))

            } else {
                setText(R.string.unconnected_state)
                setTextColor(getColor(R.color.red_error))
                shapeDrawable.setStroke(2.0f, getColor(R.color.red_error))
            }
        }
    }
}


================================================
FILE: android/example/src/main/java/com/coinbase/android/beta/SecondActivity.java
================================================
package com.coinbase.android.beta;

import static com.coinbase.android.nativesdk.CoinbaseWalletSDKKt.CBW_PACKAGE_NAME;

import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import com.coinbase.android.nativesdk.CoinbaseWalletSDK;
import com.coinbase.android.nativesdk.message.request.Action;
import com.coinbase.android.nativesdk.message.request.Web3JsonRPC;
import com.coinbase.android.nativesdk.message.response.ActionResult;

import java.util.ArrayList;

public class SecondActivity extends AppCompatActivity {

    final int CBW_ACTIVITY_RESULT_CODE = 9182736;

    CoinbaseWalletSDK client;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        client = new CoinbaseWalletSDK(
                Uri.parse("https://myappxyz.com"),
                getApplicationContext(),
                CBW_PACKAGE_NAME,
                intent -> {
                    startActivityForResult(intent, CBW_ACTIVITY_RESULT_CODE);
                }
        );
    }

    @Override
    protected void onStart() {
        super.onStart();

        ArrayList<Action> actions = new ArrayList<>();
        actions.add(
                new Web3JsonRPC.RequestAccounts().action(false)
        );

        client.initiateHandshake(
                actions,
                (results, account) -> {
                    for (ActionResult result : results) {
                        if (result instanceof ActionResult.Result) {
                            ((ActionResult.Result) result).getValue();
                        }

                        if (result instanceof ActionResult.Error) {
                            ((ActionResult.Error) result).getCode();
                            ((ActionResult.Error) result).getMessage();
                        }
                    }
                },
                error -> {
                }
        );
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode != CBW_ACTIVITY_RESULT_CODE) {
            return;
        }

        if (data == null) {
            return;
        }

        Uri url = data.getData();
        client.handleResponse(url);
    }
}


================================================
FILE: android/example/src/main/res/drawable/ic_launcher_background.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="108dp"
    android:height="108dp"
    android:viewportWidth="108"
    android:viewportHeight="108">
    <path
        android:fillColor="#3DDC84"
        android:pathData="M0,0h108v108h-108z" />
    <path
        android:fillColor="#00000000"
        android:pathData="M9,0L9,108"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M19,0L19,108"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M29,0L29,108"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M39,0L39,108"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M49,0L49,108"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M59,0L59,108"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M69,0L69,108"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M79,0L79,108"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M89,0L89,108"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M99,0L99,108"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M0,9L108,9"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M0,19L108,19"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M0,29L108,29"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M0,39L108,39"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M0,49L108,49"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M0,59L108,59"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M0,69L108,69"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M0,79L108,79"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M0,89L108,89"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M0,99L108,99"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M19,29L89,29"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M19,39L89,39"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M19,49L89,49"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M19,59L89,59"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M19,69L89,69"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M19,79L89,79"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M29,19L29,89"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M39,19L39,89"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M49,19L49,89"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M59,19L59,89"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M69,19L69,89"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
    <path
        android:fillColor="#00000000"
        android:pathData="M79,19L79,89"
        android:strokeWidth="0.8"
        android:strokeColor="#33FFFFFF" />
</vector>


================================================
FILE: android/example/src/main/res/drawable-v24/ic_launcher_foreground.xml
================================================
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:aapt="http://schemas.android.com/aapt"
    android:width="108dp"
    android:height="108dp"
    android:viewportWidth="108"
    android:viewportHeight="108">
    <path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
        <aapt:attr name="android:fillColor">
            <gradient
                android:endX="85.84757"
                android:endY="92.4963"
                android:startX="42.9492"
                android:startY="49.59793"
                android:type="linear">
                <item
                    android:color="#44000000"
                    android:offset="0.0" />
                <item
                    android:color="#00000000"
                    android:offset="1.0" />
            </gradient>
        </aapt:attr>
    </path>
    <path
        android:fillColor="#FFFFFF"
        android:fillType="nonZero"
        android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
        android:strokeWidth="1"
        android:strokeColor="#00000000" />
</vector>

================================================
FILE: android/example/src/main/res/layout/activity_main.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="start"
        android:text="@string/select_an_option"
        android:textSize="16sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintBottom_toBottomOf="@id/connected_status"
        app:layout_constraintTop_toTopOf="@id/connected_status" />

    <TextView
        android:id="@+id/connected_status"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="12dp"
        android:text="@string/unconnected_state"
        android:textColor="@color/red_error"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@id/barrier"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/connect_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        app:layout_constraintTop_toBottomOf="@id/connected_status">

        <com.google.android.material.button.MaterialButton
            android:id="@+id/connectWalletButton"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:text="@string/connect_wallet"
            app:cornerRadius="16dp"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/request_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:visibility="gone"
        app:layout_constraintTop_toBottomOf="@id/connected_status"
        tools:visibility="gone">

        <com.google.android.material.button.MaterialButton
            android:id="@+id/personalSign"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:text="@string/request_personal_sign"
            app:cornerRadius="16dp"
            app:layout_constraintTop_toTopOf="parent" />

        <com.google.android.material.button.MaterialButton
            android:id="@+id/remove_account"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:layout_marginTop="16dp"
            android:text="@string/remove_account"
            app:cornerRadius="16dp"
            app:layout_constraintTop_toBottomOf="@+id/personalSign" />
    </androidx.constraintlayout.widget.ConstraintLayout>

    <androidx.constraintlayout.widget.Barrier
        android:id="@+id/barrier"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:barrierDirection="bottom"
        app:constraint_referenced_ids="connect_container,request_container" />

    <TextView
        android:id="@+id/textArea"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:fontFamily="monospace"
        app:layout_constraintTop_toBottomOf="@id/barrier" />
</androidx.constraintlayout.widget.ConstraintLayout>

================================================
FILE: android/example/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
    <background android:drawable="@drawable/ic_launcher_background" />
    <foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

================================================
FILE: android/example/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
    <background android:drawable="@drawable/ic_launcher_background" />
    <foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

================================================
FILE: android/example/src/main/res/values/colors.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="purple_200">#FFBB86FC</color>
    <color name="purple_500">#FF6200EE</color>
    <color name="purple_700">#FF3700B3</color>
    <color name="teal_200">#FF03DAC5</color>
    <color name="teal_700">#FF018786</color>
    <color name="black">#FF000000</color>
    <color name="white">#FFFFFFFF</color>
    <color name="red_error">#F44336</color>
</resources>

================================================
FILE: android/example/src/main/res/values/strings.xml
================================================
<resources>
    <string name="app_name">WalletSDK ClientApp</string>
    <string name="connect_wallet">Connect Wallet</string>
    <string name="request_personal_sign">Request personal_sign</string>
    <string name="remove_account">Remove Account</string>
    <string name="select_an_option">Select an option</string>
    <string name="connection_removed">Connection Removed</string>
    <string name="connected_state">Connected: %s</string>
    <string name="unconnected_state">Not Connected</string>
</resources>

================================================
FILE: android/example/src/main/res/values/themes.xml
================================================
<resources xmlns:tools="http://schemas.android.com/tools">
    <!-- Base application theme. -->
    <style name="Theme.ClientApp" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
        <!-- Primary brand color. -->
        <item name="colorPrimary">#F57C00</item>
        <item name="colorPrimaryVariant">#EF6C00</item>
        <item name="colorOnPrimary">@color/white</item>
        <!-- Secondary brand color. -->
        <item name="colorSecondary">@color/teal_200</item>
        <item name="colorSecondaryVariant">@color/teal_700</item>
        <item name="colorOnSecondary">@color/black</item>
        <!-- Status bar color. -->
        <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
        <!-- Customize your theme here. -->
    </style>
</resources>

================================================
FILE: android/example/src/main/res/values-night/themes.xml
================================================
<resources xmlns:tools="http://schemas.android.com/tools">
    <!-- Base application theme. -->
    <style name="Theme.ClientApp" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
        <!-- Primary brand color. -->
        <item name="colorPrimary">#2196F3</item>
        <item name="colorPrimaryVariant">#03A9F4</item>
        <item name="colorOnPrimary">@color/black</item>
        <!-- Secondary brand color. -->
        <item name="colorSecondary">@color/teal_200</item>
        <item name="colorSecondaryVariant">@color/teal_200</item>
        <item name="colorOnSecondary">@color/black</item>
        <!-- Status bar color. -->
        <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
        <!-- Customize your theme here. -->
    </style>
</resources>

================================================
FILE: android/example/src/main/res/xml/backup_rules.xml
================================================
<?xml version="1.0" encoding="utf-8"?><!--
   Sample backup rules file; uncomment and customize as necessary.
   See https://developer.android.com/guide/topics/data/autobackup
   for details.
   Note: This file is ignored for devices older that API 31
   See https://developer.android.com/about/versions/12/backup-restore
-->
<full-backup-content>
    <!--
   <include domain="sharedpref" path="."/>
   <exclude domain="sharedpref" path="device.xml"/>
-->
</full-backup-content>

================================================
FILE: android/example/src/main/res/xml/data_extraction_rules.xml
================================================
<?xml version="1.0" encoding="utf-8"?><!--
   Sample data extraction rules file; uncomment and customize as necessary.
   See https://developer.android.com/about/versions/12/backup-restore#xml-changes
   for details.
-->
<data-extraction-rules>
    <cloud-backup>
        <!-- TODO: Use <include> and <exclude> to control what is backed up.
        <include .../>
        <exclude .../>
        -->
    </cloud-backup>
    <!--
    <device-transfer>
        <include .../>
        <exclude .../>
    </device-transfer>
    -->
</data-extraction-rules>

================================================
FILE: android/gradle/libs.versions.toml
================================================
[versions]
gradleplugin = "7.2.2"
kotlin = "1.6.21"
kotlinSerialization = "1.3.3"
nexus-publish = "1.1.0"

sdk-version = "1.2.0"

[libraries]

android-ktx = { module = "androidx.core:core-ktx", version = "1.9.0" }
android-appcompat = { module = "androidx.appcompat:appcompat", version = "1.5.1" }
android-constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version = "2.1.4" }
android-material = { module = "com.google.android.material:material", version = "1.6.1" }
kotlin-serialization = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinSerialization" }
security-crypto = { module = "androidx.security:security-crypto", version = "1.0.0" }
security-tink = { module = "com.google.crypto.tink:tink-android", version = "1.6.1" }

# Test Libs
androidx-junit4 = { module = "androidx.test.ext:junit", version = "1.1.3" }
junit4 = { module = "junit:junit", version = "4.13.2" }
kotest = { module = "io.kotest:kotest-assertions-core", version = "5.5.0" }

[plugins]
android-application = { id = "com.android.application", version.ref = "gradleplugin" }
android-library = { id = "com.android.library", version.ref = "gradleplugin" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
maven-publish = { id = "io.github.gradle-nexus.publish-plugin", version.ref = "nexus-publish" }

================================================
FILE: android/gradle/wrapper/gradle-wrapper.properties
================================================
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists


================================================
FILE: android/gradle.properties
================================================
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app"s APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true

================================================
FILE: android/gradlew
================================================
#!/bin/sh

#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

##############################################################################
#
#   Gradle start up script for POSIX generated by Gradle.
#
#   Important for running:
#
#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
#       noncompliant, but you have some other compliant shell such as ksh or
#       bash, then to run this script, type that shell name before the whole
#       command line, like:
#
#           ksh Gradle
#
#       Busybox and similar reduced shells will NOT work, because this script
#       requires all of these POSIX shell features:
#         * functions;
#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;
#         * compound commands having a testable exit status, especially «case»;
#         * various built-in commands including «command», «set», and «ulimit».
#
#   Important for patching:
#
#   (2) This script targets any POSIX shell, so it avoids extensions provided
#       by Bash, Ksh, etc; in particular arrays are avoided.
#
#       The "traditional" practice of packing multiple parameters into a
#       space-separated string is a well documented source of bugs and security
#       problems, so this is (mostly) avoided, by progressively accumulating
#       options in "$@", and eventually passing that to Java.
#
#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
#       see the in-line comments for details.
#
#       There are tweaks for specific operating systems such as AIX, CygWin,
#       Darwin, MinGW, and NonStop.
#
#   (3) This script is generated from the Groovy template
#       https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
#       within the Gradle project.
#
#       You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################

# Attempt to set APP_HOME

# Resolve links: $0 may be a link
app_path=$0

# Need this for daisy-chained symlinks.
while
    APP_HOME=${app_path%"${app_path##*/}"}  # leaves a trailing /; empty if no leading path
    [ -h "$app_path" ]
do
    ls=$( ls -ld "$app_path" )
    link=${ls#*' -> '}
    case $link in             #(
      /*)   app_path=$link ;; #(
      *)    app_path=$APP_HOME$link ;;
    esac
done

APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit

APP_NAME="Gradle"
APP_BASE_NAME=${0##*/}

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum

warn () {
    echo "$*"
} >&2

die () {
    echo
    echo "$*"
    echo
    exit 1
} >&2

# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in                #(
  CYGWIN* )         cygwin=true  ;; #(
  Darwin* )         darwin=true  ;; #(
  MSYS* | MINGW* )  msys=true    ;; #(
  NONSTOP* )        nonstop=true ;;
esac

CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar


# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
        # IBM's JDK on AIX uses strange locations for the executables
        JAVACMD=$JAVA_HOME/jre/sh/java
    else
        JAVACMD=$JAVA_HOME/bin/java
    fi
    if [ ! -x "$JAVACMD" ] ; then
        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
    fi
else
    JAVACMD=java
    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi

# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
    case $MAX_FD in #(
      max*)
        MAX_FD=$( ulimit -H -n ) ||
            warn "Could not query maximum file descriptor limit"
    esac
    case $MAX_FD in  #(
      '' | soft) :;; #(
      *)
        ulimit -n "$MAX_FD" ||
            warn "Could not set maximum file descriptor limit to $MAX_FD"
    esac
fi

# Collect all arguments for the java command, stacking in reverse order:
#   * args from the command line
#   * the main class name
#   * -classpath
#   * -D...appname settings
#   * --module-path (only if needed)
#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.

# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
    APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
    CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )

    JAVACMD=$( cygpath --unix "$JAVACMD" )

    # Now convert the arguments - kludge to limit ourselves to /bin/sh
    for arg do
        if
            case $arg in                                #(
              -*)   false ;;                            # don't mess with options #(
              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath
                    [ -e "$t" ] ;;                      #(
              *)    false ;;
            esac
        then
            arg=$( cygpath --path --ignore --mixed "$arg" )
        fi
        # Roll the args list around exactly as many times as the number of
        # args, so each arg winds up back in the position where it started, but
        # possibly modified.
        #
        # NB: a `for` loop captures its iteration list before it begins, so
        # changing the positional parameters here affects neither the number of
        # iterations, nor the values presented in `arg`.
        shift                   # remove old arg
        set -- "$@" "$arg"      # push replacement arg
    done
fi

# Collect all arguments for the java command;
#   * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
#     shell script including quotes and variable substitutions, so put them in
#     double quotes to make sure that they get re-expanded; and
#   * put everything else in single quotes, so that it's not re-expanded.

set -- \
        "-Dorg.gradle.appname=$APP_BASE_NAME" \
        -classpath "$CLASSPATH" \
        org.gradle.wrapper.GradleWrapperMain \
        "$@"

# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
#   readarray ARGS < <( xargs -n1 <<<"$var" ) &&
#   set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#

eval "set -- $(
        printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
        xargs -n1 |
        sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
        tr '\n' ' '
    )" '"$@"'

exec "$JAVACMD" "$@"


================================================
FILE: android/gradlew.bat
================================================
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem      https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem

@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem  Gradle startup script for Windows
@rem
@rem ##########################################################################

@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal

set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%

@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi

@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"

@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome

set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute

echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe

if exist "%JAVA_EXE%" goto execute

echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:execute
@rem Setup the command line

set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar


@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*

:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd

:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1

:mainEnd
if "%OS%"=="Windows_NT" endlocal

:omega


================================================
FILE: android/scripts/publish-root.gradle
================================================
// Create variables with empty default values
ext["signing.keyId"] = ''
ext["signing.password"] = ''
ext["signing.key"] = ''
ext["ossrhUsername"] = ''
ext["ossrhPassword"] = ''
ext["sonatypeStagingProfileId"] = ''
ext["snapshot"] = false

File secretPropsFile = project.rootProject.file('local.properties')
if (secretPropsFile.exists()) {
    // Read local.properties file first if it exists
    Properties p = new Properties()
    new FileInputStream(secretPropsFile).withCloseable { is -> p.load(is) }
    p.each { name, value -> ext[name] = value }
} else {
    // Use system environment variables
    ext["ossrhUsername"] = System.getenv('OSSRH_USERNAME')
    ext["ossrhPassword"] = System.getenv('OSSRH_PASSWORD')
    ext["sonatypeStagingProfileId"] = '61a7f2c94aea57'
    ext["signing.keyId"] = System.getenv('SIGNING_KEY_ID')
    ext["signing.password"] = System.getenv('SIGNING_PASSWORD')
    ext["signing.key"] = System.getenv('SIGNING_KEY')
    ext["snapshot"] = System.getenv('SNAPSHOT')
}
def versionName = libs.versions.sdk.version
def snapshotVersionName = "${versionName}-SNAPSHOT"

if (snapshot) {
    ext["rootVersionName"] = snapshotVersionName
} else {
    ext["rootVersionName"] = versionName
}

// Set up Sonatype repository
nexusPublishing {
    repositories {
        sonatype {
            stagingProfileId = sonatypeStagingProfileId
            username = ossrhUsername
            password = ossrhPassword
            version = versionName
        }
    }
}


================================================
FILE: android/settings.gradle
================================================
pluginManagement {
    repositories {
        gradlePluginPortal()
        google()
        mavenCentral()
    }
}

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}

rootProject.name = "Wallet SDK"
include ':example', ':walletsdk'


================================================
FILE: android/walletsdk/.editorconfig
================================================
[{*.kt, *.kts}]
max_line_length = 120

================================================
FILE: android/walletsdk/.gitignore
================================================
/build

================================================
FILE: android/walletsdk/build.gradle
================================================
plugins {
    alias libs.plugins.android.library
    alias libs.plugins.kotlin.android
    id 'org.jetbrains.kotlin.plugin.serialization' version '1.6.21'
    id 'maven-publish'
    id 'signing'
}

android {
    compileSdk 34

    defaultConfig {
        minSdk 23
        targetSdk 34

        versionCode 3
        versionName libs.versions.sdk.version.get()

        buildConfigField "int", "LIBRARY_VERSION_CODE", "${versionCode}"
        buildConfigField "String", "LIBRARY_VERSION_NAME", "\"${versionName}\""

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        consumerProguardFiles "consumer-rules.pro"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }

    publishing {
        singleVariant("release") {
            withSourcesJar()
            withJavadocJar()
        }
    }

    testOptions {
        unitTests {
            includeAndroidResources = true
        }
    }
}

dependencies {
    implementation libs.kotlin.serialization
    implementation libs.security.crypto
    implementation libs.security.tink

    testImplementation libs.junit4
    testImplementation libs.kotest
    androidTestImplementation libs.androidx.junit4
}

afterEvaluate {
    publishing {
        publications {
            release(MavenPublication) {
                from components.release
                groupId 'com.coinbase'
                artifactId 'coinbase-wallet-sdk'
                version = android.defaultConfig.versionName

                pom {
                    name = 'coinbase-wallet-sdk'
                    description = 'Coinbase Wallet Mobile SDK'
                    url = 'https://github.com/MobileWalletProtocol/wallet-mobile-sdk'
                    licenses {
                        license {
                            name = 'Coinbase License'
                            url = 'https://github.com/MobileWalletProtocol/wallet-mobile-sdk/blob/master/LICENSE'
                        }
                    }
                    developers {
                        developer {
                            id = 'bangtoven'
                            name = 'Jungho Bang'
                            email = 'me@bangtoven.com'
                        }
                        developer {
                            id = 'vishnumad'
                            name = 'Vishnu Madhusoodanan'
                            email = 'vishnu.madhusoodanan@coinbase.com'
                        }
                    }
                    scm {
                        developerConnection = 'scm:git@github.com:MobileWalletProtocol/wallet-mobile-sdk.git'
                        url = 'https://github.com/MobileWalletProtocol/wallet-mobile-sdk/tree/main'
                    }
                }
            }
        }
    }
}

signing {
    useInMemoryPgpKeys(
            rootProject.ext["signing.keyId"],
            rootProject.ext["signing.key"],
            rootProject.ext["signing.password"],
    )
    sign publishing.publications
}


================================================
FILE: android/walletsdk/consumer-rules.pro
================================================
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
#   public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

# Keep `Companion` object fields of serializable classes.
# This avoids serializer lookup through `getDeclaredClasses` as done for named companion objects.
-if @kotlinx.serialization.Serializable class **
-keepclassmembers class <1> {
    static <1>$Companion Companion;
}

# Keep `serializer()` on companion objects (both default and named) of serializable classes.
-if @kotlinx.serialization.Serializable class ** {
    static **$* *;
}
-keepclassmembers class <2>$<3> {
    kotlinx.serialization.KSerializer serializer(...);
}

# Keep `INSTANCE.serializer()` of serializable objects.
-if @kotlinx.serialization.Serializable class ** {
    public static ** INSTANCE;
}
-keepclassmembers class <1> {
    public static <1> INSTANCE;
    kotlinx.serialization.KSerializer serializer(...);
}

# @Serializable and @Polymorphic are used at runtime for polymorphic serialization.
-keepattributes RuntimeVisibleAnnotations,AnnotationDefault

# Serializer for classes with named companion objects are retrieved using `getDeclaredClasses`.
# If you have any, uncomment and replace classes with those containing named companion objects.
#-keepattributes InnerClasses # Needed for `getDeclaredClasses`.
#-if @kotlinx.serialization.Serializable class
#com.example.myapplication.HasNamedCompanion, # <-- List serializable classes with named companions.
#com.example.myapplication.HasNamedCompanion2
#{
#    static **$* *;
#}
#-keepnames class <1>$$serializer { # -keepnames suffices; class is kept when serializer() is kept.
#    static <1>$$serializer INSTANCE;
#}

================================================
FILE: android/walletsdk/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
#   public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

# Keep `Companion` object fields of serializable classes.
# This avoids serializer lookup through `getDeclaredClasses` as done for named companion objects.
-if @kotlinx.serialization.Serializable class **
-keepclassmembers class <1> {
    static <1>$Companion Companion;
}

# Keep `serializer()` on companion objects (both default and named) of serializable classes.
-if @kotlinx.serialization.Serializable class ** {
    static **$* *;
}
-keepclassmembers class <2>$<3> {
    kotlinx.serialization.KSerializer serializer(...);
}

# Keep `INSTANCE.serializer()` of serializable objects.
-if @kotlinx.serialization.Serializable class ** {
    public static ** INSTANCE;
}
-keepclassmembers class <1> {
    public static <1> INSTANCE;
    kotlinx.serialization.KSerializer serializer(...);
}

# @Serializable and @Polymorphic are used at runtime for polymorphic serialization.
-keepattributes RuntimeVisibleAnnotations,AnnotationDefault

# Serializer for classes with named companion objects are retrieved using `getDeclaredClasses`.
# If you have any, uncomment and replace classes with those containing named companion objects.
#-keepattributes InnerClasses # Needed for `getDeclaredClasses`.
#-if @kotlinx.serialization.Serializable class
#com.example.myapplication.HasNamedCompanion, # <-- List serializable classes with named companions.
#com.example.myapplication.HasNamedCompanion2
#{
#    static **$* *;
#}
#-keepnames class <1>$$serializer { # -keepnames suffices; class is kept when serializer() is kept.
#    static <1>$$serializer INSTANCE;
#}

================================================
FILE: android/walletsdk/src/androidTest/java/com/coinbase/android/nativesdk/ExampleInstrumentedTest.kt
================================================
package com.coinbase.android.nativesdk

import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4

import org.junit.Test
import org.junit.runner.RunWith

import org.junit.Assert.*

/**
 * Instrumented test, which will execute on an Android device.
 *
 * See [testing documentation](http://d.android.com/tools/testing).
 */
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
    @Test
    fun useAppContext() {
        // Context of the app under test.
        val appContext = InstrumentationRegistry.getInstrumentation().targetContext
        assertEquals("com.coinbase.android.walletsegue.test", appContext.packageName)
    }
}

================================================
FILE: android/walletsdk/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.coinbase.android.nativesdk">

</manifest>

================================================
FILE: android/walletsdk/src/main/java/com/coinbase/android/nativesdk/CoinbaseWalletSDK.kt
================================================
package com.coinbase.android.nativesdk

import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.net.Uri
import com.coinbase.android.nativesdk.key.KeyManager
import com.coinbase.android.nativesdk.message.JSON
import com.coinbase.android.nativesdk.message.request.Account
import com.coinbase.android.nativesdk.message.request.Action
import com.coinbase.android.nativesdk.message.request.ETH_REQUEST_ACCOUNTS
import com.coinbase.android.nativesdk.message.request.RequestContent
import com.coinbase.android.nativesdk.message.request.RequestConverter
import com.coinbase.android.nativesdk.message.request.UnencryptedRequestContent
import com.coinbase.android.nativesdk.message.request.UnencryptedRequestMessage
import com.coinbase.android.nativesdk.message.request.nonHandshakeActions
import com.coinbase.android.nativesdk.message.response.FailureResponseCallback
import com.coinbase.android.nativesdk.message.response.ResponseHandler
import com.coinbase.android.nativesdk.message.response.ResponseResult
import com.coinbase.android.nativesdk.message.response.ActionResult
import com.coinbase.android.nativesdk.message.response.ResponseConverter
import com.coinbase.android.nativesdk.message.response.SuccessHandshakeResponseCallback
import com.coinbase.android.nativesdk.message.response.SuccessRequestResponseCallback
import com.coinbase.android.nativesdk.task.TaskManager
import kotlinx.serialization.decodeFromString
import java.security.interfaces.ECPublicKey
import java.util.Date
import java.util.UUID

const val CBW_PACKAGE_NAME = "org.toshi"
private const val CBW_SCHEME = "cbwallet://wsegue"

class CoinbaseWalletSDK(
    domain: Uri,
    private val appContext: Context,
    private val hostPackageName: String = CBW_PACKAGE_NAME,
    private val openIntent: (Intent) -> Unit
) {
    private val domain: Uri
    private var sdkVersion = BuildConfig.LIBRARY_VERSION_NAME
    private val keyManager by lazy { KeyManager(appContext, hostPackageName) }
    private val taskManager by lazy { TaskManager() }

    private val launchWalletIntent: Intent?
        get() = appContext.packageManager.getLaunchIntentForPackage(hostPackageName)

    val isCoinbaseWalletInstalled get() = launchWalletIntent != null
    val isConnected: Boolean get() = keyManager.peerPublicKey != null
    val ownPublicKey: ECPublicKey get() = keyManager.ownPublicKey
    val peerPublicKey: ECPublicKey? get() = keyManager.peerPublicKey

    companion object {
        fun getCoinbaseWalletMWPVersion(context: Context): String? {
            val intents = listOf(
                "1.1" to Intent(Intent.ACTION_VIEW, Uri.parse("mwp+1.1://")),
                "1.0" to Intent(Intent.ACTION_VIEW, Uri.parse("cbwallet://"))
            )

            for ((version, intent) in intents) {
                if (intent.resolveActivity(context.packageManager) != null) {
                    return version
                }
            }

            return null
        }
    }

    init {
        this.domain = if (domain.pathSegments.size < 2) {
            domain.buildUpon()
                .appendPath("wsegue")
                .build()
        } else {
            domain
        }
    }

    constructor(
        domain: Uri,
        appContext: Context,
        hostPackageName: String,
        openIntent: OpenIntentCallback
    ) : this(
        domain,
        appContext,
        hostPackageName,
        { intent -> openIntent.call(intent) }
    )

    fun appendVersionTag(tag: String) {
        sdkVersion += "/$tag"
    }

    /**
     * Make handshake request to get session key from wallet
     * @param initialActions Batch of actions that you'd want to execute after successful handshake. `eth_requestAccounts` by default.
     * @param onResponse Response callback with regular response result and optional parsed [Account] object.
     */
    fun initiateHandshake(
        initialActions: List<Action>? = null,
        onResponse: (ResponseResult, Account?) -> Unit
    ) {
        resetSession()

        val hasIllegalAction = initialActions?.any { nonHandshakeActions.contains(it.method) } == true
        if (hasIllegalAction) {
            onResponse(Result.failure(CoinbaseWalletSDKError.InvalidHandshakeRequest), null)
            return
        }

        val message = UnencryptedRequestMessage(
            uuid = UUID.randomUUID().toString(),
            version = sdkVersion,
            timestamp = Date(),
            sender = keyManager.ownPublicKey,
            content = UnencryptedRequestContent(
                handshake = RequestContent.Handshake(
                    appId = appContext.packageName,
                    callback = domain.toString(),
                    initialActions = initialActions
                )
            ),
            callbackUrl = domain.toString()
        )

        send(message) { result ->
            // Get index of eth_requestAccounts action
            val requestAccountsIndex = initialActions?.indexOfFirst { it.method == ETH_REQUEST_ACCOUNTS } ?: -1
            if (requestAccountsIndex == -1) {
                onResponse(result, null)
                return@send
            }

            // Get response from Wallet at index
            val requestAccountsResult = result.getOrNull()?.getOrNull(requestAccountsIndex)
            if (requestAccountsResult !is ActionResult.Result) {
                onResponse(result, null)
                return@send
            }

            val account = try {
                JSON.decodeFromString<Account>(requestAccountsResult.value)
            } catch (e: Exception) {
                null
            }

            onResponse(result, account)
        }
    }

    fun initiateHandshake(
        initialActions: List<Action>? = null,
        onSuccess: SuccessHandshakeResponseCallback,
        onFailure: FailureResponseCallback
    ) {
        initiateHandshake(initialActions) { result, account ->
            result
                .onSuccess { onSuccess.call(it, account) }
                .onFailure { onFailure.call(it) }
        }
    }

    /**
     * Make regular requests. It requires session key you get after successful handshake.
     */
    fun makeRequest(
        request: RequestContent.Request,
        onResponse: ResponseHandler
    ) {
        val message = UnencryptedRequestMessage(
            uuid = UUID.randomUUID().toString(),
            version = sdkVersion,
            timestamp = Date(),
            sender = keyManager.ownPublicKey,
            content = UnencryptedRequestContent(request = request),
            callbackUrl = domain.toString()
        )

        send(message, onResponse)
    }

    fun makeRequest(
        request: RequestContent.Request,
        onSuccess: SuccessRequestResponseCallback,
        onFailure: FailureResponseCallback
    ) {
        makeRequest(request) { result ->
            result
                .onSuccess { onSuccess.call(it) }
                .onFailure { onFailure.call(it) }
        }
    }

    /**
     * Handle incoming deep links
     * @param url deep link url
     * @return `false` if the input was not response message type, or `true` if SDK handled the input
     */
    fun handleResponse(url: Uri): Boolean {
        if (!isWalletSegueResponseURL(url)) {
            return false
        }

        val ownPublicKey = keyManager.ownPublicKey
        val peerPublicKey = keyManager.peerPublicKey

        val message = ResponseConverter.decode(
            url = url,
            ownPublicKey = ownPublicKey,
            ownPrivateKey = keyManager.ownPrivateKey,
            peerPublicKey = peerPublicKey
        )

        if (peerPublicKey == null && message.sender != ownPublicKey) {
            keyManager.storePeerPublicKey(message.sender as ECPublicKey)
        }

        return taskManager.handleResponse(message)
    }

    fun resetSession() {
        taskManager.reset()
        keyManager.resetKeys()
    }

    private fun send(message: UnencryptedRequestMessage, onResponse: ResponseHandler) {
        val uri: Uri
        try {
            uri = RequestConverter.encode(
                message = message,
                recipient = Uri.parse(CBW_SCHEME),
                ownPrivateKey = keyManager.ownPrivateKey,
                peerPublicKey = keyManager.peerPublicKey
            )
        } catch (e: Throwable) {
            when (e) {
                is CoinbaseWalletSDKError -> onResponse(Result.failure(e))
                else -> onResponse(Result.failure(CoinbaseWalletSDKError.EncodingFailed))
            }
            return
        }

        val intent = launchWalletIntent
        if (intent == null) {
            onResponse(Result.failure(CoinbaseWalletSDKError.OpenWalletFailed))
            return
        }

        // Prevent intent from launching app in new window
        intent.type = Intent.ACTION_VIEW
        if (intent.flags and Intent.FLAG_ACTIVITY_NEW_TASK > 0) {
            intent.flags = intent.flags and Intent.FLAG_ACTIVITY_NEW_TASK.inv()
        }

        intent.data = uri

        taskManager.registerResponseHandler(message, onResponse)
        openIntent(intent)
    }

    private fun isWalletSegueResponseURL(uri: Uri): Boolean {
        return uri.host == domain.host && uri.path == domain.path && uri.getQueryParameter("p") != null
    }
}


================================================
FILE: android/walletsdk/src/main/java/com/coinbase/android/nativesdk/CoinbaseWalletSDKError.kt
================================================
package com.coinbase.android.nativesdk

sealed class CoinbaseWalletSDKError(
    errorMessage: String? = null,
    cause: Throwable? = null
) : Exception(errorMessage, cause) {
    object EncodingFailed : CoinbaseWalletSDKError("Encoding failed")
    object DecodingFailed : CoinbaseWalletSDKError("Decoding failed")
    object MissingSharedSecret : CoinbaseWalletSDKError("Missing shared secret")
    object OpenWalletFailed : CoinbaseWalletSDKError("Could not open wallet")
    object InvalidHandshakeRequest : CoinbaseWalletSDKError("Could not process this request in handshake")
    class WalletReturnedError(error: String) : CoinbaseWalletSDKError(error)
    class UserNotAuthenticated(message: String, cause: Throwable) : CoinbaseWalletSDKError(message, cause)
}

================================================
FILE: android/walletsdk/src/main/java/com/coinbase/android/nativesdk/OpenIntentCallback.kt
================================================
package com.coinbase.android.nativesdk

import android.content.Intent

interface OpenIntentCallback {
    fun call(intent: Intent)
}

================================================
FILE: android/walletsdk/src/main/java/com/coinbase/android/nativesdk/key/KeyManager.kt
================================================
package com.coinbase.android.nativesdk.key

import KeyStore
import android.content.Context
import com.google.crypto.tink.subtle.EllipticCurves
import java.security.KeyPair
import java.security.interfaces.ECPrivateKey
import java.security.interfaces.ECPublicKey

private const val OWN_KEY_PAIR_ALIAS = "own_key_pair"

internal class KeyManager(appContext: Context, host: String) {

    private val keyStore: KeyStore
    private var ownKeyPair: KeyPair? = null

    val ownPublicKey: ECPublicKey
        get() {
            val own = ownKeyPair ?: getOrCreateKeyPair(OWN_KEY_PAIR_ALIAS)
            if (ownKeyPair == null) ownKeyPair = own
            return own.public as ECPublicKey
        }

    val ownPrivateKey: ECPrivateKey
        get() {
            val own = ownKeyPair ?: getOrCreateKeyPair(OWN_KEY_PAIR_ALIAS)
            if (ownKeyPair == null) ownKeyPair = own
            return own.private as ECPrivateKey
        }

    val peerPublicKey: ECPublicKey?
        get() = keyStore.peerPublicKey

    init {
        keyStore = KeyStore(
            fileName = "${host}_wallet_segue_key_store",
            context = appContext
        )
    }

    fun storePeerPublicKey(key: ECPublicKey) {
        keyStore.peerPublicKey = key
    }

    fun resetKeys() {
        keyStore.reset()

        // Create new KeyPair
        ownKeyPair = getOrCreateKeyPair(OWN_KEY_PAIR_ALIAS)
    }

    private fun deleteKeyPair(alias: String) {
        keyStore.deleteKeyPair(alias)
    }

    private fun getOrCreateKeyPair(alias: String): KeyPair {
        val keyPair = keyStore.getKeyPair(alias)
        return if (keyPair != null) {
            // Already have keys in encrypted storage
            keyPair
        } else {
            // Generate new key pair and save to encrypted storage
            val kp = EllipticCurves.generateKeyPair(EllipticCurves.CurveType.NIST_P256)
            keyStore.saveKeyPair(alias, kp)
            kp
        }
    }
}

================================================
FILE: android/walletsdk/src/main/java/com/coinbase/android/nativesdk/key/KeyStore.kt
================================================
import android.app.KeyguardManager
import android.content.Context
import android.content.SharedPreferences
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import android.security.keystore.UserNotAuthenticatedException
import android.util.Log
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKeys
import com.coinbase.android.nativesdk.CoinbaseWalletSDKError
import com.google.crypto.tink.subtle.Base64
import com.google.crypto.tink.subtle.EllipticCurves
import java.security.KeyPair
import java.security.KeyStore
import java.security.interfaces.ECPublicKey

private const val DEPRECATED_MAIN_KEY_ALIAS = "wallet_segue_main_key"
private const val HAS_MIGRATED_TO_VERSION_120_ALIAS = "has_migrated_to_version_1.2.0"

private const val PUBLIC_KEY_ALIAS = "public_key"
private const val PRIVATE_KEY_ALIAS = "private_key"
private const val PEER_PUBLIC_KEY_ALIAS = "peer_public_key"
private const val OWN_KEY_PAIR_ALIAS = "own_key_pair"

class KeyStore(
    private val fileName: String,
    private val context: Context
) {
    private val storage: SharedPreferences

    var peerPublicKey: ECPublicKey?
        get() {
            val encoded = storage.getString(PEER_PUBLIC_KEY_ALIAS, null) ?: return null
            val bytes = Base64.decode(encoded)
            return EllipticCurves.getEcPublicKey(bytes)
        }
        set(value) {
            if (value != null) {
                val encoded = Base64.encode(value.encoded)
                storage.edit()
                    .putString(PEER_PUBLIC_KEY_ALIAS, encoded)
                    .commit()
            }
        }

    init {
        storage = getSharedPrefs()
    }

    fun getKeyPair(alias: String): KeyPair? {
        val publicKeyAlias = "${alias}-${PUBLIC_KEY_ALIAS}"
        val privateKeyAlias = "${alias}-${PRIVATE_KEY_ALIAS}"

        val publicKeyB64 = storage.getString(publicKeyAlias, null)
        val privateKeyB64 = storage.getString(privateKeyAlias, null)

        return if (publicKeyB64 != null && privateKeyB64 != null) {
            // Already have keys in encrypted storage
            val publicKeyBytes = Base64.decode(publicKeyB64)
            val privateKeyBytes = Base64.decode(privateKeyB64)

            KeyPair(
                EllipticCurves.getEcPublicKey(publicKeyBytes),
                EllipticCurves.getEcPrivateKey(privateKeyBytes)
            )
        } else {
            null
        }
    }

    fun saveKeyPair(alias: String, keyPair: KeyPair) {
        val publicKeyAlias = "${alias}-${PUBLIC_KEY_ALIAS}"
        val privateKeyAlias = "${alias}-${PRIVATE_KEY_ALIAS}"

        storage
            .edit()
            .putString(publicKeyAlias, Base64.encode(keyPair.public.encoded))
            .putString(privateKeyAlias, Base64.encode(keyPair.private.encoded))
            .commit()
    }

    fun deleteKeyPair(alias: String) {
        val publicKeyAlias = "${alias}-${PUBLIC_KEY_ALIAS}"
        val privateKeyAlias = "${alias}-${PRIVATE_KEY_ALIAS}"

        storage.edit()
            .remove(publicKeyAlias)
            .remove(privateKeyAlias)
            .commit()
    }

    fun reset() {
        val publicKeyAlias = "${OWN_KEY_PAIR_ALIAS}-${PUBLIC_KEY_ALIAS}"
        val privateKeyAlias = "${OWN_KEY_PAIR_ALIAS}-${PRIVATE_KEY_ALIAS}"

        storage.edit()
            .remove(publicKeyAlias)
            .remove(privateKeyAlias)
            .remove(PEER_PUBLIC_KEY_ALIAS)
            .commit()
    }

    private fun getSharedPrefs(): SharedPreferences {
        val sharedPrefs = context.getSharedPreferences("${fileName}_raw", Context.MODE_PRIVATE)
        val hasMigratedToVersion120 = sharedPrefs.getBoolean(HAS_MIGRATED_TO_VERSION_120_ALIAS, false)

        if (!hasMigratedToVersion120) {
            try {
                // Perform the migration
                migrateEncryptedPrefs(sharedPrefs)
            } catch (e: Exception) {
                // Clear Shared Prefs State
                sharedPrefs.edit().clear().commit()
            } finally {
                // Mark as migrated
                sharedPrefs.edit().putBoolean(HAS_MIGRATED_TO_VERSION_120_ALIAS, true).commit()
            }
        }

        return sharedPrefs
    }

    private fun migrateEncryptedPrefs(newPrefs: SharedPreferences) {
        // 1. Open the old EncryptedSharedPreferences
        val encryptedPrefs = getEncryptedPrefs()

        // 2. Copy all string typed key-value pairs from encrypted prefs to new prefs in plain text
        val allEntries = encryptedPrefs.all
        for ((key, value) in allEntries) {
            if (value != null) {
                when (value) {
                    is String  -> newPrefs.edit().putString(key, value).commit()
                }
            }
        }

        // 3. Clear the old EncryptedSharedPreferences
        encryptedPrefs.edit().clear().commit()
    }

    private fun getEncryptedPrefs(): SharedPreferences {
        // Create main key that secures encrypted storage
        val purposes = KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT

        val keyGenSpec = with(KeyGenParameterSpec.Builder(DEPRECATED_MAIN_KEY_ALIAS, purposes)) {
            val keyguard = context.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
            if (keyguard.isDeviceSecure) {
                setUserAuthenticationRequired(true)
                setUserAuthenticationValidityDurationSeconds(172_800) // 2 days
            }

            setBlockModes(KeyProperties.BLOCK_MODE_GCM)
            setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
            setKeySize(256)
            build()
        }

        val mainKey = MasterKeys.getOrCreate(keyGenSpec)

        return EncryptedSharedPreferences.create(
            fileName,
            mainKey,
            context,
            EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
            EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
        )
    }
}

================================================
FILE: android/walletsdk/src/main/java/com/coinbase/android/nativesdk/key/PublicKeySerializer.kt
================================================
package com.coinbase.android.nativesdk.key

import com.google.crypto.tink.subtle.Base64
import com.google.crypto.tink.subtle.EllipticCurves
import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import java.security.PublicKey

internal object PublicKeySerializer : KSerializer<PublicKey> {
    override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("PublicKey", PrimitiveKind.STRING)

    override fun serialize(encoder: Encoder, value: PublicKey) = encoder.encodeString(Base64.encode(value.encoded))

    override fun deserialize(decoder: Decoder): PublicKey =
        EllipticCurves.getEcPublicKey(Base64.decode(decoder.decodeString()))
}

================================================
FILE: android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/Cipher.kt
================================================
package com.coinbase.android.nativesdk.message

import com.google.crypto.tink.subtle.AesGcmJce
import com.google.crypto.tink.subtle.Base64

internal object Cipher {
    fun encrypt(secret: ByteArray, message: String): String {
        val associatedData = "encrypted data"
        val encrypted = AesGcmJce(secret).encrypt(message.toByteArray(), associatedData.toByteArray())
        return Base64.encode(encrypted)
    }

    fun decrypt(secret: ByteArray, encryptedMessage: String): String {
        val encryptedBytes = Base64.decode(encryptedMessage)
        val associatedData = "encrypted data"
        val decryptedBytes = AesGcmJce(secret).decrypt(encryptedBytes, associatedData.toByteArray())
        return String(decryptedBytes)
    }
}

================================================
FILE: android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/DateSerializer.kt
================================================
package com.coinbase.android.nativesdk.message

import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import java.util.Date

internal object DateSerializer : KSerializer<Date> {
    override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.LONG)
    override fun serialize(encoder: Encoder, value: Date) = encoder.encodeLong(value.time)
    override fun deserialize(decoder: Decoder): Date = Date(decoder.decodeLong())
}

================================================
FILE: android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/JSON.kt
================================================
package com.coinbase.android.nativesdk.message

import kotlinx.serialization.json.Json

internal val JSON = Json {
    encodeDefaults = true
    classDiscriminator = "#wsegue_type"
}

================================================
FILE: android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/Message.kt
================================================
package com.coinbase.android.nativesdk.message

import com.coinbase.android.nativesdk.key.PublicKeySerializer
import kotlinx.serialization.Serializable
import java.security.PublicKey
import java.util.Date

@Serializable
data class Message<Content>(
    val uuid: String,
    val version: String,
    @Serializable(with = PublicKeySerializer::class)
    val sender: PublicKey,
    val content: Content,
    @Serializable(with = DateSerializer::class)
    val timestamp: Date,
    val callbackUrl: String?
) {
    fun <T> copy(newContent: T): Message<T> {
        return Message(
            uuid = uuid,
            version = version,
            sender = sender,
            content = newContent,
            timestamp = timestamp,
            callbackUrl = callbackUrl
        )
    }
}

================================================
FILE: android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/MessageConverter.kt
================================================
package com.coinbase.android.nativesdk.message

import android.net.Uri
import com.google.crypto.tink.subtle.EllipticCurves
import java.security.interfaces.ECPrivateKey
import java.security.interfaces.ECPublicKey

interface MessageConverter<UnencryptedMessageType, EncryptedMessageType> {

    fun encode(
        message: UnencryptedMessageType,
        recipient: Uri,
        ownPrivateKey: ECPrivateKey? = null,
        peerPublicKey: ECPublicKey? = null
    ): Uri

    fun decode(
        url: Uri,
        ownPublicKey: ECPublicKey? = null,
        ownPrivateKey: ECPrivateKey? = null,
        peerPublicKey: ECPublicKey? = null
    ): UnencryptedMessageType

    fun decodeWithoutDecryption(url: Uri): EncryptedMessageType

    fun getSharedSecret(
        ownPublicKey: ECPublicKey? = null,
        ownPrivateKey: ECPrivateKey? = null,
        peerPublicKey: ECPublicKey? = null,
        messageSender: ECPublicKey? = null,
    ): ByteArray? {
        val myPrivateKey = ownPrivateKey ?: return null
        val otherPublicKey = (peerPublicKey ?: messageSender) ?: return null

        if (otherPublicKey == ownPublicKey) {
            return null
        }

        return EllipticCurves.computeSharedSecret(myPrivateKey, otherPublicKey)
    }
}

================================================
FILE: android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/request/Account.kt
================================================
package com.coinbase.android.nativesdk.message.request

import kotlinx.serialization.Serializable

@Serializable
class Account(
    val chain: String,
    val networkId: Long,
    val address: String
)

================================================
FILE: android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/request/Action.kt
================================================
package com.coinbase.android.nativesdk.message.request

import kotlinx.serialization.Serializable

@Serializable
class Action {
    val method: String
    private val paramsJson: String
    private val optional: Boolean

    constructor(method: String, paramsJson: String, optional: Boolean = false) {
        this.method = method
        this.paramsJson = paramsJson
        this.optional = optional
    }

    constructor(rpc: Web3JsonRPC, optional: Boolean = false) {
        val (method, paramsJson) = rpc.asJson
        this.method = method
        this.paramsJson = paramsJson
        this.optional = optional
    }

    override fun equals(other: Any?): Boolean {
        return if (other !is Action) {
            false
        } else {
            // Compare the data members and return accordingly
            this.method == other.method && this.paramsJson == other.paramsJson &&
                    this.optional == other.optional
        }
    }

    override fun hashCode(): Int {
        var result = method.hashCode()
        result = 31 * result + paramsJson.hashCode()
        result = 31 * result + optional.hashCode()
        return result
    }
}

================================================
FILE: android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/request/EncryptedRequestMessage.kt
================================================
package com.coinbase.android.nativesdk.message.request

import com.coinbase.android.nativesdk.CoinbaseWalletSDKError
import com.coinbase.android.nativesdk.message.Cipher
import com.coinbase.android.nativesdk.message.JSON
import com.coinbase.android.nativesdk.message.Message
import kotlinx.serialization.EncodeDefault
import kotlinx.serialization.EncodeDefault.Mode.NEVER
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString

typealias EncryptedRequestMessage = Message<EncryptedRequestContent>

@Serializable
data class EncryptedRequest(val data: String)

@OptIn(ExperimentalSerializationApi::class)
@Serializable
data class EncryptedRequestContent(
    @EncodeDefault(NEVER) val handshake: RequestContent.Handshake? = null,
    @EncodeDefault(NEVER) val request: EncryptedRequest? = null
)

fun EncryptedRequestMessage.decrypt(secret: ByteArray?): UnencryptedRequestMessage {
    val content = when {
        this.content.handshake != null -> {
            UnencryptedRequestContent(handshake = this.content.handshake)
        }
        this.content.request != null -> {
            if (secret == null) throw CoinbaseWalletSDKError.MissingSharedSecret

            val requestJson = Cipher.decrypt(secret, this.content.request.data)
            val request: RequestContent.Request = JSON.decodeFromString(requestJson)
            UnencryptedRequestContent(request = request)
        }
        else -> throw CoinbaseWalletSDKError.DecodingFailed
    }

    return copy(newContent = content)
}

================================================
FILE: android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/request/RequestConverter.kt
================================================
package com.coinbase.android.nativesdk.message.request

import android.net.Uri
import com.coinbase.android.nativesdk.CoinbaseWalletSDKError
import com.coinbase.android.nativesdk.message.MessageConverter
import com.coinbase.android.nativesdk.message.JSON
import com.google.crypto.tink.subtle.Base64
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import java.security.interfaces.ECPrivateKey
import java.security.interfaces.ECPublicKey

object RequestConverter : MessageConverter<UnencryptedRequestMessage, EncryptedRequestMessage> {

    override fun encode(
        message: UnencryptedRequestMessage,
        recipient: Uri,
        ownPrivateKey: ECPrivateKey?,
        peerPublicKey: ECPublicKey?
    ): Uri {
        val secret = getSharedSecret(ownPrivateKey = ownPrivateKey, peerPublicKey = peerPublicKey)
        val encrypted = message.encrypt(secret)
        val json = JSON.encodeToString(encrypted)

        return recipient.buildUpon()
            .appendQueryParameter("p", Base64.encode(json.toByteArray()))
            .build()
    }

    override fun decode(
        url: Uri,
        ownPublicKey: ECPublicKey?,
        ownPrivateKey: ECPrivateKey?,
        peerPublicKey: ECPublicKey?
    ): UnencryptedRequestMessage {
        val decoded = decodeWithoutDecryption(url)
        val secret = getSharedSecret(
            ownPublicKey = ownPublicKey,
            ownPrivateKey = ownPrivateKey,
            peerPublicKey = peerPublicKey,
            messageSender = decoded.sender as ECPublicKey
        )

        return decoded.decrypt(secret)
    }

    override fun decodeWithoutDecryption(url: Uri): EncryptedRequestMessage {
        val encoded = url.getQueryParameter("p") ?: throw CoinbaseWalletSDKError.DecodingFailed
        val messageJsonString = String(Base64.decode(encoded))
        return JSON.decodeFromString(messageJsonString)
    }
}

================================================
FILE: android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/request/UnencryptedRequestMessage.kt
================================================
package com.coinbase.android.nativesdk.message.request

import com.coinbase.android.nativesdk.CoinbaseWalletSDKError
import com.coinbase.android.nativesdk.message.Cipher
import com.coinbase.android.nativesdk.message.JSON
import com.coinbase.android.nativesdk.message.Message
import kotlinx.serialization.EncodeDefault
import kotlinx.serialization.EncodeDefault.Mode.NEVER
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString

typealias UnencryptedRequestMessage = Message<UnencryptedRequestContent>

sealed interface RequestContent {
    @Serializable
    data class Handshake(
        val appId: String,
        val callback: String,
        val appName: String? = null,
        val appIconUrl: String? = null,
        val initialActions: List<Action>? = null
    ) : RequestContent

    @Serializable
    data class Request(
        val actions: List<Action>,
        val account: Account? = null
    ) : RequestContent
}

@OptIn(ExperimentalSerializationApi::class)
@Serializable
data class UnencryptedRequestContent(
    @EncodeDefault(NEVER) val handshake: RequestContent.Handshake? = null,
    @EncodeDefault(NEVER) val request: RequestContent.Request? = null
) {
    val sealed get() = handshake ?: request ?: throw IllegalStateException()
}

fun UnencryptedRequestMessage.encrypt(secret: ByteArray?): EncryptedRequestMessage {
    val encryptedContent = when (val content = this.content.sealed) {
        is RequestContent.Handshake -> {
            EncryptedRequestContent(handshake = content)
        }
        is RequestContent.Request -> {
            if (secret == null) throw CoinbaseWalletSDKError.MissingSharedSecret

            val requestJson = JSON.encodeToString(content)
            val encrypted = Cipher.encrypt(secret, requestJson)
            EncryptedRequestContent(request = EncryptedRequest(encrypted))
        }
    }

    return copy(newContent = encryptedContent)
}

================================================
FILE: android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/request/Web3JsonRPC.kt
================================================
package com.coinbase.android.nativesdk.message.request

import com.coinbase.android.nativesdk.message.JSON
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString

private typealias BigInt = String

const val ETH_REQUEST_ACCOUNTS = "eth_requestAccounts"
const val PERSONAL_SIGN = "personal_sign"
const val ETH_SIGN_TYPED_DATA_V3 = "eth_signTypedData_v3"
const val ETH_SIGN_TYPED_DATA_V4 = "eth_signTypedData_v4"
const val ETH_SIGN_TRANSACTION = "eth_signTransaction"
const val ETH_SEND_TRANSACTION = "eth_sendTransaction"
const val WALLET_SWITCH_ETHEREUM_CHAIN = "wallet_switchEthereumChain"
const val WALLET_ADD_ETHEREUM_CHAIN = "wallet_addEthereumChain"
const val WALLET_WATCH_ASSET = "wallet_watchAsset"

val nonHandshakeActions = listOf(ETH_SEND_TRANSACTION, ETH_SIGN_TRANSACTION)

@Suppress("unused")
@Serializable
sealed class Web3JsonRPC {

    @Serializable
    @SerialName(ETH_REQUEST_ACCOUNTS)
    class RequestAccounts : Web3JsonRPC()

    @Serializable
    @SerialName(PERSONAL_SIGN)
    class PersonalSign(
        val address: String,
        val message: String
    ) : Web3JsonRPC()

    @Serializable
    @SerialName(ETH_SIGN_TYPED_DATA_V3)
    class SignTypedDataV3(
        val address: String,
        val typedDataJson: String
    ) : Web3JsonRPC()

    @Serializable
    @SerialName(ETH_SIGN_TYPED_DATA_V4)
    class SignTypedDataV4(
        val address: String,
        val typedDataJson: String
    ) : Web3JsonRPC()

    @Serializable
    @SerialName(ETH_SIGN_TRANSACTION)
    class SignTransaction(
        val fromAddress: String,
        val toAddress: String?,
        val weiValue: BigInt,
        val data: String,
        val nonce: Int?,
        val gasPriceInWei: BigInt?,
        val maxFeePerGas: BigInt?,
        val maxPriorityFeePerGas: BigInt?,
        val gasLimit: BigInt?,
        val chainId: String
    ) : Web3JsonRPC()

    @Serializable
    @SerialName(ETH_SEND_TRANSACTION)
    class SendTransaction(
        val fromAddress: String,
        val toAddress: String?,
        val weiValue: BigInt,
        val data: String,
        val nonce: Int?,
        val gasPriceInWei: BigInt?,
        val maxFeePerGas: BigInt?,
        val maxPriorityFeePerGas: BigInt?,
        val gasLimit: BigInt?,
        val chainId: String,
        val actionSource: ActionSource? = null
    ) : Web3JsonRPC()

    @Serializable
    @SerialName(WALLET_SWITCH_ETHEREUM_CHAIN)
    class SwitchEthereumChain(val chainId: String) : Web3JsonRPC()

    @Serializable
    @SerialName(WALLET_ADD_ETHEREUM_CHAIN)
    class AddEthereumChain(
        val chainId: String,
        val blockExplorerUrls: List<String>? = null,
        val chainName: String? = null,
        val iconUrls: List<String>? = null,
        val nativeCurrency: AddChainNativeCurrency? = null,
        val rpcUrls: List<String> = emptyList()
    ) : Web3JsonRPC()

    @Serializable
    @SerialName(WALLET_WATCH_ASSET)
    class WatchAsset(
        val type: String,
        val options: WatchAssetOptions
    ) : Web3JsonRPC()

    internal val asJson: Pair<String, String>
        get() {
            val json = JSON.encodeToString(this)
            val method = when (this) {
                is RequestAccounts -> ETH_REQUEST_ACCOUNTS
                is SendTransaction -> ETH_SEND_TRANSACTION
                is SignTransaction -> ETH_SIGN_TRANSACTION
                is PersonalSign -> PERSONAL_SIGN
                is SignTypedDataV3 -> ETH_SIGN_TYPED_DATA_V3
                is SignTypedDataV4 -> ETH_SIGN_TYPED_DATA_V4
                is AddEthereumChain -> WALLET_ADD_ETHEREUM_CHAIN
                is SwitchEthereumChain -> WALLET_SWITCH_ETHEREUM_CHAIN
                is WatchAsset -> WALLET_WATCH_ASSET
            }

            return method to json
        }

    fun action(optional: Boolean = false): Action = Action(rpc = this, optional = optional)
}

@Serializable
class AddChainNativeCurrency(val name: String, val symbol: String, val decimals: Int)

@Serializable
class WatchAssetOptions(val address: String, val symbol: String?, val decimals: Int?, val image: String?)

@Serializable
class ActionSource(val url: String)


================================================
FILE: android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/response/ActionResult.kt
================================================
package com.coinbase.android.nativesdk.message.response

import com.coinbase.android.nativesdk.CoinbaseWalletSDKError
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.JsonDecoder
import kotlinx.serialization.json.JsonEncoder
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.decodeFromJsonElement
import kotlinx.serialization.json.encodeToJsonElement
import kotlinx.serialization.json.jsonObject

@Serializable(with = ActionResultSerializer::class)
sealed class ActionResult {
    @Serializable
    class Result(val value: String) : ActionResult()

    @Serializable
    class Error(val code: Long, val message: String) : ActionResult()
}

internal object ActionResultSerializer : KSerializer<ActionResult> {
    override val descriptor: SerialDescriptor = buildClassSerialDescriptor("ReturnValue")

    override fun serialize(encoder: Encoder, value: ActionResult) {
        val output = encoder as? JsonEncoder ?: throw CoinbaseWalletSDKError.EncodingFailed
        val formatter = output.json

        val json = buildJsonObject {
            when (value) {
                is ActionResult.Result -> put("result", formatter.encodeToJsonElement(value))
                is ActionResult.Error -> put("error", formatter.encodeToJsonElement(value))
            }
        }

        output.encodeJsonElement(json)
    }

    override fun deserialize(decoder: Decoder): ActionResult {
        val input = decoder as? JsonDecoder ?: throw CoinbaseWalletSDKError.DecodingFailed
        val formatter = input.json
        val json = input.decodeJsonElement().jsonObject

        return when (val key = json.keys.firstOrNull()) {
            "result" -> formatter.decodeFromJsonElement<ActionResult.Result>(json.getValue(key))
            "error" -> formatter.decodeFromJsonElement<ActionResult.Error>(json.getValue(key))
            else -> throw CoinbaseWalletSDKError.DecodingFailed
        }
    }
}

================================================
FILE: android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/response/EncryptedResponseMessage.kt
================================================
package com.coinbase.android.nativesdk.message.response

import com.coinbase.android.nativesdk.CoinbaseWalletSDKError
import com.coinbase.android.nativesdk.message.Cipher
import com.coinbase.android.nativesdk.message.JSON
import com.coinbase.android.nativesdk.message.Message
import kotlinx.serialization.EncodeDefault
import kotlinx.serialization.EncodeDefault.Mode.NEVER
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString

typealias EncryptedResponseMessage = Message<EncryptedResponseContent>

@Serializable
data class EncryptedResponse(
    val requestId: String? = null,
    val data: String
)

@OptIn(ExperimentalSerializationApi::class)
@Serializable
data class EncryptedResponseContent(
    @EncodeDefault(NEVER) val response: EncryptedResponse? = null,
    @EncodeDefault(NEVER) val failure: ResponseContent.Failure? = null
)

fun EncryptedResponseMessage.decrypt(secret: ByteArray?): UnencryptedResponseMessage {
    val content: UnencryptedResponseContent = when {
        this.content.failure != null -> {
            UnencryptedResponseContent(failure = this.content.failure)
        }
        this.content.response != null -> {
            if (secret == null) throw CoinbaseWalletSDKError.MissingSharedSecret

            val responseJson = Cipher.decrypt(secret, this.content.response.data)
            val response: ResponseContent.Response = JSON.decodeFromString(responseJson)
            UnencryptedResponseContent(response = response)
        }
        else -> throw CoinbaseWalletSDKError.DecodingFailed
    }

    return copy(newContent = content)
}


================================================
FILE: android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/response/Response.kt
================================================
package com.coinbase.android.nativesdk.message.response

typealias ResponseResult = Result<List<ActionResult>>
typealias ResponseHandler = (ResponseResult) -> Unit

================================================
FILE: android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/response/ResponseCallback.kt
================================================
package com.coinbase.android.nativesdk.message.response

import com.coinbase.android.nativesdk.message.request.Account

interface SuccessHandshakeResponseCallback {
    fun call(result: List<ActionResult>, account: Account?)
}

interface SuccessRequestResponseCallback {
    fun call(result: List<ActionResult>)
}

interface FailureResponseCallback {
    fun call(error: Throwable)
}


================================================
FILE: android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/response/ResponseConverter.kt
================================================
package com.coinbase.android.nativesdk.message.response

import android.net.Uri
import com.coinbase.android.nativesdk.CoinbaseWalletSDKError
import com.coinbase.android.nativesdk.message.MessageConverter
import com.coinbase.android.nativesdk.message.JSON
import com.google.crypto.tink.subtle.Base64
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import java.security.interfaces.ECPrivateKey
import java.security.interfaces.ECPublicKey

object ResponseConverter : MessageConverter<UnencryptedResponseMessage, EncryptedResponseMessage> {

    override fun encode(
        message: UnencryptedResponseMessage,
        recipient: Uri,
        ownPrivateKey: ECPrivateKey?,
        peerPublicKey: ECPublicKey?
    ): Uri {
        val secret = getSharedSecret(ownPrivateKey = ownPrivateKey, peerPublicKey = peerPublicKey)
        val encrypted = message.encrypt(secret)
        val json = JSON.encodeToString(encrypted)

        return recipient.buildUpon()
            .appendQueryParameter("p", Base64.encode(json.toByteArray()))
            .build()
    }

    override fun decode(
        url: Uri,
        ownPublicKey: ECPublicKey?,
        ownPrivateKey: ECPrivateKey?,
        peerPublicKey: ECPublicKey?
    ): UnencryptedResponseMessage {
        val decoded = decodeWithoutDecryption(url)
        val secret = getSharedSecret(
            ownPublicKey = ownPublicKey,
            ownPrivateKey = ownPrivateKey,
            peerPublicKey = peerPublicKey,
            messageSender = decoded.sender as ECPublicKey
        )

        return decoded.decrypt(secret)
    }

    override fun decodeWithoutDecryption(url: Uri): EncryptedResponseMessage {
        val encoded = url.getQueryParameter("p") ?: throw CoinbaseWalletSDKError.DecodingFailed
        val messageJsonString = String(Base64.decode(encoded))
        return JSON.decodeFromString(messageJsonString)
    }
}

================================================
FILE: android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/response/UnencryptedResponseMessage.kt
================================================
package com.coinbase.android.nativesdk.message.response

import com.coinbase.android.nativesdk.CoinbaseWalletSDKError
import com.coinbase.android.nativesdk.message.Cipher
import com.coinbase.android.nativesdk.message.JSON
import com.coinbase.android.nativesdk.message.Message
import kotlinx.serialization.EncodeDefault
import kotlinx.serialization.EncodeDefault.Mode.NEVER
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString

typealias UnencryptedResponseMessage = Message<UnencryptedResponseContent>

sealed interface ResponseContent {
    @Serializable
    data class Response(
        val requestId: String,
        val values: List<ActionResult>
    ) : ResponseContent

    @Serializable
    data class Failure(
        val requestId: String,
        val description: String
    ) : ResponseContent
}

@OptIn(ExperimentalSerializationApi::class)
@Serializable
data class UnencryptedResponseContent(
    @EncodeDefault(NEVER) val failure: ResponseContent.Failure? = null,
    @EncodeDefault(NEVER) val response: ResponseContent.Response? = null
) {
    val sealed get() = failure ?: response ?: throw IllegalStateException()
}

fun UnencryptedResponseMessage.encrypt(secret: ByteArray?): EncryptedResponseMessage {
    val encryptedContent: EncryptedResponseContent = when (val content = this.content.sealed) {
        is ResponseContent.Failure -> {
            EncryptedResponseContent(failure = content)
        }
        is ResponseContent.Response -> {
            if (secret == null) throw CoinbaseWalletSDKError.MissingSharedSecret

            val responseJson = JSON.encodeToString(content)
            val encrypted = Cipher.encrypt(secret, responseJson)
            EncryptedResponseContent(
                response = EncryptedResponse(
                    requestId = content.requestId,
                    data = encrypted
                )
            )
        }
    }

    return copy(newContent = encryptedContent)
}

================================================
FILE: android/walletsdk/src/main/java/com/coinbase/android/nativesdk/task/Task.kt
================================================
package com.coinbase.android.nativesdk.task

import com.coinbase.android.nativesdk.message.request.UnencryptedRequestMessage
import com.coinbase.android.nativesdk.message.response.ResponseHandler
import java.util.Date

internal class Task(
    val request: UnencryptedRequestMessage,
    val handler: ResponseHandler,
    val timestamp: Date
)

================================================
FILE: android/walletsdk/src/main/java/com/coinbase/android/nativesdk/task/TaskManager.kt
================================================
package com.coinbase.android.nativesdk.task

import com.coinbase.android.nativesdk.CoinbaseWalletSDKError
import com.coinbase.android.nativesdk.message.request.UnencryptedRequestMessage
import com.coinbase.android.nativesdk.message.response.ResponseContent
import com.coinbase.android.nativesdk.message.response.ResponseHandler
import com.coinbase.android.nativesdk.message.response.ResponseResult
import com.coinbase.android.nativesdk.message.response.UnencryptedResponseMessage

internal class TaskManager {
    private val tasks = HashMap<String, Task>()

    fun registerResponseHandler(message: UnencryptedRequestMessage, handler: ResponseHandler) {
        tasks[message.uuid] = Task(
            request = message,
            handler = handler,
            timestamp = message.timestamp
        )
    }

    fun handleResponse(message: UnencryptedResponseMessage): Boolean {
        val requestId: String
        val result: ResponseResult = when (val response = message.content.sealed) {
            is ResponseContent.Response -> {
                requestId = response.requestId
                Result.success(response.values)
            }
            is ResponseContent.Failure -> {
                requestId = response.requestId
                Result.failure(CoinbaseWalletSDKError.WalletReturnedError(response.description))
            }
        }

        val task = tasks[requestId] ?: return false

        task.handler(result)
        tasks.remove(requestId)
        return true
    }

    fun reset(){
        tasks.clear()
    }
}

================================================
FILE: android/walletsdk/src/test/java/com/coinbase/android/nativesdk/ExampleUnitTest.kt
================================================
package com.coinbase.android.nativesdk

import org.junit.Test

import org.junit.Assert.*

/**
 * Example local unit test, which will execute on the development machine (host).
 *
 * See [testing documentation](http://d.android.com/tools/testing).
 */
class ExampleUnitTest {
    @Test
    fun addition_isCorrect() {
        assertEquals(4, 2 + 2)
    }
}

================================================
FILE: android/walletsdk/src/test/java/com/coinbase/android/nativesdk/helper/InputStreamExtensions.kt
================================================
package com.coinbase.android.nativesdk.helper

import java.io.IOException
import java.io.InputStream

@Throws(IOException::class)
fun InputStream?.readFileWithNewLineFromResources(): String {
    return this?.bufferedReader()
        .use { bufferReader ->
            val builder = StringBuilder()
            var str: String? = bufferReader?.readLine()
            while (str != null) {
                builder.append(str)
                str = bufferReader?.readLine()
            }
            builder.toString().replace(" ", "")
        }
}



================================================
FILE: android/walletsdk/src/test/java/com/coinbase/android/nativesdk/message/request/Web3JsonRPCTest.kt
================================================
package com.coinbase.android.nativesdk.message.request

import com.coinbase.android.nativesdk.helper.readFileWithNewLineFromResources
import io.kotest.matchers.shouldBe
import org.junit.Test

private const val typedData =
    "{\"types\":{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"},{\"name\":\"salt\",\"type\":\"bytes32\"}],\"Bid\":[{\"name\":\"amount\",\"type\":\"uint256\"},{\"name\":\"bidder\",\"type\":\"Identity\"}],\"Identity\":[{\"name\":\"userId\",\"type\":\"uint256\"},{\"name\":\"wallet\",\"type\":\"address\"}]},\"domain\":{\"name\":\"DApp Browser Test DApp\",\"version\":\"1\",\"chainId\":1,\"verifyingContract\":\"0x1C56346CD2A2Bf3202F771f50d3D14a367B48070\",\"salt\":\"0xf2d857f4a3edcb9b78b4d503bfe733db1e3f6cdc2b7971ee739626c97e86a558\"},\"primaryType\":\"Bid\",\"message\":{\"amount\":100,\"bidder\":{\"userId\":323,\"wallet\":\"0x3333333333333333333333333333333333333333\"}}}"

class Web3JsonRPCTest {

    @Test
    fun action_Test_Eth_Request_Accounts_Action() {
        val expectedAction = Action(
            method = "eth_requestAccounts",
            paramsJson = "{\"#wsegue_type\":\"eth_requestAccounts\"}",
            optional = false
        )

        val action = Web3JsonRPC.RequestAccounts().action()
        action shouldBe expectedAction
    }

    @Test
    fun action_Test_Personal_Sign_Action() {
        val inputStream = javaClass.classLoader?.getResourceAsStream("personal_sign.json")
        val personalSignJson = inputStream.readFileWithNewLineFromResources()
        val expectedAction = Action(
            method = "personal_sign",
            paramsJson = personalSignJson,
            optional = false
        )

        val action = Web3JsonRPC.PersonalSign("0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", "hello").action()
        action shouldBe expectedAction
    }

    @Test
    fun action_Test_Sign_TypedData_V3_Action() {
        val inputStream = javaClass.classLoader?.getResourceAsStream("sign_typed_data_v3.json")
        val paramsJson = inputStream.readFileWithNewLineFromResources()
        val expectedAction = Action(
            method = "eth_signTypedData_v3",
            paramsJson = paramsJson.replace("DAppBrowserTestDApp", "DApp Browser Test DApp"),
            optional = false
        )
        val action = Web3JsonRPC.SignTypedDataV3("0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", typedData).action()
        action shouldBe expectedAction
    }

    @Test
    fun action_Test_Sign_TypedData_V4_Action() {
        val inputStream = javaClass.classLoader?.getResourceAsStream("sign_typed_data_v4.json")
        val paramsJson = inputStream.readFileWithNewLineFromResources()
        val expectedAction = Action(
            method = "eth_signTypedData_v4",
            paramsJson = paramsJson.replace("DAppBrowserTestDApp", "DApp Browser Test DApp"),
            optional = false
        )

        val action = Web3JsonRPC.SignTypedDataV4("0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", typedData).action()
        action shouldBe expectedAction
    }

    @Test
    fun action_Test_Sign_Transaction_Action() {
        val inputStream = javaClass.classLoader?.getResourceAsStream("sign_transaction.json")
        val paramsJson = inputStream.readFileWithNewLineFromResources()
        val expectedAction = Action(
            method = ETH_SIGN_TRANSACTION,
            paramsJson = paramsJson,
            optional = false
        )

        val action = Web3JsonRPC.SignTransaction(
            fromAddress = "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
            toAddress = "0x571a6a108adb08f9ca54fe8605280f9ee0ed4af6",
            weiValue = "10000000000000",
            data = "0x",
            nonce = null,
            gasPriceInWei = null,
            maxFeePerGas = null,
            maxPriorityFeePerGas = null,
            gasLimit = "1000",
            chainId = "1",
        ).action()
        action shouldBe expectedAction
    }

    @Test
    fun action_Test_Send_Transaction_Action() {
        val inputStream = javaClass.classLoader?.getResourceAsStream("send_transaction.json")
        val paramsJson = inputStream.readFileWithNewLineFromResources()
        val expectedAction = Action(
            method = ETH_SEND_TRANSACTION,
            paramsJson = paramsJson,
            optional = false
        )

        val action = Web3JsonRPC.SendTransaction(
            fromAddress = "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
            toAddress = "0x571a6a108adb08f9ca54fe8605280f9ee0ed4af6",
            weiValue = "10000000000000",
            data = "0x",
            nonce = null,
            gasPriceInWei = null,
            maxFeePerGas = null,
            maxPriorityFeePerGas = null,
            gasLimit = "1000",
            chainId = "1",
        ).action()
        action shouldBe expectedAction
    }

    @Test
    fun action_Test_Switch_Chain_Action() {
        val expectedAction = Action(
            method = WALLET_SWITCH_ETHEREUM_CHAIN,
            paramsJson = "{\"#wsegue_type\":\"wallet_switchEthereumChain\",\"chainId\":\"1\"}",
            optional = false
        )

        val action = Web3JsonRPC.SwitchEthereumChain(chainId = "1").action()
        action shouldBe expectedAction
    }

    @Test
    fun action_Test_Add_Chain_Action() {
        val inputStream = javaClass.classLoader?.getResourceAsStream("add_chain.json")
        val paramsJson = inputStream.readFileWithNewLineFromResources()
        val expectedAction = Action(
            method = WALLET_ADD_ETHEREUM_CHAIN,
            paramsJson = paramsJson,
            optional = false
        )

        val action = Web3JsonRPC.AddEthereumChain(chainId = "137").action()
        action shouldBe expectedAction
    }

    @Test
    fun action_Test_Watch_Asset_Action() {
        val inputStream = javaClass.classLoader?.getResourceAsStream("watch_asset.json")
        val paramsJson = inputStream.readFileWithNewLineFromResources()
        val expectedAction = Action(
            method = WALLET_WATCH_ASSET,
            paramsJson = paramsJson,
            optional = false
        )

        val action = Web3JsonRPC.WatchAsset(
            type = "type",
            options = WatchAssetOptions(
                address = "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
                symbol = "APE",
                decimals = 3,
                image = "image_site"
            )
        ).action()
        action shouldBe expectedAction
    }
}


================================================
FILE: android/walletsdk/src/test/resources/add_chain.json
================================================
{
  "#wsegue_type": "wallet_addEthereumChain",
  "chainId": "137",
  "blockExplorerUrls": null,
  "chainName": null,
  "iconUrls": null,
  "nativeCurrency": null,
  "rpcUrls": []
}

================================================
FILE: android/walletsdk/src/test/resources/personal_sign.json
================================================
{
  "#wsegue_type": "personal_sign",
  "address": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
  "message": "hello"
}

================================================
FILE: android/walletsdk/src/test/resources/send_transaction.json
================================================
{
  "#wsegue_type": "eth_sendTransaction",
  "fromAddress": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
  "toAddress": "0x571a6a108adb08f9ca54fe8605280f9ee0ed4af6",
  "weiValue": "10000000000000",
  "data": "0x",
  "nonce": null,
  "gasPriceInWei": null,
  "maxFeePerGas": null,
  "maxPriorityFeePerGas": null,
  "gasLimit": "1000",
  "chainId": "1"
}

================================================
FILE: android/walletsdk/src/test/resources/sign_transaction.json
================================================
{
  "#wsegue_type": "eth_signTransaction",
  "fromAddress": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
  "toAddress": "0x571a6a108adb08f9ca54fe8605280f9ee0ed4af6",
  "weiValue": "10000000000000",
  "data": "0x",
  "nonce": null,
  "gasPriceInWei": null,
  "maxFeePerGas": null,
  "maxPriorityFeePerGas": null,
  "gasLimit": "1000",
  "chainId": "1"
}

================================================
FILE: android/walletsdk/src/test/resources/sign_typed_data_v3.json
================================================
{
  "#wsegue_type": "eth_signTypedData_v3",
  "address": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
  "typedDataJson": "{\"types\":{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"},{\"name\":\"salt\",\"type\":\"bytes32\"}],\"Bid\":[{\"name\":\"amount\",\"type\":\"uint256\"},{\"name\":\"bidder\",\"type\":\"Identity\"}],\"Identity\":[{\"name\":\"userId\",\"type\":\"uint256\"},{\"name\":\"wallet\",\"type\":\"address\"}]},\"domain\":{\"name\":\"DApp Browser Test DApp\",\"version\":\"1\",\"chainId\":1,\"verifyingContract\":\"0x1C56346CD2A2Bf3202F771f50d3D14a367B48070\",\"salt\":\"0xf2d857f4a3edcb9b78b4d503bfe733db1e3f6cdc2b7971ee739626c97e86a558\"},\"primaryType\":\"Bid\",\"message\":{\"amount\":100,\"bidder\":{\"userId\":323,\"wallet\":\"0x3333333333333333333333333333333333333333\"}}}"
}

================================================
FILE: android/walletsdk/src/test/resources/sign_typed_data_v4.json
================================================
{
  "#wsegue_type": "eth_signTypedData_v4",
  "address": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
  "typedDataJson": "{\"types\":{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"},{\"name\":\"salt\",\"type\":\"bytes32\"}],\"Bid\":[{\"name\":\"amount\",\"type\":\"uint256\"},{\"name\":\"bidder\",\"type\":\"Identity\"}],\"Identity\":[{\"name\":\"userId\",\"type\":\"uint256\"},{\"name\":\"wallet\",\"type\":\"address\"}]},\"domain\":{\"name\":\"DApp Browser Test DApp\",\"version\":\"1\",\"chainId\":1,\"verifyingContract\":\"0x1C56346CD2A2Bf3202F771f50d3D14a367B48070\",\"salt\":\"0xf2d857f4a3edcb9b78b4d503bfe733db1e3f6cdc2b7971ee739626c97e86a558\"},\"primaryType\":\"Bid\",\"message\":{\"amount\":100,\"bidder\":{\"userId\":323,\"wallet\":\"0x3333333333333333333333333333333333333333\"}}}"
}

================================================
FILE: android/walletsdk/src/test/resources/watch_asset.json
================================================
{
  "#wsegue_type": "wallet_watchAsset",
  "type": "type",
  "options": {
    "address": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
    "symbol": "APE",
    "decimals": 3,
    "image": "image_site"
  }
}

================================================
FILE: docs/.gitignore
================================================
# Dependencies
/node_modules

# Production
/build

# Generated files
.docusaurus
.cache-loader

# Misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*


================================================
FILE: docs/babel.config.js
================================================
module.exports = {
  presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
};


================================================
FILE: docs/docs/client-sdk/android-api-reference.md
================================================
---
title: "API Reference"
slug: "android-api-reference"
category: "633d1d37bc7103008654c123"
---

# Actions

The `initiateHandshake` and `makeRequest` methods accept a list of actions to perform. An `Action` can be created using the `Web3JsonRPC` class.

Below is a list of supported actions for each method:

| Action | RPC method | initiateHandshake | makeRequest |
| :--- | :--- | :--- | :--- |
| [RequestAccounts](doc:android-api-reference#requestaccounts) | [eth_requestAccounts](https://eips.ethereum.org/EIPS/eip-1102) | ✔️ Supported | ✔️ Supported |
| [SignTransaction](doc:android-api-reference#signtransaction) | [eth_signTransaction](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_signtransaction) | ❌ Not supported | ✔️ Supported |
| [SendTransaction](doc:android-api-reference#sendtransaction) | [eth_sendTransaction](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sendtransaction) | ❌ Not supported | ✔️ Supported |
| - | [eth_sign](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign) | ❌ Not supported | ❌ Not supported |
| [PersonalSign](doc:android-api-reference#personalsign) | [personal_sign](https://eips.ethereum.org/EIPS/eip-191) | ✔️ Supported | ✔️ Supported |
| [SignTypedDataV3](doc:android-api-reference#signtypeddatav3) | [eth_signTypedData_v3](https://eips.ethereum.org/EIPS/eip-712) | ✔️ Supported | ✔️ Supported |
| [SignTypedDataV4](doc:android-api-reference#signtypeddatav4) | [eth_signTypedData_v4](https://eips.ethereum.org/EIPS/eip-712) | ✔️ Supported | ✔️ Supported |
| [SwitchEthereumChain](doc:android-api-reference#switchethereumchain) | [wallet_switchEthereumChain](https://eips.ethereum.org/EIPS/eip-3326) | ✔️ Supported | ✔️ Supported |
| [AddEthereumChain](doc:android-api-reference#addethereumchain) | [wallet_addEthereumChain](https://eips.ethereum.org/EIPS/eip-3085) | ✔️ Supported | ✔️ Supported |
| [WatchAsset](doc:android-api-reference#watchasset) | [wallet_watchAsset](https://eips.ethereum.org/EIPS/eip-747) | ✔️ Supported | ✔️ Supported |

## RequestAccounts

Request that the user provides an account in the form of an Ethereum address.

### Parameters

None.

### Example

```kotlin Kotlin
val requestAccounts = Web3JsonRPC.RequestAccounts().action()
```
```java Java
Action requestAccounts = new Web3JsonRPC.RequestAccounts().action(false);
```

## PersonalSign

Sign a message by calculating an Ethereum specific signature with: `sign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))`.

Adding a prefix to the message makes the calculated signature recognisable as an Ethereum specific signature. This prevents misuse where a malicious DApp can sign arbitrary data (e.g. transaction) and use the signature to impersonate the victim.

See [personal_sign](https://eips.ethereum.org/EIPS/eip-191).

### Parameters

| Name | Type | Description |
| :--- | :--- | :--- |
| address | `String` | Address to sign data with. |
| message | `String` | Message data to sign. |

### Example

```kotlin Kotlin
val personalSign = Web3JsonRPC.PersonalSign(
   address = "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"
   message = "0xdeadbeaf"
).action()
```
```java Java
Action personalSign = new Web3JsonRPC.PersonalSign(
       "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
       "0xdeadbeaf")
       .action(false);
```

## SignTypedDataV3

Sign typed structured data.

See [eth_signTypedData_v3](https://eips.ethereum.org/EIPS/eip-712).

### Parameters

| Name | Type | Description |
| :--- | :--- | :--- |
| address | `String` | Address to sign data with. |
| typedDataJson | `String` | Typed data to sign. Structured according to the JSON-Schema specified in [EIP-712](https://eips.ethereum.org/EIPS/eip-712). |

### Example

```kotlin Kotlin
val signTypedDataV3 = Web3JsonRPC.SignTypedDataV3(
   address = "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
   typedDataJson = typedData
).action()
```
```java Java
Action signTypedDataV3 = new Web3JsonRPC.SignTypedDataV3(
       "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
       typedData)
       .action(false);
```

## SignTypedDataV4

Sign typed structured data.

See [eth_signTypedData_v4](https://eips.ethereum.org/EIPS/eip-712).

### Parameters

| Name | Type | Description |
| :--- | :--- | :--- |
| address | `String` | Address to sign data with. |
| typedDataJson | `String` | Typed data to sign. Structured according to the JSON-Schema specified in [EIP-712](https://eips.ethereum.org/EIPS/eip-712). |

### Example

```kotlin Kotlin
val signTypedDataV4 = Web3JsonRPC.SignTypedDataV4(
   address = "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
   typedDataJson = typedData
).action()
```
```java Java
Action signTypedDataV4 = new Web3JsonRPC.SignTypedDataV4(
       "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
       typedData)
       .action(false);
```

## SignTransaction

Sign a transaction that can be submitted to the network at a later time.

See [eth_signTransaction](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_signtransaction).

### Parameters

| Name | Type | Description |
| :--- | :--- | :--- |
| fromAddress | `String` | Address the transaction is sent from. |
| toAddress | `String` | **Optional**. Address the transaction is sent to. |
| weiValue | `BigInt` | Value for the transaction, in Wei. |
| data | `String` | Compiled code of a contract or the hash of the invoked method signature and encoded parameters. |
| nonce | `Int` | **Optional**. Nonce of the transaction. Allows for overwriting pending transactions that use an identical nonce. |
| gasPriceInWei | `BigInt` | **Optional**. Gas price for the transaction, in Wei. |
| maxFeePerGas | `BigInt` | **Optional**. Maximum fee per unit of gas for the transaction. |
| maxPriorityFeePerGas | `BigInt` | **Optional**. Maximum priority fee per unit of gas for the transaction. |
| gasLimit | `BigInt` | **Optional**. Gas limit for the transaction. |
| chainId | `String` | Chain ID for the transaction, as an integer string. |

### Example

```kotlin Kotlin
val signTransaction = Web3JsonRPC.SignTransaction(
   fromAddress = "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
   toAddress = "0x000000000000000000000000000000000000dEaD",
   weiValue = "10000000000000",
   data = "0x",
   nonce = 1,
   gasPriceInWei = "30000000000",
   maxFeePerGas = "60000000000",
   maxPriorityFeePerGas = "2500000000",
   gasLimit = "1000",
   chainId = "1"
).action()
```
```java Java
Action signTransaction = new Web3JsonRPC.SignTransaction(
       "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", // fromAddress
       "0x000000000000000000000000000000000000dEaD", // toAddress
       "10000000000000", // weiValue
       "0x", // data
       1, // nonce
       "30000000000", // gasPriceInWei
       "60000000000", // maxFeePerGas
       "2500000000", // maxPriorityFeePerGas
       "1000", // gasLimit
       "1") // chainId
       .action(false);
```

## SendTransaction

Send a transaction, or create a contract if the `data` field contains code.

See [eth_sendTransaction](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sendtransaction).

### Parameters

| Name | Type | Description |
| :--- | :--- | :--- |
| fromAddress | `String` | Address the transaction is sent from. |
| toAddress | `String` | **Optional**. Address the transaction is sent to. |
| weiValue | `BigInt` | Value for the transaction, in Wei. |
| data | `String` | Compiled code of a contract or the hash of the invoked method signature and encoded parameters. |
| nonce | `Int` | **Optional**. Nonce of the transaction. Allows for overwriting pending transactions that use an identical nonce. |
| gasPriceInWei | `BigInt` | **Optional**. Gas price for the transaction, in Wei. |
| maxFeePerGas | `BigInt` | **Optional**. Maximum fee per unit of gas for the transaction. |
| maxPriorityFeePerGas | `BigInt` | **Optional**. Maximum priority fee per unit of gas for the transaction. |
| gasLimit | `BigInt` | **Optional**. Gas limit for the transaction. |
| chainId | `String` | Chain ID for the transaction, as an integer string. |

### Example

```kotlin Kotlin
val sendTransaction = Web3JsonRPC.SendTransaction(
   fromAddress = "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
   toAddress = "0x000000000000000000000000000000000000dEaD",
   weiValue = "10000000000000",
   data = "0x",
   nonce = 1,
   gasPriceInWei = "30000000000",
   maxFeePerGas = "60000000000",
   maxPriorityFeePerGas = "2500000000",
   gasLimit = "1000",
   chainId = "1"
).action()
```
```java Java
Action sendTransaction = new Web3JsonRPC.SendTransaction(
       "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", // fromAddress
       "0x000000000000000000000000000000000000dEaD", // toAddress
       "10000000000000", // weiValue
       "0x", // data
       1, // nonce
       "30000000000", // gasPriceInWei
       "60000000000", // maxFeePerGas
       "2500000000", // maxPriorityFeePerGas
       "1000", // gasLimit
       "1") // chainId
       .action(false);
```

## SwitchEthereumChain

Switch a wallet’s currently active chain.

See [wallet_switchEthereumChain](https://eips.ethereum.org/EIPS/eip-3326).

### Parameters

| Name | Type | Description |
| :--- | :--- | :--- |
| chainId | `String` | ID of the chain to switch to, as an integer string. |

### Example

```kotlin Kotlin
val switchEthereumChain = Web3JsonRPC.SwitchEthereumChain(
   chainId = "1666600000"
).action()
```
```java Java
Action switchEthereumChain = new Web3JsonRPC.SwitchEthereumChain(
       "1666600000") // chainId
       .action(false);
```

## AddEthereumChain

Add a chain to a wallet.

See [wallet_addEthereumChain](https://eips.ethereum.org/EIPS/eip-3085).

### Parameters

| Name | Type | Description |
| :--- | :--- | :--- |
| chainId | `String` | ID of the chain to add, as an integer string. |
| blockExplorerUrls | `List<String>` | **Optional**. List of block explorer URL strings. |
| chainName | `String` | **Optional**. Name of the chain to add. |
| iconUrls | `List<String>` | **Optional**. List of image icons URL strings. |
| nativeCurrency | [`AddChainNativeCurrency`](doc:android-api-reference#addchainnativecurrency) | **Optional**. Data for the chain’s native currency. |
| rpcUrls | `List<String>` | List of RPC URL strings. Defaults to an empty list. |

### Example

```kotlin Kotlin
val addEthereumChain = Web3JsonRPC.AddEthereumChain(
   chainId = "1666600000",
   blockExplorerUrls = listOf("https://explorer.harmony.one"),
   chainName = "Harmony Mainnet",
   iconUrls = listOf("https://harmonynews.one/wp-content/uploads/2019/11/slfdjs.png"),
   nativeCurrency = AddChainNativeCurrency("ONE", "ONE", 18)
).action()
```
```java Java
Action addEthereumChain = new Web3JsonRPC.AddEthereumChain(
       "1666600000", // chainId
       List.of("https://explorer.harmony.one"), // blockExplorerUrls
       "Harmony Mainnet", // chainName
       List.of("https://harmonynews.one/wp-content/uploads/2019/11/slfdjs.png"), // iconUrls
       new AddChainNativeCurrency("ONE", "ONE", 18)) // nativeCurrency
       .action(false);
```

## WatchAsset

Add and track a new asset within a wallet.

See [wallet_watchAsset](https://eips.ethereum.org/EIPS/eip-747).

### Parameters

| Name | Type | Description |
| :--- | :--- | :--- |
| type | `String` | Type of token asset. (i.e. `ERC20`, `ERC721`). |
| options | [`WatchAssetOptions`](doc:android-api-reference#watchassetoptions) | Data of the asset to watch (i.e. contract address, name, icon, etc.) |

### Example

```kotlin Kotlin
val watchAsset = Web3JsonRPC.WatchAsset(
   type = "ERC20",
   options = WatchAssetOptions(
      "0xcf664087a5bb0237a0bad6742852ec6c8d69a27a",
      "WONE",
      18,
      "https://s2.coinmarketcap.com/static/img/coins/64x64/11696.png"
   )
).action()
```
```java Java
Action watchAsset = new Web3JsonRPC.WatchAsset(
       "ERC20", // type
       new WatchAssetOptions( // options
               "0xcf664087a5bb0237a0bad6742852ec6c8d69a27a", // address
               "WONE", // symbol
               18, // decimals
               "https://s2.coinmarketcap.com/static/img/coins/64x64/11696.png") // image
       ).action(false);
```

# Types

## AddChainNativeCurrency

Defines a native currency to add when making a request to add a new Ethereum chain.

See [AddEthereumChain](doc:android-api-reference#addethereumchain).

### Properties

| Name | Type | Description |
| :--- | :--- | :--- |
| name | `String` | Name of native currency for the chain. |
| symbol | `String` | Symbol of native currency for the chain. |
| decimals | `Int` | Decimals of precision, as an integer. |

### Example

```kotlin Kotlin
val nativeCurrency = AddChainNativeCurrency("ONE", "ONE", 18)
```
```java Java
AddChainNativeCurrency nativeCurrency = new AddChainNativeCurrency("ONE", "ONE", 18);
```

## WatchAssetOptions

Defines options when making a request to watch a new asset.

See [WatchAsset](doc:android-api-reference#watchasset).

### Properties

| Name | Type | Description |
| :--- | :--- | :--- |
| address | `String` | Contract address for the token asset. |
| symbol | `String` | **Optional**. Symbol for the token asset. |
| decimals | `Int` | **Optional**. Decimals of precision, as an integer. |
| image | `String` | **Optional**. Logo image for the token asset. |

### Example

```kotlin Kotlin
val watchAssetOptions = WatchAssetOptions(
      address = "0xcf664087a5bb0237a0bad6742852ec6c8d69a27a",
      symbol = "WONE",
      decimals = 18,
      image = "https://s2.coinmarketcap.com/static/img/coins/64x64/11696.png"
   )

```
```java Java
WatchAssetOptions watchAssetOptions = new WatchAssetOptions(
        "0xcf664087a5bb0237a0bad6742852ec6c8d69a27a", // address
        "WONE", // symbol
        18, // decimals
        "https://s2.coinmarketcap.com/static/img/coins/64x64/11696.png") // image
       );
```


================================================
FILE: docs/docs/client-sdk/android-establishing-a-connection.md
================================================
---
title: "Establishing a connection"
slug: "android-establishing-a-connection"
category: "633d1d37bc7103008654c123"
---

A connection to Coinbase Wallet can be initiated by calling the `initiateHandshake` function provided by the SDK. The function also takes in an optional `initialActions` parameter which apps can use to take certain actions along with the initial handshake request.

```kotlin Kotlin
val requestAccount = Web3JsonRPC.RequestAccounts().action()
val handShakeActions = listOf(requestAccount)

client.initiateHandshake(
   initialActions = handShakeActions
) { result: Result<List<ActionResult>>, account: Account? ->
    result.onSuccess { actionResults: List<ActionResult> ->
        actionResults.handleSuccess("Handshake", handShakeActions, account)
    }
    result.onFailure { err ->
        err.handleError("HandShake")
    }
}
```
```java Java
// requestAccounts request
ArrayList<Action> actions = new ArrayList<>();
actions.add(
   new Web3JsonRPC.RequestAccounts().action(false)
);

// Initiate handshake
client.initiateHandshake(
   actions,
   (results, account) -> {
      for (ActionResult result : results) {
         if (result instanceof ActionResult.Result) {
            ((ActionResult.Result) result).getValue();
         }

         if (result instanceof ActionResult.Error) {
            ((ActionResult.Error) result).getCode();
            ((ActionResult.Error) result).getMessage();
         }
      }
   },
   error -> {
   }
);
```

An example handshake request is provided in the [sample application](https://github.com/coinbase/wallet-mobile-sdk/blob/master/android/example/src/main/java/com/coinbase/android/beta/MainActivity.kt#L52).

================================================
FILE: docs/docs/client-sdk/android-install.md
================================================
---
title: "Install"
slug: "android-install"
category: "633d1d37bc7103008654c123"
---

The Coinbase Wallet Mobile SDK is available on [Maven Central](https://search.maven.org/artifact/com.coinbase/coinbase-wallet-sdk/0.1.0/aar).

## Gradle

Add Coinbase Wallet SDK to your `build.gradle` file.

```groovy
repositories {
   mavenCentral()
}

dependencies {
   implementation "com.coinbase:coinbase-wallet-sdk:1.0.3"
}
```

## Maven

Add Coinbase Wallet SDK to your `pom.xml` file.

```xml
<dependency>
	<groupId>com.coinbase</groupId>
	<artifactId>coinbase-wallet-sdk</artifactId>
	<version>1.0.3</version>
</dependency>
```

================================================
FILE: docs/docs/client-sdk/android-making-requests.md
================================================
---
title: "Making requests"
slug: "android-making-requests"
category: "633d1d37bc7103008654c123"
---

Requests to Coinbase Wallet can be made by calling the `makeRequest` function provided by the SDK. This function also accepts a list of actions that can be taken in as a single batch request.

```kotlin Kotlin
val signTypedDataV3 = Web3JsonRPC.SignTypedDataV3(
   "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", // address
   "" // typed data JSON
).action()
val requestActions = listOf(signTypedDataV3)

client.makeRequest(request = RequestContent.Request(actions = requestActions)) { result ->
   result.fold(
       onSuccess = { returnValues ->
           returnValues.handleSuccess("Request", requestActions)
       },
       onFailure = { err ->
           err.handleError("Request")
       }
   )
}
```

================================================
FILE: docs/docs/client-sdk/android-setup.md
================================================
---
title: "Setup"
slug: "android-setup"
category: "633d1d37bc7103008654c123"
---

In order for your app to interact with Coinbase Wallet, you must add a [queries element](https://developer.android.com/guide/topics/manifest/queries-element) to your `AndroidManifest.xml` file, specifying the package name for Coinbase Wallet, `org.toshi`.

```xml AndroidManifest.xml
<queries>
      <package android:name="org.toshi" />
</queries>
```

Before the SDK can be used, it needs to be configured with an App Link to your application. This callback URL will be used by the Coinbase Wallet application to navigate back to your application.

```kotlin Kotlin
CoinbaseWalletSDK(
    appContext = applicationContext,
    domain = Uri.parse("https://www.myappxyz.com"),
    openIntent = { intent -> launcher.launch(intent) }
)
```
```java Java
new CoinbaseWalletSDK(
    Uri.parse("https://www.myappxyz.com"),
    getApplicationContext(),
    CBW_PACKAGE_NAME,
    intent -> {
        startActivityForResult(intent, CBW_ACTIVITY_RESULT_CODE);
    }
);
```

When your application receives a response from Coinbase Wallet via App Links, this URL needs to be handed off to the SDK via the `handleResponse` function.

```kotlin Kotlin
launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
   val uri = result.data?.data ?: return@registerForActivityResult
   client.handleResponse(uri)
}
```
```java Java
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
   super.onActivityResult(requestCode, resultCode, data);

   if (requestCode != CBW_ACTIVITY_RESULT_CODE) {
       return;
   }

   if (data == null) {
       return;
   }

   Uri url = data.getData();
   client.handleResponse(url);
}
```

An example is provided in our [sample application](https://github.com/coinbase/wallet-mobile-sdk/blob/master/android/example/src/main/java/com/coinbase/android/beta/MainActivity.kt#L27).

================================================
FILE: docs/docs/client-sdk/ios-api-reference.md
================================================
---
title: "API Reference"
slug: "ios-api-reference"
category: "633d1d37bc7103008654c123"
---

# Actions

The `initiateHandshake` and `makeRequest` methods accept a list of actions to perform. An `Action` can be created using the `Web3JsonRPC` class.

Below is a list of supported actions for each method:

| Action | RPC method | initiateHandshake | makeRequest |
| :--- | :--- | :--- | :--- |
| [RequestAccounts](doc:ios-api-reference#requestaccounts) | [eth_requestAccounts](https://eips.ethereum.org/EIPS/eip-1102) | ✔️ Supported | ✔️ Supported |
| [SignTransaction](doc:ios-api-reference#signtransaction) | [eth_signTransaction](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_signtransaction) | ❌ Not supported | ✔️ Supported |
| [SendTransaction](doc:ios-api-reference#sendtransaction) | [eth_sendTransaction](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sendtransaction) | ❌ Not supported | ✔️ Supported |
| - | [eth_sign](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign) | ❌ Not supported | ❌ Not supported |
| [PersonalSign](doc:ios-api-reference#personalsign) | [personal_sign](https://eips.ethereum.org/EIPS/eip-191) | ✔️ Supported | ✔️ Supported |
| [SignTypedDataV3](doc:ios-api-reference#signtypeddatav3) | [eth_signTypedData_v3](https://eips.ethereum.org/EIPS/eip-712) | ✔️ Supported | ✔️ Supported |
| [SignTypedDataV4](doc:ios-api-reference#signtypeddatav4) | [eth_signTypedData_v4](https://eips.ethereum.org/EIPS/eip-712) | ✔️ Supported | ✔️ Supported |
| [SwitchEthereumChain](doc:ios-api-reference#switchethereumchain) | [wallet_switchEthereumChain](https://eips.ethereum.org/EIPS/eip-3326) | ✔️ Supported | ✔️ Supported |
| [AddEthereumChain](doc:ios-api-reference#addethereumchain) | [wallet_addEthereumChain](https://eips.ethereum.org/EIPS/eip-3085) | ✔️ Supported | ✔️ Supported |
| [WatchAsset](doc:ios-api-reference#watchasset) | [wallet_watchAsset](https://eips.ethereum.org/EIPS/eip-747) | ✔️ Supported | ✔️ Supported |

## RequestAccounts

Request that the user provides an account in the form of an Ethereum address.

### Parameters

None.

### Example

```swift
let requestAccounts = Action(jsonRpc: .eth_requestAccounts)
```

## PersonalSign

Sign a message by calculating an Ethereum specific signature with: `sign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))`.

Adding a prefix to the message makes the calculated signature recognisable as an Ethereum specific signature. This prevents misuse where a malicious DApp can sign arbitrary data (e.g. transaction) and use the signature to impersonate the victim.

See [personal_sign](https://eips.ethereum.org/EIPS/eip-191).

### Parameters

| Name | Type | Description |
| :--- | :--- | :--- |
| address | `String` | Address to sign data with. |
| message | `String` | Message data to sign. |

### Example

```swift
let personalSign =
      Action(jsonRpc: .personal_sign(
            address: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
            message: "0xdeadbeaf"))
```

## SignTypedDataV3

Sign typed structured data.

See [eth_signTypedData_v3](https://eips.ethereum.org/EIPS/eip-712).

### Parameters

| Name | Type | Description |
| :--- | :--- | :--- |
| address | `String` | Address to sign data with. |
| typedDataJson | `String` | Typed data to sign. Structured according to the JSON-Schema specified in [EIP-712](https://eips.ethereum.org/EIPS/eip-712). |

### Example

```swift
let signTypedDataV3 =
      Action(jsonRpc: .eth_signTypedData_v3(
            address: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
            typedDataJson: JSONString(encode: typedData)!))
```

## SignTypedDataV4

Sign typed structured data.

See [eth_signTypedData_v4](https://eips.ethereum.org/EIPS/eip-712).

### Parameters

| Name | Type | Description |
| :--- | :--- | :--- |
| address | `String` | Address to sign data with. |
| typedDataJson | `String` | Typed data to sign. Structured according to the JSON-Schema specified in [EIP-712](https://eips.ethereum.org/EIPS/eip-712). |

### Example

```swift
let signTypedDataV4 =
      Action(jsonRpc: .eth_signTypedData_v4(
            address: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
            typedDataJson: JSONString(encode: typedData)!))
```

## SignTransaction

Sign a transaction that can be submitted to the network at a later time.

See [eth_signTransaction](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_signtransaction).

### Parameters

| Name | Type | Description |
| :--- | :--- | :--- |
| fromAddress | `String` | Address the transaction is sent from. |
| toAddress | `String` | **Optional**. Address the transaction is sent to. |
| weiValue | `BigInt` | Value for the transaction, in Wei. |
| data | `String` | Compiled code of a contract or the hash of the invoked method signature and encoded parameters. |
| nonce | `Int` | **Optional**. Nonce of the transaction. Allows for overwriting pending transactions that use an identical nonce. |
| gasPriceInWei | `BigInt` | **Optional**. Gas price for the transaction, in Wei. |
| maxFeePerGas | `BigInt` | **Optional**. Maximum fee per unit of gas for the transaction. |
| maxPriorityFeePerGas | `BigInt` | **Optional**. Maximum priority fee per unit of gas for the transaction. |
| gasLimit | `BigInt` | **Optional**. Gas limit for the transaction. |
| chainId | `String` | Chain ID for the transaction, as an integer string. |

### Example

```swift
let signTransaction = 
      Action(jsonRpc: .eth_signTransaction(
             fromAddress: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
             toAddress: "0x000000000000000000000000000000000000dEaD",
             weiValue: "10000000000000",
             data: "0x",
             nonce: 1,
             gasPriceInWei: "30000000000",
             maxFeePerGas: "60000000000",
             maxPriorityFeePerGas: "2500000000",
             gasLimit: "1000",
             chainId: "1"))
```

## SendTransaction

Send a transaction, or create a contract if the `data` field contains code.

See [eth_sendTransaction](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sendtransaction).

### Parameters

| Name | Type | Description |
| :--- | :--- | :--- |
| fromAddress | `String` | Address the transaction is sent from. |
| toAddress | `String` | **Optional**. Address the transaction is sent to. |
| weiValue | `BigInt` | Value for the transaction, in Wei. |
| data | `String` | Compiled code of a contract or the hash of the invoked method signature and encoded parameters. |
| nonce | `Int` | **Optional**. Nonce of the transaction. Allows for overwriting pending transactions that use an identical nonce. |
| gasPriceInWei | `BigInt` | **Optional**. Gas price for the transaction, in Wei. |
| maxFeePerGas | `BigInt` | **Optional**. Maximum fee per unit of gas for the transaction. |
| maxPriorityFeePerGas | `BigInt` | **Optional**. Maximum priority fee per unit of gas for the transaction. |
| gasLimit | `BigInt` | **Optional**. Gas limit for the transaction. |
| chainId | `String` | Chain ID for the transaction, as an integer string. |

### Example

```swift
let sendTransaction = 
      Action(jsonRpc: .eth_sendTransaction(
             fromAddress: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
             toAddress: "0x000000000000000000000000000000000000dEaD",
             weiValue: "10000000000000",
             data: "0x",
             nonce: 1,
             gasPriceInWei: "30000000000",
             maxFeePerGas: "60000000000",
             maxPriorityFeePerGas: "2500000000",
             gasLimit: "1000",
             chainId: "1"))
```

## SwitchEthereumChain

Switch a wallet’s currently active chain.

See [wallet_switchEthereumChain](https://eips.ethereum.org/EIPS/eip-3326).

### Parameters

| Name | Type | Description |
| :--- | :--- | :--- |
| chainId | `String` | ID of the chain to switch to, as an integer string. |

### Example

```swift
let switchEthereumChain =
      Action(jsonRpc: .wallet_switchEthereumChain(chainId: "1666600000"))
```

## AddEthereumChain

Add a chain to a wallet.

See [wallet_addEthereumChain](https://eips.ethereum.org/EIPS/eip-3085).

### Parameters

| Name | Type | Description |
| :--- | :--- | :--- |
| chainId | `String` | ID of the chain to add, as an integer string. |
| blockExplorerUrls | `List<String>` | **Optional**. List of block explorer URL strings. |
| chainName | `String` | **Optional**. Name of the chain to add. |
| iconUrls | `List<String>` | **Optional**. List of image icons URL strings. |
| nativeCurrency | [`AddChainNativeCurrency`](doc:ios-api-reference#addchainnativecurrency) | **Optional**. Data for the chain’s native currency. |
| rpcUrls | `List<String>` | List of RPC URL strings. Defaults to an empty list. |

### Example

```swift
let addEthereumChain = 
      Action(jsonRpc: .wallet_addEthereumChain(
             chainId: "1666600000",
              blockExplorerUrls: ["https://explorer.harmony.one"],
              chainName: "Harmony Mainnet",
              iconUrls: ["https://harmonynews.one/wp-content/uploads/2019/11/slfdjs.png"],
              nativeCurrency: AddChainNativeCurrency(
                    name: "ONE",
                    symbol: "ONE",
                    decimals: 18)
             ))
```

## WatchAsset

Add and track a new asset within a wallet.

See [wallet_watchAsset](https://eips.ethereum.org/EIPS/eip-747).

### Parameters

| Name | Type | Description |
| :--- | :--- | :--- |
| type | `String` | Type of token asset. (i.e. `ERC20`, `ERC721`). |
| options | [`WatchAssetOptions`](doc:ios-api-reference#watchassetoptions) | Data of the asset to watch (i.e. contract address, name, icon, etc.) |

### Example

```swift
let watchAsset = 
      Action(jsonRpc: .wallet_watchAsset(
             type: "ERC20",
             options: WatchAssetOptions(
                    address: "0xcf664087a5bb0237a0bad6742852ec6c8d69a27a",
                    symbol: "WONE",
                    decimals: 18,
                    image: "https://s2.coinmarketcap.com/static/img/coins/64x64/11696.png")
             ))
```

# Types

## AddChainNativeCurrency

Defines a native currency to add when making a request to add a new Ethereum chain.

See [AddEthereumChain](doc:ios-api-reference#addethereumchain).

### Properties

| Name | Type | Description |
| :--- | :--- | :--- |
| name | `String` | Name of native currency for the chain. |
| symbol | `String` | Symbol of native currency for the chain. |
| decimals | `Int` | Decimals of precision, as an integer. |

### Example

```swift
let nativeCurrency =
      AddChainNativeCurrency(name: "ONE", symbol: "ONE", decimals: 18)
```

## WatchAssetOptions

Defines options when making a request to watch a new asset.

See [WatchAsset](doc:ios-api-reference#watchasset).

### Properties

| Name | Type | Description |
| :--- | :--- | :--- |
| address | `String` | Contract address for the token asset. |
| symbol | `String` | **Optional**. Symbol for the token asset. |
| decimals | `Int` | **Optional**. Decimals of precision, as an integer. |
| image | `String` | **Optional**. Logo image for the token asset. |

### Example

```swift
let watchAssetOptions = WatchAssetOptions(
      address: "0xcf664087a5bb0237a0bad6742852ec6c8d69a27a",
      symbol: "WONE",
      decimals: 18,
      image: "https://s2.coinmarketcap.com/static/img/coins/64x64/11696.png")
```


================================================
FILE: docs/docs/client-sdk/ios-establishing-a-connection.md
================================================
---
title: "Establishing a connection"
slug: "ios-establishing-a-connection"
category: "633d1d37bc7103008654c123"
---

A connection to Coinbase Wallet can be initiated by calling the `initiateHandshake` function provided by the SDK. The function also takes in an optional `initialActions` parameter which apps can use to take certain actions along with the initial handshake request.

```swift
private let cbwallet = CoinbaseWalletSDK.shared

cbwallet.initiateHandshake(
    initialActions: [
        Action(jsonRpc: .eth_requestAccounts)
    ]
) { result, account in
    switch result {
    case .success(let response):
        self.logObject(label: "Response:\n", response)

        guard let account = account else { return }
        self.logObject(label: "Account:\n", account)
        self.address = account.address
    case .failure(let error):
        self.log("\(error)")
    }
    self.updateSessionStatus()
}
```

An example handshake request is provided in our [sample application](https://github.com/coinbase/wallet-mobile-sdk/blob/master/ios/example/SampleClient/ViewController.swift#L63).

================================================
FILE: docs/docs/client-sdk/ios-install.md
================================================
---
title: "Install"
slug: "ios-install"
category: "633d1d37bc7103008654c123"
---

The Coinbase Wallet Mobile SDK is available on both [CocoaPods](https://cocoapods.org/) and [Swift Package Manager](https://swift.org/package-manager).

## Cocoapods

Add Coinbase Wallet SDK to your `Podfile`.

```ruby
use_frameworks!

target 'YOUR_TARGET_NAME' do
    pod 'CoinbaseWalletSDK', '1.0.3'
end
```

Replace `YOUR_TARGET_NAME`, and then in the `Podfile` directory run:

```bash
pod install
```

## Swift Package Manager

Add Coinbase Wallet SDK to your `Package.swift` file.

Under **File > Add packages…** enter the package url: [https://github.com/coinbase/wallet-mobile-sdk](https://github.com/coinbase/wallet-mobile-sdk)

```swift
import PackageDescription

let package = Package(
    name: "YOUR_PROJECT_NAME",
    dependencies: [
        .package(url: "https://github.com/coinbase/wallet-mobile-sdk.git", from: "1.0.3"),
    ]
)
```

Replace `YOUR_PROJECT_NAME`, and then run:

```bash
swift build
```

================================================
FILE: docs/docs/client-sdk/ios-making-requests.md
================================================
---
title: "Making requests"
slug: "ios-making-requests"
category: "633d1d37bc7103008654c123"
---

Requests to Coinbase Wallet can be made by calling the `makeRequest` function provided by the SDK. This function also accepts a list of `actions` that can be taken in as a single batch request.

```swift
cbwallet.makeRequest(
    Request(actions: [
        Action(jsonRpc: .eth_signTypedData_v3(
            address: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826",
            message: Data()))
    ])
) { result in
    self.log("\(result)")
}
```

An example request is provided in our [sample application](https://github.com/coinbase/coinbase-wallet-sdk/blob/master/examples/native-sdk-ios-client/SampleApp/ViewController.swift#L29).

================================================
FILE: docs/docs/client-sdk/ios-setup.md
================================================
---
title: "Setup"
slug: "ios-setup"
category: "633d1d37bc7103008654c123"
---

Coinbase Wallet Mobile SDK uses [Universal Links](https://developer.apple.com/ios/universal-links/) to communicate between Coinbase Wallet and your application.

Before the SDK can be used, it needs to be configured with a Universal Link to your application. This callback URL will be used by the Coinbase Wallet application to navigate back to your application.

```swift
CoinbaseWalletSDK.configure(
    callback: URL(string: "https://myappxyz.com/mycallback")!
)
```

When your application receives a response from Coinbase Wallet via a Universal Link, this URL needs to be handed off to the SDK via the `handleResponse` function.

```swift
func application(_ app: UIApplication, open url: URL ...) -> Bool {
    if (try? CoinbaseWalletSDK.shared.handleResponse(url)) == true {
        return true
    }
    // handle other types of deep links
    return false
}
```

It’s recommended to place this configuration logic in the AppDelegate as shown in this [example](https://github.com/coinbase/wallet-mobile-sdk/blob/master/ios/example/SampleClient/AppDelegate.swift#L19).

================================================
FILE: docs/docs/client-sdk/mobile-sdk-overview.md
================================================
---
title: "Overview"
slug: "mobile-sdk-overview"
category: "633d1d37bc7103008654c123"
---

[Coinbase Wallet Mobile SDK](https://github.com/coinbase/wallet-mobile-sdk) is an open source SDK which allows you to connect your native mobile applications to millions of Coinbase Wallet users.

## Platforms

The SDK is available for the following platforms:

- [iOS](https://cocoapods.org/pods/CoinbaseWalletSDK)
- [Android](https://mavenlibs.com/maven/dependency/com.coinbase/coinbase-wallet-sdk)

We also provide wrapper libraries and modules for [React Native](https://www.npmjs.com/package/@coinbase/wallet-mobile-sdk) and [Flutter](https://pub.dev/packages/coinbase_wallet_sdk) applications.

## Features

- **Easy**: Simplified and improved wallet integration for native mobile applications via deep-linking, without requiring a web application.
- **Decentralized and reliable**: Doesn't depend on external services and relay servers for delivering messages and app-to-wallet communication. 
- **Secure**: Utilizes end-to-end encryption with secure key exchange and decentralized identity verification using the well-known URI standard for universal links.
- **Efficient**: Reduces the number of hops between client applications and wallet via support for batch requests.
- **Open-source**: All of the code for Coinbase Wallet Mobile SDK is open source and available on [GitHub](https://github.com/coinbase/wallet-mobile-sdk).

================================================
FILE: docs/docs/spec/batch.md
================================================
# Batch requests

To improve UX by minimizing app switches, 
MWP allows client apps to make requests with multiple actions at once. 
Wallets should return results in a single response message as well.
Client can specify whether each action is required or optional to customize the flow.

## `Request` has `action`s
- A `request` message contains an array of `action`s
- Each `action` defines a single JSON RPC call with corresponding parameters in JSON format
- `optional` boolean property to tell the host wallet to cancel the request if it fails to process non-optional action.

### Example request message with three actions batched
```json
{
  "version": "1.0.3",
  "sender": "AD6aqQNPr4/NRQymzqr14qjlnO9LN5JaEs/XEwEGTno=",
  "content": {
    "request": {
      "actions": [
        {
          "paramsJson": "{\"chainId\":\"137\"}",
          "method": "wallet_switchEthereumChain",
          "optional": false
        },
        {
          "paramsJson": "{\"address\":\"0x571a6a108adb08f9ca54fe8605280F9EE0eD4AF6\",\"message\":\"message\"}",
          "method": "personal_sign",
          "optional": true
        },
        {
          "paramsJson": "{\"toAddress\":\"0\",\"fromAddress\":\"0x571a6a108adb08f9ca54fe8605280F9EE0eD4AF6\",\"chainId\":\"137\",\"weiValue\":\"0\",\"data\":\"\"}",
          "method": "eth_sendTransaction",
          "optional": false
        }
      ]
    }
  },
  "timestamp": 689616588.09238,
  "callbackUrl": "myappxyz://mycallback/wsegue",
  "uuid": "84920218-ED92-4DF7-83BC-3CBFD1E5C7E3"
}
```

## `Response` has `value`s

- A `response` message contains array of `value`s
- `value` can be either
    - `result`: JSON string
    - `error`: error code and message

### Example

coming soon


================================================
FILE: docs/docs/spec/encryption.md
================================================
# Encryption

MWP uses deep links for direct communication between peers.

To ensure security, all messages in MWP after secure key exchange process are end-to-end encrypted.

## Key generation

Both the client and the wallet generate their own key pair for each session via [Key-agreement protocol](https://en.wikipedia.org/wiki/Key-agreement_protocol) using [Elliptic-curve](https://en.wikipedia.org/wiki/Elliptic-curve_cryptography).

Each peer stores its private key in secure persistent storage
and share its public key with the other party.

## Key exchange to derive shared secret

MWP uses [Diffie–Hellman key exchange](https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange) method to securely share cryptographic keys over deep links.

This method allows the two parties to derive the same shared secret offline using its own private key and the peer's public key.

## Message `content` encryption

After successful [handshake process](handshake) to exchange keys, subsequent messages ([`content` data](messages#content)) are encrypted with the common shared secret using a symmetric-key algorithm.

It uses [AES](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard)-[GCM](https://en.wikipedia.org/wiki/Galois/Counter_Mode) algorithm for cryptographic operations.

### Example message after encryption
```json
{
  "version": "1.0.3",
  "sender": "lEC/X3K68rlgOoldMdk0D77738Y7W0mDbMMV5R6VyCE=",
  "content": {
    "request": {
      "data": "bgPGRoCBgH10b0IUhs8ZWRRPhFBGUlS3ESmB+xiGNb7n7oUdU9L9PGABmla/kCdnmES6iWXI7u5xzKm/CzPMGvlvlXLuRGlU4RjGJqbcQ55He3UcBXOgB0q489Vx2cx0fllrISuo87//kfcSolCWNSCHSBuSmojORG8YmO1L20724C8YKQrPxjmfWm5YyZxp/HyTnwX60eRJb819FZI4Zfc4RkTp4h+1A2lzBlERelr+MojfVBBBwxv4qQTAn7QRbUgoU+1CfblqcuB7bHUvfl+OwyZqIoxP68agkU9Na3aKDSM+oK6q9IBKG5X4Vz1+CBVchR5vggY+D7Omdaes6uDL443yV3uf8XHyv5ieWGgIS8bGgkdPvMrAtv78wdBr6iWLlh0pF7RyrPOWq/h8WiYerbAD9RFYhAxo1z3dymFgLamn/rf1LS+xu+sClKDrFx3DYkHEa/75CyQokBQiJFqO/sCTBLnXzV5I9bbjTTGuHi5tE/lKnsMsDz5tBpedavo9BT2bJNRUGh7yPMFybxV1hjyamlobBxyxik2GNjh09bINpZ4HVxe3mpmQWdg0NZiE5HG08HRHWooV+wQavMsWLqmOQtH30dy3+WMRSfURrrVdRXm0TZda6wCdU+sPbLPuvWucfdCTG62P8rGqklavjDQL8kkWAnsgMkCnAQJyoGqFHtGxjNd3rH5Pmkd7RC34fkEOsXxxKMzyOMlZjgr4a1MHO0URbrgA5k3IPdQ83Iq2GRpboshyHRyy27ClH6She9rQXUnbRI7WcGK/YCVu97rTxjWT8AzS8twI7egN6BhyricjMoUXNCewxWUBO4pp316mHtnPyktvFAZxF5Q/hbM2bcFQS2fdWooRUWlB405yv+magBC89GDbJHwBN73q3KTtYFVb5N7vDVIU71eGhL6ehve3NPcGxLKbRXWxWQnKNpIeWZ9W2mNWI5C6mbaasPbgGxW228OEs9FxjNmdA6XCScctgb8b31nM8xPOWeD+q33UIdNpQvkrZicPu7f5lGXGYibjsXnNWdO3tiOg6kuiHevt5Jqp35bO1Vn6y3UzZu6xwbUZQbE4NmR6j9BlGuNGS40Y91O/eCrFzSyayxPl6plRoekn2djBGHDyBZVwXfSKQef6gK9jV1RxQTjKbO6rDGR1hRgqWDvDeDLg03GBqwP93ZwqANK1jxpLOm0wbUycCl8grwAzTrZ0bJ68aUlT/Jmi3VAyV4QAwED8IZ0ipjLz7EmXkQWjuhChIiSwjkR6EEfctQhLK1+xvLsY796OSXG18qTAfjx2vgyGoxxrmEnufTIh4a9A+CTYQzNU137aRLXK/rN7Xs0d51xbis/FVm9ysgBNuWfxlOpVeahkvNSHzAM7Wn4WP/nlWp1yly/R/KrEE5iFi2dVxE9UMQFcbJ/xFDl+dj4hMJDFdCf1tyuP+ZCF6VSOjNUt6TCn2uXNTjIIJj2ZuH3O0YETcESMy+HwR8mmqn4DaFbbzRkZo7szOR3kGzKU8yk0fuW+McZtXfGd9YWG6wZEdMSV210jsmnDHklgHND87Zw0uZBdOWAYc6KzmTU1i2FxOEZaCjCGm9NDaVtgb1+gjrMUQN4KTuEWKaFpW74dZQymnfR9W/SYjH62DRLLEMDBV3xJDXl8fUgusnXMbLvf97fe/qZ7X1fgK70cWDJRTYSvziOC9knXQgOnr94bGaqWbzr7I2x6ODgTC6dczM9HJWOHjNvV8jouhgQIRldOaKA7ALLIEslhA6beJ/hnD2C2JpVwrcur/rCi2RZ5YOC3NKSvOv2sn4PG3++dpqHah1Zi4sdBKRxngSRCCcC1i123zmO3O4zSzI1i/Lo="
    }
  },
  "timestamp": 689610765.957546,
  "callbackUrl": "myappxyz://mycallback/wsegue",
  "uuid": "71BCE700-D717-4463-B4E4-4ECDCFC179A3"
}
```

### Example message before encryption (internal usage)
```json
{
  "version": "1.0.3",
  "sender": "lEC/X3K68rlgOoldMdk0D77738Y7W0mDbMMV5R6VyCE=",
  "content": {
    "request": {
      "actions": [
        {
          "paramsJson": "{\"address\":\"0x571a6a108adb08f9ca54fe8605280F9EE0eD4AF6\",\"message\":\"message\"}",
          "method": "personal_sign",
          "optional": false
        },
        {
          "paramsJson": "{\"typedDataJson\":\"{\\\"types\\\":{\\\"Identity\\\":[{\\\"type\\\":\\\"uint256\\\",\\\"name\\\":\\\"userId\\\"},{\\\"type\\\":\\\"address\\\",\\\"name\\\":\\\"wallet\\\"}],\\\"Bid\\\":[{\\\"name\\\":\\\"amount\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"name\\\":\\\"bidder\\\",\\\"type\\\":\\\"Identity\\\"}],\\\"EIP712Domain\\\":[{\\\"name\\\":\\\"name\\\",\\\"type\\\":\\\"string\\\"},{\\\"name\\\":\\\"version\\\",\\\"type\\\":\\\"string\\\"},{\\\"name\\\":\\\"chainId\\\",\\\"type\\\":\\\"uint256\\\"},{\\\"name\\\":\\\"verifyingContract\\\",\\\"type\\\":\\\"address\\\"},{\\\"type\\\":\\\"bytes32\\\",\\\"name\\\":\\\"salt\\\"}]},\\\"primaryType\\\":\\\"Bid\\\",\\\"message\\\":{\\\"bidder\\\":{\\\"userId\\\":323,\\\"wallet\\\":\\\"0x3333333333333333333333333333333333333333\\\"},\\\"amount\\\":100},\\\"domain\\\":{\\\"salt\\\":\\\"0xf2d857f4a3edcb9b78b4d503bfe733db1e3f6cdc2b7971ee739626c97e86a558\\\",\\\"name\\\":\\\"DApp Browser Test DApp\\\",\\\"chainId\\\":1,\\\"version\\\":\\\"1\\\",\\\"verifyingContract\\\":\\\"0x1C56346CD2A2Bf3202F771f50d3D14a367B48070\\\"}}\",\"address\":\"0x571a6a108adb08f9ca54fe8605280F9EE0eD4AF6\"}",
          "method": "eth_signTypedData_v3",
          "optional": false
        }
      ]
    }
  },
  "timestamp": 689610765.957546,
  "callbackUrl": "myappxyz://mycallback/wsegue",
  "uuid": "71BCE700-D717-4463-B4E4-4ECDCFC179A3"
}
```

## Messages without encryption

However, there are two exceptions where the content data are not encrypted:
1. Handshake calls from the client in order to exchange keys with the wallet
2. Failure responses from wallet to return errors happening during the handshake processes

### Example handshake request message
```json
{
  "version": "1.0.3",
  "sender": "lEC/X3K68rlgOoldMdk0D77738Y7W0mDbMMV5R6VyCE=",
  "content": {
    "handshake": {
      "appId": "com.coinbase.SampleClient",
      "callback": "myappxyz://mycallback/wsegue",
      "initialActions": [
        {
          "paramsJson": "{}",
          "method": "eth_requestAccounts",
          "optional": false
        }
      ]
    }
  },
  "timestamp": 689587969.289106,
  "callbackUrl": "myappxyz://mycallback/wsegue",
  "uuid": "451711FA-96B6-4955-B6EA-EFA78CEB89F5"
}
```

### Example failure response message
```json
{
  "version": "1.0.3",
  "sender": "lEC/X3K68rlgOoldMdk0D77738Y7W0mDbMMV5R6VyCE=",
  "content": {
    "failure": {
      "requestId": "B78F510E-DD5C-4477-8350-7550FAC7452E",
      "description": "Request denied"
    }
  },
  "timestamp": 689611333.369556,
  "uuid": "E485820B-8F5E-4F8C-9A00-CE5B5B9C6F35"
}
```

## Implementation

Coinbase's SDK is built with 
[Apple CryptoKit](https://developer.apple.com/documentation/cryptokit/) for iOS, 
[Google Tink](https://github.com/google/tink) and [androidx.security](https://developer.android.com/jetpack/androidx/releases/security) for Android.

![](img/diffie-hellman.png)
> source: https://commons.wikimedia.org/wiki/File:Public_key_shared_secret.svg


================================================
FILE: docs/docs/spec/handshake.md
================================================
# Handshake

For key exchange, client apps make `handshake` calls to ask wallets to generate and share a key to encrypt subsequent messages on the session.

## Handshake request message from client

`content` of a handshake message contains following:

### `appId`
Bundle ID (iOS) or application/package ID (Android). 
e.g. "com.coinbase.SampleClient"

### `callback`
Sender's URL to receive response from receiver.
For the best security measure, [universal links](https://developer.apple.com/ios/universal-links/) (or [app links](https://developer.android.com/training/app-links)) are recommended.

### `initialActions`
(optional) Actions to request after successful handshake process.
e.g. `eth_requestAccounts` to get user's eth account info along with the handshake response

### Example request message
```json
{
  "version": "1.0.3",
  "sender": "lEC/X3K68rlgOoldMdk0D77738Y7W0mDbMMV5R6VyCE=",
  "content": {
    "handshake": {
      "appId": "com.coinbase.SampleClient",
      "callback": "myappxyz://mycallback/wsegue",
      "initialActions": [
        {
          "paramsJson": "{}",
          "method": "eth_requestAccounts",
          "optional": false
        }
      ]
    }
  },
  "timestamp": 689587969.289106,
  "callbackUrl": "myappxyz://mycallback/wsegue",
  "uuid": "451711FA-96B6-4955-B6EA-EFA78CEB89F5"
}
```

## Response from wallet

Once the host wallet [verifies the client app](verification) and gets approval from the user,
it generates a key pair for the session and shares it with the caller.

### Example response message (success)
```json
{
  "version": "1.0.3",
  "sender": "EnX8x2D6lHzTg8YZCLybHPwivbCBRyFlP8aA235+MBg=",
  "content": {
    "response": {
      "requestId": "5A920962-ECBE-42BC-A956-83A56F0D52F8",
      "values": [
        {
          "result": {
            "value": "{\"chain\":\"eth\",\"networkId\":1,\"address\":\"0x571a6a108adb08f9ca54fe8605280F9EE0eD4AF6\"}"
          }
        }
      ]
    }
  },
  "timestamp": 689615011.030334,
  "uuid": "7446663A-685A-47E5-89E3-C1D37F085330"
}
```

### Example response message (failure)
```json
{
  "version": "1.0.3",
  "sender": "lEC/X3K68rlgOoldMdk0D77738Y7W0mDbMMV5R6VyCE=",
  "content": {
    "failure": {
      "requestId": "B78F510E-DD5C-4477-8350-7550FAC7452E",
      "description": "Request denied"
    }
  },
  "timestamp": 689611333.369556,
  "uuid": "E485820B-8F5E-4F8C-9A00-CE5B5B9C6F35"
}
```


================================================
FILE: docs/docs/spec/messages-example.md
================================================
# Example

### handshake
- URL
`https://go.cb-w.com/wsegue?p=eyJ2ZXJzaW9uIjoiMS4wLjMiLCJzZW5kZXIiOiJsRUNcL1gzSzY4cmxnT29sZE1kazBENzc3MzhZN1cwbURiTU1WNVI2VnlDRT0iLCJjb250ZW50Ijp7ImhhbmRzaGFrZSI6eyJhcHBJZCI6ImNvbS5jb2luYmFzZS5TYW1wbGVDbGllbnQiLCJjYWxsYmFjayI6Im15YXBweHl6OlwvXC9teWNhbGxiYWNrXC93c2VndWUiLCJpbml0aWFsQWN0aW9ucyI6W3sicGFyYW1zSnNvbiI6Int9IiwibWV0aG9kIjoiZXRoX3JlcXVlc3RBY2NvdW50cyIsIm9wdGlvbmFsIjpmYWxzZX1dfX0sInRpbWVzdGFtcCI6MTY2Nzg5NTE2OTI4OS4xMDYsImNhbGxiYWNrVXJsIjoibXlhcHB4eXo6XC9cL215Y2FsbGJhY2tcL3dzZWd1ZSIsInV1aWQiOiI0NTE3MTFGQS05NkI2LTQ5NTUtQjZFQS1FRkE3OENFQjg5RjUifQ%3D%3D`
- JSON (decoded the URL above. handshake messages are not encrypted)
```json
{
  "version": "1.0.3",
  "sender": "lEC/X3K68rlgOoldMdk0D77738Y7W0mDbMMV5R6VyCE=",
  "content": {
    "handshake": {
      "appId": "com.coinbase.SampleClient",
      "callback": "myappxyz://mycallback/wsegue",
      "initialActions": [
        {
          "paramsJson": "{}",
          "method": "eth_requestAccounts",
          "optional": false
        }
      ]
    }
  },
  "timestamp": 689587969.289106,
  "callbackUrl": "myappxyz://mycallback/wsegue",
  "uuid": "451711FA-96B6-4955-B6EA-EFA78CEB89F5"
}
```

### request
- URL
`https://go.cb-w.com/wsegue?p=eyJ2ZXJzaW9uIjoiMS4yLjMiLCJzZW5kZXIiOiJmbW5IZVh3OTNlY000QnFzSXpRTk5zb2FvS0ZxK3NOMHZRaWdvaVNQZ2dvPSIsImNvbnRlbnQiOnsicmVxdWVzdCI6eyJfMCI6IkdQYUwwTWJjbVhoVWU5eUprY0p5dnRJWVJUM3RXNEhcL1lBUmNKTXZGZlZWOWh6OXcya1h3YmxIMEJPcFN2UXI0RVhoV0FVUlwvZGFwWUVMZ2lvTkFXY3IxVlwvY1JoNDVUaFN2SFV1cHRlY0lJR0tLeGxKTWdwZ2RiMWNJRWhNWEdpVElBYkZTblJTOVlwOFowOHJcL3pkcjlBVytFQjRXSXBLcnhTTmVqQXRRTDJWTDByRWE2YzhvM0lodG5DQ1U1SzRpaVVZcTJkamd0eGRJZm1FbmhrTUFCQVwvSm5INFpBPT0ifX0sInV1aWQiOiJEMzg3MUYwRS03QkNFLTQxMjYtQjY1Ny05QjlGOEQ1NEU3N0YifQ%3D%3D`
- encrypted JSON (decoded from the URL above)
```json
{
  "version": "1.2.3",
  "sender": "oEC2AZndVwTcLs3ixQyxThlHrKBNdBczbWp9OjeglGY=",
  "content": {
    "request": {
      "data": "/LzMCiGCpiYuUHp2vdlQM4V+f7hYygKI2qhX/ZWuFA6/aqZ/bmnWhROK14vtBH3sbrROqfefMXue3rbqLOg1s+xzh6iXoVavhIeCSevugp1ZlERG9q+CSuLXyRR3tou6wdsJ60jOTDjGzLCvcHp2ykglfDUr2qaVRo3i/RXsJRoPrW9CurSM9+TmNZ46aq1Y/K8lBcpq1aFUYSn7+kHHR8xBY+QoPE0yox+dZrvSi7Z16fX3uwZ3NQPmhPqQXpDFEHrZeKEzoIZAPA8NUlrajgY/1mxhbkH9tmM8X5vSG7w="
    }
  },
  "uuid": "3E445386-8CB3-4995-99EC-DCF06A60081C"
}
```
- decrypted JSON (to pass via RN - native bridge)
```json
{
  "version": "1.2.3",
  "sender": "qSAE/fvQ1cnZvVnKDjiHRyzK6bVQ/qJ7W29DL2aMjns=",
  "content": {
    "request": {
      "actions": [
        {
          "paramsJson" : "{}",
          "method" : "eth_requestAccounts",
          "optional" : false
        },
        {
          "paramsJson" : "{\"fromAddress\":\"\",\"data\":\"bWVzc2FnZQ==\"}",
          "method" : "personal_sign",
          "optional" : false
        }
      ],
      "account": {
        "chain": "eth",
        "networkId": 17,
        "address": "0x12345678ABCD"
      }
    }
  },
  "uuid": "853BFBB5-A6F1-4FBA-B8C6-DC2BE3CCF6DF"
}
```

### response
- plain response JSON (to pass via RN - native bridge)
```json
{
  "version": "7.13.1",
  "sender": "u9IB3p8tN8P4U2LvYfaCphd8/bXRN34eTnuQPO4g6zQ=",
  "content": {
    "response": {
      "requestId": "9D34C731-397B-473B-9850-C6F0261BC085",
      "values": [
        {
          "result": {
            "value": "return value 1"
          }
        },
        {
          "result": {
            "value": "return value 2"
          }
        },
        {
          "error": {
            "message": "error 1",
            "code": 1
          }
        },
        {
          "error"
Download .txt
gitextract_l82khy5j/

├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.yml
│   │   ├── config.yml
│   │   └── feature_request.yml
│   ├── PULL_REQUEST_TEMPLATE.md
│   └── workflows/
│       ├── publish.yml
│       ├── run_tests.yml
│       └── version_update.yml
├── .gitignore
├── CODEOWNERS
├── CoinbaseWalletSDK.podspec
├── Gemfile
├── LICENSE
├── Package.swift
├── README.md
├── android/
│   ├── README.md
│   ├── build.gradle
│   ├── example/
│   │   ├── .editorconfig
│   │   ├── .gitignore
│   │   ├── build.gradle
│   │   ├── proguard-rules.pro
│   │   └── src/
│   │       └── main/
│   │           ├── AndroidManifest.xml
│   │           ├── java/
│   │           │   └── com/
│   │           │       └── coinbase/
│   │           │           └── android/
│   │           │               └── beta/
│   │           │                   ├── ActionsManager.kt
│   │           │                   ├── MainActivity.kt
│   │           │                   └── SecondActivity.java
│   │           └── res/
│   │               ├── drawable/
│   │               │   └── ic_launcher_background.xml
│   │               ├── drawable-v24/
│   │               │   └── ic_launcher_foreground.xml
│   │               ├── layout/
│   │               │   └── activity_main.xml
│   │               ├── mipmap-anydpi-v26/
│   │               │   ├── ic_launcher.xml
│   │               │   └── ic_launcher_round.xml
│   │               ├── values/
│   │               │   ├── colors.xml
│   │               │   ├── strings.xml
│   │               │   └── themes.xml
│   │               ├── values-night/
│   │               │   └── themes.xml
│   │               └── xml/
│   │                   ├── backup_rules.xml
│   │                   └── data_extraction_rules.xml
│   ├── gradle/
│   │   ├── libs.versions.toml
│   │   └── wrapper/
│   │       ├── gradle-wrapper.jar
│   │       └── gradle-wrapper.properties
│   ├── gradle.properties
│   ├── gradlew
│   ├── gradlew.bat
│   ├── scripts/
│   │   └── publish-root.gradle
│   ├── settings.gradle
│   └── walletsdk/
│       ├── .editorconfig
│       ├── .gitignore
│       ├── build.gradle
│       ├── consumer-rules.pro
│       ├── proguard-rules.pro
│       └── src/
│           ├── androidTest/
│           │   └── java/
│           │       └── com/
│           │           └── coinbase/
│           │               └── android/
│           │                   └── nativesdk/
│           │                       └── ExampleInstrumentedTest.kt
│           ├── main/
│           │   ├── AndroidManifest.xml
│           │   └── java/
│           │       └── com/
│           │           └── coinbase/
│           │               └── android/
│           │                   └── nativesdk/
│           │                       ├── CoinbaseWalletSDK.kt
│           │                       ├── CoinbaseWalletSDKError.kt
│           │                       ├── OpenIntentCallback.kt
│           │                       ├── key/
│           │                       │   ├── KeyManager.kt
│           │                       │   ├── KeyStore.kt
│           │                       │   └── PublicKeySerializer.kt
│           │                       ├── message/
│           │                       │   ├── Cipher.kt
│           │                       │   ├── DateSerializer.kt
│           │                       │   ├── JSON.kt
│           │                       │   ├── Message.kt
│           │                       │   ├── MessageConverter.kt
│           │                       │   ├── request/
│           │                       │   │   ├── Account.kt
│           │                       │   │   ├── Action.kt
│           │                       │   │   ├── EncryptedRequestMessage.kt
│           │                       │   │   ├── RequestConverter.kt
│           │                       │   │   ├── UnencryptedRequestMessage.kt
│           │                       │   │   └── Web3JsonRPC.kt
│           │                       │   └── response/
│           │                       │       ├── ActionResult.kt
│           │                       │       ├── EncryptedResponseMessage.kt
│           │                       │       ├── Response.kt
│           │                       │       ├── ResponseCallback.kt
│           │                       │       ├── ResponseConverter.kt
│           │                       │       └── UnencryptedResponseMessage.kt
│           │                       └── task/
│           │                           ├── Task.kt
│           │                           └── TaskManager.kt
│           └── test/
│               ├── java/
│               │   └── com/
│               │       └── coinbase/
│               │           └── android/
│               │               └── nativesdk/
│               │                   ├── ExampleUnitTest.kt
│               │                   ├── helper/
│               │                   │   └── InputStreamExtensions.kt
│               │                   └── message/
│               │                       └── request/
│               │                           └── Web3JsonRPCTest.kt
│               └── resources/
│                   ├── add_chain.json
│                   ├── personal_sign.json
│                   ├── send_transaction.json
│                   ├── sign_transaction.json
│                   ├── sign_typed_data_v3.json
│                   ├── sign_typed_data_v4.json
│                   └── watch_asset.json
├── docs/
│   ├── .gitignore
│   ├── babel.config.js
│   ├── docs/
│   │   ├── client-sdk/
│   │   │   ├── android-api-reference.md
│   │   │   ├── android-establishing-a-connection.md
│   │   │   ├── android-install.md
│   │   │   ├── android-making-requests.md
│   │   │   ├── android-setup.md
│   │   │   ├── ios-api-reference.md
│   │   │   ├── ios-establishing-a-connection.md
│   │   │   ├── ios-install.md
│   │   │   ├── ios-making-requests.md
│   │   │   ├── ios-setup.md
│   │   │   └── mobile-sdk-overview.md
│   │   ├── spec/
│   │   │   ├── batch.md
│   │   │   ├── encryption.md
│   │   │   ├── handshake.md
│   │   │   ├── messages-example.md
│   │   │   ├── messages-request.md
│   │   │   ├── messages-response.md
│   │   │   ├── messages.md
│   │   │   ├── multi-chain.md
│   │   │   ├── network.md
│   │   │   └── verification.md
│   │   └── spec-overview.md
│   ├── docusaurus.config.js
│   ├── package.json
│   ├── sidebars.js
│   ├── spec.md
│   ├── src/
│   │   ├── components/
│   │   │   └── HomepageFeatures/
│   │   │       ├── index.tsx
│   │   │       └── styles.module.css
│   │   ├── css/
│   │   │   └── custom.css
│   │   └── pages/
│   │       ├── index.module.css
│   │       └── index.tsx
│   ├── static/
│   │   └── .nojekyll
│   └── tsconfig.json
├── flutter/
│   ├── .gitignore
│   ├── .metadata
│   ├── .pubignore
│   ├── .vscode/
│   │   └── settings.json
│   ├── CHANGELOG.md
│   ├── README.md
│   ├── analysis_options.yaml
│   ├── android/
│   │   ├── .gitignore
│   │   ├── build.gradle
│   │   ├── gradle/
│   │   │   └── wrapper/
│   │   │       └── gradle-wrapper.properties
│   │   ├── settings.gradle
│   │   └── src/
│   │       └── main/
│   │           ├── AndroidManifest.xml
│   │           └── kotlin/
│   │               └── com/
│   │                   └── coinbase/
│   │                       └── flutter/
│   │                           └── wallet_sdk/
│   │                               └── CoinbaseWalletSdkFlutterPlugin.kt
│   ├── example/
│   │   ├── .gitignore
│   │   ├── README.md
│   │   ├── analysis_options.yaml
│   │   ├── android/
│   │   │   ├── .gitignore
│   │   │   ├── app/
│   │   │   │   ├── build.gradle
│   │   │   │   └── src/
│   │   │   │       ├── debug/
│   │   │   │       │   └── AndroidManifest.xml
│   │   │   │       ├── main/
│   │   │   │       │   ├── AndroidManifest.xml
│   │   │   │       │   ├── kotlin/
│   │   │   │       │   │   └── xyz/
│   │   │   │       │   │       └── tribes/
│   │   │   │       │   │           └── coinbase/
│   │   │   │       │   │               └── coinbase_wallet_sdk_flutter_example/
│   │   │   │       │   │                   └── MainActivity.kt
│   │   │   │       │   └── res/
│   │   │   │       │       ├── drawable/
│   │   │   │       │       │   └── launch_background.xml
│   │   │   │       │       ├── drawable-v21/
│   │   │   │       │       │   └── launch_background.xml
│   │   │   │       │       ├── values/
│   │   │   │       │       │   └── styles.xml
│   │   │   │       │       └── values-night/
│   │   │   │       │           └── styles.xml
│   │   │   │       └── profile/
│   │   │   │           └── AndroidManifest.xml
│   │   │   ├── build.gradle
│   │   │   ├── gradle/
│   │   │   │   └── wrapper/
│   │   │   │       └── gradle-wrapper.properties
│   │   │   ├── gradle.properties
│   │   │   └── settings.gradle
│   │   ├── ios/
│   │   │   ├── .gitignore
│   │   │   ├── Flutter/
│   │   │   │   ├── AppFrameworkInfo.plist
│   │   │   │   ├── Debug.xcconfig
│   │   │   │   └── Release.xcconfig
│   │   │   ├── Podfile
│   │   │   ├── Runner/
│   │   │   │   ├── AppDelegate.swift
│   │   │   │   ├── Assets.xcassets/
│   │   │   │   │   ├── AppIcon.appiconset/
│   │   │   │   │   │   └── Contents.json
│   │   │   │   │   └── LaunchImage.imageset/
│   │   │   │   │       ├── Contents.json
│   │   │   │   │       └── README.md
│   │   │   │   ├── Base.lproj/
│   │   │   │   │   ├── LaunchScreen.storyboard
│   │   │   │   │   └── Main.storyboard
│   │   │   │   ├── Info.plist
│   │   │   │   └── Runner-Bridging-Header.h
│   │   │   └── Runner.xcodeproj/
│   │   │       └── project.pbxproj
│   │   ├── lib/
│   │   │   └── main.dart
│   │   ├── pubspec.yaml
│   │   └── test/
│   │       └── widget_test.dart
│   ├── ios/
│   │   ├── .gitignore
│   │   ├── Assets/
│   │   │   └── .gitkeep
│   │   ├── Classes/
│   │   │   ├── CoinbaseWalletSdkFlutterPlugin.h
│   │   │   ├── CoinbaseWalletSdkFlutterPlugin.m
│   │   │   └── SwiftCoinbaseWalletSdkFlutterPlugin.swift
│   │   └── coinbase_wallet_sdk.podspec
│   ├── lib/
│   │   ├── account.dart
│   │   ├── action.dart
│   │   ├── coinbase_wallet_sdk.dart
│   │   ├── coinbase_wallet_sdk_method_channel.dart
│   │   ├── coinbase_wallet_sdk_platform_interface.dart
│   │   ├── configuration.dart
│   │   ├── eth_web3_rpc.dart
│   │   ├── request.dart
│   │   └── return_value.dart
│   ├── pubspec.yaml
│   └── test/
│       ├── coinbase_wallet_sdk_method_channel_test.dart
│       └── coinbase_wallet_sdk_test.dart
├── ios/
│   ├── CoinbaseWalletSDK/
│   │   ├── CoinbaseWalletSDK.swift
│   │   ├── Error.swift
│   │   ├── Host/
│   │   │   ├── CoinbaseWalletHostSDK.swift
│   │   │   └── ResponseMessage+init.swift
│   │   ├── Key/
│   │   │   ├── Key+RawRepresentable.swift
│   │   │   ├── KeyManager.swift
│   │   │   ├── KeyStorage.swift
│   │   │   └── KeyStorageItem.swift
│   │   ├── Message/
│   │   │   ├── Cipher.swift
│   │   │   ├── EncryptedMessage.swift
│   │   │   ├── JSONString.swift
│   │   │   ├── Message.swift
│   │   │   ├── MessageConverter.swift
│   │   │   ├── Request/
│   │   │   │   ├── Account.swift
│   │   │   │   ├── Action.swift
│   │   │   │   ├── EncryptedRequestContent.swift
│   │   │   │   ├── Request.swift
│   │   │   │   ├── RequestMessage.swift
│   │   │   │   └── Web3JSONRPC.swift
│   │   │   ├── Response/
│   │   │   │   ├── ActionResult.swift
│   │   │   │   ├── EncryptedResponseContent.swift
│   │   │   │   └── ResponseMessage.swift
│   │   │   └── URL+extension.swift
│   │   ├── Resources/
│   │   │   └── CoinbaseWalletSDK+version.swift
│   │   ├── Task/
│   │   │   ├── Task.swift
│   │   │   └── TaskManager.swift
│   │   └── Test/
│   │       └── ExampleTest.swift
│   ├── README.md
│   └── example/
│       ├── Podfile
│       ├── README.md
│       ├── SampleClient/
│       │   ├── AppDelegate.swift
│       │   ├── Base.lproj/
│       │   │   └── Main.storyboard
│       │   ├── Info.plist
│       │   └── ViewController.swift
│       ├── SampleClient.xcodeproj/
│       │   └── project.pbxproj
│       ├── SampleWallet/
│       │   ├── AppDelegate.swift
│       │   ├── Base.lproj/
│       │   │   └── Main.storyboard
│       │   └── Info.plist
│       └── SampleWallet.xcodeproj/
│           └── project.pbxproj
└── react-native/
    ├── .eslintrc.js
    ├── .npmignore
    ├── README.md
    ├── android/
    │   ├── build.gradle
    │   ├── proguard-rules.pro
    │   └── src/
    │       └── main/
    │           ├── AndroidManifest.xml
    │           └── java/
    │               └── expo/
    │                   └── modules/
    │                       └── coinbasewalletsdkexpo/
    │                           ├── ActivityLifecycleListener.kt
    │                           ├── CoinbaseWalletSDKModule.kt
    │                           ├── CoinbaseWalletSDKPackage.kt
    │                           └── records/
    │                               ├── AccountRecord.kt
    │                               ├── ActionRecord.kt
    │                               ├── ActionResultRecord.kt
    │                               ├── ConfigParamsRecord.kt
    │                               ├── HandshakeParamsRecord.kt
    │                               └── RequestParamsRecord.kt
    ├── example/
    │   ├── .buckconfig
    │   ├── .bundle/
    │   │   └── config
    │   ├── .eslintrc.js
    │   ├── .flowconfig
    │   ├── .gitignore
    │   ├── .prettierrc.js
    │   ├── .watchmanconfig
    │   ├── App.js
    │   ├── __tests__/
    │   │   └── App-test.js
    │   ├── _node-version
    │   ├── app.json
    │   ├── babel.config.js
    │   ├── index.js
    │   ├── metro.config.js
    │   └── package.json
    ├── expo-module.config.json
    ├── ios/
    │   ├── CoinbaseWalletSDKExpo.podspec
    │   ├── CoinbaseWalletSDKModule.swift
    │   └── Records/
    │       ├── AccountRecord.swift
    │       ├── ActionRecord.swift
    │       ├── ActionResultRecord.swift
    │       ├── ConfigParamsRecord.swift
    │       ├── HandshakeParamsRecord.swift
    │       └── RequestParamsRecord.swift
    ├── package.json
    ├── src/
    │   ├── CoinbaseWalletSDK.ts
    │   ├── CoinbaseWalletSDK.types.ts
    │   ├── CoinbaseWalletSDKModule.ts
    │   ├── WalletMobileSDKEVMProvider.ts
    │   └── types/
    │       ├── core/
    │       │   ├── type.ts
    │       │   └── util.ts
    │       └── provider/
    │           ├── JSONRPC.ts
    │           └── Web3Provider.ts
    └── tsconfig.json
Download .txt
SYMBOL INDEX (151 symbols across 24 files)

FILE: android/example/src/main/java/com/coinbase/android/beta/SecondActivity.java
  class SecondActivity (line 19) | public class SecondActivity extends AppCompatActivity {
    method onCreate (line 25) | @Override
    method onStart (line 40) | @Override
    method onActivityResult (line 68) | @Override

FILE: docs/src/components/HomepageFeatures/index.tsx
  type FeatureItem (line 5) | type FeatureItem = {
  function Feature (line 50) | function Feature({title, description}: FeatureItem) {
  function HomepageFeatures (line 61) | function HomepageFeatures(): JSX.Element {

FILE: docs/src/pages/index.tsx
  function HomepageHeader (line 10) | function HomepageHeader() {
  function Home (line 29) | function Home(): JSX.Element {

FILE: flutter/example/lib/main.dart
  function main (line 9) | void main()
  class MyApp (line 13) | class MyApp extends StatefulWidget {
    method createState (line 17) | State<MyApp> createState()
  class _MyAppState (line 20) | class _MyAppState extends State<MyApp> {
    method initState (line 26) | void initState()
    method _requestAccount (line 42) | Future<void> _requestAccount()
    method _personalSign (line 63) | Future<void> _personalSign()
    method _resetSession (line 88) | Future<void> _resetSession()
    method build (line 102) | Widget build(BuildContext context)

FILE: flutter/example/test/widget_test.dart
  function main (line 13) | void main()

FILE: flutter/lib/account.dart
  class Account (line 1) | class Account {
    method toJson (line 12) | Map<String, dynamic> toJson()

FILE: flutter/lib/action.dart
  class Action (line 3) | class Action {
    method toJson (line 26) | Map<String, dynamic> toJson()

FILE: flutter/lib/coinbase_wallet_sdk.dart
  class CoinbaseWalletSDK (line 12) | class CoinbaseWalletSDK {
    method configure (line 18) | Future<void> configure(Configuration configuration)
    method initiateHandshake (line 31) | Future<List<ReturnValueWithAccount>> initiateHandshake(
    method makeRequest (line 54) | Future<List<ReturnValue>> makeRequest(Request request)
    method resetSession (line 65) | Future<void> resetSession()
    method isAppInstalled (line 70) | Future<bool> isAppInstalled()
    method _configureIOS (line 78) | Future<void> _configureIOS(IOSConfiguration? configuration)
    method _configureAndroid (line 86) | Future<void> _configureAndroid(AndroidConfiguration? configuration)
  class ReturnValueWithAccount (line 95) | class ReturnValueWithAccount {

FILE: flutter/lib/coinbase_wallet_sdk_method_channel.dart
  class MethodChannelCoinbaseWalletSdkFlutter (line 9) | class MethodChannelCoinbaseWalletSdkFlutter
    method call (line 16) | Future<dynamic> call(String method, [arguments])

FILE: flutter/lib/coinbase_wallet_sdk_platform_interface.dart
  class CoinbaseWalletSdkFlutterPlatform (line 5) | abstract class CoinbaseWalletSdkFlutterPlatform extends PlatformInterface {
    method call (line 27) | Future<dynamic> call(String method, [dynamic arguments])
  class PlatformError (line 30) | class PlatformError implements Exception {
    method toString (line 37) | String toString()
  class PlatformResult (line 42) | class PlatformResult {

FILE: flutter/lib/configuration.dart
  class Configuration (line 1) | class Configuration {
  class IOSConfiguration (line 11) | class IOSConfiguration {
    method toJson (line 20) | Map<String, dynamic> toJson()
  class AndroidConfiguration (line 28) | class AndroidConfiguration {
    method toJson (line 35) | Map<String, dynamic> toJson()

FILE: flutter/lib/eth_web3_rpc.dart
  class RequestAccounts (line 5) | class RequestAccounts extends Action {
  class PersonalSign (line 13) | class PersonalSign extends Action {
  class SignTypedDataV3 (line 28) | class SignTypedDataV3 extends Action {
  class SignTypedDataV4 (line 46) | class SignTypedDataV4 extends Action {
  class SignTransaction (line 64) | class SignTransaction extends Action {
  class SendTransaction (line 93) | class SendTransaction extends Action {
  class SwitchEthereumChain (line 122) | class SwitchEthereumChain extends Action {

FILE: flutter/lib/request.dart
  class Request (line 4) | class Request {
    method toJson (line 13) | Map<String, dynamic> toJson()

FILE: flutter/lib/return_value.dart
  class ReturnValue (line 1) | class ReturnValue {
  class ReturnValueError (line 21) | class ReturnValueError {

FILE: flutter/test/coinbase_wallet_sdk_method_channel_test.dart
  function main (line 5) | void main()

FILE: flutter/test/coinbase_wallet_sdk_test.dart
  function main (line 26) | void main()

FILE: react-native/example/App.js
  function logVersion (line 60) | async function logVersion() {

FILE: react-native/src/CoinbaseWalletSDK.ts
  function configure (line 17) | function configure({
  function initiateHandshake (line 29) | async function initiateHandshake(
  function makeRequest (line 44) | async function makeRequest(
  function handleResponse (line 62) | function handleResponse(url: URL): boolean {
  function isCoinbaseWalletInstalled (line 66) | async function isCoinbaseWalletInstalled(): Promise<boolean> {
  function getCoinbaseWalletMWPVersion (line 70) | async function getCoinbaseWalletMWPVersion(): Promise<string | undefined> {
  function isConnected (line 74) | function isConnected(): boolean {
  function resetSession (line 78) | function resetSession() {

FILE: react-native/src/CoinbaseWalletSDK.types.ts
  type ConfigurationParams (line 1) | type ConfigurationParams = {
  type Action (line 7) | type Action = {
  type Account (line 13) | type Account = {
  type Result (line 19) | type Result = {
  type ActionSource (line 25) | type ActionSource = {

FILE: react-native/src/WalletMobileSDKEVMProvider.ts
  constant CACHED_ADDRESSES_KEY (line 39) | const CACHED_ADDRESSES_KEY = "mobile_sdk.addresses";
  constant CHAIN_ID_KEY (line 40) | const CHAIN_ID_KEY = "mobile_sdk.chain_id";
  type WalletMobileSDKProviderOptions (line 42) | interface WalletMobileSDKProviderOptions {
  type KVStorage (line 49) | interface KVStorage
  type AddEthereumChainParams (line 52) | interface AddEthereumChainParams {
  type SwitchEthereumChainParams (line 65) | interface SwitchEthereumChainParams {
  type WatchAssetParams (line 69) | interface WatchAssetParams {
  type EthereumTransactionParams (line 79) | interface EthereumTransactionParams {
  class WalletMobileSDKEVMProvider (line 93) | class WalletMobileSDKEVMProvider
    method constructor (line 102) | constructor(opts?: WalletMobileSDKProviderOptions) {
    method selectedAddress (line 130) | public get selectedAddress(): AddressString | undefined {
    method networkVersion (line 134) | public get networkVersion(): string {
    method host (line 138) | public get host(): string {
    method connected (line 146) | public get connected(): boolean {
    method chainId (line 150) | public get chainId(): string {
    method supportsSubscriptions (line 154) | public supportsSubscriptions(): boolean {
    method disconnect (line 158) | public disconnect(): boolean {
    method send (line 180) | public send(
    method sendAsync (line 231) | public async sendAsync(
    method request (line 256) | public async request<T>(args: RequestArguments): Promise<T> {
    method _sendRequest (line 297) | private _sendRequest(request: JSONRPCRequest): JSONRPCResponse {
    method _sendMultipleRequestsAsync (line 312) | private _sendMultipleRequestsAsync(
    method _sendRequestAsync (line 318) | private _sendRequestAsync(request: JSONRPCRequest): Promise<JSONRPCRes...
    method _handleSynchronousMethods (line 341) | private _handleSynchronousMethods({ method }: JSONRPCRequest) {
    method _handleAsynchronouseMethods (line 356) | private async _handleAsynchronouseMethods(
    method _eth_accounts (line 392) | private _eth_accounts(): string[] {
    method _eth_coinbase (line 396) | private _eth_coinbase(): string | null {
    method _net_version (line 400) | private _net_version(): string {
    method _eth_chainId (line 404) | private _eth_chainId(): string {
    method _eth_requestAccounts (line 408) | private async _eth_requestAccounts(): Promise<JSONRPCResponse> {
    method _personal_sign (line 423) | private async _personal_sign(params: unknown[]): Promise<JSONRPCRespon...
    method _eth_signTypedData (line 444) | private async _eth_signTypedData(
    method _eth_signTransaction (line 471) | private async _eth_signTransaction(
    method _prepareTransactionParams (line 509) | private _prepareTransactionParams(tx: {
    method _wallet_switchEthereumChain (line 554) | private async _wallet_switchEthereumChain(
    method _wallet_addEthereumChain (line 589) | private async _wallet_addEthereumChain(
    method _wallet_watchAsset (line 635) | private async _wallet_watchAsset(params: unknown): Promise<JSONRPCResp...
    method _makeEthereumJsonRpcRequest (line 688) | private async _makeEthereumJsonRpcRequest(
    method _makeHandshakeRequest (line 713) | private async _makeHandshakeRequest(
    method _makeSDKRequest (line 736) | private async _makeSDKRequest(action: Action): Promise<unknown> {
    method _getProviderError (line 757) | private _getProviderError(result: Result) {
    method _getChainId (line 769) | private _getChainId(): IntNumber {
    method _updateChainId (line 775) | private _updateChainId(chainId: number) {
    method _setAddresses (line 784) | private _setAddresses(addresses: string[]) {
    method _requireAuthorization (line 798) | private _requireAuthorization() {

FILE: react-native/src/types/core/type.ts
  type Tag (line 4) | interface Tag<T extends string, RealType> {
  type OpaqueType (line 9) | type OpaqueType<T extends string, U> = U & Tag<T, U>;
  function OpaqueType (line 11) | function OpaqueType<T extends Tag<string, unknown>>() {
  type HexString (line 15) | type HexString = OpaqueType<'HexString', string>;
  type AddressString (line 18) | type AddressString = OpaqueType<'AddressString', string>;
  type BigIntString (line 21) | type BigIntString = OpaqueType<'BigIntString', string>;
  type IntNumber (line 24) | type IntNumber = OpaqueType<'IntNumber', number>;
  function IntNumber (line 25) | function IntNumber(num: number): IntNumber {
  type Callback (line 29) | type Callback<T> = (err: Error | null, result: T | null) => void;

FILE: react-native/src/types/core/util.ts
  constant INT_STRING_REGEX (line 8) | const INT_STRING_REGEX = /^[0-9]*$/;
  constant HEXADECIMAL_STRING_REGEX (line 9) | const HEXADECIMAL_STRING_REGEX = /^[a-f0-9]*$/;
  function hexStringToUint8Array (line 11) | function hexStringToUint8Array(hexString: string): Uint8Array {
  function hexStringFromBuffer (line 15) | function hexStringFromBuffer(buf: Buffer, includePrefix = false): HexStr...
  function bigIntStringFromBN (line 20) | function bigIntStringFromBN(bn: BN): BigIntString {
  function intNumberFromHexString (line 24) | function intNumberFromHexString(hex: HexString): IntNumber {
  function hexStringFromIntNumber (line 28) | function hexStringFromIntNumber(num: IntNumber): HexString {
  function has0xPrefix (line 32) | function has0xPrefix(str: string): boolean {
  function strip0x (line 36) | function strip0x(hex: string): string {
  function prepend0x (line 43) | function prepend0x(hex: string): string {
  function isHexString (line 50) | function isHexString(hex: unknown): hex is HexString {
  class InvalidParamsError (line 58) | class InvalidParamsError extends Error {
    method constructor (line 60) | constructor(message: string) {
  function ensureHexString (line 65) | function ensureHexString(hex: unknown, includePrefix = false): HexString {
  function ensureEvenLengthHexString (line 75) | function ensureEvenLengthHexString(hex: unknown, includePrefix = false):...
  function ensureAddressString (line 83) | function ensureAddressString(str: unknown): AddressString {
  function ensureBuffer (line 93) | function ensureBuffer(str: unknown): Buffer {
  function ensureIntNumber (line 107) | function ensureIntNumber(num: unknown): IntNumber {
  function ensureBN (line 122) | function ensureBN(val: unknown): BN {
  function ensureParsedJSONObject (line 140) | function ensureParsedJSONObject<T extends object>(val: unknown): T {
  function isBigNumber (line 152) | function isBigNumber(val: unknown): boolean {

FILE: react-native/src/types/provider/JSONRPC.ts
  type JSONRPCMethod (line 4) | type JSONRPCMethod =
  type JSONRPCRequest (line 42) | interface JSONRPCRequest<T = any> {
  type JSONRPCResponse (line 49) | interface JSONRPCResponse<T = any, U = any> {

FILE: react-native/src/types/provider/Web3Provider.ts
  type Web3Provider (line 7) | interface Web3Provider {
  type RequestArguments (line 26) | interface RequestArguments {
Condensed preview — 273 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (526K chars).
[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yml",
    "chars": 1693,
    "preview": "name: Bug report\ndescription: Create a report to help us improve\ntitle: \"Bug: \"\nlabels: [\"type: bug\"]\n\nbody:\n  - type: i"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "chars": 194,
    "preview": "blank_issues_enabled: false\ncontact_links:\n  - name: Coinbase Wallet Developer Docs\n    url: https://docs.cloud.coinbase"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.yml",
    "chars": 1141,
    "preview": "name: Feature request\ndescription: Suggest an idea for this project\ntitle: \"Feature Request: \"\nlabels: [\"type: enhanceme"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 167,
    "preview": "### _Summary_\n\n<!--\n  What changed? Link to relevant issues.\n-->\n\n### _How did you test your changes?_\n\n<!--\n  Verify ch"
  },
  {
    "path": ".github/workflows/publish.yml",
    "chars": 4016,
    "preview": "name: Tag & Publish [auto]\n\non:\n  push:\n    branches:\n      - master\n\njobs:\n  environment: release\n  permissions:\n    co"
  },
  {
    "path": ".github/workflows/run_tests.yml",
    "chars": 912,
    "preview": "name: Run Tests\n\non:\n  pull_request:\n    branches:\n      - master\n\njobs:\n  android:\n    name: Android\n    runs-on: ubunt"
  },
  {
    "path": ".github/workflows/version_update.yml",
    "chars": 3752,
    "preview": "name: Version Update PR\n\non:\n  workflow_dispatch:\n    inputs:\n      packageVersion:\n        description: \"The version to"
  },
  {
    "path": ".gitignore",
    "chars": 2553,
    "preview": "# misc\n.DS_Store\n\n# Native mobile\n\n## User settings\nxcuserdata/\n\n## compatibility with Xcode 8 and earlier (ignoring not"
  },
  {
    "path": "CODEOWNERS",
    "chars": 61,
    "preview": "* @coinbase/wallet-mobile-sdk\n.github/workflows/* @bangtoven\n"
  },
  {
    "path": "CoinbaseWalletSDK.podspec",
    "chars": 1385,
    "preview": "Pod::Spec.new do |s|\n  s.name                  = 'CoinbaseWalletSDK'\n  s.version               = '1.1.2'\n  s.summary    "
  },
  {
    "path": "Gemfile",
    "chars": 47,
    "preview": "source 'https://rubygems.org'\n\ngem 'cocoapods'\n"
  },
  {
    "path": "LICENSE",
    "chars": 559,
    "preview": "Copyright (c) 2022 Coinbase, Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this "
  },
  {
    "path": "Package.swift",
    "chars": 614,
    "preview": "// swift-tools-version: 5.4\n\nimport PackageDescription\n\nlet package = Package(\n    name: \"CoinbaseWalletSDK\",\n    platfo"
  },
  {
    "path": "README.md",
    "chars": 2301,
    "preview": "# Coinbase Wallet Mobile SDK\n\n[![Cocoapods](https://img.shields.io/cocoapods/v/CoinbaseWalletSDK)](https://cocoapods.org"
  },
  {
    "path": "android/README.md",
    "chars": 5099,
    "preview": "# Coinbase Wallet Mobile SDK\n\n[![Maven](https://img.shields.io/maven-central/v/com.coinbase/coinbase-wallet-sdk?label=ma"
  },
  {
    "path": "android/build.gradle",
    "chars": 420,
    "preview": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\nplugins {\n    alias "
  },
  {
    "path": "android/example/.editorconfig",
    "chars": 37,
    "preview": "[{*.kt, *.kts}]\nmax_line_length = 120"
  },
  {
    "path": "android/example/.gitignore",
    "chars": 6,
    "preview": "/build"
  },
  {
    "path": "android/example/build.gradle",
    "chars": 1404,
    "preview": "plugins {\n    id 'com.android.application'\n    id 'org.jetbrains.kotlin.android'\n}\n\nandroid {\n    compileSdk 33\n\n    sig"
  },
  {
    "path": "android/example/proguard-rules.pro",
    "chars": 750,
    "preview": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguar"
  },
  {
    "path": "android/example/src/main/AndroidManifest.xml",
    "chars": 1064,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:to"
  },
  {
    "path": "android/example/src/main/java/com/coinbase/android/beta/ActionsManager.kt",
    "chars": 2364,
    "preview": "package com.coinbase.android.beta\n\nimport android.content.Context\nimport android.content.SharedPreferences\nimport com.co"
  },
  {
    "path": "android/example/src/main/java/com/coinbase/android/beta/MainActivity.kt",
    "chars": 5948,
    "preview": "package com.coinbase.android.beta\n\nimport android.content.Intent\nimport android.net.Uri\nimport android.os.Bundle\nimport "
  },
  {
    "path": "android/example/src/main/java/com/coinbase/android/beta/SecondActivity.java",
    "chars": 2476,
    "preview": "package com.coinbase.android.beta;\n\nimport static com.coinbase.android.nativesdk.CoinbaseWalletSDKKt.CBW_PACKAGE_NAME;\n\n"
  },
  {
    "path": "android/example/src/main/res/drawable/ic_launcher_background.xml",
    "chars": 5606,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:wi"
  },
  {
    "path": "android/example/src/main/res/drawable-v24/ic_launcher_foreground.xml",
    "chars": 1702,
    "preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    "
  },
  {
    "path": "android/example/src/main/res/layout/activity_main.xml",
    "chars": 3743,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas."
  },
  {
    "path": "android/example/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "chars": 272,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <b"
  },
  {
    "path": "android/example/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "chars": 272,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <b"
  },
  {
    "path": "android/example/src/main/res/values/colors.xml",
    "chars": 422,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"purple_200\">#FFBB86FC</color>\n    <color name=\"purpl"
  },
  {
    "path": "android/example/src/main/res/values/strings.xml",
    "chars": 515,
    "preview": "<resources>\n    <string name=\"app_name\">WalletSDK ClientApp</string>\n    <string name=\"connect_wallet\">Connect Wallet</s"
  },
  {
    "path": "android/example/src/main/res/values/themes.xml",
    "chars": 811,
    "preview": "<resources xmlns:tools=\"http://schemas.android.com/tools\">\n    <!-- Base application theme. -->\n    <style name=\"Theme.C"
  },
  {
    "path": "android/example/src/main/res/values-night/themes.xml",
    "chars": 811,
    "preview": "<resources xmlns:tools=\"http://schemas.android.com/tools\">\n    <!-- Base application theme. -->\n    <style name=\"Theme.C"
  },
  {
    "path": "android/example/src/main/res/xml/backup_rules.xml",
    "chars": 478,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n   Sample backup rules file; uncomment and customize as necessary.\n   See htt"
  },
  {
    "path": "android/example/src/main/res/xml/data_extraction_rules.xml",
    "chars": 551,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\n   Sample data extraction rules file; uncomment and customize as necessary.\n "
  },
  {
    "path": "android/gradle/libs.versions.toml",
    "chars": 1361,
    "preview": "[versions]\ngradleplugin = \"7.2.2\"\nkotlin = \"1.6.21\"\nkotlinSerialization = \"1.3.3\"\nnexus-publish = \"1.1.0\"\n\nsdk-version ="
  },
  {
    "path": "android/gradle/wrapper/gradle-wrapper.properties",
    "chars": 202,
    "preview": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributi"
  },
  {
    "path": "android/gradle.properties",
    "chars": 1358,
    "preview": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will ov"
  },
  {
    "path": "android/gradlew",
    "chars": 8047,
    "preview": "#!/bin/sh\n\n#\n# Copyright © 2015-2021 the original authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"Lice"
  },
  {
    "path": "android/gradlew.bat",
    "chars": 2674,
    "preview": "@rem\n@rem Copyright 2015 the original author or authors.\n@rem\n@rem Licensed under the Apache License, Version 2.0 (the \""
  },
  {
    "path": "android/scripts/publish-root.gradle",
    "chars": 1484,
    "preview": "// Create variables with empty default values\next[\"signing.keyId\"] = ''\next[\"signing.password\"] = ''\next[\"signing.key\"] "
  },
  {
    "path": "android/settings.gradle",
    "chars": 347,
    "preview": "pluginManagement {\n    repositories {\n        gradlePluginPortal()\n        google()\n        mavenCentral()\n    }\n}\n\ndepe"
  },
  {
    "path": "android/walletsdk/.editorconfig",
    "chars": 37,
    "preview": "[{*.kt, *.kts}]\nmax_line_length = 120"
  },
  {
    "path": "android/walletsdk/.gitignore",
    "chars": 6,
    "preview": "/build"
  },
  {
    "path": "android/walletsdk/build.gradle",
    "chars": 3323,
    "preview": "plugins {\n    alias libs.plugins.android.library\n    alias libs.plugins.kotlin.android\n    id 'org.jetbrains.kotlin.plug"
  },
  {
    "path": "android/walletsdk/consumer-rules.pro",
    "chars": 2305,
    "preview": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguar"
  },
  {
    "path": "android/walletsdk/proguard-rules.pro",
    "chars": 2305,
    "preview": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguar"
  },
  {
    "path": "android/walletsdk/src/androidTest/java/com/coinbase/android/nativesdk/ExampleInstrumentedTest.kt",
    "chars": 694,
    "preview": "package com.coinbase.android.nativesdk\n\nimport androidx.test.platform.app.InstrumentationRegistry\nimport androidx.test.e"
  },
  {
    "path": "android/walletsdk/src/main/AndroidManifest.xml",
    "chars": 166,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package="
  },
  {
    "path": "android/walletsdk/src/main/java/com/coinbase/android/nativesdk/CoinbaseWalletSDK.kt",
    "chars": 9354,
    "preview": "package com.coinbase.android.nativesdk\n\nimport android.annotation.SuppressLint\nimport android.content.Context\nimport and"
  },
  {
    "path": "android/walletsdk/src/main/java/com/coinbase/android/nativesdk/CoinbaseWalletSDKError.kt",
    "chars": 768,
    "preview": "package com.coinbase.android.nativesdk\n\nsealed class CoinbaseWalletSDKError(\n    errorMessage: String? = null,\n    cause"
  },
  {
    "path": "android/walletsdk/src/main/java/com/coinbase/android/nativesdk/OpenIntentCallback.kt",
    "chars": 132,
    "preview": "package com.coinbase.android.nativesdk\n\nimport android.content.Intent\n\ninterface OpenIntentCallback {\n    fun call(inten"
  },
  {
    "path": "android/walletsdk/src/main/java/com/coinbase/android/nativesdk/key/KeyManager.kt",
    "chars": 1954,
    "preview": "package com.coinbase.android.nativesdk.key\n\nimport KeyStore\nimport android.content.Context\nimport com.google.crypto.tink"
  },
  {
    "path": "android/walletsdk/src/main/java/com/coinbase/android/nativesdk/key/KeyStore.kt",
    "chars": 6043,
    "preview": "import android.app.KeyguardManager\nimport android.content.Context\nimport android.content.SharedPreferences\nimport androi"
  },
  {
    "path": "android/walletsdk/src/main/java/com/coinbase/android/nativesdk/key/PublicKeySerializer.kt",
    "chars": 913,
    "preview": "package com.coinbase.android.nativesdk.key\n\nimport com.google.crypto.tink.subtle.Base64\nimport com.google.crypto.tink.su"
  },
  {
    "path": "android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/Cipher.kt",
    "chars": 747,
    "preview": "package com.coinbase.android.nativesdk.message\n\nimport com.google.crypto.tink.subtle.AesGcmJce\nimport com.google.crypto."
  },
  {
    "path": "android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/DateSerializer.kt",
    "chars": 713,
    "preview": "package com.coinbase.android.nativesdk.message\n\nimport kotlinx.serialization.KSerializer\nimport kotlinx.serialization.de"
  },
  {
    "path": "android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/JSON.kt",
    "chars": 182,
    "preview": "package com.coinbase.android.nativesdk.message\n\nimport kotlinx.serialization.json.Json\n\ninternal val JSON = Json {\n    e"
  },
  {
    "path": "android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/Message.kt",
    "chars": 787,
    "preview": "package com.coinbase.android.nativesdk.message\n\nimport com.coinbase.android.nativesdk.key.PublicKeySerializer\nimport kot"
  },
  {
    "path": "android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/MessageConverter.kt",
    "chars": 1254,
    "preview": "package com.coinbase.android.nativesdk.message\n\nimport android.net.Uri\nimport com.google.crypto.tink.subtle.EllipticCurv"
  },
  {
    "path": "android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/request/Account.kt",
    "chars": 201,
    "preview": "package com.coinbase.android.nativesdk.message.request\n\nimport kotlinx.serialization.Serializable\n\n@Serializable\nclass A"
  },
  {
    "path": "android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/request/Action.kt",
    "chars": 1166,
    "preview": "package com.coinbase.android.nativesdk.message.request\n\nimport kotlinx.serialization.Serializable\n\n@Serializable\nclass A"
  },
  {
    "path": "android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/request/EncryptedRequestMessage.kt",
    "chars": 1586,
    "preview": "package com.coinbase.android.nativesdk.message.request\n\nimport com.coinbase.android.nativesdk.CoinbaseWalletSDKError\nimp"
  },
  {
    "path": "android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/request/RequestConverter.kt",
    "chars": 1912,
    "preview": "package com.coinbase.android.nativesdk.message.request\n\nimport android.net.Uri\nimport com.coinbase.android.nativesdk.Coi"
  },
  {
    "path": "android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/request/UnencryptedRequestMessage.kt",
    "chars": 1988,
    "preview": "package com.coinbase.android.nativesdk.message.request\n\nimport com.coinbase.android.nativesdk.CoinbaseWalletSDKError\nimp"
  },
  {
    "path": "android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/request/Web3JsonRPC.kt",
    "chars": 4204,
    "preview": "package com.coinbase.android.nativesdk.message.request\n\nimport com.coinbase.android.nativesdk.message.JSON\nimport kotlin"
  },
  {
    "path": "android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/response/ActionResult.kt",
    "chars": 2215,
    "preview": "package com.coinbase.android.nativesdk.message.response\n\nimport com.coinbase.android.nativesdk.CoinbaseWalletSDKError\nim"
  },
  {
    "path": "android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/response/EncryptedResponseMessage.kt",
    "chars": 1667,
    "preview": "package com.coinbase.android.nativesdk.message.response\n\nimport com.coinbase.android.nativesdk.CoinbaseWalletSDKError\nim"
  },
  {
    "path": "android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/response/Response.kt",
    "chars": 163,
    "preview": "package com.coinbase.android.nativesdk.message.response\n\ntypealias ResponseResult = Result<List<ActionResult>>\ntypealias"
  },
  {
    "path": "android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/response/ResponseCallback.kt",
    "chars": 384,
    "preview": "package com.coinbase.android.nativesdk.message.response\n\nimport com.coinbase.android.nativesdk.message.request.Account\n\n"
  },
  {
    "path": "android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/response/ResponseConverter.kt",
    "chars": 1919,
    "preview": "package com.coinbase.android.nativesdk.message.response\n\nimport android.net.Uri\nimport com.coinbase.android.nativesdk.Co"
  },
  {
    "path": "android/walletsdk/src/main/java/com/coinbase/android/nativesdk/message/response/UnencryptedResponseMessage.kt",
    "chars": 2030,
    "preview": "package com.coinbase.android.nativesdk.message.response\n\nimport com.coinbase.android.nativesdk.CoinbaseWalletSDKError\nim"
  },
  {
    "path": "android/walletsdk/src/main/java/com/coinbase/android/nativesdk/task/Task.kt",
    "chars": 343,
    "preview": "package com.coinbase.android.nativesdk.task\n\nimport com.coinbase.android.nativesdk.message.request.UnencryptedRequestMes"
  },
  {
    "path": "android/walletsdk/src/main/java/com/coinbase/android/nativesdk/task/TaskManager.kt",
    "chars": 1551,
    "preview": "package com.coinbase.android.nativesdk.task\n\nimport com.coinbase.android.nativesdk.CoinbaseWalletSDKError\nimport com.coi"
  },
  {
    "path": "android/walletsdk/src/test/java/com/coinbase/android/nativesdk/ExampleUnitTest.kt",
    "chars": 354,
    "preview": "package com.coinbase.android.nativesdk\n\nimport org.junit.Test\n\nimport org.junit.Assert.*\n\n/**\n * Example local unit test"
  },
  {
    "path": "android/walletsdk/src/test/java/com/coinbase/android/nativesdk/helper/InputStreamExtensions.kt",
    "chars": 547,
    "preview": "package com.coinbase.android.nativesdk.helper\n\nimport java.io.IOException\nimport java.io.InputStream\n\n@Throws(IOExceptio"
  },
  {
    "path": "android/walletsdk/src/test/java/com/coinbase/android/nativesdk/message/request/Web3JsonRPCTest.kt",
    "chars": 6601,
    "preview": "package com.coinbase.android.nativesdk.message.request\n\nimport com.coinbase.android.nativesdk.helper.readFileWithNewLine"
  },
  {
    "path": "android/walletsdk/src/test/resources/add_chain.json",
    "chars": 180,
    "preview": "{\n  \"#wsegue_type\": \"wallet_addEthereumChain\",\n  \"chainId\": \"137\",\n  \"blockExplorerUrls\": null,\n  \"chainName\": null,\n  \""
  },
  {
    "path": "android/walletsdk/src/test/resources/personal_sign.json",
    "chars": 118,
    "preview": "{\n  \"#wsegue_type\": \"personal_sign\",\n  \"address\": \"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826\",\n  \"message\": \"hello\"\n}"
  },
  {
    "path": "android/walletsdk/src/test/resources/send_transaction.json",
    "chars": 353,
    "preview": "{\n  \"#wsegue_type\": \"eth_sendTransaction\",\n  \"fromAddress\": \"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826\",\n  \"toAddress\":"
  },
  {
    "path": "android/walletsdk/src/test/resources/sign_transaction.json",
    "chars": 353,
    "preview": "{\n  \"#wsegue_type\": \"eth_signTransaction\",\n  \"fromAddress\": \"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826\",\n  \"toAddress\":"
  },
  {
    "path": "android/walletsdk/src/test/resources/sign_typed_data_v3.json",
    "chars": 947,
    "preview": "{\n  \"#wsegue_type\": \"eth_signTypedData_v3\",\n  \"address\": \"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826\",\n  \"typedDataJson\""
  },
  {
    "path": "android/walletsdk/src/test/resources/sign_typed_data_v4.json",
    "chars": 947,
    "preview": "{\n  \"#wsegue_type\": \"eth_signTypedData_v4\",\n  \"address\": \"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826\",\n  \"typedDataJson\""
  },
  {
    "path": "android/walletsdk/src/test/resources/watch_asset.json",
    "chars": 206,
    "preview": "{\n  \"#wsegue_type\": \"wallet_watchAsset\",\n  \"type\": \"type\",\n  \"options\": {\n    \"address\": \"0xCD2a3d9F938E13CD947Ec05AbC7F"
  },
  {
    "path": "docs/.gitignore",
    "chars": 233,
    "preview": "# Dependencies\n/node_modules\n\n# Production\n/build\n\n# Generated files\n.docusaurus\n.cache-loader\n\n# Misc\n.DS_Store\n.env.lo"
  },
  {
    "path": "docs/babel.config.js",
    "chars": 89,
    "preview": "module.exports = {\n  presets: [require.resolve('@docusaurus/core/lib/babel/preset')],\n};\n"
  },
  {
    "path": "docs/docs/client-sdk/android-api-reference.md",
    "chars": 13794,
    "preview": "---\ntitle: \"API Reference\"\nslug: \"android-api-reference\"\ncategory: \"633d1d37bc7103008654c123\"\n---\n\n# Actions\n\nThe `initi"
  },
  {
    "path": "docs/docs/client-sdk/android-establishing-a-connection.md",
    "chars": 1683,
    "preview": "---\ntitle: \"Establishing a connection\"\nslug: \"android-establishing-a-connection\"\ncategory: \"633d1d37bc7103008654c123\"\n--"
  },
  {
    "path": "docs/docs/client-sdk/android-install.md",
    "chars": 623,
    "preview": "---\ntitle: \"Install\"\nslug: \"android-install\"\ncategory: \"633d1d37bc7103008654c123\"\n---\n\nThe Coinbase Wallet Mobile SDK is"
  },
  {
    "path": "docs/docs/client-sdk/android-making-requests.md",
    "chars": 810,
    "preview": "---\ntitle: \"Making requests\"\nslug: \"android-making-requests\"\ncategory: \"633d1d37bc7103008654c123\"\n---\n\nRequests to Coinb"
  },
  {
    "path": "docs/docs/client-sdk/android-setup.md",
    "chars": 1961,
    "preview": "---\ntitle: \"Setup\"\nslug: \"android-setup\"\ncategory: \"633d1d37bc7103008654c123\"\n---\n\nIn order for your app to interact wit"
  },
  {
    "path": "docs/docs/client-sdk/ios-api-reference.md",
    "chars": 11384,
    "preview": "---\ntitle: \"API Reference\"\nslug: \"ios-api-reference\"\ncategory: \"633d1d37bc7103008654c123\"\n---\n\n# Actions\n\nThe `initiateH"
  },
  {
    "path": "docs/docs/client-sdk/ios-establishing-a-connection.md",
    "chars": 1102,
    "preview": "---\ntitle: \"Establishing a connection\"\nslug: \"ios-establishing-a-connection\"\ncategory: \"633d1d37bc7103008654c123\"\n---\n\nA"
  },
  {
    "path": "docs/docs/client-sdk/ios-install.md",
    "chars": 1001,
    "preview": "---\ntitle: \"Install\"\nslug: \"ios-install\"\ncategory: \"633d1d37bc7103008654c123\"\n---\n\nThe Coinbase Wallet Mobile SDK is ava"
  },
  {
    "path": "docs/docs/client-sdk/ios-making-requests.md",
    "chars": 732,
    "preview": "---\ntitle: \"Making requests\"\nslug: \"ios-making-requests\"\ncategory: \"633d1d37bc7103008654c123\"\n---\n\nRequests to Coinbase "
  },
  {
    "path": "docs/docs/client-sdk/ios-setup.md",
    "chars": 1153,
    "preview": "---\ntitle: \"Setup\"\nslug: \"ios-setup\"\ncategory: \"633d1d37bc7103008654c123\"\n---\n\nCoinbase Wallet Mobile SDK uses [Universa"
  },
  {
    "path": "docs/docs/client-sdk/mobile-sdk-overview.md",
    "chars": 1427,
    "preview": "---\ntitle: \"Overview\"\nslug: \"mobile-sdk-overview\"\ncategory: \"633d1d37bc7103008654c123\"\n---\n\n[Coinbase Wallet Mobile SDK]"
  },
  {
    "path": "docs/docs/spec/batch.md",
    "chars": 1730,
    "preview": "# Batch requests\n\nTo improve UX by minimizing app switches, \nMWP allows client apps to make requests with multiple actio"
  },
  {
    "path": "docs/docs/spec/encryption.md",
    "chars": 6866,
    "preview": "# Encryption\n\nMWP uses deep links for direct communication between peers.\n\nTo ensure security, all messages in MWP after"
  },
  {
    "path": "docs/docs/spec/handshake.md",
    "chars": 2403,
    "preview": "# Handshake\n\nFor key exchange, client apps make `handshake` calls to ask wallets to generate and share a key to encrypt "
  },
  {
    "path": "docs/docs/spec/messages-example.md",
    "chars": 5666,
    "preview": "# Example\n\n### handshake\n- URL\n`https://go.cb-w.com/wsegue?p=eyJ2ZXJzaW9uIjoiMS4wLjMiLCJzZW5kZXIiOiJsRUNcL1gzSzY4cmxnT29"
  },
  {
    "path": "docs/docs/spec/messages-request.md",
    "chars": 894,
    "preview": "# Request content\n\nRequest message has `request` as its `content`, which contains following:\n\n## Properties\n\n### `action"
  },
  {
    "path": "docs/docs/spec/messages-response.md",
    "chars": 1227,
    "preview": "# Response content\n\nResponse content can be either `response` or `failure`.\n\n## `response`\n\nAs long as the host wallet c"
  },
  {
    "path": "docs/docs/spec/messages.md",
    "chars": 1343,
    "preview": "# Messages\n\nCommunications between client and server (wallet host) in MWP are through exchanging discrete stateless mess"
  },
  {
    "path": "docs/docs/spec/multi-chain.md",
    "chars": 510,
    "preview": "# Multi-chain support\n\nMWP is chain-agnostic. \nAs long as the wallet supports the chain and is able to process the reque"
  },
  {
    "path": "docs/docs/spec/network.md",
    "chars": 95,
    "preview": "# Transport layer\n\nDeep linking through universal links on iOS.\nIntent + app links on android.\n"
  },
  {
    "path": "docs/docs/spec/verification.md",
    "chars": 778,
    "preview": "# Verification\n\nDecentralized verification of participating apps’ authenticity using [.well-known](https://en.wikipedia."
  },
  {
    "path": "docs/docs/spec-overview.md",
    "chars": 1095,
    "preview": "---\ntitle: \"Overview\"\nslug: \"spec\"\n---\n\n# Overview\n\n## Mobile Wallet Protocol\n\n![](spec/img/overview.png)\n\nMWP is a prot"
  },
  {
    "path": "docs/docusaurus.config.js",
    "chars": 3444,
    "preview": "// @ts-check\n// Note: type annotations allow type checking and IDEs autocompletion\n\nconst lightCodeTheme = require('pris"
  },
  {
    "path": "docs/package.json",
    "chars": 1131,
    "preview": "{\n  \"name\": \"mobile-wallet-protocol\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"docusaurus\": \"docusau"
  },
  {
    "path": "docs/sidebars.js",
    "chars": 1455,
    "preview": "/**\n * Creating a sidebar enables you to:\n - create an ordered group of docs\n - render a sidebar for each doc of that gr"
  },
  {
    "path": "docs/spec.md",
    "chars": 192,
    "preview": "---\nlayout: page\ntitle: \"Spec\"\npermalink: /spec\n---\n\n# Mobile Wallet Protocol (MWP)\n\nMWP is a protocol to allow mobile w"
  },
  {
    "path": "docs/src/components/HomepageFeatures/index.tsx",
    "chars": 1670,
    "preview": "import React from 'react';\nimport clsx from 'clsx';\nimport styles from './styles.module.css';\n\ntype FeatureItem = {\n  ti"
  },
  {
    "path": "docs/src/components/HomepageFeatures/styles.module.css",
    "chars": 138,
    "preview": ".features {\n  display: flex;\n  align-items: center;\n  padding: 2rem 0;\n  width: 100%;\n}\n\n.featureSvg {\n  height: 200px;\n"
  },
  {
    "path": "docs/src/css/custom.css",
    "chars": 1042,
    "preview": "/**\n * Any CSS included here will be global. The classic template\n * bundles Infima by default. Infima is a CSS framewor"
  },
  {
    "path": "docs/src/pages/index.module.css",
    "chars": 383,
    "preview": "/**\n * CSS files with the .module.css suffix will be treated as CSS modules\n * and scoped locally.\n */\n\n.heroBanner {\n  "
  },
  {
    "path": "docs/src/pages/index.tsx",
    "chars": 1125,
    "preview": "import React from 'react';\nimport clsx from 'clsx';\nimport Link from '@docusaurus/Link';\nimport useDocusaurusContext fro"
  },
  {
    "path": "docs/static/.nojekyll",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "docs/tsconfig.json",
    "chars": 190,
    "preview": "{\n  // This file is not used in compilation. It is here just for a nice editor experience.\n  \"extends\": \"@tsconfig/docus"
  },
  {
    "path": "flutter/.gitignore",
    "chars": 541,
    "preview": "# Miscellaneous\n*.class\n*.log\n*.pyc\n*.swp\n.DS_Store\n.atom/\n.buildlog/\n.history\n.svn/\nmigrate_working_dir/\n\n# IntelliJ re"
  },
  {
    "path": "flutter/.metadata",
    "chars": 1079,
    "preview": "# This file tracks properties of this Flutter project.\n# Used by Flutter tool to assess capabilities and perform upgrade"
  },
  {
    "path": "flutter/.pubignore",
    "chars": 13,
    "preview": "example\ntest\n"
  },
  {
    "path": "flutter/.vscode/settings.json",
    "chars": 47,
    "preview": "{\n  \"workbench.colorTheme\": \"Solarized Light\"\n}"
  },
  {
    "path": "flutter/CHANGELOG.md",
    "chars": 40,
    "preview": "## 1.0.0\n\n- iOS/Android Flutter support\n"
  },
  {
    "path": "flutter/README.md",
    "chars": 1843,
    "preview": "# coinbase_wallet_sdk\n\nA flutter wrapper for CoinbaseWallet mobile SDK\n\nNote: This wrapper only supports iOS and Android"
  },
  {
    "path": "flutter/analysis_options.yaml",
    "chars": 154,
    "preview": "include: package:flutter_lints/flutter.yaml\n\n# Additional information about this file can be found at\n# https://dart.dev"
  },
  {
    "path": "flutter/android/.gitignore",
    "chars": 102,
    "preview": "*.iml\n.gradle\n/local.properties\n/.idea/workspace.xml\n/.idea/libraries\n.DS_Store\n/build\n/captures\n.cxx\n"
  },
  {
    "path": "flutter/android/build.gradle",
    "chars": 1258,
    "preview": "group 'com.coinbase.coinbase_wallet_sdk'\nversion '1.0-SNAPSHOT'\n\nbuildscript {\n    ext.kotlin_version = '1.6.10'\n    rep"
  },
  {
    "path": "flutter/android/gradle/wrapper/gradle-wrapper.properties",
    "chars": 77,
    "preview": "distributionUrl=https\\://services.gradle.org/distributions/gradle-7.4-all.zip"
  },
  {
    "path": "flutter/android/settings.gradle",
    "chars": 41,
    "preview": "rootProject.name = 'coinbase_wallet_sdk'\n"
  },
  {
    "path": "flutter/android/src/main/AndroidManifest.xml",
    "chars": 126,
    "preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  package=\"com.coinbase.flutter.wallet_sdk\">\n</mani"
  },
  {
    "path": "flutter/android/src/main/kotlin/com/coinbase/flutter/wallet_sdk/CoinbaseWalletSdkFlutterPlugin.kt",
    "chars": 7146,
    "preview": "package com.coinbase.flutter.wallet_sdk\n\nimport android.content.Context\nimport android.content.Intent\nimport android.net"
  },
  {
    "path": "flutter/example/.gitignore",
    "chars": 753,
    "preview": "# Miscellaneous\n*.class\n*.log\n*.pyc\n*.swp\n.DS_Store\n.atom/\n.buildlog/\n.history\n.svn/\nmigrate_working_dir/\n\n# IntelliJ re"
  },
  {
    "path": "flutter/example/README.md",
    "chars": 603,
    "preview": "# coinbase_wallet_sdk_example\n\nDemonstrates how to use the coinbase_wallet_sdk plugin.\n\n## Getting Started\n\nThis project"
  },
  {
    "path": "flutter/example/analysis_options.yaml",
    "chars": 1453,
    "preview": "# This file configures the analyzer, which statically analyzes Dart code to\n# check for errors, warnings, and lints.\n#\n#"
  },
  {
    "path": "flutter/example/android/.gitignore",
    "chars": 285,
    "preview": "gradle-wrapper.jar\n/.gradle\n/captures/\n/gradlew\n/gradlew.bat\n/local.properties\nGeneratedPluginRegistrant.java\n\n# Remembe"
  },
  {
    "path": "flutter/example/android/app/build.gradle",
    "chars": 2709,
    "preview": "def localProperties = new Properties()\ndef localPropertiesFile = rootProject.file('local.properties')\nif (localPropertie"
  },
  {
    "path": "flutter/example/android/app/src/debug/AndroidManifest.xml",
    "chars": 440,
    "preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"xyz.tribes.coinbase.coinbase_wallet_sd"
  },
  {
    "path": "flutter/example/android/app/src/main/AndroidManifest.xml",
    "chars": 1842,
    "preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"xyz.tribes.coinbase.coinbase_wallet_sd"
  },
  {
    "path": "flutter/example/android/app/src/main/kotlin/xyz/tribes/coinbase/coinbase_wallet_sdk_flutter_example/MainActivity.kt",
    "chars": 761,
    "preview": "package xyz.tribes.coinbase.coinbase_wallet_sdk_example\n\nimport android.content.Intent\nimport android.net.Uri\nimport and"
  },
  {
    "path": "flutter/example/android/app/src/main/res/drawable/launch_background.xml",
    "chars": 434,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Modify this file to customize your launch splash screen -->\n<layer-list xmln"
  },
  {
    "path": "flutter/example/android/app/src/main/res/drawable-v21/launch_background.xml",
    "chars": 438,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Modify this file to customize your launch splash screen -->\n<layer-list xmln"
  },
  {
    "path": "flutter/example/android/app/src/main/res/values/styles.xml",
    "chars": 996,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- Theme applied to the Android Window while the process is sta"
  },
  {
    "path": "flutter/example/android/app/src/main/res/values-night/styles.xml",
    "chars": 995,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- Theme applied to the Android Window while the process is sta"
  },
  {
    "path": "flutter/example/android/app/src/profile/AndroidManifest.xml",
    "chars": 440,
    "preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"xyz.tribes.coinbase.coinbase_wallet_sd"
  },
  {
    "path": "flutter/example/android/build.gradle",
    "chars": 592,
    "preview": "buildscript {\n    ext.kotlin_version = '1.6.10'\n    repositories {\n        google()\n        mavenCentral()\n    }\n\n    de"
  },
  {
    "path": "flutter/example/android/gradle/wrapper/gradle-wrapper.properties",
    "chars": 231,
    "preview": "#Fri Jun 23 08:50:38 CEST 2017\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER"
  },
  {
    "path": "flutter/example/android/gradle.properties",
    "chars": 82,
    "preview": "org.gradle.jvmargs=-Xmx1536M\nandroid.useAndroidX=true\nandroid.enableJetifier=true\n"
  },
  {
    "path": "flutter/example/android/settings.gradle",
    "chars": 463,
    "preview": "include ':app'\n\ndef localPropertiesFile = new File(rootProject.projectDir, \"local.properties\")\ndef properties = new Prop"
  },
  {
    "path": "flutter/example/ios/.gitignore",
    "chars": 569,
    "preview": "**/dgph\n*.mode1v3\n*.mode2v3\n*.moved-aside\n*.pbxuser\n*.perspectivev3\n**/*sync/\n.sconsign.dblite\n.tags*\n**/.vagrant/\n**/De"
  },
  {
    "path": "flutter/example/ios/Flutter/AppFrameworkInfo.plist",
    "chars": 774,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "flutter/example/ios/Flutter/Debug.xcconfig",
    "chars": 107,
    "preview": "#include? \"Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig\"\n#include \"Generated.xcconfig\"\n"
  },
  {
    "path": "flutter/example/ios/Flutter/Release.xcconfig",
    "chars": 109,
    "preview": "#include? \"Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig\"\n#include \"Generated.xcconfig\"\n"
  },
  {
    "path": "flutter/example/ios/Podfile",
    "chars": 1348,
    "preview": "platform :ios, '13.0'\n\n# CocoaPods analytics sends network stats synchronously affecting flutter build latency.\nENV['COC"
  },
  {
    "path": "flutter/example/ios/Runner/AppDelegate.swift",
    "chars": 1205,
    "preview": "import UIKit\nimport Flutter\nimport CoinbaseWalletSDK\n\n@UIApplicationMain\n@objc class AppDelegate: FlutterAppDelegate {\n "
  },
  {
    "path": "flutter/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "chars": 2519,
    "preview": "{\n  \"images\" : [\n    {\n      \"size\" : \"20x20\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-20x20@2x.png\",\n   "
  },
  {
    "path": "flutter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json",
    "chars": 391,
    "preview": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"LaunchImage.png\",\n      \"scale\" : \"1x\"\n    },\n  "
  },
  {
    "path": "flutter/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md",
    "chars": 336,
    "preview": "# Launch Screen Assets\n\nYou can customize the launch screen with your own desired assets by replacing the image files in"
  },
  {
    "path": "flutter/example/ios/Runner/Base.lproj/LaunchScreen.storyboard",
    "chars": 2377,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard"
  },
  {
    "path": "flutter/example/ios/Runner/Base.lproj/Main.storyboard",
    "chars": 1605,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard"
  },
  {
    "path": "flutter/example/ios/Runner/Info.plist",
    "chars": 2122,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
  },
  {
    "path": "flutter/example/ios/Runner/Runner-Bridging-Header.h",
    "chars": 38,
    "preview": "#import \"GeneratedPluginRegistrant.h\"\n"
  },
  {
    "path": "flutter/example/ios/Runner.xcodeproj/project.pbxproj",
    "chars": 22428,
    "preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 51;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
  },
  {
    "path": "flutter/example/lib/main.dart",
    "chars": 4044,
    "preview": "import 'dart:async';\n\nimport 'package:coinbase_wallet_sdk/coinbase_wallet_sdk.dart';\nimport 'package:coinbase_wallet_sdk"
  },
  {
    "path": "flutter/example/pubspec.yaml",
    "chars": 3320,
    "preview": "name: coinbase_wallet_sdk_example\ndescription: Demonstrates how to use the coinbase_wallet_sdk plugin.\n\n# The following "
  },
  {
    "path": "flutter/example/test/widget_test.dart",
    "chars": 932,
    "preview": "// This is a basic Flutter widget test.\n//\n// To perform an interaction with a widget in your test, use the WidgetTester"
  },
  {
    "path": "flutter/ios/.gitignore",
    "chars": 418,
    "preview": ".idea/\n.vagrant/\n.sconsign.dblite\n.svn/\n\n.DS_Store\n*.swp\nprofile\n\nDerivedData/\nbuild/\nGeneratedPluginRegistrant.h\nGenera"
  },
  {
    "path": "flutter/ios/Assets/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "flutter/ios/Classes/CoinbaseWalletSdkFlutterPlugin.h",
    "chars": 102,
    "preview": "#import <Flutter/Flutter.h>\n\n@interface CoinbaseWalletSdkFlutterPlugin : NSObject<FlutterPlugin>\n@end\n"
  },
  {
    "path": "flutter/ios/Classes/CoinbaseWalletSdkFlutterPlugin.m",
    "chars": 656,
    "preview": "#import \"CoinbaseWalletSdkFlutterPlugin.h\"\n#if __has_include(<coinbase_wallet_sdk/coinbase_wallet_sdk-Swift.h>)\n#import "
  },
  {
    "path": "flutter/ios/Classes/SwiftCoinbaseWalletSdkFlutterPlugin.swift",
    "chars": 5899,
    "preview": "import Flutter\nimport UIKit\nimport CoinbaseWalletSDK\n\npublic class SwiftCoinbaseWalletSdkFlutterPlugin: NSObject, Flutte"
  },
  {
    "path": "flutter/ios/coinbase_wallet_sdk.podspec",
    "chars": 952,
    "preview": "#\n# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.\n# Run `pod lib lint coinbase_wall"
  },
  {
    "path": "flutter/lib/account.dart",
    "chars": 558,
    "preview": "class Account {\n  final String chain;\n  final int networkId;\n  final String address;\n\n  const Account({\n    required thi"
  },
  {
    "path": "flutter/lib/action.dart",
    "chars": 628,
    "preview": "import 'dart:convert';\n\nclass Action {\n  final String method;\n  final String paramsJson;\n  final bool optional;\n\n  const"
  },
  {
    "path": "flutter/lib/coinbase_wallet_sdk.dart",
    "chars": 3610,
    "preview": "import 'dart:convert';\n\nimport 'package:coinbase_wallet_sdk/account.dart';\nimport 'package:coinbase_wallet_sdk/action.da"
  },
  {
    "path": "flutter/lib/coinbase_wallet_sdk_method_channel.dart",
    "chars": 775,
    "preview": "import 'dart:convert';\n\nimport 'package:flutter/foundation.dart';\nimport 'package:flutter/services.dart';\n\nimport 'coinb"
  },
  {
    "path": "flutter/lib/coinbase_wallet_sdk_platform_interface.dart",
    "chars": 1421,
    "preview": "import 'package:plugin_platform_interface/plugin_platform_interface.dart';\n\nimport 'coinbase_wallet_sdk_method_channel.d"
  },
  {
    "path": "flutter/lib/configuration.dart",
    "chars": 679,
    "preview": "class Configuration {\n  final IOSConfiguration? ios;\n  final AndroidConfiguration? android;\n\n  Configuration({\n    requi"
  },
  {
    "path": "flutter/lib/eth_web3_rpc.dart",
    "chars": 3543,
    "preview": "import 'dart:convert';\n\nimport 'package:coinbase_wallet_sdk/action.dart';\n\nclass RequestAccounts extends Action {\n  cons"
  },
  {
    "path": "flutter/lib/request.dart",
    "chars": 426,
    "preview": "import 'package:coinbase_wallet_sdk/account.dart';\nimport 'package:coinbase_wallet_sdk/action.dart';\n\nclass Request {\n  "
  },
  {
    "path": "flutter/lib/return_value.dart",
    "chars": 713,
    "preview": "class ReturnValue {\n  final String? value;\n  final ReturnValueError? error;\n\n  const ReturnValue({\n    this.value,\n    t"
  },
  {
    "path": "flutter/pubspec.yaml",
    "chars": 743,
    "preview": "name: coinbase_wallet_sdk\ndescription: Fluter implementation of Coinbase Wallet SDK.\nversion: 1.0.4\nhomepage: https://wa"
  },
  {
    "path": "flutter/test/coinbase_wallet_sdk_method_channel_test.dart",
    "chars": 690,
    "preview": "import 'package:coinbase_wallet_sdk/coinbase_wallet_sdk_method_channel.dart';\nimport 'package:flutter/services.dart';\nim"
  },
  {
    "path": "flutter/test/coinbase_wallet_sdk_test.dart",
    "chars": 1462,
    "preview": "import 'package:coinbase_wallet_sdk/coinbase_wallet_sdk_method_channel.dart';\nimport 'package:coinbase_wallet_sdk/coinba"
  },
  {
    "path": "ios/CoinbaseWalletSDK/CoinbaseWalletSDK.swift",
    "chars": 7651,
    "preview": "//\n//  CoinbaseWalletSDK.swift\n//  WalletSegue\n//\n//  Created by Jungho Bang on 5/20/22.\n//\n\nimport Foundation\nimport Cr"
  },
  {
    "path": "ios/CoinbaseWalletSDK/Error.swift",
    "chars": 369,
    "preview": "//\n//  Error.swift\n//  WalletSegue\n//\n//  Created by Jungho Bang on 6/16/22.\n//\n\nimport Foundation\n\nextension CoinbaseWa"
  },
  {
    "path": "ios/CoinbaseWalletSDK/Host/CoinbaseWalletHostSDK.swift",
    "chars": 911,
    "preview": "//\n//  CoinbaseWalletHostSDK.swift\n//  CoinbaseWalletSDK\n//\n//  Created by Jungho Bang on 9/2/22.\n//\n\nimport Foundation\n"
  },
  {
    "path": "ios/CoinbaseWalletSDK/Host/ResponseMessage+init.swift",
    "chars": 522,
    "preview": "//\n//  ResponseMessage+init.swift\n//  CoinbaseWalletSDK\n//\n//  Created by Jungho Bang on 9/2/22.\n//\n\nimport Foundation\n\n"
  },
  {
    "path": "ios/CoinbaseWalletSDK/Key/Key+RawRepresentable.swift",
    "chars": 819,
    "preview": "//\n//  Key+RawRepresentable.swift\n//  WalletSegue\n//\n//  Created by Jungho Bang on 6/13/22.\n//\n\nimport Foundation\n\npubli"
  },
  {
    "path": "ios/CoinbaseWalletSDK/Key/KeyManager.swift",
    "chars": 1899,
    "preview": "//\n//  KeyManager.swift\n//  WalletSegue\n//\n//  Created by Jungho Bang on 6/9/22.\n//\n\nimport Foundation\nimport CryptoKit\n"
  },
  {
    "path": "ios/CoinbaseWalletSDK/Key/KeyStorage.swift",
    "chars": 2760,
    "preview": "//\n//  KeyStorage.swift\n//  WalletSegue\n//\n//  Created by Jungho Bang on 6/17/22.\n//\n\nimport Foundation\n\nfinal class Key"
  },
  {
    "path": "ios/CoinbaseWalletSDK/Key/KeyStorageItem.swift",
    "chars": 581,
    "preview": "//\n//  KeyStorageItem.swift\n//  WalletSegue\n//\n//  Created by Jungho Bang on 6/17/22.\n//\n\nimport Foundation\n\nstruct KeyS"
  },
  {
    "path": "ios/CoinbaseWalletSDK/Message/Cipher.swift",
    "chars": 1260,
    "preview": "//\n//  Cryptography.swift\n//  WalletSegue\n//\n//  Created by Jungho Bang on 6/17/22.\n//\n\nimport Foundation\nimport CryptoK"
  },
  {
    "path": "ios/CoinbaseWalletSDK/Message/EncryptedMessage.swift",
    "chars": 974,
    "preview": "//\n//  EncryptedMessage.swift\n//  WalletSegue\n//\n//  Created by Jungho Bang on 6/23/22.\n//\n\nimport Foundation\nimport Cry"
  },
  {
    "path": "ios/CoinbaseWalletSDK/Message/JSONString.swift",
    "chars": 1551,
    "preview": "//\n//  JSONString.swift\n//  CoinbaseWalletSDK\n//\n//  Created by Jungho Bang on 8/19/22.\n//\n\nimport Foundation\n\npublic st"
  },
  {
    "path": "ios/CoinbaseWalletSDK/Message/Message.swift",
    "chars": 1408,
    "preview": "//\n//  Message.swift\n//  WalletSegue\n//\n//  Created by Jungho Bang on 6/13/22.\n//\n\nimport Foundation\nimport CryptoKit\n\np"
  },
  {
    "path": "ios/CoinbaseWalletSDK/Message/MessageConverter.swift",
    "chars": 1967,
    "preview": "//\n//  MessageRenderer.swift\n//  WalletSegue\n//\n//  Created by Jungho Bang on 6/14/22.\n//\n\nimport Foundation\nimport Cryp"
  },
  {
    "path": "ios/CoinbaseWalletSDK/Message/Request/Account.swift",
    "chars": 399,
    "preview": "//\n//  Account.swift\n//  WalletSegue\n//\n//  Created by Jungho Bang on 6/13/22.\n//\n\nimport Foundation\n\npublic struct Acco"
  },
  {
    "path": "ios/CoinbaseWalletSDK/Message/Request/Action.swift",
    "chars": 738,
    "preview": "//\n//  Action.swift\n//  WalletSegueHost\n//\n//  Created by Jungho Bang on 6/21/22.\n//\n\nimport Foundation\n\npublic struct A"
  },
  {
    "path": "ios/CoinbaseWalletSDK/Message/Request/EncryptedRequestContent.swift",
    "chars": 1570,
    "preview": "//\n//  EncryptedRequestContent.swift\n//  WalletSegue\n//\n//  Created by Jungho Bang on 6/23/22.\n//\n\nimport Foundation\nimp"
  }
]

// ... and 73 more files (download for full content)

About this extraction

This page contains the full source code of the coinbase/wallet-mobile-sdk GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 273 files (467.0 KB), approximately 129.7k tokens, and a symbol index with 151 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!