@thru/wallet 0.2.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -0
- package/android/build.gradle +37 -0
- package/android/src/main/AndroidManifest.xml +1 -0
- package/android/src/main/java/org/thru/walletnative/ThruWebViewBridgeModule.kt +77 -0
- package/app.plugin.cjs +101 -0
- package/dist/BrowserSDK-CpRFiJsW.d.ts +409 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +941 -0
- package/dist/index.js.map +1 -0
- package/dist/native/react.d.ts +109 -0
- package/dist/native/react.js +2381 -0
- package/dist/native/react.js.map +1 -0
- package/dist/native.d.ts +329 -0
- package/dist/native.js +1126 -0
- package/dist/native.js.map +1 -0
- package/dist/react-ui.d.ts +5 -0
- package/dist/react-ui.js +266 -0
- package/dist/react-ui.js.map +1 -0
- package/dist/react.d.ts +66 -0
- package/dist/react.js +1151 -0
- package/dist/react.js.map +1 -0
- package/expo-module.config.json +6 -0
- package/package.json +114 -0
- package/src/BrowserSDK.ts +315 -0
- package/src/index.ts +27 -0
- package/src/interfaces/IThruChain.ts +37 -0
- package/src/interfaces/accounts.ts +61 -0
- package/src/interfaces/index.ts +9 -0
- package/src/interfaces/types.ts +95 -0
- package/src/native/NativeSDK.test.ts +819 -0
- package/src/native/NativeSDK.ts +773 -0
- package/src/native/index.ts +39 -0
- package/src/native/provider/NativeProvider.ts +363 -0
- package/src/native/provider/WebViewBridge.test.ts +339 -0
- package/src/native/provider/WebViewBridge.ts +339 -0
- package/src/native/provider/chains/ThruChain.ts +85 -0
- package/src/native/provider/shell.html +88 -0
- package/src/native/provider/shell.test.ts +56 -0
- package/src/native/provider/shell.ts +111 -0
- package/src/native/provider/shims-html.d.ts +4 -0
- package/src/native/react/ThruContext.ts +37 -0
- package/src/native/react/ThruProvider.tsx +168 -0
- package/src/native/react/ThruWalletSheet.tsx +1162 -0
- package/src/native/react/android-webauthn.ts +37 -0
- package/src/native/react/hooks/useAccounts.ts +35 -0
- package/src/native/react/hooks/useThru.ts +11 -0
- package/src/native/react/hooks/useWallet.ts +71 -0
- package/src/native/react/hooks/useWalletAvailability.ts +31 -0
- package/src/native/react/hooks/waitForWallet.ts +21 -0
- package/src/native/react/index.ts +29 -0
- package/src/protocol/index.ts +2 -0
- package/src/protocol/postMessage.ts +283 -0
- package/src/protocol/walletState.ts +12 -0
- package/src/provider/EmbeddedProvider.ts +330 -0
- package/src/provider/IframeManager.ts +438 -0
- package/src/provider/chains/ThruChain.ts +86 -0
- package/src/provider/index.ts +17 -0
- package/src/provider/types/messages.ts +37 -0
- package/src/react/ThruContext.ts +31 -0
- package/src/react/ThruProvider.tsx +169 -0
- package/src/react/hooks/useAccounts.ts +38 -0
- package/src/react/hooks/useThru.ts +11 -0
- package/src/react/hooks/useWallet.ts +81 -0
- package/src/react/index.ts +30 -0
- package/src/react-ui/ThruAccountSwitcher.tsx +187 -0
- package/src/react-ui/custom.d.ts +8 -0
- package/src/react-ui/index.ts +1 -0
- package/src/static/logo.png +0 -0
- package/src/static/logomark_red.svg +11 -0
package/README.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# @thru/wallet
|
|
2
|
+
|
|
3
|
+
Low-level browser SDK for embedding the Thru wallet experience. It manages the iframe-based embedded provider, forwards lifecycle events, and exposes a ready-to-use `Thru` RPC client alongside wallet account management utilities.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @thru/wallet
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Basic Usage
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { BrowserSDK } from '@thru/wallet';
|
|
15
|
+
|
|
16
|
+
// Configure the wallet iframe location and the RPC endpoint to talk to
|
|
17
|
+
const sdk = new BrowserSDK({
|
|
18
|
+
iframeUrl: 'https://wallet.thru.org/embedded',
|
|
19
|
+
rpcUrl: 'https://grpc-web.alphanet.thruput.org',
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
await sdk.initialize(); // injects the iframe once
|
|
23
|
+
|
|
24
|
+
// Observe lifecycle events
|
|
25
|
+
sdk.on('connect', ({ accounts }) => {
|
|
26
|
+
console.log('Connected accounts', accounts);
|
|
27
|
+
});
|
|
28
|
+
sdk.on('disconnect', () => console.log('Wallet disconnected'));
|
|
29
|
+
sdk.on('error', (err) => console.error('Wallet error', err));
|
|
30
|
+
|
|
31
|
+
// Trigger the wallet connect flow
|
|
32
|
+
const result = await sdk.connect();
|
|
33
|
+
const primary = result.accounts[0];
|
|
34
|
+
|
|
35
|
+
// Use the embedded Thru RPC client
|
|
36
|
+
const thru = sdk.getThru();
|
|
37
|
+
const account = await thru.accounts.get(primary.address);
|
|
38
|
+
|
|
39
|
+
// Disconnect when finished
|
|
40
|
+
await sdk.disconnect();
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Key Capabilities
|
|
44
|
+
|
|
45
|
+
- Handles iframe creation and cleanup (`initialize`, `destroy`)
|
|
46
|
+
- Connection helpers (`connect`, `disconnect`, `isConnected`, `selectAccount`)
|
|
47
|
+
- Event emitter for wallet state changes (`connect`, `disconnect`, `lock`, `error`, `accountChanged`)
|
|
48
|
+
- Access to a typed Thru RPC client via `sdk.getThru()` for querying on-chain data or submitting transactions
|
|
49
|
+
|
|
50
|
+
## React Native
|
|
51
|
+
|
|
52
|
+
React Native apps use the native wallet entrypoints from this same package:
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
import { ThruProvider, ThruWalletSheet } from '@thru/wallet/native/react';
|
|
56
|
+
|
|
57
|
+
export default function Root() {
|
|
58
|
+
return (
|
|
59
|
+
<ThruProvider config={{ walletUrl: 'https://wallet.thru.org/embedded' }}>
|
|
60
|
+
<App />
|
|
61
|
+
<ThruWalletSheet />
|
|
62
|
+
</ThruProvider>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Expo apps should install the config plugin from `@thru/wallet/native/plugin`.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
apply plugin: 'com.android.library'
|
|
2
|
+
apply plugin: 'kotlin-android'
|
|
3
|
+
apply plugin: 'maven-publish'
|
|
4
|
+
|
|
5
|
+
group = 'org.thru.walletnative'
|
|
6
|
+
version = '0.0.1'
|
|
7
|
+
|
|
8
|
+
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
|
9
|
+
apply from: expoModulesCorePlugin
|
|
10
|
+
applyKotlinExpoModulesCorePlugin()
|
|
11
|
+
|
|
12
|
+
useCoreDependencies()
|
|
13
|
+
useExpoPublishing()
|
|
14
|
+
|
|
15
|
+
useDefaultAndroidSdkVersions()
|
|
16
|
+
|
|
17
|
+
android {
|
|
18
|
+
namespace = "org.thru.walletnative"
|
|
19
|
+
|
|
20
|
+
defaultConfig {
|
|
21
|
+
versionCode 1
|
|
22
|
+
versionName "0.0.1"
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
publishing {
|
|
26
|
+
multipleVariants {
|
|
27
|
+
withSourcesJar()
|
|
28
|
+
withJavadocJar()
|
|
29
|
+
allVariants()
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
dependencies {
|
|
35
|
+
implementation project(':expo-modules-core')
|
|
36
|
+
implementation 'androidx.webkit:webkit:1.14.0'
|
|
37
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android" />
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
package org.thru.walletnative
|
|
2
|
+
|
|
3
|
+
import android.view.View
|
|
4
|
+
import android.view.ViewGroup
|
|
5
|
+
import android.webkit.WebView
|
|
6
|
+
import androidx.webkit.WebSettingsCompat
|
|
7
|
+
import androidx.webkit.WebViewFeature
|
|
8
|
+
import expo.modules.kotlin.modules.Module
|
|
9
|
+
import expo.modules.kotlin.modules.ModuleDefinition
|
|
10
|
+
import kotlinx.coroutines.Dispatchers
|
|
11
|
+
import kotlinx.coroutines.runBlocking
|
|
12
|
+
import kotlinx.coroutines.withContext
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Bridges react-native-webview's `WebView` to androidx.webkit's
|
|
16
|
+
* `WebSettingsCompat.setWebAuthenticationSupport`, which is required
|
|
17
|
+
* for `navigator.credentials.create/get` to succeed inside the WebView.
|
|
18
|
+
* This module does not create or read passkeys itself; it only flips the
|
|
19
|
+
* WebView setting so the wallet page can own the WebAuthn request.
|
|
20
|
+
*
|
|
21
|
+
* react-native-webview does not call this itself today
|
|
22
|
+
* (https://github.com/react-native-webview/react-native-webview/issues/3807),
|
|
23
|
+
* so the host (ThruWalletSheet) calls our `enableWebAuthnSupport`
|
|
24
|
+
* function after the WebView mounts.
|
|
25
|
+
*
|
|
26
|
+
* The Gradle deps (`androidx.webkit:webkit:1.14.0`,
|
|
27
|
+
* `androidx.credentials:credentials*`) are pulled in by our Expo
|
|
28
|
+
* config plugin; no extra host-app wiring required.
|
|
29
|
+
*/
|
|
30
|
+
class ThruWebViewBridgeModule : Module() {
|
|
31
|
+
override fun definition() = ModuleDefinition {
|
|
32
|
+
Name("ThruWebViewBridge")
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Resolve the mounted react-native-webview by native view tag, find
|
|
36
|
+
* the WebView inside it, and enable WebAuthn support on it.
|
|
37
|
+
* Returns true if the call landed; false if the feature isn't
|
|
38
|
+
* supported on this WebView (e.g. ancient WebView version), no
|
|
39
|
+
* view tag was provided, or no WebView was found.
|
|
40
|
+
*/
|
|
41
|
+
AsyncFunction("enableWebAuthnSupport") { viewTag: Int? ->
|
|
42
|
+
runBlocking {
|
|
43
|
+
withContext(Dispatchers.Main) {
|
|
44
|
+
val rootView = appContext.currentActivity?.window?.decorView
|
|
45
|
+
?: return@withContext false
|
|
46
|
+
val targetView = viewTag?.let { rootView.findViewById<View>(it) }
|
|
47
|
+
?: return@withContext false
|
|
48
|
+
val webView = findWebView(targetView)
|
|
49
|
+
?: return@withContext false
|
|
50
|
+
|
|
51
|
+
if (!WebViewFeature.isFeatureSupported(WebViewFeature.WEB_AUTHENTICATION)) {
|
|
52
|
+
return@withContext false
|
|
53
|
+
}
|
|
54
|
+
WebSettingsCompat.setWebAuthenticationSupport(
|
|
55
|
+
webView.settings,
|
|
56
|
+
WebSettingsCompat.WEB_AUTHENTICATION_SUPPORT_FOR_APP,
|
|
57
|
+
)
|
|
58
|
+
true
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** react-native-webview wraps the WebView in an RNCWebView container;
|
|
65
|
+
* walk the descendants to find the first WebView. */
|
|
66
|
+
private fun findWebView(view: View?): WebView? {
|
|
67
|
+
if (view == null) return null
|
|
68
|
+
if (view is WebView) return view
|
|
69
|
+
if (view is ViewGroup) {
|
|
70
|
+
for (i in 0 until view.childCount) {
|
|
71
|
+
val found = findWebView(view.getChildAt(i))
|
|
72
|
+
if (found != null) return found
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return null
|
|
76
|
+
}
|
|
77
|
+
}
|
package/app.plugin.cjs
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/* Expo entrypoint for the config plugin. Keep this file dependency-free so
|
|
2
|
+
Expo can load it from a clean workspace before package build artifacts exist. */
|
|
3
|
+
|
|
4
|
+
const DEFAULT_RP_DOMAIN = "wallet.thru.org";
|
|
5
|
+
const APP_BOUND_DOMAIN_CAP = 10;
|
|
6
|
+
const MIN_ANDROID_SDK_FOR_PASSKEYS = 28;
|
|
7
|
+
const ANDROID_SYSTEM_BRIGHTNESS_PERMISSION =
|
|
8
|
+
"android.permission.WRITE_SETTINGS";
|
|
9
|
+
const IOS_ASSOCIATED_DOMAIN_MODES = new Set([
|
|
10
|
+
"developer",
|
|
11
|
+
"managed",
|
|
12
|
+
"developer+managed",
|
|
13
|
+
]);
|
|
14
|
+
|
|
15
|
+
const ANDROID_CREDENTIAL_MANAGER_DEPS = [
|
|
16
|
+
"androidx.credentials:credentials:1.5.0",
|
|
17
|
+
"androidx.credentials:credentials-play-services-auth:1.5.0",
|
|
18
|
+
"androidx.webkit:webkit:1.14.0",
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
function withThruWalletNative(config, opts = {}) {
|
|
22
|
+
const rpDomain = opts.rpDomain || DEFAULT_RP_DOMAIN;
|
|
23
|
+
const associatedDomainMode = opts.iosAssociatedDomainMode;
|
|
24
|
+
if (
|
|
25
|
+
associatedDomainMode &&
|
|
26
|
+
!IOS_ASSOCIATED_DOMAIN_MODES.has(associatedDomainMode)
|
|
27
|
+
) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
`[@thru/wallet/native/plugin] Invalid iosAssociatedDomainMode "${associatedDomainMode}". Expected developer, managed, or developer+managed.`,
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (!config.ios) config.ios = {};
|
|
34
|
+
if (!config.ios.infoPlist) config.ios.infoPlist = {};
|
|
35
|
+
|
|
36
|
+
const existingAppBoundDomains = Array.isArray(
|
|
37
|
+
config.ios.infoPlist.WKAppBoundDomains,
|
|
38
|
+
)
|
|
39
|
+
? config.ios.infoPlist.WKAppBoundDomains
|
|
40
|
+
: [];
|
|
41
|
+
if (!existingAppBoundDomains.includes(rpDomain)) {
|
|
42
|
+
if (existingAppBoundDomains.length >= APP_BOUND_DOMAIN_CAP) {
|
|
43
|
+
throw new Error(
|
|
44
|
+
`[@thru/wallet/native/plugin] WKAppBoundDomains is capped at ${APP_BOUND_DOMAIN_CAP} entries; cannot add ${rpDomain}. Drop an unused domain from your Info.plist before adding the wallet.`,
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
config.ios.infoPlist.WKAppBoundDomains = [
|
|
48
|
+
...existingAppBoundDomains,
|
|
49
|
+
rpDomain,
|
|
50
|
+
];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const webCredentialsDomain = associatedDomainMode
|
|
54
|
+
? `webcredentials:${rpDomain}?mode=${associatedDomainMode}`
|
|
55
|
+
: `webcredentials:${rpDomain}`;
|
|
56
|
+
const associatedDomains = Array.isArray(config.ios.associatedDomains)
|
|
57
|
+
? config.ios.associatedDomains
|
|
58
|
+
: [];
|
|
59
|
+
if (!associatedDomains.includes(webCredentialsDomain)) {
|
|
60
|
+
config.ios.associatedDomains = [
|
|
61
|
+
...associatedDomains,
|
|
62
|
+
webCredentialsDomain,
|
|
63
|
+
];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!config.android) config.android = {};
|
|
67
|
+
const currentMin = config.android.minSdkVersion || 0;
|
|
68
|
+
if (currentMin < MIN_ANDROID_SDK_FOR_PASSKEYS) {
|
|
69
|
+
config.android.minSdkVersion = MIN_ANDROID_SDK_FOR_PASSKEYS;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const existingPermissions = Array.isArray(config.android.permissions)
|
|
73
|
+
? config.android.permissions.slice()
|
|
74
|
+
: [];
|
|
75
|
+
if (!existingPermissions.includes(ANDROID_SYSTEM_BRIGHTNESS_PERMISSION)) {
|
|
76
|
+
existingPermissions.push(ANDROID_SYSTEM_BRIGHTNESS_PERMISSION);
|
|
77
|
+
}
|
|
78
|
+
config.android.permissions = existingPermissions;
|
|
79
|
+
|
|
80
|
+
const existingDeps = Array.isArray(config.android.extraDependencies)
|
|
81
|
+
? config.android.extraDependencies.slice()
|
|
82
|
+
: [];
|
|
83
|
+
for (const dep of ANDROID_CREDENTIAL_MANAGER_DEPS) {
|
|
84
|
+
if (!existingDeps.includes(dep)) existingDeps.push(dep);
|
|
85
|
+
}
|
|
86
|
+
config.android.extraDependencies = existingDeps;
|
|
87
|
+
|
|
88
|
+
config.android.extraProguardRules = [
|
|
89
|
+
config.android.extraProguardRules,
|
|
90
|
+
"-keep class androidx.credentials.** { *; }",
|
|
91
|
+
"-keep class androidx.webkit.** { *; }",
|
|
92
|
+
"-keep class com.google.android.gms.fido.** { *; }",
|
|
93
|
+
]
|
|
94
|
+
.filter(Boolean)
|
|
95
|
+
.join("\n");
|
|
96
|
+
|
|
97
|
+
return config;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
module.exports = withThruWalletNative;
|
|
101
|
+
module.exports.default = withThruWalletNative;
|
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
import { Thru } from '@thru/sdk/client';
|
|
2
|
+
|
|
3
|
+
declare const AddressType: {
|
|
4
|
+
readonly THRU: "thru";
|
|
5
|
+
};
|
|
6
|
+
type AddressType = (typeof AddressType)[keyof typeof AddressType];
|
|
7
|
+
interface WalletAccount {
|
|
8
|
+
accountType: AddressType;
|
|
9
|
+
address: string;
|
|
10
|
+
label: string;
|
|
11
|
+
}
|
|
12
|
+
interface AppMetadata {
|
|
13
|
+
appId: string;
|
|
14
|
+
appName: string;
|
|
15
|
+
appUrl: string;
|
|
16
|
+
imageUrl?: string;
|
|
17
|
+
}
|
|
18
|
+
interface ConnectResult {
|
|
19
|
+
walletId?: string;
|
|
20
|
+
accounts: WalletAccount[];
|
|
21
|
+
selectedAccount?: WalletAccount | null;
|
|
22
|
+
status?: "pending" | "completed";
|
|
23
|
+
metadata?: AppMetadata;
|
|
24
|
+
}
|
|
25
|
+
declare const ThruTransactionEncoding: {
|
|
26
|
+
readonly SIGNING_PAYLOAD_BASE64: "signing_payload_base64";
|
|
27
|
+
readonly RAW_TRANSACTION_BASE64: "raw_transaction_base64";
|
|
28
|
+
};
|
|
29
|
+
type ThruTransactionEncoding = (typeof ThruTransactionEncoding)[keyof typeof ThruTransactionEncoding];
|
|
30
|
+
interface ThruSigningContext {
|
|
31
|
+
mode: "managed_fee_payer";
|
|
32
|
+
selectedAccountPublicKey: string | null;
|
|
33
|
+
feePayerPublicKey: string;
|
|
34
|
+
signerPublicKey: string;
|
|
35
|
+
acceptedInputEncodings: ThruTransactionEncoding[];
|
|
36
|
+
outputEncoding: typeof ThruTransactionEncoding.RAW_TRANSACTION_BASE64;
|
|
37
|
+
}
|
|
38
|
+
interface ThruTransactionReviewSimulation {
|
|
39
|
+
before?: string;
|
|
40
|
+
after?: string;
|
|
41
|
+
}
|
|
42
|
+
interface ThruTransactionReviewAbiReflection {
|
|
43
|
+
label?: string;
|
|
44
|
+
kind?: string | null;
|
|
45
|
+
typeName?: string;
|
|
46
|
+
value?: unknown;
|
|
47
|
+
rawHex?: string;
|
|
48
|
+
source?: string;
|
|
49
|
+
error?: string;
|
|
50
|
+
}
|
|
51
|
+
interface ThruTransactionReviewPayload {
|
|
52
|
+
appName?: string;
|
|
53
|
+
programAddress?: string;
|
|
54
|
+
abiName?: string;
|
|
55
|
+
instruction?: string;
|
|
56
|
+
simulation?: ThruTransactionReviewSimulation;
|
|
57
|
+
abiReflection?: ThruTransactionReviewAbiReflection;
|
|
58
|
+
}
|
|
59
|
+
interface ThruTransactionIntent {
|
|
60
|
+
walletAddress?: string;
|
|
61
|
+
programAddress: string;
|
|
62
|
+
instructionData: string;
|
|
63
|
+
readWriteAddresses?: string[];
|
|
64
|
+
readOnlyAddresses?: string[];
|
|
65
|
+
review?: ThruTransactionReviewPayload;
|
|
66
|
+
}
|
|
67
|
+
interface ConnectedApp {
|
|
68
|
+
accountId: number;
|
|
69
|
+
appId: string;
|
|
70
|
+
origin: string;
|
|
71
|
+
metadata: AppMetadata;
|
|
72
|
+
connectedAt: number;
|
|
73
|
+
updatedAt: number;
|
|
74
|
+
}
|
|
75
|
+
interface SignMessageParams {
|
|
76
|
+
message: string | Uint8Array;
|
|
77
|
+
networkId: string;
|
|
78
|
+
}
|
|
79
|
+
interface SignMessageResult$1 {
|
|
80
|
+
signature: Uint8Array;
|
|
81
|
+
publicKey: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Minimal Thru chain interface exposed to SDK consumers.
|
|
86
|
+
* The concrete implementation will evolve as the Thru transaction
|
|
87
|
+
* flow is fleshed out, but maintaining a dedicated contract now
|
|
88
|
+
* keeps the Surface area aligned with other chain adapters.
|
|
89
|
+
*/
|
|
90
|
+
interface IThruChain {
|
|
91
|
+
/** Indicates whether the wallet has approved a Thru connection. */
|
|
92
|
+
readonly connected: boolean;
|
|
93
|
+
/**
|
|
94
|
+
* Initiate a Thru connection flow. Resolves with the connected address once
|
|
95
|
+
* the user has approved the request.
|
|
96
|
+
*/
|
|
97
|
+
connect(): Promise<{
|
|
98
|
+
publicKey: string;
|
|
99
|
+
}>;
|
|
100
|
+
/** Disconnect the currently connected Thru account. */
|
|
101
|
+
disconnect(): Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* Return the current embedded signing contract for Thru transactions.
|
|
104
|
+
*
|
|
105
|
+
* The selected account is the managed wallet account shown to the user.
|
|
106
|
+
* The fee payer / signer can differ when the wallet routes transactions
|
|
107
|
+
* through an embedded manager profile.
|
|
108
|
+
*/
|
|
109
|
+
getSigningContext(): Promise<ThruSigningContext>;
|
|
110
|
+
/**
|
|
111
|
+
* Sign a wallet-managed transaction intent and return canonical raw
|
|
112
|
+
* transaction bytes encoded as base64. The wallet owns fee payer choice,
|
|
113
|
+
* account ordering, headers, nonces, and final wire layout.
|
|
114
|
+
*/
|
|
115
|
+
signTransaction(transaction: ThruTransactionIntent): Promise<string>;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
declare const POST_MESSAGE_REQUEST_TYPES: {
|
|
119
|
+
readonly CONNECT: "connect";
|
|
120
|
+
readonly DISCONNECT: "disconnect";
|
|
121
|
+
readonly SIGN_MESSAGE: "signMessage";
|
|
122
|
+
readonly SIGN_TRANSACTION: "signTransaction";
|
|
123
|
+
readonly GET_ACCOUNTS: "getAccounts";
|
|
124
|
+
readonly GET_CONNECTION_STATE: "getConnectionState";
|
|
125
|
+
readonly GET_SIGNING_CONTEXT: "getSigningContext";
|
|
126
|
+
readonly SELECT_ACCOUNT: "selectAccount";
|
|
127
|
+
readonly MANAGE_ACCOUNTS: "manageAccounts";
|
|
128
|
+
};
|
|
129
|
+
type RequestType = (typeof POST_MESSAGE_REQUEST_TYPES)[keyof typeof POST_MESSAGE_REQUEST_TYPES];
|
|
130
|
+
declare const EMBEDDED_PROVIDER_EVENTS: {
|
|
131
|
+
readonly CONNECT_START: "connect_start";
|
|
132
|
+
readonly CONNECT: "connect";
|
|
133
|
+
readonly DISCONNECT: "disconnect";
|
|
134
|
+
readonly CONNECT_ERROR: "connect_error";
|
|
135
|
+
readonly ERROR: "error";
|
|
136
|
+
readonly LOCK: "lock";
|
|
137
|
+
readonly UI_SHOW: "ui_show";
|
|
138
|
+
readonly ACCOUNT_CHANGED: "account_changed";
|
|
139
|
+
};
|
|
140
|
+
type EmbeddedProviderEvent = (typeof EMBEDDED_PROVIDER_EVENTS)[keyof typeof EMBEDDED_PROVIDER_EVENTS];
|
|
141
|
+
declare const POST_MESSAGE_EVENT_TYPE: "event";
|
|
142
|
+
declare const IFRAME_READY_EVENT: "iframe:ready";
|
|
143
|
+
declare const DEFAULT_IFRAME_URL = "http://localhost:3000/embedded";
|
|
144
|
+
declare const createRequestId: (prefix?: string) => string;
|
|
145
|
+
interface BaseRequest {
|
|
146
|
+
id: string;
|
|
147
|
+
origin: string;
|
|
148
|
+
}
|
|
149
|
+
interface ConnectRequestMessage extends BaseRequest {
|
|
150
|
+
type: typeof POST_MESSAGE_REQUEST_TYPES.CONNECT;
|
|
151
|
+
payload: ConnectRequestPayload;
|
|
152
|
+
}
|
|
153
|
+
interface DisconnectRequestMessage extends BaseRequest {
|
|
154
|
+
type: typeof POST_MESSAGE_REQUEST_TYPES.DISCONNECT;
|
|
155
|
+
payload?: undefined;
|
|
156
|
+
}
|
|
157
|
+
interface SignMessageRequestMessage extends BaseRequest {
|
|
158
|
+
type: typeof POST_MESSAGE_REQUEST_TYPES.SIGN_MESSAGE;
|
|
159
|
+
payload: SignMessagePayload;
|
|
160
|
+
}
|
|
161
|
+
interface SignTransactionRequestMessage extends BaseRequest {
|
|
162
|
+
type: typeof POST_MESSAGE_REQUEST_TYPES.SIGN_TRANSACTION;
|
|
163
|
+
payload: SignTransactionPayload;
|
|
164
|
+
}
|
|
165
|
+
interface GetAccountsRequestMessage extends BaseRequest {
|
|
166
|
+
type: typeof POST_MESSAGE_REQUEST_TYPES.GET_ACCOUNTS;
|
|
167
|
+
payload?: undefined;
|
|
168
|
+
}
|
|
169
|
+
interface GetConnectionStateRequestMessage extends BaseRequest {
|
|
170
|
+
type: typeof POST_MESSAGE_REQUEST_TYPES.GET_CONNECTION_STATE;
|
|
171
|
+
payload: ConnectRequestPayload;
|
|
172
|
+
}
|
|
173
|
+
interface GetSigningContextRequestMessage extends BaseRequest {
|
|
174
|
+
type: typeof POST_MESSAGE_REQUEST_TYPES.GET_SIGNING_CONTEXT;
|
|
175
|
+
payload?: undefined;
|
|
176
|
+
}
|
|
177
|
+
interface SelectAccountRequestMessage extends BaseRequest {
|
|
178
|
+
type: typeof POST_MESSAGE_REQUEST_TYPES.SELECT_ACCOUNT;
|
|
179
|
+
payload: SelectAccountPayload;
|
|
180
|
+
}
|
|
181
|
+
interface ManageAccountsRequestMessage extends BaseRequest {
|
|
182
|
+
type: typeof POST_MESSAGE_REQUEST_TYPES.MANAGE_ACCOUNTS;
|
|
183
|
+
payload?: undefined;
|
|
184
|
+
}
|
|
185
|
+
type PostMessageRequest = ConnectRequestMessage | DisconnectRequestMessage | SignMessageRequestMessage | SignTransactionRequestMessage | GetAccountsRequestMessage | GetConnectionStateRequestMessage | GetSigningContextRequestMessage | SelectAccountRequestMessage | ManageAccountsRequestMessage;
|
|
186
|
+
interface DisconnectResult {
|
|
187
|
+
}
|
|
188
|
+
interface GetAccountsResult {
|
|
189
|
+
accounts: WalletAccount[];
|
|
190
|
+
}
|
|
191
|
+
interface GetConnectionStateResult {
|
|
192
|
+
isAuthorized: boolean;
|
|
193
|
+
isConnected: boolean;
|
|
194
|
+
isUnlocked: boolean;
|
|
195
|
+
hasPasskey: boolean;
|
|
196
|
+
hasWalletAccount: boolean;
|
|
197
|
+
accounts: WalletAccount[];
|
|
198
|
+
selectedAccount: WalletAccount | null;
|
|
199
|
+
metadata: AppMetadata | null;
|
|
200
|
+
}
|
|
201
|
+
interface SelectAccountPayload {
|
|
202
|
+
publicKey: string;
|
|
203
|
+
}
|
|
204
|
+
interface SelectAccountResult {
|
|
205
|
+
account: WalletAccount;
|
|
206
|
+
}
|
|
207
|
+
interface ManageAccountsResult {
|
|
208
|
+
accounts: WalletAccount[];
|
|
209
|
+
selectedAccount: WalletAccount | null;
|
|
210
|
+
}
|
|
211
|
+
type RequestResultMap = {
|
|
212
|
+
[POST_MESSAGE_REQUEST_TYPES.CONNECT]: ConnectResult;
|
|
213
|
+
[POST_MESSAGE_REQUEST_TYPES.DISCONNECT]: DisconnectResult;
|
|
214
|
+
[POST_MESSAGE_REQUEST_TYPES.SIGN_MESSAGE]: SignMessageResult;
|
|
215
|
+
[POST_MESSAGE_REQUEST_TYPES.SIGN_TRANSACTION]: SignTransactionResult;
|
|
216
|
+
[POST_MESSAGE_REQUEST_TYPES.GET_ACCOUNTS]: GetAccountsResult;
|
|
217
|
+
[POST_MESSAGE_REQUEST_TYPES.GET_CONNECTION_STATE]: GetConnectionStateResult;
|
|
218
|
+
[POST_MESSAGE_REQUEST_TYPES.GET_SIGNING_CONTEXT]: GetSigningContextResult;
|
|
219
|
+
[POST_MESSAGE_REQUEST_TYPES.SELECT_ACCOUNT]: SelectAccountResult;
|
|
220
|
+
[POST_MESSAGE_REQUEST_TYPES.MANAGE_ACCOUNTS]: ManageAccountsResult;
|
|
221
|
+
};
|
|
222
|
+
interface ResponseErrorPayload {
|
|
223
|
+
code: ErrorCode;
|
|
224
|
+
message: string;
|
|
225
|
+
data?: unknown;
|
|
226
|
+
}
|
|
227
|
+
type SuccessResponse<TType extends RequestType> = {
|
|
228
|
+
id: string;
|
|
229
|
+
success: true;
|
|
230
|
+
result: RequestResultMap[TType];
|
|
231
|
+
};
|
|
232
|
+
type ErrorResponse = {
|
|
233
|
+
id: string;
|
|
234
|
+
success: false;
|
|
235
|
+
error: ResponseErrorPayload;
|
|
236
|
+
};
|
|
237
|
+
type PostMessageResponse<TType extends RequestType = RequestType> = SuccessResponse<TType> | ErrorResponse;
|
|
238
|
+
type SuccessfulPostMessageResponse<TType extends RequestType = RequestType> = Extract<PostMessageResponse<TType>, {
|
|
239
|
+
success: true;
|
|
240
|
+
}>;
|
|
241
|
+
type InferPostMessageResponse<TRequest extends PostMessageRequest> = PostMessageResponse<TRequest["type"]>;
|
|
242
|
+
type InferSuccessfulPostMessageResponse<TRequest extends PostMessageRequest> = SuccessfulPostMessageResponse<TRequest["type"]>;
|
|
243
|
+
interface PostMessageEvent<TEvent extends EmbeddedProviderEvent = EmbeddedProviderEvent, TData = any> {
|
|
244
|
+
type: typeof POST_MESSAGE_EVENT_TYPE;
|
|
245
|
+
event: TEvent;
|
|
246
|
+
data?: TData;
|
|
247
|
+
}
|
|
248
|
+
declare const ErrorCode: {
|
|
249
|
+
readonly USER_REJECTED: "USER_REJECTED";
|
|
250
|
+
readonly WALLET_LOCKED: "WALLET_LOCKED";
|
|
251
|
+
readonly INVALID_PASSWORD: "INVALID_PASSWORD";
|
|
252
|
+
readonly ALREADY_CONNECTED: "ALREADY_CONNECTED";
|
|
253
|
+
readonly ACCOUNT_NOT_FOUND: "ACCOUNT_NOT_FOUND";
|
|
254
|
+
readonly ACCOUNT_CHANGED: "ACCOUNT_CHANGED";
|
|
255
|
+
readonly INVALID_TRANSACTION: "INVALID_TRANSACTION";
|
|
256
|
+
readonly TRANSACTION_FAILED: "TRANSACTION_FAILED";
|
|
257
|
+
readonly INSUFFICIENT_FUNDS: "INSUFFICIENT_FUNDS";
|
|
258
|
+
readonly NETWORK_ERROR: "NETWORK_ERROR";
|
|
259
|
+
readonly TIMEOUT: "TIMEOUT";
|
|
260
|
+
readonly UNKNOWN_ERROR: "UNKNOWN_ERROR";
|
|
261
|
+
};
|
|
262
|
+
type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode];
|
|
263
|
+
type ConnectMetadataInput = Partial<AppMetadata>;
|
|
264
|
+
type ConnectIntent = "default" | "switch-account";
|
|
265
|
+
interface ConnectRequestPayload {
|
|
266
|
+
metadata?: ConnectMetadataInput;
|
|
267
|
+
preferredAccountAddress?: string;
|
|
268
|
+
intent?: ConnectIntent;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
interface SignMessagePayload {
|
|
272
|
+
message: string | number[];
|
|
273
|
+
accountIndex?: number;
|
|
274
|
+
}
|
|
275
|
+
interface SignMessageResult {
|
|
276
|
+
signature: number[];
|
|
277
|
+
publicKey: string;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Wallet-managed instruction signing intent.
|
|
281
|
+
*
|
|
282
|
+
* Dapps provide the instruction data and account context. The wallet owns
|
|
283
|
+
* signing strategy details such as passkey validation, fee payer choice,
|
|
284
|
+
* account ordering, headers, nonces, and final wire layout. Review metadata
|
|
285
|
+
* is treated as untrusted display-only data.
|
|
286
|
+
*/
|
|
287
|
+
interface SignTransactionPayload {
|
|
288
|
+
walletAddress?: string;
|
|
289
|
+
programAddress: string;
|
|
290
|
+
instructionData: string;
|
|
291
|
+
readWriteAddresses?: string[];
|
|
292
|
+
readOnlyAddresses?: string[];
|
|
293
|
+
review?: TransactionReviewPayload;
|
|
294
|
+
}
|
|
295
|
+
interface SignTransactionResult {
|
|
296
|
+
signedTransaction: string;
|
|
297
|
+
}
|
|
298
|
+
interface TransactionReviewSimulation {
|
|
299
|
+
before?: string;
|
|
300
|
+
after?: string;
|
|
301
|
+
}
|
|
302
|
+
interface TransactionReviewAbiReflection {
|
|
303
|
+
label?: string;
|
|
304
|
+
kind?: string | null;
|
|
305
|
+
typeName?: string;
|
|
306
|
+
value?: unknown;
|
|
307
|
+
rawHex?: string;
|
|
308
|
+
source?: string;
|
|
309
|
+
error?: string;
|
|
310
|
+
}
|
|
311
|
+
interface TransactionReviewPayload {
|
|
312
|
+
appName?: string;
|
|
313
|
+
programAddress?: string;
|
|
314
|
+
abiName?: string;
|
|
315
|
+
instruction?: string;
|
|
316
|
+
simulation?: TransactionReviewSimulation;
|
|
317
|
+
abiReflection?: TransactionReviewAbiReflection;
|
|
318
|
+
}
|
|
319
|
+
interface GetSigningContextResult {
|
|
320
|
+
signingContext: ThruSigningContext;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
interface BrowserSDKConfig {
|
|
324
|
+
iframeUrl?: string;
|
|
325
|
+
addressTypes?: AddressType[];
|
|
326
|
+
rpcUrl?: string;
|
|
327
|
+
}
|
|
328
|
+
interface ConnectOptions {
|
|
329
|
+
metadata?: ConnectMetadataInput;
|
|
330
|
+
}
|
|
331
|
+
type SDKEvent = 'connect' | 'disconnect' | 'lock' | 'error' | 'accountChanged';
|
|
332
|
+
type EventCallback = (...args: any[]) => void;
|
|
333
|
+
/**
|
|
334
|
+
* Browser SDK - Main entry point for dApp developers
|
|
335
|
+
* Wraps EmbeddedProvider with a clean, simple API
|
|
336
|
+
*/
|
|
337
|
+
declare class BrowserSDK {
|
|
338
|
+
private provider;
|
|
339
|
+
private eventListeners;
|
|
340
|
+
private initialized;
|
|
341
|
+
private thruClient;
|
|
342
|
+
private connectInFlight;
|
|
343
|
+
private lastConnectResult;
|
|
344
|
+
constructor(config?: BrowserSDKConfig);
|
|
345
|
+
/**
|
|
346
|
+
* Initialize the SDK (creates iframe)
|
|
347
|
+
* Must be called before using the SDK
|
|
348
|
+
*/
|
|
349
|
+
initialize(): Promise<void>;
|
|
350
|
+
/**
|
|
351
|
+
* Connect to wallet
|
|
352
|
+
* Shows wallet modal and requests connection
|
|
353
|
+
*/
|
|
354
|
+
connect(options?: ConnectOptions): Promise<ConnectResult>;
|
|
355
|
+
/**
|
|
356
|
+
* Mount the wallet iframe inline in a container.
|
|
357
|
+
*/
|
|
358
|
+
mountInline(container: HTMLElement): Promise<void>;
|
|
359
|
+
/**
|
|
360
|
+
* Disconnect from wallet
|
|
361
|
+
*/
|
|
362
|
+
disconnect(): Promise<void>;
|
|
363
|
+
/**
|
|
364
|
+
* Check if connected
|
|
365
|
+
*/
|
|
366
|
+
isConnected(): boolean;
|
|
367
|
+
/**
|
|
368
|
+
* Get all accounts
|
|
369
|
+
*/
|
|
370
|
+
getAccounts(): WalletAccount[];
|
|
371
|
+
getSelectedAccount(): WalletAccount | null;
|
|
372
|
+
selectAccount(publicKey: string): Promise<WalletAccount>;
|
|
373
|
+
manageAccounts(): Promise<ManageAccountsResult>;
|
|
374
|
+
/**
|
|
375
|
+
* Get Thru chain API (iframe-backed signer)
|
|
376
|
+
*/
|
|
377
|
+
get thru(): IThruChain;
|
|
378
|
+
/**
|
|
379
|
+
* Event emitter: on
|
|
380
|
+
*/
|
|
381
|
+
on(event: SDKEvent, callback: EventCallback): void;
|
|
382
|
+
/**
|
|
383
|
+
* Event emitter: off
|
|
384
|
+
*/
|
|
385
|
+
off(event: SDKEvent, callback: EventCallback): void;
|
|
386
|
+
/**
|
|
387
|
+
* Event emitter: once (listen once and auto-remove)
|
|
388
|
+
*/
|
|
389
|
+
once(event: SDKEvent, callback: EventCallback): void;
|
|
390
|
+
/**
|
|
391
|
+
* Emit event to all listeners
|
|
392
|
+
*/
|
|
393
|
+
private emit;
|
|
394
|
+
/**
|
|
395
|
+
* Set up event forwarding from provider to SDK
|
|
396
|
+
*/
|
|
397
|
+
private setupEventForwarding;
|
|
398
|
+
/**
|
|
399
|
+
* Destroy SDK and cleanup
|
|
400
|
+
*/
|
|
401
|
+
destroy(): void;
|
|
402
|
+
private resolveMetadata;
|
|
403
|
+
private resolveAppUrl;
|
|
404
|
+
private deriveAppName;
|
|
405
|
+
getThru(): Thru;
|
|
406
|
+
private refreshCachedAccounts;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
export { type TransactionReviewSimulation as $, AddressType as A, BrowserSDK as B, type ConnectIntent as C, DEFAULT_IFRAME_URL as D, EMBEDDED_PROVIDER_EVENTS as E, type SelectAccountPayload as F, type GetAccountsRequestMessage as G, type SelectAccountRequestMessage as H, IFRAME_READY_EVENT as I, type SelectAccountResult as J, type SignMessageParams as K, type SignMessagePayload as L, type ManageAccountsRequestMessage as M, type SignMessageRequestMessage as N, type SignMessageResult$1 as O, POST_MESSAGE_EVENT_TYPE as P, type SignTransactionPayload as Q, type RequestType as R, type SDKEvent as S, type SignTransactionRequestMessage as T, type SignTransactionResult as U, type SuccessfulPostMessageResponse as V, type ThruSigningContext as W, ThruTransactionEncoding as X, type ThruTransactionIntent as Y, type TransactionReviewAbiReflection as Z, type TransactionReviewPayload as _, type AppMetadata as a, type WalletAccount as a0, createRequestId as a1, type BrowserSDKConfig as b, type ConnectMetadataInput as c, type ConnectOptions as d, type ConnectRequestMessage as e, type ConnectRequestPayload as f, type ConnectResult as g, type ConnectedApp as h, type DisconnectRequestMessage as i, type DisconnectResult as j, type EmbeddedProviderEvent as k, ErrorCode as l, type EventCallback as m, type GetAccountsResult as n, type GetConnectionStateRequestMessage as o, type GetConnectionStateResult as p, type GetSigningContextRequestMessage as q, type GetSigningContextResult as r, type IThruChain as s, type InferPostMessageResponse as t, type InferSuccessfulPostMessageResponse as u, type ManageAccountsResult as v, POST_MESSAGE_REQUEST_TYPES as w, type PostMessageEvent as x, type PostMessageRequest as y, type PostMessageResponse as z };
|