@meshconnect/uwc-injected-connector 0.2.7 → 0.2.9
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.js +2 -2
- package/dist/injected-connector.js.map +1 -1
- package/dist/services/ethereum-transaction-service.d.ts.map +1 -1
- package/dist/services/ethereum-transaction-service.js +11 -20
- package/dist/services/ethereum-transaction-service.js.map +1 -1
- package/dist/services/signature-service.d.ts +2 -2
- package/dist/services/signature-service.d.ts.map +1 -1
- package/dist/services/signature-service.js +3 -10
- package/dist/services/signature-service.js.map +1 -1
- package/dist/services/solana/solana-transaction-service.d.ts +14 -2
- package/dist/services/solana/solana-transaction-service.d.ts.map +1 -1
- package/dist/services/solana/solana-transaction-service.js +87 -47
- package/dist/services/solana/solana-transaction-service.js.map +1 -1
- package/dist/services/solana/solana-wallet-service.d.ts +6 -7
- package/dist/services/solana/solana-wallet-service.d.ts.map +1 -1
- package/dist/services/solana/solana-wallet-service.js +13 -15
- package/dist/services/solana/solana-wallet-service.js.map +1 -1
- package/dist/services/transaction-service.d.ts +2 -2
- package/dist/services/transaction-service.d.ts.map +1 -1
- package/dist/services/transaction-service.js.map +1 -1
- package/dist/wallet-standard-discovery.d.ts +11 -9
- package/dist/wallet-standard-discovery.d.ts.map +1 -1
- package/dist/wallet-standard-discovery.js +47 -23
- package/dist/wallet-standard-discovery.js.map +1 -1
- package/package.json +2 -2
- package/src/injected-connector.ts +2 -2
- package/src/services/signature-service.ts +5 -17
- package/src/services/solana/solana-transaction-service.ts +121 -60
- package/src/services/solana/solana-wallet-service.ts +21 -23
- package/src/services/transaction-service.ts +3 -3
- package/src/wallet-standard-discovery.ts +77 -32
|
@@ -3,22 +3,24 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Simple implementation to get Solana wallets using the Wallet Standard API
|
|
5
5
|
*/
|
|
6
|
-
import
|
|
7
|
-
import type {
|
|
6
|
+
import { StandardWalletAdapter } from '@solana/wallet-standard-wallet-adapter-base';
|
|
7
|
+
import type { Transaction } from '@solana/web3.js';
|
|
8
|
+
export interface ExtendedStandardWalletAdapter extends StandardWalletAdapter {
|
|
9
|
+
customFunctions: ('sendSerializedTransaction' | 'signSerializedTransaction' | 'signAllSerializedTransactions')[];
|
|
10
|
+
sendSerializedTransaction: (transaction: unknown, rpcUrl: string) => Promise<string>;
|
|
11
|
+
signSerializedTransaction: (transaction: unknown) => Promise<Error | Transaction>;
|
|
12
|
+
signAllSerializedTransactions: (transactions: unknown[]) => Promise<Error | Transaction[]>;
|
|
13
|
+
}
|
|
14
|
+
export type SolanaAdapter = ExtendedStandardWalletAdapter | StandardWalletAdapter;
|
|
8
15
|
export interface WalletStandardInfo {
|
|
9
16
|
uuid: string;
|
|
10
17
|
name: string;
|
|
11
18
|
chains: string[];
|
|
12
19
|
features: string[];
|
|
13
|
-
adapter:
|
|
14
|
-
}
|
|
15
|
-
export interface SolanaWalletWithAdapter {
|
|
16
|
-
info: WalletStandardInfo;
|
|
17
|
-
wallet: Wallet;
|
|
18
|
-
adapter?: WalletAdapter;
|
|
20
|
+
adapter: SolanaAdapter | undefined;
|
|
19
21
|
}
|
|
20
22
|
/**
|
|
21
23
|
* Gets all available Solana wallets using Wallet Standard
|
|
22
24
|
*/
|
|
23
|
-
export declare function getSolanaWallets(): WalletStandardInfo[]
|
|
25
|
+
export declare function getSolanaWallets(): Promise<WalletStandardInfo[]>;
|
|
24
26
|
//# sourceMappingURL=wallet-standard-discovery.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wallet-standard-discovery.d.ts","sourceRoot":"","sources":["../src/wallet-standard-discovery.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
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,CAClC,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;CACpC;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"}
|
|
@@ -6,11 +6,56 @@
|
|
|
6
6
|
import { getWallets } from '@wallet-standard/app';
|
|
7
7
|
import { isWalletAdapterCompatibleStandardWallet } from '@solana/wallet-adapter-base';
|
|
8
8
|
import { StandardWalletAdapter } from '@solana/wallet-standard-wallet-adapter-base';
|
|
9
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Polls for bridge wallets when UWCBridgeInitialized is true
|
|
11
|
+
* @returns Promise that resolves to an array of detected wallets from the bridge
|
|
12
|
+
*/
|
|
13
|
+
async function pollForBridgeWallets() {
|
|
14
|
+
const pollInterval = 100; // Poll every 100ms
|
|
15
|
+
const maxPollTime = 3000; // Poll for maximum 3 seconds
|
|
16
|
+
const startTime = Date.now();
|
|
17
|
+
return new Promise(resolve => {
|
|
18
|
+
const poll = () => {
|
|
19
|
+
// Check if we've exceeded the max poll time
|
|
20
|
+
if (Date.now() - startTime > maxPollTime) {
|
|
21
|
+
resolve([]);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
// Check if window.walletStandardWallets is available
|
|
25
|
+
if (
|
|
26
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
27
|
+
// @ts-ignore - window.eip6963Wallets is set by the bridge
|
|
28
|
+
window.walletStandardWallets &&
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
30
|
+
// @ts-ignore - window.eip6963Wallets is set by the bridge
|
|
31
|
+
Array.isArray(window.walletStandardWallets)) {
|
|
32
|
+
const bridgeWallets =
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
34
|
+
// @ts-ignore
|
|
35
|
+
window.walletStandardWallets;
|
|
36
|
+
resolve(bridgeWallets);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
// Continue polling
|
|
40
|
+
setTimeout(poll, pollInterval);
|
|
41
|
+
};
|
|
42
|
+
// Start polling
|
|
43
|
+
poll();
|
|
44
|
+
});
|
|
45
|
+
}
|
|
10
46
|
/**
|
|
11
47
|
* Gets all available Solana wallets using Wallet Standard
|
|
12
48
|
*/
|
|
13
|
-
export function getSolanaWallets() {
|
|
49
|
+
export async function getSolanaWallets() {
|
|
50
|
+
// UWCBridgeChildInitialized is only initialized if app runs in an iframe. We can skip checking for bridge proxy providers when it's not necessary.
|
|
51
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
52
|
+
// @ts-ignore - window.UWCBridgeInitialized is set by the bridge
|
|
53
|
+
if (window.UWCBridgeChildInitialized === true) {
|
|
54
|
+
const wallets = await pollForBridgeWallets();
|
|
55
|
+
if (wallets.length > 0) {
|
|
56
|
+
return wallets;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
14
59
|
const { get } = getWallets();
|
|
15
60
|
const wallets = get();
|
|
16
61
|
const solanaWallets = [];
|
|
@@ -33,27 +78,6 @@ export function getSolanaWallets() {
|
|
|
33
78
|
walletNames.add(wallet.name);
|
|
34
79
|
}
|
|
35
80
|
}
|
|
36
|
-
// Initialize traditional wallet adapters - Only import CBW for now, as it's not using Wallet Standard
|
|
37
|
-
const walletAdapters = [new CoinbaseWalletAdapter()];
|
|
38
|
-
// Add traditional wallet adapters (but skip duplicates)
|
|
39
|
-
for (const adapter of walletAdapters) {
|
|
40
|
-
if (walletNames.has(adapter.name)) {
|
|
41
|
-
// Skipping duplicate wallet already detected via Wallet Standard
|
|
42
|
-
continue;
|
|
43
|
-
}
|
|
44
|
-
const readyState = adapter.readyState;
|
|
45
|
-
const isDetected = readyState === 'Installed' || readyState === 'Loadable';
|
|
46
|
-
// Only add if installed
|
|
47
|
-
if (isDetected) {
|
|
48
|
-
solanaWallets.push({
|
|
49
|
-
uuid: `${adapter.name}-traditional`.toLowerCase().replace(/\s+/g, '-'),
|
|
50
|
-
name: adapter.name,
|
|
51
|
-
chains: ['solana:mainnet'],
|
|
52
|
-
features: [],
|
|
53
|
-
adapter: adapter
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
81
|
return solanaWallets;
|
|
58
82
|
}
|
|
59
83
|
/**
|
|
@@ -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;
|
|
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.2.
|
|
3
|
+
"version": "0.2.9",
|
|
4
4
|
"description": "Injected connector for Universal Wallet Connector",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"bs58": "^6.0.0",
|
|
27
27
|
"buffer": "^6.0.3",
|
|
28
28
|
"ethers": "^6.15.0",
|
|
29
|
-
"@meshconnect/uwc-types": "0.2.
|
|
29
|
+
"@meshconnect/uwc-types": "0.2.6"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"typescript": "^5.9.2"
|
|
@@ -55,7 +55,7 @@ export class InjectedConnector implements Connector {
|
|
|
55
55
|
*/
|
|
56
56
|
private async initializeWalletDiscovery(): Promise<void> {
|
|
57
57
|
await this.ethereumService.initializeDiscovery()
|
|
58
|
-
this.solanaService.initializeDiscovery()
|
|
58
|
+
await this.solanaService.initializeDiscovery()
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
/**
|
|
@@ -84,7 +84,7 @@ export class InjectedConnector implements Connector {
|
|
|
84
84
|
|
|
85
85
|
case 'solana': {
|
|
86
86
|
// Re-fetch Solana wallets
|
|
87
|
-
this.solanaService.initializeDiscovery()
|
|
87
|
+
await this.solanaService.initializeDiscovery()
|
|
88
88
|
|
|
89
89
|
// Convert to DetectedWalletInfo format
|
|
90
90
|
return this.solanaService.getDetectedWallets().map(wallet => ({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { EthereumProvider } from '../eip6963-discovery'
|
|
2
|
-
import type { WalletAdapter } from '@solana/wallet-adapter-base'
|
|
3
2
|
import bs58 from 'bs58'
|
|
4
3
|
import { parseError } from '../utils/error-utils'
|
|
4
|
+
import type { SolanaAdapter } from '../wallet-standard-discovery'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Service for handling message signing operations for injected wallets
|
|
@@ -45,32 +45,20 @@ export class SignatureService {
|
|
|
45
45
|
*/
|
|
46
46
|
async signSolanaMessage(
|
|
47
47
|
message: string,
|
|
48
|
-
adapter:
|
|
48
|
+
adapter: SolanaAdapter
|
|
49
49
|
): Promise<string> {
|
|
50
|
-
if (!adapter) {
|
|
51
|
-
throw new Error('Adapter is required for Solana message signing')
|
|
52
|
-
}
|
|
53
|
-
|
|
54
50
|
if (!message) {
|
|
55
51
|
throw new Error('Message is required for signing')
|
|
56
52
|
}
|
|
57
53
|
|
|
58
|
-
// Check if adapter supports signMessage
|
|
59
|
-
const signingAdapter = adapter as WalletAdapter & {
|
|
60
|
-
signMessage?: (message: Uint8Array) => Promise<Uint8Array>
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (!signingAdapter.signMessage) {
|
|
64
|
-
throw new Error('Solana adapter does not support message signing')
|
|
65
|
-
}
|
|
66
|
-
|
|
67
54
|
try {
|
|
68
55
|
// Convert message to Uint8Array for Solana
|
|
69
56
|
const encoder = new TextEncoder()
|
|
70
57
|
const messageBytes = encoder.encode(message)
|
|
71
58
|
|
|
72
|
-
//
|
|
73
|
-
|
|
59
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
60
|
+
// @ts-ignore
|
|
61
|
+
const signedMessage = await adapter.signMessage(messageBytes)
|
|
74
62
|
|
|
75
63
|
// Encode signature using base58 for Solana (standard encoding for Solana)
|
|
76
64
|
// The signature is returned as a Uint8Array, encode it to base58 string
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { Transaction, Connection } from '@solana/web3.js'
|
|
2
|
-
import type { WalletAdapter } from '@solana/wallet-adapter-base'
|
|
1
|
+
import { Transaction, Connection, PublicKey } from '@solana/web3.js'
|
|
3
2
|
import type {
|
|
4
3
|
SolanaNativeTransferRequest,
|
|
5
4
|
NetworkRpcMap,
|
|
@@ -10,6 +9,10 @@ import type {
|
|
|
10
9
|
} from '@meshconnect/uwc-types'
|
|
11
10
|
import { parseError } from '../../utils/error-utils'
|
|
12
11
|
import { SolanaTransactionBuilder } from './solana-transaction-builder'
|
|
12
|
+
import type {
|
|
13
|
+
ExtendedStandardWalletAdapter,
|
|
14
|
+
SolanaAdapter
|
|
15
|
+
} from '../../wallet-standard-discovery'
|
|
13
16
|
|
|
14
17
|
/**
|
|
15
18
|
* Service for handling Solana transaction operations
|
|
@@ -28,7 +31,7 @@ export class SolanaTransactionService {
|
|
|
28
31
|
*/
|
|
29
32
|
async sendTransaction(
|
|
30
33
|
request: SolanaTransactionRequest,
|
|
31
|
-
adapter:
|
|
34
|
+
adapter: SolanaAdapter
|
|
32
35
|
): Promise<string> {
|
|
33
36
|
try {
|
|
34
37
|
// Handle different types of Solana transactions
|
|
@@ -55,23 +58,82 @@ export class SolanaTransactionService {
|
|
|
55
58
|
}
|
|
56
59
|
}
|
|
57
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Helper: Validate wallet address matches
|
|
63
|
+
*/
|
|
64
|
+
private async validateWalletMatch(
|
|
65
|
+
adapter: SolanaAdapter,
|
|
66
|
+
expectedAddress: string
|
|
67
|
+
): Promise<string> {
|
|
68
|
+
const base58PublicKey = await adapter.publicKey?.toBase58()
|
|
69
|
+
if (base58PublicKey !== expectedAddress) {
|
|
70
|
+
throw new Error('From address does not match connected wallet')
|
|
71
|
+
}
|
|
72
|
+
return base58PublicKey
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Helper: Get RPC URL with fallback
|
|
77
|
+
*/
|
|
78
|
+
private getRpcUrl(networkId?: NetworkId): string {
|
|
79
|
+
return networkId && this.networkRpcMap[networkId]
|
|
80
|
+
? this.networkRpcMap[networkId]
|
|
81
|
+
: 'https://api.mainnet-beta.solana.com'
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Helper: Execute transaction with sendSerializedTransaction fallback
|
|
86
|
+
*/
|
|
87
|
+
private async executeTransaction(
|
|
88
|
+
adapter: SolanaAdapter,
|
|
89
|
+
transaction: Transaction,
|
|
90
|
+
rpcUrl: string
|
|
91
|
+
): Promise<string> {
|
|
92
|
+
let transactionSignature: string | undefined
|
|
93
|
+
|
|
94
|
+
// Try to use sendSerializedTransaction if available
|
|
95
|
+
try {
|
|
96
|
+
const extendedAdapter = adapter as ExtendedStandardWalletAdapter
|
|
97
|
+
const serializedTx = transaction.serialize({
|
|
98
|
+
requireAllSignatures: false,
|
|
99
|
+
verifySignatures: false
|
|
100
|
+
})
|
|
101
|
+
if (extendedAdapter.sendSerializedTransaction) {
|
|
102
|
+
transactionSignature = await extendedAdapter.sendSerializedTransaction(
|
|
103
|
+
serializedTx,
|
|
104
|
+
rpcUrl
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
} catch {
|
|
108
|
+
// Fallback to regular sendTransaction
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// If sendSerializedTransaction didn't work or wasn't available
|
|
112
|
+
if (!transactionSignature) {
|
|
113
|
+
const connection = new Connection(rpcUrl)
|
|
114
|
+
transactionSignature = await adapter.sendTransaction(
|
|
115
|
+
transaction,
|
|
116
|
+
connection
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (transactionSignature === undefined) {
|
|
121
|
+
throw new Error(`Couldn't get the transaction signature`)
|
|
122
|
+
}
|
|
123
|
+
return transactionSignature
|
|
124
|
+
}
|
|
125
|
+
|
|
58
126
|
/**
|
|
59
127
|
* Send native SOL transfer
|
|
60
128
|
*/
|
|
61
129
|
private async sendNativeTransaction(
|
|
62
|
-
adapter:
|
|
130
|
+
adapter: SolanaAdapter,
|
|
63
131
|
request: SolanaNativeTransferRequest,
|
|
64
132
|
networkId?: NetworkId
|
|
65
133
|
): Promise<string> {
|
|
66
134
|
try {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Verify the from address matches connected wallet
|
|
72
|
-
if (adapter.publicKey.toBase58() !== request.from) {
|
|
73
|
-
throw new Error('From address does not match connected wallet')
|
|
74
|
-
}
|
|
135
|
+
// Validate wallet
|
|
136
|
+
await this.validateWalletMatch(adapter, request.from)
|
|
75
137
|
|
|
76
138
|
// Blockhash is required
|
|
77
139
|
if (!request.blockhash) {
|
|
@@ -84,17 +146,11 @@ export class SolanaTransactionService {
|
|
|
84
146
|
await this.builder.buildTransferInstructions(request)
|
|
85
147
|
|
|
86
148
|
transaction.recentBlockhash = request.blockhash
|
|
87
|
-
transaction.feePayer =
|
|
149
|
+
transaction.feePayer = new PublicKey(request.from)
|
|
88
150
|
|
|
89
|
-
//
|
|
90
|
-
const rpcUrl =
|
|
91
|
-
|
|
92
|
-
? this.networkRpcMap[networkId]
|
|
93
|
-
: 'https://api.mainnet-beta.solana.com'
|
|
94
|
-
const connection = new Connection(rpcUrl)
|
|
95
|
-
|
|
96
|
-
const signature = await adapter.sendTransaction(transaction, connection)
|
|
97
|
-
return signature
|
|
151
|
+
// Execute with helpers
|
|
152
|
+
const rpcUrl = this.getRpcUrl(networkId)
|
|
153
|
+
return await this.executeTransaction(adapter, transaction, rpcUrl)
|
|
98
154
|
} catch (error) {
|
|
99
155
|
parseError(error)
|
|
100
156
|
}
|
|
@@ -104,19 +160,13 @@ export class SolanaTransactionService {
|
|
|
104
160
|
* Send SPL token transfer
|
|
105
161
|
*/
|
|
106
162
|
private async sendSplTokenTransaction(
|
|
107
|
-
adapter:
|
|
163
|
+
adapter: SolanaAdapter,
|
|
108
164
|
request: SolanaTokenTransferRequest,
|
|
109
165
|
networkId?: NetworkId
|
|
110
166
|
): Promise<string> {
|
|
111
167
|
try {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Verify the from address matches connected wallet
|
|
117
|
-
if (adapter.publicKey.toBase58() !== request.from) {
|
|
118
|
-
throw new Error('From address does not match connected wallet')
|
|
119
|
-
}
|
|
168
|
+
// Validate wallet
|
|
169
|
+
await this.validateWalletMatch(adapter, request.from)
|
|
120
170
|
|
|
121
171
|
// Blockhash is required
|
|
122
172
|
if (!request.blockhash) {
|
|
@@ -129,17 +179,11 @@ export class SolanaTransactionService {
|
|
|
129
179
|
await this.builder.buildTransferInstructions(request)
|
|
130
180
|
|
|
131
181
|
transaction.recentBlockhash = request.blockhash
|
|
132
|
-
transaction.feePayer =
|
|
182
|
+
transaction.feePayer = new PublicKey(request.from)
|
|
133
183
|
|
|
134
|
-
//
|
|
135
|
-
const rpcUrl =
|
|
136
|
-
|
|
137
|
-
? this.networkRpcMap[networkId]
|
|
138
|
-
: 'https://api.mainnet-beta.solana.com'
|
|
139
|
-
const connection = new Connection(rpcUrl)
|
|
140
|
-
|
|
141
|
-
const signature = await adapter.sendTransaction(transaction, connection)
|
|
142
|
-
return signature
|
|
184
|
+
// Execute with helpers
|
|
185
|
+
const rpcUrl = this.getRpcUrl(networkId)
|
|
186
|
+
return await this.executeTransaction(adapter, transaction, rpcUrl)
|
|
143
187
|
} catch (error) {
|
|
144
188
|
parseError(error)
|
|
145
189
|
}
|
|
@@ -149,40 +193,57 @@ export class SolanaTransactionService {
|
|
|
149
193
|
* Send native SOL transfer
|
|
150
194
|
*/
|
|
151
195
|
private async sendGenericTransferWithInstructions(
|
|
152
|
-
adapter:
|
|
196
|
+
adapter: SolanaAdapter,
|
|
153
197
|
request: SolanaGenericTransferRequest,
|
|
154
198
|
networkId?: NetworkId
|
|
155
199
|
): Promise<string> {
|
|
156
200
|
try {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Verify the from address matches connected wallet
|
|
162
|
-
if (adapter.publicKey.toBase58() !== request.feePayer) {
|
|
163
|
-
throw new Error('From address does not match connected wallet')
|
|
164
|
-
}
|
|
201
|
+
// Validate wallet
|
|
202
|
+
await this.validateWalletMatch(adapter, request.feePayer)
|
|
165
203
|
|
|
166
204
|
// Blockhash is required
|
|
167
205
|
if (!request.blockhash) {
|
|
168
206
|
throw new Error('Blockhash is required for Solana transactions')
|
|
169
207
|
}
|
|
170
208
|
|
|
171
|
-
// Create transaction
|
|
209
|
+
// Create versioned transaction
|
|
172
210
|
const transaction = await this.builder.getVersionedTransaction(
|
|
173
|
-
|
|
211
|
+
new PublicKey(request.feePayer),
|
|
174
212
|
request
|
|
175
213
|
)
|
|
176
214
|
|
|
177
|
-
// Get RPC URL
|
|
178
|
-
const rpcUrl =
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
215
|
+
// Get RPC URL
|
|
216
|
+
const rpcUrl = this.getRpcUrl(networkId)
|
|
217
|
+
|
|
218
|
+
// VersionedTransaction can't use our helper method, handle directly
|
|
219
|
+
let transactionSignature: string | undefined
|
|
220
|
+
|
|
221
|
+
try {
|
|
222
|
+
const extendedAdapter = adapter as ExtendedStandardWalletAdapter
|
|
223
|
+
const serializedTx = transaction.serialize()
|
|
224
|
+
if (extendedAdapter.sendSerializedTransaction) {
|
|
225
|
+
transactionSignature =
|
|
226
|
+
await extendedAdapter.sendSerializedTransaction(
|
|
227
|
+
serializedTx,
|
|
228
|
+
rpcUrl
|
|
229
|
+
)
|
|
230
|
+
}
|
|
231
|
+
} catch {
|
|
232
|
+
// Fallback to regular sendTransaction
|
|
233
|
+
}
|
|
183
234
|
|
|
184
|
-
|
|
185
|
-
|
|
235
|
+
if (!transactionSignature) {
|
|
236
|
+
const connection = new Connection(rpcUrl)
|
|
237
|
+
transactionSignature = await adapter.sendTransaction(
|
|
238
|
+
transaction,
|
|
239
|
+
connection
|
|
240
|
+
)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (transactionSignature === undefined) {
|
|
244
|
+
throw new Error(`Couldn't get the transaction signature`)
|
|
245
|
+
}
|
|
246
|
+
return transactionSignature
|
|
186
247
|
} catch (error) {
|
|
187
248
|
parseError(error)
|
|
188
249
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { NetworkId, AvailableAddress } from '@meshconnect/uwc-types'
|
|
2
|
-
import type { WalletAdapter } from '@solana/wallet-adapter-base'
|
|
3
2
|
import {
|
|
4
3
|
getSolanaWallets,
|
|
4
|
+
type SolanaAdapter,
|
|
5
5
|
type WalletStandardInfo
|
|
6
6
|
} from '../../wallet-standard-discovery'
|
|
7
7
|
import { StorageService } from '../storage-service'
|
|
@@ -11,7 +11,7 @@ import { StorageService } from '../storage-service'
|
|
|
11
11
|
*/
|
|
12
12
|
export class SolanaWalletService {
|
|
13
13
|
private detectedWallets: WalletStandardInfo[] = []
|
|
14
|
-
private connectedAdapter:
|
|
14
|
+
private connectedAdapter: SolanaAdapter | null = null
|
|
15
15
|
private account: string | null = null
|
|
16
16
|
private storageService: StorageService
|
|
17
17
|
|
|
@@ -22,8 +22,8 @@ export class SolanaWalletService {
|
|
|
22
22
|
/**
|
|
23
23
|
* Initialize wallet discovery
|
|
24
24
|
*/
|
|
25
|
-
initializeDiscovery(): void {
|
|
26
|
-
this.detectedWallets = getSolanaWallets()
|
|
25
|
+
async initializeDiscovery(): Promise<void> {
|
|
26
|
+
this.detectedWallets = await getSolanaWallets()
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/**
|
|
@@ -44,30 +44,27 @@ export class SolanaWalletService {
|
|
|
44
44
|
* Check if a Solana wallet is already connected
|
|
45
45
|
*/
|
|
46
46
|
async checkExistingConnection(
|
|
47
|
-
adapter:
|
|
47
|
+
adapter: SolanaAdapter,
|
|
48
48
|
walletUuid: string
|
|
49
49
|
): Promise<string | null> {
|
|
50
50
|
try {
|
|
51
|
+
const base58PublicKey = await adapter.publicKey?.toBase58()
|
|
51
52
|
// Check if adapter has a publicKey (means it's connected)
|
|
52
|
-
if (
|
|
53
|
-
return
|
|
53
|
+
if (base58PublicKey) {
|
|
54
|
+
return base58PublicKey
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
// If this wallet was previously connected, try to reconnect
|
|
57
58
|
// This should work without prompting for wallets that support it
|
|
58
59
|
if (this.storageService.wasSolanaWalletPreviouslyConnected(walletUuid)) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
!adapter.connecting &&
|
|
62
|
-
'connect' in adapter
|
|
63
|
-
) {
|
|
60
|
+
const walletIsConnecting = await adapter.connecting
|
|
61
|
+
if (!walletIsConnecting) {
|
|
64
62
|
try {
|
|
65
|
-
// Type assertion needed because TypeScript can't narrow the type properly
|
|
66
63
|
await adapter.connect()
|
|
67
|
-
|
|
68
|
-
const
|
|
69
|
-
if (
|
|
70
|
-
return
|
|
64
|
+
|
|
65
|
+
const base58PublicKey = await adapter.publicKey?.toBase58()
|
|
66
|
+
if (base58PublicKey) {
|
|
67
|
+
return base58PublicKey
|
|
71
68
|
}
|
|
72
69
|
} catch {
|
|
73
70
|
// Silent fail - wallet requires user interaction or doesn't support silent reconnect
|
|
@@ -83,15 +80,16 @@ export class SolanaWalletService {
|
|
|
83
80
|
/**
|
|
84
81
|
* Connect to wallet
|
|
85
82
|
*/
|
|
86
|
-
async connect(adapter:
|
|
83
|
+
async connect(adapter: SolanaAdapter, walletUuid: string): Promise<string> {
|
|
87
84
|
// Connect to the Solana wallet
|
|
88
85
|
await adapter.connect()
|
|
89
86
|
|
|
90
|
-
|
|
91
|
-
|
|
87
|
+
const address = await adapter.publicKey?.toBase58()
|
|
88
|
+
|
|
89
|
+
if (!address) {
|
|
90
|
+
throw new Error('No address returned from wallet')
|
|
92
91
|
}
|
|
93
92
|
|
|
94
|
-
const address = adapter.publicKey.toBase58()
|
|
95
93
|
this.connectedAdapter = adapter
|
|
96
94
|
this.account = address
|
|
97
95
|
|
|
@@ -124,7 +122,7 @@ export class SolanaWalletService {
|
|
|
124
122
|
* Set connection state
|
|
125
123
|
*/
|
|
126
124
|
setConnectionState(
|
|
127
|
-
adapter:
|
|
125
|
+
adapter: SolanaAdapter | null,
|
|
128
126
|
account: string | null,
|
|
129
127
|
walletUuid?: string
|
|
130
128
|
): void {
|
|
@@ -147,7 +145,7 @@ export class SolanaWalletService {
|
|
|
147
145
|
/**
|
|
148
146
|
* Get connected adapter
|
|
149
147
|
*/
|
|
150
|
-
getConnectedAdapter():
|
|
148
|
+
getConnectedAdapter(): SolanaAdapter | null {
|
|
151
149
|
return this.connectedAdapter
|
|
152
150
|
}
|
|
153
151
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { EthereumProvider } from '../eip6963-discovery'
|
|
2
|
-
import type { WalletAdapter } from '@solana/wallet-adapter-base'
|
|
3
2
|
import type {
|
|
4
3
|
TransactionRequest,
|
|
5
4
|
TransactionResult,
|
|
@@ -10,6 +9,7 @@ import type {
|
|
|
10
9
|
import { EthereumTransactionService } from './ethereum/ethereum-transaction-service'
|
|
11
10
|
import { SolanaTransactionService } from './solana/solana-transaction-service'
|
|
12
11
|
import { parseError } from '../utils/error-utils'
|
|
12
|
+
import type { SolanaAdapter } from '../wallet-standard-discovery'
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Service for handling transaction operations across different wallet types
|
|
@@ -29,7 +29,7 @@ export class TransactionService {
|
|
|
29
29
|
async sendTransaction(
|
|
30
30
|
request: TransactionRequest,
|
|
31
31
|
namespace: 'eip155' | 'solana',
|
|
32
|
-
provider: EthereumProvider |
|
|
32
|
+
provider: EthereumProvider | SolanaAdapter
|
|
33
33
|
): Promise<TransactionResult> {
|
|
34
34
|
if (namespace === 'eip155') {
|
|
35
35
|
return await this.ethereumService.sendTransaction(
|
|
@@ -39,7 +39,7 @@ export class TransactionService {
|
|
|
39
39
|
} else if (namespace === 'solana') {
|
|
40
40
|
return await this.solanaService.sendTransaction(
|
|
41
41
|
request as SolanaTransactionRequest,
|
|
42
|
-
provider as
|
|
42
|
+
provider as SolanaAdapter
|
|
43
43
|
)
|
|
44
44
|
} else {
|
|
45
45
|
throw parseError(new Error(`Unsupported namespace: ${namespace}`))
|