@wopr-network/crypto-plugins 1.0.1
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/.github/workflows/ci.yml +33 -0
- package/.github/workflows/publish.yml +12 -0
- package/biome.json +23 -0
- package/dist/__tests__/bitcoin-encoder.test.d.ts +2 -0
- package/dist/__tests__/bitcoin-encoder.test.d.ts.map +1 -0
- package/dist/__tests__/bitcoin-encoder.test.js +97 -0
- package/dist/__tests__/bitcoin-encoder.test.js.map +1 -0
- package/dist/__tests__/dogecoin-encoder.test.d.ts +2 -0
- package/dist/__tests__/dogecoin-encoder.test.d.ts.map +1 -0
- package/dist/__tests__/dogecoin-encoder.test.js +57 -0
- package/dist/__tests__/dogecoin-encoder.test.js.map +1 -0
- package/dist/__tests__/litecoin-encoder.test.d.ts +2 -0
- package/dist/__tests__/litecoin-encoder.test.d.ts.map +1 -0
- package/dist/__tests__/litecoin-encoder.test.js +44 -0
- package/dist/__tests__/litecoin-encoder.test.js.map +1 -0
- package/dist/__tests__/registry.test.d.ts +2 -0
- package/dist/__tests__/registry.test.d.ts.map +1 -0
- package/dist/__tests__/registry.test.js +75 -0
- package/dist/__tests__/registry.test.js.map +1 -0
- package/dist/__tests__/rpc.test.d.ts +2 -0
- package/dist/__tests__/rpc.test.d.ts.map +1 -0
- package/dist/__tests__/rpc.test.js +31 -0
- package/dist/__tests__/rpc.test.js.map +1 -0
- package/dist/__tests__/solana-encoder.test.d.ts +2 -0
- package/dist/__tests__/solana-encoder.test.d.ts.map +1 -0
- package/dist/__tests__/solana-encoder.test.js +85 -0
- package/dist/__tests__/solana-encoder.test.js.map +1 -0
- package/dist/__tests__/solana-watcher.test.d.ts +2 -0
- package/dist/__tests__/solana-watcher.test.d.ts.map +1 -0
- package/dist/__tests__/solana-watcher.test.js +281 -0
- package/dist/__tests__/solana-watcher.test.js.map +1 -0
- package/dist/__tests__/sweep-key-parity.test.d.ts +2 -0
- package/dist/__tests__/sweep-key-parity.test.d.ts.map +1 -0
- package/dist/__tests__/sweep-key-parity.test.js +236 -0
- package/dist/__tests__/sweep-key-parity.test.js.map +1 -0
- package/dist/__tests__/tron-encoder.test.d.ts +2 -0
- package/dist/__tests__/tron-encoder.test.d.ts.map +1 -0
- package/dist/__tests__/tron-encoder.test.js +93 -0
- package/dist/__tests__/tron-encoder.test.js.map +1 -0
- package/dist/__tests__/utxo-watcher.test.d.ts +2 -0
- package/dist/__tests__/utxo-watcher.test.d.ts.map +1 -0
- package/dist/__tests__/utxo-watcher.test.js +218 -0
- package/dist/__tests__/utxo-watcher.test.js.map +1 -0
- package/dist/bitcoin/encoder.d.ts +15 -0
- package/dist/bitcoin/encoder.d.ts.map +1 -0
- package/dist/bitcoin/encoder.js +286 -0
- package/dist/bitcoin/encoder.js.map +1 -0
- package/dist/bitcoin/index.d.ts +4 -0
- package/dist/bitcoin/index.d.ts.map +1 -0
- package/dist/bitcoin/index.js +20 -0
- package/dist/bitcoin/index.js.map +1 -0
- package/dist/dogecoin/encoder.d.ts +19 -0
- package/dist/dogecoin/encoder.d.ts.map +1 -0
- package/dist/dogecoin/encoder.js +145 -0
- package/dist/dogecoin/encoder.js.map +1 -0
- package/dist/dogecoin/index.d.ts +4 -0
- package/dist/dogecoin/index.d.ts.map +1 -0
- package/dist/dogecoin/index.js +20 -0
- package/dist/dogecoin/index.js.map +1 -0
- package/dist/evm/encoder.d.ts +7 -0
- package/dist/evm/encoder.d.ts.map +1 -0
- package/dist/evm/encoder.js +43 -0
- package/dist/evm/encoder.js.map +1 -0
- package/dist/evm/eth-watcher.d.ts +38 -0
- package/dist/evm/eth-watcher.d.ts.map +1 -0
- package/dist/evm/eth-watcher.js +138 -0
- package/dist/evm/eth-watcher.js.map +1 -0
- package/dist/evm/index.d.ts +16 -0
- package/dist/evm/index.d.ts.map +1 -0
- package/dist/evm/index.js +34 -0
- package/dist/evm/index.js.map +1 -0
- package/dist/evm/types.d.ts +43 -0
- package/dist/evm/types.d.ts.map +1 -0
- package/dist/evm/types.js +101 -0
- package/dist/evm/types.js.map +1 -0
- package/dist/evm/watcher.d.ts +42 -0
- package/dist/evm/watcher.d.ts.map +1 -0
- package/dist/evm/watcher.js +162 -0
- package/dist/evm/watcher.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/litecoin/encoder.d.ts +8 -0
- package/dist/litecoin/encoder.d.ts.map +1 -0
- package/dist/litecoin/encoder.js +16 -0
- package/dist/litecoin/encoder.js.map +1 -0
- package/dist/litecoin/index.d.ts +4 -0
- package/dist/litecoin/index.d.ts.map +1 -0
- package/dist/litecoin/index.js +20 -0
- package/dist/litecoin/index.js.map +1 -0
- package/dist/shared/test-helpers/index.d.ts +9 -0
- package/dist/shared/test-helpers/index.d.ts.map +1 -0
- package/dist/shared/test-helpers/index.js +30 -0
- package/dist/shared/test-helpers/index.js.map +1 -0
- package/dist/shared/utxo/index.d.ts +5 -0
- package/dist/shared/utxo/index.d.ts.map +1 -0
- package/dist/shared/utxo/index.js +3 -0
- package/dist/shared/utxo/index.js.map +1 -0
- package/dist/shared/utxo/rpc.d.ts +24 -0
- package/dist/shared/utxo/rpc.d.ts.map +1 -0
- package/dist/shared/utxo/rpc.js +75 -0
- package/dist/shared/utxo/rpc.js.map +1 -0
- package/dist/shared/utxo/types.d.ts +40 -0
- package/dist/shared/utxo/types.d.ts.map +1 -0
- package/dist/shared/utxo/types.js +2 -0
- package/dist/shared/utxo/types.js.map +1 -0
- package/dist/shared/utxo/watcher.d.ts +55 -0
- package/dist/shared/utxo/watcher.d.ts.map +1 -0
- package/dist/shared/utxo/watcher.js +150 -0
- package/dist/shared/utxo/watcher.js.map +1 -0
- package/dist/solana/encoder.d.ts +13 -0
- package/dist/solana/encoder.d.ts.map +1 -0
- package/dist/solana/encoder.js +62 -0
- package/dist/solana/encoder.js.map +1 -0
- package/dist/solana/index.d.ts +17 -0
- package/dist/solana/index.d.ts.map +1 -0
- package/dist/solana/index.js +32 -0
- package/dist/solana/index.js.map +1 -0
- package/dist/solana/sweeper.d.ts +47 -0
- package/dist/solana/sweeper.d.ts.map +1 -0
- package/dist/solana/sweeper.js +151 -0
- package/dist/solana/sweeper.js.map +1 -0
- package/dist/solana/types.d.ts +49 -0
- package/dist/solana/types.d.ts.map +1 -0
- package/dist/solana/types.js +2 -0
- package/dist/solana/types.js.map +1 -0
- package/dist/solana/watcher.d.ts +59 -0
- package/dist/solana/watcher.d.ts.map +1 -0
- package/dist/solana/watcher.js +251 -0
- package/dist/solana/watcher.js.map +1 -0
- package/dist/sweep/evm-sweeper.d.ts +31 -0
- package/dist/sweep/evm-sweeper.d.ts.map +1 -0
- package/dist/sweep/evm-sweeper.js +229 -0
- package/dist/sweep/evm-sweeper.js.map +1 -0
- package/dist/sweep/index.d.ts +22 -0
- package/dist/sweep/index.d.ts.map +1 -0
- package/dist/sweep/index.js +290 -0
- package/dist/sweep/index.js.map +1 -0
- package/dist/sweep/tron-sweeper.d.ts +40 -0
- package/dist/sweep/tron-sweeper.d.ts.map +1 -0
- package/dist/sweep/tron-sweeper.js +363 -0
- package/dist/sweep/tron-sweeper.js.map +1 -0
- package/dist/sweep/utxo-sweeper.d.ts +14 -0
- package/dist/sweep/utxo-sweeper.d.ts.map +1 -0
- package/dist/sweep/utxo-sweeper.js +13 -0
- package/dist/sweep/utxo-sweeper.js.map +1 -0
- package/dist/tron/address-convert.d.ts +15 -0
- package/dist/tron/address-convert.d.ts.map +1 -0
- package/dist/tron/address-convert.js +95 -0
- package/dist/tron/address-convert.js.map +1 -0
- package/dist/tron/encoder.d.ts +20 -0
- package/dist/tron/encoder.d.ts.map +1 -0
- package/dist/tron/encoder.js +67 -0
- package/dist/tron/encoder.js.map +1 -0
- package/dist/tron/index.d.ts +6 -0
- package/dist/tron/index.d.ts.map +1 -0
- package/dist/tron/index.js +20 -0
- package/dist/tron/index.js.map +1 -0
- package/dist/tron/sha256.d.ts +6 -0
- package/dist/tron/sha256.d.ts.map +1 -0
- package/dist/tron/sha256.js +90 -0
- package/dist/tron/sha256.js.map +1 -0
- package/dist/tron/watcher.d.ts +42 -0
- package/dist/tron/watcher.d.ts.map +1 -0
- package/dist/tron/watcher.js +168 -0
- package/dist/tron/watcher.js.map +1 -0
- package/package.json +47 -0
- package/src/__tests__/bitcoin-encoder.test.ts +115 -0
- package/src/__tests__/dogecoin-encoder.test.ts +66 -0
- package/src/__tests__/litecoin-encoder.test.ts +51 -0
- package/src/__tests__/registry.test.ts +91 -0
- package/src/__tests__/rpc.test.ts +36 -0
- package/src/__tests__/solana-encoder.test.ts +103 -0
- package/src/__tests__/solana-watcher.test.ts +316 -0
- package/src/__tests__/sweep-key-parity.test.ts +302 -0
- package/src/__tests__/tron-encoder.test.ts +108 -0
- package/src/__tests__/utxo-watcher.test.ts +252 -0
- package/src/bitcoin/encoder.ts +320 -0
- package/src/bitcoin/index.ts +23 -0
- package/src/dogecoin/encoder.ts +161 -0
- package/src/dogecoin/index.ts +23 -0
- package/src/evm/encoder.ts +49 -0
- package/src/evm/eth-watcher.ts +168 -0
- package/src/evm/index.ts +46 -0
- package/src/evm/types.ts +146 -0
- package/src/evm/watcher.ts +189 -0
- package/src/index.ts +21 -0
- package/src/litecoin/encoder.ts +18 -0
- package/src/litecoin/index.ts +23 -0
- package/src/shared/test-helpers/index.ts +36 -0
- package/src/shared/utxo/index.ts +12 -0
- package/src/shared/utxo/rpc.ts +80 -0
- package/src/shared/utxo/types.ts +43 -0
- package/src/shared/utxo/watcher.ts +195 -0
- package/src/solana/encoder.ts +72 -0
- package/src/solana/index.ts +36 -0
- package/src/solana/sweeper.ts +196 -0
- package/src/solana/types.ts +52 -0
- package/src/solana/watcher.ts +282 -0
- package/src/sweep/evm-sweeper.ts +296 -0
- package/src/sweep/index.ts +353 -0
- package/src/sweep/tron-sweeper.ts +467 -0
- package/src/sweep/utxo-sweeper.ts +23 -0
- package/src/tron/address-convert.ts +91 -0
- package/src/tron/encoder.ts +74 -0
- package/src/tron/index.ts +23 -0
- package/src/tron/sha256.ts +100 -0
- package/src/tron/watcher.ts +208 -0
- package/tsconfig.json +17 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tron/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAe,MAAM,2CAA2C,CAAC;AAK3F,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAC3E,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,eAAO,MAAM,UAAU,EAAE,YAaxB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { keccakB58Encoder } from "./encoder.js";
|
|
2
|
+
import { TronEvmWatcher } from "./watcher.js";
|
|
3
|
+
export { hexToTron, isTronAddress, tronToHex } from "./address-convert.js";
|
|
4
|
+
export { encodeKeccakB58Address, keccakB58Encoder } from "./encoder.js";
|
|
5
|
+
export { TronEvmWatcher } from "./watcher.js";
|
|
6
|
+
export const tronPlugin = {
|
|
7
|
+
pluginId: "tron",
|
|
8
|
+
supportedCurve: "secp256k1",
|
|
9
|
+
encoders: {
|
|
10
|
+
"keccak-b58check": keccakB58Encoder,
|
|
11
|
+
},
|
|
12
|
+
createWatcher(opts) {
|
|
13
|
+
return new TronEvmWatcher(opts);
|
|
14
|
+
},
|
|
15
|
+
createSweeper() {
|
|
16
|
+
throw new Error("Not implemented");
|
|
17
|
+
},
|
|
18
|
+
version: 1,
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tron/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAC3E,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,MAAM,CAAC,MAAM,UAAU,GAAiB;IACvC,QAAQ,EAAE,MAAM;IAChB,cAAc,EAAE,WAAW;IAC3B,QAAQ,EAAE;QACT,iBAAiB,EAAE,gBAAgB;KACnC;IACD,aAAa,CAAC,IAAiB;QAC9B,OAAO,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;IACD,aAAa;QACZ,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACpC,CAAC;IACD,OAAO,EAAE,CAAC;CACV,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sha256.d.ts","sourceRoot":"","sources":["../../src/tron/sha256.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,wBAAgB,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU,CA0FnD"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SHA-256 implementation (pure TypeScript).
|
|
3
|
+
* Shared within the tron module for encoder and address-convert.
|
|
4
|
+
*/
|
|
5
|
+
function ror32(x, n) {
|
|
6
|
+
return (x >>> n) | (x << (32 - n));
|
|
7
|
+
}
|
|
8
|
+
export function sha256(data) {
|
|
9
|
+
const K = [
|
|
10
|
+
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98,
|
|
11
|
+
0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
|
|
12
|
+
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8,
|
|
13
|
+
0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
|
14
|
+
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819,
|
|
15
|
+
0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
|
|
16
|
+
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7,
|
|
17
|
+
0xc67178f2,
|
|
18
|
+
];
|
|
19
|
+
const msgLen = data.length;
|
|
20
|
+
const bitLen = msgLen * 8;
|
|
21
|
+
const padLen = ((msgLen + 9 + 63) & ~63) - msgLen;
|
|
22
|
+
const padded = new Uint8Array(msgLen + padLen);
|
|
23
|
+
padded.set(data);
|
|
24
|
+
padded[msgLen] = 0x80;
|
|
25
|
+
const view = new DataView(padded.buffer);
|
|
26
|
+
view.setUint32(padded.length - 4, bitLen, false);
|
|
27
|
+
let h0 = 0x6a09e667;
|
|
28
|
+
let h1 = 0xbb67ae85;
|
|
29
|
+
let h2 = 0x3c6ef372;
|
|
30
|
+
let h3 = 0xa54ff53a;
|
|
31
|
+
let h4 = 0x510e527f;
|
|
32
|
+
let h5 = 0x9b05688c;
|
|
33
|
+
let h6 = 0x1f83d9ab;
|
|
34
|
+
let h7 = 0x5be0cd19;
|
|
35
|
+
const w = new Int32Array(64);
|
|
36
|
+
for (let offset = 0; offset < padded.length; offset += 64) {
|
|
37
|
+
for (let i = 0; i < 16; i++) {
|
|
38
|
+
w[i] = view.getInt32(offset + i * 4, false);
|
|
39
|
+
}
|
|
40
|
+
for (let i = 16; i < 64; i++) {
|
|
41
|
+
const s0 = (ror32(w[i - 15], 7) ^ ror32(w[i - 15], 18) ^ (w[i - 15] >>> 3)) | 0;
|
|
42
|
+
const s1 = (ror32(w[i - 2], 17) ^ ror32(w[i - 2], 19) ^ (w[i - 2] >>> 10)) | 0;
|
|
43
|
+
w[i] = (w[i - 16] + s0 + w[i - 7] + s1) | 0;
|
|
44
|
+
}
|
|
45
|
+
let a = h0;
|
|
46
|
+
let b = h1;
|
|
47
|
+
let c = h2;
|
|
48
|
+
let d = h3;
|
|
49
|
+
let e = h4;
|
|
50
|
+
let f = h5;
|
|
51
|
+
let g = h6;
|
|
52
|
+
let h = h7;
|
|
53
|
+
for (let i = 0; i < 64; i++) {
|
|
54
|
+
const S1 = (ror32(e, 6) ^ ror32(e, 11) ^ ror32(e, 25)) | 0;
|
|
55
|
+
const ch = ((e & f) ^ (~e & g)) | 0;
|
|
56
|
+
const temp1 = (h + S1 + ch + K[i] + w[i]) | 0;
|
|
57
|
+
const S0 = (ror32(a, 2) ^ ror32(a, 13) ^ ror32(a, 22)) | 0;
|
|
58
|
+
const maj = ((a & b) ^ (a & c) ^ (b & c)) | 0;
|
|
59
|
+
const temp2 = (S0 + maj) | 0;
|
|
60
|
+
h = g;
|
|
61
|
+
g = f;
|
|
62
|
+
f = e;
|
|
63
|
+
e = (d + temp1) | 0;
|
|
64
|
+
d = c;
|
|
65
|
+
c = b;
|
|
66
|
+
b = a;
|
|
67
|
+
a = (temp1 + temp2) | 0;
|
|
68
|
+
}
|
|
69
|
+
h0 = (h0 + a) | 0;
|
|
70
|
+
h1 = (h1 + b) | 0;
|
|
71
|
+
h2 = (h2 + c) | 0;
|
|
72
|
+
h3 = (h3 + d) | 0;
|
|
73
|
+
h4 = (h4 + e) | 0;
|
|
74
|
+
h5 = (h5 + f) | 0;
|
|
75
|
+
h6 = (h6 + g) | 0;
|
|
76
|
+
h7 = (h7 + h) | 0;
|
|
77
|
+
}
|
|
78
|
+
const result = new Uint8Array(32);
|
|
79
|
+
const rv = new DataView(result.buffer);
|
|
80
|
+
rv.setInt32(0, h0, false);
|
|
81
|
+
rv.setInt32(4, h1, false);
|
|
82
|
+
rv.setInt32(8, h2, false);
|
|
83
|
+
rv.setInt32(12, h3, false);
|
|
84
|
+
rv.setInt32(16, h4, false);
|
|
85
|
+
rv.setInt32(20, h5, false);
|
|
86
|
+
rv.setInt32(24, h6, false);
|
|
87
|
+
rv.setInt32(28, h7, false);
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=sha256.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sha256.js","sourceRoot":"","sources":["../../src/tron/sha256.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { IChainWatcher, PaymentEvent, WatcherOpts } from "@wopr-network/platform-core/crypto-plugin";
|
|
2
|
+
/**
|
|
3
|
+
* Tron EVM-compatible watcher.
|
|
4
|
+
*
|
|
5
|
+
* Tron exposes an EVM-compatible JSON-RPC endpoint that supports eth_getLogs.
|
|
6
|
+
* This watcher wraps the EVM watcher pattern but converts between Tron T...
|
|
7
|
+
* Base58Check addresses and 0x hex addresses at the boundary.
|
|
8
|
+
*
|
|
9
|
+
* - setWatchedAddresses: accepts T... addresses, converts to 0x hex for filtering
|
|
10
|
+
* - poll results: converts 0x hex addresses back to T... for PaymentEvent output
|
|
11
|
+
*/
|
|
12
|
+
export declare class TronEvmWatcher implements IChainWatcher {
|
|
13
|
+
private _cursor;
|
|
14
|
+
private _stopped;
|
|
15
|
+
private readonly chain;
|
|
16
|
+
private readonly token;
|
|
17
|
+
private readonly rpc;
|
|
18
|
+
private readonly confirmations;
|
|
19
|
+
private readonly contractAddress;
|
|
20
|
+
private readonly decimals;
|
|
21
|
+
private readonly cursorStore;
|
|
22
|
+
private readonly watcherId;
|
|
23
|
+
/** Hex addresses used for RPC filtering. */
|
|
24
|
+
private _watchedHexAddresses;
|
|
25
|
+
/** Map from lowercase hex -> original T... address for reverse lookup. */
|
|
26
|
+
private readonly _hexToTronMap;
|
|
27
|
+
constructor(opts: WatcherOpts);
|
|
28
|
+
init(): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Set watched addresses. Accepts Tron T... addresses.
|
|
31
|
+
* Converts to 0x hex internally for RPC filtering.
|
|
32
|
+
*/
|
|
33
|
+
setWatchedAddresses(addresses: string[]): void;
|
|
34
|
+
getCursor(): number;
|
|
35
|
+
stop(): void;
|
|
36
|
+
/**
|
|
37
|
+
* Poll for TRC-20 Transfer events using the EVM-compatible JSON-RPC.
|
|
38
|
+
* Converts hex addresses in results back to Tron T... format.
|
|
39
|
+
*/
|
|
40
|
+
poll(): Promise<PaymentEvent[]>;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=watcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watcher.d.ts","sourceRoot":"","sources":["../../src/tron/watcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,aAAa,EAEb,YAAY,EACZ,WAAW,EACX,MAAM,2CAA2C,CAAC;AAkDnD;;;;;;;;;GASG;AACH,qBAAa,cAAe,YAAW,aAAa;IACnD,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAU;IAC9B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAsB;IAClD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,4CAA4C;IAC5C,OAAO,CAAC,oBAAoB,CAAgB;IAC5C,0EAA0E;IAC1E,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAkC;gBAEpD,IAAI,EAAE,WAAW;IAYvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAK3B;;;OAGG;IACH,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI;IAS9C,SAAS,IAAI,MAAM;IAInB,IAAI,IAAI,IAAI;IAIZ;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;CAoFrC"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { hexToTron, tronToHex } from "./address-convert.js";
|
|
2
|
+
const TRANSFER_TOPIC = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef";
|
|
3
|
+
/** Create a JSON-RPC caller for Tron's EVM-compatible endpoint. */
|
|
4
|
+
function createRpcCaller(rpcUrl, extraHeaders) {
|
|
5
|
+
let id = 0;
|
|
6
|
+
const headers = { "Content-Type": "application/json", ...extraHeaders };
|
|
7
|
+
return async (method, params) => {
|
|
8
|
+
const res = await fetch(rpcUrl, {
|
|
9
|
+
method: "POST",
|
|
10
|
+
headers,
|
|
11
|
+
body: JSON.stringify({ jsonrpc: "2.0", id: ++id, method, params }),
|
|
12
|
+
});
|
|
13
|
+
if (!res.ok) {
|
|
14
|
+
const body = await res.text().catch(() => "");
|
|
15
|
+
const hasApiKey = "TRON-PRO-API-KEY" in headers;
|
|
16
|
+
console.error(`[rpc] ${method} ${res.status} auth=${hasApiKey} url=${rpcUrl.replace(/apikey=[^&]+/, "apikey=***")} body=${body.slice(0, 200)}`);
|
|
17
|
+
throw new Error(`RPC ${method} failed: ${res.status}`);
|
|
18
|
+
}
|
|
19
|
+
const data = (await res.json());
|
|
20
|
+
if (data.error)
|
|
21
|
+
throw new Error(`RPC ${method} error: ${data.error.message}`);
|
|
22
|
+
return data.result;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Convert token raw amount (BigInt) to USD cents (integer).
|
|
27
|
+
* Stablecoins are 1:1 USD. Truncates fractional cents.
|
|
28
|
+
*/
|
|
29
|
+
function centsFromTokenAmount(rawAmount, decimals) {
|
|
30
|
+
return Number((rawAmount * 100n) / 10n ** BigInt(decimals));
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Tron EVM-compatible watcher.
|
|
34
|
+
*
|
|
35
|
+
* Tron exposes an EVM-compatible JSON-RPC endpoint that supports eth_getLogs.
|
|
36
|
+
* This watcher wraps the EVM watcher pattern but converts between Tron T...
|
|
37
|
+
* Base58Check addresses and 0x hex addresses at the boundary.
|
|
38
|
+
*
|
|
39
|
+
* - setWatchedAddresses: accepts T... addresses, converts to 0x hex for filtering
|
|
40
|
+
* - poll results: converts 0x hex addresses back to T... for PaymentEvent output
|
|
41
|
+
*/
|
|
42
|
+
export class TronEvmWatcher {
|
|
43
|
+
_cursor = 0;
|
|
44
|
+
_stopped = false;
|
|
45
|
+
chain;
|
|
46
|
+
token;
|
|
47
|
+
rpc;
|
|
48
|
+
confirmations;
|
|
49
|
+
contractAddress;
|
|
50
|
+
decimals;
|
|
51
|
+
cursorStore;
|
|
52
|
+
watcherId;
|
|
53
|
+
/** Hex addresses used for RPC filtering. */
|
|
54
|
+
_watchedHexAddresses = [];
|
|
55
|
+
/** Map from lowercase hex -> original T... address for reverse lookup. */
|
|
56
|
+
_hexToTronMap = new Map();
|
|
57
|
+
constructor(opts) {
|
|
58
|
+
this.chain = opts.chain;
|
|
59
|
+
this.token = opts.token;
|
|
60
|
+
this.rpc = createRpcCaller(opts.rpcUrl, opts.rpcHeaders);
|
|
61
|
+
this._cursor = 0;
|
|
62
|
+
this.confirmations = opts.confirmations;
|
|
63
|
+
this.contractAddress = (opts.contractAddress ?? "").toLowerCase();
|
|
64
|
+
this.decimals = opts.decimals;
|
|
65
|
+
this.cursorStore = opts.cursorStore;
|
|
66
|
+
this.watcherId = `tron:${opts.chain}:${opts.token}`;
|
|
67
|
+
}
|
|
68
|
+
async init() {
|
|
69
|
+
const saved = await this.cursorStore.get(this.watcherId);
|
|
70
|
+
if (saved !== null)
|
|
71
|
+
this._cursor = saved;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Set watched addresses. Accepts Tron T... addresses.
|
|
75
|
+
* Converts to 0x hex internally for RPC filtering.
|
|
76
|
+
*/
|
|
77
|
+
setWatchedAddresses(addresses) {
|
|
78
|
+
this._hexToTronMap.clear();
|
|
79
|
+
this._watchedHexAddresses = addresses.map((addr) => {
|
|
80
|
+
const hex = tronToHex(addr).toLowerCase();
|
|
81
|
+
this._hexToTronMap.set(hex, addr);
|
|
82
|
+
return hex;
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
getCursor() {
|
|
86
|
+
return this._cursor;
|
|
87
|
+
}
|
|
88
|
+
stop() {
|
|
89
|
+
this._stopped = true;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Poll for TRC-20 Transfer events using the EVM-compatible JSON-RPC.
|
|
93
|
+
* Converts hex addresses in results back to Tron T... format.
|
|
94
|
+
*/
|
|
95
|
+
async poll() {
|
|
96
|
+
if (this._stopped || this._watchedHexAddresses.length === 0)
|
|
97
|
+
return [];
|
|
98
|
+
const latestHex = (await this.rpc("eth_blockNumber", []));
|
|
99
|
+
const latest = Number.parseInt(latestHex, 16);
|
|
100
|
+
const confirmed = latest - this.confirmations;
|
|
101
|
+
if (latest < this._cursor)
|
|
102
|
+
return [];
|
|
103
|
+
// Filter by topic[2] (to address) using hex addresses
|
|
104
|
+
const toFilter = this._watchedHexAddresses.length > 0
|
|
105
|
+
? this._watchedHexAddresses.map((a) => `0x000000000000000000000000${a.slice(2)}`)
|
|
106
|
+
: null;
|
|
107
|
+
const logs = (await this.rpc("eth_getLogs", [
|
|
108
|
+
{
|
|
109
|
+
address: this.contractAddress,
|
|
110
|
+
topics: [TRANSFER_TOPIC, null, toFilter],
|
|
111
|
+
fromBlock: `0x${this._cursor.toString(16)}`,
|
|
112
|
+
toBlock: `0x${latest.toString(16)}`,
|
|
113
|
+
},
|
|
114
|
+
]));
|
|
115
|
+
// Group logs by block
|
|
116
|
+
const logsByBlock = new Map();
|
|
117
|
+
for (const log of logs) {
|
|
118
|
+
const bn = Number.parseInt(log.blockNumber, 16);
|
|
119
|
+
const arr = logsByBlock.get(bn);
|
|
120
|
+
if (arr)
|
|
121
|
+
arr.push(log);
|
|
122
|
+
else
|
|
123
|
+
logsByBlock.set(bn, [log]);
|
|
124
|
+
}
|
|
125
|
+
const events = [];
|
|
126
|
+
const blockNums = [...logsByBlock.keys()].sort((a, b) => a - b);
|
|
127
|
+
for (const blockNum of blockNums) {
|
|
128
|
+
const confs = latest - blockNum;
|
|
129
|
+
for (const log of logsByBlock.get(blockNum) ?? []) {
|
|
130
|
+
const txKey = `${log.transactionHash}:${log.logIndex}`;
|
|
131
|
+
const lastConf = await this.cursorStore.getConfirmationCount(this.watcherId, txKey);
|
|
132
|
+
if (lastConf !== null && confs <= lastConf)
|
|
133
|
+
continue;
|
|
134
|
+
const toHex = `0x${log.topics[2].slice(26)}`.toLowerCase();
|
|
135
|
+
const fromHex = `0x${log.topics[1].slice(26)}`.toLowerCase();
|
|
136
|
+
const rawAmount = BigInt(log.data);
|
|
137
|
+
const amountUsdCents = centsFromTokenAmount(rawAmount, this.decimals);
|
|
138
|
+
// Convert hex addresses back to Tron T... format
|
|
139
|
+
const toTron = this._hexToTronMap.get(toHex) ?? hexToTron(toHex);
|
|
140
|
+
const fromTron = hexToTron(fromHex);
|
|
141
|
+
events.push({
|
|
142
|
+
chain: this.chain,
|
|
143
|
+
token: this.token,
|
|
144
|
+
from: fromTron,
|
|
145
|
+
to: toTron,
|
|
146
|
+
rawAmount: rawAmount.toString(),
|
|
147
|
+
amountUsdCents,
|
|
148
|
+
txHash: log.transactionHash,
|
|
149
|
+
blockNumber: blockNum,
|
|
150
|
+
confirmations: confs,
|
|
151
|
+
confirmationsRequired: this.confirmations,
|
|
152
|
+
});
|
|
153
|
+
await this.cursorStore.saveConfirmationCount(this.watcherId, txKey, confs);
|
|
154
|
+
}
|
|
155
|
+
if (blockNum <= confirmed) {
|
|
156
|
+
this._cursor = blockNum + 1;
|
|
157
|
+
await this.cursorStore.save(this.watcherId, this._cursor);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
// Advance cursor if no logs found but confirmed blocks exist
|
|
161
|
+
if (blockNums.length === 0 && confirmed >= this._cursor) {
|
|
162
|
+
this._cursor = confirmed + 1;
|
|
163
|
+
await this.cursorStore.save(this.watcherId, this._cursor);
|
|
164
|
+
}
|
|
165
|
+
return events;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=watcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watcher.js","sourceRoot":"","sources":["../../src/tron/watcher.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAc5D,MAAM,cAAc,GAAG,oEAAoE,CAAC;AAE5F,mEAAmE;AACnE,SAAS,eAAe,CAAC,MAAc,EAAE,YAAqC;IAC7E,IAAI,EAAE,GAAG,CAAC,CAAC;IACX,MAAM,OAAO,GAA2B,EAAE,cAAc,EAAE,kBAAkB,EAAE,GAAG,YAAY,EAAE,CAAC;IAChG,OAAO,KAAK,EAAE,MAAc,EAAE,MAAiB,EAAoB,EAAE;QACpE,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,MAAM,EAAE;YAC/B,MAAM,EAAE,MAAM;YACd,OAAO;YACP,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;SAClE,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACb,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YAC9C,MAAM,SAAS,GAAG,kBAAkB,IAAI,OAAO,CAAC;YAChD,OAAO,CAAC,KAAK,CACZ,SAAS,MAAM,IAAI,GAAG,CAAC,MAAM,SAAS,SAAS,QAAQ,MAAM,CAAC,OAAO,CAAC,cAAc,EAAE,YAAY,CAAC,SAAS,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAChI,CAAC;YACF,MAAM,IAAI,KAAK,CAAC,OAAO,MAAM,YAAY,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QACxD,CAAC;QACD,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAsD,CAAC;QACrF,IAAI,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,OAAO,MAAM,WAAW,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC9E,OAAO,IAAI,CAAC,MAAM,CAAC;IACpB,CAAC,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,oBAAoB,CAAC,SAAiB,EAAE,QAAgB;IAChE,OAAO,MAAM,CAAC,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,GAAG,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC7D,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,OAAO,cAAc;IAClB,OAAO,GAAG,CAAC,CAAC;IACZ,QAAQ,GAAG,KAAK,CAAC;IACR,KAAK,CAAS;IACd,KAAK,CAAS;IACd,GAAG,CAAU;IACb,aAAa,CAAS;IACtB,eAAe,CAAS;IACxB,QAAQ,CAAS;IACjB,WAAW,CAAsB;IACjC,SAAS,CAAS;IACnC,4CAA4C;IACpC,oBAAoB,GAAa,EAAE,CAAC;IAC5C,0EAA0E;IACzD,aAAa,GAAwB,IAAI,GAAG,EAAE,CAAC;IAEhE,YAAY,IAAiB;QAC5B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACxB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACxB,IAAI,CAAC,GAAG,GAAG,eAAe,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QACzD,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;QACjB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC;QACxC,IAAI,CAAC,eAAe,GAAG,CAAC,IAAI,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QAClE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC9B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;QACpC,IAAI,CAAC,SAAS,GAAG,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;IACrD,CAAC;IAED,KAAK,CAAC,IAAI;QACT,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACzD,IAAI,KAAK,KAAK,IAAI;YAAE,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;IAC1C,CAAC;IAED;;;OAGG;IACH,mBAAmB,CAAC,SAAmB;QACtC,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC;QAC3B,IAAI,CAAC,oBAAoB,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YAClD,MAAM,GAAG,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;YAC1C,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YAClC,OAAO,GAAG,CAAC;QACZ,CAAC,CAAC,CAAC;IACJ,CAAC;IAED,SAAS;QACR,OAAO,IAAI,CAAC,OAAO,CAAC;IACrB,CAAC;IAED,IAAI;QACH,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;IACtB,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,IAAI;QACT,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,oBAAoB,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAEvE,MAAM,SAAS,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAW,CAAC;QACpE,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QAC9C,MAAM,SAAS,GAAG,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC;QAE9C,IAAI,MAAM,GAAG,IAAI,CAAC,OAAO;YAAE,OAAO,EAAE,CAAC;QAErC,sDAAsD;QACtD,MAAM,QAAQ,GACb,IAAI,CAAC,oBAAoB,CAAC,MAAM,GAAG,CAAC;YACnC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,6BAA6B,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YACjF,CAAC,CAAC,IAAI,CAAC;QAET,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE;YAC3C;gBACC,OAAO,EAAE,IAAI,CAAC,eAAe;gBAC7B,MAAM,EAAE,CAAC,cAAc,EAAE,IAAI,EAAE,QAAQ,CAAC;gBACxC,SAAS,EAAE,KAAK,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE;gBAC3C,OAAO,EAAE,KAAK,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE;aACnC;SACD,CAAC,CAAa,CAAC;QAEhB,sBAAsB;QACtB,MAAM,WAAW,GAAG,IAAI,GAAG,EAAoB,CAAC;QAChD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACxB,MAAM,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;YAChD,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAChC,IAAI,GAAG;gBAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;;gBAClB,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QACjC,CAAC;QAED,MAAM,MAAM,GAAmB,EAAE,CAAC;QAElC,MAAM,SAAS,GAAG,CAAC,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAChE,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YAClC,MAAM,KAAK,GAAG,MAAM,GAAG,QAAQ,CAAC;YAEhC,KAAK,MAAM,GAAG,IAAI,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;gBACnD,MAAM,KAAK,GAAG,GAAG,GAAG,CAAC,eAAe,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;gBAEvD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,oBAAoB,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;gBACpF,IAAI,QAAQ,KAAK,IAAI,IAAI,KAAK,IAAI,QAAQ;oBAAE,SAAS;gBAErD,MAAM,KAAK,GAAG,KAAK,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC;gBAC3D,MAAM,OAAO,GAAG,KAAK,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC;gBAC7D,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBACnC,MAAM,cAAc,GAAG,oBAAoB,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAEtE,iDAAiD;gBACjD,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,SAAS,CAAC,KAAK,CAAC,CAAC;gBACjE,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;gBAEpC,MAAM,CAAC,IAAI,CAAC;oBACX,KAAK,EAAE,IAAI,CAAC,KAAK;oBACjB,KAAK,EAAE,IAAI,CAAC,KAAK;oBACjB,IAAI,EAAE,QAAQ;oBACd,EAAE,EAAE,MAAM;oBACV,SAAS,EAAE,SAAS,CAAC,QAAQ,EAAE;oBAC/B,cAAc;oBACd,MAAM,EAAE,GAAG,CAAC,eAAe;oBAC3B,WAAW,EAAE,QAAQ;oBACrB,aAAa,EAAE,KAAK;oBACpB,qBAAqB,EAAE,IAAI,CAAC,aAAa;iBACzC,CAAC,CAAC;gBAEH,MAAM,IAAI,CAAC,WAAW,CAAC,qBAAqB,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;YAC5E,CAAC;YAED,IAAI,QAAQ,IAAI,SAAS,EAAE,CAAC;gBAC3B,IAAI,CAAC,OAAO,GAAG,QAAQ,GAAG,CAAC,CAAC;gBAC5B,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YAC3D,CAAC;QACF,CAAC;QAED,6DAA6D;QAC7D,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,SAAS,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACzD,IAAI,CAAC,OAAO,GAAG,SAAS,GAAG,CAAC,CAAC;YAC7B,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAC3D,CAAC;QAED,OAAO,MAAM,CAAC;IACf,CAAC;CACD"}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wopr-network/crypto-plugins",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"packageManager": "pnpm@10.31.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"crypto-sweep": "dist/sweep/index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"test": "vitest run",
|
|
12
|
+
"lint": "biome check src/"
|
|
13
|
+
},
|
|
14
|
+
"exports": {
|
|
15
|
+
".": "./dist/index.js",
|
|
16
|
+
"./evm": "./dist/evm/index.js",
|
|
17
|
+
"./bitcoin": "./dist/bitcoin/index.js",
|
|
18
|
+
"./litecoin": "./dist/litecoin/index.js",
|
|
19
|
+
"./dogecoin": "./dist/dogecoin/index.js",
|
|
20
|
+
"./tron": "./dist/tron/index.js",
|
|
21
|
+
"./solana": "./dist/solana/index.js",
|
|
22
|
+
"./shared/utxo": "./dist/shared/utxo/index.js"
|
|
23
|
+
},
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"@wopr-network/platform-core": "*"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@biomejs/biome": "^2.4.8",
|
|
29
|
+
"@types/node": "^25.5.0",
|
|
30
|
+
"@wopr-network/platform-core": "^1.65.0",
|
|
31
|
+
"typescript": "^6.0.2",
|
|
32
|
+
"vitest": "^4.1.1"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@noble/curves": "^2.0.1",
|
|
36
|
+
"@noble/hashes": "^2.0.1",
|
|
37
|
+
"@scure/bip32": "^2.0.1",
|
|
38
|
+
"@scure/bip39": "^2.0.1",
|
|
39
|
+
"viem": "^2.30.0"
|
|
40
|
+
},
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public"
|
|
43
|
+
},
|
|
44
|
+
"release": {
|
|
45
|
+
"extends": "@wopr-network/semantic-release-config"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { bech32Encoder, encodeBech32Address, hash160 } from "../bitcoin/index.js";
|
|
4
|
+
|
|
5
|
+
describe("hash160", () => {
|
|
6
|
+
it("produces a 20-byte output", () => {
|
|
7
|
+
const input = new Uint8Array(33).fill(0x02);
|
|
8
|
+
const result = hash160(input);
|
|
9
|
+
expect(result).toBeInstanceOf(Uint8Array);
|
|
10
|
+
expect(result.length).toBe(20);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("is deterministic", () => {
|
|
14
|
+
const input = new Uint8Array([0x03, ...new Array(32).fill(0xab)]);
|
|
15
|
+
const a = hash160(input);
|
|
16
|
+
const b = hash160(input);
|
|
17
|
+
expect(Array.from(a)).toEqual(Array.from(b));
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("different inputs produce different hashes", () => {
|
|
21
|
+
const a = hash160(new Uint8Array(33).fill(0x02));
|
|
22
|
+
const b = hash160(new Uint8Array(33).fill(0x03));
|
|
23
|
+
expect(Array.from(a)).not.toEqual(Array.from(b));
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
describe("encodeBech32Address", () => {
|
|
28
|
+
it("produces a bc1q... address for mainnet BTC", () => {
|
|
29
|
+
// Use a known compressed public key (33 bytes starting with 02 or 03)
|
|
30
|
+
const pubkey = new Uint8Array(33);
|
|
31
|
+
pubkey[0] = 0x02;
|
|
32
|
+
for (let i = 1; i < 33; i++) pubkey[i] = i;
|
|
33
|
+
|
|
34
|
+
const address = encodeBech32Address(pubkey, "bc");
|
|
35
|
+
expect(address).toMatch(/^bc1q[a-z0-9]+$/);
|
|
36
|
+
// bech32 addresses are 42-62 chars for segwit v0
|
|
37
|
+
expect(address.length).toBeGreaterThanOrEqual(42);
|
|
38
|
+
expect(address.length).toBeLessThanOrEqual(62);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("produces ltc1q... for Litecoin", () => {
|
|
42
|
+
const pubkey = new Uint8Array(33);
|
|
43
|
+
pubkey[0] = 0x03;
|
|
44
|
+
for (let i = 1; i < 33; i++) pubkey[i] = 0xff - i;
|
|
45
|
+
|
|
46
|
+
const address = encodeBech32Address(pubkey, "ltc");
|
|
47
|
+
expect(address).toMatch(/^ltc1q[a-z0-9]+$/);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("produces tb1q... for testnet BTC", () => {
|
|
51
|
+
const pubkey = new Uint8Array(33);
|
|
52
|
+
pubkey[0] = 0x02;
|
|
53
|
+
for (let i = 1; i < 33; i++) pubkey[i] = 0x42;
|
|
54
|
+
|
|
55
|
+
const address = encodeBech32Address(pubkey, "tb");
|
|
56
|
+
expect(address).toMatch(/^tb1q[a-z0-9]+$/);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("same pubkey + hrp always produces the same address", () => {
|
|
60
|
+
const pubkey = new Uint8Array(33);
|
|
61
|
+
pubkey[0] = 0x02;
|
|
62
|
+
pubkey.fill(0xde, 1);
|
|
63
|
+
|
|
64
|
+
const a = encodeBech32Address(pubkey, "bc");
|
|
65
|
+
const b = encodeBech32Address(pubkey, "bc");
|
|
66
|
+
expect(a).toBe(b);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("different pubkeys produce different addresses", () => {
|
|
70
|
+
const pub1 = new Uint8Array(33);
|
|
71
|
+
pub1[0] = 0x02;
|
|
72
|
+
pub1.fill(0x11, 1);
|
|
73
|
+
|
|
74
|
+
const pub2 = new Uint8Array(33);
|
|
75
|
+
pub2[0] = 0x02;
|
|
76
|
+
pub2.fill(0x22, 1);
|
|
77
|
+
|
|
78
|
+
const a = encodeBech32Address(pub1, "bc");
|
|
79
|
+
const b = encodeBech32Address(pub2, "bc");
|
|
80
|
+
expect(a).not.toBe(b);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
describe("bech32Encoder (IAddressEncoder)", () => {
|
|
85
|
+
it("encodingType returns 'bech32'", () => {
|
|
86
|
+
expect(bech32Encoder.encodingType()).toBe("bech32");
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("encode with hrp param produces correct prefix", () => {
|
|
90
|
+
const pubkey = new Uint8Array(33);
|
|
91
|
+
pubkey[0] = 0x02;
|
|
92
|
+
pubkey.fill(0xaa, 1);
|
|
93
|
+
|
|
94
|
+
const addr = bech32Encoder.encode(pubkey, { hrp: "bc" });
|
|
95
|
+
expect(addr).toMatch(/^bc1q/);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("encode defaults to bc (mainnet) when hrp not provided", () => {
|
|
99
|
+
const pubkey = new Uint8Array(33);
|
|
100
|
+
pubkey[0] = 0x03;
|
|
101
|
+
pubkey.fill(0xbb, 1);
|
|
102
|
+
|
|
103
|
+
const addr = bech32Encoder.encode(pubkey, {});
|
|
104
|
+
expect(addr).toMatch(/^bc1q/);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("encode with ltc hrp produces ltc1q address", () => {
|
|
108
|
+
const pubkey = new Uint8Array(33);
|
|
109
|
+
pubkey[0] = 0x02;
|
|
110
|
+
pubkey.fill(0xcc, 1);
|
|
111
|
+
|
|
112
|
+
const addr = bech32Encoder.encode(pubkey, { hrp: "ltc" });
|
|
113
|
+
expect(addr).toMatch(/^ltc1q/);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { HDKey } from "@scure/bip32";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { encodeP2pkhAddress, p2pkhEncoder } from "../dogecoin/encoder.js";
|
|
4
|
+
|
|
5
|
+
const TEST_XPUB =
|
|
6
|
+
"xpub6BnqJwdqnXEZdkynN5CsrYZr3MULY933SdLrswFfKPDFandTXPQDWY225FveTPUJXS8D91Ddp7FEfaGrvVxuMBGQsyoBYRLu6VMB3Ni2H2Z";
|
|
7
|
+
|
|
8
|
+
function derivePublicKey(xpub: string, index: number): Uint8Array {
|
|
9
|
+
const master = HDKey.fromExtendedKey(xpub);
|
|
10
|
+
const child = master.deriveChild(0).deriveChild(index);
|
|
11
|
+
if (!child.publicKey) throw new Error("Failed to derive public key");
|
|
12
|
+
return child.publicKey;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
describe("Dogecoin P2PKH encoder", () => {
|
|
16
|
+
it("produces D... addresses with default version byte 0x1e", () => {
|
|
17
|
+
const pubkey = derivePublicKey(TEST_XPUB, 0);
|
|
18
|
+
const address = p2pkhEncoder.encode(pubkey, {});
|
|
19
|
+
expect(address).toMatch(/^D[1-9A-HJ-NP-Za-km-z]+$/);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("produces different addresses for different indices", () => {
|
|
23
|
+
const addr0 = p2pkhEncoder.encode(derivePublicKey(TEST_XPUB, 0), {});
|
|
24
|
+
const addr1 = p2pkhEncoder.encode(derivePublicKey(TEST_XPUB, 1), {});
|
|
25
|
+
expect(addr0).not.toBe(addr1);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("produces consistent results for the same key", () => {
|
|
29
|
+
const pubkey = derivePublicKey(TEST_XPUB, 0);
|
|
30
|
+
const addr1 = p2pkhEncoder.encode(pubkey, {});
|
|
31
|
+
const addr2 = p2pkhEncoder.encode(pubkey, {});
|
|
32
|
+
expect(addr1).toBe(addr2);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("respects custom version param", () => {
|
|
36
|
+
const pubkey = derivePublicKey(TEST_XPUB, 0);
|
|
37
|
+
// Version byte 0x00 = Bitcoin mainnet P2PKH (starts with 1)
|
|
38
|
+
const btcAddr = p2pkhEncoder.encode(pubkey, { version: "0" });
|
|
39
|
+
expect(btcAddr).toMatch(/^1[1-9A-HJ-NP-Za-km-z]+$/);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("address length is 33-34 characters for DOGE", () => {
|
|
43
|
+
const pubkey = derivePublicKey(TEST_XPUB, 0);
|
|
44
|
+
const address = p2pkhEncoder.encode(pubkey, {});
|
|
45
|
+
// P2PKH addresses are typically 25-34 chars, DOGE mainnet usually 34
|
|
46
|
+
expect(address.length).toBeGreaterThanOrEqual(25);
|
|
47
|
+
expect(address.length).toBeLessThanOrEqual(34);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("encodeP2pkhAddress function works directly", () => {
|
|
51
|
+
const pubkey = derivePublicKey(TEST_XPUB, 0);
|
|
52
|
+
const address = encodeP2pkhAddress(pubkey, 0x1e);
|
|
53
|
+
expect(address).toMatch(/^D/);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("reports encoding type as p2pkh", () => {
|
|
57
|
+
expect(p2pkhEncoder.encodingType()).toBe("p2pkh");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("DOGE addresses only contain valid Base58 characters", () => {
|
|
61
|
+
const pubkey = derivePublicKey(TEST_XPUB, 0);
|
|
62
|
+
const address = p2pkhEncoder.encode(pubkey, {});
|
|
63
|
+
// Base58 excludes 0, O, I, l
|
|
64
|
+
expect(address).not.toMatch(/[0OIl]/);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { HDKey } from "@scure/bip32";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { bech32Encoder } from "../litecoin/encoder.js";
|
|
4
|
+
|
|
5
|
+
const TEST_XPUB =
|
|
6
|
+
"xpub6BnqJwdqnXEZdkynN5CsrYZr3MULY933SdLrswFfKPDFandTXPQDWY225FveTPUJXS8D91Ddp7FEfaGrvVxuMBGQsyoBYRLu6VMB3Ni2H2Z";
|
|
7
|
+
|
|
8
|
+
function derivePublicKey(xpub: string, index: number): Uint8Array {
|
|
9
|
+
const master = HDKey.fromExtendedKey(xpub);
|
|
10
|
+
const child = master.deriveChild(0).deriveChild(index);
|
|
11
|
+
if (!child.publicKey) throw new Error("Failed to derive public key");
|
|
12
|
+
return child.publicKey;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
describe("Litecoin bech32 encoder", () => {
|
|
16
|
+
it("produces ltc1q... addresses", () => {
|
|
17
|
+
const pubkey = derivePublicKey(TEST_XPUB, 0);
|
|
18
|
+
const address = bech32Encoder.encode(pubkey, {});
|
|
19
|
+
expect(address).toMatch(/^ltc1q[a-z0-9]{38,42}$/);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("produces different addresses for different indices", () => {
|
|
23
|
+
const addr0 = bech32Encoder.encode(derivePublicKey(TEST_XPUB, 0), {});
|
|
24
|
+
const addr1 = bech32Encoder.encode(derivePublicKey(TEST_XPUB, 1), {});
|
|
25
|
+
expect(addr0).not.toBe(addr1);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("produces consistent results for the same key", () => {
|
|
29
|
+
const pubkey = derivePublicKey(TEST_XPUB, 0);
|
|
30
|
+
const addr1 = bech32Encoder.encode(pubkey, {});
|
|
31
|
+
const addr2 = bech32Encoder.encode(pubkey, {});
|
|
32
|
+
expect(addr1).toBe(addr2);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("respects custom hrp param", () => {
|
|
36
|
+
const pubkey = derivePublicKey(TEST_XPUB, 0);
|
|
37
|
+
const testnetAddr = bech32Encoder.encode(pubkey, { hrp: "tltc" });
|
|
38
|
+
expect(testnetAddr).toMatch(/^tltc1q/);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("reports encoding type as bech32", () => {
|
|
42
|
+
expect(bech32Encoder.encodingType()).toBe("bech32");
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("address length is 43 characters (ltc1q + 38 chars for 20-byte witness)", () => {
|
|
46
|
+
const pubkey = derivePublicKey(TEST_XPUB, 0);
|
|
47
|
+
const address = bech32Encoder.encode(pubkey, {});
|
|
48
|
+
// ltc1q... bech32 addresses for 20-byte programs are 43 chars
|
|
49
|
+
expect(address.length).toBe(43);
|
|
50
|
+
});
|
|
51
|
+
});
|