Initial Commit

This commit is contained in:
2026-05-27 23:47:53 +01:00
parent fbc70f96e6
commit 9b28db724f
18103 changed files with 1600554 additions and 0 deletions

View File

@@ -0,0 +1,150 @@
import type {
ChainId,
FunctionSignature,
TxMetadata,
} from "../types/crypto.types.js";
/** Well-known ERC-20 / ERC-721 function selectors. */
export const KNOWN_SELECTORS: FunctionSignature[] = [
{
selector: "0xa9059cbb",
name: "transfer",
signature: "transfer(address,uint256)",
},
{
selector: "0x095ea7b3",
name: "approve",
signature: "approve(address,uint256)",
},
{
selector: "0x23b872dd",
name: "transferFrom",
signature: "transferFrom(address,address,uint256)",
},
{
selector: "0x70a08231",
name: "balanceOf",
signature: "balanceOf(address)",
},
{
selector: "0xdd62ed3e",
name: "allowance",
signature: "allowance(address,address)",
},
{
selector: "0x18160ddd",
name: "totalSupply",
signature: "totalSupply()",
},
{
selector: "0x42842e0e",
name: "safeTransferFrom",
signature: "safeTransferFrom(address,address,uint256)",
},
{
selector: "0xa22cb465",
name: "setApprovalForAll",
signature: "setApprovalForAll(address,bool)",
},
];
const EVM_TX_HASH = /^0x[0-9a-fA-F]{64}$/;
const UTXO_TX_HASH = /^[0-9a-fA-F]{64}$/;
const SOLANA_TX_SIG = /^[1-9A-HJ-NP-Za-km-z]{87,88}$/;
const CALLDATA_PATTERN = /^0x[0-9a-fA-F]{8,}$/;
const EVM_CHAINS: ChainId[] = [
"ethereum",
"polygon",
"arbitrum",
"optimism",
"avalanche",
"bsc",
"base",
];
/**
* Decode a transaction hash and extract metadata. Determines the hash type
* (`evm` / `utxo` / `solana` / `unknown`) and which chains it could belong to.
*/
export function decodeTxHash(hash: string): TxMetadata {
if (!hash || typeof hash !== "string") {
return { hash: "", chains: [], valid: false, hashType: "unknown" };
}
const trimmed = hash.trim();
if (EVM_TX_HASH.test(trimmed)) {
return {
hash: trimmed,
chains: [...EVM_CHAINS],
valid: true,
hashType: "evm",
hashHex: trimmed.slice(2).toLowerCase(),
};
}
if (UTXO_TX_HASH.test(trimmed)) {
return {
hash: trimmed,
chains: ["bitcoin", "litecoin", "dogecoin"],
valid: true,
hashType: "utxo",
hashHex: trimmed.toLowerCase(),
};
}
if (SOLANA_TX_SIG.test(trimmed)) {
return {
hash: trimmed,
chains: ["solana"],
valid: true,
hashType: "solana",
};
}
return { hash: trimmed, chains: [], valid: false, hashType: "unknown" };
}
/**
* Look up a function selector in the known-signatures table. The lookup is
* case-insensitive on the input selector.
*
* @example
* lookupSelector('0xa9059cbb')
* // { selector: '0xa9059cbb', name: 'transfer', signature: 'transfer(address,uint256)' }
*/
export function lookupSelector(
selector: string
): FunctionSignature | undefined {
const normalized = selector.toLowerCase();
return KNOWN_SELECTORS.find((s) => s.selector === normalized);
}
/**
* Extract the 4-byte function selector from calldata. Returns `undefined`
* for empty / non-string / non-hex / too-short input.
*
* @example
* extractSelector('0xa9059cbb000000000000000000000000...')
* // '0xa9059cbb'
*/
export function extractSelector(calldata: string): string | undefined {
if (!calldata || typeof calldata !== "string") return undefined;
const trimmed = calldata.trim();
if (!CALLDATA_PATTERN.test(trimmed)) return undefined;
return trimmed.slice(0, 10).toLowerCase();
}
/**
* Decode calldata and return the matching function signature if known.
* This is a naive matcher — it does not decode the argument bytes, only
* the 4-byte selector. ABI-aware decoding lands in a follow-up change.
*/
export function decodeCalldata(
calldata: string
): FunctionSignature | undefined {
const selector = extractSelector(calldata);
if (!selector) return undefined;
return lookupSelector(selector);
}