@meshconnect/uwc-injected-connector 0.11.0 → 0.12.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/dist/injected-connector.d.ts +8 -0
- package/dist/injected-connector.d.ts.map +1 -1
- package/dist/injected-connector.js +90 -0
- package/dist/injected-connector.js.map +1 -1
- package/dist/utils/solana-account-utils.d.ts +9 -0
- package/dist/utils/solana-account-utils.d.ts.map +1 -0
- package/dist/utils/solana-account-utils.js +19 -0
- package/dist/utils/solana-account-utils.js.map +1 -0
- package/dist/wallet-standard-discovery.d.ts +2 -1
- package/dist/wallet-standard-discovery.d.ts.map +1 -1
- package/dist/wallet-standard-discovery.js.map +1 -1
- package/package.json +4 -4
- package/src/injected-connector.ts +112 -0
- package/src/signSolanaTransactionBytes.test.ts +747 -0
- package/src/utils/solana-account-utils.ts +24 -0
- package/src/wallet-standard-discovery.ts +7 -0
|
@@ -41,5 +41,13 @@ export declare class InjectedConnector implements Connector {
|
|
|
41
41
|
* wallet_getCapabilities and the hex address format it requires.
|
|
42
42
|
*/
|
|
43
43
|
getWalletCapabilities(from: string, networks: Network[]): Promise<Record<string, EVMCapabilities>>;
|
|
44
|
+
/**
|
|
45
|
+
* Sign serialized Solana tx bytes without broadcasting (raw bytes in/out, no
|
|
46
|
+
* @solana/web3.js for callers). Tries: bridge (iframe) → Wallet Standard
|
|
47
|
+
* feature → legacy adapter. The feature path avoids Transaction.serialize(),
|
|
48
|
+
* which crashes some mobile WebViews. Errors go through parseError (typed
|
|
49
|
+
* "rejected" on user cancel).
|
|
50
|
+
*/
|
|
51
|
+
signSolanaTransactionBytes(serializedTx: Uint8Array): Promise<Uint8Array>;
|
|
44
52
|
}
|
|
45
53
|
//# sourceMappingURL=injected-connector.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"injected-connector.d.ts","sourceRoot":"","sources":["../src/injected-connector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EAEP,yBAAyB,EACzB,iCAAiC,EACjC,SAAS,EACT,eAAe,EACf,mBAAmB,EACnB,SAAS,EACT,yBAAyB,EACzB,wBAAwB,EACxB,sBAAsB,EACtB,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EAEjB,aAAa,EACb,eAAe,EACf,aAAa,EACb,cAAc,EACd,gBAAgB,EACjB,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"injected-connector.d.ts","sourceRoot":"","sources":["../src/injected-connector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EAEP,yBAAyB,EACzB,iCAAiC,EACjC,SAAS,EACT,eAAe,EACf,mBAAmB,EACnB,SAAS,EACT,yBAAyB,EACzB,wBAAwB,EACxB,sBAAsB,EACtB,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EAEjB,aAAa,EACb,eAAe,EACf,aAAa,EACb,cAAc,EACd,gBAAgB,EACjB,MAAM,wBAAwB,CAAA;AAkB/B,qBAAa,iBAAkB,YAAW,SAAS;IACjD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAgB;IAC/C,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,WAAW,CAAmB;IACtC,OAAO,CAAC,UAAU,CAAkB;IACpC,OAAO,CAAC,iBAAiB,CAAmB;IAC5C,OAAO,CAAC,gBAAgB,CAAkB;IAC1C,OAAO,CAAC,kBAAkB,CAAoB;IAC9C,OAAO,CAAC,aAAa,CAAe;IACpC,OAAO,CAAC,qBAAqB,CAAqC;gBAGhE,aAAa,GAAE,aAAkB,EACjC,eAAe,GAAE,cAAc,EAAO,EACtC,gBAAgB,CAAC,EAAE,gBAAgB;IA8BrC;;OAEG;IACG,mBAAmB,CACvB,SAAS,EAAE,SAAS,EACpB,eAAe,GAAE,cAAc,EAAO,GACrC,OAAO,CACN,yBAAyB,EAAE,GAC3B,wBAAwB,EAAE,GAC1B,sBAAsB,EAAE,GACxB,qBAAqB,EAAE,CAC1B;IAwDD;;OAEG;IACG,OAAO,CACX,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,yBAAyB,GAAG,iCAAiC,GACtE,OAAO,CAAC,eAAe,CAAC;IAyC3B;;OAEG;IACG,aAAa,CACjB,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,yBAAyB,GAAG,iCAAiC,GACtE,OAAO,CAAC,mBAAmB,CAAC;IAI/B;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAIjC;;OAEG;IACG,WAAW,CACf,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,yBAAyB,GAAG,iCAAiC,GACtE,OAAO,CAAC,aAAa,CAAC;IAiFzB;;OAEG;IACG,eAAe,CACnB,OAAO,EAAE,kBAAkB,EAC3B,QAAQ,EAAE,yBAAyB,GAAG,iCAAiC,GACtE,OAAO,CAAC,iBAAiB,CAAC;IA+D7B;;;;OAIG;IACG,qBAAqB,CACzB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,OAAO,EAAE,GAClB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAS3C;;;;;;OAMG;IACG,0BAA0B,CAC9B,YAAY,EAAE,UAAU,GACvB,OAAO,CAAC,UAAU,CAAC;CAgGvB"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { assertSameMessage } from '@meshconnect/uwc-types';
|
|
2
|
+
import { Transaction, VersionedTransaction } from '@solana/web3.js';
|
|
1
3
|
import { BridgeChild } from '@meshconnect/uwc-bridge-child';
|
|
2
4
|
import { EthereumWalletService } from './services/ethereum/ethereum-wallet-service';
|
|
3
5
|
import { SolanaWalletService } from './services/solana/solana-wallet-service';
|
|
@@ -7,6 +9,8 @@ import { StorageService } from './services/storage-service';
|
|
|
7
9
|
import { ConnectionManager } from './services/connection-manager';
|
|
8
10
|
import { SignatureService } from './services/signature-service';
|
|
9
11
|
import { TransactionService } from './services/transaction-service';
|
|
12
|
+
import { parseError } from './utils/error-utils';
|
|
13
|
+
import { resolveSigningAccount } from './utils/solana-account-utils';
|
|
10
14
|
export class InjectedConnector {
|
|
11
15
|
storageService;
|
|
12
16
|
ethereumService;
|
|
@@ -246,5 +250,91 @@ export class InjectedConnector {
|
|
|
246
250
|
}
|
|
247
251
|
return await this.ethereumService.getCapabilities(from, networks);
|
|
248
252
|
}
|
|
253
|
+
/**
|
|
254
|
+
* Sign serialized Solana tx bytes without broadcasting (raw bytes in/out, no
|
|
255
|
+
* @solana/web3.js for callers). Tries: bridge (iframe) → Wallet Standard
|
|
256
|
+
* feature → legacy adapter. The feature path avoids Transaction.serialize(),
|
|
257
|
+
* which crashes some mobile WebViews. Errors go through parseError (typed
|
|
258
|
+
* "rejected" on user cancel).
|
|
259
|
+
*/
|
|
260
|
+
async signSolanaTransactionBytes(serializedTx) {
|
|
261
|
+
const currentNetworkId = this.connectionManager.getCurrentNetworkId();
|
|
262
|
+
if (!currentNetworkId?.startsWith('solana:')) {
|
|
263
|
+
throw new Error('signSolanaTransactionBytes requires an active Solana connection');
|
|
264
|
+
}
|
|
265
|
+
const solanaAdapter = this.solanaService.getConnectedAdapter();
|
|
266
|
+
if (!solanaAdapter) {
|
|
267
|
+
throw new Error('No connected Solana adapter');
|
|
268
|
+
}
|
|
269
|
+
try {
|
|
270
|
+
// Path 1: bridge (iframe). The wallet lives on the parent; forward bytes.
|
|
271
|
+
// `await customFunctions` (not a truthy check) — Comlink proxies every
|
|
272
|
+
// property as truthy, so the awaited list is the only reliable signal.
|
|
273
|
+
const extendedAdapter = solanaAdapter;
|
|
274
|
+
const customFns = await extendedAdapter.customFunctions;
|
|
275
|
+
if (customFns?.includes('signSolanaTransactionBytes')) {
|
|
276
|
+
// Sign with the child's connected account — the parent's publicKey may
|
|
277
|
+
// have drifted.
|
|
278
|
+
const signed = await extendedAdapter.signSolanaTransactionBytes(serializedTx, this.connectionManager.getCurrentAccount() ?? undefined);
|
|
279
|
+
// Verify in the iframe (trusted), not on the parent, so a tampered
|
|
280
|
+
// parent can't bypass it. Byte-stable round-trip → safe for the bridge's
|
|
281
|
+
// legacy sub-path too (see the "byte-stable" test).
|
|
282
|
+
assertSameMessage(serializedTx, signed);
|
|
283
|
+
return signed;
|
|
284
|
+
}
|
|
285
|
+
// Path 2: Wallet Standard solana:signTransaction (raw bytes in/out).
|
|
286
|
+
const wallet = solanaAdapter.wallet;
|
|
287
|
+
const SIGN_TX = 'solana:signTransaction';
|
|
288
|
+
if (wallet && SIGN_TX in wallet.features && wallet.accounts.length > 0) {
|
|
289
|
+
const account = resolveSigningAccount(wallet.accounts, this.connectionManager.getCurrentAccount());
|
|
290
|
+
const feature = wallet.features[SIGN_TX];
|
|
291
|
+
const [output] = await feature.signTransaction({
|
|
292
|
+
account,
|
|
293
|
+
transaction: serializedTx
|
|
294
|
+
});
|
|
295
|
+
if (!output?.signedTransaction) {
|
|
296
|
+
throw new Error('Wallet returned no signed transaction');
|
|
297
|
+
}
|
|
298
|
+
// Reject a tampered message before the relay broadcasts.
|
|
299
|
+
assertSameMessage(serializedTx, output.signedTransaction);
|
|
300
|
+
return output.signedTransaction;
|
|
301
|
+
}
|
|
302
|
+
// Path 3: legacy adapter (no .wallet getter).
|
|
303
|
+
if (!solanaAdapter.signTransaction) {
|
|
304
|
+
throw new Error('Connected wallet does not support signTransaction');
|
|
305
|
+
}
|
|
306
|
+
// V0 + legacy. requireAllSignatures:false — the relay fills the fee-payer slot.
|
|
307
|
+
let transaction;
|
|
308
|
+
try {
|
|
309
|
+
transaction = VersionedTransaction.deserialize(serializedTx);
|
|
310
|
+
}
|
|
311
|
+
catch {
|
|
312
|
+
try {
|
|
313
|
+
transaction = Transaction.from(serializedTx);
|
|
314
|
+
}
|
|
315
|
+
catch {
|
|
316
|
+
throw new Error('Failed to deserialize transaction as either versioned or legacy format');
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
const signed = await solanaAdapter.signTransaction(transaction);
|
|
320
|
+
const signedBytes = signed instanceof VersionedTransaction
|
|
321
|
+
? signed.serialize()
|
|
322
|
+
: new Uint8Array(signed.serialize({
|
|
323
|
+
requireAllSignatures: false,
|
|
324
|
+
verifySignatures: false
|
|
325
|
+
}));
|
|
326
|
+
// Same guard as Path 1/2. The deserialize→sign→reserialize round-trip is
|
|
327
|
+
// byte-stable (see the "byte-stable" tests), so this rejects a tampering
|
|
328
|
+
// adapter without false-positiving a legit sign.
|
|
329
|
+
assertSameMessage(serializedTx, signedBytes);
|
|
330
|
+
return signedBytes;
|
|
331
|
+
}
|
|
332
|
+
catch (err) {
|
|
333
|
+
// Normalize: turns a wallet rejection (EIP-1193 4001 / "user rejected")
|
|
334
|
+
// into a WalletConnectorError{ type: 'rejected' } so the Link UI can tell
|
|
335
|
+
// "user cancelled" apart from a real failure. parseError always throws.
|
|
336
|
+
throw parseError(err);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
249
339
|
}
|
|
250
340
|
//# sourceMappingURL=injected-connector.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"injected-connector.js","sourceRoot":"","sources":["../src/injected-connector.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"injected-connector.js","sourceRoot":"","sources":["../src/injected-connector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pick which wallet account signs. We must sign with the account the user
|
|
3
|
+
* actually connected — never guess. A wrong signer produces a useless signature
|
|
4
|
+
* for a payment, so we throw instead of silently falling back.
|
|
5
|
+
*/
|
|
6
|
+
export declare function resolveSigningAccount<T extends {
|
|
7
|
+
address: string;
|
|
8
|
+
}>(accounts: ReadonlyArray<T>, connectedAddress: string | null | undefined): T;
|
|
9
|
+
//# sourceMappingURL=solana-account-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"solana-account-utils.d.ts","sourceRoot":"","sources":["../../src/utils/solana-account-utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,SAAS;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,EACjE,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,EAC1B,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC1C,CAAC,CAeH"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pick which wallet account signs. We must sign with the account the user
|
|
3
|
+
* actually connected — never guess. A wrong signer produces a useless signature
|
|
4
|
+
* for a payment, so we throw instead of silently falling back.
|
|
5
|
+
*/
|
|
6
|
+
export function resolveSigningAccount(accounts, connectedAddress) {
|
|
7
|
+
if (connectedAddress) {
|
|
8
|
+
const match = accounts.find(a => a.address === connectedAddress);
|
|
9
|
+
if (!match) {
|
|
10
|
+
throw new Error('Connected Solana account not found in the wallet — refusing to sign with a different account');
|
|
11
|
+
}
|
|
12
|
+
return match;
|
|
13
|
+
}
|
|
14
|
+
// No explicit selection is only safe when the wallet has exactly one account.
|
|
15
|
+
if (accounts.length === 1)
|
|
16
|
+
return accounts[0];
|
|
17
|
+
throw new Error('Cannot determine which Solana account to sign with — multiple accounts and none selected');
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=solana-account-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"solana-account-utils.js","sourceRoot":"","sources":["../../src/utils/solana-account-utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CACnC,QAA0B,EAC1B,gBAA2C;IAE3C,IAAI,gBAAgB,EAAE,CAAC;QACrB,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,gBAAgB,CAAC,CAAA;QAChE,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CACb,8FAA8F,CAC/F,CAAA;QACH,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC;IACD,8EAA8E;IAC9E,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,QAAQ,CAAC,CAAC,CAAE,CAAA;IAC9C,MAAM,IAAI,KAAK,CACb,0FAA0F,CAC3F,CAAA;AACH,CAAC"}
|
|
@@ -6,10 +6,11 @@
|
|
|
6
6
|
import { StandardWalletAdapter } from '@solana/wallet-standard-wallet-adapter-base';
|
|
7
7
|
import type { Transaction } from '@solana/web3.js';
|
|
8
8
|
export interface ExtendedStandardWalletAdapter extends StandardWalletAdapter {
|
|
9
|
-
customFunctions: ('sendSerializedTransaction' | 'signSerializedTransaction' | 'signAllSerializedTransactions')[];
|
|
9
|
+
customFunctions: ('sendSerializedTransaction' | 'signSerializedTransaction' | 'signAllSerializedTransactions' | 'signSolanaTransactionBytes')[];
|
|
10
10
|
sendSerializedTransaction: (transaction: unknown, rpcUrl: string) => Promise<string>;
|
|
11
11
|
signSerializedTransaction: (transaction: unknown) => Promise<Error | Transaction>;
|
|
12
12
|
signAllSerializedTransactions: (transactions: unknown[]) => Promise<Error | Transaction[]>;
|
|
13
|
+
signSolanaTransactionBytes: (transaction: unknown, connectedAddress?: string) => Promise<Uint8Array>;
|
|
13
14
|
}
|
|
14
15
|
export type SolanaAdapter = ExtendedStandardWalletAdapter | StandardWalletAdapter;
|
|
15
16
|
export interface WalletStandardInfo {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wallet-standard-discovery.d.ts","sourceRoot":"","sources":["../src/wallet-standard-discovery.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAE,qBAAqB,EAAE,MAAM,6CAA6C,CAAA;AACnF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAElD,MAAM,WAAW,6BAA8B,SAAQ,qBAAqB;IAC1E,eAAe,EAAE,CACb,2BAA2B,GAC3B,2BAA2B,GAC3B,+BAA+B,
|
|
1
|
+
{"version":3,"file":"wallet-standard-discovery.d.ts","sourceRoot":"","sources":["../src/wallet-standard-discovery.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAE,qBAAqB,EAAE,MAAM,6CAA6C,CAAA;AACnF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAElD,MAAM,WAAW,6BAA8B,SAAQ,qBAAqB;IAC1E,eAAe,EAAE,CACb,2BAA2B,GAC3B,2BAA2B,GAC3B,+BAA+B,GAC/B,4BAA4B,CAC/B,EAAE,CAAA;IACH,yBAAyB,EAAE,CACzB,WAAW,EAAE,OAAO,EACpB,MAAM,EAAE,MAAM,KACX,OAAO,CAAC,MAAM,CAAC,CAAA;IACpB,yBAAyB,EAAE,CACzB,WAAW,EAAE,OAAO,KACjB,OAAO,CAAC,KAAK,GAAG,WAAW,CAAC,CAAA;IACjC,6BAA6B,EAAE,CAC7B,YAAY,EAAE,OAAO,EAAE,KACpB,OAAO,CAAC,KAAK,GAAG,WAAW,EAAE,CAAC,CAAA;IAGnC,0BAA0B,EAAE,CAC1B,WAAW,EAAE,OAAO,EACpB,gBAAgB,CAAC,EAAE,MAAM,KACtB,OAAO,CAAC,UAAU,CAAC,CAAA;CACzB;AAED,MAAM,MAAM,aAAa,GACrB,6BAA6B,GAC7B,qBAAqB,CAAA;AAEzB,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,OAAO,EAAE,aAAa,GAAG,SAAS,CAAA;CACnC;AA6CD;;GAEG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAwCtE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wallet-standard-discovery.js","sourceRoot":"","sources":["../src/wallet-standard-discovery.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACjD,OAAO,EAAE,uCAAuC,EAAE,MAAM,6BAA6B,CAAA;AACrF,OAAO,EAAE,qBAAqB,EAAE,MAAM,6CAA6C,CAAA;
|
|
1
|
+
{"version":3,"file":"wallet-standard-discovery.js","sourceRoot":"","sources":["../src/wallet-standard-discovery.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meshconnect/uwc-injected-connector",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Injected connector for Universal Wallet Connector",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
"uuid": "^13.0.0",
|
|
29
29
|
"viem": "^2.44.4",
|
|
30
30
|
"@meshconnect/uwc-bridge-child": "0.2.1",
|
|
31
|
-
"@meshconnect/uwc-constants": "0.6.
|
|
32
|
-
"@meshconnect/uwc-ton-connector": "0.6.
|
|
33
|
-
"@meshconnect/uwc-types": "0.
|
|
31
|
+
"@meshconnect/uwc-constants": "0.6.3",
|
|
32
|
+
"@meshconnect/uwc-ton-connector": "0.6.1",
|
|
33
|
+
"@meshconnect/uwc-types": "0.14.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"typescript": "^5.9.3"
|
|
@@ -20,6 +20,9 @@ import type {
|
|
|
20
20
|
WalletMetadata,
|
|
21
21
|
TonConnectConfig
|
|
22
22
|
} from '@meshconnect/uwc-types'
|
|
23
|
+
import { assertSameMessage } from '@meshconnect/uwc-types'
|
|
24
|
+
import { Transaction, VersionedTransaction } from '@solana/web3.js'
|
|
25
|
+
import type { StandardWalletAdapter } from '@solana/wallet-standard-wallet-adapter-base'
|
|
23
26
|
import { BridgeChild } from '@meshconnect/uwc-bridge-child'
|
|
24
27
|
|
|
25
28
|
import { EthereumWalletService } from './services/ethereum/ethereum-wallet-service'
|
|
@@ -30,6 +33,9 @@ import { StorageService } from './services/storage-service'
|
|
|
30
33
|
import { ConnectionManager } from './services/connection-manager'
|
|
31
34
|
import { SignatureService } from './services/signature-service'
|
|
32
35
|
import { TransactionService } from './services/transaction-service'
|
|
36
|
+
import type { ExtendedStandardWalletAdapter } from './wallet-standard-discovery'
|
|
37
|
+
import { parseError } from './utils/error-utils'
|
|
38
|
+
import { resolveSigningAccount } from './utils/solana-account-utils'
|
|
33
39
|
|
|
34
40
|
export class InjectedConnector implements Connector {
|
|
35
41
|
private readonly storageService: StorageService
|
|
@@ -379,4 +385,110 @@ export class InjectedConnector implements Connector {
|
|
|
379
385
|
}
|
|
380
386
|
return await this.ethereumService.getCapabilities(from, networks)
|
|
381
387
|
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Sign serialized Solana tx bytes without broadcasting (raw bytes in/out, no
|
|
391
|
+
* @solana/web3.js for callers). Tries: bridge (iframe) → Wallet Standard
|
|
392
|
+
* feature → legacy adapter. The feature path avoids Transaction.serialize(),
|
|
393
|
+
* which crashes some mobile WebViews. Errors go through parseError (typed
|
|
394
|
+
* "rejected" on user cancel).
|
|
395
|
+
*/
|
|
396
|
+
async signSolanaTransactionBytes(
|
|
397
|
+
serializedTx: Uint8Array
|
|
398
|
+
): Promise<Uint8Array> {
|
|
399
|
+
const currentNetworkId = this.connectionManager.getCurrentNetworkId()
|
|
400
|
+
if (!currentNetworkId?.startsWith('solana:')) {
|
|
401
|
+
throw new Error(
|
|
402
|
+
'signSolanaTransactionBytes requires an active Solana connection'
|
|
403
|
+
)
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const solanaAdapter = this.solanaService.getConnectedAdapter()
|
|
407
|
+
if (!solanaAdapter) {
|
|
408
|
+
throw new Error('No connected Solana adapter')
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
try {
|
|
412
|
+
// Path 1: bridge (iframe). The wallet lives on the parent; forward bytes.
|
|
413
|
+
// `await customFunctions` (not a truthy check) — Comlink proxies every
|
|
414
|
+
// property as truthy, so the awaited list is the only reliable signal.
|
|
415
|
+
const extendedAdapter = solanaAdapter as ExtendedStandardWalletAdapter
|
|
416
|
+
const customFns = await extendedAdapter.customFunctions
|
|
417
|
+
if (customFns?.includes('signSolanaTransactionBytes')) {
|
|
418
|
+
// Sign with the child's connected account — the parent's publicKey may
|
|
419
|
+
// have drifted.
|
|
420
|
+
const signed = await extendedAdapter.signSolanaTransactionBytes(
|
|
421
|
+
serializedTx,
|
|
422
|
+
this.connectionManager.getCurrentAccount() ?? undefined
|
|
423
|
+
)
|
|
424
|
+
// Verify in the iframe (trusted), not on the parent, so a tampered
|
|
425
|
+
// parent can't bypass it. Byte-stable round-trip → safe for the bridge's
|
|
426
|
+
// legacy sub-path too (see the "byte-stable" test).
|
|
427
|
+
assertSameMessage(serializedTx, signed)
|
|
428
|
+
return signed
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// Path 2: Wallet Standard solana:signTransaction (raw bytes in/out).
|
|
432
|
+
const wallet = (solanaAdapter as StandardWalletAdapter).wallet
|
|
433
|
+
const SIGN_TX = 'solana:signTransaction'
|
|
434
|
+
|
|
435
|
+
if (wallet && SIGN_TX in wallet.features && wallet.accounts.length > 0) {
|
|
436
|
+
const account = resolveSigningAccount(
|
|
437
|
+
wallet.accounts,
|
|
438
|
+
this.connectionManager.getCurrentAccount()
|
|
439
|
+
)
|
|
440
|
+
const feature = wallet.features[SIGN_TX]
|
|
441
|
+
const [output] = await feature.signTransaction({
|
|
442
|
+
account,
|
|
443
|
+
transaction: serializedTx
|
|
444
|
+
})
|
|
445
|
+
if (!output?.signedTransaction) {
|
|
446
|
+
throw new Error('Wallet returned no signed transaction')
|
|
447
|
+
}
|
|
448
|
+
// Reject a tampered message before the relay broadcasts.
|
|
449
|
+
assertSameMessage(serializedTx, output.signedTransaction)
|
|
450
|
+
return output.signedTransaction
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// Path 3: legacy adapter (no .wallet getter).
|
|
454
|
+
if (!solanaAdapter.signTransaction) {
|
|
455
|
+
throw new Error('Connected wallet does not support signTransaction')
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// V0 + legacy. requireAllSignatures:false — the relay fills the fee-payer slot.
|
|
459
|
+
let transaction: Transaction | VersionedTransaction
|
|
460
|
+
try {
|
|
461
|
+
transaction = VersionedTransaction.deserialize(serializedTx)
|
|
462
|
+
} catch {
|
|
463
|
+
try {
|
|
464
|
+
transaction = Transaction.from(serializedTx)
|
|
465
|
+
} catch {
|
|
466
|
+
throw new Error(
|
|
467
|
+
'Failed to deserialize transaction as either versioned or legacy format'
|
|
468
|
+
)
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
const signed = await solanaAdapter.signTransaction(transaction)
|
|
473
|
+
const signedBytes =
|
|
474
|
+
signed instanceof VersionedTransaction
|
|
475
|
+
? signed.serialize()
|
|
476
|
+
: new Uint8Array(
|
|
477
|
+
signed.serialize({
|
|
478
|
+
requireAllSignatures: false,
|
|
479
|
+
verifySignatures: false
|
|
480
|
+
})
|
|
481
|
+
)
|
|
482
|
+
// Same guard as Path 1/2. The deserialize→sign→reserialize round-trip is
|
|
483
|
+
// byte-stable (see the "byte-stable" tests), so this rejects a tampering
|
|
484
|
+
// adapter without false-positiving a legit sign.
|
|
485
|
+
assertSameMessage(serializedTx, signedBytes)
|
|
486
|
+
return signedBytes
|
|
487
|
+
} catch (err) {
|
|
488
|
+
// Normalize: turns a wallet rejection (EIP-1193 4001 / "user rejected")
|
|
489
|
+
// into a WalletConnectorError{ type: 'rejected' } so the Link UI can tell
|
|
490
|
+
// "user cancelled" apart from a real failure. parseError always throws.
|
|
491
|
+
throw parseError(err)
|
|
492
|
+
}
|
|
493
|
+
}
|
|
382
494
|
}
|
|
@@ -0,0 +1,747 @@
|
|
|
1
|
+
// @vitest-environment node
|
|
2
|
+
//
|
|
3
|
+
// Node env: @solana/web3.js's VersionedTransaction.deserialize fails its
|
|
4
|
+
// `instanceof Uint8Array` check under jsdom. @vitest-environment is per-file,
|
|
5
|
+
// so this is a separate file from injected-connector.test.ts (jsdom).
|
|
6
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
|
7
|
+
import { assertSameMessage } from '@meshconnect/uwc-types'
|
|
8
|
+
import { InjectedConnector } from './injected-connector'
|
|
9
|
+
|
|
10
|
+
// Mock all service dependencies — same pattern as injected-connector.test.ts
|
|
11
|
+
vi.mock('./services/storage-service')
|
|
12
|
+
vi.mock('./services/ethereum/ethereum-wallet-service')
|
|
13
|
+
vi.mock('./services/tron/tron-wallet-service')
|
|
14
|
+
vi.mock('./services/connection-manager')
|
|
15
|
+
vi.mock('./services/signature-service')
|
|
16
|
+
vi.mock('./services/transaction-service')
|
|
17
|
+
vi.mock('@meshconnect/uwc-bridge-child', () => ({ BridgeChild: vi.fn() }))
|
|
18
|
+
|
|
19
|
+
// SolanaWalletService needs fine-grained control — we mock at the module level
|
|
20
|
+
// and override getConnectedAdapter per test.
|
|
21
|
+
vi.mock('./services/solana/solana-wallet-service')
|
|
22
|
+
|
|
23
|
+
// Build a minimal valid serialized VersionedTransaction for deserialize tests.
|
|
24
|
+
// We import the real web3.js so the bytes are structurally sound.
|
|
25
|
+
import {
|
|
26
|
+
Keypair,
|
|
27
|
+
SystemProgram,
|
|
28
|
+
Transaction,
|
|
29
|
+
TransactionMessage,
|
|
30
|
+
VersionedTransaction
|
|
31
|
+
} from '@solana/web3.js'
|
|
32
|
+
|
|
33
|
+
const payer = Keypair.generate()
|
|
34
|
+
const recipient = Keypair.generate().publicKey
|
|
35
|
+
|
|
36
|
+
function buildSerializedV0Tx(): Uint8Array {
|
|
37
|
+
const msg = new TransactionMessage({
|
|
38
|
+
payerKey: payer.publicKey,
|
|
39
|
+
recentBlockhash: '11111111111111111111111111111111',
|
|
40
|
+
instructions: [
|
|
41
|
+
SystemProgram.transfer({
|
|
42
|
+
fromPubkey: payer.publicKey,
|
|
43
|
+
toPubkey: recipient,
|
|
44
|
+
lamports: 1
|
|
45
|
+
})
|
|
46
|
+
]
|
|
47
|
+
}).compileToV0Message()
|
|
48
|
+
return new VersionedTransaction(msg).serialize()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Signed bytes simulated by signing a copy of the tx with the payer key.
|
|
52
|
+
function buildSignedV0Bytes(): Uint8Array {
|
|
53
|
+
const msg = new TransactionMessage({
|
|
54
|
+
payerKey: payer.publicKey,
|
|
55
|
+
recentBlockhash: '11111111111111111111111111111111',
|
|
56
|
+
instructions: [
|
|
57
|
+
SystemProgram.transfer({
|
|
58
|
+
fromPubkey: payer.publicKey,
|
|
59
|
+
toPubkey: recipient,
|
|
60
|
+
lamports: 1
|
|
61
|
+
})
|
|
62
|
+
]
|
|
63
|
+
}).compileToV0Message()
|
|
64
|
+
const tx = new VersionedTransaction(msg)
|
|
65
|
+
tx.sign([payer])
|
|
66
|
+
return tx.serialize()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Same message shape as the builders above but a different transfer amount, so
|
|
70
|
+
// its message bytes differ — models a wallet that tampered with the request.
|
|
71
|
+
function buildSignedV0BytesWith(lamports: number): Uint8Array {
|
|
72
|
+
const msg = new TransactionMessage({
|
|
73
|
+
payerKey: payer.publicKey,
|
|
74
|
+
recentBlockhash: '11111111111111111111111111111111',
|
|
75
|
+
instructions: [
|
|
76
|
+
SystemProgram.transfer({
|
|
77
|
+
fromPubkey: payer.publicKey,
|
|
78
|
+
toPubkey: recipient,
|
|
79
|
+
lamports
|
|
80
|
+
})
|
|
81
|
+
]
|
|
82
|
+
}).compileToV0Message()
|
|
83
|
+
const tx = new VersionedTransaction(msg)
|
|
84
|
+
tx.sign([payer])
|
|
85
|
+
return tx.serialize()
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
describe('InjectedConnector.signSolanaTransactionBytes', () => {
|
|
89
|
+
let connector: InjectedConnector
|
|
90
|
+
// References to the auto-mocked service instances created during construction.
|
|
91
|
+
let mockConnManager: ReturnType<typeof vi.fn>
|
|
92
|
+
let mockSolService: ReturnType<typeof vi.fn>
|
|
93
|
+
|
|
94
|
+
beforeEach(async () => {
|
|
95
|
+
vi.clearAllMocks()
|
|
96
|
+
|
|
97
|
+
connector = new InjectedConnector()
|
|
98
|
+
|
|
99
|
+
const { ConnectionManager } = await import('./services/connection-manager')
|
|
100
|
+
const { SolanaWalletService } =
|
|
101
|
+
await import('./services/solana/solana-wallet-service')
|
|
102
|
+
|
|
103
|
+
mockConnManager = (vi.mocked(ConnectionManager).mock.results[0] as any)
|
|
104
|
+
.value
|
|
105
|
+
mockSolService = (vi.mocked(SolanaWalletService).mock.results[0] as any)
|
|
106
|
+
.value
|
|
107
|
+
|
|
108
|
+
// Default: active Solana connection
|
|
109
|
+
mockConnManager.getCurrentNetworkId.mockReturnValue(
|
|
110
|
+
'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'
|
|
111
|
+
)
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
// ── Guard errors ──────────────────────────────────────────────────────────
|
|
115
|
+
|
|
116
|
+
it('throws when the active network is not solana', async () => {
|
|
117
|
+
mockConnManager.getCurrentNetworkId.mockReturnValue('eip155:1')
|
|
118
|
+
|
|
119
|
+
await expect(
|
|
120
|
+
connector.signSolanaTransactionBytes(buildSerializedV0Tx())
|
|
121
|
+
).rejects.toThrow(
|
|
122
|
+
'signSolanaTransactionBytes requires an active Solana connection'
|
|
123
|
+
)
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
it('throws when getCurrentNetworkId returns null', async () => {
|
|
127
|
+
mockConnManager.getCurrentNetworkId.mockReturnValue(null)
|
|
128
|
+
|
|
129
|
+
await expect(
|
|
130
|
+
connector.signSolanaTransactionBytes(buildSerializedV0Tx())
|
|
131
|
+
).rejects.toThrow(
|
|
132
|
+
'signSolanaTransactionBytes requires an active Solana connection'
|
|
133
|
+
)
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
it('throws when no Solana adapter is connected', async () => {
|
|
137
|
+
mockSolService.getConnectedAdapter.mockReturnValue(null)
|
|
138
|
+
|
|
139
|
+
await expect(
|
|
140
|
+
connector.signSolanaTransactionBytes(buildSerializedV0Tx())
|
|
141
|
+
).rejects.toThrow('No connected Solana adapter')
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
it('throws when adapter lacks signTransaction and wallet getter is absent', async () => {
|
|
145
|
+
// Adapter with no .wallet, no .signTransaction — unsupported wallet
|
|
146
|
+
mockSolService.getConnectedAdapter.mockReturnValue({
|
|
147
|
+
signAndSendTransaction: vi.fn()
|
|
148
|
+
// signTransaction intentionally absent
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
await expect(
|
|
152
|
+
connector.signSolanaTransactionBytes(buildSerializedV0Tx())
|
|
153
|
+
).rejects.toThrow('Connected wallet does not support signTransaction')
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
// ── Direct Wallet Standard feature path ──────────────────────────────────
|
|
157
|
+
|
|
158
|
+
it('calls the solana:signTransaction feature directly and returns signedTransaction bytes', async () => {
|
|
159
|
+
const signedBytes = buildSignedV0Bytes()
|
|
160
|
+
const featureSignTx = vi
|
|
161
|
+
.fn()
|
|
162
|
+
.mockResolvedValue([{ signedTransaction: signedBytes }])
|
|
163
|
+
const mockAccount = { address: payer.publicKey.toBase58() }
|
|
164
|
+
const mockWallet = {
|
|
165
|
+
accounts: [mockAccount],
|
|
166
|
+
features: {
|
|
167
|
+
'solana:signTransaction': { signTransaction: featureSignTx }
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// Adapter shaped as StandardWalletAdapter — exposes .wallet getter
|
|
171
|
+
const mockAdapter = {
|
|
172
|
+
wallet: mockWallet,
|
|
173
|
+
signTransaction: vi.fn(), // present but must NOT be called
|
|
174
|
+
signAndSendTransaction: vi.fn() // must NEVER be called
|
|
175
|
+
}
|
|
176
|
+
mockSolService.getConnectedAdapter.mockReturnValue(mockAdapter)
|
|
177
|
+
|
|
178
|
+
const serialized = buildSerializedV0Tx()
|
|
179
|
+
const result = await connector.signSolanaTransactionBytes(serialized)
|
|
180
|
+
|
|
181
|
+
expect(result).toBe(signedBytes)
|
|
182
|
+
expect(featureSignTx).toHaveBeenCalledOnce()
|
|
183
|
+
expect(featureSignTx).toHaveBeenCalledWith({
|
|
184
|
+
account: mockAccount,
|
|
185
|
+
transaction: serialized
|
|
186
|
+
})
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
it('SECURITY: rejects a wallet that returns a different transaction (tampered message)', async () => {
|
|
190
|
+
// Asked to sign lamports:1, the wallet returns a signed lamports:999 tx.
|
|
191
|
+
const tampered = buildSignedV0BytesWith(999)
|
|
192
|
+
const featureSignTx = vi
|
|
193
|
+
.fn()
|
|
194
|
+
.mockResolvedValue([{ signedTransaction: tampered }])
|
|
195
|
+
const mockAccount = { address: payer.publicKey.toBase58() }
|
|
196
|
+
const mockAdapter = {
|
|
197
|
+
wallet: {
|
|
198
|
+
accounts: [mockAccount],
|
|
199
|
+
features: {
|
|
200
|
+
'solana:signTransaction': { signTransaction: featureSignTx }
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
signTransaction: vi.fn()
|
|
204
|
+
}
|
|
205
|
+
mockSolService.getConnectedAdapter.mockReturnValue(mockAdapter)
|
|
206
|
+
|
|
207
|
+
await expect(
|
|
208
|
+
connector.signSolanaTransactionBytes(buildSerializedV0Tx())
|
|
209
|
+
).rejects.toThrow('Signed transaction does not match the request')
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
it('passes the raw bytes, not a deserialized object, to the feature', async () => {
|
|
213
|
+
const signedBytes = buildSignedV0Bytes()
|
|
214
|
+
const featureSignTx = vi
|
|
215
|
+
.fn()
|
|
216
|
+
.mockResolvedValue([{ signedTransaction: signedBytes }])
|
|
217
|
+
const serialized = buildSerializedV0Tx()
|
|
218
|
+
mockSolService.getConnectedAdapter.mockReturnValue({
|
|
219
|
+
wallet: {
|
|
220
|
+
accounts: [{ address: 'any' }],
|
|
221
|
+
features: {
|
|
222
|
+
'solana:signTransaction': { signTransaction: featureSignTx }
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
signTransaction: vi.fn(),
|
|
226
|
+
signAndSendTransaction: vi.fn()
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
await connector.signSolanaTransactionBytes(serialized)
|
|
230
|
+
|
|
231
|
+
// The argument passed to the feature must be the exact same Uint8Array reference
|
|
232
|
+
const callArg = featureSignTx.mock.calls[0][0]
|
|
233
|
+
expect(callArg.transaction).toBe(serialized)
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
// ── INVARIANT: sign-only never broadcasts ─────────────────────────────────
|
|
237
|
+
|
|
238
|
+
it('INVARIANT: signAndSendTransaction is never called on the direct-feature path', async () => {
|
|
239
|
+
const signedBytes = buildSignedV0Bytes()
|
|
240
|
+
const signAndSend = vi.fn()
|
|
241
|
+
mockSolService.getConnectedAdapter.mockReturnValue({
|
|
242
|
+
wallet: {
|
|
243
|
+
accounts: [{ address: 'any' }],
|
|
244
|
+
features: {
|
|
245
|
+
'solana:signTransaction': {
|
|
246
|
+
signTransaction: vi
|
|
247
|
+
.fn()
|
|
248
|
+
.mockResolvedValue([{ signedTransaction: signedBytes }])
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
signTransaction: vi.fn(),
|
|
253
|
+
signAndSendTransaction: signAndSend
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
await connector.signSolanaTransactionBytes(buildSerializedV0Tx())
|
|
257
|
+
|
|
258
|
+
expect(signAndSend).not.toHaveBeenCalled()
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
it('surfaces a wallet rejection on the feature path as a typed "rejected" error', async () => {
|
|
262
|
+
// The Link UI needs to tell "user cancelled" apart from a real failure, so a
|
|
263
|
+
// rejection must arrive as WalletConnectorError{ type: 'rejected' } — not a
|
|
264
|
+
// generic Error.
|
|
265
|
+
mockSolService.getConnectedAdapter.mockReturnValue({
|
|
266
|
+
wallet: {
|
|
267
|
+
accounts: [{ address: 'any' }],
|
|
268
|
+
features: {
|
|
269
|
+
'solana:signTransaction': {
|
|
270
|
+
signTransaction: vi
|
|
271
|
+
.fn()
|
|
272
|
+
.mockRejectedValue(new Error('user rejected'))
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
signTransaction: vi.fn(),
|
|
277
|
+
signAndSendTransaction: vi.fn()
|
|
278
|
+
})
|
|
279
|
+
|
|
280
|
+
await expect(
|
|
281
|
+
connector.signSolanaTransactionBytes(buildSerializedV0Tx())
|
|
282
|
+
).rejects.toMatchObject({ type: 'rejected', message: 'user rejected' })
|
|
283
|
+
})
|
|
284
|
+
|
|
285
|
+
it('falls back to direct feature path even when wallet.accounts is empty (zero-account edge)', async () => {
|
|
286
|
+
// accounts.length === 0 → falls through to the adapter fallback
|
|
287
|
+
const signedBytes = buildSignedV0Bytes()
|
|
288
|
+
const adapterSignTx = vi
|
|
289
|
+
.fn()
|
|
290
|
+
.mockResolvedValue(VersionedTransaction.deserialize(signedBytes))
|
|
291
|
+
mockSolService.getConnectedAdapter.mockReturnValue({
|
|
292
|
+
wallet: {
|
|
293
|
+
accounts: [], // empty → skip feature path
|
|
294
|
+
features: {
|
|
295
|
+
'solana:signTransaction': {
|
|
296
|
+
signTransaction: vi.fn() // must NOT be called
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
signTransaction: adapterSignTx,
|
|
301
|
+
signAndSendTransaction: vi.fn()
|
|
302
|
+
})
|
|
303
|
+
|
|
304
|
+
const result = await connector.signSolanaTransactionBytes(
|
|
305
|
+
buildSerializedV0Tx()
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
expect(adapterSignTx).toHaveBeenCalledOnce()
|
|
309
|
+
expect(result).toBeInstanceOf(Uint8Array)
|
|
310
|
+
expect(result.length).toBeGreaterThan(0)
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
// ── Adapter fallback path ─────────────────────────────────────────────────
|
|
314
|
+
|
|
315
|
+
it('falls back to adapter.signTransaction when wallet getter is absent', async () => {
|
|
316
|
+
const signedBytes = buildSignedV0Bytes()
|
|
317
|
+
const adapterSignTx = vi
|
|
318
|
+
.fn()
|
|
319
|
+
.mockResolvedValue(VersionedTransaction.deserialize(signedBytes))
|
|
320
|
+
// No .wallet property at all — undefined
|
|
321
|
+
mockSolService.getConnectedAdapter.mockReturnValue({
|
|
322
|
+
wallet: undefined,
|
|
323
|
+
signTransaction: adapterSignTx,
|
|
324
|
+
signAndSendTransaction: vi.fn()
|
|
325
|
+
})
|
|
326
|
+
|
|
327
|
+
const result = await connector.signSolanaTransactionBytes(
|
|
328
|
+
buildSerializedV0Tx()
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
expect(adapterSignTx).toHaveBeenCalledOnce()
|
|
332
|
+
// Deserialized → re-serialized; returned bytes must be a non-empty Uint8Array
|
|
333
|
+
expect(result).toBeInstanceOf(Uint8Array)
|
|
334
|
+
expect(result.length).toBeGreaterThan(0)
|
|
335
|
+
})
|
|
336
|
+
|
|
337
|
+
it('falls back when wallet lacks the solana:signTransaction feature key', async () => {
|
|
338
|
+
const signedBytes = buildSignedV0Bytes()
|
|
339
|
+
const adapterSignTx = vi
|
|
340
|
+
.fn()
|
|
341
|
+
.mockResolvedValue(VersionedTransaction.deserialize(signedBytes))
|
|
342
|
+
mockSolService.getConnectedAdapter.mockReturnValue({
|
|
343
|
+
wallet: {
|
|
344
|
+
accounts: [{ address: 'any' }],
|
|
345
|
+
features: {} // key absent
|
|
346
|
+
},
|
|
347
|
+
signTransaction: adapterSignTx,
|
|
348
|
+
signAndSendTransaction: vi.fn()
|
|
349
|
+
})
|
|
350
|
+
|
|
351
|
+
await connector.signSolanaTransactionBytes(buildSerializedV0Tx())
|
|
352
|
+
|
|
353
|
+
expect(adapterSignTx).toHaveBeenCalledOnce()
|
|
354
|
+
})
|
|
355
|
+
|
|
356
|
+
it('INVARIANT: signAndSendTransaction is never called on the adapter fallback path', async () => {
|
|
357
|
+
const signedBytes = buildSignedV0Bytes()
|
|
358
|
+
const signAndSend = vi.fn()
|
|
359
|
+
mockSolService.getConnectedAdapter.mockReturnValue({
|
|
360
|
+
wallet: undefined,
|
|
361
|
+
signTransaction: vi
|
|
362
|
+
.fn()
|
|
363
|
+
.mockResolvedValue(VersionedTransaction.deserialize(signedBytes)),
|
|
364
|
+
signAndSendTransaction: signAndSend
|
|
365
|
+
})
|
|
366
|
+
|
|
367
|
+
await connector.signSolanaTransactionBytes(buildSerializedV0Tx())
|
|
368
|
+
|
|
369
|
+
expect(signAndSend).not.toHaveBeenCalled()
|
|
370
|
+
})
|
|
371
|
+
|
|
372
|
+
it('surfaces an adapter-fallback failure as a typed "unknown" error, preserving the message', async () => {
|
|
373
|
+
// A non-rejection failure (e.g. locked wallet) stays type 'unknown' but keeps
|
|
374
|
+
// the original message so it is still actionable in logs.
|
|
375
|
+
mockSolService.getConnectedAdapter.mockReturnValue({
|
|
376
|
+
wallet: undefined,
|
|
377
|
+
signTransaction: vi.fn().mockRejectedValue(new Error('wallet locked')),
|
|
378
|
+
signAndSendTransaction: vi.fn()
|
|
379
|
+
})
|
|
380
|
+
|
|
381
|
+
await expect(
|
|
382
|
+
connector.signSolanaTransactionBytes(buildSerializedV0Tx())
|
|
383
|
+
).rejects.toMatchObject({ type: 'unknown', message: 'wallet locked' })
|
|
384
|
+
})
|
|
385
|
+
|
|
386
|
+
it('deserializes the input bytes before passing to adapter.signTransaction', async () => {
|
|
387
|
+
const signedBytes = buildSignedV0Bytes()
|
|
388
|
+
const adapterSignTx = vi
|
|
389
|
+
.fn()
|
|
390
|
+
.mockResolvedValue(VersionedTransaction.deserialize(signedBytes))
|
|
391
|
+
mockSolService.getConnectedAdapter.mockReturnValue({
|
|
392
|
+
wallet: undefined,
|
|
393
|
+
signTransaction: adapterSignTx,
|
|
394
|
+
signAndSendTransaction: vi.fn()
|
|
395
|
+
})
|
|
396
|
+
|
|
397
|
+
await connector.signSolanaTransactionBytes(buildSerializedV0Tx())
|
|
398
|
+
|
|
399
|
+
const arg = adapterSignTx.mock.calls[0][0]
|
|
400
|
+
// adapter receives a VersionedTransaction, not raw bytes
|
|
401
|
+
expect(arg).toBeInstanceOf(VersionedTransaction)
|
|
402
|
+
})
|
|
403
|
+
|
|
404
|
+
it('SECURITY (Path 3): rejects a tampered tx from a legacy adapter', async () => {
|
|
405
|
+
// Adapter returns a signed tx with a different message (lamports 999).
|
|
406
|
+
const adapterSignTx = vi
|
|
407
|
+
.fn()
|
|
408
|
+
.mockResolvedValue(
|
|
409
|
+
VersionedTransaction.deserialize(buildSignedV0BytesWith(999))
|
|
410
|
+
)
|
|
411
|
+
mockSolService.getConnectedAdapter.mockReturnValue({
|
|
412
|
+
wallet: undefined,
|
|
413
|
+
signTransaction: adapterSignTx,
|
|
414
|
+
signAndSendTransaction: vi.fn()
|
|
415
|
+
})
|
|
416
|
+
|
|
417
|
+
await expect(
|
|
418
|
+
connector.signSolanaTransactionBytes(buildSerializedV0Tx())
|
|
419
|
+
).rejects.toThrow('Signed transaction does not match the request')
|
|
420
|
+
})
|
|
421
|
+
|
|
422
|
+
// ── Bridge path (Comlink-proxied adapter) ────────────────────────────────
|
|
423
|
+
|
|
424
|
+
it('BRIDGE PATH: calls adapter.signSolanaTransactionBytes and returns its bytes without touching wallet.features', async () => {
|
|
425
|
+
const bridgeBytes = buildSignedV0Bytes()
|
|
426
|
+
const bridgeFn = vi.fn().mockResolvedValue(bridgeBytes)
|
|
427
|
+
// wallet.features is present but must NOT be touched — assert via spy
|
|
428
|
+
const featureSignTx = vi.fn()
|
|
429
|
+
const mockAdapter = {
|
|
430
|
+
// Bridge advertises the customFunction; detection awaits this list.
|
|
431
|
+
customFunctions: ['signSolanaTransactionBytes'],
|
|
432
|
+
// Extended bridge property — present on the Comlink-proxied adapter
|
|
433
|
+
signSolanaTransactionBytes: bridgeFn,
|
|
434
|
+
// Direct path artifacts — must remain untouched
|
|
435
|
+
wallet: {
|
|
436
|
+
accounts: [{ address: 'AAA' }],
|
|
437
|
+
features: {
|
|
438
|
+
'solana:signTransaction': { signTransaction: featureSignTx }
|
|
439
|
+
}
|
|
440
|
+
},
|
|
441
|
+
signTransaction: vi.fn(),
|
|
442
|
+
signAndSendTransaction: vi.fn()
|
|
443
|
+
}
|
|
444
|
+
mockSolService.getConnectedAdapter.mockReturnValue(mockAdapter)
|
|
445
|
+
mockConnManager.getCurrentAccount.mockReturnValue('AAA')
|
|
446
|
+
|
|
447
|
+
const serialized = buildSerializedV0Tx()
|
|
448
|
+
const result = await connector.signSolanaTransactionBytes(serialized)
|
|
449
|
+
|
|
450
|
+
expect(result).toBe(bridgeBytes)
|
|
451
|
+
expect(bridgeFn).toHaveBeenCalledOnce()
|
|
452
|
+
// The connected account is threaded to the parent so it can't fall back to
|
|
453
|
+
// a drifted publicKey.
|
|
454
|
+
expect(bridgeFn).toHaveBeenCalledWith(serialized, 'AAA')
|
|
455
|
+
// The Wallet Standard feature path must NOT have been used
|
|
456
|
+
expect(featureSignTx).not.toHaveBeenCalled()
|
|
457
|
+
})
|
|
458
|
+
|
|
459
|
+
it('BRIDGE PATH: threads the connected account even when it differs from accounts[0]', async () => {
|
|
460
|
+
const bridgeFn = vi.fn().mockResolvedValue(buildSignedV0Bytes())
|
|
461
|
+
mockSolService.getConnectedAdapter.mockReturnValue({
|
|
462
|
+
customFunctions: ['signSolanaTransactionBytes'],
|
|
463
|
+
signSolanaTransactionBytes: bridgeFn,
|
|
464
|
+
wallet: undefined,
|
|
465
|
+
signTransaction: vi.fn(),
|
|
466
|
+
signAndSendTransaction: vi.fn()
|
|
467
|
+
})
|
|
468
|
+
mockConnManager.getCurrentAccount.mockReturnValue('CONNECTED_ACCT')
|
|
469
|
+
|
|
470
|
+
const serialized = buildSerializedV0Tx()
|
|
471
|
+
await connector.signSolanaTransactionBytes(serialized)
|
|
472
|
+
|
|
473
|
+
expect(bridgeFn).toHaveBeenCalledWith(serialized, 'CONNECTED_ACCT')
|
|
474
|
+
})
|
|
475
|
+
|
|
476
|
+
it('BRIDGE PATH INVARIANT: signAndSendTransaction is never called when the bridge wrapper handles signing', async () => {
|
|
477
|
+
const signAndSend = vi.fn()
|
|
478
|
+
const mockAdapter = {
|
|
479
|
+
customFunctions: ['signSolanaTransactionBytes'],
|
|
480
|
+
signSolanaTransactionBytes: vi
|
|
481
|
+
.fn()
|
|
482
|
+
.mockResolvedValue(buildSignedV0Bytes()),
|
|
483
|
+
wallet: undefined,
|
|
484
|
+
signTransaction: vi.fn(),
|
|
485
|
+
signAndSendTransaction: signAndSend
|
|
486
|
+
}
|
|
487
|
+
mockSolService.getConnectedAdapter.mockReturnValue(mockAdapter)
|
|
488
|
+
|
|
489
|
+
await connector.signSolanaTransactionBytes(buildSerializedV0Tx())
|
|
490
|
+
|
|
491
|
+
expect(signAndSend).not.toHaveBeenCalled()
|
|
492
|
+
})
|
|
493
|
+
|
|
494
|
+
it('BRIDGE PATH: returns the exact Uint8Array the bridge wrapper resolves with', async () => {
|
|
495
|
+
// Ensures no re-serialization happens on the bridge path — bytes pass through as-is
|
|
496
|
+
const expectedBytes = buildSignedV0Bytes()
|
|
497
|
+
const mockAdapter = {
|
|
498
|
+
customFunctions: ['signSolanaTransactionBytes'],
|
|
499
|
+
signSolanaTransactionBytes: vi.fn().mockResolvedValue(expectedBytes),
|
|
500
|
+
wallet: undefined,
|
|
501
|
+
signTransaction: vi.fn(),
|
|
502
|
+
signAndSendTransaction: vi.fn()
|
|
503
|
+
}
|
|
504
|
+
mockSolService.getConnectedAdapter.mockReturnValue(mockAdapter)
|
|
505
|
+
|
|
506
|
+
const result = await connector.signSolanaTransactionBytes(
|
|
507
|
+
buildSerializedV0Tx()
|
|
508
|
+
)
|
|
509
|
+
|
|
510
|
+
expect(result).toBe(expectedBytes)
|
|
511
|
+
})
|
|
512
|
+
|
|
513
|
+
it('BRIDGE PATH SECURITY: rejects tampered bytes returned by the parent', async () => {
|
|
514
|
+
// The wallet signs on the parent (client page); the child (iframe) verifies
|
|
515
|
+
// here. A parent that returns a different-message tx must be rejected.
|
|
516
|
+
const tampered = buildSignedV0BytesWith(999)
|
|
517
|
+
const mockAdapter = {
|
|
518
|
+
customFunctions: ['signSolanaTransactionBytes'],
|
|
519
|
+
signSolanaTransactionBytes: vi.fn().mockResolvedValue(tampered),
|
|
520
|
+
wallet: undefined,
|
|
521
|
+
signTransaction: vi.fn(),
|
|
522
|
+
signAndSendTransaction: vi.fn()
|
|
523
|
+
}
|
|
524
|
+
mockSolService.getConnectedAdapter.mockReturnValue(mockAdapter)
|
|
525
|
+
|
|
526
|
+
await expect(
|
|
527
|
+
connector.signSolanaTransactionBytes(buildSerializedV0Tx())
|
|
528
|
+
).rejects.toThrow('Signed transaction does not match the request')
|
|
529
|
+
})
|
|
530
|
+
|
|
531
|
+
// Closes the version-coupling break: an older bridge-parent without
|
|
532
|
+
// `signSolanaTransactionBytes` in customFunctions must NOT trigger the bridge
|
|
533
|
+
// path (Comlink would otherwise present every property as truthy and we'd
|
|
534
|
+
// call a method that doesn't exist on the parent).
|
|
535
|
+
it('BRIDGE COMPAT: falls back to direct path when bridge customFunctions lacks signSolanaTransactionBytes (old bridge-parent)', async () => {
|
|
536
|
+
const signedBytes = buildSignedV0Bytes()
|
|
537
|
+
const bridgeFn = vi.fn()
|
|
538
|
+
const featureSignTx = vi
|
|
539
|
+
.fn()
|
|
540
|
+
.mockResolvedValue([{ signedTransaction: signedBytes }])
|
|
541
|
+
const mockAdapter = {
|
|
542
|
+
// Old bridge: only the previous customFunctions, NOT signSolanaTransactionBytes
|
|
543
|
+
customFunctions: [
|
|
544
|
+
'sendSerializedTransaction',
|
|
545
|
+
'signSerializedTransaction'
|
|
546
|
+
],
|
|
547
|
+
// Sync truthy check would falsely match this on a real Comlink proxy
|
|
548
|
+
signSolanaTransactionBytes: bridgeFn,
|
|
549
|
+
wallet: {
|
|
550
|
+
accounts: [{ address: 'AAA' }],
|
|
551
|
+
features: {
|
|
552
|
+
'solana:signTransaction': { signTransaction: featureSignTx }
|
|
553
|
+
}
|
|
554
|
+
},
|
|
555
|
+
signTransaction: vi.fn(),
|
|
556
|
+
signAndSendTransaction: vi.fn()
|
|
557
|
+
}
|
|
558
|
+
mockSolService.getConnectedAdapter.mockReturnValue(mockAdapter)
|
|
559
|
+
|
|
560
|
+
const result = await connector.signSolanaTransactionBytes(
|
|
561
|
+
buildSerializedV0Tx()
|
|
562
|
+
)
|
|
563
|
+
|
|
564
|
+
expect(result).toBe(signedBytes)
|
|
565
|
+
expect(bridgeFn).not.toHaveBeenCalled()
|
|
566
|
+
expect(featureSignTx).toHaveBeenCalledOnce()
|
|
567
|
+
})
|
|
568
|
+
|
|
569
|
+
// Gap #18: bridge-path error propagation. Comlink flattens the parent's error
|
|
570
|
+
// to a plain Error, so we re-classify by message — a parent-side rejection must
|
|
571
|
+
// still reach the caller as type 'rejected'.
|
|
572
|
+
it('BRIDGE PATH: a wallet rejection on the parent surfaces as a typed "rejected" error', async () => {
|
|
573
|
+
const mockAdapter = {
|
|
574
|
+
customFunctions: ['signSolanaTransactionBytes'],
|
|
575
|
+
signSolanaTransactionBytes: vi
|
|
576
|
+
.fn()
|
|
577
|
+
.mockRejectedValue(new Error('user rejected on the parent')),
|
|
578
|
+
wallet: undefined,
|
|
579
|
+
signTransaction: vi.fn(),
|
|
580
|
+
signAndSendTransaction: vi.fn()
|
|
581
|
+
}
|
|
582
|
+
mockSolService.getConnectedAdapter.mockReturnValue(mockAdapter)
|
|
583
|
+
|
|
584
|
+
await expect(
|
|
585
|
+
connector.signSolanaTransactionBytes(buildSerializedV0Tx())
|
|
586
|
+
).rejects.toMatchObject({ type: 'rejected' })
|
|
587
|
+
})
|
|
588
|
+
|
|
589
|
+
// ── Multi-account direct path ──────────────────────────────────────────────
|
|
590
|
+
|
|
591
|
+
it('MULTI-ACCOUNT: picks the account matching getCurrentAccount(), not accounts[0]', async () => {
|
|
592
|
+
const signedBytes = buildSignedV0Bytes()
|
|
593
|
+
const featureSignTx = vi
|
|
594
|
+
.fn()
|
|
595
|
+
.mockResolvedValue([{ signedTransaction: signedBytes }])
|
|
596
|
+
const accountAAA = { address: 'AAA' }
|
|
597
|
+
const accountBBB = { address: 'BBB' }
|
|
598
|
+
const mockAdapter = {
|
|
599
|
+
// No bridge wrapper — must use direct feature path
|
|
600
|
+
wallet: {
|
|
601
|
+
accounts: [accountAAA, accountBBB],
|
|
602
|
+
features: {
|
|
603
|
+
'solana:signTransaction': { signTransaction: featureSignTx }
|
|
604
|
+
}
|
|
605
|
+
},
|
|
606
|
+
signTransaction: vi.fn(),
|
|
607
|
+
signAndSendTransaction: vi.fn()
|
|
608
|
+
}
|
|
609
|
+
mockSolService.getConnectedAdapter.mockReturnValue(mockAdapter)
|
|
610
|
+
// Simulate user connected as second account
|
|
611
|
+
mockConnManager.getCurrentAccount.mockReturnValue('BBB')
|
|
612
|
+
|
|
613
|
+
await connector.signSolanaTransactionBytes(buildSerializedV0Tx())
|
|
614
|
+
|
|
615
|
+
const callArg = featureSignTx.mock.calls[0][0]
|
|
616
|
+
expect(callArg.account).toBe(accountBBB)
|
|
617
|
+
expect(callArg.account).not.toBe(accountAAA)
|
|
618
|
+
})
|
|
619
|
+
|
|
620
|
+
it('MULTI-ACCOUNT: throws instead of guessing when no account is selected and several exist', async () => {
|
|
621
|
+
// Signing with the wrong key yields a useless signature for a payment, so we
|
|
622
|
+
// refuse rather than fall back to accounts[0].
|
|
623
|
+
const featureSignTx = vi.fn()
|
|
624
|
+
const mockAdapter = {
|
|
625
|
+
wallet: {
|
|
626
|
+
accounts: [{ address: 'AAA' }, { address: 'BBB' }],
|
|
627
|
+
features: {
|
|
628
|
+
'solana:signTransaction': { signTransaction: featureSignTx }
|
|
629
|
+
}
|
|
630
|
+
},
|
|
631
|
+
signTransaction: vi.fn(),
|
|
632
|
+
signAndSendTransaction: vi.fn()
|
|
633
|
+
}
|
|
634
|
+
mockSolService.getConnectedAdapter.mockReturnValue(mockAdapter)
|
|
635
|
+
mockConnManager.getCurrentAccount.mockReturnValue(null)
|
|
636
|
+
|
|
637
|
+
await expect(
|
|
638
|
+
connector.signSolanaTransactionBytes(buildSerializedV0Tx())
|
|
639
|
+
).rejects.toThrow('Cannot determine which Solana account to sign with')
|
|
640
|
+
expect(featureSignTx).not.toHaveBeenCalled()
|
|
641
|
+
})
|
|
642
|
+
|
|
643
|
+
it('MULTI-ACCOUNT: throws when the selected account is not in the wallet (never signs with a different account)', async () => {
|
|
644
|
+
const featureSignTx = vi.fn()
|
|
645
|
+
const mockAdapter = {
|
|
646
|
+
wallet: {
|
|
647
|
+
accounts: [{ address: 'AAA' }, { address: 'BBB' }],
|
|
648
|
+
features: {
|
|
649
|
+
'solana:signTransaction': { signTransaction: featureSignTx }
|
|
650
|
+
}
|
|
651
|
+
},
|
|
652
|
+
signTransaction: vi.fn(),
|
|
653
|
+
signAndSendTransaction: vi.fn()
|
|
654
|
+
}
|
|
655
|
+
mockSolService.getConnectedAdapter.mockReturnValue(mockAdapter)
|
|
656
|
+
// Address that doesn't match any wallet account
|
|
657
|
+
mockConnManager.getCurrentAccount.mockReturnValue('ZZZZ_NOT_IN_WALLET')
|
|
658
|
+
|
|
659
|
+
await expect(
|
|
660
|
+
connector.signSolanaTransactionBytes(buildSerializedV0Tx())
|
|
661
|
+
).rejects.toThrow('Connected Solana account not found in the wallet')
|
|
662
|
+
expect(featureSignTx).not.toHaveBeenCalled()
|
|
663
|
+
})
|
|
664
|
+
|
|
665
|
+
it('SINGLE-ACCOUNT: signs with the only account when none is explicitly selected', async () => {
|
|
666
|
+
const signedBytes = buildSignedV0Bytes()
|
|
667
|
+
const featureSignTx = vi
|
|
668
|
+
.fn()
|
|
669
|
+
.mockResolvedValue([{ signedTransaction: signedBytes }])
|
|
670
|
+
const onlyAccount = { address: 'AAA' }
|
|
671
|
+
mockSolService.getConnectedAdapter.mockReturnValue({
|
|
672
|
+
wallet: {
|
|
673
|
+
accounts: [onlyAccount],
|
|
674
|
+
features: {
|
|
675
|
+
'solana:signTransaction': { signTransaction: featureSignTx }
|
|
676
|
+
}
|
|
677
|
+
},
|
|
678
|
+
signTransaction: vi.fn(),
|
|
679
|
+
signAndSendTransaction: vi.fn()
|
|
680
|
+
})
|
|
681
|
+
mockConnManager.getCurrentAccount.mockReturnValue(null)
|
|
682
|
+
|
|
683
|
+
await connector.signSolanaTransactionBytes(buildSerializedV0Tx())
|
|
684
|
+
|
|
685
|
+
expect(featureSignTx.mock.calls[0][0].account).toBe(onlyAccount)
|
|
686
|
+
})
|
|
687
|
+
})
|
|
688
|
+
|
|
689
|
+
describe('reserialize is byte-stable (Path 1 + Path 3 check safety)', () => {
|
|
690
|
+
// Paths 1 (bridge legacy) and 3 (direct legacy) deserialize → sign →
|
|
691
|
+
// re-serialize, then assertSameMessage runs on the result. These prove the
|
|
692
|
+
// round-trip preserves the message, so a legit sign isn't wrongly rejected.
|
|
693
|
+
it('preserves the message through deserialize → user-sign → serialize (v0)', () => {
|
|
694
|
+
const feePayer = Keypair.generate()
|
|
695
|
+
const user = Keypair.generate()
|
|
696
|
+
const msg = new TransactionMessage({
|
|
697
|
+
payerKey: feePayer.publicKey,
|
|
698
|
+
recentBlockhash: '11111111111111111111111111111111',
|
|
699
|
+
instructions: [
|
|
700
|
+
SystemProgram.transfer({
|
|
701
|
+
fromPubkey: user.publicKey, // makes `user` a required signer (slot 1)
|
|
702
|
+
toPubkey: recipient,
|
|
703
|
+
lamports: 1
|
|
704
|
+
})
|
|
705
|
+
]
|
|
706
|
+
}).compileToV0Message()
|
|
707
|
+
|
|
708
|
+
// Relay (Alchemy) signs slot 0; the user slot is still empty — this is what
|
|
709
|
+
// the FE receives from /build.
|
|
710
|
+
const built = new VersionedTransaction(msg)
|
|
711
|
+
built.sign([feePayer])
|
|
712
|
+
const input = built.serialize()
|
|
713
|
+
|
|
714
|
+
// Bridge legacy fallback: deserialize → user signs slot 1 → re-serialize.
|
|
715
|
+
const round = VersionedTransaction.deserialize(input)
|
|
716
|
+
round.sign([user])
|
|
717
|
+
const reserialized = round.serialize()
|
|
718
|
+
|
|
719
|
+
// The canonical check must accept the re-serialized output.
|
|
720
|
+
expect(() => assertSameMessage(input, reserialized)).not.toThrow()
|
|
721
|
+
})
|
|
722
|
+
|
|
723
|
+
it('preserves the message through deserialize → user-sign → serialize (legacy)', () => {
|
|
724
|
+
const feePayer = Keypair.generate()
|
|
725
|
+
const user = Keypair.generate()
|
|
726
|
+
const tx = new Transaction()
|
|
727
|
+
tx.recentBlockhash = '11111111111111111111111111111111'
|
|
728
|
+
tx.feePayer = feePayer.publicKey
|
|
729
|
+
tx.add(
|
|
730
|
+
SystemProgram.transfer({
|
|
731
|
+
fromPubkey: user.publicKey,
|
|
732
|
+
toPubkey: recipient,
|
|
733
|
+
lamports: 1
|
|
734
|
+
})
|
|
735
|
+
)
|
|
736
|
+
tx.partialSign(feePayer) // slot 0 signed; user slot empty
|
|
737
|
+
const input = new Uint8Array(tx.serialize({ requireAllSignatures: false }))
|
|
738
|
+
|
|
739
|
+
const round = Transaction.from(input)
|
|
740
|
+
round.partialSign(user)
|
|
741
|
+
const reserialized = new Uint8Array(
|
|
742
|
+
round.serialize({ requireAllSignatures: false })
|
|
743
|
+
)
|
|
744
|
+
|
|
745
|
+
expect(() => assertSameMessage(input, reserialized)).not.toThrow()
|
|
746
|
+
})
|
|
747
|
+
})
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pick which wallet account signs. We must sign with the account the user
|
|
3
|
+
* actually connected — never guess. A wrong signer produces a useless signature
|
|
4
|
+
* for a payment, so we throw instead of silently falling back.
|
|
5
|
+
*/
|
|
6
|
+
export function resolveSigningAccount<T extends { address: string }>(
|
|
7
|
+
accounts: ReadonlyArray<T>,
|
|
8
|
+
connectedAddress: string | null | undefined
|
|
9
|
+
): T {
|
|
10
|
+
if (connectedAddress) {
|
|
11
|
+
const match = accounts.find(a => a.address === connectedAddress)
|
|
12
|
+
if (!match) {
|
|
13
|
+
throw new Error(
|
|
14
|
+
'Connected Solana account not found in the wallet — refusing to sign with a different account'
|
|
15
|
+
)
|
|
16
|
+
}
|
|
17
|
+
return match
|
|
18
|
+
}
|
|
19
|
+
// No explicit selection is only safe when the wallet has exactly one account.
|
|
20
|
+
if (accounts.length === 1) return accounts[0]!
|
|
21
|
+
throw new Error(
|
|
22
|
+
'Cannot determine which Solana account to sign with — multiple accounts and none selected'
|
|
23
|
+
)
|
|
24
|
+
}
|
|
@@ -15,6 +15,7 @@ export interface ExtendedStandardWalletAdapter extends StandardWalletAdapter {
|
|
|
15
15
|
| 'sendSerializedTransaction'
|
|
16
16
|
| 'signSerializedTransaction'
|
|
17
17
|
| 'signAllSerializedTransactions'
|
|
18
|
+
| 'signSolanaTransactionBytes'
|
|
18
19
|
)[]
|
|
19
20
|
sendSerializedTransaction: (
|
|
20
21
|
transaction: unknown,
|
|
@@ -26,6 +27,12 @@ export interface ExtendedStandardWalletAdapter extends StandardWalletAdapter {
|
|
|
26
27
|
signAllSerializedTransactions: (
|
|
27
28
|
transactions: unknown[]
|
|
28
29
|
) => Promise<Error | Transaction[]>
|
|
30
|
+
// Sign-only, raw bytes (so no Transaction object crosses Comlink). See
|
|
31
|
+
// BridgeParent for the connectedAddress rationale.
|
|
32
|
+
signSolanaTransactionBytes: (
|
|
33
|
+
transaction: unknown,
|
|
34
|
+
connectedAddress?: string
|
|
35
|
+
) => Promise<Uint8Array>
|
|
29
36
|
}
|
|
30
37
|
|
|
31
38
|
export type SolanaAdapter =
|