@hashgraph/hedera-wallet-connect 2.0.4-canary.f71fa76.0 → 2.0.5-canary.7b24ac9.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/README.md +141 -8
- package/dist/lib/dapp/DAppSigner.js +47 -4
- package/dist/lib/dapp/index.js +9 -1
- package/dist/lib/shared/logger.d.ts +3 -0
- package/dist/lib/shared/logger.js +30 -0
- package/dist/lib/shared/utils.d.ts +6 -1
- package/dist/lib/shared/utils.js +41 -0
- package/dist/reown/adapter.d.ts +1 -1
- package/dist/reown/adapter.js +36 -7
- package/dist/reown/connectors/HederaConnector.d.ts +1 -3
- package/dist/reown/connectors/HederaConnector.js +4 -10
- package/dist/reown/providers/EIP155Provider.d.ts +1 -0
- package/dist/reown/providers/EIP155Provider.js +5 -5
- package/dist/reown/providers/HIP820Provider.js +1 -3
- package/dist/reown/providers/HederaProvider.d.ts +2 -0
- package/dist/reown/providers/HederaProvider.js +52 -17
- package/dist/reown/utils/account.js +25 -4
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ read transactions. Hedera implements EVM compatible smart contracts using
|
|
|
13
13
|
[Hyperledger Besu](https://besu.hyperledger.org/) under the hood.
|
|
14
14
|
|
|
15
15
|
Ethereum developers and toolsets often expect to interact with Ethereum compatible chains using
|
|
16
|
-
the [Ethereum JSON-RPC](https://ethereum.org/en/developers/docs/apis/json-rpc/). To
|
|
16
|
+
the [Ethereum JSON-RPC](https://ethereum.org/en/developers/docs/apis/json-rpc/). To achieve
|
|
17
17
|
compatibility with this API,
|
|
18
18
|
[Hedera JSON-RPC Providers](https://docs.hedera.com/hedera/core-concepts/smart-contracts/json-rpc-relay#community-hosted-json-rpc-relays)
|
|
19
19
|
operate a software middlelayer that translates Ethereum JSON-RPC compatible API calls into
|
|
@@ -26,7 +26,7 @@ transactions to wallets over the WalletConnect network using the JSON-RPC spec d
|
|
|
26
26
|
Hedera native transactions or use Ethereum JSON-RPC calls sent to a Hedera JSON-RPC Relay
|
|
27
27
|
provider which then communicates with Hedera consensus and mirror nodes.
|
|
28
28
|
|
|
29
|
-
On a high level, JSON-RPC is a type of API
|
|
29
|
+
On a high level, JSON-RPC is a type of API structure, such as SOAP, gRPC, REST, GraphQL, etc. In
|
|
30
30
|
the Hedera ecosystem, there are distinct concepts regarding JSON-RPC APIs to consider:
|
|
31
31
|
|
|
32
32
|
- Ethereum JSON-RPC spec defines how to interact with Ethereum compatible networks
|
|
@@ -34,7 +34,7 @@ the Hedera ecosystem, there are distinct concepts regarding JSON-RPC APIs to con
|
|
|
34
34
|
- Wallets in the Hedera ecosystem also support a separate specification that defines how to send
|
|
35
35
|
transactions and messages to wallets over the WalletConnect network without relying on a
|
|
36
36
|
Hedera JSON-RPC Relay provider. This is a Hedera specific specification defined for utilizing
|
|
37
|
-
the WalletConnect network
|
|
37
|
+
the WalletConnect network distinct from other JSON-RPC specs such as the one defined by the
|
|
38
38
|
Ethereum network.
|
|
39
39
|
|
|
40
40
|
For more information see:
|
|
@@ -64,7 +64,7 @@ reviewing the [Reown docs](https://docs.reown.com/overview).
|
|
|
64
64
|
1. Add Hedera dependencies to your project:
|
|
65
65
|
|
|
66
66
|
```sh
|
|
67
|
-
npm install @hashgraph/hedera-wallet-connect
|
|
67
|
+
npm install @hashgraph/hedera-wallet-connect @hashgraph/sdk @walletconnect/modal
|
|
68
68
|
```
|
|
69
69
|
|
|
70
70
|
2. Initialize dApp Connector
|
|
@@ -121,7 +121,7 @@ await dAppConnector.openModal()
|
|
|
121
121
|
2. Add Hedera dependencies to your project:
|
|
122
122
|
|
|
123
123
|
```sh
|
|
124
|
-
npm install @hashgraph/hedera-wallet-connect@2.0.
|
|
124
|
+
npm install @hashgraph/hedera-wallet-connect@2.0.4-canary.3ca04e9.0 @hashgraph/sdk @walletconnect/universal-provider
|
|
125
125
|
```
|
|
126
126
|
|
|
127
127
|
3. Update `createAppKit` with adapters and a universal provider for Hedera. Note the
|
|
@@ -154,7 +154,7 @@ const hederaEVMAdapter = new HederaAdapter({
|
|
|
154
154
|
})
|
|
155
155
|
|
|
156
156
|
const universalProvider = (await HederaProvider.init({
|
|
157
|
-
projectId: "YOUR_PROJECT_ID"
|
|
157
|
+
projectId: "YOUR_PROJECT_ID",
|
|
158
158
|
metadata,
|
|
159
159
|
})) as unknown as UniversalProvider, // avoid type mismatch error due to missing of private properties in HederaProvider
|
|
160
160
|
|
|
@@ -211,6 +211,141 @@ createAppKit({
|
|
|
211
211
|
- [Hedera Wallet Example by Hgraph](https://github.com/hgraph-io/hedera-wallet)
|
|
212
212
|
- <em>[Add an example, demo, or tool here](https://github.com/hashgraph/hedera-wallet-connect/pulls)</em>
|
|
213
213
|
|
|
214
|
+
# Multi-Signature Transactions
|
|
215
|
+
|
|
216
|
+
Multi-signature (multi-sig) workflows allow multiple parties to sign a single transaction before it's executed on the Hedera network. This is commonly used for:
|
|
217
|
+
|
|
218
|
+
- Treasury operations requiring approval from multiple parties
|
|
219
|
+
- Escrow services
|
|
220
|
+
- Joint accounts
|
|
221
|
+
- Backend co-signing for additional security
|
|
222
|
+
|
|
223
|
+
## Using `hedera_signTransaction` for Multi-Sig Workflows
|
|
224
|
+
|
|
225
|
+
The `hedera_signTransaction` method allows you to collect a signature from a wallet without immediately executing the transaction. This signature can then be combined with additional signatures (such as from a backend service) before final execution.
|
|
226
|
+
|
|
227
|
+
### Example: Frontend Wallet Signature + Backend Co-Signature
|
|
228
|
+
|
|
229
|
+
This example demonstrates a common pattern where a user signs a transaction in their wallet, and then a backend service adds its signature before executing the transaction.
|
|
230
|
+
|
|
231
|
+
#### Step 1: Create and Sign Transaction on Frontend
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
import { DAppConnector, HederaJsonRpcMethod } from '@hashgraph/hedera-wallet-connect'
|
|
235
|
+
import { TransferTransaction, Hbar, AccountId } from '@hashgraph/sdk'
|
|
236
|
+
|
|
237
|
+
// Initialize your DAppConnector (see Getting Started section)
|
|
238
|
+
const dAppConnector = new DAppConnector(/* ... */)
|
|
239
|
+
|
|
240
|
+
// Create a transaction
|
|
241
|
+
const transaction = new TransferTransaction()
|
|
242
|
+
.addHbarTransfer(userAccountId, new Hbar(-10))
|
|
243
|
+
.addHbarTransfer(recipientAccountId, new Hbar(10))
|
|
244
|
+
.setTransactionMemo('Multi-sig transfer')
|
|
245
|
+
|
|
246
|
+
// Request signature from wallet (does NOT execute)
|
|
247
|
+
const signer = dAppConnector.getSigner(userAccountId)
|
|
248
|
+
const signedTransaction = await signer.signTransaction(transaction)
|
|
249
|
+
|
|
250
|
+
// Convert signed transaction to bytes for transmission to backend
|
|
251
|
+
const signedTransactionBytes = signedTransaction.toBytes()
|
|
252
|
+
|
|
253
|
+
// Send to backend
|
|
254
|
+
const response = await fetch('/api/execute-transaction', {
|
|
255
|
+
method: 'POST',
|
|
256
|
+
headers: { 'Content-Type': 'application/json' },
|
|
257
|
+
body: JSON.stringify({
|
|
258
|
+
signedTransaction: Buffer.from(signedTransactionBytes).toString('base64'),
|
|
259
|
+
}),
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
const result = await response.json()
|
|
263
|
+
console.log('Transaction executed:', result.transactionId)
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
#### Step 2: Add Backend Signature and Execute
|
|
267
|
+
|
|
268
|
+
On your backend, use the `addSignatureToTransaction` utility to add your server's signature:
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
import { Transaction, PrivateKey, Client } from '@hashgraph/sdk'
|
|
272
|
+
import { addSignatureToTransaction } from '@hashgraph/hedera-wallet-connect'
|
|
273
|
+
|
|
274
|
+
// Backend API endpoint
|
|
275
|
+
app.post('/api/execute-transaction', async (req, res) => {
|
|
276
|
+
try {
|
|
277
|
+
// Reconstruct transaction from bytes
|
|
278
|
+
const signedTransactionBytes = Buffer.from(req.body.signedTransaction, 'base64')
|
|
279
|
+
const signedTransaction = Transaction.fromBytes(signedTransactionBytes)
|
|
280
|
+
|
|
281
|
+
// Load your backend private key (store securely!)
|
|
282
|
+
const backendPrivateKey = PrivateKey.fromStringED25519(process.env.BACKEND_PRIVATE_KEY)
|
|
283
|
+
|
|
284
|
+
// Add backend signature to the transaction
|
|
285
|
+
const fullySignedTransaction = await addSignatureToTransaction(
|
|
286
|
+
signedTransaction,
|
|
287
|
+
backendPrivateKey,
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
// Execute the fully signed transaction
|
|
291
|
+
const client = Client.forTestnet() // or Client.forMainnet()
|
|
292
|
+
client.setOperator(backendAccountId, backendPrivateKey)
|
|
293
|
+
|
|
294
|
+
const txResponse = await fullySignedTransaction.execute(client)
|
|
295
|
+
const receipt = await txResponse.getReceipt(client)
|
|
296
|
+
|
|
297
|
+
res.json({
|
|
298
|
+
success: true,
|
|
299
|
+
transactionId: txResponse.transactionId.toString(),
|
|
300
|
+
status: receipt.status.toString(),
|
|
301
|
+
})
|
|
302
|
+
} catch (error) {
|
|
303
|
+
console.error('Error executing transaction:', error)
|
|
304
|
+
res.status(500).json({ error: error.message })
|
|
305
|
+
}
|
|
306
|
+
})
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### Important Notes
|
|
310
|
+
|
|
311
|
+
1. **Transaction Must Be Frozen**: Before signing, ensure your transaction is frozen.
|
|
312
|
+
|
|
313
|
+
2. **Signature Order**: Signatures can be added in any order. Hedera validates that all required signatures are present when the transaction is executed.
|
|
314
|
+
|
|
315
|
+
3. **Security Considerations**:
|
|
316
|
+
- Never expose backend private keys to the frontend
|
|
317
|
+
- Validate transaction contents on the backend before adding your signature
|
|
318
|
+
- Implement proper authentication and authorization
|
|
319
|
+
- Consider implementing transaction limits and approval workflows
|
|
320
|
+
|
|
321
|
+
4. **Multiple Signatures**: You can add more than two signatures using the same pattern:
|
|
322
|
+
|
|
323
|
+
```typescript
|
|
324
|
+
// Add multiple signatures sequentially
|
|
325
|
+
let signedTx = await addSignatureToTransaction(transaction, privateKey1)
|
|
326
|
+
signedTx = await addSignatureToTransaction(signedTx, privateKey2)
|
|
327
|
+
signedTx = await addSignatureToTransaction(signedTx, privateKey3)
|
|
328
|
+
|
|
329
|
+
// Execute with all signatures
|
|
330
|
+
await signedTx.execute(client)
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
5. **Threshold Keys**: For accounts with threshold key structures, ensure you collect enough signatures to meet the threshold requirement before execution.
|
|
334
|
+
|
|
335
|
+
### Alternative: Using `hedera_signAndExecuteTransaction`
|
|
336
|
+
|
|
337
|
+
If you don't need backend co-signing and want the wallet to execute the transaction immediately:
|
|
338
|
+
|
|
339
|
+
```typescript
|
|
340
|
+
// This signs AND executes in one call
|
|
341
|
+
const result = await dAppConnector.signAndExecuteTransaction({
|
|
342
|
+
signerAccountId: `hedera:testnet:${userAccountId}`,
|
|
343
|
+
transactionList: transactionToBase64String(transaction),
|
|
344
|
+
})
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
Use `hedera_signTransaction` when you need to collect multiple signatures. Use `hedera_signAndExecuteTransaction` when the wallet's signature alone is sufficient to execute the transaction.
|
|
348
|
+
|
|
214
349
|
# Hedera Wallets
|
|
215
350
|
|
|
216
351
|
- [Hashpack](https://hashpack.app/)
|
|
@@ -226,12 +361,10 @@ refer to how to send transactions to wallets using the `hedera:(mainnet|testnet)
|
|
|
226
361
|
While minimal, the main breaking changes are:
|
|
227
362
|
|
|
228
363
|
- remove WalletConnect v1 modals
|
|
229
|
-
|
|
230
364
|
- these are very old, though in the spirit of semver, we kept the dependency until this
|
|
231
365
|
library's v2 release
|
|
232
366
|
|
|
233
367
|
- remove setting node id's within this library for transactions
|
|
234
|
-
|
|
235
368
|
- initially, a transaction created by the Hedera Javascript SDK needed to have one or more
|
|
236
369
|
consensus node ids set to be able to serialize into bytes, sent over a network, and
|
|
237
370
|
deserialized by the SDK
|
|
@@ -146,7 +146,15 @@ export class DAppSigner {
|
|
|
146
146
|
* @returns transaction - `Transaction` object with signature
|
|
147
147
|
*/
|
|
148
148
|
async signTransaction(transaction) {
|
|
149
|
-
|
|
149
|
+
var _a, _b;
|
|
150
|
+
// Ensure transaction is frozen with node account IDs before signing
|
|
151
|
+
// This is required so the transaction can be executed later by any client
|
|
152
|
+
if (!transaction.isFrozen()) {
|
|
153
|
+
transaction.freezeWith(this._getHederaClient());
|
|
154
|
+
}
|
|
155
|
+
// Extract the first node account ID from the frozen transaction to preserve it in the transaction body
|
|
156
|
+
const nodeAccountId = (_b = (_a = transaction.nodeAccountIds) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : null;
|
|
157
|
+
const transactionBody = transactionToTransactionBody(transaction, nodeAccountId);
|
|
150
158
|
if (!transactionBody)
|
|
151
159
|
throw new Error('Failed to serialize transaction body');
|
|
152
160
|
const transactionBodyBase64 = transactionBodyToBase64String(transactionBody);
|
|
@@ -158,9 +166,44 @@ export class DAppSigner {
|
|
|
158
166
|
},
|
|
159
167
|
});
|
|
160
168
|
const sigMap = base64StringToSignatureMap(signatureMap);
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
169
|
+
// Get the original transaction bytes to preserve the full transaction structure
|
|
170
|
+
// including all node account IDs
|
|
171
|
+
const originalTransactionBytes = transaction.toBytes();
|
|
172
|
+
const originalTransactionList = proto.TransactionList.decode(originalTransactionBytes);
|
|
173
|
+
// Add the signature to all transactions in the list
|
|
174
|
+
// Each transaction in the list corresponds to a different node
|
|
175
|
+
const signedTransactionList = originalTransactionList.transactionList.map((tx) => {
|
|
176
|
+
// Check if the transaction has signedTransactionBytes (frozen transactions)
|
|
177
|
+
if (tx.signedTransactionBytes) {
|
|
178
|
+
// Decode the SignedTransaction to access the bodyBytes and existing sigMap
|
|
179
|
+
const signedTx = proto.SignedTransaction.decode(tx.signedTransactionBytes);
|
|
180
|
+
const existingSigMap = signedTx.sigMap || proto.SignatureMap.create({});
|
|
181
|
+
// Merge the new signatures with existing signatures
|
|
182
|
+
const mergedSigPairs = [...(existingSigMap.sigPair || []), ...(sigMap.sigPair || [])];
|
|
183
|
+
// Create updated SignedTransaction with merged signatures
|
|
184
|
+
const updatedSignedTx = proto.SignedTransaction.encode({
|
|
185
|
+
bodyBytes: signedTx.bodyBytes,
|
|
186
|
+
sigMap: proto.SignatureMap.create({
|
|
187
|
+
sigPair: mergedSigPairs,
|
|
188
|
+
}),
|
|
189
|
+
}).finish();
|
|
190
|
+
return {
|
|
191
|
+
signedTransactionBytes: updatedSignedTx,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
// Transaction has bodyBytes and sigMap at the top level (not frozen)
|
|
196
|
+
const existingSigMap = tx.sigMap || proto.SignatureMap.create({});
|
|
197
|
+
// Merge the new signatures with existing signatures
|
|
198
|
+
const mergedSigPairs = [...(existingSigMap.sigPair || []), ...(sigMap.sigPair || [])];
|
|
199
|
+
return Object.assign(Object.assign({}, tx), { sigMap: Object.assign(Object.assign({}, existingSigMap), { sigPair: mergedSigPairs }) });
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
// Encode the signed transaction list back to bytes
|
|
203
|
+
const signedBytes = proto.TransactionList.encode({
|
|
204
|
+
transactionList: signedTransactionList,
|
|
205
|
+
}).finish();
|
|
206
|
+
return Transaction.fromBytes(signedBytes);
|
|
164
207
|
}
|
|
165
208
|
async _tryExecuteTransactionRequest(request) {
|
|
166
209
|
try {
|
package/dist/lib/dapp/index.js
CHANGED
|
@@ -355,9 +355,17 @@ export class DAppConnector {
|
|
|
355
355
|
if (!this.walletConnectClient) {
|
|
356
356
|
throw new Error('WalletConnect is not initialized');
|
|
357
357
|
}
|
|
358
|
+
const requiredNamespaces = networkNamespaces(this.network, this.supportedMethods, this.supportedEvents);
|
|
359
|
+
this.logger.debug('V1 DAppConnector: Connecting with params:', {
|
|
360
|
+
network: this.network.toString(),
|
|
361
|
+
pairingTopic,
|
|
362
|
+
requiredNamespaces,
|
|
363
|
+
supportedMethods: this.supportedMethods,
|
|
364
|
+
supportedEvents: this.supportedEvents,
|
|
365
|
+
});
|
|
358
366
|
return this.walletConnectClient.connect({
|
|
359
367
|
pairingTopic,
|
|
360
|
-
requiredNamespaces
|
|
368
|
+
requiredNamespaces,
|
|
361
369
|
});
|
|
362
370
|
}
|
|
363
371
|
async request({ method, params, }) {
|
|
@@ -16,3 +16,6 @@ export declare class DefaultLogger implements ILogger {
|
|
|
16
16
|
info(message: string, ...args: any[]): void;
|
|
17
17
|
debug(message: string, ...args: any[]): void;
|
|
18
18
|
}
|
|
19
|
+
export declare function setGlobalLogLevel(level: LogLevel): void;
|
|
20
|
+
export declare function getGlobalLogLevel(): LogLevel;
|
|
21
|
+
export declare function createLogger(name: string, level?: LogLevel): DefaultLogger;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
var _a;
|
|
1
2
|
export class DefaultLogger {
|
|
2
3
|
constructor(logLevel = 'info', name) {
|
|
3
4
|
this.logLevel = 'info';
|
|
@@ -31,3 +32,32 @@ export class DefaultLogger {
|
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
}
|
|
35
|
+
// Global logger configuration
|
|
36
|
+
let globalLogLevel = 'info';
|
|
37
|
+
// Check if environment variable is set
|
|
38
|
+
if (typeof process !== 'undefined' && ((_a = process.env) === null || _a === void 0 ? void 0 : _a.HWC_LOG_LEVEL)) {
|
|
39
|
+
const envLevel = process.env.HWC_LOG_LEVEL.toLowerCase();
|
|
40
|
+
if (['error', 'warn', 'info', 'debug', 'off'].includes(envLevel)) {
|
|
41
|
+
globalLogLevel = envLevel;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// Check if localStorage is available (browser environment)
|
|
45
|
+
if (typeof localStorage !== 'undefined') {
|
|
46
|
+
const storedLevel = localStorage.getItem('hwc_log_level');
|
|
47
|
+
if (storedLevel && ['error', 'warn', 'info', 'debug', 'off'].includes(storedLevel)) {
|
|
48
|
+
globalLogLevel = storedLevel;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export function setGlobalLogLevel(level) {
|
|
52
|
+
globalLogLevel = level;
|
|
53
|
+
if (typeof localStorage !== 'undefined') {
|
|
54
|
+
localStorage.setItem('hwc_log_level', level);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
export function getGlobalLogLevel() {
|
|
58
|
+
return globalLogLevel;
|
|
59
|
+
}
|
|
60
|
+
// Factory function to create logger instances
|
|
61
|
+
export function createLogger(name, level) {
|
|
62
|
+
return new DefaultLogger(level || globalLogLevel, name);
|
|
63
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AccountId, PublicKey, Transaction, LedgerId, Query, SignerSignature } from '@hashgraph/sdk';
|
|
1
|
+
import { AccountId, PublicKey, PrivateKey, Transaction, LedgerId, Query, SignerSignature } from '@hashgraph/sdk';
|
|
2
2
|
import { ProposalTypes, SessionTypes } from '@walletconnect/types';
|
|
3
3
|
import { proto } from '@hashgraph/proto';
|
|
4
4
|
/**
|
|
@@ -273,3 +273,8 @@ export declare const accountAndLedgerFromSession: (session: SessionTypes.Struct)
|
|
|
273
273
|
network: LedgerId;
|
|
274
274
|
account: AccountId;
|
|
275
275
|
}[];
|
|
276
|
+
/**
|
|
277
|
+
* Adds an additional signature to an already-signed transaction.
|
|
278
|
+
* Uses proto-level manipulation to preserve existing signatures.
|
|
279
|
+
*/
|
|
280
|
+
export declare function addSignatureToTransaction<T extends Transaction>(transaction: T, privateKey: PrivateKey): Promise<T>;
|
package/dist/lib/shared/utils.js
CHANGED
|
@@ -418,3 +418,44 @@ export const accountAndLedgerFromSession = (session) => {
|
|
|
418
418
|
};
|
|
419
419
|
});
|
|
420
420
|
};
|
|
421
|
+
/**
|
|
422
|
+
* Adds an additional signature to an already-signed transaction.
|
|
423
|
+
* Uses proto-level manipulation to preserve existing signatures.
|
|
424
|
+
*/
|
|
425
|
+
export async function addSignatureToTransaction(transaction, privateKey) {
|
|
426
|
+
const originalBytes = transaction.toBytes();
|
|
427
|
+
const originalList = proto.TransactionList.decode(originalBytes);
|
|
428
|
+
const firstTransaction = originalList.transactionList[0];
|
|
429
|
+
let bodyBytes;
|
|
430
|
+
if (firstTransaction.signedTransactionBytes) {
|
|
431
|
+
const signedTx = proto.SignedTransaction.decode(firstTransaction.signedTransactionBytes);
|
|
432
|
+
bodyBytes = signedTx.bodyBytes;
|
|
433
|
+
}
|
|
434
|
+
else {
|
|
435
|
+
bodyBytes = firstTransaction.bodyBytes;
|
|
436
|
+
}
|
|
437
|
+
const signature = await privateKey.sign(bodyBytes);
|
|
438
|
+
const publicKey = privateKey.publicKey;
|
|
439
|
+
const signedTransactionList = originalList.transactionList.map((tx) => {
|
|
440
|
+
const newSigPair = publicKey._toProtobufSignature(signature);
|
|
441
|
+
if (tx.signedTransactionBytes) {
|
|
442
|
+
const signedTx = proto.SignedTransaction.decode(tx.signedTransactionBytes);
|
|
443
|
+
const existingSigMap = signedTx.sigMap || proto.SignatureMap.create({});
|
|
444
|
+
const mergedSigPairs = [...(existingSigMap.sigPair || []), newSigPair];
|
|
445
|
+
const updatedSignedTx = proto.SignedTransaction.encode({
|
|
446
|
+
bodyBytes: signedTx.bodyBytes,
|
|
447
|
+
sigMap: proto.SignatureMap.create({ sigPair: mergedSigPairs }),
|
|
448
|
+
}).finish();
|
|
449
|
+
return { signedTransactionBytes: updatedSignedTx };
|
|
450
|
+
}
|
|
451
|
+
else {
|
|
452
|
+
const existingSigMap = tx.sigMap || proto.SignatureMap.create({});
|
|
453
|
+
const mergedSigPairs = [...(existingSigMap.sigPair || []), newSigPair];
|
|
454
|
+
return Object.assign(Object.assign({}, tx), { sigMap: Object.assign(Object.assign({}, existingSigMap), { sigPair: mergedSigPairs }) });
|
|
455
|
+
}
|
|
456
|
+
});
|
|
457
|
+
const signedBytes = proto.TransactionList.encode({
|
|
458
|
+
transactionList: signedTransactionList,
|
|
459
|
+
}).finish();
|
|
460
|
+
return Transaction.fromBytes(signedBytes);
|
|
461
|
+
}
|
package/dist/reown/adapter.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ type GetProfileResult = {
|
|
|
17
17
|
profileName: string;
|
|
18
18
|
};
|
|
19
19
|
export declare class HederaAdapter extends AdapterBlueprint {
|
|
20
|
-
private
|
|
20
|
+
private logger;
|
|
21
21
|
constructor(params: HederaAdapter.Params);
|
|
22
22
|
setUniversalProvider(universalProvider: UniversalProvider): Promise<void>;
|
|
23
23
|
connect(params: AdapterBlueprint.ConnectParams): Promise<AdapterBlueprint.ConnectResult>;
|
package/dist/reown/adapter.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { CoreHelperUtil, WcHelpersUtil } from '@reown/appkit';
|
|
2
2
|
import { isReownName } from '@reown/appkit-common';
|
|
3
3
|
import { AdapterBlueprint } from '@reown/appkit/adapters';
|
|
4
|
-
import { ProviderUtil } from '@reown/appkit/store';
|
|
5
4
|
import { LedgerId } from '@hashgraph/sdk';
|
|
6
5
|
import { BrowserProvider, Contract, formatUnits, JsonRpcSigner, parseUnits } from 'ethers';
|
|
7
6
|
import { HederaConnector } from './connectors';
|
|
8
|
-
import { hederaNamespace, getAccountBalance } from './utils';
|
|
7
|
+
import { hederaNamespace, getAccountBalance, HederaChainDefinition } from './utils';
|
|
8
|
+
import { createLogger } from '../lib/shared/logger';
|
|
9
9
|
export class HederaAdapter extends AdapterBlueprint {
|
|
10
10
|
constructor(params) {
|
|
11
11
|
var _a, _b;
|
|
@@ -23,18 +23,47 @@ export class HederaAdapter extends AdapterBlueprint {
|
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
super(Object.assign({}, params));
|
|
26
|
-
this.
|
|
27
|
-
|
|
26
|
+
this.logger = createLogger('HederaAdapter');
|
|
27
|
+
// Override getCaipNetworks to return appropriate networks based on namespace
|
|
28
|
+
this.getCaipNetworks = (namespace) => {
|
|
29
|
+
const targetNamespace = namespace || this.namespace;
|
|
30
|
+
if (targetNamespace === 'eip155') {
|
|
31
|
+
// Return EIP155 Hedera networks
|
|
32
|
+
return [HederaChainDefinition.EVM.Mainnet, HederaChainDefinition.EVM.Testnet];
|
|
33
|
+
}
|
|
34
|
+
else if (targetNamespace === hederaNamespace) {
|
|
35
|
+
// Return native Hedera networks
|
|
36
|
+
return [HederaChainDefinition.Native.Mainnet, HederaChainDefinition.Native.Testnet];
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
// Return all Hedera networks if no specific namespace is requested
|
|
40
|
+
return [
|
|
41
|
+
HederaChainDefinition.EVM.Mainnet,
|
|
42
|
+
HederaChainDefinition.EVM.Testnet,
|
|
43
|
+
HederaChainDefinition.Native.Mainnet,
|
|
44
|
+
HederaChainDefinition.Native.Testnet,
|
|
45
|
+
];
|
|
46
|
+
}
|
|
47
|
+
};
|
|
28
48
|
}
|
|
29
49
|
async setUniversalProvider(universalProvider) {
|
|
30
50
|
this.addConnector(new HederaConnector({
|
|
31
51
|
provider: universalProvider,
|
|
32
52
|
caipNetworks: this.getCaipNetworks() || [],
|
|
33
53
|
namespace: this.namespace,
|
|
34
|
-
namespaceMode: this.namespaceMode,
|
|
35
54
|
}));
|
|
36
55
|
}
|
|
37
56
|
async connect(params) {
|
|
57
|
+
this.logger.debug('connect called with params:', params);
|
|
58
|
+
// Get the WalletConnect connector and ensure it connects with proper namespaces
|
|
59
|
+
const connector = this.getWalletConnectConnector();
|
|
60
|
+
if (connector && 'connectWalletConnect' in connector) {
|
|
61
|
+
this.logger.debug('Calling HederaConnector.connectWalletConnect');
|
|
62
|
+
await connector.connectWalletConnect();
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
this.logger.warn('HederaConnector not found or connectWalletConnect method missing');
|
|
66
|
+
}
|
|
38
67
|
return Promise.resolve({
|
|
39
68
|
id: 'WALLET_CONNECT',
|
|
40
69
|
type: 'WALLET_CONNECT',
|
|
@@ -49,7 +78,7 @@ export class HederaAdapter extends AdapterBlueprint {
|
|
|
49
78
|
await connector.disconnect();
|
|
50
79
|
}
|
|
51
80
|
catch (error) {
|
|
52
|
-
|
|
81
|
+
this.logger.warn('disconnect - error', error);
|
|
53
82
|
}
|
|
54
83
|
return { connections: [] };
|
|
55
84
|
}
|
|
@@ -191,7 +220,7 @@ export class HederaAdapter extends AdapterBlueprint {
|
|
|
191
220
|
if (this.namespace !== 'eip155') {
|
|
192
221
|
throw new Error('Namespace is not eip155');
|
|
193
222
|
}
|
|
194
|
-
const provider =
|
|
223
|
+
const provider = this.provider;
|
|
195
224
|
if (!provider) {
|
|
196
225
|
throw new Error('Provider is undefined');
|
|
197
226
|
}
|
|
@@ -10,8 +10,7 @@ export declare class HederaConnector implements ChainAdapterConnector {
|
|
|
10
10
|
readonly chain: ChainNamespace;
|
|
11
11
|
provider: UniversalProvider;
|
|
12
12
|
protected caipNetworks: CaipNetwork[];
|
|
13
|
-
|
|
14
|
-
constructor({ provider, caipNetworks, namespace, namespaceMode, }: HederaConnector.Options);
|
|
13
|
+
constructor({ provider, caipNetworks, namespace }: HederaConnector.Options);
|
|
15
14
|
get chains(): CaipNetwork[];
|
|
16
15
|
connectWalletConnect(): Promise<{
|
|
17
16
|
clientId: string;
|
|
@@ -25,7 +24,6 @@ export declare namespace HederaConnector {
|
|
|
25
24
|
provider: UniversalProvider;
|
|
26
25
|
caipNetworks: CaipNetwork[];
|
|
27
26
|
namespace: 'hedera' | 'eip155';
|
|
28
|
-
namespaceMode?: 'optional' | 'required';
|
|
29
27
|
};
|
|
30
28
|
}
|
|
31
29
|
export {};
|
|
@@ -2,7 +2,7 @@ import { ConstantsUtil } from '@reown/appkit-common';
|
|
|
2
2
|
import { PresetsUtil } from '@reown/appkit-utils';
|
|
3
3
|
import { createNamespaces } from '../utils';
|
|
4
4
|
export class HederaConnector {
|
|
5
|
-
constructor({ provider, caipNetworks, namespace
|
|
5
|
+
constructor({ provider, caipNetworks, namespace }) {
|
|
6
6
|
this.id = ConstantsUtil.CONNECTOR_ID.WALLET_CONNECT;
|
|
7
7
|
this.name = PresetsUtil.ConnectorNamesMap[ConstantsUtil.CONNECTOR_ID.WALLET_CONNECT];
|
|
8
8
|
this.type = 'WALLET_CONNECT';
|
|
@@ -10,20 +10,14 @@ export class HederaConnector {
|
|
|
10
10
|
this.caipNetworks = caipNetworks;
|
|
11
11
|
this.provider = provider;
|
|
12
12
|
this.chain = namespace;
|
|
13
|
-
this.namespaceMode = namespaceMode;
|
|
14
13
|
}
|
|
15
14
|
get chains() {
|
|
16
15
|
return this.caipNetworks;
|
|
17
16
|
}
|
|
18
17
|
async connectWalletConnect() {
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const connectParams = this.namespaceMode === 'required'
|
|
23
|
-
? { requiredNamespaces: namespaces }
|
|
24
|
-
: { optionalNamespaces: namespaces };
|
|
25
|
-
await this.provider.connect(connectParams);
|
|
26
|
-
}
|
|
18
|
+
const namespaces = createNamespaces(this.caipNetworks);
|
|
19
|
+
const connectParams = { optionalNamespaces: namespaces };
|
|
20
|
+
await this.provider.connect(connectParams);
|
|
27
21
|
return {
|
|
28
22
|
clientId: await this.provider.client.core.crypto.getClientId(),
|
|
29
23
|
session: this.provider.session,
|
|
@@ -8,6 +8,7 @@ declare class EIP155Provider implements IProvider {
|
|
|
8
8
|
namespace: SessionNamespace;
|
|
9
9
|
httpProviders: RpcProvidersMap;
|
|
10
10
|
events: EventEmitter;
|
|
11
|
+
private logger;
|
|
11
12
|
constructor({ client, events, namespace, }: {
|
|
12
13
|
client: IProvider['client'];
|
|
13
14
|
events: EventEmitter;
|
|
@@ -2,9 +2,11 @@ import { JsonRpcProvider } from '@walletconnect/jsonrpc-provider';
|
|
|
2
2
|
import { HttpConnection } from '@walletconnect/jsonrpc-http-connection';
|
|
3
3
|
import { formatJsonRpcRequest } from '@walletconnect/jsonrpc-utils';
|
|
4
4
|
import { BUNDLER_URL, getChainId, HederaChainDefinition } from '../utils';
|
|
5
|
+
import { createLogger } from '../../lib/shared/logger';
|
|
5
6
|
class EIP155Provider {
|
|
6
7
|
constructor({ client, events, namespace, }) {
|
|
7
8
|
this.name = 'eip155';
|
|
9
|
+
this.logger = createLogger('EIP155Provider');
|
|
8
10
|
this.namespace = namespace;
|
|
9
11
|
this.events = events;
|
|
10
12
|
this.client = client;
|
|
@@ -51,9 +53,7 @@ class EIP155Provider {
|
|
|
51
53
|
return this.chainId.toString();
|
|
52
54
|
if (this.namespace.defaultChain)
|
|
53
55
|
return this.namespace.defaultChain;
|
|
54
|
-
const chainId = this.namespace.chains[0];
|
|
55
|
-
if (!chainId)
|
|
56
|
-
throw new Error(`ChainId not found`);
|
|
56
|
+
const chainId = this.namespace.chains[0] || 'eip155:295'; // default to mainnet
|
|
57
57
|
return chainId.split(':')[1];
|
|
58
58
|
}
|
|
59
59
|
// ---------- Private ----------------------------------------------- //
|
|
@@ -146,7 +146,7 @@ class EIP155Provider {
|
|
|
146
146
|
return await this.getUserOperationReceipt(bundlerUrl, args);
|
|
147
147
|
}
|
|
148
148
|
catch (error) {
|
|
149
|
-
|
|
149
|
+
this.logger.warn('Failed to fetch call status from bundler', error, bundlerUrl);
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
152
|
const customUrl = (_b = session.sessionProperties) === null || _b === void 0 ? void 0 : _b.bundler_url;
|
|
@@ -155,7 +155,7 @@ class EIP155Provider {
|
|
|
155
155
|
return await this.getUserOperationReceipt(customUrl, args);
|
|
156
156
|
}
|
|
157
157
|
catch (error) {
|
|
158
|
-
|
|
158
|
+
this.logger.warn('Failed to fetch call status from custom bundler', error, customUrl);
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
161
|
if (this.namespace.methods.includes(args.request.method)) {
|
|
@@ -42,9 +42,7 @@ class HIP820Provider {
|
|
|
42
42
|
return this.chainId;
|
|
43
43
|
if (this.namespace.defaultChain)
|
|
44
44
|
return this.namespace.defaultChain;
|
|
45
|
-
const chainId = this.namespace.chains[0];
|
|
46
|
-
if (!chainId)
|
|
47
|
-
throw new Error(`ChainId not found`);
|
|
45
|
+
const chainId = this.namespace.chains[0] || 'hedera:mainnet'; // default to mainnet
|
|
48
46
|
return chainId.split(':')[1];
|
|
49
47
|
}
|
|
50
48
|
// create signer on demand
|
|
@@ -11,6 +11,7 @@ export type HederaWalletConnectProviderConfig = {
|
|
|
11
11
|
chains: CaipNetwork[];
|
|
12
12
|
} & UniversalProviderOpts;
|
|
13
13
|
export declare class HederaProvider extends UniversalProvider {
|
|
14
|
+
private hederaLogger;
|
|
14
15
|
nativeProvider?: HIP820Provider;
|
|
15
16
|
eip155Provider?: EIP155Provider;
|
|
16
17
|
constructor(opts: UniversalProviderOpts);
|
|
@@ -157,6 +158,7 @@ export declare class HederaProvider extends UniversalProvider {
|
|
|
157
158
|
net_version(): Promise<string>;
|
|
158
159
|
web3_clientVersion(): Promise<string>;
|
|
159
160
|
eth_chainId(): Promise<string>;
|
|
161
|
+
connect(params?: any): Promise<any>;
|
|
160
162
|
pair(pairingTopic: string | undefined): ReturnType<UniversalProvider['pair']>;
|
|
161
163
|
private initProviders;
|
|
162
164
|
get rpcProviders(): RpcProviderMap;
|
|
@@ -5,25 +5,19 @@ import { HederaJsonRpcMethod, } from '../..';
|
|
|
5
5
|
import { getChainsFromApprovedSession, mergeRequiredOptionalNamespaces, } from '../utils';
|
|
6
6
|
import HIP820Provider from './HIP820Provider';
|
|
7
7
|
import EIP155Provider from './EIP155Provider';
|
|
8
|
+
import { createLogger } from '../../lib/shared/logger';
|
|
8
9
|
// Reown AppKit UniversalProvider for HIP-820 & EIP-155 version implementation of the @hashgraph/hedera-wallet-connect DAppConnector
|
|
9
10
|
export class HederaProvider extends UniversalProvider {
|
|
10
11
|
constructor(opts) {
|
|
11
12
|
super(opts);
|
|
13
|
+
this.hederaLogger = createLogger('HederaProvider');
|
|
12
14
|
}
|
|
13
15
|
static async init(opts) {
|
|
14
|
-
var _a, _b
|
|
16
|
+
var _a, _b;
|
|
15
17
|
const provider = new HederaProvider(opts);
|
|
16
|
-
//@ts-expect-error
|
|
18
|
+
//@ts-expect-error
|
|
17
19
|
await provider.initialize();
|
|
18
|
-
provider.namespaces = Object.assign(Object.assign({}, (((_a = provider.
|
|
19
|
-
? {
|
|
20
|
-
eip155: Object.assign(Object.assign({}, (_b = provider.namespaces) === null || _b === void 0 ? void 0 : _b.eip155), { rpcMap: (_c = provider.optionalNamespaces) === null || _c === void 0 ? void 0 : _c.eip155.rpcMap }),
|
|
21
|
-
}
|
|
22
|
-
: {})), (((_d = provider.namespaces) === null || _d === void 0 ? void 0 : _d.hedera)
|
|
23
|
-
? {
|
|
24
|
-
hedera: Object.assign(Object.assign({}, (_e = provider.namespaces) === null || _e === void 0 ? void 0 : _e.hedera), { rpcMap: (_f = provider.optionalNamespaces) === null || _f === void 0 ? void 0 : _f.hedera.rpcMap }),
|
|
25
|
-
}
|
|
26
|
-
: {}));
|
|
20
|
+
provider.namespaces = Object.assign(Object.assign({}, (((_a = provider.providerOpts) === null || _a === void 0 ? void 0 : _a.optionalNamespaces) || {})), (((_b = provider.providerOpts) === null || _b === void 0 ? void 0 : _b.requiredNamespaces) || {}));
|
|
27
21
|
if (provider.session)
|
|
28
22
|
provider.initProviders();
|
|
29
23
|
return provider;
|
|
@@ -32,13 +26,13 @@ export class HederaProvider extends UniversalProvider {
|
|
|
32
26
|
this.events.emit(event, data);
|
|
33
27
|
}
|
|
34
28
|
getAccountAddresses() {
|
|
35
|
-
if (!this.session
|
|
29
|
+
if (!this.session) {
|
|
36
30
|
throw new Error('Not initialized. Please call connect()');
|
|
37
31
|
}
|
|
38
32
|
return Object.values(this.session.namespaces).flatMap((namespace) => { var _a; return (_a = namespace.accounts.map((account) => account.split(':')[2])) !== null && _a !== void 0 ? _a : []; });
|
|
39
33
|
}
|
|
40
34
|
async request(args, chain, expiry) {
|
|
41
|
-
var _a, _b, _c, _d;
|
|
35
|
+
var _a, _b, _c, _d, _e;
|
|
42
36
|
if (!this.session || !this.namespaces) {
|
|
43
37
|
throw new Error('Please call connect() before request()');
|
|
44
38
|
}
|
|
@@ -59,8 +53,8 @@ export class HederaProvider extends UniversalProvider {
|
|
|
59
53
|
if (!this.eip155Provider) {
|
|
60
54
|
throw new Error('eip155Provider not initialized');
|
|
61
55
|
}
|
|
62
|
-
chainId = chainId !== null && chainId !== void 0 ? chainId : (_c = this.namespaces
|
|
63
|
-
return (
|
|
56
|
+
chainId = chainId !== null && chainId !== void 0 ? chainId : (_d = (_c = this.namespaces) === null || _c === void 0 ? void 0 : _c.eip155) === null || _d === void 0 ? void 0 : _d.chains[0];
|
|
57
|
+
return (_e = this.eip155Provider) === null || _e === void 0 ? void 0 : _e.request({
|
|
64
58
|
request: Object.assign({}, args),
|
|
65
59
|
chainId: chainId,
|
|
66
60
|
topic: this.session.topic,
|
|
@@ -411,7 +405,45 @@ export class HederaProvider extends UniversalProvider {
|
|
|
411
405
|
async eth_chainId() {
|
|
412
406
|
return this.request({ method: 'eth_chainId', params: [] });
|
|
413
407
|
}
|
|
408
|
+
async connect(params) {
|
|
409
|
+
this.hederaLogger.debug('connect called with params:', params);
|
|
410
|
+
// Update the internal namespace properties before connecting
|
|
411
|
+
if (params) {
|
|
412
|
+
if (params.requiredNamespaces) {
|
|
413
|
+
this.hederaLogger.debug('Setting requiredNamespaces:', params.requiredNamespaces);
|
|
414
|
+
// @ts-ignore - accessing private property
|
|
415
|
+
this.requiredNamespaces = params.requiredNamespaces;
|
|
416
|
+
}
|
|
417
|
+
if (params.optionalNamespaces) {
|
|
418
|
+
this.hederaLogger.debug('Setting optionalNamespaces:', params.requiredNamespaces);
|
|
419
|
+
// @ts-ignore - accessing private property
|
|
420
|
+
this.optionalNamespaces = params.optionalNamespaces;
|
|
421
|
+
}
|
|
422
|
+
if (params.namespaces) {
|
|
423
|
+
this.hederaLogger.debug('Setting namespaces:', params.namespaces);
|
|
424
|
+
// @ts-ignore - accessing private property
|
|
425
|
+
this.namespaces = params.namespaces;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
this.hederaLogger.debug('Calling super.connect with params');
|
|
429
|
+
// Try to directly pass the namespaces to the parent connect
|
|
430
|
+
let result;
|
|
431
|
+
try {
|
|
432
|
+
result = await super.connect(params);
|
|
433
|
+
}
|
|
434
|
+
catch (error) {
|
|
435
|
+
this.hederaLogger.error('Error in super.connect:', error);
|
|
436
|
+
throw error;
|
|
437
|
+
}
|
|
438
|
+
this.hederaLogger.info('super.connect completed successfully');
|
|
439
|
+
this.hederaLogger.debug('Result from super.connect:', result);
|
|
440
|
+
this.initProviders();
|
|
441
|
+
return result;
|
|
442
|
+
}
|
|
414
443
|
async pair(pairingTopic) {
|
|
444
|
+
console.log(pairingTopic);
|
|
445
|
+
//@ts-expect-error
|
|
446
|
+
console.log(this.requiredNamespaces);
|
|
415
447
|
const session = await super.pair(pairingTopic);
|
|
416
448
|
this.initProviders();
|
|
417
449
|
return session;
|
|
@@ -426,10 +458,13 @@ export class HederaProvider extends UniversalProvider {
|
|
|
426
458
|
const namespaces = Object.keys(this.namespaces);
|
|
427
459
|
const providers = {};
|
|
428
460
|
namespaces.forEach((namespace) => {
|
|
429
|
-
|
|
461
|
+
var _a, _b, _c, _d;
|
|
462
|
+
const accounts = ((_b = (_a = this.session) === null || _a === void 0 ? void 0 : _a.namespaces[namespace]) === null || _b === void 0 ? void 0 : _b.accounts) || [];
|
|
430
463
|
const approvedChains = getChainsFromApprovedSession(accounts);
|
|
431
464
|
const mergedNamespaces = mergeRequiredOptionalNamespaces(this.namespaces, this.optionalNamespaces);
|
|
432
|
-
const combinedNamespace = Object.assign(Object.assign({}, mergedNamespaces[namespace]), { accounts, chains: approvedChains })
|
|
465
|
+
const combinedNamespace = Object.assign(Object.assign(Object.assign({}, mergedNamespaces[namespace]), { accounts, chains: approvedChains }), (((_d = (_c = this.optionalNamespaces) === null || _c === void 0 ? void 0 : _c[namespace]) === null || _d === void 0 ? void 0 : _d.rpcMap) && {
|
|
466
|
+
rpcMap: this.optionalNamespaces[namespace].rpcMap,
|
|
467
|
+
}));
|
|
433
468
|
switch (namespace) {
|
|
434
469
|
case 'hedera': {
|
|
435
470
|
const provider = new HIP820Provider({
|
|
@@ -1,20 +1,41 @@
|
|
|
1
1
|
import { AccountBalanceQuery, AccountId, Client, LedgerId, } from '@hashgraph/sdk';
|
|
2
|
+
import { createLogger } from '../../lib/shared/logger';
|
|
3
|
+
const logger = createLogger('AccountUtils');
|
|
2
4
|
export async function getAccountBalance(ledgerId, address) {
|
|
3
5
|
const client = ledgerId === LedgerId.TESTNET ? Client.forTestnet() : Client.forMainnet();
|
|
4
6
|
let accountId;
|
|
5
7
|
try {
|
|
8
|
+
// First try to parse as a Hedera account ID (e.g., "0.0.12345")
|
|
6
9
|
accountId = AccountId.fromString(address);
|
|
7
10
|
}
|
|
8
11
|
catch (e) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
// If it's an EVM address (starts with 0x), try to get the associated account
|
|
13
|
+
if (address.startsWith('0x')) {
|
|
14
|
+
try {
|
|
15
|
+
accountId = AccountId.fromEvmAddress(0, 0, address);
|
|
16
|
+
// Try to populate the account number from the mirror node
|
|
17
|
+
// This will fail if the EVM address doesn't have an associated Hedera account
|
|
18
|
+
if (accountId.num.isZero() && accountId.evmAddress != null) {
|
|
19
|
+
await accountId.populateAccountNum(client);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
catch (populateError) {
|
|
23
|
+
// If we can't find a Hedera account for this EVM address, return null
|
|
24
|
+
logger.debug('No Hedera account found for EVM address:', address);
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
// Not a valid account ID or EVM address
|
|
30
|
+
logger.debug('Invalid address format:', address);
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
13
33
|
}
|
|
14
34
|
try {
|
|
15
35
|
return await new AccountBalanceQuery().setAccountId(accountId).execute(client);
|
|
16
36
|
}
|
|
17
37
|
catch (e) {
|
|
38
|
+
logger.debug('Failed to get account balance:', e);
|
|
18
39
|
return null;
|
|
19
40
|
}
|
|
20
41
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hashgraph/hedera-wallet-connect",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.5-canary.7b24ac9.0",
|
|
4
4
|
"description": "A library to facilitate integrating Hedera with WalletConnect",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
"@swc/jest": "^0.2.37",
|
|
39
39
|
"@types/jest": "^30.0.0",
|
|
40
40
|
"jest": "^30.0.3",
|
|
41
|
+
"nodemon": "^3.1.10",
|
|
41
42
|
"prettier": "^3.5.3",
|
|
42
43
|
"ts-node": "^10.9.2",
|
|
43
44
|
"typescript": "^5.8.2"
|