@mysten-incubation/dev-wallet 0.0.1 → 0.3.0
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/CHANGELOG.md +139 -0
- package/LICENSE +189 -0
- package/dist/_virtual/{_@oxc-project_runtime@0.107.0 → _@oxc-project_runtime@0.127.0}/helpers/decorate.mjs +2 -3
- package/dist/adapters/base-adapter.mjs +6 -7
- package/dist/adapters/base-adapter.mjs.map +1 -1
- package/dist/adapters/browser.d.mts +4 -1
- package/dist/adapters/browser.mjs +4 -2
- package/dist/adapters/build-managed-account.mjs +8 -10
- package/dist/adapters/build-managed-account.mjs.map +1 -1
- package/dist/adapters/devstack-adapter.d.mts +111 -0
- package/dist/adapters/devstack-adapter.d.mts.map +1 -0
- package/dist/adapters/devstack-adapter.mjs +224 -0
- package/dist/adapters/devstack-adapter.mjs.map +1 -0
- package/dist/adapters/devstack-paths.d.mts +11 -0
- package/dist/adapters/devstack-paths.d.mts.map +1 -0
- package/dist/adapters/devstack-paths.mjs +11 -0
- package/dist/adapters/devstack-paths.mjs.map +1 -0
- package/dist/adapters/fork-relay.d.mts +109 -0
- package/dist/adapters/fork-relay.d.mts.map +1 -0
- package/dist/adapters/fork-relay.mjs +208 -0
- package/dist/adapters/fork-relay.mjs.map +1 -0
- package/dist/adapters/idb-store.mjs +12 -16
- package/dist/adapters/idb-store.mjs.map +1 -1
- package/dist/adapters/in-memory-adapter.mjs +4 -10
- package/dist/adapters/in-memory-adapter.mjs.map +1 -1
- package/dist/adapters/passkey-adapter.mjs +4 -12
- package/dist/adapters/passkey-adapter.mjs.map +1 -1
- package/dist/adapters/remote-cli-adapter.mjs +37 -72
- package/dist/adapters/remote-cli-adapter.mjs.map +1 -1
- package/dist/adapters/webcrypto-adapter.mjs +2 -4
- package/dist/adapters/webcrypto-adapter.mjs.map +1 -1
- package/dist/bin/cli.mjs +9 -22
- package/dist/bin/cli.mjs.map +1 -1
- package/dist/client/dev-wallet-client.mjs +13 -28
- package/dist/client/dev-wallet-client.mjs.map +1 -1
- package/dist/client/index.mjs +1 -2
- package/dist/client/request-handler.mjs +36 -42
- package/dist/client/request-handler.mjs.map +1 -1
- package/dist/index.mjs +1 -2
- package/dist/react/components.d.mts +9 -9
- package/dist/react/components.d.mts.map +1 -1
- package/dist/react/components.mjs +2 -5
- package/dist/react/components.mjs.map +1 -1
- package/dist/react/context.d.mts +3 -3
- package/dist/react/context.d.mts.map +1 -1
- package/dist/react/context.mjs +3 -8
- package/dist/react/context.mjs.map +1 -1
- package/dist/react/index.mjs +1 -2
- package/dist/react/useDevWallet.d.mts +3 -0
- package/dist/react/useDevWallet.d.mts.map +1 -1
- package/dist/react/useDevWallet.mjs +9 -14
- package/dist/react/useDevWallet.mjs.map +1 -1
- package/dist/server/cli-signing-middleware.mjs +7 -20
- package/dist/server/cli-signing-middleware.mjs.map +1 -1
- package/dist/server/index.mjs +1 -2
- package/dist/standalone/assets/{in-memory-adapter-CBF4h2KD.js → in-memory-adapter-qRkNfj9O.js} +1 -1
- package/dist/standalone/assets/main-DDltQnzR.js +3954 -0
- package/dist/standalone/assets/{webcrypto-adapter-DysAubFb.js → webcrypto-adapter-FejcrL9x.js} +1 -1
- package/dist/standalone/index.html +11 -12
- package/dist/ui/copy-controller.mjs +3 -3
- package/dist/ui/copy-controller.mjs.map +1 -1
- package/dist/ui/dev-wallet-account-selector.d.mts +3 -4
- package/dist/ui/dev-wallet-account-selector.d.mts.map +1 -1
- package/dist/ui/dev-wallet-account-selector.mjs +48 -25
- package/dist/ui/dev-wallet-account-selector.mjs.map +1 -1
- package/dist/ui/dev-wallet-accounts.d.mts +9 -4
- package/dist/ui/dev-wallet-accounts.d.mts.map +1 -1
- package/dist/ui/dev-wallet-accounts.mjs +62 -140
- package/dist/ui/dev-wallet-accounts.mjs.map +1 -1
- package/dist/ui/dev-wallet-balances.d.mts +10 -3
- package/dist/ui/dev-wallet-balances.d.mts.map +1 -1
- package/dist/ui/dev-wallet-balances.mjs +241 -43
- package/dist/ui/dev-wallet-balances.mjs.map +1 -1
- package/dist/ui/dev-wallet-connect.d.mts +3 -3
- package/dist/ui/dev-wallet-connect.d.mts.map +1 -1
- package/dist/ui/dev-wallet-connect.mjs +24 -16
- package/dist/ui/dev-wallet-connect.mjs.map +1 -1
- package/dist/ui/dev-wallet-dropdown.d.mts +3 -3
- package/dist/ui/dev-wallet-dropdown.d.mts.map +1 -1
- package/dist/ui/dev-wallet-dropdown.mjs +37 -47
- package/dist/ui/dev-wallet-dropdown.mjs.map +1 -1
- package/dist/ui/dev-wallet-fork-panel.d.mts +43 -0
- package/dist/ui/dev-wallet-fork-panel.d.mts.map +1 -0
- package/dist/ui/dev-wallet-fork-panel.mjs +500 -0
- package/dist/ui/dev-wallet-fork-panel.mjs.map +1 -0
- package/dist/ui/dev-wallet-network-badge.d.mts +3 -4
- package/dist/ui/dev-wallet-network-badge.d.mts.map +1 -1
- package/dist/ui/dev-wallet-network-badge.mjs +52 -21
- package/dist/ui/dev-wallet-network-badge.mjs.map +1 -1
- package/dist/ui/dev-wallet-new-account.d.mts +3 -4
- package/dist/ui/dev-wallet-new-account.d.mts.map +1 -1
- package/dist/ui/dev-wallet-new-account.mjs +31 -105
- package/dist/ui/dev-wallet-new-account.mjs.map +1 -1
- package/dist/ui/dev-wallet-objects.d.mts +3 -3
- package/dist/ui/dev-wallet-objects.d.mts.map +1 -1
- package/dist/ui/dev-wallet-objects.mjs +76 -39
- package/dist/ui/dev-wallet-objects.mjs.map +1 -1
- package/dist/ui/dev-wallet-panel.d.mts +24 -4
- package/dist/ui/dev-wallet-panel.d.mts.map +1 -1
- package/dist/ui/dev-wallet-panel.mjs +247 -64
- package/dist/ui/dev-wallet-panel.mjs.map +1 -1
- package/dist/ui/dev-wallet-popup.d.mts +3 -5
- package/dist/ui/dev-wallet-popup.d.mts.map +1 -1
- package/dist/ui/dev-wallet-popup.mjs +19 -15
- package/dist/ui/dev-wallet-popup.mjs.map +1 -1
- package/dist/ui/dev-wallet-settings.d.mts +3 -4
- package/dist/ui/dev-wallet-settings.d.mts.map +1 -1
- package/dist/ui/dev-wallet-settings.mjs +149 -97
- package/dist/ui/dev-wallet-settings.mjs.map +1 -1
- package/dist/ui/dev-wallet-signing-modal.d.mts +11 -4
- package/dist/ui/dev-wallet-signing-modal.d.mts.map +1 -1
- package/dist/ui/dev-wallet-signing-modal.mjs +46 -18
- package/dist/ui/dev-wallet-signing-modal.mjs.map +1 -1
- package/dist/ui/dev-wallet-signing.d.mts +9 -3
- package/dist/ui/dev-wallet-signing.d.mts.map +1 -1
- package/dist/ui/dev-wallet-signing.mjs +119 -130
- package/dist/ui/dev-wallet-signing.mjs.map +1 -1
- package/dist/ui/dev-wallet-standalone.d.mts +8 -3
- package/dist/ui/dev-wallet-standalone.d.mts.map +1 -1
- package/dist/ui/dev-wallet-standalone.mjs +303 -38
- package/dist/ui/dev-wallet-standalone.mjs.map +1 -1
- package/dist/ui/dev-wallet-tab-bar.d.mts +13 -5
- package/dist/ui/dev-wallet-tab-bar.d.mts.map +1 -1
- package/dist/ui/dev-wallet-tab-bar.mjs +143 -82
- package/dist/ui/dev-wallet-tab-bar.mjs.map +1 -1
- package/dist/ui/index.d.mts +3 -2
- package/dist/ui/index.mjs +2 -2
- package/dist/ui/mount.d.mts +14 -1
- package/dist/ui/mount.d.mts.map +1 -1
- package/dist/ui/mount.mjs +5 -2
- package/dist/ui/mount.mjs.map +1 -1
- package/dist/ui/styles.mjs +428 -66
- package/dist/ui/styles.mjs.map +1 -1
- package/dist/ui/transaction-analyzer.mjs +19 -30
- package/dist/ui/transaction-analyzer.mjs.map +1 -1
- package/dist/ui/utils.d.mts +59 -0
- package/dist/ui/utils.d.mts.map +1 -0
- package/dist/ui/utils.mjs +42 -15
- package/dist/ui/utils.mjs.map +1 -1
- package/dist/ui/wallet-controller.mjs +89 -20
- package/dist/ui/wallet-controller.mjs.map +1 -1
- package/dist/wallet/constants.d.mts +9 -0
- package/dist/wallet/constants.d.mts.map +1 -0
- package/dist/wallet/constants.mjs +1 -1
- package/dist/wallet/dev-wallet.mjs +42 -99
- package/dist/wallet/dev-wallet.mjs.map +1 -1
- package/dist/wallet/initializer.d.mts +3 -0
- package/dist/wallet/initializer.d.mts.map +1 -1
- package/dist/wallet/initializer.mjs +9 -14
- package/dist/wallet/initializer.mjs.map +1 -1
- package/dist/wallet/signing.mjs +8 -21
- package/dist/wallet/signing.mjs.map +1 -1
- package/package.json +8 -6
- package/src/adapters/browser.ts +21 -0
- package/src/adapters/devstack-adapter.ts +342 -0
- package/src/adapters/devstack-paths.ts +15 -0
- package/src/adapters/fork-relay.ts +321 -0
- package/src/app/index.html +10 -11
- package/src/react/useDevWallet.ts +5 -1
- package/src/ui/dev-wallet-account-selector.ts +44 -17
- package/src/ui/dev-wallet-accounts.ts +87 -124
- package/src/ui/dev-wallet-balances.ts +248 -27
- package/src/ui/dev-wallet-connect.ts +19 -8
- package/src/ui/dev-wallet-dropdown.ts +7 -5
- package/src/ui/dev-wallet-fork-panel.ts +591 -0
- package/src/ui/dev-wallet-network-badge.ts +49 -10
- package/src/ui/dev-wallet-new-account.ts +21 -62
- package/src/ui/dev-wallet-objects.ts +59 -19
- package/src/ui/dev-wallet-panel.ts +261 -42
- package/src/ui/dev-wallet-popup.ts +12 -6
- package/src/ui/dev-wallet-settings.ts +159 -94
- package/src/ui/dev-wallet-signing-modal.ts +47 -7
- package/src/ui/dev-wallet-signing.ts +124 -97
- package/src/ui/dev-wallet-standalone.ts +310 -22
- package/src/ui/dev-wallet-tab-bar.ts +132 -70
- package/src/ui/index.ts +3 -0
- package/src/ui/mount.ts +23 -1
- package/src/ui/styles.ts +434 -58
- package/src/ui/utils.ts +66 -0
- package/src/ui/wallet-controller.ts +103 -5
- package/src/wallet/initializer.ts +7 -1
- package/dist/standalone/assets/main-VE4olb-Q.js +0 -2841
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mysten-incubation/dev-wallet",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "A modular dev wallet for Sui",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Mysten Labs <build@mystenlabs.com>",
|
|
@@ -64,19 +64,20 @@
|
|
|
64
64
|
"devDependencies": {
|
|
65
65
|
"@lit/react": "^1.0.8",
|
|
66
66
|
"@mysten/signers": "^1.0.1",
|
|
67
|
-
"@mysten/sui": "^2.
|
|
67
|
+
"@mysten/sui": "^2.17.0",
|
|
68
|
+
"@testing-library/dom": "^10.4.1",
|
|
68
69
|
"@testing-library/react": "^16.3.1",
|
|
69
70
|
"@types/node": "^25.0.8",
|
|
70
71
|
"@types/react": "^19.2.8",
|
|
71
|
-
"@vitest/browser": "^4.
|
|
72
|
-
"@vitest/browser-playwright": "^4.
|
|
72
|
+
"@vitest/browser": "^4.1.6",
|
|
73
|
+
"@vitest/browser-playwright": "^4.1.6",
|
|
73
74
|
"happy-dom": "^20.1.0",
|
|
74
75
|
"playwright": "*",
|
|
75
76
|
"react": "^19.2.3",
|
|
76
77
|
"react-dom": "^19.2.3",
|
|
77
78
|
"typescript": "^5.9.3",
|
|
78
79
|
"vite": "^7.3.1",
|
|
79
|
-
"vitest": "^4.
|
|
80
|
+
"vitest": "^4.1.6"
|
|
80
81
|
},
|
|
81
82
|
"dependencies": {
|
|
82
83
|
"@hono/node-server": "^1.19.9",
|
|
@@ -90,7 +91,7 @@
|
|
|
90
91
|
"peerDependencies": {
|
|
91
92
|
"@lit/react": "^1.0.8",
|
|
92
93
|
"@mysten/signers": "^1.0.1",
|
|
93
|
-
"@mysten/sui": "^2.
|
|
94
|
+
"@mysten/sui": "^2.17.0",
|
|
94
95
|
"@types/react": ">=17.0.0",
|
|
95
96
|
"react": ">=17.0.0"
|
|
96
97
|
},
|
|
@@ -110,6 +111,7 @@
|
|
|
110
111
|
},
|
|
111
112
|
"scripts": {
|
|
112
113
|
"clean": "rm -rf tsconfig.tsbuildinfo ./dist",
|
|
114
|
+
"build:docs": "tsx ../docs/scripts/build-docs.ts",
|
|
113
115
|
"build": "rm -rf dist && tsc --noEmit && tsdown && vite build --config vite.standalone.config.ts && vite build --config vite.bookmarklet.config.ts",
|
|
114
116
|
"prettier:check": "prettier -c --ignore-unknown .",
|
|
115
117
|
"prettier:fix": "prettier -w --ignore-unknown .",
|
package/src/adapters/browser.ts
CHANGED
|
@@ -11,5 +11,26 @@ export { BaseSignerAdapter } from './base-adapter.js';
|
|
|
11
11
|
export { buildManagedAccount } from './build-managed-account.js';
|
|
12
12
|
export { InMemorySignerAdapter } from './in-memory-adapter.js';
|
|
13
13
|
export { RemoteCliAdapter, CliProxySigner } from './remote-cli-adapter.js';
|
|
14
|
+
export {
|
|
15
|
+
DevstackSignerAdapter,
|
|
16
|
+
DevstackProxySigner,
|
|
17
|
+
parseDevstackToken,
|
|
18
|
+
createDevstackAdapterFromManifest,
|
|
19
|
+
type DevstackSignerAdapterOptions,
|
|
20
|
+
type DevstackAdapterManifest,
|
|
21
|
+
} from './devstack-adapter.js';
|
|
22
|
+
// Wire-level HTTP path contract mirrored from devstack's wallet plugin;
|
|
23
|
+
// kept duplicated to avoid closing a workspace cycle.
|
|
24
|
+
export { DEVSTACK_WALLET_HTTP_PATH, type DevstackWalletHttpPathValue } from './devstack-paths.js';
|
|
25
|
+
export {
|
|
26
|
+
ForkRelay,
|
|
27
|
+
ForkRelayHttpError,
|
|
28
|
+
createForkRelayFromManifest,
|
|
29
|
+
type ForkRelayManifest,
|
|
30
|
+
type ForkRelayOptions,
|
|
31
|
+
type ForkRelayResult,
|
|
32
|
+
type ForkStatus,
|
|
33
|
+
type ForkImpersonationSlot,
|
|
34
|
+
} from './fork-relay.js';
|
|
14
35
|
export { WebCryptoSignerAdapter } from './webcrypto-adapter.js';
|
|
15
36
|
export { PasskeySignerAdapter } from './passkey-adapter.js';
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
// Copyright (c) Mysten Labs, Inc.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
//
|
|
4
|
+
// Devstack signer adapter — exposes accounts resolved by `devstack up`'s
|
|
5
|
+
// `wallet()` plugin to dApp Kit, signing transactions over HTTP so
|
|
6
|
+
// private keys never enter the frontend bundle. Mirrors RemoteCliAdapter's
|
|
7
|
+
// out-of-process model; the difference is the source of accounts (devstack
|
|
8
|
+
// resolved signers vs `sui keytool list`) and the endpoint paths.
|
|
9
|
+
|
|
10
|
+
import { Signer } from '@mysten/sui/cryptography';
|
|
11
|
+
import type { PublicKey, SignatureScheme } from '@mysten/sui/cryptography';
|
|
12
|
+
import { Ed25519PublicKey } from '@mysten/sui/keypairs/ed25519';
|
|
13
|
+
import { Secp256k1PublicKey } from '@mysten/sui/keypairs/secp256k1';
|
|
14
|
+
import { Secp256r1PublicKey } from '@mysten/sui/keypairs/secp256r1';
|
|
15
|
+
import { fromBase64, toBase64 } from '@mysten/sui/utils';
|
|
16
|
+
|
|
17
|
+
import type { ManagedAccount } from '../types.js';
|
|
18
|
+
import { BaseSignerAdapter } from './base-adapter.js';
|
|
19
|
+
import { buildManagedAccount } from './build-managed-account.js';
|
|
20
|
+
import { DEVSTACK_WALLET_HTTP_PATH } from './devstack-paths.js';
|
|
21
|
+
|
|
22
|
+
const DEVSTACK_WALLET_FEATURES = [
|
|
23
|
+
'sui:signTransaction',
|
|
24
|
+
'sui:signAndExecuteTransaction',
|
|
25
|
+
'sui:signPersonalMessage',
|
|
26
|
+
] as const;
|
|
27
|
+
|
|
28
|
+
interface ServerAccountInfo {
|
|
29
|
+
name: string;
|
|
30
|
+
address: string;
|
|
31
|
+
scheme: SignatureScheme;
|
|
32
|
+
publicKey: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
class AuthError extends Error {
|
|
36
|
+
constructor() {
|
|
37
|
+
super('Unauthorized');
|
|
38
|
+
this.name = 'AuthError';
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function publicKeyForScheme(base64: string, scheme: SignatureScheme | string): PublicKey {
|
|
43
|
+
const bytes = fromBase64(base64);
|
|
44
|
+
// The devstack server's wallet-app endpoint surfaces the scheme in
|
|
45
|
+
// the lowercase form it standardised at the Account boundary
|
|
46
|
+
// (`'ed25519'`, `'secp256k1'`, `'secp256r1'`). The Sui SDK's
|
|
47
|
+
// `SignatureScheme` union is mixed-case (`'ED25519'`, `'Secp256k1'`,
|
|
48
|
+
// …). Normalise to lowercase before matching so either casing parses.
|
|
49
|
+
switch (String(scheme).toLowerCase()) {
|
|
50
|
+
case 'ed25519':
|
|
51
|
+
return new Ed25519PublicKey(bytes);
|
|
52
|
+
case 'secp256k1':
|
|
53
|
+
return new Secp256k1PublicKey(bytes);
|
|
54
|
+
case 'secp256r1':
|
|
55
|
+
return new Secp256r1PublicKey(bytes);
|
|
56
|
+
default:
|
|
57
|
+
throw new Error(`Unsupported key scheme: ${scheme}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Signer that delegates transaction signing to the devstack wallet-app
|
|
63
|
+
* over HTTP. Mirrors {@link CliProxySigner} but talks to the
|
|
64
|
+
* `wallet()` plugin's endpoints under `/api/v1/devstack/*`.
|
|
65
|
+
*/
|
|
66
|
+
export class DevstackProxySigner extends Signer {
|
|
67
|
+
#address: string;
|
|
68
|
+
#publicKey: PublicKey;
|
|
69
|
+
#scheme: SignatureScheme;
|
|
70
|
+
#serverOrigin: string;
|
|
71
|
+
#authToken: string | null;
|
|
72
|
+
|
|
73
|
+
constructor(options: {
|
|
74
|
+
address: string;
|
|
75
|
+
publicKey: PublicKey;
|
|
76
|
+
scheme: SignatureScheme;
|
|
77
|
+
serverOrigin: string;
|
|
78
|
+
authToken?: string | null;
|
|
79
|
+
}) {
|
|
80
|
+
super();
|
|
81
|
+
this.#address = options.address;
|
|
82
|
+
this.#publicKey = options.publicKey;
|
|
83
|
+
this.#scheme = options.scheme;
|
|
84
|
+
this.#serverOrigin = options.serverOrigin;
|
|
85
|
+
this.#authToken = options.authToken ?? null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async sign(_bytes: Uint8Array): Promise<Uint8Array<ArrayBuffer>> {
|
|
89
|
+
throw new Error(
|
|
90
|
+
'DevstackProxySigner does not support raw digest signing. ' +
|
|
91
|
+
'Use signTransaction (the wallet-app signs BCS-serialized TransactionData).',
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
getKeyScheme(): SignatureScheme {
|
|
96
|
+
return this.#scheme;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
getPublicKey(): PublicKey {
|
|
100
|
+
return this.#publicKey;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
override toSuiAddress(): string {
|
|
104
|
+
return this.#address;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
override async signTransaction(bytes: Uint8Array) {
|
|
108
|
+
const headers: Record<string, string> = { 'Content-Type': 'application/json' };
|
|
109
|
+
if (this.#authToken !== null) {
|
|
110
|
+
headers['Authorization'] = `Bearer ${this.#authToken}`;
|
|
111
|
+
}
|
|
112
|
+
const requestBytes = toBase64(bytes);
|
|
113
|
+
const res = await fetch(`${this.#serverOrigin}${DEVSTACK_WALLET_HTTP_PATH.SIGN_TRANSACTION}`, {
|
|
114
|
+
method: 'POST',
|
|
115
|
+
headers,
|
|
116
|
+
body: JSON.stringify({
|
|
117
|
+
address: this.#address,
|
|
118
|
+
bytes: requestBytes,
|
|
119
|
+
}),
|
|
120
|
+
});
|
|
121
|
+
if (!res.ok) {
|
|
122
|
+
const body = await res.json().catch(() => ({}));
|
|
123
|
+
const message = (body as { error?: unknown }).error;
|
|
124
|
+
throw new Error(
|
|
125
|
+
`Devstack signing failed: ${typeof message === 'string' ? message : res.statusText}`,
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
const { bytes: responseBytes, signature } = (await res.json()) as {
|
|
129
|
+
bytes?: string;
|
|
130
|
+
signature?: string;
|
|
131
|
+
};
|
|
132
|
+
if (typeof responseBytes !== 'string' || responseBytes.length === 0) {
|
|
133
|
+
throw new Error('Devstack signing failed: server returned invalid signed bytes');
|
|
134
|
+
}
|
|
135
|
+
if (typeof signature !== 'string' || signature.length === 0) {
|
|
136
|
+
throw new Error('Devstack signing failed: server returned invalid signature');
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
bytes: responseBytes,
|
|
140
|
+
signature,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
override async signPersonalMessage(bytes: Uint8Array) {
|
|
145
|
+
const headers: Record<string, string> = { 'Content-Type': 'application/json' };
|
|
146
|
+
if (this.#authToken !== null) {
|
|
147
|
+
headers['Authorization'] = `Bearer ${this.#authToken}`;
|
|
148
|
+
}
|
|
149
|
+
const res = await fetch(
|
|
150
|
+
`${this.#serverOrigin}${DEVSTACK_WALLET_HTTP_PATH.SIGN_PERSONAL_MESSAGE}`,
|
|
151
|
+
{
|
|
152
|
+
method: 'POST',
|
|
153
|
+
headers,
|
|
154
|
+
body: JSON.stringify({
|
|
155
|
+
address: this.#address,
|
|
156
|
+
bytes: toBase64(bytes),
|
|
157
|
+
}),
|
|
158
|
+
},
|
|
159
|
+
);
|
|
160
|
+
if (!res.ok) {
|
|
161
|
+
const body = await res.json().catch(() => ({}));
|
|
162
|
+
const message = (body as { error?: unknown }).error;
|
|
163
|
+
throw new Error(
|
|
164
|
+
`Devstack personal-message signing failed: ${
|
|
165
|
+
typeof message === 'string' ? message : res.statusText
|
|
166
|
+
}`,
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
const { bytes: responseBytes, signature } = (await res.json()) as {
|
|
170
|
+
bytes?: string;
|
|
171
|
+
signature?: string;
|
|
172
|
+
};
|
|
173
|
+
if (typeof responseBytes !== 'string' || responseBytes.length === 0) {
|
|
174
|
+
throw new Error(
|
|
175
|
+
'Devstack personal-message signing failed: server returned invalid signed bytes',
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
if (typeof signature !== 'string' || signature.length === 0) {
|
|
179
|
+
throw new Error('Devstack personal-message signing failed: server returned no signature');
|
|
180
|
+
}
|
|
181
|
+
return { bytes: responseBytes, signature };
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export interface DevstackSignerAdapterOptions {
|
|
186
|
+
/** Wallet-app origin (e.g. `http://localhost:9420`). Read from the
|
|
187
|
+
* matching endpoint entry on the active manifest. */
|
|
188
|
+
serverOrigin: string;
|
|
189
|
+
/** Bearer token. Parse `?token=<hex>` from the manifest entry's
|
|
190
|
+
* `pairUrl`. Omit if the wallet-app runs without auth. */
|
|
191
|
+
token?: string | null;
|
|
192
|
+
/** Override the adapter's display name. Defaults to `'Devstack'`. */
|
|
193
|
+
name?: string;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* {@link SignerAdapter} that surfaces every account resolved by `devstack up`
|
|
198
|
+
* (including `cliSigner`/`envSigner`/`generatedKeypair` slots) without
|
|
199
|
+
* shipping their private keys into the frontend bundle. All signing happens
|
|
200
|
+
* server-side via the `wallet()` plugin.
|
|
201
|
+
*
|
|
202
|
+
* The simplest construction uses devstack's generated `dapp-kit-config.ts`,
|
|
203
|
+
* which bakes the wallet adapter wiring at codegen time — apps spread
|
|
204
|
+
* `devstackDappKitConfig` into `createDAppKit(...)` and never touch the
|
|
205
|
+
* adapter directly.
|
|
206
|
+
*
|
|
207
|
+
* To construct one manually (e.g. from a non-manifest source):
|
|
208
|
+
*
|
|
209
|
+
* ```ts
|
|
210
|
+
* const adapter = new DevstackSignerAdapter({
|
|
211
|
+
* serverOrigin: 'http://localhost:9420',
|
|
212
|
+
* token: '<bearer hex>',
|
|
213
|
+
* });
|
|
214
|
+
* ```
|
|
215
|
+
*/
|
|
216
|
+
export class DevstackSignerAdapter extends BaseSignerAdapter {
|
|
217
|
+
readonly id = 'devstack';
|
|
218
|
+
readonly name: string;
|
|
219
|
+
readonly allowAutoSign = true;
|
|
220
|
+
|
|
221
|
+
#serverOrigin: string;
|
|
222
|
+
#authToken: string | null;
|
|
223
|
+
|
|
224
|
+
constructor(options: DevstackSignerAdapterOptions) {
|
|
225
|
+
super();
|
|
226
|
+
try {
|
|
227
|
+
new URL(options.serverOrigin);
|
|
228
|
+
} catch {
|
|
229
|
+
throw new Error(`DevstackSignerAdapter: invalid serverOrigin "${options.serverOrigin}"`);
|
|
230
|
+
}
|
|
231
|
+
this.#serverOrigin = options.serverOrigin;
|
|
232
|
+
this.#authToken = options.token ?? null;
|
|
233
|
+
this.name = options.name ?? 'Devstack';
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async initialize(): Promise<void> {
|
|
237
|
+
try {
|
|
238
|
+
const accounts = await this.#fetchAccounts();
|
|
239
|
+
this.setInitialAccounts(accounts);
|
|
240
|
+
} catch (error) {
|
|
241
|
+
if (error instanceof AuthError) {
|
|
242
|
+
console.warn('[dev-wallet] devstack adapter: unauthorized — skipping account import');
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
console.warn('[dev-wallet] devstack adapter: initialization failed:', error);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
override destroy(): void {
|
|
250
|
+
this.#authToken = null;
|
|
251
|
+
super.destroy();
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
async #fetchAccounts(): Promise<ManagedAccount[]> {
|
|
255
|
+
const headers: Record<string, string> = { 'Content-Type': 'application/json' };
|
|
256
|
+
if (this.#authToken !== null) {
|
|
257
|
+
headers['Authorization'] = `Bearer ${this.#authToken}`;
|
|
258
|
+
}
|
|
259
|
+
const res = await fetch(`${this.#serverOrigin}${DEVSTACK_WALLET_HTTP_PATH.ACCOUNTS}`, {
|
|
260
|
+
headers,
|
|
261
|
+
});
|
|
262
|
+
if (res.status === 401 || res.status === 403) throw new AuthError();
|
|
263
|
+
if (!res.ok) {
|
|
264
|
+
throw new Error(`Failed to fetch devstack accounts: ${res.statusText}`);
|
|
265
|
+
}
|
|
266
|
+
const { accounts } = (await res.json()) as { accounts: ServerAccountInfo[] };
|
|
267
|
+
return accounts.map((info) => {
|
|
268
|
+
const publicKey = publicKeyForScheme(info.publicKey, info.scheme);
|
|
269
|
+
const signer = new DevstackProxySigner({
|
|
270
|
+
address: info.address,
|
|
271
|
+
publicKey,
|
|
272
|
+
scheme: info.scheme,
|
|
273
|
+
serverOrigin: this.#serverOrigin,
|
|
274
|
+
authToken: this.#authToken,
|
|
275
|
+
});
|
|
276
|
+
return buildManagedAccount(signer, info.address, info.name, DEVSTACK_WALLET_FEATURES);
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Pull the bearer token off a paired URL produced by the `wallet()`
|
|
283
|
+
* plugin. Returns `null` if the input is undefined, malformed, or
|
|
284
|
+
* carries a `<redacted>` placeholder (the manifest's pairUrl carries
|
|
285
|
+
* the redacted form; the real token lives in a sibling 0o600 file the
|
|
286
|
+
* consumer reads separately).
|
|
287
|
+
*
|
|
288
|
+
* The token rides in the URL fragment as `#token=<hex>`.
|
|
289
|
+
*/
|
|
290
|
+
export function parseDevstackToken(pairedUrl: string | undefined): string | null {
|
|
291
|
+
if (pairedUrl === undefined) return null;
|
|
292
|
+
try {
|
|
293
|
+
const url = new URL(pairedUrl);
|
|
294
|
+
const hash = url.hash; // e.g. "#token=abcd"
|
|
295
|
+
if (hash.length <= 1) return null;
|
|
296
|
+
const params = new URLSearchParams(hash.slice(1));
|
|
297
|
+
const token = params.get('token');
|
|
298
|
+
if (token === null || token === '<redacted>') return null;
|
|
299
|
+
return token;
|
|
300
|
+
} catch {
|
|
301
|
+
return null;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/** Narrow input — the only field the adapter consumes is
|
|
306
|
+
* `app.wallet.{url, pairUrl}`. Codegen emits exactly this shape so
|
|
307
|
+
* generated `dapp-kit-config.ts` doesn't have to fabricate placeholder
|
|
308
|
+
* manifest fields (`stack.app`, `coins`, etc.) just to satisfy the
|
|
309
|
+
* full `Manifest` type. Mirrors a slice of `AppManifest` from
|
|
310
|
+
* `@mysten-incubation/devstack` without importing it (dev-wallet
|
|
311
|
+
* doesn't depend on devstack — circular). */
|
|
312
|
+
export interface DevstackAdapterManifest {
|
|
313
|
+
app?: {
|
|
314
|
+
wallet?: {
|
|
315
|
+
url: string;
|
|
316
|
+
pairUrl?: string;
|
|
317
|
+
};
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Convenience: read the wallet-app endpoint off a devstack manifest and
|
|
323
|
+
* build a configured adapter, or return `null` when the entry isn't
|
|
324
|
+
* present (no `wallet(...)` in the stack, or it hasn't come up yet).
|
|
325
|
+
*
|
|
326
|
+
* The wallet entry's `pairUrl` carries the `#token=…` fragment used to
|
|
327
|
+
* extract the bearer token. The full `Manifest` shape from
|
|
328
|
+
* `@mysten-incubation/devstack` is structurally compatible with
|
|
329
|
+
* {@link DevstackAdapterManifest}, so
|
|
330
|
+
* `createDevstackAdapterFromManifest(devstackManifest)` typechecks
|
|
331
|
+
* without a cast.
|
|
332
|
+
*/
|
|
333
|
+
export function createDevstackAdapterFromManifest(
|
|
334
|
+
manifest: DevstackAdapterManifest,
|
|
335
|
+
): DevstackSignerAdapter | null {
|
|
336
|
+
const wallet = manifest.app?.wallet;
|
|
337
|
+
if (wallet === undefined) return null;
|
|
338
|
+
return new DevstackSignerAdapter({
|
|
339
|
+
serverOrigin: wallet.url,
|
|
340
|
+
token: parseDevstackToken(wallet.pairUrl),
|
|
341
|
+
});
|
|
342
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Mirror of `packages/devstack/src/plugins/wallet/protocol.ts` `WalletHttpPath`.
|
|
2
|
+
// Duplicated here rather than imported because devstack already
|
|
3
|
+
// (peer-)depends on `@mysten-incubation/dev-wallet` for codegen-emitted
|
|
4
|
+
// wallet glue, and adding the reverse edge would close the workspace
|
|
5
|
+
// cycle and break turbo's build ordering.
|
|
6
|
+
|
|
7
|
+
export const DEVSTACK_WALLET_HTTP_PATH = {
|
|
8
|
+
HEALTH: '/api/v1/devstack/health',
|
|
9
|
+
ACCOUNTS: '/api/v1/devstack/accounts',
|
|
10
|
+
SIGN_TRANSACTION: '/api/v1/devstack/sign-transaction',
|
|
11
|
+
SIGN_PERSONAL_MESSAGE: '/api/v1/devstack/sign-personal-message',
|
|
12
|
+
} as const;
|
|
13
|
+
|
|
14
|
+
export type DevstackWalletHttpPathValue =
|
|
15
|
+
(typeof DEVSTACK_WALLET_HTTP_PATH)[keyof typeof DEVSTACK_WALLET_HTTP_PATH];
|