├── .gitattributes ├── .github └── workflows │ └── build.yml ├── .gitignore ├── .prettierrc ├── .releaserc.json ├── .vscode └── settings.json ├── README.md ├── android ├── app │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── com │ │ │ └── trust │ │ │ └── web3 │ │ │ └── demo │ │ │ ├── App.kt │ │ │ ├── DAppMethod.kt │ │ │ ├── MainActivity.kt │ │ │ ├── Numeric.kt │ │ │ ├── WebAppInterface.kt │ │ │ └── WebViewExtension.kt │ │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── themes.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── lib │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── res │ │ └── raw │ │ └── trust_min.js └── settings.gradle ├── bun.lockb ├── bunfig.toml ├── docs ├── BUILD.md ├── NEW.md └── USAGE.md ├── eslint.config.js ├── jitpack.yml ├── package.json ├── packages ├── android-web3-provider │ ├── package.json │ ├── rollup.config.js │ ├── rollup.config2.js │ ├── settings.gradle │ ├── src │ │ └── index.ts │ └── tsconfig.json ├── aptos │ ├── AptosProvider.ts │ ├── README.md │ ├── exceptions │ │ └── RPCError.ts │ ├── index.ts │ ├── package.json │ ├── rollup.config.js │ ├── tests │ │ └── AptosProvider.spec.ts │ ├── tsconfig.json │ └── types │ │ └── AptosProvider.ts ├── core │ ├── Provider.ts │ ├── README.md │ ├── adapter │ │ ├── Adapter.ts │ │ ├── CallbackAdapter.ts │ │ ├── PromiseAdapter.ts │ │ └── tests │ │ │ ├── CallbackBridge.spec.ts │ │ │ └── PromiseBridge.spec.ts │ ├── exceptions │ │ └── RPCError.ts │ ├── index.ts │ ├── package.json │ ├── rollup.config.js │ └── tsconfig.json ├── cosmos │ ├── CosmosProvider.ts │ ├── MobileAdapter.ts │ ├── README.md │ ├── index.ts │ ├── package.json │ ├── rollup.config.js │ ├── tests │ │ └── CosmosProvider.spec.ts │ ├── tsconfig.json │ └── types │ │ └── CosmosProvider.ts ├── ethereum │ ├── EthereumProvider.ts │ ├── MobileAdapter.ts │ ├── README.md │ ├── RPCServer.ts │ ├── exceptions │ │ └── RPCError.ts │ ├── index.ts │ ├── package.json │ ├── rollup.config.js │ ├── tests │ │ ├── EthereumProvider.spec.ts │ │ └── mocks │ │ │ └── Wallet.ts │ ├── tsconfig.json │ ├── types.ts │ └── types │ │ ├── EthereumProvider.ts │ │ └── RPC.ts ├── ios-web3-provider │ ├── .swiftpm │ │ └── xcode │ │ │ └── xcuserdata │ │ │ └── fivezone.xcuserdatad │ │ │ └── xcschemes │ │ │ └── xcschememanagement.plist │ ├── Package.swift │ ├── README.md │ ├── TrustWeb3Provider.podspec │ ├── global.d.ts │ ├── index.ts │ ├── ios │ │ ├── Packages │ │ │ └── WalletCore │ │ │ │ ├── .swiftpm │ │ │ │ └── xcode │ │ │ │ │ └── xcuserdata │ │ │ │ │ └── fivezone.xcuserdatad │ │ │ │ │ └── xcschemes │ │ │ │ │ └── xcschememanagement.plist │ │ │ │ └── Package.swift │ │ ├── PodsTest │ │ │ ├── Podfile │ │ │ ├── Podfile.lock │ │ │ ├── PodsTest.xcodeproj │ │ │ │ ├── project.pbxproj │ │ │ │ ├── project.xcworkspace │ │ │ │ │ └── contents.xcworkspacedata │ │ │ │ └── xcshareddata │ │ │ │ │ └── xcschemes │ │ │ │ │ └── PodsTest.xcscheme │ │ │ ├── PodsTest.xcworkspace │ │ │ │ └── contents.xcworkspacedata │ │ │ ├── PodsTest │ │ │ │ ├── Assets.xcassets │ │ │ │ │ ├── AccentColor.colorset │ │ │ │ │ │ └── Contents.json │ │ │ │ │ ├── AppIcon.appiconset │ │ │ │ │ │ └── Contents.json │ │ │ │ │ └── Contents.json │ │ │ │ ├── ContentView.swift │ │ │ │ ├── PodsTestApp.swift │ │ │ │ └── Preview Content │ │ │ │ │ └── Preview Assets.xcassets │ │ │ │ │ └── Contents.json │ │ │ └── PodsTestTests │ │ │ │ └── PodsTestTests.swift │ │ ├── TrustWeb3Provider.xcodeproj │ │ │ ├── project.pbxproj │ │ │ ├── project.xcworkspace │ │ │ │ ├── contents.xcworkspacedata │ │ │ │ ├── xcshareddata │ │ │ │ │ └── IDEWorkspaceChecks.plist │ │ │ │ └── xcuserdata │ │ │ │ │ └── fivezone.xcuserdatad │ │ │ │ │ └── UserInterfaceState.xcuserstate │ │ │ ├── xcshareddata │ │ │ │ └── xcschemes │ │ │ │ │ └── TrustWeb3Provider-Example.xcscheme │ │ │ └── xcuserdata │ │ │ │ └── fivezone.xcuserdatad │ │ │ │ └── xcschemes │ │ │ │ └── xcschememanagement.plist │ │ └── TrustWeb3Provider │ │ │ ├── AppDelegate.swift │ │ │ ├── Base.lproj │ │ │ ├── LaunchScreen.xib │ │ │ └── Main.storyboard │ │ │ ├── DAppMethod.swift │ │ │ ├── DAppWebViewController.swift │ │ │ ├── Images.xcassets │ │ │ └── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ ├── Info.plist │ │ │ └── WKScriptMessage+JSON.swift │ ├── package.json │ ├── rollup.config.js │ ├── swift │ │ ├── ProviderNetwork.swift │ │ ├── TrustWeb3Provider.swift │ │ ├── WKWebView+Extension.swift │ │ └── trust-min.js │ └── tsconfig.json ├── solana │ ├── MobileAdapter.ts │ ├── README.md │ ├── SolanaProvider.ts │ ├── adapter │ │ ├── account.ts │ │ ├── icon.ts │ │ ├── initialize.ts │ │ ├── register.ts │ │ ├── solana.ts │ │ ├── wallet.ts │ │ └── window.ts │ ├── exceptions │ │ └── RPCError.ts │ ├── index.ts │ ├── package.json │ ├── rollup.config.js │ ├── tests │ │ ├── SolanaProvider.spec.ts │ │ └── mocks │ │ │ └── window.ts │ ├── tsconfig.json │ ├── types │ │ └── SolanaProvider.ts │ └── util.ts ├── ton │ ├── MobileAdapter.ts │ ├── README.md │ ├── TonBridge.ts │ ├── TonProvider.ts │ ├── exceptions │ │ ├── RPCError.ts │ │ └── TonConnectError.ts │ ├── index.ts │ ├── package.json │ ├── rollup.config.js │ ├── tests │ │ └── TonProvider.spec.ts │ ├── tsconfig.json │ └── types │ │ ├── TonBridge.ts │ │ └── TonProvider.ts └── tron │ ├── TronProvider.ts │ ├── exceptions │ └── RPCError.ts │ ├── index.ts │ ├── package.json │ ├── rollup.config.js │ ├── tests │ └── TronProvider.spec.ts │ ├── tsconfig.json │ └── types │ └── TronProvider.ts ├── rollup.config.js ├── scripts ├── build.ts ├── generate.ts ├── link.ts ├── packages.ts ├── publish.ts └── rename.ts ├── templates ├── exceptions │ └── RPCError.ts ├── index.ts ├── package.json ├── rollup.config.js ├── tests │ └── {{ name }}Provider.spec.ts ├── tsconfig.json ├── types │ └── {{ name}}Provider.ts └── {{ name }}Provider.ts └── tsconfig.json /.gitattributes: -------------------------------------------------------------------------------- 1 | trust-min.js filter=lfs diff=lfs merge=lfs -text 2 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build Packages 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | env: 7 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 8 | 9 | jobs: 10 | github-release: 11 | name: Github Release 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | with: 16 | ref: main 17 | - uses: oven-sh/setup-bun@v1 18 | - uses: actions/setup-node@v4 19 | with: 20 | node-version: '20.x' 21 | registry-url: 'https://npm.pkg.github.com' 22 | scope: '@trustwallet' 23 | - name: Generate version 24 | id: get-next-version 25 | run: | 26 | bun install --frozen-lockfile 27 | bun run build:version 28 | env: 29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 30 | - name: Set output 31 | id: vars 32 | run: echo "tag=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT 33 | - name: build packages 34 | run: | 35 | bun install 36 | bun run build:packages 37 | bun run test 38 | bun run rename ${{ steps.get-next-version.outputs.new-release-version }} 39 | bun run publish 40 | env: 41 | NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 42 | - name: Create Release 43 | id: create_release 44 | uses: actions/create-release@latest 45 | env: 46 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 47 | with: 48 | tag_name: v${{ steps.get-next-version.outputs.new-release-version }} 49 | release_name: 50 | Release ${{ steps.get-next-version.outputs.new-release-version }} 51 | body: | 52 | New Release 🚀 53 | draft: false 54 | prerelease: false 55 | permissions: 56 | actions: write 57 | contents: write 58 | deployments: write 59 | packages: write 60 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore 2 | 3 | # Logs 4 | 5 | logs 6 | _.log 7 | npm-debug.log_ 8 | yarn-debug.log* 9 | yarn-error.log* 10 | lerna-debug.log* 11 | .pnpm-debug.log* 12 | 13 | # Caches 14 | 15 | .cache 16 | 17 | # Diagnostic reports (https://nodejs.org/api/report.html) 18 | 19 | report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json 20 | 21 | # Runtime data 22 | 23 | pids 24 | _.pid 25 | _.seed 26 | *.pid.lock 27 | 28 | # Directory for instrumented libs generated by jscoverage/JSCover 29 | 30 | lib-cov 31 | 32 | # Coverage directory used by tools like istanbul 33 | 34 | coverage 35 | *.lcov 36 | 37 | # nyc test coverage 38 | 39 | .nyc_output 40 | 41 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 42 | 43 | .grunt 44 | 45 | # Bower dependency directory (https://bower.io/) 46 | 47 | bower_components 48 | 49 | # node-waf configuration 50 | 51 | .lock-wscript 52 | 53 | # Compiled binary addons (https://nodejs.org/api/addons.html) 54 | 55 | build/Release 56 | 57 | # Dependency directories 58 | 59 | node_modules/ 60 | jspm_packages/ 61 | 62 | # Snowpack dependency directory (https://snowpack.dev/) 63 | 64 | web_modules/ 65 | 66 | # TypeScript cache 67 | 68 | *.tsbuildinfo 69 | 70 | # Optional npm cache directory 71 | 72 | .npm 73 | 74 | # Optional eslint cache 75 | 76 | .eslintcache 77 | 78 | # Optional stylelint cache 79 | 80 | .stylelintcache 81 | 82 | # Microbundle cache 83 | 84 | .rpt2_cache/ 85 | .rts2_cache_cjs/ 86 | .rts2_cache_es/ 87 | .rts2_cache_umd/ 88 | 89 | # Optional REPL history 90 | 91 | .node_repl_history 92 | 93 | # Output of 'npm pack' 94 | 95 | *.tgz 96 | 97 | # Yarn Integrity file 98 | 99 | .yarn-integrity 100 | 101 | # dotenv environment variable files 102 | 103 | .env 104 | .env.development.local 105 | .env.test.local 106 | .env.production.local 107 | .env.local 108 | 109 | # parcel-bundler cache (https://parceljs.org/) 110 | 111 | .parcel-cache 112 | 113 | # Next.js build output 114 | 115 | .next 116 | out 117 | 118 | # Nuxt.js build / generate output 119 | 120 | .nuxt 121 | dist 122 | 123 | # Gatsby files 124 | 125 | # Comment in the public line in if your project uses Gatsby and not Next.js 126 | 127 | # https://nextjs.org/blog/next-9-1#public-directory-support 128 | 129 | # public 130 | 131 | # vuepress build output 132 | 133 | .vuepress/dist 134 | 135 | # vuepress v2.x temp and cache directory 136 | 137 | .temp 138 | 139 | # Docusaurus cache and generated files 140 | 141 | .docusaurus 142 | 143 | # Serverless directories 144 | 145 | .serverless/ 146 | 147 | # FuseBox cache 148 | 149 | .fusebox/ 150 | 151 | # DynamoDB Local files 152 | 153 | .dynamodb/ 154 | 155 | # TernJS port file 156 | 157 | .tern-port 158 | 159 | # Stores VSCode versions used for testing VSCode extensions 160 | 161 | .vscode-test 162 | 163 | # yarn v2 164 | 165 | .yarn/cache 166 | .yarn/unplugged 167 | .yarn/build-state.yml 168 | .yarn/install-state.gz 169 | .pnp.* 170 | 171 | # IntelliJ based IDEs 172 | .idea 173 | 174 | # Finder (MacOS) folder config 175 | .DS_Store 176 | android/build 177 | android/app/build/* 178 | android/lib/build/* 179 | android/.gradle 180 | local.properties -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "always", 3 | "printWidth": 80, 4 | "proseWrap": "always", 5 | "semi": true, 6 | "singleQuote": true, 7 | "trailingComma": "all", 8 | "tabWidth": 2, 9 | "useTabs": false, 10 | "bracketSpacing": true 11 | } 12 | -------------------------------------------------------------------------------- /.releaserc.json: -------------------------------------------------------------------------------- 1 | { 2 | "branches": [ 3 | "main", 4 | "hotfix/*", 5 | { "name": "release-v\\d+\\.\\d+\\.\\d+", "prerelease": true } 6 | ], 7 | "plugins": ["semantic-release-export-data"] 8 | } 9 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "Bounceable", 4 | "outdir", 5 | "Parens", 6 | "pmqjw", 7 | "prelink", 8 | "subpackages", 9 | "uuidv" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Trust Web3 Provider 2 | 3 | ``` 4 | ___ ___ ___ 5 | ___ / /\ / /\ / /\ ___ 6 | /__/\ / /::\ / /:/ / /::\ /__/\ 7 | \ \:\ / /:/\:\ / /:/ /__/:/\:\ \ \:\ 8 | \__\:\ / /::\ \:\ / /:/ _\_ \:\ \:\ \__\:\ 9 | / /::\ /__/:/\:\_\:\ /__/:/ /\ /__/\ \:\ \:\ / /::\ 10 | / /:/\:\ \__\/~|::\/:/ \ \:\ /:/ \ \:\ \:\_\/ / /:/\:\ 11 | / /:/__\/ | |:|::/ \ \:\ /:/ \ \:\_\:\ / /:/__\/ 12 | /__/:/ | |:|\/ \ \:\/:/ \ \:\/:/ /__/:/ 13 | \__\/ |__|:|~ \ \::/ \ \::/ \__\/ 14 | \__\| \__\/ \__\/ 15 | 16 | ``` 17 | 18 | A modular TypeScript library designed to offer Web3 interfaces, enabling your 19 | wallet to connect with decentralized applications. 20 | 21 | ``` 22 | +----------------+ +------------------+ +---------------+ 23 | | | | | | | 24 | | dApps | <-----> | web3 provider | <-----> | your wallet | 25 | | | | | | | 26 | +----------------+ +------------------+ +---------------+ 27 | 28 | ``` 29 | 30 | ## Supported chains 31 | 32 | - Cosmos [Docs](/packages/cosmos/README.md) 33 | - Solana - _Wallet Standard fully compatible_ [Docs](/packages/solana/README.md) 34 | - Ethereum _EIP-1193_ [Docs](/packages/ethereum/README.md) 35 | 36 | # Useful links 37 | 38 | [Using the library](/docs/USAGE.md) 39 | 40 | [Contributing](/docs/BUILD.md) 41 | 42 | [Adding a new chain](/docs/NEW.md) 43 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'com.android.application' 3 | id 'kotlin-android' 4 | } 5 | 6 | android { 7 | compileSdkVersion 30 8 | buildToolsVersion "30.0.3" 9 | 10 | defaultConfig { 11 | applicationId "com.trust.web3.demo" 12 | minSdkVersion 23 13 | targetSdkVersion 30 14 | versionCode 1 15 | versionName "1.0" 16 | 17 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 18 | } 19 | 20 | buildTypes { 21 | release { 22 | minifyEnabled false 23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 24 | } 25 | } 26 | compileOptions { 27 | sourceCompatibility JavaVersion.VERSION_1_8 28 | targetCompatibility JavaVersion.VERSION_1_8 29 | } 30 | kotlinOptions { 31 | jvmTarget = '1.8' 32 | } 33 | } 34 | 35 | dependencies { 36 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" 37 | implementation 'androidx.core:core-ktx:1.2.0' 38 | implementation 'androidx.appcompat:appcompat:1.2.0' 39 | implementation 'com.google.android.material:material:1.1.0' 40 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 41 | 42 | implementation "com.louiscad.splitties:splitties-alertdialog-material:3.0.0" 43 | implementation "com.trustwallet:wallet-core:2.9.7" 44 | 45 | implementation 'com.github.trustwallet:trust-web3-provider:2.0.0-alpha' 46 | testImplementation 'junit:junit:4.+' 47 | androidTestImplementation 'androidx.test.ext:junit:1.1.1' 48 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' 49 | } -------------------------------------------------------------------------------- /android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/trust/web3/demo/App.kt: -------------------------------------------------------------------------------- 1 | package com.trust.web3.demo 2 | 3 | import android.app.Application 4 | 5 | class App: Application() { 6 | init { 7 | System.loadLibrary("TrustWalletCore") 8 | } 9 | } -------------------------------------------------------------------------------- /android/app/src/main/java/com/trust/web3/demo/DAppMethod.kt: -------------------------------------------------------------------------------- 1 | package com.trust.web3.demo 2 | 3 | enum class DAppMethod { 4 | SIGNTRANSACTION, 5 | SIGNPERSONALMESSAGE, 6 | SIGNMESSAGE, 7 | SIGNTYPEDMESSAGE, 8 | ECRECOVER, 9 | REQUESTACCOUNTS, 10 | WATCHASSET, 11 | ADDETHEREUMCHAIN, 12 | UNKNOWN; 13 | 14 | companion object { 15 | fun fromValue(value: String): DAppMethod { 16 | return when (value) { 17 | "signTransaction" -> SIGNTRANSACTION 18 | "signPersonalMessage" -> SIGNPERSONALMESSAGE 19 | "signMessage" -> SIGNMESSAGE 20 | "signTypedMessage" -> SIGNTYPEDMESSAGE 21 | "ecRecover" -> ECRECOVER 22 | "requestAccounts" -> REQUESTACCOUNTS 23 | "watchAsset" -> WATCHASSET 24 | "addEthereumChain" -> ADDETHEREUMCHAIN 25 | else -> UNKNOWN 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/trust/web3/demo/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.trust.web3.demo 2 | 3 | import android.graphics.Bitmap 4 | import android.net.http.SslError 5 | import android.os.Bundle 6 | import android.webkit.SslErrorHandler 7 | import android.webkit.WebView 8 | import android.webkit.WebViewClient 9 | import androidx.appcompat.app.AppCompatActivity 10 | 11 | class MainActivity : AppCompatActivity() { 12 | companion object { 13 | private const val DAPP_URL = "https://www.magiceden.io/me" 14 | private const val CHAIN_ID = 56 15 | private const val RPC_URL = "https://bsc-dataseed2.binance.org" 16 | } 17 | 18 | override fun onCreate(savedInstanceState: Bundle?) { 19 | super.onCreate(savedInstanceState) 20 | 21 | setContentView(R.layout.activity_main) 22 | 23 | val provderJs = loadProviderJs() 24 | val initJs = loadInitJs( 25 | CHAIN_ID, 26 | RPC_URL 27 | ) 28 | WebView.setWebContentsDebuggingEnabled(true) 29 | val webview: WebView = findViewById(R.id.webview) 30 | webview.settings.run { 31 | javaScriptEnabled = true 32 | domStorageEnabled = true 33 | } 34 | WebAppInterface(this, webview, DAPP_URL).run { 35 | webview.addJavascriptInterface(this, "_tw_") 36 | 37 | val webViewClient = object : WebViewClient() { 38 | override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) { 39 | super.onPageStarted(view, url, favicon) 40 | view?.evaluateJavascript(provderJs, null) 41 | view?.evaluateJavascript(initJs, null) 42 | } 43 | 44 | override fun onReceivedSslError( 45 | view: WebView?, 46 | handler: SslErrorHandler?, 47 | error: SslError? 48 | ) { 49 | // Ignore SSL certificate errors 50 | handler?.proceed() 51 | println(error.toString()) 52 | } 53 | } 54 | webview.webViewClient = webViewClient 55 | webview.loadUrl(DAPP_URL) 56 | } 57 | } 58 | 59 | private fun loadProviderJs(): String { 60 | return resources.openRawResource(R.raw.trust_min).bufferedReader().use { it.readText() } 61 | } 62 | 63 | private fun loadInitJs(chainId: Int, rpcUrl: String): String { 64 | val source = """ 65 | (function() { 66 | var config = { 67 | ethereum: { 68 | chainId: $chainId, 69 | rpcUrl: "$rpcUrl" 70 | }, 71 | solana: { 72 | cluster: "mainnet-beta", 73 | }, 74 | isDebug: true 75 | }; 76 | trustwallet.ethereum = new trustwallet.Provider(config); 77 | trustwallet.solana = new trustwallet.SolanaProvider(config); 78 | trustwallet.postMessage = (json) => { 79 | window._tw_.postMessage(JSON.stringify(json)); 80 | } 81 | window.ethereum = trustwallet.ethereum; 82 | })(); 83 | """ 84 | return source 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/trust/web3/demo/Numeric.kt: -------------------------------------------------------------------------------- 1 | package com.trust.web3.demo 2 | 3 | import kotlin.experimental.and 4 | 5 | object Numeric { 6 | fun containsHexPrefix(input: String): Boolean { 7 | return input.length > 1 && input[0] == '0' && input[1] == 'x' 8 | } 9 | 10 | fun cleanHexPrefix(input: String): String { 11 | return if (containsHexPrefix(input)) { 12 | input.substring(2) 13 | } else { 14 | input 15 | } 16 | } 17 | 18 | fun hexStringToByteArray(input: String): ByteArray { 19 | val cleanInput = cleanHexPrefix(input) 20 | 21 | val len = cleanInput.length 22 | 23 | if (len == 0) { 24 | return byteArrayOf() 25 | } 26 | 27 | val data: ByteArray 28 | val startIdx: Int 29 | if (len % 2 != 0) { 30 | data = ByteArray(len / 2 + 1) 31 | data[0] = Character.digit(cleanInput[0], 16).toByte() 32 | startIdx = 1 33 | } else { 34 | data = ByteArray(len / 2) 35 | startIdx = 0 36 | } 37 | 38 | var i = startIdx 39 | while (i < len) { 40 | data[(i + 1) / 2] = 41 | ((Character.digit(cleanInput[i], 16) shl 4) + Character.digit( 42 | cleanInput[i + 1], 43 | 16 44 | )).toByte() 45 | i += 2 46 | } 47 | return data 48 | } 49 | 50 | fun toHexString(input: ByteArray?, offset: Int, length: Int, withPrefix: Boolean): String { 51 | val stringBuilder = StringBuilder() 52 | if (withPrefix) { 53 | stringBuilder.append("0x") 54 | } 55 | for (i in offset until offset + length) { 56 | stringBuilder.append(String.format("%02x", input!![i] and 0xFF.toByte())) 57 | } 58 | 59 | return stringBuilder.toString() 60 | } 61 | 62 | fun toHexString(input: ByteArray?): String { 63 | return toHexString(input, 0, input!!.size, true) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/trust/web3/demo/WebAppInterface.kt: -------------------------------------------------------------------------------- 1 | package com.trust.web3.demo 2 | 3 | import android.content.Context 4 | import android.webkit.JavascriptInterface 5 | import android.webkit.WebView 6 | import org.json.JSONObject 7 | import splitties.alertdialog.appcompat.cancelButton 8 | import splitties.alertdialog.appcompat.message 9 | import splitties.alertdialog.appcompat.okButton 10 | import splitties.alertdialog.appcompat.title 11 | import splitties.alertdialog.material.materialAlertDialog 12 | import wallet.core.jni.CoinType 13 | import wallet.core.jni.Curve 14 | import wallet.core.jni.PrivateKey 15 | 16 | class WebAppInterface( 17 | private val context: Context, 18 | private val webView: WebView, 19 | private val dappUrl: String 20 | ) { 21 | private val privateKey = 22 | PrivateKey("0x4646464646464646464646464646464646464646464646464646464646464646".toHexByteArray()) 23 | private val addr = CoinType.ETHEREUM.deriveAddress(privateKey).toLowerCase() 24 | private val pubKey = CoinType.SOLANA.deriveAddress(privateKey) 25 | 26 | @JavascriptInterface 27 | fun postMessage(json: String) { 28 | val obj = JSONObject(json) 29 | println(obj) 30 | val id = obj.getLong("id") 31 | val method = DAppMethod.fromValue(obj.getString("name")) 32 | val network = obj.getString("network") 33 | when (method) { 34 | DAppMethod.REQUESTACCOUNTS -> { 35 | context.materialAlertDialog { 36 | title = "Request Accounts" 37 | message = "${dappUrl} requests your address" 38 | okButton { 39 | val address = if (network == "solana") pubKey else addr 40 | val setAddress = "window.$network.setAddress(\"$address\");" 41 | val callback = "window.$network.sendResponse($id, [\"$address\"])" 42 | webView.post { 43 | webView.evaluateJavascript(setAddress) { 44 | // ignore 45 | } 46 | webView.evaluateJavascript(callback) { value -> 47 | println(value) 48 | } 49 | } 50 | } 51 | cancelButton() 52 | }.show() 53 | } 54 | DAppMethod.SIGNMESSAGE -> { 55 | val data = extractMessage(obj) 56 | if (network == "ethereum") 57 | handleSignMessage(id, data, addPrefix = false) 58 | else 59 | handleSignSolanaMessage(id, data) 60 | } 61 | DAppMethod.SIGNPERSONALMESSAGE -> { 62 | val data = extractMessage(obj) 63 | handleSignMessage(id, data, addPrefix = true) 64 | } 65 | DAppMethod.SIGNTYPEDMESSAGE -> { 66 | val data = extractMessage(obj) 67 | val raw = extractRaw(obj) 68 | handleSignTypedMessage(id, data, raw) 69 | } 70 | else -> { 71 | context.materialAlertDialog { 72 | title = "Error" 73 | message = "$method not implemented" 74 | okButton { 75 | } 76 | }.show() 77 | } 78 | } 79 | } 80 | 81 | private fun extractMessage(json: JSONObject): ByteArray { 82 | val param = json.getJSONObject("object") 83 | val data = param.getString("data") 84 | return Numeric.hexStringToByteArray(data) 85 | } 86 | 87 | private fun extractRaw(json: JSONObject): String { 88 | val param = json.getJSONObject("object") 89 | return param.getString("raw") 90 | } 91 | 92 | private fun handleSignMessage(id: Long, data: ByteArray, addPrefix: Boolean) { 93 | context.materialAlertDialog { 94 | title = "Sign Ethereum Message" 95 | message = if (addPrefix) String(data, Charsets.UTF_8) else Numeric.toHexString(data) 96 | cancelButton { 97 | webView.sendError("ethereum","Cancel", id) 98 | } 99 | okButton { 100 | webView.sendResult("ethereum", signEthereumMessage(data, addPrefix), id) 101 | } 102 | }.show() 103 | } 104 | 105 | private fun handleSignSolanaMessage(id: Long, data: ByteArray) { 106 | context.materialAlertDialog { 107 | title = "Sign Solana Message" 108 | message = String(data, Charsets.UTF_8) ?: Numeric.toHexString(data) 109 | cancelButton { 110 | webView.sendError("solana", "Cancel", id) 111 | } 112 | okButton { 113 | webView.sendResult("solana", signSolanaMessage(data), id) 114 | } 115 | }.show() 116 | } 117 | 118 | private fun handleSignTypedMessage(id: Long, data: ByteArray, raw: String) { 119 | context.materialAlertDialog { 120 | title = "Sign Typed Message" 121 | message = raw 122 | cancelButton { 123 | webView.sendError("ethereum","Cancel", id) 124 | } 125 | okButton { 126 | webView.sendResult("ethereum", signEthereumMessage(data, false), id) 127 | } 128 | }.show() 129 | } 130 | 131 | private fun signEthereumMessage(message: ByteArray, addPrefix: Boolean): String { 132 | var data = message 133 | if (addPrefix) { 134 | val messagePrefix = "\u0019Ethereum Signed Message:\n" 135 | val prefix = (messagePrefix + message.size).toByteArray() 136 | val result = ByteArray(prefix.size + message.size) 137 | System.arraycopy(prefix, 0, result, 0, prefix.size) 138 | System.arraycopy(message, 0, result, prefix.size, message.size) 139 | data = wallet.core.jni.Hash.keccak256(result) 140 | } 141 | 142 | val signatureData = privateKey.sign(data, Curve.SECP256K1) 143 | .apply { 144 | (this[this.size - 1]) = (this[this.size - 1] + 27).toByte() 145 | } 146 | return Numeric.toHexString(signatureData) 147 | } 148 | 149 | private fun signSolanaMessage(message: ByteArray): String { 150 | val signature = privateKey.sign(message, Curve.ED25519) 151 | return Numeric.toHexString(signature) 152 | 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/trust/web3/demo/WebViewExtension.kt: -------------------------------------------------------------------------------- 1 | package com.trust.web3.demo 2 | 3 | import android.webkit.WebView 4 | 5 | fun WebView.sendError(network: String, message: String, methodId: Long) { 6 | val script = "window.$network.sendError($methodId, \"$message\")" 7 | this.post { 8 | this.evaluateJavascript(script) {} 9 | } 10 | } 11 | 12 | fun WebView.sendResult(network: String, message: String, methodId: Long) { 13 | val script = "window.$network.sendResponse($methodId, \"$message\")" 14 | this.post { 15 | this.evaluateJavascript(script) {} 16 | } 17 | } 18 | 19 | fun WebView.sendResults(network: String, messages: List, methodId: Long) { 20 | val message = messages.joinToString(separator = ",") 21 | val script = "window.$network.sendResponse($methodId, \"$message\")" 22 | this.post { 23 | this.evaluateJavascript(script) {} 24 | } 25 | } 26 | 27 | fun String.toHexByteArray(): ByteArray { 28 | return Numeric.hexStringToByteArray(this) 29 | } 30 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /android/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFBB86FC 4 | #FF6200EE 5 | #FF3700B3 6 | #FF03DAC5 7 | #FF018786 8 | #FF000000 9 | #FFFFFFFF 10 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Web3 Provider Demo 3 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | buildscript { 3 | ext.kotlin_version = "1.4.31" 4 | repositories { 5 | google() 6 | mavenCentral() 7 | 8 | maven { url 'https://jitpack.io' } 9 | } 10 | dependencies { 11 | classpath 'com.android.tools.build:gradle:4.2.1' 12 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 13 | classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0' 14 | } 15 | } 16 | 17 | allprojects { 18 | repositories { 19 | google() 20 | mavenCentral() 21 | 22 | maven { url 'https://jitpack.io' } 23 | 24 | maven { 25 | url = uri("https://maven.pkg.github.com/trustwallet/wallet-core") 26 | Properties properties = new Properties() 27 | properties.load(project.rootProject.file('local.properties').newDataInputStream()) 28 | credentials { 29 | username = properties.getProperty("gpr.user") 30 | password = properties.getProperty("gpr.key") 31 | } 32 | } 33 | } 34 | } 35 | 36 | task clean(type: Delete) { 37 | delete rootProject.buildDir 38 | } 39 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app"s APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | # Kotlin code style for this project: "official" or "obsolete": 21 | kotlin.code.style=official 22 | # Disable generation of the BuildConfig class 23 | android.defaults.buildfeatures.buildconfig=false 24 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustwallet/trust-web3-provider/e94d1c57bed40b90deedf04d3e56c8c817be9886/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Mar 17 17:43:08 JST 2021 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip 7 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /android/lib/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.github.dcendents.android-maven' 3 | apply plugin: 'maven-publish' 4 | 5 | group='com.trustwallet' 6 | 7 | def getArtificatId = { -> 8 | return "web3-provider" 9 | } 10 | def getVersionName = { -> 11 | return System.getenv('TAG_NAME') ?: "1.0.4" 12 | } 13 | 14 | android { 15 | compileSdkVersion 28 16 | 17 | defaultConfig { 18 | minSdkVersion 23 19 | targetSdkVersion 28 20 | versionCode 1 21 | project.archivesBaseName = getArtificatId() 22 | versionName getVersionName() 23 | } 24 | 25 | buildTypes { 26 | release { 27 | minifyEnabled false 28 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 29 | } 30 | } 31 | 32 | } 33 | 34 | dependencies {} 35 | 36 | publishing { 37 | publications { 38 | web3provider(MavenPublication) { 39 | groupId group 40 | artifactId getArtificatId() 41 | version getVersionName() 42 | artifact("$buildDir/outputs/aar/${getArtificatId()}-release.aar") 43 | } 44 | } 45 | 46 | repositories { 47 | maven { 48 | name = "GitHubPackages" 49 | url = uri("https://maven.pkg.github.com/trustwallet/trust-web3-provider") 50 | credentials { 51 | username = System.getenv("GPR_USER") 52 | password = System.getenv("GPR_API_KEY") 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /android/lib/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /android/lib/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | include ':lib' 3 | rootProject.name = "Web3 Provider Demo" -------------------------------------------------------------------------------- /bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustwallet/trust-web3-provider/e94d1c57bed40b90deedf04d3e56c8c817be9886/bun.lockb -------------------------------------------------------------------------------- /bunfig.toml: -------------------------------------------------------------------------------- 1 | [test] 2 | root = "./packages" -------------------------------------------------------------------------------- /docs/BUILD.md: -------------------------------------------------------------------------------- 1 | ## Contributing 2 | 3 | ### Fork and set up your local env 4 | 5 | Install bun 6 | 7 | ```bash 8 | curl https://bun.sh/install | bash 9 | ``` 10 | 11 | Install deps 12 | 13 | ```bash 14 | bun install 15 | ``` 16 | 17 | ### Useful scripts 18 | 19 | Build packages 20 | 21 | ```bash 22 | bun run build:packages 23 | ``` 24 | 25 | Run tests 26 | 27 | ```bash 28 | bun run test 29 | ``` 30 | 31 | Run tests watch mode 32 | 33 | ```bash 34 | bun run test:watch 35 | ``` 36 | 37 | ### Test locally 38 | 39 | If you wish to test a package inside the extension, let's say solana: 40 | 41 | ```bash 42 | cd packages/solana 43 | npm link 44 | ``` 45 | 46 | Then you can run in the extension workspace: 47 | 48 | ```bash 49 | npm link @trustwallet/web3-provider-solana 50 | ``` 51 | 52 | --- 53 | 54 | ## Adding a new chain 55 | 56 | [Adding a new chain](/docs/NEW.md) 57 | -------------------------------------------------------------------------------- /docs/NEW.md: -------------------------------------------------------------------------------- 1 | ## Adding a new chain 2 | 3 | Run the generate command 4 | 5 | ```bash 6 | bun run generate awesomeNewChain 7 | ``` 8 | 9 | This will generate all the boilerplate structure for your new chain: 10 | 11 | ``` 12 | 📦 newChain 13 | ├─ tests 14 | ├─ exceptions 15 | ├─ types 16 | ├─ index.ts 17 | ├─ NewChainProvider.ts 18 | └─ package.json 19 | ``` 20 | 21 | Then you can build it using the command 22 | 23 | ```bash 24 | bun run build:packages 25 | ``` 26 | -------------------------------------------------------------------------------- /docs/USAGE.md: -------------------------------------------------------------------------------- 1 | ## Using the library 2 | 3 | # 1. Run 4 | 5 | ```bash 6 | npm i @trustwallet/web3-provider-core 7 | ``` 8 | 9 | # 2. Install your desired chain 10 | 11 | Let's use for example, ethereum 12 | 13 | ```bash 14 | npm i @trustwallet/web3-provider-ethereum 15 | ``` 16 | 17 | # 3. Example usage 18 | 19 | ```typescript 20 | import { Web3Provider } from '@trustwallet/web3-provider-core'; 21 | import { EthereumProvider } from '@trustwallet/web3-provider-ethereum'; 22 | 23 | const ethereum = new EthereumProvider(); 24 | 25 | new Web3Provider({ 26 | strategy: AdapterStrategy.PROMISES, 27 | handler: (params: IHandlerParams) => {}, 28 | }).registerProvider(ethereum); 29 | 30 | // Register the ethereum provider 31 | window.ethereum = ethereum; 32 | ``` 33 | 34 | dApps that use EIP-1193 will be able to connect to your wallet now. 35 | 36 | --- 37 | 38 | ## Find more about the chains 39 | 40 | - Cosmos [Docs](/packages/cosmos/README.md) 41 | - Solana - _Wallet Standard fully compatible_ [Docs](/packages/solana/README.md) 42 | - Ethereum _EIP-1193_ [Docs](/packages/ethereum/README.md) 43 | 44 | ### Using the callback Adapter 45 | 46 | ```typescript 47 | const provider = new Web3Provider({ 48 | strategy: AdapterStrategy.CALLBACK, 49 | }).registerProvider(ethereum); 50 | 51 | const handler = (params: IHandlerParams) => { 52 | provider.sendResponse(params.id, ['0x0....']); 53 | }; 54 | 55 | provider.setHandler(handler); 56 | ``` 57 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import globals from 'globals'; 2 | import tseslint from 'typescript-eslint'; 3 | 4 | export default [ 5 | { languageOptions: { globals: globals.browser } }, 6 | ...tseslint.configs.recommended, 7 | { 8 | ignores: ['templates/', '**/dist'], 9 | }, 10 | { 11 | rules: { 12 | 'no-unused-vars': 'off', 13 | '@typescript-eslint/no-unused-vars': 'off', 14 | '@typescript-eslint/no-explicit-any': 'off', 15 | '@typescript-eslint/no-namespace': 'off', 16 | }, 17 | }, 18 | ]; 19 | -------------------------------------------------------------------------------- /jitpack.yml: -------------------------------------------------------------------------------- 1 | before_install: 2 | - echo "installing" 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@trustwallet/web3-provider", 3 | "private": true, 4 | "module": "index.ts", 5 | "type": "module", 6 | "scripts": { 7 | "lint": "eslint .", 8 | "build": "bun build --entrypoints ./index.ts --outdir ./dist --target browser", 9 | "test:watch": "bun test --watch --only", 10 | "test": "bun test", 11 | "test:only": "bun run test --only", 12 | "dev": "bun run ./scripts/link.ts", 13 | "build:packages": "bun run ./scripts/build.ts", 14 | "generate": "bun run ./scripts/generate.ts", 15 | "rename": "bun run ./scripts/rename.ts", 16 | "publish": "bun run ./scripts/publish.ts", 17 | "build:version": "NODE_ENV=production semantic-release --dry-run" 18 | }, 19 | "workspaces": [ 20 | "packages/*" 21 | ], 22 | "devDependencies": { 23 | "@rollup/plugin-commonjs": "22.0.2", 24 | "@rollup/plugin-json": "6.1.0", 25 | "@rollup/plugin-node-resolve": "13.3.0", 26 | "@types/bun": "latest", 27 | "esbuild": "0.17.19", 28 | "eslint": "9.x", 29 | "globals": "^15.3.0", 30 | "rollup": "2.79.2", 31 | "rollup-plugin-esbuild": "4.9.3", 32 | "simple-scaffold": "2.2.1", 33 | "typescript": "^5.0.0", 34 | "typescript-eslint": "^7.10.0" 35 | }, 36 | "peerDependencies": { 37 | "typescript": "^5.0.0" 38 | }, 39 | "dependencies": { 40 | "semantic-release-export-data": "^1.1.0", 41 | "semantic-release": "^24.2.0" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/android-web3-provider/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@trustwallet/android-web3-provider", 3 | "version": "4.0.0", 4 | "type": "module", 5 | "main": "dist/index.cjs.js", 6 | "module": "dist/index.es.js", 7 | "unpkg": "dist/index.umd.js", 8 | "types": "dist/types/index.d.ts", 9 | "author": "Trust ", 10 | "license": "MIT", 11 | "sideEffects": false, 12 | "files": [ 13 | "dist" 14 | ], 15 | "scripts": { 16 | "build:clean": "rm -rf dist", 17 | "build:types": "tsc", 18 | "build:source": "bun build:clean; rollup --config ./rollup.config.js && rollup --config ./rollup.config2.js", 19 | "dev": "bun build ./index.ts --outdir ./dist --watch" 20 | }, 21 | "dependencies": { 22 | "@trustwallet/web3-provider-aptos": "workspace:*", 23 | "@trustwallet/web3-provider-core": "workspace:*", 24 | "@trustwallet/web3-provider-cosmos": "workspace:*", 25 | "@trustwallet/web3-provider-ethereum": "workspace:*", 26 | "@trustwallet/web3-provider-solana": "workspace:*", 27 | "@trustwallet/web3-provider-ton": "workspace:*", 28 | "core-js": "^3.38.1", 29 | "uuid": "9.0.1" 30 | }, 31 | "devDependencies": { 32 | "@babel/preset-env": "^7.25.8", 33 | "@babel/preset-typescript": "^7.25.7", 34 | "@rollup/plugin-babel": "^6.0.4", 35 | "@rollup/plugin-terser": "^0.4.4", 36 | "@types/uuid": "^9.0.8", 37 | "rollup-plugin-corejs": "^1.0.0", 38 | "rollup-plugin-polyfill-node": "0.13.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/android-web3-provider/rollup.config.js: -------------------------------------------------------------------------------- 1 | import commonjs from '@rollup/plugin-commonjs'; 2 | import { name, dependencies } from './package.json'; 3 | import nodePolyfills from 'rollup-plugin-polyfill-node'; 4 | import inject from '@rollup/plugin-inject'; 5 | import babel from '@rollup/plugin-babel'; 6 | import resolve from '@rollup/plugin-node-resolve'; 7 | import json from '@rollup/plugin-json'; 8 | 9 | const input = './src/index.ts'; 10 | const plugins = [ 11 | json(), 12 | nodePolyfills(), 13 | resolve({ browser: true, preferBuiltins: false }), 14 | commonjs(), 15 | babel({ 16 | babelHelpers: 'bundled', 17 | extensions: ['.js', '.ts'], 18 | exclude: 'node_modules/**', 19 | presets: [ 20 | [ 21 | '@babel/preset-env', 22 | { 23 | targets: 'chrome 67', 24 | corejs: '3.21.1', 25 | }, 26 | ], 27 | '@babel/preset-typescript', 28 | ], 29 | }), 30 | inject({ 31 | modules: { 32 | Buffer: ['buffer', 'Buffer'], 33 | }, 34 | }), 35 | ]; 36 | 37 | function createConfig(packageName) { 38 | return [ 39 | { 40 | input, 41 | plugins, 42 | output: { 43 | file: './dist/index.js', 44 | format: 'umd', 45 | name: packageName, 46 | sourcemap: false, 47 | }, 48 | }, 49 | ]; 50 | } 51 | 52 | export default createConfig(name, Object.keys(dependencies)); 53 | -------------------------------------------------------------------------------- /packages/android-web3-provider/rollup.config2.js: -------------------------------------------------------------------------------- 1 | import { name, dependencies } from './package.json'; 2 | import babel from '@rollup/plugin-babel'; 3 | import terser from '@rollup/plugin-terser'; 4 | 5 | const input = './dist/index.js'; 6 | 7 | const plugins = [ 8 | babel({ 9 | babelHelpers: 'bundled', 10 | extensions: ['.js'], 11 | presets: [ 12 | [ 13 | '@babel/preset-env', 14 | { 15 | targets: 'chrome 67', 16 | useBuiltIns: false, 17 | corejs: '3.21.1', 18 | }, 19 | ], 20 | ], 21 | }), 22 | 23 | terser(), 24 | ]; 25 | 26 | function createConfig(packageName) { 27 | return [ 28 | { 29 | input, 30 | plugins, 31 | output: { 32 | file: '../../android/lib/src/main/res/raw/trust_min.js', 33 | format: 'umd', 34 | name: packageName, 35 | sourcemap: false, 36 | extend: true, 37 | }, 38 | }, 39 | ]; 40 | } 41 | 42 | export default createConfig(name, Object.keys(dependencies)); 43 | -------------------------------------------------------------------------------- /packages/android-web3-provider/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | include ':lib' 3 | rootProject.name = "Web3 Provider Demo" -------------------------------------------------------------------------------- /packages/android-web3-provider/src/index.ts: -------------------------------------------------------------------------------- 1 | import 'core-js'; 2 | import { v4 as uuidv4 } from 'uuid'; 3 | 4 | import { SolanaProvider } from '@trustwallet/web3-provider-solana'; 5 | import { EthereumProvider } from '@trustwallet/web3-provider-ethereum'; 6 | import { CosmosProvider } from '@trustwallet/web3-provider-cosmos'; 7 | import { Web3Provider } from '@trustwallet/web3-provider-core'; 8 | import { AptosProvider } from '@trustwallet/web3-provider-aptos'; 9 | import { TonBridge, TonProvider } from '@trustwallet/web3-provider-ton'; 10 | 11 | import type { 12 | AdapterStrategyType, 13 | IHandler, 14 | } from '@trustwallet/web3-provider-core/adapter/Adapter'; 15 | 16 | import type { ISolanaProviderConfig } from '@trustwallet/web3-provider-solana/types/SolanaProvider'; 17 | import type { ICosmosProviderConfig } from '@trustwallet/web3-provider-cosmos/types/CosmosProvider'; 18 | import type { IEthereumProviderConfig } from '@trustwallet/web3-provider-ethereum/types/EthereumProvider'; 19 | import type { IAptosProviderConfig } from '@trustwallet/web3-provider-aptos/types/AptosProvider'; 20 | 21 | import type { ITonProviderConfig } from '@trustwallet/web3-provider-ton/types/TonProvider'; 22 | import type { ITonBridgeConfig } from '@trustwallet/web3-provider-ton/types/TonBridge'; 23 | 24 | const core = (strategy: AdapterStrategyType, handler?: IHandler) => 25 | new Web3Provider({ strategy, handler }); 26 | 27 | const solana = (config: ISolanaProviderConfig) => new SolanaProvider(config); 28 | 29 | const cosmos = (config: ICosmosProviderConfig) => new CosmosProvider(config); 30 | 31 | const ethereum = (config: IEthereumProviderConfig) => 32 | new EthereumProvider(config); 33 | 34 | const aptos = (config: IAptosProviderConfig) => new AptosProvider(config); 35 | 36 | const ton = (config: ITonProviderConfig) => new TonProvider(config); 37 | 38 | const tonBridge = (config: ITonBridgeConfig, provider: TonProvider) => 39 | new TonBridge(config, provider); 40 | 41 | window.trustwallet = { 42 | core, 43 | solana, 44 | cosmos, 45 | ethereum, 46 | aptos, 47 | ton, 48 | tonBridge, 49 | randomUUID: () => uuidv4(), 50 | }; 51 | -------------------------------------------------------------------------------- /packages/android-web3-provider/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "exclude": [ 3 | "package.json", 4 | "rollup.config.js", 5 | "tsconfig.json", 6 | "tests", 7 | "./dist" 8 | ], 9 | "compilerOptions": { 10 | "rootDir": "./", 11 | "outDir": "./dist/types", 12 | "lib": ["ES2020", "DOM"], 13 | "target": "ES6", 14 | "module": "ESNext", 15 | "moduleResolution": "node", 16 | "esModuleInterop": true, 17 | "skipLibCheck": true 18 | }, 19 | "include": ["./**/*.ts"] 20 | } 21 | -------------------------------------------------------------------------------- /packages/aptos/AptosProvider.ts: -------------------------------------------------------------------------------- 1 | import { BaseProvider } from '@trustwallet/web3-provider-core'; 2 | import type IAptosProvider from './types/AptosProvider'; 3 | import type { 4 | IAptosProviderConfig, 5 | ISignMessagePayload, 6 | } from './types/AptosProvider'; 7 | 8 | export class AptosProvider extends BaseProvider implements IAptosProvider { 9 | static NETWORK = 'aptos'; 10 | 11 | private _isConnected = false; 12 | 13 | private _network; 14 | 15 | public chainId: string | null = null; 16 | 17 | public address: string | null = null; 18 | 19 | static bufferToHex(buffer: Buffer | Uint8Array | string) { 20 | return '0x' + Buffer.from(buffer).toString('hex'); 21 | } 22 | 23 | static messageToBuffer(message: string | Buffer) { 24 | let buffer = Buffer.from([]); 25 | try { 26 | if (typeof message === 'string') { 27 | buffer = Buffer.from(message.replace('0x', ''), 'hex'); 28 | } else { 29 | buffer = Buffer.from(message); 30 | } 31 | } catch (err) { 32 | console.log(`messageToBuffer error: ${err}`); 33 | } 34 | 35 | return buffer; 36 | } 37 | 38 | constructor(config?: IAptosProviderConfig) { 39 | super(); 40 | 41 | if (config) { 42 | if (config.network) { 43 | this._network = config.network; 44 | 45 | if (config.chainId) { 46 | this.chainId = config.chainId; 47 | } 48 | } 49 | } 50 | } 51 | 52 | setConfig(config: { network: string; address: string; chainId: string }) { 53 | this._network = config.network; 54 | this.address = config.address; 55 | this.chainId = config.chainId; 56 | } 57 | 58 | async connect() { 59 | const accountInfo = await this.account(); 60 | this._isConnected = true; 61 | this.emit('connect'); 62 | return accountInfo; 63 | } 64 | 65 | disconnect() { 66 | this._isConnected = false; 67 | this.emit('disconnect'); 68 | } 69 | 70 | isConnected() { 71 | return this._isConnected; 72 | } 73 | 74 | async account() { 75 | const data = await this.request({ 76 | method: 'requestAccounts', 77 | params: {}, 78 | }); 79 | return JSON.parse(data); 80 | } 81 | 82 | network() { 83 | return this._network; 84 | } 85 | 86 | getNetwork(): string { 87 | return AptosProvider.NETWORK; 88 | } 89 | 90 | async signMessage(payload: ISignMessagePayload) { 91 | const prefix = 'APTOS'; 92 | const address = (await this.account()).address; 93 | 94 | let fullMessage = prefix; 95 | 96 | const application = 97 | window.location.protocol + '//' + window.location.hostname; 98 | 99 | if (payload.address) { 100 | fullMessage += '\naddress: ' + address; 101 | } 102 | 103 | if (payload.application) { 104 | fullMessage += '\napplication: ' + application; 105 | } 106 | 107 | if (payload.chainId) { 108 | fullMessage += '\nchainId: ' + this.chainId; 109 | } 110 | 111 | fullMessage += '\nmessage: ' + payload.message; 112 | fullMessage += '\nnonce: ' + payload.nonce; 113 | 114 | const buffer = Buffer.from(fullMessage); 115 | const hex = AptosProvider.bufferToHex(buffer); 116 | 117 | return this.request({ method: 'signMessage', params: { data: hex } }).then( 118 | (signature) => { 119 | return { 120 | address: address, 121 | application: application, 122 | chainId: this.chainId, 123 | fullMessage: fullMessage, 124 | message: payload.message, 125 | nonce: payload.nonce, 126 | prefix: prefix, 127 | signature: signature, 128 | }; 129 | }, 130 | ); 131 | } 132 | 133 | async signAndSubmitTransaction(tx: string) { 134 | const signedTx = await this.signTransaction(tx); 135 | 136 | const hex = await this.request({ 137 | method: 'sendTransaction', 138 | params: { tx: signedTx }, 139 | }); 140 | 141 | return { hash: AptosProvider.messageToBuffer(hex).toString() }; 142 | } 143 | 144 | async signTransaction(tx: string) { 145 | const hex = await this.request({ 146 | method: 'signTransaction', 147 | params: { data: tx }, 148 | }); 149 | 150 | return JSON.parse(AptosProvider.messageToBuffer(hex).toString()); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /packages/aptos/README.md: -------------------------------------------------------------------------------- 1 | # Trust Web3 Provider 2 | 3 | ``` 4 | 5 | 6 | ,---. | 7 | |---|,---.|--- ,---.,---. 8 | | || || | |`---. 9 | ` '|---'`--- `---'`---' 10 | | 11 | 12 | ``` 13 | 14 | ### Aptos JavaScript Provider Implementation 15 | 16 | ### Config Object 17 | 18 | ```typescript 19 | const config: { 20 | isTrust?: boolean; 21 | network?: string; 22 | chainId?: string | null; 23 | } = {}; 24 | ``` 25 | 26 | ### Usage 27 | 28 | ```typescript 29 | const aptos = new AptosProvider(config); 30 | ``` 31 | -------------------------------------------------------------------------------- /packages/aptos/exceptions/RPCError.ts: -------------------------------------------------------------------------------- 1 | export class RPCError extends Error { 2 | code: number; 3 | 4 | constructor(code: number, message: string) { 5 | super(); 6 | this.code = code; 7 | this.message = message; 8 | } 9 | 10 | toString() { 11 | return `${this.message} (${this.code})`; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/aptos/index.ts: -------------------------------------------------------------------------------- 1 | export * from './AptosProvider'; 2 | -------------------------------------------------------------------------------- /packages/aptos/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@trustwallet/web3-provider-aptos", 3 | "version": "4.0.0", 4 | "type": "module", 5 | "main": "dist/index.cjs.js", 6 | "module": "dist/index.es.js", 7 | "unpkg": "dist/index.umd.js", 8 | "types": "dist/types/index.d.ts", 9 | "author": "Trust ", 10 | "license": "MIT", 11 | "sideEffects": false, 12 | "files": [ 13 | "dist" 14 | ], 15 | "scripts": { 16 | "build:clean": "rm -rf dist", 17 | "build:types": "tsc", 18 | "build:source": "bun build:clean; rollup --config ./rollup.config.js; bun run build:types", 19 | "dev": "bun build ./index.ts --outdir ./dist --watch" 20 | }, 21 | "dependencies": { }, 22 | "devDependencies": { 23 | "@trustwallet/web3-provider-core": "workspace:*" 24 | } 25 | } -------------------------------------------------------------------------------- /packages/aptos/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { name, dependencies } from './package.json'; 2 | import createConfig from '../../rollup.config'; 3 | 4 | export default createConfig(name, Object.keys(dependencies)); 5 | -------------------------------------------------------------------------------- /packages/aptos/tests/AptosProvider.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect, jest, afterEach } from 'bun:test'; 2 | import { Web3Provider } from '@trustwallet/web3-provider-core'; 3 | import { AptosProvider } from '../AptosProvider'; 4 | import { AdapterStrategy } from '@trustwallet/web3-provider-core/adapter/Adapter'; 5 | 6 | let aptos = new AptosProvider(); 7 | const account = '0x0000000000000000000000000000000000000000'; 8 | 9 | afterEach(() => { 10 | aptos = new AptosProvider(); 11 | }); 12 | 13 | (global as any).window = {}; 14 | 15 | // Mock window 16 | Object.assign(global.window, { 17 | location: { 18 | protocol: 'https', 19 | hostname: 'trust', 20 | }, 21 | }); 22 | 23 | test('Aptos -> connect()', async () => { 24 | new Web3Provider({ 25 | strategy: AdapterStrategy.PROMISES, 26 | handler: () => Promise.resolve(JSON.stringify([account])), 27 | }).registerProvider(aptos); 28 | 29 | const accounts = await aptos.connect(); 30 | expect(accounts).toEqual([account]); 31 | }); 32 | 33 | test('Aptos -> signMessage()', async () => { 34 | const handler = jest.fn(() => Promise.resolve(JSON.stringify([account]))); 35 | 36 | new Web3Provider({ 37 | strategy: AdapterStrategy.PROMISES, 38 | handler, 39 | }).registerProvider(aptos); 40 | 41 | aptos.setConfig({ 42 | network: 'n', 43 | address: '123', 44 | chainId: '1', 45 | }); 46 | 47 | await aptos.signMessage({ 48 | address: '1', 49 | application: '2', 50 | message: '3', 51 | nonce: '4', 52 | chainId: '1', 53 | }); 54 | 55 | expect(handler).toBeCalledTimes(2); 56 | expect(handler).toHaveBeenNthCalledWith( 57 | 2, 58 | expect.objectContaining({ 59 | name: 'signMessage', 60 | }), 61 | ); 62 | }); 63 | -------------------------------------------------------------------------------- /packages/aptos/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "exclude": ["package.json", "rollup.config.js", "tsconfig.json", "tests", "./dist"], 4 | "compilerOptions": { 5 | "rootDir": "./", 6 | "outDir": "./dist/types", 7 | "emitDeclarationOnly": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/aptos/types/AptosProvider.ts: -------------------------------------------------------------------------------- 1 | export interface IAptosProviderConfig { 2 | isTrust?: boolean; 3 | network?: string; 4 | chainId?: string | null; 5 | } 6 | 7 | export default interface IAptosProvider {} 8 | 9 | export interface ISignMessagePayload { 10 | address: string; 11 | application: string; 12 | message: string; 13 | nonce: string; 14 | chainId: string; 15 | } 16 | -------------------------------------------------------------------------------- /packages/core/Provider.ts: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from 'events'; 2 | import type { CallbackAdapter } from './adapter/CallbackAdapter'; 3 | import type { PromiseAdapter } from './adapter/PromiseAdapter'; 4 | import { Adapter, AdapterStrategy } from './adapter/Adapter'; 5 | 6 | export interface IRequestArguments { 7 | method: string; 8 | params?: unknown[] | object; 9 | } 10 | 11 | export interface IBaseProvider { 12 | sendResponse(requestId: number, response: any): void; 13 | sendError(requestId: number, response: any): void; 14 | setAdapter(adapter: Adapter): IBaseProvider; 15 | request(args: IRequestArguments): Promise; 16 | } 17 | 18 | /** 19 | * Base provider 20 | * 21 | * All providers should extend this one 22 | */ 23 | export abstract class BaseProvider 24 | extends EventEmitter 25 | implements IBaseProvider 26 | { 27 | adapter!: CallbackAdapter | PromiseAdapter; 28 | 29 | setAdapter(adapter: CallbackAdapter | PromiseAdapter) { 30 | this.adapter = adapter; 31 | return this; 32 | } 33 | 34 | /** 35 | * 36 | * @param args 37 | */ 38 | async request(args: IRequestArguments): Promise { 39 | try { 40 | if (!this.adapter) { 41 | throw new Error( 42 | 'No adapter set, maybe you forgot to register the provider?', 43 | ); 44 | } 45 | 46 | const res = await this.adapter.request(args, this.getNetwork()); 47 | 48 | // Emit internally the response 49 | this.emit('onResponseReady', args, res); 50 | 51 | return res as T; 52 | } catch (e) { 53 | throw e; 54 | } 55 | } 56 | 57 | abstract getNetwork(): string; 58 | 59 | /** 60 | * Send Response if the adapter is on callback mode 61 | * @param requestId 62 | * @param response 63 | */ 64 | sendResponse(requestId: number, response: any) { 65 | if (!this.adapter) { 66 | throw new Error('Adapter not found'); 67 | } 68 | 69 | if (this.adapter.getStrategy() !== AdapterStrategy.CALLBACK) { 70 | throw new Error('Trying to send callback request on promisified adapter'); 71 | } 72 | 73 | (this.adapter as CallbackAdapter).sendResponse(requestId, response); 74 | } 75 | 76 | /** 77 | * Send error 78 | * @param requestId 79 | * @param response 80 | */ 81 | sendError(requestId: number, response: any) { 82 | if (!this.adapter) { 83 | throw new Error('Adapter not found'); 84 | } 85 | 86 | if (this.adapter.getStrategy() !== AdapterStrategy.CALLBACK) { 87 | throw new Error('Trying to send callback request on promisified adapter'); 88 | } 89 | 90 | (this.adapter as CallbackAdapter).sendError(requestId, response); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /packages/core/README.md: -------------------------------------------------------------------------------- 1 | # Trust Web3 Provider 2 | 3 | ``` 4 | 5 | // __ __ __ ___ 6 | // / ` / \ |__) |__ 7 | // \__, \__/ | \ |___ 8 | // 9 | 10 | ``` 11 | 12 | ### Core Package Description 13 | 14 | Handler strategy and handler registration 15 | -------------------------------------------------------------------------------- /packages/core/adapter/Adapter.ts: -------------------------------------------------------------------------------- 1 | import { 2 | IHandlerParams, 3 | ICallbackAdapterRequestParams, 4 | } from './CallbackAdapter'; 5 | 6 | export const AdapterStrategy = { 7 | PROMISES: 'PROMISES', 8 | CALLBACK: 'CALLBACK', 9 | } as const; 10 | 11 | interface IAdapter {} 12 | 13 | export interface IAdapterRequestParams { 14 | params?: unknown[] | object; 15 | method: string; 16 | } 17 | 18 | export type IHandler = (params: IHandlerParams) => Promise | void; 19 | 20 | export type AdapterStrategyType = keyof typeof AdapterStrategy; 21 | 22 | /** 23 | * Abstract adapter 24 | */ 25 | export abstract class Adapter { 26 | /** 27 | * Strategy to wait for wallet's response 28 | */ 29 | private strategy!: AdapterStrategyType; 30 | 31 | /** 32 | * Function that will handle requests on wallet side 33 | */ 34 | private handler!: IHandler; 35 | 36 | static isCallbackAdapterRequest( 37 | params: IAdapterRequestParams | ICallbackAdapterRequestParams, 38 | ): params is ICallbackAdapterRequestParams { 39 | return (params as ICallbackAdapterRequestParams).id !== undefined; 40 | } 41 | 42 | constructor(strategy: AdapterStrategyType) { 43 | this.setStrategy(strategy); 44 | } 45 | 46 | setHandler(remoteHandler: IHandler) { 47 | this.handler = remoteHandler; 48 | return this; 49 | } 50 | 51 | request( 52 | params: IAdapterRequestParams | ICallbackAdapterRequestParams, 53 | network: string, 54 | ): Promise | void { 55 | if (!this.handler) { 56 | throw new Error('No handler defined for Adapter'); 57 | } 58 | 59 | if (Adapter.isCallbackAdapterRequest(params)) { 60 | return this.handler({ 61 | network, 62 | id: params.id, 63 | name: params.method, 64 | params: params.params, 65 | object: params.params, 66 | }); 67 | } 68 | 69 | return this.handler({ 70 | name: params.method, 71 | network, 72 | params: params.params, 73 | object: params.params, 74 | }); 75 | } 76 | 77 | setStrategy(strategy: AdapterStrategyType) { 78 | this.strategy = strategy; 79 | return this; 80 | } 81 | 82 | getStrategy() { 83 | return this.strategy; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /packages/core/adapter/CallbackAdapter.ts: -------------------------------------------------------------------------------- 1 | import { RPCError } from '../exceptions/RPCError'; 2 | import { IRequestArguments } from '../Provider'; 3 | 4 | import { Adapter, AdapterStrategy, IAdapterRequestParams } from './Adapter'; 5 | 6 | export interface ICallbackAdapterRequestParams extends IAdapterRequestParams { 7 | id: number; 8 | } 9 | 10 | export interface IHandlerParams { 11 | id?: ICallbackAdapterRequestParams['id']; 12 | network: string; 13 | name: IAdapterRequestParams['method']; 14 | params: IAdapterRequestParams['params']; 15 | 16 | // Retro compatibility with apps 17 | object: IAdapterRequestParams['params']; 18 | } 19 | 20 | interface ICallbackEntry { 21 | resolve: (value: unknown) => void; 22 | reject: (error?: any) => any; 23 | } 24 | 25 | /** 26 | * CallbackAdapter 27 | * 28 | * Adapter implementation that uses callbacks and requires 29 | * sendResponse() to resolve the web3 promise or sendError() to reject it 30 | */ 31 | export class CallbackAdapter extends Adapter { 32 | constructor() { 33 | super(AdapterStrategy.CALLBACK); 34 | } 35 | 36 | private callback: Map = new Map(); 37 | 38 | async request(params: IRequestArguments, network: string): Promise { 39 | return new Promise((resolve, reject) => { 40 | const id = new Date().getTime() + Math.floor(Math.random() * 1000); 41 | this.callback.set(id.toString(), { reject, resolve }); 42 | super.request({ ...params, id }, network); 43 | }); 44 | } 45 | 46 | public sendResponse(requestId: number, response: any) { 47 | if (this.callback.has(requestId.toString())) { 48 | const callback = this.callback.get(requestId.toString()); 49 | this.callback.delete(requestId.toString()); 50 | callback?.resolve(response); 51 | } else { 52 | console.error(`Unable to find callback for requestId: ${requestId}`); 53 | } 54 | } 55 | 56 | public sendError(requestId: number, error: any) { 57 | if (this.callback.has(requestId.toString())) { 58 | const callback = this.callback.get(requestId.toString()); 59 | this.callback.delete(requestId.toString()); 60 | 61 | let errorParsed = error; 62 | 63 | // Parse error strings from mobile 64 | if ( 65 | typeof errorParsed === 'string' && 66 | !isNaN(parseInt(errorParsed, 10)) 67 | ) { 68 | errorParsed = new RPCError(parseInt(errorParsed, 10), errorParsed); 69 | } 70 | 71 | callback?.reject(errorParsed); 72 | } else { 73 | console.error(`Unable to find callback for requestId: ${requestId}`); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /packages/core/adapter/PromiseAdapter.ts: -------------------------------------------------------------------------------- 1 | import { IRequestArguments } from '../Provider'; 2 | import { Adapter, AdapterStrategy, IAdapterRequestParams } from './Adapter'; 3 | 4 | export class PromiseAdapter extends Adapter { 5 | constructor() { 6 | super(AdapterStrategy.PROMISES); 7 | } 8 | 9 | request(params: IRequestArguments, network: string): Promise | void { 10 | return super.request(params as IAdapterRequestParams, network); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/core/adapter/tests/CallbackBridge.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test, jest } from 'bun:test'; 2 | import { CallbackAdapter, IHandlerParams } from '../CallbackAdapter'; 3 | import { AdapterStrategy } from '../Adapter'; 4 | 5 | test('CallbackAdapter → Strategy is correct', () => { 6 | const adapter = new CallbackAdapter(); 7 | expect(adapter.getStrategy()).toEqual(AdapterStrategy.CALLBACK); 8 | }); 9 | 10 | test('CallbackAdapter → Handler is set and resolved promise', async () => { 11 | const adapter = new CallbackAdapter(); 12 | 13 | const response = 'pong'; 14 | 15 | const handler = jest.fn((params: IHandlerParams) => { 16 | adapter.sendResponse(params.id!, response); 17 | return Promise.resolve(); 18 | }); 19 | 20 | adapter.setHandler(handler); 21 | 22 | const params = { method: 'ping', params: [] }; 23 | 24 | const promise = adapter.request(params, 'ethereum'); 25 | 26 | expect(handler).toHaveBeenCalled(); 27 | expect(promise).resolves.toBe(response); 28 | }); 29 | 30 | test('CallbackAdapter → Handler is set and rejects promise', async () => { 31 | const adapter = new CallbackAdapter(); 32 | 33 | const response = 'error'; 34 | 35 | const handler = jest.fn((params: IHandlerParams) => { 36 | adapter.sendError(params.id!, response); 37 | return Promise.resolve(); 38 | }); 39 | 40 | adapter.setHandler(handler); 41 | 42 | const params = { method: 'ping', params: [] }; 43 | 44 | const promise = adapter.request(params, 'ethereum'); 45 | 46 | expect(handler).toHaveBeenCalled(); 47 | expect(promise).rejects.toBe(response); 48 | }); 49 | 50 | test('CallbackAdapter → Parameters are correct', async () => { 51 | const adapter = new CallbackAdapter(); 52 | 53 | const response = 'pong'; 54 | 55 | const handler = jest.fn((params: IHandlerParams) => { 56 | adapter.sendResponse(params.id!, response); 57 | return Promise.resolve(); 58 | }); 59 | 60 | adapter.setHandler(handler); 61 | 62 | const params = { method: 'ping', params: [1, 2, 3] }; 63 | adapter.request(params, 'ethereum'); 64 | 65 | expect(handler).toHaveBeenCalledWith( 66 | expect.objectContaining({ 67 | name: params.method, 68 | params: params.params, 69 | network: 'ethereum', 70 | }), 71 | ); 72 | }); 73 | -------------------------------------------------------------------------------- /packages/core/adapter/tests/PromiseBridge.spec.ts: -------------------------------------------------------------------------------- 1 | import { expect, test, jest } from 'bun:test'; 2 | import { PromiseAdapter } from '../PromiseAdapter'; 3 | import { AdapterStrategy, IAdapterRequestParams } from '../Adapter'; 4 | import { IHandlerParams } from '../CallbackAdapter'; 5 | 6 | test('PromiseAdapter → Strategy is correct', () => { 7 | const adapter = new PromiseAdapter(); 8 | expect(adapter.getStrategy()).toEqual(AdapterStrategy.PROMISES); 9 | }); 10 | 11 | test('PromiseAdapter → Handler is set and resolved promise', async () => { 12 | const adapter = new PromiseAdapter(); 13 | const response = 'pong'; 14 | 15 | const handler = jest.fn((_params: IHandlerParams) => { 16 | return Promise.resolve(response); 17 | }); 18 | 19 | adapter.setHandler(handler); 20 | 21 | const params = { method: 'ping', params: [] }; 22 | const promise = adapter.request(params, 'ethereum'); 23 | 24 | expect(handler).toHaveBeenCalled(); 25 | expect(promise).resolves.toBe(response); 26 | }); 27 | 28 | test('PromiseAdapter → Handler is set and rejects promise', async () => { 29 | const adapter = new PromiseAdapter(); 30 | 31 | const response = 'error'; 32 | 33 | const handler = jest.fn((_params: IHandlerParams) => { 34 | return Promise.reject(response); 35 | }); 36 | 37 | adapter.setHandler(handler); 38 | 39 | const params = { method: 'ping', params: [] }; 40 | 41 | const promise = adapter.request(params, 'ethereum'); 42 | 43 | expect(handler).toHaveBeenCalled(); 44 | expect(promise).rejects.toBe(response); 45 | }); 46 | 47 | test('PromiseAdapter → Parameters are correct', async () => { 48 | const adapter = new PromiseAdapter(); 49 | 50 | const handler = jest.fn((_params: IHandlerParams) => { 51 | return Promise.resolve(); 52 | }); 53 | 54 | adapter.setHandler(handler); 55 | 56 | const params = { method: 'ping', params: [1, 2, 3] }; 57 | adapter.request(params, 'ethereum'); 58 | 59 | expect(handler).toHaveBeenCalledWith( 60 | expect.objectContaining({ 61 | name: params.method, 62 | params: params.params, 63 | network: 'ethereum', 64 | }), 65 | ); 66 | }); 67 | -------------------------------------------------------------------------------- /packages/core/exceptions/RPCError.ts: -------------------------------------------------------------------------------- 1 | export class RPCError extends Error { 2 | code: number; 3 | 4 | constructor(code: number, message: string) { 5 | super(); 6 | this.code = code; 7 | this.message = message; 8 | } 9 | 10 | toString() { 11 | return `${this.message} (${this.code})`; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/core/index.ts: -------------------------------------------------------------------------------- 1 | import { BaseProvider, IBaseProvider } from './Provider'; 2 | import { 3 | AdapterStrategy, 4 | AdapterStrategyType, 5 | IHandler, 6 | type Adapter, 7 | } from './adapter/Adapter'; 8 | import { CallbackAdapter } from './adapter/CallbackAdapter'; 9 | import { PromiseAdapter } from './adapter/PromiseAdapter'; 10 | 11 | /** 12 | * Trust web3 Provider 13 | * 14 | * 15 | */ 16 | export class Web3Provider { 17 | private adapter!: Adapter; 18 | 19 | constructor(params: { strategy: AdapterStrategyType; handler?: IHandler }) { 20 | const adapter = 21 | params.strategy === AdapterStrategy.CALLBACK 22 | ? new CallbackAdapter() 23 | : new PromiseAdapter(); 24 | 25 | if (params.handler) { 26 | adapter.setHandler(params.handler); 27 | } 28 | 29 | this.setAdapter(adapter); 30 | } 31 | 32 | setHandler(handler: IHandler) { 33 | this.adapter.setHandler(handler); 34 | } 35 | 36 | private setAdapter(adapter: Adapter) { 37 | this.adapter = adapter; 38 | return this; 39 | } 40 | 41 | registerProvider(provider: BaseProvider) { 42 | provider.setAdapter(this.adapter); 43 | return this; 44 | } 45 | 46 | registerProviders(providers: BaseProvider[]) { 47 | providers.forEach((provider) => this.registerProvider(provider)); 48 | return this; 49 | } 50 | 51 | sendResponse(requestId: number, response: any) { 52 | if (this.adapter.getStrategy() === 'CALLBACK') { 53 | (this.adapter as CallbackAdapter).sendResponse(requestId, response); 54 | } 55 | } 56 | 57 | sendError(requestId: number, error: any) { 58 | if (this.adapter.getStrategy() === 'CALLBACK') { 59 | (this.adapter as CallbackAdapter).sendError(requestId, error); 60 | } 61 | } 62 | } 63 | 64 | export * from './Provider'; 65 | -------------------------------------------------------------------------------- /packages/core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@trustwallet/web3-provider-core", 3 | "version": "4.0.0", 4 | "type": "module", 5 | "main": "dist/index.cjs.js", 6 | "module": "dist/index.es.js", 7 | "unpkg": "dist/index.umd.js", 8 | "types": "dist/types/index.d.ts", 9 | "author": "Trust ", 10 | "license": "MIT", 11 | "sideEffects": false, 12 | "files": [ 13 | "dist" 14 | ], 15 | "scripts": { 16 | "build:clean": "rm -rf dist", 17 | "build:types": "tsc", 18 | "build:source": "bun build:clean; rollup --config ./rollup.config.js; bun run build:types", 19 | "dev": "bun build:clean; rollup -w --config ./rollup.config.js", 20 | "build": "bun build ./index.ts --outdir ./dist" 21 | }, 22 | "dependencies": { 23 | "events": "^3.3.0", 24 | "uuid": "9.0.1" 25 | }, 26 | "devDependencies": { 27 | "@types/uuid": "^9.0.8" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/core/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { name, dependencies } from './package.json'; 2 | import createConfig from '../../rollup.config'; 3 | 4 | export default createConfig(name, Object.keys(dependencies)); 5 | -------------------------------------------------------------------------------- /packages/core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "exclude": [ 4 | "package.json", 5 | "rollup.config.js", 6 | "tsconfig.json", 7 | "tests", 8 | "./dist", 9 | "**/*.spec.ts" 10 | ], 11 | "compilerOptions": { 12 | "rootDir": "./", 13 | "outDir": "./dist/types", 14 | "emitDeclarationOnly": true 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/cosmos/CosmosProvider.ts: -------------------------------------------------------------------------------- 1 | import { 2 | BaseProvider, 3 | IRequestArguments, 4 | } from '@trustwallet/web3-provider-core'; 5 | import { 6 | BroadcastMode, 7 | DirectSignDoc, 8 | ICosmosProvider, 9 | ICosmosProviderConfig, 10 | } from './types/CosmosProvider'; 11 | import { StdSignDoc } from '@cosmjs/amino'; 12 | import { MobileAdapter } from './MobileAdapter'; 13 | import { WalletAccount } from '@cosmos-kit/core'; 14 | 15 | export class CosmosProvider extends BaseProvider implements ICosmosProvider { 16 | static NETWORK = 'cosmos'; 17 | 18 | private mobileAdapter!: MobileAdapter; 19 | 20 | #disableMobileAdapter: boolean = false; 21 | 22 | /** 23 | * Mobile required overwriting this to true 24 | */ 25 | isKeplr: boolean = true; 26 | 27 | isTrust: boolean = true; 28 | 29 | isTrustWallet: boolean = true; 30 | 31 | constructor(config?: ICosmosProviderConfig) { 32 | super(); 33 | 34 | if (config) { 35 | if (typeof config.disableMobileAdapter !== 'undefined') { 36 | this.#disableMobileAdapter = config.disableMobileAdapter; 37 | } 38 | 39 | if (typeof config.isKeplr !== 'undefined') { 40 | this.isKeplr = config.isKeplr; 41 | } 42 | 43 | if (typeof config.isTrust !== 'undefined') { 44 | this.isTrust = config.isTrust; 45 | this.isTrustWallet = config.isTrust; 46 | } 47 | } 48 | 49 | if (!this.#disableMobileAdapter) { 50 | this.mobileAdapter = new MobileAdapter(this); 51 | } 52 | } 53 | 54 | static bufferToHex(buffer: Buffer | Uint8Array | string) { 55 | return '0x' + Buffer.from(buffer).toString('hex'); 56 | } 57 | 58 | getNetwork(): string { 59 | return CosmosProvider.NETWORK; 60 | } 61 | 62 | isMobileAdapterEnabled() { 63 | return !this.#disableMobileAdapter; 64 | } 65 | 66 | enable(chainIds: string | string[]): Promise { 67 | return this.request({ 68 | method: 'enable', 69 | params: { chainIds }, 70 | }); 71 | } 72 | 73 | /** 74 | * Call request handler directly 75 | * @param args 76 | * @returns 77 | */ 78 | internalRequest(args: IRequestArguments): Promise { 79 | return super.request(args); 80 | } 81 | 82 | /** 83 | * request order is 84 | * 85 | * mobileAdapter (if enabled) 86 | * -----> client handler (internalRequest) 87 | * 88 | * @param args 89 | * @returns 90 | */ 91 | request(args: IRequestArguments): Promise { 92 | const next = () => { 93 | return this.internalRequest(args) as Promise; 94 | }; 95 | 96 | if (this.mobileAdapter) { 97 | return this.mobileAdapter.request(args, next); 98 | } 99 | 100 | return next(); 101 | } 102 | 103 | getKey(chainId: string) { 104 | return this.request({ 105 | method: 'getKey', 106 | params: { chainId: chainId }, 107 | }); 108 | } 109 | 110 | async sendTx( 111 | chainId: string, 112 | tx: Uint8Array, 113 | mode: BroadcastMode, 114 | ): Promise { 115 | const raw = Buffer.from(tx).toString('base64'); 116 | 117 | const hash = await this.request({ 118 | method: 'sendTx', 119 | params: { 120 | raw, 121 | chainId, 122 | mode, 123 | }, 124 | }); 125 | 126 | return new Uint8Array(Buffer.from(hash, 'hex')); 127 | } 128 | 129 | async signArbitrary( 130 | chainId: string, 131 | signerAddress: string, 132 | payload: string | Uint8Array, 133 | ) { 134 | const buffer = Buffer.from(payload); 135 | const data = CosmosProvider.bufferToHex(buffer); 136 | 137 | const signature = await this.request<{ signature: string }>({ 138 | method: 'signArbitrary', 139 | params: { 140 | chainId, 141 | data, 142 | signerAddress, 143 | }, 144 | }); 145 | 146 | return signature; 147 | } 148 | 149 | async signAmino(chainId: string, _signer: string, signDoc: StdSignDoc) { 150 | const response = await this.request({ 151 | method: 'signAmino', 152 | params: { 153 | chainId, 154 | sign_doc: signDoc, 155 | }, 156 | }); 157 | 158 | const { signed, signature } = JSON.parse(response); 159 | return { signed: signed as StdSignDoc, signature }; 160 | } 161 | 162 | async signDirect( 163 | chainId: string, 164 | signerAddress: string, 165 | signDoc: DirectSignDoc, 166 | ) { 167 | const object = { 168 | bodyBytes: CosmosProvider.bufferToHex(signDoc.bodyBytes), 169 | authInfoBytes: CosmosProvider.bufferToHex(signDoc.authInfoBytes), 170 | }; 171 | 172 | const response = await this.request({ 173 | method: 'signDirect', 174 | params: { 175 | signerAddress, 176 | chainId, 177 | sign_doc: object, 178 | }, 179 | }); 180 | 181 | const { signature } = JSON.parse(response); 182 | return { signed: signDoc, signature: signature as string }; 183 | } 184 | 185 | experimentalSuggestChain() {} 186 | 187 | getOfflineSignerDirect(chainId: string) { 188 | return { 189 | getAccounts: async () => { 190 | return [await this.getKey(chainId)]; 191 | }, 192 | 193 | signDirect: async (signerAddress: string, signDoc: DirectSignDoc) => { 194 | if (chainId !== signDoc.chainId) { 195 | throw new Error('Unmatched chain id with the offline signer'); 196 | } 197 | 198 | const key = await this.getKey(signDoc.chainId); 199 | 200 | if (key.address !== signerAddress) { 201 | throw new Error('Unknown signer address'); 202 | } 203 | 204 | return await this.signDirect(chainId, signerAddress, signDoc); 205 | }, 206 | }; 207 | } 208 | 209 | getOfflineSigner(chainId: string) { 210 | return this.getOfflineSignerAmino(chainId); 211 | } 212 | 213 | getOfflineSignerAuto(chainId: string) { 214 | return this.getOfflineSignerAmino(chainId); 215 | } 216 | 217 | getOfflineSignerAmino(chainId: string) { 218 | return { 219 | getAccounts: async () => { 220 | const key = (await this.getKey(chainId)) as unknown as { 221 | pubKey: Buffer; 222 | bech32Address: string; 223 | }; 224 | 225 | return [ 226 | { 227 | address: key.bech32Address, 228 | algo: 'secp256k1', 229 | pubkey: key.pubKey, 230 | }, 231 | ]; 232 | }, 233 | 234 | sign: (signerAddress: string, signDoc: StdSignDoc) => { 235 | return this.signAmino(chainId, signerAddress, signDoc); 236 | }, 237 | 238 | signAmino: (signerAddress: string, signDoc: StdSignDoc) => { 239 | return this.signAmino(chainId, signerAddress, signDoc); 240 | }, 241 | }; 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /packages/cosmos/MobileAdapter.ts: -------------------------------------------------------------------------------- 1 | import { IRequestArguments } from '@trustwallet/web3-provider-core'; 2 | import { CosmosProvider } from './CosmosProvider'; 3 | 4 | /** 5 | * Adapting some requests to legacy mobile API 6 | * 7 | * This adapter provides the APIs with the method names and params the extension and mobile are 8 | * ready to handle 9 | */ 10 | export class MobileAdapter { 11 | private provider!: CosmosProvider; 12 | 13 | constructor(provider: CosmosProvider) { 14 | this.provider = provider; 15 | } 16 | 17 | /** 18 | * Mobile adapter maps some cosmos methods to existing mobile method names 19 | * @param args 20 | * @param next 21 | * @returns 22 | */ 23 | async request( 24 | args: IRequestArguments, 25 | next: () => Promise, 26 | ): Promise { 27 | if (args.method === 'getKey') { 28 | const res = await this.provider.internalRequest({ 29 | method: 'requestAccounts', 30 | params: args.params, 31 | }); 32 | 33 | const account = JSON.parse(res); 34 | 35 | return { 36 | algo: 'secp256k1', 37 | address: account.address, 38 | bech32Address: account.address, 39 | pubKey: Buffer.from(account.pubKey, 'hex'), 40 | } as unknown as T; 41 | } 42 | 43 | const map: Record = { 44 | signAmino: 'signTransaction', 45 | signDirect: 'signTransaction', 46 | signArbitrary: 'signMessage', 47 | sendTx: 'sendTransaction', 48 | }; 49 | 50 | if (map[args.method]) { 51 | return this.provider.internalRequest({ 52 | method: map[args.method], 53 | params: args.params, 54 | }); 55 | } 56 | 57 | return next(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /packages/cosmos/README.md: -------------------------------------------------------------------------------- 1 | # Trust Web3 Provider 2 | 3 | ``` 4 | 5 | // __ __ __ __ __ 6 | // / ` / \ /__` |\/| / \ /__` 7 | // \__, \__/ .__/ | | \__/ .__/ 8 | // 9 | 10 | ``` 11 | 12 | ### Cosmos JavaScript Provider Implementation 13 | 14 | ### Config Object 15 | 16 | ```typescript 17 | const config: { 18 | disableMobileAdapter?: boolean; 19 | isKeplr?: boolean; 20 | isTrust?: boolean; 21 | } = {}; 22 | ``` 23 | 24 | ### Usage 25 | 26 | ```typescript 27 | const cosmos = new CosmosProvider(config); 28 | ``` 29 | -------------------------------------------------------------------------------- /packages/cosmos/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CosmosProvider'; 2 | -------------------------------------------------------------------------------- /packages/cosmos/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@trustwallet/web3-provider-cosmos", 3 | "version": "4.0.0", 4 | "type": "module", 5 | "main": "dist/index.cjs.js", 6 | "module": "dist/index.es.js", 7 | "unpkg": "dist/index.umd.js", 8 | "types": "dist/types/index.d.ts", 9 | "author": "Trust ", 10 | "license": "MIT", 11 | "sideEffects": false, 12 | "files": [ 13 | "dist" 14 | ], 15 | "scripts": { 16 | "build:clean": "rm -rf dist", 17 | "build:types": "tsc", 18 | "build:source": "bun build:clean; rollup --config ./rollup.config.js; bun run build:types", 19 | "dev": "bun build ./index.ts --outdir ./dist --watch" 20 | }, 21 | "dependencies": { 22 | "@cosmjs/amino": "0.32.3", 23 | "@cosmjs/proto-signing": "^0.32.3", 24 | "@trustwallet/web3-provider-core": "workspace:*" 25 | }, 26 | "devDependencies": { 27 | "@cosmos-kit/core": "^2.10.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/cosmos/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { name, dependencies } from './package.json'; 2 | import createConfig from '../../rollup.config'; 3 | 4 | export default createConfig(name, Object.keys(dependencies)); 5 | -------------------------------------------------------------------------------- /packages/cosmos/tests/CosmosProvider.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect, jest, afterEach } from 'bun:test'; 2 | import { Web3Provider } from '@trustwallet/web3-provider-core'; 3 | import { AdapterStrategy } from '@trustwallet/web3-provider-core/adapter/Adapter'; 4 | import { IHandlerParams } from '@trustwallet/web3-provider-core/adapter/CallbackAdapter'; 5 | import { SignTypedDataVersion, TypedDataUtils } from '@metamask/eth-sig-util'; 6 | import { CosmosProvider } from '../CosmosProvider'; 7 | import { StdSignDoc } from '@cosmjs/amino'; 8 | import { DirectSignDoc } from '@cosmos-kit/core'; 9 | import { BroadcastMode } from '../types/CosmosProvider'; 10 | 11 | let cosmos = new CosmosProvider(); 12 | const chainId = 'atom'; 13 | 14 | const account = 'cosmos1utt2qsfwr7pmqjw87aaf6rpgx049zel779e5ur'; 15 | const pubKey = Buffer.from('hello world').toString('hex'); 16 | 17 | afterEach(() => { 18 | cosmos = new CosmosProvider(); 19 | }); 20 | 21 | test('Cosmos Provider → initialization config is ok', async () => { 22 | cosmos = new CosmosProvider({ isKeplr: true }); 23 | expect(cosmos.isKeplr).toBeTrue(); 24 | 25 | cosmos = new CosmosProvider({ isKeplr: false }); 26 | expect(cosmos.isKeplr).toBeFalse(); 27 | }); 28 | 29 | test('Cosmos Provider → getKey -> payload is correct', async () => { 30 | const handler = jest.fn((_params: IHandlerParams) => 31 | Promise.resolve(JSON.stringify({ address: account, pubKey })), 32 | ); 33 | 34 | new Web3Provider({ 35 | strategy: AdapterStrategy.PROMISES, 36 | handler, 37 | }).registerProvider(cosmos); 38 | 39 | await cosmos.getKey(chainId); 40 | 41 | expect(handler).toHaveBeenCalledWith( 42 | expect.objectContaining({ 43 | network: CosmosProvider.NETWORK, 44 | params: { chainId }, 45 | }), 46 | ); 47 | }); 48 | 49 | test('Cosmos Provider → signAmino -> payload is correct', async () => { 50 | const handler = jest.fn((_params: IHandlerParams) => 51 | Promise.resolve(JSON.stringify({ address: account, pubKey })), 52 | ); 53 | 54 | new Web3Provider({ 55 | strategy: AdapterStrategy.PROMISES, 56 | handler, 57 | }).registerProvider(cosmos); 58 | 59 | await cosmos.signAmino(chainId, account, { 60 | foo: 'bar', 61 | } as unknown as StdSignDoc); 62 | 63 | expect(handler).toHaveBeenCalledWith( 64 | expect.objectContaining({ 65 | network: CosmosProvider.NETWORK, 66 | name: 'signTransaction', 67 | params: { chainId, sign_doc: { foo: 'bar' } }, 68 | }), 69 | ); 70 | }); 71 | 72 | test('Cosmos Provider → signDirect -> payload is correct', async () => { 73 | const handler = jest.fn((_params: IHandlerParams) => 74 | Promise.resolve(JSON.stringify({ address: account, pubKey })), 75 | ); 76 | 77 | new Web3Provider({ 78 | strategy: AdapterStrategy.PROMISES, 79 | handler, 80 | }).registerProvider(cosmos); 81 | 82 | const payload = { 83 | bodyBytes: Buffer.from('bar'), 84 | authInfoBytes: Buffer.from('bar'), 85 | chainId, 86 | accountNumber: null, 87 | }; 88 | 89 | await cosmos.signDirect(chainId, account, payload); 90 | 91 | expect(handler).toHaveBeenCalledWith( 92 | expect.objectContaining({ 93 | name: 'signTransaction', 94 | network: CosmosProvider.NETWORK, 95 | params: { 96 | signerAddress: account, 97 | chainId, 98 | sign_doc: { 99 | bodyBytes: CosmosProvider.bufferToHex(payload.bodyBytes), 100 | authInfoBytes: CosmosProvider.bufferToHex(payload.authInfoBytes), 101 | }, 102 | }, 103 | }), 104 | ); 105 | }); 106 | 107 | test('Cosmos Provider → signArbitrary -> payload is correct', async () => { 108 | const handler = jest.fn((_params: IHandlerParams) => Promise.resolve()); 109 | 110 | new Web3Provider({ 111 | strategy: AdapterStrategy.PROMISES, 112 | handler, 113 | }).registerProvider(cosmos); 114 | 115 | const payload = 'hello world'; 116 | await cosmos.signArbitrary(chainId, account, payload); 117 | 118 | expect(handler).toHaveBeenCalledWith( 119 | expect.objectContaining({ 120 | name: 'signMessage', 121 | network: CosmosProvider.NETWORK, 122 | params: { 123 | signerAddress: account, 124 | chainId, 125 | data: CosmosProvider.bufferToHex(payload), 126 | }, 127 | }), 128 | ); 129 | }); 130 | 131 | test('Cosmos Provider → sendTx -> payload is correct', async () => { 132 | const handler = jest.fn((_params: IHandlerParams) => Promise.resolve('0x0')); 133 | 134 | new Web3Provider({ 135 | strategy: AdapterStrategy.PROMISES, 136 | handler, 137 | }).registerProvider(cosmos); 138 | 139 | const payload = Buffer.from('mock tx'); 140 | await cosmos.sendTx(chainId, payload, 'block' as BroadcastMode); 141 | 142 | expect(handler).toHaveBeenCalledWith( 143 | expect.objectContaining({ 144 | name: 'sendTransaction', 145 | network: CosmosProvider.NETWORK, 146 | params: { 147 | chainId, 148 | raw: payload.toString('base64'), 149 | mode: 'block', 150 | }, 151 | }), 152 | ); 153 | }); 154 | 155 | test('Cosmos Provider → getOfflineSignerAmino', async () => { 156 | const signer = cosmos.getOfflineSignerAmino(chainId); 157 | 158 | expect(signer).toHaveProperty('getAccounts'); 159 | expect(signer).toHaveProperty('sign'); 160 | expect(signer).toHaveProperty('signAmino'); 161 | }); 162 | 163 | test('Cosmos Provider → getOfflineSignerDirect', async () => { 164 | const signer = cosmos.getOfflineSignerDirect(chainId); 165 | 166 | expect(signer).toHaveProperty('getAccounts'); 167 | expect(signer).toHaveProperty('signDirect'); 168 | }); 169 | -------------------------------------------------------------------------------- /packages/cosmos/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "exclude": ["package.json", "rollup.config.js", "tsconfig.json", "tests", "./dist"], 4 | "compilerOptions": { 5 | "rootDir": "./", 6 | "outDir": "./dist/types", 7 | "emitDeclarationOnly": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/cosmos/types/CosmosProvider.ts: -------------------------------------------------------------------------------- 1 | import { StdSignDoc } from '@cosmjs/amino'; 2 | 3 | export interface SignOptions { 4 | readonly preferNoSetFee?: boolean; 5 | readonly preferNoSetMemo?: boolean; 6 | readonly disableBalanceCheck?: boolean; 7 | } 8 | 9 | export declare enum BroadcastMode { 10 | /** Return after tx commit */ 11 | Block = 'block', 12 | /** Return after CheckTx */ 13 | Sync = 'sync', 14 | /** Return right away */ 15 | Async = 'async', 16 | } 17 | 18 | export interface DirectSignDoc { 19 | /** SignDoc bodyBytes */ 20 | bodyBytes: Uint8Array | Buffer; 21 | /** SignDoc authInfoBytes */ 22 | authInfoBytes: Uint8Array | Buffer; 23 | /** SignDoc chainId */ 24 | chainId: string | null; 25 | /** SignDoc accountNumber */ 26 | accountNumber: bigint | null; 27 | } 28 | 29 | export interface ICosmosProvider { 30 | signAmino: ( 31 | chainId: string, 32 | signer: string, 33 | signDoc: StdSignDoc, 34 | signOptions?: SignOptions, 35 | ) => Promise<{ signed: StdSignDoc; signature: string }>; 36 | 37 | signDirect: ( 38 | chainId: string, 39 | signer: string, 40 | signDoc: DirectSignDoc, 41 | signOptions?: SignOptions, 42 | ) => Promise<{ signed: DirectSignDoc; signature: string }>; 43 | 44 | signArbitrary: ( 45 | chainId: string, 46 | signer: string, 47 | data: string | Uint8Array, 48 | ) => Promise<{ signature: string }>; 49 | 50 | sendTx( 51 | chainId: string, 52 | tx: Uint8Array, 53 | mode: BroadcastMode, 54 | ): Promise; 55 | } 56 | 57 | export interface ICosmosProviderConfig { 58 | disableMobileAdapter?: boolean; 59 | isKeplr?: boolean; 60 | isTrust?: boolean; 61 | } 62 | -------------------------------------------------------------------------------- /packages/ethereum/README.md: -------------------------------------------------------------------------------- 1 | # Trust Web3 Provider 2 | 3 | ``` 4 | // ___ ___ ___ __ ___ 5 | // |__ | |__| |__ |__) |__ | | |\/| 6 | // |___ | | | |___ | \ |___ \__/ | | 7 | // 8 | ``` 9 | 10 | ### Ethereum JavaScript Provider Implementation 11 | 12 | ### Config Object 13 | 14 | ```typescript 15 | const config: { 16 | rpc?: string; 17 | chainId?: string; 18 | overwriteMetamask?: boolean; 19 | supportedMethods?: string[]; 20 | unsupportedMethods?: string[]; 21 | disableMobileAdapter?: boolean; 22 | isTrust?: boolean; 23 | } = {}; 24 | ``` 25 | 26 | ### Usage 27 | 28 | ```typescript 29 | const ethereum = new EthereumProvider(config); 30 | ``` 31 | -------------------------------------------------------------------------------- /packages/ethereum/RPCServer.ts: -------------------------------------------------------------------------------- 1 | import { IRequestArguments } from './types'; 2 | export interface RPC { 3 | call(payload: { 4 | jsonrpc: string; 5 | method: string; 6 | params: IRequestArguments['params']; 7 | }): Promise; 8 | } 9 | 10 | export class RPCServer implements RPC { 11 | #rpcUrl: string; 12 | 13 | constructor(rpcUrl: string) { 14 | this.#rpcUrl = rpcUrl; 15 | } 16 | 17 | async getBlockNumber() { 18 | const json = await this.call({ 19 | jsonrpc: '2.0', 20 | method: 'eth_blockNumber', 21 | params: [], 22 | }); 23 | 24 | return json.result; 25 | } 26 | 27 | async getBlockByNumber(number: number) { 28 | const json = await this.call({ 29 | jsonrpc: '2.0', 30 | method: 'eth_getBlockByNumber', 31 | params: [number, false], 32 | }); 33 | 34 | return json.result; 35 | } 36 | 37 | getFilterLogs(filter: string) { 38 | return this.call({ 39 | jsonrpc: '2.0', 40 | method: 'eth_getLogs', 41 | params: [filter], 42 | }); 43 | } 44 | 45 | async call(payload: { 46 | jsonrpc: string; 47 | method: string; 48 | params: IRequestArguments['params']; 49 | }) { 50 | const response = await fetch(this.#rpcUrl, { 51 | method: 'POST', 52 | headers: { 53 | Accept: 'application/json', 54 | 'Content-Type': 'application/json', 55 | }, 56 | body: JSON.stringify({ 57 | id: new Date().getTime() + Math.floor(Math.random() * 1000), 58 | ...payload, 59 | }), 60 | }); 61 | 62 | const json = await response.json(); 63 | 64 | if (!json.result && json.error) { 65 | throw new Error(json.error.message || 'rpc error'); 66 | } 67 | 68 | return json.result; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /packages/ethereum/exceptions/RPCError.ts: -------------------------------------------------------------------------------- 1 | export class RPCError extends Error { 2 | code: number; 3 | 4 | constructor(code: number, message: string) { 5 | super(); 6 | this.code = code; 7 | this.message = message; 8 | } 9 | 10 | toString() { 11 | return `${this.message} (${this.code})`; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/ethereum/index.ts: -------------------------------------------------------------------------------- 1 | export * from './EthereumProvider'; 2 | -------------------------------------------------------------------------------- /packages/ethereum/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@trustwallet/web3-provider-ethereum", 3 | "version": "4.0.0", 4 | "type": "module", 5 | "main": "dist/index.cjs.js", 6 | "module": "dist/index.es.js", 7 | "unpkg": "dist/index.umd.js", 8 | "types": "dist/types/index.d.ts", 9 | "author": "Trust ", 10 | "license": "MIT", 11 | "sideEffects": false, 12 | "files": [ 13 | "dist" 14 | ], 15 | "scripts": { 16 | "build:clean": "rm -rf dist", 17 | "build:types": "tsc", 18 | "build:source": "bun build:clean; rollup --config ./rollup.config.js; bun run build:types", 19 | "dev": "bun build ./index.ts --outdir ./dist --watch" 20 | }, 21 | "dependencies": { 22 | "@metamask/eth-sig-util": "^7.0.1", 23 | "@trustwallet/web3-provider-core": "workspace:*" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/ethereum/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { name, dependencies } from './package.json'; 2 | import createConfig from '../../rollup.config'; 3 | 4 | export default createConfig(name, Object.keys(dependencies)); 5 | -------------------------------------------------------------------------------- /packages/ethereum/tests/mocks/Wallet.ts: -------------------------------------------------------------------------------- 1 | export class EthereumWalletMock { 2 | requestAccounts() {} 3 | } 4 | -------------------------------------------------------------------------------- /packages/ethereum/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "exclude": ["package.json", "rollup.config.js", "tsconfig.json", "tests", "./dist"], 4 | "compilerOptions": { 5 | "rootDir": "./", 6 | "outDir": "./dist/types", 7 | "emitDeclarationOnly": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/ethereum/types.ts: -------------------------------------------------------------------------------- 1 | import type IEthereumProvider from './types/EthereumProvider'; 2 | 3 | export interface IRequestArguments { 4 | method: string; 5 | params?: unknown[] | object; 6 | } 7 | 8 | export type IProviderAccounts = string[]; 9 | 10 | export interface IProviderMessage { 11 | type: string; 12 | data: unknown; 13 | } 14 | 15 | export interface IProviderInfo { 16 | chainId: string; 17 | } 18 | 19 | export interface IProviderRpcError extends Error { 20 | message: string; 21 | code: number; 22 | data?: unknown; 23 | } 24 | 25 | export type IProviderChainId = IProviderInfo['chainId']; 26 | 27 | export enum EmitterSupportedEvents { 28 | CONNECT = 'connect', 29 | DISCONNECT = 'disconnect', 30 | MESSAGE = 'message', 31 | CHAIN_CHANGED = 'chainChanged', 32 | ACCOUNTS_CHANGED = 'accountsChanged', 33 | } 34 | 35 | export declare namespace IProviderEvents { 36 | type IEvent = 37 | | 'connect' 38 | | 'disconnect' 39 | | 'message' 40 | | 'chainChanged' 41 | | 'accountsChanged'; 42 | 43 | interface IEventArguments { 44 | connect: IProviderInfo; 45 | disconnect: IProviderRpcError; 46 | message: IProviderMessage; 47 | chainChanged: IProviderChainId; 48 | accountsChanged: IProviderAccounts; 49 | } 50 | } 51 | 52 | export interface IEthereumProviderListener { 53 | on: ( 54 | event: E, 55 | listener: (args: IProviderEvents.IEventArguments[E]) => void, 56 | ) => IEthereumProvider; 57 | 58 | once: ( 59 | event: E, 60 | listener: (args: IProviderEvents.IEventArguments[E]) => void, 61 | ) => IEthereumProvider; 62 | 63 | off: ( 64 | event: E, 65 | listener: (args: IProviderEvents.IEventArguments[E]) => void, 66 | ) => IEthereumProvider; 67 | 68 | removeListener: ( 69 | event: E, 70 | listener: (args: IProviderEvents.IEventArguments[E]) => void, 71 | ) => IEthereumProvider; 72 | 73 | emit: ( 74 | event: E, 75 | payload: IProviderEvents.IEventArguments[E], 76 | ) => boolean; 77 | } 78 | 79 | export interface IWatchAsset { 80 | type: string; 81 | options: { 82 | type: string; 83 | address: string; 84 | symbol: string; 85 | decimals: number; 86 | }; 87 | } 88 | 89 | export interface IPermissionRes { 90 | caveats: { type: string; value: string }[]; 91 | } 92 | -------------------------------------------------------------------------------- /packages/ethereum/types/EthereumProvider.ts: -------------------------------------------------------------------------------- 1 | import { 2 | EmitterSupportedEvents, 3 | IProviderAccounts, 4 | IProviderChainId, 5 | IProviderInfo, 6 | IProviderMessage, 7 | IProviderRpcError, 8 | IRequestArguments, 9 | } from '../types'; 10 | 11 | export interface IEthereumProviderConfig { 12 | rpc?: string; 13 | address?: string; 14 | rpcUrl?: string; 15 | chainId?: string; 16 | overwriteMetamask?: boolean; 17 | supportedMethods?: string[]; 18 | unsupportedMethods?: string[]; 19 | disableMobileAdapter?: boolean; 20 | isTrust?: boolean; 21 | } 22 | 23 | /** 24 | * EIP-1193: Ethereum Provider JavaScript API 25 | * 26 | * https://eips.ethereum.org/EIPS/eip-1193 27 | */ 28 | export default interface IEthereumProvider { 29 | request(args: IRequestArguments): Promise; 30 | 31 | setChainId(chainId: string): void; 32 | 33 | /** 34 | * @deprecated 35 | * @param args 36 | * @param callback 37 | */ 38 | sendAsync( 39 | args: IRequestArguments, 40 | callback: (error: any | null, data: unknown | null) => void, 41 | ): void; 42 | 43 | on( 44 | event: EmitterSupportedEvents.CONNECT, 45 | listener: (info: IProviderInfo) => void, 46 | ): IEthereumProvider; 47 | 48 | on( 49 | event: EmitterSupportedEvents.DISCONNECT, 50 | listener: (error: IProviderRpcError) => void, 51 | ): IEthereumProvider; 52 | 53 | on( 54 | event: EmitterSupportedEvents.MESSAGE, 55 | listener: (message: IProviderMessage) => void, 56 | ): IEthereumProvider; 57 | 58 | on( 59 | event: EmitterSupportedEvents.CHAIN_CHANGED, 60 | listener: (chainId: IProviderChainId) => void, 61 | ): IEthereumProvider; 62 | 63 | on( 64 | event: EmitterSupportedEvents.ACCOUNTS_CHANGED, 65 | listener: (accounts: IProviderAccounts) => void, 66 | ): IEthereumProvider; 67 | } 68 | 69 | export enum RPCMethods { 70 | eth_requestAccounts = 'eth_requestAccounts', 71 | } 72 | -------------------------------------------------------------------------------- /packages/ethereum/types/RPC.ts: -------------------------------------------------------------------------------- 1 | export declare type JsonRpcVersion = '2.0'; 2 | 3 | export declare type JsonRpcId = number | string | void; 4 | 5 | export interface JsonRpcResponseBase { 6 | jsonrpc: JsonRpcVersion; 7 | id: JsonRpcId; 8 | } 9 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/.swiftpm/xcode/xcuserdata/fivezone.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | TrustWeb3Provider.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 2 11 | 12 | ios-web3-provider-Package.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 0 16 | 17 | trust-web3-provider-Package.xcscheme_^#shared#^_ 18 | 19 | orderHint 20 | 0 21 | 22 | 23 | SuppressBuildableAutocreation 24 | 25 | ios-web3-provider 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.5 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "TrustWeb3Provider", 7 | products: [ 8 | .library( 9 | name: "TrustWeb3Provider", 10 | targets: ["TrustWeb3Provider"] 11 | ) 12 | ], 13 | dependencies: [], 14 | targets: [ 15 | .target( 16 | name: "TrustWeb3Provider", 17 | dependencies: [], 18 | path: "swift", 19 | resources: [ 20 | .process("trust-min.js", localization: .none) 21 | ] 22 | ) 23 | ] 24 | ) 25 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/README.md: -------------------------------------------------------------------------------- 1 | # Trust Web3 Provider 2 | 3 | ### iOS Adapter 4 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/TrustWeb3Provider.podspec: -------------------------------------------------------------------------------- 1 | # Copyright © 2017-2022 Trust Wallet. 2 | # 3 | # This file is part of Trust. The full Trust copyright notice, including 4 | # terms governing use, modification, and redistribution, is contained in the 5 | # file LICENSE at the root of the source code distribution tree. 6 | 7 | Pod::Spec.new do |s| 8 | s.name = 'TrustWeb3Provider' 9 | s.version = '1.0.0' 10 | s.summary = 'Web3 javascript wrapper provider for iOS and Android platforms.' 11 | 12 | s.description = <<-DESC 13 | Web3 javascript wrapper provider for iOS and Android platforms. 14 | The magic behind the dApps browsers 15 | DESC 16 | 17 | s.homepage = 'https://github.com/TrustWallet/trust-web3-provider' 18 | s.license = { :type => 'MIT', :file => 'LICENSE' } 19 | s.author = { 'hewigovens' => 'hewigovens@gmail.com', 'Viktor Radchenko' => 'vikmeup' } 20 | s.source = { :git => 'https://github.com/TrustWallet/trust-web3-provider.git', :tag => s.version.to_s } 21 | s.social_media_url = 'https://twitter.com/TrustWallet' 22 | 23 | s.ios.deployment_target = '13.0' 24 | s.source_files = 'swift/*.swift' 25 | s.resource_bundles = { 26 | 'TrustWeb3Provider' => ['swift/trust-min.js'] 27 | } 28 | end 29 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/global.d.ts: -------------------------------------------------------------------------------- 1 | declare global { 2 | interface Window { 3 | trustwallet: any; 4 | } 5 | } 6 | 7 | export {}; 8 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/index.ts: -------------------------------------------------------------------------------- 1 | import { SolanaProvider } from '@trustwallet/web3-provider-solana'; 2 | import { EthereumProvider } from '@trustwallet/web3-provider-ethereum'; 3 | import { CosmosProvider } from '@trustwallet/web3-provider-cosmos'; 4 | import { Web3Provider } from '@trustwallet/web3-provider-core'; 5 | import { 6 | AdapterStrategyType, 7 | IHandler, 8 | } from '@trustwallet/web3-provider-core/adapter/Adapter'; 9 | import { ISolanaProviderConfig } from '@trustwallet/web3-provider-solana/types/SolanaProvider'; 10 | import { ICosmosProviderConfig } from '@trustwallet/web3-provider-cosmos/types/CosmosProvider'; 11 | import { IEthereumProviderConfig } from '@trustwallet/web3-provider-ethereum/types/EthereumProvider'; 12 | import { AptosProvider } from '@trustwallet/web3-provider-aptos'; 13 | import { IAptosProviderConfig } from '@trustwallet/web3-provider-aptos/types/AptosProvider'; 14 | import { ITonProviderConfig } from '@trustwallet/web3-provider-ton/types/TonProvider'; 15 | import { ITonBridgeConfig } from '@trustwallet/web3-provider-ton/types/TonBridge'; 16 | import { TonBridge, TonProvider } from '@trustwallet/web3-provider-ton'; 17 | 18 | const core = (strategy: AdapterStrategyType, handler?: IHandler) => 19 | new Web3Provider({ strategy, handler }); 20 | 21 | const solana = (config: ISolanaProviderConfig) => new SolanaProvider(config); 22 | 23 | const cosmos = (config: ICosmosProviderConfig) => new CosmosProvider(config); 24 | 25 | const ethereum = (config: IEthereumProviderConfig) => 26 | new EthereumProvider(config); 27 | 28 | const aptos = (config: IAptosProviderConfig) => new AptosProvider(config); 29 | 30 | const ton = (config: ITonProviderConfig) => new TonProvider(config); 31 | 32 | const tonBridge = (config: ITonBridgeConfig, provider: TonProvider) => 33 | new TonBridge(config, provider); 34 | 35 | window.trustwallet = { 36 | core, 37 | solana, 38 | cosmos, 39 | ethereum, 40 | aptos, 41 | ton, 42 | tonBridge, 43 | }; 44 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/ios/Packages/WalletCore/.swiftpm/xcode/xcuserdata/fivezone.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SwiftProtobuf.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 4 11 | 12 | WalletCore.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 3 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/ios/Packages/WalletCore/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.3 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "WalletCore", 6 | platforms: [.iOS(.v13)], 7 | products: [ 8 | .library(name: "WalletCore", targets: ["WalletCore"]), 9 | .library(name: "SwiftProtobuf", targets: ["SwiftProtobuf"]) 10 | ], 11 | dependencies: [], 12 | targets: [ 13 | .binaryTarget( 14 | name: "WalletCore", 15 | url: "https://github.com/trustwallet/wallet-core/releases/download/3.0.5/WalletCore.xcframework.zip", 16 | checksum: "10b50d569849349f82072325ca2d7cc549c2de4ece1c1ce2b2021d607ebcac17" 17 | ), 18 | .binaryTarget( 19 | name: "SwiftProtobuf", 20 | url: "https://github.com/trustwallet/wallet-core/releases/download/3.0.5/SwiftProtobuf.xcframework.zip", 21 | checksum: "c84ebee2d15c0d310a60981eb69e0dfc41871fcc22ac8fbfa1677361506e73cf" 22 | ) 23 | ] 24 | ) 25 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/ios/PodsTest/Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '13.0' 2 | 3 | target 'PodsTest' do 4 | use_frameworks! 5 | pod 'TrustWeb3Provider', :path => '../../TrustWeb3Provider.podspec' 6 | 7 | target 'PodsTestTests' do 8 | inherit! :search_paths 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/ios/PodsTest/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - TrustWeb3Provider (1.0.0) 3 | 4 | DEPENDENCIES: 5 | - TrustWeb3Provider (from `../../TrustWeb3Provider.podspec`) 6 | 7 | EXTERNAL SOURCES: 8 | TrustWeb3Provider: 9 | :path: "../../TrustWeb3Provider.podspec" 10 | 11 | SPEC CHECKSUMS: 12 | TrustWeb3Provider: 3542a569aa2d28031ac2edfe594e3563376df738 13 | 14 | PODFILE CHECKSUM: 6c87b8cefa328e150428f744e344b4b887098d7e 15 | 16 | COCOAPODS: 1.11.3 17 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/ios/PodsTest/PodsTest.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/ios/PodsTest/PodsTest.xcodeproj/xcshareddata/xcschemes/PodsTest.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 53 | 55 | 61 | 62 | 63 | 64 | 70 | 72 | 78 | 79 | 80 | 81 | 83 | 84 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/ios/PodsTest/PodsTest.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/ios/PodsTest/PodsTest/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/ios/PodsTest/PodsTest/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "platform" : "ios", 6 | "size" : "1024x1024" 7 | } 8 | ], 9 | "info" : { 10 | "author" : "xcode", 11 | "version" : 1 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/ios/PodsTest/PodsTest/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/ios/PodsTest/PodsTest/ContentView.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2017-2022 Trust Wallet. 2 | // 3 | // This file is part of Trust. The full Trust copyright notice, including 4 | // terms governing use, modification, and redistribution, is contained in the 5 | // file LICENSE at the root of the source code distribution tree. 6 | 7 | import SwiftUI 8 | import TrustWeb3Provider 9 | 10 | struct ContentView: View { 11 | var body: some View { 12 | VStack { 13 | Image(systemName: "globe") 14 | .imageScale(.large) 15 | .foregroundColor(.accentColor) 16 | Text("Hello, world!") 17 | } 18 | .padding() 19 | } 20 | } 21 | 22 | struct ContentView_Previews: PreviewProvider { 23 | static var previews: some View { 24 | ContentView() 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/ios/PodsTest/PodsTest/PodsTestApp.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2017-2022 Trust Wallet. 2 | // 3 | // This file is part of Trust. The full Trust copyright notice, including 4 | // terms governing use, modification, and redistribution, is contained in the 5 | // file LICENSE at the root of the source code distribution tree. 6 | import SwiftUI 7 | 8 | @main 9 | struct PodsTestApp: App { 10 | var body: some Scene { 11 | WindowGroup { 12 | ContentView() 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/ios/PodsTest/PodsTest/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/ios/PodsTest/PodsTestTests/PodsTestTests.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2017-2022 Trust Wallet. 2 | // 3 | // This file is part of Trust. The full Trust copyright notice, including 4 | // terms governing use, modification, and redistribution, is contained in the 5 | // file LICENSE at the root of the source code distribution tree. 6 | 7 | import XCTest 8 | import TrustWeb3Provider 9 | @testable import PodsTest 10 | 11 | final class PodsTestTests: XCTestCase { 12 | func testLoadJs() throws { 13 | let ethereumConfig = TrustWeb3Provider.Config.EthereumConfig( 14 | address: "0x9d8a62f656a8d1615c1294fd71e9cfb3e4855a4f", 15 | chainId: 1, 16 | rpcUrl: "https://cloudflare-eth.com" 17 | ) 18 | let provider = TrustWeb3Provider(config: TrustWeb3Provider.Config(ethereum: ethereumConfig)) 19 | let url = provider.providerJsUrl 20 | let data = try Data(contentsOf: url) 21 | 22 | XCTAssertTrue(data.count > 0) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/ios/TrustWeb3Provider.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/ios/TrustWeb3Provider.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/ios/TrustWeb3Provider.xcodeproj/project.xcworkspace/xcuserdata/fivezone.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trustwallet/trust-web3-provider/e94d1c57bed40b90deedf04d3e56c8c817be9886/packages/ios-web3-provider/ios/TrustWeb3Provider.xcodeproj/project.xcworkspace/xcuserdata/fivezone.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /packages/ios-web3-provider/ios/TrustWeb3Provider.xcodeproj/xcshareddata/xcschemes/TrustWeb3Provider-Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/ios/TrustWeb3Provider.xcodeproj/xcuserdata/fivezone.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | TrustWeb3Provider-Example.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 1 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/ios/TrustWeb3Provider/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2017-2020 Trust Wallet. 2 | // 3 | // This file is part of Trust. The full Trust copyright notice, including 4 | // terms governing use, modification, and redistribution, is contained in the 5 | // file LICENSE at the root of the source code distribution tree. 6 | 7 | import UIKit 8 | 9 | @UIApplicationMain 10 | class AppDelegate: UIResponder, UIApplicationDelegate { 11 | 12 | var window: UIWindow? 13 | 14 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 15 | return true 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/ios/TrustWeb3Provider/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/ios/TrustWeb3Provider/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/ios/TrustWeb3Provider/DAppMethod.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2017-2020 Trust Wallet. 2 | // 3 | // This file is part of Trust. The full Trust copyright notice, including 4 | // terms governing use, modification, and redistribution, is contained in the 5 | // file LICENSE at the root of the source code distribution tree. 6 | 7 | import Foundation 8 | 9 | enum DAppMethod: String, Decodable, CaseIterable { 10 | case signRawTransaction 11 | case signTransaction 12 | case signMessage 13 | case signTypedMessage 14 | case signPersonalMessage 15 | case sendTransaction 16 | case ecRecover 17 | case requestAccounts 18 | case watchAsset 19 | case addEthereumChain 20 | case switchEthereumChain // legacy compatible 21 | case switchChain 22 | } 23 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/ios/TrustWeb3Provider/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "size" : "1024x1024", 46 | "scale" : "1x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/ios/TrustWeb3Provider/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | NSAppTransportSecurity 26 | 27 | NSAllowsArbitraryLoadsInWebContent 28 | 29 | 30 | UILaunchStoryboardName 31 | LaunchScreen 32 | UIMainStoryboardFile 33 | Main 34 | UIRequiredDeviceCapabilities 35 | 36 | armv7 37 | 38 | UISupportedInterfaceOrientations 39 | 40 | UIInterfaceOrientationPortrait 41 | UIInterfaceOrientationLandscapeLeft 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/ios/TrustWeb3Provider/WKScriptMessage+JSON.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2017-2020 Trust Wallet. 2 | // 3 | // This file is part of Trust. The full Trust copyright notice, including 4 | // terms governing use, modification, and redistribution, is contained in the 5 | // file LICENSE at the root of the source code distribution tree. 6 | 7 | import Foundation 8 | import WebKit 9 | 10 | extension WKScriptMessage { 11 | var json: [String: Any] { 12 | if let string = body as? String, 13 | let data = string.data(using: .utf8), 14 | let object = try? JSONSerialization.jsonObject(with: data, options: []), 15 | let dict = object as? [String: Any] { 16 | return dict 17 | } else if let object = body as? [String: Any] { 18 | return object 19 | } 20 | return [:] 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@trustwallet/ios-web3-provider", 3 | "version": "4.0.0", 4 | "type": "module", 5 | "main": "dist/index.cjs.js", 6 | "module": "dist/index.es.js", 7 | "unpkg": "dist/index.umd.js", 8 | "types": "dist/types/index.d.ts", 9 | "author": "Trust ", 10 | "license": "MIT", 11 | "sideEffects": false, 12 | "files": [ 13 | "dist" 14 | ], 15 | "scripts": { 16 | "build:clean": "rm -rf dist", 17 | "build:types": "tsc", 18 | "build:source": "bun build:clean; rollup --config ./rollup.config.js", 19 | "dev": "bun build ./index.ts --outdir ./dist --watch" 20 | }, 21 | "dependencies": { 22 | "@trustwallet/web3-provider-core": "workspace:*", 23 | "@trustwallet/web3-provider-ethereum": "workspace:*", 24 | "@trustwallet/web3-provider-solana": "workspace:*", 25 | "@trustwallet/web3-provider-cosmos": "workspace:*", 26 | "@trustwallet/web3-provider-aptos": "workspace:*", 27 | "@trustwallet/web3-provider-ton": "workspace:*", 28 | "rollup-plugin-polyfill-node": "0.13.0" 29 | }, 30 | "devDependencies": {} 31 | } 32 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/rollup.config.js: -------------------------------------------------------------------------------- 1 | import esbuild from 'rollup-plugin-esbuild'; 2 | import { nodeResolve } from '@rollup/plugin-node-resolve'; 3 | import commonjs from '@rollup/plugin-commonjs'; 4 | import { name, dependencies } from './package.json'; 5 | import nodePolyfills from 'rollup-plugin-polyfill-node'; 6 | import inject from '@rollup/plugin-inject'; 7 | import json from '@rollup/plugin-json'; 8 | 9 | const input = './index.ts'; 10 | const plugins = [ 11 | json(), 12 | nodeResolve({ preferBuiltins: false, browser: true }), 13 | commonjs(), 14 | inject({ 15 | modules: { 16 | Buffer: ['buffer', 'Buffer'], 17 | }, 18 | }), 19 | nodePolyfills(), 20 | esbuild({ 21 | minify: true, 22 | tsconfig: './tsconfig.json', 23 | loaders: { 24 | '.json': 'json', 25 | }, 26 | }), 27 | ]; 28 | 29 | function createConfig( 30 | packageName, 31 | packageDependencies, 32 | umd = {}, 33 | cjs = {}, 34 | es = {}, 35 | ) { 36 | return [ 37 | { 38 | input, 39 | plugins, 40 | output: { 41 | file: './swift/trust-min.js', 42 | format: 'umd', 43 | exports: 'named', 44 | name: packageName, 45 | sourcemap: false, 46 | ...umd, 47 | }, 48 | }, 49 | ]; 50 | } 51 | 52 | export default createConfig(name, Object.keys(dependencies)); 53 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/swift/ProviderNetwork.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2017-2022 Trust Wallet. 2 | // 3 | // This file is part of Trust. The full Trust copyright notice, including 4 | // terms governing use, modification, and redistribution, is contained in the 5 | // file LICENSE at the root of the source code distribution tree. 6 | 7 | public enum ProviderNetwork: String, Decodable { 8 | case ethereum 9 | case solana 10 | case cosmos 11 | case aptos 12 | case ton 13 | } 14 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/swift/WKWebView+Extension.swift: -------------------------------------------------------------------------------- 1 | // Copyright © 2017-2022 Trust Wallet. 2 | // 3 | // This file is part of Trust. The full Trust copyright notice, including 4 | // terms governing use, modification, and redistribution, is contained in the 5 | // file LICENSE at the root of the source code distribution tree. 6 | 7 | import WebKit 8 | 9 | public struct TypeWrapper { 10 | let value: T 11 | 12 | init(value: T) { 13 | self.value = value 14 | } 15 | } 16 | 17 | public extension WKWebView { 18 | var tw: TypeWrapper { 19 | return TypeWrapper(value: self) 20 | } 21 | } 22 | 23 | public extension TypeWrapper where T == WKWebView { 24 | func set(network: String, address: String) { 25 | let script = String(format: "trustwallet.\(network).setAddress(\"%@\");", address.lowercased()) 26 | value.evaluateJavaScript(script) 27 | } 28 | 29 | func set(config: TrustWeb3Provider.Config) { 30 | let script = """ 31 | var config = { 32 | ethereum: { 33 | address: "\(config.ethereum.address)", 34 | chainId: \(config.ethereum.chainId), 35 | rpcUrl: "\(config.ethereum.rpcUrl)" 36 | } 37 | }; 38 | ethereum.setConfig(config); 39 | """ 40 | value.evaluateJavaScript(script) 41 | } 42 | 43 | func emitChange(chainId: Int) { 44 | let string = "0x" + String(chainId, radix: 16) 45 | let script = String(format: "trustwallet.ethereum.emitChainChanged(\"%@\");", string) 46 | value.evaluateJavaScript(script) 47 | } 48 | 49 | func send(network: ProviderNetwork, error: String, to id: Int64) { 50 | let script = String(format: "trustwallet.\(network.rawValue).sendError(%ld, \"%@\")", id, error) 51 | value.evaluateJavaScript(script) 52 | } 53 | 54 | func send(network: ProviderNetwork, result: String, to id: Int64) { 55 | let script = String(format: "trustwallet.\(network.rawValue).sendResponse(%ld, \'%@\')", id, result) 56 | value.evaluateJavaScript(script) 57 | } 58 | 59 | func sendNull(network: ProviderNetwork, id: Int64) { 60 | let script = String(format: "trustwallet.\(network.rawValue).sendResponse(%ld, null)", id) 61 | value.evaluateJavaScript(script) 62 | } 63 | 64 | func send(network: ProviderNetwork, results: [String], to id: Int64) { 65 | let array = results.map { String(format: "\"%@\"", $0) } 66 | let script = String(format: "trustwallet.\(network.rawValue).sendResponse(%ld, [%@])", id, array.joined(separator: ",")) 67 | value.evaluateJavaScript(script) 68 | } 69 | 70 | func removeScriptHandler() { 71 | value.configuration.userContentController.removeScriptMessageHandler(forName: TrustWeb3Provider.scriptHandlerName) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/swift/trust-min.js: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:e617351ded83fa70b56327bc39a882fa5cffa19a3e76e35bf3618cd74b16b757 3 | size 1123827 4 | -------------------------------------------------------------------------------- /packages/ios-web3-provider/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "exclude": [ 4 | "package.json", 5 | "rollup.config.js", 6 | "tsconfig.json", 7 | "tests", 8 | "./dist" 9 | ], 10 | "compilerOptions": { 11 | "rootDir": "./", 12 | "outDir": "./dist/types", 13 | "emitDeclarationOnly": true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/solana/MobileAdapter.ts: -------------------------------------------------------------------------------- 1 | import { IRequestArguments } from '@trustwallet/web3-provider-core'; 2 | import { SolanaProvider } from './SolanaProvider'; 3 | import { isVersionedTransaction } from './adapter/solana'; 4 | import { PublicKey, Transaction, VersionedTransaction } from '@solana/web3.js'; 5 | import { ConnectOptions } from './types/SolanaProvider'; 6 | import * as bs58 from 'bs58'; 7 | 8 | /** 9 | * Adapting some requests to legacy mobile API 10 | * 11 | * This adapter provides the APIs with the method names and params the extension and mobile are 12 | * ready to handle 13 | */ 14 | export class MobileAdapter { 15 | private provider!: SolanaProvider; 16 | private useLegacySign = false; 17 | 18 | constructor(provider: SolanaProvider, useLegacySign = false) { 19 | this.provider = provider; 20 | this.useLegacySign = useLegacySign; 21 | } 22 | 23 | async connect( 24 | options?: ConnectOptions | undefined, 25 | ): Promise<{ publicKey: PublicKey }> { 26 | const addresses = await this.provider.internalRequest({ 27 | method: 'requestAccounts', 28 | params: { options }, 29 | }); 30 | 31 | this.provider.emit('connect'); 32 | return { publicKey: new PublicKey(addresses[0]) }; 33 | } 34 | 35 | async signTransaction( 36 | tx: T, 37 | ): Promise { 38 | if (this.useLegacySign) { 39 | return (await this.legacySign(tx)) as T; 40 | } 41 | 42 | const data = JSON.stringify(tx); 43 | 44 | let version: string | number = 'legacy'; 45 | let rawMessage: string; 46 | 47 | if (isVersionedTransaction(tx)) { 48 | version = tx.version; 49 | rawMessage = Buffer.from(tx.message.serialize()).toString('base64'); 50 | } else { 51 | rawMessage = Buffer.from(tx.serializeMessage()).toString('base64'); 52 | } 53 | 54 | const raw = Buffer.from( 55 | tx.serialize({ requireAllSignatures: false, verifySignatures: false }), 56 | ).toString('base64'); 57 | 58 | const signatureEncoded = await this.provider.internalRequest({ 59 | method: 'signRawTransaction', 60 | params: { 61 | data, 62 | raw, 63 | rawMessage, 64 | version, 65 | }, 66 | }); 67 | 68 | return this.provider.mapSignedTransaction(tx, signatureEncoded); 69 | } 70 | 71 | async legacySign(tx: T) { 72 | const data = JSON.stringify(tx); 73 | 74 | const version = 75 | typeof (tx as VersionedTransaction).version !== 'number' 76 | ? 'legacy' 77 | : (tx as VersionedTransaction).version; 78 | 79 | const raw = bs58.encode( 80 | version === 'legacy' 81 | ? (tx as Transaction).serializeMessage() 82 | : version === 0 83 | ? (tx as VersionedTransaction).message.serialize() 84 | : tx.serialize(), 85 | ); 86 | 87 | try { 88 | const signatureEncoded = await this.provider.internalRequest({ 89 | method: 'signRawTransaction', 90 | params: { data, raw, version }, 91 | }); 92 | 93 | return this.provider.mapSignedTransaction(tx, signatureEncoded); 94 | } catch (error) { 95 | console.log(`<== Error: ${error}`); 96 | } 97 | } 98 | 99 | /** 100 | * Mobile adapter maps some solana methods to existing mobile method names 101 | * @param args 102 | * @param next 103 | * @returns 104 | */ 105 | async request( 106 | args: IRequestArguments, 107 | next: () => Promise, 108 | ): Promise { 109 | switch (args.method) { 110 | case 'signTransaction': { 111 | return this.signTransaction( 112 | args.params as Transaction | VersionedTransaction, 113 | ) as unknown as T; 114 | } 115 | 116 | case 'connect': { 117 | return this.connect( 118 | (args?.params as { options: ConnectOptions })?.options, 119 | ) as unknown as T; 120 | } 121 | } 122 | 123 | return next(); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /packages/solana/README.md: -------------------------------------------------------------------------------- 1 | # Trust Web3 Provider 2 | 3 | ``` 4 | 5 | // __ __ 6 | // /__` / \ | /\ |\ | /\ 7 | // .__/ \__/ |___ /~~\ | \| /~~\ 8 | // 9 | 10 | ``` 11 | 12 | ### Solana JavaScript Provider Implementation that uses Wallet Standard 13 | 14 | ### Config Object 15 | 16 | ```typescript 17 | const config: { 18 | isTrust?: boolean; 19 | enableAdapter?: boolean; 20 | cluster?: string; 21 | disableMobileAdapter?: boolean; 22 | } = {}; 23 | ``` 24 | 25 | ### Usage 26 | 27 | ```typescript 28 | const solana = new SolanaProvider(config); 29 | ``` 30 | -------------------------------------------------------------------------------- /packages/solana/adapter/account.ts: -------------------------------------------------------------------------------- 1 | // This is copied with modification from @wallet-standard/wallet 2 | 3 | import { 4 | SolanaSignAndSendTransaction, 5 | SolanaSignMessage, 6 | SolanaSignTransaction, 7 | } from '@solana/wallet-standard-features'; 8 | import type { WalletAccount } from '@wallet-standard/base'; 9 | import { SOLANA_CHAINS } from './solana'; 10 | 11 | const chains = SOLANA_CHAINS; 12 | const features = [ 13 | SolanaSignAndSendTransaction, 14 | SolanaSignTransaction, 15 | SolanaSignMessage, 16 | ] as const; 17 | 18 | export class TrustWalletAccount implements WalletAccount { 19 | readonly #address: WalletAccount['address']; 20 | readonly #publicKey: WalletAccount['publicKey']; 21 | readonly #chains: WalletAccount['chains']; 22 | readonly #features: WalletAccount['features']; 23 | readonly #label: WalletAccount['label']; 24 | readonly #icon: WalletAccount['icon']; 25 | 26 | get address() { 27 | return this.#address; 28 | } 29 | 30 | get publicKey() { 31 | return this.#publicKey.slice(); 32 | } 33 | 34 | get chains() { 35 | return this.#chains.slice(); 36 | } 37 | 38 | get features() { 39 | return this.#features.slice(); 40 | } 41 | 42 | get label() { 43 | return this.#label; 44 | } 45 | 46 | get icon() { 47 | return this.#icon; 48 | } 49 | 50 | constructor({ 51 | address, 52 | publicKey, 53 | label, 54 | icon, 55 | }: Omit) { 56 | if (new.target === TrustWalletAccount) { 57 | Object.freeze(this); 58 | } 59 | 60 | this.#address = address; 61 | this.#publicKey = publicKey; 62 | this.#chains = chains; 63 | this.#features = features; 64 | this.#label = label; 65 | this.#icon = icon; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /packages/solana/adapter/icon.ts: -------------------------------------------------------------------------------- 1 | import type { WalletIcon } from '@wallet-standard/base'; 2 | 3 | export const icon: WalletIcon = 4 | 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTgiIGhlaWdodD0iNjUiIHZpZXdCb3g9IjAgMCA1OCA2NSIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTAgOS4zODk0OUwyOC44OTA3IDBWNjUuMDA0MkM4LjI1NDUgNTYuMzM2OSAwIDM5LjcyNDggMCAzMC4zMzUzVjkuMzg5NDlaIiBmaWxsPSIjMDUwMEZGIi8+CjxwYXRoIGQ9Ik01Ny43ODIyIDkuMzg5NDlMMjguODkxNSAwVjY1LjAwNDJDNDkuNTI3NyA1Ni4zMzY5IDU3Ljc4MjIgMzkuNzI0OCA1Ny43ODIyIDMwLjMzNTNWOS4zODk0OVoiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl8yMjAxXzY5NDIpIi8+CjxkZWZzPgo8bGluZWFyR3JhZGllbnQgaWQ9InBhaW50MF9saW5lYXJfMjIwMV82OTQyIiB4MT0iNTEuMzYxNSIgeTE9Ii00LjE1MjkzIiB4Mj0iMjkuNTM4NCIgeTI9IjY0LjUxNDciIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agb2Zmc2V0PSIwLjAyMTEyIiBzdG9wLWNvbG9yPSIjMDAwMEZGIi8+CjxzdG9wIG9mZnNldD0iMC4wNzYyNDIzIiBzdG9wLWNvbG9yPSIjMDA5NEZGIi8+CjxzdG9wIG9mZnNldD0iMC4xNjMwODkiIHN0b3AtY29sb3I9IiM0OEZGOTEiLz4KPHN0b3Agb2Zmc2V0PSIwLjQyMDA0OSIgc3RvcC1jb2xvcj0iIzAwOTRGRiIvPgo8c3RvcCBvZmZzZXQ9IjAuNjgyODg2IiBzdG9wLWNvbG9yPSIjMDAzOEZGIi8+CjxzdG9wIG9mZnNldD0iMC45MDI0NjUiIHN0b3AtY29sb3I9IiMwNTAwRkYiLz4KPC9saW5lYXJHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K' as const; 5 | -------------------------------------------------------------------------------- /packages/solana/adapter/initialize.ts: -------------------------------------------------------------------------------- 1 | import ISolanaProvider from '../types/SolanaProvider'; 2 | import { registerWallet } from './register'; 3 | 4 | function initialize(trust: ISolanaProvider): void { 5 | registerWallet(trust.getInstanceWithAdapter()); 6 | } 7 | 8 | export default initialize; 9 | -------------------------------------------------------------------------------- /packages/solana/adapter/register.ts: -------------------------------------------------------------------------------- 1 | // This is copied from @wallet-standard/wallet 2 | 3 | import type { 4 | DEPRECATED_WalletsWindow, 5 | Wallet, 6 | WalletEventsWindow, 7 | WindowRegisterWalletEvent, 8 | WindowRegisterWalletEventCallback, 9 | } from '@wallet-standard/base'; 10 | 11 | export function registerWallet(wallet: Wallet): void { 12 | const callback: WindowRegisterWalletEventCallback = ({ register }) => 13 | register(wallet); 14 | try { 15 | (window as WalletEventsWindow).dispatchEvent( 16 | new RegisterWalletEvent(callback), 17 | ); 18 | } catch (error) { 19 | console.error( 20 | 'wallet-standard:register-wallet event could not be dispatched\n', 21 | error, 22 | ); 23 | } 24 | try { 25 | (window as WalletEventsWindow).addEventListener( 26 | 'wallet-standard:app-ready', 27 | ({ detail: api }) => callback(api), 28 | ); 29 | } catch (error) { 30 | console.error( 31 | 'wallet-standard:app-ready event listener could not be added\n', 32 | error, 33 | ); 34 | } 35 | } 36 | 37 | class RegisterWalletEvent extends Event implements WindowRegisterWalletEvent { 38 | readonly #detail: WindowRegisterWalletEventCallback; 39 | 40 | get detail() { 41 | return this.#detail; 42 | } 43 | 44 | get type() { 45 | return 'wallet-standard:register-wallet' as const; 46 | } 47 | 48 | constructor(callback: WindowRegisterWalletEventCallback) { 49 | super('wallet-standard:register-wallet', { 50 | bubbles: false, 51 | cancelable: false, 52 | composed: false, 53 | }); 54 | this.#detail = callback; 55 | } 56 | 57 | /** @deprecated */ 58 | preventDefault(): never { 59 | throw new Error('preventDefault cannot be called'); 60 | } 61 | 62 | /** @deprecated */ 63 | stopImmediatePropagation(): never { 64 | throw new Error('stopImmediatePropagation cannot be called'); 65 | } 66 | 67 | /** @deprecated */ 68 | stopPropagation(): never { 69 | throw new Error('stopPropagation cannot be called'); 70 | } 71 | } 72 | 73 | /** @deprecated */ 74 | export function DEPRECATED_registerWallet(wallet: Wallet): void { 75 | registerWallet(wallet); 76 | try { 77 | ((window as DEPRECATED_WalletsWindow).navigator.wallets ||= []).push( 78 | ({ register }) => register(wallet), 79 | ); 80 | } catch (error) { 81 | console.error('window.navigator.wallets could not be pushed\n', error); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /packages/solana/adapter/solana.ts: -------------------------------------------------------------------------------- 1 | // This is copied from @solana/wallet-standard-chains 2 | 3 | import type { IdentifierString } from '@wallet-standard/base'; 4 | import type { Transaction, VersionedTransaction } from '@solana/web3.js'; 5 | 6 | /** Solana Mainnet (beta) cluster, e.g. https://api.mainnet-beta.solana.com */ 7 | export const SOLANA_MAINNET_CHAIN = 'solana:mainnet'; 8 | 9 | /** Solana Devnet cluster, e.g. https://api.devnet.solana.com */ 10 | export const SOLANA_DEVNET_CHAIN = 'solana:devnet'; 11 | 12 | /** Solana Testnet cluster, e.g. https://api.testnet.solana.com */ 13 | export const SOLANA_TESTNET_CHAIN = 'solana:testnet'; 14 | 15 | /** Solana Localnet cluster, e.g. http://localhost:8899 */ 16 | export const SOLANA_LOCALNET_CHAIN = 'solana:localnet'; 17 | 18 | /** Array of all Solana clusters */ 19 | export const SOLANA_CHAINS = [SOLANA_MAINNET_CHAIN] as const; 20 | 21 | /** Type of all Solana clusters */ 22 | export type SolanaChain = (typeof SOLANA_CHAINS)[number]; 23 | 24 | /** 25 | * Check if a chain corresponds with one of the Solana clusters. 26 | */ 27 | export function isSolanaChain(chain: IdentifierString): chain is SolanaChain { 28 | return SOLANA_CHAINS.includes(chain as SolanaChain); 29 | } 30 | 31 | export function isVersionedTransaction( 32 | transaction: Transaction | VersionedTransaction, 33 | ): transaction is VersionedTransaction { 34 | return 'version' in transaction; 35 | } 36 | -------------------------------------------------------------------------------- /packages/solana/adapter/window.ts: -------------------------------------------------------------------------------- 1 | export interface TrustEvent { 2 | connect(...args: unknown[]): unknown; 3 | disconnect(...args: unknown[]): unknown; 4 | accountChanged(...args: unknown[]): unknown; 5 | } 6 | 7 | export interface TrustEventEmitter { 8 | on( 9 | event: E, 10 | listener: TrustEvent[E], 11 | context?: any, 12 | ): void; 13 | off( 14 | event: E, 15 | listener: TrustEvent[E], 16 | context?: any, 17 | ): void; 18 | } 19 | -------------------------------------------------------------------------------- /packages/solana/exceptions/RPCError.ts: -------------------------------------------------------------------------------- 1 | export class RPCError extends Error { 2 | code: number; 3 | 4 | constructor(code: number, message: string) { 5 | super(); 6 | this.code = code; 7 | this.message = message; 8 | } 9 | 10 | toString() { 11 | return `${this.message} (${this.code})`; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/solana/index.ts: -------------------------------------------------------------------------------- 1 | export * from './SolanaProvider'; 2 | -------------------------------------------------------------------------------- /packages/solana/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@trustwallet/web3-provider-solana", 3 | "version": "4.0.0", 4 | "type": "module", 5 | "main": "dist/index.cjs.js", 6 | "module": "dist/index.es.js", 7 | "unpkg": "dist/index.umd.js", 8 | "types": "dist/types/index.d.ts", 9 | "author": "Trust ", 10 | "license": "MIT", 11 | "sideEffects": false, 12 | "files": [ 13 | "dist" 14 | ], 15 | "scripts": { 16 | "build:clean": "rm -rf dist", 17 | "build:types": "tsc", 18 | "build:source": "bun build:clean; rollup --config ./rollup.config.js; bun run build:types", 19 | "dev": "bun build ./index.ts --outdir ./dist --watch" 20 | }, 21 | "dependencies": { 22 | "@solana/wallet-standard-features": "1.2.0", 23 | "@solana/web3.js": "1.91.8", 24 | "@wallet-standard/base": "1.1.0", 25 | "@wallet-standard/features": "1.0.3", 26 | "bs58": "4.0.1", 27 | "@trustwallet/web3-provider-core": "workspace:*", 28 | "rpc-websockets": "7.11.0" 29 | }, 30 | "devDependencies": { 31 | "@types/bs58": "^4.0.1" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/solana/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { name, dependencies } from './package.json'; 2 | import createConfig from '../../rollup.config'; 3 | 4 | export default createConfig(name, Object.keys(dependencies)); 5 | -------------------------------------------------------------------------------- /packages/solana/tests/SolanaProvider.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect, jest, afterEach } from 'bun:test'; 2 | import { Web3Provider } from '@trustwallet/web3-provider-core'; 3 | import { SolanaProvider } from '../SolanaProvider'; 4 | import { AdapterStrategy } from '@trustwallet/web3-provider-core/adapter/Adapter'; 5 | import { window } from './mocks/window'; 6 | import { IHandlerParams } from '@trustwallet/web3-provider-core/adapter/CallbackAdapter'; 7 | import { 8 | PublicKey, 9 | SystemProgram, 10 | Transaction, 11 | VersionedTransaction, 12 | } from '@solana/web3.js'; 13 | import { StandardConnect } from '@wallet-standard/features'; 14 | import { 15 | SolanaSignMessage, 16 | SolanaSignTransaction, 17 | } from '@solana/wallet-standard-features'; 18 | 19 | // Mock window to allow solana adapter to work 20 | global.window = window; 21 | 22 | let Solana = new SolanaProvider(); 23 | const account = '3z9vL1zjN6qyAFHhHQdWYRTFAcy69pJydkZmSFBKHg1R'; 24 | const signature = 25 | '5LrcE2f6uvydKRquEJ8xp19heGxSvqsVbcqUeFoiWbXe8JNip7ftPQNTAVPyTK7ijVdpkzmKKaAQR7MWMmujAhXD'; 26 | 27 | function transaction() { 28 | const accountPublicKey = new PublicKey(account); 29 | const transaction = new Transaction().add( 30 | SystemProgram.transfer({ 31 | fromPubkey: accountPublicKey, 32 | toPubkey: accountPublicKey, 33 | lamports: 100, 34 | }), 35 | ); 36 | 37 | transaction.feePayer = accountPublicKey; 38 | transaction.recentBlockhash = '6VdVbpsv7b5cSekEimjMTddydrikUsbeXQcizEk6LqSn'; 39 | 40 | return transaction; 41 | } 42 | 43 | afterEach(() => { 44 | Solana = new SolanaProvider(); 45 | }); 46 | 47 | test('Solana Provider → connect -> payload is correct', async () => { 48 | const handler = jest.fn((_params: IHandlerParams) => 49 | Promise.resolve([account]), 50 | ); 51 | 52 | new Web3Provider({ 53 | strategy: AdapterStrategy.PROMISES, 54 | handler: handler, 55 | }).registerProvider(Solana); 56 | 57 | await window.wallet.features[StandardConnect].connect(); 58 | 59 | //await Solana.getInstanceWithAdapter().connect(); 60 | 61 | expect(handler).toHaveBeenCalledWith( 62 | expect.objectContaining({ 63 | name: 'requestAccounts', 64 | network: 'solana', 65 | }), 66 | ); 67 | }); 68 | 69 | test('Solana Provider → signMessage -> payload is correct', async () => { 70 | const handler = jest.fn((_params: IHandlerParams) => 71 | Promise.resolve([account]), 72 | ); 73 | 74 | new Web3Provider({ 75 | strategy: AdapterStrategy.PROMISES, 76 | handler: handler, 77 | }).registerProvider(Solana); 78 | 79 | const accountConnect = await window.wallet.features[ 80 | StandardConnect 81 | ].connect(); 82 | 83 | await window.wallet.features[SolanaSignMessage].signMessage({ 84 | account: accountConnect.accounts[0], 85 | message: Buffer.from('Random message'), 86 | }); 87 | 88 | expect(handler).toHaveBeenCalledWith( 89 | expect.objectContaining({ 90 | name: 'signMessage', 91 | network: 'solana', 92 | params: { 93 | data: `0x${Buffer.from('Random message').toString('hex')}`, 94 | }, 95 | }), 96 | ); 97 | }); 98 | 99 | test('Solana Provider → signTransaction -> payload is correct for legacy', async () => { 100 | const handler = jest.fn((_params: IHandlerParams) => { 101 | if (_params.name === 'requestAccounts') { 102 | return Promise.resolve([account]); 103 | } else { 104 | return Promise.resolve(signature); 105 | } 106 | }); 107 | 108 | const transactionPayload = transaction(); 109 | 110 | new Web3Provider({ 111 | strategy: AdapterStrategy.PROMISES, 112 | handler: handler, 113 | }).registerProvider(Solana); 114 | 115 | const accountConnect = await window.wallet.features[ 116 | StandardConnect 117 | ].connect(); 118 | 119 | await window.wallet.features[SolanaSignTransaction].signTransaction({ 120 | account: accountConnect.accounts[0], 121 | transaction: transactionPayload.serialize({ verifySignatures: false }), 122 | }); 123 | 124 | expect(handler).toHaveBeenNthCalledWith( 125 | 2, 126 | expect.objectContaining({ 127 | name: 'signRawTransaction', 128 | network: 'solana', 129 | params: expect.objectContaining({ 130 | raw: Buffer.from( 131 | transactionPayload.serialize({ 132 | requireAllSignatures: false, 133 | verifySignatures: false, 134 | }), 135 | ).toString('base64'), 136 | 137 | rawMessage: Buffer.from(transactionPayload.serializeMessage()).toString( 138 | 'base64', 139 | ), 140 | 141 | version: 'legacy', 142 | 143 | data: JSON.stringify( 144 | VersionedTransaction.deserialize( 145 | transactionPayload.serialize({ verifySignatures: false }), 146 | ), 147 | ), 148 | }), 149 | }), 150 | ); 151 | }); 152 | -------------------------------------------------------------------------------- /packages/solana/tests/mocks/window.ts: -------------------------------------------------------------------------------- 1 | import { TrustWallet } from '../../adapter/wallet'; 2 | export let provider = null; 3 | 4 | export const window = { 5 | wallet: null, 6 | 7 | dispatchEvent: (event: Event) => { 8 | const $this = window; 9 | 10 | // Mock wallet standard registration system to window object 11 | if (event.type === 'wallet-standard:register-wallet') { 12 | (event as any).detail({ 13 | register: (wallet: TrustWallet) => { 14 | $this.wallet = wallet; 15 | }, 16 | }); 17 | } 18 | 19 | return true; 20 | }, 21 | 22 | addEventListener: () => {}, 23 | } as unknown as Window & typeof globalThis & { wallet: TrustWallet }; 24 | -------------------------------------------------------------------------------- /packages/solana/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "exclude": ["package.json", "rollup.config.js", "tsconfig.json", "tests", "./dist"], 4 | "compilerOptions": { 5 | "rootDir": "./", 6 | "outDir": "./dist/types", 7 | "emitDeclarationOnly": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/solana/types/SolanaProvider.ts: -------------------------------------------------------------------------------- 1 | import { 2 | SolanaSignInInput, 3 | SolanaSignInOutput, 4 | } from '@solana/wallet-standard-features'; 5 | import { 6 | PublicKey, 7 | Transaction, 8 | VersionedTransaction, 9 | SendOptions, 10 | TransactionSignature, 11 | } from '@solana/web3.js'; 12 | import { TrustEventEmitter } from '../adapter/window'; 13 | import { TrustWallet } from '../adapter/wallet'; 14 | 15 | export interface ISolanaProviderConfig { 16 | isTrust?: boolean; 17 | enableAdapter?: boolean; 18 | cluster?: string; 19 | disableMobileAdapter?: boolean; 20 | useLegacySign?: boolean; 21 | } 22 | 23 | export interface ConnectOptions { 24 | onlyIfTrusted?: boolean | undefined; 25 | } 26 | 27 | export default interface ISolanaProvider extends TrustEventEmitter { 28 | publicKey: PublicKey | null; 29 | connect(options?: { 30 | onlyIfTrusted?: boolean; 31 | }): Promise<{ publicKey: PublicKey }>; 32 | disconnect(): Promise; 33 | signAndSendTransaction( 34 | transaction: T, 35 | options?: SendOptions, 36 | ): Promise<{ signature: TransactionSignature }>; 37 | signTransaction( 38 | transaction: T, 39 | ): Promise; 40 | signAllTransactions( 41 | transactions: T[], 42 | ): Promise; 43 | signMessage(message: Uint8Array): Promise<{ signature: Uint8Array }>; 44 | signIn(input?: SolanaSignInInput): Promise; 45 | getInstanceWithAdapter(): TrustWallet; 46 | } 47 | -------------------------------------------------------------------------------- /packages/solana/util.ts: -------------------------------------------------------------------------------- 1 | // This is copied from @wallet-standard/wallet 2 | 3 | export function bytesEqual(a: Uint8Array, b: Uint8Array): boolean { 4 | return arraysEqual(a, b); 5 | } 6 | 7 | interface Indexed { 8 | length: number; 9 | [index: number]: T; 10 | } 11 | 12 | export function arraysEqual(a: Indexed, b: Indexed): boolean { 13 | if (a === b) return true; 14 | 15 | const length = a.length; 16 | if (length !== b.length) return false; 17 | 18 | for (let i = 0; i < length; i++) { 19 | if (a[i] !== b[i]) return false; 20 | } 21 | 22 | return true; 23 | } 24 | -------------------------------------------------------------------------------- /packages/ton/README.md: -------------------------------------------------------------------------------- 1 | # Trust Web3 Provider 2 | 3 | ``` 4 | ___ ___ ___ 5 | /\ \ /\ \ /\__\ 6 | \:\ \ /::\ \ /:| _|_ 7 | /::\__\ /:/\:\__\ /::|/\__\ 8 | /:/\/__/ \:\/:/ / \/|::/ / 9 | \/__/ \::/ / |:/ / 10 | \/__/ \/__/ 11 | ``` 12 | 13 | ### Ton JavaScript Provider Implementation 14 | 15 | ### Config Object 16 | 17 | ```typescript 18 | const config: { 19 | isTrust?: boolean; 20 | disableMobileAdapter?: boolean; 21 | version?: string; 22 | } = {}; 23 | ``` 24 | 25 | ### Usage 26 | 27 | ```typescript 28 | const ton = new TonProvider(config); 29 | ``` 30 | 31 | ### Bridge usage 32 | 33 | ```typescript 34 | const bridgeConfig: { 35 | isWalletBrowser: boolean; 36 | walletInfo: WalletInfo; 37 | deviceInfo: DeviceInfo; 38 | } = {}; 39 | 40 | const bridge = new TonBridge(ton, bridgeConfig); 41 | ``` 42 | -------------------------------------------------------------------------------- /packages/ton/TonProvider.ts: -------------------------------------------------------------------------------- 1 | import { BaseProvider } from '@trustwallet/web3-provider-core'; 2 | import type ITonProvider from './types/TonProvider'; 3 | import type { ITonProviderConfig } from './types/TonProvider'; 4 | import { MobileAdapter } from './MobileAdapter'; 5 | 6 | export class TonProvider extends BaseProvider implements ITonProvider { 7 | static NETWORK = 'ton'; 8 | private mobileAdapter!: MobileAdapter; 9 | 10 | version = 'v4R2'; 11 | 12 | constructor(config?: ITonProviderConfig) { 13 | super(); 14 | 15 | if (config) { 16 | if (config.version) { 17 | this.version = config.version; 18 | } 19 | } 20 | 21 | if (!config?.disableMobileAdapter) { 22 | this.mobileAdapter = new MobileAdapter(this); 23 | } 24 | } 25 | 26 | disconnect() { 27 | return this.send('tonConnect_disconnect', {}); 28 | } 29 | 30 | isConnected(): Promise { 31 | return Promise.resolve(true); 32 | } 33 | 34 | async send(method: string, params?: unknown[] | object): Promise { 35 | const next = () => { 36 | return this.internalRequest(method, params) as Promise; 37 | }; 38 | 39 | if (this.mobileAdapter) { 40 | return await this.mobileAdapter.request(method, params); 41 | } 42 | 43 | return await next(); 44 | } 45 | 46 | internalRequest( 47 | method: string, 48 | params: object | unknown[] | undefined, 49 | ): Promise { 50 | return super.request({ 51 | method, 52 | params, 53 | }); 54 | } 55 | 56 | getNetwork(): string { 57 | return TonProvider.NETWORK; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /packages/ton/exceptions/RPCError.ts: -------------------------------------------------------------------------------- 1 | export class RPCError extends Error { 2 | code: number; 3 | 4 | constructor(code: number, message: string) { 5 | super(); 6 | this.code = code; 7 | this.message = message; 8 | } 9 | 10 | toString() { 11 | return `${this.message} (${this.code})`; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/ton/exceptions/TonConnectError.ts: -------------------------------------------------------------------------------- 1 | export class TonConnectError extends Error { 2 | code?: number; 3 | 4 | constructor(message: string, code?: number) { 5 | super(message); 6 | this.code = code; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/ton/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TonProvider'; 2 | export * from './TonBridge'; 3 | -------------------------------------------------------------------------------- /packages/ton/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@trustwallet/web3-provider-ton", 3 | "version": "4.0.0", 4 | "type": "module", 5 | "main": "dist/index.cjs.js", 6 | "module": "dist/index.es.js", 7 | "unpkg": "dist/index.umd.js", 8 | "types": "dist/types/index.d.ts", 9 | "author": "Trust ", 10 | "license": "MIT", 11 | "sideEffects": false, 12 | "files": [ 13 | "dist" 14 | ], 15 | "scripts": { 16 | "build:clean": "rm -rf dist", 17 | "build:types": "tsc", 18 | "build:source": "bun build:clean; rollup --config ./rollup.config.js; bun run build:types", 19 | "dev": "bun build ./index.ts --outdir ./dist --watch" 20 | }, 21 | "peerDependencies": {}, 22 | "dependencies": { 23 | "@ton/crypto": "3.3.0", 24 | "@ton/ton": "15.1.0", 25 | "@trustwallet/web3-provider-core": "workspace:*" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/ton/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { name, dependencies } from './package.json'; 2 | import createConfig from '../../rollup.config'; 3 | 4 | export default createConfig(name, Object.keys(dependencies)); 5 | -------------------------------------------------------------------------------- /packages/ton/tests/TonProvider.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect, jest, afterEach } from 'bun:test'; 2 | import { Web3Provider } from '@trustwallet/web3-provider-core'; 3 | import { TonProvider } from '../TonProvider'; 4 | import { AdapterStrategy } from '@trustwallet/web3-provider-core/adapter/Adapter'; 5 | import { IHandlerParams } from '@trustwallet/web3-provider-core/adapter/CallbackAdapter'; 6 | 7 | let Ton = new TonProvider(); 8 | const account = 9 | '0:d4d9dc4b9024a4be47b8b35b02d24c679faf2d3d139c16462f9a6c34b8694cc0'; 10 | 11 | afterEach(() => { 12 | Ton = new TonProvider(); 13 | }); 14 | 15 | test('Ton Connect → tonConnect_connect', async () => { 16 | new Web3Provider({ 17 | strategy: AdapterStrategy.PROMISES, 18 | handler: () => Promise.resolve(JSON.stringify([{ address: account }])), 19 | }).registerProvider(Ton); 20 | 21 | const accounts = await Ton.send('tonConnect_connect'); 22 | expect(accounts).toEqual([{ address: account }]); 23 | }); 24 | 25 | test('Ton Connect → tonConnect_connect → mobile adapter', async () => { 26 | const handler = jest.fn((_params: IHandlerParams) => 27 | Promise.resolve(JSON.stringify([{ address: account }])), 28 | ); 29 | 30 | new Web3Provider({ 31 | strategy: AdapterStrategy.PROMISES, 32 | handler, 33 | }).registerProvider(Ton); 34 | 35 | await Ton.send('tonConnect_connect'); 36 | 37 | expect(handler).toHaveBeenCalledWith( 38 | expect.objectContaining({ name: 'requestAccounts' }), 39 | ); 40 | }); 41 | 42 | test('Ton Connect → ton_rawSign', async () => { 43 | const handler = jest.fn((_params: IHandlerParams) => 44 | Promise.resolve(JSON.stringify([{ address: account }])), 45 | ); 46 | 47 | new Web3Provider({ 48 | strategy: AdapterStrategy.PROMISES, 49 | handler, 50 | }).registerProvider(Ton); 51 | 52 | await Ton.send('ton_rawSign', { message: '123' }); 53 | 54 | expect(handler).toHaveBeenCalledWith( 55 | expect.objectContaining({ 56 | name: 'signMessage', 57 | object: { message: '123' }, 58 | }), 59 | ); 60 | }); 61 | 62 | test('Ton Connect → ton_sendTransaction', async () => { 63 | const handler = jest.fn((_params: IHandlerParams) => 64 | Promise.resolve(JSON.stringify([{ name: 'ton_addr', address: account }])), 65 | ); 66 | 67 | new Web3Provider({ 68 | strategy: AdapterStrategy.PROMISES, 69 | handler, 70 | }).registerProvider(Ton); 71 | 72 | await Ton.send('tonConnect_connect'); 73 | await Ton.send('ton_sendTransaction', [ 74 | { network: '-239', messages: [], from: account, valid_until: 124 }, 75 | ]); 76 | 77 | expect(handler).toHaveBeenCalledWith( 78 | expect.objectContaining({ 79 | name: 'signTransaction', 80 | object: { 81 | network: '-239', 82 | messages: [], 83 | from: account, 84 | valid_until: 124, 85 | }, 86 | }), 87 | ); 88 | }); 89 | 90 | test('Ton Connect → tonConnect_sendTransaction', async () => { 91 | const handler = jest.fn((_params: IHandlerParams) => 92 | Promise.resolve(JSON.stringify([{ name: 'ton_addr', address: account }])), 93 | ); 94 | 95 | new Web3Provider({ 96 | strategy: AdapterStrategy.PROMISES, 97 | handler, 98 | }).registerProvider(Ton); 99 | 100 | await Ton.send('tonConnect_connect'); 101 | await Ton.send('tonConnect_sendTransaction', [ 102 | { network: '-239', messages: [], from: account, valid_until: 124 }, 103 | ]); 104 | 105 | expect(handler).toHaveBeenCalledWith( 106 | expect.objectContaining({ 107 | name: 'signTransaction', 108 | object: { 109 | network: '-239', 110 | messages: [], 111 | from: account, 112 | valid_until: 124, 113 | }, 114 | }), 115 | ); 116 | }); 117 | 118 | test('Ton Connect → ton_requestAccounts', async () => { 119 | const handler = jest.fn((_params: IHandlerParams) => 120 | Promise.resolve(JSON.stringify([{ nonBounceable: account }])), 121 | ); 122 | 123 | new Web3Provider({ 124 | strategy: AdapterStrategy.PROMISES, 125 | handler, 126 | }).registerProvider(Ton); 127 | 128 | const res = await Ton.send('ton_requestAccounts'); 129 | 130 | expect(res).toEqual([account]); 131 | 132 | expect(handler).toHaveBeenCalledWith( 133 | expect.objectContaining({ 134 | name: 'requestAccounts', 135 | }), 136 | ); 137 | }); 138 | 139 | test('Ton Connect → ton_requestWallets', async () => { 140 | const handler = jest.fn((_params: IHandlerParams) => 141 | Promise.resolve(JSON.stringify([{ nonBounceable: account }])), 142 | ); 143 | 144 | new Web3Provider({ 145 | strategy: AdapterStrategy.PROMISES, 146 | handler, 147 | }).registerProvider(Ton); 148 | 149 | const res = await Ton.send('ton_requestWallets'); 150 | 151 | expect(res).toEqual([{ address: account, version: 'v4R2' }]); 152 | 153 | expect(handler).toHaveBeenCalledWith( 154 | expect.objectContaining({ 155 | name: 'requestAccounts', 156 | }), 157 | ); 158 | }); 159 | -------------------------------------------------------------------------------- /packages/ton/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "exclude": ["package.json", "rollup.config.js", "tsconfig.json", "tests", "./dist"], 4 | "compilerOptions": { 5 | "rootDir": "./", 6 | "outDir": "./dist/types", 7 | "emitDeclarationOnly": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/ton/types/TonBridge.ts: -------------------------------------------------------------------------------- 1 | enum NETWORK { 2 | MAINNET = '-239', 3 | TESTNET = '-3', 4 | } 5 | 6 | type Feature = 7 | | { name: 'SendTransaction'; maxMessages: number } // `maxMessages` is maximum number of messages in one `SendTransaction` that the wallet supports 8 | | { name: 'SignData' }; 9 | 10 | export type DeviceInfo = { 11 | platform: 'iphone' | 'ipad' | 'android' | 'windows' | 'mac' | 'linux'; 12 | appName: string; // e.g. "Tonkeeper" 13 | appVersion: string; // e.g. "2.3.367" 14 | maxProtocolVersion: number; 15 | features: Feature[]; // list of supported features and methods in RPC 16 | // Currently there is only one feature -- 'SendTransaction'; 17 | }; 18 | 19 | export interface WalletInfo { 20 | name: string; 21 | image: string; 22 | tondns?: string; 23 | about_url: string; 24 | } 25 | 26 | export type ConnectRequest = { 27 | manifestUrl: string; 28 | items: ConnectItem[]; // data items to share with the app 29 | }; 30 | 31 | type ConnectItem = TonAddressItem | TonProofItem; 32 | 33 | type TonAddressItem = { 34 | name: 'ton_addr'; 35 | }; 36 | 37 | type TonProofItem = { 38 | name: 'ton_proof'; 39 | payload: string; // arbitrary payload, e.g. nonce + expiration timestamp. 40 | }; 41 | 42 | // Untrusted data returned by the wallet. 43 | // If you need a guarantee that the user owns this address and public key, you need to additionally request a ton_proof. 44 | export type TonAddressItemReply = { 45 | name: 'ton_addr'; 46 | address: string; // TON address raw (`0:`) 47 | network: NETWORK; // network global_id 48 | publicKey: string; // HEX string without 0x 49 | walletStateInit: string; // Base64 (not url safe) encoded state init cell for the wallet contract 50 | }; 51 | 52 | type TonProofItemReply = TonProofItemReplySuccess | TonProofItemReplyError; 53 | 54 | export type TonProofItemReplySuccess = { 55 | name: 'ton_proof'; 56 | proof: { 57 | timestamp: string; // 64-bit unix epoch time of the signing operation (seconds) 58 | domain: { 59 | lengthBytes: number; // AppDomain Length 60 | value: string; // app domain name (as url part, without encoding) 61 | }; 62 | signature: string; // base64-encoded signature 63 | payload: string; // payload from the request 64 | }; 65 | }; 66 | 67 | type TonProofItemReplyError = { 68 | name: 'ton_addr'; 69 | error: { 70 | code: number; 71 | message?: string; 72 | }; 73 | }; 74 | 75 | export type ConnectItemReply = TonAddressItemReply | TonProofItemReply; 76 | 77 | type ConnectEventSuccess = { 78 | event: 'connect'; 79 | id: number; 80 | payload: { 81 | items: ConnectItemReply[]; 82 | device: DeviceInfo; 83 | }; 84 | }; 85 | 86 | export type ConnectEventError = { 87 | event: 'connect_error'; 88 | id: number; 89 | payload: { 90 | code: number; 91 | message: string; 92 | }; 93 | }; 94 | 95 | export type ConnectEvent = ConnectEventSuccess | ConnectEventError; 96 | 97 | export type WalletResponse = WalletResponseSuccess | WalletResponseError; 98 | 99 | interface WalletResponseSuccess { 100 | result: string; 101 | id: string; 102 | } 103 | 104 | export interface WalletResponseError { 105 | error: { code: number; message: string; data?: unknown }; 106 | id: string; 107 | } 108 | 109 | export interface WalletEvent { 110 | event: WalletEventName; 111 | id?: string; 112 | payload: any; 113 | } 114 | 115 | type WalletEventName = 'connect' | 'connect_error' | 'disconnect'; 116 | 117 | export interface AppRequest { 118 | method: string; 119 | params: string[]; 120 | id: string; 121 | } 122 | 123 | export type TonConnectCallback = (event: WalletEvent) => void; 124 | 125 | export interface ITonBridgeConfig { 126 | isWalletBrowser: boolean; 127 | walletInfo: WalletInfo; 128 | deviceInfo: DeviceInfo; 129 | } 130 | 131 | export interface TonConnectBridge { 132 | deviceInfo: DeviceInfo; 133 | walletInfo?: WalletInfo; 134 | protocolVersion: number; 135 | isWalletBrowser: boolean; 136 | connect( 137 | protocolVersion: number, 138 | message: ConnectRequest, 139 | ): Promise; 140 | restoreConnection(): Promise; 141 | send(message: AppRequest): Promise; 142 | listen(callback: (event: WalletEvent) => void): () => void; 143 | } 144 | -------------------------------------------------------------------------------- /packages/ton/types/TonProvider.ts: -------------------------------------------------------------------------------- 1 | export interface ITonProviderConfig { 2 | isTrust?: boolean; 3 | disableMobileAdapter?: boolean; 4 | version?: string; 5 | } 6 | 7 | export default interface ITonProvider { 8 | isConnected(): Promise; 9 | send(method: string, params?: unknown[] | object): Promise; 10 | } 11 | -------------------------------------------------------------------------------- /packages/tron/TronProvider.ts: -------------------------------------------------------------------------------- 1 | import { BaseProvider } from '@trustwallet/web3-provider-core'; 2 | import type ITronProvider from './types/TronProvider'; 3 | import type { ITronProviderConfig } from './types/TronProvider'; 4 | import { TronWeb } from 'tronweb'; 5 | import { SignedTransaction, Transaction } from 'tronweb/lib/esm/types'; 6 | 7 | interface IRequestArguments { 8 | readonly method: string; 9 | readonly params?: unknown[] | object; 10 | } 11 | 12 | export class TronProvider extends BaseProvider implements ITronProvider { 13 | static NETWORK = 'tron'; 14 | 15 | ready = false; 16 | 17 | tronWeb!: TronWeb; 18 | 19 | #config!: ITronProviderConfig; 20 | 21 | #node!: string; 22 | 23 | constructor(config?: ITronProviderConfig) { 24 | super(); 25 | 26 | if (config) { 27 | this.#config = config; 28 | } 29 | 30 | this.on('accountsChanged', (accounts: string[]) => { 31 | if (accounts.length === 0) { 32 | window.postMessage( 33 | { 34 | message: { 35 | action: 'disconnect', 36 | data: {}, 37 | }, 38 | }, 39 | '*', 40 | ); 41 | } else { 42 | this.tronWeb.setAddress(accounts[0]); 43 | window.postMessage( 44 | { 45 | message: { 46 | action: 'accountsChanged', 47 | data: { 48 | address: accounts[0], 49 | }, 50 | }, 51 | }, 52 | '*', 53 | ); 54 | } 55 | }); 56 | } 57 | 58 | getNetwork(): string { 59 | return TronProvider.NETWORK; 60 | } 61 | 62 | #internalRequest(args: IRequestArguments): Promise { 63 | return super.request(args); 64 | } 65 | 66 | request(args: IRequestArguments): Promise { 67 | const { method, params } = args; 68 | 69 | switch (method) { 70 | case 'tron_requestAccounts': 71 | return this.#requestAccounts(); 72 | } 73 | 74 | return Promise.resolve(null); 75 | } 76 | 77 | setNode(url: string) { 78 | this.#node = url; 79 | this.tronWeb = new TronWeb({ fullHost: url }); 80 | } 81 | 82 | async signMessage() { 83 | throw new Error('Not implemented signMessage'); 84 | } 85 | 86 | async signMessageV2( 87 | data: string | Uint8Array | Array, 88 | ): Promise { 89 | return await this.#internalRequest({ 90 | method: 'signMessage', 91 | params: { 92 | data, 93 | isEthSign: false, 94 | }, 95 | }); 96 | } 97 | 98 | async sign( 99 | transaction: T, 100 | ): Promise { 101 | if (typeof transaction === 'object') { 102 | const result = await this.#internalRequest({ 103 | method: 'signTransaction', 104 | params: { 105 | transaction, 106 | raw: false, 107 | }, 108 | }); 109 | 110 | return result; 111 | } else if (typeof transaction === 'string') { 112 | return this.signMessageV2(transaction); 113 | } else { 114 | console.error('tx is not an object'); 115 | throw new Error('Invalid TX format'); 116 | } 117 | } 118 | 119 | async signTransactionOffline() { 120 | console.log('signTransactionOffline CALLED'); 121 | } 122 | 123 | async #requestAccounts() { 124 | try { 125 | const accounts = await this.#internalRequest({ 126 | method: 'requestAccounts', 127 | params: {}, 128 | }); 129 | 130 | if (accounts) { 131 | this.ready = true; 132 | 133 | this.tronWeb.trx.signMessageV2 = this.signMessageV2.bind(this) as any; 134 | this.tronWeb.trx.sign = this.sign.bind(this); 135 | 136 | this.tronWeb.setAddress(accounts[0]); 137 | 138 | window.postMessage( 139 | { 140 | message: { 141 | action: 'connect', 142 | data: {}, 143 | }, 144 | }, 145 | '*', 146 | ); 147 | 148 | return { code: 200 }; 149 | } 150 | } catch (e) { 151 | console.error(e); 152 | 153 | return { code: 4001 }; 154 | } 155 | } 156 | 157 | connect() { 158 | return this.#requestAccounts(); 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /packages/tron/exceptions/RPCError.ts: -------------------------------------------------------------------------------- 1 | export class RPCError extends Error { 2 | code: number; 3 | 4 | constructor(code: number, message: string) { 5 | super(); 6 | this.code = code; 7 | this.message = message; 8 | } 9 | 10 | toString() { 11 | return `${this.message} (${this.code})`; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/tron/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TronProvider'; 2 | -------------------------------------------------------------------------------- /packages/tron/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@trustwallet/web3-provider-tron", 3 | "version": "4.0.0", 4 | "type": "module", 5 | "main": "dist/index.cjs.js", 6 | "module": "dist/index.es.js", 7 | "unpkg": "dist/index.umd.js", 8 | "types": "dist/types/index.d.ts", 9 | "author": "Trust ", 10 | "license": "MIT", 11 | "sideEffects": false, 12 | "files": [ 13 | "dist" 14 | ], 15 | "scripts": { 16 | "build:clean": "rm -rf dist", 17 | "build:types": "tsc", 18 | "build:source": "bun build:clean; rollup --config ./rollup.config.js; bun run build:types", 19 | "dev": "bun build ./index.ts --outdir ./dist --watch" 20 | }, 21 | "dependencies": { 22 | "tronweb": "6.0.1" 23 | }, 24 | "devDependencies": { 25 | "@trustwallet/web3-provider-core": "workspace:*" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/tron/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { name, dependencies } from './package.json'; 2 | import createConfig from '../../rollup.config'; 3 | 4 | export default createConfig(name, Object.keys(dependencies)); 5 | -------------------------------------------------------------------------------- /packages/tron/tests/TronProvider.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect, jest, afterEach } from 'bun:test'; 2 | import { Web3Provider } from '@trustwallet/web3-provider-core'; 3 | import { TronProvider } from '../TronProvider'; 4 | import { AdapterStrategy } from '@trustwallet/web3-provider-core/adapter/Adapter'; 5 | 6 | let Tron = new TronProvider(); 7 | const account = '0x0000000000000000000000000000000000000000'; 8 | 9 | afterEach(() => { 10 | Tron = new TronProvider(); 11 | Tron.setNode('https://foo.baz'); 12 | }); 13 | 14 | // Direct methods 15 | test('Tron Awesome test', async () => { 16 | new Web3Provider({ 17 | strategy: AdapterStrategy.PROMISES, 18 | handler: () => Promise.resolve([account]), 19 | }).registerProvider(Tron); 20 | 21 | const accounts = await Tron.request({ 22 | method: 'tron_requestAccounts', 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /packages/tron/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "exclude": ["package.json", "rollup.config.js", "tsconfig.json", "tests", "./dist"], 4 | "compilerOptions": { 5 | "rootDir": "./", 6 | "outDir": "./dist/types", 7 | "emitDeclarationOnly": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/tron/types/TronProvider.ts: -------------------------------------------------------------------------------- 1 | export interface ITronProviderConfig { 2 | isTrust?: boolean; 3 | nodeURL: string; 4 | } 5 | 6 | export default interface ITronProvider {} 7 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import esbuild from 'rollup-plugin-esbuild'; 2 | import { nodeResolve } from '@rollup/plugin-node-resolve'; 3 | import commonjs from '@rollup/plugin-commonjs'; 4 | import json from '@rollup/plugin-json'; 5 | 6 | const input = './index.ts'; 7 | const plugins = [ 8 | json(), 9 | nodeResolve({ preferBuiltins: false, browser: true }), 10 | commonjs(), 11 | esbuild({ 12 | minify: true, 13 | tsconfig: './tsconfig.json', 14 | loaders: { 15 | '.json': 'json', 16 | }, 17 | }), 18 | ]; 19 | 20 | export default function createConfig( 21 | packageName, 22 | packageDependencies, 23 | umd = {}, 24 | cjs = {}, 25 | es = {}, 26 | ) { 27 | return [ 28 | { 29 | input, 30 | plugins, 31 | output: { 32 | file: './dist/index.umd.js', 33 | format: 'umd', 34 | exports: 'named', 35 | name: packageName, 36 | sourcemap: true, 37 | ...umd, 38 | }, 39 | }, 40 | { 41 | input, 42 | plugins, 43 | external: packageDependencies, 44 | output: [ 45 | { 46 | file: './dist/index.cjs.js', 47 | format: 'cjs', 48 | exports: 'named', 49 | name: packageName, 50 | sourcemap: true, 51 | ...cjs, 52 | }, 53 | { 54 | file: './dist/index.es.js', 55 | format: 'es', 56 | exports: 'named', 57 | name: packageName, 58 | sourcemap: true, 59 | ...es, 60 | }, 61 | ], 62 | }, 63 | ]; 64 | } 65 | -------------------------------------------------------------------------------- /scripts/build.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs'; 2 | import * as path from 'path'; 3 | import { execSync } from 'child_process'; 4 | 5 | const subpackagesDir = path.resolve(__dirname, '../packages'); 6 | 7 | const directories = fs 8 | .readdirSync(subpackagesDir, { withFileTypes: true }) 9 | .filter((dirent) => dirent.isDirectory()) 10 | .map((dirent) => dirent.name); 11 | 12 | directories.forEach((directory) => { 13 | const dirPath = path.join(subpackagesDir, directory); 14 | 15 | console.log(`Building ${directory}`); 16 | 17 | try { 18 | execSync('bun run build:source', { stdio: 'inherit', cwd: dirPath }); 19 | console.log(`Built ${directory}`); 20 | } catch (error) { 21 | console.error(`Failed to build ${directory}`); 22 | console.error(error); 23 | } 24 | }); 25 | -------------------------------------------------------------------------------- /scripts/generate.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import { mkdir, rm, readdir } from 'node:fs/promises'; 3 | import { execSync } from 'child_process'; 4 | 5 | const subpackagesDir = path.resolve(__dirname, '../packages'); 6 | const chainName = (process.argv[2] || '').toLowerCase(); 7 | 8 | if (!chainName) { 9 | throw new Error('Please enter a chain name'); 10 | } 11 | 12 | async function generate() { 13 | console.log(` 14 | ___ ___ ___ 15 | ___ / /\\ / /\\ / /\\ ___ 16 | /__/\\ / /::\\ / /:/ / /::\\ /__/\\ 17 | \\ \\:\\ / /:/\\:\\ / /:/ /__/:/\\:\\ \\ \\:\\ 18 | \\__\\:\\ / /::\\ \\:\\ / /:/ _\\_ \\:\\ \\:\\ \\__\\:\\ 19 | / /::\\ /__/:/\\:\\_\\:\\ /__/:/ /\\ /__/\\ \\:\\ \\:\\ / /::\\ 20 | / /:/\\:\\ \\__\\/~|::\\/:/ \\ \\:\\ /:/ \\ \\:\\ \\:\\_\\/ / /:/\\:\\ 21 | / /:/__\\/ | |:|::/ \\ \\:\\ /:/ \\ \\:\\_\\:\\ / /:/__\\/ 22 | /__/:/ | |:|\\/ \\ \\:\\/:/ \\ \\:\\/:/ /__/:/ 23 | \\__\\/ |__|:|~ \\ \\::/ \\ \\::/ \\__\\/ 24 | \\__\\| \\__\\/ \\__\\/ 25 | 26 | \n\n 27 | Generating a new chain provider.... 28 | `); 29 | 30 | const base = path.join(subpackagesDir, chainName); 31 | // check if already exists 32 | try { 33 | await readdir(base); 34 | console.error(`Oops, directory ${base} already exists, aborting`); 35 | return; 36 | } catch {} 37 | 38 | try { 39 | // Generate new dir, fails if already exists 40 | const folders = ['tests', 'exceptions', 'types']; 41 | await mkdir(base); 42 | await Promise.all( 43 | folders.map((folder) => 44 | mkdir(path.join(subpackagesDir, chainName, folder)), 45 | ), 46 | ); 47 | 48 | // Execute template generation 49 | execSync( 50 | `simple-scaffold -q \\ 51 | -t templates \\ 52 | -o packages/${chainName} \\ 53 | ${chainName.slice(0, 1).toUpperCase() + chainName.slice(1)} --log-level none`, 54 | { 55 | stdio: 'inherit', 56 | cwd: path.resolve(__dirname, '../'), 57 | }, 58 | ); 59 | 60 | console.log(`Boilerplate code generated for ${chainName} 🚀 Have Fun!`); 61 | } catch (e) { 62 | console.error(e); 63 | await rm(path.join(subpackagesDir, chainName), { 64 | recursive: true, 65 | force: true, 66 | }); 67 | } 68 | } 69 | 70 | generate(); 71 | -------------------------------------------------------------------------------- /scripts/link.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs'; 2 | import * as path from 'path'; 3 | import { execSync, exec } from 'child_process'; 4 | import { allowedPackages } from './packages'; 5 | 6 | const subpackagesDir = path.resolve(__dirname, '../packages'); 7 | 8 | const directories = fs 9 | .readdirSync(subpackagesDir, { withFileTypes: true }) 10 | .filter((dirent) => dirent.isDirectory()) 11 | .map((dirent) => dirent.name) 12 | .filter((name) => allowedPackages.includes(name)); 13 | 14 | let command = `npm link `; 15 | 16 | Promise.all( 17 | directories.map((directory) => { 18 | const dirPath = path.join(subpackagesDir, directory); 19 | 20 | console.log(`Building ${directory}`); 21 | 22 | try { 23 | execSync('bun build:clean', { stdio: 'inherit', cwd: dirPath }); 24 | exec('tsc -w', { cwd: dirPath }); 25 | exec('rollup --config ./rollup.config.js --watch', { 26 | cwd: dirPath, 27 | }); 28 | 29 | setTimeout( 30 | () => execSync('npm link --silent', { stdio: 'inherit', cwd: dirPath }), 31 | 2000, 32 | ); 33 | console.log(`Built ${directory}`); 34 | command += `@trustwallet/web3-provider-${directory} `; 35 | } catch (error) { 36 | console.error(`Failed to build ${directory}`); 37 | console.error(error); 38 | } 39 | }), 40 | ).then(() => console.warn(`\n\nUse the packages like this: \n\n${command}\n`)); 41 | -------------------------------------------------------------------------------- /scripts/packages.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * List of packages that are able to build and distribute 3 | */ 4 | export const allowedPackages = [ 5 | 'core', 6 | 'cosmos', 7 | 'ethereum', 8 | 'solana', 9 | 'aptos', 10 | 'ton', 11 | 'tron', 12 | ]; 13 | -------------------------------------------------------------------------------- /scripts/publish.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs'; 2 | import * as path from 'path'; 3 | import { execSync } from 'child_process'; 4 | import { allowedPackages } from './packages'; 5 | 6 | /** 7 | * Executes publish to npm 8 | */ 9 | const subpackagesDir = path.resolve(__dirname, '../packages'); 10 | 11 | const directories = fs 12 | .readdirSync(subpackagesDir, { withFileTypes: true }) 13 | .filter((dirent) => dirent.isDirectory()) 14 | .map((dirent) => dirent.name) 15 | .filter((name) => allowedPackages.includes(name)); 16 | 17 | directories.forEach((directory) => { 18 | const dirPath = path.join(subpackagesDir, directory); 19 | 20 | console.log(`Publishing ${directory}`); 21 | 22 | try { 23 | execSync(`npm publish --access public`, { 24 | stdio: 'inherit', 25 | cwd: dirPath, 26 | }); 27 | console.log(`Published ${directory}`); 28 | } catch (error) { 29 | console.error(`Failed to build ${directory}`); 30 | console.error(error); 31 | } 32 | }); 33 | -------------------------------------------------------------------------------- /scripts/rename.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs'; 2 | import * as path from 'path'; 3 | 4 | /** 5 | * Renames dependencies version for packages 6 | * and version in package.json 7 | */ 8 | const subpackagesDir = path.resolve(__dirname, '../packages'); 9 | const version = process.argv[2]; 10 | 11 | if (!version) { 12 | throw new Error('Invalid version'); 13 | } 14 | 15 | const directories = fs 16 | .readdirSync(subpackagesDir, { withFileTypes: true }) 17 | .filter((dirent) => dirent.isDirectory()) 18 | .map((dirent) => dirent.name); 19 | 20 | directories.forEach((directory) => { 21 | const dirPath = path.join(subpackagesDir, directory); 22 | const packageJson = path.join(dirPath, 'package.json'); 23 | const file = JSON.parse(fs.readFileSync(packageJson, 'utf-8')); 24 | 25 | file.version = version; 26 | 27 | if (directory !== 'core') { 28 | const update = (deps: any) => { 29 | if (deps) { 30 | Object.keys(deps).forEach((dep) => { 31 | if (deps[dep] === 'workspace:*') { 32 | deps[dep] = version; 33 | } 34 | }); 35 | } 36 | }; 37 | 38 | update(file.dependencies); 39 | } 40 | 41 | fs.writeFileSync(packageJson, JSON.stringify(file, null, 2)); 42 | }); 43 | -------------------------------------------------------------------------------- /templates/exceptions/RPCError.ts: -------------------------------------------------------------------------------- 1 | export class RPCError extends Error { 2 | code: number; 3 | 4 | constructor(code: number, message: string) { 5 | super(); 6 | this.code = code; 7 | this.message = message; 8 | } 9 | 10 | toString() { 11 | return `${this.message} (${this.code})`; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /templates/index.ts: -------------------------------------------------------------------------------- 1 | export * from './{{name}}Provider'; 2 | -------------------------------------------------------------------------------- /templates/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@trustwallet/web3-provider-{{camelCase name}}", 3 | "version": "4.0.0", 4 | "type": "module", 5 | "main": "dist/index.cjs.js", 6 | "module": "dist/index.es.js", 7 | "unpkg": "dist/index.umd.js", 8 | "types": "dist/types/index.d.ts", 9 | "author": "Trust ", 10 | "license": "MIT", 11 | "sideEffects": false, 12 | "files": [ 13 | "dist" 14 | ], 15 | "scripts": { 16 | "build:clean": "rm -rf dist", 17 | "build:types": "tsc", 18 | "build:source": "bun build:clean; rollup --config ./rollup.config.js; bun run build:types", 19 | "dev": "bun build ./index.ts --outdir ./dist --watch" 20 | }, 21 | "dependencies": { }, 22 | "devDependencies": { 23 | "@trustwallet/web3-provider-core": "workspace:*" 24 | } 25 | } -------------------------------------------------------------------------------- /templates/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { name, dependencies } from './package.json'; 2 | import createConfig from '../../rollup.config'; 3 | 4 | export default createConfig(name, Object.keys(dependencies)); 5 | -------------------------------------------------------------------------------- /templates/tests/{{ name }}Provider.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect, jest, afterEach } from 'bun:test'; 2 | import { Web3Provider } from '@trustwallet/web3-provider-core'; 3 | import { {{name}}Provider } from '../{{name}}Provider'; 4 | import { AdapterStrategy } from '@trustwallet/web3-provider-core/adapter/Adapter'; 5 | 6 | let {{name}} = new {{name}}Provider(); 7 | const account = '0x0000000000000000000000000000000000000000'; 8 | 9 | afterEach(() => { 10 | {{name}} = new {{name}}Provider(); 11 | }); 12 | 13 | // Direct methods 14 | test('{{name}} Awesome test', async () => { 15 | new Web3Provider({ 16 | strategy: AdapterStrategy.PROMISES, 17 | handler: () => Promise.resolve([account]), 18 | }).registerProvider({{name}}); 19 | 20 | const accounts = await {{name}}.request({ method: 'test_method' }); 21 | expect(accounts).toEqual([account]); 22 | }); 23 | -------------------------------------------------------------------------------- /templates/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "exclude": ["package.json", "rollup.config.js", "tsconfig.json", "tests", "./dist"], 4 | "compilerOptions": { 5 | "rootDir": "./", 6 | "outDir": "./dist/types", 7 | "emitDeclarationOnly": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /templates/types/{{ name}}Provider.ts: -------------------------------------------------------------------------------- 1 | export interface I{{name}}ProviderConfig { 2 | isTrust?: boolean; 3 | } 4 | 5 | export default interface I{{name}}Provider {} -------------------------------------------------------------------------------- /templates/{{ name }}Provider.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | import { BaseProvider } from '@trustwallet/web3-provider-core'; 4 | import type I{{name}}Provider from './types/{{name}}Provider'; 5 | import type { I{{name}}ProviderConfig } from './types/{{name}}Provider'; 6 | 7 | export class {{name}}Provider 8 | extends BaseProvider 9 | implements I{{name}}Provider 10 | { 11 | static NETWORK = '{{name}}'; 12 | 13 | constructor(config?: I{{ name }}ProviderConfig) { 14 | super(); 15 | // Your constructor logic here for setting config 16 | } 17 | 18 | getNetwork(): string { 19 | return {{name}}Provider.NETWORK; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | // Enable latest features 4 | "lib": ["ES2020", "DOM"], 5 | "target": "ES2020", 6 | "module": "ES2020", 7 | "allowJs": false, 8 | "composite": true, 9 | 10 | // Bundler mode 11 | "moduleResolution": "node", 12 | 13 | // Best practices 14 | "strict": true, 15 | "skipLibCheck": true, 16 | "noFallthroughCasesInSwitch": true, 17 | 18 | // Some stricter flags (disabled by default) 19 | "noUnusedLocals": false, 20 | "noUnusedParameters": false, 21 | "noPropertyAccessFromIndexSignature": false 22 | } 23 | } 24 | --------------------------------------------------------------------------------