/** * EVM Transaction Types */ /** * Gas configuration for EVM transactions */ export interface EVMGasConfig { gasLimit?: number | null maxFeePerGas?: number | null maxPriorityFeePerGas?: number | null } /** * EVM transaction parameters ready for sending (viem format) */ export interface EVMTransactionParams { from?: string to?: string data?: string value?: bigint gasLimit?: bigint maxFeePerGas?: bigint maxPriorityFeePerGas?: bigint } /** * Request for native EVM token transfer (ETH, BNB, MATIC, etc.) */ export interface EVMNativeTransferRequest { to: string amount: bigint from: string gasConfig?: EVMGasConfig } /** * Request for EVM smart contract interaction */ export interface EVMContractCallRequest { contractAddress: string // eslint-disable-next-line @typescript-eslint/no-explicit-any abi: any[] // ethers.InterfaceAbi functionName: string args: unknown[] from: string /** * Native currency to attach to a payable call, in wei (unsigned). A bigint, or a * decimal or `0x`-hex string — `1000000000000000000n`, `'1000000000000000000'`, * and `'0xde0b6b3a7640000'` are all 1 ETH. Omitted → 0. */ value?: bigint | string gasConfig?: EVMGasConfig } /** * Request for EVM transaction call data */ export interface EVMDataTransferRequest { from: string to: string data: string /** * Native currency to attach to the call, in wei (unsigned). A bigint, or a * decimal or `0x`-hex string — `1000000000000000000n`, `'1000000000000000000'`, * and `'0xde0b6b3a7640000'` are all 1 ETH. Omitted → 0. */ value?: bigint | string chainId: string gasConfig?: EVMGasConfig } /** * Request for batch EVM transactions (EIP-5792) */ export interface EVMBatchTransactionRequest { version: string from: string chainId: string atomicRequired: boolean calls: ( | EVMNativeTransferRequest | EVMContractCallRequest | EVMDataTransferRequest )[] } /** * EVM wallet capabilities */ export interface EVMCapabilities { alternateGasFees?: EVMCapability atomic?: EVMCapability paymasterService?: EVMCapability } export type EVMCapability = { status: EVMCapabilityStatus } export type EVMCapabilityStatus = 'supported' | 'ready' | 'unsupported' /** * Solana Transaction Types */ /** * Request for native SOL transfer */ export interface SolanaNativeTransferRequest { from: string to: string amount: bigint blockhash: string } /** * Request for SPL token transfer */ export interface SolanaTokenTransferRequest extends SolanaNativeTransferRequest { tokenMint: string tokenDecimals: number tokenProgram?: string } /** * Request for Solana transfers with instructions */ export interface SolanaGenericTransferRequest { feePayer: string blockhash: string instructions: SolanaTransactionInstruction[] states?: SolanaAddressLookupTable[] additionalRequests?: ( | SolanaNativeTransferRequest | SolanaTokenTransferRequest )[] } export interface SolanaAddressLookupTable { deactivationSlot: bigint lastExtendedSlot: number lastExtendedStartIndex: number key: string authority?: string addresses: string[] } export interface SolanaTransactionInstruction { programId: string accounts: SolanaAccountMeta[] data: string } export interface SolanaAccountMeta { shouldFillPubkey: boolean pubKey: string | null isWritable: boolean isSigner: boolean } /** * Tron Transaction Types */ /** * Request for native TRX transfer */ export interface TronNativeTransferRequest { from: string // sender address (base58) to: string // recipient address (base58) // amount in SUN (1 TRX = 1,000,000 SUN). `bigint` avoids the float-precision // loss of `number` above 2^53; native amounts are serialized to the node as a // JSON number, so they must still be within the safe-integer range. amount: number | bigint } /** * Request for TRC20 token transfer */ export interface TronTRC20TransferRequest { from: string // sender address (base58) to: string // recipient address (base58) // amount in the token's base units. `bigint` carries full precision — TRC20 // amounts are ABI-encoded as a 256-bit word, never as a JSON number, so they // are not bound by the safe-integer range. amount: number | bigint contractAddress: string // TRC20 contract address (base58) } /** * Request to broadcast a pre-encoded Tron `TriggerSmartContract` call verbatim. * * Used for bridging deposits where the provider (Relay) returns fully-formed * calldata that MUST be broadcast byte-for-byte: it carries a trailing tag (the * Relay request id appended after the ABI `transfer` args) that ties the deposit * to the quote. Re-encoding a plain `transfer(to, amount)` — as * {@link TronTRC20TransferRequest} does — would drop that tag and the deposit * could never be matched/filled. Unlike the TRC20 request, the connector does * NOT derive the calldata here; it forwards `data` unchanged and verifies the * node-built transaction reproduces it exactly before signing. * * Any selector is accepted: the node's `triggersmartcontract` endpoint takes the * complete calldata in its `data` field and re-emits it verbatim, so a router * `deposit`/`swap` forwards as faithfully as a plain `transfer`. Only the TRC20 * `transfer(address,uint256)` layout (`a9059cbb`) additionally has its recipient * word decoded and sanity-checked; for every other selector the args are opaque * and the byte-for-byte built-tx guard is the protection. */ export interface TronContractCallRequest { from: string // sender / owner address (base58 or hex) contractAddress: string // target contract address (base58 or hex) /** * Native TRX to attach, in SUN, for a **payable** call — a router's * `depositNative(address,bytes32)` takes no amount argument, so the deposit * amount can only travel here. Omit (or 0) for a non-payable call such as a * TRC20 `transfer`/`approve`, where the amount lives in the calldata. * * Serialized to the node as a JSON number, so — like * {@link TronNativeTransferRequest.amount} — it must stay within the * safe-integer range. Getting this wrong is silent: a payable call sent with 0 * still succeeds on-chain and simply moves nothing. */ callValue?: number | bigint // Full ABI calldata incl. the 4-byte selector, hex (with or without `0x`). // Forwarded to the node verbatim — never re-encoded. data: string } export type TronTransactionRequest = | TronNativeTransferRequest | TronTRC20TransferRequest | TronContractCallRequest /** * Bitcoin (bip122) Transaction Types */ /** SIGHASH flag for a PSBT input (Wallet Standard bitcoin values). */ export type BitcoinSigHash = | 'ALL' | 'NONE' | 'SINGLE' | 'ALL|ANYONECANPAY' | 'NONE|ANYONECANPAY' | 'SINGLE|ANYONECANPAY' /** Which inputs of a PSBT a given address should sign. */ export interface BitcoinPsbtInputToSign { address: string signingIndexes: number[] sigHash?: BitcoinSigHash } /** * Path B — sign a backend-constructed PSBT (Wallet Standard `signTransaction`). * The wallet signs the requested inputs and returns the signed PSBT; the * connector finalizes and broadcasts (to mempool.space). Not a wallet broadcast. */ export interface BitcoinPsbtSignRequest { from: string /** Base64-encoded PSBT (BIP-174). */ psbt: string /** Inputs to sign; when omitted the wallet signs all it can. */ inputsToSign?: BitcoinPsbtInputToSign[] } /** * Path A — high-level transfer (Trust Wallet WalletConnect `sendTransfer`). The * wallet does coin selection, fee estimation, signing, and broadcast. */ export interface BitcoinSendTransferRequest { from: string to: string // amount in satoshis. `bigint` avoids float-precision loss; sats are // serialized to a JSON number over WalletConnect, so values must stay within // the safe-integer range (BTC's 2.1e15-sat cap does). amount: number | bigint } export type BitcoinTransactionRequest = | BitcoinPsbtSignRequest | BitcoinSendTransferRequest /** * Common Transaction Types */ /** * Logical parameters for a TON Jetton (TEP-74) transfer. * * On TON, token transfers work differently from EVM: instead of calling a single * token contract, the message is sent to the sender's Jetton wallet contract, * which routes tokens to the recipient's Jetton wallet on-chain. * * Use with buildJettonTransferPayload and buildTonNativeRequestFromJettonTransfer * in @meshconnect/uwc-ton-connector to produce a TonNativeTransferRequest. * * @see https://github.com/ton-blockchain/TEPs/blob/master/text/0074-jettons-standard.md * @see https://docs.ton.org/standard/tokens/jettons/transfer */ export interface TonJettonTransferParams { /** Recipient's TON address (not their Jetton wallet — routing happens on-chain). */ destination: string /** Token amount in base units. Account for decimals (e.g. USDT 6 decimals: "1000000" = 1 USDT). */ amount: string /** Address for excess TON gas refund. Should be the sender's address. */ responseDestination: string /** * Nanotons forwarded with a transfer_notification to the recipient's contract. * "0" (default): no notification — tokens transfer silently. Wallet apps still show it. * \> "0": recipient contract is notified (needed for DEX swaps, payment triggers). */ forwardTonAmount?: string /** Text comment for the recipient. Only delivered when forwardTonAmount > 0. */ forwardComment?: string /** 64-bit query id for correlating request/response (default 0). Must be 0 to 2^64-1. */ queryId?: string } /** TON native transfer request — also used for Jetton transfers (with payload carrying the TEP-74 Cell). */ export interface TonNativeTransferRequest { /** Destination address. For native: recipient. For Jetton: sender's Jetton wallet contract. */ to: string /** Nanotons as string. For native: transfer amount. For Jetton: gas attached to the message. */ amount: string /** Sender's TON address. */ from: string /** Base64-encoded BOC. For Jetton transfers, this carries the TEP-74 transfer Cell. */ payload?: string /** Base64-encoded BOC for deploying a contract alongside the transfer. */ stateInit?: string /** * @deprecated Not transmittable. TON Connect's request shape allows only * `validUntil` / `network` / `from` / `messages`, so `@tonconnect/sdk` rejects a * request carrying a send mode and the wallet picks the mode itself (Tonkeeper * uses pay-gas-separately + ignore-errors). Setting this throws in * `buildTonTransactionRequest`. To send an entire balance, compute the amount. * Slated for removal in the next major of this package. */ sendMode?: number /** Unix timestamp (seconds) after which the transaction expires. Defaults to now + 5 min. */ validUntil?: number } /** Transaction identifier returned by the connector (e.g. hex hash on EVM, base58 signature on Solana). */ export type TransactionResult = string /** * Result of a batch transaction */ export interface BatchTransactionResult { id: string status: number atomic: boolean receipts: Array<{ transactionHash: TransactionResult }> } /** * Generic transaction request that can be either EVM or Solana */ export type TransactionRequest = | EthereumTransactionRequest | SolanaTransactionRequest | TronTransactionRequest | TonNativeTransferRequest | BitcoinTransactionRequest export type EthereumTransactionRequest = | EVMNativeTransferRequest | EVMContractCallRequest | EVMBatchTransactionRequest | EVMDataTransferRequest export type SolanaTransactionRequest = | SolanaNativeTransferRequest | SolanaTokenTransferRequest | SolanaGenericTransferRequest /** * Normalize an EVM `value` (in wei) to a bigint for viem. * * Accepts a bigint or a decimal / `0x`-hex string. Missing/nullish → 0n. Anything * else throws with context rather than silently coercing to 0 on a money path: * empty/whitespace, non-numeric, binary/octal (`0b`/`0o`), negative, or a * non-string/non-bigint value (e.g. a number arriving from untyped JSON). */ export function toEvmValueBigInt(value?: bigint | string | null): bigint { if (value == null) return 0n if (typeof value === 'bigint') { if (value < 0n) throw new Error(`Invalid EVM value: "${value}"`) return value } if (typeof value !== 'string') { throw new Error( `Invalid EVM value: expected bigint or string, got ${typeof value}` ) } const trimmed = value.trim() if (trimmed === '') { throw new Error('Invalid EVM value: empty string') } // BigInt() accepts 0b/0o prefixes; reject so only decimal and 0x-hex wei parse. if (/^[+-]?0[bo]/i.test(trimmed)) { throw new Error(`Invalid EVM value: "${value}"`) } let result: bigint try { result = BigInt(trimmed) } catch { throw new Error(`Invalid EVM value: "${value}"`) } if (result < 0n) throw new Error(`Invalid EVM value: "${value}"`) return result }