@wopr-network/platform-core 1.61.0 → 1.61.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.
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* - p2pkh: DOGE (D...), TRON (T...) — params: { version }
|
|
11
11
|
* - evm: ETH, ERC-20 (0x...) — params: {}
|
|
12
12
|
*/
|
|
13
|
+
import { secp256k1 } from "@noble/curves/secp256k1.js";
|
|
13
14
|
import { ripemd160 } from "@noble/hashes/legacy.js";
|
|
14
15
|
import { sha256 } from "@noble/hashes/sha2.js";
|
|
15
16
|
import { bech32 } from "@scure/base";
|
|
@@ -53,7 +54,13 @@ function encodeP2pkh(pubkey, versionByte) {
|
|
|
53
54
|
return base58encode(full);
|
|
54
55
|
}
|
|
55
56
|
function encodeEvm(pubkey) {
|
|
56
|
-
|
|
57
|
+
// HDKey.publicKey is SEC1 compressed (33 bytes, 02/03 prefix).
|
|
58
|
+
// Ethereum addresses = keccak256(uncompressed_pubkey[1:]).slice(-20).
|
|
59
|
+
// viem's publicKeyToAddress expects uncompressed (65 bytes, 04 prefix).
|
|
60
|
+
// Decompress via secp256k1 point recovery before hashing.
|
|
61
|
+
const hexKey = Array.from(pubkey, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
62
|
+
const uncompressed = secp256k1.Point.fromHex(hexKey).toBytes(false);
|
|
63
|
+
const hexPubKey = `0x${Array.from(uncompressed, (b) => b.toString(16).padStart(2, "0")).join("")}`;
|
|
57
64
|
return publicKeyToAddress(hexPubKey);
|
|
58
65
|
}
|
|
59
66
|
// ---------- public API ----------
|
|
@@ -284,8 +284,15 @@ export async function startWatchers(opts) {
|
|
|
284
284
|
if (!method.rpcUrl)
|
|
285
285
|
continue;
|
|
286
286
|
const rpcCall = createRpcCaller(method.rpcUrl);
|
|
287
|
-
|
|
288
|
-
|
|
287
|
+
let latestBlock;
|
|
288
|
+
try {
|
|
289
|
+
const latestHex = (await rpcCall("eth_blockNumber", []));
|
|
290
|
+
latestBlock = Number.parseInt(latestHex, 16);
|
|
291
|
+
}
|
|
292
|
+
catch (err) {
|
|
293
|
+
log("Skipping ETH watcher — RPC unreachable", { chain: method.chain, token: method.token, error: String(err) });
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
289
296
|
const backfillStart = Math.max(0, latestBlock - BACKFILL_BLOCKS);
|
|
290
297
|
const activeAddresses = await chargeStore.listActiveDepositAddresses();
|
|
291
298
|
// Only watch addresses for native charges on this chain (not ERC20 charges)
|
|
@@ -346,8 +353,15 @@ export async function startWatchers(opts) {
|
|
|
346
353
|
if (!method.rpcUrl || !method.contractAddress)
|
|
347
354
|
continue;
|
|
348
355
|
const rpcCall = createRpcCaller(method.rpcUrl);
|
|
349
|
-
|
|
350
|
-
|
|
356
|
+
let latestBlock;
|
|
357
|
+
try {
|
|
358
|
+
const latestHex = (await rpcCall("eth_blockNumber", []));
|
|
359
|
+
latestBlock = Number.parseInt(latestHex, 16);
|
|
360
|
+
}
|
|
361
|
+
catch (err) {
|
|
362
|
+
log("Skipping EVM watcher — RPC unreachable", { chain: method.chain, token: method.token, error: String(err) });
|
|
363
|
+
continue;
|
|
364
|
+
}
|
|
351
365
|
const activeAddresses = await chargeStore.listActiveDepositAddresses();
|
|
352
366
|
const chainAddresses = activeAddresses.filter((a) => a.chain === method.chain).map((a) => a.address);
|
|
353
367
|
const watcher = new EvmWatcher({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wopr-network/platform-core",
|
|
3
|
-
"version": "1.61.
|
|
3
|
+
"version": "1.61.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -131,6 +131,7 @@
|
|
|
131
131
|
"dependencies": {
|
|
132
132
|
"@aws-sdk/client-ses": "^3.1014.0",
|
|
133
133
|
"@hono/node-server": "^1.19.11",
|
|
134
|
+
"@noble/curves": "^2.0.1",
|
|
134
135
|
"@noble/hashes": "^2.0.1",
|
|
135
136
|
"@scure/base": "^2.0.0",
|
|
136
137
|
"@scure/bip32": "^2.0.1",
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* - p2pkh: DOGE (D...), TRON (T...) — params: { version }
|
|
11
11
|
* - evm: ETH, ERC-20 (0x...) — params: {}
|
|
12
12
|
*/
|
|
13
|
+
import { secp256k1 } from "@noble/curves/secp256k1.js";
|
|
13
14
|
import { ripemd160 } from "@noble/hashes/legacy.js";
|
|
14
15
|
import { sha256 } from "@noble/hashes/sha2.js";
|
|
15
16
|
import { bech32 } from "@scure/base";
|
|
@@ -64,7 +65,14 @@ function encodeP2pkh(pubkey: Uint8Array, versionByte: number): string {
|
|
|
64
65
|
}
|
|
65
66
|
|
|
66
67
|
function encodeEvm(pubkey: Uint8Array): string {
|
|
67
|
-
|
|
68
|
+
// HDKey.publicKey is SEC1 compressed (33 bytes, 02/03 prefix).
|
|
69
|
+
// Ethereum addresses = keccak256(uncompressed_pubkey[1:]).slice(-20).
|
|
70
|
+
// viem's publicKeyToAddress expects uncompressed (65 bytes, 04 prefix).
|
|
71
|
+
// Decompress via secp256k1 point recovery before hashing.
|
|
72
|
+
const hexKey = Array.from(pubkey, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
73
|
+
const uncompressed = secp256k1.Point.fromHex(hexKey).toBytes(false);
|
|
74
|
+
const hexPubKey =
|
|
75
|
+
`0x${Array.from(uncompressed, (b: number) => b.toString(16).padStart(2, "0")).join("")}` as `0x${string}`;
|
|
68
76
|
return publicKeyToAddress(hexPubKey);
|
|
69
77
|
}
|
|
70
78
|
|
|
@@ -373,8 +373,14 @@ export async function startWatchers(opts: WatcherServiceOpts): Promise<() => voi
|
|
|
373
373
|
if (!method.rpcUrl) continue;
|
|
374
374
|
|
|
375
375
|
const rpcCall = createRpcCaller(method.rpcUrl);
|
|
376
|
-
|
|
377
|
-
|
|
376
|
+
let latestBlock: number;
|
|
377
|
+
try {
|
|
378
|
+
const latestHex = (await rpcCall("eth_blockNumber", [])) as string;
|
|
379
|
+
latestBlock = Number.parseInt(latestHex, 16);
|
|
380
|
+
} catch (err) {
|
|
381
|
+
log("Skipping ETH watcher — RPC unreachable", { chain: method.chain, token: method.token, error: String(err) });
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
378
384
|
const backfillStart = Math.max(0, latestBlock - BACKFILL_BLOCKS);
|
|
379
385
|
|
|
380
386
|
const activeAddresses = await chargeStore.listActiveDepositAddresses();
|
|
@@ -446,8 +452,14 @@ export async function startWatchers(opts: WatcherServiceOpts): Promise<() => voi
|
|
|
446
452
|
if (!method.rpcUrl || !method.contractAddress) continue;
|
|
447
453
|
|
|
448
454
|
const rpcCall = createRpcCaller(method.rpcUrl);
|
|
449
|
-
|
|
450
|
-
|
|
455
|
+
let latestBlock: number;
|
|
456
|
+
try {
|
|
457
|
+
const latestHex = (await rpcCall("eth_blockNumber", [])) as string;
|
|
458
|
+
latestBlock = Number.parseInt(latestHex, 16);
|
|
459
|
+
} catch (err) {
|
|
460
|
+
log("Skipping EVM watcher — RPC unreachable", { chain: method.chain, token: method.token, error: String(err) });
|
|
461
|
+
continue;
|
|
462
|
+
}
|
|
451
463
|
|
|
452
464
|
const activeAddresses = await chargeStore.listActiveDepositAddresses();
|
|
453
465
|
const chainAddresses = activeAddresses.filter((a) => a.chain === method.chain).map((a) => a.address);
|