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
[](https://cocoapods.org/pods/CoinbaseWalletSDK)
[](https://mavenlibs.com/maven/dependency/com.coinbase/coinbase-wallet-sdk)
[](https://www.npmjs.com/package/@coinbase/wallet-mobile-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
[](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.

> 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"
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
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[](https://cocoapods.org"
},
{
"path": "android/README.md",
"chars": 5099,
"preview": "# Coinbase Wallet Mobile SDK\n\n[ 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\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.