@hexora/core 1.0.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.
@@ -0,0 +1,11 @@
1
+ import { NormalizedTransaction, ChainId } from "./types/index.js";
2
+ declare class TransactionCache {
3
+ private store;
4
+ private key;
5
+ get(address: string, chain: ChainId): NormalizedTransaction[] | null;
6
+ set(address: string, chain: ChainId, txs: NormalizedTransaction[]): void;
7
+ clear(): void;
8
+ }
9
+ export declare const txCache: TransactionCache;
10
+ export {};
11
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAUlE,cAAM,gBAAgB;IACpB,OAAO,CAAC,KAAK,CAAiC;IAE9C,OAAO,CAAC,GAAG;IAIX,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,qBAAqB,EAAE,GAAG,IAAI;IAUpE,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,qBAAqB,EAAE,GAAG,IAAI;IAOxE,KAAK,IAAI,IAAI;CAGd;AAED,eAAO,MAAM,OAAO,kBAAyB,CAAC"}
package/dist/cache.js ADDED
@@ -0,0 +1,31 @@
1
+ // In-memory session cache. Privacy-first — no persistence, clears on page unload.
2
+ const CACHE_TTL_MS = 5 * 60 * 1000;
3
+ class TransactionCache {
4
+ constructor() {
5
+ this.store = new Map();
6
+ }
7
+ key(address, chain) {
8
+ return `${chain}:${address.toLowerCase()}`;
9
+ }
10
+ get(address, chain) {
11
+ const entry = this.store.get(this.key(address, chain));
12
+ if (!entry)
13
+ return null;
14
+ if (Date.now() - entry.fetchedAt > CACHE_TTL_MS) {
15
+ this.store.delete(this.key(address, chain));
16
+ return null;
17
+ }
18
+ return entry.transactions;
19
+ }
20
+ set(address, chain, txs) {
21
+ this.store.set(this.key(address, chain), {
22
+ transactions: txs,
23
+ fetchedAt: Date.now(),
24
+ });
25
+ }
26
+ clear() {
27
+ this.store.clear();
28
+ }
29
+ }
30
+ export const txCache = new TransactionCache();
31
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAEA,kFAAkF;AAClF,MAAM,YAAY,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AAOnC,MAAM,gBAAgB;IAAtB;QACU,UAAK,GAAG,IAAI,GAAG,EAAsB,CAAC;IA0BhD,CAAC;IAxBS,GAAG,CAAC,OAAe,EAAE,KAAc;QACzC,OAAO,GAAG,KAAK,IAAI,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;IAC7C,CAAC;IAED,GAAG,CAAC,OAAe,EAAE,KAAc;QACjC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;QACvD,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,GAAG,YAAY,EAAE,CAAC;YAChD,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;YAC5C,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC,YAAY,CAAC;IAC5B,CAAC;IAED,GAAG,CAAC,OAAe,EAAE,KAAc,EAAE,GAA4B;QAC/D,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE;YACvC,YAAY,EAAE,GAAG;YACjB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC,CAAC;IACL,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;CACF;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,IAAI,gBAAgB,EAAE,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { ChainId, NormalizedTransaction, HistoryProvider } from "../types/index.js";
2
+ type ApiKeys = Record<string, string | undefined>;
3
+ export declare class DefaultHistoryProvider implements HistoryProvider {
4
+ private readonly apiKeys;
5
+ constructor(apiKeys?: ApiKeys);
6
+ getTransactions(address: string, chain: ChainId, limit: number): Promise<NormalizedTransaction[]>;
7
+ private getApiKey;
8
+ private fetchNormal;
9
+ private fetchToken;
10
+ }
11
+ export {};
12
+ //# sourceMappingURL=fetcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetcher.d.ts","sourceRoot":"","sources":["../../src/history/fetcher.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,OAAO,EACP,qBAAqB,EACrB,eAAe,EAChB,MAAM,mBAAmB,CAAC;AAe3B,KAAK,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAuBlD,qBAAa,sBAAuB,YAAW,eAAe;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,GAAE,OAAY;IAE5C,eAAe,CACnB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,qBAAqB,EAAE,CAAC;IAyBnC,OAAO,CAAC,SAAS;YASH,WAAW;YAyBX,UAAU;CAwBzB"}
@@ -0,0 +1,156 @@
1
+ const EXPLORER_CONFIG = {
2
+ ethereum: { baseUrl: "https://api.etherscan.io/api" },
3
+ bnb: { baseUrl: "https://api.bscscan.com/api" },
4
+ polygon: { baseUrl: "https://api.polygonscan.com/api" },
5
+ avalanche: { baseUrl: "https://api.snowtrace.io/api" },
6
+ arbitrum: { baseUrl: "https://api.arbiscan.io/api" },
7
+ optimism: { baseUrl: "https://api-optimistic.etherscan.io/api" },
8
+ };
9
+ // Works without API key (rate limited). Pass apiKeys for higher limits.
10
+ export class DefaultHistoryProvider {
11
+ constructor(apiKeys = {}) {
12
+ this.apiKeys = apiKeys;
13
+ }
14
+ async getTransactions(address, chain, limit) {
15
+ const config = EXPLORER_CONFIG[chain];
16
+ if (!config)
17
+ return [];
18
+ const key = this.getApiKey(chain);
19
+ const [normal, token] = await Promise.allSettled([
20
+ this.fetchNormal(config.baseUrl, address, limit, key),
21
+ this.fetchToken(config.baseUrl, address, limit, key),
22
+ ]);
23
+ const results = [];
24
+ if (normal.status === "fulfilled")
25
+ results.push(...normal.value);
26
+ if (token.status === "fulfilled")
27
+ results.push(...token.value);
28
+ const seen = new Set();
29
+ return results
30
+ .filter((tx) => {
31
+ if (seen.has(tx.hash))
32
+ return false;
33
+ seen.add(tx.hash);
34
+ return true;
35
+ })
36
+ .sort((a, b) => b.timestamp - a.timestamp)
37
+ .slice(0, limit);
38
+ }
39
+ getApiKey(chain) {
40
+ const map = {
41
+ ethereum: this.apiKeys["etherscan"],
42
+ bnb: this.apiKeys["bscscan"],
43
+ polygon: this.apiKeys["polygonscan"],
44
+ };
45
+ return map[chain] ?? "";
46
+ }
47
+ async fetchNormal(base, address, limit, key) {
48
+ const data = await fetchWithRetry(buildUrl(base, {
49
+ module: "account",
50
+ action: "txlist",
51
+ address,
52
+ startblock: "0",
53
+ endblock: "99999999",
54
+ page: "1",
55
+ offset: String(limit),
56
+ sort: "desc",
57
+ apikey: key,
58
+ }));
59
+ if (!data?.result || !Array.isArray(data.result))
60
+ return [];
61
+ return data.result.map((tx) => normalizeEVMTx(tx, address));
62
+ }
63
+ async fetchToken(base, address, limit, key) {
64
+ const data = await fetchWithRetry(buildUrl(base, {
65
+ module: "account",
66
+ action: "tokentx",
67
+ address,
68
+ startblock: "0",
69
+ endblock: "99999999",
70
+ page: "1",
71
+ offset: String(limit),
72
+ sort: "desc",
73
+ apikey: key,
74
+ }));
75
+ if (!data?.result || !Array.isArray(data.result))
76
+ return [];
77
+ return data.result.map((tx) => normalizeEVMTokenTx(tx, address));
78
+ }
79
+ }
80
+ // 0xe19c2253 — batch transfer(address[],address[],address[],uint256[])
81
+ // Real attack tx: 0x05c6e673787275bdff029723492a07f4d9aad9b0e4fbfb7ff95bfb12e641bd48
82
+ const BATCH_POISON_IDS = new Set(["0xe19c2253"]);
83
+ function normalizeEVMTx(tx, userAddress) {
84
+ const value = BigInt(tx.value || "0");
85
+ const methodId = tx.input?.slice(0, 10) ?? "0x";
86
+ return {
87
+ hash: tx.hash,
88
+ from: tx.from.toLowerCase(),
89
+ to: (tx.to || "").toLowerCase(),
90
+ value,
91
+ timestamp: Number(tx.timeStamp),
92
+ blockNumber: Number(tx.blockNumber),
93
+ isIncoming: tx.to?.toLowerCase() === userAddress.toLowerCase(),
94
+ contractAddress: tx.contractAddress || undefined,
95
+ methodId: methodId || undefined,
96
+ isZeroValue: value === 0n,
97
+ isBatchPoison: value === 0n && BATCH_POISON_IDS.has(methodId),
98
+ };
99
+ }
100
+ function normalizeEVMTokenTx(tx, userAddress) {
101
+ const tokenValue = BigInt(tx.value || "0");
102
+ return {
103
+ hash: tx.hash,
104
+ from: tx.from.toLowerCase(),
105
+ to: tx.to.toLowerCase(),
106
+ value: 0n,
107
+ tokenValue,
108
+ timestamp: Number(tx.timeStamp),
109
+ blockNumber: Number(tx.blockNumber),
110
+ isIncoming: tx.to.toLowerCase() === userAddress.toLowerCase(),
111
+ contractAddress: tx.contractAddress,
112
+ isZeroValue: tokenValue === 0n,
113
+ isBatchPoison: tokenValue === 0n,
114
+ };
115
+ }
116
+ function buildUrl(base, params) {
117
+ return (base +
118
+ "?" +
119
+ Object.entries(params)
120
+ .filter(([, v]) => v !== "")
121
+ .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)
122
+ .join("&"));
123
+ }
124
+ async function fetchWithRetry(url, retries = 2, delay = 1000) {
125
+ for (let i = 0; i <= retries; i++) {
126
+ try {
127
+ const res = await fetch(url, {
128
+ headers: { Accept: "application/json" },
129
+ signal: AbortSignal.timeout(8000),
130
+ });
131
+ if (!res.ok) {
132
+ if (res.status === 429 && i < retries) {
133
+ await sleep(delay * (i + 1));
134
+ continue;
135
+ }
136
+ return null;
137
+ }
138
+ const json = await res.json();
139
+ if (json?.status === "0" && json?.message !== "No transactions found")
140
+ return null;
141
+ return json;
142
+ }
143
+ catch {
144
+ if (i < retries) {
145
+ await sleep(delay);
146
+ continue;
147
+ }
148
+ return null;
149
+ }
150
+ }
151
+ return null;
152
+ }
153
+ function sleep(ms) {
154
+ return new Promise((r) => setTimeout(r, ms));
155
+ }
156
+ //# sourceMappingURL=fetcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetcher.js","sourceRoot":"","sources":["../../src/history/fetcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export type { ChainId, RiskLevel, ScamReason, ErrorCode, NormalizedTransaction, CheckError, EIP1193Provider, PhantomProvider, RawProvider, HexoraProvider, ProviderType, HistoryProvider, } from "./types/index.js";
2
+ export { EVM_CHAIN_MAP } from "./types/index.js";
3
+ export { detectProvider } from "./providers/detector.js";
4
+ export { txCache } from "./cache.js";
5
+ export { validateAddress } from "./validator.js";
6
+ export { calculateSimilarity, findMostSimilar } from "./similarity.js";
7
+ export { DefaultHistoryProvider } from "./history/fetcher.js";
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,OAAO,EACP,SAAS,EACT,UAAU,EACV,SAAS,EACT,qBAAqB,EACrB,UAAU,EACV,eAAe,EACf,eAAe,EACf,WAAW,EACX,cAAc,EACd,YAAY,EACZ,eAAe,GAChB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ export { EVM_CHAIN_MAP } from "./types/index.js";
2
+ export { detectProvider } from "./providers/detector.js";
3
+ export { txCache } from "./cache.js";
4
+ export { validateAddress } from "./validator.js";
5
+ export { calculateSimilarity, findMostSimilar } from "./similarity.js";
6
+ export { DefaultHistoryProvider } from "./history/fetcher.js";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { RawProvider, HexoraProvider } from "../types/index.js";
2
+ export declare function detectProvider(raw: RawProvider): HexoraProvider;
3
+ //# sourceMappingURL=detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detector.d.ts","sourceRoot":"","sources":["../../src/providers/detector.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EAGX,cAAc,EAKf,MAAM,mBAAmB,CAAC;AA6E3B,wBAAgB,cAAc,CAAC,GAAG,EAAE,WAAW,GAAG,cAAc,CAO/D"}
@@ -0,0 +1,79 @@
1
+ import { EVM_CHAIN_MAP, } from "../types/index.js";
2
+ function isEIP1193(p) {
3
+ return (typeof p === "object" &&
4
+ p !== null &&
5
+ "request" in p &&
6
+ typeof p.request === "function");
7
+ }
8
+ function isPhantom(p) {
9
+ return (typeof p === "object" &&
10
+ p !== null &&
11
+ ("isPhantom" in p || "publicKey" in p));
12
+ }
13
+ class EVMAdapter {
14
+ constructor(provider) {
15
+ this.provider = provider;
16
+ }
17
+ isEVM() {
18
+ return true;
19
+ }
20
+ getProviderType() {
21
+ return "eip1193";
22
+ }
23
+ async rawChainId() {
24
+ try {
25
+ const id = await this.provider.request({ method: "eth_chainId" });
26
+ return String(id);
27
+ }
28
+ catch {
29
+ try {
30
+ const v = await this.provider.request({ method: "net_version" });
31
+ return "0x" + Number(v).toString(16);
32
+ }
33
+ catch {
34
+ throw buildError("network_unavailable", "Failed to get chainId from provider");
35
+ }
36
+ }
37
+ }
38
+ async chainId() {
39
+ const raw = await this.rawChainId();
40
+ const hex = raw.startsWith("0x") ? raw : "0x" + Number(raw).toString(16);
41
+ const chain = EVM_CHAIN_MAP[hex];
42
+ if (!chain)
43
+ throw buildError("unsupported_chain", `Chain ${raw} is not supported yet`);
44
+ return chain;
45
+ }
46
+ }
47
+ class SolanaAdapter {
48
+ constructor(_provider) {
49
+ this._provider = _provider;
50
+ }
51
+ isEVM() {
52
+ return false;
53
+ }
54
+ getProviderType() {
55
+ return "phantom";
56
+ }
57
+ async rawChainId() {
58
+ return "solana-mainnet";
59
+ }
60
+ async chainId() {
61
+ return "solana";
62
+ }
63
+ }
64
+ // Auto-detects provider type and wraps into unified HexoraProvider.
65
+ // Supports all EIP-1193 wallets + Phantom.
66
+ // New chains (Bitcoin, Tron) — add adapter here, nothing else changes.
67
+ export function detectProvider(raw) {
68
+ if (isEIP1193(raw))
69
+ return new EVMAdapter(raw);
70
+ if (isPhantom(raw))
71
+ return new SolanaAdapter(raw);
72
+ throw buildError("unknown_provider", "Unknown provider. Must implement EIP-1193 or be Phantom-compatible.");
73
+ }
74
+ function buildError(code, message) {
75
+ const err = new Error(message);
76
+ err.hexoraCode = code;
77
+ return err;
78
+ }
79
+ //# sourceMappingURL=detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detector.js","sourceRoot":"","sources":["../../src/providers/detector.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,aAAa,GAEd,MAAM,mBAAmB,CAAC;AAE3B,SAAS,SAAS,CAAC,CAAU;IAC3B,OAAO,CACL,OAAO,CAAC,KAAK,QAAQ;QACrB,CAAC,KAAK,IAAI;QACV,SAAS,IAAI,CAAC;QACd,OAAQ,CAAqB,CAAC,OAAO,KAAK,UAAU,CACrD,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,CAAU;IAC3B,OAAO,CACL,OAAO,CAAC,KAAK,QAAQ;QACrB,CAAC,KAAK,IAAI;QACV,CAAC,WAAW,IAAI,CAAC,IAAI,WAAW,IAAI,CAAC,CAAC,CACvC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU;IACd,YAA6B,QAAyB;QAAzB,aAAQ,GAAR,QAAQ,CAAiB;IAAG,CAAC;IAC1D,KAAK;QACH,OAAO,IAAI,CAAC;IACd,CAAC;IACD,eAAe;QACb,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,UAAU;QACd,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;YAClE,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC;QACpB,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC;gBACH,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;gBACjE,OAAO,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;YACvC,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,UAAU,CACd,qBAAqB,EACrB,qCAAqC,CACtC,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAO;QACX,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;QACpC,MAAM,GAAG,GAAG,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QACzE,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,CAAC,KAAK;YACR,MAAM,UAAU,CACd,mBAAmB,EACnB,SAAS,GAAG,uBAAuB,CACpC,CAAC;QACJ,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AAED,MAAM,aAAa;IACjB,YAA6B,SAA0B;QAA1B,cAAS,GAAT,SAAS,CAAiB;IAAG,CAAC;IAC3D,KAAK;QACH,OAAO,KAAK,CAAC;IACf,CAAC;IACD,eAAe;QACb,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,KAAK,CAAC,UAAU;QACd,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IACD,KAAK,CAAC,OAAO;QACX,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF;AAED,oEAAoE;AACpE,2CAA2C;AAC3C,uEAAuE;AACvE,MAAM,UAAU,cAAc,CAAC,GAAgB;IAC7C,IAAI,SAAS,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC;IAC/C,IAAI,SAAS,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,aAAa,CAAC,GAAG,CAAC,CAAC;IAClD,MAAM,UAAU,CACd,kBAAkB,EAClB,qEAAqE,CACtE,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CACjB,IAAwB,EACxB,OAAe;IAEf,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,OAAO,CAA+C,CAAC;IAC7E,GAAG,CAAC,UAAU,GAAG,IAAI,CAAC;IACtB,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,10 @@
1
+ export declare function normalizeAddress(address: string): string;
2
+ export declare function calculateSimilarity(a: string, b: string): number;
3
+ export interface SimilarityMatch {
4
+ address: string;
5
+ similarityScore: number;
6
+ prefixMatch: boolean;
7
+ suffixMatch: boolean;
8
+ }
9
+ export declare function findMostSimilar(input: string, known: string[], threshold?: number): SimilarityMatch | null;
10
+ //# sourceMappingURL=similarity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"similarity.d.ts","sourceRoot":"","sources":["../src/similarity.ts"],"names":[],"mappings":"AAGA,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAWhE;AAoDD,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EAAE,EACf,SAAS,GAAE,MAAW,GACrB,eAAe,GAAG,IAAI,CAqBxB"}
@@ -0,0 +1,88 @@
1
+ // Weighted similarity: prefix 40% + suffix 40% + levenshtein 20%
2
+ // Mirrors attacker strategy: same first/last chars, different middle.
3
+ export function normalizeAddress(address) {
4
+ return address.toLowerCase();
5
+ }
6
+ export function calculateSimilarity(a, b) {
7
+ const na = normalizeAddress(a);
8
+ const nb = normalizeAddress(b);
9
+ if (na === nb)
10
+ return 100;
11
+ const bodyA = na.startsWith("0x") ? na.slice(2) : na;
12
+ const bodyB = nb.startsWith("0x") ? nb.slice(2) : nb;
13
+ return Math.round(prefixSimilarity(bodyA, bodyB, 6) * 0.4 +
14
+ suffixSimilarity(bodyA, bodyB, 6) * 0.4 +
15
+ levenshteinSimilarity(bodyA, bodyB) * 0.2);
16
+ }
17
+ function prefixSimilarity(a, b, len) {
18
+ const pa = a.slice(0, len);
19
+ const pb = b.slice(0, len);
20
+ let m = 0;
21
+ for (let i = 0; i < Math.min(pa.length, pb.length); i++) {
22
+ const ca = pa[i];
23
+ const cb = pb[i];
24
+ if (ca !== undefined && cb !== undefined && ca === cb)
25
+ m++;
26
+ }
27
+ return (m / len) * 100;
28
+ }
29
+ function suffixSimilarity(a, b, len) {
30
+ const sa = a.slice(-len);
31
+ const sb = b.slice(-len);
32
+ let m = 0;
33
+ for (let i = 0; i < Math.min(sa.length, sb.length); i++) {
34
+ const ca = sa[i];
35
+ const cb = sb[i];
36
+ if (ca !== undefined && cb !== undefined && ca === cb)
37
+ m++;
38
+ }
39
+ return (m / len) * 100;
40
+ }
41
+ function levenshteinSimilarity(a, b) {
42
+ const maxLen = Math.max(a.length, b.length);
43
+ if (maxLen === 0)
44
+ return 100;
45
+ return Math.round((1 - levenshteinDistance(a, b) / maxLen) * 100);
46
+ }
47
+ function levenshteinDistance(a, b) {
48
+ const n = b.length;
49
+ const dp = Array.from({ length: n + 1 }, (_, i) => i);
50
+ for (let i = 1; i <= a.length; i++) {
51
+ let prev = dp[0] ?? 0;
52
+ dp[0] = i;
53
+ for (let j = 1; j <= n; j++) {
54
+ const temp = dp[j] ?? 0;
55
+ const ai = a[i - 1];
56
+ const bj = b[j - 1];
57
+ dp[j] =
58
+ ai !== undefined && bj !== undefined && ai === bj
59
+ ? prev
60
+ : 1 + Math.min(prev, dp[j] ?? 0, dp[j - 1] ?? 0);
61
+ prev = temp;
62
+ }
63
+ }
64
+ return dp[n] ?? 0;
65
+ }
66
+ export function findMostSimilar(input, known, threshold = 85) {
67
+ const ni = normalizeAddress(input);
68
+ let best = null;
69
+ for (const addr of known) {
70
+ if (normalizeAddress(addr) === ni)
71
+ continue;
72
+ const score = calculateSimilarity(input, addr);
73
+ if (score >= threshold && (!best || score > best.similarityScore)) {
74
+ const bi = ni.startsWith("0x") ? ni.slice(2) : ni;
75
+ const ba = normalizeAddress(addr).startsWith("0x")
76
+ ? normalizeAddress(addr).slice(2)
77
+ : normalizeAddress(addr);
78
+ best = {
79
+ address: addr,
80
+ similarityScore: score,
81
+ prefixMatch: bi.slice(0, 4) === ba.slice(0, 4),
82
+ suffixMatch: bi.slice(-4) === ba.slice(-4),
83
+ };
84
+ }
85
+ }
86
+ return best;
87
+ }
88
+ //# sourceMappingURL=similarity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"similarity.js","sourceRoot":"","sources":["../src/similarity.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,sEAAsE;AAEtE,MAAM,UAAU,gBAAgB,CAAC,OAAe;IAC9C,OAAO,OAAO,CAAC,WAAW,EAAE,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,CAAS,EAAE,CAAS;IACtD,MAAM,EAAE,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAC/B,MAAM,EAAE,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAC/B,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,GAAG,CAAC;IAC1B,MAAM,KAAK,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACrD,MAAM,KAAK,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACrD,OAAO,IAAI,CAAC,KAAK,CACf,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,GAAG,GAAG;QACrC,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,GAAG,GAAG;QACvC,qBAAqB,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,GAAG,CAC5C,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,CAAS,EAAE,CAAS,EAAE,GAAW;IACzD,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC3B,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC3B,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACxD,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;QACjB,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;QACjB,IAAI,EAAE,KAAK,SAAS,IAAI,EAAE,KAAK,SAAS,IAAI,EAAE,KAAK,EAAE;YAAE,CAAC,EAAE,CAAC;IAC7D,CAAC;IACD,OAAO,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;AACzB,CAAC;AAED,SAAS,gBAAgB,CAAC,CAAS,EAAE,CAAS,EAAE,GAAW;IACzD,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC;IACzB,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC;IACzB,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACxD,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;QACjB,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;QACjB,IAAI,EAAE,KAAK,SAAS,IAAI,EAAE,KAAK,SAAS,IAAI,EAAE,KAAK,EAAE;YAAE,CAAC,EAAE,CAAC;IAC7D,CAAC;IACD,OAAO,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;AACzB,CAAC;AAED,SAAS,qBAAqB,CAAC,CAAS,EAAE,CAAS;IACjD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;IAC5C,IAAI,MAAM,KAAK,CAAC;QAAE,OAAO,GAAG,CAAC;IAC7B,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,mBAAmB,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC;AACpE,CAAC;AAED,SAAS,mBAAmB,CAAC,CAAS,EAAE,CAAS;IAC/C,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;IACnB,MAAM,EAAE,GAAa,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IAChE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACnC,IAAI,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACtB,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACV,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5B,MAAM,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACxB,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACpB,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACpB,EAAE,CAAC,CAAC,CAAC;gBACH,EAAE,KAAK,SAAS,IAAI,EAAE,KAAK,SAAS,IAAI,EAAE,KAAK,EAAE;oBAC/C,CAAC,CAAC,IAAI;oBACN,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YACrD,IAAI,GAAG,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACpB,CAAC;AASD,MAAM,UAAU,eAAe,CAC7B,KAAa,EACb,KAAe,EACf,YAAoB,EAAE;IAEtB,MAAM,EAAE,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IACnC,IAAI,IAAI,GAA2B,IAAI,CAAC;IAExC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,gBAAgB,CAAC,IAAI,CAAC,KAAK,EAAE;YAAE,SAAS;QAC5C,MAAM,KAAK,GAAG,mBAAmB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAC/C,IAAI,KAAK,IAAI,SAAS,IAAI,CAAC,CAAC,IAAI,IAAI,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC;YAClE,MAAM,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAClD,MAAM,EAAE,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;gBAChD,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;gBACjC,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;YAC3B,IAAI,GAAG;gBACL,OAAO,EAAE,IAAI;gBACb,eAAe,EAAE,KAAK;gBACtB,WAAW,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC9C,WAAW,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;aAC3C,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,58 @@
1
+ export type ChainId = "ethereum" | "bnb" | "polygon" | "avalanche" | "arbitrum" | "optimism" | "solana" | "bitcoin" | "tron";
2
+ export declare const EVM_CHAIN_MAP: Record<string, ChainId>;
3
+ export type RiskLevel = "none" | "low" | "medium" | "high" | "critical";
4
+ export type ScamReason = "address_poisoning" | "zero_value_transfer" | "batch_poisoning" | "transferfrom_spoofing" | "dust_attack" | "new_suspicious_address" | "known_phishing" | "malicious_domain" | "phishing_domain" | "typosquat_domain";
5
+ export interface NormalizedTransaction {
6
+ hash: string;
7
+ from: string;
8
+ to: string;
9
+ value: bigint;
10
+ tokenValue?: bigint;
11
+ timestamp: number;
12
+ blockNumber: number;
13
+ isIncoming: boolean;
14
+ contractAddress?: string | undefined;
15
+ methodId?: string | undefined;
16
+ isZeroValue: boolean;
17
+ isBatchPoison: boolean;
18
+ }
19
+ export interface CheckError {
20
+ code: ErrorCode;
21
+ message: string;
22
+ }
23
+ export type ErrorCode = "network_unavailable" | "history_fetch_failed" | "unsupported_chain" | "invalid_address" | "unknown_provider" | "rate_limited" | "unknown";
24
+ export interface EIP1193Provider {
25
+ request(args: {
26
+ method: string;
27
+ params?: unknown[];
28
+ }): Promise<unknown>;
29
+ on?(event: string, handler: (...args: unknown[]) => void): void;
30
+ removeListener?(event: string, handler: (...args: unknown[]) => void): void;
31
+ }
32
+ export interface PhantomProvider {
33
+ isPhantom: boolean;
34
+ publicKey?: {
35
+ toString(): string;
36
+ };
37
+ connect(): Promise<{
38
+ publicKey: {
39
+ toString(): string;
40
+ };
41
+ }>;
42
+ request?(args: {
43
+ method: string;
44
+ params?: unknown;
45
+ }): Promise<unknown>;
46
+ }
47
+ export type RawProvider = EIP1193Provider | PhantomProvider | Record<string, unknown>;
48
+ export interface HexoraProvider {
49
+ chainId(): Promise<ChainId>;
50
+ rawChainId(): Promise<string>;
51
+ isEVM(): boolean;
52
+ getProviderType(): ProviderType;
53
+ }
54
+ export type ProviderType = "eip1193" | "phantom" | "unknown";
55
+ export interface HistoryProvider {
56
+ getTransactions(address: string, chain: ChainId, limit: number): Promise<NormalizedTransaction[]>;
57
+ }
58
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ // EVM numeric chain ID → ChainId mapping
2
+ export const EVM_CHAIN_MAP = {
3
+ "0x1": "ethereum",
4
+ "0x38": "bnb",
5
+ "0x89": "polygon",
6
+ "0xa86a": "avalanche",
7
+ "0xa4b1": "arbitrum",
8
+ "0xa": "optimism",
9
+ };
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAYA,yCAAyC;AACzC,MAAM,CAAC,MAAM,aAAa,GAA4B;IACpD,KAAK,EAAE,UAAU;IACjB,MAAM,EAAE,KAAK;IACb,MAAM,EAAE,SAAS;IACjB,QAAQ,EAAE,WAAW;IACrB,QAAQ,EAAE,UAAU;IACpB,KAAK,EAAE,UAAU;CAClB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { ChainId } from "./types/index.js";
2
+ export declare function validateAddress(address: string, chain: ChainId): boolean;
3
+ //# sourceMappingURL=validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAW3C,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAYxE"}
@@ -0,0 +1,24 @@
1
+ const EVM_CHAINS = new Set([
2
+ "ethereum",
3
+ "bnb",
4
+ "polygon",
5
+ "avalanche",
6
+ "arbitrum",
7
+ "optimism",
8
+ ]);
9
+ export function validateAddress(address, chain) {
10
+ if (!address || typeof address !== "string")
11
+ return false;
12
+ if (EVM_CHAINS.has(chain))
13
+ return /^0x[0-9a-fA-F]{40}$/.test(address);
14
+ if (chain === "solana")
15
+ return /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(address);
16
+ if (chain === "bitcoin")
17
+ return (/^1[a-km-zA-HJ-NP-Z1-9]{25,34}$/.test(address) ||
18
+ /^3[a-km-zA-HJ-NP-Z1-9]{25,34}$/.test(address) ||
19
+ /^bc1[a-z0-9]{6,87}$/.test(address));
20
+ if (chain === "tron")
21
+ return /^T[a-km-zA-HJ-NP-Z1-9]{33}$/.test(address);
22
+ return address.length > 0;
23
+ }
24
+ //# sourceMappingURL=validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.js","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,GAAG,IAAI,GAAG,CAAU;IAClC,UAAU;IACV,KAAK;IACL,SAAS;IACT,WAAW;IACX,UAAU;IACV,UAAU;CACX,CAAC,CAAC;AAEH,MAAM,UAAU,eAAe,CAAC,OAAe,EAAE,KAAc;IAC7D,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC1D,IAAI,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC;QAAE,OAAO,qBAAqB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACtE,IAAI,KAAK,KAAK,QAAQ;QAAE,OAAO,+BAA+B,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC7E,IAAI,KAAK,KAAK,SAAS;QACrB,OAAO,CACL,gCAAgC,CAAC,IAAI,CAAC,OAAO,CAAC;YAC9C,gCAAgC,CAAC,IAAI,CAAC,OAAO,CAAC;YAC9C,qBAAqB,CAAC,IAAI,CAAC,OAAO,CAAC,CACpC,CAAC;IACJ,IAAI,KAAK,KAAK,MAAM;QAAE,OAAO,6BAA6B,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzE,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;AAC5B,CAAC"}
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@hexora/core",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "devDependencies": {
18
+ "typescript": "^5.5.4"
19
+ },
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "scripts": {
24
+ "build": "tsc",
25
+ "lint": "eslint src",
26
+ "dev": "tsc --watch"
27
+ }
28
+ }