@meshconnect/uwc-wallet-connect-connector 0.2.0 → 0.2.2
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/connection-service.d.ts.map +1 -1
- package/dist/services/connection-service.js +0 -2
- package/dist/services/connection-service.js.map +1 -1
- package/dist/services/ethereum/ethereum-transaction-builder.d.ts +14 -0
- package/dist/services/ethereum/ethereum-transaction-builder.d.ts.map +1 -0
- package/dist/services/ethereum/ethereum-transaction-builder.js +60 -0
- package/dist/services/ethereum/ethereum-transaction-builder.js.map +1 -0
- package/dist/services/ethereum/ethereum-transaction-service.d.ts +21 -0
- package/dist/services/ethereum/ethereum-transaction-service.d.ts.map +1 -0
- package/dist/services/ethereum/ethereum-transaction-service.js +107 -0
- package/dist/services/ethereum/ethereum-transaction-service.js.map +1 -0
- package/dist/services/solana/solana-transaction-builder.d.ts +20 -0
- package/dist/services/solana/solana-transaction-builder.d.ts.map +1 -0
- package/dist/services/solana/solana-transaction-builder.js +112 -0
- package/dist/services/solana/solana-transaction-builder.js.map +1 -0
- package/dist/services/solana/solana-transaction-service.d.ts +17 -0
- package/dist/services/solana/solana-transaction-service.d.ts.map +1 -0
- package/dist/services/solana/solana-transaction-service.js +178 -0
- package/dist/services/solana/solana-transaction-service.js.map +1 -0
- package/dist/services/transaction-service.d.ts +2 -17
- package/dist/services/transaction-service.d.ts.map +1 -1
- package/dist/services/transaction-service.js +8 -246
- package/dist/services/transaction-service.js.map +1 -1
- package/package.json +3 -2
- package/src/services/connection-service.ts +0 -3
- package/src/services/ethereum/ethereum-transaction-builder.ts +82 -0
- package/src/services/ethereum/ethereum-transaction-service.ts +152 -0
- package/src/services/solana/solana-transaction-builder.ts +214 -0
- package/src/services/solana/solana-transaction-service.ts +294 -0
- package/src/services/transaction-service.ts +17 -339
- package/src/utils/account-utils.ts +1 -1
- package/src/utils/solana-transactions.ts +0 -24
|
@@ -1,39 +1,30 @@
|
|
|
1
|
-
import { ethers } from 'ethers'
|
|
2
|
-
import { Buffer } from 'buffer'
|
|
3
|
-
import {
|
|
4
|
-
Connection,
|
|
5
|
-
PublicKey,
|
|
6
|
-
Transaction,
|
|
7
|
-
VersionedTransaction
|
|
8
|
-
} from '@solana/web3.js'
|
|
9
1
|
import type {
|
|
10
2
|
TransactionRequest,
|
|
11
3
|
TransactionResult,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
SolanaNativeTransferRequest,
|
|
15
|
-
NetworkId,
|
|
4
|
+
EthereumTransactionRequest,
|
|
5
|
+
SolanaTransactionRequest,
|
|
16
6
|
NetworkRpcMap
|
|
17
7
|
} from '@meshconnect/uwc-types'
|
|
18
|
-
import type SignClient from '@walletconnect/sign-client'
|
|
19
8
|
import { WalletConnectClient } from './walletconnect-client'
|
|
20
9
|
import { ConnectionService } from './connection-service'
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import { getSolanaTransaction } from '../utils/solana-transactions'
|
|
24
|
-
import type { SessionTypes } from '@walletconnect/types'
|
|
25
|
-
import base58 from 'bs58'
|
|
26
|
-
import { standardizeSignature } from '../utils/encoding-utils'
|
|
10
|
+
import { EthereumTransactionService } from './ethereum/ethereum-transaction-service'
|
|
11
|
+
import { SolanaTransactionService } from './solana/solana-transaction-service'
|
|
27
12
|
|
|
28
13
|
/**
|
|
29
14
|
* Service for handling transactions in WalletConnect
|
|
30
15
|
*/
|
|
31
16
|
export class TransactionService {
|
|
17
|
+
private ethereumService: EthereumTransactionService
|
|
18
|
+
private solanaService: SolanaTransactionService
|
|
19
|
+
|
|
32
20
|
constructor(
|
|
33
21
|
private walletConnectClient: WalletConnectClient,
|
|
34
22
|
private connectionService: ConnectionService,
|
|
35
|
-
|
|
36
|
-
) {
|
|
23
|
+
networkRpcMap: NetworkRpcMap = {}
|
|
24
|
+
) {
|
|
25
|
+
this.ethereumService = new EthereumTransactionService()
|
|
26
|
+
this.solanaService = new SolanaTransactionService(networkRpcMap)
|
|
27
|
+
}
|
|
37
28
|
|
|
38
29
|
/**
|
|
39
30
|
* Send a transaction with the connected wallet
|
|
@@ -63,18 +54,17 @@ export class TransactionService {
|
|
|
63
54
|
const namespace = activeNetwork.id.split(':')[0]
|
|
64
55
|
|
|
65
56
|
if (namespace === 'eip155') {
|
|
66
|
-
return this.
|
|
57
|
+
return this.ethereumService.sendTransaction(
|
|
67
58
|
client,
|
|
68
59
|
session,
|
|
69
|
-
request,
|
|
70
|
-
activeNetwork.id
|
|
71
|
-
activeAddress
|
|
60
|
+
request as EthereumTransactionRequest,
|
|
61
|
+
activeNetwork.id
|
|
72
62
|
)
|
|
73
63
|
} else if (namespace === 'solana') {
|
|
74
|
-
return this.
|
|
64
|
+
return this.solanaService.sendTransaction(
|
|
75
65
|
client,
|
|
76
66
|
session,
|
|
77
|
-
request as
|
|
67
|
+
request as SolanaTransactionRequest,
|
|
78
68
|
activeNetwork.id,
|
|
79
69
|
activeAddress
|
|
80
70
|
)
|
|
@@ -82,316 +72,4 @@ export class TransactionService {
|
|
|
82
72
|
throw new Error(`Unsupported namespace: ${namespace}`)
|
|
83
73
|
}
|
|
84
74
|
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Send an Ethereum transaction
|
|
88
|
-
*/
|
|
89
|
-
private async sendEthereumTransaction(
|
|
90
|
-
client: SignClient,
|
|
91
|
-
session: SessionTypes.Struct,
|
|
92
|
-
request: TransactionRequest,
|
|
93
|
-
activeNetworkId: string,
|
|
94
|
-
activeAddress: string
|
|
95
|
-
): Promise<string> {
|
|
96
|
-
try {
|
|
97
|
-
// Handle different types of EVM transactions
|
|
98
|
-
if ('contractAddress' in request && 'abi' in request) {
|
|
99
|
-
// Contract call
|
|
100
|
-
return await this.sendContractCall(
|
|
101
|
-
client,
|
|
102
|
-
session,
|
|
103
|
-
request as EVMContractCallRequest,
|
|
104
|
-
activeNetworkId,
|
|
105
|
-
activeAddress
|
|
106
|
-
)
|
|
107
|
-
} else if ('calls' in request) {
|
|
108
|
-
// Batch transaction - not yet supported
|
|
109
|
-
throw new Error(
|
|
110
|
-
'Batch transactions are not yet supported for WalletConnect'
|
|
111
|
-
)
|
|
112
|
-
} else if ('amount' in request && typeof request.amount === 'bigint') {
|
|
113
|
-
// Native transfer
|
|
114
|
-
return await this.sendNativeTransfer(
|
|
115
|
-
client,
|
|
116
|
-
session,
|
|
117
|
-
request as EVMNativeTransferRequest,
|
|
118
|
-
activeNetworkId,
|
|
119
|
-
activeAddress
|
|
120
|
-
)
|
|
121
|
-
} else {
|
|
122
|
-
throw new Error('Invalid transaction request type')
|
|
123
|
-
}
|
|
124
|
-
} catch (error) {
|
|
125
|
-
throw parseError(error)
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Send a Solana transaction
|
|
131
|
-
*/
|
|
132
|
-
private async sendSolanaTransaction(
|
|
133
|
-
client: SignClient,
|
|
134
|
-
session: SessionTypes.Struct,
|
|
135
|
-
request: SolanaNativeTransferRequest,
|
|
136
|
-
activeNetworkId: string,
|
|
137
|
-
activeAddress: string
|
|
138
|
-
): Promise<string> {
|
|
139
|
-
try {
|
|
140
|
-
// Verify the from address matches active address
|
|
141
|
-
if (request.from !== activeAddress) {
|
|
142
|
-
throw new Error('From address does not match connected wallet')
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Blockhash is required
|
|
146
|
-
if (!request.blockhash) {
|
|
147
|
-
throw new Error('Blockhash is required for Solana transactions')
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// Create the transaction using the utility function
|
|
151
|
-
let transaction: Transaction | VersionedTransaction =
|
|
152
|
-
getSolanaTransaction(request)
|
|
153
|
-
|
|
154
|
-
// Serialize the transaction for WalletConnect
|
|
155
|
-
const serializedTransaction = transaction
|
|
156
|
-
.serialize({
|
|
157
|
-
verifySignatures: false
|
|
158
|
-
})
|
|
159
|
-
.toString('base64')
|
|
160
|
-
|
|
161
|
-
// Get the chain ID (e.g., "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp" for mainnet)
|
|
162
|
-
const chainId = activeNetworkId
|
|
163
|
-
|
|
164
|
-
try {
|
|
165
|
-
// First try signAndSendTransaction (preferred method)
|
|
166
|
-
const result = await client.request({
|
|
167
|
-
topic: session.topic,
|
|
168
|
-
chainId,
|
|
169
|
-
request: {
|
|
170
|
-
method: 'solana_signAndSendTransaction',
|
|
171
|
-
params: {
|
|
172
|
-
transaction: serializedTransaction
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
})
|
|
176
|
-
|
|
177
|
-
// WalletConnect returns the signature directly for Solana
|
|
178
|
-
return result as string
|
|
179
|
-
} catch (signAndSendError: unknown) {
|
|
180
|
-
const errorMessage =
|
|
181
|
-
signAndSendError instanceof Error
|
|
182
|
-
? signAndSendError.message
|
|
183
|
-
: String(signAndSendError)
|
|
184
|
-
// If signAndSendTransaction is not supported, fallback to signTransaction
|
|
185
|
-
if (
|
|
186
|
-
errorMessage.includes('solana_signAndSendTransaction') ||
|
|
187
|
-
errorMessage.includes('Missing or invalid')
|
|
188
|
-
) {
|
|
189
|
-
// Sign the transaction only
|
|
190
|
-
const result: { transaction: string } | { signature: string } =
|
|
191
|
-
await client.request({
|
|
192
|
-
topic: session.topic,
|
|
193
|
-
chainId,
|
|
194
|
-
request: {
|
|
195
|
-
method: 'solana_signTransaction',
|
|
196
|
-
params: {
|
|
197
|
-
transaction: serializedTransaction
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
})
|
|
201
|
-
|
|
202
|
-
if ('signature' in result) {
|
|
203
|
-
const decoded = base58.decode(result.signature)
|
|
204
|
-
transaction.addSignature(
|
|
205
|
-
new PublicKey(request.from),
|
|
206
|
-
Buffer.from(decoded) as Buffer & Uint8Array
|
|
207
|
-
)
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
if ('transaction' in result) {
|
|
211
|
-
const decodedTransaction = Buffer.from(result.transaction, 'base64')
|
|
212
|
-
|
|
213
|
-
if (transaction instanceof VersionedTransaction) {
|
|
214
|
-
transaction = VersionedTransaction.deserialize(
|
|
215
|
-
new Uint8Array(decodedTransaction)
|
|
216
|
-
)
|
|
217
|
-
} else {
|
|
218
|
-
transaction = Transaction.from(decodedTransaction)
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// Get RPC URL from the network RPC map or fall back to public endpoint
|
|
223
|
-
const rpcUrl =
|
|
224
|
-
this.networkRpcMap[activeNetworkId as NetworkId] ||
|
|
225
|
-
'https://api.mainnet-beta.solana.com'
|
|
226
|
-
const connection = new Connection(rpcUrl)
|
|
227
|
-
const rawSignature = await connection.sendRawTransaction(
|
|
228
|
-
transaction.serialize(),
|
|
229
|
-
{
|
|
230
|
-
skipPreflight: false,
|
|
231
|
-
maxRetries: 3,
|
|
232
|
-
preflightCommitment: 'confirmed'
|
|
233
|
-
}
|
|
234
|
-
)
|
|
235
|
-
|
|
236
|
-
return standardizeSignature(rawSignature)
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// If it's a different error, throw it
|
|
240
|
-
throw signAndSendError
|
|
241
|
-
}
|
|
242
|
-
} catch (error) {
|
|
243
|
-
throw parseError(error)
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
/**
|
|
248
|
-
* Send native token transfer (ETH, BNB, MATIC, etc.)
|
|
249
|
-
*/
|
|
250
|
-
private async sendNativeTransfer(
|
|
251
|
-
client: SignClient,
|
|
252
|
-
session: SessionTypes.Struct,
|
|
253
|
-
request: EVMNativeTransferRequest,
|
|
254
|
-
activeNetworkId: string,
|
|
255
|
-
activeAddress: string
|
|
256
|
-
): Promise<string> {
|
|
257
|
-
try {
|
|
258
|
-
// Use the active network chainId
|
|
259
|
-
const chainId = getChainIdFromNetworkId(activeNetworkId as NetworkId)
|
|
260
|
-
|
|
261
|
-
// Build transaction using ethers
|
|
262
|
-
const tx: ethers.TransactionRequest = {
|
|
263
|
-
from: request.from || activeAddress,
|
|
264
|
-
to: request.to,
|
|
265
|
-
value: request.amount
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
// Add gas configuration if provided
|
|
269
|
-
if (request.gasConfig?.gasLimit) {
|
|
270
|
-
tx.gasLimit = BigInt(Math.floor(request.gasConfig.gasLimit))
|
|
271
|
-
}
|
|
272
|
-
if (request.gasConfig?.maxFeePerGas) {
|
|
273
|
-
tx.maxFeePerGas = BigInt(Math.floor(request.gasConfig.maxFeePerGas))
|
|
274
|
-
}
|
|
275
|
-
if (request.gasConfig?.maxPriorityFeePerGas) {
|
|
276
|
-
tx.maxPriorityFeePerGas = BigInt(
|
|
277
|
-
Math.floor(request.gasConfig.maxPriorityFeePerGas)
|
|
278
|
-
)
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// Convert to hex format for WalletConnect
|
|
282
|
-
const txParams: Record<string, string> = {
|
|
283
|
-
from: tx.from as string,
|
|
284
|
-
to: tx.to as string,
|
|
285
|
-
value: '0x' + (tx.value ? BigInt(tx.value).toString(16) : '0'),
|
|
286
|
-
data: '0x' // Empty data for native transfers
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
// Add gas params if present
|
|
290
|
-
if (tx.gasLimit) {
|
|
291
|
-
txParams['gasLimit'] = '0x' + tx.gasLimit.toString(16)
|
|
292
|
-
}
|
|
293
|
-
if (tx.maxFeePerGas) {
|
|
294
|
-
txParams['maxFeePerGas'] = '0x' + tx.maxFeePerGas.toString(16)
|
|
295
|
-
}
|
|
296
|
-
if (tx.maxPriorityFeePerGas) {
|
|
297
|
-
txParams['maxPriorityFeePerGas'] =
|
|
298
|
-
'0x' + tx.maxPriorityFeePerGas.toString(16)
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
const hash = await client.request({
|
|
302
|
-
topic: session.topic,
|
|
303
|
-
chainId: `eip155:${chainId}`,
|
|
304
|
-
request: {
|
|
305
|
-
method: 'eth_sendTransaction',
|
|
306
|
-
params: [txParams]
|
|
307
|
-
}
|
|
308
|
-
})
|
|
309
|
-
|
|
310
|
-
return hash as string
|
|
311
|
-
} catch (error) {
|
|
312
|
-
throw parseError(error)
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
/**
|
|
317
|
-
* Send smart contract transaction (including ERC-20 transfers)
|
|
318
|
-
*/
|
|
319
|
-
private async sendContractCall(
|
|
320
|
-
client: SignClient,
|
|
321
|
-
session: SessionTypes.Struct,
|
|
322
|
-
request: EVMContractCallRequest,
|
|
323
|
-
activeNetworkId: string,
|
|
324
|
-
activeAddress: string
|
|
325
|
-
): Promise<string> {
|
|
326
|
-
try {
|
|
327
|
-
// Use the active network chainId
|
|
328
|
-
const chainId = getChainIdFromNetworkId(activeNetworkId as NetworkId)
|
|
329
|
-
|
|
330
|
-
// Encode the contract call data using ethers
|
|
331
|
-
const iface = new ethers.Interface(request.abi)
|
|
332
|
-
const data = iface.encodeFunctionData(request.functionName, request.args)
|
|
333
|
-
|
|
334
|
-
// Build transaction using ethers
|
|
335
|
-
const tx: ethers.TransactionRequest = {
|
|
336
|
-
from: request.from || activeAddress,
|
|
337
|
-
to: request.contractAddress,
|
|
338
|
-
data
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
// Add value for payable functions
|
|
342
|
-
if (request.value) {
|
|
343
|
-
tx.value = BigInt(request.value)
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
// Add gas configuration if provided
|
|
347
|
-
if (request.gasConfig?.gasLimit) {
|
|
348
|
-
tx.gasLimit = BigInt(Math.floor(request.gasConfig.gasLimit))
|
|
349
|
-
}
|
|
350
|
-
if (request.gasConfig?.maxFeePerGas) {
|
|
351
|
-
tx.maxFeePerGas = BigInt(Math.floor(request.gasConfig.maxFeePerGas))
|
|
352
|
-
}
|
|
353
|
-
if (request.gasConfig?.maxPriorityFeePerGas) {
|
|
354
|
-
tx.maxPriorityFeePerGas = BigInt(
|
|
355
|
-
Math.floor(request.gasConfig.maxPriorityFeePerGas)
|
|
356
|
-
)
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
// Convert to hex format for WalletConnect
|
|
360
|
-
const txParams: Record<string, string> = {
|
|
361
|
-
from: tx.from as string,
|
|
362
|
-
to: tx.to as string,
|
|
363
|
-
data: tx.data as string
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
// Add value if present
|
|
367
|
-
if (tx.value) {
|
|
368
|
-
txParams['value'] = '0x' + BigInt(tx.value).toString(16)
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
// Add gas params if present
|
|
372
|
-
if (tx.gasLimit) {
|
|
373
|
-
txParams['gasLimit'] = '0x' + tx.gasLimit.toString(16)
|
|
374
|
-
}
|
|
375
|
-
if (tx.maxFeePerGas) {
|
|
376
|
-
txParams['maxFeePerGas'] = '0x' + tx.maxFeePerGas.toString(16)
|
|
377
|
-
}
|
|
378
|
-
if (tx.maxPriorityFeePerGas) {
|
|
379
|
-
txParams['maxPriorityFeePerGas'] =
|
|
380
|
-
'0x' + tx.maxPriorityFeePerGas.toString(16)
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
const hash = await client.request({
|
|
384
|
-
topic: session.topic,
|
|
385
|
-
chainId: `eip155:${chainId}`,
|
|
386
|
-
request: {
|
|
387
|
-
method: 'eth_sendTransaction',
|
|
388
|
-
params: [txParams]
|
|
389
|
-
}
|
|
390
|
-
})
|
|
391
|
-
|
|
392
|
-
return hash as string
|
|
393
|
-
} catch (error) {
|
|
394
|
-
throw parseError(error)
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
75
|
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { SolanaNativeTransferRequest } from '@meshconnect/uwc-types'
|
|
2
|
-
import {
|
|
3
|
-
PublicKey,
|
|
4
|
-
SystemProgram,
|
|
5
|
-
Transaction,
|
|
6
|
-
VersionedTransaction
|
|
7
|
-
} from '@solana/web3.js'
|
|
8
|
-
|
|
9
|
-
export function getSolanaTransaction(params: SolanaNativeTransferRequest) {
|
|
10
|
-
if (!params.blockhash) {
|
|
11
|
-
throw new Error('Blockhash is required for Solana transactions')
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const transaction: Transaction | VersionedTransaction = new Transaction().add(
|
|
15
|
-
SystemProgram.transfer({
|
|
16
|
-
fromPubkey: new PublicKey(params.from),
|
|
17
|
-
toPubkey: new PublicKey(params.to),
|
|
18
|
-
lamports: Number(params.amount)
|
|
19
|
-
})
|
|
20
|
-
)
|
|
21
|
-
transaction.recentBlockhash = params.blockhash
|
|
22
|
-
transaction.feePayer = new PublicKey(params.from)
|
|
23
|
-
return transaction
|
|
24
|
-
}
|