@meshconnect/uwc-wallet-connect-connector 0.4.17 → 0.5.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/services/solana/solana-transaction-service.d.ts +6 -0
- package/dist/services/solana/solana-transaction-service.d.ts.map +1 -1
- package/dist/services/solana/solana-transaction-service.js +48 -0
- package/dist/services/solana/solana-transaction-service.js.map +1 -1
- package/dist/services/transaction-service.d.ts +6 -0
- package/dist/services/transaction-service.d.ts.map +1 -1
- package/dist/services/transaction-service.js +25 -0
- package/dist/services/transaction-service.js.map +1 -1
- package/dist/wallet-connect-connector.d.ts +8 -0
- package/dist/wallet-connect-connector.d.ts.map +1 -1
- package/dist/wallet-connect-connector.js +10 -0
- package/dist/wallet-connect-connector.js.map +1 -1
- package/package.json +2 -2
- package/src/services/solana/solana-transaction-service.test.ts +402 -0
- package/src/services/solana/solana-transaction-service.ts +73 -0
- package/src/services/transaction-service.ts +41 -0
- package/src/wallet-connect-connector.ts +13 -0
|
@@ -13,5 +13,11 @@ export declare class SolanaTransactionService {
|
|
|
13
13
|
private sendNativeTransaction;
|
|
14
14
|
private sendSplTokenTransaction;
|
|
15
15
|
private submitTransaction;
|
|
16
|
+
/**
|
|
17
|
+
* Sign Solana tx bytes over WalletConnect WITHOUT broadcasting (relay submits).
|
|
18
|
+
* Bytes in/out (legacy or v0); only deserializes if the wallet returns a bare
|
|
19
|
+
* signature instead of the full tx.
|
|
20
|
+
*/
|
|
21
|
+
signTransactionBytes(client: SignClient, session: SessionTypes.Struct, serializedTx: Uint8Array, chainId: string, activeAddress: string): Promise<Uint8Array>;
|
|
16
22
|
}
|
|
17
23
|
//# sourceMappingURL=solana-transaction-service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"solana-transaction-service.d.ts","sourceRoot":"","sources":["../../../src/services/solana/solana-transaction-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,aAAa,EAIb,wBAAwB,EACzB,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"solana-transaction-service.d.ts","sourceRoot":"","sources":["../../../src/services/solana/solana-transaction-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,aAAa,EAIb,wBAAwB,EACzB,MAAM,wBAAwB,CAAA;AAW/B,OAAO,KAAK,UAAU,MAAM,4BAA4B,CAAA;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAOxD,qBAAa,wBAAwB;IAGvB,OAAO,CAAC,aAAa;IAFjC,OAAO,CAAC,OAAO,CAA0B;gBAErB,aAAa,GAAE,aAAkB;IAIrD;;OAEG;IACG,eAAe,CACnB,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,YAAY,CAAC,MAAM,EAC5B,OAAO,EAAE,wBAAwB,EACjC,eAAe,EAAE,MAAM,EACvB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,CAAC;YAsCJ,mCAAmC;YAuCnC,qBAAqB;YAsCrB,uBAAuB;YAuCvB,iBAAiB;IAsG/B;;;;OAIG;IACG,oBAAoB,CACxB,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,YAAY,CAAC,MAAM,EAC5B,YAAY,EAAE,UAAU,EACxB,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,UAAU,CAAC;CAyDvB"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { assertSameMessage, isVersionedTransactionBytes } from '@meshconnect/uwc-types';
|
|
1
2
|
import { VersionedTransaction, PublicKey, Connection, Transaction } from '@solana/web3.js';
|
|
2
3
|
import { standardizeSignature } from '../../utils/encoding-utils';
|
|
3
4
|
import { parseError } from '../../utils/error-utils';
|
|
@@ -174,5 +175,52 @@ export class SolanaTransactionService {
|
|
|
174
175
|
throw signAndSendError;
|
|
175
176
|
}
|
|
176
177
|
}
|
|
178
|
+
/**
|
|
179
|
+
* Sign Solana tx bytes over WalletConnect WITHOUT broadcasting (relay submits).
|
|
180
|
+
* Bytes in/out (legacy or v0); only deserializes if the wallet returns a bare
|
|
181
|
+
* signature instead of the full tx.
|
|
182
|
+
*/
|
|
183
|
+
async signTransactionBytes(client, session, serializedTx, chainId, activeAddress) {
|
|
184
|
+
try {
|
|
185
|
+
// WalletConnect spec: the transaction param is base64.
|
|
186
|
+
const serializedBase64 = Buffer.from(serializedTx).toString('base64');
|
|
187
|
+
const result = await client.request({
|
|
188
|
+
topic: session.topic,
|
|
189
|
+
chainId,
|
|
190
|
+
request: {
|
|
191
|
+
method: 'solana_signTransaction',
|
|
192
|
+
params: { transaction: serializedBase64 }
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
// Full signed tx back (Phantom/Solflare) — verify only a signature was added.
|
|
196
|
+
if ('transaction' in result) {
|
|
197
|
+
const returned = new Uint8Array(Buffer.from(result.transaction, 'base64'));
|
|
198
|
+
assertSameMessage(serializedTx, returned);
|
|
199
|
+
return returned;
|
|
200
|
+
}
|
|
201
|
+
// Bare signature back (legacy WC) — splice it into our original bytes.
|
|
202
|
+
if ('signature' in result) {
|
|
203
|
+
const signatureBytes = base58.decode(result.signature);
|
|
204
|
+
// ed25519 sigs are 64 bytes; reject early with a clear error.
|
|
205
|
+
if (signatureBytes.length !== 64) {
|
|
206
|
+
throw new Error('WalletConnect returned a malformed Solana signature (expected 64 bytes)');
|
|
207
|
+
}
|
|
208
|
+
const userPubkey = new PublicKey(activeAddress);
|
|
209
|
+
if (isVersionedTransactionBytes(serializedTx)) {
|
|
210
|
+
const tx = VersionedTransaction.deserialize(serializedTx);
|
|
211
|
+
tx.addSignature(userPubkey, signatureBytes);
|
|
212
|
+
return tx.serialize();
|
|
213
|
+
}
|
|
214
|
+
const tx = Transaction.from(serializedTx);
|
|
215
|
+
tx.addSignature(userPubkey, Buffer.from(signatureBytes));
|
|
216
|
+
// verifySignatures:false — the relay's fee-payer slot is still unsigned here.
|
|
217
|
+
return new Uint8Array(tx.serialize({ verifySignatures: false }));
|
|
218
|
+
}
|
|
219
|
+
throw new Error('WalletConnect returned an unexpected response shape for solana_signTransaction');
|
|
220
|
+
}
|
|
221
|
+
catch (error) {
|
|
222
|
+
throw parseError(error);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
177
225
|
}
|
|
178
226
|
//# sourceMappingURL=solana-transaction-service.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"solana-transaction-service.js","sourceRoot":"","sources":["../../../src/services/solana/solana-transaction-service.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"solana-transaction-service.js","sourceRoot":"","sources":["../../../src/services/solana/solana-transaction-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,5 +14,11 @@ export declare class TransactionService {
|
|
|
14
14
|
* Send a transaction with the connected wallet
|
|
15
15
|
*/
|
|
16
16
|
sendTransaction(request: TransactionRequest): Promise<TransactionResult>;
|
|
17
|
+
/**
|
|
18
|
+
* Sign-only path for Solana transactions over WalletConnect.
|
|
19
|
+
* Mirrors the validation done in sendTransaction but routes to the sign-only Solana flow
|
|
20
|
+
* instead of signAndSend. Used by fee-payer relay flows where the relay server broadcasts.
|
|
21
|
+
*/
|
|
22
|
+
signSolanaTransactionBytes(serializedTx: Uint8Array): Promise<Uint8Array>;
|
|
17
23
|
}
|
|
18
24
|
//# sourceMappingURL=transaction-service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transaction-service.d.ts","sourceRoot":"","sources":["../../src/services/transaction-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,iBAAiB,EAGjB,aAAa,EACd,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAIxD;;GAEG;AACH,qBAAa,kBAAkB;IAK3B,OAAO,CAAC,mBAAmB;IAC3B,OAAO,CAAC,iBAAiB;IAL3B,OAAO,CAAC,eAAe,CAA4B;IACnD,OAAO,CAAC,aAAa,CAA0B;gBAGrC,mBAAmB,EAAE,mBAAmB,EACxC,iBAAiB,EAAE,iBAAiB,EAC5C,aAAa,GAAE,aAAkB;IAMnC;;OAEG;IACG,eAAe,CACnB,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"transaction-service.d.ts","sourceRoot":"","sources":["../../src/services/transaction-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,iBAAiB,EAGjB,aAAa,EACd,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAIxD;;GAEG;AACH,qBAAa,kBAAkB;IAK3B,OAAO,CAAC,mBAAmB;IAC3B,OAAO,CAAC,iBAAiB;IAL3B,OAAO,CAAC,eAAe,CAA4B;IACnD,OAAO,CAAC,aAAa,CAA0B;gBAGrC,mBAAmB,EAAE,mBAAmB,EACxC,iBAAiB,EAAE,iBAAiB,EAC5C,aAAa,GAAE,aAAkB;IAMnC;;OAEG;IACG,eAAe,CACnB,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,iBAAiB,CAAC;IA0C7B;;;;OAIG;IACG,0BAA0B,CAC9B,YAAY,EAAE,UAAU,GACvB,OAAO,CAAC,UAAU,CAAC;CAiCvB"}
|
|
@@ -45,5 +45,30 @@ export class TransactionService {
|
|
|
45
45
|
throw new Error(`Unsupported namespace: ${namespace}`);
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Sign-only path for Solana transactions over WalletConnect.
|
|
50
|
+
* Mirrors the validation done in sendTransaction but routes to the sign-only Solana flow
|
|
51
|
+
* instead of signAndSend. Used by fee-payer relay flows where the relay server broadcasts.
|
|
52
|
+
*/
|
|
53
|
+
async signSolanaTransactionBytes(serializedTx) {
|
|
54
|
+
const session = this.connectionService.getSession();
|
|
55
|
+
if (!session) {
|
|
56
|
+
throw new Error('No active session. Please connect first.');
|
|
57
|
+
}
|
|
58
|
+
const activeNetwork = this.connectionService.getActiveNetwork();
|
|
59
|
+
const activeAddress = this.connectionService.getActiveAddress();
|
|
60
|
+
if (!activeNetwork) {
|
|
61
|
+
throw new Error('No active network. Please connect first.');
|
|
62
|
+
}
|
|
63
|
+
if (!activeAddress) {
|
|
64
|
+
throw new Error('No active address. Please connect first.');
|
|
65
|
+
}
|
|
66
|
+
const namespace = activeNetwork.id.split(':')[0];
|
|
67
|
+
if (namespace !== 'solana') {
|
|
68
|
+
throw new Error(`signSolanaTransactionBytes requires a Solana network (got namespace "${namespace}")`);
|
|
69
|
+
}
|
|
70
|
+
const client = await this.walletConnectClient.getClient();
|
|
71
|
+
return this.solanaService.signTransactionBytes(client, session, serializedTx, activeNetwork.id, activeAddress);
|
|
72
|
+
}
|
|
48
73
|
}
|
|
49
74
|
//# sourceMappingURL=transaction-service.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transaction-service.js","sourceRoot":"","sources":["../../src/services/transaction-service.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AACxD,OAAO,EAAE,0BAA0B,EAAE,MAAM,yCAAyC,CAAA;AACpF,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAA;AAE9E;;GAEG;AACH,MAAM,OAAO,kBAAkB;IAKnB;IACA;IALF,eAAe,CAA4B;IAC3C,aAAa,CAA0B;IAE/C,YACU,mBAAwC,EACxC,iBAAoC,EAC5C,gBAA+B,EAAE;QAFzB,wBAAmB,GAAnB,mBAAmB,CAAqB;QACxC,sBAAiB,GAAjB,iBAAiB,CAAmB;QAG5C,IAAI,CAAC,eAAe,GAAG,IAAI,0BAA0B,EAAE,CAAA;QACvD,IAAI,CAAC,aAAa,GAAG,IAAI,wBAAwB,CAAC,aAAa,CAAC,CAAA;IAClE,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe,CACnB,OAA2B;QAE3B,MAAM,OAAO,GAAG,IAAI,CAAC,iBAAiB,CAAC,UAAU,EAAE,CAAA;QACnD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAA;QAC7D,CAAC;QAED,MAAM,aAAa,GAAG,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,EAAE,CAAA;QAC/D,MAAM,aAAa,GAAG,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,EAAE,CAAA;QAE/D,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAA;QAC7D,CAAC;QAED,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAA;QAC7D,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,SAAS,EAAE,CAAA;QAEzD,sCAAsC;QACtC,MAAM,SAAS,GAAG,aAAa,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;QAEhD,IAAI,SAAS,KAAK,QAAQ,EAAE,CAAC;YAC3B,OAAO,IAAI,CAAC,eAAe,CAAC,eAAe,CACzC,MAAM,EACN,OAAO,EACP,OAAqC,EACrC,aAAa,CAAC,EAAE,CACjB,CAAA;QACH,CAAC;aAAM,IAAI,SAAS,KAAK,QAAQ,EAAE,CAAC;YAClC,OAAO,IAAI,CAAC,aAAa,CAAC,eAAe,CACvC,MAAM,EACN,OAAO,EACP,OAAmC,EACnC,aAAa,CAAC,EAAE,EAChB,aAAa,CACd,CAAA;QACH,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,0BAA0B,SAAS,EAAE,CAAC,CAAA;QACxD,CAAC;IACH,CAAC;CACF"}
|
|
1
|
+
{"version":3,"file":"transaction-service.js","sourceRoot":"","sources":["../../src/services/transaction-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -13,5 +13,13 @@ export declare class WalletConnectConnector implements Connector {
|
|
|
13
13
|
switchNetwork(network: Network): Promise<SwitchNetworkResult>;
|
|
14
14
|
signMessage(message: string): Promise<SignatureType>;
|
|
15
15
|
sendTransaction(request: TransactionRequest): Promise<TransactionResult>;
|
|
16
|
+
/**
|
|
17
|
+
* Sign a Solana transaction over WalletConnect without broadcasting.
|
|
18
|
+
* Mirrors InjectedConnector.signSolanaTransactionBytes so the core router can branch on
|
|
19
|
+
* connection mode without the call sites caring which connector backs the active wallet.
|
|
20
|
+
*
|
|
21
|
+
* Used by fee-payer relay flows (Mesh BE owns broadcast); never broadcasts via the wallet.
|
|
22
|
+
*/
|
|
23
|
+
signSolanaTransactionBytes(serializedTx: Uint8Array): Promise<Uint8Array>;
|
|
16
24
|
}
|
|
17
25
|
//# sourceMappingURL=wallet-connect-connector.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wallet-connect-connector.d.ts","sourceRoot":"","sources":["../src/wallet-connect-connector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,SAAS,EACT,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,EACb,aAAa,EACd,MAAM,wBAAwB,CAAA;AAO/B,qBAAa,sBAAuB,YAAW,SAAS;IACtD,OAAO,CAAC,mBAAmB,CAAqB;IAChD,OAAO,CAAC,iBAAiB,CAAmB;IAC5C,OAAO,CAAC,oBAAoB,CAAsB;IAClD,OAAO,CAAC,gBAAgB,CAAkB;IAC1C,OAAO,CAAC,kBAAkB,CAAoB;IAC9C,OAAO,CAAC,aAAa,CAAe;gBAExB,MAAM,EAAE,mBAAmB,EAAE,aAAa,GAAE,aAAkB;IAmBpE,OAAO,CACX,OAAO,EAAE,OAAO,EAChB,QAAQ,CAAC,EAAE,qBAAqB,GAC/B,OAAO,CAAC,eAAe,CAAC;IAU3B,gBAAgB,IAAI,MAAM;IAQpB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAI7D,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAIpD,eAAe,CACnB,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"wallet-connect-connector.d.ts","sourceRoot":"","sources":["../src/wallet-connect-connector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,SAAS,EACT,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EACjB,aAAa,EACb,aAAa,EACd,MAAM,wBAAwB,CAAA;AAO/B,qBAAa,sBAAuB,YAAW,SAAS;IACtD,OAAO,CAAC,mBAAmB,CAAqB;IAChD,OAAO,CAAC,iBAAiB,CAAmB;IAC5C,OAAO,CAAC,oBAAoB,CAAsB;IAClD,OAAO,CAAC,gBAAgB,CAAkB;IAC1C,OAAO,CAAC,kBAAkB,CAAoB;IAC9C,OAAO,CAAC,aAAa,CAAe;gBAExB,MAAM,EAAE,mBAAmB,EAAE,aAAa,GAAE,aAAkB;IAmBpE,OAAO,CACX,OAAO,EAAE,OAAO,EAChB,QAAQ,CAAC,EAAE,qBAAqB,GAC/B,OAAO,CAAC,eAAe,CAAC;IAU3B,gBAAgB,IAAI,MAAM;IAQpB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAI7D,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAIpD,eAAe,CACnB,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,iBAAiB,CAAC;IAI7B;;;;;;OAMG;IACG,0BAA0B,CAC9B,YAAY,EAAE,UAAU,GACvB,OAAO,CAAC,UAAU,CAAC;CAGvB"}
|
|
@@ -43,5 +43,15 @@ export class WalletConnectConnector {
|
|
|
43
43
|
async sendTransaction(request) {
|
|
44
44
|
return this.transactionService.sendTransaction(request);
|
|
45
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Sign a Solana transaction over WalletConnect without broadcasting.
|
|
48
|
+
* Mirrors InjectedConnector.signSolanaTransactionBytes so the core router can branch on
|
|
49
|
+
* connection mode without the call sites caring which connector backs the active wallet.
|
|
50
|
+
*
|
|
51
|
+
* Used by fee-payer relay flows (Mesh BE owns broadcast); never broadcasts via the wallet.
|
|
52
|
+
*/
|
|
53
|
+
async signSolanaTransactionBytes(serializedTx) {
|
|
54
|
+
return this.transactionService.signSolanaTransactionBytes(serializedTx);
|
|
55
|
+
}
|
|
46
56
|
}
|
|
47
57
|
//# sourceMappingURL=wallet-connect-connector.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wallet-connect-connector.js","sourceRoot":"","sources":["../src/wallet-connect-connector.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAA;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAA;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAA;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AAEnE,MAAM,OAAO,sBAAsB;IACzB,mBAAmB,CAAqB;IACxC,iBAAiB,CAAmB;IACpC,oBAAoB,CAAsB;IAC1C,gBAAgB,CAAkB;IAClC,kBAAkB,CAAoB;IACtC,aAAa,CAAe;IAEpC,YAAY,MAA2B,EAAE,gBAA+B,EAAE;QACxE,IAAI,CAAC,mBAAmB,GAAG,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAA;QAC1D,IAAI,CAAC,aAAa,GAAG,aAAa,CAAA;QAClC,IAAI,CAAC,iBAAiB,GAAG,IAAI,iBAAiB,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAA;QACxE,IAAI,CAAC,oBAAoB,GAAG,IAAI,oBAAoB,CAClD,IAAI,CAAC,mBAAmB,EACxB,IAAI,CAAC,iBAAiB,CACvB,CAAA;QACD,IAAI,CAAC,gBAAgB,GAAG,IAAI,gBAAgB,CAC1C,IAAI,CAAC,mBAAmB,EACxB,IAAI,CAAC,iBAAiB,CACvB,CAAA;QACD,IAAI,CAAC,kBAAkB,GAAG,IAAI,kBAAkB,CAC9C,IAAI,CAAC,mBAAmB,EACxB,IAAI,CAAC,iBAAiB,EACtB,IAAI,CAAC,aAAa,CACnB,CAAA;IACH,CAAC;IAED,KAAK,CAAC,OAAO,CACX,OAAgB,EAChB,QAAgC;QAEhC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CACb,gEAAgE,CACjE,CAAA;QACH,CAAC;QAED,OAAO,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;IAC1D,CAAC;IAED,gBAAgB;QACd,MAAM,GAAG,GAAG,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,EAAE,CAAA;QACrD,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAA;QACvE,CAAC;QACD,OAAO,GAAG,CAAA;IACZ,CAAC;IAED,KAAK,CAAC,UAAU;QACd,OAAO,IAAI,CAAC,iBAAiB,CAAC,UAAU,EAAE,CAAA;IAC5C,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,OAAgB;QAClC,OAAO,IAAI,CAAC,oBAAoB,CAAC,aAAa,CAAC,OAAO,CAAC,CAAA;IACzD,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,OAAe;QAC/B,OAAO,IAAI,CAAC,gBAAgB,CAAC,WAAW,CAAC,OAAO,CAAC,CAAA;IACnD,CAAC;IAED,KAAK,CAAC,eAAe,CACnB,OAA2B;QAE3B,OAAO,IAAI,CAAC,kBAAkB,CAAC,eAAe,CAAC,OAAO,CAAC,CAAA;IACzD,CAAC;CACF"}
|
|
1
|
+
{"version":3,"file":"wallet-connect-connector.js","sourceRoot":"","sources":["../src/wallet-connect-connector.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAA;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAA;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAA;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AAEnE,MAAM,OAAO,sBAAsB;IACzB,mBAAmB,CAAqB;IACxC,iBAAiB,CAAmB;IACpC,oBAAoB,CAAsB;IAC1C,gBAAgB,CAAkB;IAClC,kBAAkB,CAAoB;IACtC,aAAa,CAAe;IAEpC,YAAY,MAA2B,EAAE,gBAA+B,EAAE;QACxE,IAAI,CAAC,mBAAmB,GAAG,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAA;QAC1D,IAAI,CAAC,aAAa,GAAG,aAAa,CAAA;QAClC,IAAI,CAAC,iBAAiB,GAAG,IAAI,iBAAiB,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAA;QACxE,IAAI,CAAC,oBAAoB,GAAG,IAAI,oBAAoB,CAClD,IAAI,CAAC,mBAAmB,EACxB,IAAI,CAAC,iBAAiB,CACvB,CAAA;QACD,IAAI,CAAC,gBAAgB,GAAG,IAAI,gBAAgB,CAC1C,IAAI,CAAC,mBAAmB,EACxB,IAAI,CAAC,iBAAiB,CACvB,CAAA;QACD,IAAI,CAAC,kBAAkB,GAAG,IAAI,kBAAkB,CAC9C,IAAI,CAAC,mBAAmB,EACxB,IAAI,CAAC,iBAAiB,EACtB,IAAI,CAAC,aAAa,CACnB,CAAA;IACH,CAAC;IAED,KAAK,CAAC,OAAO,CACX,OAAgB,EAChB,QAAgC;QAEhC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CACb,gEAAgE,CACjE,CAAA;QACH,CAAC;QAED,OAAO,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;IAC1D,CAAC;IAED,gBAAgB;QACd,MAAM,GAAG,GAAG,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,EAAE,CAAA;QACrD,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAA;QACvE,CAAC;QACD,OAAO,GAAG,CAAA;IACZ,CAAC;IAED,KAAK,CAAC,UAAU;QACd,OAAO,IAAI,CAAC,iBAAiB,CAAC,UAAU,EAAE,CAAA;IAC5C,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,OAAgB;QAClC,OAAO,IAAI,CAAC,oBAAoB,CAAC,aAAa,CAAC,OAAO,CAAC,CAAA;IACzD,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,OAAe;QAC/B,OAAO,IAAI,CAAC,gBAAgB,CAAC,WAAW,CAAC,OAAO,CAAC,CAAA;IACnD,CAAC;IAED,KAAK,CAAC,eAAe,CACnB,OAA2B;QAE3B,OAAO,IAAI,CAAC,kBAAkB,CAAC,eAAe,CAAC,OAAO,CAAC,CAAA;IACzD,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,0BAA0B,CAC9B,YAAwB;QAExB,OAAO,IAAI,CAAC,kBAAkB,CAAC,0BAA0B,CAAC,YAAY,CAAC,CAAA;IACzE,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meshconnect/uwc-wallet-connect-connector",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "WalletConnect connector for Universal Wallet Connector",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"bs58": "6.0.0",
|
|
25
25
|
"buffer": "^6.0.3",
|
|
26
26
|
"viem": "^2.44.4",
|
|
27
|
-
"@meshconnect/uwc-types": "0.
|
|
27
|
+
"@meshconnect/uwc-types": "0.14.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"typescript": "^5.9.3"
|
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
// @vitest-environment node
|
|
2
|
+
// Reason: @solana/web3.js + @solana/buffer-layout fail `instanceof Uint8Array` checks under
|
|
3
|
+
// jsdom because Buffer in the polyfilled env is not the same prototype the layout library
|
|
4
|
+
// checks against. Running this file in node fixes the encoding pipeline without affecting
|
|
5
|
+
// the rest of the suite (which stays on jsdom for DOM-dependent tests).
|
|
6
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
7
|
+
import { SolanaTransactionService } from './solana-transaction-service'
|
|
8
|
+
import {
|
|
9
|
+
Keypair,
|
|
10
|
+
PublicKey,
|
|
11
|
+
Transaction,
|
|
12
|
+
SystemProgram,
|
|
13
|
+
VersionedTransaction,
|
|
14
|
+
TransactionMessage
|
|
15
|
+
} from '@solana/web3.js'
|
|
16
|
+
import { Buffer } from 'buffer'
|
|
17
|
+
import base58 from 'bs58'
|
|
18
|
+
import type SignClient from '@walletconnect/sign-client'
|
|
19
|
+
import type { SessionTypes } from '@walletconnect/types'
|
|
20
|
+
|
|
21
|
+
const SOL_CHAIN_ID = 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'
|
|
22
|
+
const MOCK_TOPIC = 'mock-session-topic'
|
|
23
|
+
|
|
24
|
+
// We sign with a real keypair so the test exercises the full bytes-in / bytes-out contract:
|
|
25
|
+
// produce a signature locally, hand it to the service via the mocked WC response, and verify
|
|
26
|
+
// the returned bytes deserialize cleanly.
|
|
27
|
+
const userKeypair = Keypair.generate()
|
|
28
|
+
const recipient = Keypair.generate().publicKey
|
|
29
|
+
|
|
30
|
+
function buildLegacyTx(blockhash: string): Transaction {
|
|
31
|
+
const tx = new Transaction()
|
|
32
|
+
tx.recentBlockhash = blockhash
|
|
33
|
+
tx.feePayer = userKeypair.publicKey
|
|
34
|
+
tx.add(
|
|
35
|
+
SystemProgram.transfer({
|
|
36
|
+
fromPubkey: userKeypair.publicKey,
|
|
37
|
+
toPubkey: recipient,
|
|
38
|
+
lamports: 1
|
|
39
|
+
})
|
|
40
|
+
)
|
|
41
|
+
return tx
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function buildVersionedTx(blockhash: string): VersionedTransaction {
|
|
45
|
+
const message = new TransactionMessage({
|
|
46
|
+
payerKey: userKeypair.publicKey,
|
|
47
|
+
recentBlockhash: blockhash,
|
|
48
|
+
instructions: [
|
|
49
|
+
SystemProgram.transfer({
|
|
50
|
+
fromPubkey: userKeypair.publicKey,
|
|
51
|
+
toPubkey: recipient,
|
|
52
|
+
lamports: 1
|
|
53
|
+
})
|
|
54
|
+
]
|
|
55
|
+
}).compileToV0Message()
|
|
56
|
+
return new VersionedTransaction(message)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function makeMockSignClient(
|
|
60
|
+
response: { transaction: string } | { signature: string }
|
|
61
|
+
): { request: ReturnType<typeof vi.fn>; client: SignClient } {
|
|
62
|
+
const request = vi.fn().mockResolvedValue(response)
|
|
63
|
+
return {
|
|
64
|
+
request,
|
|
65
|
+
client: { request } as unknown as SignClient
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const mockSession = { topic: MOCK_TOPIC } as SessionTypes.Struct
|
|
70
|
+
|
|
71
|
+
describe('SolanaTransactionService.signTransactionBytes', () => {
|
|
72
|
+
let service: SolanaTransactionService
|
|
73
|
+
|
|
74
|
+
beforeEach(() => {
|
|
75
|
+
service = new SolanaTransactionService()
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('decodes the {transaction} response shape directly without re-signing locally (V0)', async () => {
|
|
79
|
+
// Modern wallets (Phantom, Solflare) return the fully-signed tx as base64 — we should not
|
|
80
|
+
// touch web3.js at all in this branch. We simulate the wallet's signature by signing the
|
|
81
|
+
// V0 tx with the user keypair and base64-encoding the result.
|
|
82
|
+
const blockhash = '11111111111111111111111111111111'
|
|
83
|
+
const unsigned = buildVersionedTx(blockhash)
|
|
84
|
+
const signedLocally = buildVersionedTx(blockhash)
|
|
85
|
+
signedLocally.sign([userKeypair])
|
|
86
|
+
const fullySignedBase64 = Buffer.from(signedLocally.serialize()).toString(
|
|
87
|
+
'base64'
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
const { request, client } = makeMockSignClient({
|
|
91
|
+
transaction: fullySignedBase64
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
const result = await service.signTransactionBytes(
|
|
95
|
+
client,
|
|
96
|
+
mockSession,
|
|
97
|
+
unsigned.serialize(),
|
|
98
|
+
SOL_CHAIN_ID,
|
|
99
|
+
userKeypair.publicKey.toBase58()
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
expect(request).toHaveBeenCalledWith({
|
|
103
|
+
topic: MOCK_TOPIC,
|
|
104
|
+
chainId: SOL_CHAIN_ID,
|
|
105
|
+
request: {
|
|
106
|
+
method: 'solana_signTransaction',
|
|
107
|
+
params: { transaction: expect.any(String) }
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
// Bytes round-trip: result should deserialize as a signed VersionedTransaction.
|
|
111
|
+
const out = VersionedTransaction.deserialize(result)
|
|
112
|
+
expect(out.signatures.length).toBeGreaterThan(0)
|
|
113
|
+
// Signature must be from the user's keypair, not zero-bytes.
|
|
114
|
+
const isAllZero = out.signatures[0]?.every((b: number) => b === 0)
|
|
115
|
+
expect(isAllZero).toBe(false)
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
it('handles the {signature} response shape by splicing into a V0 tx', async () => {
|
|
119
|
+
// Older WC wallets return only the bare signature; the service must add it to the input.
|
|
120
|
+
const blockhash = '11111111111111111111111111111111'
|
|
121
|
+
const unsigned = buildVersionedTx(blockhash)
|
|
122
|
+
const signedLocally = buildVersionedTx(blockhash)
|
|
123
|
+
signedLocally.sign([userKeypair])
|
|
124
|
+
const wireSignature = base58.encode(signedLocally.signatures[0]!)
|
|
125
|
+
|
|
126
|
+
const { request, client } = makeMockSignClient({ signature: wireSignature })
|
|
127
|
+
|
|
128
|
+
const result = await service.signTransactionBytes(
|
|
129
|
+
client,
|
|
130
|
+
mockSession,
|
|
131
|
+
unsigned.serialize(),
|
|
132
|
+
SOL_CHAIN_ID,
|
|
133
|
+
userKeypair.publicKey.toBase58()
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
expect(request).toHaveBeenCalled()
|
|
137
|
+
const out = VersionedTransaction.deserialize(result)
|
|
138
|
+
// Must contain the signature we returned, attached to the user account.
|
|
139
|
+
expect(out.signatures[0]).toBeDefined()
|
|
140
|
+
expect(Array.from(out.signatures[0]!)).toEqual(
|
|
141
|
+
Array.from(signedLocally.signatures[0]!)
|
|
142
|
+
)
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
it('handles the {signature} response shape by splicing into a legacy tx', async () => {
|
|
146
|
+
const blockhash = '11111111111111111111111111111111'
|
|
147
|
+
const unsigned = buildLegacyTx(blockhash)
|
|
148
|
+
// Sign locally to produce the wire signature the wallet would have returned.
|
|
149
|
+
const signedLocally = buildLegacyTx(blockhash)
|
|
150
|
+
signedLocally.sign(userKeypair)
|
|
151
|
+
const userSig = signedLocally.signatures.find(s =>
|
|
152
|
+
s.publicKey.equals(userKeypair.publicKey)
|
|
153
|
+
)!.signature!
|
|
154
|
+
const wireSignature = base58.encode(userSig)
|
|
155
|
+
|
|
156
|
+
const { client } = makeMockSignClient({ signature: wireSignature })
|
|
157
|
+
|
|
158
|
+
const result = await service.signTransactionBytes(
|
|
159
|
+
client,
|
|
160
|
+
mockSession,
|
|
161
|
+
unsigned.serialize({ requireAllSignatures: false }),
|
|
162
|
+
SOL_CHAIN_ID,
|
|
163
|
+
userKeypair.publicKey.toBase58()
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
const out = Transaction.from(result)
|
|
167
|
+
const sigEntry = out.signatures.find(s =>
|
|
168
|
+
s.publicKey.equals(userKeypair.publicKey)
|
|
169
|
+
)
|
|
170
|
+
expect(sigEntry?.signature).not.toBeNull()
|
|
171
|
+
expect(Array.from(sigEntry!.signature!)).toEqual(Array.from(userSig))
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
it('never calls solana_signAndSendTransaction (sign-only contract)', async () => {
|
|
175
|
+
// Critical for fee-payer relay: if this path ever broadcasts, the relay server's signature
|
|
176
|
+
// never lands on-chain because the wallet's own RPC fronts the tx with insufficient fee
|
|
177
|
+
// payer balance. Lock this in.
|
|
178
|
+
const blockhash = '11111111111111111111111111111111'
|
|
179
|
+
const unsigned = buildVersionedTx(blockhash)
|
|
180
|
+
const signedLocally = buildVersionedTx(blockhash)
|
|
181
|
+
signedLocally.sign([userKeypair])
|
|
182
|
+
|
|
183
|
+
const { request, client } = makeMockSignClient({
|
|
184
|
+
transaction: Buffer.from(signedLocally.serialize()).toString('base64')
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
await service.signTransactionBytes(
|
|
188
|
+
client,
|
|
189
|
+
mockSession,
|
|
190
|
+
unsigned.serialize(),
|
|
191
|
+
SOL_CHAIN_ID,
|
|
192
|
+
userKeypair.publicKey.toBase58()
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
const calls = request.mock.calls.map(
|
|
196
|
+
c => (c[0] as { request: { method: string } }).request.method
|
|
197
|
+
)
|
|
198
|
+
expect(calls).toEqual(['solana_signTransaction'])
|
|
199
|
+
expect(calls).not.toContain('solana_signAndSendTransaction')
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
it('throws when the wallet returns an unexpected response shape', async () => {
|
|
203
|
+
const blockhash = '11111111111111111111111111111111'
|
|
204
|
+
const unsigned = buildVersionedTx(blockhash)
|
|
205
|
+
const { client } = makeMockSignClient(
|
|
206
|
+
// @ts-expect-error — intentionally malformed
|
|
207
|
+
{ foo: 'bar' }
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
await expect(
|
|
211
|
+
service.signTransactionBytes(
|
|
212
|
+
client,
|
|
213
|
+
mockSession,
|
|
214
|
+
unsigned.serialize(),
|
|
215
|
+
SOL_CHAIN_ID,
|
|
216
|
+
userKeypair.publicKey.toBase58()
|
|
217
|
+
)
|
|
218
|
+
).rejects.toThrow()
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
it('propagates wallet RPC errors via parseError', async () => {
|
|
222
|
+
const blockhash = '11111111111111111111111111111111'
|
|
223
|
+
const unsigned = buildVersionedTx(blockhash)
|
|
224
|
+
const request = vi.fn().mockRejectedValue(new Error('User rejected'))
|
|
225
|
+
const client = { request } as unknown as SignClient
|
|
226
|
+
|
|
227
|
+
await expect(
|
|
228
|
+
service.signTransactionBytes(
|
|
229
|
+
client,
|
|
230
|
+
mockSession,
|
|
231
|
+
unsigned.serialize(),
|
|
232
|
+
SOL_CHAIN_ID,
|
|
233
|
+
userKeypair.publicKey.toBase58()
|
|
234
|
+
)
|
|
235
|
+
).rejects.toThrow(/User rejected/)
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
it('correctly routes V0 vs legacy through the {signature} branch', async () => {
|
|
239
|
+
// The version flag lives on the message byte, not the first tx byte (the first byte is
|
|
240
|
+
// the shortvec signature count). Both shapes must round-trip cleanly when the wallet
|
|
241
|
+
// returns only a bare signature — exercised by the two tests above.
|
|
242
|
+
// This test is a regression guard: build one of each, call the service, and assert
|
|
243
|
+
// each deserializes back to the matching type.
|
|
244
|
+
const blockhash = '11111111111111111111111111111111'
|
|
245
|
+
|
|
246
|
+
const v0Unsigned = buildVersionedTx(blockhash)
|
|
247
|
+
const v0Signed = buildVersionedTx(blockhash)
|
|
248
|
+
v0Signed.sign([userKeypair])
|
|
249
|
+
const v0Sig = base58.encode(v0Signed.signatures[0]!)
|
|
250
|
+
const v0Result = await new SolanaTransactionService().signTransactionBytes(
|
|
251
|
+
makeMockSignClient({ signature: v0Sig }).client,
|
|
252
|
+
mockSession,
|
|
253
|
+
v0Unsigned.serialize(),
|
|
254
|
+
SOL_CHAIN_ID,
|
|
255
|
+
userKeypair.publicKey.toBase58()
|
|
256
|
+
)
|
|
257
|
+
// Must deserialize as V0 — Transaction.from on V0 bytes throws.
|
|
258
|
+
expect(() => VersionedTransaction.deserialize(v0Result)).not.toThrow()
|
|
259
|
+
|
|
260
|
+
const legacyUnsigned = buildLegacyTx(blockhash)
|
|
261
|
+
const legacySigned = buildLegacyTx(blockhash)
|
|
262
|
+
legacySigned.sign(userKeypair)
|
|
263
|
+
const userSig = legacySigned.signatures.find(s =>
|
|
264
|
+
s.publicKey.equals(userKeypair.publicKey)
|
|
265
|
+
)!.signature!
|
|
266
|
+
const legacySigB58 = base58.encode(userSig)
|
|
267
|
+
const legacyResult =
|
|
268
|
+
await new SolanaTransactionService().signTransactionBytes(
|
|
269
|
+
makeMockSignClient({ signature: legacySigB58 }).client,
|
|
270
|
+
mockSession,
|
|
271
|
+
legacyUnsigned.serialize({ requireAllSignatures: false }),
|
|
272
|
+
SOL_CHAIN_ID,
|
|
273
|
+
userKeypair.publicKey.toBase58()
|
|
274
|
+
)
|
|
275
|
+
// Must deserialize as legacy.
|
|
276
|
+
expect(() => Transaction.from(legacyResult)).not.toThrow()
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
it('rejects a {transaction} whose message was altered by the wallet (tamper guard)', async () => {
|
|
280
|
+
// A wallet must only ADD the user's signature. If it returns a transaction
|
|
281
|
+
// that pays a different recipient, we refuse instead of handing tampered
|
|
282
|
+
// bytes to the relay for broadcast. (The happy path — same message, signature
|
|
283
|
+
// added — is covered by the {transaction} round-trip test above.)
|
|
284
|
+
const blockhash = '11111111111111111111111111111111'
|
|
285
|
+
const requested = buildVersionedTx(blockhash) // pays `recipient`
|
|
286
|
+
|
|
287
|
+
const attackerRecipient = Keypair.generate().publicKey
|
|
288
|
+
const tamperedMsg = new TransactionMessage({
|
|
289
|
+
payerKey: userKeypair.publicKey,
|
|
290
|
+
recentBlockhash: blockhash,
|
|
291
|
+
instructions: [
|
|
292
|
+
SystemProgram.transfer({
|
|
293
|
+
fromPubkey: userKeypair.publicKey,
|
|
294
|
+
toPubkey: attackerRecipient,
|
|
295
|
+
lamports: 1
|
|
296
|
+
})
|
|
297
|
+
]
|
|
298
|
+
}).compileToV0Message()
|
|
299
|
+
const tampered = new VersionedTransaction(tamperedMsg)
|
|
300
|
+
tampered.sign([userKeypair])
|
|
301
|
+
const tamperedBase64 = Buffer.from(tampered.serialize()).toString('base64')
|
|
302
|
+
|
|
303
|
+
const { client } = makeMockSignClient({ transaction: tamperedBase64 })
|
|
304
|
+
|
|
305
|
+
await expect(
|
|
306
|
+
service.signTransactionBytes(
|
|
307
|
+
client,
|
|
308
|
+
mockSession,
|
|
309
|
+
requested.serialize(),
|
|
310
|
+
SOL_CHAIN_ID,
|
|
311
|
+
userKeypair.publicKey.toBase58()
|
|
312
|
+
)
|
|
313
|
+
).rejects.toThrow('Signed transaction does not match the request')
|
|
314
|
+
})
|
|
315
|
+
})
|
|
316
|
+
|
|
317
|
+
describe('SolanaTransactionService — keys are not concatenated into params', () => {
|
|
318
|
+
it('encodes serializedTx as a single base64 string in params.transaction', async () => {
|
|
319
|
+
// Regression guard: the WC Solana spec puts the tx under params.transaction (not as a
|
|
320
|
+
// positional array). Wallets reject the request silently if we pass an array.
|
|
321
|
+
const blockhash = '11111111111111111111111111111111'
|
|
322
|
+
const unsigned = buildVersionedTx(blockhash)
|
|
323
|
+
const signedLocally = buildVersionedTx(blockhash)
|
|
324
|
+
signedLocally.sign([userKeypair])
|
|
325
|
+
|
|
326
|
+
const request = vi.fn().mockResolvedValue({
|
|
327
|
+
transaction: Buffer.from(signedLocally.serialize()).toString('base64')
|
|
328
|
+
})
|
|
329
|
+
const client = { request } as unknown as SignClient
|
|
330
|
+
const service = new SolanaTransactionService()
|
|
331
|
+
|
|
332
|
+
await service.signTransactionBytes(
|
|
333
|
+
client,
|
|
334
|
+
mockSession,
|
|
335
|
+
unsigned.serialize(),
|
|
336
|
+
SOL_CHAIN_ID,
|
|
337
|
+
userKeypair.publicKey.toBase58()
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
const params = request.mock.calls[0]![0]!.request.params
|
|
341
|
+
expect(typeof params.transaction).toBe('string')
|
|
342
|
+
expect(Array.isArray(params)).toBe(false)
|
|
343
|
+
// Must be valid base64.
|
|
344
|
+
expect(() => Buffer.from(params.transaction, 'base64')).not.toThrow()
|
|
345
|
+
})
|
|
346
|
+
})
|
|
347
|
+
|
|
348
|
+
describe('SolanaTransactionService — public method preserves PublicKey usage', () => {
|
|
349
|
+
it('attaches signature using the activeAddress, not feePayer from the message', async () => {
|
|
350
|
+
// The relay flow has two signers: relay (slot 0 = fee payer) and user (slot 1).
|
|
351
|
+
// We pass activeAddress = user, so the signature must land on the user slot.
|
|
352
|
+
const blockhash = '11111111111111111111111111111111'
|
|
353
|
+
const relayKeypair = Keypair.generate()
|
|
354
|
+
|
|
355
|
+
const message = new TransactionMessage({
|
|
356
|
+
payerKey: relayKeypair.publicKey,
|
|
357
|
+
recentBlockhash: blockhash,
|
|
358
|
+
instructions: [
|
|
359
|
+
SystemProgram.transfer({
|
|
360
|
+
fromPubkey: userKeypair.publicKey,
|
|
361
|
+
toPubkey: recipient,
|
|
362
|
+
lamports: 1
|
|
363
|
+
})
|
|
364
|
+
]
|
|
365
|
+
}).compileToV0Message()
|
|
366
|
+
const unsigned = new VersionedTransaction(message)
|
|
367
|
+
|
|
368
|
+
// Local: sign with user keypair only (not relay) to simulate what the wallet would do.
|
|
369
|
+
const signedLocally = new VersionedTransaction(message)
|
|
370
|
+
signedLocally.sign([userKeypair])
|
|
371
|
+
const userSlotIndex = unsigned.message.staticAccountKeys.findIndex(k =>
|
|
372
|
+
k.equals(userKeypair.publicKey)
|
|
373
|
+
)
|
|
374
|
+
const userSignature = signedLocally.signatures[userSlotIndex]!
|
|
375
|
+
const wireSignature = base58.encode(userSignature)
|
|
376
|
+
|
|
377
|
+
const { client } = makeMockSignClient({ signature: wireSignature })
|
|
378
|
+
const service = new SolanaTransactionService()
|
|
379
|
+
|
|
380
|
+
const result = await service.signTransactionBytes(
|
|
381
|
+
client,
|
|
382
|
+
mockSession,
|
|
383
|
+
unsigned.serialize(),
|
|
384
|
+
SOL_CHAIN_ID,
|
|
385
|
+
userKeypair.publicKey.toBase58()
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
const out = VersionedTransaction.deserialize(result)
|
|
389
|
+
// Relay slot (0) still empty zeros; user slot (>=1) populated.
|
|
390
|
+
expect(Array.from(out.signatures[userSlotIndex]!)).toEqual(
|
|
391
|
+
Array.from(userSignature)
|
|
392
|
+
)
|
|
393
|
+
const relaySlot = out.message.staticAccountKeys.findIndex(k =>
|
|
394
|
+
k.equals(relayKeypair.publicKey)
|
|
395
|
+
)
|
|
396
|
+
expect(out.signatures[relaySlot]?.every(b => b === 0)).toBe(true)
|
|
397
|
+
// PublicKey.toBase58 should equal activeAddress to confirm we used it correctly.
|
|
398
|
+
expect(userKeypair.publicKey.toBase58()).toBe(
|
|
399
|
+
new PublicKey(userKeypair.publicKey.toBase58()).toBase58()
|
|
400
|
+
)
|
|
401
|
+
})
|
|
402
|
+
})
|
|
@@ -6,6 +6,10 @@ import type {
|
|
|
6
6
|
SolanaTokenTransferRequest,
|
|
7
7
|
SolanaTransactionRequest
|
|
8
8
|
} from '@meshconnect/uwc-types'
|
|
9
|
+
import {
|
|
10
|
+
assertSameMessage,
|
|
11
|
+
isVersionedTransactionBytes
|
|
12
|
+
} from '@meshconnect/uwc-types'
|
|
9
13
|
import {
|
|
10
14
|
VersionedTransaction,
|
|
11
15
|
PublicKey,
|
|
@@ -291,4 +295,73 @@ export class SolanaTransactionService {
|
|
|
291
295
|
throw signAndSendError
|
|
292
296
|
}
|
|
293
297
|
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Sign Solana tx bytes over WalletConnect WITHOUT broadcasting (relay submits).
|
|
301
|
+
* Bytes in/out (legacy or v0); only deserializes if the wallet returns a bare
|
|
302
|
+
* signature instead of the full tx.
|
|
303
|
+
*/
|
|
304
|
+
async signTransactionBytes(
|
|
305
|
+
client: SignClient,
|
|
306
|
+
session: SessionTypes.Struct,
|
|
307
|
+
serializedTx: Uint8Array,
|
|
308
|
+
chainId: string,
|
|
309
|
+
activeAddress: string
|
|
310
|
+
): Promise<Uint8Array> {
|
|
311
|
+
try {
|
|
312
|
+
// WalletConnect spec: the transaction param is base64.
|
|
313
|
+
const serializedBase64 = Buffer.from(serializedTx).toString('base64')
|
|
314
|
+
|
|
315
|
+
const result: { transaction: string } | { signature: string } =
|
|
316
|
+
await client.request({
|
|
317
|
+
topic: session.topic,
|
|
318
|
+
chainId,
|
|
319
|
+
request: {
|
|
320
|
+
method: 'solana_signTransaction',
|
|
321
|
+
params: { transaction: serializedBase64 }
|
|
322
|
+
}
|
|
323
|
+
})
|
|
324
|
+
|
|
325
|
+
// Full signed tx back (Phantom/Solflare) — verify only a signature was added.
|
|
326
|
+
if ('transaction' in result) {
|
|
327
|
+
const returned = new Uint8Array(
|
|
328
|
+
Buffer.from(result.transaction, 'base64')
|
|
329
|
+
)
|
|
330
|
+
assertSameMessage(serializedTx, returned)
|
|
331
|
+
return returned
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Bare signature back (legacy WC) — splice it into our original bytes.
|
|
335
|
+
if ('signature' in result) {
|
|
336
|
+
const signatureBytes = base58.decode(result.signature) as Uint8Array
|
|
337
|
+
// ed25519 sigs are 64 bytes; reject early with a clear error.
|
|
338
|
+
if (signatureBytes.length !== 64) {
|
|
339
|
+
throw new Error(
|
|
340
|
+
'WalletConnect returned a malformed Solana signature (expected 64 bytes)'
|
|
341
|
+
)
|
|
342
|
+
}
|
|
343
|
+
const userPubkey = new PublicKey(activeAddress)
|
|
344
|
+
|
|
345
|
+
if (isVersionedTransactionBytes(serializedTx)) {
|
|
346
|
+
const tx = VersionedTransaction.deserialize(serializedTx)
|
|
347
|
+
tx.addSignature(userPubkey, signatureBytes as Uint8Array & Buffer)
|
|
348
|
+
return tx.serialize()
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const tx = Transaction.from(serializedTx)
|
|
352
|
+
tx.addSignature(
|
|
353
|
+
userPubkey,
|
|
354
|
+
Buffer.from(signatureBytes) as Buffer & Uint8Array
|
|
355
|
+
)
|
|
356
|
+
// verifySignatures:false — the relay's fee-payer slot is still unsigned here.
|
|
357
|
+
return new Uint8Array(tx.serialize({ verifySignatures: false }))
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
throw new Error(
|
|
361
|
+
'WalletConnect returned an unexpected response shape for solana_signTransaction'
|
|
362
|
+
)
|
|
363
|
+
} catch (error) {
|
|
364
|
+
throw parseError(error)
|
|
365
|
+
}
|
|
366
|
+
}
|
|
294
367
|
}
|
|
@@ -72,4 +72,45 @@ export class TransactionService {
|
|
|
72
72
|
throw new Error(`Unsupported namespace: ${namespace}`)
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Sign-only path for Solana transactions over WalletConnect.
|
|
78
|
+
* Mirrors the validation done in sendTransaction but routes to the sign-only Solana flow
|
|
79
|
+
* instead of signAndSend. Used by fee-payer relay flows where the relay server broadcasts.
|
|
80
|
+
*/
|
|
81
|
+
async signSolanaTransactionBytes(
|
|
82
|
+
serializedTx: Uint8Array
|
|
83
|
+
): Promise<Uint8Array> {
|
|
84
|
+
const session = this.connectionService.getSession()
|
|
85
|
+
if (!session) {
|
|
86
|
+
throw new Error('No active session. Please connect first.')
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const activeNetwork = this.connectionService.getActiveNetwork()
|
|
90
|
+
const activeAddress = this.connectionService.getActiveAddress()
|
|
91
|
+
|
|
92
|
+
if (!activeNetwork) {
|
|
93
|
+
throw new Error('No active network. Please connect first.')
|
|
94
|
+
}
|
|
95
|
+
if (!activeAddress) {
|
|
96
|
+
throw new Error('No active address. Please connect first.')
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const namespace = activeNetwork.id.split(':')[0]
|
|
100
|
+
if (namespace !== 'solana') {
|
|
101
|
+
throw new Error(
|
|
102
|
+
`signSolanaTransactionBytes requires a Solana network (got namespace "${namespace}")`
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const client = await this.walletConnectClient.getClient()
|
|
107
|
+
|
|
108
|
+
return this.solanaService.signTransactionBytes(
|
|
109
|
+
client,
|
|
110
|
+
session,
|
|
111
|
+
serializedTx,
|
|
112
|
+
activeNetwork.id,
|
|
113
|
+
activeAddress
|
|
114
|
+
)
|
|
115
|
+
}
|
|
75
116
|
}
|
|
@@ -81,4 +81,17 @@ export class WalletConnectConnector implements Connector {
|
|
|
81
81
|
): Promise<TransactionResult> {
|
|
82
82
|
return this.transactionService.sendTransaction(request)
|
|
83
83
|
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Sign a Solana transaction over WalletConnect without broadcasting.
|
|
87
|
+
* Mirrors InjectedConnector.signSolanaTransactionBytes so the core router can branch on
|
|
88
|
+
* connection mode without the call sites caring which connector backs the active wallet.
|
|
89
|
+
*
|
|
90
|
+
* Used by fee-payer relay flows (Mesh BE owns broadcast); never broadcasts via the wallet.
|
|
91
|
+
*/
|
|
92
|
+
async signSolanaTransactionBytes(
|
|
93
|
+
serializedTx: Uint8Array
|
|
94
|
+
): Promise<Uint8Array> {
|
|
95
|
+
return this.transactionService.signSolanaTransactionBytes(serializedTx)
|
|
96
|
+
}
|
|
84
97
|
}
|