@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,33 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
build-lint-test:
|
|
11
|
+
runs-on: self-hosted
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
|
|
15
|
+
- uses: pnpm/action-setup@v4
|
|
16
|
+
with:
|
|
17
|
+
version: 9
|
|
18
|
+
|
|
19
|
+
- uses: actions/setup-node@v4
|
|
20
|
+
with:
|
|
21
|
+
node-version: 24
|
|
22
|
+
cache: pnpm
|
|
23
|
+
|
|
24
|
+
- run: pnpm install --frozen-lockfile
|
|
25
|
+
|
|
26
|
+
- name: Lint
|
|
27
|
+
run: npx biome check src/
|
|
28
|
+
|
|
29
|
+
- name: Build
|
|
30
|
+
run: pnpm build
|
|
31
|
+
|
|
32
|
+
- name: Test
|
|
33
|
+
run: pnpm test
|
package/biome.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://biomejs.dev/schemas/2.4.8/schema.json",
|
|
3
|
+
"formatter": {
|
|
4
|
+
"indentStyle": "tab",
|
|
5
|
+
"lineWidth": 120
|
|
6
|
+
},
|
|
7
|
+
"linter": {
|
|
8
|
+
"enabled": true,
|
|
9
|
+
"rules": {
|
|
10
|
+
"recommended": true,
|
|
11
|
+
"style": {
|
|
12
|
+
"noNonNullAssertion": "warn"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"assist": {
|
|
17
|
+
"actions": {
|
|
18
|
+
"source": {
|
|
19
|
+
"organizeImports": "on"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bitcoin-encoder.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/bitcoin-encoder.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { bech32Encoder, encodeBech32Address, hash160 } from "../bitcoin/index.js";
|
|
3
|
+
describe("hash160", () => {
|
|
4
|
+
it("produces a 20-byte output", () => {
|
|
5
|
+
const input = new Uint8Array(33).fill(0x02);
|
|
6
|
+
const result = hash160(input);
|
|
7
|
+
expect(result).toBeInstanceOf(Uint8Array);
|
|
8
|
+
expect(result.length).toBe(20);
|
|
9
|
+
});
|
|
10
|
+
it("is deterministic", () => {
|
|
11
|
+
const input = new Uint8Array([0x03, ...new Array(32).fill(0xab)]);
|
|
12
|
+
const a = hash160(input);
|
|
13
|
+
const b = hash160(input);
|
|
14
|
+
expect(Array.from(a)).toEqual(Array.from(b));
|
|
15
|
+
});
|
|
16
|
+
it("different inputs produce different hashes", () => {
|
|
17
|
+
const a = hash160(new Uint8Array(33).fill(0x02));
|
|
18
|
+
const b = hash160(new Uint8Array(33).fill(0x03));
|
|
19
|
+
expect(Array.from(a)).not.toEqual(Array.from(b));
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
describe("encodeBech32Address", () => {
|
|
23
|
+
it("produces a bc1q... address for mainnet BTC", () => {
|
|
24
|
+
// Use a known compressed public key (33 bytes starting with 02 or 03)
|
|
25
|
+
const pubkey = new Uint8Array(33);
|
|
26
|
+
pubkey[0] = 0x02;
|
|
27
|
+
for (let i = 1; i < 33; i++)
|
|
28
|
+
pubkey[i] = i;
|
|
29
|
+
const address = encodeBech32Address(pubkey, "bc");
|
|
30
|
+
expect(address).toMatch(/^bc1q[a-z0-9]+$/);
|
|
31
|
+
// bech32 addresses are 42-62 chars for segwit v0
|
|
32
|
+
expect(address.length).toBeGreaterThanOrEqual(42);
|
|
33
|
+
expect(address.length).toBeLessThanOrEqual(62);
|
|
34
|
+
});
|
|
35
|
+
it("produces ltc1q... for Litecoin", () => {
|
|
36
|
+
const pubkey = new Uint8Array(33);
|
|
37
|
+
pubkey[0] = 0x03;
|
|
38
|
+
for (let i = 1; i < 33; i++)
|
|
39
|
+
pubkey[i] = 0xff - i;
|
|
40
|
+
const address = encodeBech32Address(pubkey, "ltc");
|
|
41
|
+
expect(address).toMatch(/^ltc1q[a-z0-9]+$/);
|
|
42
|
+
});
|
|
43
|
+
it("produces tb1q... for testnet BTC", () => {
|
|
44
|
+
const pubkey = new Uint8Array(33);
|
|
45
|
+
pubkey[0] = 0x02;
|
|
46
|
+
for (let i = 1; i < 33; i++)
|
|
47
|
+
pubkey[i] = 0x42;
|
|
48
|
+
const address = encodeBech32Address(pubkey, "tb");
|
|
49
|
+
expect(address).toMatch(/^tb1q[a-z0-9]+$/);
|
|
50
|
+
});
|
|
51
|
+
it("same pubkey + hrp always produces the same address", () => {
|
|
52
|
+
const pubkey = new Uint8Array(33);
|
|
53
|
+
pubkey[0] = 0x02;
|
|
54
|
+
pubkey.fill(0xde, 1);
|
|
55
|
+
const a = encodeBech32Address(pubkey, "bc");
|
|
56
|
+
const b = encodeBech32Address(pubkey, "bc");
|
|
57
|
+
expect(a).toBe(b);
|
|
58
|
+
});
|
|
59
|
+
it("different pubkeys produce different addresses", () => {
|
|
60
|
+
const pub1 = new Uint8Array(33);
|
|
61
|
+
pub1[0] = 0x02;
|
|
62
|
+
pub1.fill(0x11, 1);
|
|
63
|
+
const pub2 = new Uint8Array(33);
|
|
64
|
+
pub2[0] = 0x02;
|
|
65
|
+
pub2.fill(0x22, 1);
|
|
66
|
+
const a = encodeBech32Address(pub1, "bc");
|
|
67
|
+
const b = encodeBech32Address(pub2, "bc");
|
|
68
|
+
expect(a).not.toBe(b);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
describe("bech32Encoder (IAddressEncoder)", () => {
|
|
72
|
+
it("encodingType returns 'bech32'", () => {
|
|
73
|
+
expect(bech32Encoder.encodingType()).toBe("bech32");
|
|
74
|
+
});
|
|
75
|
+
it("encode with hrp param produces correct prefix", () => {
|
|
76
|
+
const pubkey = new Uint8Array(33);
|
|
77
|
+
pubkey[0] = 0x02;
|
|
78
|
+
pubkey.fill(0xaa, 1);
|
|
79
|
+
const addr = bech32Encoder.encode(pubkey, { hrp: "bc" });
|
|
80
|
+
expect(addr).toMatch(/^bc1q/);
|
|
81
|
+
});
|
|
82
|
+
it("encode defaults to bc (mainnet) when hrp not provided", () => {
|
|
83
|
+
const pubkey = new Uint8Array(33);
|
|
84
|
+
pubkey[0] = 0x03;
|
|
85
|
+
pubkey.fill(0xbb, 1);
|
|
86
|
+
const addr = bech32Encoder.encode(pubkey, {});
|
|
87
|
+
expect(addr).toMatch(/^bc1q/);
|
|
88
|
+
});
|
|
89
|
+
it("encode with ltc hrp produces ltc1q address", () => {
|
|
90
|
+
const pubkey = new Uint8Array(33);
|
|
91
|
+
pubkey[0] = 0x02;
|
|
92
|
+
pubkey.fill(0xcc, 1);
|
|
93
|
+
const addr = bech32Encoder.encode(pubkey, { hrp: "ltc" });
|
|
94
|
+
expect(addr).toMatch(/^ltc1q/);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
//# sourceMappingURL=bitcoin-encoder.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bitcoin-encoder.test.js","sourceRoot":"","sources":["../../src/__tests__/bitcoin-encoder.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dogecoin-encoder.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/dogecoin-encoder.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { HDKey } from "@scure/bip32";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { encodeP2pkhAddress, p2pkhEncoder } from "../dogecoin/encoder.js";
|
|
4
|
+
const TEST_XPUB = "xpub6BnqJwdqnXEZdkynN5CsrYZr3MULY933SdLrswFfKPDFandTXPQDWY225FveTPUJXS8D91Ddp7FEfaGrvVxuMBGQsyoBYRLu6VMB3Ni2H2Z";
|
|
5
|
+
function derivePublicKey(xpub, index) {
|
|
6
|
+
const master = HDKey.fromExtendedKey(xpub);
|
|
7
|
+
const child = master.deriveChild(0).deriveChild(index);
|
|
8
|
+
if (!child.publicKey)
|
|
9
|
+
throw new Error("Failed to derive public key");
|
|
10
|
+
return child.publicKey;
|
|
11
|
+
}
|
|
12
|
+
describe("Dogecoin P2PKH encoder", () => {
|
|
13
|
+
it("produces D... addresses with default version byte 0x1e", () => {
|
|
14
|
+
const pubkey = derivePublicKey(TEST_XPUB, 0);
|
|
15
|
+
const address = p2pkhEncoder.encode(pubkey, {});
|
|
16
|
+
expect(address).toMatch(/^D[1-9A-HJ-NP-Za-km-z]+$/);
|
|
17
|
+
});
|
|
18
|
+
it("produces different addresses for different indices", () => {
|
|
19
|
+
const addr0 = p2pkhEncoder.encode(derivePublicKey(TEST_XPUB, 0), {});
|
|
20
|
+
const addr1 = p2pkhEncoder.encode(derivePublicKey(TEST_XPUB, 1), {});
|
|
21
|
+
expect(addr0).not.toBe(addr1);
|
|
22
|
+
});
|
|
23
|
+
it("produces consistent results for the same key", () => {
|
|
24
|
+
const pubkey = derivePublicKey(TEST_XPUB, 0);
|
|
25
|
+
const addr1 = p2pkhEncoder.encode(pubkey, {});
|
|
26
|
+
const addr2 = p2pkhEncoder.encode(pubkey, {});
|
|
27
|
+
expect(addr1).toBe(addr2);
|
|
28
|
+
});
|
|
29
|
+
it("respects custom version param", () => {
|
|
30
|
+
const pubkey = derivePublicKey(TEST_XPUB, 0);
|
|
31
|
+
// Version byte 0x00 = Bitcoin mainnet P2PKH (starts with 1)
|
|
32
|
+
const btcAddr = p2pkhEncoder.encode(pubkey, { version: "0" });
|
|
33
|
+
expect(btcAddr).toMatch(/^1[1-9A-HJ-NP-Za-km-z]+$/);
|
|
34
|
+
});
|
|
35
|
+
it("address length is 33-34 characters for DOGE", () => {
|
|
36
|
+
const pubkey = derivePublicKey(TEST_XPUB, 0);
|
|
37
|
+
const address = p2pkhEncoder.encode(pubkey, {});
|
|
38
|
+
// P2PKH addresses are typically 25-34 chars, DOGE mainnet usually 34
|
|
39
|
+
expect(address.length).toBeGreaterThanOrEqual(25);
|
|
40
|
+
expect(address.length).toBeLessThanOrEqual(34);
|
|
41
|
+
});
|
|
42
|
+
it("encodeP2pkhAddress function works directly", () => {
|
|
43
|
+
const pubkey = derivePublicKey(TEST_XPUB, 0);
|
|
44
|
+
const address = encodeP2pkhAddress(pubkey, 0x1e);
|
|
45
|
+
expect(address).toMatch(/^D/);
|
|
46
|
+
});
|
|
47
|
+
it("reports encoding type as p2pkh", () => {
|
|
48
|
+
expect(p2pkhEncoder.encodingType()).toBe("p2pkh");
|
|
49
|
+
});
|
|
50
|
+
it("DOGE addresses only contain valid Base58 characters", () => {
|
|
51
|
+
const pubkey = derivePublicKey(TEST_XPUB, 0);
|
|
52
|
+
const address = p2pkhEncoder.encode(pubkey, {});
|
|
53
|
+
// Base58 excludes 0, O, I, l
|
|
54
|
+
expect(address).not.toMatch(/[0OIl]/);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
//# sourceMappingURL=dogecoin-encoder.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dogecoin-encoder.test.js","sourceRoot":"","sources":["../../src/__tests__/dogecoin-encoder.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"litecoin-encoder.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/litecoin-encoder.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { HDKey } from "@scure/bip32";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { bech32Encoder } from "../litecoin/encoder.js";
|
|
4
|
+
const TEST_XPUB = "xpub6BnqJwdqnXEZdkynN5CsrYZr3MULY933SdLrswFfKPDFandTXPQDWY225FveTPUJXS8D91Ddp7FEfaGrvVxuMBGQsyoBYRLu6VMB3Ni2H2Z";
|
|
5
|
+
function derivePublicKey(xpub, index) {
|
|
6
|
+
const master = HDKey.fromExtendedKey(xpub);
|
|
7
|
+
const child = master.deriveChild(0).deriveChild(index);
|
|
8
|
+
if (!child.publicKey)
|
|
9
|
+
throw new Error("Failed to derive public key");
|
|
10
|
+
return child.publicKey;
|
|
11
|
+
}
|
|
12
|
+
describe("Litecoin bech32 encoder", () => {
|
|
13
|
+
it("produces ltc1q... addresses", () => {
|
|
14
|
+
const pubkey = derivePublicKey(TEST_XPUB, 0);
|
|
15
|
+
const address = bech32Encoder.encode(pubkey, {});
|
|
16
|
+
expect(address).toMatch(/^ltc1q[a-z0-9]{38,42}$/);
|
|
17
|
+
});
|
|
18
|
+
it("produces different addresses for different indices", () => {
|
|
19
|
+
const addr0 = bech32Encoder.encode(derivePublicKey(TEST_XPUB, 0), {});
|
|
20
|
+
const addr1 = bech32Encoder.encode(derivePublicKey(TEST_XPUB, 1), {});
|
|
21
|
+
expect(addr0).not.toBe(addr1);
|
|
22
|
+
});
|
|
23
|
+
it("produces consistent results for the same key", () => {
|
|
24
|
+
const pubkey = derivePublicKey(TEST_XPUB, 0);
|
|
25
|
+
const addr1 = bech32Encoder.encode(pubkey, {});
|
|
26
|
+
const addr2 = bech32Encoder.encode(pubkey, {});
|
|
27
|
+
expect(addr1).toBe(addr2);
|
|
28
|
+
});
|
|
29
|
+
it("respects custom hrp param", () => {
|
|
30
|
+
const pubkey = derivePublicKey(TEST_XPUB, 0);
|
|
31
|
+
const testnetAddr = bech32Encoder.encode(pubkey, { hrp: "tltc" });
|
|
32
|
+
expect(testnetAddr).toMatch(/^tltc1q/);
|
|
33
|
+
});
|
|
34
|
+
it("reports encoding type as bech32", () => {
|
|
35
|
+
expect(bech32Encoder.encodingType()).toBe("bech32");
|
|
36
|
+
});
|
|
37
|
+
it("address length is 43 characters (ltc1q + 38 chars for 20-byte witness)", () => {
|
|
38
|
+
const pubkey = derivePublicKey(TEST_XPUB, 0);
|
|
39
|
+
const address = bech32Encoder.encode(pubkey, {});
|
|
40
|
+
// ltc1q... bech32 addresses for 20-byte programs are 43 chars
|
|
41
|
+
expect(address.length).toBe(43);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
//# sourceMappingURL=litecoin-encoder.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"litecoin-encoder.test.js","sourceRoot":"","sources":["../../src/__tests__/litecoin-encoder.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/registry.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { bitcoinPlugin, dogecoinPlugin, evmPlugin, litecoinPlugin, solanaPlugin, tronPlugin } from "../index.js";
|
|
3
|
+
const allPlugins = [evmPlugin, bitcoinPlugin, litecoinPlugin, dogecoinPlugin, tronPlugin, solanaPlugin];
|
|
4
|
+
/** Plugin IDs that have real createWatcher implementations. */
|
|
5
|
+
const implementedIds = new Set(["evm", "bitcoin", "litecoin", "dogecoin", "tron", "solana"]);
|
|
6
|
+
/** Plugin IDs that have real createSweeper implementations (don't throw on construction). */
|
|
7
|
+
const sweeperImplementedIds = new Set(["solana"]);
|
|
8
|
+
/** Plugins that still have stub watcher/sweeper implementations. */
|
|
9
|
+
const stubPlugins = allPlugins.filter((p) => !implementedIds.has(p.pluginId));
|
|
10
|
+
/** Plugins with real createWatcher implementations. */
|
|
11
|
+
const implementedPlugins = allPlugins.filter((p) => implementedIds.has(p.pluginId));
|
|
12
|
+
describe("Plugin registry", () => {
|
|
13
|
+
it("all plugins have unique pluginIds", () => {
|
|
14
|
+
const ids = allPlugins.map((p) => p.pluginId);
|
|
15
|
+
expect(new Set(ids).size).toBe(ids.length);
|
|
16
|
+
});
|
|
17
|
+
it("all plugins implement IChainPlugin shape", () => {
|
|
18
|
+
for (const plugin of allPlugins) {
|
|
19
|
+
expect(plugin.pluginId).toBeTypeOf("string");
|
|
20
|
+
expect(plugin.supportedCurve).toMatch(/^(secp256k1|ed25519)$/);
|
|
21
|
+
expect(plugin.encoders).toBeTypeOf("object");
|
|
22
|
+
expect(plugin.createWatcher).toBeTypeOf("function");
|
|
23
|
+
expect(plugin.createSweeper).toBeTypeOf("function");
|
|
24
|
+
expect(plugin.version).toBeTypeOf("number");
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
it("secp256k1 plugins: evm, bitcoin, litecoin, dogecoin, tron", () => {
|
|
28
|
+
const secp = allPlugins.filter((p) => p.supportedCurve === "secp256k1");
|
|
29
|
+
expect(secp.map((p) => p.pluginId).sort()).toEqual(["bitcoin", "dogecoin", "evm", "litecoin", "tron"]);
|
|
30
|
+
});
|
|
31
|
+
it("ed25519 plugins: solana", () => {
|
|
32
|
+
const ed = allPlugins.filter((p) => p.supportedCurve === "ed25519");
|
|
33
|
+
expect(ed.map((p) => p.pluginId)).toEqual(["solana"]);
|
|
34
|
+
});
|
|
35
|
+
it("stub createWatcher throws Not implemented", () => {
|
|
36
|
+
for (const plugin of stubPlugins) {
|
|
37
|
+
expect(() => plugin.createWatcher({})).toThrow("Not implemented");
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
it("implemented createWatcher does not throw", () => {
|
|
41
|
+
for (const plugin of implementedPlugins) {
|
|
42
|
+
expect(() => plugin.createWatcher({})).not.toThrow();
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
it("stub createSweeper throws Not implemented", () => {
|
|
46
|
+
const sweeperStubs = allPlugins.filter((p) => !sweeperImplementedIds.has(p.pluginId));
|
|
47
|
+
for (const plugin of sweeperStubs) {
|
|
48
|
+
expect(() => plugin.createSweeper({})).toThrow("Not implemented");
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
it("implemented createSweeper does not throw", () => {
|
|
52
|
+
const sweeperImpl = allPlugins.filter((p) => sweeperImplementedIds.has(p.pluginId));
|
|
53
|
+
for (const plugin of sweeperImpl) {
|
|
54
|
+
expect(() => plugin.createSweeper({})).not.toThrow();
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
it("evm plugin has evm encoder", () => {
|
|
58
|
+
expect(evmPlugin.encoders).toHaveProperty("evm");
|
|
59
|
+
expect(evmPlugin.encoders.evm.encodingType()).toBe("evm");
|
|
60
|
+
});
|
|
61
|
+
it("solana plugin has base58-solana encoder", () => {
|
|
62
|
+
expect(solanaPlugin.encoders).toHaveProperty("base58-solana");
|
|
63
|
+
expect(solanaPlugin.encoders["base58-solana"].encodingType()).toBe("base58-solana");
|
|
64
|
+
});
|
|
65
|
+
it("can build a registry map from plugins", () => {
|
|
66
|
+
const registry = new Map();
|
|
67
|
+
for (const plugin of allPlugins) {
|
|
68
|
+
registry.set(plugin.pluginId, plugin);
|
|
69
|
+
}
|
|
70
|
+
expect(registry.size).toBe(6);
|
|
71
|
+
expect(registry.get("evm")).toBe(evmPlugin);
|
|
72
|
+
expect(registry.get("solana")).toBe(solanaPlugin);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
//# sourceMappingURL=registry.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.test.js","sourceRoot":"","sources":["../../src/__tests__/registry.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/rpc.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { parseRpcUrl } from "../shared/utxo/rpc.js";
|
|
3
|
+
describe("parseRpcUrl", () => {
|
|
4
|
+
it("extracts credentials from URL with embedded auth", () => {
|
|
5
|
+
const result = parseRpcUrl("http://myuser:mypass@localhost:8332");
|
|
6
|
+
expect(result.rpcUser).toBe("myuser");
|
|
7
|
+
expect(result.rpcPassword).toBe("mypass");
|
|
8
|
+
expect(result.rpcUrl).toBe("http://localhost:8332");
|
|
9
|
+
});
|
|
10
|
+
it("handles URL-encoded credentials", () => {
|
|
11
|
+
const result = parseRpcUrl("http://user%40name:p%40ss@host:8332");
|
|
12
|
+
expect(result.rpcUser).toBe("user@name");
|
|
13
|
+
expect(result.rpcPassword).toBe("p@ss");
|
|
14
|
+
});
|
|
15
|
+
it("returns empty credentials for URL without auth", () => {
|
|
16
|
+
const result = parseRpcUrl("http://localhost:8332");
|
|
17
|
+
expect(result.rpcUser).toBe("");
|
|
18
|
+
expect(result.rpcPassword).toBe("");
|
|
19
|
+
expect(result.rpcUrl).toBe("http://localhost:8332");
|
|
20
|
+
});
|
|
21
|
+
it("strips trailing slash from parsed URL", () => {
|
|
22
|
+
const result = parseRpcUrl("http://user:pass@localhost:8332/");
|
|
23
|
+
expect(result.rpcUrl).toBe("http://localhost:8332");
|
|
24
|
+
});
|
|
25
|
+
it("handles non-URL strings gracefully", () => {
|
|
26
|
+
const result = parseRpcUrl("not-a-url");
|
|
27
|
+
expect(result.rpcUrl).toBe("not-a-url");
|
|
28
|
+
expect(result.rpcUser).toBe("");
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
//# sourceMappingURL=rpc.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc.test.js","sourceRoot":"","sources":["../../src/__tests__/rpc.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpD,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC5B,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC3D,MAAM,MAAM,GAAG,WAAW,CAAC,qCAAqC,CAAC,CAAC;QAClE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC1C,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QAC1C,MAAM,MAAM,GAAG,WAAW,CAAC,qCAAqC,CAAC,CAAC;QAClE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACzC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACzD,MAAM,MAAM,GAAG,WAAW,CAAC,uBAAuB,CAAC,CAAC;QACpD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAChC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACpC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAChD,MAAM,MAAM,GAAG,WAAW,CAAC,kCAAkC,CAAC,CAAC;QAC/D,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC7C,MAAM,MAAM,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"solana-encoder.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/solana-encoder.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { ed25519 } from "@noble/curves/ed25519.js";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { base58Encode, SolanaAddressEncoder } from "../solana/encoder.js";
|
|
4
|
+
describe("SolanaAddressEncoder", () => {
|
|
5
|
+
const encoder = new SolanaAddressEncoder();
|
|
6
|
+
it("encodingType returns base58-solana", () => {
|
|
7
|
+
expect(encoder.encodingType()).toBe("base58-solana");
|
|
8
|
+
});
|
|
9
|
+
it("encodes a known 32-byte pubkey to correct Base58 address", () => {
|
|
10
|
+
// All-ones pubkey (32 bytes of 0x01)
|
|
11
|
+
const pubkey = new Uint8Array(32).fill(1);
|
|
12
|
+
const address = encoder.encode(pubkey, {});
|
|
13
|
+
// Base58 encoding of 32 bytes of 0x01
|
|
14
|
+
expect(typeof address).toBe("string");
|
|
15
|
+
expect(address.length).toBeGreaterThanOrEqual(32);
|
|
16
|
+
expect(address.length).toBeLessThanOrEqual(44);
|
|
17
|
+
});
|
|
18
|
+
it("produces deterministic addresses", () => {
|
|
19
|
+
const pubkey = new Uint8Array(32);
|
|
20
|
+
pubkey[31] = 42;
|
|
21
|
+
const a1 = encoder.encode(pubkey, {});
|
|
22
|
+
const a2 = encoder.encode(pubkey, {});
|
|
23
|
+
expect(a1).toBe(a2);
|
|
24
|
+
});
|
|
25
|
+
it("rejects non-32-byte input", () => {
|
|
26
|
+
expect(() => encoder.encode(new Uint8Array(20), {})).toThrow("32-byte");
|
|
27
|
+
expect(() => encoder.encode(new Uint8Array(33), {})).toThrow("32-byte");
|
|
28
|
+
expect(() => encoder.encode(new Uint8Array(0), {})).toThrow("32-byte");
|
|
29
|
+
});
|
|
30
|
+
it("encodes all-zero pubkey with leading 1s", () => {
|
|
31
|
+
const pubkey = new Uint8Array(32); // all zeros
|
|
32
|
+
const address = encoder.encode(pubkey, {});
|
|
33
|
+
// Base58 encodes leading zero bytes as '1'
|
|
34
|
+
expect(address.startsWith("1")).toBe(true);
|
|
35
|
+
});
|
|
36
|
+
it("derives correct address from Ed25519 seed 0x00...01", () => {
|
|
37
|
+
// Create a 32-byte seed with last byte = 1
|
|
38
|
+
const seed = new Uint8Array(32);
|
|
39
|
+
seed[31] = 1;
|
|
40
|
+
// Derive Ed25519 public key from private key (seed)
|
|
41
|
+
const publicKey = ed25519.getPublicKey(seed);
|
|
42
|
+
expect(publicKey.length).toBe(32);
|
|
43
|
+
// Encode as Solana address
|
|
44
|
+
const address = encoder.encode(publicKey, {});
|
|
45
|
+
// Verify it's a valid Base58 string
|
|
46
|
+
expect(address).toMatch(/^[1-9A-HJ-NP-Za-km-z]+$/);
|
|
47
|
+
expect(address.length).toBeGreaterThanOrEqual(32);
|
|
48
|
+
expect(address.length).toBeLessThanOrEqual(44);
|
|
49
|
+
// The address should be the Base58 of the raw pubkey — verify round-trip
|
|
50
|
+
const reencoded = base58Encode(publicKey);
|
|
51
|
+
expect(address).toBe(reencoded);
|
|
52
|
+
});
|
|
53
|
+
it("derives correct address for well-known Ed25519 test vector", () => {
|
|
54
|
+
// Seed = 32 bytes of 0x00...01
|
|
55
|
+
const seed = new Uint8Array(32);
|
|
56
|
+
seed[31] = 1;
|
|
57
|
+
const publicKey = ed25519.getPublicKey(seed);
|
|
58
|
+
// The Ed25519 public key for private key [0..0, 1] is a known value.
|
|
59
|
+
// The Solana address is just the Base58 of this 32-byte key.
|
|
60
|
+
const address = encoder.encode(publicKey, {});
|
|
61
|
+
// Ed25519 pubkey for seed 0x00..01 = 4cb5abf6ad79fbf5abbccafcc269d85cd2651ed4b885b5869f241aedf0a5ba29
|
|
62
|
+
// (this is the compressed Y coordinate of the point)
|
|
63
|
+
const expectedPubkeyHex = "4cb5abf6ad79fbf5abbccafcc269d85cd2651ed4b885b5869f241aedf0a5ba29";
|
|
64
|
+
const expectedPubkey = new Uint8Array(32);
|
|
65
|
+
for (let i = 0; i < 32; i++) {
|
|
66
|
+
expectedPubkey[i] = Number.parseInt(expectedPubkeyHex.slice(i * 2, i * 2 + 2), 16);
|
|
67
|
+
}
|
|
68
|
+
expect(publicKey).toEqual(expectedPubkey);
|
|
69
|
+
// Now verify the Base58 encoding of this pubkey
|
|
70
|
+
const expectedAddress = base58Encode(expectedPubkey);
|
|
71
|
+
expect(address).toBe(expectedAddress);
|
|
72
|
+
});
|
|
73
|
+
it("base58Encode handles various byte patterns", () => {
|
|
74
|
+
// Single byte
|
|
75
|
+
const single = new Uint8Array([0xff]);
|
|
76
|
+
const encoded = base58Encode(single);
|
|
77
|
+
expect(encoded).toBe("5Q");
|
|
78
|
+
// Empty-ish: all zeros should give all '1's
|
|
79
|
+
const zeros = new Uint8Array(3);
|
|
80
|
+
expect(base58Encode(zeros)).toBe("111");
|
|
81
|
+
// Known value: [1] should give "2"
|
|
82
|
+
expect(base58Encode(new Uint8Array([1]))).toBe("2");
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
//# sourceMappingURL=solana-encoder.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"solana-encoder.test.js","sourceRoot":"","sources":["../../src/__tests__/solana-encoder.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"solana-watcher.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/solana-watcher.test.ts"],"names":[],"mappings":""}
|